Make UI respond instantly when holding/cancelling production/research.

master
Cyp 2011-12-05 14:22:18 +01:00
parent a35ff1e8fe
commit 5c2cf9fa06
9 changed files with 132 additions and 99 deletions

View File

@ -4702,8 +4702,7 @@ static bool loadSaveStructure2(const char *pFileName, STRUCTURE **ppList)
psFactory->timeStartHold = ini.value("Factory/timeStartHold", psFactory->timeStartHold).toInt();
psFactory->loopsPerformed = ini.value("Factory/loopsPerformed", psFactory->loopsPerformed).toInt();
psFactory->productionOutput = ini.value("Factory/productionOutput", psFactory->productionOutput).toInt();
psFactory->statusPending = (FACTORY_STATUS_PENDING)ini.value("Factory/statusPending", psFactory->statusPending).toInt();
psFactory->pendingCount = ini.value("Factory/pendingCount", psFactory->pendingCount).toInt();
// statusPending and pendingCount belong to the GUI, not the game state.
psFactory->secondaryOrder = ini.value("Factory/secondaryOrder", psFactory->secondaryOrder).toInt();
//adjust the module structures IMD
if (capacity)
@ -4931,8 +4930,7 @@ bool writeStructFile(const char *pFileName)
ini.setValue("Factory/timeStartHold", psFactory->timeStartHold);
ini.setValue("Factory/loopsPerformed", psFactory->loopsPerformed);
ini.setValue("Factory/productionOutput", psFactory->productionOutput);
ini.setValue("Factory/statusPending", psFactory->statusPending); // FACTORY_STATUS_PENDING enum
ini.setValue("Factory/pendingCount", psFactory->pendingCount);
// statusPending and pendingCount belong to the GUI, not the game state.
ini.setValue("Factory/secondaryOrder", psFactory->secondaryOrder);
if (psFactory->psSubject != NULL) ini.setValue("Factory/template", psFactory->psSubject->multiPlayerID);

View File

