You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
487 lines
12 KiB
487 lines
12 KiB
4 years ago
|
/*==LICENSE==*
|
||
|
|
||
|
CyanWorlds.com Engine - MMOG client, server and tools
|
||
|
Copyright (C) 2011 Cyan Worlds, Inc.
|
||
|
|
||
|
This program is free software: you can redistribute it and/or modify
|
||
|
it under the terms of the GNU General Public License as published by
|
||
|
the Free Software Foundation, either version 3 of the License, or
|
||
|
(at your option) any later version.
|
||
|
|
||
|
This program is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
GNU General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License
|
||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
|
||
|
Additional permissions under GNU GPL version 3 section 7
|
||
|
|
||
|
If you modify this Program, or any covered work, by linking or
|
||
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||
|
(or a modified version of those libraries),
|
||
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||
|
licensors of this Program grant you additional
|
||
|
permission to convey the resulting work. Corresponding Source for a
|
||
|
non-source form of such a combination shall include the source code for
|
||
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||
|
work.
|
||
|
|
||
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||
|
or by snail mail at:
|
||
|
Cyan Worlds, Inc.
|
||
|
14617 N Newport Hwy
|
||
|
Mead, WA 99021
|
||
|
|
||
|
*==LICENSE==*/
|
||
|
#include "HeadSpin.h"
|
||
|
#include "plResponderWait.h"
|
||
|
#include "plResponderComponentPriv.h"
|
||
|
#include "resource.h"
|
||
|
#include "../plModifier/plResponderModifier.h"
|
||
|
|
||
|
#include "plResponderLink.h"
|
||
|
|
||
|
class plResponderWaitProc;
|
||
|
extern plResponderWaitProc gResponderWaitProc;
|
||
|
|
||
|
enum
|
||
|
{
|
||
|
kWaitWhoOld,
|
||
|
kWaitPointOld,
|
||
|
kWaitMe,
|
||
|
kWaitWho,
|
||
|
kWaitPoint,
|
||
|
};
|
||
|
|
||
|
ParamBlockDesc2 gResponderWaitBlock
|
||
|
(
|
||
|
kResponderWaitBlk, _T("waitCmd"), 0, NULL, P_AUTO_UI,
|
||
|
|
||
|
IDD_COMP_RESPOND_WAIT, IDS_COMP_WAIT, 0, 0, &gResponderWaitProc,
|
||
|
|
||
|
kWaitWhoOld, _T("whoOld"), TYPE_INT_TAB, 0, 0, 0,
|
||
|
end,
|
||
|
|
||
|
kWaitPointOld, _T("pointOld"), TYPE_STRING_TAB, 0, 0, 0,
|
||
|
end,
|
||
|
|
||
|
kWaitMe, _T("me"), TYPE_BOOL, 0, 0,
|
||
|
p_ui, TYPE_SINGLECHEKBOX, IDC_WAIT_ON_ME_CHECK,
|
||
|
end,
|
||
|
|
||
|
kWaitWho, _T("who"), TYPE_INT, 0, 0,
|
||
|
p_default, -1,
|
||
|
end,
|
||
|
|
||
|
kWaitPoint, _T("point"), TYPE_STRING, 0, 0,
|
||
|
end,
|
||
|
|
||
|
end
|
||
|
);
|
||
|
void ResponderWait::SetDesc(ClassDesc2 *desc) { gResponderWaitBlock.SetClassDesc(desc); }
|
||
|
|
||
|
void ResponderWait::FixupWaitBlock(IParamBlock2 *waitPB)
|
||
|
{
|
||
|
if (waitPB->Count(kWaitWhoOld) > 0)
|
||
|
{
|
||
|
int who = waitPB->GetInt(kWaitWhoOld, 0, 0);
|
||
|
waitPB->SetValue(kWaitWho, 0, who);
|
||
|
waitPB->Delete(kWaitWhoOld, 0, 1);
|
||
|
}
|
||
|
|
||
|
if (waitPB->Count(kWaitPointOld) > 0)
|
||
|
{
|
||
|
TCHAR* point = waitPB->GetStr(kWaitPointOld, 0, 0);
|
||
|
waitPB->SetValue(kWaitPoint, 0, point);
|
||
|
waitPB->Delete(kWaitPointOld, 0, 1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
IParamBlock2 *ResponderWait::CreatePB()
|
||
|
{
|
||
|
return CreateParameterBlock2(&gResponderWaitBlock, nil);
|
||
|
}
|
||
|
|
||
|
bool ResponderWait::GetWaitOnMe(IParamBlock2* waitPB)
|
||
|
{
|
||
|
return (waitPB->GetInt(kWaitMe) != 0);
|
||
|
}
|
||
|
|
||
|
int ResponderWait::GetWaitingOn(IParamBlock2* waitPB)
|
||
|
{
|
||
|
return waitPB->GetInt(kWaitWho);
|
||
|
}
|
||
|
|
||
|
const char* ResponderWait::GetWaitPoint(IParamBlock2* waitPB)
|
||
|
{
|
||
|
const char* point = waitPB->GetStr(kWaitPoint);
|
||
|
if (point && *point == '\0')
|
||
|
return nil;
|
||
|
return point;
|
||
|
}
|
||
|
|
||
|
class plResponderWaitProc : public ParamMap2UserDlgProc
|
||
|
{
|
||
|
protected:
|
||
|
IParamBlock2 *fStatePB;
|
||
|
IParamBlock2 *fWaitPB;
|
||
|
|
||
|
int fCurCmd;
|
||
|
HWND fhDlg;
|
||
|
HWND fhList;
|
||
|
|
||
|
public:
|
||
|
void Init(IParamBlock2 *curStatePB, int curCmd, HWND hList) { fStatePB = curStatePB; fCurCmd = curCmd; fhList = hList; }
|
||
|
|
||
|
BOOL DlgProc(TimeValue t, IParamMap2 *pm, HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
|
||
|
|
||
|
void DeleteThis() {}
|
||
|
|
||
|
protected:
|
||
|
void LoadWho(bool setDefault=false);
|
||
|
void LoadPoint(bool force=false);
|
||
|
|
||
|
IParamBlock2 *GetCmdParams(int cmdIdx);
|
||
|
};
|
||
|
static plResponderWaitProc gResponderWaitProc;
|
||
|
|
||
|
void ResponderWait::InitDlg(IParamBlock2 *curStatePB, int curCmd, HWND hList)
|
||
|
{
|
||
|
gResponderWaitProc.Init(curStatePB, curCmd, hList);
|
||
|
}
|
||
|
|
||
|
IParamBlock2 *plResponderWaitProc::GetCmdParams(int cmdIdx)
|
||
|
{
|
||
|
return (IParamBlock2*)fStatePB->GetReferenceTarget(kStateCmdParams, 0, cmdIdx);
|
||
|
}
|
||
|
|
||
|
BOOL plResponderWaitProc::DlgProc(TimeValue t, IParamMap2 *pm, HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
switch (msg)
|
||
|
{
|
||
|
case WM_INITDIALOG:
|
||
|
{
|
||
|
fhDlg = hDlg;
|
||
|
|
||
|
fWaitPB = pm->GetParamBlock();
|
||
|
|
||
|
ResponderWait::FixupWaitBlock(fWaitPB);
|
||
|
|
||
|
IParamBlock2 *pb = GetCmdParams(fCurCmd);
|
||
|
plResponderCmd *cmd = plResponderCmd::Find(pb);
|
||
|
pm->Enable(kWaitMe, cmd->IsWaitable(pb));
|
||
|
|
||
|
LoadWho();
|
||
|
LoadPoint();
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
case WM_CUSTEDIT_ENTER:
|
||
|
if (wParam == IDC_MARKER_EDIT)
|
||
|
{
|
||
|
ICustEdit *edit = GetICustEdit((HWND)lParam);
|
||
|
char buf[256];
|
||
|
edit->GetText(buf, sizeof(buf));
|
||
|
fWaitPB->SetValue(kWaitPoint, 0, buf);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WM_COMMAND:
|
||
|
{
|
||
|
int code = HIWORD(wParam);
|
||
|
int id = LOWORD(wParam);
|
||
|
|
||
|
if (id == IDC_CHECK_WAIT && code == BN_CLICKED)
|
||
|
{
|
||
|
BOOL checked = (IsDlgButtonChecked(hDlg, IDC_CHECK_WAIT) == BST_CHECKED);
|
||
|
if (!checked)
|
||
|
{
|
||
|
fWaitPB->SetValue(kWaitWho, 0, -1);
|
||
|
fWaitPB->SetValue(kWaitPoint, 0, "");
|
||
|
|
||
|
LoadPoint();
|
||
|
|
||
|
HWND hWho = GetDlgItem(hDlg, IDC_WAIT_WHO);
|
||
|
EnableWindow(hWho, FALSE);
|
||
|
ComboBox_ResetContent(hWho);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LoadWho(true);
|
||
|
LoadPoint();
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
else if (id == IDC_WAIT_WHO && code == CBN_SELCHANGE)
|
||
|
{
|
||
|
HWND hWho = (HWND)lParam;
|
||
|
int who = ComboBox_GetCurSel(hWho);
|
||
|
int idx = ComboBox_GetItemData(hWho, who);
|
||
|
fWaitPB->SetValue(kWaitWho, 0, idx);
|
||
|
|
||
|
LoadPoint();
|
||
|
return TRUE;
|
||
|
}
|
||
|
else if (id == IDC_RADIO_FINISH && code == BN_CLICKED)
|
||
|
{
|
||
|
fWaitPB->SetValue(kWaitPoint, 0, "");
|
||
|
LoadPoint();
|
||
|
return TRUE;
|
||
|
}
|
||
|
else if (id == IDC_RADIO_POINT && code == BN_CLICKED)
|
||
|
{
|
||
|
LoadPoint(true);
|
||
|
return TRUE;
|
||
|
}
|
||
|
else if (id == IDC_WAIT_POINT && code == CBN_SELCHANGE)
|
||
|
{
|
||
|
HWND hPoint = (HWND)lParam;
|
||
|
if (ComboBox_GetCurSel(hPoint) != CB_ERR)
|
||
|
{
|
||
|
char buf[256];
|
||
|
ComboBox_GetText(hPoint, buf, sizeof(buf));
|
||
|
fWaitPB->SetValue(kWaitPoint, 0, buf);
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
void plResponderWaitProc::LoadWho(bool setDefault)
|
||
|
{
|
||
|
HWND hWho = GetDlgItem(fhDlg, IDC_WAIT_WHO);
|
||
|
int who = fWaitPB->GetInt(kWaitWho);
|
||
|
|
||
|
ComboBox_ResetContent(hWho);
|
||
|
|
||
|
int numFound = 0;
|
||
|
|
||
|
// Copy all the commands before this one to the 'who' combo box
|
||
|
for (int i = 0; i < fCurCmd; i++)
|
||
|
{
|
||
|
IParamBlock2 *pb = GetCmdParams(i);
|
||
|
plResponderCmd *cmd = plResponderCmd::Find(pb);
|
||
|
|
||
|
if (cmd->IsWaitable(pb))
|
||
|
{
|
||
|
int idx = ComboBox_AddString(hWho, cmd->GetInstanceName(pb));
|
||
|
ComboBox_SetItemData(hWho, idx, i);
|
||
|
|
||
|
// If the saved 'who' is valid, select it and check the wait checkbox
|
||
|
if (who == i)
|
||
|
{
|
||
|
ComboBox_SetCurSel(hWho, idx);
|
||
|
CheckDlgButton(fhDlg, IDC_CHECK_WAIT, BST_CHECKED);
|
||
|
EnableWindow(hWho, TRUE);
|
||
|
}
|
||
|
|
||
|
numFound++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Pick the last item in the who combo as the default
|
||
|
if (setDefault && numFound > 0)
|
||
|
{
|
||
|
HWND hWho = GetDlgItem(fhDlg, IDC_WAIT_WHO);
|
||
|
int idx = ComboBox_GetItemData(hWho, numFound-1);
|
||
|
fWaitPB->SetValue(kWaitWho, 0, idx);
|
||
|
|
||
|
ComboBox_SetCurSel(hWho, numFound-1);
|
||
|
CheckDlgButton(fhDlg, IDC_CHECK_WAIT, BST_CHECKED);
|
||
|
EnableWindow(hWho, TRUE);
|
||
|
}
|
||
|
|
||
|
// Disable the wait checkbox if there are no waitable commands behind this one
|
||
|
EnableWindow(GetDlgItem(fhDlg, IDC_CHECK_WAIT), (numFound > 0));
|
||
|
}
|
||
|
|
||
|
void plResponderWaitProc::LoadPoint(bool force)
|
||
|
{
|
||
|
int who = fWaitPB->GetInt(kWaitWho);
|
||
|
const char *point = fWaitPB->GetStr(kWaitPoint);
|
||
|
if (point && *point == '\0')
|
||
|
point = nil;
|
||
|
|
||
|
CheckRadioButton(fhDlg, IDC_RADIO_FINISH, IDC_RADIO_POINT, point || force ? IDC_RADIO_POINT : IDC_RADIO_FINISH);
|
||
|
|
||
|
BOOL enableAll = (who != -1);
|
||
|
EnableWindow(GetDlgItem(fhDlg, IDC_RADIO_FINISH), enableAll);
|
||
|
EnableWindow(GetDlgItem(fhDlg, IDC_RADIO_POINT), enableAll);
|
||
|
|
||
|
BOOL enablePoint = ((point != nil) || force) && enableAll;
|
||
|
EnableWindow(GetDlgItem(fhDlg, IDC_WAIT_POINT), enablePoint);
|
||
|
ComboBox_ResetContent(GetDlgItem(fhDlg, IDC_WAIT_POINT));
|
||
|
|
||
|
if (enableAll)
|
||
|
{
|
||
|
IParamBlock2 *pb = (IParamBlock2*)fStatePB->GetReferenceTarget(kStateCmdParams, 0, who);
|
||
|
plResponderCmd *cmd = plResponderCmd::Find(pb);
|
||
|
|
||
|
// KLUDGE - stupid one-shot needs editable box
|
||
|
if (cmd == &(plResponderCmdOneShot::Instance()))
|
||
|
{
|
||
|
ShowWindow(GetDlgItem(fhDlg, IDC_WAIT_POINT), SW_HIDE);
|
||
|
|
||
|
HWND hEdit = GetDlgItem(fhDlg, IDC_MARKER_EDIT);
|
||
|
ShowWindow(hEdit, SW_SHOW);
|
||
|
ICustEdit *custEdit = GetICustEdit(hEdit);
|
||
|
custEdit->SetText(point ? (char*)point : "");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ShowWindow(GetDlgItem(fhDlg, IDC_WAIT_POINT), SW_SHOW);
|
||
|
|
||
|
HWND hEdit = GetDlgItem(fhDlg, IDC_MARKER_EDIT);
|
||
|
ShowWindow(hEdit, SW_HIDE);
|
||
|
|
||
|
plResponderCmd::WaitPoints waitPoints;
|
||
|
cmd->GetWaitPoints(pb, waitPoints);
|
||
|
|
||
|
HWND hCombo = GetDlgItem(fhDlg, IDC_WAIT_POINT);
|
||
|
ComboBox_ResetContent(hCombo);
|
||
|
|
||
|
if (waitPoints.size() == 0)
|
||
|
{
|
||
|
EnableWindow(GetDlgItem(fhDlg, IDC_RADIO_POINT), FALSE);
|
||
|
EnableWindow(GetDlgItem(fhDlg, IDC_WAIT_POINT), FALSE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for (int i = 0; i < waitPoints.size(); i++)
|
||
|
{
|
||
|
const char *marker = waitPoints[i].c_str();
|
||
|
int idx = ComboBox_AddString(hCombo, marker);
|
||
|
if (point && !strcmp(point, marker))
|
||
|
ComboBox_SetCurSel(hCombo, idx);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static IParamBlock2 *GetWaitBlk(IParamBlock2 *state, int idx)
|
||
|
{
|
||
|
return (IParamBlock2*)state->GetReferenceTarget(kStateCmdWait, 0, idx);
|
||
|
}
|
||
|
|
||
|
void ResponderWait::CmdRemoved(IParamBlock2 *state, int delIdx)
|
||
|
{
|
||
|
int numCmds = state->Count(kStateCmdParams);
|
||
|
for (int i = delIdx; i < numCmds; i++)
|
||
|
{
|
||
|
IParamBlock2 *pb = GetWaitBlk(state, i);
|
||
|
|
||
|
int who = pb->GetInt(kWaitWho);
|
||
|
|
||
|
if (who == delIdx)
|
||
|
pb->SetValue(kWaitWho, 0, -1);
|
||
|
if (who > delIdx)
|
||
|
pb->SetValue(kWaitWho, 0, who-1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// A command was moved from oldIdx to newIdx. Fix all the wait commands.
|
||
|
void ResponderWait::CmdMoved(IParamBlock2 *state, int oldIdx, int newIdx)
|
||
|
{
|
||
|
int numCmds = state->Count(kStateCmdParams);
|
||
|
|
||
|
// Moved forward
|
||
|
if (oldIdx < newIdx)
|
||
|
{
|
||
|
// Patch up the commands that were ahead of this one
|
||
|
for (int i = oldIdx; i < numCmds; i++)
|
||
|
{
|
||
|
if (i == newIdx)
|
||
|
continue;
|
||
|
|
||
|
IParamBlock2 *pb = GetWaitBlk(state, i);
|
||
|
|
||
|
int who = pb->GetInt(kWaitWho);
|
||
|
|
||
|
// If the command was waiting on the moved one, and is now behind it, invalidate it
|
||
|
if (who == oldIdx && i < newIdx)
|
||
|
pb->SetValue(kWaitWho, 0, -1);
|
||
|
//
|
||
|
else if (who == oldIdx)
|
||
|
pb->SetValue(kWaitWho, 0, newIdx);
|
||
|
// If it was waiting on one ahead of it, correct the index
|
||
|
else if (who > oldIdx && who <= newIdx)
|
||
|
pb->SetValue(kWaitWho, 0, who-1);
|
||
|
}
|
||
|
}
|
||
|
// Moved backward
|
||
|
else
|
||
|
{
|
||
|
// If this command was waiting on any of the commands now ahead of it, invalidate it
|
||
|
IParamBlock2 *movedPB = GetWaitBlk(state, newIdx);
|
||
|
int who = movedPB->GetInt(kWaitWho);
|
||
|
if (who >= newIdx)
|
||
|
movedPB->SetValue(kWaitWho, 0, -1);
|
||
|
|
||
|
for (int i = newIdx+1; i < numCmds; i++)
|
||
|
{
|
||
|
// Is this command waiting on any of the commands it is moving in back of?
|
||
|
IParamBlock2 *pb = GetWaitBlk(state, i);
|
||
|
int who = pb->GetInt(kWaitWho);
|
||
|
if (who == oldIdx)
|
||
|
pb->SetValue(kWaitWho, 0, newIdx);
|
||
|
if (who >= newIdx && who < oldIdx)
|
||
|
pb->SetValue(kWaitWho, 0, who+1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Determine if any of the wait commands will be invalidated by this move
|
||
|
bool ResponderWait::ValidateCmdMove(IParamBlock2 *state, int oldIdx, int newIdx)
|
||
|
{
|
||
|
// Moving forward
|
||
|
if (oldIdx < newIdx)
|
||
|
{
|
||
|
// Are any of the commands ahead of this one waiting on it?
|
||
|
for (int i = oldIdx+1; i <= newIdx; i++)
|
||
|
{
|
||
|
IParamBlock2 *pb = GetWaitBlk(state, i);
|
||
|
|
||
|
if (pb->GetInt(kWaitWho) == oldIdx)
|
||
|
{
|
||
|
int ret = hsMessageBox("You are moving this command ahead of another command that waits on it.\nAre you sure you want to do that?", "Warning", hsMessageBoxYesNo);
|
||
|
if (ret == hsMBoxYes)
|
||
|
return true;
|
||
|
else
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// Moving backward
|
||
|
else
|
||
|
{
|
||
|
// Is this command waiting on any of the commands it is moving in back of?
|
||
|
IParamBlock2 *pb = GetWaitBlk(state, oldIdx);
|
||
|
|
||
|
int who = pb->GetInt(kWaitWho);
|
||
|
if (who >= newIdx && who < oldIdx)
|
||
|
{
|
||
|
int ret = hsMessageBox("You are moving this command behind another command that it is waiting on.\nAre you sure you want to do that?", "Warning", hsMessageBoxYesNo);
|
||
|
if (ret == hsMBoxYes)
|
||
|
return true;
|
||
|
else
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|