From 5df38d5042ebc7f66059ebbff394371688f445b6 Mon Sep 17 00:00:00 2001 From: Wanne Date: Mon, 23 Sep 2013 06:59:29 +0000 Subject: [PATCH] Improve loading speed of stash (by Moa) - improved processing of sector stash (opening/closing) - improved loading speed of save games - improved processing of items droped by militia (most noteable after autoresolve) - and some other code related changes see: http://www.ja-galaxy-forum.com/board/ubbthreads.php/topics/325332/FIX_improve_loading_speed_of_s.html#Post325332 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Notes: removed some functions, still in code so but renamed to *_OLD() because they are from Sirtech and should be kept as I have read in "ยง18) If possible, we don't just delete the old code, but comment it out (or #ifdef it out) for reference. We delete it only if it's really necessary." git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@6434 3b4a5df2-a311-0410-b5c6-a8a6f20db521 --- Strategic/Campaign Types.h | 2 +- Strategic/Map Screen Interface Bottom.cpp | 2 +- .../Map Screen Interface Map Inventory.cpp | 442 +++++++++++++++++- .../Map Screen Interface Map Inventory.h | 7 +- Strategic/Strategic Turns.cpp | 2 +- Strategic/strategicmap.cpp | 16 +- Tactical/Soldier Control.cpp | 12 + Tactical/Tactical Save.cpp | 26 +- Tactical/rt time defines.h | 8 +- TileEngine/structure.cpp | 5 + 10 files changed, 494 insertions(+), 28 deletions(-) diff --git a/Strategic/Campaign Types.h b/Strategic/Campaign Types.h index 2e908ff7..92ca18b9 100644 --- a/Strategic/Campaign Types.h +++ b/Strategic/Campaign Types.h @@ -470,7 +470,7 @@ typedef struct SECTORINFO // Replacing these variables with the ones above. They really are unused. //UINT16 usUNUSEDMilitiaLevels; // unused (ARM) //UINT8 ubUNUSEDNumberOfJoeBlowCivilians; // unused (ARM) - UINT32 uiTimeCurrentSectorWasLastLoaded; //Specifies the last time the player was in the sector + UINT32 uiTimeCurrentSectorWasLastLoaded; //in game minutes, Specifies the last time the player was in the sector. UINT8 ubUNUSEDNumberOfEnemiesThoughtToBeHere; // using bLastKnownEnemies instead UINT32 uiTimeLastPlayerLiberated; //in game seconds (used to prevent the queen from attacking for awhile) diff --git a/Strategic/Map Screen Interface Bottom.cpp b/Strategic/Map Screen Interface Bottom.cpp index adf40fb0..e677d4bb 100644 --- a/Strategic/Map Screen Interface Bottom.cpp +++ b/Strategic/Map Screen Interface Bottom.cpp @@ -307,7 +307,7 @@ void RenderMapScreenInterfaceBottom( BOOLEAN fForceMapscreenFullRender ) // HEADROCK Changed this line to accept outside influence through the new boolean: //if ( fForceMapscreenFullRender == TRUE || fMapScreenBottomDirty == TRUE) // HEADROCK HAM 3.6: OK, let's always render this panel, as long as the team inventory screen isn't open. - if ( fMapScreenBottomDirty || !fShowInventoryFlag ) + if ( fMapScreenBottomDirty || (!fShowInventoryFlag && fForceMapscreenFullRender)) { // get and blt panel GetVideoObject(&hHandle, guiMAPBOTTOMPANEL ); diff --git a/Strategic/Map Screen Interface Map Inventory.cpp b/Strategic/Map Screen Interface Map Inventory.cpp index dc362774..9a991356 100644 --- a/Strategic/Map Screen Interface Map Inventory.cpp +++ b/Strategic/Map Screen Interface Map Inventory.cpp @@ -31,6 +31,7 @@ #include "interface panels.h" #include "wordwrap.h" #include "Soldier macros.h" + #include "rt time defines.h" #endif #include "ShopKeeper Interface.h" @@ -798,11 +799,17 @@ void CreateDestroyMapInventoryPoolButtons( BOOLEAN fExitFromMapScreen ) // Flugente: certain features need to alter an item's temperature value depending on the time passed // if we do these functions here and adjust for the time passed since this sector was loaded last, it will seem to the player // as if these checks are always performed in any sector - SectorInventoryCooldownFunctions(sSelMapX, sSelMapY, ( INT16 )( iCurrentMapSectorZ )); + //Moa: removed this function and replaced by HandleSectorCooldownFunctions() below + //SectorInventoryCooldownFunctions(sSelMapX, sSelMapY, ( INT16 )( iCurrentMapSectorZ )); // build stash BuildStashForSelectedSector( sSelMapX, sSelMapY, ( INT16 )( iCurrentMapSectorZ ) ); + //Moa: added the handling function instead of SectorInventoryCooldown, which has loaded the items from the tempfile (loading also done in BuildStashForSelectedSector) + HandleSectorCooldownFunctions( sSelMapX, sSelMapY, (INT8)iCurrentMapSectorZ, (WORLDITEM*) &(*pInventoryPoolList.begin()) , pInventoryPoolList.size(), TRUE ); + //SetLastTimePlayerWasInSector( sSelMapX, sSelMapY, (INT8)iCurrentMapSectorZ ); + //SaveWorldItemsToTempItemFile( sSelMapX, sSelMapY, (INT8)iCurrentMapSectorZ, pInventoryPoolList.size(), (WORLDITEM*) &(*pInventoryPoolList.begin()) ); + // HEADROCK HAM 5: Reset all BigItem image numbers, just in case. ResetAllMapInventoryBigItemGraphics(); @@ -852,6 +859,9 @@ void CreateDestroyMapInventoryPoolButtons( BOOLEAN fExitFromMapScreen ) // clear up unseen list ClearUpTempUnSeenList( ); + // undo item decay (will be saved once and only when entering sector) + HandleSectorCooldownFunctions( sSelMapX, sSelMapY, (INT8)iCurrentMapSectorZ, (WORLDITEM*) &(*pInventoryPoolList.begin()) , pInventoryPoolList.size(), TRUE , TRUE); + // now save results SaveSeenAndUnseenItems( ); @@ -912,7 +922,98 @@ void ClearUpTempUnSeenList( void ) return; } +////////////////////////////////////// +//@brief Saves pSaveList and pInventoryPoolList either into file or into memmory. +// Takes any existing items from pInventoryPoolList and all items from pSaveList to save same into +// file if map is not loaded or memmory if the map is loaded. Make sure to remove all filters before +// calling this function! +// +// Globals which get modified: +// WORLDITEM* pSaveList ...If successfull pSaveList gets cleared +// UINT32 uiNumberOfUnSeenItems ...and uiNumberOfUnSeenItems set to 0. +// +// Globals used to save the list: +// INT16 gWorldSectorX,gWorldSectorY +// INT8 gWorldSectorZ ...Current loaded sector. +// INT32 sSelMapX, sSelMapY +// INT32 iCurrentMapSectorZ ...Current selected sector. +// std::vector pInventoryPoolList ...The stash of unfiltered Items. +// Notes: +// The original function had set the visible and exist flag for every worlditem which had existing objects, +// also it has set the WORLD_ITEM_GRIDNO_NOT_SET_USE_ENTRY_POINT using TileIsOutOfBounds() but this is not +// possible since we dont know the boundaries of a unloaded sector, occationally some data got lost. For +// loaded maps this check was not performed... +// In case this function should mimic the old behavier activate the preprocessor instruction(s), in this case +// those checks ARE performed for loaded maps. +//@auth SirTech +//@auth (merged into single loop by Moa) +////////////////////////////////////// void SaveSeenAndUnseenItems( void ) +{ + std::vector worldItemsSaveList; //exists() on front and exists() && visible != 0 on back. + UINT32 iExistingItems = 0; //fExists + + //build save list and add flag WORLD_ITEM_GRIDNO_NOT_SET_USE_ENTRY_POINT if required. + worldItemsSaveList.reserve( pInventoryPoolList.size() + uiNumberOfUnSeenItems ); + + if ( worldItemsSaveList.capacity() == 0 ) //nothing to do anyways so get out of here + return; + + //make list of seen items + for ( UINT32 i = 0; i < pInventoryPoolList.size(); i++ ) + { +#if 0 + if ( pInventoryPoolList[ i ].object.exists() ) + { + pInventoryPoolList[ i ].fExists = TRUE; + pInventoryPoolList[ i ].bVisible = TRUE; + //Check + if(TileIsOutOfBounds( pInventoryPoolList[ i ].sGridNo) && !( pInventoryPoolList[ i ].usFlags & WORLD_ITEM_GRIDNO_NOT_SET_USE_ENTRY_POINT ) ) + { + pInventoryPoolList[ i ].usFlags |= WORLD_ITEM_GRIDNO_NOT_SET_USE_ENTRY_POINT; + + // Display warning..... + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_BETAVERSION, L"Error: Trying to add item ( %d: %s ) to invalid gridno in unloaded sector. Please Report.", pInventoryPoolList[ i ].object.usItem, ItemNames[ pInventoryPoolList[ i ].object.usItem] ); + } + +#else + if ( pInventoryPoolList[i].fExists ) + { +#endif + worldItemsSaveList.push_back(pInventoryPoolList[i]); + iExistingItems++; + } + } + + //check whether memmory (loaded map) or file is used to save the items + if( ( gWorldSectorX == sSelMapX ) && ( gWorldSectorY == sSelMapY ) && ( gbWorldSectorZ == ( INT8 ) ( iCurrentMapSectorZ ) ) ) + { + //handle in existing function + ReBuildWorldItemStashForLoadedSector( iExistingItems, uiNumberOfUnSeenItems, &(*worldItemsSaveList.begin()), pSaveList ); + } + else + { + //copy remaining unseen items into savelist + if ( uiNumberOfUnSeenItems > 0 && pSaveList != NULL) + worldItemsSaveList.insert( worldItemsSaveList.end(), pSaveList, pSaveList + uiNumberOfUnSeenItems ); + + //save the items to file (skipping all checks of AddWorldItemsToUnLoadedSector(), allready done here!, also we do not delete the file before we overwrite) + if ( !SaveWorldItemsToTempItemFile( sSelMapX, sSelMapY, ( INT8 ) iCurrentMapSectorZ, uiNumberOfUnSeenItems + iExistingItems, &(*worldItemsSaveList.begin()) ) ) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_BETAVERSION, L"Error: Could not save %d seen and %d unseen items to disc! Please Report.", iExistingItems, uiNumberOfUnSeenItems ); + return; + } + } + uiNumberOfUnSeenItems = 0; + if( pSaveList != NULL ) + { + delete[] ( pSaveList ); + pSaveList = NULL; + } +} + +//original Sirtech function, modified once in rev1325 +void SaveSeenAndUnseenItems_OLD( void ) { WORLDITEM *pSeenItemsList = NULL; UINT32 iCounter = 0; @@ -1466,7 +1567,7 @@ void MapInvenPoolSlots(MOUSE_REGION * pRegion, INT32 iReason ) BeginInventoryPoolPtr( &( pInventoryPoolList[ ( iCurrentInventoryPoolPage * MAP_INVENTORY_POOL_SLOT_COUNT ) + iCounter ].object ) ); } else - { + {//we have an item on cursor // if in battle inform player they will have to do this in tactical // if( ( gTacticalStatus.fEnemyInSector ) ||( ( sSelMapX == gWorldSectorX ) && ( sSelMapY == gWorldSectorY ) && ( iCurrentMapSectorZ == gbWorldSectorZ ) && ( gTacticalStatus.uiFlags & INCOMBAT ) ) ) @@ -1814,8 +1915,8 @@ void DestroyMapInventoryButtons( void ) return; } - -void BuildStashForSelectedSector( INT16 sMapX, INT16 sMapY, INT16 sMapZ ) +INT32 GetSizeOfStashInSector_OLD( INT16 sMapX, INT16 sMapY, INT16 sMapZ, BOOLEAN fCountStacksAsOne ); +void BuildStashForSelectedSector_OLD( INT16 sMapX, INT16 sMapY, INT16 sMapZ ) { INT32 iSize = 0; UINT32 uiItemCount = 0; @@ -1829,7 +1930,7 @@ void BuildStashForSelectedSector( INT16 sMapX, INT16 sMapY, INT16 sMapZ ) // #endif // get size of the current stash in sector (count stacks as one item) - iSize = GetSizeOfStashInSector( sMapX, sMapY, sMapZ, TRUE ); + iSize = GetSizeOfStashInSector_OLD( sMapX, sMapY, sMapZ, TRUE ); // round off .. we want at least 1 free page of space... iSize = ((iSize / MAP_INVENTORY_POOL_SLOT_COUNT) + 1) * MAP_INVENTORY_POOL_SLOT_COUNT; @@ -1982,6 +2083,219 @@ void BuildStashForSelectedSector( INT16 sMapX, INT16 sMapY, INT16 sMapZ ) SortSectorInventory( pInventoryPoolList, uiTotalNumberOfSeenItems ); } + +//////////////////////////// +// @brief: Creates filtered and unfiltered lists for stash and stores them in global variables. +// +// If loaded sector matches the parameter sector globals are used to build the stash, otherwise the items are read from temp file (if any) +// Globals used to build the stash +// INT32 MAP_INVENTORY_POOL_SLOT_COUNT ...Number of Slots per page. +// INT16 gWorldSectorX,gWorldSectorY +// INT8 gWorldSectorZ ...Current loaded sector. +// UINT32 guiNumWorldItems ...Number of itemsstacks in the loaded sector. +// WORLDITEM * gWorldItems ...Global dynamic array of itemstacks in the loaded sector. +// +// Globals used to save the lists: +// INT32 iLastInventoryPoolPage ...page index where still one item is displayed (0..) +// std::vector pInventoryPoolList ...Stores unfiltered items and itemstacks of the sector (only items that return TRUE for @see IsMapScreenWorldItemVisibleInMapInventory() ) vector.size() is 1 + a multiple of MAP_INVENTORY_POOL_SLOT_COUNT. +// UINT32 uiNumberOfUnSeenItems ...Number of filtered items in that sector (only items that exist and return TRUE for @see IsMapScreenWorldItemInvisibleInMapInventory() ). +// WORLDITEM *pUnSeenItems ...Stores filtered items in that sector +// +// @calls CheckGridNoOfItemsInMapScreenMapInventory(), SortSectorInventory() +// @Todo: remove CheckGridNoOfItemsInMapScreenMapInventory() by identifying the root cause of the missing flag +//@auth SirTech, ChrisL +//@auth (merged into single loop by Moa) +//////////////////////////// +void BuildStashForSelectedSector( INT16 sMapX, INT16 sMapY, INT16 sMapZ ) +{ + + UINT32 fNumTotal = 0, fNumShown = 0, fNumFiltered = 0, fNumFlagsSet = 0; //itemstack count + std::vector fFilteredItems; //store filtered items to be converted later to an array. + std::vector fWorldItems; //store everything here what we can get (WORLDITEM.fExists == TRUE) + // pInventoryPoolList //store unfiltered items directly into the global + + + // if map is allready loaded use gWorldItems[] and guiNumWorldItems to build lists + if( ( sMapX == gWorldSectorX )&&( gWorldSectorY == sMapY ) &&(gbWorldSectorZ == sMapZ ) ) + { + // approximate capacitiy + fFilteredItems.reserve( 50 ); //since we are building the stash from blank, there is probably no filter set and only few items get into fFilteredItems + fWorldItems.reserve(guiNumWorldItems); + // start with empty list (global) + pInventoryPoolList.clear( ); + pInventoryPoolList.reserve( MAP_INVENTORY_POOL_SLOT_COUNT * ( 1 + (guiNumWorldItems/MAP_INVENTORY_POOL_SLOT_COUNT) ) ); + + + // sector loaded, just copy from list + for( UINT32 i = 0; i < guiNumWorldItems; i++ ) + { + + if( IsMapScreenWorldItemVisibleInMapInventory( &gWorldItems[ i ] ) ) + { + if( ( gWorldItems[i].object.exists() == true ) && ( TileIsOutOfBounds(gWorldItems[ i ].sGridNo) ) && !( gWorldItems[ i ].usFlags & WORLD_ITEM_GRIDNO_NOT_SET_USE_ENTRY_POINT ) ) + { + //set the flag +#ifndef _DEBUG + pInventoryPoolList[ i ].usFlags |= WORLD_ITEM_GRIDNO_NOT_SET_USE_ENTRY_POINT; +#endif + fNumFlagsSet++; + } + // unfiltered? add to visible and total list + pInventoryPoolList.push_back( gWorldItems[ i ] ); + fWorldItems.push_back( gWorldItems[ i ] ); + + fNumShown++; + } + else if ( IsMapScreenWorldItemInvisibleInMapInventory( &gWorldItems[ i ] ) ) + { + if( ( gWorldItems[i].object.exists() == true ) && ( TileIsOutOfBounds(gWorldItems[ i ].sGridNo) ) && !( gWorldItems[ i ].usFlags & WORLD_ITEM_GRIDNO_NOT_SET_USE_ENTRY_POINT ) ) + { + //set the flag +#ifndef _DEBUG + gWorldItems[ i ].usFlags |= WORLD_ITEM_GRIDNO_NOT_SET_USE_ENTRY_POINT; +#endif + fNumFlagsSet++; + } + // filtered? add to invisible and total list + fFilteredItems.push_back( gWorldItems[ i ] ); + fWorldItems.push_back( gWorldItems[ i ] ); + } + else if ( gWorldItems[ i ].fExists ) + { + // dont skip it, we reuse this loop to create a complete list of all items + fWorldItems.push_back( gWorldItems[ i ] ); +#ifdef _DEBUG + //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_BETAVERSION, L"The %d item in the list is hidden or does not exist.", i ); +#endif + } + } + + // update countings + fNumTotal = fWorldItems.size(); + fNumFiltered = fFilteredItems.size(); + fNumShown = pInventoryPoolList.size(); + + // double check if counting was correct +#ifdef JA2BETAVERSION + AssertGE( guiNumWorldItems, fNumTotal ); + AssertGE( fNumTotal, fNumFiltered + fNumShown ); +#endif + } + else + { // if map not loaded, use tempfile to build lists + + + BOOLEAN error; + // get total number of itemstacks from temp file... + error = GetNumberOfWorldItemsFromTempItemFile( sMapX, sMapY, ( INT8 )( sMapZ ), &( fNumTotal ), FALSE ); + Assert( error ); + + // ...and use this number to allocate space + fFilteredItems.reserve( 50 ); //since we are building the stash from blank, there is probably no filter set and only few items get into fFilteredItems, was 8 changed to 50 because of bobby ray + + //initialize at least one element to avoid null dereference of iterator + fWorldItems.resize(fNumTotal+1); + + // start with empty list (global) + pInventoryPoolList.reserve( MAP_INVENTORY_POOL_SLOT_COUNT * ( 1 + (fNumTotal/MAP_INVENTORY_POOL_SLOT_COUNT) ) ); + pInventoryPoolList.clear( ); + + // load items into fWorldItems vector + if ( !LoadWorldItemsFromTempItemFile( sMapX, sMapY, (INT8) sMapZ, &(*fWorldItems.begin()) ) ) + { + DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("LoadWorldItemsFromTempItemFile: failed in BuildStashForSelectedSector()" ) ); + return; + } + + // was temporay used to get #items in file, now count what actually is added + fNumTotal = 0; + // now run through list and copy reference + for(UINT32 i = 0; i < fWorldItems.size(); i++ ) + { + // TEST!! If the item exists, and is NOT VALID, report it + if( fWorldItems[i].fExists && fWorldItems[ i ].object.usItem > MAXITEMS ) + { + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_BETAVERSION, L"The %d item in the list is NOT valid (ID%d). Please send save. DF 1.", i, fWorldItems[i].object.usItem ); + } + + if( IsMapScreenWorldItemVisibleInMapInventory( &fWorldItems[ i ] ) ) + { + if( ( fWorldItems[i].object.exists() == true ) && ( TileIsOutOfBounds(fWorldItems[ i ].sGridNo) ) && !( fWorldItems[ i ].usFlags & WORLD_ITEM_GRIDNO_NOT_SET_USE_ENTRY_POINT ) ) + { + //set the flag +#ifndef _DEBUG + fWorldItems[ i ].usFlags |= WORLD_ITEM_GRIDNO_NOT_SET_USE_ENTRY_POINT; +#endif + fNumFlagsSet++; + } + // unfiltered? add to visible + pInventoryPoolList.push_back( fWorldItems[i] ); + fNumTotal++; + } + else if ( IsMapScreenWorldItemInvisibleInMapInventory( &fWorldItems[ i ] ) ) + { + if( ( fWorldItems[i].object.exists() == true ) && ( TileIsOutOfBounds(fWorldItems[ i ].sGridNo) ) && !( fWorldItems[ i ].usFlags & WORLD_ITEM_GRIDNO_NOT_SET_USE_ENTRY_POINT ) ) + { + //set the flag +#ifndef _DEBUG + fWorldItems[ i ].usFlags |= WORLD_ITEM_GRIDNO_NOT_SET_USE_ENTRY_POINT; +#endif + fNumFlagsSet++; + } + // filtered? add to invisible and total list + fFilteredItems.push_back( fWorldItems[ i ] ); + fNumTotal++; + } + else if ( fWorldItems[ i ].fExists ) + { + // dont skip it, we reuse this loop to create a complete list of existing items + fNumTotal++; +#ifdef _DEBUG + //ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_BETAVERSION, L"The %d item in the list does not exist.", i ); +#endif + } + } + // update countings + //fNumTotal = fWorldItems.size(); + fNumFiltered = fFilteredItems.size(); + fNumShown = pInventoryPoolList.size(); + + // double check if counting was correct +#ifdef JA2BETAVERSION + AssertGE( fNumTotal, fNumFiltered + fNumShown ); + AssertGE( fWorldItems.size(), fNumTotal ); +#endif + }// done with lists... + + + // ... set globals: set index for last page ... + iLastInventoryPoolPage = (INT32)(fNumShown / MAP_INVENTORY_POOL_SLOT_COUNT); + + uiNumberOfUnSeenItems = fNumFiltered; + + // to copy fFilteredItems (vector) to global (array) + if (uiNumberOfUnSeenItems > 0) + { + pUnSeenItems = new WORLDITEM[uiNumberOfUnSeenItems];//gets passed to pSaveList in ClearUpTempUnSeenList() and deleted by SaveSeenAndUnseenItems() + std::copy(fFilteredItems.begin(), fFilteredItems.end(), pUnSeenItems ); + } + //resize globallist to a multiple of MAP_INVENTORY_POOL_SLOT_COUNT + one element (some other code does expect that) + pInventoryPoolList.resize(MAP_INVENTORY_POOL_SLOT_COUNT * (iLastInventoryPoolPage+1) ); + + // Report corrected flags / missing flags + if( fNumFlagsSet > 0 ) + { +#ifndef _DEBUG + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_BETAVERSION, L"Item with invalid gridno doesnt have flag set:# %d, this was corrected.", fNumFlagsSet ); +#else + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_BETAVERSION, L"Item with invalid gridno doesnt have flag set:# %d, this was not corrected! Figure out why.", fNumFlagsSet ); +#endif + } + + //Sort the sector inventory + SortSectorInventory( pInventoryPoolList, fNumShown ); +} + void ReBuildWorldItemStashForLoadedSector( INT32 iNumberSeenItems, INT32 iNumberUnSeenItems, WORLDITEM *pSeenItemsList, WORLDITEM *pUnSeenItemsList ) { INT32 iTotalNumberOfItems = 0; @@ -2048,8 +2362,8 @@ void DestroyStash( void ) pInventoryPoolList.clear(); } - -INT32 GetSizeOfStashInSector( INT16 sMapX, INT16 sMapY, INT16 sMapZ, BOOLEAN fCountStacksAsOne ) +//Moa: merged into BuildStashForSelectedSector +INT32 GetSizeOfStashInSector_OLD( INT16 sMapX, INT16 sMapY, INT16 sMapZ, BOOLEAN fCountStacksAsOne ) { // get # of items in sector that are visible to the player UINT32 uiTotalNumberOfItems = 0, uiTotalNumberOfRealItems = 0; @@ -5223,8 +5537,9 @@ void HandleSetFilterButtons() } } +//Moa:moved code to CreateDestroyMapInventoryPoolButtons() and EnterSector() to decrease loading time // Flugente: handle various cooldown functions in a sector -void SectorInventoryCooldownFunctions( INT16 sMapX, INT16 sMapY, INT16 sMapZ ) +/*void SectorInventoryCooldownFunctions( INT16 sMapX, INT16 sMapY, INT16 sMapZ ) { UINT32 uiTotalNumberOfRealItems = 0; WORLDITEM * pTotalSectorList = NULL; @@ -5270,12 +5585,114 @@ void SectorInventoryCooldownFunctions( INT16 sMapX, INT16 sMapY, INT16 sMapZ ) //Save the Items to the the file SaveWorldItemsToTempItemFile( sMapX, sMapY, (INT8)sMapZ, uiTotalNumberOfRealItems, pTotalSectorList ); +}*/ + +// @brief modifies data of items including, but not limited to: bDirtLevel, bTemperature (food/weapon overheat) +// Uses various external parameters set in ini file(s) labeled under [Tactical Weapon Overheating Settings], [Tactical Food Settings], [Strategic Gameplay Settings](advanced repair/dirt system) +// to calculate a delta decay and adds it to the itemStack.data +// It is assumed that the itemStack consists of the same usItem. +// Items can not have negative dirt and temperature (0 is used instead). +// @param itemstack: A single item or a itemsstack which will be decayed (dirt, temperature) depending on ini settings. +// @param seconds: Time passed in seconds for which the delta decay is calculated and added to the items in itemstack. Can handle up to +-2147483647/(60*60*24*365) ~ 68 years. This means you can pass in positive seconds to decay the items and negative seconds to undecay them. +// @param naturalDirt: Dirt of the sector, if omitted default = 100 is used. +// @param isUnderground: flag to reduce food decay in underground sectors to 80%, if omitted default = FALSE is used. +// @auth origninal code by flugente +// @auth Moa +void HandleItemCooldownFunctions( OBJECTTYPE* itemStack, INT32 deltaSeconds, UINT16 naturalDirt, BOOLEAN isUnderground ) +{ + INT32 tickspassed = deltaSeconds / NUM_SEC_PER_TACTICAL_TURN;//1 tick is 5 seconds + + if ( tickspassed == 0 || !itemStack->exists() || + !( gGameExternalOptions.fWeaponOverheating || gGameExternalOptions.fDirtSystem || gGameOptions.fFoodSystem ) ) + return; + + +//original code by flugente, renamed variables to fit here, removed "min (OVERHEATING_MAX_TEMPERATURE, newValue)" for dirt to allow to go beyond maximum and deduct later the same amount if neccessary. + // ... if we use overheating and item is a gun, a launcher or a barrel ... + if ( gGameExternalOptions.fWeaponOverheating && ( Item[itemStack->usItem].usItemClass & (IC_GUN|IC_LAUNCHER) || Item[itemStack->usItem].barrel == TRUE ) ) + { + for(INT16 i = 0; i < itemStack->ubNumberOfObjects; ++i) // ... there might be multiple items here (item stack), so for each one ... + { + FLOAT guntemperature = (*itemStack)[i]->data.bTemperature; // ... get temperature ... + + FLOAT cooldownfactor = GetItemCooldownFactor(itemStack); // ... get item cooldown factor provided of attachments ... + + if ( Item[itemStack->usItem].barrel == TRUE ) // ... a barrel lying around cools down a bit faster ... + cooldownfactor *= gGameExternalOptions.iCooldownModificatorLonelyBarrel; + + FLOAT newguntemperature = max(0.0f, guntemperature - tickspassed * cooldownfactor ); // ... calculate new temperature ... + +#if 0//def JA2TESTVERSION + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"World: Item temperature lowered from %4.2f to %4.2f", guntemperature, newguntemperature ); +#endif + + (*itemStack)[i]->data.bTemperature = newguntemperature; // ... set new temperature + + // for every objects, we also have to check wether there are weapon attachments (eg. underbarrel weapons), and cool them down too + attachmentList::iterator iterend = (*itemStack)[i]->attachments.end(); + for (attachmentList::iterator iter = (*itemStack)[i]->attachments.begin(); iter != iterend; ++iter) + { + if ( iter->exists() && Item[ iter->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER) ) + { + FLOAT temperature = (*iter)[i]->data.bTemperature; // ... get temperature of item ... + + FLOAT cooldownfactor = GetItemCooldownFactor( &(*iter) ); // ... get cooldown factor ... + + FLOAT newtemperature = max(0.0f, temperature - tickspassed * cooldownfactor ); // ... calculate new temperature ... + + (*iter)[i]->data.bTemperature = newtemperature; // ... set new temperature + +#if 0//def JA2TESTVERSION + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"World: Item temperature lowered from %4.2f to %4.2f", temperature, newtemperature ); +#endif + + // we assume that there can exist only 1 underbarrel weapon per gun + break; + } + } + } + }//end overheating + + // ... if it is a weapon or armor and dirt system is active ... + if ( gGameExternalOptions.fDirtSystem && ( (Item[ itemStack->usItem ].usItemClass & IC_WEAPON) || (Item[ itemStack->usItem ].usItemClass & IC_ARMOUR) ) ) + { + FLOAT dirtincreasefactor = GetItemDirtIncreaseFactor( itemStack, FALSE ); // ... get dirt increase factor ... + + // the current sector determines how much dirt increases + dirtincreasefactor *= (naturalDirt)/100; + + dirtincreasefactor /= gGameExternalOptions.usSectorDirtDivider; + + if ( dirtincreasefactor > 0.0f ) // ... item can get dirtier ... + { + for( INT16 i = 0; i < itemStack->ubNumberOfObjects; ++i ) // ... there might be multiple items here (item stack), so for each one ... + { + (*itemStack)[i]->data.bDirtLevel = max(0.0f, (*itemStack)[i]->data.bDirtLevel + tickspassed * dirtincreasefactor ); // set new dirt value + } + } + }//end dirt stuff + + // ... if it is food and the food system is active ... + if ( gGameOptions.fFoodSystem && Item[ itemStack->usItem ].foodtype > 0 ) + { + if ( Food[ Item[ itemStack->usItem ].foodtype ].usDecayRate > 0.0f ) // ... if the food can decay... + { + // if in undergound sector the food will decay less + FLOAT sectorModifier = gGameExternalOptions.sFoodDecayModificator * ( isUnderground? 0.8f : 1.0f ); + + for( INT16 i = 0; i < itemStack->ubNumberOfObjects; ++i ) // ... there might be multiple items here (item stack), so for each one ... + { + (*itemStack)[i]->data.bTemperature = max( 0.0f, (*itemStack)[i]->data.bTemperature - tickspassed * sectorModifier * Food[ Item[ itemStack->usItem ].foodtype ].usDecayRate ); // set new temperature + } + } + }//end food } -// Flugente: handle various cooldwon functions over an array of items in a specific sector. +// Flugente: handle various cooldown functions over an array of items in a specific sector. // if fWithMinutes = true, adjust cooldown for time since sector was last entered // otherwise its used for a turn-precise cooldown -void HandleSectorCooldownFunctions( INT16 sMapX, INT16 sMapY, INT8 sMapZ, WORLDITEM* pWorldItem, UINT32 size, BOOLEAN fWithMinutes ) +//Moa: code inside pWorldItem loop moved to HandleItemCooldownFunctions, added optional fUndo flag to undecay items (default = FALSE) +void HandleSectorCooldownFunctions( INT16 sMapX, INT16 sMapY, INT8 sMapZ, WORLDITEM* pWorldItem, UINT32 size, BOOLEAN fWithMinutes, BOOLEAN fUndo ) { // if not using overheating or food system, no point in all this if ( !gGameExternalOptions.fWeaponOverheating && !gGameExternalOptions.fDirtSystem && !gGameOptions.fFoodSystem ) @@ -5318,6 +5735,10 @@ void HandleSectorCooldownFunctions( INT16 sMapX, INT16 sMapY, INT8 sMapZ, WORLDI for( UINT32 uiCount = 0; uiCount < size; ++uiCount ) // ... for all items in the world ... { + HandleItemCooldownFunctions( &(pWorldItem[ uiCount ].object), tickspassed * ( fUndo ? -NUM_SEC_PER_TACTICAL_TURN : NUM_SEC_PER_TACTICAL_TURN ), sectormod, (sMapZ > 0) ); + +//moved to HandleItemCooldownFunctions to reuse those calculations (see SOLDIERTYPE::SoldierInventoryCoolDown()) +/* if( pWorldItem[ uiCount ].fExists ) // ... if item exists ... { OBJECTTYPE* pObj = &(pWorldItem[ uiCount ].object); // ... get pointer for this item ... @@ -5399,5 +5820,6 @@ void HandleSectorCooldownFunctions( INT16 sMapX, INT16 sMapY, INT8 sMapZ, WORLDI } } } +*/ } } diff --git a/Strategic/Map Screen Interface Map Inventory.h b/Strategic/Map Screen Interface Map Inventory.h index cfad2852..61c14b84 100644 --- a/Strategic/Map Screen Interface Map Inventory.h +++ b/Strategic/Map Screen Interface Map Inventory.h @@ -39,8 +39,6 @@ void CreateDestroyMapInventoryPoolButtons( BOOLEAN fExitFromMapScreen ); // bail out of sector inventory mode if it is on void CancelSectorInventoryDisplayIfOn( BOOLEAN fExitFromMapScreen ); -INT32 GetSizeOfStashInSector( INT16 sMapX, INT16 sMapY, INT16 sMapZ, BOOLEAN fCountStacksAsOne ); - // get total number of items in sector INT32 GetTotalNumberOfItems( void ); @@ -81,9 +79,10 @@ BOOLEAN SwitchToInventoryPoolQ(UINT8 newidx); #endif // Flugente: handle various cooldown functions in a sector -void SectorInventoryCooldownFunctions( INT16 sMapX, INT16 sMapY, INT16 sMapZ ); +//void SectorInventoryCooldownFunctions( INT16 sMapX, INT16 sMapY, INT16 sMapZ ); // Flugente: handle various cooldown functions over an array of items in a specific sector. // if fWithMinutes = true, adjust cooldown for time since sector was last entered // otherwise its used for a turn-precise cooldown -void HandleSectorCooldownFunctions( INT16 sMapX, INT16 sMapY, INT8 sMapZ, WORLDITEM* pWorldItem, UINT32 size, BOOLEAN fWithMinutes ); \ No newline at end of file +void HandleSectorCooldownFunctions( INT16 sMapX, INT16 sMapY, INT8 sMapZ, WORLDITEM* pWorldItem, UINT32 size, BOOLEAN fWithMinutes, BOOLEAN fUndo = FALSE); +void HandleItemCooldownFunctions( OBJECTTYPE* itemStack, INT32 deltaSeconds, UINT16 naturalDirt = 100, BOOLEAN isUnderground = FALSE); \ No newline at end of file diff --git a/Strategic/Strategic Turns.cpp b/Strategic/Strategic Turns.cpp index a05614ef..c708006b 100644 --- a/Strategic/Strategic Turns.cpp +++ b/Strategic/Strategic Turns.cpp @@ -21,7 +21,7 @@ #include "assignments.h" #endif -#define NUM_SEC_PER_STRATEGIC_TURN ( NUM_SEC_IN_MIN * 15 ) // Every fifteen minutes + UINT32 guiLastStrategicTime = 0; diff --git a/Strategic/strategicmap.cpp b/Strategic/strategicmap.cpp index fe4d77a6..91aadee1 100644 --- a/Strategic/strategicmap.cpp +++ b/Strategic/strategicmap.cpp @@ -2885,6 +2885,10 @@ SOLDIERTYPE *pSoldier=NULL; #endif } +extern void SetLastTimePlayerWasInSector(); +//Moa: 09/14/2013 this function modifies uiTimeCurrentSectorWasLastLoaded and the various decay of items in that sector as well +// @calls HandleSectorCooldownFunctions +// @calls SetLastTimePlayerWasInSector BOOLEAN EnterSector( INT16 sSectorX, INT16 sSectorY , INT8 bSectorZ ) { INT32 i; @@ -3017,7 +3021,17 @@ BOOLEAN EnterSector( INT16 sSectorX, INT16 sSectorY , INT8 bSectorZ ) // Flugente: certain features need to alter an item's temperature value depending on the time passed // if we do these functions here and adjust for the time passed since this sector was loaded last, it will seem to the player // as if these checks are always performed in any sector - SectorInventoryCooldownFunctions(sSectorX, sSectorY, bSectorZ); + //Moa: removed this function and replaced by the handling function. + //SectorInventoryCooldownFunctions(sSectorX, sSectorY, bSectorZ); + //moved from SectorInventoryCooldownFunctions. Invisible items are handled as well. + //Since we have allready loaded the items previously we can use the globals here. + HandleSectorCooldownFunctions( sSectorX, sSectorY, (INT8)bSectorZ, gWorldItems, guiNumWorldItems, TRUE ); + //Update LastTimePlayerWasInSector + SetLastTimePlayerWasInSector(); + + //Save to tempfile + SaveWorldItemsToTempItemFile( sSectorX, sSectorY, (INT8)bSectorZ, guiNumWorldItems, gWorldItems ); + return TRUE; //because the map was loaded. } diff --git a/Tactical/Soldier Control.cpp b/Tactical/Soldier Control.cpp index 6abfb739..d652cb7d 100644 --- a/Tactical/Soldier Control.cpp +++ b/Tactical/Soldier Control.cpp @@ -13807,6 +13807,7 @@ BOOLEAN SOLDIERTYPE::SoldierCarriesTwoHandedWeapon( void ) return( FALSE ); } +extern void HandleItemCooldownFunctions( OBJECTTYPE* itemStack, INT32 deltaSeconds, UINT16 naturalDirt = 100, BOOLEAN isUnderground = TRUE ); // Flugente: Cool down/decay all items in inventory void SOLDIERTYPE::SoldierInventoryCoolDown(void) { @@ -13865,6 +13866,16 @@ void SOLDIERTYPE::SoldierInventoryCoolDown(void) if ( !gGameExternalOptions.fWeaponOverheating && !gGameExternalOptions.fDirtSystem && !gGameOptions.fFoodSystem ) return; +#if TRUE //start reusing existing code from HandleItemCooldownFunctions, set to FALSE if original code should be used + INT8 numStacks = (INT8)this->inv.size(); // remember inventorysize, so we don't call size() repeatedly + extern UINT32 guiLastTacticalRealTime, guiLastStrategicTime; + UINT32 secondsPassed = 5;//GetJA2Clock() > guiLastTacticalRealTime? (GetJA2Clock() - guiLastTacticalRealTime)/1000 : 0; + for ( INT8 bLoop = 0; bLoop < numStacks; ++bLoop) // ... for all items in our inventory ... + { + HandleItemCooldownFunctions( &(this->inv[bLoop]), secondsPassed ); + } + +#else //start using original redundant code // one hour has 60 minutes, with 12 5-second-intervals (cooldown values are based on 5-second values) FLOAT fooddecaymod = gGameExternalOptions.sFoodDecayModificator; @@ -13966,6 +13977,7 @@ void SOLDIERTYPE::SoldierInventoryCoolDown(void) } } } +#endif //end using original code } // Flugente: determine if we can rest our weapon on something. This can only happen when STANDING/CROUCHED. As a result, we get superior handling modifiers (we apply the PRONE modfiers) diff --git a/Tactical/Tactical Save.cpp b/Tactical/Tactical Save.cpp index 5cc38087..4b0bc461 100644 --- a/Tactical/Tactical Save.cpp +++ b/Tactical/Tactical Save.cpp @@ -820,7 +820,12 @@ BOOLEAN AddItemsToUnLoadedSector( INT16 sMapX, INT16 sMapY, INT8 bMapZ, INT32 sG WORLDITEM *pWorldItems; UINT32 cnt; UINT32 uiLoop1=0; - + + if ( uiNumberOfItemsToAdd == 0 && fReplaceEntireFile == FALSE ) + { + //Moa: nothing to do, so get out of here! + return( TRUE ); + } if( !GetNumberOfWorldItemsFromTempItemFile( sMapX, sMapY, bMapZ, &uiNumberOfItems, TRUE ) ) { @@ -3364,26 +3369,28 @@ void SetNumberOfVisibleWorldItemsInSectorStructureForSector( INT16 sMapX, INT16 } } - +//Moa 09/19/13: changed loop upperbound from uiTotalNumberOfRealItems to uiTotalNumberOfItems, +// this effectivly removes one entire loop in GetNumberOfActiveWorldItemsFromTempFile and 2 file reads. +// also changed type of iCounter from INT32 to UINT32 and for in if-clauses from true to TRUE to get rid of unneccessary casts. void SynchronizeItemTempFileVisbleItemsToSectorInfoVisbleItems( INT16 sMapX, INT16 sMapY, INT8 bMapZ, BOOLEAN fLoadingGame ) { - UINT32 uiTotalNumberOfItems = 0, uiTotalNumberOfRealItems = 0; + UINT32 uiTotalNumberOfItems = 0;//, uiTotalNumberOfRealItems = 0; WORLDITEM * pTotalSectorList = NULL; UINT32 uiItemCount = 0; - INT32 iCounter = 0; + UINT32 iCounter = 0; BOOLEAN fReturn; - + /* // get total number, visable and invisible fReturn = GetNumberOfActiveWorldItemsFromTempFile( sMapX, sMapY, bMapZ, &( uiTotalNumberOfRealItems ) ); - if (fReturn == false) + if (fReturn == TRUE) { DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("GetNumberOfActiveWorldItemsFromTempFile failed" ) ); Assert( fReturn ); - } + }*/ fReturn = GetNumberOfWorldItemsFromTempItemFile( sMapX, sMapY, bMapZ, &( uiTotalNumberOfItems ), FALSE ); - if (fReturn == false) + if (fReturn == TRUE) { DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("GetNumberOfWorldItemsFromTempItemFile failed" ) ); Assert( fReturn ); @@ -3399,7 +3406,8 @@ void SynchronizeItemTempFileVisbleItemsToSectorInfoVisbleItems( INT16 sMapX, INT } // now run through list and - for( iCounter = 0; ( UINT32 )( iCounter )< uiTotalNumberOfRealItems; iCounter++ ) + //for( iCounter = 0; ( UINT32 )( iCounter )< uiTotalNumberOfRealItems; iCounter++ ) + for( iCounter = 0; iCounter < uiTotalNumberOfItems; iCounter++ ) { // if visible to player, then state fact if( IsMapScreenWorldItemVisibleInMapInventory( &pTotalSectorList[ iCounter ] ) ) diff --git a/Tactical/rt time defines.h b/Tactical/rt time defines.h index d816af41..445ee50a 100644 --- a/Tactical/rt time defines.h +++ b/Tactical/rt time defines.h @@ -11,8 +11,14 @@ #define RT_FIRST_AID_GAIN_MODIFIER 12 -#define NUM_REAL_SEC_PER_TACTICAL_TURN 5000 +#ifndef NUM_SEC_IN_MIN +#define NUM_SEC_IN_MIN 60 +#endif +#define NUM_REAL_SEC_PER_TACTICAL_TURN 5000 + +#define NUM_SEC_PER_STRATEGIC_TURN ( NUM_SEC_IN_MIN * 15 ) // Every fifteen minutes +#define NUM_SEC_PER_TACTICAL_TURN 5 #define RT_COMPRESSION_TACTICAL_TURN_MODIFIER 10 diff --git a/TileEngine/structure.cpp b/TileEngine/structure.cpp index edfce86a..f00daeaf 100644 --- a/TileEngine/structure.cpp +++ b/TileEngine/structure.cpp @@ -1875,6 +1875,11 @@ void DebugStructurePage1( void ) { gprintf( 0, LINE_HEIGHT * 1, L"DDoorRt with orientation %s", WallOrientationString[pStructure->ubWallOrientation] ); } + else if (pStructure->fFlags & STRUCTURE_PERSON) + { + if (pStructure->pDBStructureRef != NULL && pStructure->pDBStructureRef->pDBStructure != NULL) + gprintf( 0, LINE_HEIGHT * 1, L"PersonStructure with StructureNumber %d", pStructure->pDBStructureRef->pDBStructure->usStructureNumber ); + } else { gprintf( 0, LINE_HEIGHT * 1, L"UNKNOWN STRUCTURE! (%x)", pStructure->fFlags );