Skip to content

Commit

Permalink
power: Implement a power queue in power.cpp.
Browse files Browse the repository at this point in the history
Structures now need to be rewritten to request all required power at the start of construction.
  • Loading branch information
Cyp committed Nov 7, 2011
1 parent d3ee6bf commit 43ce2e5
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 90 deletions.
2 changes: 0 additions & 2 deletions src/loop.cpp
Expand Up @@ -299,8 +299,6 @@ GAMECODE gameLoop(void)

fireWaitingCallbacks(); //Now is the good time to fire waiting callbacks (since interpreter is off now)

throttleEconomy();

for(i = 0; i < MAX_PLAYERS; i++)
{
//update the current power available for a player
Expand Down
163 changes: 82 additions & 81 deletions src/power.cpp
Expand Up @@ -45,7 +45,7 @@
#include "random.h"


#define EXTRACT_POINTS 1
#define EXTRACT_POINTS 1
#define EASY_POWER_MOD 110
#define NORMAL_POWER_MOD 100
#define HARD_POWER_MOD 90
Expand All @@ -55,95 +55,108 @@

//flag used to check for power calculations to be done or not
bool powerCalculated;
static UDWORD nextPowerSystemUpdate;

/* Updates the current power based on the extracted power and a Power Generator*/
static void updateCurrentPower(POWER_GEN *psPowerGen, UDWORD player);
static int64_t updateExtractedPower(STRUCTURE *psBuilding);

//returns the relevant list based on OffWorld or OnWorld
static STRUCTURE* powerStructList(UBYTE player);
static STRUCTURE *powerStructList(int player);

struct PLAYER_POWER
struct PowerRequest
{
int64_t amount; ///< Amount of power being requested.
unsigned id; ///< Structure which is requesting power.
};

struct PlayerPower
{
// All fields are 32.32 fixed point.
int64_t currentPower; ///< The current amount of power avaialble to the player.
int64_t powerProduced; ///< Power produced
int64_t powerRequested; ///< Power requested
int64_t economyThrottle; ///< What fraction of the requested power is actually delivered
int64_t currentPower; ///< The current amount of power available to the player.
std::vector<PowerRequest> powerQueue; ///< Requested power.
};

static PLAYER_POWER asPower[MAX_PLAYERS];
static PlayerPower asPower[MAX_PLAYERS];

/*allocate the space for the playerPower*/
bool allocPlayerPower(void)
bool allocPlayerPower()
{
clearPlayerPower();
powerCalculated = true;
return true;
}

/*clear the playerPower */
void clearPlayerPower(void)
void clearPlayerPower()
{
UDWORD player;

for (player = 0; player < MAX_PLAYERS; player++)
for (unsigned player = 0; player < MAX_PLAYERS; player++)
{
asPower[player].currentPower = 0;
asPower[player].powerProduced = 0;
asPower[player].powerRequested = 0;
asPower[player].economyThrottle = FP_ONE;
asPower[player].powerQueue.clear();
}
nextPowerSystemUpdate = 0;
}

static void syncDebugEconomy(unsigned player, char ch)
/// Returns true iff the power is available. New requests replace old ones (without losing the position in the queue).
static bool addPowerRequest(unsigned player, unsigned id, int64_t amount)
{
syncDebug("%c economy%u = %"PRId64",%"PRId64",%"PRId64",%"PRId64"", ch, player, asPower[player].currentPower, asPower[player].economyThrottle, asPower[player].powerProduced, asPower[player].powerRequested);
PlayerPower *p = &asPower[player];

int64_t requiredPower = amount;
size_t n;
for (n = 0; n < p->powerQueue.size() && p->powerQueue[n].id != id; ++n)
{
requiredPower += p->powerQueue[n].amount;
}
if (n == p->powerQueue.size())
{
p->powerQueue.resize(n + 1);
p->powerQueue[n].id = id;
}
p->powerQueue[n].amount = amount;
return requiredPower <= p->currentPower;
}

void throttleEconomy(void)
void delPowerRequest(STRUCTURE *psStruct)
{
int player;
int64_t newThrottle;
PlayerPower *p = &asPower[psStruct->player];

if (gameTime < nextPowerSystemUpdate)
for (size_t n = 0; n < p->powerQueue.size(); ++n)
{
return;
if (p->powerQueue[n].id == psStruct->id)
{
p->powerQueue.erase(p->powerQueue.begin() + n);
return;
}
}
nextPowerSystemUpdate = gameTime + 1000;
}

for (player = 0; player < MAX_PLAYERS; player++)
{
syncDebugEconomy(player, '<');
static int64_t checkPrecisePowerRequest(STRUCTURE *psStruct)
{
PlayerPower *p = &asPower[psStruct->player];

if (asPower[player].currentPower >= asPower[player].powerRequested ||
asPower[player].powerRequested <= asPower[player].powerProduced)
{
// we have enough power
newThrottle = FP_ONE;
}
else
{
newThrottle = (asPower[player].powerProduced + asPower[player].currentPower) / (asPower[player].powerRequested/FP_ONE + 1);
}
if (newThrottle <= asPower[player].economyThrottle)
{
// quickly slow down
asPower[player].economyThrottle = newThrottle;
}
else if ((asPower[player].powerRequested/FP_ONE + 1) * asPower[player].economyThrottle * 2 < asPower[player].currentPower)
int64_t requiredPower = 0;
for (size_t n = 0; n < p->powerQueue.size(); ++n)
{
requiredPower += p->powerQueue[n].amount;
if (p->powerQueue[n].id == psStruct->id)
{
// slowly speed up
asPower[player].economyThrottle += FP_ONE/50;
p->powerQueue.erase(p->powerQueue.begin() + n);
return requiredPower;
}
CLIP(asPower[player].economyThrottle, 0, FP_ONE);
asPower[player].powerProduced = 0;
asPower[player].powerRequested = 0;

syncDebugEconomy(player, '>');
}

ASSERT(false, "Checking power for nonexistent power request.");
return 1000000*FP_ONE;
}

int32_t checkPowerRequest(STRUCTURE *psStruct)
{
return checkPrecisePowerRequest(psStruct) / FP_ONE;
}

static void syncDebugEconomy(unsigned player, char ch)
{
syncDebug("%c economy%u = %"PRId64"", ch, player, asPower[player].currentPower);
}

/*check the current power - if enough return true, else return false */
Expand Down Expand Up @@ -214,7 +227,7 @@ static int64_t updateExtractedPower(STRUCTURE *psBuilding)
}

//returns the relevant list based on OffWorld or OnWorld
STRUCTURE* powerStructList(UBYTE player)
STRUCTURE* powerStructList(int player)
{
ASSERT(player < MAX_PLAYERS, "powerStructList: Bad player");
if (offWorldKeepLists)
Expand All @@ -235,17 +248,18 @@ void updatePlayerPower(UDWORD player)

ASSERT(player < MAX_PLAYERS, "updatePlayerPower: Bad player");

for (psStruct = powerStructList((UBYTE)player); psStruct != NULL; psStruct =
psStruct->psNext)
syncDebugEconomy(player, '<');

for (psStruct = powerStructList(player); psStruct != NULL; psStruct = psStruct->psNext)
{
if (psStruct->pStructureType->type == REF_POWER_GEN && psStruct->
status == SS_BUILT)
if (psStruct->pStructureType->type == REF_POWER_GEN && psStruct->status == SS_BUILT)
{
updateCurrentPower((POWER_GEN *)psStruct->pFunctionality, player);
}
}
asPower[player].powerProduced += asPower[player].currentPower - powerBefore;
syncDebug("updatePlayerPower%u %"PRId64"->%"PRId64"", player, powerBefore, asPower[player].currentPower);

syncDebugEconomy(player, '<');
}

/* Updates the current power based on the extracted power and a Power Generator*/
Expand Down Expand Up @@ -316,40 +330,27 @@ int64_t getPrecisePower(unsigned player)
return asPower[player].currentPower;
}

