engine/ai/graphPartition.cc
2024-01-07 04:36:33 +00:00

128 lines
3.7 KiB
C++

//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "ai/graph.h"
//-------------------------------------------------------------------------------------
GraphPartition::GraphPartition()
{
mType = ForceField;
mCanJetDown = false;
// mPartition.setSize(gNavGraph->numNodesAll());
// mPartition.clear();
}
void GraphPartition::install(const GraphPartition& p)
{
mPartition.copy(p.mPartition);
}
// Allocate the bit vector and clear it.
void GraphPartition::setSize(S32 N)
{
mPartition.setSize(N);
}
// Consumer uses a regular partition to build the downhill partition. We check here to
// see if it's any different from the regular partition.
void GraphPartition::setDownhill(const GraphPartition& downhill)
{
U32 bytes = mPartition.getByteSize();
AssertFatal(mType == Armor, "Only armor types can have a downhill component");
AssertFatal(bytes == downhill.mPartition.getByteSize(), "Unequal partition sizes");
if (dMemcmp(mPartition.getBits(), downhill.mPartition.getBits(), bytes)) {
mCanJetDown = true;
mDownhill.copy(downhill.mPartition);
}
else {
mCanJetDown = false;
}
}
// See if partition can answer question of whether or not we can get from A to B.
GraphPartition::Answer GraphPartition::reachable(S32 A, S32 B)
{
if (mPartition.test(A))
{
if (mPartition.test(B) || (mCanJetDown && mDownhill.test(B)))
return CanReach;
else
return CannotReach;
}
else if (mPartition.test(B))
return CannotReach;
else
return Ambiguous;
}
//-------------------------------------------------------------------------------------
PartitionList::PartitionList()
{
mType = GraphPartition::ForceField;
}
PartitionList::~PartitionList()
{
clear();
}
//-------------------------------------------------------------------------------------
void PartitionList::clear()
{
while (size()) {
last().~GraphPartition();
pop_back();
}
}
// This is called after searches that have failed to reach their target to register the
// new partition that has been discovered. ie. when a force field has changed states,
// then partition lists are invalid and get rebuilt as searches happen.
void PartitionList::pushPartition(const GraphPartition& partition)
{
GraphPartition empty;
// I'd like to construct the entry in the vector, but can't get it to go...
// i.e increment(); last().GraphPartition();
// But this should work, given that BitVector doesn't override assignment... ugh.
push_back(empty);
last().install(partition);
last().setType(mType);
}
// Our partition lists will probably never have the complete answer to this. Need an
// ambiguous return value.
GraphPartition::Answer PartitionList::reachable(S32 A, S32 B)
{
for (iterator partition = begin(); partition != end(); partition++)
{
GraphPartition::Answer answer = partition->reachable(A, B);
if (answer != GraphPartition::Ambiguous)
return answer;
}
AssertFatal(mType != GraphPartition::Armor, "Armor partitions are never ambiguous");
return GraphPartition::Ambiguous;
}
// When partitions are built at mission start, it has to check and see which nodes have
// entries after finishing each pass. It goes until graph is filled.
S32 PartitionList::haveEntry(S32 forNode)
{
for (iterator partition = begin(); partition != end(); partition++)
if (partition->test(forNode))
return true;
return false;
}