本篇是游戏脚本的实现(3)的续篇。
首先来看看WinMain函数以及主窗口处理过程的实现:
//-----------------------------------------------------------------------------------
// Routine entry.
//-----------------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE inst, HINSTANCE, LPSTR cmd_line, int cmd_show)
{
const char* class_name = "mls edit class";
WNDCLASS win_class;
// create window class and register it
win_class.style = CS_HREDRAW | CS_VREDRAW;
win_class.lpfnWndProc = window_proc;
win_class.cbClsExtra = 0;
win_class.cbWndExtra = DLGWINDOWEXTRA;
win_class.hInstance = inst;
win_class.hIcon = LoadIcon(inst, IDI_APPLICATION);
win_class.hCursor = LoadCursor(NULL, IDC_ARROW);
win_class.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
win_class.lpszMenuName = NULL;
win_class.lpszClassName = class_name;
if(! RegisterClass(&win_class))
return FALSE;
// The CreateDialog macro creates a modeless dialog box from a dialog box template resource.
// The CreateDialog macro uses the CreateDialogParam function.
//
// HWND CreateDialog(
// HINSTANCE hInstance,
// LPCTSTR lpTemplate,
// HWND hWndParent,
// DLGPROC lpDialogFunc);
//
// hInstance:
// [in] Handle to the module whose executable file contains the dialog box template.
//
// lpTemplate
// [in] Specifies the dialog box template. This parameter is either the pointer to a null-terminated
// character string that specifies the name of the dialog box template or an integer value that
// specifies the resource identifier of the dialog box template. If the parameter specifies a resource
// identifier, its high-order word must be zero and its low-order word must contain the identifier.
// You can use the MAKEINTRESOURCE macro to create this value.
//
// hWndParent:
// [in] Handle to the window that owns the dialog box.
//
// lpDialogFunc:
// [in] Pointer to the dialog box procedure. For more information about the dialog box procedure,
// see DialogProc.
//
// Return Value:
// If the function succeeds, the return value is the handle to the dialog box.
// If the function fails, the return value is NULL. To get extended error information, call GetLastError.
// Create the dialog box window and show it
g_hwnd = CreateDialog(inst, MAKEINTRESOURCE(IDD_MAIN), 0, NULL);
ShowWindow(g_hwnd, cmd_show);
UpdateWindow(g_hwnd);
g_script_wnd = GetDlgItem(g_hwnd, IDC_SCRIPT);
g_script_addr_wnd = GetDlgItem(g_hwnd, IDC_SCRIPT_ADDR);
g_action_wnd = GetDlgItem(g_hwnd, IDC_ACTION);
// force a load of action in default.mla
load_actions_from_file("..\\Data\\Default.mla");
MSG msg;
// message loop
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
delete g_root_script;
UnregisterClass(class_name, inst);
return 0;
}
//------------------------------------------------------------------------------------------------
// Main window procedure.
//------------------------------------------------------------------------------------------------
LRESULT CALLBACK window_proc(HWND hwnd, UINT msg_id, WPARAM word_param, LPARAM long_param)
{
switch(msg_id)
{
case WM_COMMAND:
wm_command_proc(word_param);
break;
case WM_CREATE:
// initialize the save/load dialog box information
ZeroMemory(&g_ofn, sizeof(OPENFILENAME));
g_ofn.lStructSize = sizeof(OPENFILENAME);
g_ofn.nMaxFile = MAX_PATH;
g_ofn.nMaxFileTitle = MAX_PATH;
g_ofn.Flags = OFN_HIDEREADONLY | OFN_CREATEPROMPT | OFN_OVERWRITEPROMPT;
// clear script filenmae
g_script_file[0] = 0;
g_action_file[0] = 0;
// clear all list boxes
reset_listbox(g_script_wnd);
reset_listbox(g_script_addr_wnd);
reset_listbox(g_action_wnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg_id, word_param, long_param);
}
return 0;
}
使用load_actions_from_file函数来加载行为脚本:
//-----------------------------------------------------------------------------------
// Load action template file.
//-----------------------------------------------------------------------------------
BOOL load_actions_from_file(const char* filename)
{
if(filename == NULL) // ask for filename if none passed
{
// setup the open dialog information
g_ofn.hwndOwner = g_hwnd;
g_ofn.lpstrFile = g_action_file;
g_ofn.lpstrTitle = "Load Actions File";
g_ofn.lpstrFilter = "MLS Action Files (*.mla)\0*.mla\0All Files (*.*)\0*.*\0\0";
g_ofn.lpstrDefExt = "mla";
// get action template file name
//
// Creates an Open dialog box that lets the user specify the drive, directory,
// and the name of a file to open.
if(! GetOpenFileName(&g_ofn))
return FALSE;
// ask if sure to make new script
if(! new_script())
return FALSE;
}
else
strcpy(g_action_file, filename);
// attempt to load actions
if(! g_action_template.load_actions(g_action_file))
{
MessageBox(g_hwnd, g_action_file, "Unable to open file", MB_OK);
return FALSE;
}
// clear the list box
reset_listbox(g_action_wnd);
// get a pointer to the parent action
ACTION_PTR act_ptr = g_action_template.get_root_action();
long num_actions = g_action_template.get_num_actions();
// loop through all actions
for(long i = 0; i < num_actions; i++)
{
char text[2048];
// get expanded action text
g_action_template.expand_default_action_text(text, act_ptr);
// add action text to action list
add_string_to_listbox(g_action_wnd, text);
// go to next action
act_ptr = act_ptr->next;
}
return TRUE;
}
所有的脚本编辑命令都在wm_command_proc函数中处理:
//-------------------------------------------------------------------------------------------------
// The WM_COMMAND message is sent when the user selects a command item from a menu, when a control
// sends a notification message to its parent window, or when an accelerator keystroke is translated.
//
// WM_COMMAND
// WPARAM wParam
// LPARAM lParam;
//
// wParam:
// The high-order word specifies the notification code if the message is from a control.
// If the message is from an accelerator, this value is 1. If the message is from a menu,
// this value is zero.
//
// The low-order word specifies the identifier of the menu item, control, or accelerator.
//
// lParam:
// Handle to the control sending the message if the message is from a control.
// Otherwise, this parameter is NULL.
//
// If an application processes this message, it should return zero.
//-------------------------------------------------------------------------------------------------
void wm_command_proc(WPARAM word_param)
{
switch(LOWORD(word_param))
{
case IDC_NEW: // create a new script
new_script();
break;
case IDC_LOAD: // load a script file
load_script();
break;
case IDC_SAVE: // save a script file
save_script();
break;
case IDC_LOADACTIONS: // load an action file
load_actions_from_file(NULL);
break;
case IDC_SCRIPT: // edit a script
if(HIWORD(word_param) != LBN_DBLCLK)
break;
case IDC_EDIT:
edit_script();
break;
case IDC_ACTIONS: // add an actiotion
if(HIWORD(word_param) != LBN_DBLCLK)
break;
case IDC_ADD:
add_script();
break;
case IDC_INSERT: // insert a script
insert_script();
break;
case IDC_DELETE: // delete a script
delete_script();
break;
case IDC_UP: // move up script
move_up_script();
break;
case IDC_DOWN: // move down script
move_down_script();
break;
}
}
new_script函数用来提示用户是否真要创建一个脚本,如果是将清除脚本列表框中的脚本:
//-----------------------------------------------------------------------------------
// New a script.
//-----------------------------------------------------------------------------------
BOOL new_script()
{
const char* msg_info = "Are you sure? (Discards any unsaved script information)";
if(MessageBox(g_hwnd, msg_info, "New Script", MB_YESNO) == IDYES)
{
delete g_root_script;
g_root_script = NULL;
g_num_script = 0;
// clear out listbox
reset_listbox(g_script_wnd);
reset_listbox(g_script_addr_wnd);
return TRUE;
}
return TRUE;
}
load_script用来加载脚本并将其添加到脚本列表框中:
//-----------------------------------------------------------------------------------
// Load script from file.
//-----------------------------------------------------------------------------------
BOOL load_script()
{
// setup the open dialog infomation
g_ofn.hwndOwner = g_hwnd;
g_ofn.lpstrFile = g_script_file;
g_ofn.lpstrTitle = "Load Script File";
g_ofn.lpstrFilter = "MLS Script Files (*.mls)\0*.mls\0All Files (*.*)\0*.*\0\0";
g_ofn.lpstrDefExt = "mls";
// ask for filename
if(! GetOpenFileName(&g_ofn))
return FALSE;
FILE* fp;
// open the file for input
if((fp = fopen(g_script_file, "rb")) == NULL)
{
MessageBox(g_hwnd, g_script_file, "Unable to open file.", MB_OK);
return FALSE;
}
// delete the current script
delete g_root_script;
char text[2048];
SCRIPT_PTR script_ptr = NULL;
// get number of script
fread(&g_num_script, 1, sizeof(long), fp);
// loop through each script
for(long i = 0; i < g_num_script; i++)
{
// allocate a script structure and link in
SCRIPT_PTR script = new SCRIPT;
script->next = NULL;
if(script_ptr == NULL)
g_root_script = script;
else
script_ptr->next = script;
script_ptr = script;
// get index of actions and number of entries
fread(&script->action_index, 1, sizeof(long), fp);
fread(&script->num_entries, 1, sizeof(long), fp);
// get entry data (if any)
if(script->num_entries)
{
// allocate entry array
script->entries = new ENTRY[script->num_entries];
// load in each entry
for(long j = 0; j < script->num_entries; j++)
{
// get entry type and data
fread(&script->entries[j].type, 1, sizeof(long), fp);
fread(&script->entries[j].io_value, 1, sizeof(long), fp);
// get text (if any)
if(script->entries[j].type == ENTRY_TEXT)
{
long length = script->entries[j].length;
if(length)
{
// allocate a buffer and get string
script->entries[j].text = new char[length];
fread(script->entries[j].text, 1, length, fp);
}
}
}
}
}
fclose(fp);
// clear the script and script address boxes
reset_listbox(g_script_wnd);
reset_listbox(g_script_addr_wnd);
// add script to listbox
script_ptr = g_root_script;
while(script_ptr)
{
// add script text to listbox
g_action_template.expand_action_text(text, script_ptr);
add_string_to_listbox(g_script_wnd, text);
// add script pointer to listbox
sprintf(text, "%lu", script_ptr);
add_string_to_listbox(g_script_addr_wnd, text);
script_ptr = script_ptr->next;
}
return TRUE;
}
save_script将脚本存储到文件中:
//-----------------------------------------------------------------------------------
// Save script to file.
//-----------------------------------------------------------------------------------
BOOL save_script()
{
// make sure there is some script actions
if(g_num_script == 0)
{
MessageBox(g_hwnd, "No script actions exist!", "Error", MB_OK);
return FALSE;
}
// setup the open dialog information
g_ofn.hwndOwner = g_hwnd;
g_ofn.lpstrFile = g_script_file;
g_ofn.lpstrTitle = "Save Script File";
g_ofn.lpstrFilter = "MLS Script Files (*.mls)\0*.mls\0All Files (*.*)\0*.*\0\0";
g_ofn.lpstrDefExt = "mls";
// ask for filename
if(! GetSaveFileName(&g_ofn))
return FALSE;
FILE* fp;
// open the file for output
if((fp = fopen(g_script_file, "wb")) == NULL)
{
MessageBox(g_hwnd, g_script_file, "Unable to save file.", MB_OK);
return FALSE;
}
// output number of scripts
fwrite(&g_num_script, 1, sizeof(long), fp);
// loop through each script
for(long i = 0; i < g_num_script; i++)
{
char text[256];
// get a pointer to the script structure (do not depend on list)
get_listbox_text(g_script_addr_wnd, i, text);
SCRIPT_PTR script_ptr = (SCRIPT_PTR) atol(text);
// output index of action and number of entries
fwrite(&script_ptr->action_index, 1, sizeof(long), fp);
fwrite(&script_ptr->num_entries, 1, sizeof(long), fp);
// output entry data (if any)
for(long j = 0; j < script_ptr->num_entries; j++)
{
// write entry type and data
fwrite(&script_ptr->entries[j].type, 1, sizeof(long), fp);
fwrite(&script_ptr->entries[j].io_value, 1, sizeof(long), fp);
// write text (if any)
if(script_ptr->entries[j].type == ENTRY_TEXT && script_ptr->entries[j].text)
fwrite(script_ptr->entries[j].text, 1, script_ptr->entries[j].length, fp);
}
}
fclose(fp);
return TRUE;
}
edit_script用于编辑当前选中的脚本行:
//-----------------------------------------------------------------------------------
// Edit script.
//-----------------------------------------------------------------------------------
void edit_script()
{
int sel;
// see if a script was selected
if((sel = (int)get_listbox_selected(g_script_wnd)) == LB_ERR)
return;
char text[2048];
// get pointer to script entry
get_listbox_text(g_script_addr_wnd, sel, text);
SCRIPT_PTR script = (SCRIPT_PTR) atol(text);
// setup the script to edit
g_modify_script = script;
// call the modify script dialog
g_show_cancel = FALSE;
DialogBox(NULL, MAKEINTRESOURCE(IDD_MODIFY), g_hwnd, modify_dialog_proc);
// update script listbox
g_action_template.expand_action_text(text, script);
delete_listbox_string(g_script_wnd, sel);
insert_string_to_listbox(g_script_wnd, sel, text);
}