// Why is there randomity in the power code?
static int randomRound(int64_t val)
int requestPowerFor(STRUCTURE *psStruct, int32_t amount, int points)
{
return (val + gameRandU32()) >> 32;
return requestPrecisePowerFor(psStruct, amount*FP_ONE, points);
}

int requestPowerFor(int player, int32_t amount, int points)
int requestPrecisePowerFor(STRUCTURE *psStruct, int64_t amount, int points)
{
return requestPrecisePowerFor(player, amount*FP_ONE, points);
}

int requestPrecisePowerFor(int player, int64_t amount, int points)
{
int pointsConsidered = randomRound(points * asPower[player].economyThrottle);
// only what it needs for the n amount of points we consider giving
int64_t amountConsidered;

if (points == 0 || amount <= 0 || !powerCalculated)
{
return points;
}

amountConsidered = amount * pointsConsidered / points;

// keep track on how much energy we could possibly spend
asPower[player].powerRequested += amount;

if (amountConsidered <= asPower[player].currentPower)
bool haveEnoughPower = addPowerRequest(psStruct->player, psStruct->id, amount);
if (haveEnoughPower)
{
// you can have it
asPower[player].currentPower -= amountConsidered;
syncDebug("requestPrecisePowerFor%d give%d,want%d", player, pointsConsidered, points);
return pointsConsidered;
asPower[psStruct->player].currentPower -= amount;
delPowerRequest(psStruct);
syncDebug("requestPrecisePowerFor%d,%u amount%"PRId64"", psStruct->player, psStruct->id, amount);
return points;
}
syncDebug("requestPrecisePowerFor%d giveNone,want%d", player, points);
syncDebug("requestPrecisePowerFor%d,%u wait,amount%"PRId64"", psStruct->player, psStruct->id, amount);
return 0; // no power this frame
}
12 changes: 8 additions & 4 deletions src/power.h
Expand Up @@ -33,14 +33,20 @@ extern bool allocPlayerPower(void);
/** Clear the playerPower. */
extern void clearPlayerPower(void);

