mirror of
https://github.com/thug1src/thug.git
synced 2025-01-22 05:43:47 +00:00
5185 lines
153 KiB
C++
5185 lines
153 KiB
C++
|
#include <core/defines.h>
|
||
|
#include <sk/ParkEditor/EdRail.h>
|
||
|
#include <sk/ParkEditor2/EdMap.h>
|
||
|
#include <sk/ParkEditor2/ParkEd.h>
|
||
|
#include <sk/ParkEditor2/clipboard.h>
|
||
|
#include <core/math.h>
|
||
|
#include <core/crc.h>
|
||
|
#include <gel/scripting/checksum.h>
|
||
|
#include <gel/scripting/script.h>
|
||
|
#include <gel/scripting/struct.h>
|
||
|
#include <gel/scripting/array.h>
|
||
|
#include <gel/scripting/symboltable.h>
|
||
|
#include <gel/scripting/symboltype.h>
|
||
|
#include <gel/scripting/component.h>
|
||
|
#include <gel/scripting/vecpair.h>
|
||
|
#include <gel/scripting/utils.h>
|
||
|
#include <gel/music/music.h>
|
||
|
#include <sys/file/filesys.h>
|
||
|
#include <sk/gamenet/gamenet.h>
|
||
|
#include <sk/components/raileditorcomponent.h>
|
||
|
#include <sk/components/goaleditorcomponent.h>
|
||
|
#include <sk/engine/feeler.h>
|
||
|
|
||
|
DefinePoolableClass(Ed::CMapListNode);
|
||
|
|
||
|
#ifdef __PLAT_NGC__
|
||
|
#define _16(a) (((a>>8)&0x00ff)|((a<<8)&0xff00))
|
||
|
#define _32(a) (((a>>24)&0x000000ff)|((a>>8)&0x0000ff00)|((a<<8)&0x00ff0000)|((a<<24)&0xff000000))
|
||
|
#else
|
||
|
#define _16(a) a
|
||
|
#define _32(a) a
|
||
|
#endif // __PLAT_NGC__
|
||
|
|
||
|
#if 1
|
||
|
#ifdef __PLAT_NGPS__
|
||
|
#define __USE_EXTERNAL_BUFFER__
|
||
|
#include <gfx/nx.h>
|
||
|
#include <gfx/ngps/nx/dma.h>
|
||
|
#define __EXTERNAL_BUFFER__ NxPs2::dma::pRuntimeBuffer
|
||
|
#define ACQUIRE_BUFFER Nx::CEngine::sFinishRendering();
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
namespace Ed
|
||
|
{
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
DefineSingletonClass(CParkManager, "Park Manager");
|
||
|
|
||
|
|
||
|
|
||
|
CParkManager *CParkManager::sp_instance = NULL;
|
||
|
|
||
|
GridDims::GridDims(uint8 x, sint8 y, uint8 z, uint8 w, uint8 h, uint8 l)
|
||
|
{
|
||
|
m_dims[0] = x;
|
||
|
m_dims[1] = (uint8) y;
|
||
|
m_dims[2] = z;
|
||
|
m_dims[3] = w;
|
||
|
m_dims[4] = h;
|
||
|
m_dims[5] = l;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
uint8 &GridDims::operator [](sint i)
|
||
|
{
|
||
|
Dbg_Assert(i < 6);
|
||
|
return m_dims[i];
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
// Effectively gives the area an H of infinity
|
||
|
void GridDims::MakeInfinitelyHigh()
|
||
|
{
|
||
|
m_dims[4] = 127 - (sint8) m_dims[1];
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
// Effectively gives the area an H of infinity
|
||
|
void GridDims::MakeInfiniteOnY()
|
||
|
{
|
||
|
m_dims[1] = (uint8) -100;
|
||
|
m_dims[4] = 200;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void GridDims::PrintContents() const
|
||
|
{
|
||
|
printf("pos=(%d,%d,%d) dims=(%d,%d,%d)\n",
|
||
|
m_dims[0], (sint8) m_dims[1], m_dims[2],
|
||
|
m_dims[3], m_dims[4], m_dims[5]);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
CMetaPiece::CMetaPiece()
|
||
|
{
|
||
|
m_flags = EFlags(0);
|
||
|
mp_additional_desc_tab = NULL;
|
||
|
m_total_entries = 0;
|
||
|
m_num_used_entries = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
CMetaPiece::~CMetaPiece()
|
||
|
{
|
||
|
if (mp_additional_desc_tab)
|
||
|
delete mp_additional_desc_tab;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
CConcreteMetaPiece *CMetaPiece::CastToConcreteMeta()
|
||
|
{
|
||
|
Dbg_MsgAssert(this == NULL || (m_flags & mCONCRETE_META), ("not a concrete metapiece"));
|
||
|
return (CConcreteMetaPiece *) this;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
CAbstractMetaPiece *CMetaPiece::CastToAbstractMeta()
|
||
|
{
|
||
|
Dbg_MsgAssert(this == NULL || (m_flags & mABSTRACT_META), ("not an abstract metapiece"));
|
||
|
return (CAbstractMetaPiece *) this;
|
||
|
}
|
||
|
|
||
|
bool CMetaPiece::IsRestartOrFlag()
|
||
|
{
|
||
|
switch (m_name_checksum)
|
||
|
{
|
||
|
case CRCC(0xdc09a6a4,"Sk3Ed_RS_1p"):
|
||
|
case CRCC(0xca07b4fc,"Sk3Ed_RS_Mp"):
|
||
|
case CRCC(0x3a784d4c,"Sk3Ed_Rs_Ho"):
|
||
|
case CRCC(0x4e2efd2a,"Sk3Ed_Rs_KOTH"):
|
||
|
case CRCC(0x613c7766,"Sk4Ed_Team_Yellow"):
|
||
|
case CRCC(0xec82433c,"Sk4Ed_Team_Green"):
|
||
|
case CRCC(0xd7eb62b5,"Sk4Ed_Team_Red"):
|
||
|
case CRCC(0x8a1576b6,"Sk4Ed_Team_Blue"):
|
||
|
return true;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool CMetaPiece::IsCompletelyWithinArea(const GridDims &area)
|
||
|
{
|
||
|
if (m_cell_area.GetX() >= area.GetX() && m_cell_area.GetX()+m_cell_area.GetW() <= area.GetX()+area.GetW() &&
|
||
|
m_cell_area.GetZ() >= area.GetZ() && m_cell_area.GetZ()+m_cell_area.GetL() <= area.GetZ()+area.GetL())
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
Use to set rotation of abstract metapiece for testing purposes (in GetMetaPiecesAt()), or
|
||
|
to set rotation of concrete metapiece before adding to park.
|
||
|
*/
|
||
|
void CMetaPiece::SetRot(Mth::ERot90 newRot)
|
||
|
{
|
||
|
Dbg_MsgAssert(!(m_flags & CMetaPiece::mIN_PARK), ("metapiece already in park -- can't change rotation"));
|
||
|
|
||
|
// just want to change relative to current rotation
|
||
|
Mth::ERot90 rot = Mth::ERot90((newRot + 4 - m_rot) & 3);
|
||
|
m_rot = newRot;
|
||
|
if (rot & 1)
|
||
|
{
|
||
|
// switch W and L
|
||
|
m_cell_area.SetWHL(m_cell_area.GetL(), m_cell_area.GetH(), m_cell_area.GetW());
|
||
|
}
|
||
|
|
||
|
SMetaDescriptor temp_new_first[USUAL_NUM_DESCRIPTORS];
|
||
|
|
||
|
// Create a new table, which will soon replace the old one
|
||
|
SMetaDescriptor *p_meta_tab = NULL;
|
||
|
if (mp_additional_desc_tab)
|
||
|
{
|
||
|
Mem::Manager::sHandle().PushContext(CParkManager::sInstance()->GetGenerator()->GetParkEditorHeap());
|
||
|
p_meta_tab = new SMetaDescriptor[m_total_entries-USUAL_NUM_DESCRIPTORS];
|
||
|
Mem::Manager::sHandle().PopContext();
|
||
|
}
|
||
|
for (uint i = 0; i < m_num_used_entries; i++)
|
||
|
{
|
||
|
// "dims" contains position of upper-left, after rotation
|
||
|
SMetaDescriptor &out = (i < USUAL_NUM_DESCRIPTORS) ? temp_new_first[i] : p_meta_tab[i-USUAL_NUM_DESCRIPTORS];
|
||
|
SMetaDescriptor &in = (i < USUAL_NUM_DESCRIPTORS) ? m_first_desc_tab[i] : mp_additional_desc_tab[i-USUAL_NUM_DESCRIPTORS];
|
||
|
out = in;
|
||
|
|
||
|
// dimensions with current rotation (not new)
|
||
|
// OOG!
|
||
|
GridDims in_dims(0, 0, 0);
|
||
|
if (m_flags & mABSTRACT_META)
|
||
|
{
|
||
|
CAbstractMetaPiece *p_meta = CParkManager::sInstance()->GetAbstractMeta(in.mPieceName);
|
||
|
in_dims = p_meta->GetArea();
|
||
|
if ((in.mRot & 1))
|
||
|
{
|
||
|
// for a concrete metapiece, the retrieved cell dimensions will already reflect
|
||
|
// the current rotation, so no need to enter this block
|
||
|
in_dims.SetWHL(in_dims.GetL(), in_dims.GetH(), in_dims.GetW()); // switch W & L
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
in.mpPiece->GetCellDims(&in_dims);
|
||
|
}
|
||
|
|
||
|
switch(rot)
|
||
|
{
|
||
|
case Mth::ROT_0:
|
||
|
out.mX = in.mX;
|
||
|
out.mZ = in.mZ;
|
||
|
break;
|
||
|
case Mth::ROT_90:
|
||
|
out.mX = in.mZ;
|
||
|
out.mZ = m_cell_area.GetL() - in.mX - in_dims.GetW();
|
||
|
break;
|
||
|
case Mth::ROT_180:
|
||
|
out.mX = m_cell_area.GetW() - in.mX - in_dims.GetW();
|
||
|
out.mZ = m_cell_area.GetL() - in.mZ - in_dims.GetL();
|
||
|
break;
|
||
|
case Mth::ROT_270:
|
||
|
out.mX = m_cell_area.GetW() - in.mZ - in_dims.GetL();
|
||
|
out.mZ = in.mX;
|
||
|
break;
|
||
|
default:
|
||
|
Dbg_MsgAssert(0, ("ahhh-oooop?"));
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
out.mY = in.mY;
|
||
|
out.mRot = Mth::ERot90((in.mRot + rot) & 3);
|
||
|
|
||
|
// this will also copy in.mPieceName, if this is an abstract metapiece
|
||
|
out.mpPiece = in.mpPiece;
|
||
|
} // end for
|
||
|
|
||
|
if (mp_additional_desc_tab)
|
||
|
delete mp_additional_desc_tab;
|
||
|
mp_additional_desc_tab = p_meta_tab;
|
||
|
for (int i = 0; i < USUAL_NUM_DESCRIPTORS; i++)
|
||
|
{
|
||
|
m_first_desc_tab[i] = temp_new_first[i];
|
||
|
//printf("desc at (%d,%d,%d)\n", m_first_desc_tab[i].mX, m_first_desc_tab[i].mY, m_first_desc_tab[i].mZ);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
// returns postion of piece's center, relative to center of metapiece
|
||
|
Mth::Vector CMetaPiece::GetRelativePosOfContainedPiece(int index)
|
||
|
{
|
||
|
// center_pos in world coordinates
|
||
|
Mth::Vector center_pos;
|
||
|
center_pos[X] = (float) m_cell_area.GetW() * CParkGenerator::CELL_WIDTH / 2.0f;
|
||
|
center_pos[Y] = 0;
|
||
|
center_pos[Z] = (float) m_cell_area.GetL() * CParkGenerator::CELL_LENGTH / 2.0f;
|
||
|
|
||
|
SMetaDescriptor &desc = get_desc_at_index(index);
|
||
|
CPiece *p_piece = GetContainedPiece(index);
|
||
|
Mth::Vector piece_pos(desc.mX * CParkGenerator::CELL_WIDTH + p_piece->GetDimsWithRot(Mth::ERot90(desc.mRot)).GetX() / 2.0f,
|
||
|
desc.mY * CParkGenerator::CELL_HEIGHT,
|
||
|
desc.mZ * CParkGenerator::CELL_LENGTH + p_piece->GetDimsWithRot(Mth::ERot90(desc.mRot)).GetZ() / 2.0f);
|
||
|
return piece_pos - center_pos;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void CMetaPiece::BuildElement3dSectorsArray(Script::CArray *pArray)
|
||
|
{
|
||
|
pArray->SetSizeAndType(m_num_used_entries, ESYMBOLTYPE_STRUCTURE);
|
||
|
for (uint i = 0; i < m_num_used_entries; i++)
|
||
|
{
|
||
|
SMetaDescriptor &desc = get_desc_at_index(i);
|
||
|
|
||
|
Script::CStruct *p_struct = new Script::CStruct();
|
||
|
p_struct->AddChecksum(NONAME, desc.mPieceName);
|
||
|
Mth::Vector pos = GetRelativePosOfContainedPiece(i);
|
||
|
p_struct->AddVector(NONAME, pos.GetX(), pos.GetY(), pos.GetZ());
|
||
|
|
||
|
pArray->SetStructure(i, p_struct);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
Creates new table of SMetaDescriptors. Might copy old one.
|
||
|
*/
|
||
|
void CMetaPiece::initialize_desc_table(int numEntries)
|
||
|
{
|
||
|
SMetaDescriptor *p_new_tab = NULL;
|
||
|
if (numEntries > USUAL_NUM_DESCRIPTORS)
|
||
|
{
|
||
|
Mem::Manager::sHandle().PushContext(CParkManager::sInstance()->GetGenerator()->GetParkEditorHeap());
|
||
|
p_new_tab = new SMetaDescriptor[numEntries-USUAL_NUM_DESCRIPTORS];
|
||
|
Mem::Manager::sHandle().PopContext();
|
||
|
}
|
||
|
|
||
|
// Copy old table, if any. Only copied if there are to be at least as many entries as
|
||
|
// there were before.
|
||
|
if (p_new_tab && mp_additional_desc_tab && m_total_entries <= (uint) numEntries)
|
||
|
{
|
||
|
for (uint i = USUAL_NUM_DESCRIPTORS; i < m_total_entries; i++)
|
||
|
p_new_tab[i-USUAL_NUM_DESCRIPTORS] = mp_additional_desc_tab[i-USUAL_NUM_DESCRIPTORS];
|
||
|
}
|
||
|
|
||
|
if (mp_additional_desc_tab)
|
||
|
delete mp_additional_desc_tab;
|
||
|
mp_additional_desc_tab = p_new_tab;
|
||
|
m_total_entries = numEntries;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
Returns specified descriptor.
|
||
|
*/
|
||
|
SMetaDescriptor &CMetaPiece::get_desc_at_index(int i)
|
||
|
{
|
||
|
if (i < USUAL_NUM_DESCRIPTORS) return m_first_desc_tab[i];
|
||
|
|
||
|
Dbg_MsgAssert(mp_additional_desc_tab && (uint) i < m_num_used_entries, ("descriptor entry doesn't exist"));
|
||
|
return mp_additional_desc_tab[i-USUAL_NUM_DESCRIPTORS];
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
CConcreteMetaPiece::CConcreteMetaPiece()
|
||
|
{
|
||
|
m_flags = EFlags(m_flags | mCONCRETE_META);
|
||
|
m_rot = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
int CConcreteMetaPiece::CountContainedPieces()
|
||
|
{
|
||
|
return m_num_used_entries;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
CPiece *CConcreteMetaPiece::GetContainedPiece(int index)
|
||
|
{
|
||
|
if ((uint) index >= m_num_used_entries || index < 0)
|
||
|
return NULL;
|
||
|
|
||
|
return get_desc_at_index(index).mpPiece;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
Used for the cursor piece, allowing any position and rotation, not just cell-aligned with 90 degree
|
||
|
increments. Doesn't affect "hard" position, rotation.
|
||
|
*/
|
||
|
void CConcreteMetaPiece::SetSoftRot(Mth::Vector pos, float rot)
|
||
|
{
|
||
|
//Ryan("moving metapiece to (%.2f,%.2f,%.2f)\n", pos[X], pos[Y], pos[Z]);
|
||
|
|
||
|
Mth::Vector center(m_cell_area.GetW() * CParkGenerator::CELL_WIDTH / 2.0f,
|
||
|
0.0f,
|
||
|
m_cell_area.GetL() * CParkGenerator::CELL_LENGTH / 2.0f);
|
||
|
|
||
|
for (uint i = 0; i < m_num_used_entries; i++)
|
||
|
{
|
||
|
SMetaDescriptor &desc = get_desc_at_index(i);
|
||
|
|
||
|
// BAKU
|
||
|
Mth::Vector piece_dims = desc.mpPiece->GetDims();
|
||
|
Mth::Vector piece_pos(desc.mX * CParkGenerator::CELL_WIDTH + piece_dims[X] / 2.0f - center[X],
|
||
|
desc.mY * CParkGenerator::CELL_HEIGHT - center[Y],
|
||
|
desc.mZ * CParkGenerator::CELL_LENGTH + piece_dims[Z] / 2.0f - center[Z]);
|
||
|
|
||
|
Mth::Matrix rot_mat;
|
||
|
rot_mat.Ident();
|
||
|
rot_mat.SetPos(piece_pos);
|
||
|
rot_mat.RotateY(Mth::DegToRad(rot));
|
||
|
rot_mat.Translate(pos);
|
||
|
|
||
|
//Ryan(" sub-piece position (%d) (%.2f,%.2f,%.2f)\n", desc.mY, rot_mat[Mth::POS][X], rot_mat[Mth::POS][Y], rot_mat[Mth::POS][Z]);
|
||
|
|
||
|
desc.mpPiece->CastToCClonedPiece()->SetDesiredPos(rot_mat[Mth::POS], CClonedPiece::CHANGE_SECTOR);
|
||
|
//desc.mpPiece->CastToCClonedPiece()->SetDesiredRot(Mth::ROT_0, CClonedPiece::CHANGE_SECTOR);
|
||
|
|
||
|
float soft_rot = 90.0f * (float) desc.mRot + rot;
|
||
|
desc.mpPiece->CastToCClonedPiece()->SetSoftRot(soft_rot);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Turn on or off the highlight effect for this concrete meta piece
|
||
|
// which just turns the effect on or off for the cloned pieces that make it up
|
||
|
void CConcreteMetaPiece::Highlight(bool on, bool gapHighlight)
|
||
|
{
|
||
|
for (uint i = 0; i < m_num_used_entries; i++)
|
||
|
{
|
||
|
SMetaDescriptor &desc = get_desc_at_index(i);
|
||
|
if (desc.mpPiece->GetFlags() & CPiece::mCLONED_PIECE)
|
||
|
{
|
||
|
desc.mpPiece->CastToCClonedPiece()->Highlight(on, gapHighlight);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void CConcreteMetaPiece::SetVisibility(bool visible)
|
||
|
{
|
||
|
for (uint i = 0; i < m_num_used_entries; i++)
|
||
|
{
|
||
|
SMetaDescriptor &desc = get_desc_at_index(i);
|
||
|
desc.mpPiece->CastToCClonedPiece()->SetActive(visible);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
Use after calls to add_piece() have been made. Once metapiece has been locked, it can be added to
|
||
|
the world or used as a cursor
|
||
|
*/
|
||
|
void CConcreteMetaPiece::lock()
|
||
|
{
|
||
|
// work out dimensions of metapiece from contained pieces
|
||
|
Mth::Vector min_pos, max_pos;
|
||
|
get_max_min_world_coords(max_pos, min_pos);
|
||
|
|
||
|
Mth::Vector my_dims;
|
||
|
my_dims.Set(max_pos.GetX() - min_pos.GetX(), max_pos.GetY() - min_pos.GetY(), max_pos.GetZ() - min_pos.GetZ());
|
||
|
|
||
|
m_cell_area.SetWHL((uint8) ((my_dims.GetX() + 2.0f) / CParkGenerator::CELL_WIDTH),
|
||
|
(uint8) ((my_dims.GetY() + 2.0f) / CParkGenerator::CELL_HEIGHT),
|
||
|
(uint8) ((my_dims.GetZ() + 2.0f) / CParkGenerator::CELL_LENGTH));
|
||
|
|
||
|
if (m_cell_area[H] < 1) m_cell_area[H] = 1;
|
||
|
|
||
|
//Dbg_Assert(m_cell_area.mW > 0 && m_cell_area.mL > 0);
|
||
|
|
||
|
// reposition all contained pieces relative to center bottom
|
||
|
for (uint i = 0; i < m_num_used_entries; i++)
|
||
|
{
|
||
|
CClonedPiece *p_piece = get_desc_at_index(i).mpPiece->CastToCClonedPiece();
|
||
|
|
||
|
//Mth::Vector piece_dims = p_piece->GetDims();
|
||
|
p_piece->m_pos[X] = p_piece->m_pos.GetX() - min_pos.GetX() - my_dims.GetX() / 2.0f;
|
||
|
p_piece->m_pos[Z] = p_piece->m_pos.GetZ() - min_pos.GetZ() - my_dims.GetZ() / 2.0f;
|
||
|
p_piece->m_pos[Y] = p_piece->m_pos.GetY(); // - min_pos.GetY();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
Called by lock()
|
||
|
*/
|
||
|
void CConcreteMetaPiece::get_max_min_world_coords(Mth::Vector &max, Mth::Vector &min)
|
||
|
{
|
||
|
min.Set(100000.0f, 100000.0f, 100000.0f, 0.0f);
|
||
|
max.Set(-100000.0f, -100000.0f, -100000.0f, 0.0f);
|
||
|
|
||
|
for (uint i = 0; i < m_num_used_entries; i++)
|
||
|
{
|
||
|
CClonedPiece *p_piece = get_desc_at_index(i).mpPiece->CastToCClonedPiece();
|
||
|
|
||
|
Mth::Vector piece_dims = p_piece->GetDims();
|
||
|
Mth::Vector piece_pos = p_piece->GetPos();
|
||
|
|
||
|
if (piece_pos.GetX() - piece_dims.GetX() / 2.0f < min.GetX())
|
||
|
min[X] = piece_pos.GetX() - piece_dims.GetX() / 2.0f;
|
||
|
if (piece_pos.GetX() + piece_dims.GetX() / 2.0f > max.GetX())
|
||
|
max[X] = piece_pos.GetX() + piece_dims.GetX() / 2.0f;
|
||
|
|
||
|
if (piece_pos.GetZ() - piece_dims.GetZ() / 2.0f < min.GetZ())
|
||
|
min[Z] = piece_pos.GetZ() - piece_dims.GetZ() / 2.0f;
|
||
|
if (piece_pos.GetZ() + piece_dims.GetZ() / 2.0f > max.GetZ())
|
||
|
max[Z] = piece_pos.GetZ() + piece_dims.GetZ() / 2.0f;
|
||
|
|
||
|
if (piece_pos.GetY() < min.GetY())
|
||
|
min[Y] = piece_pos.GetY();
|
||
|
if (piece_pos.GetY() + piece_dims.GetY() > max.GetY())
|
||
|
max[Y] = piece_pos.GetY() + piece_dims.GetY();
|
||
|
}
|
||
|
|
||
|
//Dbg_Assert(max[X] - min[X] > 1.0f && max[Z] - min[Z] > 1.0f);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
Determines if overlap between specified area of park and this metapiece.
|
||
|
|
||
|
If excludeRisers set, then we ignore overlaps with contained CPieces that are risers.
|
||
|
*/
|
||
|
bool CConcreteMetaPiece::test_for_conflict(GridDims area, bool excludeRisers)
|
||
|
{
|
||
|
// for now, we simply see if this metapiece overlaps with the area
|
||
|
// later, we may add code that tests against contained pieces
|
||
|
|
||
|
Dbg_Assert(m_cell_area.GetW() > 0 && m_cell_area.GetL() > 0 && m_cell_area.GetH() > 0);
|
||
|
Dbg_MsgAssert(area.GetW() > 0 && area.GetL() > 0 && area.GetH() > 0, ("invalid dimensions (%d,%d,%d)",
|
||
|
area.GetW(), area.GetW(), area.GetL()));
|
||
|
|
||
|
// do quick test
|
||
|
|
||
|
if (m_cell_area.GetX() + m_cell_area.GetW() <= area.GetX())
|
||
|
return false;
|
||
|
if (m_cell_area.GetX() >= area.GetX() + area.GetW())
|
||
|
return false;
|
||
|
if (m_cell_area.GetY() + m_cell_area.GetH() <= area.GetY())
|
||
|
return false;
|
||
|
if (m_cell_area.GetY() >= area.GetY() + area.GetH())
|
||
|
return false;
|
||
|
if (m_cell_area.GetZ() + m_cell_area.GetL() <= area.GetZ())
|
||
|
return false;
|
||
|
if (m_cell_area.GetZ() >= area.GetZ() + area.GetL())
|
||
|
return false;
|
||
|
|
||
|
bool contains_risers = false;
|
||
|
if (excludeRisers)
|
||
|
{
|
||
|
for (uint i = 0; i < m_num_used_entries; i++)
|
||
|
{
|
||
|
SMetaDescriptor &desc = get_desc_at_index(i);
|
||
|
if (desc.mRiser) contains_risers = true;
|
||
|
}
|
||
|
}
|
||
|
// '|| if !excludeRisers' is implicit
|
||
|
if (!contains_risers) return true;
|
||
|
|
||
|
for (uint i = 0; i < m_num_used_entries; i++)
|
||
|
{
|
||
|
SMetaDescriptor &desc = get_desc_at_index(i);
|
||
|
CClonedPiece *p_piece = GetContainedPiece(i)->CastToCClonedPiece();
|
||
|
GridDims piece_area;
|
||
|
p_piece->GetCellDims(&piece_area);
|
||
|
piece_area[X] = m_cell_area.GetX() + desc.mX;
|
||
|
piece_area[Y] = m_cell_area.GetY() + desc.mY;
|
||
|
piece_area[Z] = m_cell_area.GetZ() + desc.mZ;
|
||
|
|
||
|
if (!desc.mRiser &&
|
||
|
piece_area.GetX() + piece_area.GetW() > area.GetX() &&
|
||
|
piece_area.GetY() + piece_area.GetH() > area.GetY() &&
|
||
|
piece_area.GetZ() + piece_area.GetL() > area.GetZ() &&
|
||
|
piece_area.GetX() < area.GetX() + area.GetW() &&
|
||
|
piece_area.GetY() < area.GetY() + area.GetH() &&
|
||
|
piece_area.GetZ() < area.GetZ() + area.GetL())
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
See comments with original declaration.
|
||
|
|
||
|
It is fine if pPiece has been rotated already.
|
||
|
*/
|
||
|
void CConcreteMetaPiece::add_piece(CPiece *pPiece, GridDims *pPos, Mth::ERot90 rot, bool isRiser)
|
||
|
{
|
||
|
Dbg_Assert(pPiece);
|
||
|
Dbg_MsgAssert(!(pPiece->GetFlags() & CPiece::mIN_WORLD), ("piece already in world"));
|
||
|
|
||
|
CClonedPiece *p_cloned = pPiece->CastToCClonedPiece();
|
||
|
#ifdef __NOPT_ASSERT__
|
||
|
if (m_num_used_entries > 0)
|
||
|
{
|
||
|
if (get_desc_at_index(0).mpPiece->GetFlags() & CPiece::mSOFT_PIECE)
|
||
|
{
|
||
|
Dbg_MsgAssert(pPiece->GetFlags() & CPiece::mSOFT_PIECE, ("must be a soft piece"));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Dbg_MsgAssert(!(pPiece->GetFlags() & CPiece::mSOFT_PIECE), ("must be a hard piece"));
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
Dbg_MsgAssert(m_num_used_entries < m_total_entries, ("out of entries"));
|
||
|
SMetaDescriptor &desc = get_desc_at_index(m_num_used_entries++);
|
||
|
|
||
|
// Set position relative to northwest bottom of piece. For now.
|
||
|
Mth::Vector piece_dims = p_cloned->GetDims();
|
||
|
Mth::Vector desired_pos;
|
||
|
desired_pos.Set(pPos->GetX() * CParkGenerator::CELL_WIDTH + piece_dims.GetX() / 2.0f,
|
||
|
pPos->GetY() * CParkGenerator::CELL_HEIGHT, // + piece_dims.GetY() / 2.0f,
|
||
|
pPos->GetZ() * CParkGenerator::CELL_LENGTH + piece_dims.GetZ() / 2.0f);
|
||
|
p_cloned->SetDesiredPos(desired_pos, CClonedPiece::MARKER_ONLY);
|
||
|
|
||
|
desc.mpPiece = p_cloned;
|
||
|
desc.mX = pPos->GetX();
|
||
|
desc.mY = pPos->GetY();
|
||
|
desc.mZ = pPos->GetZ();
|
||
|
desc.mRot = rot;
|
||
|
desc.mRiser = isRiser ? 1 : 0;
|
||
|
|
||
|
/*
|
||
|
if (isRiser)
|
||
|
{
|
||
|
printf("hoogaboog 2 (%d,%d,%d), desc.mRiser is %d, desc.mRiser at 0x%x, index %d\n",
|
||
|
desc.mX, desc.mY, desc.mZ, desc.mRiser, &desc.mRiser, m_num_used_entries-1);
|
||
|
}
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
CAbstractMetaPiece::CAbstractMetaPiece()
|
||
|
{
|
||
|
m_flags = EFlags(m_flags | mABSTRACT_META);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
CPiece *CAbstractMetaPiece::GetContainedPiece(int index)
|
||
|
{
|
||
|
if ((uint) index >= m_num_used_entries || index < 0)
|
||
|
return NULL;
|
||
|
|
||
|
CPiece *p_piece = CParkManager::sInstance()->GetGenerator()->GetMasterPiece(get_desc_at_index(index).mPieceName);
|
||
|
Dbg_Assert(p_piece);
|
||
|
return p_piece;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
See comments with original declaration. It is fine if pPiece has been rotated already.
|
||
|
|
||
|
Automatically changes stored cell WHL dimensions of metapiece to include new addition.
|
||
|
*/
|
||
|
void CAbstractMetaPiece::add_piece(CPiece *pPiece, GridDims *pPos, Mth::ERot90 rot, bool isRiser)
|
||
|
{
|
||
|
Dbg_Assert(pPiece);
|
||
|
CSourcePiece *p_source = NULL;
|
||
|
if (pPiece->GetFlags() & CPiece::mSOURCE_PIECE)
|
||
|
p_source = pPiece->CastToCSourcePiece();
|
||
|
if (!p_source)
|
||
|
Dbg_MsgAssert(0, ("not supported yet"));
|
||
|
|
||
|
Dbg_MsgAssert(m_num_used_entries < m_total_entries, ("out of entries"));
|
||
|
SMetaDescriptor &desc = get_desc_at_index(m_num_used_entries++);
|
||
|
|
||
|
if (p_source)
|
||
|
{
|
||
|
desc.mX = pPos->GetX();
|
||
|
desc.mY = pPos->GetY();
|
||
|
desc.mZ = pPos->GetZ();
|
||
|
desc.mRot = rot;
|
||
|
desc.mRiser = (uint8) isRiser;
|
||
|
desc.mPieceName = p_source->GetType();
|
||
|
|
||
|
int highest_x = pPos->GetX() + pPos->GetW();
|
||
|
int highest_y = pPos->GetY() + pPos->GetH();
|
||
|
int highest_z = pPos->GetZ() + pPos->GetL();
|
||
|
|
||
|
uint8 current_w = m_cell_area.GetW();
|
||
|
uint8 current_h = m_cell_area.GetH();
|
||
|
uint8 current_l = m_cell_area.GetL();
|
||
|
|
||
|
if (highest_x > current_w)
|
||
|
current_w = highest_x;
|
||
|
if (highest_y > current_h)
|
||
|
current_h = highest_y;
|
||
|
if (highest_z > current_l)
|
||
|
current_l = highest_z;
|
||
|
|
||
|
m_cell_area.SetWHL(current_w, current_h, current_l);
|
||
|
if (m_cell_area[H] < 1) m_cell_area[H] = 1;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
if (isRiser)
|
||
|
{
|
||
|
printf("hoogaboog 1 (%d,%d,%d), index %d\n", desc.mX, desc.mY, desc.mZ, m_num_used_entries-1);
|
||
|
}
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void CAbstractMetaPiece::add_piece_dumb(CAbstractMetaPiece *pMeta, GridDims *pPos, Mth::ERot90 rot, bool isRiser)
|
||
|
{
|
||
|
Dbg_MsgAssert(m_num_used_entries < m_total_entries, ("out of entries"));
|
||
|
SMetaDescriptor &desc = get_desc_at_index(m_num_used_entries++);
|
||
|
|
||
|
if (pMeta)
|
||
|
{
|
||
|
desc.mX = pPos->GetX();
|
||
|
desc.mY = pPos->GetY();
|
||
|
desc.mZ = pPos->GetZ();
|
||
|
desc.mRot = rot;
|
||
|
desc.mRiser = (uint8) isRiser;
|
||
|
desc.mPieceName = pMeta->GetNameChecksum();
|
||
|
|
||
|
int highest_x = pPos->GetX() + pPos->GetW();
|
||
|
int highest_y = pPos->GetY() + pPos->GetH();
|
||
|
int highest_z = pPos->GetZ() + pPos->GetL();
|
||
|
|
||
|
uint8 current_w = m_cell_area.GetW();
|
||
|
uint8 current_h = m_cell_area.GetH();
|
||
|
uint8 current_l = m_cell_area.GetL();
|
||
|
|
||
|
if (highest_x > current_w)
|
||
|
current_w = highest_x;
|
||
|
if (highest_y > current_h)
|
||
|
current_h = highest_y;
|
||
|
if (highest_z > current_l)
|
||
|
current_l = highest_z;
|
||
|
|
||
|
m_cell_area.SetWHL(current_w, current_h, current_l);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
if (isRiser)
|
||
|
{
|
||
|
printf("hoogaboog 1 (%d,%d,%d), index %d\n", desc.mX, desc.mY, desc.mZ, m_num_used_entries-1);
|
||
|
}
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
SMetaDescriptor CAbstractMetaPiece::get_desc_with_expansion(int index)
|
||
|
{
|
||
|
#if 1
|
||
|
int count = 0;
|
||
|
for (uint j = 0; j < m_num_used_entries; j++)
|
||
|
{
|
||
|
SMetaDescriptor &outer_desc = get_desc_at_index(j);
|
||
|
|
||
|
CAbstractMetaPiece *p_contained_meta = CParkManager::sInstance()->GetAbstractMeta(outer_desc.mPieceName);
|
||
|
if (p_contained_meta->m_flags & CMetaPiece::mSINGULAR)
|
||
|
{
|
||
|
if (count == index)
|
||
|
return outer_desc;
|
||
|
count++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for (uint i = 0; i < p_contained_meta->m_num_used_entries; i++)
|
||
|
{
|
||
|
SMetaDescriptor &inner_desc = p_contained_meta->get_desc_at_index(i);
|
||
|
if (count == index)
|
||
|
{
|
||
|
SMetaDescriptor ret_desc = inner_desc;
|
||
|
ret_desc.mPieceName = inner_desc.mPieceName;
|
||
|
ret_desc.mRot = inner_desc.mRot + outer_desc.mRot;
|
||
|
|
||
|
GridDims outer_dims = GetArea();
|
||
|
|
||
|
GridDims inner_dims = p_contained_meta->GetArea();
|
||
|
|
||
|
ret_desc.mX = outer_desc.mX;
|
||
|
ret_desc.mZ = outer_desc.mZ;
|
||
|
ret_desc.mY = outer_desc.mY + inner_desc.mY;
|
||
|
|
||
|
switch(outer_desc.mRot)
|
||
|
{
|
||
|
case Mth::ROT_0:
|
||
|
ret_desc.mX += inner_desc.mX;
|
||
|
ret_desc.mZ += inner_desc.mZ;
|
||
|
break;
|
||
|
case Mth::ROT_90:
|
||
|
ret_desc.mX += inner_desc.mZ;
|
||
|
ret_desc.mZ += outer_dims.GetW() - inner_desc.mX - inner_dims.GetW();
|
||
|
break;
|
||
|
case Mth::ROT_180:
|
||
|
ret_desc.mX += outer_dims.GetW() - inner_desc.mX - inner_dims.GetW();
|
||
|
ret_desc.mZ += outer_dims.GetL() - inner_desc.mZ - inner_dims.GetL();
|
||
|
break;
|
||
|
case Mth::ROT_270:
|
||
|
ret_desc.mX += outer_dims.GetL() - inner_desc.mZ - inner_dims.GetL();
|
||
|
ret_desc.mZ += inner_desc.mX;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return ret_desc;
|
||
|
}
|
||
|
count++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
Dbg_MsgAssert(0, ("what the bloody 'ell?"));
|
||
|
SMetaDescriptor dumb;
|
||
|
return dumb;
|
||
|
#else
|
||
|
return get_desc_at_index(index);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
int CAbstractMetaPiece::count_descriptors_expanded()
|
||
|
{
|
||
|
#if 1
|
||
|
int count = 0;
|
||
|
for (uint j = 0; j < m_num_used_entries; j++)
|
||
|
{
|
||
|
SMetaDescriptor &outer_desc = get_desc_at_index(j);
|
||
|
|
||
|
CAbstractMetaPiece *p_contained_meta = CParkManager::sInstance()->GetAbstractMeta(outer_desc.mPieceName);
|
||
|
Dbg_MsgAssert(p_contained_meta, ("couldn't find metapiece %s", Script::FindChecksumName(outer_desc.mPieceName)));
|
||
|
if (p_contained_meta->m_flags & CMetaPiece::mSINGULAR)
|
||
|
{
|
||
|
count++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for (uint i = 0; i < p_contained_meta->m_num_used_entries; i++)
|
||
|
{
|
||
|
count++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return count;
|
||
|
#else
|
||
|
return m_num_used_entries;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
CMetaPiece *CMapListNode::GetMeta()
|
||
|
{
|
||
|
Dbg_Assert(this);
|
||
|
Dbg_MsgAssert(((uint32)this) != 0x03030303,("Bad CMapListNode pointer ! (0x03030303)"));
|
||
|
Dbg_MsgAssert(((uint32)this) != 0x55555555,("Bad CMapListNode pointer ! (0x55555555)"));
|
||
|
Dbg_Assert(mp_meta);
|
||
|
return mp_meta;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void CMapListNode::DestroyList()
|
||
|
{
|
||
|
CMapListNode *p_node = this;
|
||
|
while (p_node)
|
||
|
{
|
||
|
CMapListNode *p_next_node = p_node->mp_next;
|
||
|
delete p_node;
|
||
|
p_node = p_next_node;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void CMapListNode::VerifyIntegrity()
|
||
|
{
|
||
|
CMapListNode *p_outer_node = this;
|
||
|
while (p_outer_node)
|
||
|
{
|
||
|
CMapListNode *p_inner_node = p_outer_node->mp_next;
|
||
|
while (p_inner_node)
|
||
|
{
|
||
|
Dbg_Assert(p_inner_node->GetMeta() != p_outer_node->GetMeta());
|
||
|
p_inner_node = p_inner_node->mp_next;
|
||
|
}
|
||
|
p_outer_node = p_outer_node->mp_next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
CMapListTemp::CMapListTemp(CMapListNode *p_list)
|
||
|
{
|
||
|
mp_list = p_list;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
CMapListTemp::~CMapListTemp()
|
||
|
{
|
||
|
if (mp_list)
|
||
|
mp_list->DestroyList();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
CMapListNode *CMapListTemp::GetList()
|
||
|
{
|
||
|
return mp_list;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void CMapListTemp::PrintContents()
|
||
|
{
|
||
|
printf("contents of map list:\n");
|
||
|
CMapListNode *p_node = mp_list;
|
||
|
while(p_node)
|
||
|
{
|
||
|
printf(" address=%p area=", p_node->GetMeta());
|
||
|
p_node->GetMeta()->GetArea().PrintContents();
|
||
|
p_node = p_node->GetNext();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
CParkManager::CParkManager()
|
||
|
{
|
||
|
mp_generator = new CParkGenerator();
|
||
|
|
||
|
mp_concrete_metapiece_list = NULL;
|
||
|
mp_abstract_metapiece_list = NULL;
|
||
|
m_num_concrete_metapieces = 0;
|
||
|
m_num_general_concrete_metapieces = 0;
|
||
|
m_dma_piece_count = 0;
|
||
|
m_num_abstract_metapieces = 0;
|
||
|
|
||
|
m_floor_height_map = NULL;
|
||
|
|
||
|
for (int i = 0; i < FLOOR_MAX_WIDTH; i++)
|
||
|
for (int j = 0; j < FLOOR_MAX_LENGTH; j++)
|
||
|
mp_bucket_list[i][j] = NULL;
|
||
|
|
||
|
m_state_on = false;
|
||
|
|
||
|
sp_instance = this;
|
||
|
|
||
|
mp_compressed_map_buffer = new uint8[COMPRESSED_MAP_SIZE];
|
||
|
m_compressed_map_flags = mNO_FLAGS;
|
||
|
m_park_is_valid = false;
|
||
|
|
||
|
mp_gap_manager = NULL;
|
||
|
|
||
|
for (int i = 0; i < NUM_RISER_INFO_SLOTS; i++)
|
||
|
{
|
||
|
char name0[128];
|
||
|
sprintf(name0, "floor_wall_block%d", i+1);
|
||
|
m_riser_piece_checksum[i][0] = Script::GenerateCRC(name0);
|
||
|
|
||
|
char name1[128];
|
||
|
sprintf(name1, "wall_block%d", i+1);
|
||
|
m_riser_piece_checksum[i][1] = Script::GenerateCRC(name1);
|
||
|
|
||
|
char name2[128];
|
||
|
sprintf(name2, "floor_block%d", i+1);
|
||
|
m_riser_piece_checksum[i][2] = Script::GenerateCRC(name2);
|
||
|
}
|
||
|
|
||
|
m_theme = 0;
|
||
|
|
||
|
// Mick: Create a compressed map buffer, equivalent to an empty park
|
||
|
fake_compressed_map_buffer();
|
||
|
|
||
|
mp_column_slide_list = NULL;
|
||
|
|
||
|
mp_park_name[0]=0;
|
||
|
|
||
|
#ifdef USE_BUILD_LIST
|
||
|
m_build_list_size=0;
|
||
|
mp_build_list_entry=NULL;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
CParkManager::~CParkManager()
|
||
|
{
|
||
|
#ifdef USE_BUILD_LIST
|
||
|
if (mp_build_list_entry)
|
||
|
{
|
||
|
#ifndef __USE_EXTERNAL_BUFFER__
|
||
|
Mem::Free(mp_build_list_entry);
|
||
|
#endif
|
||
|
mp_build_list_entry=NULL;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
delete mp_generator;
|
||
|
delete mp_compressed_map_buffer;
|
||
|
|
||
|
sp_instance = NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
Boots up park editor.
|
||
|
|
||
|
-Loads up files needed
|
||
|
-Initializes buffers
|
||
|
-Initializes CParkGenerator module
|
||
|
-Calls Rebuild(), which:
|
||
|
-Clears map
|
||
|
-Generates riser geometry
|
||
|
-Creates piece set database
|
||
|
*/
|
||
|
void CParkManager::Initialize()
|
||
|
{
|
||
|
ParkEd("CParkManager::Initialize()");
|
||
|
|
||
|
if (m_state_on)
|
||
|
return;
|
||
|
m_state_on = true;
|
||
|
|
||
|
|
||
|
Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().TopDownHeap());
|
||
|
Mem::CPoolable<CMapListNode>::SCreatePool(16000, "CMapListNode");
|
||
|
Mem::CPoolable<CMapListNode>::SPrintInfo();
|
||
|
|
||
|
Mem::CPoolable<CClipboardEntry>::SCreatePool(MAX_CLIPBOARD_METAS, "CClipboardEntry");
|
||
|
Mem::CPoolable<CClipboard>::SCreatePool(MAX_CLIPBOARDS, "CClipboard");
|
||
|
Mem::Manager::sHandle().PopContext();
|
||
|
|
||
|
mp_generator->InitializeMasterPieces(MAX_WIDTH, 16, MAX_LENGTH, GetTheme());
|
||
|
mp_generator->ReadInRailInfo();
|
||
|
|
||
|
create_abstract_metapieces();
|
||
|
|
||
|
setup_road_mask();
|
||
|
|
||
|
Dbg_MsgAssert(!m_floor_height_map, ("bad monkey!!!"));
|
||
|
m_floor_height_map = new FloorHeightEntry*[FLOOR_MAX_WIDTH];
|
||
|
for (int i = 0; i < FLOOR_MAX_WIDTH; i++)
|
||
|
{
|
||
|
m_floor_height_map[i] = new FloorHeightEntry[FLOOR_MAX_LENGTH];
|
||
|
for (int j = 0; j < FLOOR_MAX_LENGTH; j++)
|
||
|
{
|
||
|
m_floor_height_map[i][j].mMarkAsSlid = false;
|
||
|
m_floor_height_map[i][j].mSlideAmount = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
setup_default_dimensions();
|
||
|
|
||
|
mp_gap_manager = new CGapManager(this);
|
||
|
|
||
|
RebuildWholePark(false);
|
||
|
|
||
|
Script::CArray *p_set_array = Script::GetArray("Ed_piece_sets", Script::ASSERT);
|
||
|
m_total_sets = p_set_array->GetSize();
|
||
|
Dbg_Assert(m_total_sets <= MAX_SETS);
|
||
|
|
||
|
Script::CArray *p_piece_array = Script::GetArray("Ed_standard_metapieces", Script::ASSERT);
|
||
|
int last_piece_index=p_piece_array->GetSize();
|
||
|
int last_set_index=-1;
|
||
|
|
||
|
for (int s = m_total_sets-1; s >=0 ; --s)
|
||
|
{
|
||
|
Script::CStruct *p_set = p_set_array->GetStructure(s);
|
||
|
|
||
|
m_palette_set[s].mpName = NULL;
|
||
|
p_set->GetText("name", &m_palette_set[s].mpName, Script::ASSERT);
|
||
|
m_palette_set[s].mNameCrc = Script::GenerateCRC(m_palette_set[s].mpName);
|
||
|
m_palette_set[s].mSelectedEntry = 0;
|
||
|
|
||
|
m_palette_set[s].mTotalEntries=0;
|
||
|
|
||
|
uint32 first_checksum;
|
||
|
if (p_set->GetChecksum("first", &first_checksum))
|
||
|
{
|
||
|
int first_index=0;
|
||
|
if (!GetAbstractMeta(first_checksum, &first_index))
|
||
|
{
|
||
|
Dbg_MsgAssert(0, ("couldn't find first-in-set entry"));
|
||
|
}
|
||
|
|
||
|
// make sure index in previous first-in_set_entry is less than this one
|
||
|
if (last_set_index>=0)
|
||
|
{
|
||
|
Dbg_MsgAssert(first_index <
|
||
|
last_piece_index,
|
||
|
("sets %s and %s are out of order in EdPieces2.q",
|
||
|
m_palette_set[s].mpName,
|
||
|
m_palette_set[last_set_index].mpName));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Dbg_MsgAssert(first_index <
|
||
|
last_piece_index,
|
||
|
("set %s has a bad first piece in EdPieces2.q",
|
||
|
m_palette_set[s].mpName));
|
||
|
}
|
||
|
m_palette_set[s].mTotalEntries=last_piece_index-first_index;
|
||
|
last_piece_index=first_index;
|
||
|
last_set_index=s;
|
||
|
|
||
|
// Now that we know the number of entries, create the set.
|
||
|
int entry=first_index;
|
||
|
for (int i=0; i<m_palette_set[s].mTotalEntries; ++i)
|
||
|
{
|
||
|
CAbstractMetaPiece *p_abstract = GetAbstractMetaByIndex(entry);
|
||
|
|
||
|
Dbg_Assert(i < CPieceSet::MAX_ENTRIES);
|
||
|
m_palette_set[s].mEntryTab[i].mNameCrc = p_abstract->GetNameChecksum();
|
||
|
|
||
|
Script::CStruct *p_piece_entry = p_piece_array->GetStructure(entry);
|
||
|
if (!p_piece_entry->GetLocalString("text_name", &m_palette_set[s].mEntryTab[i].mpName))
|
||
|
{
|
||
|
m_palette_set[s].mEntryTab[i].mpName = NULL;
|
||
|
}
|
||
|
|
||
|
++entry;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
m_palette_set[s].mIsClipboardSet=false;
|
||
|
if (p_set->ContainsFlag(CRCD(0x45c6c158,"clipboard_set")))
|
||
|
{
|
||
|
m_palette_set[s].mIsClipboardSet=true;
|
||
|
m_palette_set[s].mTotalEntries=MAX_CLIPBOARDS;
|
||
|
|
||
|
const char *p_clipboard_title=Script::GetString(CRCD(0x4e677220,"ClipboardTitle"));
|
||
|
|
||
|
for (int i=0; i<MAX_CLIPBOARDS; ++i)
|
||
|
{
|
||
|
char p_name[100];
|
||
|
sprintf(p_name,"Clipboard%d",i);
|
||
|
|
||
|
m_palette_set[s].mEntryTab[i].mpName=p_clipboard_title;
|
||
|
m_palette_set[s].mEntryTab[i].mNameCrc=Script::GenerateCRC(p_name);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
m_palette_set[s].mVisible = !p_set->ContainsFlag("hidden");
|
||
|
#ifdef __PLAT_NGC__
|
||
|
if (p_set->ContainsFlag("no_gamecube"))
|
||
|
m_palette_set[s].mVisible = false;
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
float CParkManager::GetClipboardProportionUsed()
|
||
|
{
|
||
|
float proportion_clipboard_entries=((float)Mem::CPoolable<CClipboardEntry>::SGetNumUsedItems())/Mem::CPoolable<CClipboardEntry>::SGetTotalItems();
|
||
|
float proportion_clipboard_slots=((float)Mem::CPoolable<CClipboard>::SGetNumUsedItems())/Mem::CPoolable<CClipboard>::SGetTotalItems();
|
||
|
|
||
|
if (proportion_clipboard_entries > proportion_clipboard_slots)
|
||
|
{
|
||
|
return proportion_clipboard_entries;
|
||
|
}
|
||
|
return proportion_clipboard_slots;
|
||
|
}
|
||
|
|
||
|
// This is just a public version of the private function
|
||
|
// needed so the parks can be saved from within the park editor
|
||
|
// This just updates the contents of the map buffer that will be used
|
||
|
// by the enxt two public functions
|
||
|
void CParkManager::WriteCompressedMapBuffer()
|
||
|
{
|
||
|
if (m_state_on)
|
||
|
write_compressed_map_buffer();
|
||
|
}
|
||
|
|
||
|
uint8* CParkManager::GetCompressedMapBuffer(bool markSaved)
|
||
|
{
|
||
|
/*
|
||
|
The compressed map buffer is valid if:
|
||
|
|
||
|
-The park manager is active AND (in sync with built park OR newer than built park) OR
|
||
|
-The park manager is not active
|
||
|
*/
|
||
|
|
||
|
Dbg_MsgAssert((m_compressed_map_flags & mIS_VALID), ("compressed map buffer not valid"));
|
||
|
if (m_state_on)
|
||
|
{
|
||
|
Dbg_MsgAssert((m_compressed_map_flags & mIN_SYNC_WITH_PARK) || (m_compressed_map_flags & mIS_NEWER_THAN_PARK),
|
||
|
("park has changed, compressed map buffer out of sync"));
|
||
|
}
|
||
|
|
||
|
#ifdef __NOPT_ASSERT__
|
||
|
CompressedMapHeader *p_header = (CompressedMapHeader *) mp_compressed_map_buffer;
|
||
|
Dbg_Printf( "************ NUM METAS: %d\n", p_header->mNumMetas );
|
||
|
#endif // __NOPT_ASSERT__
|
||
|
|
||
|
if (markSaved)
|
||
|
m_compressed_map_flags = ECompressedMapFlags(m_compressed_map_flags & ~mNOT_SAVED_LOCAL);
|
||
|
|
||
|
return mp_compressed_map_buffer;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void CParkManager::SetCompressedMapBuffer( uint8* src_buffer, bool markNotSaved )
|
||
|
{
|
||
|
ParkEd("SetCompressedMapBuffer()");
|
||
|
|
||
|
|
||
|
memcpy( mp_compressed_map_buffer, src_buffer, COMPRESSED_MAP_SIZE );
|
||
|
m_compressed_map_flags = ECompressedMapFlags(m_compressed_map_flags | mIS_VALID);
|
||
|
m_compressed_map_flags = ECompressedMapFlags(m_compressed_map_flags | mIS_NEWER_THAN_PARK);
|
||
|
|
||
|
if (markNotSaved)
|
||
|
m_compressed_map_flags = ECompressedMapFlags(m_compressed_map_flags | mNOT_SAVED_LOCAL);
|
||
|
|
||
|
#ifdef __NOPT_ASSERT__
|
||
|
CompressedMapHeader *p_header = (CompressedMapHeader *) mp_compressed_map_buffer;
|
||
|
//uint32 checksum=Crc::GenerateCRCCaseSensitive((const char*)mp_compressed_map_buffer+4,COMPRESSED_MAP_SIZE-4);
|
||
|
//Dbg_MsgAssert(checksum==p_header->mChecksum,("Park editor buffer checksum mismatch !"));
|
||
|
|
||
|
Dbg_Printf( "************ NUM METAS: %d\n", p_header->mNumMetas );
|
||
|
#endif // __NOPT_ASSERT__
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
bool CParkManager::IsMapSavedLocally()
|
||
|
{
|
||
|
if ((!(m_compressed_map_flags & mIN_SYNC_WITH_PARK) && !(m_compressed_map_flags & mIS_NEWER_THAN_PARK)) ||
|
||
|
(m_compressed_map_flags & mNOT_SAVED_LOCAL))
|
||
|
return false;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
void CParkManager::WriteIntoStructure(Script::CStruct *p_struct)
|
||
|
{
|
||
|
WriteCompressedMapBuffer(); // Ensure map buffer is correct
|
||
|
uint32 *p_map_buffer = (uint32*) GetCompressedMapBuffer(true);
|
||
|
int size = COMPRESSED_MAP_SIZE ;
|
||
|
|
||
|
// create the array
|
||
|
Script::CArray *p_map=new Script::CArray;
|
||
|
p_map->SetArrayType(size/4,ESYMBOLTYPE_INTEGER);
|
||
|
// copy the park editor into it
|
||
|
for (int i=0;i<size/4;i++)
|
||
|
{
|
||
|
p_map->SetInteger(i,p_map_buffer[i]);
|
||
|
}
|
||
|
|
||
|
// append it to p_struct
|
||
|
p_struct->AddArrayPointer(CRCD(0x337c5289,"Park_editor_map"),p_map);
|
||
|
|
||
|
// Now also add in any created goals, so that the goals do not have to saved out to a separate file.
|
||
|
Script::CStruct *p_goals_struct=new Script::CStruct;
|
||
|
|
||
|
Obj::CGoalEditorComponent *p_goal_editor=Obj::GetGoalEditor();
|
||
|
Dbg_MsgAssert(p_goal_editor,("No goal editor component ???"));
|
||
|
p_goal_editor->WriteIntoStructure(CRCD(0xe8b4b836,"Load_Sk5Ed"),p_goals_struct);
|
||
|
|
||
|
|
||
|
p_struct->AddStructurePointer(CRCD(0xd8eb825e,"Park_editor_goals"),p_goals_struct);
|
||
|
|
||
|
// Add in the created rails.
|
||
|
Obj::GetRailEditor()->WriteIntoStructure(p_struct);
|
||
|
|
||
|
p_struct->AddInteger(CRCD(0xb7e39b53,"MaxPlayers"),GetGenerator()->GetMaxPlayers());
|
||
|
}
|
||
|
|
||
|
#ifdef __PLAT_NGC__
|
||
|
void CParkManager::ReadFromStructure(Script::CStruct *p_struct, bool do_post_mem_card_load, bool preMadePark)
|
||
|
#else
|
||
|
void CParkManager::ReadFromStructure(Script::CStruct *p_struct, bool do_post_mem_card_load)
|
||
|
#endif
|
||
|
{
|
||
|
Obj::CGoalEditorComponent *p_goal_editor=Obj::GetGoalEditor();
|
||
|
Dbg_MsgAssert(p_goal_editor,("No goal editor component ???"));
|
||
|
|
||
|
p_goal_editor->ClearOnlyParkGoals();
|
||
|
|
||
|
// Read in any created goals.
|
||
|
Script::CStruct *p_goals_struct=NULL;
|
||
|
if (p_struct->GetStructure(CRCD(0xd8eb825e,"Park_editor_goals"),&p_goals_struct))
|
||
|
{
|
||
|
p_goal_editor->ReadFromStructure(p_goals_struct,Obj::CGoalEditorComponent::LOADING_PARK_GOALS);
|
||
|
}
|
||
|
|
||
|
// Read in the created rails
|
||
|
Spt::SingletonPtr<Ed::CParkEditor> p_park_ed;
|
||
|
if (!p_park_ed->EditingCustomPark())
|
||
|
{
|
||
|
// Do not call UpdateSuperSectors after deleting any existing rails if playing a park,
|
||
|
// otherwise the entire park will disappear from under the skater due to all the sectors
|
||
|
// having been flagged for deletion.
|
||
|
Obj::CRailEditorComponent::sUpdateSuperSectorsAfterDeletingRailSectors=false;
|
||
|
}
|
||
|
Obj::GetRailEditor()->ReadFromStructure(p_struct);
|
||
|
Obj::CRailEditorComponent::sUpdateSuperSectorsAfterDeletingRailSectors=true;
|
||
|
|
||
|
int max_players=2;
|
||
|
p_struct->GetInteger(CRCD(0xb7e39b53,"MaxPlayers"),&max_players);
|
||
|
Ed::CParkManager::Instance()->GetGenerator()->SetMaxPlayers(max_players);
|
||
|
|
||
|
int old_theme = GetTheme();
|
||
|
WriteCompressedMapBuffer();
|
||
|
uint32 *p_map_buffer = (uint32*) GetCompressedMapBuffer();
|
||
|
int size = Ed::CParkManager::COMPRESSED_MAP_SIZE ;
|
||
|
// get the array
|
||
|
Script::CArray *p_map=NULL;
|
||
|
if (p_struct->GetArray("Park_editor_map",&p_map,true))
|
||
|
{
|
||
|
// copy the park editor map from structure to buffer
|
||
|
for (int i=0;i<size/4;i++)
|
||
|
{
|
||
|
#ifdef __PLAT_NGC__
|
||
|
if (preMadePark)
|
||
|
{
|
||
|
uint32 v=p_map->GetInteger(i);
|
||
|
p_map_buffer[i] = ((v>>24) | (((v>>16)&0xff)<<8) | (((v>>8)&0xff)<<16) | ((v&0xff)<<24));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
p_map_buffer[i] = p_map->GetInteger(i);
|
||
|
}
|
||
|
#else
|
||
|
p_map_buffer[i] = p_map->GetInteger(i);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
#ifdef __PLAT_NGC__
|
||
|
if (preMadePark)
|
||
|
{
|
||
|
// If loading a pre-made park, it will need the map buffer endianness swapped since
|
||
|
// it was saved from the PS2.
|
||
|
SwapMapBufferEndianness();
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if (do_post_mem_card_load)
|
||
|
{
|
||
|
Spt::SingletonPtr<Ed::CParkEditor> p_park_ed;
|
||
|
p_park_ed->PostMemoryCardLoad((uint8*) p_map_buffer, old_theme);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int CParkManager::GetTheme()
|
||
|
{
|
||
|
if (m_compressed_map_flags & mIS_VALID)
|
||
|
{
|
||
|
int theme = (((CompressedMapHeader *) mp_compressed_map_buffer)->mTheme);
|
||
|
Dbg_MsgAssert(theme >= 0 && theme <= MAX_THEMES, ("nonsense theme %d", theme));
|
||
|
return theme;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void CParkManager::SetTheme(int theme)
|
||
|
{
|
||
|
Dbg_MsgAssert(theme >= 0 && theme < MAX_THEMES , ("nonsense theme %d", theme));
|
||
|
m_theme = theme;
|
||
|
write_compressed_map_buffer();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
const char *CParkManager::GetParkName()
|
||
|
{
|
||
|
if (mp_compressed_map_buffer && ((CompressedMapHeader *) mp_compressed_map_buffer)->mVersion == (VERSION))
|
||
|
return ((CompressedMapHeader *) mp_compressed_map_buffer)->mParkName;
|
||
|
else
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
uint32 CParkManager::GetParkChecksum()
|
||
|
{
|
||
|
if (mp_compressed_map_buffer && ((CompressedMapHeader *) mp_compressed_map_buffer)->mVersion == (VERSION))
|
||
|
return ((CompressedMapHeader *) mp_compressed_map_buffer)->mChecksum;
|
||
|
else
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int CParkManager::GetCompressedParkWidth()
|
||
|
{
|
||
|
if (mp_compressed_map_buffer && ((CompressedMapHeader *) mp_compressed_map_buffer)->mVersion == (VERSION))
|
||
|
return ((CompressedMapHeader *) mp_compressed_map_buffer)->mW;
|
||
|
else
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int CParkManager::GetCompressedParkLength()
|
||
|
{
|
||
|
if (mp_compressed_map_buffer && ((CompressedMapHeader *) mp_compressed_map_buffer)->mVersion == (VERSION))
|
||
|
return ((CompressedMapHeader *) mp_compressed_map_buffer)->mL;
|
||
|
else
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
void CParkManager::SetParkName(const char *pName)
|
||
|
{
|
||
|
if (!mp_compressed_map_buffer || ((CompressedMapHeader *) mp_compressed_map_buffer)->mVersion != (VERSION)) return;
|
||
|
Dbg_Assert(pName);
|
||
|
Dbg_MsgAssert(strlen(pName) < 64, ("park name too long"));
|
||
|
strcpy(((CompressedMapHeader *) mp_compressed_map_buffer)->mParkName, pName);
|
||
|
strcpy(mp_park_name, pName);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void CParkManager::AccessDisk(bool save, int fileSlot)
|
||
|
{
|
||
|
char fullname[64];
|
||
|
sprintf(fullname, "CustomParks\\custom%d.prk", fileSlot);
|
||
|
|
||
|
if (save)
|
||
|
{
|
||
|
// Ryan("I am saving park %s\n", fullname);
|
||
|
// printf("I am saving park %s\n", fullname);
|
||
|
|
||
|
Script::CStruct *p_struct=new Script::CStruct;
|
||
|
WriteIntoStructure(p_struct);
|
||
|
uint32 size=Script::CalculateBufferSize(p_struct);
|
||
|
uint8 *p_buffer=(uint8*)Mem::Malloc(size);
|
||
|
Script::WriteToBuffer(p_struct,p_buffer,size);
|
||
|
|
||
|
void *fp = File::Open(fullname, "wb");
|
||
|
Dbg_MsgAssert(fp, ("failed to open file %s for write", fullname));
|
||
|
File::Write(p_buffer, size, 1, fp);
|
||
|
File::Close(fp);
|
||
|
|
||
|
Mem::Free(p_buffer);
|
||
|
delete p_struct;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Ryan("I am loading park %s\n", fullname);
|
||
|
// printf("I am loading park %s\n", fullname);
|
||
|
void *fp = File::Open(fullname, "rb");
|
||
|
Dbg_MsgAssert(fp, ("failed to open file %s for read", fullname));
|
||
|
|
||
|
int size=File::GetFileSize(fp);
|
||
|
|
||
|
uint8 *p_buffer=(uint8*)Mem::Malloc(size);
|
||
|
|
||
|
File::Read(p_buffer, size, 1, fp);
|
||
|
File::Close(fp);
|
||
|
|
||
|
Script::CStruct *p_struct=new Script::CStruct;
|
||
|
Script::ReadFromBuffer(p_struct,p_buffer);
|
||
|
Mem::Free(p_buffer);
|
||
|
|
||
|
#ifdef __PLAT_NGC__
|
||
|
ReadFromStructure(p_struct,false,true);
|
||
|
#else
|
||
|
ReadFromStructure(p_struct,false);
|
||
|
#endif
|
||
|
|
||
|
delete p_struct;
|
||
|
|
||
|
m_compressed_map_flags = ECompressedMapFlags(m_compressed_map_flags | (mIS_NEWER_THAN_PARK + mIS_VALID));
|
||
|
m_compressed_map_flags = ECompressedMapFlags(m_compressed_map_flags & ~mIN_SYNC_WITH_PARK);
|
||
|
m_compressed_map_flags = ECompressedMapFlags(m_compressed_map_flags & ~mNOT_SAVED_LOCAL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
Destroys everything, concrete metas, abstract metas, floor map.
|
||
|
*/
|
||
|
// K: Added type so that DESTROY_ONLY_PIECES can be passed when this function is used to clean
|
||
|
// up the park editor heap for deletion when playing a park.
|
||
|
void CParkManager::Destroy(CParkGenerator::EDestroyType type)
|
||
|
{
|
||
|
ParkEd("CParkManager::Destroy(), m_compressed_map_flags=%08x", m_compressed_map_flags);
|
||
|
|
||
|
if (!m_state_on)
|
||
|
return;
|
||
|
|
||
|
if (!(m_compressed_map_flags & mIN_SYNC_WITH_PARK) && !(m_compressed_map_flags & mIS_NEWER_THAN_PARK))
|
||
|
{
|
||
|
write_compressed_map_buffer();
|
||
|
}
|
||
|
|
||
|
Dbg_Assert(mp_gap_manager);
|
||
|
mp_gap_manager->RemoveAllGaps();
|
||
|
|
||
|
// remove all abstract metapieces
|
||
|
CMapListNode *p_node = NULL;
|
||
|
while((p_node = mp_abstract_metapiece_list))
|
||
|
{
|
||
|
CMetaPiece *p_meta = p_node->GetMeta();
|
||
|
remove_metapiece_from_node_list(p_meta, &mp_abstract_metapiece_list);
|
||
|
delete p_meta;
|
||
|
}
|
||
|
m_num_abstract_metapieces = 0;
|
||
|
|
||
|
destroy_concrete_metapieces(type);
|
||
|
|
||
|
mp_generator->UnloadMasterPieces();
|
||
|
mp_generator->DestroyRailInfo(); // info from node array (mostly rails)
|
||
|
|
||
|
Dbg_MsgAssert(m_floor_height_map, ("bad bad monkey!!!"));
|
||
|
for (int i = 0; i < FLOOR_MAX_WIDTH; i++)
|
||
|
delete [] m_floor_height_map[i];
|
||
|
delete [] m_floor_height_map;
|
||
|
m_floor_height_map = NULL;
|
||
|
|
||
|
m_state_on = false;
|
||
|
// since park is destroyed, buffer is out of sync and newer than park
|
||
|
m_compressed_map_flags = ECompressedMapFlags(m_compressed_map_flags & ~mIN_SYNC_WITH_PARK);
|
||
|
m_compressed_map_flags = ECompressedMapFlags(m_compressed_map_flags | mIS_NEWER_THAN_PARK);
|
||
|
m_park_is_valid = false;
|
||
|
|
||
|
Dbg_Assert(mp_gap_manager);
|
||
|
delete mp_gap_manager;
|
||
|
mp_gap_manager = NULL;
|
||
|
|
||
|
if (mp_column_slide_list)
|
||
|
mp_column_slide_list->DestroyList();
|
||
|
mp_column_slide_list = NULL;
|
||
|
|
||
|
Mem::CPoolable<CClipboard>::SRemovePool();
|
||
|
Mem::CPoolable<CClipboardEntry>::SRemovePool();
|
||
|
Mem::CPoolable<CMapListNode>::SRemovePool();
|
||
|
}
|
||
|
|
||
|
|
||
|
void CParkManager::RebuildWholePark(bool clearPark)
|
||
|
{
|
||
|
ParkEd("CParkManager::RebuildWholePark() 0x%x", m_compressed_map_flags);
|
||
|
|
||
|
setup_lighting(); // ensure light arrays are correct for current theme
|
||
|
|
||
|
Dbg_Assert(m_state_on);
|
||
|
|
||
|
if (!(m_compressed_map_flags & mIN_SYNC_WITH_PARK) &&
|
||
|
!(m_compressed_map_flags & mIS_NEWER_THAN_PARK) &&
|
||
|
m_park_is_valid)
|
||
|
{
|
||
|
//Ryan("writing compressed map buffer\n");
|
||
|
write_compressed_map_buffer();
|
||
|
}
|
||
|
|
||
|
Dbg_Printf( "************* Rebuilding whole park : %d\n", (int) clearPark );
|
||
|
destroy_concrete_metapieces(CParkGenerator::DESTROY_PIECES_AND_SECTORS);
|
||
|
mp_generator->GenerateCollisionInfo(false);
|
||
|
|
||
|
if (clearPark || !(m_compressed_map_flags & mIS_VALID))
|
||
|
{
|
||
|
//Ryan("clearing park\n");
|
||
|
Dbg_MsgAssert(m_floor_height_map, ("bad bad monkey!!!"));
|
||
|
|
||
|
for (int j = 0; j < FLOOR_MAX_LENGTH; j++)
|
||
|
{
|
||
|
for (int i = 0; i < FLOOR_MAX_WIDTH; i++)
|
||
|
{
|
||
|
int x = i;
|
||
|
int z = j;
|
||
|
m_floor_height_map[x][z].mHeight = 0; //Mth::Rnd(4);
|
||
|
m_floor_height_map[x][z].mEnclosedFloor = 0;
|
||
|
m_floor_height_map[x][z].mMarkAsSlid = false;
|
||
|
m_floor_height_map[i][j].mSlideAmount = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
write_compressed_map_buffer();
|
||
|
SetParkName("unnamed park");
|
||
|
m_compressed_map_flags = ECompressedMapFlags(m_compressed_map_flags & ~mNOT_SAVED_LOCAL);
|
||
|
clearPark = true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// use compressed map
|
||
|
read_from_compressed_map_buffer();
|
||
|
}
|
||
|
|
||
|
RebuildInnerShell(m_park_near_bounds);
|
||
|
generate_floor_pieces_from_height_map(clearPark, false);
|
||
|
|
||
|
mp_generator->GenerateCollisionInfo();
|
||
|
// mp_generator->GenerateNodeInfo(mp_concrete_metapiece_list);
|
||
|
|
||
|
m_park_is_valid = true;
|
||
|
|
||
|
if (clearPark)
|
||
|
{
|
||
|
m_compressed_map_flags = ECompressedMapFlags(m_compressed_map_flags | mIN_SYNC_WITH_PARK);
|
||
|
}
|
||
|
|
||
|
// K: Now that the park geometry has been built and collision info generated,
|
||
|
// update the created rails.
|
||
|
Obj::GetRailEditor()->RefreshGeometry();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
-Might clear map
|
||
|
-Generates riser geometry (from height map)
|
||
|
|
||
|
The only place we call this function with firstTestMemory true is from CCursor::ChangeFloorHeight()
|
||
|
*/
|
||
|
bool CParkManager::RebuildFloor(bool firstTestMemory)
|
||
|
{
|
||
|
ParkEd("CParkManager::RebuildFloor()");
|
||
|
|
||
|
Dbg_Assert(m_state_on);
|
||
|
|
||
|
//Dbg_Printf( "************* Rebuilding floor\n" );
|
||
|
|
||
|
if (firstTestMemory)
|
||
|
{
|
||
|
if (!generate_floor_pieces_from_height_map(false, true))
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
generate_floor_pieces_from_height_map(false, false);
|
||
|
|
||
|
//CConcreteMetaPiece *p_out = CreateConcreteMeta(GetAbstractMeta(Script::GenerateCRC("gloopy")));
|
||
|
//GridDims dims(m_park_near_bounds.GetX(), 0, m_park_near_bounds.GetZ());
|
||
|
//AddMetaPieceToPark(dims, p_out);
|
||
|
|
||
|
mp_generator->GenerateCollisionInfo();
|
||
|
|
||
|
return true;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
void CParkManager::RebuildNodeArray()
|
||
|
{
|
||
|
ParkEd("CParkManager::RebuildNodeArray()");
|
||
|
|
||
|
|
||
|
// clear any pre-exisiting automatic restarts
|
||
|
// so we have slots free to add new ones
|
||
|
mp_generator->ClearAutomaticRestarts();
|
||
|
|
||
|
|
||
|
// add default restarts
|
||
|
// (they won't be added if player-placed ones already exist)
|
||
|
// there are 18 points
|
||
|
// 1p, 2p, 4 flags, 6 horse, 6 KOTH
|
||
|
for (int p = 0; p < 18; p++)
|
||
|
{
|
||
|
CParkGenerator::RestartType restart_type = CParkGenerator::vONE_PLAYER;
|
||
|
|
||
|
GridDims restart_area;
|
||
|
restart_area = GetParkNearBounds(); // returns the rectangle enclosed by the fence
|
||
|
restart_area.SetXYZ(restart_area.GetX()+restart_area.GetW()/2, 0, restart_area.GetZ()+restart_area.GetL()/2); // sets xyz to the midpoint
|
||
|
restart_area.SetWHL(1,1,1); // needed for when we get the floor height
|
||
|
|
||
|
|
||
|
bool find_ground = true; // most restarts need to find the ground, except copied horse points
|
||
|
|
||
|
int need = 1; // Most restarts only need one. Horse/Multi being the current exception
|
||
|
if (p == 1)
|
||
|
{
|
||
|
restart_type = CParkGenerator::vMULTIPLAYER;
|
||
|
restart_area.SetXYZ(restart_area.GetX()+1, 0, restart_area.GetZ());
|
||
|
}
|
||
|
|
||
|
if (p == 2)
|
||
|
{
|
||
|
restart_type = CParkGenerator::vRED_FLAG;
|
||
|
restart_area.SetXYZ(restart_area.GetX()-2, 0, restart_area.GetZ()+2);
|
||
|
}
|
||
|
|
||
|
if (p == 3)
|
||
|
{
|
||
|
restart_type = CParkGenerator::vGREEN_FLAG;
|
||
|
restart_area.SetXYZ(restart_area.GetX()+0, 0, restart_area.GetZ()+2);
|
||
|
}
|
||
|
|
||
|
if (p == 4)
|
||
|
{
|
||
|
restart_type = CParkGenerator::vBLUE_FLAG;
|
||
|
restart_area.SetXYZ(restart_area.GetX()+2, 0, restart_area.GetZ()+2);
|
||
|
}
|
||
|
|
||
|
if (p == 5)
|
||
|
{
|
||
|
restart_type = CParkGenerator::vYELLOW_FLAG;
|
||
|
restart_area.SetXYZ(restart_area.GetX()+4, 0, restart_area.GetZ()+2);
|
||
|
}
|
||
|
|
||
|
// all the dummy horse/multi restart points go in a line at Z-2
|
||
|
if (p >= 6 && p <=11) // 6,7,8,9,10,11
|
||
|
{
|
||
|
need = 6;
|
||
|
restart_type = CParkGenerator::vHORSE;
|
||
|
|
||
|
#if 0
|
||
|
// Code to make horse points be evenly distributed between 1p/2p nodes
|
||
|
// but it's not usable, as the players will start at the same point
|
||
|
// either all multi points need to be different, of the code needs
|
||
|
// to check in 2P (and multi) for same node positions
|
||
|
// either are too risky to implement right now
|
||
|
static GridDims horse_points[6]; // needs to be static, so I can include it in this conditional
|
||
|
GridDims dims;
|
||
|
if (p==6)
|
||
|
{
|
||
|
// about to try the first horse point
|
||
|
// so fill the array with appropriate values
|
||
|
int num_actual_horse = mp_generator->NumRestartsOfType(restart_type);
|
||
|
// printf ("There are %d actual horse points\n",num_actual_horse);
|
||
|
if (num_actual_horse == 0)
|
||
|
{
|
||
|
// printf ("No horse points, using 1p/2p\n");
|
||
|
// not even got one, so fill the array with 1p,2p,1p,2p,1p,2p
|
||
|
for (int i = 0;i<6;i+=2)
|
||
|
{
|
||
|
dims = mp_generator->GetRestartDims(CParkGenerator::vONE_PLAYER,0);
|
||
|
horse_points[i] = restart_area;
|
||
|
horse_points[i].SetXYZ(dims.GetX(),0,dims.GetZ());
|
||
|
dims = mp_generator->GetRestartDims(CParkGenerator::vMULTIPLAYER,0);
|
||
|
horse_points[i+1] = restart_area;
|
||
|
horse_points[i+1].SetXYZ(dims.GetX(),0,dims.GetZ());
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// we have one or more real horse points, so find out where they are
|
||
|
// and copy those values for any automatic horse points, if needed
|
||
|
for (int i = 0;i<6;i++)
|
||
|
{
|
||
|
if (i < num_actual_horse)
|
||
|
{
|
||
|
// copy the n initial values into the array
|
||
|
horse_points[i] = mp_generator->GetRestartDims(CParkGenerator::vHORSE,i);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// and duplicate these through the rest of the array
|
||
|
// so we will get an even distribution
|
||
|
// n = 1 gives [ 1 1 1 1 1 1 ]
|
||
|
// n = 2 gives [ 1 2 1 2 1 2 ]
|
||
|
// n = 3 gives [ 1 2 3 1 2 3 ]
|
||
|
// n = 4 gives [ 1 2 3 4 1 2 ]
|
||
|
// n = 5 gives [ 1 2 3 4 5 1 ]
|
||
|
// n = 6 gives [ 1 2 3 4 5 6 ]
|
||
|
horse_points[i] = horse_points[i % num_actual_horse];
|
||
|
}
|
||
|
// printf ("Horse %d: (%d,%d,%d)\n",horse_points[i].GetX(),horse_points[i].GetY(),horse_points[i].GetX());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// copy the appropiate value from the array
|
||
|
restart_area = horse_points[p-6];
|
||
|
find_ground = false; // Don't find the ground when copying existing restarts, as we will be raised up by 1p/2p/horse pieces
|
||
|
//printf ("Using Restart Area(%d,%d,%d)\n",restart_area.GetX(), restart_area.GetY(), restart_area.GetZ());
|
||
|
|
||
|
|
||
|
#else
|
||
|
restart_area.SetXYZ(restart_area.GetX()-3 + (p-6), 0, restart_area.GetZ()-2);
|
||
|
//printf ("Using Restart Area(%d,%d,%d)\n",restart_area.GetX(), restart_area.GetY(), restart_area.GetZ());
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
|
||
|
bool auto_copy = false;
|
||
|
|
||
|
if ( p >= 12 && p <= 17 ) // 12,13,14,15,16,17
|
||
|
{
|
||
|
auto_copy = true; // copy any existing restart point position, if there is one
|
||
|
need = 6;
|
||
|
restart_type = CParkGenerator::vKING_OF_HILL;
|
||
|
restart_area.SetXYZ(restart_area.GetX()-3 + (p-12), 0, restart_area.GetZ()-3);
|
||
|
}
|
||
|
|
||
|
if (mp_generator->NotEnoughRestartsOfType(restart_type, need))
|
||
|
{
|
||
|
if (find_ground)
|
||
|
{
|
||
|
restart_area.SetXYZ(restart_area.GetX(),GetFloorHeight(restart_area),restart_area.GetZ());
|
||
|
CMapListTemp meta_list = GetMetaPiecesAt(restart_area);
|
||
|
if (!meta_list.IsEmpty())
|
||
|
{
|
||
|
restart_area[Y] = restart_area.GetY() + meta_list.GetList()->GetConcreteMeta()->GetArea().GetH();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Mth::Vector restart_pos = GridCoordinatesToWorld(restart_area);
|
||
|
restart_pos[X] = restart_pos[X] + CParkGenerator::CELL_WIDTH / 2.0f;
|
||
|
restart_pos[Z] = restart_pos[Z] + CParkGenerator::CELL_LENGTH / 2.0f;
|
||
|
|
||
|
// Fix to TT12221, where the flags would be floating if over a pool.
|
||
|
CFeeler feeler;
|
||
|
feeler.SetStart(restart_pos+Mth::Vector(0.0f, 10000.0f, 0.0f));
|
||
|
feeler.SetEnd(restart_pos+Mth::Vector(0.0f, -1000.0f, 0.0f));
|
||
|
if (feeler.GetCollision())
|
||
|
{
|
||
|
restart_pos[Y]=feeler.GetPoint().GetY();
|
||
|
}
|
||
|
|
||
|
// printf("restart point %d at: cell=(%d,%d,%d) world=(%.4f,%.4f,%.4f)\n", p,
|
||
|
// restart_area.GetX(), restart_area.GetY(), restart_area.GetZ(),
|
||
|
// restart_pos[X], restart_pos[Y], restart_pos[Z]);
|
||
|
|
||
|
mp_generator->AddRestart(restart_pos, 0, restart_area, restart_type, true, auto_copy);
|
||
|
}
|
||
|
} // end for p
|
||
|
|
||
|
mp_generator->GenerateNodeInfo(mp_concrete_metapiece_list);
|
||
|
}
|
||
|
|
||
|
|
||
|
uint32 CParkManager::GetShellSceneID()
|
||
|
{
|
||
|
char p_shell_name[40];
|
||
|
if (GetTheme())
|
||
|
{
|
||
|
sprintf(p_shell_name,"sk5ed%d_shell",GetTheme()+1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
strcpy(p_shell_name,"sk5ed_shell");
|
||
|
}
|
||
|
return Script::GenerateCRC(p_shell_name);
|
||
|
}
|
||
|
|
||
|
void CParkManager::RebuildInnerShell(GridDims newNearBounds)
|
||
|
{
|
||
|
ParkEd("CParkManager::RebuildInnerShell()");
|
||
|
|
||
|
Dbg_Printf( "************* Rebuilding inner shell\n" );
|
||
|
|
||
|
#if 1
|
||
|
ParkEd("old shell bounds: (%d,%d,%d)-(%d,%d,%d)\n",
|
||
|
m_park_near_bounds.GetX(), m_park_near_bounds.GetY(), m_park_near_bounds.GetZ(),
|
||
|
m_park_near_bounds.GetW(), m_park_near_bounds.GetH(), m_park_near_bounds.GetL());
|
||
|
#endif
|
||
|
m_park_near_bounds = newNearBounds;
|
||
|
#if 1
|
||
|
ParkEd("new shell bounds: (%d,%d,%d)-(%d,%d,%d)\n",
|
||
|
newNearBounds.GetX(), newNearBounds.GetY(), newNearBounds.GetZ(),
|
||
|
newNearBounds.GetW(), newNearBounds.GetH(), newNearBounds.GetL());
|
||
|
#endif
|
||
|
|
||
|
// west
|
||
|
m_road_mask_tab[0][X] = m_park_near_bounds.GetX() - 1;
|
||
|
m_road_mask_tab[0][Z] = m_park_near_bounds.GetZ() - 1;
|
||
|
m_road_mask_tab[0][W] = 1;
|
||
|
m_road_mask_tab[0][L] = m_park_near_bounds.GetL() + 2;
|
||
|
|
||
|
// east
|
||
|
m_road_mask_tab[1][X] = m_park_near_bounds.GetX() + m_park_near_bounds.GetW();
|
||
|
m_road_mask_tab[1][Z] = m_park_near_bounds.GetZ() - 1;
|
||
|
m_road_mask_tab[1][W] = 1;
|
||
|
m_road_mask_tab[1][L] = m_park_near_bounds.GetL() + 2;
|
||
|
|
||
|
// north
|
||
|
m_road_mask_tab[2][X] = m_park_near_bounds.GetX() - 1;
|
||
|
m_road_mask_tab[2][Z] = m_park_near_bounds.GetZ() - 1;
|
||
|
m_road_mask_tab[2][W] = m_park_near_bounds.GetW() + 2;
|
||
|
m_road_mask_tab[2][L] = 1;
|
||
|
|
||
|
// south
|
||
|
m_road_mask_tab[3][X] = m_park_near_bounds.GetX() - 1;
|
||
|
m_road_mask_tab[3][Z] = m_park_near_bounds.GetZ() + m_park_near_bounds.GetL();
|
||
|
m_road_mask_tab[3][W] = m_park_near_bounds.GetW() + 2;
|
||
|
m_road_mask_tab[3][L] = 1;
|
||
|
|
||
|
//#if DEBUG_THIS_DAMN_THING
|
||
|
//int destroy_type2_count = 0;
|
||
|
//#endif
|
||
|
|
||
|
// destroy all existing inner shell pieces
|
||
|
// also: kill everything that's outside the near bounds
|
||
|
CMapListNode *p_node = mp_concrete_metapiece_list;
|
||
|
while(p_node)
|
||
|
{
|
||
|
CMapListNode *p_next_node = p_node->GetNext();
|
||
|
GridDims meta_area = p_node->GetConcreteMeta()->GetArea();
|
||
|
|
||
|
if (p_node->GetConcreteMeta()->IsInnerShell())
|
||
|
{
|
||
|
DestroyConcreteMeta(p_node->GetConcreteMeta(), mDONT_DESTROY_PIECES_ABOVE);
|
||
|
}
|
||
|
#if 1
|
||
|
else if ( !p_node->GetConcreteMeta()->IsRiser() &&
|
||
|
p_node->GetConcreteMeta()->IsInPark() &&
|
||
|
(meta_area.GetX() < m_park_near_bounds.GetX() ||
|
||
|
meta_area.GetZ() < m_park_near_bounds.GetZ() ||
|
||
|
meta_area.GetX() + meta_area.GetW() > m_park_near_bounds.GetX() + m_park_near_bounds.GetW() ||
|
||
|
meta_area.GetZ() + meta_area.GetL() > m_park_near_bounds.GetZ() + m_park_near_bounds.GetL()))
|
||
|
{
|
||
|
DestroyConcreteMeta(p_node->GetConcreteMeta(), mDONT_DESTROY_PIECES_ABOVE);
|
||
|
//#if DEBUG_THIS_DAMN_THING
|
||
|
//destroy_type2_count++;
|
||
|
//#endif
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
p_node = p_next_node;
|
||
|
}
|
||
|
|
||
|
uint32 fence_meta_name_crc = Script::GenerateCRC("Sk4Ed_Fence_20x20");
|
||
|
CAbstractMetaPiece *p_abstract_fence_meta = GetAbstractMeta(fence_meta_name_crc);
|
||
|
|
||
|
for (int x = m_park_near_bounds.GetX(); x < m_park_near_bounds.GetX() + m_park_near_bounds.GetW(); x += 2)
|
||
|
{
|
||
|
GridDims road_test_area;
|
||
|
road_test_area.SetWHL(2, 1, 1);
|
||
|
|
||
|
// north
|
||
|
GridDims pos(x, 0, m_park_near_bounds.GetZ() - 1);
|
||
|
road_test_area.SetXYZ(pos.GetX(), 0, pos.GetZ() + 1);
|
||
|
if (!IsOccupiedByRoad(road_test_area))
|
||
|
{
|
||
|
CConcreteMetaPiece *p_meta = CreateConcreteMeta(p_abstract_fence_meta);
|
||
|
p_meta->SetRot(Mth::ROT_0);
|
||
|
p_meta->MarkAsInnerShell();
|
||
|
AddMetaPieceToPark(pos, p_meta);
|
||
|
}
|
||
|
|
||
|
// south
|
||
|
pos.SetXYZ(x, 0, m_park_near_bounds.GetZ() + m_park_near_bounds.GetL());
|
||
|
road_test_area.SetXYZ(pos.GetX(), 0, pos.GetZ() - 1);
|
||
|
if (!IsOccupiedByRoad(road_test_area))
|
||
|
{
|
||
|
CConcreteMetaPiece *p_meta = CreateConcreteMeta(p_abstract_fence_meta);
|
||
|
p_meta->SetRot(Mth::ROT_180);
|
||
|
p_meta->MarkAsInnerShell();
|
||
|
AddMetaPieceToPark(pos, p_meta);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (int z = m_park_near_bounds.GetZ(); z < m_park_near_bounds.GetZ() + m_park_near_bounds.GetL(); z += 2)
|
||
|
{
|
||
|
GridDims road_test_area;
|
||
|
road_test_area.SetWHL(1, 1, 2);
|
||
|
|
||
|
// west
|
||
|
GridDims pos(m_park_near_bounds.GetX() - 1, 0, z);
|
||
|
road_test_area.SetXYZ(pos.GetX() + 1, 0, pos.GetZ());
|
||
|
if (!IsOccupiedByRoad(road_test_area))
|
||
|
{
|
||
|
CConcreteMetaPiece *p_meta = CreateConcreteMeta(p_abstract_fence_meta);
|
||
|
p_meta->SetRot(Mth::ROT_90);
|
||
|
p_meta->MarkAsInnerShell();
|
||
|
AddMetaPieceToPark(pos, p_meta);
|
||
|
}
|
||
|
|
||
|
// east
|
||
|
pos.SetXYZ(m_park_near_bounds.GetX() + m_park_near_bounds.GetW(), 0, z);
|
||
|
road_test_area.SetXYZ(pos.GetX() - 1, 0, pos.GetZ());
|
||
|
if (!IsOccupiedByRoad(road_test_area))
|
||
|
{
|
||
|
CConcreteMetaPiece *p_meta = CreateConcreteMeta(p_abstract_fence_meta);
|
||
|
p_meta->SetRot(Mth::ROT_270);
|
||
|
p_meta->MarkAsInnerShell();
|
||
|
AddMetaPieceToPark(pos, p_meta);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//ParkEd("destroyed %d non-riser pieces\n", destroy_type2_count);
|
||
|
|
||
|
for (int x = 0; x < MAX_WIDTH; x++)
|
||
|
{
|
||
|
for (int z = 0; z < MAX_LENGTH; z++)
|
||
|
{
|
||
|
if (x < m_park_near_bounds.GetX() ||
|
||
|
z < m_park_near_bounds.GetZ() ||
|
||
|
x >= m_park_near_bounds.GetX() + m_park_near_bounds.GetW() ||
|
||
|
z >= m_park_near_bounds.GetZ() + m_park_near_bounds.GetL())
|
||
|
{
|
||
|
m_floor_height_map[x][z].mHeight = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
mp_generator->RemoveOuterShellPieces(GetTheme());
|
||
|
mp_generator->GenerateCollisionInfo();
|
||
|
|
||
|
// mp_generator->GenerateNodeInfo(mp_concrete_metapiece_list);
|
||
|
ParkEd("end RebuildInnerShell()\n");
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
Retrieves the abstract meta with the specified name checksum. Returns its index.
|
||
|
*/
|
||
|
CAbstractMetaPiece *CParkManager::GetAbstractMeta(uint32 type, int *pRetIndex)
|
||
|
{
|
||
|
Dbg_Assert(m_state_on);
|
||
|
|
||
|
CMapListNode *p_node = mp_abstract_metapiece_list;
|
||
|
int index = m_num_abstract_metapieces-1;
|
||
|
while(p_node)
|
||
|
{
|
||
|
CAbstractMetaPiece *p_meta = p_node->GetAbstractMeta();
|
||
|
Dbg_Assert(p_meta);
|
||
|
if (p_meta->m_name_checksum == type)
|
||
|
{
|
||
|
if (pRetIndex)
|
||
|
*pRetIndex = index;
|
||
|
return p_meta;
|
||
|
}
|
||
|
|
||
|
index--;
|
||
|
p_node = p_node->GetNext();
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
Retrieves the abstract meta with the specified index.
|
||
|
*/
|
||
|
CAbstractMetaPiece *CParkManager::GetAbstractMetaByIndex(int index)
|
||
|
{
|
||
|
Dbg_Assert(m_state_on);
|
||
|
|
||
|
CMapListNode *p_node = mp_abstract_metapiece_list;
|
||
|
int i = m_num_abstract_metapieces-1;
|
||
|
while(p_node)
|
||
|
{
|
||
|
CAbstractMetaPiece *p_meta = p_node->GetAbstractMeta();
|
||
|
Dbg_Assert(p_meta);
|
||
|
if (i == index)
|
||
|
return p_meta;
|
||
|
|
||
|
i--;
|
||
|
p_node = p_node->GetNext();
|
||
|
}
|
||
|
|
||
|
Dbg_MsgAssert(0, ("index %d out of range", i));
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
Creates a concrete copy of the specified abstract meta.
|
||
|
*/
|
||
|
CConcreteMetaPiece *CParkManager::CreateConcreteMeta(CAbstractMetaPiece *pSource, bool isSoft)
|
||
|
{
|
||
|
Dbg_Assert(m_state_on);
|
||
|
Dbg_Assert(pSource);
|
||
|
|
||
|
Mem::Manager::sHandle().PushContext(mp_generator->GetParkEditorHeap());
|
||
|
CConcreteMetaPiece *p_meta = new CConcreteMetaPiece();
|
||
|
Mem::Manager::sHandle().PopContext();
|
||
|
|
||
|
int num_entries = pSource->count_descriptors_expanded();
|
||
|
p_meta->initialize_desc_table(num_entries);
|
||
|
p_meta->m_name_checksum = pSource->m_name_checksum;
|
||
|
|
||
|
CPiece::EFlags clone_flags = (isSoft) ? CPiece::mSOFT_PIECE : CPiece::mNO_FLAGS;
|
||
|
|
||
|
if (pSource->IsRiser())
|
||
|
{
|
||
|
p_meta->set_flag(CMetaPiece::mIS_RISER);
|
||
|
clone_flags = CPiece::EFlags(clone_flags | CPiece::mFLOOR);
|
||
|
}
|
||
|
if (pSource->NoRails())
|
||
|
{
|
||
|
p_meta->set_flag(CMetaPiece::mNO_RAILS);
|
||
|
clone_flags = CPiece::EFlags(clone_flags | CPiece::mNO_RAILS);
|
||
|
}
|
||
|
if (pSource->m_flags & CMetaPiece::mCONTAINS_RISERS)
|
||
|
{
|
||
|
p_meta->set_flag(CMetaPiece::mCONTAINS_RISERS);
|
||
|
}
|
||
|
|
||
|
// pick through source piece, for each descriptor entry, make new cloned piece
|
||
|
for (int i = 0; i < num_entries; i++)
|
||
|
{
|
||
|
SMetaDescriptor desc = pSource->get_desc_with_expansion(i);
|
||
|
|
||
|
CClonedPiece *p_piece =
|
||
|
mp_generator->ClonePiece(CParkManager::sInstance()->GetGenerator()->GetMasterPiece(desc.mPieceName), clone_flags);
|
||
|
p_piece->SetDesiredRot(Mth::ERot90(desc.mRot), CClonedPiece::MARKER_ONLY);
|
||
|
GridDims dims(desc.mX, desc.mY, desc.mZ);
|
||
|
p_meta->add_piece(p_piece, &dims, Mth::ERot90(desc.mRot), (desc.mRiser != 0));
|
||
|
|
||
|
#if 0
|
||
|
// Ryan: this call is unnecessary
|
||
|
if (!isSoft)
|
||
|
{
|
||
|
mp_generator->CalculateLighting(p_piece);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if 0
|
||
|
if (pSource->GetNameChecksum() == Script::GenerateCRC("Low_Short_Deck"))
|
||
|
{
|
||
|
printf(" rotation: %d\n", desc.mRot);
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
p_meta->lock();
|
||
|
|
||
|
#if 1
|
||
|
#ifdef __NOPT_ASSERT__
|
||
|
GridDims test_area = p_meta->GetArea();
|
||
|
Dbg_MsgAssert(test_area.GetW() > 0 && test_area.GetH() > 0 && test_area.GetL() > 0,
|
||
|
("metapiece %s has invalid dimensions (%d,%d,%d)", Script::FindChecksumName(p_meta->GetNameChecksum()),
|
||
|
test_area.GetW(), test_area.GetH(), test_area.GetL()));
|
||
|
|
||
|
#if 0
|
||
|
if (1 || p_meta->GetNameChecksum() == Script::GenerateCRC("Sk4Ed_Fence_10x10"))
|
||
|
printf("OY! metapiece %s has dimensions (%d,%d,%d)\n", Script::FindChecksumName(p_meta->GetNameChecksum()),
|
||
|
test_area.GetW(), test_area.GetH(), test_area.GetL());
|
||
|
#endif
|
||
|
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
Mem::Manager::sHandle().PushContext(mp_generator->GetParkEditorHeap());
|
||
|
CMapListNode *p_node = new CMapListNode();
|
||
|
Mem::Manager::sHandle().PopContext();
|
||
|
p_node->mp_meta = p_meta;
|
||
|
|
||
|
#if 0
|
||
|
p_node->mp_next = mp_concrete_metapiece_list;
|
||
|
mp_concrete_metapiece_list = p_node;
|
||
|
#else
|
||
|
p_node->mp_next = NULL;
|
||
|
if (!mp_concrete_metapiece_list)
|
||
|
{
|
||
|
mp_concrete_metapiece_list = p_node;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CMapListNode *p_add = mp_concrete_metapiece_list;
|
||
|
while( p_add->mp_next)
|
||
|
{
|
||
|
p_add = p_add->mp_next;
|
||
|
}
|
||
|
p_add->mp_next = p_node;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
m_num_concrete_metapieces++;
|
||
|
|
||
|
return p_meta;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void CParkManager::DestroyConcreteMeta(CConcreteMetaPiece *pMeta, EDestroyFlags flags)
|
||
|
{
|
||
|
Dbg_Assert(m_state_on);
|
||
|
if (pMeta->m_flags & CMetaPiece::mLOCK_AGAINST_DELETE) return;
|
||
|
Dbg_MsgAssert(!(pMeta->m_flags & CMetaPiece::mLOCK_AGAINST_DELETE), ("Metapiece is locked, can't deleted"));
|
||
|
|
||
|
if (CCursor::sInstance(false))
|
||
|
CCursor::sInstance()->InformOfMetapieceDeletion(pMeta);
|
||
|
|
||
|
// remove any gaps attached to this piece
|
||
|
RemoveGap(pMeta);
|
||
|
|
||
|
if (!pMeta->IsInnerShell() && pMeta->IsInPark())
|
||
|
{
|
||
|
decrement_meta_count(pMeta->GetNameChecksum());
|
||
|
if (!pMeta->IsRiser())
|
||
|
{
|
||
|
m_compressed_map_flags = ECompressedMapFlags(m_compressed_map_flags & ~(mIN_SYNC_WITH_PARK | mIS_NEWER_THAN_PARK));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// destroy all metas that are ABOVE this one
|
||
|
if (!pMeta->IsRiser() && (flags & mDESTROY_PIECES_ABOVE))
|
||
|
{
|
||
|
GridDims test_area = pMeta->GetArea();
|
||
|
test_area[Y] = test_area.GetY() + test_area.GetH();
|
||
|
test_area.MakeInfinitelyHigh();
|
||
|
// XXX
|
||
|
Ryan("die now: ");
|
||
|
//test_area.PrintContents();
|
||
|
DestroyMetasInArea(test_area, EDestroyFlags(mEXCLUDE_RISERS | mDESTROY_PIECES_ABOVE));
|
||
|
}
|
||
|
|
||
|
apply_meta_contained_risers_to_floor(pMeta, false);
|
||
|
|
||
|
debucketify_metapiece(pMeta);
|
||
|
remove_metapiece_from_node_list(pMeta, &mp_concrete_metapiece_list);
|
||
|
|
||
|
#if 0
|
||
|
printf("concrete metapiece %s destroyed: cell dims (%d,%d,%d)-(%d,%d,%d), flags=0x%x\n",
|
||
|
Script::FindChecksumName(pMeta->GetNameChecksum()),
|
||
|
pMeta->m_cell_area.GetX(), pMeta->m_cell_area.GetY(), pMeta->m_cell_area.GetZ(),
|
||
|
pMeta->m_cell_area.GetW(), pMeta->m_cell_area.GetH(), pMeta->m_cell_area.GetL(),
|
||
|
pMeta->m_flags);
|
||
|
#endif
|
||
|
|
||
|
|
||
|
CParkGenerator::RestartType restart_type = IsRestartPiece(pMeta->GetNameChecksum());
|
||
|
if (restart_type != CParkGenerator::vEMPTY)
|
||
|
{
|
||
|
mp_generator->RemoveRestart(pMeta->GetArea(),restart_type);
|
||
|
}
|
||
|
|
||
|
// take out metapiece
|
||
|
for (uint i = 0; i < pMeta->m_num_used_entries; i++)
|
||
|
{
|
||
|
CClonedPiece *p_piece = pMeta->get_desc_at_index(i).mpPiece->CastToCClonedPiece();
|
||
|
Dbg_Assert(p_piece);
|
||
|
mp_generator->DestroyClonedPiece(p_piece);
|
||
|
}
|
||
|
|
||
|
delete pMeta;
|
||
|
m_num_concrete_metapieces--;
|
||
|
}
|
||
|
|
||
|
|
||
|
void CParkManager::HighlightMetasInArea(GridDims area, bool on)
|
||
|
{
|
||
|
CMapListTemp list = GetAreaMetaPieces(area);
|
||
|
CMapListNode *p_entry = list.GetList();
|
||
|
|
||
|
while(p_entry)
|
||
|
{
|
||
|
CMetaPiece *p_meta=p_entry->GetMeta();
|
||
|
if (p_meta)
|
||
|
{
|
||
|
if (p_meta->IsConcrete() && p_meta->IsCompletelyWithinArea(area))
|
||
|
{
|
||
|
p_entry->GetConcreteMeta()->Highlight(on);
|
||
|
}
|
||
|
}
|
||
|
p_entry = p_entry->GetNext();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
GridDims CParkManager::FindBoundingArea(GridDims area)
|
||
|
{
|
||
|
int min_x=1000000;
|
||
|
int min_z=1000000;
|
||
|
int max_x=-1000000;
|
||
|
int max_z=-1000000;
|
||
|
|
||
|
CMapListTemp list = GetAreaMetaPieces(area);
|
||
|
CMapListNode *p_entry = list.GetList();
|
||
|
|
||
|
while(p_entry)
|
||
|
{
|
||
|
CMetaPiece *p_meta=p_entry->GetMeta();
|
||
|
if (p_meta && p_meta->IsConcrete())
|
||
|
{
|
||
|
GridDims meta_area = p_entry->GetConcreteMeta()->GetArea();
|
||
|
int x1=meta_area.GetX();
|
||
|
int z1=meta_area.GetZ();
|
||
|
int x2=x1+meta_area.GetW()-1;
|
||
|
int z2=z1+meta_area.GetL()-1;
|
||
|
|
||
|
if (x1 < min_x) min_x=x1;
|
||
|
if (x2 > max_x) max_x=x2;
|
||
|
if (z1 < min_z) min_z=z1;
|
||
|
if (z2 > max_z) max_z=z2;
|
||
|
}
|
||
|
p_entry = p_entry->GetNext();
|
||
|
}
|
||
|
|
||
|
GridDims bounding_area=area;
|
||
|
if (min_x <= max_x && min_z <= max_z)
|
||
|
{
|
||
|
bounding_area.SetXYZ(min_x, 0, min_z);
|
||
|
bounding_area.SetWHL(max_x-min_x+1, 1, max_z-min_z+1);
|
||
|
}
|
||
|
return bounding_area;
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
// K: Does the same as CCursor::AttemptRemove() but for any area
|
||
|
bool CParkManager::DestroyMetasInArea(GridDims area, bool doNotDestroyRestartsOrFlags, bool onlyIfWithinArea)
|
||
|
{
|
||
|
bool destroyed_something=false;
|
||
|
CMapListTemp metas_at_pos = GetAreaMetaPieces(area);
|
||
|
CMapListNode *p_entry = metas_at_pos.GetList();
|
||
|
while (p_entry)
|
||
|
{
|
||
|
CConcreteMetaPiece *p_meta = p_entry->GetConcreteMeta();
|
||
|
if (p_meta->IsRiser() ||
|
||
|
(doNotDestroyRestartsOrFlags && p_meta->IsRestartOrFlag()) ||
|
||
|
(onlyIfWithinArea && !p_meta->IsCompletelyWithinArea(area)))
|
||
|
{
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DestroyConcreteMeta(p_meta, CParkManager::mDESTROY_PIECES_ABOVE);
|
||
|
destroyed_something=true;
|
||
|
}
|
||
|
|
||
|
p_entry = p_entry->GetNext();
|
||
|
}
|
||
|
|
||
|
// Also destroy any rail points in the area.
|
||
|
Mth::Vector corner_pos;
|
||
|
Mth::Vector area_dims;
|
||
|
corner_pos=Ed::CParkManager::Instance()->GridCoordinatesToWorld(area,&area_dims);
|
||
|
Obj::GetRailEditor()->ClipRails(corner_pos[X], corner_pos[Z],
|
||
|
corner_pos[X]+area_dims[X], corner_pos[Z]+area_dims[Z],
|
||
|
Obj::CRailEditorComponent::DELETE_POINTS_INSIDE);
|
||
|
|
||
|
if (destroyed_something)
|
||
|
{
|
||
|
RebuildFloor();
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
Destroys concrete metapieces in specified area, according to flags.
|
||
|
|
||
|
Flags:
|
||
|
-mDESTROY_PIECES_ABOVE: if set, whenever a meta is destroyed, recursively
|
||
|
destroy all metas above it
|
||
|
|
||
|
Return value:
|
||
|
upper 16 bits: number metas killed
|
||
|
lower 16 bits: number pieces killed
|
||
|
*/
|
||
|
uint32 CParkManager::DestroyMetasInArea(GridDims area, EDestroyFlags flags)
|
||
|
{
|
||
|
uint16 metas_killed = 0;
|
||
|
uint16 pieces_killed = 0;
|
||
|
CMapListNode *p_list = GetMetaPiecesAt(area, Mth::ROT_0, NULL, (flags & mEXCLUDE_RISERS));
|
||
|
CMapListNode *p_node = p_list;
|
||
|
while (p_node)
|
||
|
{
|
||
|
if (!(flags & mEXCLUDE_PIECES_MARKED_AS_SLID) || !(p_node->GetConcreteMeta()->m_flags & CMetaPiece::mMARK_AS_SLID))
|
||
|
{
|
||
|
metas_killed++;
|
||
|
pieces_killed += p_node->GetConcreteMeta()->m_num_used_entries;
|
||
|
DestroyConcreteMeta(p_node->GetConcreteMeta(), flags);
|
||
|
}
|
||
|
p_node = p_node->GetNext();
|
||
|
}
|
||
|
p_list->DestroyList();
|
||
|
|
||
|
return ((metas_killed<<16) | pieces_killed);
|
||
|
}
|
||
|
|
||
|
int CParkManager::get_dma_usage(uint32 pieceChecksum)
|
||
|
{
|
||
|
Script::CStruct *p_dma_usage=Script::GetStructure(CRCD(0x9547da8d,"DMA_Usage"),Script::ASSERT);
|
||
|
int usage=1;
|
||
|
p_dma_usage->GetInteger(pieceChecksum, &usage);
|
||
|
return usage;
|
||
|
}
|
||
|
|
||
|
void CParkManager::increment_meta_count(uint32 pieceChecksum)
|
||
|
{
|
||
|
++m_num_general_concrete_metapieces;
|
||
|
m_dma_piece_count += get_dma_usage(pieceChecksum);
|
||
|
|
||
|
//printf("IncrementMetaCount '%s', %d DMA=%d\n",Script::FindChecksumName(pieceChecksum),m_num_general_concrete_metapieces,m_dma_piece_count);
|
||
|
}
|
||
|
|
||
|
void CParkManager::decrement_meta_count(uint32 pieceChecksum)
|
||
|
{
|
||
|
--m_num_general_concrete_metapieces;
|
||
|
m_dma_piece_count -= get_dma_usage(pieceChecksum);
|
||
|
|
||
|
//printf("DecrementMetaCount '%s' %d DMA=%d\n",Script::FindChecksumName(pieceChecksum),m_num_general_concrete_metapieces,m_dma_piece_count);
|
||
|
Dbg_MsgAssert(m_dma_piece_count >= 0,("Negative m_dma_piece_count of %d\n",m_dma_piece_count));
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
Position is in cell coordinates, relative to northwest corner of 256X256 grid.
|
||
|
Y coordinate is relative to "ground level", can be + or -.
|
||
|
|
||
|
Rotation is 0-3.
|
||
|
*/
|
||
|
void CParkManager::AddMetaPieceToPark(GridDims pos, CConcreteMetaPiece *pMetaPiece)
|
||
|
{
|
||
|
Dbg_Assert(m_state_on);
|
||
|
|
||
|
Dbg_MsgAssert(!(pMetaPiece->m_flags & CMetaPiece::mIN_PARK), ("metapiece already in park"));
|
||
|
pMetaPiece->set_flag(CMetaPiece::mIN_PARK);
|
||
|
|
||
|
pMetaPiece->m_cell_area.SetXYZ(pos.GetX(), pos.GetY(), pos.GetZ());
|
||
|
|
||
|
// center_pos in world coordinates
|
||
|
Mth::Vector center_pos;
|
||
|
center_pos[X] = ((float) pos.GetX() + (float) pMetaPiece->m_cell_area.GetW() / 2.0f) * CParkGenerator::CELL_WIDTH;
|
||
|
center_pos[X] -= (CParkGenerator::CELL_WIDTH * (float) CParkManager::FLOOR_MAX_WIDTH) / 2.0f;
|
||
|
center_pos[Z] = ((float) pos.GetZ() + (float) pMetaPiece->m_cell_area.GetL() / 2.0f) * CParkGenerator::CELL_LENGTH;
|
||
|
center_pos[Z] -= (CParkGenerator::CELL_LENGTH * (float) CParkManager::FLOOR_MAX_LENGTH) / 2.0f;
|
||
|
center_pos[Y] = pos.GetY() * CParkGenerator::CELL_HEIGHT;
|
||
|
|
||
|
// XXX
|
||
|
#if 0
|
||
|
Dbg_Printf("adding piece to park: (%d,%d,%d), (%.2f,%.2f,%.2f)\n",
|
||
|
pos.GetX(), pos.GetY(), pos.GetZ(),
|
||
|
center_pos[X], center_pos[Y], center_pos[Z]);
|
||
|
#endif
|
||
|
|
||
|
for (uint i = 0; i < pMetaPiece->m_num_used_entries; i++)
|
||
|
{
|
||
|
Mth::Vector rel_pos = pMetaPiece->GetRelativePosOfContainedPiece(i);
|
||
|
CClonedPiece *p_piece = pMetaPiece->GetContainedPiece(i)->CastToCClonedPiece();
|
||
|
|
||
|
// reposition piece from metapiece-relative coordinates to world-relative
|
||
|
Mth::Vector abs_pos;
|
||
|
abs_pos[X] = center_pos[X] + rel_pos[X];
|
||
|
abs_pos[Z] = center_pos[Z] + rel_pos[Z];
|
||
|
abs_pos[Y] = center_pos[Y] + rel_pos[Y];
|
||
|
|
||
|
p_piece->SetDesiredPos(abs_pos, CClonedPiece::CHANGE_SECTOR);
|
||
|
p_piece->SetDesiredRot(Mth::ERot90((p_piece->GetRot() + pMetaPiece->m_rot) & 3), CClonedPiece::CHANGE_SECTOR);
|
||
|
mp_generator->AddClonedPieceToWorld(p_piece);
|
||
|
mp_generator->CalculateLighting(p_piece);
|
||
|
}
|
||
|
|
||
|
apply_meta_contained_risers_to_floor(pMetaPiece, true);
|
||
|
bucketify_metapiece(pMetaPiece);
|
||
|
|
||
|
// If it's a restart point, then add that to the list of restart points
|
||
|
CParkGenerator::RestartType restart_type = IsRestartPiece(pMetaPiece->GetNameChecksum());
|
||
|
if (restart_type != CParkGenerator::vEMPTY)
|
||
|
{
|
||
|
mp_generator->AddRestart(center_pos,pMetaPiece->m_rot,pos,restart_type,false);
|
||
|
}
|
||
|
|
||
|
if (!pMetaPiece->IsInnerShell())
|
||
|
{
|
||
|
if (!pMetaPiece->IsRiser())
|
||
|
{
|
||
|
m_compressed_map_flags = ECompressedMapFlags(m_compressed_map_flags & ~(mIN_SYNC_WITH_PARK | mIS_NEWER_THAN_PARK));
|
||
|
}
|
||
|
increment_meta_count(pMetaPiece->GetNameChecksum());
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
"Moves" a metapiece from one position to another. Really, the old metapiece is destroyed, and a new copy created,
|
||
|
so be careful to replace any pointers to old one.
|
||
|
*/
|
||
|
CConcreteMetaPiece *CParkManager::RelocateMetaPiece(CConcreteMetaPiece *pMeta, int changeX, int changeY, int changeZ)
|
||
|
{
|
||
|
GridDims area = pMeta->GetArea();
|
||
|
uint32 name = pMeta->GetNameChecksum();
|
||
|
Mth::ERot90 rot = pMeta->GetRot();
|
||
|
CMetaPiece::EFlags old_flags = pMeta->m_flags;
|
||
|
|
||
|
// get gap associated with metapiece
|
||
|
int gap_half;
|
||
|
bool gap_exists = false;
|
||
|
CGapManager::GapDescriptor *p_gap_desc = GetGapDescriptor(area, &gap_half);
|
||
|
CGapManager::GapDescriptor new_gap_desc;
|
||
|
if (p_gap_desc)
|
||
|
{
|
||
|
gap_exists = true;
|
||
|
new_gap_desc = *p_gap_desc;
|
||
|
|
||
|
// remove it
|
||
|
RemoveGap(*p_gap_desc);
|
||
|
|
||
|
// shift gap descriptor to new position
|
||
|
new_gap_desc.loc[gap_half][X] = new_gap_desc.loc[gap_half].GetX() + changeX;
|
||
|
new_gap_desc.loc[gap_half][Y] = new_gap_desc.loc[gap_half].GetY() + changeY;
|
||
|
new_gap_desc.loc[gap_half][Z] = new_gap_desc.loc[gap_half].GetZ() + changeZ;
|
||
|
}
|
||
|
|
||
|
DestroyConcreteMeta(pMeta, mDONT_DESTROY_PIECES_ABOVE);
|
||
|
|
||
|
area[X] += changeX;
|
||
|
area[Y] = area.GetY() + changeY;
|
||
|
area[Z] += changeZ;
|
||
|
|
||
|
CConcreteMetaPiece *p_new_meta = CreateConcreteMeta(GetAbstractMeta(name), false);
|
||
|
p_new_meta->SetRot(rot);
|
||
|
p_new_meta->m_flags = old_flags;
|
||
|
p_new_meta->clear_flag(CMetaPiece::mIN_PARK);
|
||
|
AddMetaPieceToPark(area, p_new_meta);
|
||
|
|
||
|
if (gap_exists)
|
||
|
{
|
||
|
AddGap(new_gap_desc);
|
||
|
}
|
||
|
|
||
|
return p_new_meta;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
Returns list of concrete metapieces in specified area.
|
||
|
|
||
|
Modes:
|
||
|
pPiece == NULL, grab all pieces in area specified by 'dims', excluding risers and riser-containing metas if desired.
|
||
|
|
||
|
pPiece != NULL, does pretty much the same thing right now.
|
||
|
*/
|
||
|
|
||
|
CMapListNode *CParkManager::GetMetaPiecesAt(GridDims dims, Mth::ERot90 rot, CAbstractMetaPiece *pPiece, bool excludeRisers)
|
||
|
{
|
||
|
Dbg_Assert(m_state_on);
|
||
|
|
||
|
if (!pPiece)
|
||
|
{
|
||
|
CMapListNode *p_out_list = NULL;
|
||
|
|
||
|
// need to be scanning an area bigger than 0
|
||
|
//if (dims.mW == 0) dims.mW++;
|
||
|
//if (dims.mL == 0) dims.mL++;
|
||
|
|
||
|
// no piece supplied, just scan through and grab all metapieces
|
||
|
int end_x = dims.GetX() + dims.GetW();
|
||
|
for (int x = dims.GetX(); x < end_x; x++)
|
||
|
{
|
||
|
int end_z = dims.GetZ() + dims.GetL();
|
||
|
for (int z = dims.GetZ(); z < end_z; z++)
|
||
|
{
|
||
|
CMapListNode *p_node = mp_bucket_list[x][z];
|
||
|
|
||
|
while(p_node)
|
||
|
{
|
||
|
//Ryan("boogah %d\n", x);
|
||
|
if ((!excludeRisers || !(p_node->GetMeta()->IsRiser())) &&
|
||
|
p_node->GetConcreteMeta()->test_for_conflict(dims, excludeRisers))
|
||
|
{
|
||
|
add_metapiece_to_node_list(p_node->GetMeta(), &p_out_list);
|
||
|
}
|
||
|
|
||
|
p_node = p_node->GetNext();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
p_out_list->VerifyIntegrity();
|
||
|
return p_out_list;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Dbg_MsgAssert(pPiece->GetRot() == Mth::ROT_0, ("abstract metapiece needs 0 rotation"));
|
||
|
|
||
|
// build a descriptor table rotated and shifted to correct world coordinates
|
||
|
|
||
|
// rotate the abstract meta piece to the desired rotation
|
||
|
pPiece->SetRot(rot);
|
||
|
dims[W] = pPiece->m_cell_area.GetW();
|
||
|
dims[H] = pPiece->m_cell_area.GetH();
|
||
|
dims[L] = pPiece->m_cell_area.GetL();
|
||
|
|
||
|
CMapListNode *p_out_list = NULL;
|
||
|
|
||
|
// grab list of all concrete metas
|
||
|
CMapListTemp metas_in_park = GetMetaPiecesAt(dims);
|
||
|
|
||
|
// for each contained piece
|
||
|
for (uint i = 0; i < pPiece->m_num_used_entries; i++)
|
||
|
{
|
||
|
SMetaDescriptor &desc = pPiece->get_desc_at_index(i);
|
||
|
GridDims test_area(desc.mX, desc.mY, desc.mZ);
|
||
|
test_area[X] += dims.GetX();
|
||
|
test_area[Y] += dims.GetY();
|
||
|
test_area[Z] += dims.GetZ();
|
||
|
|
||
|
CMapListNode *p_in_park_entry = metas_in_park.GetList();
|
||
|
while (p_in_park_entry)
|
||
|
{
|
||
|
if (p_in_park_entry->GetConcreteMeta()->test_for_conflict(test_area, false))
|
||
|
add_metapiece_to_node_list(p_in_park_entry->GetMeta(), &p_out_list);
|
||
|
|
||
|
p_in_park_entry = p_in_park_entry->GetNext();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// return abstract meta to a zero rotation
|
||
|
pPiece->SetRot(Mth::ROT_0);
|
||
|
p_out_list->VerifyIntegrity();
|
||
|
return p_out_list;
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
// This is just a slightly faster version of GetMetaPiecesAt, which gets all
|
||
|
CMapListNode *CParkManager::GetAreaMetaPieces(GridDims dims)
|
||
|
{
|
||
|
Dbg_Assert(m_state_on);
|
||
|
|
||
|
CMapListNode *p_out_list = NULL;
|
||
|
|
||
|
int end_x = dims.GetX() + dims.GetW();
|
||
|
for (int x = dims.GetX(); x < end_x; x++)
|
||
|
{
|
||
|
int end_z = dims.GetZ() + dims.GetL();
|
||
|
for (int z = dims.GetZ(); z < end_z; z++)
|
||
|
{
|
||
|
CMapListNode *p_node = mp_bucket_list[x][z];
|
||
|
while(p_node)
|
||
|
{
|
||
|
add_metapiece_to_node_list(p_node->GetMeta(), &p_out_list);
|
||
|
p_node = p_node->GetNext();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return p_out_list;
|
||
|
}
|
||
|
|
||
|
// K: These two functions used by CClipboard::CopySelectionToClipboard
|
||
|
CMapListNode *CParkManager::GetMapListNode(int x, int z)
|
||
|
{
|
||
|
return mp_bucket_list[x][z];
|
||
|
}
|
||
|
|
||
|
int CParkManager::GetFloorHeight(int x, int z)
|
||
|
{
|
||
|
return m_floor_height_map[x][z].mHeight;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
Used to determine if resizing park will destroy existing metas.
|
||
|
*/
|
||
|
bool CParkManager::AreMetasOutsideBounds(GridDims new_dims)
|
||
|
{
|
||
|
//Ryan("New Park Bounds are: (%d,%d,%d)-(%d,%d,%d)\n",
|
||
|
// new_dims.GetX(), new_dims.GetY(), new_dims.GetZ(),
|
||
|
// new_dims.GetW(), new_dims.GetH(), new_dims.GetL());
|
||
|
CMapListNode *p_node = mp_concrete_metapiece_list;
|
||
|
while(p_node)
|
||
|
{
|
||
|
CConcreteMetaPiece *p_meta = p_node->GetConcreteMeta();
|
||
|
GridDims meta_area = p_meta->GetArea();
|
||
|
//Ryan("Checking if meta in bounds: is_riser=%d, inner_shell=%d (%d,%d,%d)-(%d,%d,%d)\n",
|
||
|
// p_meta->IsRiser(), p_meta->IsInnerShell(),
|
||
|
// meta_area.GetX(), meta_area.GetY(), meta_area.GetZ(),
|
||
|
// meta_area.GetW(), meta_area.GetH(), meta_area.GetL());
|
||
|
if ((meta_area.GetX() < new_dims.GetX() ||
|
||
|
meta_area.GetZ() < new_dims.GetZ() ||
|
||
|
meta_area.GetX() + meta_area.GetW() > new_dims.GetX() + new_dims.GetW() ||
|
||
|
meta_area.GetZ() + meta_area.GetL() > new_dims.GetZ() + new_dims.GetL()) &&
|
||
|
!p_meta->IsRiser() &&
|
||
|
!p_meta->IsInnerShell() &&
|
||
|
(p_meta->m_flags & CMetaPiece::mIN_PARK))
|
||
|
return true;
|
||
|
p_node = p_node->GetNext();
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
Used to determine if resizing park will destroy existing metas.
|
||
|
*/
|
||
|
bool CParkManager::EnoughMemoryToResize(GridDims new_dims)
|
||
|
{
|
||
|
int current_num_tiles = m_park_near_bounds.GetW() * m_park_near_bounds.GetL();
|
||
|
int new_num_tiles = new_dims.GetW() * new_dims.GetL();
|
||
|
|
||
|
if (new_num_tiles - current_num_tiles > GetGenerator()->GetResourceSize("max_dma_pieces") - GetDMAPieceCount())
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
int park_add_amount = (new_num_tiles - current_num_tiles) * mp_generator->GetResourceSize("floor_piece_size_park");
|
||
|
int main_add_amount = (new_num_tiles - current_num_tiles) * mp_generator->GetResourceSize("floor_piece_size_main");
|
||
|
|
||
|
CParkGenerator::MemUsageInfo usage_info = mp_generator->GetResourceUsageInfo();
|
||
|
if (usage_info.mParkHeapFree < park_add_amount)
|
||
|
{
|
||
|
Ryan("not enough memory for resize on park heap, need %d, have %d\n", park_add_amount, usage_info.mParkHeapFree);
|
||
|
return false;
|
||
|
}
|
||
|
if (usage_info.mMainHeapFree < main_add_amount)
|
||
|
{
|
||
|
Ryan("not enough memory for resize on main heap, need %d, have %d\n", main_add_amount, usage_info.mMainHeapFree);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
#ifdef __PLAT_NGC__
|
||
|
// NGC has problems resizing if the top down heap is low due to UpdateSuperSectors requiring some temporary space.
|
||
|
int required_top_down_heap=TOP_DOWN_REQUIRED_MARGIN;
|
||
|
|
||
|
// If increasing the size of the park, then in the worse case the TD heap may reduce by main_add_amount,
|
||
|
// if none of the fragments got used.
|
||
|
// We want there to be more than TOP_DOWN_REQUIRED_MARGIN after increasing the size, so that the user
|
||
|
// will be able to reduce the size afterwards, so add in main_add_amount to the requirement.
|
||
|
if (main_add_amount > 0)
|
||
|
{
|
||
|
required_top_down_heap += main_add_amount;
|
||
|
}
|
||
|
|
||
|
Mem::Heap *p_top_down_heap = Mem::Manager::sHandle().TopDownHeap();
|
||
|
// Check if there is enough TD heap at the moment
|
||
|
if (p_top_down_heap->mp_region->MemAvailable() < required_top_down_heap)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
Returns max floor height within specified
|
||
|
*/
|
||
|
int CParkManager::GetFloorHeight(GridDims dims, bool *pRetUniformHeight)
|
||
|
{
|
||
|
Dbg_Assert(m_state_on);
|
||
|
Dbg_MsgAssert(m_floor_height_map, ("bad bad monkey!!!"));
|
||
|
|
||
|
int max_height = -10000;
|
||
|
|
||
|
if (pRetUniformHeight)
|
||
|
*pRetUniformHeight = true;
|
||
|
int corner_height = m_floor_height_map[dims.GetX()][dims.GetZ()].mHeight;
|
||
|
|
||
|
for (int x = dims.GetX(); x < dims.GetX() + dims.GetW(); x++)
|
||
|
{
|
||
|
for (int z = dims.GetZ(); z < dims.GetZ() + dims.GetL(); z++)
|
||
|
{
|
||
|
Dbg_MsgAssert(x >= 0 && z >= 0 && x < FLOOR_MAX_WIDTH && z < FLOOR_MAX_LENGTH,
|
||
|
("out of bounds (%d,%d)", x, z));
|
||
|
if (pRetUniformHeight && m_floor_height_map[x][z].mHeight != corner_height)
|
||
|
*pRetUniformHeight = false;
|
||
|
if (m_floor_height_map[x][z].mHeight > max_height)
|
||
|
max_height = m_floor_height_map[x][z].mHeight;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return max_height;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
#if 0
|
||
|
/*
|
||
|
Changes the floor height stored in the height map, A subsequent call to
|
||
|
generate_floor_pieces_from_height_map() will make the geometry.
|
||
|
*/
|
||
|
void CParkManager::SetFloorHeight(GridDims area, int newHeight, bool justDropHighest)
|
||
|
{
|
||
|
for (int x = area.GetX(); x < area.GetX() + area.GetW(); x++)
|
||
|
{
|
||
|
for (int z = area.GetZ(); z < area.GetZ() + area.GetL(); z++)
|
||
|
{
|
||
|
Dbg_MsgAssert(x >= 0 && z >= 0 && x < FLOOR_MAX_WIDTH && z < FLOOR_MAX_LENGTH,
|
||
|
("out of bounds (%d,%d)", x, z));
|
||
|
|
||
|
GridDims test_area(x, 0, z, 1, 1, 1);
|
||
|
if (IsOccupiedByRoad(test_area))
|
||
|
{
|
||
|
m_floor_height_map[x][z].mHeight = 0;
|
||
|
}
|
||
|
if (justDropHighest)
|
||
|
{
|
||
|
if (m_floor_height_map[x][z].mHeight > newHeight)
|
||
|
m_floor_height_map[x][z].mHeight = newHeight;
|
||
|
}
|
||
|
else
|
||
|
m_floor_height_map[x][z].mHeight = newHeight;
|
||
|
}
|
||
|
}
|
||
|
m_compressed_map_flags = ECompressedMapFlags(m_compressed_map_flags & ~(mIN_SYNC_WITH_PARK | mIS_NEWER_THAN_PARK));
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
void CParkManager::ResetFloorHeights(GridDims area)
|
||
|
{
|
||
|
// First move all the pieces in the area such that their y's are zero.
|
||
|
CMapListTemp metas_at_pos = GetAreaMetaPieces(area);
|
||
|
CMapListNode *p_entry = metas_at_pos.GetList();
|
||
|
while (p_entry)
|
||
|
{
|
||
|
CConcreteMetaPiece *p_meta = p_entry->GetConcreteMeta();
|
||
|
if (!p_meta->IsRiser())
|
||
|
{
|
||
|
GridDims meta_area=p_meta->GetArea();
|
||
|
RelocateMetaPiece(p_meta,0,-meta_area.GetY(),0);
|
||
|
|
||
|
// Set the floor heights under the piece to zero. Need to do this as well
|
||
|
// as zeroing the heights for the whole area, in case the piece sticks out
|
||
|
// of the area.
|
||
|
for (int x = meta_area.GetX(); x < meta_area.GetX() + meta_area.GetW(); x++)
|
||
|
{
|
||
|
for (int z = meta_area.GetZ(); z < meta_area.GetZ() + meta_area.GetL(); z++)
|
||
|
{
|
||
|
Dbg_MsgAssert(x >= 0 && z >= 0 && x < FLOOR_MAX_WIDTH && z < FLOOR_MAX_LENGTH,
|
||
|
("out of bounds (%d,%d)", x, z));
|
||
|
m_floor_height_map[x][z].mHeight=0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
p_entry = p_entry->GetNext();
|
||
|
}
|
||
|
|
||
|
// Then set all the floor heights to zero
|
||
|
for (int x = area.GetX(); x < area.GetX() + area.GetW(); x++)
|
||
|
{
|
||
|
for (int z = area.GetZ(); z < area.GetZ() + area.GetL(); z++)
|
||
|
{
|
||
|
Dbg_MsgAssert(x >= 0 && z >= 0 && x < FLOOR_MAX_WIDTH && z < FLOOR_MAX_LENGTH,
|
||
|
("out of bounds (%d,%d)", x, z));
|
||
|
m_floor_height_map[x][z].mHeight=0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// K: Do I need this?
|
||
|
m_compressed_map_flags = ECompressedMapFlags(m_compressed_map_flags & ~(mIN_SYNC_WITH_PARK | mIS_NEWER_THAN_PARK));
|
||
|
|
||
|
// Then rebuild the floor so that the above changes take effect.
|
||
|
RebuildFloor();
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
A "column" is a 3D region defined by the XZ rectangle of 'area'. Its bottom is at height 'y'. All the
|
||
|
metapieces within the column will change y position by the amount specified. Floor heights within the
|
||
|
column will change as well.
|
||
|
|
||
|
Returns true if success.
|
||
|
*/
|
||
|
bool CParkManager::SlideColumn(GridDims area, int bottom, int top, bool up, bool uneven)
|
||
|
{
|
||
|
ESlideColumnFlags flags = ESlideColumnFlags(mFIRST_RECURSE);
|
||
|
if (up) flags = ESlideColumnFlags(flags | mUP);
|
||
|
if (uneven) flags = ESlideColumnFlags(flags | mUNEVEN);
|
||
|
|
||
|
/* Remove bookkeeping left from last SlideColumn */
|
||
|
finish_slide_column();
|
||
|
if (mp_column_slide_list)
|
||
|
mp_column_slide_list->DestroyList();
|
||
|
mp_column_slide_list = NULL;
|
||
|
m_num_metas_killed_in_slide = 0;
|
||
|
m_num_pieces_killed_in_slide = 0;
|
||
|
|
||
|
#if 1
|
||
|
if (uneven && intersection_with_riser_containing_metas(area))
|
||
|
return false;
|
||
|
#endif
|
||
|
|
||
|
if (!slide_column_part_one(area, bottom, top, flags, &mp_column_slide_list))
|
||
|
{
|
||
|
fix_slide_column_part_one_failure();
|
||
|
return false;
|
||
|
}
|
||
|
slide_column_part_two(mp_column_slide_list);
|
||
|
|
||
|
if (!up)
|
||
|
kill_pieces_in_layer_under_area(area);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
Undoes the results of a successful SlideColumn()
|
||
|
*/
|
||
|
void CParkManager::UndoSlideColumn()
|
||
|
{
|
||
|
fix_slide_column_part_one_failure();
|
||
|
|
||
|
CMapListNode *p_node = mp_column_slide_list;
|
||
|
while(p_node)
|
||
|
{
|
||
|
p_node->mp_meta = RelocateMetaPiece(p_node->GetConcreteMeta(), 0, -p_node->mSlideAmount, 0);
|
||
|
p_node = p_node->GetNext();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// K: This is copied from CCursor::ChangeFloorHeight
|
||
|
// Modified to take a GridDims parameter so that it can be used by the clipboard pasting code.
|
||
|
bool CParkManager::ChangeFloorHeight(GridDims dims, int dir)
|
||
|
{
|
||
|
/*
|
||
|
Uneven floor:
|
||
|
If going up, raise to height of topmost
|
||
|
If going down, only lower ones on same level
|
||
|
*/
|
||
|
|
||
|
bool uniform_height;
|
||
|
int height = GetFloorHeight(dims, &uniform_height);
|
||
|
|
||
|
/*
|
||
|
Now,
|
||
|
*/
|
||
|
|
||
|
bool success = true;
|
||
|
if (SlideColumn(dims, dims.GetY(), height, (dir > 0), !uniform_height))
|
||
|
{
|
||
|
//Ryan("Slide column, dir = %d, dims=", dir);
|
||
|
//dims.PrintContents();
|
||
|
|
||
|
// K: This was required in the CCursor version of ChangeFloorHeight, can't
|
||
|
// call it here though cos it is a member function of CCursor ...
|
||
|
//change_cell_pos(0, 0);
|
||
|
|
||
|
Spt::SingletonPtr<CParkEditor> p_editor;
|
||
|
if (RebuildFloor(p_editor->IsParkFull()))
|
||
|
{
|
||
|
HighlightMetasWithGaps(false, NULL);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// out of memory, so reverse slide
|
||
|
UndoSlideColumn();
|
||
|
RebuildFloor();
|
||
|
success = false;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
success = false;
|
||
|
|
||
|
return success;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
Converts a cell based XYZ coordinate to its world coordinate equivalent.
|
||
|
*/
|
||
|
Mth::Vector CParkManager::GridCoordinatesToWorld(const GridDims &cellDims, Mth::Vector *pRetDims)
|
||
|
{
|
||
|
Mth::Vector world_pos(((int) cellDims.GetX() - (int) CParkManager::FLOOR_MAX_WIDTH / 2) * CParkGenerator::CELL_WIDTH,
|
||
|
(int) cellDims.GetY() * CParkGenerator::CELL_HEIGHT,
|
||
|
((int) cellDims.GetZ() - (int) CParkManager::FLOOR_MAX_LENGTH / 2) * CParkGenerator::CELL_LENGTH);
|
||
|
|
||
|
if (pRetDims)
|
||
|
{
|
||
|
(*pRetDims)[X] = cellDims.GetW() * CParkGenerator::CELL_WIDTH;
|
||
|
(*pRetDims)[Y] = cellDims.GetH() * CParkGenerator::CELL_HEIGHT;
|
||
|
(*pRetDims)[Z] = cellDims.GetL() * CParkGenerator::CELL_LENGTH;
|
||
|
#if 0
|
||
|
printf("dims: (%d,%d,%d)-(%d,%d,%d)\n",
|
||
|
cellDims.GetW(), cellDims.GetH(), cellDims.GetL(),
|
||
|
(int) cellDims.GetX() - (int) CParkManager::FLOOR_MAX_WIDTH / 2,
|
||
|
(int) cellDims.GetY(),
|
||
|
(int) cellDims.GetZ() - (int) CParkManager::FLOOR_MAX_LENGTH / 2);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
return world_pos;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
CParkManager *CParkManager::sInstance()
|
||
|
{
|
||
|
Dbg_Assert(sp_instance);
|
||
|
return sp_instance;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
The manager keeps track of a piece database that matches the selection set the user sees at the top of the screen.
|
||
|
*/
|
||
|
CParkManager::CPieceSet &CParkManager::GetPieceSet(int setNumber, int *pMenuSetNumber)
|
||
|
{
|
||
|
Dbg_Assert(setNumber >= 0 && setNumber < MAX_SETS);
|
||
|
|
||
|
int menu_set_number = 0;
|
||
|
for (int s = 0; s < setNumber; s++)
|
||
|
{
|
||
|
if (m_palette_set[s].mVisible)
|
||
|
menu_set_number++;
|
||
|
}
|
||
|
|
||
|
if (pMenuSetNumber)
|
||
|
*pMenuSetNumber = menu_set_number;
|
||
|
|
||
|
return m_palette_set[setNumber];
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
y coordinates, dimensions of 'area' not used.
|
||
|
*/
|
||
|
bool CParkManager::IsOccupiedByRoad(GridDims area)
|
||
|
{
|
||
|
for (uint i = 0; i < m_road_mask_tab_size; i++)
|
||
|
{
|
||
|
bool overlap = true;
|
||
|
if (area.GetX() + area.GetW() <= m_road_mask_tab[i].GetX()) overlap = false;
|
||
|
else if (area.GetX() >= m_road_mask_tab[i].GetX() + m_road_mask_tab[i].GetW()) overlap = false;
|
||
|
else if (area.GetZ() + area.GetL() <= m_road_mask_tab[i].GetZ()) overlap = false;
|
||
|
else if (area.GetZ() >= m_road_mask_tab[i].GetZ() + m_road_mask_tab[i].GetL()) overlap = false;
|
||
|
|
||
|
if (overlap) return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool CParkManager::CanPlacePiecesIn(GridDims cellDims, bool ignoreFloorHeight)
|
||
|
{
|
||
|
Spt::SingletonPtr<CParkEditor> p_editor;
|
||
|
if (p_editor->IsParkFull())
|
||
|
{
|
||
|
ParkEd("p_editor->IsParkFull()");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Check if there are any pieces in the area already.
|
||
|
// Not using GetMetaPiecesAt because it does not detect pieces in lowered cells for some reason.
|
||
|
CMapListTemp metas_at_pos = GetAreaMetaPieces(cellDims);
|
||
|
CMapListNode *p_entry = metas_at_pos.GetList();
|
||
|
while (p_entry)
|
||
|
{
|
||
|
CConcreteMetaPiece *p_meta=p_entry->GetConcreteMeta();
|
||
|
if (!p_meta->IsRiser())
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
p_entry = p_entry->GetNext();
|
||
|
}
|
||
|
|
||
|
if (!ignoreFloorHeight)
|
||
|
{
|
||
|
bool uniform_floor;
|
||
|
int floor_height = GetFloorHeight(cellDims, &uniform_floor);
|
||
|
if (floor_height != cellDims.GetY() || !uniform_floor)
|
||
|
{
|
||
|
ParkEd("floor_height != cellDims.GetY() || !uniform_floor");
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (IsOccupiedByRoad(cellDims))
|
||
|
{
|
||
|
ParkEd("IsOccupiedByRoad(cellDims)");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
// pHalf returns the half number associated with the piece, if any gap found
|
||
|
CGapManager::GapDescriptor *CParkManager::GetGapDescriptor(GridDims &area, int *pHalf)
|
||
|
{
|
||
|
area.SetWHL(1,1,1);
|
||
|
CMapListTemp meta_list = GetMetaPiecesAt(area);
|
||
|
if (meta_list.IsEmpty())
|
||
|
return NULL;
|
||
|
CConcreteMetaPiece *p_meta = meta_list.GetList()->GetConcreteMeta();
|
||
|
|
||
|
int tab_index;
|
||
|
Dbg_Assert(mp_gap_manager);
|
||
|
if (!mp_gap_manager->IsGapAttached(p_meta, &tab_index))
|
||
|
return NULL;
|
||
|
|
||
|
CGapManager::GapDescriptor *pDesc = mp_gap_manager->GetGapDescriptor(tab_index, pHalf);
|
||
|
Dbg_MsgAssert(pDesc, ("couldn't find gap descriptor"));
|
||
|
return pDesc;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
Call from:
|
||
|
|
||
|
read_from_compressed_map_buffer(), CParkEditor, gap adjustment code, gap name changer
|
||
|
|
||
|
-see if meta at cursor loc
|
||
|
-if user working on gap already, fail
|
||
|
-if no prexisiting, remove gap-in-progress
|
||
|
-build descriptor
|
||
|
-add gap
|
||
|
*/
|
||
|
bool CParkManager::AddGap(CGapManager::GapDescriptor &descriptor)
|
||
|
{
|
||
|
Dbg_Assert(mp_gap_manager);
|
||
|
int gap_tab_index = mp_gap_manager->GetFreeGapIndex();
|
||
|
if (gap_tab_index == -1) return false;
|
||
|
|
||
|
for (int i = 0; i < descriptor.numCompleteHalves; i++)
|
||
|
{
|
||
|
// fetch piece associated with this gap half
|
||
|
descriptor.loc[i].SetWHL(1,1,1);
|
||
|
CMapListTemp meta_list = GetMetaPiecesAt(descriptor.loc[i]);
|
||
|
if (meta_list.IsEmpty())
|
||
|
return false;
|
||
|
Dbg_MsgAssert(!meta_list.IsEmpty(), ("am expecting a metapiece here"));
|
||
|
CConcreteMetaPiece *p_meta = meta_list.GetList()->GetConcreteMeta();
|
||
|
Dbg_MsgAssert(p_meta, ("no pieces found at (%d,%d,%d)", descriptor.loc[i].GetX(), descriptor.loc[i].GetY(), descriptor.loc[i].GetZ()));
|
||
|
Dbg_MsgAssert(!mp_gap_manager->IsGapAttached(p_meta, NULL), ("gap is already attached"));
|
||
|
p_meta->set_flag(CMetaPiece::mGAP_ATTACHED);
|
||
|
|
||
|
descriptor.loc[i] = p_meta->GetArea();
|
||
|
|
||
|
#if 0
|
||
|
Ryan(" Placing gap half %d, loc=(%d,%d,%d-%d,%d,%d), rot=%d, left=%d, right=%d\n", i,
|
||
|
descriptor.loc[i].GetX(), descriptor.loc[i].GetY(), descriptor.loc[i].GetZ(),
|
||
|
descriptor.loc[i].GetW(), descriptor.loc[i].GetH(), descriptor.loc[i].GetL(),
|
||
|
descriptor.rot[i], descriptor.leftExtent[i], descriptor.rightExtent[i]);
|
||
|
#endif
|
||
|
|
||
|
GridDims area = p_meta->GetArea();
|
||
|
|
||
|
#if 1
|
||
|
// work out gap positioning
|
||
|
Mth::Vector gap_pos;
|
||
|
float gap_length = 0.0f;
|
||
|
int gap_rot = 0;
|
||
|
switch(descriptor.rot[i])
|
||
|
{
|
||
|
case 0: // east
|
||
|
gap_length = (area.GetL() + descriptor.leftExtent[i] + descriptor.rightExtent[i]) * CParkGenerator::CELL_LENGTH;
|
||
|
gap_pos[X] = (area.GetX() + area.GetW()) * CParkGenerator::CELL_WIDTH - CParkGenerator::CELL_WIDTH / 2.0f - 1.0f;
|
||
|
gap_pos[Z] = (area.GetZ() - descriptor.rightExtent[i]) * CParkGenerator::CELL_LENGTH + gap_length / 2.0f - CParkGenerator::CELL_LENGTH;
|
||
|
gap_pos[Y] = area.GetY() * CParkGenerator::CELL_HEIGHT;
|
||
|
gap_rot = 1;
|
||
|
break;
|
||
|
case 1: // north
|
||
|
gap_length = (area.GetW() + descriptor.leftExtent[i] + descriptor.rightExtent[i]) * CParkGenerator::CELL_WIDTH;
|
||
|
gap_pos[X] = (area.GetX() - descriptor.rightExtent[i]) * CParkGenerator::CELL_WIDTH + gap_length / 2.0f - CParkGenerator::CELL_WIDTH;
|
||
|
gap_pos[Z] = area.GetZ() * CParkGenerator::CELL_LENGTH - CParkGenerator::CELL_LENGTH / 2.0f + 1.0f;
|
||
|
gap_pos[Y] = area.GetY() * CParkGenerator::CELL_HEIGHT;
|
||
|
gap_rot = 0;
|
||
|
break;
|
||
|
case 2: // west
|
||
|
gap_length = (area.GetL() + descriptor.leftExtent[i] + descriptor.rightExtent[i]) * CParkGenerator::CELL_LENGTH;
|
||
|
gap_pos[X] = area.GetX() * CParkGenerator::CELL_WIDTH - CParkGenerator::CELL_WIDTH / 2.0f + 1.0f;
|
||
|
gap_pos[Z] = (area.GetZ() - descriptor.leftExtent[i]) * CParkGenerator::CELL_LENGTH + gap_length / 2.0f - CParkGenerator::CELL_LENGTH;
|
||
|
gap_pos[Y] = area.GetY() * CParkGenerator::CELL_HEIGHT;
|
||
|
gap_rot = 1;
|
||
|
break;
|
||
|
case 3: // south
|
||
|
gap_length = (area.GetW() + descriptor.leftExtent[i] + descriptor.rightExtent[i]) * CParkGenerator::CELL_WIDTH;
|
||
|
gap_pos[X] = (area.GetX() - descriptor.leftExtent[i]) * CParkGenerator::CELL_WIDTH + gap_length / 2.0f - CParkGenerator::CELL_WIDTH;
|
||
|
gap_pos[Z] = (area.GetZ() + area.GetL()) * CParkGenerator::CELL_LENGTH - CParkGenerator::CELL_LENGTH / 2.0f - 1.0f;
|
||
|
gap_pos[Y] = area.GetY() * CParkGenerator::CELL_HEIGHT;
|
||
|
gap_rot = 0;
|
||
|
break;
|
||
|
default:
|
||
|
Dbg_MsgAssert(0, ("not a valid gap rotation"));
|
||
|
break;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
gap_pos[X] -= MAX_WIDTH * CParkGenerator::CELL_WIDTH / 2.0f;
|
||
|
gap_pos[Z] -= MAX_LENGTH * CParkGenerator::CELL_LENGTH / 2.0f;
|
||
|
|
||
|
CClonedPiece *p_gap_piece = mp_generator->CreateGapPiece(gap_pos, gap_length, gap_rot);
|
||
|
p_gap_piece->SetScaleX(gap_length / CParkGenerator::CELL_WIDTH);
|
||
|
|
||
|
// create gap
|
||
|
if (i == 0)
|
||
|
mp_gap_manager->StartGap(p_gap_piece, p_meta, gap_tab_index);
|
||
|
else
|
||
|
mp_gap_manager->EndGap(p_gap_piece, p_meta, gap_tab_index);
|
||
|
}
|
||
|
|
||
|
descriptor.tabIndex = gap_tab_index;
|
||
|
mp_gap_manager->SetGapInfo(gap_tab_index, descriptor);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
Called from: change cursor, cleanup, gap placement, gap adjustment, name change
|
||
|
*/
|
||
|
void CParkManager::RemoveGap(CGapManager::GapDescriptor &descriptor)
|
||
|
{
|
||
|
#if 1
|
||
|
// XXX
|
||
|
for (int half = 0; half < 2; half++)
|
||
|
Ryan(" removing gap half %d (%d,%d,%d),(%d,%d,%d) left=%d right=%d, index=%d\n", half,
|
||
|
descriptor.loc[half].GetX(), descriptor.loc[half].GetY(), descriptor.loc[half].GetZ(),
|
||
|
descriptor.loc[half].GetW(), descriptor.loc[half].GetH(), descriptor.loc[half].GetL(),
|
||
|
descriptor.leftExtent[half], descriptor.rightExtent[half],
|
||
|
descriptor.tabIndex);
|
||
|
#endif
|
||
|
|
||
|
CConcreteMetaPiece *p_meta[2];
|
||
|
for (int half = 0; half < descriptor.numCompleteHalves; half++)
|
||
|
{
|
||
|
CMapListTemp meta_list = GetMetaPiecesAt(descriptor.loc[half]);
|
||
|
Dbg_MsgAssert(!meta_list.IsEmpty(), ("no pieces found at (%d,%d,%d)", descriptor.loc[half].GetX(), descriptor.loc[half].GetY(), descriptor.loc[half].GetZ()));
|
||
|
|
||
|
#if 1
|
||
|
if (!meta_list.IsSingular())
|
||
|
{
|
||
|
// printf("failed singularity, half %d\n", half);
|
||
|
meta_list.PrintContents();
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// go through list, find metapiece matching location above
|
||
|
// there is only SUPPOSED to be one metapiece in list, but sometimes there are more
|
||
|
// and I have no idea why, so fuck it
|
||
|
CMapListNode *p_node = meta_list.GetList();
|
||
|
while(p_node)
|
||
|
{
|
||
|
p_meta[half] = p_node->GetConcreteMeta();
|
||
|
GridDims area = p_meta[half]->GetArea();
|
||
|
|
||
|
if (area.GetX() == descriptor.loc[half].GetX() &&
|
||
|
area.GetY() == descriptor.loc[half].GetY() &&
|
||
|
area.GetZ() == descriptor.loc[half].GetZ())
|
||
|
break;
|
||
|
|
||
|
p_node = p_node->GetNext();
|
||
|
}
|
||
|
|
||
|
//p_meta[half] = meta_list.GetList()->GetConcreteMeta();
|
||
|
p_meta[half]->Highlight(false);
|
||
|
p_meta[half]->clear_flag(CMetaPiece::mGAP_ATTACHED);
|
||
|
}
|
||
|
|
||
|
int tab_index;
|
||
|
Dbg_Assert(mp_gap_manager);
|
||
|
if (mp_gap_manager->IsGapAttached(p_meta[0], &tab_index))
|
||
|
{
|
||
|
mp_gap_manager->RemoveGap(tab_index);
|
||
|
}
|
||
|
|
||
|
descriptor.tabIndex = -1;
|
||
|
// Reset the cancel flags to the default, to fix TT9493
|
||
|
descriptor.mCancelFlags=Script::GetInteger(CRCD(0x9a27e74d,"Cancel_Ground"));
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void CParkManager::RemoveGap(CConcreteMetaPiece *pMeta)
|
||
|
{
|
||
|
int tab_index;
|
||
|
Dbg_Assert(mp_gap_manager);
|
||
|
if (!mp_gap_manager->IsGapAttached(pMeta, &tab_index))
|
||
|
return;
|
||
|
|
||
|
int half;
|
||
|
CGapManager::GapDescriptor *pDesc = mp_gap_manager->GetGapDescriptor(tab_index, &half);
|
||
|
Dbg_MsgAssert(pDesc, ("couldn't find gap descriptor"));
|
||
|
RemoveGap(*pDesc);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void CParkManager::HighlightMetasWithGaps(bool highlightOn, CGapManager::GapDescriptor *pDesc)
|
||
|
{
|
||
|
CMapListNode *p_node = mp_concrete_metapiece_list;
|
||
|
while (p_node)
|
||
|
{
|
||
|
if (p_node->GetConcreteMeta()->m_flags & CMetaPiece::mGAP_ATTACHED)
|
||
|
p_node->GetConcreteMeta()->Highlight(highlightOn, true);
|
||
|
p_node = p_node->GetNext();
|
||
|
}
|
||
|
|
||
|
mp_generator->SetGapPiecesVisible(false);
|
||
|
|
||
|
if (highlightOn && pDesc && pDesc->tabIndex >= 0)
|
||
|
{
|
||
|
mp_gap_manager->MakeGapWireframe(pDesc->tabIndex);
|
||
|
}
|
||
|
else if (!highlightOn)
|
||
|
{
|
||
|
mp_generator->SetGapPiecesVisible(false);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Added for use by s_generate_summary_info in mcfunc.cpp
|
||
|
void CParkManager::GetSummaryInfoFromBuffer(uint8 *p_buffer, int *p_numGaps, int *p_numMetas, uint16 *p_theme, uint32 *p_todScript, int *p_width, int *p_length)
|
||
|
{
|
||
|
CompressedMapHeader *p_header=(CompressedMapHeader*)p_buffer;
|
||
|
*p_width=p_header->mW;
|
||
|
*p_length=p_header->mL;
|
||
|
*p_numGaps=p_header->mNumGaps;
|
||
|
*p_numMetas=p_header->mNumMetas;
|
||
|
*p_theme=p_header->mTheme;
|
||
|
if (p_header->mTODScript)
|
||
|
{
|
||
|
*p_todScript=p_header->mTODScript;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*p_todScript=CRCD(0x1ca1ff20,"default");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
Creates a "stack" of risers within the specified vertical column. If !simpleBuild, will keep exisiting
|
||
|
riser metapieces if they do the job.
|
||
|
|
||
|
'top' refers to cell position of top of topmost riser
|
||
|
*/
|
||
|
void CParkManager::output_riser_stack(BuildFloorParams ¶ms)
|
||
|
{
|
||
|
Dbg_MsgAssert(m_floor_height_map, ("bad bad monkey!!!"));
|
||
|
|
||
|
Dbg_MsgAssert(params.top >= -16 && params.top <= 15, ("faulty floor height %d, at (%d,%d)", params.top, params.x, params.z));
|
||
|
|
||
|
int lowest_neighbor = 10000;
|
||
|
|
||
|
// work out lowest neighbor
|
||
|
if (params.x > m_park_far_bounds.GetX())
|
||
|
{
|
||
|
if (m_floor_height_map[params.x-1][params.z].mHeight < lowest_neighbor)
|
||
|
lowest_neighbor = m_floor_height_map[params.x-1][params.z].mHeight;
|
||
|
}
|
||
|
else
|
||
|
lowest_neighbor = (lowest_neighbor > 0) ? 0 : lowest_neighbor;
|
||
|
|
||
|
if (params.x < m_park_far_bounds.GetX() + m_park_far_bounds.GetW() - 1)
|
||
|
{
|
||
|
if (m_floor_height_map[params.x+1][params.z].mHeight < lowest_neighbor)
|
||
|
lowest_neighbor = m_floor_height_map[params.x+1][params.z].mHeight;
|
||
|
}
|
||
|
else
|
||
|
lowest_neighbor = (lowest_neighbor > 0) ? 0 : lowest_neighbor;
|
||
|
|
||
|
if (params.z > m_park_far_bounds.GetZ())
|
||
|
{
|
||
|
if (m_floor_height_map[params.x][params.z-1].mHeight < lowest_neighbor)
|
||
|
lowest_neighbor = m_floor_height_map[params.x][params.z-1].mHeight;
|
||
|
}
|
||
|
else
|
||
|
lowest_neighbor = (lowest_neighbor > 0) ? 0 : lowest_neighbor;
|
||
|
|
||
|
if (params.z < m_park_far_bounds.GetZ() + m_park_far_bounds.GetL() - 1)
|
||
|
{
|
||
|
if (m_floor_height_map[params.x][params.z+1].mHeight < lowest_neighbor)
|
||
|
lowest_neighbor = m_floor_height_map[params.x][params.z+1].mHeight;
|
||
|
}
|
||
|
else
|
||
|
lowest_neighbor = (lowest_neighbor > 0) ? 0 : lowest_neighbor;
|
||
|
|
||
|
EFloorFlags flags = mHAS_BOTTOM;
|
||
|
GridDims road_test_area(params.x, 0, params.z, 1, 1, 1);
|
||
|
if (IsOccupiedByRoad(road_test_area))
|
||
|
{
|
||
|
flags = EFloorFlags(flags | mNO_COVER);
|
||
|
params.top = 0;
|
||
|
}
|
||
|
|
||
|
if (lowest_neighbor < params.top)
|
||
|
{
|
||
|
params.bottom = lowest_neighbor;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
params.bottom = params.top-1;
|
||
|
flags = EFloorFlags(flags & ~mHAS_BOTTOM);
|
||
|
}
|
||
|
|
||
|
params.flags = flags;
|
||
|
for (int y = params.bottom; y < params.top; y++)
|
||
|
{
|
||
|
if (y == params.top-1 && !(flags & mNO_COVER))
|
||
|
params.flags = EFloorFlags(params.flags | mHAS_TOP);
|
||
|
|
||
|
if (y == -1)
|
||
|
{
|
||
|
if (y <= lowest_neighbor)
|
||
|
params.heightSlotOffset = 3; // group 4 -- bottom level, just below surface
|
||
|
else
|
||
|
params.heightSlotOffset = 2; // group 3 -- not bottom level, just below surface
|
||
|
}
|
||
|
else if (y < -1)
|
||
|
{
|
||
|
if (y <= lowest_neighbor)
|
||
|
params.heightSlotOffset = 0; // group 1 -- bottom level, not touching surface
|
||
|
else
|
||
|
params.heightSlotOffset = 1; // group 2 -- not bottom level, not touching surface
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (y == params.top-1)
|
||
|
{
|
||
|
if (y == 0)
|
||
|
params.heightSlotOffset = 4; // group 5 -- top level risers sitting on surface
|
||
|
else
|
||
|
params.heightSlotOffset = 7; // group 8 -- risers sitting above surface, top level
|
||
|
}
|
||
|
else if (y == 0)
|
||
|
params.heightSlotOffset = 5; // group 6 -- risers sitting on surface, but not top level
|
||
|
else
|
||
|
params.heightSlotOffset = 6; // group 7 -- risers sitting above surface, not top level
|
||
|
}
|
||
|
|
||
|
params.y = y;
|
||
|
if (params.simpleBuild)
|
||
|
build_add_floor_piece_simple(params);
|
||
|
else
|
||
|
build_add_floor_piece(params);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
Creates a riser metapiece, if one is needed.
|
||
|
*/
|
||
|
void CParkManager::build_add_floor_piece(BuildFloorParams ¶ms)
|
||
|
{
|
||
|
uint32 type = TYPE_EMPTY_BLOCK;
|
||
|
if (params.flags & mHAS_BOTTOM)
|
||
|
{
|
||
|
if (params.flags & mHAS_TOP)
|
||
|
type = m_riser_piece_checksum[params.heightSlotOffset][0];
|
||
|
else
|
||
|
type = m_riser_piece_checksum[params.heightSlotOffset][1];
|
||
|
}
|
||
|
else if (params.flags & mHAS_TOP)
|
||
|
{
|
||
|
type = m_riser_piece_checksum[params.heightSlotOffset][2];
|
||
|
}
|
||
|
else
|
||
|
return;
|
||
|
|
||
|
// see if floor already included in metapiece at this position
|
||
|
int floor_height = params.y + 1;
|
||
|
Dbg_MsgAssert(floor_height >= -16 && floor_height <= 15, ("faulty floor height %d, at (%d,%d,%d)",
|
||
|
floor_height, params.x, params.y, params.z));
|
||
|
uint32 floor_bit = (1<<(floor_height+16));
|
||
|
if (m_floor_height_map[params.x][params.z].mEnclosedFloor & floor_bit)
|
||
|
{
|
||
|
#if 0
|
||
|
printf("preexisting riser at %d (%d,%d)!\n", floor_height, params.x, params.z);
|
||
|
#endif
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// see if floor piece is already there and if it has desired type
|
||
|
GridDims test_dims(params.x, params.y, params.z, 1, 1, 1);
|
||
|
CMapListNode *p_node = GetMetaPiecesAt(test_dims);
|
||
|
if (p_node)
|
||
|
{
|
||
|
if (p_node->GetMeta()->m_name_checksum == type)
|
||
|
{
|
||
|
/*
|
||
|
if (type == TYPE_FLOOR_BLOCK && 0)
|
||
|
printf("preserving floor block at %d,%d,%d\n",
|
||
|
p_node->GetMeta()->GetArea().GetX(),
|
||
|
p_node->GetMeta()->GetArea().GetY(),
|
||
|
p_node->GetMeta()->GetArea().GetZ());
|
||
|
*/
|
||
|
|
||
|
// undo mark for kill
|
||
|
p_node->GetMeta()->clear_flag(CMetaPiece::mMARK_FOR_KILL);
|
||
|
p_node->DestroyList();
|
||
|
return;
|
||
|
}
|
||
|
else
|
||
|
p_node->DestroyList();
|
||
|
}
|
||
|
|
||
|
if (!params.dryRun)
|
||
|
{
|
||
|
#ifdef USE_BUILD_LIST
|
||
|
enum
|
||
|
{
|
||
|
MAX_BUILD_LIST_SIZE=10000,
|
||
|
};
|
||
|
Dbg_MsgAssert(m_build_list_size<MAX_BUILD_LIST_SIZE-1,("Build list overflow"));
|
||
|
|
||
|
if (!mp_build_list_entry)
|
||
|
{
|
||
|
Dbg_MsgAssert(m_build_list_size==0,("Expected m_build_list_size to be 0"));
|
||
|
#ifndef __USE_EXTERNAL_BUFFER__
|
||
|
Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().FrontEndHeap());
|
||
|
mp_build_list_entry=(SBuildListEntry*)Mem::Malloc(MAX_BUILD_LIST_SIZE * sizeof(SBuildListEntry));
|
||
|
Mem::Manager::sHandle().PopContext();
|
||
|
#else
|
||
|
ACQUIRE_BUFFER
|
||
|
mp_build_list_entry = (SBuildListEntry*)__EXTERNAL_BUFFER__;
|
||
|
#endif
|
||
|
}
|
||
|
mp_build_list_entry[m_build_list_size].mType=type;
|
||
|
GridDims pos(params.x, params.y, params.z);
|
||
|
mp_build_list_entry[m_build_list_size].mPos=pos;
|
||
|
++m_build_list_size;
|
||
|
#else
|
||
|
CConcreteMetaPiece *p_out = CreateConcreteMeta(GetAbstractMeta(type));
|
||
|
GridDims pos(params.x, params.y, params.z);
|
||
|
AddMetaPieceToPark(pos, p_out);
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#if 0
|
||
|
if (type == TYPE_FLOOR_BLOCK)
|
||
|
printf("adding floor block at %d,%d,%d\n",
|
||
|
params.x,
|
||
|
params.y,
|
||
|
params.z);
|
||
|
|
||
|
if (type == TYPE_FLOOR_WALL_BLOCK)
|
||
|
printf("adding floor wall block at %d,%d,%d\n",
|
||
|
params.x,
|
||
|
params.y,
|
||
|
params.z);
|
||
|
#endif
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
params.addCount2 += GetAbstractMeta(type)->m_num_used_entries;
|
||
|
}
|
||
|
params.addCount++;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
Creates a riser metapiece, period.
|
||
|
*/
|
||
|
void CParkManager::build_add_floor_piece_simple(BuildFloorParams ¶ms)
|
||
|
{
|
||
|
uint32 type = TYPE_EMPTY_BLOCK;
|
||
|
if (params.flags & mHAS_BOTTOM)
|
||
|
{
|
||
|
if (params.flags & mHAS_TOP)
|
||
|
type = m_riser_piece_checksum[params.heightSlotOffset][0];
|
||
|
else
|
||
|
type = m_riser_piece_checksum[params.heightSlotOffset][1];
|
||
|
}
|
||
|
else if (params.flags & mHAS_TOP)
|
||
|
{
|
||
|
type = m_riser_piece_checksum[params.heightSlotOffset][2];
|
||
|
}
|
||
|
else
|
||
|
return;
|
||
|
|
||
|
|
||
|
CConcreteMetaPiece *p_out = CreateConcreteMeta(GetAbstractMeta(type));
|
||
|
GridDims pos(params.x, params.y, params.z);
|
||
|
AddMetaPieceToPark(pos, p_out);
|
||
|
params.addCount++;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
Some metapieces contain risers.
|
||
|
*/
|
||
|
void CParkManager::apply_meta_contained_risers_to_floor(CConcreteMetaPiece *pMetaPiece, bool add)
|
||
|
{
|
||
|
for (uint i = 0; i < pMetaPiece->m_num_used_entries; i++)
|
||
|
{
|
||
|
CClonedPiece *p_piece = pMetaPiece->GetContainedPiece(i)->CastToCClonedPiece();
|
||
|
|
||
|
// see if this piece affects floor height
|
||
|
SMetaDescriptor &desc = pMetaPiece->get_desc_at_index(i);
|
||
|
if (desc.mRiser)
|
||
|
{
|
||
|
GridDims riser_area;
|
||
|
p_piece->GetCellDims(&riser_area);
|
||
|
riser_area[X] = pMetaPiece->m_cell_area.GetX() + desc.mX;
|
||
|
riser_area[Y] = pMetaPiece->m_cell_area.GetY() + desc.mY;
|
||
|
riser_area[Z] = pMetaPiece->m_cell_area.GetZ() + desc.mZ;
|
||
|
|
||
|
int start_x = riser_area.GetX();
|
||
|
int end_x = start_x + riser_area.GetW();
|
||
|
int start_z = riser_area.GetZ();
|
||
|
int end_z = start_z + riser_area.GetL();
|
||
|
#if 0
|
||
|
printf("raising floor at: (%d,%d,%d)+(%d,%d,%d), desc.mRiser is %d at 0x%x, index %d\n",
|
||
|
pMetaPiece->m_cell_area.GetX(), pMetaPiece->m_cell_area.GetY(), pMetaPiece->m_cell_area.GetZ(),
|
||
|
desc.mX, desc.mY, desc.mZ, desc.mRiser, &desc.mRiser, i);
|
||
|
#endif
|
||
|
for (int x = start_x; x < end_x; x++)
|
||
|
{
|
||
|
for (int z = start_z; z < end_z; z++)
|
||
|
{
|
||
|
Dbg_MsgAssert(x >= 0 && z >= 0 && x < FLOOR_MAX_WIDTH && z < FLOOR_MAX_LENGTH,
|
||
|
("out of bounds (%d,%d)", x, z));
|
||
|
if (add)
|
||
|
{
|
||
|
if (m_floor_height_map[x][z].mHeight < riser_area.GetY() + riser_area.GetH())
|
||
|
m_floor_height_map[x][z].mHeight = riser_area.GetY() + riser_area.GetH();
|
||
|
if (m_floor_height_map[x][z].mHeight > 15)
|
||
|
m_floor_height_map[x][z].mHeight = 15;
|
||
|
if (m_floor_height_map[x][z].mHeight < -16)
|
||
|
m_floor_height_map[x][z].mHeight = -16;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Are there non-riser metapieces above this one?
|
||
|
GridDims area_above = riser_area;
|
||
|
area_above[Y] = riser_area.GetY() + riser_area.GetH();
|
||
|
area_above.MakeInfinitelyHigh();
|
||
|
CMapListTemp meta_list = GetMetaPiecesAt(area_above, Mth::ROT_0, NULL, true);
|
||
|
if (meta_list.IsEmpty())
|
||
|
{
|
||
|
if (m_floor_height_map[x][z].mHeight > riser_area.GetY())
|
||
|
m_floor_height_map[x][z].mHeight = riser_area.GetY();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (int y = riser_area.GetY(); y < riser_area.GetY() + riser_area.GetH(); y++)
|
||
|
{
|
||
|
if (add)
|
||
|
m_floor_height_map[x][z].mEnclosedFloor |= (1<<(y+16+1));
|
||
|
else
|
||
|
m_floor_height_map[x][z].mEnclosedFloor &= ~(1<<(y+16+1));
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
printf(" floor change: (%d,%d) to %d, flags 0x%x, bottom %d, top %d\n",
|
||
|
x, z, m_floor_height_map[x][z].mHeight, m_floor_height_map[x][z].mEnclosedFloor,
|
||
|
riser_area.GetY(), riser_area.GetY() + riser_area.GetH());
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
bool CParkManager::intersection_with_riser_containing_metas(GridDims area)
|
||
|
{
|
||
|
area.MakeInfiniteOnY();
|
||
|
|
||
|
CMapListTemp list = GetMetaPiecesAt(area, Mth::ROT_0, NULL, true);
|
||
|
CMapListNode *p_node = list.GetList();
|
||
|
while (p_node)
|
||
|
{
|
||
|
if (p_node->GetConcreteMeta()->m_flags & CMetaPiece::mCONTAINS_RISERS)
|
||
|
return true;
|
||
|
p_node = p_node->GetNext();
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
Change map height. Add metapieces in column to move list. Repeat this for every metapiece in move list. No
|
||
|
metapiece will end up in move list twice, though.
|
||
|
|
||
|
Good LUCK figuring this out. :)
|
||
|
*/
|
||
|
bool CParkManager::slide_column_part_one(GridDims area, int bottom, int top, ESlideColumnFlags flags, CMapListNode **ppMoveList)
|
||
|
{
|
||
|
GridDims test_area = area;
|
||
|
test_area[Y] = (uint8) bottom;
|
||
|
if (flags & mFIRST_RECURSE)
|
||
|
test_area.MakeInfiniteOnY();
|
||
|
else
|
||
|
test_area.MakeInfinitelyHigh();
|
||
|
|
||
|
for (int x = test_area.GetX(); x < test_area.GetX() + test_area.GetW(); x++)
|
||
|
{
|
||
|
for (int z = test_area.GetZ(); z < test_area.GetZ() + test_area.GetL(); z++)
|
||
|
{
|
||
|
Dbg_MsgAssert(x >= 0 && z >= 0 && x < FLOOR_MAX_WIDTH && z < FLOOR_MAX_LENGTH,
|
||
|
("out of bounds (%d,%d)", x, z));
|
||
|
if (!m_floor_height_map[x][z].mMarkAsSlid)
|
||
|
{
|
||
|
int change_amount = 0;
|
||
|
if (flags & mUNEVEN)
|
||
|
{
|
||
|
if (flags & mUP)
|
||
|
change_amount = top - m_floor_height_map[x][z].mHeight;
|
||
|
else
|
||
|
change_amount = (m_floor_height_map[x][z].mHeight == top) ? -1 : 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (flags & mUP)
|
||
|
change_amount = 1;
|
||
|
else
|
||
|
change_amount = -1;
|
||
|
}
|
||
|
|
||
|
m_floor_height_map[x][z].mHeight += change_amount;
|
||
|
m_floor_height_map[x][z].mSlideAmount = change_amount;
|
||
|
|
||
|
if (m_floor_height_map[x][z].mHeight < -16 || m_floor_height_map[x][z].mHeight > 15)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
m_floor_height_map[x][z].mMarkAsSlid = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CMapListTemp list = GetMetaPiecesAt(test_area, Mth::ROT_0, NULL, true);
|
||
|
CMapListNode *p_node = list.GetList();
|
||
|
while (p_node)
|
||
|
{
|
||
|
CConcreteMetaPiece *p_meta = p_node->GetConcreteMeta();
|
||
|
GridDims meta_area = p_meta->GetArea();
|
||
|
|
||
|
if (!p_meta->IsRiser() && !(p_meta->m_flags & CMetaPiece::mMARK_AS_SLID))
|
||
|
{
|
||
|
/*
|
||
|
Are we actually going to move this meta?
|
||
|
|
||
|
Even surface:
|
||
|
-yes
|
||
|
|
||
|
Uneven
|
||
|
-up: only if lower than top
|
||
|
-down
|
||
|
*/
|
||
|
|
||
|
p_meta->set_flag(CMetaPiece::mMARK_AS_SLID);
|
||
|
Mem::Manager::sHandle().PushContext(mp_generator->GetParkEditorHeap());
|
||
|
CMapListNode *p_new_node = new CMapListNode();
|
||
|
Mem::Manager::sHandle().PopContext();
|
||
|
p_new_node->mp_next = *ppMoveList;
|
||
|
p_new_node->mp_meta = p_meta;
|
||
|
*ppMoveList = p_new_node;
|
||
|
|
||
|
#if 0
|
||
|
Ryan("rising meta at: ");
|
||
|
p_meta->GetArea().PrintContents();
|
||
|
#endif
|
||
|
|
||
|
p_new_node->mSlideAmount = 0;
|
||
|
if (flags & mUNEVEN)
|
||
|
{
|
||
|
if (flags & mUP)
|
||
|
p_new_node->mSlideAmount = top - meta_area.GetY();
|
||
|
else
|
||
|
p_new_node->mSlideAmount = (meta_area.GetY() == top) ? -1 : 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (flags & mUP)
|
||
|
p_new_node->mSlideAmount = 1;
|
||
|
else
|
||
|
p_new_node->mSlideAmount = -1;
|
||
|
}
|
||
|
|
||
|
ESlideColumnFlags recurse_flags = ESlideColumnFlags(flags & ~mFIRST_RECURSE);
|
||
|
if (!slide_column_part_one(meta_area, meta_area.GetY(), top, recurse_flags, ppMoveList))
|
||
|
return false;
|
||
|
}
|
||
|
p_node = p_node->GetNext();
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void CParkManager::fix_slide_column_part_one_failure()
|
||
|
{
|
||
|
for (int x = 0; x < FLOOR_MAX_WIDTH; x++)
|
||
|
{
|
||
|
for (int z = 0; z < FLOOR_MAX_LENGTH; z++)
|
||
|
{
|
||
|
if (m_floor_height_map[x][z].mMarkAsSlid)
|
||
|
{
|
||
|
m_floor_height_map[x][z].mMarkAsSlid = false;
|
||
|
m_floor_height_map[x][z].mHeight -= m_floor_height_map[x][z].mSlideAmount;
|
||
|
}
|
||
|
if (m_floor_height_map[x][z].mHeight > 15)
|
||
|
m_floor_height_map[x][z].mHeight = 15;
|
||
|
if (m_floor_height_map[x][z].mHeight < -16)
|
||
|
m_floor_height_map[x][z].mHeight = -16;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
Go through move list, relocate each metapiece
|
||
|
*/
|
||
|
void CParkManager::slide_column_part_two(CMapListNode *pMoveList)
|
||
|
{
|
||
|
//Mem::Heap *p_top_down_heap = Mem::Manager::sHandle().TopDownHeap();
|
||
|
|
||
|
CMapListNode *p_node = pMoveList;
|
||
|
while (p_node)
|
||
|
{
|
||
|
CConcreteMetaPiece *p_meta = p_node->GetConcreteMeta();
|
||
|
|
||
|
if (p_node->mSlideAmount < 0)
|
||
|
{
|
||
|
kill_pieces_in_layer_under_area(p_meta->GetArea());
|
||
|
}
|
||
|
|
||
|
p_node->mp_meta = RelocateMetaPiece(p_meta, 0, p_node->mSlideAmount, 0);
|
||
|
|
||
|
//if (p_top_down_heap->mp_region->MemAvailable() < 200000)
|
||
|
//{
|
||
|
// GetGenerator()->GetClonedScene()->UpdateSuperSectors();
|
||
|
//}
|
||
|
|
||
|
p_node = p_node->GetNext();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void CParkManager::kill_pieces_in_layer_under_area(GridDims area)
|
||
|
{
|
||
|
GridDims kill_area = area;
|
||
|
kill_area[Y] = area.GetY() - 1;
|
||
|
kill_area[H] = 1;
|
||
|
|
||
|
#if 0
|
||
|
printf("killing metas in area: (%d,%d,%d)-(%d,%d,%d)\n",
|
||
|
kill_area.GetX(), kill_area.GetY(), kill_area.GetZ(),
|
||
|
kill_area.GetW(), kill_area.GetH(), kill_area.GetL());
|
||
|
#endif
|
||
|
|
||
|
uint32 killed_result = DestroyMetasInArea(kill_area, mEXCLUDE_PIECES_MARKED_AS_SLID);
|
||
|
m_num_metas_killed_in_slide += killed_result>>16;
|
||
|
m_num_pieces_killed_in_slide += killed_result & 0xFFFF;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
Undo 'slid' markers in floor map array. Turn off MARK_AS_SLID flags on metapieces.
|
||
|
*/
|
||
|
void CParkManager::finish_slide_column()
|
||
|
{
|
||
|
for (int x = m_park_far_bounds.GetX(); x < m_park_far_bounds.GetX() + m_park_far_bounds.GetW(); x++)
|
||
|
{
|
||
|
for (int z = m_park_far_bounds.GetZ(); z < m_park_far_bounds.GetZ() + m_park_far_bounds.GetL(); z++)
|
||
|
{
|
||
|
Dbg_MsgAssert(x >= 0 && z >= 0 && x < FLOOR_MAX_WIDTH && z < FLOOR_MAX_LENGTH,
|
||
|
("out of bounds (%d,%d)", x, z));
|
||
|
m_floor_height_map[x][z].mMarkAsSlid = false;
|
||
|
m_floor_height_map[x][z].mSlideAmount = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CMapListNode *p_node = mp_concrete_metapiece_list;
|
||
|
while(p_node)
|
||
|
{
|
||
|
p_node->GetConcreteMeta()->clear_flag(CMetaPiece::mMARK_AS_SLID);
|
||
|
p_node = p_node->GetNext();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifdef USE_BUILD_LIST
|
||
|
void CParkManager::create_metas_in_build_list()
|
||
|
{
|
||
|
for (int i=0; i<m_build_list_size; ++i)
|
||
|
{
|
||
|
Dbg_MsgAssert(mp_build_list_entry,("NULL mp_build_list_entry"));
|
||
|
CConcreteMetaPiece *p_out = CreateConcreteMeta(GetAbstractMeta(mp_build_list_entry[i].mType));
|
||
|
AddMetaPieceToPark(mp_build_list_entry[i].mPos, p_out);
|
||
|
}
|
||
|
m_build_list_size=0;
|
||
|
if (mp_build_list_entry)
|
||
|
{
|
||
|
#ifndef __USE_EXTERNAL_BUFFER__
|
||
|
Mem::Free(mp_build_list_entry);
|
||
|
#endif
|
||
|
mp_build_list_entry=NULL;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
Turns the height map into actual riser geometry. Creates all the CConcreteMetaPieces that are needed, destroys
|
||
|
the ones that aren't. If an existing CConcreteMetaPiece matches the height map, it is preserved.
|
||
|
|
||
|
The simpleBuild parameter causes all riser metapieces to be destroyed and rebuilt. Use this parameter
|
||
|
when you know you'll be doing this anyway.
|
||
|
|
||
|
dryRun means don't actually create or destroy pieces, just make a count
|
||
|
*/
|
||
|
bool CParkManager::generate_floor_pieces_from_height_map(bool simpleBuild, bool dryRun)
|
||
|
{
|
||
|
ParkEd("CParkManager::generate_floor_pieces_from_height_map(simpleBuild = %d)", simpleBuild);
|
||
|
|
||
|
Dbg_Assert(m_state_on);
|
||
|
|
||
|
//printf("=============== generate_floor_pieces_from_height_map() ========================\n");
|
||
|
|
||
|
// mark all existing floor pieces for destruction (some will be unmarked later)
|
||
|
int mark_count = 0; // counts all risers existing upon entering this function
|
||
|
CMapListNode *p_node = mp_concrete_metapiece_list;
|
||
|
while(p_node)
|
||
|
{
|
||
|
CMetaPiece *p_meta = p_node->GetMeta();
|
||
|
if (p_meta->IsRiser())
|
||
|
{
|
||
|
p_meta->set_flag(CMetaPiece::mMARK_FOR_KILL);
|
||
|
mark_count++;
|
||
|
}
|
||
|
p_node = p_node->GetNext();
|
||
|
}
|
||
|
mark_count += m_num_metas_killed_in_slide;
|
||
|
|
||
|
#ifdef USE_BUILD_LIST
|
||
|
m_build_list_size=0;
|
||
|
Dbg_MsgAssert(mp_build_list_entry==NULL,("Non-NULL mp_build_list_entry"));
|
||
|
#endif
|
||
|
|
||
|
|
||
|
Dbg_MsgAssert(m_floor_height_map, ("bad bad monkey!!!"));
|
||
|
BuildFloorParams riser_build_params;
|
||
|
riser_build_params.simpleBuild = simpleBuild;
|
||
|
riser_build_params.dryRun = dryRun;
|
||
|
riser_build_params.addCount = 0; // counts all risers added by the output_riser_stack() calls
|
||
|
riser_build_params.addCount2 = 0;
|
||
|
for (int x = m_park_near_bounds.GetX() - 1; x < m_park_near_bounds.GetX() + m_park_near_bounds.GetW() + 1; x++)
|
||
|
{
|
||
|
for (int z = m_park_near_bounds.GetZ() - 1; z < m_park_near_bounds.GetZ() + m_park_near_bounds.GetL() + 1; z++)
|
||
|
{
|
||
|
Dbg_MsgAssert(x >= 0 && z >= 0 && x < FLOOR_MAX_WIDTH && z < FLOOR_MAX_LENGTH,
|
||
|
("out of bounds (%d,%d)", x, z));
|
||
|
riser_build_params.x = x;
|
||
|
riser_build_params.z = z;
|
||
|
riser_build_params.top = m_floor_height_map[x][z].mHeight;
|
||
|
riser_build_params.bottom = m_park_far_bounds.GetY();
|
||
|
output_riser_stack(riser_build_params);
|
||
|
}
|
||
|
|
||
|
#ifdef __PLAT_XBOX__
|
||
|
// On the XBox the large amount of CPU time taken up by rebuilding the park causes a glitch when
|
||
|
// wma music is playing. So make sure Pcm::Update gets called often whilst in this inner loop.
|
||
|
DirectSoundDoWork();
|
||
|
Pcm::Update();
|
||
|
#endif // __PLAT_XBOX__
|
||
|
#ifdef __PLAT_NGC__
|
||
|
// Same for the NGC ...
|
||
|
Pcm::Update();
|
||
|
#endif // __PLAT_NGC__
|
||
|
}
|
||
|
|
||
|
// remove all marked floor piece
|
||
|
int kill_count = 0; // counts risers killed
|
||
|
int kill_count2 = 0; // counts contained pieces
|
||
|
int left_count = 0; // counts risers not killed plus those added
|
||
|
p_node = mp_concrete_metapiece_list;
|
||
|
while(p_node)
|
||
|
{
|
||
|
CMapListNode *p_nextNode = p_node->GetNext(); // get next node now, as DestroyConcretMeta, below, can delete current node
|
||
|
CMetaPiece *p_meta = p_node->GetMeta();
|
||
|
if (p_meta->m_flags & CMetaPiece::mMARK_FOR_KILL)
|
||
|
{
|
||
|
kill_count++;
|
||
|
kill_count2 += p_meta->m_num_used_entries;
|
||
|
if (!dryRun)
|
||
|
{
|
||
|
//p_node->GetConcreteMeta()->GetArea().PrintContents();
|
||
|
DestroyConcreteMeta(p_node->GetConcreteMeta(), mDONT_DESTROY_PIECES_ABOVE);
|
||
|
}
|
||
|
}
|
||
|
else if (p_meta->IsRiser())
|
||
|
left_count++;
|
||
|
p_node = p_nextNode;
|
||
|
}
|
||
|
kill_count += m_num_metas_killed_in_slide;
|
||
|
kill_count2 += m_num_pieces_killed_in_slide;
|
||
|
|
||
|
|
||
|
#ifdef USE_BUILD_LIST
|
||
|
mp_generator->GetClonedScene()->UpdateSuperSectors();
|
||
|
if (!dryRun)
|
||
|
{
|
||
|
left_count+=m_build_list_size;
|
||
|
create_metas_in_build_list();
|
||
|
}
|
||
|
Dbg_MsgAssert(mp_build_list_entry==NULL,("Non-NULL mp_build_list_entry"));
|
||
|
#endif
|
||
|
|
||
|
// risers preexisting + risers added - risers killed == risers left
|
||
|
Dbg_Assert(dryRun || riser_build_params.addCount == left_count + kill_count - mark_count);
|
||
|
|
||
|
//printf("riser_build_params.addCount = %d kill_count = %d, kill_count2 = %d\n",riser_build_params.addCount,kill_count,kill_count2);
|
||
|
|
||
|
//if (dryRun)
|
||
|
// printf("DRYRUN: ");
|
||
|
//printf("marked %d pieces, killed %d, not killed %d, left %d, added %d\n",
|
||
|
// mark_count, kill_count, mark_count - kill_count, left_count, riser_build_params.addCount);
|
||
|
//printf("addCount2 = %d, killCount2 = %d\n", riser_build_params.addCount2, kill_count2);
|
||
|
|
||
|
if (dryRun && (riser_build_params.addCount > kill_count || riser_build_params.addCount2 > kill_count2))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//if (dryRun && (riser_build_params.addCount - kill_count > 200))
|
||
|
//{
|
||
|
// // Don't allow height changes that will result in too many pieces being created, to prevent
|
||
|
// // running out of memory.
|
||
|
// return false;
|
||
|
//}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
Create new list if none
|
||
|
*/
|
||
|
void CParkManager::add_metapiece_to_node_list(CMetaPiece *pMetaToAdd, CMapListNode **ppList)
|
||
|
{
|
||
|
CMapListNode *p_test_node = *ppList;
|
||
|
while(p_test_node)
|
||
|
{
|
||
|
if (p_test_node->GetMeta() == pMetaToAdd) return; // it's in there
|
||
|
p_test_node = p_test_node->GetNext();
|
||
|
}
|
||
|
|
||
|
// not in list already, so add it
|
||
|
Mem::Manager::sHandle().PushContext(mp_generator->GetParkEditorHeap());
|
||
|
CMapListNode *p_new_node = new CMapListNode();
|
||
|
Mem::Manager::sHandle().PopContext();
|
||
|
p_new_node->mp_meta = pMetaToAdd;
|
||
|
p_new_node->mp_next = *ppList;
|
||
|
*ppList = p_new_node;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
Opposite of above
|
||
|
*/
|
||
|
void CParkManager::remove_metapiece_from_node_list(CMetaPiece *pMetaToRemove, CMapListNode **ppList)
|
||
|
{
|
||
|
CMapListNode *p_node = *ppList;
|
||
|
CMapListNode *p_prev = NULL;
|
||
|
while(p_node)
|
||
|
{
|
||
|
if (p_node->GetMeta() == pMetaToRemove)
|
||
|
{
|
||
|
if (p_prev)
|
||
|
p_prev->mp_next = p_node->GetNext();
|
||
|
else
|
||
|
*ppList = p_node->GetNext();
|
||
|
|
||
|
delete p_node;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
p_prev = p_node;
|
||
|
p_node = p_node->GetNext();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void CParkManager::bucketify_metapiece(CConcreteMetaPiece *pMeta)
|
||
|
{
|
||
|
for (int x = 0; x < pMeta->m_cell_area.GetW(); x++)
|
||
|
{
|
||
|
for (int z = 0; z < pMeta->m_cell_area.GetL(); z++)
|
||
|
{
|
||
|
Mem::Manager::sHandle().PushContext(mp_generator->GetParkEditorHeap());
|
||
|
CMapListNode *p_new_entry = new CMapListNode();
|
||
|
Mem::Manager::sHandle().PopContext();
|
||
|
p_new_entry->mp_meta = pMeta;
|
||
|
|
||
|
p_new_entry->mp_next = mp_bucket_list[x + pMeta->m_cell_area.GetX()][z + pMeta->m_cell_area.GetZ()];
|
||
|
mp_bucket_list[x + pMeta->m_cell_area.GetX()][z + pMeta->m_cell_area.GetZ()] = p_new_entry;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void CParkManager::debucketify_metapiece(CConcreteMetaPiece *pMeta)
|
||
|
{
|
||
|
for (int x = 0; x < pMeta->m_cell_area.GetW(); x++)
|
||
|
{
|
||
|
for (int z = 0; z < pMeta->m_cell_area.GetL(); z++)
|
||
|
{
|
||
|
CMapListNode *p_prev = NULL;
|
||
|
CMapListNode *p_entry = mp_bucket_list[x + pMeta->m_cell_area.GetX()][z + pMeta->m_cell_area.GetZ()];
|
||
|
while(p_entry)
|
||
|
{
|
||
|
// piece should occur only once per list
|
||
|
|
||
|
if (p_entry->mp_meta == pMeta)
|
||
|
{
|
||
|
if (p_prev)
|
||
|
p_prev->mp_next = p_entry->mp_next;
|
||
|
else
|
||
|
mp_bucket_list[x + pMeta->m_cell_area.GetX()][z + pMeta->m_cell_area.GetZ()] = p_entry->mp_next;
|
||
|
delete p_entry;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
p_prev = p_entry;
|
||
|
p_entry = p_entry->mp_next;
|
||
|
}
|
||
|
} // end for z
|
||
|
} // end for x
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void CParkManager::create_abstract_metapieces()
|
||
|
{
|
||
|
ParkEd("CParkManager::create_abstract_metapieces()");
|
||
|
|
||
|
/*
|
||
|
This add_later stuff is so we can create singular metapieces that weren't defined in
|
||
|
Ed_standard_metapieces. Every CPiece that exists must have a corresponding singular
|
||
|
metapiece, at least an abstract one.
|
||
|
*/
|
||
|
uint32 add_later_tab[1000];
|
||
|
uint add_later_count = 0;
|
||
|
|
||
|
Script::CArray *p_metapiece_array = Script::GetArray("Ed_standard_metapieces", Script::ASSERT);
|
||
|
|
||
|
// this first loop makes sure that metapieces named in EdPieces2.q actually exist
|
||
|
for (uint i = 0; i < p_metapiece_array->GetSize(); i++)
|
||
|
{
|
||
|
Script::CStruct *p_entry = p_metapiece_array->GetStructure(i);
|
||
|
|
||
|
// see if singular or multiple metapiece
|
||
|
uint32 single_crc = 0;
|
||
|
if (p_entry->GetChecksum("single", &single_crc))
|
||
|
{
|
||
|
mp_generator->GetMasterPiece(single_crc, false);
|
||
|
}
|
||
|
} // end for
|
||
|
|
||
|
|
||
|
// now, build abstract metapieces from Ed_standard_metapieces array
|
||
|
for (uint i = 0; i < p_metapiece_array->GetSize(); i++)
|
||
|
{
|
||
|
Script::CStruct *p_entry = p_metapiece_array->GetStructure(i);
|
||
|
|
||
|
Mem::Manager::sHandle().PushContext(mp_generator->GetParkEditorHeap());
|
||
|
CAbstractMetaPiece *p_meta = new CAbstractMetaPiece();
|
||
|
Mem::Manager::sHandle().PopContext();
|
||
|
|
||
|
// see if singular or multiple metapiece
|
||
|
uint32 single_crc = 0;
|
||
|
Script::CArray *p_multiple_array = NULL;
|
||
|
if (p_entry->GetChecksum("single", &single_crc))
|
||
|
{
|
||
|
p_meta->initialize_desc_table(1);
|
||
|
|
||
|
CSourcePiece *p_source_piece = mp_generator->GetMasterPiece(single_crc, true);
|
||
|
|
||
|
GridDims area(0, 0, 0);
|
||
|
p_source_piece->GetCellDims(&area);
|
||
|
Script::CArray *p_pos_array = NULL;
|
||
|
if (p_entry->GetArray("pos", &p_pos_array))
|
||
|
{
|
||
|
area.SetXYZ(p_pos_array->GetInteger(0), p_pos_array->GetInteger(1), p_pos_array->GetInteger(2));
|
||
|
}
|
||
|
|
||
|
p_meta->add_piece(p_source_piece, &area);
|
||
|
|
||
|
// if just a singular meta, use the name checksum already associated with single piece
|
||
|
p_meta->m_name_checksum = p_source_piece->GetType();
|
||
|
Dbg_Assert(add_later_count < 1000);
|
||
|
add_later_tab[add_later_count++] = p_meta->m_name_checksum;
|
||
|
p_meta->set_flag(CMetaPiece::mSINGULAR);
|
||
|
|
||
|
// Finally, Check to see if it is a special type
|
||
|
// and add it to the table of special types:
|
||
|
|
||
|
uint32 special_type;
|
||
|
if (p_entry->GetChecksum(CRCD(0xf176a9fd,"special_type"), &special_type))
|
||
|
{
|
||
|
|
||
|
// gap piece detection here ----- need to reinstate this when we do gaps
|
||
|
if (special_type == CRCD(0x2813ab8a,"gap_placement"))
|
||
|
p_meta->set_flag(CMetaPiece::mGAP_PLACEMENT);
|
||
|
if (special_type == CRCD(0xfc26b6f4,"area_selection"))
|
||
|
p_meta->set_flag(CMetaPiece::mAREA_SELECTION);
|
||
|
if (special_type == CRCD(0xffd81c08,"rail_placement"))
|
||
|
p_meta->set_flag(CMetaPiece::mRAIL_PLACEMENT);
|
||
|
|
||
|
if (special_type == CRCD(0x48fa9c7b,"restart_1"))
|
||
|
SetRestartTypeId(CParkGenerator::vONE_PLAYER, single_crc);
|
||
|
if (special_type == CRCD(0x419183b2,"restart_multi"))
|
||
|
SetRestartTypeId(CParkGenerator::vMULTIPLAYER, single_crc);
|
||
|
if (special_type == CRCD(0xe69aefaf,"restart_horse"))
|
||
|
SetRestartTypeId(CParkGenerator::vHORSE, single_crc);
|
||
|
if (special_type == CRCD(0xa091ce25,"king_of_hill"))
|
||
|
SetRestartTypeId(CParkGenerator::vKING_OF_HILL, single_crc);
|
||
|
|
||
|
if (special_type == CRCD(0x74b0f4e9,"red_flag"))
|
||
|
{
|
||
|
SetRestartTypeId(CParkGenerator::vRED_FLAG, single_crc);
|
||
|
p_meta->set_flag(CMetaPiece::mNOT_ON_GC);
|
||
|
}
|
||
|
if (special_type == CRCD(0xc893acf8,"green_flag"))
|
||
|
{
|
||
|
SetRestartTypeId(CParkGenerator::vGREEN_FLAG, single_crc);
|
||
|
p_meta->set_flag(CMetaPiece::mNOT_ON_GC);
|
||
|
}
|
||
|
if (special_type == CRCD(0x40bdfa7e,"blue_flag"))
|
||
|
{
|
||
|
SetRestartTypeId(CParkGenerator::vBLUE_FLAG, single_crc);
|
||
|
p_meta->set_flag(CMetaPiece::mNOT_ON_GC);
|
||
|
}
|
||
|
if (special_type == CRCD(0x3ae047fc,"yellow_flag"))
|
||
|
{
|
||
|
SetRestartTypeId(CParkGenerator::vYELLOW_FLAG, single_crc);
|
||
|
p_meta->set_flag(CMetaPiece::mNOT_ON_GC);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
else if (p_entry->GetArray("multiple", &p_multiple_array))
|
||
|
{
|
||
|
bool contains_risers = false;
|
||
|
p_meta->initialize_desc_table(p_multiple_array->GetSize());
|
||
|
|
||
|
for (uint j = 0; j < p_multiple_array->GetSize(); j++)
|
||
|
{
|
||
|
Script::CStruct *p_name_pos = p_multiple_array->GetStructure(j);
|
||
|
|
||
|
Script::CComponent *p_name_crc_comp = p_name_pos->GetNextComponent(NULL);
|
||
|
Dbg_Assert(p_name_crc_comp->mType == ESYMBOLTYPE_NAME);
|
||
|
uint32 name_crc = p_name_crc_comp->mChecksum;
|
||
|
|
||
|
Script::CArray *p_pos_array = NULL;
|
||
|
p_name_pos->GetArray(NONAME, &p_pos_array, Script::ASSERT);
|
||
|
|
||
|
CSourcePiece *p_source_piece = mp_generator->GetMasterPiece(name_crc, true);
|
||
|
Dbg_Assert(add_later_count < 1000);
|
||
|
add_later_tab[add_later_count++] = name_crc;
|
||
|
|
||
|
GridDims area;
|
||
|
p_source_piece->GetCellDims(&area);
|
||
|
area.SetXYZ(p_pos_array->GetInteger(0), p_pos_array->GetInteger(1), p_pos_array->GetInteger(2));
|
||
|
|
||
|
Mth::ERot90 rot = Mth::ROT_0;
|
||
|
if (p_pos_array->GetSize() > 3)
|
||
|
rot = (Mth::ERot90) p_pos_array->GetInteger(3);
|
||
|
|
||
|
if (p_name_pos->ContainsFlag(CRCD(0xcd75a3f,"riser")))
|
||
|
contains_risers = true;
|
||
|
p_meta->add_piece(p_source_piece, &area, rot, p_name_pos->ContainsFlag(CRCD(0xcd75a3f,"riser")));
|
||
|
} // end for
|
||
|
|
||
|
if (contains_risers)
|
||
|
p_meta->set_flag(CMetaPiece::mCONTAINS_RISERS);
|
||
|
}
|
||
|
else if (p_entry->GetArray("ack", &p_multiple_array))
|
||
|
{
|
||
|
p_meta->initialize_desc_table(p_multiple_array->GetSize());
|
||
|
|
||
|
for (uint j = 0; j < p_multiple_array->GetSize(); j++)
|
||
|
{
|
||
|
Script::CStruct *p_name_pos = p_multiple_array->GetStructure(j);
|
||
|
|
||
|
Script::CComponent *p_name_crc_comp = p_name_pos->GetNextComponent(NULL);
|
||
|
Dbg_Assert(p_name_crc_comp->mType == ESYMBOLTYPE_NAME);
|
||
|
uint32 name_crc = p_name_crc_comp->mChecksum;
|
||
|
|
||
|
Script::CArray *p_pos_array = NULL;
|
||
|
p_name_pos->GetArray(NONAME, &p_pos_array, Script::ASSERT);
|
||
|
|
||
|
CAbstractMetaPiece *p_source_meta = GetAbstractMeta(name_crc);
|
||
|
|
||
|
GridDims area = p_source_meta->GetArea();
|
||
|
area.SetXYZ(p_pos_array->GetInteger(0), p_pos_array->GetInteger(1), p_pos_array->GetInteger(2));
|
||
|
|
||
|
Mth::ERot90 rot = Mth::ROT_0;
|
||
|
if (p_pos_array->GetSize() > 3)
|
||
|
rot = (Mth::ERot90) p_pos_array->GetInteger(3);
|
||
|
|
||
|
p_meta->add_piece_dumb(p_source_meta, &area, rot, p_name_pos->ContainsFlag(CRCD(0xcd75a3f,"riser")));
|
||
|
} // end for
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Dbg_MsgAssert(0, ("screwy entry %d in Ed_standard_metapieces", i));
|
||
|
}
|
||
|
|
||
|
#if 1
|
||
|
#ifdef __NOPT_ASSERT__
|
||
|
GridDims test_area = p_meta->GetArea();
|
||
|
Dbg_MsgAssert(test_area.GetW() > 0 && test_area.GetH() > 0 && test_area.GetL() > 0,
|
||
|
("metapiece %s has invalid dimensions (%d,%d,%d)", Script::FindChecksumName(p_meta->GetNameChecksum()),
|
||
|
test_area.GetW(), test_area.GetH(), test_area.GetL()));
|
||
|
#if 0
|
||
|
if (p_meta->GetNameChecksum() == Script::GenerateCRC("Sk4Ed_Fence_10x10"))
|
||
|
printf("OY! metapiece %s has dimensions (%d,%d,%d)\n", Script::FindChecksumName(p_meta->GetNameChecksum()),
|
||
|
test_area.GetW(), test_area.GetH(), test_area.GetL());
|
||
|
#endif
|
||
|
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
// the name provided in EdPieces.q, if any, takes precedence
|
||
|
if (p_entry->GetChecksum("name", &p_meta->m_name_checksum))
|
||
|
{
|
||
|
// this metapiece has been renamed, so we must treat it as a non-singular piece
|
||
|
p_meta->clear_flag(CMetaPiece::mSINGULAR);
|
||
|
}
|
||
|
// make sure no piece with checksum currently exists
|
||
|
Dbg_MsgAssert(!GetAbstractMeta(p_meta->m_name_checksum), ("name checksum already used for metapiece"));
|
||
|
|
||
|
if (p_entry->ContainsFlag("is_riser"))
|
||
|
p_meta->set_flag(CMetaPiece::mIS_RISER);
|
||
|
if (p_entry->ContainsFlag("no_rails"))
|
||
|
{
|
||
|
# ifdef __NOPT_ASSERT__
|
||
|
Ryan("No rails for %s\n", Script::FindChecksumName(p_meta->m_name_checksum));
|
||
|
# endif
|
||
|
p_meta->set_flag(CMetaPiece::mNO_RAILS);
|
||
|
}
|
||
|
|
||
|
Mem::Manager::sHandle().PushContext(mp_generator->GetParkEditorHeap());
|
||
|
CMapListNode *p_node = new CMapListNode();
|
||
|
Mem::Manager::sHandle().PopContext();
|
||
|
p_node->mp_meta = p_meta;
|
||
|
p_node->mp_next = mp_abstract_metapiece_list;
|
||
|
mp_abstract_metapiece_list = p_node;
|
||
|
m_num_abstract_metapieces++;
|
||
|
} // end for
|
||
|
|
||
|
|
||
|
for (uint i = 0; i < add_later_count; i++)
|
||
|
{
|
||
|
if (GetAbstractMeta(add_later_tab[i]))
|
||
|
continue;
|
||
|
|
||
|
Mem::Manager::sHandle().PushContext(mp_generator->GetParkEditorHeap());
|
||
|
CAbstractMetaPiece *p_meta = new CAbstractMetaPiece();
|
||
|
Mem::Manager::sHandle().PopContext();
|
||
|
|
||
|
p_meta->initialize_desc_table(1);
|
||
|
CSourcePiece *p_source_piece = mp_generator->GetMasterPiece(add_later_tab[i], true);
|
||
|
|
||
|
GridDims area(0, 0, 0);
|
||
|
p_source_piece->GetCellDims(&area);
|
||
|
p_meta->add_piece(p_source_piece, &area);
|
||
|
|
||
|
p_meta->m_name_checksum = add_later_tab[i];
|
||
|
p_meta->set_flag(CMetaPiece::mSINGULAR);
|
||
|
|
||
|
Mem::Manager::sHandle().PushContext(mp_generator->GetParkEditorHeap());
|
||
|
CMapListNode *p_node = new CMapListNode();
|
||
|
Mem::Manager::sHandle().PopContext();
|
||
|
p_node->mp_meta = p_meta;
|
||
|
p_node->mp_next = mp_abstract_metapiece_list;
|
||
|
mp_abstract_metapiece_list = p_node;
|
||
|
m_num_abstract_metapieces++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void CParkManager::SetRestartTypeId(CParkGenerator::RestartType type, uint32 id)
|
||
|
{
|
||
|
|
||
|
// Mick
|
||
|
// printf ("SetRestartTypeId(%d,%x)\n",type,id);
|
||
|
if (type > CParkGenerator::vEMPTY && type < CParkGenerator::vNUM_RESTART_TYPES)
|
||
|
{
|
||
|
m_restartPieceIdTab[type] = id;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
switch(type)
|
||
|
{
|
||
|
case CParkGenerator::vONE_PLAYER:
|
||
|
// printf ("Found vONE_PLAYER\n");
|
||
|
m_restartPieceIdTab[0] = id;
|
||
|
break;
|
||
|
case CParkGenerator::vMULTIPLAYER:
|
||
|
// printf ("Found vMULTIPLAYER\n");
|
||
|
m_restartPieceIdTab[1] = id;
|
||
|
break;
|
||
|
case CParkGenerator::vHORSE:
|
||
|
// printf ("Found vHORSE\n");
|
||
|
m_restartPieceIdTab[2] = id;
|
||
|
break;
|
||
|
case CParkGenerator::vKING_OF_HILL:
|
||
|
// printf ("Found vKING_OF_HILL\n");
|
||
|
m_restartPieceIdTab[3] = id;
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
// returns the type of restart piece this is, or vEMPTY is it is not a restart piece
|
||
|
// (vEMPTY is 0, so the return value can be treated as true/false)
|
||
|
CParkGenerator::RestartType CParkManager::IsRestartPiece(uint32 id)
|
||
|
{
|
||
|
for (int type = CParkGenerator::vONE_PLAYER; type < CParkGenerator::vNUM_RESTART_TYPES; type++)
|
||
|
{
|
||
|
if (id == m_restartPieceIdTab[type])
|
||
|
{
|
||
|
return (CParkGenerator::RestartType) type;
|
||
|
}
|
||
|
}
|
||
|
return CParkGenerator::vEMPTY;
|
||
|
|
||
|
/*
|
||
|
if (id == m_restartPieceIdTab[0])
|
||
|
return CParkGenerator::vONE_PLAYER;
|
||
|
if (id == m_restartPieceIdTab[1])
|
||
|
return CParkGenerator::vMULTIPLAYER;
|
||
|
if (id == m_restartPieceIdTab[2])
|
||
|
return CParkGenerator::vHORSE;
|
||
|
if (id == m_restartPieceIdTab[3])
|
||
|
return CParkGenerator::vKING_OF_HILL;
|
||
|
return CParkGenerator::vEMPTY;
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
Commented out cos I just discovered Destroy() does pretty much the same thing!
|
||
|
|
||
|
// K: This is for freeing up as much memory as possible when playing a park, so that
|
||
|
// the number of players can be increased. Each player requires 830K.
|
||
|
void CParkManager::FreeUpMemoryForPlayingPark()
|
||
|
{
|
||
|
// Delete everything in the park editor heap, so that it can be removed, freeing
|
||
|
// up 900K.
|
||
|
|
||
|
// First delete the cursor.
|
||
|
Ed::CParkEditor::Instance()->DeleteCursor();
|
||
|
|
||
|
printf("After deleting cursor ...\n");
|
||
|
printf("Num CMapListNode's = %d\n",Ed::CMapListNode::SGetNumUsedItems());
|
||
|
MemView_AnalyzeHeap(mp_generator->GetParkEditorHeap());
|
||
|
|
||
|
mp_generator->DeleteSourceAndClonedPieces();
|
||
|
|
||
|
// Delete the concrete metapieces
|
||
|
CMapListNode *p_node = mp_concrete_metapiece_list;
|
||
|
while(p_node)
|
||
|
{
|
||
|
CMapListNode *p_next_node = p_node->GetNext();
|
||
|
delete p_node->GetConcreteMeta();
|
||
|
delete p_node;
|
||
|
p_node = p_next_node;
|
||
|
}
|
||
|
m_num_concrete_metapieces=0;
|
||
|
mp_concrete_metapiece_list=NULL;
|
||
|
|
||
|
printf("After deleting CParkManager::mp_concrete_metapiece_list ...\n");
|
||
|
printf("Num CMapListNode's = %d\n",Ed::CMapListNode::SGetNumUsedItems());
|
||
|
MemView_AnalyzeHeap(Ed::CParkManager::sInstance()->GetGenerator()->GetParkEditorHeap());
|
||
|
|
||
|
// Free up the abstract metapieces.
|
||
|
p_node = mp_abstract_metapiece_list;
|
||
|
while(p_node)
|
||
|
{
|
||
|
CMapListNode *p_next_node = p_node->GetNext();
|
||
|
delete p_node->GetAbstractMeta();
|
||
|
delete p_node;
|
||
|
p_node = p_next_node;
|
||
|
}
|
||
|
m_num_abstract_metapieces=0;
|
||
|
mp_abstract_metapiece_list=NULL;
|
||
|
|
||
|
|
||
|
printf("After deleting CParkManager::mp_abstract_metapiece_list ...\n");
|
||
|
printf("Num CMapListNode's = %d\n",Ed::CMapListNode::SGetNumUsedItems());
|
||
|
MemView_AnalyzeHeap(Ed::CParkManager::sInstance()->GetGenerator()->GetParkEditorHeap());
|
||
|
|
||
|
|
||
|
// The park editor heap is now totally empty!
|
||
|
// So delete it.
|
||
|
mp_generator->DeleteParkEditorHeap();
|
||
|
|
||
|
|
||
|
|
||
|
printf("After deleting stuff ...\n");
|
||
|
printf("Num CMapListNode's = %d\n",Ed::CMapListNode::SGetNumUsedItems());
|
||
|
MemView_AnalyzeHeap(Ed::CParkManager::sInstance()->GetGenerator()->GetParkEditorHeap());
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
// K: Added type so that DESTROY_ONLY_PIECES can be passed when this function is used to clean
|
||
|
// up the park editor heap for deletion when playing a park.
|
||
|
void CParkManager::destroy_concrete_metapieces(CParkGenerator::EDestroyType type)
|
||
|
{
|
||
|
ParkEd("CParkManager::destroy_concrete_metapieces()");
|
||
|
|
||
|
Dbg_Assert(mp_gap_manager);
|
||
|
mp_gap_manager->RemoveAllGaps();
|
||
|
|
||
|
// Commented these out because destroy_concrete_metapieces gets called via
|
||
|
// ScriptFreeUpMemoryForPlayingPark, which must not delete the edited rails.
|
||
|
// (Fix to TT2125)
|
||
|
//Obj::GetRailEditor()->DestroyRailGeometry();
|
||
|
//Obj::GetRailEditor()->DestroyPostGeometry();
|
||
|
|
||
|
// remove all concrete metapieces, except locked ones
|
||
|
CMapListNode *p_node = mp_concrete_metapiece_list;
|
||
|
while(p_node)
|
||
|
{
|
||
|
CMapListNode *p_next_node = p_node->GetNext();
|
||
|
DestroyConcreteMeta(p_node->GetConcreteMeta(), mDONT_DESTROY_PIECES_ABOVE);
|
||
|
p_node = p_next_node;
|
||
|
}
|
||
|
|
||
|
mp_generator->DestroyAllClonedPieces(type); // if any are left
|
||
|
|
||
|
mp_generator->KillRestarts(); // This should have been taken care of by destrying the actual concrete metas, but just to be safe....
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifdef __PLAT_NGC__
|
||
|
void CParkManager::SwapMapBufferEndianness()
|
||
|
{
|
||
|
CompressedMapHeader *p_header = (CompressedMapHeader *)mp_compressed_map_buffer;
|
||
|
|
||
|
p_header->mChecksum=_32(p_header->mChecksum);
|
||
|
p_header->mSizeInBytes=_16(p_header->mSizeInBytes);
|
||
|
p_header->mVersion=_16(p_header->mVersion);
|
||
|
p_header->mTheme=_16(p_header->mTheme);
|
||
|
p_header->mParkSize=_16(p_header->mParkSize);
|
||
|
p_header->mNumMetas=_16(p_header->mNumMetas);
|
||
|
p_header->mNumGaps=_16(p_header->mNumGaps);
|
||
|
p_header->mTODScript=_32(p_header->mTODScript);
|
||
|
|
||
|
uint32 *p_metas=(uint32*)((uint8*)(p_header+1) + FLOOR_MAX_WIDTH * FLOOR_MAX_LENGTH);
|
||
|
for (int i=0; i<p_header->mNumMetas; ++i)
|
||
|
{
|
||
|
p_metas[0]=_32(p_metas[0]);
|
||
|
p_metas[1]=_32(p_metas[1]);
|
||
|
p_metas+=2;
|
||
|
}
|
||
|
|
||
|
CompressedGap *p_gap=(CompressedGap*)p_metas;
|
||
|
for (int i=0; i<p_header->mNumGaps; ++i)
|
||
|
{
|
||
|
p_gap->score=_16(p_gap->score);
|
||
|
p_gap->mCancelFlags=_32(p_gap->mCancelFlags);
|
||
|
++p_gap;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
Park editor map file format:
|
||
|
|
||
|
Header
|
||
|
-size
|
||
|
-version
|
||
|
-theme
|
||
|
-X, Z, W, L
|
||
|
-number of metas
|
||
|
|
||
|
Floor height array, each entry:
|
||
|
-height
|
||
|
-texture
|
||
|
(included risers taken care of by placed metapieces)
|
||
|
|
||
|
Meta entries:
|
||
|
-10 bits: index
|
||
|
-8 bits: X
|
||
|
-8 bits: Z
|
||
|
-6 bits: padding
|
||
|
-2 bits: rot
|
||
|
-5 bits: Y
|
||
|
-1 bit: padding
|
||
|
(total: 40)
|
||
|
|
||
|
Gap info
|
||
|
|
||
|
User-defined stamps
|
||
|
-number contained
|
||
|
-source meta
|
||
|
-8 bits: X
|
||
|
-8 bits: Z
|
||
|
-6 bits: Y
|
||
|
-2 bits: rot
|
||
|
*/
|
||
|
|
||
|
void CParkManager::write_compressed_map_buffer()
|
||
|
{
|
||
|
Dbg_Assert(m_state_on);
|
||
|
ParkEd("CParkManager::write_compressed_map_buffer()");
|
||
|
//DumpUnwindStack( 20, 0 );
|
||
|
|
||
|
if (m_compressed_map_flags & mIS_NEWER_THAN_PARK)
|
||
|
// we just loaded this park, so don't touch it
|
||
|
return;
|
||
|
|
||
|
for (int i=0; i<COMPRESSED_MAP_SIZE; ++i)
|
||
|
{
|
||
|
mp_compressed_map_buffer[i]=0;
|
||
|
}
|
||
|
|
||
|
Script::CArray *p_save_map_array = Script::GetArray("Ed_Save_Map", Script::ASSERT);
|
||
|
uint save_map_array_size = p_save_map_array->GetSize();
|
||
|
|
||
|
CompressedMapHeader *p_header = (CompressedMapHeader *) mp_compressed_map_buffer;
|
||
|
p_header->mVersion = (VERSION);
|
||
|
p_header->mTheme = (m_theme);
|
||
|
p_header->mParkSize = (0);
|
||
|
p_header->mX = m_park_near_bounds.GetX();
|
||
|
p_header->mZ = m_park_near_bounds.GetZ();
|
||
|
p_header->mW = m_park_near_bounds.GetW();
|
||
|
p_header->mL = m_park_near_bounds.GetL();
|
||
|
p_header->mTODScript = Ed::CParkEditor::Instance()->GetTimeOfDayScript();
|
||
|
p_header->mMaxPlayers=GetGenerator()->GetMaxPlayers();
|
||
|
Dbg_MsgAssert(strlen(mp_park_name) < 64,("Park name '%s' too long",mp_park_name));
|
||
|
strcpy(p_header->mParkName,mp_park_name);
|
||
|
|
||
|
CompressedFloorEntry *p_floor_entry = (CompressedFloorEntry *) (p_header + 1);
|
||
|
for (int i = 0; i < FLOOR_MAX_WIDTH; i++)
|
||
|
{
|
||
|
for (int j = 0; j < FLOOR_MAX_LENGTH; j++)
|
||
|
{
|
||
|
p_floor_entry->mHeight = (sint8) m_floor_height_map[i][j].mHeight;
|
||
|
p_floor_entry++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
uint8 *p_meta_entry = (uint8 *) p_floor_entry;
|
||
|
|
||
|
int num_metas_outputted = 0;
|
||
|
CMapListNode *p_meta_node = mp_concrete_metapiece_list;
|
||
|
while(p_meta_node)
|
||
|
{
|
||
|
CConcreteMetaPiece *p_meta = p_meta_node->GetConcreteMeta();
|
||
|
if (!p_meta->IsRiser() && !p_meta->IsInnerShell() && p_meta->IsInPark())
|
||
|
{
|
||
|
uint32 *p_meta_entry_first = (uint32 *) p_meta_entry;
|
||
|
uint32 *p_meta_entry_second = (uint32 *) (p_meta_entry + 4);
|
||
|
|
||
|
GridDims meta_area = p_meta->GetArea();
|
||
|
|
||
|
uint32 metapiece_index = 0;
|
||
|
uint32 metapiece_name_checksum = p_meta->GetNameChecksum();
|
||
|
for (; metapiece_index < save_map_array_size; metapiece_index++)
|
||
|
{
|
||
|
if (p_save_map_array->GetChecksum(metapiece_index) == metapiece_name_checksum)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (metapiece_index < save_map_array_size)
|
||
|
{
|
||
|
*p_meta_entry_first = metapiece_index & 1023;
|
||
|
*p_meta_entry_first |= meta_area.GetX() << 10;
|
||
|
*p_meta_entry_first |= meta_area.GetZ() << 18;
|
||
|
|
||
|
*p_meta_entry_second = p_meta->GetRot() & 3;
|
||
|
*p_meta_entry_second |= ((meta_area.GetY() + 16) & 31) << 2;
|
||
|
|
||
|
*p_meta_entry_first = (*p_meta_entry_first);
|
||
|
*p_meta_entry_second = (*p_meta_entry_second);
|
||
|
//Ryan("compressed piece: 0x%x 0x%x\n", *p_meta_entry_first, *p_meta_entry_second);
|
||
|
|
||
|
p_meta_entry += 8;
|
||
|
num_metas_outputted++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
p_meta_node = p_meta_node->GetNext();
|
||
|
}
|
||
|
|
||
|
int buffer_used_size = (uint32) p_meta_entry - (uint32) p_header;
|
||
|
Dbg_MsgAssert(buffer_used_size <= COMPRESSED_MAP_SIZE, ("compressed map buffer (%d) needs to be bigger than (%d)",COMPRESSED_MAP_SIZE,buffer_used_size));
|
||
|
p_header->mNumMetas = (num_metas_outputted);
|
||
|
|
||
|
/* Gap Section */
|
||
|
|
||
|
// count number of gaps
|
||
|
CGapManager::GapDescriptor *p_desc_tab[CGapManager::vMAX_GAPS];
|
||
|
int num_gaps = 0;
|
||
|
int gap;
|
||
|
for (gap = 0; gap < CGapManager::vMAX_GAPS; gap++)
|
||
|
{
|
||
|
int half = 0;
|
||
|
CGapManager::GapDescriptor *pDesc = mp_gap_manager->GetGapDescriptor(gap, &half);
|
||
|
if (pDesc && half == 0 && pDesc->numCompleteHalves == 2)
|
||
|
p_desc_tab[num_gaps++] = pDesc;
|
||
|
}
|
||
|
p_header->mNumGaps = (num_gaps);
|
||
|
|
||
|
// write gaps
|
||
|
CompressedGap *p_out_gap = (CompressedGap *) p_meta_entry;
|
||
|
for (gap = 0; gap < num_gaps; gap++)
|
||
|
{
|
||
|
p_out_gap->rot = 0;
|
||
|
for (int half = 0; half < 2; half++)
|
||
|
{
|
||
|
p_out_gap->x[half] = p_desc_tab[gap]->loc[half].GetX();
|
||
|
p_out_gap->y[half] = p_desc_tab[gap]->loc[half].GetY() + (MAX_HEIGHT>>1);
|
||
|
p_out_gap->z[half] = p_desc_tab[gap]->loc[half].GetZ();
|
||
|
p_out_gap->rot |= p_desc_tab[gap]->rot[half]<<(half*4);
|
||
|
|
||
|
p_out_gap->extent[half] = (uint8) ((p_desc_tab[gap]->leftExtent[half] & 15) << 4);
|
||
|
p_out_gap->extent[half] |= (uint8) (p_desc_tab[gap]->rightExtent[half] & 15);
|
||
|
//Ryan("adding gap at (%d,%d,%d)\n", p_out_gap->x[half], p_out_gap->y[half], p_out_gap->z[half]);
|
||
|
}
|
||
|
Dbg_MsgAssert(strlen(p_desc_tab[gap]->text) <= 31, ("too many characters in gap name %s", p_desc_tab[gap]->text));
|
||
|
strcpy(p_out_gap->text, p_desc_tab[gap]->text);
|
||
|
p_out_gap->score = ((uint16) p_desc_tab[gap]->score);
|
||
|
|
||
|
p_out_gap->mCancelFlags=p_desc_tab[gap]->mCancelFlags;
|
||
|
|
||
|
p_out_gap++;
|
||
|
}
|
||
|
|
||
|
buffer_used_size = (uint32) p_out_gap - (uint32) p_header;
|
||
|
Dbg_MsgAssert(buffer_used_size <= COMPRESSED_MAP_SIZE, ("compressed map buffer (%d) needs to be bigger than (%d)",COMPRESSED_MAP_SIZE,buffer_used_size));
|
||
|
p_header->mSizeInBytes = buffer_used_size;
|
||
|
|
||
|
/* Flag section */
|
||
|
|
||
|
if (!(m_compressed_map_flags & mIN_SYNC_WITH_PARK) && !(m_compressed_map_flags & mIS_NEWER_THAN_PARK))
|
||
|
m_compressed_map_flags = ECompressedMapFlags(m_compressed_map_flags | mNOT_SAVED_LOCAL);
|
||
|
|
||
|
m_compressed_map_flags = ECompressedMapFlags(m_compressed_map_flags | (mIN_SYNC_WITH_PARK + mIS_VALID));
|
||
|
m_compressed_map_flags = ECompressedMapFlags(m_compressed_map_flags & ~mIS_NEWER_THAN_PARK);
|
||
|
|
||
|
|
||
|
p_header->mChecksum = (Crc::GenerateCRCCaseSensitive((const char *) mp_compressed_map_buffer + 4, COMPRESSED_MAP_SIZE-4));
|
||
|
|
||
|
// XXX
|
||
|
ParkEd("end CParkManager::write_compressed_map_buffer()");
|
||
|
}
|
||
|
|
||
|
|
||
|
// Create a minimal compressed map buffer
|
||
|
void CParkManager::fake_compressed_map_buffer()
|
||
|
{
|
||
|
ParkEd("CParkManager::fake_compressed_map_buffer()");
|
||
|
|
||
|
// Script::CArray *p_save_map_array = Script::GetArray("Ed_Save_Map", Script::ASSERT);
|
||
|
// uint save_map_array_size = p_save_map_array->GetSize();
|
||
|
|
||
|
setup_default_dimensions();
|
||
|
|
||
|
CompressedMapHeader *p_header = (CompressedMapHeader *) mp_compressed_map_buffer;
|
||
|
p_header->mVersion = (VERSION);
|
||
|
p_header->mTheme = (m_theme);
|
||
|
p_header->mParkSize = (0);
|
||
|
p_header->mX = m_park_near_bounds.GetX();
|
||
|
p_header->mZ = m_park_near_bounds.GetZ();
|
||
|
p_header->mW = m_park_near_bounds.GetW();
|
||
|
p_header->mL = m_park_near_bounds.GetL();
|
||
|
|
||
|
Ed::CParkEditor *p_editor=Ed::CParkEditor::Instance();
|
||
|
if (p_editor)
|
||
|
{
|
||
|
p_header->mTODScript = p_editor->GetTimeOfDayScript();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
p_header->mTODScript=0;
|
||
|
}
|
||
|
|
||
|
p_header->mMaxPlayers=2;
|
||
|
strcpy(p_header->mParkName, "unnamed park");
|
||
|
|
||
|
CompressedFloorEntry *p_floor_entry = (CompressedFloorEntry *) (p_header + 1);
|
||
|
for (int i = 0; i < FLOOR_MAX_WIDTH; i++)
|
||
|
{
|
||
|
for (int j = 0; j < FLOOR_MAX_LENGTH; j++)
|
||
|
{
|
||
|
p_floor_entry->mHeight = 0; // (sint8) m_floor_height_map[i][j].mHeight;
|
||
|
p_floor_entry++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
uint8 *p_meta_entry = (uint8 *) p_floor_entry;
|
||
|
int num_metas_outputted = 0;
|
||
|
int buffer_used_size = (uint32) p_meta_entry - (uint32) p_header;
|
||
|
p_header->mNumMetas = num_metas_outputted;
|
||
|
p_header->mChecksum = Crc::GenerateCRCCaseSensitive((const char *) mp_compressed_map_buffer + 4, buffer_used_size - 4);
|
||
|
int num_gaps = 0;
|
||
|
p_header->mNumGaps = num_gaps;
|
||
|
|
||
|
// write gaps
|
||
|
CompressedGap *p_out_gap = (CompressedGap *) p_meta_entry;
|
||
|
buffer_used_size = (uint32) p_out_gap - (uint32) p_header;
|
||
|
Dbg_MsgAssert(buffer_used_size <= COMPRESSED_MAP_SIZE, ("compressed map buffer (%d) needs to be bigger than (%d)",COMPRESSED_MAP_SIZE,buffer_used_size));
|
||
|
p_header->mSizeInBytes = buffer_used_size;
|
||
|
|
||
|
/* Flag section */
|
||
|
|
||
|
if (!(m_compressed_map_flags & mIN_SYNC_WITH_PARK) && !(m_compressed_map_flags & mIS_NEWER_THAN_PARK))
|
||
|
m_compressed_map_flags = ECompressedMapFlags(m_compressed_map_flags | mNOT_SAVED_LOCAL);
|
||
|
|
||
|
m_compressed_map_flags = ECompressedMapFlags(m_compressed_map_flags | (mIN_SYNC_WITH_PARK + mIS_VALID));
|
||
|
m_compressed_map_flags = ECompressedMapFlags(m_compressed_map_flags & ~mIS_NEWER_THAN_PARK);
|
||
|
|
||
|
// XXX
|
||
|
ParkEd("end CParkManager::fake_compressed_map_buffer()");
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
void CParkManager::read_from_compressed_map_buffer()
|
||
|
{
|
||
|
Dbg_Assert(m_state_on);
|
||
|
// XXX
|
||
|
ParkEd("CParkManager::read_from_compressed_map_buffer()");
|
||
|
|
||
|
Script::CArray *p_save_map_array = Script::GetArray("Ed_Save_Map", Script::ASSERT);
|
||
|
uint32 dead_piece_checksum = Script::GenerateCRC("Sk4Ed_Dead");
|
||
|
|
||
|
Dbg_MsgAssert(m_compressed_map_flags & mIS_VALID, ("compressed map is invalid"));
|
||
|
|
||
|
CompressedMapHeader *p_header = (CompressedMapHeader *) mp_compressed_map_buffer;
|
||
|
// make sure latest version
|
||
|
if (p_header->mVersion != VERSION)
|
||
|
{
|
||
|
read_from_compressed_map_buffer_old();
|
||
|
GetGenerator()->SetMaxPlayers(1);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
m_park_near_bounds[X] = p_header->mX;
|
||
|
m_park_near_bounds[Z] = p_header->mZ;
|
||
|
m_park_near_bounds[W] = p_header->mW;
|
||
|
m_park_near_bounds[L] = p_header->mL;
|
||
|
m_theme = p_header->mTheme;
|
||
|
Ed::CParkEditor::Instance()->SetTimeOfDayScript(p_header->mTODScript);
|
||
|
#ifdef __PLAT_NGC__
|
||
|
p_header->mMaxPlayers=2;
|
||
|
#endif
|
||
|
GetGenerator()->SetMaxPlayers(p_header->mMaxPlayers);
|
||
|
// SG: Was setting to the incorrect number (8 when it should have been 2). I think
|
||
|
// it is redundant anyway as max players is set elsewhere already
|
||
|
//GameNet::Manager::Instance()->SetMaxPlayers(p_header->mMaxPlayers);
|
||
|
|
||
|
CompressedFloorEntry *p_floor_entry = (CompressedFloorEntry *) (p_header + 1);
|
||
|
for (int i = 0; i < FLOOR_MAX_WIDTH; i++)
|
||
|
{
|
||
|
for (int j = 0; j < FLOOR_MAX_LENGTH; j++)
|
||
|
{
|
||
|
m_floor_height_map[i][j].mHeight = (int) p_floor_entry->mHeight;
|
||
|
m_floor_height_map[i][j].mEnclosedFloor = 0;
|
||
|
p_floor_entry++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
uint8 *p_meta_entry = (uint8 *) p_floor_entry;
|
||
|
Dbg_Printf( "****** NUM METAS WHILE READING FROM BUFFER : %d\n", p_header->mNumMetas );
|
||
|
for (int i = 0; i < p_header->mNumMetas; i++)
|
||
|
{
|
||
|
uint32 *p_meta_entry_first = (uint32 *) p_meta_entry;
|
||
|
uint32 *p_meta_entry_second = (uint32 *) (p_meta_entry + 4);
|
||
|
uint32 meta1 = *p_meta_entry_first;
|
||
|
uint32 meta2 = *p_meta_entry_second;
|
||
|
|
||
|
//Ryan("compressed piece: 0x%x 0x%x\n", *p_meta_entry_first, *p_meta_entry_second);
|
||
|
|
||
|
uint32 metapiece_index = meta1 & 1023;
|
||
|
uint32 metapiece_checksum = p_save_map_array->GetChecksum(metapiece_index);
|
||
|
|
||
|
if (metapiece_checksum != dead_piece_checksum)
|
||
|
{
|
||
|
CAbstractMetaPiece *p_source_meta = GetAbstractMeta(metapiece_checksum);
|
||
|
Dbg_MsgAssert(p_source_meta, ("couldn't find abstract meta %s", Script::FindChecksumName(metapiece_checksum)));
|
||
|
#ifdef __PLAT_NGC__
|
||
|
if (!(p_source_meta->m_flags & CMetaPiece::mNOT_ON_GC))
|
||
|
#endif
|
||
|
{
|
||
|
CConcreteMetaPiece *p_meta = CreateConcreteMeta(p_source_meta);
|
||
|
GridDims pos;
|
||
|
pos[X] = (meta1 >> 10) & 255;
|
||
|
pos[Z] = (meta1 >> 18) & 255;
|
||
|
pos[Y] = ((meta2 >> 2) & 31) - 16;
|
||
|
int rot = meta2 & 3;
|
||
|
p_meta->SetRot(Mth::ERot90(rot));
|
||
|
AddMetaPieceToPark(pos, p_meta);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
p_meta_entry += 8;
|
||
|
}
|
||
|
|
||
|
/* Gap section */
|
||
|
|
||
|
CompressedGap *p_in_gap = (CompressedGap *) p_meta_entry;
|
||
|
for (int g = 0; g < p_header->mNumGaps; g++)
|
||
|
{
|
||
|
CGapManager::GapDescriptor desc;
|
||
|
|
||
|
for (int half = 0; half < 2; half++)
|
||
|
{
|
||
|
desc.loc[half][X] = p_in_gap->x[half];
|
||
|
desc.loc[half][Y] = p_in_gap->y[half] - (MAX_HEIGHT>>1);
|
||
|
desc.loc[half][Z] = p_in_gap->z[half];
|
||
|
desc.rot[half] = (p_in_gap->rot>>(half*4)) & 15;
|
||
|
|
||
|
desc.leftExtent[half] = (p_in_gap->extent[half]>>4) & 15;
|
||
|
desc.rightExtent[half] = (p_in_gap->extent[half]) & 15;
|
||
|
//Ryan("adding gap at (%d,%d,%d)\n", p_in_gap->x[half], p_in_gap->y[half], p_in_gap->z[half]);
|
||
|
}
|
||
|
Dbg_Assert(strlen(p_in_gap->text) < 32);
|
||
|
strcpy(desc.text, p_in_gap->text);
|
||
|
desc.score = (int) p_in_gap->score;
|
||
|
desc.numCompleteHalves = 2;
|
||
|
desc.mCancelFlags=p_in_gap->mCancelFlags;
|
||
|
|
||
|
AddGap(desc);
|
||
|
|
||
|
p_in_gap++;
|
||
|
}
|
||
|
|
||
|
m_compressed_map_flags = ECompressedMapFlags(m_compressed_map_flags | mIN_SYNC_WITH_PARK);
|
||
|
m_compressed_map_flags = ECompressedMapFlags(m_compressed_map_flags & ~mIS_NEWER_THAN_PARK);
|
||
|
|
||
|
// XXX
|
||
|
ParkEd("end CParkManager::read_from_compressed_map_buffer()");
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void CParkManager::read_from_compressed_map_buffer_old()
|
||
|
{
|
||
|
Dbg_Assert(m_state_on);
|
||
|
// XXX
|
||
|
ParkEd("CParkManager::read_from_compressed_map_buffer()");
|
||
|
|
||
|
Script::CArray *p_save_map_array = Script::GetArray("Ed_Save_Map", Script::ASSERT);
|
||
|
uint32 dead_piece_checksum = Script::GenerateCRC("Sk4Ed_Dead");
|
||
|
|
||
|
Dbg_MsgAssert(m_compressed_map_flags & mIS_VALID, ("compressed map is invalid"));
|
||
|
|
||
|
CompressedMapHeader *p_header = (CompressedMapHeader *) mp_compressed_map_buffer;
|
||
|
|
||
|
// make sure proper version
|
||
|
Dbg_MsgAssert((p_header->mVersion) == VERSION-1, ("can't read park with this version #: %d", (p_header->mVersion)));
|
||
|
|
||
|
// XXX
|
||
|
// for (int zzz = 0; zzz < 16; zzz++)
|
||
|
// printf("OUT OF DATE PARK FORMAT -- SAVE NOW. OUT OF DATE PARK FORMAT -- SAVE NOW. OUT OF DATE PARK FORMAT -- SAVE NOW.\n");
|
||
|
|
||
|
m_park_near_bounds[X] = p_header->mX;
|
||
|
m_park_near_bounds[Z] = p_header->mZ;
|
||
|
m_park_near_bounds[W] = p_header->mW;
|
||
|
m_park_near_bounds[L] = p_header->mL;
|
||
|
m_theme = (p_header->mTheme);
|
||
|
Ed::CParkEditor::Instance()->SetTimeOfDayScript(p_header->mTODScript);
|
||
|
|
||
|
GetGenerator()->SetMaxPlayers(p_header->mMaxPlayers);
|
||
|
// SG: Was setting to the incorrect number (8 when it should have been 2). I think
|
||
|
// it is redundant anyway as max players is set elsewhere already
|
||
|
//GameNet::Manager::Instance()->SetMaxPlayers(p_header->mMaxPlayers);
|
||
|
|
||
|
CompressedFloorEntry *p_floor_entry = (CompressedFloorEntry *) (p_header + 1);
|
||
|
for (int i = 0; i < FLOOR_MAX_WIDTH; i++)
|
||
|
{
|
||
|
for (int j = 0; j < FLOOR_MAX_LENGTH; j++)
|
||
|
{
|
||
|
m_floor_height_map[i][j].mHeight = (int) p_floor_entry->mHeight;
|
||
|
m_floor_height_map[i][j].mEnclosedFloor = 0;
|
||
|
p_floor_entry++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
uint8 *p_meta_entry = (uint8 *) p_floor_entry;
|
||
|
Dbg_Printf( "****** NUM METAS WHILE READING FROM BUFFER : %d\n", p_header->mNumMetas );
|
||
|
for (int i = 0; i < (p_header->mNumMetas); i++)
|
||
|
{
|
||
|
uint32 *p_meta_entry_first = (uint32 *) p_meta_entry;
|
||
|
uint32 *p_meta_entry_second = (uint32 *) (p_meta_entry + 4);
|
||
|
uint32 meta1 = (*p_meta_entry_first);
|
||
|
uint32 meta2 = (*p_meta_entry_second);
|
||
|
|
||
|
//Ryan("compressed piece: 0x%x 0x%x\n", *p_meta_entry_first, *p_meta_entry_second);
|
||
|
|
||
|
uint32 metapiece_index = meta1 & 1023;
|
||
|
uint32 metapiece_checksum = p_save_map_array->GetChecksum(metapiece_index);
|
||
|
|
||
|
if (metapiece_checksum != dead_piece_checksum)
|
||
|
{
|
||
|
CAbstractMetaPiece *p_source_meta = GetAbstractMeta(metapiece_checksum);
|
||
|
Dbg_MsgAssert(p_source_meta, ("couldn't find abstract meta %s", Script::FindChecksumName(metapiece_checksum)));
|
||
|
#ifdef __PLAT_NGC__
|
||
|
if (!(p_source_meta->m_flags & CMetaPiece::mNOT_ON_GC))
|
||
|
#endif
|
||
|
{
|
||
|
CConcreteMetaPiece *p_meta = CreateConcreteMeta(p_source_meta);
|
||
|
GridDims pos;
|
||
|
pos[X] = (meta1 >> 10) & 255;
|
||
|
pos[Z] = (meta1 >> 18) & 255;
|
||
|
pos[Y] = ((meta2 >> 2) & 31) - 16;
|
||
|
int rot = meta2 & 3;
|
||
|
p_meta->SetRot(Mth::ERot90(rot));
|
||
|
AddMetaPieceToPark(pos, p_meta);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
p_meta_entry += 8;
|
||
|
}
|
||
|
|
||
|
// Gap section
|
||
|
|
||
|
CompressedGapOld *p_in_gap = (CompressedGapOld *) p_meta_entry;
|
||
|
for (int g = 0; g < (p_header->mNumGaps); g++)
|
||
|
{
|
||
|
CGapManager::GapDescriptor desc;
|
||
|
|
||
|
for (int half = 0; half < 2; half++)
|
||
|
{
|
||
|
desc.loc[half][X] = p_in_gap->x[half];
|
||
|
desc.loc[half][Y] = p_in_gap->y[half] - (MAX_HEIGHT>>1);
|
||
|
desc.loc[half][Z] = p_in_gap->z[half];
|
||
|
desc.rot[half] = (p_in_gap->rot>>(half*4)) & 15;
|
||
|
|
||
|
desc.leftExtent[half] = (p_in_gap->extent[half]>>4) & 15;
|
||
|
desc.rightExtent[half] = (p_in_gap->extent[half]) & 15;
|
||
|
//Ryan("adding gap at (%d,%d,%d)\n", p_in_gap->x[half], p_in_gap->y[half], p_in_gap->z[half]);
|
||
|
}
|
||
|
Dbg_Assert(strlen(p_in_gap->text) < 32);
|
||
|
strcpy(desc.text, p_in_gap->text);
|
||
|
desc.score = (int) (p_in_gap->score);
|
||
|
desc.numCompleteHalves = 2;
|
||
|
|
||
|
AddGap(desc);
|
||
|
|
||
|
p_in_gap++;
|
||
|
}
|
||
|
|
||
|
m_compressed_map_flags = ECompressedMapFlags(m_compressed_map_flags | mIN_SYNC_WITH_PARK);
|
||
|
m_compressed_map_flags = ECompressedMapFlags(m_compressed_map_flags & ~mIS_NEWER_THAN_PARK);
|
||
|
|
||
|
// XXX
|
||
|
ParkEd("end CParkManager::read_from_compressed_map_buffer_old()");
|
||
|
}
|
||
|
|
||
|
void CParkManager::setup_default_dimensions()
|
||
|
{
|
||
|
int default_inner_dim = Script::GetInt("ed_default_inner_dim", Script::ASSERT);
|
||
|
Dbg_Assert(default_inner_dim <= MAX_WIDTH && default_inner_dim <= MAX_LENGTH);
|
||
|
|
||
|
m_park_far_bounds.SetXYZ(1, -4, 1);
|
||
|
m_park_far_bounds.SetWHL(MAX_WIDTH, 8, MAX_LENGTH);
|
||
|
m_park_near_bounds.SetXYZ(1 + (MAX_WIDTH - default_inner_dim) / 2, -4, 1 + (MAX_LENGTH - default_inner_dim) / 2);
|
||
|
m_park_near_bounds.SetWHL(default_inner_dim, 8, default_inner_dim);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void CParkManager::setup_road_mask()
|
||
|
{
|
||
|
/*
|
||
|
The first four entries in m_road_mask_tab will be set up in RebuildInnerShell()
|
||
|
*/
|
||
|
|
||
|
Script::CArray *p_road_mask_array = Script::GetArray("Ed_Roadmask", Script::ASSERT);
|
||
|
m_road_mask_tab_size = p_road_mask_array->GetSize();
|
||
|
for (uint i = 4; i < 4 + m_road_mask_tab_size; i++)
|
||
|
{
|
||
|
Dbg_Assert(i < NUM_ROAD_PIECES);
|
||
|
Script::CArray *p_entry = p_road_mask_array->GetArray(i);
|
||
|
|
||
|
m_road_mask_tab[i][X] = p_entry->GetInt(0);
|
||
|
m_road_mask_tab[i][Z] = p_entry->GetInt(1);
|
||
|
m_road_mask_tab[i][W] = p_entry->GetInt(2);
|
||
|
m_road_mask_tab[i][L] = p_entry->GetInt(3);
|
||
|
m_road_mask_tab[i][Y] = 0;
|
||
|
m_road_mask_tab[i].MakeInfinitelyHigh();
|
||
|
}
|
||
|
|
||
|
m_road_mask_tab_size += 4;
|
||
|
}
|
||
|
|
||
|
|
||
|
void CParkManager::setup_lighting()
|
||
|
{
|
||
|
|
||
|
|
||
|
Script::CArray *pThemeArray = Script::GetArray("Editor_Light_Info");
|
||
|
// Script::CArray *pSizeArray = pThemeArray->GetArray(m_currentThemeIndex);
|
||
|
// Script::CScriptStructure *pLightInfo = pSizeArray->GetStructure(m_currentShellSizeIndex);
|
||
|
Script::CArray *pSizeArray = pThemeArray->GetArray(0);
|
||
|
Script::CScriptStructure *pLightInfo = pSizeArray->GetStructure(0);
|
||
|
|
||
|
float amb_const;
|
||
|
pLightInfo->GetFloat("ambient_const", &amb_const, true);
|
||
|
Mth::Vector ambient_rgb;
|
||
|
pLightInfo->GetVector("ambient_rgb", &ambient_rgb, true);
|
||
|
float falloff_const;
|
||
|
pLightInfo->GetFloat("falloff_const", &falloff_const, true);
|
||
|
Mth::Vector falloff_rgb;
|
||
|
pLightInfo->GetVector("falloff_rgb", &falloff_rgb, true);
|
||
|
float cursor_ambience;
|
||
|
pLightInfo->GetFloat("cursor_ambience", &cursor_ambience, true);
|
||
|
|
||
|
|
||
|
Script::CArray *pLightArray;
|
||
|
pLightInfo->GetArray("pos", &pLightArray, true);
|
||
|
|
||
|
mp_generator->SetLightProps(pLightArray->GetSize(),
|
||
|
amb_const * ambient_rgb.GetX(), amb_const * ambient_rgb.GetY(), amb_const * ambient_rgb.GetZ(),
|
||
|
falloff_const * falloff_rgb.GetX(), falloff_const * falloff_rgb.GetY(), falloff_const * falloff_rgb.GetZ(),
|
||
|
cursor_ambience);
|
||
|
|
||
|
for (int i = 0; i < (int)pLightArray->GetSize(); i++)
|
||
|
{
|
||
|
Script::CVector *pInPos = pLightArray->GetVector(i);
|
||
|
Mth::Vector outPos;
|
||
|
outPos.Set(pInPos->mX * CParkGenerator::CELL_WIDTH,
|
||
|
pInPos->mY * CParkGenerator::CELL_HEIGHT,
|
||
|
pInPos->mZ * CParkGenerator::CELL_LENGTH);
|
||
|
mp_generator->SetLight(outPos, i);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
}
|