45 changes: 13 additions & 32 deletions src/scriptfuncs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1191,7 +1191,7 @@ bool scrIsStructureAvailable()
return false;
}
if (apStructTypeLists[player][index] == AVAILABLE
&& asStructLimits[player][index].currentQuantity < asStructLimits[player][index].limit)
&& asStructureStats[index].curCount[player] < asStructureStats[index].upgrade[player].limit)
{
bResult = true;
}
Expand Down Expand Up @@ -2781,7 +2781,6 @@ bool scrSetStructureLimits()
{
SDWORD player, limit;
UDWORD structInc;
STRUCTURE_LIMITS *psStructLimits;

if (!stackPopParams(3, ST_STRUCTURESTAT, &structInc, VAL_INT, &limit, VAL_INT, &player))
{
Expand Down Expand Up @@ -2809,10 +2808,7 @@ bool scrSetStructureLimits()
return false;
}

psStructLimits = asStructLimits[player];
psStructLimits[structInc].limit = limit;

psStructLimits[structInc].globalLimit = limit;
asStructureStats[structInc].upgrade[player].limit = limit;

return true;
}
Expand Down Expand Up @@ -4439,7 +4435,6 @@ bool scrSetReinforcementTime()
bool scrSetAllStructureLimits()
{
SDWORD player, limit;
STRUCTURE_LIMITS *psStructLimits;
UDWORD i;

if (!stackPopParams(2, VAL_INT, &limit, VAL_INT, &player))
Expand All @@ -4461,13 +4456,9 @@ bool scrSetAllStructureLimits()
}

//set all the limits to the value specified
psStructLimits = asStructLimits[player];
for (i = 0; i < numStructureStats; i++)
{
psStructLimits[i].limit = limit;

psStructLimits[i].globalLimit = limit;

asStructureStats[i].upgrade[player].limit = limit;
}

return true;
Expand Down Expand Up @@ -5639,7 +5630,7 @@ bool scrTakeOverSingleStructure()

