⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 script.cpp

📁 用MFC写的RPG游戏
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//
// 脚本(Script)的执行
//
//		Copyright (c) 2000-2001 Chihiro.SAKAMOTO (HyperWorks)
//
#include "stdafx.h"
#include <stdlib.h>
#include "MainWin.h"
#include "File.h"
#include "Misc.h"
#include "Script.h"

//
// 构造函数
//
CScriptAction::CScriptAction(CMainWin *win, CAction *oldAction, int mode)
	: CAction(win, oldAction), reader(0)
{
	// 命令表格(command table)的初始化
	cmd_table.insert(CmdTab("set",		&CScriptAction::SetCmd));
	cmd_table.insert(CmdTab("calc",		&CScriptAction::SetCmd));
	cmd_table.insert(CmdTab("text",		&CScriptAction::TextCmd));
	cmd_table.insert(CmdTab("goto",		&CScriptAction::GotoCmd));
	cmd_table.insert(CmdTab("if",		&CScriptAction::IfCmd));
	cmd_table.insert(CmdTab("menu",		&CScriptAction::MenuCmd));
	cmd_table.insert(CmdTab("exec",		&CScriptAction::ExecCmd));
	cmd_table.insert(CmdTab("load",		&CScriptAction::LoadCmd));
	cmd_table.insert(CmdTab("update",	&CScriptAction::UpdateCmd));
	cmd_table.insert(CmdTab("clear",	&CScriptAction::ClearCmd));
	cmd_table.insert(CmdTab("music",	&CScriptAction::MusicCmd));
	cmd_table.insert(CmdTab("stopm",	&CScriptAction::StopmCmd));
	cmd_table.insert(CmdTab("wait",		&CScriptAction::WaitCmd));
	cmd_table.insert(CmdTab("sound",	&CScriptAction::SoundCmd));
	cmd_table.insert(CmdTab("fadein",	&CScriptAction::FadeInCmd));
	cmd_table.insert(CmdTab("fadeout",	&CScriptAction::FadeOutCmd));
	cmd_table.insert(CmdTab("wipein",	&CScriptAction::WipeInCmd));
	cmd_table.insert(CmdTab("wipeout",	&CScriptAction::WipeOutCmd));
	cmd_table.insert(CmdTab("cutin",	&CScriptAction::CutInCmd));
	cmd_table.insert(CmdTab("cutout",	&CScriptAction::CutOutCmd));
	cmd_table.insert(CmdTab("whitein",	&CScriptAction::WhiteInCmd));
	cmd_table.insert(CmdTab("whiteout",	&CScriptAction::WhiteOutCmd));
	cmd_table.insert(CmdTab("flash",	&CScriptAction::FlashCmd));
	cmd_table.insert(CmdTab("shake",	&CScriptAction::ShakeCmd));
	cmd_table.insert(CmdTab("mode",		&CScriptAction::ModeCmd));
	cmd_table.insert(CmdTab("system",	&CScriptAction::SystemCmd));
	cmd_table.insert(CmdTab("battle",	&CScriptAction::BattleCmd));
	cmd_table.insert(CmdTab("end",		&CScriptAction::EndCmd));

	status = Continue;
	Pressed = FALSE;
	MenuSelect = -1;
	PlayMode = mode;

	delete reader;
	reader = 0;
}

//
// 析构函数
//
CScriptAction::~CScriptAction()
{
	delete reader;
}

//
// 错误事件的格式
//
char *__cdecl CScriptAction::Format(const char *fmt, ...)
{
	static	char	tmp[256];

	va_list	args;
	va_start(args, fmt);
	_vsnprintf(tmp, sizeof(tmp), fmt, args);
	va_end(args);

	return tmp;
}

//
// 暂停
//
void CScriptAction::Pause()
{
	switch (status) {
	  case WaitMenuDone:	// 等待菜单
		if (MenuSelect >= 0) {
			Parent->SelectMenu(MenuSelect, false);
			MenuSelect = -1;
		}
		break;
	}
}

//
// 解除暂停
//
void CScriptAction::Resume()
{
	switch (status) {
	  case WaitMenuDone:	// 等待菜单
		{
			CPoint	point;
			GetCursorPos(&point);
			Parent->ScreenToClient(&point);
			MenuSelect = Parent->GetMenuSelect(point);
			if (MenuSelect >= 0)
				Parent->SelectMenu(MenuSelect, true);
		}
		break;
	}
}

//
// 按下鼠标左键时的处理
//
void CScriptAction::LButtonDown(UINT modKeys, CPoint point)
{
	switch (status) {
	  case WaitMenuDone:	// 等待菜单
		Pressed = TRUE;
		break;
	}
}

//
// 放开鼠标左键时的处理
//
void CScriptAction::LButtonUp(UINT modKeys, CPoint point)
{
	switch (status) {
	  case WaitKeyPressed:	// 等待按键
		Parent->HideWaitMark();
		status = Continue;
		break;

	  case WaitMenuDone:	// 等待菜单
		if (Pressed) {
			Pressed = FALSE;
			MouseMove(modKeys, point);

			if (MenuSelect >= 0) {
				Parent->SetValue(MenuAnser, Parent->GetMenuAnser(MenuSelect));
				Parent->HideMenuWindow();
				status = Continue;
			}
			MenuSelect = -1;
		}
		break;
	}
}