@ -5446,12 +5446,13 @@ static bool setResearchStats(BASE_OBJECT *psObj, BASE_STATS *psStats)
{
// Say that we want to do reseach [sic].
sendResearchStatus(psBuilding, pResearch->ref - REF_RESEARCH_START, selectedPlayer, true);
setStatusPendingStart(*psResFacilty, pResearch); // Tell UI that we are going to research.
}
else
{
cancelResearch(psBuilding, ModeQueue);
setStatusPendingCancel(*psResFacilty);
}
psResFacilty->psSubjectPending = pResearch; // Tell UI that we are going to research.
//stop the button from flashing once a topic has been chosen
stopReticuleButtonFlash(IDRET_RESEARCH);
return true;
@ -5734,10 +5735,10 @@ static void intObjStatRMBPressed(UDWORD id)
else if (psStructure->pStructureType->type == REF_RESEARCH)
{
//check if active
if (((RESEARCH_FACILITY *)psStructure->pFunctionality)->psSubject)
if (structureIsResearchingPending(psStructure))
{
//if not curently on hold, set it
if (((RESEARCH_FACILITY *)psStructure->pFunctionality)->timeStartHold == 0)
if (!StructureIsOnHoldPending(psStructure))
{
holdResearch(psStructure, ModeQueue);
}

View File

@ -135,9 +135,6 @@ static SDWORD ButtonDrawYOffset;
static void DeleteButtonData(void);
static bool StructureIsResearching(STRUCTURE *Structure);
static bool StructureIsResearchingPending(STRUCTURE *Structure);
// Set audio IDs for form opening/closing anims.
// Use -1 to dissable audio.
@ -219,7 +216,6 @@ void intUpdateProgressBar(WIDGET *psWidget, W_CONTEXT *psContext)
STRUCTURE *Structure;
FACTORY *Manufacture;
RESEARCH_FACILITY *Research;
PLAYER_RESEARCH *pPlayerRes;
W_BARGRAPH *BarGraph = (W_BARGRAPH*)psWidget;
psObj = (BASE_OBJECT*)BarGraph->pUserData; // Get the object associated with this widget.
@ -286,18 +282,25 @@ void intUpdateProgressBar(WIDGET *psWidget, W_CONTEXT *psContext)
formatPower(BarGraph, neededPower, powerToBuild);
}
}
else if(StructureIsResearching(Structure)) // Is it researching.
else if(structureIsResearchingPending(Structure)) // Is it researching.
{
Research = StructureGetResearch(Structure);
pPlayerRes = &asPlayerResList[selectedPlayer][Research->psSubject->index];
if (pPlayerRes->currentPoints != 0)
unsigned currentPoints = 0;
if (Research->psSubject != NULL)
{
currentPoints = asPlayerResList[selectedPlayer][Research->psSubject->index].currentPoints;
}
if (currentPoints != 0)
{
int researchRate = Research->timeStartHold == 0? Research->researchPoints : 0;
formatTime(BarGraph, pPlayerRes->currentPoints, Research->psSubject->researchPoints, researchRate, _("Research Progress"));
formatTime(BarGraph, currentPoints, Research->psSubject->researchPoints, researchRate, _("Research Progress"));
}
else
{
formatPower(BarGraph, checkPowerRequest(Structure), Research->psSubject->researchPower);
// Not yet started production.
int neededPower = checkPowerRequest(Structure);
int powerToBuild = Research->psSubject != NULL? Research->psSubject->researchPower : 0;
formatPower(BarGraph, neededPower, powerToBuild);
}
}
@ -763,7 +766,7 @@ void intDisplayStatusButton(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset, WZ
break;
case REF_RESEARCH:
if (StructureIsResearchingPending(Structure))
if (structureIsResearchingPending(Structure))
{
iIMDShape *shape = (iIMDShape *)Object;
Stats = (BASE_STATS*)Buffer->Data2;
@ -2634,6 +2637,16 @@ iIMDShape *DroidGetIMD(DROID *Droid)
return Droid->sDisplay.imd;
}
template<typename Functionality>
static inline bool _structureIsManufacturingPending(Functionality const &functionality)
{
if (functionality.statusPending != FACTORY_NOTHING_PENDING)
{
return functionality.statusPending == FACTORY_START_PENDING || functionality.statusPending == FACTORY_HOLD_PENDING;
}
return functionality.psSubject != NULL;
}
bool StructureIsManufacturingPending(STRUCTURE *structure)
{
switch (structure->pStructureType->type)
@ -2641,12 +2654,7 @@ bool StructureIsManufacturingPending(STRUCTURE *structure)
case REF_FACTORY:
case REF_CYBORG_FACTORY:
case REF_VTOL_FACTORY:
if (structure->pFunctionality->factory.statusPending != FACTORY_NOTHING_PENDING)
{
return structure->pFunctionality->factory.statusPending == FACTORY_START_PENDING ||
structure->pFunctionality->factory.statusPending == FACTORY_HOLD_PENDING;
}
return structure->pFunctionality->factory.psSubject != NULL;
return _structureIsManufacturingPending(structure->pFunctionality->factory);
default:
return false;
}
@ -2657,15 +2665,19 @@ FACTORY *StructureGetFactory(STRUCTURE *Structure)
return &Structure->pFunctionality->factory;
}
static bool StructureIsResearching(STRUCTURE *Structure)
bool structureIsResearchingPending(STRUCTURE *structure)
{
return Structure->pStructureType->type == REF_RESEARCH && Structure->pFunctionality->researchFacility.psSubject != NULL;
return structure->pStructureType->type == REF_RESEARCH && _structureIsManufacturingPending(structure->pFunctionality->researchFacility);
}
static bool StructureIsResearchingPending(STRUCTURE *Structure)
template<typename Functionality>
static inline bool structureIsOnHoldPending(Functionality const &functionality)
{
return Structure->pStructureType->type == REF_RESEARCH && (Structure->pFunctionality->researchFacility.psSubject != NULL ||
Structure->pFunctionality->researchFacility.psSubjectPending != NULL);
if (functionality.statusPending != FACTORY_NOTHING_PENDING)
{
return functionality.statusPending == FACTORY_HOLD_PENDING;
}
return functionality.timeStartHold != 0;
}
bool StructureIsOnHoldPending(STRUCTURE *structure)
@ -2675,17 +2687,9 @@ bool StructureIsOnHoldPending(STRUCTURE *structure)
case REF_FACTORY:
case REF_CYBORG_FACTORY:
case REF_VTOL_FACTORY:
if (structure->pFunctionality->factory.statusPending != FACTORY_NOTHING_PENDING)
{
return structure->pFunctionality->factory.statusPending == FACTORY_HOLD_PENDING;
}
return structure->pFunctionality->factory.timeStartHold != 0;
return structureIsOnHoldPending(structure->pFunctionality->factory);
case REF_RESEARCH:
if (structure->pFunctionality->researchFacility.psSubjectPending != NULL)
{
return false;
}
return structure->pFunctionality->researchFacility.timeStartHold != 0;
return structureIsOnHoldPending(structure->pFunctionality->researchFacility);
default:
ASSERT(false, "Huh?");
return false;