structureInc = psStructToTake->pStructureType->ref - REF_STRUCTURE_START;
if (playerToGain == (SDWORD)selectedPlayer && StructIsFactory(psStructToTake) &&
asStructLimits[playerToGain][structureInc].currentQuantity >= MAX_FACTORY)
asStructureStats[structureInc].curCount[playerToGain] >= MAX_FACTORY)
{
debug(LOG_NEVER, "scrTakeOverSingleStructure - factory ignored for selectedPlayer\n");
psNewStruct = nullptr;
Expand All @@ -5650,11 +5641,10 @@ bool scrTakeOverSingleStructure()
if (psNewStruct)
{
//check the structure limits aren't compromised
if (asStructLimits[playerToGain][structureInc].currentQuantity >
asStructLimits[playerToGain][structureInc].limit)
if (asStructureStats[structureInc].curCount[playerToGain] >
asStructureStats[structureInc].upgrade[playerToGain].limit)
{
asStructLimits[playerToGain][structureInc].limit = asStructLimits[
playerToGain][structureInc].currentQuantity;
asStructureStats[structureInc].upgrade[playerToGain].limit = asStructureStats[structureInc].curCount[playerToGain];
}
//for each structure taken - add graphical effect if the selectedPlayer
if (playerToGain == (SDWORD)selectedPlayer)
Expand Down Expand Up @@ -5728,7 +5718,7 @@ bool scrTakeOverStructsInArea()
//don't work on factories for the selectedPlayer
structureInc = psStruct->pStructureType->ref - REF_STRUCTURE_START;
if (toPlayer == (SDWORD)selectedPlayer && StructIsFactory(psStruct) &&
asStructLimits[toPlayer][structureInc].currentQuantity >= MAX_FACTORY)
asStructureStats[structureInc].curCount[toPlayer] >= MAX_FACTORY)
{
debug(LOG_NEVER, "scrTakeOverStructsInArea - factory ignored for selectedPlayer\n");
}
Expand All @@ -5741,11 +5731,9 @@ bool scrTakeOverStructsInArea()
numChanged++;
//check the structure limits aren't compromised
//structureInc = psNewStruct->pStructureType->ref - REF_STRUCTURE_START;
if (asStructLimits[toPlayer][structureInc].currentQuantity >
asStructLimits[toPlayer][structureInc].limit)
if (asStructureStats[structureInc].curCount[toPlayer] > asStructureStats[structureInc].upgrade[toPlayer].limit)
{
asStructLimits[toPlayer][structureInc].limit = asStructLimits[
toPlayer][structureInc].currentQuantity;
asStructureStats[structureInc].upgrade[toPlayer].limit = asStructureStats[structureInc].curCount[toPlayer];
}
//for each structure taken - add graphical effect if the selectedPlayer
if (toPlayer == (SDWORD)selectedPlayer)
Expand Down Expand Up @@ -6425,7 +6413,6 @@ bool scrGetStructureLimit()
{
SDWORD player, limit;
UDWORD structInc;
STRUCTURE_LIMITS *psStructLimits;

if (!stackPopParams(2, ST_STRUCTURESTAT, &structInc, VAL_INT, &player))
{
Expand All @@ -6447,8 +6434,7 @@ bool scrGetStructureLimit()
return false;
}

psStructLimits = asStructLimits[player];
limit = (SDWORD)psStructLimits[structInc].limit;
limit = asStructureStats[structInc].upgrade[player].limit;

scrFunctionResult.v.ival = limit;
if (!stackPushResult(VAL_INT, &scrFunctionResult))
Expand All @@ -6466,7 +6452,6 @@ bool scrStructureLimitReached()
SDWORD player;
bool bLimit = false;
UDWORD structInc;
STRUCTURE_LIMITS *psStructLimits;

if (!stackPopParams(2, ST_STRUCTURESTAT, &structInc, VAL_INT, &player))
{
Expand All @@ -6488,9 +6473,7 @@ bool scrStructureLimitReached()
return false;
}

psStructLimits = asStructLimits[player];

if (psStructLimits[structInc].currentQuantity >= psStructLimits[structInc].limit)
if (asStructureStats[structInc].curCount[player] >= asStructureStats[structInc].upgrade[player].limit)
{
bLimit = true;
}
Expand All @@ -6510,7 +6493,6 @@ bool scrGetNumStructures()
{
SDWORD player, numStructures;
UDWORD structInc;
STRUCTURE_LIMITS *psStructLimits;

if (!stackPopParams(2, ST_STRUCTURESTAT, &structInc, VAL_INT, &player))
{
Expand All @@ -6530,8 +6512,7 @@ bool scrGetNumStructures()
return false;
}

psStructLimits = asStructLimits[player];
numStructures = (SDWORD)psStructLimits[structInc].currentQuantity;
numStructures = asStructureStats[structInc].curCount[player];

scrFunctionResult.v.ival = numStructures;
if (!stackPushResult(VAL_INT, &scrFunctionResult))
Expand Down
128 changes: 29 additions & 99 deletions src/structure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,6 @@ UDWORD researchModuleStat;
//holder for all StructureStats
STRUCTURE_STATS *asStructureStats;
UDWORD numStructureStats;
//holder for the limits of each structure per map
STRUCTURE_LIMITS *asStructLimits[MAX_PLAYERS];

//used to hold the modifiers cross refd by weapon effect and structureStrength
STRUCTSTRENGTH_MODIFIER asStructStrengthModifier[WE_NUMEFFECTS][NUM_STRUCT_STRENGTH];
Expand Down Expand Up @@ -254,7 +252,6 @@ void structureInitVars()
droidLimit[i] = INT16_MAX;
commanderLimit[i] = INT16_MAX;
constructorLimit[i] = INT16_MAX;
asStructLimits[i] = nullptr;
for (j = 0; j < NUM_FLAG_TYPES; j++)
{
factoryNumFlag[i][j].clear();
Expand Down Expand Up @@ -449,6 +446,19 @@ bool loadStructureStats(const QString& filename)
// save indexes of special structures for futher use
initModuleStats(inc, psStats->type); // This function looks like a hack. But slightly less hacky than before.

if (ini.contains("userLimits"))
{
Vector3i limits = ini.vector3i("userLimits");
psStats->minLimit = limits[0];
psStats->maxLimit = limits[2];
psStats->base.limit = limits[1];
}
else
{
psStats->minLimit = 0;
psStats->maxLimit = LOTS_OF;
psStats->base.limit = LOTS_OF;
}
psStats->base.research = ini.value("researchPoints", 0).toInt();
psStats->base.moduleResearch = ini.value("moduleResearchPoints", 0).toInt();
psStats->base.production = ini.value("productionPoints", 0).toInt();
Expand All @@ -463,6 +473,7 @@ bool loadStructureStats(const QString& filename)
psStats->base.thermal = ini.value("thermal", 0).toUInt();
for (int i = 0; i < MAX_PLAYERS; i++)
{
psStats->upgrade[i].limit = psStats->base.limit;
psStats->upgrade[i].research = psStats->base.research;
psStats->upgrade[i].moduleResearch = psStats->base.moduleResearch;
psStats->upgrade[i].power = psStats->base.power;
Expand Down Expand Up @@ -566,60 +577,26 @@ bool loadStructureStats(const QString& filename)
}
ASSERT_OR_RETURN(false, g_psStatDestroyStruct, "Destroy structure stat not found");

// allocate the structureLimits structure
for (int player = 0; player < MAX_PLAYERS; ++player)
{
asStructLimits[player] = (STRUCTURE_LIMITS *)malloc(sizeof(STRUCTURE_LIMITS) * numStructureStats);
}
initStructLimits();

return true;
}

//initialise the structure limits structure
void initStructLimits()
{
for (unsigned player = 0; player < MAX_PLAYERS; player++)
{
STRUCTURE_LIMITS *psStructLimits = asStructLimits[player];
STRUCTURE_STATS *psStat = asStructureStats;

for (unsigned i = 0; i < numStructureStats; i++)
{
psStructLimits[i].limit = LOTS_OF;
psStructLimits[i].currentQuantity = 0;
psStructLimits[i].globalLimit = LOTS_OF;
if (isLasSat(psStat) || psStat->type == REF_SAT_UPLINK)
{
psStructLimits[i].limit = 1;
psStructLimits[i].globalLimit = 1;
}
psStat++;
}
}
}

/* set the current number of structures of each type built */
void setCurrentStructQuantity(bool displayError)
{
for (unsigned player = 0; player < MAX_PLAYERS; player++)
{
STRUCTURE_LIMITS *psStructLimits = asStructLimits[player];

//initialise the current quantity for all structures
for (unsigned inc = 0; inc < numStructureStats; inc++)
{
psStructLimits[inc].currentQuantity = 0;
asStructureStats[inc].curCount[player] = 0;
}

for (STRUCTURE *psCurr = apsStructLists[player]; psCurr != nullptr; psCurr = psCurr->psNext)
for (const STRUCTURE *psCurr = apsStructLists[player]; psCurr != nullptr; psCurr = psCurr->psNext)
{
unsigned inc = psCurr->pStructureType - asStructureStats;
psStructLimits[inc].currentQuantity++;
asStructureStats[inc].curCount[player]++;
if (displayError)
{
//check quantity never exceeds the limit
ASSERT(psStructLimits[inc].currentQuantity <= psStructLimits[inc].limit,
ASSERT(asStructureStats[inc].curCount[player] <= asStructureStats[inc].upgrade[player].limit,
"There appears to be too many %s on this map!", getName(&asStructureStats[inc]));
}
}
Expand Down Expand Up @@ -681,23 +658,11 @@ bool loadStructureStrengthModifiers(const char *pFileName)
return true;
}


bool structureStatsShutDown()
{
delete[] asStructureStats;
asStructureStats = nullptr;
numStructureStats = 0;

//free up the structLimits structure
for (unsigned inc = 0; inc < MAX_PLAYERS ; inc++)
{
if (asStructLimits[inc])
{
free(asStructLimits[inc]);
asStructLimits[inc] = nullptr;
}
}

return true;
}

Expand Down Expand Up @@ -1303,20 +1268,12 @@ STRUCTURE *buildStructureDir(STRUCTURE_STATS *pStructureType, UDWORD x, UDWORD y

ASSERT_OR_RETURN(nullptr, max <= numStructureStats, "Invalid structure type");

if (pStructureType->id.compare("A0CyborgFactory") == 0 && player == 0 && !bMultiPlayer)
{
// HACK: correcting SP bug, needs fixing in script(!!) (only applies for player 0)
// should be OK for Skirmish/MP games, since that is set correctly.
// scrSetStructureLimits() is called by scripts to set this normally.
asStructLimits[player][max].limit = MAX_FACTORY;
asStructLimits[player][max].globalLimit = MAX_FACTORY;
}
// Don't allow more than interface limits
if (asStructLimits[player][max].currentQuantity + 1 > asStructLimits[player][max].limit)
if (asStructureStats[max].curCount[player] + 1 > asStructureStats[max].upgrade[player].limit)
{
debug(LOG_ERROR, "Player %u: Building %s could not be built due to building limits (has %d, max %d)!",
player, getName(pStructureType), asStructLimits[player][max].currentQuantity,
asStructLimits[player][max].limit);
debug(LOG_ERROR, "Player %u: Building %s could not be built due to building limits (has %u, max %u)!",
player, getName(pStructureType), asStructureStats[max].curCount[player],
asStructureStats[max].upgrade[player].limit);
return nullptr;
}

Expand Down Expand Up @@ -1583,7 +1540,7 @@ STRUCTURE *buildStructureDir(STRUCTURE_STATS *pStructureType, UDWORD x, UDWORD y
addStructure(psBuilding);

clustNewStruct(psBuilding);
asStructLimits[player][max].currentQuantity++;
asStructureStats[max].curCount[player]++;

if (isLasSat(psBuilding->pStructureType))
{
Expand Down Expand Up @@ -3792,16 +3749,13 @@ UDWORD fillStructureList(STRUCTURE_STATS **ppList, UDWORD selectedPlayer, UDWORD
//if currently on a mission can't build factory/research/power/derricks
if (!missionIsOffworld())
{
for (psCurr = apsStructLists[selectedPlayer]; psCurr != nullptr; psCurr =
psCurr->psNext)
for (psCurr = apsStructLists[selectedPlayer]; psCurr != nullptr; psCurr = psCurr->psNext)
{
if (psCurr->pStructureType->type == REF_RESEARCH && psCurr->status ==
SS_BUILT)
if (psCurr->pStructureType->type == REF_RESEARCH && psCurr->status == SS_BUILT)
{
researchModule = true;
}
else if (psCurr->pStructureType->type == REF_FACTORY && psCurr->status ==
SS_BUILT)
else if (psCurr->pStructureType->type == REF_FACTORY && psCurr->status == SS_BUILT)
{
factoryModule = true;
}
Expand All @@ -3820,7 +3774,7 @@ UDWORD fillStructureList(STRUCTURE_STATS **ppList, UDWORD selectedPlayer, UDWORD
if (apStructTypeLists[selectedPlayer][inc] == AVAILABLE || (includeRedundantDesigns && apStructTypeLists[selectedPlayer][inc] == REDUNDANT))
{
//check not built the maximum allowed already
if (asStructLimits[selectedPlayer][inc].currentQuantity < asStructLimits[selectedPlayer][inc].limit)
if (asStructureStats[inc].curCount[selectedPlayer] < asStructureStats[inc].upgrade[selectedPlayer].limit)
{
psBuilding = asStructureStats + inc;

Expand Down Expand Up @@ -3878,30 +3832,6 @@ UDWORD fillStructureList(STRUCTURE_STATS **ppList, UDWORD selectedPlayer, UDWORD
continue;
}
}
//paranoid check!!
if (psBuilding->type == REF_FACTORY ||
psBuilding->type == REF_CYBORG_FACTORY ||
psBuilding->type == REF_VTOL_FACTORY)
{
//NEVER EVER EVER WANT MORE THAN 5 FACTORIES
if (asStructLimits[selectedPlayer][inc].currentQuantity >= MAX_FACTORY)
{
continue;
}
}
//HARD_CODE don't ever want more than one Las Sat structure
if (isLasSat(psBuilding) && getLasSatExists(selectedPlayer))
{
continue;
}
//HARD_CODE don't ever want more than one Sat Uplink structure
if (psBuilding->type == REF_SAT_UPLINK)
{
if (asStructLimits[selectedPlayer][inc].currentQuantity >= 1)
{
continue;
}
}

debug(LOG_NEVER, "adding %s (%x)", getName(psBuilding), apStructTypeLists[selectedPlayer][inc]);
ppList[count++] = psBuilding;
Expand Down Expand Up @@ -4543,9 +4473,9 @@ bool removeStruct(STRUCTURE *psDel, bool bDestroy)
}

//subtract one from the structLimits list so can build another - don't allow to go less than zero!
if (asStructLimits[psDel->player][psDel->pStructureType - asStructureStats].currentQuantity)
if (asStructureStats[psDel->pStructureType - asStructureStats].curCount[psDel->player])
{
asStructLimits[psDel->player][psDel->pStructureType - asStructureStats].currentQuantity--;
asStructureStats[psDel->pStructureType - asStructureStats].curCount[psDel->player]--;
}

//if it is a factory - need to reset the factoryNumFlag
Expand Down
3 changes: 0 additions & 3 deletions src/structure.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ extern SBYTE productionPlayer;
//holder for all StructureStats
extern STRUCTURE_STATS *asStructureStats;
extern UDWORD numStructureStats;
extern STRUCTURE_LIMITS *asStructLimits[MAX_PLAYERS];

//used to hold the modifiers cross refd by weapon effect and structureStrength
extern STRUCTSTRENGTH_MODIFIER asStructStrengthModifier[WE_NUMEFFECTS][NUM_STRUCT_STRENGTH];
Expand Down Expand Up @@ -144,8 +143,6 @@ bool checkLength(UDWORD maxRange, UDWORD x, UDWORD y, UDWORD *pDroidX, UDWORD *p

void alignStructure(STRUCTURE *psBuilding);

//initialise the structure limits structure
void initStructLimits();
/* set the current number of structures of each type built */
void setCurrentStructQuantity(bool displayError);
/* get a stat inc based on the name */
Expand Down
18 changes: 10 additions & 8 deletions src/structuredef.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,11 @@ enum STRUCT_ANIM_STATES
//this structure is used to hold the permanent stats for each type of building
struct STRUCTURE_STATS : public BASE_STATS
{
STRUCTURE_STATS() : pBaseIMD(nullptr), pECM(nullptr), pSensor(nullptr) {};
STRUCTURE_STATS() : pBaseIMD(nullptr), pECM(nullptr), pSensor(nullptr)
{
memset(curCount, 0, sizeof(curCount));
memset(upgrade, 0, sizeof(upgrade));
}

STRUCTURE_TYPE type; /* the type of structure */
STRUCT_STRENGTH strength; /* strength against the weapon effects */
Expand All @@ -118,6 +122,10 @@ struct STRUCTURE_STATS : public BASE_STATS
struct WEAPON_STATS *psWeapStat[MAX_WEAPONS];
uint64_t flags;

unsigned minLimit; ///< lowest value user can set limit to (currently unused)
unsigned maxLimit; ///< highest value user can set limit to, LOTS_OF = no limit
unsigned curCount[MAX_PLAYERS]; ///< current number of instances of this type

struct
{
unsigned research;
Expand All @@ -132,6 +140,7 @@ struct STRUCTURE_STATS : public BASE_STATS
unsigned thermal;
unsigned hitpoints;
unsigned resistance; // resist enemy takeover; 0 = immune
unsigned limit; // current max limit for this type, LOTS_OF = no limit
} upgrade[MAX_PLAYERS], base;
};

Expand Down Expand Up @@ -259,13 +268,6 @@ struct STRUCTURE : public BASE_OBJECT
};

#define LOTS_OF 0xFFFFFFFF // highest number the limit can be set to
struct STRUCTURE_LIMITS
{
uint32_t limit; // the number allowed to be built
uint32_t currentQuantity; // the number of the type currently built per player
uint32_t globalLimit; // multiplayer only. sets the max value selectable (limits changed by player)
};


//the three different types of factory (currently) - FACTORY, CYBORG_FACTORY, VTOL_FACTORY
// added repair facilities as they need an assembly point as well
Expand Down