diff options
Diffstat (limited to 'src/Generating/PiecePool.cpp')
-rw-r--r-- | src/Generating/PiecePool.cpp | 503 |
1 files changed, 503 insertions, 0 deletions
diff --git a/src/Generating/PiecePool.cpp b/src/Generating/PiecePool.cpp new file mode 100644 index 000000000..201c70afd --- /dev/null +++ b/src/Generating/PiecePool.cpp @@ -0,0 +1,503 @@ +// PiecePool.cpp + +// Implements the cPiecePool class representing a pool of cPieces - "parts" of a structure, used in piece-generators +// A cPiece is a single static part of a structure that can rotate around the Y axis, has connectors to other pieces and knows how to draw itself into the world. +// The pool manages the pieces and provides lists of its pieces matching criteria, and provides relative weights for the random distribution of pieces. + +#include "Globals.h" +#include "PiecePool.h" +#include "VerticalStrategy.h" +#include "VerticalLimit.h" + + + + + +//////////////////////////////////////////////////////////////////////////////// +// cPiece: + +bool cPiece::SetVerticalStrategyFromString(const AString & a_StrategyDesc, bool a_LogWarnings) +{ + auto strategy = CreateVerticalStrategyFromString(a_StrategyDesc, a_LogWarnings); + if (strategy == nullptr) + { + return false; + } + m_VerticalStrategy = strategy; + return true; +} + + + + + +bool cPiece::SetVerticalLimitFromString(const AString & a_LimitDesc, bool a_LogWarnings) +{ + auto limit = CreateVerticalLimitFromString(a_LimitDesc, a_LogWarnings); + if (limit == nullptr) + { + return false; + } + m_VerticalLimit = limit; + return true; +} + + + + + +Vector3i cPiece::RotatePos(const Vector3i & a_Pos, int a_NumCCWRotations) const +{ + Vector3i Size = GetSize(); + switch (a_NumCCWRotations) + { + case 0: + { + // No rotation needed + return a_Pos; + } + case 1: + { + // 1 CCW rotation: + return Vector3i(a_Pos.z, a_Pos.y, Size.x - a_Pos.x - 1); + } + case 2: + { + // 2 rotations ( = axis flip): + return Vector3i(Size.x - a_Pos.x - 1, a_Pos.y, Size.z - a_Pos.z - 1); + } + case 3: + { + // 1 CW rotation: + return Vector3i(Size.z - a_Pos.z - 1, a_Pos.y, a_Pos.x); + } + } + ASSERT(!"Unhandled rotation"); + return a_Pos; +} + + + + + +cPiece::cConnector cPiece::RotateMoveConnector(const cConnector & a_Connector, int a_NumCCWRotations, int a_MoveX, int a_MoveY, int a_MoveZ) const +{ + cPiece::cConnector res(a_Connector); + + // Rotate the res connector: + switch (a_NumCCWRotations) + { + case 0: + { + // No rotation needed + break; + } + case 1: + { + // 1 CCW rotation: + res.m_Direction = cConnector::RotateDirectionCCW(res.m_Direction); + break; + } + case 2: + { + // 2 rotations ( = axis flip): + res.m_Direction = cConnector::RotateDirection(res.m_Direction); + break; + } + case 3: + { + // 1 CW rotation: + res.m_Direction = cConnector::RotateDirectionCW(res.m_Direction); + break; + } + } + res.m_Pos = RotatePos(a_Connector.m_Pos, a_NumCCWRotations); + + // Move the res connector: + res.m_Pos.x += a_MoveX; + res.m_Pos.y += a_MoveY; + res.m_Pos.z += a_MoveZ; + + return res; +} + + + + + +cCuboid cPiece::RotateHitBoxToConnector( + const cPiece::cConnector & a_MyConnector, + const Vector3i & a_ToConnectorPos, + int a_NumCCWRotations +) const +{ + ASSERT(a_NumCCWRotations == (a_NumCCWRotations % 4)); + Vector3i ConnPos = RotatePos(a_MyConnector.m_Pos, a_NumCCWRotations); + ConnPos = a_ToConnectorPos - ConnPos; + return RotateMoveHitBox(a_NumCCWRotations, ConnPos.x, ConnPos.y, ConnPos.z); +} + + + + + +cCuboid cPiece::RotateMoveHitBox(int a_NumCCWRotations, int a_MoveX, int a_MoveY, int a_MoveZ) const +{ + ASSERT(a_NumCCWRotations == (a_NumCCWRotations % 4)); + cCuboid res = GetHitBox(); + res.p1 = RotatePos(res.p1, a_NumCCWRotations); + res.p2 = RotatePos(res.p2, a_NumCCWRotations); + res.p1.Move(a_MoveX, a_MoveY, a_MoveZ); + res.p2.Move(a_MoveX, a_MoveY, a_MoveZ); + return res; +} + + + + + +//////////////////////////////////////////////////////////////////////////////// +// cPiece::cConnector: + +cPiece::cConnector::cConnector(int a_X, int a_Y, int a_Z, int a_Type, eDirection a_Direction) : + m_Pos(a_X, a_Y, a_Z), + m_Type(a_Type), + m_Direction(a_Direction) +{ +} + + + + + +cPiece::cConnector::cConnector(const Vector3i & a_Pos, int a_Type, eDirection a_Direction) : + m_Pos(a_Pos), + m_Type(a_Type), + m_Direction(a_Direction) +{ +} + + + + + +Vector3i cPiece::cConnector::AddDirection(const Vector3i & a_Pos, eDirection a_Direction) +{ + switch (a_Direction) + { + case dirXM: return Vector3i(a_Pos.x - 1, a_Pos.y, a_Pos.z); + case dirXP: return Vector3i(a_Pos.x + 1, a_Pos.y, a_Pos.z); + case dirYM: return Vector3i(a_Pos.x, a_Pos.y - 1, a_Pos.z); + case dirYP: return Vector3i(a_Pos.x, a_Pos.y + 1, a_Pos.z); + case dirZM: return Vector3i(a_Pos.x, a_Pos.y, a_Pos.z - 1); + case dirZP: return Vector3i(a_Pos.x, a_Pos.y, a_Pos.z + 1); + case dirYM_XM_ZM: return Vector3i(a_Pos.x, a_Pos.y - 1, a_Pos.z); + case dirYM_XM_ZP: return Vector3i(a_Pos.x, a_Pos.y - 1, a_Pos.z); + case dirYM_XP_ZM: return Vector3i(a_Pos.x, a_Pos.y - 1, a_Pos.z); + case dirYM_XP_ZP: return Vector3i(a_Pos.x, a_Pos.y - 1, a_Pos.z); + case dirYP_XM_ZM: return Vector3i(a_Pos.x, a_Pos.y + 1, a_Pos.z); + case dirYP_XM_ZP: return Vector3i(a_Pos.x, a_Pos.y + 1, a_Pos.z); + case dirYP_XP_ZM: return Vector3i(a_Pos.x, a_Pos.y + 1, a_Pos.z); + case dirYP_XP_ZP: return Vector3i(a_Pos.x, a_Pos.y + 1, a_Pos.z); + } + #if !defined(__clang__) + ASSERT(!"Unknown connector direction"); + return a_Pos; + #endif +} + + + + + +const char * cPiece::cConnector::DirectionToString(eDirection a_Direction) +{ + switch (a_Direction) + { + case dirXM: return "x-"; + case dirXP: return "x+"; + case dirYM: return "y-"; + case dirYP: return "y+"; + case dirZM: return "z-"; + case dirZP: return "z+"; + case dirYM_XM_ZM: return "y-x-z-"; + case dirYM_XM_ZP: return "y-x-z+"; + case dirYM_XP_ZM: return "y-x+z-"; + case dirYM_XP_ZP: return "y-x+z+"; + case dirYP_XM_ZM: return "y+x-z-"; + case dirYP_XM_ZP: return "y+x-z+"; + case dirYP_XP_ZM: return "y+x+z-"; + case dirYP_XP_ZP: return "y+x+z+"; + } + #if !defined(__clang__) + ASSERT(!"Unknown connector direction"); + return "<unknown>"; + #endif +} + + + + + +bool cPiece::cConnector::IsValidDirection(int a_Direction) +{ + switch (a_Direction) + { + case dirXM: + case dirXP: + case dirYM: + case dirYP: + case dirZM: + case dirZP: + case dirYM_XM_ZM: + case dirYM_XM_ZP: + case dirYM_XP_ZM: + case dirYM_XP_ZP: + case dirYP_XM_ZM: + case dirYP_XM_ZP: + case dirYP_XP_ZM: + case dirYP_XP_ZP: + { + return true; + } + } + return false; +} + + + + + +cPiece::cConnector::eDirection cPiece::cConnector::RotateDirection(eDirection a_Direction) +{ + // 180-degree rotation: + switch (a_Direction) + { + case dirXM: return dirXP; + case dirXP: return dirXM; + case dirYM: return dirYM; + case dirYP: return dirYP; + case dirZM: return dirZM; + case dirZP: return dirZP; + case dirYM_XM_ZM: return dirYM_XP_ZP; + case dirYM_XM_ZP: return dirYM_XP_ZM; + case dirYM_XP_ZM: return dirYM_XM_ZP; + case dirYM_XP_ZP: return dirYM_XM_ZM; + case dirYP_XM_ZM: return dirYP_XP_ZP; + case dirYP_XM_ZP: return dirYP_XP_ZM; + case dirYP_XP_ZM: return dirYP_XM_ZP; + case dirYP_XP_ZP: return dirYP_XM_ZM; + } + #if !defined(__clang__) + ASSERT(!"Unknown connector direction"); + return a_Direction; + #endif +} + + + + + +cPiece::cConnector::eDirection cPiece::cConnector::RotateDirectionCCW(eDirection a_Direction) +{ + // 90 degrees CCW rotation: + switch (a_Direction) + { + case dirXM: return dirZP; + case dirXP: return dirZM; + case dirYM: return dirYM; + case dirYP: return dirYP; + case dirZM: return dirXM; + case dirZP: return dirXP; + case dirYM_XM_ZM: return dirYM_XM_ZP; + case dirYM_XM_ZP: return dirYM_XP_ZP; + case dirYM_XP_ZM: return dirYM_XM_ZM; + case dirYM_XP_ZP: return dirYM_XP_ZM; + case dirYP_XM_ZM: return dirYP_XM_ZP; + case dirYP_XM_ZP: return dirYP_XP_ZP; + case dirYP_XP_ZM: return dirYP_XM_ZM; + case dirYP_XP_ZP: return dirYP_XP_ZM; + } + #if !defined(__clang__) + ASSERT(!"Unknown connector direction"); + return a_Direction; + #endif +} + + + + + +cPiece::cConnector::eDirection cPiece::cConnector::RotateDirectionCW(eDirection a_Direction) +{ + // 90 degrees CW rotation: + switch (a_Direction) + { + case dirXM: return dirZM; + case dirXP: return dirZP; + case dirYM: return dirYM; + case dirYP: return dirYP; + case dirZM: return dirXP; + case dirZP: return dirXM; + case dirYM_XM_ZM: return dirYM_XP_ZM; + case dirYM_XM_ZP: return dirYM_XM_ZM; + case dirYM_XP_ZM: return dirYM_XP_ZP; + case dirYM_XP_ZP: return dirYM_XM_ZP; + case dirYP_XM_ZM: return dirYP_XP_ZM; + case dirYP_XM_ZP: return dirYP_XM_ZM; + case dirYP_XP_ZM: return dirYP_XP_ZP; + case dirYP_XP_ZP: return dirYP_XM_ZP; + } + #if !defined(__clang__) + ASSERT(!"Unknown connector direction"); + return a_Direction; + #endif +} + + + + + +int cPiece::cConnector::GetNumCCWRotationsToFit(eDirection a_FixedDir, eDirection a_RotatingDir) +{ + // Translation of direction - direction -> number of CCW rotations needed: + // You need DirectionRotationTable[fixed][rot] CCW turns to connect rot to fixed (they are opposite) + // -1 if not possible + static const int DirectionRotationTable[14][14] = + { + /* YM, YP, ZM, ZP, XM, XP, YM-XM-ZM, YM-XM-ZP, YM-XP-ZM, YM-XP-ZP, YP-XM-ZM, YP-XM-ZP, YP-XP-ZM, YP-XP-ZP */ + /* YM */ { 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + /* YP */ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, + /* ZM */ {-1, -1, 2, 0, 1, 3, -1, -1, -1, -1, -1, -1, -1, -1}, + /* ZP */ {-1, -1, 0, 2, 3, 1, -1, -1, -1, -1, -1, -1, -1, -1}, + /* XM */ {-1, -1, 3, 1, 2, 0, -1, -1, -1, -1, -1, -1, -1, -1}, + /* XP */ {-1, -1, 1, 3, 0, 2, -1, -1, -1, -1, -1, -1, -1, -1}, + /* YM-XM-ZM */ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 3, 1, 2}, + /* YM-XM-ZP */ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 0, 2, 3}, + /* YM-XP-ZM */ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, 2, 0, 1}, + /* YM-XP-ZP */ {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, 1, 3, 0}, + /* YP-XM-ZM */ {-1, -1, -1, -1, -1, -1, 0, 3, 1, 2, -1, -1, -1, -1}, + /* YP-XM-ZP */ {-1, -1, -1, -1, -1, -1, 1, 0, 2, 3, -1, -1, -1, -1}, + /* YP-XP-ZM */ {-1, -1, -1, -1, -1, -1, 3, 2, 0, 1, -1, -1, -1, -1}, + /* YP-XP-ZP */ {-1, -1, -1, -1, -1, -1, 2, 1, 3, 0, -1, -1, -1, -1}, + }; + + return DirectionRotationTable[a_FixedDir][a_RotatingDir]; +} + + + + + +bool cPiece::cConnector::StringToDirection(const AString & a_Value, eDirection & a_Out) +{ + // First try converting as a number: + int dirInt; + if (StringToInteger(a_Value, dirInt)) + { + if (!IsValidDirection(dirInt)) + { + return false; + } + a_Out = static_cast<eDirection>(dirInt); + return true; + } + + // Compare to string representation: + static const struct + { + const char * m_String; + eDirection m_Value; + } StringDirections[] = + { + {"x-", dirXM}, + {"x+", dirXP}, + {"y-", dirYM}, + {"y+", dirYP}, + {"z-", dirZM}, + {"z+", dirZP}, + {"y-x-z-", dirYM_XM_ZM}, + {"y-x-z+", dirYM_XM_ZP}, + {"y-x+z-", dirYM_XP_ZM}, + {"y-x+z+", dirYM_XP_ZP}, + {"y+x-z-", dirYP_XM_ZM}, + {"y+x-z+", dirYP_XM_ZP}, + {"y+x+z-", dirYP_XP_ZM}, + {"y+x+z+", dirYP_XP_ZP}, + + // Alternate names, with slashes: + {"y-/x-/z-", dirYM_XM_ZM}, + {"y-/x-/z+", dirYM_XM_ZP}, + {"y-/x+/z-", dirYM_XP_ZM}, + {"y-/x+/z+", dirYM_XP_ZP}, + {"y+/x-/z-", dirYP_XM_ZM}, + {"y+/x-/z+", dirYP_XM_ZP}, + {"y+/x+/z-", dirYP_XP_ZM}, + {"y+/x+/z+", dirYP_XP_ZP}, + }; + auto lcValue = StrToLower(a_Value); + for (size_t i = 0; i < ARRAYCOUNT(StringDirections); i++) + { + if (strcmp(lcValue.c_str(), StringDirections[i].m_String) == 0) + { + a_Out = StringDirections[i].m_Value; + return true; + } + } + + // Not understood, failure: + return false; +} + + + + + +//////////////////////////////////////////////////////////////////////////////// +// cPlacedPiece: + +cPlacedPiece::cPlacedPiece(const cPlacedPiece * a_Parent, const cPiece & a_Piece, const Vector3i & a_Coords, int a_NumCCWRotations) : + m_Parent(a_Parent), + m_Piece(&a_Piece), + m_Coords(a_Coords), + m_NumCCWRotations(a_NumCCWRotations), + m_HasBeenMovedToGround(false) +{ + m_Depth = (m_Parent == nullptr) ? 0 : (m_Parent->GetDepth() + 1); + m_HitBox = a_Piece.RotateMoveHitBox(a_NumCCWRotations, a_Coords.x, a_Coords.y, a_Coords.z); + m_HitBox.Sort(); +} + + + + + +cPiece::cConnector cPlacedPiece::GetRotatedConnector(size_t a_Index) const +{ + cPiece::cConnectors Connectors = m_Piece->GetConnectors(); + ASSERT(Connectors.size() >= a_Index); + return m_Piece->RotateMoveConnector(Connectors[a_Index], m_NumCCWRotations, m_Coords.x, m_Coords.y, m_Coords.z); +} + + + + + +cPiece::cConnector cPlacedPiece::GetRotatedConnector(const cPiece::cConnector & a_Connector) const +{ + return m_Piece->RotateMoveConnector(a_Connector, m_NumCCWRotations, m_Coords.x, m_Coords.y, m_Coords.z); +} + + + + + +void cPlacedPiece::MoveToGroundBy(int a_OffsetY) +{ + m_Coords.y += a_OffsetY; + m_HasBeenMovedToGround = true; +} + + + + |