//
// 按下鼠标右键时的处理
//
void CScriptAction::RButtonDown(UINT modKeys, CPoint point)
{
	switch (status) {
	  case WaitKeyPressed:	// 等待按键
		Parent->FlipMessageWindow();
		break;
	}
}

//
// 移动鼠标时的处理
//
void CScriptAction::MouseMove(UINT modKeys, CPoint point)
{
	switch (status) {
	  case WaitMenuDone:	// 等待菜单
		{
			int sel = Parent->GetMenuSelect(point);
			if (sel != MenuSelect) {
				Parent->SelectMenu(MenuSelect, false);
				MenuSelect = sel;
				Parent->SelectMenu(MenuSelect, true);
			}
		}
		break;
	}
}

//
// 按下键盘时的处理
//
void CScriptAction::KeyDown(UINT key)
{
	switch (key) {
	  case VK_RETURN:
	  case VK_SPACE:
		switch (status) {
		  case WaitKeyPressed:	// 等待按键
			Parent->HideWaitMark();
			status = Continue;
			break;

		  case WaitMenuDone:	// 等待菜单
			if (MenuSelect >= 0) {
				Parent->SetValue(MenuAnser, Parent->GetMenuAnser(MenuSelect));
				Parent->HideMenuWindow();
				status = Continue;
				MenuSelect = -1;
			}
			break;
		}
		break;

	  case VK_ESCAPE:
		switch (status) {
		  case WaitKeyPressed:	// 等待按键
			Parent->FlipMessageWindow();
			break;
		}
		break;

	  case VK_UP:
		if (status == WaitMenuDone) {	// 等待菜单
			Parent->SelectMenu(MenuSelect, false);
			MenuSelect--;
			if (MenuSelect < 0)
				MenuSelect = Parent->GetMenuItemCount() - 1;
			Parent->SelectMenu(MenuSelect, true);
		}
		break;

	  case VK_DOWN:
		if (status == WaitMenuDone) {	// 等待菜单
			Parent->SelectMenu(MenuSelect, false);
			MenuSelect++;
			if (MenuSelect >= Parent->GetMenuItemCount())
				MenuSelect = 0;
			Parent->SelectMenu(MenuSelect, true);
		}
		break;
	}
}

//
// IDLE的处理
//
BOOL CScriptAction::IdleAction()
{
	if (status == Continue) {				// 执行“继续”
		do {
			status = Step();				// 执行一步
		} while (status == Continue) ;		// 继续吗?

		if (status == BreakGame) {			// 结束
			Abort();
		}
		else if (status == WaitNextIdle) {	// 等待下个IDLE处理
			status = Continue;				// 继续
			return TRUE;
		}
		else if (status == WaitWipeDone) {	// 等待特效结束
			return TRUE;					// IDLE继续
		}
	}
	return FALSE;
}

//
// 计时器的处理
//
bool CScriptAction::TimedOut(int timerId)
{
	switch (timerId) {
	  case CMainWin::TimerSleep:	// 等待Timeout
		if (status == WaitTimeOut)
			status = Continue;
		break;
	}
	return true;
}

//
// Wipe特效结束时的处理
//
void CScriptAction::WipeDone()
{
	if (status == WaitWipeDone)		// 等待特效结束
		status = Continue;
}

//
// Wave播放结束时的处理
//
void CScriptAction::WaveDone()
{
	if (status == WaitWaveDone)		// 等待WAVE播放结束
		status = Continue;
}

//
// Script执行结束
//
void CScriptAction::Abort()
{
	if (status == WaitMenuDone)		// 如果要等待菜单的话
		Parent->HideMenuWindow();	// 关闭菜单
	Parent->HideMessageWindow();	// 关闭事件

	status = BreakGame;
	delete reader;					//  删除Script
	reader = 0;

	Parent->ScriptDone();
}

//
// 读取Script档
//
bool CScriptAction::LoadFile(const char *name)
{
	char	path[_MAX_PATH];
	sprintf(path, SCRIPTPATH "%s.txt", name);

	label_table.clear();			// 清除标签表(lable table)
	delete reader;					// 丢弃之前的Script
	reader = new TextReader(path);

	return reader->IsOk();
}

//
// 读取Script档,并设定成员变量
//
BOOL CScriptAction::Load(const char *name)
{
	strncpy(Parent->GetParam().last_script, name, 16);

	if (!LoadFile(name)) {
		Parent->MessageBox(Format("无法读取 [%s] Script档案", name));
		return FALSE;
	}
	return TRUE;
}

