📄 asedoc.cpp
字号:
/* Copyright (C) William van der Sterren, 2002.
* All rights reserved worldwide.
*
* This software is provided "as is" without express or implied
* warranties. You may freely copy and compile this source into
* applications you distribute provided that the copyright text
* below is included in the resulting source code, for example:
* "Portions Copyright (C) William van der Sterren, 2002"
*/
/* Copyright (C) James Matthews, 2001.
* All rights reserved worldwide.
*
* This software is provided "as is" without express or implied
* warranties. You may freely copy and compile this source into
* applications you distribute provided that the copyright text
* below is included in the resulting source code, for example:
* "Portions Copyright (C) James Matthews, 2001"
*/
// aseDoc.cpp : implementation of the CAseDoc class
//
#include "stdafx.h"
#include "ase.h"
#include "nodeview.h"
#include "aseDoc.h"
#include "aseView.h"
#include "mainfrm.h"
#include <cmath>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CAseDoc
IMPLEMENT_DYNCREATE(CAseDoc, CDocument)
BEGIN_MESSAGE_MAP(CAseDoc, CDocument)
//{{AFX_MSG_MAP(CAseDoc)
ON_COMMAND(ID_RUNTOBREAKPOINT, OnRunToBreakpoint)
ON_UPDATE_COMMAND_UI(ID_RUNTOBREAKPOINT, OnUpdateRunToBreakpoint)
ON_COMMAND(ID_EXECUTEASTAR, OnExecuteAStar)
ON_COMMAND(ID_STEPASTAR, OnStepAStar)
ON_COMMAND(ID_VIEW_AROUTE, OnViewARoute)
ON_UPDATE_COMMAND_UI(ID_VIEW_AROUTE, OnUpdateViewARoute)
ON_COMMAND(ID_PATHING_CONTINUOUSUPDATE, OnPathingContinuousUpdate)
ON_UPDATE_COMMAND_UI(ID_PATHING_CONTINUOUSUPDATE, OnUpdatePathingContinuousUpdate)
ON_COMMAND(ID_VIEW_SEARCHSPACE, OnViewSearchspace)
ON_UPDATE_COMMAND_UI(ID_VIEW_SEARCHSPACE, OnUpdateViewSearchspace)
//}}AFX_MSG_MAP
ON_COMMAND_RANGE(ID_WEIGHT0, ID_ENEMYPOSITION, OnBrushType)
ON_UPDATE_COMMAND_UI_RANGE(ID_WEIGHT0, ID_ENEMYPOSITION, OnUpdateUIBrushType)
ON_COMMAND_RANGE(ID_PATHING_BREAKPOINTS_POINT, ID_PATHING_BREAKPOINTS_NEWCHILD, OnBreakpointType)
ON_UPDATE_COMMAND_UI_RANGE(ID_PATHING_BREAKPOINTS_POINT, ID_PATHING_BREAKPOINTS_NEWCHILD, OnUpdateUIBreakpointType)
ON_COMMAND(ID_VIEW_LOF, OnViewLineOfFire)
ON_UPDATE_COMMAND_UI(ID_VIEW_LOF, OnUpdateUIViewLineOfFire)
ON_COMMAND(ID_VIEW_THREATS, OnViewThreats)
ON_UPDATE_COMMAND_UI(ID_VIEW_THREATS, OnUpdateUIViewThreats)
ON_COMMAND(ID_THREATCOSTS_DISTANCETOTHREAT, OnThreatDistanceBasedCosts)
ON_UPDATE_COMMAND_UI(ID_THREATCOSTS_DISTANCETOTHREAT, OnUpdateUIThreatDistanceBasedCosts)
ON_COMMAND(ID_VIEW_APPROX_LOF, OnViewApproximatedLinesOfFire)
ON_UPDATE_COMMAND_UI(ID_VIEW_APPROX_LOF, OnUpdateUIViewApproximatedLinesOfFire)
ON_COMMAND(ID_THREATCOSTS_THREATCOUNT, OnThreatCountBasedCosts)
ON_UPDATE_COMMAND_UI(ID_THREATCOSTS_THREATCOUNT, OnUpdateUIThreatCountBasedCosts)
ON_COMMAND(ID_THREATCOSTS_APPROXLUT, OnThreatFromApproxTableCosts)
ON_UPDATE_COMMAND_UI(ID_THREATCOSTS_APPROXLUT, OnUpdateUIThreatFromApproxTableCosts)
ON_COMMAND_RANGE(ID_MOVEMENT_MANHATTAN, ID_MOVEMENT_DIAGONAL, OnMovementType)
ON_UPDATE_COMMAND_UI_RANGE(ID_MOVEMENT_MANHATTAN, ID_MOVEMENT_DIAGONAL, OnUpdateUIMovementType)
ON_COMMAND_RANGE(ID_MOVEMENTCOSTS_CELL, ID_MOVEMENTCOSTS_RELATIVE, OnMovementCosts)
ON_UPDATE_COMMAND_UI_RANGE(ID_MOVEMENTCOSTS_CELL, ID_MOVEMENTCOSTS_RELATIVE, OnUpdateUIMovementCosts)
ON_COMMAND_RANGE(ID_THREATCOSTS_NONE, ID_THREATCOSTS_LOFWITHMEMORY, OnThreatCosts)
ON_UPDATE_COMMAND_UI_RANGE(ID_THREATCOSTS_NONE, ID_THREATCOSTS_LOFWITHMEMORY, OnUpdateUIThreatCosts)
ON_COMMAND_RANGE(ID_THREATMOVEMENT_0, ID_THREATMOVEMENT_2, OnThreatMovement)
ON_UPDATE_COMMAND_UI_RANGE(ID_THREATMOVEMENT_0, ID_THREATMOVEMENT_2, OnUpdateUIThreatMovement)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CAseDoc construction/destruction
CAseDoc::CAseDoc()
: m_TerrainBoard(ASE_BOARDX, ASE_BOARDY),
m_ThreatBoard(ASE_BOARDX, ASE_BOARDY, &m_TerrainBoard),
m_SearchSpaceBoard(ASE_BOARDX, ASE_BOARDY, &m_TerrainBoard),
m_LOSApproximationBoard(ASE_BOARDX, ASE_BOARDY, &m_TerrainBoard, &m_ThreatBoard),
// movement type
m_bMovementDiagonal(false),
// movement costs
m_bMovementCostsVectorBased(false),
m_bMovementCostsRelative(false),
// threat costs
m_bThreatCostsNone(true),
m_bThreatCostsSimple(false),
m_bThreatLineOfFireWithAimingCosts(false),
m_bThreatCountCosts(false),
m_bDistanceToThreatCosts(false),
m_bThreatCostsFromApproximatedTable(false),
// views
m_bSearchSpace(true),
m_bThreatPositions(true),
m_bThreatLinesOfFire(true),
m_bDrawApproximatedLinesOfFire(false),
m_bDrawRoute(true)
{
m_bContinualUpdate = false;
m_uBrushType = 0;
}
CAseDoc::~CAseDoc()
{
}
BOOL CAseDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
m_TerrainBoard.Clear();
m_ThreatBoard.Clear();
m_SearchSpaceBoard.Clear();
m_cStart.x = -1;
m_cEnd.x = -1;
m_cBreakpoint.x = -1;
m_iBreakData = -1;
m_bStepped = false;
m_cAStar.Reset();
m_bDrawRoute = false;
return TRUE;
}
BOOL CAseDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
if (!CDocument::OnOpenDocument(lpszPathName))
return FALSE;
m_bStepped = false;
m_cBreakpoint.x = -1;
m_iBreakData = -1;
m_cAStar.Reset();
m_bDrawRoute = false;
m_SearchSpaceBoard.Clear();
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CAseDoc serialization
void CAseDoc::Serialize(CArchive& ar)
{
int x = ASE_BOARDX, y = ASE_BOARDY;
if (ar.IsStoring())
{
ar << x;
ar << y;
ar << m_cStart;
ar << m_cEnd;
m_TerrainBoard.WriteBoard(ar);
// writes threats after original board, so remain compatible
m_ThreatBoard.WriteBoard(ar);
}
else
{
ar >> x;
ar >> y;
ar >> m_cStart;
ar >> m_cEnd;
m_TerrainBoard.ReadBoard(ar);
// reads threats after original board, to remain compatible
m_ThreatBoard.Clear();
// test whether any threat data might be included - dirty
CFile* file;
file = ar.GetFile();
unsigned long bytesAvailable;
bytesAvailable = static_cast<unsigned long>(file->GetLength() - file->GetPosition());
if ( bytesAvailable > 0 )
{
m_ThreatBoard.ReadBoard(ar);
}
// disable button
m_bDrawApproximatedLinesOfFire = false;
m_ThreatBoard.InitializeLinesOfFire();
m_LOSApproximationBoard.Clear();
}
}
void CAseDoc::SetStatusBarText(const char* aText)
{
CMainFrame* pMfm = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
CStatusBar* statusbar = pMfm->GetStatusBar();
statusbar->SetPaneText(0, aText);
}
/////////////////////////////////////////////////////////////////////////////
// CAseDoc diagnostics
#ifdef _DEBUG
void CAseDoc::AssertValid() const
{
CDocument::AssertValid();
}
void CAseDoc::Dump(CDumpContext& dc) const
{
CDocument::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CAseDoc commands
int CAseDoc::AS_Valid(_asNode *parent, _asNode *node, int data, void *pointer)
{
int x = node->GetX();
int y = node->GetY();
CAseDoc *me = reinterpret_cast<CAseDoc *>(pointer);
if ( !me->GetTerrainBoard()->IsValidTerrainMove(parent->GetX(), parent->GetY(), x, y) )
return false;
// check for invalid diagonal movement
if ( !me->DoesUseDiagonalMovement() )
{
int px = parent->GetX();
int py = parent->GetY();
return ( ( px == x )
|| ( py == y )
);
}
else
return true;
}
void CAseDoc::NodeAdded(_asNode *node, int data)
{
if (m_cBreakpoint.x == -1 && m_iBreakData == -1) return;
//! \todo rewrite to single expression
if ( node->GetX() == m_cBreakpoint.x
&& node->GetY() == m_cBreakpoint.y
)
{
m_bBreakpointHit = true;
m_pcBreakNode = node;
}
if (data == m_iBreakData) {
m_bBreakpointHit = true;
m_pcBreakNode = node;
}
}
CNodeView *CAseDoc::GetNodeView()
{
POSITION pos;
pos = GetFirstViewPosition();
CNodeView *nv = reinterpret_cast<CNodeView *>(GetNextView(pos));
return nv;
}
CAseView *CAseDoc::GetAseView()
{
CMainFrame* pMfm = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
CAseView *view = reinterpret_cast<CAseView *>(pMfm->GetRightPane());
return view;
}
void CAseDoc::SelectMovementCostFunctions()
{
// set appropriate terrain cost function
if ( DoesUseRelativeMovementCosts() )
{
m_cAStar.udTerrainCost = ASE_Costs::CellBasedRelativeMovementCosts;
m_cAStar.udTerrainHeuristic = ASE_Costs::CellBasedRelativeMovementHeuristic;
}
else
if ( DoesUseVectorBasedMovementCosts() )
{
m_cAStar.udTerrainCost = ASE_Costs::VectorBasedNormalMovementCosts;
m_cAStar.udTerrainHeuristic = ASE_Costs::VectorBasedNormalMovementHeuristic;
}
else // cell based
{
m_cAStar.udTerrainCost = ASE_Costs::CellBasedNormalMovementCosts;
m_cAStar.udTerrainHeuristic = ASE_Costs::CellBasedNormalMovementHeuristic;
}
}
void CAseDoc::SelectThreatCostFunctions()
{
// no prediction of remaining threat costs
const char* pStatusBarText;
m_cAStar.udThreatHeuristic = ASE_Costs::ThreatsAnyModeAnyMovementHeuristic;
pStatusBarText = "A* search: traditional shortest path";
// select cost function as follows
// - approximated lof table
// - distance + count
// - distance
// - count
// - no distance, no count
// - none
// and for each of these categories, distinguish aiming, vector/cell based
if ( DoesUseThreatCostsFromApproxTable() )
{
if ( DoesUseAimingThreatCosts() )
{
if ( DoesUseVectorBasedMovementCosts() )
{
m_cAStar.udThreatCost = ASE_Costs::VectorBasedThreatsApproximateLOFAimingCosts;
}
else
{
m_cAStar.udThreatCost = ASE_Costs::CellBasedThreatsApproximateLOFAimingCosts;
}
pStatusBarText = "A* search: tactical, using costs from approximated small lookup table, taking into account aiming";
}
else
{
if ( DoesUseVectorBasedMovementCosts() )
{
m_cAStar.udThreatCost = ASE_Costs::VectorBasedThreatsApproximateLOFSimpleCosts;
}
else
{
m_cAStar.udThreatCost = ASE_Costs::CellBasedThreatsApproximateLOFSimpleCosts;
}
pStatusBarText = "A* search: tactical, using costs from approximated small lookup table";
}
}
else
if ( ( DoesUseDistanceToThreatCosts() )
&& ( DoesUseThreatCountCosts() )
)
{
if ( DoesUseAimingThreatCosts() )
{
if ( DoesUseVectorBasedMovementCosts() )
{
m_cAStar.udThreatCost = ASE_Costs::VectorBasedDistanceAndCountBasedAimingCosts;
}
else
{
m_cAStar.udThreatCost = ASE_Costs::CellBasedDistanceAndCountBasedAimingCosts;
}
pStatusBarText = "A* search: tactical, using exact distance and threat count costs, taking into account aiming";
}
else
{
if ( DoesUseVectorBasedMovementCosts() )
{
m_cAStar.udThreatCost = ASE_Costs::VectorBasedDistanceAndCountBasedSimpleCosts;
}
else
{
m_cAStar.udThreatCost = ASE_Costs::CellBasedDistanceAndCountBasedSimpleCosts;
}
pStatusBarText = "A* search: tactical, using exact distance and threat count costs";
}
}
else
if ( DoesUseDistanceToThreatCosts() )
{
if ( DoesUseAimingThreatCosts() )
{
if ( DoesUseVectorBasedMovementCosts() )
{
m_cAStar.udThreatCost = ASE_Costs::VectorBasedDistanceBasedAimingCosts;
}
else
{
m_cAStar.udThreatCost = ASE_Costs::CellBasedDistanceBasedAimingCosts;
}
pStatusBarText = "A* search: tactical, using exact distance to threat costs, taking into account aiming";
}
else
{
if ( DoesUseVectorBasedMovementCosts() )
{
m_cAStar.udThreatCost = ASE_Costs::VectorBasedDistanceBasedSimpleCosts;
}
else
{
m_cAStar.udThreatCost = ASE_Costs::CellBasedDistanceBasedSimpleCosts;
}
pStatusBarText = "A* search: tactical, using exact distance to threat costs";
}
}
else
if ( DoesUseThreatCountCosts() )
{
if ( DoesUseAimingThreatCosts() )
{
if ( DoesUseVectorBasedMovementCosts() )
{
m_cAStar.udThreatCost = ASE_Costs::VectorBasedCountBasedAimingCosts;
}
else
{
m_cAStar.udThreatCost = ASE_Costs::CellBasedCountBasedAimingCosts;
}
pStatusBarText = "A* search: tactical, using exact threat count costs, taking into account aiming";
}
else
{
if ( DoesUseVectorBasedMovementCosts() )
{
m_cAStar.udThreatCost = ASE_Costs::VectorBasedCountBasedSimpleCosts;
}
else
{
m_cAStar.udThreatCost = ASE_Costs::CellBasedCountBasedSimpleCosts;
}
pStatusBarText = "A* search: tactical, using exact threat count costs";
}
}
else
if ( DoesUseThreatCosts() )
{
if ( DoesUseAimingThreatCosts() )
{
if ( DoesUseVectorBasedMovementCosts() )
{
m_cAStar.udThreatCost = ASE_Costs::VectorBasedThreatsAimingCosts;
}
else
{
m_cAStar.udThreatCost = ASE_Costs::CellBasedThreatsAimingCosts;
}
pStatusBarText = "A* search: tactical, using exact simple threat line-of-fire costs, taking into account aiming";
}
else
{
if ( DoesUseVectorBasedMovementCosts() )
{
m_cAStar.udThreatCost = ASE_Costs::VectorBasedThreatsSimpleCosts;
}
else
{
m_cAStar.udThreatCost = ASE_Costs::CellBasedThreatsSimpleCosts;
}
pStatusBarText = "A* search: tactical, using exact simple threat line-of-fire costs";
}
}
else
{
m_cAStar.udThreatCost = ASE_Costs::ThreatsNoCosts;
}
SetStatusBarText(pStatusBarText);
}
bool CAseDoc::SetupAStar(bool stepped/* = false*/)
{
if (m_cStart.x == -1 || m_cEnd.x == -1) {
MessageBox("Please ensure that both the start and end points are specified.\nA red and green square denote the start and end points, respectively.", "A* Explorer", MB_ICONERROR);
return false;
}
CNodeView *nv = GetNodeView();
GetAseView()->RemoveHighlight();
assert( m_TerrainBoard.GetNumberOfRows() == ASE_BOARDX );
m_cAStar.SetRows(ASE_BOARDX);
m_cAStar.udValid = AS_Valid;
ASE_Costs::SetTerrainBoard(GetTerrainBoard());
ASE_Costs::SetThreatBoard(GetThreatBoard());
ASE_Costs::SetLOFApproximationBoard(GetLOSApproximationBoard());
SelectMovementCostFunctions();
SelectThreatCostFunctions();
if ( m_bThreatCostsFromApproximatedTable )
{
GetLOSApproximationBoard()->ComputeLinesOfFireApproximation();
}
m_cAStar.udNotifyList = CNodeView::OnUpdateList;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -