diff --git a/Strategic/Hourly Update.cpp b/Strategic/Hourly Update.cpp index 14916e4d..527701de 100644 --- a/Strategic/Hourly Update.cpp +++ b/Strategic/Hourly Update.cpp @@ -50,6 +50,8 @@ void HourlyDisabilityUpdate(); void HourlyStealUpdate(); // Flugente: certain characters might steal equipment (backgrounds) void HourlySnitchUpdate(); // anv: decreasing cooldown after exposition +extern SECTOR_EXT_DATA SectorExternalData[256][4]; + extern INT32 GetCurrentBalance( void ); extern void PayOffSkyriderDebtIfAny( ); #ifdef JA2UB @@ -680,161 +682,140 @@ void HourlyStealUpdate() { SOLDIERTYPE * pSoldier = NULL; SOLDIERTYPE * pOtherSoldier = NULL; - INT8 bSlot = NO_SLOT; - UINT16 usTemptation = 0; - BOOLEAN fBar = FALSE; - OBJECTTYPE* pObj = NULL; - + for( INT32 cnt = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; cnt <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; ++cnt ) { pSoldier = MercPtrs[ cnt ]; // merc must be alive, not travelling and awake. If he is in the currently loaded sector, we may not be in tactical (we would see an item suddenly disappearing) and not in combat - if ( pSoldier && !pSoldier->flags.fBetweenSectors && pSoldier->bActive && !pSoldier->flags.fMercAsleep && pSoldier->bAssignment != IN_TRANSIT && pSoldier->bAssignment != ASSIGNMENT_POW && !SPY_LOCATION( pSoldier->bAssignment ) && - !( ( ( gWorldSectorX == pSoldier->sSectorX ) && ( gWorldSectorY == pSoldier->sSectorY ) && (gbWorldSectorZ == pSoldier->bSectorZ ) ) && (gTacticalStatus.fEnemyInSector || guiCurrentScreen == GAME_SCREEN )) ) + if ( pSoldier + && Chance( 50 ) // we try to steal something in the first place only half the time + && pSoldier->HasBackgroundFlag( BACKGROUND_SCROUNGING ) + && !pSoldier->flags.fBetweenSectors + && pSoldier->bActive + && !pSoldier->flags.fMercAsleep + && pSoldier->bAssignment != IN_TRANSIT + && pSoldier->bAssignment != ASSIGNMENT_POW + && !( ( ( gWorldSectorX == pSoldier->sSectorX ) && ( gWorldSectorY == pSoldier->sSectorY ) && ( gbWorldSectorZ == pSoldier->bSectorZ ) ) && ( gTacticalStatus.fEnemyInSector || guiCurrentScreen == GAME_SCREEN ) ) ) { - if ( pSoldier->HasBackgroundFlag( BACKGROUND_SCROUNGING ) ) + UINT8 ubSectorId = SECTOR( pSoldier->sSectorX, pSoldier->sSectorY ); + UINT16 wealth = SectorExternalData[ubSectorId][0].wealth; + + // only try to steal if there's something worth stealing in the first place + if ( !wealth ) + continue; + + INT8 sectorz = pSoldier->bSectorZ; + if ( SPY_LOCATION( pSoldier->bAssignment ) ) + sectorz = max( 0, sectorz - 10 ); + + // only works in surface sectors + if ( sectorz ) + continue; + + // anv: snitches prevent scrounging in the same sector + BOOLEAN fSnitchStoppedBehaviour = FALSE; + for ( UINT32 cnt2 = gTacticalStatus.Team[OUR_TEAM].bFirstID; cnt2 <= gTacticalStatus.Team[OUR_TEAM].bLastID; ++cnt2 ) { - // 50% chance that we'll steal something - if ( Chance(50) ) + pOtherSoldier = MercPtrs[cnt2]; + + // note - snitches stop others, but can scrounge themselves (if they have scrounging specifically set in background...) + if ( pOtherSoldier + && !pOtherSoldier->flags.fBetweenSectors + && pOtherSoldier->bAssignment != IN_TRANSIT + && pOtherSoldier->bAssignment != ASSIGNMENT_POW + && !SPY_LOCATION( pOtherSoldier->bAssignment ) + && pOtherSoldier->bActive + && !pOtherSoldier->flags.fMercAsleep + && pSoldier->ubProfile != pOtherSoldier->ubProfile ) { - // anv: snitches prevent scrounging in the same sector - BOOLEAN fSnitchStoppedBehaviour = FALSE; - for( INT32 cnt2 = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; cnt2 <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; ++cnt2 ) - { - pOtherSoldier = MercPtrs[ cnt2 ]; - // note - snitches stop others, but can scrounge themselves (if they have scrounging specifically set in background...) - if( pOtherSoldier && !pOtherSoldier->flags.fBetweenSectors && pOtherSoldier->bAssignment != IN_TRANSIT && pOtherSoldier->bAssignment != ASSIGNMENT_POW && SPY_LOCATION( pOtherSoldier->bAssignment ) && - pOtherSoldier->bActive && !pOtherSoldier->flags.fMercAsleep && pSoldier->ubProfile != pOtherSoldier->ubProfile ) + if ( ProfileHasSkillTrait( pOtherSoldier->ubProfile, SNITCH_NT ) && !( pSoldier->usSoldierFlagMask2 & SOLDIER_PREVENT_MISBEHAVIOUR_OFF ) ) + { + if ( pSoldier->sSectorX == pOtherSoldier->sSectorX && pSoldier->sSectorY == pOtherSoldier->sSectorY && sectorz == pOtherSoldier->bSectorZ ) { - if ( ProfileHasSkillTrait( pOtherSoldier->ubProfile, SNITCH_NT ) && !( pSoldier->usSoldierFlagMask2 & SOLDIER_PREVENT_MISBEHAVIOUR_OFF ) ) + UINT16 bPreventChance = ( EffectiveLeadership( pOtherSoldier ) + EffectiveExpLevel( pOtherSoldier, FALSE ) / 2 ); + if ( gGameOptions.fNewTraitSystem ) { - if( pSoldier->sSectorX == pOtherSoldier->sSectorX && pSoldier->sSectorY == pOtherSoldier->sSectorY && pSoldier->bSectorZ == pOtherSoldier->bSectorZ ) - { - UINT16 bPreventChance = ( EffectiveLeadership( pOtherSoldier ) + EffectiveExpLevel( pOtherSoldier, FALSE) / 2); - if (gGameOptions.fNewTraitSystem) - { - bPreventChance += 25 * NUM_SKILL_TRAITS( pOtherSoldier, SQUADLEADER_NT ); - bPreventChance -= 25 * NUM_SKILL_TRAITS( pSoldier, STEALTHY_NT ); - } - else - { - bPreventChance -= 25 * NUM_SKILL_TRAITS( pSoldier, STEALTHY_OT ); - } - // keep 1% chance no matter what - bPreventChance = max( 0, min( 99, bPreventChance ) ); - if( bPreventChance > PreRandom( 100 ) ) - { - // merc is not amused by being prevented - HandleMoraleEvent( pSoldier, MORALE_PREVENTED_MISBEHAVIOUR, pSoldier->sSectorX, pSoldier->sSectorX, pSoldier->bSectorZ ); - // also here would be a place for dynamic relationship decrease between them - // Flugente: then lets do that, shall we? - AddOpinionEvent( pSoldier->ubProfile, pOtherSoldier->ubProfile, OPINIONEVENT_SNITCHINTERFERENCE ); - - fSnitchStoppedBehaviour = TRUE; - - continue; - } - } + bPreventChance += 25 * NUM_SKILL_TRAITS( pOtherSoldier, SQUADLEADER_NT ); + bPreventChance -= 25 * NUM_SKILL_TRAITS( pSoldier, STEALTHY_NT ); + } + else + { + bPreventChance -= 25 * NUM_SKILL_TRAITS( pSoldier, STEALTHY_OT ); } - } - } - if ( fSnitchStoppedBehaviour ) - continue; + // keep 1% chance no matter what + bPreventChance = max( 0, min( 99, bPreventChance ) ); + if ( bPreventChance > PreRandom( 100 ) ) + { + // merc is not amused by being prevented + HandleMoraleEvent( pSoldier, MORALE_PREVENTED_MISBEHAVIOUR, pSoldier->sSectorX, pSoldier->sSectorX, pSoldier->bSectorZ ); + // also here would be a place for dynamic relationship decrease between them + // Flugente: then lets do that, shall we? + AddOpinionEvent( pSoldier->ubProfile, pOtherSoldier->ubProfile, OPINIONEVENT_SNITCHINTERFERENCE ); - // we loop over this sector's inventory and look for something shiny. We will pick it up if we hae enough space in our inventory - // open sector inv - UINT32 uiTotalNumberOfRealItems = 0; - std::vector pWorldItem;//dnl ch75 271013 - BOOLEAN fReturn = FALSE; + fSnitchStoppedBehaviour = TRUE; - if ( ( gWorldSectorX == pSoldier->sSectorX ) && ( gWorldSectorY == pSoldier->sSectorY ) && (gbWorldSectorZ == pSoldier->bSectorZ ) ) - { - uiTotalNumberOfRealItems = guiNumWorldItems; - - if ( !uiTotalNumberOfRealItems ) - continue; - - pWorldItem = gWorldItems; - } - else - { - // not loaded, load - // get total number, visable and invisible - fReturn = GetNumberOfWorldItemsFromTempItemFile( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ, &( uiTotalNumberOfRealItems ), FALSE ); - Assert( fReturn ); - - if( uiTotalNumberOfRealItems > 0 ) - { - // allocate space for the list - pWorldItem.resize(uiTotalNumberOfRealItems);//dnl ch75 271013 - - if ( !uiTotalNumberOfRealItems ) continue; - - // now load into mem - LoadWorldItemsFromTempItemFile( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ, pWorldItem ); - } - } - - FLOAT bestpriceweightratio = 50.0f; // must have a value of at least 50$/100 gram - OBJECTTYPE* pTargetObj = NULL; - for( UINT32 uiCount = 0; uiCount < uiTotalNumberOfRealItems; ++uiCount ) // ... for all items in the world ... - { - if( pWorldItem[ uiCount ].fExists ) // ... if item exists ... - { - OBJECTTYPE* pObj = &(pWorldItem[ uiCount ].object); // ... get pointer for this item ... - - if ( pObj != NULL && pObj->exists() ) // ... if pointer is not obviously useless ... - { - // test wether item is reachable and useable by militia - if ( (pWorldItem[ uiCount ].usFlags & WORLD_ITEM_REACHABLE) ) - { - // of course we prefer money above everything else - if ( Item[pWorldItem[ uiCount ].object.usItem].usItemClass == IC_MONEY ) - { - // give it a high enough value - bestpriceweightratio = 1000.0f; - pTargetObj = &(pWorldItem[ uiCount ].object); - } - // ignore objects without weight (how does that happen anyway? careless modders...) - else if ( Item[pWorldItem[ uiCount ].object.usItem].ubWeight ) - { - if ( (FLOAT)(Item[pWorldItem[ uiCount ].object.usItem].usPrice) / (FLOAT)(Item[pWorldItem[ uiCount ].object.usItem].ubWeight) > bestpriceweightratio ) - { - bestpriceweightratio = (FLOAT)(Item[pWorldItem[ uiCount ].object.usItem].usPrice) / (FLOAT)(Item[pWorldItem[ uiCount ].object.usItem].ubWeight); - pTargetObj = &(pWorldItem[ uiCount ].object); - } - } - } } } } + } + } - if ( pTargetObj ) - { - if ( AutoPlaceObject( pSoldier, pTargetObj, TRUE ) ) - { - // Flugente: dynamic opinion - HandleDynamicOpinionChange( pSoldier, OPINIONEVENT_THIEF, TRUE, FALSE ); - } - } + if ( fSnitchStoppedBehaviour ) + continue; - // save the changed inventory - // open sector inv - if( ( gWorldSectorX == pSoldier->sSectorX )&&( gWorldSectorY == pSoldier->sSectorY ) && (gbWorldSectorZ == pSoldier->bSectorZ ) ) + // The old behaviour was to steal items from the sector and put them into our inventory. However that is both very annoying (especially with EPCs) and not very logical (it's more like hoarding). + // So instead we'll now simply steal money from the population and put that into our inventory. That doesn't screw with our items and earns us cash, so players might even want this behaviour. + // The downside is that this angers the population, thus lowering loyalty. + + // determine chance of success. If we fail, we get money + UINT8 chanceofsucess = pSoldier->GetThiefStealMoneyChance(); + + if ( Chance( chanceofsucess ) ) + { + // we do train dexterity a tiny bit + StatChange( pSoldier, DEXTAMT, 1, FALSE ); + + // amount of money is a random value between 1 and 5 times wealth + UINT32 amountstolen = wealth + Random( 4 * wealth ); + + // set up money object + CreateMoney( amountstolen, &gTempObject ); + + // put money in inventory or on the floor + if ( !AutoPlaceObject( pSoldier, &( gTempObject ), TRUE ) ) + { + // drop money in the sector itself + if ( ( gWorldSectorX == pSoldier->sSectorX ) && ( gWorldSectorY == pSoldier->sSectorY ) && ( gbWorldSectorZ == sectorz ) ) { - guiNumWorldItems = uiTotalNumberOfRealItems; - gWorldItems = pWorldItem; + AddItemToPool( pSoldier->sGridNo, &gTempObject, 1, pSoldier->pathing.bLevel, ( WOLRD_ITEM_FIND_SWEETSPOT_FROM_GRIDNO | WORLD_ITEM_REACHABLE ), 0 ); } else { - //Save the Items to the the file - SaveWorldItemsToTempItemFile( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ, uiTotalNumberOfRealItems, pWorldItem ); + AddItemsToUnLoadedSector( pSoldier->sSectorX, pSoldier->sSectorY, sectorz, NOWHERE, 1, &gTempObject, 0, ( WOLRD_ITEM_FIND_SWEETSPOT_FROM_GRIDNO | WORLD_ITEM_REACHABLE ), 0, 1, FALSE ); } - } + } } + + // determine chance of evading detection. If we fail, we are caught and receive a loyalty penalty + UINT8 chanceofevadingdetection = pSoldier->GetThiefEvadeDetectionChance(); + + if ( !Chance( chanceofevadingdetection ) ) + { + // we were caught. Since we have guns and the locals don't, they can't do much apart from being pissed + // of course if we do that while covert, the locals won't 'know' it was us + if ( !SPY_LOCATION( pSoldier->bAssignment ) ) + { + // we were caught. Since we have guns and the locals don't, they can't do much apart from being pissed + // lower loyalty in closest town the player has ever controlled (the penalty is lowered by distance) + AffectClosestTownLoyaltyByDistanceFrom( -LOYALTY_STOLE_MONEY_FROM_LOCALS, pSoldier->sSectorX, pSoldier->sSectorY, sectorz ); + } + } + + // Flugente: dynamic opinion + HandleDynamicOpinionChange( pSoldier, OPINIONEVENT_THIEF, TRUE, FALSE ); } } } diff --git a/Strategic/Strategic Town Loyalty.cpp b/Strategic/Strategic Town Loyalty.cpp index acf03ccc..64cccd4c 100644 --- a/Strategic/Strategic Town Loyalty.cpp +++ b/Strategic/Strategic Town Loyalty.cpp @@ -1742,9 +1742,8 @@ void AffectAllTownsLoyaltyByDistanceFrom( INT32 iLoyaltyChange, INT16 sSectorX, INT32 iPercentAdjustment; INT32 iDistanceAdjustedLoyalty; - // preset shortest distances to high values prior to searching for a minimum - for( bTownId = FIRST_TOWN; bTownId < NUM_TOWNS; bTownId++ ) + for( bTownId = FIRST_TOWN; bTownId < NUM_TOWNS; ++bTownId ) { iShortestDistance[ bTownId ] = 999999; } @@ -1760,6 +1759,14 @@ void AffectAllTownsLoyaltyByDistanceFrom( INT32 iLoyaltyChange, INT16 sSectorX, { bTownId = (UINT8) pTownNamesList[ uiIndex ]; + // Flugente: added to speed up function, remove if removed in loop below this one + // doesn't affect towns where player hasn't established a "presence" yet + if ( !gTownLoyalty[bTownId].fStarted ) + { + ++uiIndex; + continue; + } + // skip path test if distance is already known to be zero to speed this up a bit if (iShortestDistance[ bTownId ] > 0 ) { @@ -1772,14 +1779,13 @@ void AffectAllTownsLoyaltyByDistanceFrom( INT32 iLoyaltyChange, INT16 sSectorX, } } - uiIndex++; + ++uiIndex; } // must always remove that temporary group! RemoveGroup( ubTempGroupId ); - - - for( bTownId = FIRST_TOWN; bTownId < NUM_TOWNS; bTownId++ ) + + for( bTownId = FIRST_TOWN; bTownId < NUM_TOWNS; ++bTownId ) { // doesn't affect towns where player hasn't established a "presence" yet if (!gTownLoyalty[ bTownId ].fStarted) @@ -1799,8 +1805,7 @@ void AffectAllTownsLoyaltyByDistanceFrom( INT32 iLoyaltyChange, INT16 sSectorX, // add 25% per sector below the threshold iPercentAdjustment = 25 * (LOYALTY_EVENT_DISTANCE_THRESHOLD - iShortestDistance[ bTownId ]); } - else - if (iShortestDistance[ bTownId ] > LOYALTY_EVENT_DISTANCE_THRESHOLD) + else if (iShortestDistance[ bTownId ] > LOYALTY_EVENT_DISTANCE_THRESHOLD) { // subtract 10% per sector above the threshold iPercentAdjustment = -10 * (iShortestDistance[ bTownId ] - LOYALTY_EVENT_DISTANCE_THRESHOLD); @@ -1816,8 +1821,7 @@ void AffectAllTownsLoyaltyByDistanceFrom( INT32 iLoyaltyChange, INT16 sSectorX, // no distance adjustment necessary iPercentAdjustment = 0; } - - + // calculate loyalty affects as adjusted for distance to this town iDistanceAdjustedLoyalty = (iLoyaltyChange * (100 + iPercentAdjustment)) / 100; @@ -1838,10 +1842,123 @@ void AffectAllTownsLoyaltyByDistanceFrom( INT32 iLoyaltyChange, INT16 sSectorX, DecrementTownLoyalty( bTownId, iDistanceAdjustedLoyalty ); } } - } +void AffectClosestTownLoyaltyByDistanceFrom( INT32 iLoyaltyChange, INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ ) +{ + INT16 sEventSector; + UINT8 ubTempGroupId; + INT8 bTownId; + UINT32 uiIndex; + INT32 iThisDistance; + INT32 iShortestDistance[MAX_TOWNS]; + INT32 iPercentAdjustment; + INT32 iDistanceAdjustedLoyalty; + INT32 sDistanceToClosestTown = 999999; + INT8 bClosestTown = NUM_TOWNS; + + // preset shortest distances to high values prior to searching for a minimum + for ( bTownId = FIRST_TOWN; bTownId < NUM_TOWNS; ++bTownId ) + { + iShortestDistance[bTownId] = 999999; + } + + sEventSector = sSectorX + ( MAP_WORLD_X * sSectorY ); + + // need a temporary group create to use for laying down distance paths + ubTempGroupId = CreateNewPlayerGroupDepartingFromSector( (UINT8)sSectorX, (UINT8)sSectorY ); + + // calc distance to the event sector from EACH SECTOR of each town, keeping only the shortest one for every town + uiIndex = 0; + while ( pTownNamesList[uiIndex] != 0 ) + { + bTownId = (UINT8)pTownNamesList[uiIndex]; + + // Flugente: added to speed up function, remove if removed in loop below this one + // doesn't affect towns where player hasn't established a "presence" yet + if ( !gTownLoyalty[bTownId].fStarted ) + { + ++uiIndex; + continue; + } + + // skip path test if distance is already known to be zero to speed this up a bit + if ( iShortestDistance[bTownId] > 0 ) + { + // calculate across how many sectors the fastest travel path from event to this town sector + iThisDistance = FindStratPath( sEventSector, (INT16)pTownLocationsList[uiIndex], ubTempGroupId, FALSE ); + + if ( iThisDistance < iShortestDistance[bTownId] ) + { + iShortestDistance[bTownId] = iThisDistance; + } + + if ( iThisDistance < sDistanceToClosestTown ) + { + bClosestTown = bTownId; + sDistanceToClosestTown = iThisDistance; + } + } + + ++uiIndex; + } + + // must always remove that temporary group! + RemoveGroup( ubTempGroupId ); + + if ( bClosestTown < NUM_TOWNS ) + { + // if event was underground, double effective distance + if ( bSectorZ != 0 ) + { + sDistanceToClosestTown *= 2; + } + + // This number here controls how many sectors away is the "norm" for the unadjusted loyalty change value + if ( sDistanceToClosestTown < LOYALTY_EVENT_DISTANCE_THRESHOLD ) + { + // add 25% per sector below the threshold + iPercentAdjustment = 25 * ( LOYALTY_EVENT_DISTANCE_THRESHOLD - sDistanceToClosestTown ); + } + else if ( sDistanceToClosestTown > LOYALTY_EVENT_DISTANCE_THRESHOLD ) + { + // subtract 10% per sector above the threshold + iPercentAdjustment = -10 * ( sDistanceToClosestTown - LOYALTY_EVENT_DISTANCE_THRESHOLD ); + + // don't allow it to go below -100, that would change the sign of the loyalty effect! + if ( iPercentAdjustment < -100 ) + { + iPercentAdjustment = -100; + } + } + else + { + // no distance adjustment necessary + iPercentAdjustment = 0; + } + + // calculate loyalty affects as adjusted for distance to this town + iDistanceAdjustedLoyalty = ( iLoyaltyChange * ( 100 + iPercentAdjustment ) ) / 100; + + if ( iDistanceAdjustedLoyalty == 0 ) + { + // no measurable effect, skip this town + return; + } + + if ( iDistanceAdjustedLoyalty > 0 ) + { + IncrementTownLoyalty( bClosestTown, iDistanceAdjustedLoyalty ); + } + else + { + // the decrement amount MUST be positive + iDistanceAdjustedLoyalty *= -1; + DecrementTownLoyalty( bClosestTown, iDistanceAdjustedLoyalty ); + } + } +} // to be called whenever player gains control of a sector in any way void CheckIfEntireTownHasBeenLiberated( INT8 bTownId, INT16 sSectorX, INT16 sSectorY ) diff --git a/Strategic/Strategic Town Loyalty.h b/Strategic/Strategic Town Loyalty.h index b87cec02..0de943e4 100644 --- a/Strategic/Strategic Town Loyalty.h +++ b/Strategic/Strategic Town Loyalty.h @@ -50,6 +50,9 @@ // Flugente: a rotting corpse is so decayed that it disappeared (we're the ones making all those corpses, the last we could do is clean up afterwards) #define LOYALTY_PENALTY_ROTTED_CORPSE (1 * GAIN_PTS_PER_LOYALTY_PT) +// Flugente: one of our thieves was caught stealing +#define LOYALTY_STOLE_MONEY_FROM_LOCALS ((4/7) * GAIN_PTS_PER_LOYALTY_PT) + typedef enum { // There are only for distance-adjusted global loyalty effects. Others go into list above instead! @@ -186,6 +189,9 @@ void DecrementTownLoyaltyEverywhere( UINT32 uiLoyaltyDecrease ); void HandleGlobalLoyaltyEvent( UINT8 ubEventType, INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ); void AffectAllTownsLoyaltyByDistanceFrom( INT32 iLoyaltyChange, INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ); +// Flugente: like AffectAllTownsLoyaltyByDistanceFrom(...) but only for the closest town +void AffectClosestTownLoyaltyByDistanceFrom( INT32 iLoyaltyChange, INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ ); + // handle a town being liberated for the first time void CheckIfEntireTownHasBeenLiberated( INT8 bTownId, INT16 sSectorX, INT16 sSectorY ); void CheckIfEntireTownHasBeenLost( INT8 bTownId, INT16 sSectorX, INT16 sSectorY ); diff --git a/Strategic/XML_SectorNames.cpp b/Strategic/XML_SectorNames.cpp index 2812d932..25e3d385 100644 --- a/Strategic/XML_SectorNames.cpp +++ b/Strategic/XML_SectorNames.cpp @@ -100,6 +100,7 @@ SectorNameStartElementHandle(void *userData, const XML_Char *name, const char ** strcmp(name, "snakechance" ) == 0 || strcmp(name, "numsnakes" ) == 0 || strcmp(name, "maxworkers" ) == 0 || + strcmp(name, "wealth" ) == 0 || strcmp(name, "bloodcatraidpossible" ) == 0 || strcmp(name, "zombieraidpossible" ) == 0 || strcmp(name, "banditraidpossible" ) == 0 )) @@ -234,6 +235,11 @@ SectorNameEndElementHandle(void *userData, const XML_Char *name) SectorExternalData[ubSectorId][2].maxworkers = 0; SectorExternalData[ubSectorId][3].maxworkers = 0; + SectorExternalData[ubSectorId][0].wealth = pData->sectordata.wealth; + SectorExternalData[ubSectorId][1].wealth = 0; + SectorExternalData[ubSectorId][2].wealth = 0; + SectorExternalData[ubSectorId][3].wealth = 0; + SectorExternalData[ubSectorId][0].usSectorFlagMask = pData->sectordata.usSectorFlagMask; SectorExternalData[ubSectorId][1].usSectorFlagMask = 0; SectorExternalData[ubSectorId][2].usSectorFlagMask = 0; @@ -263,6 +269,7 @@ SectorNameEndElementHandle(void *userData, const XML_Char *name) pData->sectordata.snakechance = 0; pData->sectordata.numsnakes = 0; pData->sectordata.maxworkers = 0; + pData->sectordata.wealth = 0; pData->sectordata.usSectorFlagMask = 0; } else @@ -387,6 +394,11 @@ SectorNameEndElementHandle(void *userData, const XML_Char *name) pData->curElement = ELEMENT; pData->sectordata.maxworkers = (UINT8)atoi( pData->szCharData ); } + else if ( strcmp( name, "wealth" ) == 0 ) + { + pData->curElement = ELEMENT; + pData->sectordata.wealth = (UINT16)atoi( pData->szCharData ); + } else if ( strcmp( name, "bloodcatraidpossible" ) == 0 ) { pData->curElement = ELEMENT; diff --git a/Tactical/Items.h b/Tactical/Items.h index 7d12a693..847eb219 100644 --- a/Tactical/Items.h +++ b/Tactical/Items.h @@ -517,7 +517,8 @@ typedef struct UINT8 snakechance; // if positive, snakes can attack in water, the higher the number, the more often it happens UINT8 numsnakes; // how many snakes can be active at maximum - UINT8 maxworkers; // maximum number of workers in this sector; + UINT8 maxworkers; // maximum number of workers in this sector + UINT16 wealth; // rating of how rich the population in this sector is UINT32 usSectorFlagMask; // various flags diff --git a/Tactical/Soldier Control.cpp b/Tactical/Soldier Control.cpp index 8a8d06f3..f72bf5b6 100644 --- a/Tactical/Soldier Control.cpp +++ b/Tactical/Soldier Control.cpp @@ -20327,6 +20327,89 @@ FLOAT SOLDIERTYPE::GetAdministrationModifier() return 1.0f; } +// Flugente: those with the background occasionally steal money from the locals +UINT8 SOLDIERTYPE::GetThiefStealMoneyChance() +{ + if ( this->stats.bLife < OKLIFE ) + return 0; + + UINT32 val = 1 * EffectiveAgility( this, FALSE ) + 8 * EffectiveDexterity( this, FALSE ) + 10 * EffectiveExpLevel( this, FALSE ); + + // personality/disability modifiers + FLOAT persmodifier = 1.0f; + //if ( DoesMercHaveDisability( this, HEAT_INTOLERANT ) ) persmodifier -= 0.20f; + //if ( DoesMercHaveDisability( this, NERVOUS ) ) persmodifier -= 0.20f; + //if ( DoesMercHaveDisability( this, CLAUSTROPHOBIC ) ) persmodifier -= 0.20f; + //if ( DoesMercHaveDisability( this, NONSWIMMER ) ) persmodifier -= 0.20f; + //if ( DoesMercHaveDisability( this, FEAR_OF_INSECTS ) ) persmodifier -= 0.20f; + if ( DoesMercHaveDisability( this, FORGETFUL ) ) persmodifier -= 0.12f; + //if ( DoesMercHaveDisability( this, PSYCHO ) ) persmodifier -= 0.20f; + //if ( DoesMercHaveDisability( this, DEAF ) ) persmodifier -= 0.15f; + if ( DoesMercHaveDisability( this, SHORTSIGHTED ) ) persmodifier -= 0.30f; + //if ( DoesMercHaveDisability( this, HEMOPHILIAC ) ) persmodifier -= 0.20f; + //if ( DoesMercHaveDisability( this, AFRAID_OF_HEIGHTS ) ) persmodifier -= 0.20f; + //if ( DoesMercHaveDisability( this, SELF_HARM ) ) persmodifier -= 0.20f; + + if ( gGameOptions.fNewTraitSystem ) + { + if ( DoesMercHavePersonality( this, CHAR_TRAIT_SOCIABLE ) ) persmodifier += 0.25f; + if ( DoesMercHavePersonality( this, CHAR_TRAIT_LONER ) ) persmodifier -= 0.05f; + if ( DoesMercHavePersonality( this, CHAR_TRAIT_OPTIMIST ) ) persmodifier += 0.05f; + if ( DoesMercHavePersonality( this, CHAR_TRAIT_ASSERTIVE ) ) persmodifier += 0.15f; + //if ( DoesMercHavePersonality( this, CHAR_TRAIT_INTELLECTUAL ) ) persmodifier += 0.15f; + //if ( DoesMercHavePersonality( this, CHAR_TRAIT_PRIMITIVE ) ) persmodifier -= 0.15f; + if ( DoesMercHavePersonality( this, CHAR_TRAIT_AGGRESSIVE ) ) persmodifier -= 0.15f; + if ( DoesMercHavePersonality( this, CHAR_TRAIT_PHLEGMATIC ) ) persmodifier -= 0.05f; + if ( DoesMercHavePersonality( this, CHAR_TRAIT_DAUNTLESS ) ) persmodifier -= 0.13f; + //if ( DoesMercHavePersonality( this, CHAR_TRAIT_PACIFIST ) ) persmodifier -= 0.03f; + //if ( DoesMercHavePersonality( this, CHAR_TRAIT_MALICIOUS ) ) persmodifier -= 0.13f; + if ( DoesMercHavePersonality( this, CHAR_TRAIT_SHOWOFF ) ) persmodifier -= 0.08f; + if ( DoesMercHavePersonality( this, CHAR_TRAIT_COWARD ) ) persmodifier -= 0.25f; + } + + UINT32 totalvalue = val * persmodifier / 10.0f; + + ReducePointsForFatigue( this, &totalvalue ); + + totalvalue = min( 100, max( 0, totalvalue ) ); + + return totalvalue; +} + +UINT8 SOLDIERTYPE::GetThiefEvadeDetectionChance() +{ + if ( this->stats.bLife < OKLIFE ) + return 0; + + // the theoretical unboosted maximum is 1100, yet we treat it like 1000 - effectively you can boost stealth gear to give you a serious edge + UINT32 val = 250 + 5 * EffectiveExpLevel( this, FALSE ) + 5 * EffectiveAgility( this, FALSE ) + 3 * GetWornStealth( this ); + + ReducePointsForFatigue( this, &val ); + + // personality/disability modifiers + FLOAT persmodifier = 1.0f; + //if ( DoesMercHaveDisability( this, HEAT_INTOLERANT ) ) persmodifier -= 0.20f; + if ( DoesMercHaveDisability( this, NERVOUS ) ) persmodifier -= 0.04f; + //if ( DoesMercHaveDisability( this, CLAUSTROPHOBIC ) ) persmodifier -= 0.20f; + //if ( DoesMercHaveDisability( this, NONSWIMMER ) ) persmodifier -= 0.20f; + //if ( DoesMercHaveDisability( this, FEAR_OF_INSECTS ) ) persmodifier -= 0.20f; + //if ( DoesMercHaveDisability( this, FORGETFUL ) ) persmodifier -= 0.50f; + //if ( DoesMercHaveDisability( this, PSYCHO ) ) persmodifier -= 0.20f; + if ( DoesMercHaveDisability( this, DEAF ) ) persmodifier -= 0.06f; + //if ( DoesMercHaveDisability( this, SHORTSIGHTED ) ) persmodifier -= 0.40f; + //if ( DoesMercHaveDisability( this, HEMOPHILIAC ) ) persmodifier -= 0.20f; + //if ( DoesMercHaveDisability( this, AFRAID_OF_HEIGHTS ) ) persmodifier -= 0.20f; + //if ( DoesMercHaveDisability( this, SELF_HARM ) ) persmodifier -= 0.20f; + + UINT32 totalvalue = val * persmodifier / 10.0f; + + ReducePointsForFatigue( this, &totalvalue ); + + totalvalue = min( 100, max( 0, totalvalue ) ); + + return totalvalue; +} + INT32 CheckBleeding( SOLDIERTYPE *pSoldier ) { INT8 bBandaged; //,savedOurTurn; diff --git a/Tactical/Soldier Control.h b/Tactical/Soldier Control.h index ca294d42..04783184 100644 --- a/Tactical/Soldier Control.h +++ b/Tactical/Soldier Control.h @@ -2006,6 +2006,10 @@ public: // Flugente: administration assignment UINT32 GetAdministrationPoints(); FLOAT GetAdministrationModifier(); + + // Flugente: those with the background occasionally steal money from the locals + UINT8 GetThiefStealMoneyChance(); + UINT8 GetThiefEvadeDetectionChance(); ////////////////////////////////////////////////////////////////////////////// }; // SOLDIERTYPE; diff --git a/Utils/_ChineseText.cpp b/Utils/_ChineseText.cpp index 184ae192..9b4773e7 100644 --- a/Utils/_ChineseText.cpp +++ b/Utils/_ChineseText.cpp @@ -9000,7 +9000,7 @@ STR16 szBackgroundText_Flags[]= L" 会消耗掉背包中的药品 \n", //L" might consume drugs in inventory\n", L" 蔑视其他背景的角色 \n", //L" disregard for other backgrounds\n", L" +1 角色等级在地下分区时 \n", //L" +1 level in underground sectors\n", - L" 会盗窃物品 \n", //L" might steal items\n", + L" steals money from the locals sometimes\n", // TODO.Translate L" +1 埋设炸弹等级 \n", //L" +1 traplevel to planted bombs\n", L" 会导致附近的佣兵腐败 \n", //L" spreads corruption to nearby mercs\n", diff --git a/Utils/_DutchText.cpp b/Utils/_DutchText.cpp index 798ebc4c..da8cad67 100644 --- a/Utils/_DutchText.cpp +++ b/Utils/_DutchText.cpp @@ -9018,7 +9018,7 @@ STR16 szBackgroundText_Flags[]= L" might consume drugs in inventory\n", L" disregard for all other backgrounds\n", L" +1 level in underground sectors\n", - L" might steal items\n", + L" steals money from the locals sometimes\n", // TODO.Translate L" +1 traplevel to planted bombs\n", L" spreads corruption to nearby mercs\n", diff --git a/Utils/_EnglishText.cpp b/Utils/_EnglishText.cpp index 6551779b..431861ee 100644 --- a/Utils/_EnglishText.cpp +++ b/Utils/_EnglishText.cpp @@ -9000,7 +9000,7 @@ STR16 szBackgroundText_Flags[]= L" might consume drugs in inventory\n", L" disregard for all other backgrounds\n", L" +1 level in underground sectors\n", - L" might steal items\n", + L" steals money from the locals sometimes\n", L" +1 traplevel to planted bombs\n", L" spreads corruption to nearby mercs\n", diff --git a/Utils/_FrenchText.cpp b/Utils/_FrenchText.cpp index 03a849e2..5017f428 100644 --- a/Utils/_FrenchText.cpp +++ b/Utils/_FrenchText.cpp @@ -9000,7 +9000,7 @@ STR16 szBackgroundText_Flags[]= L" peut consommer des drogues se trouvant dans son inventaire\n", L" ne tient pas compte des autres passifs\n", L" +1 Niveau dans les souterrains\n", - L" peut voler des objets\n", + L" steals money from the locals sometimes\n", // TODO.Translate L" +1 Niveau pour poser des pièges\n", L" répand la corruption aux mercenaires proches\n", diff --git a/Utils/_GermanText.cpp b/Utils/_GermanText.cpp index 8c02b00a..862bcd8a 100644 --- a/Utils/_GermanText.cpp +++ b/Utils/_GermanText.cpp @@ -8830,7 +8830,7 @@ STR16 szBackgroundText_Flags[]= L" might consume drugs in inventory\n", L" disregard for all other backgrounds\n", L" +1 level in underground sectors\n", - L" might steal items\n", + L" steals money from the locals sometimes\n", // TODO.Translate L" +1 traplevel to planted bombs\n", L" spreads corruption to nearby mercs\n", diff --git a/Utils/_ItalianText.cpp b/Utils/_ItalianText.cpp index 6710b6f9..7a2c632a 100644 --- a/Utils/_ItalianText.cpp +++ b/Utils/_ItalianText.cpp @@ -9009,7 +9009,7 @@ STR16 szBackgroundText_Flags[]= L" might consume drugs in inventory\n", L" disregard for all other backgrounds\n", L" +1 level in underground sectors\n", - L" might steal items\n", + L" steals money from the locals sometimes\n", // TODO.Translate L" +1 traplevel to planted bombs\n", L" spreads corruption to nearby mercs\n", diff --git a/Utils/_PolishText.cpp b/Utils/_PolishText.cpp index 6c16e44f..43637c1f 100644 --- a/Utils/_PolishText.cpp +++ b/Utils/_PolishText.cpp @@ -9022,7 +9022,7 @@ STR16 szBackgroundText_Flags[]= L" might consume drugs in inventory\n", L" disregard for all other backgrounds\n", L" +1 level in underground sectors\n", - L" might steal items\n", + L" steals money from the locals sometimes\n", // TODO.Translate L" +1 traplevel to planted bombs\n", L" spreads corruption to nearby mercs\n", diff --git a/Utils/_RussianText.cpp b/Utils/_RussianText.cpp index 7649f6f4..e088b2ee 100644 --- a/Utils/_RussianText.cpp +++ b/Utils/_RussianText.cpp @@ -9000,7 +9000,7 @@ STR16 szBackgroundText_Flags[]= L" может употреблять наркотики из инвентаря\n", L" вне зависимости от других особенностей биографии\n", L" +1 уровень в подземных секторах\n", - L" может красть предметы\n", + L" steals money from the locals sometimes\n", // TODO.Translate L" +1 уровень ловушек при установке мин\n", L" разлагает других наёмников\n",