216 changes: 43 additions & 173 deletions src/power.c
Original file line number Diff line number Diff line change
Expand Up @@ -291,12 +291,6 @@ void updatePlayerPower(UDWORD player)
updateCurrentPower((POWER_GEN *)psStruct->pFunctionality, player);
}
}

// Check that the psLastPowered hasn't died
if (asPower[player].psLastPowered && asPower[player].psLastPowered->died)
{
asPower[player].psLastPowered = NULL;
}
}

// only used in multiplayer games.
Expand Down Expand Up @@ -333,15 +327,50 @@ void newGameInitPower(void)
}
}

static int useAvailablePower(int player, int powerWanted)
{
static int powerPerConsumer[MAX_PLAYERS] = {0}; // These values should be reset if starting a new game, but who cares about theoretically possible desynchs like that in 2.3...
static int powerConsumersThisTick[MAX_PLAYERS] = {0};
static int powerGameTimeOfThisTick[MAX_PLAYERS] = {0};

if (powerWanted <= 0)
{
return 0; // Nothing to do.
}

if (powerGameTimeOfThisTick[player] != gameTime)
{
// We ticked.
// Each object may consume POWER_PER_SECOND power per second, but not more power than is available.
powerPerConsumer[player] = gameTime / (GAME_TICKS_PER_SEC/POWER_PER_SECOND) - (gameTime - frameTime) / (GAME_TICKS_PER_SEC/POWER_PER_SECOND);
if (powerCalculated)
{
powerPerConsumer[player] = MIN(powerPerConsumer[player], asPower[player].currentPower / MAX(powerConsumersThisTick[player], 1));
}
powerConsumersThisTick[player] = 0;
powerGameTimeOfThisTick[player] = gameTime;
}

++powerConsumersThisTick[player];

if (checkPower(player, powerPerConsumer[player])) // Must still check if the power is actually available, since available power per consumer is based on data from the previous tick.
{
int availablePower = MIN(powerPerConsumer[player], powerWanted);
usePower(player, availablePower);
return availablePower;
}
return 0;
}


