Files
source/Strategic/Game Events.cpp
T
Overhaul 7a27e7105d New attack busy system
Added missing #includes

Added LUA scripting and console

Changed the way tracers are visualized, so they work more like real tracers instead of a light fountain

Fixed signedness of many grid variables used in GetMouseMapPos calls

Fixed enemy weapon choosing:  Sometimes a mortar is chosen but later rejected, but the grenade class was not reset.  Caused assertion failure

Added checks so enemies don't try to chuck RPG grenades with their hands

Now possible to shoot a someone in the head if he's in water

Fixed InitSightArrays to also clear soldier interrupt duel points.  This was causing an assertion failure elsewhere in the code because the interrupt list still had soldiers on it sometimes when this function was called.

Soldiers are much less willing to forfeit their turn over an attempt to use more APs than they have

Removed early setting of muzzle flash.  This would allow enemies to get an interrupt before you even fired.

Fixed item dropping by AI.  If AI tried to drop something while standing it would cause deadlock

Change to greatly speed up closing the sector inventory window in an unloaded sector

Added conditional compile flag to always give robot weapon ready advantage, even for 360 degree sighting


Check builddefines.h for the conditional flags.  Of greatest interest might be LUA_CONSOLE.  This will cause the game to bring up a command console when run.  However this console is severely lacking in many areas.  If anybody knows of an open-source terminal/console that could be used instead, it would be appreciated.  The existing console does bad things when you try to close it, and since it counts as a separate app, it pauses the game while it has focus.

