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
3 changes: 2 additions & 1 deletion GeneralsMD/Code/GameEngine/Include/Common/SpecialPower.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ class SpecialPowerTemplate : public Overridable
EvaMessage getEvaReadyOwn(void) const { return getFO()->m_eva_ready_own; }
EvaMessage getEvaReadyAlly(void) const { return getFO()->m_eva_ready_ally; }
EvaMessage getEvaReadyEnemy(void) const { return getFO()->m_eva_ready_enemy; }
Int getCost(void) const { return getFO()->m_cost; };
private:

const SpecialPowerTemplate* getFO() const { return (const SpecialPowerTemplate*)friend_getFinalOverride(); }
Expand Down Expand Up @@ -166,6 +166,7 @@ class SpecialPowerTemplate : public Overridable
EvaMessage m_eva_ready_own; //< eva event when own ready
EvaMessage m_eva_ready_ally; //< eva event when ally ready
EvaMessage m_eva_ready_enemy; //< eva event when enemy ready
Int m_cost; ///< money cost to use special power

static const FieldParse m_specialPowerFieldParse[]; ///< the parse table

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class OCLSpecialPowerModuleData : public SpecialPowerModuleData
Bool m_isOCLAdjustPositionToPassable; ///< Adjust target to nearest Passable cell

Bool m_selectObject; ///< Select first created object
Real m_minDistToSimilarRadius;

//We need to know what the final product is going to be for script placement calculations
//for construction sites like the sneak attack.
Expand Down
24 changes: 24 additions & 0 deletions GeneralsMD/Code/GameEngine/Source/Common/RTS/ActionManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1546,6 +1546,14 @@ Bool ActionManager::canDoSpecialPowerAtLocation( const Object *obj, const Coord3
//Not fully ready
return false;
}

// Check for money cost
if (spTemplate->getCost() > 0) {
Player* ply = obj->getControllingPlayer();
if (ply != nullptr && ply->getMoney()->countMoney() < spTemplate->getCost()) {
return false;
}
}
}

// First check terrain type, if it is cared about. Don't return a true, since there are more checks.
Expand Down Expand Up @@ -1678,6 +1686,14 @@ Bool ActionManager::canDoSpecialPowerAtObject( const Object *obj, const Object *
//Not fully ready
return false;
}

// Check for money cost
if (spTemplate->getCost() > 0) {
Player* ply = obj->getControllingPlayer();
if (ply != nullptr && ply->getMoney()->countMoney() < spTemplate->getCost()) {
return false;
}
}
}


Expand Down Expand Up @@ -2052,6 +2068,14 @@ Bool ActionManager::canDoSpecialPower( const Object *obj, const SpecialPowerTemp
//Not fully ready
return false;
}

// Check for money cost
if (spTemplate->getCost() > 0) {
Player* ply = obj->getControllingPlayer();
if (ply != nullptr && ply->getMoney()->countMoney() < spTemplate->getCost()) {
return false;
}
}
}

//use a behaviortype for custom sp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ void SpecialPowerStore::parseSpecialPowerDefinition( INI *ini )
{ "EvaReadyOwn", INI::parseEvaNameIndexList, TheEvaMessageNames, offsetof(SpecialPowerTemplate, m_eva_ready_own) },
{ "EvaReadyAlly", INI::parseEvaNameIndexList, TheEvaMessageNames, offsetof(SpecialPowerTemplate, m_eva_ready_ally) },
{ "EvaReadyEnemy", INI::parseEvaNameIndexList, TheEvaMessageNames, offsetof(SpecialPowerTemplate, m_eva_ready_enemy) },
{ "Cost", INI::parseInt, NULL, offsetof(SpecialPowerTemplate, m_cost) },
{ NULL, NULL, NULL, 0 }

};
Expand Down Expand Up @@ -333,7 +334,7 @@ SpecialPowerTemplate::SpecialPowerTemplate()
m_eva_ready_own = EVA_Invalid;
m_eva_ready_ally = EVA_Invalid;
m_eva_ready_enemy = EVA_Invalid;

