Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1442,6 +1442,7 @@ void W3DModelDrawModuleData::parseConditionState(INI* ini, void *instance, void
{ "AltTurretArtAngle", INI::parseAngleReal, nullptr, offsetof(ModelConditionInfo, m_turrets[1].m_turretArtAngle) },
{ "AltTurretPitch", parseBoneNameKey, nullptr, offsetof(ModelConditionInfo, m_turrets[1].m_turretPitchNameKey) },
{ "AltTurretArtPitch", INI::parseAngleReal, nullptr, offsetof(ModelConditionInfo, m_turrets[1].m_turretArtPitch) },
{ "Turret1", parseBoneNameKey, nullptr, offsetof(ModelConditionInfo, m_turrets[0].m_turretAngleNameKey) },
{ "Turret1ArtAngle", INI::parseAngleReal, nullptr, offsetof(ModelConditionInfo, m_turrets[0].m_turretArtAngle) },
{ "Turret1Pitch", parseBoneNameKey, nullptr, offsetof(ModelConditionInfo, m_turrets[0].m_turretPitchNameKey) },
{ "Turret1ArtPitch", INI::parseAngleReal, nullptr, offsetof(ModelConditionInfo, m_turrets[0].m_turretArtPitch) },
Expand Down
3 changes: 3 additions & 0 deletions GeneralsMD/Code/GameEngine/Include/Common/Player.h
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,9 @@ class Player : public Snapshot
/// Build structure type on front or flank of base. Gets passed to aiPlayer.
void buildBaseDefenseStructure(const AsciiString &thingName, Bool flank);

/// Build shipyard. Gets passed to aiPlayer.
void buildShipyard(const AsciiString& thingName);

/// Recruits an instance of a specific team. Gets passed to aiPlayer.
void recruitSpecificTeam(TeamPrototype *teamProto, Real recruitRadius);

Expand Down
1 change: 1 addition & 0 deletions GeneralsMD/Code/GameEngine/Include/GameLogic/AIPlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ class AIPlayer : public MemoryPoolObject,

virtual void buildSpecificAIBuilding(const AsciiString &thingName); ///< Builds this building as soon as possible.

virtual void buildAIShipyard(const AsciiString& thingName); ///< Build structure at shipyard location

virtual void recruitSpecificAITeam(TeamPrototype *teamProto, Real recruitRadius); ///< Builds this team immediately.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
class BuildListInfo;
class SpecialPowerTemplate;

typedef BitFlags<10> UsedShipyardsMask;

/**
* The computer-controlled opponent.
Expand Down Expand Up @@ -66,6 +67,8 @@ class AISkirmishPlayer : public AIPlayer

virtual void recruitSpecificAITeam(TeamPrototype *teamProto, Real recruitRadius); ///< Builds this team immediately.

virtual void buildAIShipyard(const AsciiString& thingName) override; ///< Build structure at shipyard location

virtual Bool isSkirmishAI(void) {return true;}

virtual Bool checkBridges(Object *unit, Waypoint *way);
Expand Down Expand Up @@ -110,6 +113,7 @@ class AISkirmishPlayer : public AIPlayer
Real m_curLeftFlankRightDefenseAngle;
Real m_curRightFlankLeftDefenseAngle;
Real m_curRightFlankRightDefenseAngle;
UsedShipyardsMask m_usedShipyards;

UnsignedInt m_frameToCheckEnemy;
Player *m_currentEnemy;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ class ScriptActions : public ScriptActionsInterface
void doBuildUpgrade(const AsciiString& playerName, const AsciiString& upgrade);
void doBuildBaseDefense(Bool flank);
void doBuildBaseStructure(const AsciiString& buildingType, Bool flank);
void doBuildShipyard(const AsciiString& buildingType);
void createUnitOnTeamAt(const AsciiString& unitName, const AsciiString& objType, const AsciiString& teamName, const AsciiString& waypoint);
void doNamedAttackArea(const AsciiString& unitName, const AsciiString& areaName);
void doNamedAttackTeam(const AsciiString& unitName, const AsciiString& teamName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ class ScriptConditions : public ScriptConditionsInterface
Bool evaluateSkirmishSupplySourceSafe(Condition *pCondition, Parameter *pSkirmishPlayerParm, Parameter *pMinAmountOfSupplies );
Bool evaluateSkirmishSupplySourceAttacked(Parameter *pSkirmishPlayerParm );
Bool evaluateSkirmishStartPosition(Parameter *pSkirmishPlayerParm, Parameter *startNdx );
Bool evaluateSkirmishShipsEnabled(void);


// Stubs
Expand Down
7 changes: 7 additions & 0 deletions GeneralsMD/Code/GameEngine/Include/GameLogic/Scripts.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
#define SKIRMISH_FLANK "Flank"
#define SKIRMISH_BACKDOOR "Backdoor"
#define SKIRMISH_SPECIAL "Special"
#define SKIRMISH_SHIPYARD "Shipyard"

// Skirmish Player Areas
#define SKIRMISH_AREA_HOME_BASE "Home Base"
Expand All @@ -62,11 +63,14 @@
// Skirmish trigger names.
#define MY_INNER_PERIMETER "[Skirmish]MyInnerPerimeter"
#define MY_OUTER_PERIMETER "[Skirmish]MyOuterPerimeter"
#define MY_NAVAL_PERIMETER "[Skirmish]MyNavalPerimeter"
#define ENEMY_OUTER_PERIMETER "[Skirmish]EnemyOuterPerimeter"
#define ENEMY_INNER_PERIMETER "[Skirmish]EnemyInnerPerimeter"
#define ENEMY_NAVAL_PERIMETER "[Skirmish]EnemyNavalPerimeter"

#define INNER_PERIMETER "InnerPerimeter"
#define OUTER_PERIMETER "OuterPerimeter"
#define NAVAL_PERIMETER "NavalPerimeter"

class Parameter;
class Script;
Expand Down Expand Up @@ -543,6 +547,7 @@ class ScriptAction : public MemoryPoolObject // This is the action class.
TEAM_SET_BOOBYTRAPPED, ///< Add boobytrap to all units on team.
SHOW_WEATHER, ///< show map defined weather.
AI_PLAYER_BUILD_TYPE_NEAREST_TEAM, ///< Tell the ai player to build an object nearest team.
SKIRMISH_BUILD_SHIPYARD, ///< Tell the ai player to build a shipyard
// add new items here, please
NUM_ITEMS
};
Expand Down Expand Up @@ -971,6 +976,8 @@ class Condition : public MemoryPoolObject // This is the conditional class.
START_POSITION_IS, // True if our start position matches.
NAMED_HAS_FREE_CONTAINER_SLOTS, ///< Kris -- Checks if any given container has any free slots.

SKIRMISH_SHIPS_ENABLED, // True if ships are enabled on the played map

NUM_ITEMS // Always the last condition.
};

Expand Down
5 changes: 5 additions & 0 deletions GeneralsMD/Code/GameEngine/Include/GameLogic/TerrainLogic.h
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,9 @@ class TerrainLogic : public Snapshot,

virtual void updateBridgeDamageStates(void); ///< Updates bridge's damage info.

/// Check if a point is in a NO_SHIPYARD area
virtual bool isInNoShipyardZone(const Coord3D * pos);

Bool anyBridgesDamageStatesChanged(void) {return m_bridgeDamageStatesChanged; } ///< Bridge damage states updated.
Bool isBridgeRepaired(const Object *bridge); ///< Is bridge repaired?
Bool isBridgeBroken(const Object *bridge); ///< Is bridge Broken?
Expand All @@ -318,6 +321,8 @@ class TerrainLogic : public Snapshot,
void flattenTerrain(Object *obj); ///< Flatten the terrain under a building.
void createCraterInTerrain(Object *obj); ///< Flatten the terrain under a building.

Real getShipyardPlacementAngle(const Coord3D& worldPos, const ThingTemplate* thing);

protected:

// snapshot methods
Expand Down
8 changes: 8 additions & 0 deletions GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2495,6 +2495,14 @@ void Player::buildBaseDefenseStructure(const AsciiString &thingName, Bool flank)
}
}

//=============================================================================
void Player::buildShipyard(const AsciiString &thingName) {
if (m_ai)
{
m_ai->buildAIShipyard(thingName);
}
}

//=============================================================================
void Player::buildSpecificBuilding(const AsciiString &thingName)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,15 @@ Object *BuildAssistant::buildObjectNow( Object *constructorObject, const ThingTe
Coord3D groundPos;
groundPos.x = pos->x;
groundPos.y = pos->y;
groundPos.z = TheTerrainLogic->getGroundHeight( groundPos.x, groundPos.y );
if (!what->isKindOf(KINDOF_SHIPYARD)) {
groundPos.z = TheTerrainLogic->getGroundHeight(groundPos.x, groundPos.y);
}
else {
//If shipyard adjust to water height
Real waterZ{ 0.0 }, terrainZ{ 0.0 };
TheTerrainLogic->isUnderwater(groundPos.x, groundPos.y, &waterZ, &terrainZ);
groundPos.z = std::max(waterZ, terrainZ);
}
obj->setPosition( &groundPos );

obj->setOrientation( angle );
Expand Down Expand Up @@ -1152,6 +1160,11 @@ LegalBuildCode BuildAssistant::isLocationLegalToBuild( const Coord3D *worldPos,
else {
// IF Shipyard need some special code

// check if building center is in a NO_SHIPYARD map area
if (TheTerrainLogic->isInNoShipyardZone(worldPos)) {
return LBC_RESTRICTED_TERRAIN;
}

//
// check the footprint of where the structure would go to be clear of any non-buildable
// tiles and to make sure there isn't a restricted tile and to make sure it's "flat" enough
Expand Down
38 changes: 1 addition & 37 deletions GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1673,7 +1673,6 @@ void InGameUI::handleBuildPlacements( void )

if (m_pendingPlaceType->isKindOf(KINDOF_SHIPYARD)) {
// For shipyard sample the terrain an rotate according to descending terrain (water is lower)
const GeometryInfo& geom = m_pendingPlaceType->getTemplateGeometryInfo();

Coord3D worldPos;
TheTacticalView->screenToTerrain(&loc, &worldPos);
Expand All @@ -1683,42 +1682,7 @@ void InGameUI::handleBuildPlacements( void )
TheTerrainLogic->isUnderwater(worldPos.x, worldPos.y, &waterZ, &terrainZ);
worldPos.z = std::max(terrainZ, waterZ);

Real check_radius = 0.0f;
if (geom.getGeomType() == GEOMETRY_BOX)
{
check_radius = std::max(geom.getMinorRadius(), geom.getMajorRadius());
} // end if
else if (geom.getGeomType() == GEOMETRY_SPHERE ||
geom.getGeomType() == GEOMETRY_CYLINDER)
{
check_radius = geom.getBoundingCircleRadius();
} // end else if
else
{
DEBUG_ASSERTCRASH(0, ("InGameUI::handleBuildPlacements (Shipyard placement): Undefined geometry '%d' for '%s'", geom.getGeomType(), m_pendingPlaceType->getName().str()));
return;
} // end else

//Check 4 sample points
Real hx1 = TheTerrainLogic->getGroundHeight(worldPos.x + check_radius, worldPos.y);
Real hx2 = TheTerrainLogic->getGroundHeight(worldPos.x - check_radius, worldPos.y);
Real hy1 = TheTerrainLogic->getGroundHeight(worldPos.x, worldPos.y + check_radius);
Real hy2 = TheTerrainLogic->getGroundHeight(worldPos.x, worldPos.y - check_radius);

Real dx = hx1 - hx2;
Real dy = hy1 - hy2;

Coord2D v;
v.x = dx;
v.y = dy;
constexpr Real pi2 = PI * 2.0f;
angle = v.toAngle() + m_pendingPlaceType->getPlacementViewAngle();
if (angle < 0.0f) {
angle += pi2;
}
else if (angle > pi2) {
angle -= pi2;
}
angle = TheTerrainLogic->getShipyardPlacementAngle(worldPos, m_pendingPlaceType);
}


Expand Down
21 changes: 20 additions & 1 deletion GeneralsMD/Code/GameEngine/Source/GameLogic/AI/AIPlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,14 @@ Object *AIPlayer::buildStructureWithDozer(const ThingTemplate *bldgPlan, BuildLi
}
// construct the building
Coord3D pos = *info->getLocation();
pos.z += TheTerrainLogic->getGroundHeight(pos.x, pos.y);
if (bldgPlan->isKindOf(KINDOF_SHIPYARD)) {
Real waterZ, terrainZ;
TheTerrainLogic->isUnderwater(pos.x, pos.y, &waterZ, &terrainZ);
pos.z = std::max(waterZ, terrainZ);
}
else {
pos.z += TheTerrainLogic->getGroundHeight(pos.x, pos.y);
}
if( !dozer->getAIUpdateInterface() )
{
return nullptr;
Expand Down Expand Up @@ -1756,6 +1763,18 @@ void AIPlayer::buildSpecificAIBuilding(const AsciiString &thingName)
TheScriptEngine->AppendDebugMessage(teamStr, false);
}

// ------------------------------------------------------------------------------------------------
/** Build a structure at shipyard location */
// ------------------------------------------------------------------------------------------------
void AIPlayer::buildAIShipyard(const AsciiString &thingName)
{
//
AsciiString teamStr = "Error : Solo ai doesn't support BuildShipyard. '";
teamStr.concat(thingName);
teamStr.concat("' not built.");
TheScriptEngine->AppendDebugMessage(teamStr, false);
}

// ------------------------------------------------------------------------------------------------
/** Build an upgrade. */
// ------------------------------------------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,28 @@

#define USE_DOZER 1


template<>
const char* const UsedShipyardsMask::s_bitNameList[] =
{
"SHIPYARD_1_USED",
"SHIPYARD_2_USED",
"SHIPYARD_3_USED",
"SHIPYARD_4_USED",
"SHIPYARD_5_USED",
"SHIPYARD_6_USED",
"SHIPYARD_7_USED",
"SHIPYARD_8_USED",
"SHIPYARD_9_USED",
"SHIPYARD_10_USED",
nullptr
};
static_assert(ARRAY_SIZE(UsedShipyardsMask::s_bitNameList) == UsedShipyardsMask::NumBits + 1, "Incorrect array size");

///////////////////////////////////////////////////////////////////////////////////////////////////
// PRIVATE DATA ///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////

AISkirmishPlayer::AISkirmishPlayer( Player *p ) : AIPlayer(p),
AISkirmishPlayer::AISkirmishPlayer(Player* p) : AIPlayer(p),
m_curFlankBaseDefense(0),
m_curFrontBaseDefense(0),
m_curFrontLeftDefenseAngle(0),
Expand All @@ -74,6 +89,7 @@ m_curLeftFlankLeftDefenseAngle(0),
m_curLeftFlankRightDefenseAngle(0),
m_curRightFlankLeftDefenseAngle(0),
m_curRightFlankRightDefenseAngle(0),
m_usedShipyards(0),
m_frameToCheckEnemy(0),
m_currentEnemy(nullptr)

Expand Down Expand Up @@ -847,6 +863,61 @@ void AISkirmishPlayer::recruitSpecificAITeam(TeamPrototype *teamProto, Real recr
}
}

void AISkirmishPlayer::buildAIShipyard(const AsciiString& thingName)
{
const ThingTemplate* tTemplate = TheThingFactory->findTemplate(thingName);
if (tTemplate == nullptr) {
DEBUG_CRASH(("Couldn't find shipyard structure '%s' for side %s", thingName.str(), m_player->getSide().str()));
return;
}

if (!tTemplate->isKindOf(KINDOF_SHIPYARD)) {
DEBUG_CRASH(("Cannot instruct AI to build non-Shipyard '%s' at shipyard position for side %s", thingName.str(), m_player->getSide().str()));
}

AsciiString wpLabel;
Int index{ 1 };
wpLabel.format("%s%d_%d", SKIRMISH_SHIPYARD, m_player->getMpStartIndex() + 1, index);
const Waypoint* shipyardWp = TheTerrainLogic->getWaypointByName(wpLabel);

while (shipyardWp != nullptr && index <= UsedShipyardsMask::NumBits) {
/* See if we can build there. */
Coord3D buildPos = *shipyardWp->getLocation();


//DEBUG_LOG(("SHIPYARD_BULDING: player %d flags: %u", m_player->getMpStartIndex() + 1, m_usedShipyards.toUnsignedInt()));

// skip used index
if (!m_usedShipyards.test(index - 1)) {

//Adjust to water height
Real terrainZ{ 0 };
Real waterZ{ 0 };
TheTerrainLogic->isUnderwater(buildPos.x, buildPos.y, &waterZ, &terrainZ);
buildPos.z = std::max(terrainZ, waterZ);

Real placeAngle = TheTerrainLogic->getShipyardPlacementAngle(buildPos, tTemplate);

LegalBuildCode code = TheBuildAssistant->isLocationLegalToBuild(&buildPos, tTemplate, placeAngle,
BuildAssistant::TERRAIN_RESTRICTIONS | BuildAssistant::NO_OBJECT_OVERLAP, nullptr, m_player);

Bool canBuild = LBC_OK == code;

DEBUG_LOG(("SHIPYARD_BULDING: Location %d Legal to build for player %d (%s): %s, code: %d", index, m_player->getMpStartIndex() + 1, shipyardWp->getName().str(), canBuild ? "true" : "false", static_cast<Int>(code)));

TheTerrainVisual->removeAllBibs(); // isLocationLegalToBuild adds bib feedback, turn it off. jba.
if (canBuild) {
m_usedShipyards.set(index - 1, 1);
m_player->addToPriorityBuildList(thingName, &buildPos, placeAngle);
break;
}
}
index++;
wpLabel.format("%s%d_%d", SKIRMISH_SHIPYARD, m_player->getMpStartIndex() + 1, index);
shipyardWp = TheTerrainLogic->getWaypointByName(wpLabel);
}
}




Expand Down Expand Up @@ -1223,6 +1294,8 @@ void AISkirmishPlayer::xfer( Xfer *xfer )
// right flank right defense angle
xfer->xferReal( &m_curRightFlankRightDefenseAngle );

m_usedShipyards.xfer(xfer);

}

// ------------------------------------------------------------------------------------------------
Expand Down
Loading
Loading