LUA scripting is very limited, basically just proof of concept.  There is one global variable, the Soldiers array.  An array index gives you the soldier in that slot in the currently loaded sector.  The soldier has a few things that can be accessed:  name (short name); fullname (long name); grid (current grid #, can be changed); walkto(grid) (function to walk to another grid); runto(grid) (function to run to another grid)


git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@924 3b4a5df2-a311-0410-b5c6-a8a6f20db521
2007-06-09 09:01:04 +00:00

786 lines
22 KiB
C++

#ifdef PRECOMPILEDHEADERS
#include "Strategic All.h"
#else
#include "builddefines.h"
#include <stdio.h>
#include "types.h"
#include "Game Events.h"
#include "Game Clock.h"
#include "MemMan.h"
#include "Debug.h"
#include "Font Control.h"
#include "message.h"
#include "Text.h"
#endif
#ifdef JA2TESTVERSION
CHAR16 gEventName[NUMBER_OF_EVENT_TYPES_PLUS_ONE][40]={
//1234567890123456789012345678901234567890 (increase size of array if necessary)
L"Null",
L"ChangeLightValue",
L"WeatherStart",
L"WeatherEnd",
L"CheckForQuests",
L"Ambient",
L"AIMResetMercAnnoyance",
L"BobbyRayPurchase",
L"DailyUpdateBobbyRayInventory",
L"UpdateBobbyRayInventory",
//1234567890123456789012345678901234567890 (increase size of array if necessary)
L"DailyUpdateOfMercSite",
L"Day3AddEMailFromSpeck",
L"DelayedHiringOfMerc",
L"HandleInsuredMercs",
L"PayLifeInsuranceForDeadMerc",
L"MercDailyUpdate",
L"MercAboutToLeaveComment",
L"MercContractOver",
L"GroupArrival",
L"Day2AddEMailFromIMP",
//1234567890123456789012345678901234567890 (increase size of array if necessary)
L"MercComplainEquipment",
L"HourlyUpdate",
L"HandleMineIncome",
L"SetupMineIncome",
L"QueuedBattle",
L"LeavingMercArriveInDrassen",
L"LeavingMercArriveInOmerta",
L"SetByNPCSystem",
L"SecondAirportAttendantArrived",
L"HelicopterHoverTooLong",
//1234567890123456789012345678901234567890 (increase size of array if necessary)
L"HelicopterHoverWayTooLong",
L"HelicopterDoneRefuelling",
L"MercLeaveEquipInOmerta",
L"MercLeaveEquipInDrassen",
L"DailyEarlyMorningEvents",
L"GroupAboutToArrive",
L"ProcessTacticalSchedule",
L"BeginRainStorm",
L"EndRainStorm",
L"HandleTownOpinion",
//1234567890123456789012345678901234567890 (increase size of array if necessary)
L"SetupTownOpinion",
L"DelayedDeathHandling",
L"BeginAirRaid",
L"TownLoyaltyUpdate",
L"Meanwhile",
L"BeginCreatureQuest",
L"CreatureSpread",
L"DecayCreatures",
L"CreatureNightPlanning",
L"CreatureAttack",
//1234567890123456789012345678901234567890 (increase size of array if necessary)
L"EvaluateQueenSituation",
L"CheckEnemyControlledSector",
L"TurnOnNightLights",
L"TurnOffNightLights",
L"TurnOnPrimeLights",
L"TurnOffPrimeLights",
L"MercAboutToLeaveComment",
L"ForceTimeInterupt",
L"EnricoEmailEvent",
L"InsuranceInvestigationStarted",
//1234567890123456789012345678901234567890 (increase size of array if necessary)
L"InsuranceInvestigationOver",
L"HandleMinuteUpdate",
L"TemperatureUpdate",
L"Keith going out of business",
L"MERC site back online",
L"Investigate Sector",
L"CheckIfMineCleared",
L"RemoveAssassin",
L"BandageBleedingMercs",
L"ShowUpdateMenu",
//1234567890123456789012345678901234567890 (increase size of array if necessary)
L"SetMenuReason",
L"AddSoldierToUpdateBox",
L"BeginContractRenewalSequence",
L"RPC_WHINE_ABOUT_PAY",
L"HaventMadeImpCharacterEmail",
L"Rainstorm",
L"Quarter Hour Update",
L"MERC Merc went up level email delay",
L".",
#ifdef CRIPPLED_VERSION
L"Crippled version end game check",
#endif
};
#endif
void ValidateGameEvents();
STRATEGICEVENT *gpEventList = NULL;
extern UINT32 guiGameClock;
extern BOOLEAN gfTimeInterruptPause;
BOOLEAN gfPreventDeletionOfAnyEvent = FALSE;
BOOLEAN gfEventDeletionPending = FALSE;
BOOLEAN gfProcessingGameEvents = FALSE;
UINT32 guiTimeStampOfCurrentlyExecutingEvent = 0;
//Determines if there are any events that will be processed between the current global time,
//and the beginning of the next global time.
BOOLEAN GameEventsPending( UINT32 uiAdjustment )
{
#ifdef CRIPPLED_VERSION
if( guiDay >= 8 )
{
return FALSE;
}
#endif
if( !gpEventList )
return FALSE;
if( gpEventList->uiTimeStamp <= GetWorldTotalSeconds() + uiAdjustment )
return TRUE;
return FALSE;
}
//returns TRUE if any events were deleted
BOOLEAN DeleteEventsWithDeletionPending()
{
STRATEGICEVENT *curr, *prev, *temp;
BOOLEAN fEventDeleted = FALSE;
//ValidateGameEvents();
curr = gpEventList;
prev = NULL;
while( curr )
{
//ValidateGameEvents();
if( curr->ubFlags & SEF_DELETION_PENDING )
{
if( prev )
{ //deleting node in middle
prev->next = curr->next;
temp = curr;
curr = curr->next;
MemFree( temp );
fEventDeleted = TRUE;
//ValidateGameEvents();
continue;
}
else
{ //deleting head
gpEventList = gpEventList->next;
temp = curr;
prev = NULL;
curr = curr->next;
MemFree( temp );
fEventDeleted = TRUE;
//ValidateGameEvents();
continue;
}
}
prev = curr;
curr = curr->next;
}
gfEventDeletionPending = FALSE;
return fEventDeleted;
}
void AdjustClockToEventStamp( STRATEGICEVENT *pEvent, UINT32 *puiAdjustment )
{
UINT32 uiDiff;
uiDiff = pEvent->uiTimeStamp - guiGameClock;
guiGameClock += uiDiff;
*puiAdjustment -= uiDiff;
//Calculate the day, hour, and minutes.
guiDay = ( guiGameClock / NUM_SEC_IN_DAY );
guiHour = ( guiGameClock - ( guiDay * NUM_SEC_IN_DAY ) ) / NUM_SEC_IN_HOUR;
guiMin = ( guiGameClock - ( ( guiDay * NUM_SEC_IN_DAY ) + ( guiHour * NUM_SEC_IN_HOUR ) ) ) / NUM_SEC_IN_MIN;
#ifdef CRIPPLED_VERSION
if( guiDay >= 8 )
{
guiDay = 8;
guiHour = 0;
guiMin = 0;
return;
}
#endif
swprintf( WORLDTIMESTR, L"%s %d, %02d:%02d", gpGameClockString[ STR_GAMECLOCK_DAY_NAME ], guiDay, guiHour, guiMin );
}
//If there are any events pending, they are processed, until the time limit is reached, or
//a major event is processed (one that requires the player's attention).
void ProcessPendingGameEvents( UINT32 uiAdjustment, UINT8 ubWarpCode )
{
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"ProcessPendingGameEvents");
STRATEGICEVENT *curr, *pEvent, *prev, *temp;
BOOLEAN fDeleteEvent = FALSE, fDeleteQueuedEvent = FALSE;
#ifdef CRIPPLED_VERSION
if( guiDay >= 8 )
{
return;
}
#endif
gfTimeInterrupt = FALSE;
gfProcessingGameEvents = TRUE;
//While we have events inside the time range to be updated, process them...
curr = gpEventList;
prev = NULL; //prev only used when warping time to target time.
while( !gfTimeInterrupt && curr && curr->uiTimeStamp <= guiGameClock + uiAdjustment )
{
fDeleteEvent = FALSE;
//Update the time by the difference, but ONLY if the event comes after the current time.
//In the beginning of the game, series of events are created that are placed in the list
//BEFORE the start time. Those events will be processed without influencing the actual time.
if( curr->uiTimeStamp > guiGameClock && ubWarpCode != WARPTIME_PROCESS_TARGET_TIME_FIRST )
{
AdjustClockToEventStamp( curr, &uiAdjustment );
}
//Process the event
if( ubWarpCode != WARPTIME_PROCESS_TARGET_TIME_FIRST )
{
fDeleteEvent = ExecuteStrategicEvent( curr );
}
else if( curr->uiTimeStamp == guiGameClock + uiAdjustment )
{ //if we are warping to the target time to process that event first,
if( !curr->next || curr->next->uiTimeStamp > guiGameClock + uiAdjustment )
{ //make sure that we are processing the last event for that second
AdjustClockToEventStamp( curr, &uiAdjustment );
fDeleteEvent = ExecuteStrategicEvent( curr );
if( curr && prev && fDeleteQueuedEvent )
{ //The only case where we are deleting a node in the middle of the list
prev->next = curr->next;
}
}
else
{ //We are at the current target warp time however, there are still other events following in this time cycle.
//We will only target the final event in this time. NOTE: Events are posted using a FIFO method
prev = curr;
curr = curr->next;
continue;
}
}
else
{ //We are warping time to the target time. We haven't found the event yet,
//so continuing will keep processing the list until we find it. NOTE: Events are posted using a FIFO method
prev = curr;
curr = curr->next;
continue;
}
if( fDeleteEvent )
{
//Determine if event node is a special event requiring reposting
switch( curr->ubEventType )
{
case RANGED_EVENT:
AddAdvancedStrategicEvent( ENDRANGED_EVENT, curr->ubCallbackID, curr->uiTimeStamp+curr->uiTimeOffset, curr->uiParam );
break;
case PERIODIC_EVENT:
pEvent = AddAdvancedStrategicEvent( PERIODIC_EVENT, curr->ubCallbackID, curr->uiTimeStamp+curr->uiTimeOffset, curr->uiParam );
if( pEvent )
pEvent->uiTimeOffset = curr->uiTimeOffset;
break;
case EVERYDAY_EVENT:
AddAdvancedStrategicEvent( EVERYDAY_EVENT, curr->ubCallbackID, curr->uiTimeStamp+NUM_SEC_IN_DAY, curr->uiParam );
break;
}
if( curr == gpEventList )
{
gpEventList = gpEventList->next;
MemFree( curr );
curr = gpEventList;
prev = NULL;
//ValidateGameEvents();
}
else
{
temp = curr;
prev->next = curr->next;
curr = curr->next;
MemFree( temp );
//ValidateGameEvents();
}
}
else
{
prev = curr;
curr = curr->next;
}
}
gfProcessingGameEvents = FALSE;
if( gfEventDeletionPending )
{
DeleteEventsWithDeletionPending();
}
if( uiAdjustment && !gfTimeInterrupt )
guiGameClock += uiAdjustment;
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"ProcessPendingGameEvents done");
}
BOOLEAN AddSameDayStrategicEvent( UINT8 ubCallbackID, UINT32 uiMinStamp, UINT32 uiParam )
{
return( AddStrategicEvent( ubCallbackID, uiMinStamp + GetWorldDayInMinutes(), uiParam ) );
}
BOOLEAN AddSameDayStrategicEventUsingSeconds( UINT8 ubCallbackID, UINT32 uiSecondStamp, UINT32 uiParam )
{
return( AddStrategicEventUsingSeconds( ubCallbackID, uiSecondStamp + GetWorldDayInSeconds(), uiParam ) );
}
BOOLEAN AddFutureDayStrategicEvent( UINT8 ubCallbackID, UINT32 uiMinStamp, UINT32 uiParam, UINT32 uiNumDaysFromPresent )
{
UINT32 uiDay;
uiDay = GetWorldDay();
return( AddStrategicEvent( ubCallbackID, uiMinStamp + GetFutureDayInMinutes( uiDay + uiNumDaysFromPresent ), uiParam ) );
}
BOOLEAN AddFutureDayStrategicEventUsingSeconds( UINT8 ubCallbackID, UINT32 uiSecondStamp, UINT32 uiParam, UINT32 uiNumDaysFromPresent )
{
UINT32 uiDay;
uiDay = GetWorldDay();
return( AddStrategicEventUsingSeconds( ubCallbackID, uiSecondStamp + GetFutureDayInMinutes( uiDay + uiNumDaysFromPresent ) * 60, uiParam ) );
}
STRATEGICEVENT* AddAdvancedStrategicEvent( UINT8 ubEventType, UINT8 ubCallbackID, UINT32 uiTimeStamp, UINT32 uiParam )
{
STRATEGICEVENT *pNode, *pNewNode, *pPrevNode;
if( gfProcessingGameEvents && uiTimeStamp <= guiTimeStampOfCurrentlyExecutingEvent )
{ //Prevents infinite loops of posting events that are the same time or earlier than the event
//currently being processed.
#ifdef JA2TESTVERSION
//if( ubCallbackID == EVENT_PROCESS_TACTICAL_SCHEDULE )
{
ScreenMsg( FONT_RED, MSG_DEBUG, L"%s Event Rejected: Can't post events <= time while inside an event callback. This is a special case situation that isn't a bug.", gEventName[ ubCallbackID ] );
}
//else
//{
// AssertMsg( 0, String( "%S Event Rejected: Can't post events <= time while inside an event callback.", gEventName[ ubCallbackID ] ) );
//}
#endif
return NULL;
}
pNewNode = (STRATEGICEVENT *) MemAlloc( sizeof( STRATEGICEVENT ) );
Assert( pNewNode );
memset( pNewNode, 0, sizeof( STRATEGICEVENT ) );
pNewNode->ubCallbackID = ubCallbackID;
pNewNode->uiParam = uiParam;
pNewNode->ubEventType = ubEventType;
pNewNode->uiTimeStamp = uiTimeStamp;
pNewNode->uiTimeOffset = 0;
// Search list for a place to insert
pNode = gpEventList;
// If it's the first head, do this!
if( !pNode )
{
gpEventList = pNewNode;
pNewNode->next = NULL;
}
else
{
pPrevNode = NULL;
while( pNode )
{
if( uiTimeStamp < pNode->uiTimeStamp )
{
break;
}
pPrevNode = pNode;
pNode = pNode->next;
}
// If we are at the end, set at the end!
if ( !pNode )
{
pPrevNode->next = pNewNode;
pNewNode->next = NULL;
}
else
{
// We have a previous node here
// Insert IN FRONT!
if ( pPrevNode )
{
pNewNode->next = pPrevNode->next;
pPrevNode->next = pNewNode;
}
else
{ // It's the head
pNewNode->next = gpEventList;
gpEventList = pNewNode;
}
}
}
return pNewNode ;
}
BOOLEAN AddStrategicEvent( UINT8 ubCallbackID, UINT32 uiMinStamp, UINT32 uiParam )
{
if( AddAdvancedStrategicEvent( ONETIME_EVENT, ubCallbackID, uiMinStamp*60, uiParam ) )
return TRUE;
return FALSE;
}
BOOLEAN AddStrategicEventUsingSeconds( UINT8 ubCallbackID, UINT32 uiSecondStamp, UINT32 uiParam )
{
if( AddAdvancedStrategicEvent( ONETIME_EVENT, ubCallbackID, uiSecondStamp, uiParam ) )
return TRUE;
return FALSE;
}
BOOLEAN AddRangedStrategicEvent( UINT8 ubCallbackID, UINT32 uiStartMin, UINT32 uiLengthMin, UINT32 uiParam )
{
STRATEGICEVENT *pEvent;
pEvent = AddAdvancedStrategicEvent( RANGED_EVENT, ubCallbackID, uiStartMin*60, uiParam );
if( pEvent )
{
pEvent->uiTimeOffset = uiLengthMin * 60;
return TRUE;
}
return FALSE;
}
BOOLEAN AddSameDayRangedStrategicEvent( UINT8 ubCallbackID, UINT32 uiStartMin, UINT32 uiLengthMin, UINT32 uiParam)
{
return AddRangedStrategicEvent( ubCallbackID, uiStartMin + GetWorldDayInMinutes(), uiLengthMin, uiParam );
}
BOOLEAN AddFutureDayRangedStrategicEvent( UINT8 ubCallbackID, UINT32 uiStartMin, UINT32 uiLengthMin, UINT32 uiParam, UINT32 uiNumDaysFromPresent )
{
return AddRangedStrategicEvent( ubCallbackID, uiStartMin + GetFutureDayInMinutes( GetWorldDay() + uiNumDaysFromPresent ), uiLengthMin, uiParam );
}
BOOLEAN AddRangedStrategicEventUsingSeconds( UINT8 ubCallbackID, UINT32 uiStartSeconds, UINT32 uiLengthSeconds, UINT32 uiParam )
{
STRATEGICEVENT *pEvent;
pEvent = AddAdvancedStrategicEvent( RANGED_EVENT, ubCallbackID, uiStartSeconds, uiParam );
if( pEvent )
{
pEvent->uiTimeOffset = uiLengthSeconds;
return TRUE;
}
return FALSE;
}
BOOLEAN AddSameDayRangedStrategicEventUsingSeconds( UINT8 ubCallbackID, UINT32 uiStartSeconds, UINT32 uiLengthSeconds, UINT32 uiParam)
{
return AddRangedStrategicEventUsingSeconds( ubCallbackID, uiStartSeconds + GetWorldDayInSeconds(), uiLengthSeconds, uiParam );
}
BOOLEAN AddFutureDayRangedStrategicEventUsingSeconds( UINT8 ubCallbackID, UINT32 uiStartSeconds, UINT32 uiLengthSeconds, UINT32 uiParam, UINT32 uiNumDaysFromPresent )
{
return AddRangedStrategicEventUsingSeconds( ubCallbackID, uiStartSeconds + GetFutureDayInMinutes( GetWorldDay() + uiNumDaysFromPresent ) * 60, uiLengthSeconds, uiParam );
}
BOOLEAN AddEveryDayStrategicEvent( UINT8 ubCallbackID, UINT32 uiStartMin, UINT32 uiParam )
{
if( AddAdvancedStrategicEvent( EVERYDAY_EVENT, ubCallbackID, GetWorldDayInSeconds() + uiStartMin * 60, uiParam ) )
return TRUE;
return FALSE;
}
BOOLEAN AddEveryDayStrategicEventUsingSeconds( UINT8 ubCallbackID, UINT32 uiStartSeconds, UINT32 uiParam )
{
if( AddAdvancedStrategicEvent( EVERYDAY_EVENT, ubCallbackID, GetWorldDayInSeconds() + uiStartSeconds, uiParam ) )
return TRUE;
return FALSE;
}
//NEW: Period Events
//Event will get processed automatically once every X minutes.
BOOLEAN AddPeriodStrategicEvent( UINT8 ubCallbackID, UINT32 uiOnceEveryXMinutes, UINT32 uiParam )
{
STRATEGICEVENT *pEvent;
pEvent = AddAdvancedStrategicEvent( PERIODIC_EVENT, ubCallbackID, GetWorldDayInSeconds() + uiOnceEveryXMinutes * 60, uiParam );
if( pEvent )
{
pEvent->uiTimeOffset = uiOnceEveryXMinutes * 60;
return TRUE;
}
return FALSE;
}
BOOLEAN AddPeriodStrategicEventUsingSeconds( UINT8 ubCallbackID, UINT32 uiOnceEveryXSeconds, UINT32 uiParam )
{
STRATEGICEVENT *pEvent;
pEvent = AddAdvancedStrategicEvent( PERIODIC_EVENT, ubCallbackID, GetWorldDayInSeconds() + uiOnceEveryXSeconds, uiParam );
if( pEvent )
{
pEvent->uiTimeOffset = uiOnceEveryXSeconds;
return TRUE;
}
return FALSE;
}
BOOLEAN AddPeriodStrategicEventWithOffset( UINT8 ubCallbackID, UINT32 uiOnceEveryXMinutes, UINT32 uiOffsetFromCurrent, UINT32 uiParam )
{
STRATEGICEVENT *pEvent;
pEvent = AddAdvancedStrategicEvent( PERIODIC_EVENT, ubCallbackID, GetWorldDayInSeconds() + uiOffsetFromCurrent * 60, uiParam );
if( pEvent )
{
pEvent->uiTimeOffset = uiOnceEveryXMinutes * 60;
return TRUE;
}
return FALSE;
}
BOOLEAN AddPeriodStrategicEventUsingSecondsWithOffset( UINT8 ubCallbackID, UINT32 uiOnceEveryXSeconds, UINT32 uiOffsetFromCurrent, UINT32 uiParam )
{
STRATEGICEVENT *pEvent;
pEvent = AddAdvancedStrategicEvent( PERIODIC_EVENT, ubCallbackID, GetWorldDayInSeconds() + uiOffsetFromCurrent, uiParam );
if( pEvent )
{
pEvent->uiTimeOffset = uiOnceEveryXSeconds;
return TRUE;
}
return FALSE;
}
void DeleteAllStrategicEventsOfType( UINT8 ubCallbackID )
{
STRATEGICEVENT *curr, *prev, *temp;
prev = NULL;
curr = gpEventList;
while( curr )
{
if( curr->ubCallbackID == ubCallbackID && !(curr->ubFlags & SEF_DELETION_PENDING) )
{
if( gfPreventDeletionOfAnyEvent )
{
curr->ubFlags |= SEF_DELETION_PENDING;
gfEventDeletionPending = TRUE;
prev = curr;
curr = curr->next;
continue;
}
//Detach the node
if( prev )
prev->next = curr->next;
else
gpEventList = curr->next;
//isolate and remove curr
temp = curr;
curr = curr->next;
MemFree( temp );
//ValidateGameEvents();
}
else
{ //Advance all the nodes
prev = curr;
curr = curr->next;
}
}
}
void DeleteAllStrategicEvents()
{
STRATEGICEVENT *temp;
while( gpEventList )
{
temp = gpEventList;
gpEventList = gpEventList->next;
MemFree( temp );
//ValidateGameEvents();
temp = NULL;
}
gpEventList = NULL;
}
//Searches for and removes the first event matching the supplied information. There may very well be a need
//for more specific event removal, so let me know (Kris), of any support needs. Function returns FALSE if
//no events were found or if the event wasn't deleted due to delete lock,
BOOLEAN DeleteStrategicEvent( UINT8 ubCallbackID, UINT32 uiParam )
{
STRATEGICEVENT *curr, *prev;
curr = gpEventList;
prev = NULL;
while( curr )
{ //deleting middle
if( curr->ubCallbackID == ubCallbackID && curr->uiParam == uiParam )
{
if( !(curr->ubFlags & SEF_DELETION_PENDING) )
{
if( gfPreventDeletionOfAnyEvent )
{
curr->ubFlags |= SEF_DELETION_PENDING;
gfEventDeletionPending = TRUE;
return FALSE;
}
if( prev )
{
prev->next = curr->next;
}
else
{
gpEventList = gpEventList->next;
}
MemFree( curr );
//ValidateGameEvents();
return TRUE;
}
}
prev = curr;
curr = curr->next;
}
return FALSE;
}
//part of the game.sav files (not map files)
BOOLEAN SaveStrategicEventsToSavedGame( HWFILE hFile )
{
UINT32 uiNumBytesWritten=0;
STRATEGICEVENT sGameEvent;
UINT32 uiNumGameEvents=0;
STRATEGICEVENT *pTempEvent = gpEventList;
//Go through the list and determine the number of events
while( pTempEvent )
{
pTempEvent = pTempEvent->next;
uiNumGameEvents++;
}
//write the number of strategic events
FileWrite( hFile, &uiNumGameEvents, sizeof( UINT32 ), &uiNumBytesWritten );
if( uiNumBytesWritten != sizeof( UINT32 ) )
{
return(FALSE);
}
//loop through all the events and save them.
pTempEvent = gpEventList;
while( pTempEvent )
{
//save the current structure
memcpy( &sGameEvent, pTempEvent, sizeof( STRATEGICEVENT ) );
//write the current strategic event
FileWrite( hFile, &sGameEvent, sizeof( STRATEGICEVENT ), &uiNumBytesWritten );
if( uiNumBytesWritten != sizeof( STRATEGICEVENT ) )
{
return(FALSE);
}
pTempEvent = pTempEvent->next;
}
return( TRUE );
}
BOOLEAN LoadStrategicEventsFromSavedGame( HWFILE hFile )
{
UINT32 uiNumGameEvents;
STRATEGICEVENT sGameEvent;
UINT32 cnt;
UINT32 uiNumBytesRead=0;
STRATEGICEVENT *pTemp = NULL;
//erase the old Game Event queue
DeleteAllStrategicEvents();
//Read the number of strategic events
FileRead( hFile, &uiNumGameEvents, sizeof( UINT32 ), &uiNumBytesRead );
if( uiNumBytesRead != sizeof( UINT32 ) )
{
return(FALSE);
}
pTemp = NULL;
//loop through all the events and save them.
for( cnt=0; cnt<uiNumGameEvents; cnt++ )
{
STRATEGICEVENT *pTempEvent = NULL;
// allocate memory for the event
pTempEvent = (STRATEGICEVENT *) MemAlloc( sizeof( STRATEGICEVENT ) );
if( pTempEvent == NULL )
return( FALSE );
//Read the current strategic event
FileRead( hFile, &sGameEvent, sizeof( STRATEGICEVENT ), &uiNumBytesRead );
if( uiNumBytesRead != sizeof( STRATEGICEVENT ) )
{
return(FALSE);
}
memcpy( pTempEvent, &sGameEvent, sizeof( STRATEGICEVENT ) );
// Add the new node to the list
//if its the first node,
if( cnt == 0 )
{
// assign it as the head node
gpEventList = pTempEvent;
//assign the 'current node' to the head node
pTemp = gpEventList;
}
else
{
// add the new node to the next field of the current node
pTemp->next = pTempEvent;
//advance the current node to the next node
pTemp = pTemp->next;
}
// NULL out the next field ( cause there is no next field yet )
pTempEvent->next = NULL;
}
return( TRUE );
}
void LockStrategicEventFromDeletion( STRATEGICEVENT *pEvent )
{
pEvent->ubFlags |= SEF_PREVENT_DELETION;
}
void UnlockStrategicEventFromDeletion( STRATEGICEVENT *pEvent )
{
pEvent->ubFlags &= ~SEF_PREVENT_DELETION;
}
void ValidateGameEvents()
{
STRATEGICEVENT *curr;
curr = gpEventList;
while( curr )
{
curr = curr->next;
if( curr == (STRATEGICEVENT*)0xdddddddd )
{
return;
}
}
}