m_cost = 0;
}

//-------------------------------------------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -688,8 +688,15 @@ Bool CommandButton::isValidToUseOn(const Object *sourceObj, const Object *target
Bool CommandButton::isReady(const Object *sourceObj) const
{
SpecialPowerModuleInterface *mod = sourceObj->getSpecialPowerModule( m_specialPower );
if( mod && mod->getPercentReady() == 1.0f )
return true;
if (mod) {
bool ready = mod->getPercentReady() == 1.0f;
bool can_afford{ true };
if (m_specialPower->getCost() > 0) {
can_afford = sourceObj->getControllingPlayer()->getMoney()->countMoney() >= m_specialPower->getCost();
}

if (ready && can_afford) return true;
}

if (m_upgradeTemplate && sourceObj->affectedByUpgrade(m_upgradeTemplate) && !sourceObj->hasUpgrade(m_upgradeTemplate))
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1435,6 +1435,10 @@ CommandAvailability ControlBar::getCommandAvailability( const CommandButton *com
GadgetButtonDrawInverseClock( applyToWin, percent, m_buildUpClockColor );
return COMMAND_NOT_READY;
}
else if (command->getSpecialPowerTemplate()->getCost() > 0 && player->getMoney()->countMoney() < command->getSpecialPowerTemplate()->getCost()) {
// Cannot afford
return COMMAND_CANT_AFFORD;
}
else if( SpecialAbilityUpdate *spUpdate = obj->findSpecialAbilityUpdate( command->getSpecialPowerTemplate()->getSpecialPowerType() ) )
{
if( spUpdate && spUpdate->isPowerCurrentlyInUse( command ) )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
#include "GameLogic/Module/OverchargeBehavior.h"
#include "GameLogic/Module/ProductionUpdate.h"
#include "GameLogic/ScriptEngine.h"
#include "Common/SpecialPower.h"

#include "GameNetwork/NetworkInterface.h"

Expand Down Expand Up @@ -253,6 +254,9 @@ void ControlBar::populateBuildTooltipLayout( const CommandButton *commandButton,
const ProductionPrerequisite *prereq;
Bool fireScienceButton = false;
UnsignedInt costToBuild = 0;
Bool isUseSpecialpowerButtonWithCost = false;



if(commandButton)
{
Expand Down Expand Up @@ -311,6 +315,27 @@ void ControlBar::populateBuildTooltipLayout( const CommandButton *commandButton,
descrip = TheGameText->fetch(commandButton->getDescriptionLabel());

Drawable *draw = TheInGameUI->getFirstSelectedDrawable();

//For Specialpowers with cost, add text to the tooltip
if (commandButton->getCommandType() == GUI_COMMAND_SPECIAL_POWER ||
commandButton->getCommandType() == GUI_COMMAND_SPECIAL_POWER_CONSTRUCT ||
commandButton->getCommandType() == GUI_COMMAND_SPECIAL_POWER_CONSTRUCT_FROM_SHORTCUT ||
commandButton->getCommandType() == GUI_COMMAND_SPECIAL_POWER_FROM_SHORTCUT) {
const SpecialPowerTemplate* spt = commandButton->getSpecialPowerTemplate();
if (spt != nullptr && spt->getCost() > 0) {
isUseSpecialpowerButtonWithCost = true;

costToBuild = spt->getCost();
cost.format(TheGameText->fetch("TOOLTIP:Cost"), costToBuild);

if (player->getMoney()->countMoney() < costToBuild) {
descrip.concat(L"\n\n");
descrip.concat(TheGameText->fetch("TOOLTIP:TooltipNotEnoughMoneyToBuild"));
}
}
}


Object *selectedObject = draw ? draw->getObject() : NULL;
if( selectedObject )
{
Expand All @@ -333,7 +358,6 @@ void ControlBar::populateBuildTooltipLayout( const CommandButton *commandButton,
}
}
}

//Special case: When building units & buildings, the CanMakeType determines reasons for not being able to buy stuff.
else if( thingTemplate )
{
Expand Down Expand Up @@ -518,10 +542,13 @@ void ControlBar::populateBuildTooltipLayout( const CommandButton *commandButton,
{
TheScienceStore->getNameAndDescription(st, name, descrip);

costToBuild = TheScienceStore->getSciencePurchaseCost( st );
if( costToBuild > 0 )
{
cost.format( TheGameText->fetch("TOOLTIP:ScienceCost"), costToBuild );
// Do not override cost when special power has cost
if (!isUseSpecialpowerButtonWithCost) {
costToBuild = TheScienceStore->getSciencePurchaseCost(st);
if (costToBuild > 0)
{
cost.format(TheGameText->fetch("TOOLTIP:ScienceCost"), costToBuild);
}
}

// ask each prerequisite to give us a list of the non satisfied prerequisites
Expand Down
6 changes: 3 additions & 3 deletions GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1634,10 +1634,10 @@ void InGameUI::handleBuildPlacements( void )

// If shipyard move up building to at least waterheight if lower
if (m_pendingPlaceType->isKindOf(KINDOF_SHIPYARD)) {
Real terrainZ{ 0 };
Real waterZ{ 0 };
TheTerrainLogic->isUnderwater(world.x, world.y, &waterZ, &terrainZ);
world.z = std::max(terrainZ, waterZ);
if (TheTerrainLogic->isUnderwater(world.x, world.y, &waterZ)) {
world.z = std::max(world.z, waterZ);
}
}

m_placeIcon[ 0 ]->setPosition( &world );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include "GameLogic/Object.h"

#include "GameLogic/Module/ProductionUpdate.h"
#include "GameLogic/TerrainLogic.h"



Expand Down Expand Up @@ -178,6 +179,14 @@ GameMessageDisposition PlaceEventTranslator::translateGameMessage(const GameMess
// translate the screen position of start to world target location
TheTacticalView->screenToTerrain( &anchorStart, &world );

// If shipyard move up building to at least waterheight if lower
if (build->isKindOf(KINDOF_SHIPYARD)) {
Real waterZ{ 0 };
if (TheTerrainLogic->isUnderwater(world.x, world.y, &waterZ)) {
world.z = std::max(world.z, waterZ);
}
}

Object *builderObj = TheGameLogic->findObjectByID( TheInGameUI->getPendingPlaceSourceObjectID() );

//Kris: September 27, 2002
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,9 @@
#include "GameLogic/PartitionManager.h"
#include "GameLogic/TerrainLogic.h"
#include "GameLogic/Module/OCLSpecialPower.h"
#include <Common/MessageStream.h>
#include <GameClient/InGameUI.h>
#include "Common/MessageStream.h"
#include "GameClient/InGameUI.h"
#include "Common/PlayerList.h"

///////////////////////////////////////////////////////////////////////////////////////////////////
// MODULE DATA ////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -73,6 +74,7 @@ OCLSpecialPowerModuleData::OCLSpecialPowerModuleData( void )
m_upgradeOCL.clear();
m_createLoc = CREATE_AT_EDGE_NEAR_SOURCE;
m_isOCLAdjustPositionToPassable = FALSE;
m_minDistToSimilarRadius = 0.0f;
}

//-------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -102,6 +104,7 @@ static void parseOCLUpgradePair( INI* ini, void * /*instance*/, void *store, con
{ "ReferenceObject", INI::parseAsciiString, NULL, offsetof( OCLSpecialPowerModuleData, m_referenceThingName ) },
{ "OCLAdjustPositionToPassable", INI::parseBool, NULL, offsetof( OCLSpecialPowerModuleData, m_isOCLAdjustPositionToPassable ) },
{ "SelectCreatedObject", INI::parseBool, NULL, offsetof( OCLSpecialPowerModuleData, m_selectObject ) },
{ "MinDistToSimilarRadius", INI::parseReal, NULL, offsetof(OCLSpecialPowerModuleData, m_minDistToSimilarRadius)},
{ 0, 0, 0, 0 }
};
p.add(dataFieldParse);
Expand Down Expand Up @@ -260,6 +263,41 @@ void OCLSpecialPower::doSpecialPower( UnsignedInt commandOptions )
Coord3D creationCoord;
creationCoord.set( getObject()->getPosition() );

// get the module data
const OCLSpecialPowerModuleData* modData = getOCLSpecialPowerModuleData();

if (modData->m_minDistToSimilarRadius > 0.0f) {
const ThingTemplate* checkFor = TheThingFactory->findTemplate(modData->m_referenceThingName);
if (checkFor != nullptr) {

PartitionFilterThing similarFilter(checkFor, true);

PartitionFilter* filters[2];
Int numFilters = 0;
filters[numFilters++] = &similarFilter;
filters[numFilters] = NULL;

ObjectIterator* iter = ThePartitionManager->iterateObjectsInRange(&creationCoord,
modData->m_minDistToSimilarRadius,
FROM_BOUNDINGSPHERE_2D,
filters,
ITER_FASTEST);
MemoryPoolObjectHolder holder(iter);

// We have a similar object nearby, do not trigger ocl
if (iter->first() != nullptr) {

if (getObject()->getControllingPlayer() == ThePlayerList->getLocalPlayer()) {
// play a can't do that sound (UI beep type sound)
static AudioEventRTS noCanDoSound("NoCanDoSound");
TheAudio->addAudioEvent(&noCanDoSound);
}

return;
}
}
}

// call the base class action cause we are *EXTENDING* functionality
SpecialPowerModule::doSpecialPowerAtLocation( &creationCoord, INVALID_ANGLE, commandOptions );

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,22 @@ Bool SpecialPowerModule::initiateIntentToDoSpecialPower( const Object *targetObj
//-------------------------------------------------------------------------------------------------
void SpecialPowerModule::triggerSpecialPower( const Coord3D *location )
{

Int cost{ getSpecialPowerTemplate()->getCost() };
if ( cost > 0) {
Player* ply = getObject()->getControllingPlayer();
if (ply != nullptr && ply->getMoney()->countMoney() < cost) {
// Not enough money
return;
}
else if (ply!=nullptr) {
ply->getMoney()->withdraw(cost);
}
else {
DEBUG_LOG(("Cannot withdraw money for SpecialPower '%s', player is null", getSpecialPowerTemplate()->getName().str()));
}
}

aboutToDoSpecialPower( location ); // do BEFORE recharge

createViewObject(location);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1705,11 +1705,15 @@ Object *DozerAIUpdate::construct( const ThingTemplate *what,
obj->setPosition( pos );
obj->setOrientation( angle );

// Flatten the terrain underneath the object, then adjust to the flattened height. jba.
TheTerrainLogic->flattenTerrain(obj);
Coord3D adjustedPos = *pos;
adjustedPos.z = TheTerrainLogic->getGroundHeight(pos->x, pos->y);
obj->setPosition(&adjustedPos);
// Do not flatten shipyards
if (!obj->isKindOf(KINDOF_SHIPYARD)) {

// Flatten the terrain underneath the object, then adjust to the flattened height. jba.
TheTerrainLogic->flattenTerrain(obj);
Coord3D adjustedPos = *pos;
adjustedPos.z = TheTerrainLogic->getGroundHeight(pos->x, pos->y);
obj->setPosition(&adjustedPos);
}

// Note - very important that we add to map AFTER we flatten terrain. jba.
TheAI->pathfinder()->addObjectToPathfindMap( obj );
Expand Down