//
// 进行设定,让Script从储存位置中可以再度开启
//
BOOL CScriptAction::Setup(CParams &param)
{
	reader->SetPosition(param.script_pos);

	if (param.last_bgm)
		Parent->StartMusic(param.last_bgm);

	switch (param.show_flag) {
	  case SHOWCG_IMAGE:
		if (param.last_bg[0])
			LoadGraphic(param.last_bg, POSITION_BACK);
		if (param.last_overlap[0]) {
			LoadGraphic(param.last_overlap, POSITION_OVERLAP);
		}
		Parent->WipeIn();
		status = WaitWipeDone;
		break;

	  case SHOWCG_BLACKNESS:
		Parent->CutOut();
		status = Continue;
		break;

	  case SHOWCG_WHITENESS:
		Parent->CutOut(TRUE);
		status = Continue;
		break;
	}
	return TRUE;
}

//
// 错误事件的输出
//
void __cdecl CScriptAction::Error(const char *fmt, ...)
{
	va_list	args;

	char	str[256];
	int len = 0;
	if (reader)
		len = sprintf(str, "%s:%d ", reader->GetFileName(), reader->GetLineNo());
	va_start(args, fmt);
	_vsnprintf(str + len, sizeof(str) - len, fmt, args);
	va_end(args);

	Parent->MessageBox(str);
}

//
// 比对关键字
//
bool CScriptAction::ChkKeyword(const char *str, const char *keyword)
{
	while (*str) {
		if (tolower(*str++) != *keyword++)
			return false;
	}
	return true;
}

//
// CG的指定位置设定成位置码
//
int CScriptAction::GetPosition(const char *str)
{
	if (ChkKeyword(str, "bg") || ChkKeyword(str, "back"))
		return POSITION_BACK;
	if (ChkKeyword(str, "bgo") || ChkKeyword(str, "backonly"))
		return POSITION_BACKONLY;
	if (ChkKeyword(str, "overlap"))
		return POSITION_OVERLAP;

	Error("文法错误(position)");
	return POSITION_BACK;
}

//
// 依照命令来更新指定特效
//
int CScriptAction::GetUpdateType(const char *str)
{
	if (ChkKeyword(str, "cut") || ChkKeyword(str, "now"))
		return UPDATE_NOW;
	if (ChkKeyword(str, "overlap"))
		return UPDATE_OVERLAP;
	if (ChkKeyword(str, "wipe"))
		return UPDATE_WIPE;

	Error("文法错误(update type)");
	return UPDATE_NOW;
}

//
// 移到Script中指定的位置
//
int CScriptAction::GotoCommand(const char *label)
{
	labelmap::iterator p = label_table.find(label);
	if (p == label_table.end()) {		// 找不到标签
		const char *str;
		// 从Script档中搜寻标签
		while ((str = reader->GetString()) != NULL) {
			Lexer	lexer(str);
			if (lexer.NumToken() == 1
			 && lexer.GetType() == Lexer::IsLabel) {
				if (SetLabel(lexer) != Continue)	// 登录标签
					return BreakGame;

				const char *p = lexer.GetString(0) + 1;
				if (stricmp(p, label) == 0)			// 找到标签了!
					return Continue;
			}
		}
		Error("找不到标签[%s]", label);
		return BreakGame;
	}
	reader->SetPosition(p->second);

	return Continue;
}

//
// 标签的登录指令
//
int CScriptAction::SetLabel(Lexer &lexer)
{
	if (lexer.NumToken() != 1) {
		Error("参数太多了");
		return BreakGame;
	}

	const char *label = lexer.GetString() + 1;
	labelmap::iterator p = label_table.find(label);
	if (p != label_table.end()) {	// 标签已经存在
		if (label_table[label] != reader->GetPosition()) {
			Error("标签 [%s] 已经登录过了", label);
			return BreakGame;
		}
	}
	label_table[label] = reader->GetPosition();

	return Continue;
}

//
// set指令
//
int CScriptAction::SetCmd(Lexer &lexer)
{
	const char *name = lexer.GetString();
	const char *op = lexer.GetString();
	int value;
	bool b = lexer.GetValue(&value);

	if (name == 0 || op == 0 || !b || lexer.GetString() != 0) {
		Error("文法错误");
		return BreakGame;
	}

	if (strcmp(op, "=") == 0) {			// 指定代入
		Parent->SetValue(name, value);
	}
	else if (strcmp(op, "+") == 0) {	// 加法
		Parent->AddValue(name, value);
	}
	else if (strcmp(op, "-") == 0) {	// 减法
		Parent->DelValue(name, value);
	}
	else {
		Error("文法错误");
		return BreakGame;
	}
	return Continue;
}

//
// goto指令
//
int CScriptAction::GotoCmd(Lexer &lexer)
{
	const char *label = lexer.GetString();

	if (label == 0 || lexer.GetString() != 0) {
		Error("文法错误(in goto command)");
		return BreakGame;
	}
	return GotoCommand(label);
}

//
// 取得变量或常数
//
bool CScriptAction::GetValue(Lexer &lexer, int *value)
{
	if (lexer.GetType() == Lexer::IsString) {	// 字符串
		const char *name = lexer.GetString();
		*value = Parent->GetValue(name);
		return true;
	}
	return lexer.GetValue(value);		// 当成数字读看看
}

//
// if 指令
//
int CScriptAction::IfCmd(Lexer &lexer)
{
	int	value1, value2;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -