本篇是游戏脚本的实现(4)的续篇。
add_script将行为列表框中选中的行为添加到脚本列表框中:
//-----------------------------------------------------------------------------------
// Add script.
//-----------------------------------------------------------------------------------
void add_script()
{
long sel;
// make sure an action is selected
if((sel = (long)get_listbox_selected(g_action_wnd)) == LB_ERR)
return;
// create a new script and add it
SCRIPT_PTR script = g_action_template.create_script(sel);
g_modify_script = script;
// call the modify script dialog
g_show_cancel = TRUE;
if(DialogBox(NULL, MAKEINTRESOURCE(IDD_MODIFY), g_hwnd, modify_dialog_proc))
{
// add script to link list
script->next = g_root_script;
if(g_root_script != NULL)
g_root_script->prev = script;
g_root_script = script;
// display script text
char text[2048];
ACTION_PTR act_ptr = g_action_template.get_action(sel);
g_action_template.expand_action_text(text, script);
add_string_to_listbox(g_script_wnd, text);
// add pointer to script address listbox
sprintf(text, "%lu", script);
add_string_to_listbox(g_script_addr_wnd, text);
// increase count
g_num_script++;
}
else
delete script;
}
insert_script将行为列表框中选中的行为脚本添加到脚本列表框中选中脚本的上方:
//-----------------------------------------------------------------------------------
// Insert script.
//-----------------------------------------------------------------------------------
void insert_script()
{
int act_index, script_index;
// get location to insert action
if((script_index = (int)get_listbox_selected(g_script_wnd)) == LB_ERR)
return;
// make sure an action is selected
if((act_index = (int)get_listbox_selected(g_action_wnd)) == LB_ERR)
return;
// create a new script
SCRIPT_PTR script = g_action_template.create_script(act_index);
g_modify_script = script;
// call the modify script dialog
g_show_cancel = TRUE;
if(DialogBox(NULL, MAKEINTRESOURCE(IDD_MODIFY), g_hwnd, modify_dialog_proc))
{
// add the script to link list
script->prev = NULL;
script->next = g_root_script;
g_root_script->prev = script;
g_root_script = script;
char text[2048];
// display script action text
ACTION_PTR act_ptr = g_action_template.get_action(act_index);
g_action_template.expand_action_text(text, script);
insert_string_to_listbox(g_script_wnd, script_index, text);
// add pointer to script address listbox
sprintf(text, "%lu", script);
insert_string_to_listbox(g_script_addr_wnd, script_index, text);
g_num_script++;
}
else
delete script;
}
delete_script用于删除脚本列表框中的一条脚本:
//-----------------------------------------------------------------------------------
// Delete script.
//-----------------------------------------------------------------------------------
void delete_script()
{
int sel;
// make sure there is a selection
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);
// remove script from linked list
if(script->prev)
script->prev->next = script->next;
else
g_root_script = script->next;
if(script->next)
script->next->prev = script->prev;
script->next = NULL; // so whole list is not deleted
delete script;
// clear from script and script list
delete_listbox_string(g_script_wnd, sel);
delete_listbox_string(g_script_addr_wnd, sel);
g_num_script--;
}
move_up_script和move_down_script分别将脚本上移和下移一行:
//-----------------------------------------------------------------------------------
// Move up script.
//-----------------------------------------------------------------------------------
void move_up_script()
{
int sel;
// make sure there is a selection
if((sel = (int)get_listbox_selected(g_script_wnd)) == LB_ERR)
return;
// make sure it is not topmost selection
if(sel == 0)
return;
char text[2048];
get_listbox_text(g_script_wnd, sel, text);
delete_listbox_string(g_script_wnd, sel);
insert_string_to_listbox(g_script_wnd, sel-1, text);
get_listbox_text(g_script_addr_wnd, sel, text);
delete_listbox_string(g_script_addr_wnd, sel);
insert_string_to_listbox(g_script_addr_wnd, sel-1, text);
set_listbox_selected(g_script_wnd, sel-1);
}
//-----------------------------------------------------------------------------------
// Move down script.
//-----------------------------------------------------------------------------------
void move_down_script()
{
int sel;
// make sure there is a selection
if((sel = (int)get_listbox_selected(g_script_wnd)) == LB_ERR)
return;
// make sure it is not bottommost selection
if(sel >= count_listbox(g_script_wnd)-1)
return;
char text[2048];
get_listbox_text(g_script_wnd, sel, text);
delete_listbox_string(g_script_wnd, sel);
insert_string_to_listbox(g_script_wnd, sel+1, text);
get_listbox_text(g_script_addr_wnd, sel, text);
delete_listbox_string(g_script_addr_wnd, sel);
insert_string_to_listbox(g_script_addr_wnd, sel+1, text);
set_listbox_selected(g_script_wnd, sel+1);
}
修改脚本对话框的窗口处理过程通过modify_dialog_proc来实现:
//-----------------------------------------------------------------------------------
// The DialogProc function is an application-defined callback function used with the CreateDialog
// and DialogBox families of functions. It processes messages sent to a modal or modeless dialog box.
// The DLGPROC type defines a pointer to this callback function. DialogProc is a placeholder for
// the application-defined function name.
//
// INT_PTR CALLBACK DialogProc(HWND hwndDlg,
// UINT uMsg,
// WPARAM wParam,
// LPARAM lParam
// );
//
// hwndDlg:
// [in] Handle to the dialog box.
// uMsg:
// [in] Specifies the message.
// wParam:
// [in] Specifies additional message-specific information.
// lParam:
// [in] Specifies additional message-specific information.
//
// Return Value:
// Typically, the dialog box procedure should return TRUE if it processed the message,
// and FALSE if it did not. If the dialog box procedure returns FALSE, the dialog manager performs
// the default dialog operation in response to the message.
//
// If the dialog box procedure processes a message that requires a specific return value,
// the dialog box procedure should set the desired return value by calling
// SetWindowLong(hwndDlg, DWL_MSGRESULT, lResult) immediately before returning TRUE.
// Note that you must call SetWindowLong immediately before returning TRUE; doing so earlier may
// result in the DWL_MSGRESULT value being overwritten by a nested dialog box message.
//
// The following messages are exceptions to the general rules stated above. Consult the documentation
// for the specific message for details on the semantics of the return value.
//
// WM_CHARTOITEM
// WM_COMPAREITEM
// WM_CTLCOLORBTN
// WM_CTLCOLORDLG
// WM_CTLCOLOREDIT
// WM_CTLCOLORLISTBOX
// WM_CTLCOLORSCROLLBAR
// WM_CTLCOLORSTATIC
// WM_INITDIALOG
// WM_QUERYDRAGICON
// WM_VKEYTOITEM
//
// Remarks:
// You should use the dialog box procedure only if you use the dialog box class for the dialog box.
// This is the default class and is used when no explicit class is specified in the dialog box template.
// Although the dialog box procedure is similar to a window procedure, it must not call the DefWindowProc
// function to process unwanted messages. Unwanted messages are processed internally by the dialog box
// window procedure.
//-----------------------------------------------------------------------------------
BOOL CALLBACK modify_dialog_proc(HWND dlg, UINT msg_id, WPARAM word_param, LPARAM long_param)
{
static long entry_index = 0;
switch(msg_id)
{
case WM_INITDIALOG:
if(g_modify_script == NULL) // return an error if there is no script to modify
{
// The EndDialog function destroys a modal dialog box, causing the system to end any processing
// for the dialog box.
//
// BOOL EndDialog(HWND hDlg,
// INT_PTR nResult
// );
//
// hDlg:
// [in] Handle to the dialog box to be destroyed.
//
// nResult:
// [in] Specifies the value to be returned to the application from the function that created
// the dialog box.
//
// Return Value:
// If the function succeeds, the return value is nonzero.
//
// If the function fails, the return value is zero. To get extended error information,
// call GetLastError.
EndDialog(dlg, FALSE);
return FALSE;
}
// edit first entry
entry_index = 0;
// display entry text
set_modify_dialog(dlg, g_modify_script, entry_index);
// show or hide cancel button
ShowWindow(GetDlgItem(dlg, IDC_CANCEL), g_show_cancel);
if(g_show_cancel == FALSE)
{
ShowWindow(GetDlgItem(dlg, IDC_OK), false);
ShowWindow(GetDlgItem(dlg, IDC_OK2), true);
}
else
ShowWindow(GetDlgItem(dlg, IDC_OK2), false);
return TRUE;
case WM_COMMAND:
switch(LOWORD(word_param))
{
case IDC_OK:
case IDC_OK2:
update_entry(dlg, g_modify_script, entry_index);
EndDialog(dlg, TRUE);
return TRUE;
case IDC_CANCEL:
EndDialog(dlg, FALSE);
return TRUE;
case IDC_PREV:
// only bother if not first entry
if(entry_index > 0)
{
// apply changes
// go to previous entry
update_entry(dlg, g_modify_script, entry_index);
entry_index--;
set_modify_dialog(dlg, g_modify_script, entry_index);
}
break;
case IDC_NEXT:
// only bother if not last entry
if(entry_index < g_modify_script->num_entries-1)
{
// apply changes
// go to next entry
update_entry(dlg, g_modify_script, entry_index);
entry_index++;
set_modify_dialog(dlg, g_modify_script, entry_index);
}
break;
}
}
return FALSE;
}
不同的条目类型修改脚本的对话框外观也不相同,这是通过set_modify_dialog函数来实现:
//-----------------------------------------------------------------------------------
// Set information for dialog to be modified.
//-----------------------------------------------------------------------------------
void set_modify_dialog(HWND dlg, SCRIPT_PTR script, long entry_index)
{
char text[2048];
// display full action text
g_action_template.expand_action_text(text, script);
SetWindowText(GetDlgItem(dlg, IDC_ACTIONTEXT), text);
// get control handle
HWND pre_wnd = GetDlgItem(dlg, IDC_PREV);
HWND next_wnd = GetDlgItem(dlg, IDC_NEXT);
HWND text_wnd = GetDlgItem(dlg, IDC_TEXT);
HWND choice_wnd = GetDlgItem(dlg, IDC_CHOICE);
HWND true_wnd = GetDlgItem(dlg, IDC_TRUE);
HWND false_wnd = GetDlgItem(dlg, IDC_FALSE);
HWND min_wnd = GetDlgItem(dlg, IDC_MIN);
HWND max_wnd = GetDlgItem(dlg, IDC_MAX);
HWND value_wnd = GetDlgItem(dlg, IDC_VALUE);
HWND static_min_wnd = GetDlgItem(dlg, IDC_STATIC_MIN);
HWND static_max_wnd = GetDlgItem(dlg, IDC_STATIC_MAX);
HWND static_value_wnd = GetDlgItem(dlg, IDC_STATIC_VALUE);
HWND num_wnd = GetDlgItem(dlg, IDC_NUM);
HWND frame_wnd = GetDlgItem(dlg, IDC_FRAME);
// hide all controls
ShowWindow(pre_wnd, FALSE);
ShowWindow(next_wnd, FALSE);
ShowWindow(text_wnd, FALSE);
ShowWindow(choice_wnd, FALSE);
ShowWindow(true_wnd, FALSE);
ShowWindow(false_wnd, FALSE);
ShowWindow(min_wnd, FALSE);
ShowWindow(max_wnd, FALSE);
ShowWindow(value_wnd, FALSE);
ShowWindow(static_min_wnd, FALSE);
ShowWindow(static_max_wnd, FALSE);
ShowWindow(static_value_wnd, FALSE);
// clear information
SetWindowText(num_wnd, "");
SetWindowText(frame_wnd, " No Entries ");
// get pointer to action
ACTION_PTR act_ptr = g_action_template.get_action(script->action_index);
// return if no entries to edit
if(act_ptr->num_entries_rule == 0)
return;
if(act_ptr->num_entries_rule > 1)
{
ShowWindow(pre_wnd, TRUE);
ShowWindow(next_wnd, TRUE);
}
sprintf(text, "%lu of %lu", entry_index+1, act_ptr->num_entries_rule);
SetWindowText(num_wnd, text);
EnableWindow(num_wnd, TRUE);
// enable and set specific fields based on entry type
switch(script->entries[entry_index].type)
{
case ENTRY_TEXT:
SetWindowText(frame_wnd, " Text entry ");
if(script->entries[entry_index].text)
SetWindowText(text_wnd, script->entries[entry_index].text);
ShowWindow(text_wnd, TRUE);
EnableWindow(text_wnd, TRUE);
break;
case ENTRY_BOOL:
SetWindowText(frame_wnd, " Boolean entry ");
if(script->entries[entry_index].bool_value)
{
set_button_state(true_wnd, BST_CHECKED);
set_button_state(false_wnd, BST_UNCHECKED);
}
else
{
set_button_state(true_wnd, BST_UNCHECKED);
set_button_state(false_wnd, BST_CHECKED);
}
ShowWindow(true_wnd, TRUE);
ShowWindow(false_wnd, TRUE);
break;
case ENTRY_INT:
SetWindowText(frame_wnd, " Integer entry ");
sprintf(text, "%lu", act_ptr->entries_rule[entry_index].long_min);
SetWindowText(min_wnd, text);
sprintf(text, "%lu", act_ptr->entries_rule[entry_index].long_max);
SetWindowText(max_wnd, text);
sprintf(text, "%lu", script->entries[entry_index].long_value);
SetWindowText(value_wnd, text);
ShowWindow(min_wnd, TRUE);
ShowWindow(max_wnd, TRUE);
ShowWindow(value_wnd, TRUE);
ShowWindow(static_min_wnd, TRUE);
ShowWindow(static_max_wnd, TRUE);
ShowWindow(static_value_wnd, TRUE);
break;
case ENTRY_FLOAT:
SetWindowText(frame_wnd, " Float entry ");
sprintf(text, "%lu", act_ptr->entries_rule[entry_index].float_min);
SetWindowText(min_wnd, text);
sprintf(text, "%lu", act_ptr->entries_rule[entry_index].float_max);
SetWindowText(max_wnd, text);
sprintf(text, "%lu", script->entries[entry_index].float_value);
SetWindowText(value_wnd, text);
ShowWindow(min_wnd, TRUE);
ShowWindow(max_wnd, TRUE);
ShowWindow(value_wnd, TRUE);
ShowWindow(static_min_wnd, TRUE);
ShowWindow(static_max_wnd, TRUE);
ShowWindow(static_value_wnd, TRUE);
break;
case ENTRY_CHOICE:
SetWindowText(frame_wnd, " Choice entry ");
reset_combo_content(choice_wnd);
if(act_ptr->entries_rule[entry_index].num_choices)
{
for(long i = 0; i < act_ptr->entries_rule[entry_index].num_choices; i++)
add_string_to_combo(choice_wnd, act_ptr->entries_rule[entry_index].choices[i]);
set_combo_cur_sel(choice_wnd, script->entries[entry_index].selection);
ShowWindow(choice_wnd, TRUE);
}
break;
}
}
布尔型:
整型或浮点型:
多重选项型:
文本型:
脚本信息的更新通过update_entry来实现:
//-----------------------------------------------------------------------------------
// Update script entries.
//-----------------------------------------------------------------------------------
void update_entry(HWND dlg, SCRIPT_PTR script, long entry_index)
{
// get pointer to action
ACTION_PTR act_ptr = g_action_template.get_action(script->action_index);
// return if no entries to update or incorrect entry index
if(act_ptr->num_entries_rule == 0 || entry_index >= script->num_entries)
return;
const int size = 2048;
char text[size];
ENTRY& r_entry = script->entries[entry_index];
ENTRY_RULE& r_entry_rule = act_ptr->entries_rule[entry_index];
// update fields based on type
switch(r_entry_rule.type)
{
case ENTRY_TEXT:
// delete old text
delete[] r_entry.text;
r_entry.text = NULL;
r_entry.length = 0;
GetWindowText(GetDlgItem(dlg, IDC_TEXT), text, size);
if(text)
{
r_entry.length = (long)strlen(text) + 1;
r_entry.text = new char[r_entry.length];
strcpy(r_entry.text, text);
}
break;
case ENTRY_BOOL:
// choose TRUE or FALSE from radio button
if(get_button_state(GetDlgItem(dlg, IDC_TRUE)) == BST_CHECKED)
r_entry.bool_value = TRUE;
else
r_entry.bool_value = FALSE;
break;
case ENTRY_INT:
// get int value and bounds check with min/max
GetWindowText(GetDlgItem(dlg, IDC_VALUE), text, size);
r_entry.long_value = atol(text);
if(r_entry.long_value < r_entry_rule.long_min)
r_entry.long_value = r_entry_rule.long_min;
if(r_entry.long_value > r_entry_rule.long_max)
r_entry.long_value = r_entry_rule.long_max;
break;
case ENTRY_FLOAT:
// get int value and bounds check with min/max
GetWindowText(GetDlgItem(dlg, IDC_VALUE), text, size);
r_entry.float_value = (float)atof(text);
if(r_entry.float_value < r_entry_rule.float_min)
r_entry.float_value = r_entry_rule.float_min;
if(r_entry.float_value > r_entry_rule.float_max)
r_entry.float_value = r_entry_rule.float_max;
break;
case ENTRY_CHOICE:
// store choice selection
r_entry.selection = (long)get_combo_cur_sel(GetDlgItem(dlg, IDC_CHOICE));
break;
}
}
截图:
下载源码与工程