/*accrue the power in the facilities that require it - returns true if use some power*/
BOOL accruePower(BASE_OBJECT *psObject)
void accruePower(BASE_OBJECT *psObject)
{
FACTORY *psFactory;
RESEARCH_FACILITY *psResearch;
REPAIR_FACILITY *psRepair;
SDWORD powerDiff;
UDWORD count;
BOOL bPowerUsed = false;
STRUCTURE *psStructure;
DROID *psDroid, *psTarget;

Expand All @@ -367,22 +396,7 @@ BOOL accruePower(BASE_OBJECT *psObject)
//check needs power
powerDiff = ((DROID_TEMPLATE *)psFactory->psSubject)->powerPoints -
psFactory->powerAccrued;
//if equal then don't need power
if (powerDiff)
{
if (POWER_PER_CYCLE >= powerDiff)
{
usePower(psStructure->player, powerDiff);
psFactory->powerAccrued += powerDiff;
bPowerUsed = true;
}
else if (powerDiff > POWER_PER_CYCLE)
{
usePower(psStructure->player, POWER_PER_CYCLE);
psFactory->powerAccrued += POWER_PER_CYCLE;
bPowerUsed = true;
}
}
psFactory->powerAccrued += useAvailablePower(psStructure->player, powerDiff);
}
break;
case REF_RESEARCH:
Expand All @@ -403,23 +417,8 @@ BOOL accruePower(BASE_OBJECT *psObject)
//check needs power
powerDiff = ((RESEARCH *)psResearch->psSubject)->researchPower -
psResearch->powerAccrued;
//if equal then don't need power
if (powerDiff)
{
//use the power if appropriate
if (POWER_PER_CYCLE >= powerDiff)
{
usePower(psStructure->player, powerDiff);
psResearch->powerAccrued += powerDiff;
bPowerUsed = true;
}
else if (powerDiff > POWER_PER_CYCLE)
{
usePower(psStructure->player, POWER_PER_CYCLE);
psResearch->powerAccrued += POWER_PER_CYCLE;
bPowerUsed = true;
}
}
//use the power if appropriate
psResearch->powerAccrued += useAvailablePower(psStructure->player, powerDiff);
}
}
break;
Expand All @@ -436,29 +435,11 @@ BOOL accruePower(BASE_OBJECT *psObject)
{
//check if need power
powerDiff = powerReqForDroidRepair(psDroid) - psDroid->powerAccrued;
//if equal then don't need power
if (powerDiff > 0)
{
powerDiff /= POWER_FACTOR;
if (POWER_PER_CYCLE >= powerDiff)
{
usePower(psStructure->player, powerDiff);
//the unit accrues the power so more than one thing can be working on it
psDroid->powerAccrued += (powerDiff * POWER_FACTOR);
bPowerUsed = true;
}
else if (powerDiff > POWER_PER_CYCLE)
{
usePower(psStructure->player, POWER_PER_CYCLE);
psDroid->powerAccrued += (POWER_PER_CYCLE * POWER_FACTOR);
bPowerUsed = true;
}
}
psDroid->powerAccrued += useAvailablePower(psStructure->player, powerDiff / POWER_FACTOR) * POWER_FACTOR;
}
break;
default:
//no need for power
bPowerUsed = false;
break;
}
break;
Expand All @@ -473,24 +454,7 @@ BOOL accruePower(BASE_OBJECT *psObject)
{
powerDiff = structPowerToBuild((STRUCTURE *)psDroid->psTarget) -
((STRUCTURE *)psDroid->psTarget)->currentPowerAccrued;
//if equal then don't need power
if (powerDiff)
{
if (POWER_PER_CYCLE >= powerDiff)
{
usePower(psDroid->player, powerDiff);
((STRUCTURE *)psDroid->psTarget)->currentPowerAccrued +=
powerDiff;
bPowerUsed = true;
}
else if (powerDiff > POWER_PER_CYCLE)
{
usePower(psDroid->player, POWER_PER_CYCLE);
((STRUCTURE *)psDroid->psTarget)->currentPowerAccrued +=
POWER_PER_CYCLE;
bPowerUsed = true;
}
}
((STRUCTURE *)psDroid->psTarget)->currentPowerAccrued += useAvailablePower(psDroid->player, powerDiff);
}
break;
case DROID_REPAIR:
Expand Down Expand Up @@ -519,79 +483,19 @@ BOOL accruePower(BASE_OBJECT *psObject)
if (psTarget)
{
powerDiff = powerReqForDroidRepair(psTarget) - psTarget->powerAccrued;
//if equal then don't need power
if (powerDiff > 0)
{
powerDiff /= POWER_FACTOR;
if (POWER_PER_CYCLE >= powerDiff)
{
usePower(psDroid->player, powerDiff);
//the unit accrues the power so more than one thing can be working on it
psTarget->powerAccrued += (powerDiff * POWER_FACTOR);
bPowerUsed = true;
}
else if (powerDiff > POWER_PER_CYCLE)
{
usePower(psDroid->player, POWER_PER_CYCLE);
psTarget->powerAccrued += (POWER_PER_CYCLE * POWER_FACTOR);
bPowerUsed = true;
}
}
psTarget->powerAccrued += useAvailablePower(psDroid->player, powerDiff / POWER_FACTOR) * POWER_FACTOR;
}
break;
default:
//no need for power
bPowerUsed = false;
break;
}
break;
default:
ASSERT( false, "accruePower: Invalid object type" );
}

return bPowerUsed;
}


//informs the power array that a object has been destroyed
void powerDestroyObject(BASE_OBJECT *psObject)
{
ASSERT(psObject != NULL, "invalid object");

//check that this wasn't the last object that received the power
if (asPower[psObject->player].psLastPowered == psObject)
{
updateLastPowered(NULL, psObject->player);
}
}

/*checks if the Object to be powered next - returns true if power*/
BOOL getLastPowered(BASE_OBJECT *psObject)
{
ASSERT(psObject != NULL, "invalid object");

if (asPower[psObject->player].psLastPowered == NULL)
{
return true;
}
/*if we've got round to the last object again, by setting to NULL will
enable the next object to get some power*/
if (asPower[psObject->player].psLastPowered == psObject)
{
asPower[psObject->player].psLastPowered = NULL;
}
return false;
}

/*inform the players power struct that the last object to receive power has changed*/
void updateLastPowered(BASE_OBJECT *psObject, UBYTE player)
{
ASSERT(player < MAX_PLAYERS, "updateLastPowered: Bad player (%u)", (unsigned int)player);
ASSERT(psObject == NULL || psObject->died == 0 || psObject->died == NOT_CURRENT_LIST,
"updateLastPowered: Null or dead object");

asPower[player].psLastPowered = psObject;
}

STRUCTURE *getRExtractor(STRUCTURE *psStruct)
{
Expand Down Expand Up @@ -677,37 +581,3 @@ BOOL droidUsesPower(DROID *psDroid)

return bUsesPower;
}