View File

@ -231,7 +231,8 @@ iIMDShape *DroidGetIMD(DROID *Droid);
UDWORD DroidGetIMDIndex(DROID *Droid);
bool DroidIsDemolishing(DROID *Droid);
bool StructureIsManufacturingPending(STRUCTURE *structure); ///< Returns true iff the structure is either manufacturing or on hold (even if not yet synchronised).
bool StructureIsManufacturingPending(STRUCTURE *structure); ///< Returns true iff the structure is either manufacturing or on hold (even if not yet synchronised). (But ignores research.)
bool structureIsResearchingPending(STRUCTURE *structure); ///< Returns true iff the structure is either researching or on hold (even if not yet synchronised). (But ignores manufacturing.)
bool StructureIsOnHoldPending(STRUCTURE *structure); ///< Returns true iff the structure is on hold (even if not yet synchronised).
DROID_TEMPLATE *FactoryGetTemplate(FACTORY *Factory);

View File

@ -300,6 +300,21 @@ void sendStructureInfo(STRUCTURE *psStruct, STRUCTURE_INFO structureInfo_, DROID
NETend();
}
template<typename Functionality>
static inline void popStatusPending(Functionality &functionality)
{
if (functionality.pendingCount == 0)
{
++functionality.pendingCount;
}
if (--functionality.pendingCount == 0)
{
// Subject is now synchronised, remove pending.
functionality.psSubjectPending = NULL;
functionality.statusPending = FACTORY_NOTHING_PENDING;
}
}
void recvStructureInfo(NETQUEUE queue)
{
uint8_t player = 0;
@ -341,16 +356,11 @@ void recvStructureInfo(NETQUEUE queue)
if (StructIsFactory(psStruct))
{
if (psStruct->pFunctionality->factory.pendingCount == 0)
{
++psStruct->pFunctionality->factory.pendingCount;
}
if (--psStruct->pFunctionality->factory.pendingCount == 0)
{
// Subject is now synchronised, remove pending.
psStruct->pFunctionality->factory.psSubjectPending = NULL;
psStruct->pFunctionality->factory.statusPending = FACTORY_NOTHING_PENDING;
}
popStatusPending(psStruct->pFunctionality->factory);
}
else if (psStruct->pStructureType->type == REF_RESEARCH)
{
popStatusPending(psStruct->pFunctionality->researchFacility);
}
syncDebugStructure(psStruct, '<');
@ -358,7 +368,7 @@ void recvStructureInfo(NETQUEUE queue)
switch (structureInfo)
{
case STRUCTUREINFO_MANUFACTURE: structSetManufacture(psStruct, psTempl, ModeImmediate); break;
case STRUCTUREINFO_CANCELPRODUCTION: cancelProduction(psStruct, ModeImmediate); break;
case STRUCTUREINFO_CANCELPRODUCTION: cancelProduction(psStruct, ModeImmediate, false); break;
case STRUCTUREINFO_HOLDPRODUCTION: holdProduction(psStruct, ModeImmediate); break;
case STRUCTUREINFO_RELEASEPRODUCTION: releaseProduction(psStruct, ModeImmediate); break;
case STRUCTUREINFO_HOLDRESEARCH: holdResearch(psStruct, ModeImmediate); break;

View File

@ -1213,19 +1213,18 @@ void ResearchRelease(void)
/*puts research facility on hold*/
void holdResearch(STRUCTURE *psBuilding, QUEUE_MODE mode)
{
RESEARCH_FACILITY *psResFac;
ASSERT( psBuilding->pStructureType->type == REF_RESEARCH,
"holdResearch: structure not a research facility" );
RESEARCH_FACILITY *psResFac = &psBuilding->pFunctionality->researchFacility;
if (mode == ModeQueue)
{
sendStructureInfo(psBuilding, STRUCTUREINFO_HOLDRESEARCH, NULL);
setStatusPendingHold(*psResFac);
return;
}
psResFac = (RESEARCH_FACILITY *)psBuilding->pFunctionality;
if (psResFac->psSubject)
{
//set the time the research facilty was put on hold
@ -1243,19 +1242,18 @@ void holdResearch(STRUCTURE *psBuilding, QUEUE_MODE mode)
/*release a research facility from hold*/
void releaseResearch(STRUCTURE *psBuilding, QUEUE_MODE mode)
{
RESEARCH_FACILITY *psResFac;
ASSERT( psBuilding->pStructureType->type == REF_RESEARCH,
"releaseResearch: structure not a research facility" );
RESEARCH_FACILITY *psResFac = &psBuilding->pFunctionality->researchFacility;
if (mode == ModeQueue)
{
sendStructureInfo(psBuilding, STRUCTUREINFO_RELEASERESEARCH, NULL);
setStatusPendingRelease(*psResFac);
return;
}
psResFac = (RESEARCH_FACILITY *)psBuilding->pFunctionality;
if (psResFac->psSubject && psResFac->timeStartHold)
{
//adjust the start time for the current subject
@ -1299,11 +1297,10 @@ void cancelResearch(STRUCTURE *psBuilding, QUEUE_MODE mode)
{
UDWORD topicInc;
PLAYER_RESEARCH *pPlayerRes;
RESEARCH_FACILITY *psResFac;
ASSERT(psBuilding->pStructureType->type == REF_RESEARCH, "Structure not a research facility");
psResFac = (RESEARCH_FACILITY *)psBuilding->pFunctionality;
RESEARCH_FACILITY *psResFac = &psBuilding->pFunctionality->researchFacility;
if( !(RESEARCH *)psResFac->psSubject)
{
debug(LOG_SYNC, "Invalid research topic");
@ -1320,6 +1317,7 @@ void cancelResearch(STRUCTURE *psBuilding, QUEUE_MODE mode)
sendResearchStatus(NULL, topicInc, psBuilding->player, false);
// Immediately tell the UI that we can research this now. (But don't change the game state.)
MakeResearchCancelledPending(pPlayerRes);
setStatusPendingCancel(*psResFac);
return; // Wait for our message before doing anything. (Whatever this function does...)
}

View File

@ -996,9 +996,7 @@ bool structSetManufacture(STRUCTURE *psStruct, DROID_TEMPLATE *psTempl, QUEUE_MO
if (mode == ModeQueue)
{
sendStructureInfo(psStruct, STRUCTUREINFO_MANUFACTURE, psTempl);
psStruct->pFunctionality->factory.psSubjectPending = psTempl;
psStruct->pFunctionality->factory.statusPending = FACTORY_START_PENDING;
++psFact->pendingCount;
setStatusPendingStart(*psFact, psTempl);
return true; // Wait for our message before doing anything.
}
@ -6567,13 +6565,13 @@ STRUCTURE *findDeliveryFactory(FLAG_POSITION *psDelPoint)
/*cancels the production run for the factory and returns any power that was
accrued but not used*/
void cancelProduction(STRUCTURE *psBuilding, QUEUE_MODE mode)
void cancelProduction(STRUCTURE *psBuilding, QUEUE_MODE mode, bool mayClearProductionRun)
{
ASSERT_OR_RETURN( , StructIsFactory(psBuilding), "structure not a factory");
FACTORY *psFactory = &psBuilding->pFunctionality->factory;
if (psBuilding->player == productionPlayer)
if (psBuilding->player == productionPlayer && mayClearProductionRun)
{
//clear the production run for this factory
if (psFactory->psAssemblyPoint->factoryInc < asProductionRun[psFactory->psAssemblyPoint->factoryType].size())
@ -6589,10 +6587,7 @@ void cancelProduction(STRUCTURE *psBuilding, QUEUE_MODE mode)
if (mode == ModeQueue)
{
sendStructureInfo(psBuilding, STRUCTUREINFO_CANCELPRODUCTION, NULL);
psFactory->psSubjectPending = NULL;
psFactory->statusPending = FACTORY_CANCEL_PENDING;
++psFactory->pendingCount;
setStatusPendingCancel(*psFactory);
return;
}
@ -6626,16 +6621,7 @@ void holdProduction(STRUCTURE *psBuilding, QUEUE_MODE mode)
if (mode == ModeQueue)
{
sendStructureInfo(psBuilding, STRUCTUREINFO_HOLDPRODUCTION, NULL);
if (psFactory->psSubjectPending == NULL)
{
psFactory->psSubjectPending = psFactory->psSubject;
}
else
{
psFactory->statusPending = FACTORY_HOLD_PENDING;
}
++psFactory->pendingCount;
setStatusPendingHold(*psFactory);
return;
}
@ -6666,16 +6652,7 @@ void releaseProduction(STRUCTURE *psBuilding, QUEUE_MODE mode)
if (mode == ModeQueue)
{
sendStructureInfo(psBuilding, STRUCTUREINFO_RELEASEPRODUCTION, NULL);
if (psFactory->psSubjectPending == NULL && psFactory->statusPending != FACTORY_CANCEL_PENDING)
{
psFactory->psSubjectPending = psFactory->psSubject;
}
if (psFactory->psSubjectPending != NULL)
{
psFactory->statusPending = FACTORY_START_PENDING;
}
++psFactory->pendingCount;
setStatusPendingRelease(*psFactory);
return;
}

View File

@ -317,7 +317,7 @@ extern void factoryLoopAdjust(STRUCTURE *psStruct, bool add);
/*cancels the production run for the factory and returns any power that was
accrued but not used*/
extern void cancelProduction(STRUCTURE *psBuilding, QUEUE_MODE mode);
void cancelProduction(STRUCTURE *psBuilding, QUEUE_MODE mode, bool mayClearProductionRun = true);
/*set a factory's production run to hold*/
extern void holdProduction(STRUCTURE *psBuilding, QUEUE_MODE mode);
@ -455,6 +455,48 @@ static inline void _setStructureTarget(STRUCTURE *psBuilding, BASE_OBJECT *psNew
#endif
}
// Functions for the GUI to know what's pending, before it's synchronised.
template<typename Functionality, typename Subject>
static inline void setStatusPendingStart(Functionality &functionality, Subject *subject)
{
functionality.psSubjectPending = subject;
functionality.statusPending = FACTORY_START_PENDING;
++functionality.pendingCount;
}
template<typename Functionality>
static inline void setStatusPendingCancel(Functionality &functionality)
{
functionality.psSubjectPending = NULL;
functionality.statusPending = FACTORY_CANCEL_PENDING;
++functionality.pendingCount;
}
template<typename Functionality>
static inline void setStatusPendingHold(Functionality &functionality)
{
if (functionality.psSubjectPending == NULL)
{
functionality.psSubjectPending = functionality.psSubject;
}
functionality.statusPending = FACTORY_HOLD_PENDING;
++functionality.pendingCount;
}
template<typename Functionality>
static inline void setStatusPendingRelease(Functionality &functionality)
{
if (functionality.psSubjectPending == NULL && functionality.statusPending != FACTORY_CANCEL_PENDING)
{
functionality.psSubjectPending = functionality.psSubject;
}
if (functionality.psSubjectPending != NULL)
{
functionality.statusPending = FACTORY_START_PENDING;
}
++functionality.pendingCount;
}
void checkStructure(const STRUCTURE* psStructure, const char * const location_description, const char * function, const int recurse);
#define CHECK_STRUCTURE(object) checkStructure((object), AT_MACRO, __FUNCTION__, max_check_object_recursion)

View File

@ -150,12 +150,22 @@ enum STRUCT_STATES
SS_BLUEPRINT_PLANNED_BY_ALLY,
};
enum StatusPending
{
FACTORY_NOTHING_PENDING = 0,
FACTORY_START_PENDING,
FACTORY_HOLD_PENDING,
FACTORY_CANCEL_PENDING
};
struct RESEARCH;
struct RESEARCH_FACILITY
{
RESEARCH * psSubject; // The subject the structure is working on.
RESEARCH * psSubjectPending; // The subject the structure is going to work on when the GAME_RESEARCHSTATUS message is received.
StatusPending statusPending; ///< Pending = not yet synchronised.
unsigned pendingCount; ///< Number of messages sent but not yet processed.
UDWORD capacity; /* Number of upgrade modules added*/
UDWORD timeStarted; /* The time the building started on the subject*/
UDWORD researchPoints; /* Research Points produced per research cycle*/
@ -163,14 +173,6 @@ struct RESEARCH_FACILITY
UDWORD timeStartHold; /* The time the research facility was put on hold*/
};
enum FACTORY_STATUS_PENDING
{
FACTORY_NOTHING_PENDING = 0,
FACTORY_START_PENDING,
FACTORY_HOLD_PENDING,
FACTORY_CANCEL_PENDING
};
struct DROID_TEMPLATE;
struct FACTORY
@ -183,7 +185,7 @@ struct FACTORY
Build Cycle*/
DROID_TEMPLATE * psSubject; ///< The subject the structure is working on.
DROID_TEMPLATE * psSubjectPending; ///< The subject the structure is going to working on. (Pending = not yet synchronised.)
FACTORY_STATUS_PENDING statusPending; ///< Pending = not yet synchronised.
StatusPending statusPending; ///< Pending = not yet synchronised.
unsigned pendingCount; ///< Number of messages sent but not yet processed.
UDWORD timeStarted; /* The time the building started on the subject*/