/// Removes any pending power request from this structure.
void delPowerRequest(STRUCTURE *psStruct);

/// Checks how much power must be accumulated, before the power request from this structure can be satisfied.
int32_t checkPowerRequest(STRUCTURE *psStruct);

/** Reset the power levels when a power_gen or resource_extractor is destroyed. */
extern bool resetPlayerPower(UDWORD player, STRUCTURE *psStruct);

/** Check the available power. */
bool checkPower(int player, uint32_t quantity);

extern int requestPowerFor(int player, int32_t amount, int points);
extern int requestPrecisePowerFor(int player, int64_t amount, int points);
int requestPowerFor(STRUCTURE *psStruct, int32_t amount, int points);
int requestPrecisePowerFor(STRUCTURE *psStruct, int64_t amount, int points);

extern void addPower(int player, int32_t quantity);

Expand All @@ -63,6 +69,4 @@ void powerCalc(bool on);
/** Flag used to check for power calculations to be done or not. */
extern bool powerCalculated;

extern void throttleEconomy(void);

#endif // __INCLUDED_SRC_POWER_H__
8 changes: 5 additions & 3 deletions src/structure.cpp
Expand Up @@ -912,7 +912,7 @@ void structureBuild(STRUCTURE *psStruct, DROID *psDroid, int buildPoints)
{
buildPoints = newBuildPoints - psStruct->currentBuildPts + 1;
}
buildPointsToAdd = requestPowerFor(psStruct->player, powerNeeded, buildPoints);
buildPointsToAdd = requestPowerFor(psStruct, powerNeeded, buildPoints);
}
else
{
Expand Down Expand Up @@ -3190,7 +3190,7 @@ static void aiUpdateStructure(STRUCTURE *psStructure, bool isMission)
if (pointsToAdd > 0 && pResearch->researchPoints > 0) // might be a "free" research
{
int64_t powerNeeded = (int64_t(pResearch->researchPower * pointsToAdd) << 32) / pResearch->researchPoints;
pPlayerRes->currentPoints += requestPrecisePowerFor(psStructure->player, powerNeeded, pointsToAdd);
pPlayerRes->currentPoints += requestPrecisePowerFor(psStructure, powerNeeded, pointsToAdd);
psResFacility->timeStarted = gameTime;
}
syncDebug("Research at %u/%u.", pPlayerRes->currentPoints, pResearch->researchPoints);
Expand Down Expand Up @@ -3300,7 +3300,7 @@ static void aiUpdateStructure(STRUCTURE *psStructure, bool isMission)
int64_t powerNeeded = ((int64_t)(((DROID_TEMPLATE *)pSubject)->powerPoints*secondsElapsed*psFactory->productionOutput) << 32)/((DROID_TEMPLATE*)pSubject)->buildPoints;
if (secondsElapsed > 0)
{
progress = requestPrecisePowerFor(psStructure->player, powerNeeded, secondsElapsed);
progress = requestPrecisePowerFor(psStructure, powerNeeded, secondsElapsed);
psFactory->timeToBuild -= progress;
psFactory->timeStarted = psFactory->timeStarted + secondsElapsed*GAME_TICKS_PER_SEC;
}
Expand Down Expand Up @@ -4808,6 +4808,8 @@ bool removeStruct(STRUCTURE *psDel, bool bDestroy)
intRefreshScreen();
}

delPowerRequest(psDel);

return resourceFound;
}

Expand Down

0 comments on commit 43ce2e5

Please sign in to comment.