//this is a check cos there is a problem with the power but not sure where!!
void powerCheck(BOOL bBeforePowerUsed, UBYTE player)
{
static BASE_OBJECT *psLastPowered = NULL;
static BOOL bPowerBefore = false;

ASSERT(player < MAX_PLAYERS, "powerCheck: Bad player (%u)", (unsigned int)player);

if (bBeforePowerUsed)
{
// Set what the lastPowered object is before using any power
psLastPowered = asPower[player].psLastPowered;
bPowerBefore = false;
// Check that there is power available at start of loop
if (asPower[player].currentPower > POWER_PER_CYCLE)
{
bPowerBefore = true;
}
}
else
{
/* Check to see if we've been thru the whole list of structures and
* droids and not reset the lastPowered object in the power structure and
* there was some power at the start of the loop to use. */
if (psLastPowered != NULL && psLastPowered == asPower[player].psLastPowered && bPowerBefore)
{
ASSERT(false, "Trouble at mill! bBeforePowerUsed=%d psLastPowered=%p asPower[%d].psLastPowered=%p",
(int)bBeforePowerUsed, psLastPowered, player, asPower[player].psLastPowered );
// Initialise so something can have some power next cycle
asPower[player].psLastPowered = NULL;
}
}
}
17 changes: 2 additions & 15 deletions src/power.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
/** Free power on collection of oildrum. */
#define OILDRUM_POWER 100

#define POWER_PER_CYCLE 5
#define POWER_PER_SECOND 25

/** Used to determine the power cost of repairing a droid.
Definately DON'T WANT the brackets round 1/2 - it will equate to zero! */
Expand All @@ -40,7 +40,6 @@ typedef struct _player_power
{
int32_t currentPower; /**< The current amount of power avaialble to the player. */
int32_t extractedPower; /**< The power extracted but not converted. */
BASE_OBJECT *psLastPowered; /**< The last object that received power before it ran out. */
} PLAYER_POWER;

/** Allocate the space for the playerPower. */
Expand Down Expand Up @@ -76,32 +75,20 @@ void setPlayerPower(UDWORD power, UDWORD player);
/** Temp function to give all players some power when a new game has been loaded. */
void newGameInitPower(void);

/** Informs the power array that a Object has been destroyed. */
void powerDestroyObject(BASE_OBJECT *psObject);

/** Accrue the power in the facilities that require it. */
BOOL accruePower(BASE_OBJECT *psObject);

/** Inform the players power struct that the last Object to receive power has changed. */
void updateLastPowered(BASE_OBJECT *psObject,UBYTE player);
void accruePower(BASE_OBJECT *psObject);

/** Returns the next res. Ext. in the list from the one passed in. returns 1st one
in list if passed in is NULL and NULL if there's none?
*/
STRUCTURE *getRExtractor(STRUCTURE *psStruct);

/** Checks if the object to be powered next - returns true if power. */
BOOL getLastPowered(BASE_OBJECT *psStructure);

/** Defines which structure types draw power - returns true if use power. */
BOOL structUsesPower(STRUCTURE *psStruct);

/** Defines which droid types draw power - returns true if use power. */
BOOL droidUsesPower(DROID *psDroid);

/** This is a check cos there is a problem with the power but not sure where!! */
void powerCheck(BOOL bBeforePowerUsed, UBYTE player);

/** @todo Wrap access to this global and make it static for easier sanity checking! */
extern PLAYER_POWER asPower[MAX_PLAYERS];

Expand Down
18 changes: 1 addition & 17 deletions src/structure.c
Original file line number Diff line number Diff line change
Expand Up @@ -1964,8 +1964,6 @@ STRUCTURE* buildStructure(STRUCTURE_STATS* pStructureType, UDWORD x, UDWORD y, U
{
intRefreshScreen();
}
//inform power system that won't be needing power until built
powerDestroyObject((BASE_OBJECT *)psBuilding);
}
}
if(pStructureType->type!=REF_WALL && pStructureType->type!=REF_WALLCORNER)
Expand Down Expand Up @@ -2913,18 +2911,7 @@ static void aiUpdateStructure(STRUCTURE *psStructure)
//check if any power available
if (structUsesPower(psStructure))
{
if (checkPower(psStructure->player, POWER_PER_CYCLE))
{
//check if this structure is due some power
if (getLastPowered((BASE_OBJECT *)psStructure))
{
//get some power if necessary
if (accruePower((BASE_OBJECT *)psStructure))
{
updateLastPowered((BASE_OBJECT *)psStructure, psStructure->player);
}
}
}
accruePower((BASE_OBJECT *)psStructure);
}

/* Process the functionality according to type
Expand Down Expand Up @@ -4849,9 +4836,6 @@ BOOL removeStruct(STRUCTURE *psDel, BOOL bDestroy)
removeStructFromMap(psDel);
}

//tell the power system its gone
powerDestroyObject((BASE_OBJECT *)psDel);

if (bDestroy)
{
//if the structure is a resource extractor, need to put the resource back in the map
Expand Down