📄 ase_threatboard.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"
*/
/***************************************************************************
*
* purpose: threat and line-of-fire lookup table and overlay
*/
#include "stdafx.h"
#include "ase_threatboard.h"
#include "ase_terrain.h"
#include <vector>
#include <algorithm> // though MSVC6 doesn't feature min/max there
using namespace std;
#include <cmath>
#include <cassert>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
ASE_ThreatBoard::ASE_ThreatBoard(unsigned int aNumberOfRows,
unsigned int aNumberOfColumns,
const ASE_TerrainBoard* theTerrain
)
: ASE_Board(aNumberOfRows, aNumberOfColumns, 16, m_ThreatBrushes),
m_RiskModus(eAnyLineOfFire),
m_kTerrainBoard(theTerrain),
m_kThreatLineOfFire(1),
m_kThreatPosition(15),
m_RiskFactor(4),
m_LineOfFireReach(32),
m_ThreatMovement(0),
m_ThreatBrushes(0),
m_kBaseRisk(0.15f),
m_kMaxLOFCount(6)
{
assert( m_kTerrainBoard );
assert( GetNumberOfColumns() == m_kTerrainBoard->GetNumberOfColumns() );
assert( GetNumberOfRows() == m_kTerrainBoard->GetNumberOfRows() );
FillOutPalette();
// prepare the line-of-fire template
m_PieTemplate.PrepareScan(m_LineOfFireReach);
}
ASE_ThreatBoard::~ASE_ThreatBoard()
{
delete[] m_ThreatBrushes;
RemoveAllThreats();
}
void ASE_ThreatBoard::FillOutPalette()
{
assert( m_ThreatBrushes == 0 );
assert( GetNumberOfValues() > 2 );
/*!
fill out brush table as follows:
part1: line-of-fire
3 x GetNumberOfValues()
clear terrain, all values
terrain 1, all values
terrain 2, all values
*/
unsigned int totalnumber;
unsigned int steps;
steps = GetNumberOfValues();
totalnumber = 3 * steps;
m_ThreatBrushes = new COLORREF[totalnumber];
COLORREF startrgb;
COLORREF endrgb;
float step_r, step_g, step_b;
float r, g, b;
int idx;
idx = 0;
// fill out first steps entries
startrgb = RGB(255,255,224);
endrgb = RGB(255,255,128);
step_r = static_cast<float>(GetRValue(endrgb) - GetRValue(startrgb));
step_g = static_cast<float>(GetGValue(endrgb) - GetGValue(startrgb));
step_b = static_cast<float>(GetBValue(endrgb) - GetBValue(startrgb));
step_r /= (steps - 1);
step_g /= (steps - 1);
step_b /= (steps - 1);
r = GetRValue(startrgb);
g = GetGValue(startrgb);
b = GetBValue(startrgb);
unsigned int step;
for ( step = 0; step < steps; ++step, ++idx )
{
m_ThreatBrushes[idx] = RGB(r,g,b);
r += step_r;
g += step_g;
b += step_b;
r = min(255.0f, max(0.0f, r));
g = min(255.0f, max(0.0f, g));
b = min(255.0f, max(0.0f, b));
}
// fill out second steps entries
startrgb = RGB(192,192,168);
endrgb = RGB(192,192, 96);
step_r = static_cast<float>(GetRValue(endrgb) - GetRValue(startrgb));
step_g = static_cast<float>(GetGValue(endrgb) - GetGValue(startrgb));
step_b = static_cast<float>(GetBValue(endrgb) - GetBValue(startrgb));
step_r /= (steps - 1);
step_g /= (steps - 1);
step_b /= (steps - 1);
r = GetRValue(startrgb);
g = GetGValue(startrgb);
b = GetBValue(startrgb);
for ( step = 0; step < steps; ++step, ++idx )
{
m_ThreatBrushes[idx] = RGB(r,g,b);
r += step_r;
g += step_g;
b += step_b;
r = min(255.0f, max(0.0f, r));
g = min(255.0f, max(0.0f, g));
b = min(255.0f, max(0.0f, b));
}
// fill out third steps entries
startrgb = RGB(128,128,112);
endrgb = RGB(128,128, 64);
step_r = static_cast<float>(GetRValue(endrgb) - GetRValue(startrgb));
step_g = static_cast<float>(GetGValue(endrgb) - GetGValue(startrgb));
step_b = static_cast<float>(GetBValue(endrgb) - GetBValue(startrgb));
step_r /= (steps - 1);
step_g /= (steps - 1);
step_b /= (steps - 1);
r = GetRValue(startrgb);
g = GetGValue(startrgb);
b = GetBValue(startrgb);
for ( step = 0; step < steps; ++step, ++idx )
{
m_ThreatBrushes[idx] = RGB(r,g,b);
r += step_r;
g += step_g;
b += step_b;
r = min(255.0f, max(0.0f, r));
g = min(255.0f, max(0.0f, g));
b = min(255.0f, max(0.0f, b));
}
}
int ASE_ThreatBoard::GetMaxThreatReach() const
{
return static_cast<int>(m_LineOfFireReach);
}
void ASE_ThreatBoard::MarkThreatPosition(int aRow, int aCol)
{
unsigned int idx;
idx = GetIndexForRowColumn(aRow, aCol);
// mark cell on the board
if ( GetCellValue(idx) == m_kThreatPosition )
return;
SetCellValue(idx, m_kThreatPosition);
// create threat
ASE_Threat* threat;
threat = new ASE_Threat(idx);
AddThreat(threat);
ComputeLinesOfFire();
}
void ASE_ThreatBoard::ClearThreatPosition(int aRow, int aCol)
{
unsigned int idx;
idx = GetIndexForRowColumn(aRow, aCol);
// mark cell on the board
if ( GetCellValue(idx) == 0 )
return;
// remove threat
if ( GetCellValue(idx) == m_kThreatPosition )
RemoveThreat(idx);
// mark cell on the board
SetCellValue(idx, 0);
ComputeLinesOfFire();
}
bool ASE_ThreatBoard::IsThreatPosition(int aRow, int aCol) const
{
return ( m_kThreatPosition == GetCellValue(aRow, aCol) );
}
bool ASE_ThreatBoard::IsThreatPosition(unsigned int anIndex) const
{
return ( m_kThreatPosition == GetCellValue(anIndex) );
}
void ASE_ThreatBoard::SetRiskModus(RiskModus aRiskModus)
{
assert( ( aRiskModus == eAnyLineOfFire )
|| ( aRiskModus == eMinLineOfFireDistance )
|| ( aRiskModus == eMinLineOfFireCount )
|| ( aRiskModus == eMinLineOfFireCountAndDistance )
);
m_RiskModus = aRiskModus;
}
ASE_ThreatBoard::RiskModus ASE_ThreatBoard::GetRiskModus() const
{
return m_RiskModus;
}
COLORREF ASE_ThreatBoard::GetCellColorForOffset(unsigned int anIndex, CellValue anOffset) const
{
assert( !IsEmptyCell(anIndex) );
CellValue value;
value = GetCellValue(anIndex);
unsigned int idx;
idx = anOffset * GetNumberOfValues();
idx += static_cast<unsigned int>(value);
return m_ThreatBrushes[idx];
}
COLORREF ASE_ThreatBoard::GetLineOfFireColor() const
{
return m_ThreatBrushes[GetNumberOfValues() * (m_kThreatLineOfFire - 1)];
}
unsigned int ASE_ThreatBoard::GetAssumedThreatMovement() const
{
return m_ThreatMovement;
}
void ASE_ThreatBoard::SetAssumedThreatMovement(unsigned int theAssumedThreatMovement)
{
m_ThreatMovement = theAssumedThreatMovement;
}
void ASE_ThreatBoard::ClearLinesOfFire()
{
const unsigned int maxidx = GetNumberOfColumns() * GetNumberOfRows();
for ( unsigned int idx = 0; idx < maxidx; ++idx )
{
if ( GetCellValue(idx) != m_kThreatPosition )
{
SetCellValue(idx, 0);
}
}
}
void ASE_ThreatBoard::InitializeLinesOfFire()
{
// clear old threats
RemoveAllThreats();
// locate new threats
for ( unsigned int idx = 0;
idx < (GetNumberOfRows() * GetNumberOfColumns());
++idx
)
{
if ( GetCellValue(idx) == m_kThreatPosition )
{
ASE_Threat* threat;
threat = new ASE_Threat(idx);
AddThreat(threat);
}
}
ComputeLinesOfFire();
}
void ASE_ThreatBoard::ComputeLinesOfFire()
{
ClearLinesOfFire();
for ( unsigned int r = 0; r < GetNumberOfRows(); ++r )
{
for ( unsigned int c = 0; c < GetNumberOfColumns(); ++c )
{
if ( GetCellValue(r, c) == m_kThreatPosition )
{
ComputeLinesOfFireForMovingThreat(r, c, m_ThreatMovement);
}
}
}
// select appropriate cell value function
typedef CellValue (ASE_ThreatBoard::*MemberFnDetermineRisk)(unsigned int anIndex) const;
MemberFnDetermineRisk pMemberFunction;
if ( m_RiskModus == eAnyLineOfFire )
pMemberFunction = DetermineLineOfFireRiskAnyLOF;
else
if ( m_RiskModus == eMinLineOfFireDistance )
pMemberFunction = DetermineLineOfFireRiskMinDistance;
else
if ( m_RiskModus == eMinLineOfFireCount )
pMemberFunction = DetermineLineOfFireRiskLOFCount;
else
if ( m_RiskModus == eMinLineOfFireCountAndDistance )
pMemberFunction = DetermineLineOfFireRiskDistanceLOFCount;
else
{
assert( !"unsupported risk modus" );
}
// now start marking lines of fire
ThreatList::const_iterator threat;
for ( threat = m_Threats.begin(); threat != m_Threats.end(); ++threat )
{
const ASE_Threat::PositionsUnderFire* positionsunderfire;
positionsunderfire = (*threat)->GetPositionsUnderFire();
assert( !positionsunderfire->empty() );
ASE_Threat::PositionsUnderFire::const_iterator position;
for ( position = positionsunderfire->begin();
position != positionsunderfire->end();
++position
)
{
if ( IsEmptyCell(*position) )
{
// call member function via pointer to member function
SetCellValue(*position, (this->*pMemberFunction)(*position));
}
}
}
}
void ASE_ThreatBoard::ComputeLinesOfFireForMovingThreat
(unsigned int aRow,
unsigned int aCol,
unsigned int aMaximumMovement
)
{
CoordPairList theReachablePositions;
theReachablePositions.reserve( (2 + aMaximumMovement) * (2 + aMaximumMovement) );
ConstructPossibleThreatPositions(aRow, aCol, aMaximumMovement, theReachablePositions);
assert( !theReachablePositions.empty() );
CoordPairList theCoveredPositions;
theCoveredPositions.reserve((m_LineOfFireReach+aMaximumMovement) * (m_LineOfFireReach+aMaximumMovement) * 4);
CoordPairList::const_iterator position;
for ( position = theReachablePositions.begin();
position != theReachablePositions.end();
++position
)
{
ComputeLinesOfFireFromCell(position->x, position->y, theCoveredPositions);
}
assert( !theCoveredPositions.empty() );
// now set these locations as under fire by this threat
ASE_Threat::PositionsUnderFire positionsUnderFire;
positionsUnderFire.reserve(theCoveredPositions.size());
CoordPairList::const_iterator coveredposition;
for ( coveredposition = theCoveredPositions.begin();
coveredposition != theCoveredPositions.end();
++coveredposition
)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -