diff --git a/GameSettings.cpp b/GameSettings.cpp index f227b5a4..73f3c456 100644 --- a/GameSettings.cpp +++ b/GameSettings.cpp @@ -1630,6 +1630,11 @@ void LoadGameExternalOptions() gGameExternalOptions.ubPrisonerProcessInfoDirectionChance = iniReader.ReadInteger("Strategic Gameplay Settings","PRISONER_INFO_DIRECTION_CHANCE", 40, 0, 100); gGameExternalOptions.ubPrisonerProcessRansomBaseChance = iniReader.ReadInteger("Strategic Gameplay Settings","PRISONER_RANSOM_CHANCE", 25, 0, 100); + gGameExternalOptions.ubPrisonerInterrogationPoints[PRISONER_ADMIN] = iniReader.ReadInteger("Strategic Gameplay Settings","PRISONER_INTERROGATION_POINTS_ADMIN", 80, 30, 1000); + gGameExternalOptions.ubPrisonerInterrogationPoints[PRISONER_REGULAR] = iniReader.ReadInteger("Strategic Gameplay Settings","PRISONER_INTERROGATION_POINTS_REGULAR", 100, gGameExternalOptions.ubPrisonerInterrogationPoints[PRISONER_ADMIN], 1000); + gGameExternalOptions.ubPrisonerInterrogationPoints[PRISONER_ELITE] = iniReader.ReadInteger("Strategic Gameplay Settings","PRISONER_INTERROGATION_POINTS_ELITE", 100, gGameExternalOptions.ubPrisonerInterrogationPoints[PRISONER_REGULAR], 1000); + gGameExternalOptions.ubPrisonerInterrogationPoints[PRISONER_SPECIAL] = iniReader.ReadInteger("Strategic Gameplay Settings","PRISONER_INTERROGATION_POINTS_SPECIAL", 100, gGameExternalOptions.ubPrisonerInterrogationPoints[PRISONER_ELITE], 1000); + // CHRISL: Determine how Skyrider should handle landing in enemy occupied sectors gGameExternalOptions.ubSkyriderHotLZ = iniReader.ReadInteger("Strategic Gameplay Settings", "ALLOW_SKYRIDER_HOT_LZ", 0); diff --git a/GameSettings.h b/GameSettings.h index b02fdc16..8d35886d 100644 --- a/GameSettings.h +++ b/GameSettings.h @@ -1227,6 +1227,7 @@ typedef struct UINT8 ubPrisonerProcessInfoNumberChance; UINT8 ubPrisonerProcessInfoDirectionChance; UINT8 ubPrisonerProcessRansomBaseChance; + UINT16 ubPrisonerInterrogationPoints[4]; // points needed to interrogate a prisoner of a specific type // Sandro: Alternative weapon holding (rifles fired from hip / pistols fired one-handed) UINT8 ubAllowAlternativeWeaponHolding; diff --git a/Strategic/Assignments.cpp b/Strategic/Assignments.cpp index f2be0a68..24579efb 100644 --- a/Strategic/Assignments.cpp +++ b/Strategic/Assignments.cpp @@ -2626,8 +2626,9 @@ UINT32 CalculateInterrogationValue(SOLDIERTYPE *pSoldier, UINT16 *pusMaxPts ) return 0; SECTORINFO *pSectorInfo = &( SectorInfo[ SECTOR( pSoldier->sSectorX, pSoldier->sSectorY ) ] ); - - *pusMaxPts = (UINT16)(pSectorInfo->uiNumberOfPrisonersOfWar); + + UINT8 prisonersspecial = 0, prisonerselite = 0, prisonersregular = 0, prisonersadmin = 0; + *pusMaxPts = GetNumberOrPrisoners( pSectorInfo, &prisonersspecial, &prisonerselite, &prisonersregular, &prisonersadmin ); // no prisoners -> no interrogation (this should not happen) if ( !*pusMaxPts ) @@ -2658,9 +2659,7 @@ UINT32 CalculateInterrogationValue(SOLDIERTYPE *pSoldier, UINT16 *pusMaxPts ) performancemodifier = min(1000, max(10, performancemodifier) ); usInterrogationPoints = (usInterrogationPoints * performancemodifier) / (650000); - - // TODO: adjust for cop background - + // adjust for fatigue ReducePointsForFatigue( pSoldier, &usInterrogationPoints ); @@ -2676,16 +2675,6 @@ UINT32 CalculatePrisonGuardValue(SOLDIERTYPE *pSoldier, UINT16 *pusMaxPts ) // for max points we display the maximum amount of prisoners instead *pusMaxPts = 0; - /*if ( !pSoldier || !pSoldier->bSectorZ ) - { - SECTORINFO *pSectorInfo = &( SectorInfo[ SECTOR( pSoldier->sSectorX, pSoldier->sSectorY ) ] ); - - *pusMaxPts = (UINT16)(pSectorInfo->uiNumberOfPrisonersOfWar); - } - - // no prisoners -> no interrogation (this should not happen) - if ( !*pusMaxPts ) - return .0f;*/ if ( pSoldier->flags.fMercAsleep ) return 0; @@ -2704,8 +2693,6 @@ UINT32 CalculatePrisonGuardValue(SOLDIERTYPE *pSoldier, UINT16 *pusMaxPts ) // adjust for fatigue ReducePointsForFatigue( pSoldier, &usValue ); - // TODO: adjust for prison guard background - // return current repair pts return( usValue ); } @@ -5531,7 +5518,8 @@ void HandlePrisonerProcessingInSector( INT16 sMapX, INT16 sMapY, INT8 bZ ) // Are there any prisoners in this prison? SECTORINFO *pSectorInfo = &( SectorInfo[ SECTOR( sMapX, sMapY ) ] ); - UINT32 numprisoners = pSectorInfo->uiNumberOfPrisonersOfWar; + UINT8 prisoners[PRISONER_MAX] = {0}; + UINT16 numprisoners = GetNumberOrPrisoners( pSectorInfo, &prisoners[PRISONER_SPECIAL], &prisoners[PRISONER_ELITE], &prisoners[PRISONER_REGULAR], &prisoners[PRISONER_ADMIN] ); // add interrogation progress from last hour and erase it in data UINT32 interrogationpoints = pSectorInfo->uiInterrogationHundredsLeft; @@ -5567,23 +5555,33 @@ void HandlePrisonerProcessingInSector( INT16 sMapX, INT16 sMapY, INT8 bZ ) if ( !numinterrogators ) return; + + // we first interrogate admins, then troops, then elites, then specials (once we figure out who those are :-) ) + // higher quality prisoners require more effort, but yield better rewards + UINT8 interrogatedprisoners[PRISONER_MAX] = {0}; + + for (int i = PRISONER_ADMIN; i < PRISONER_MAX; ++i) + { + while ( prisoners[i] && interrogationpoints >= gGameExternalOptions.ubPrisonerInterrogationPoints[i] ) + { + interrogationpoints -= gGameExternalOptions.ubPrisonerInterrogationPoints[i]; + --prisoners[i]; + ++interrogatedprisoners[i]; + } + } - // for every x points, we can interrogate 1 prisoner - // TODO: for now, we lose the remaining points - UINT32 prisonersinterrogated = interrogationpoints / 100; + UINT16 prisonersinterrogated = interrogatedprisoners[PRISONER_ADMIN] + interrogatedprisoners[PRISONER_REGULAR] + interrogatedprisoners[PRISONER_ELITE] + interrogatedprisoners[PRISONER_SPECIAL]; // the part that gets left behind is saved to the map (but not the part that gets lost due to there not being enough prisoners) - pSectorInfo->uiInterrogationHundredsLeft = (UINT8)(interrogationpoints - prisonersinterrogated * 100); - - if ( prisonersinterrogated > numprisoners ) - prisonersinterrogated = numprisoners; - + UINT32 losthundreds = interrogationpoints / 100; + pSectorInfo->uiInterrogationHundredsLeft = (UINT8)(interrogationpoints - losthundreds * 100); + if ( !prisonersinterrogated ) return; - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szPrisonerTextStr[STR_PRISONER_PROCESSED], prisonersinterrogated ); + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szPrisonerTextStr[STR_PRISONER_PROCESSED], interrogatedprisoners[PRISONER_ELITE], interrogatedprisoners[PRISONER_REGULAR], interrogatedprisoners[PRISONER_ADMIN] ); - UINT32 turnedmilitia = 0; + UINT8 turnedmilitia_elite = 0, turnedmilitia_regular= 0, turnedmilitia_admin = 0; UINT32 revealedpositions = 0; UINT32 ransomscollected = 0; UINT32 ransommoney = 0; @@ -5595,9 +5593,15 @@ void HandlePrisonerProcessingInSector( INT16 sMapX, INT16 sMapY, INT8 bZ ) // chance that prisoner will work on our side as militia if ( result < gGameExternalOptions.ubPrisonerProcessDefectChance ) { - ++turnedmilitia; + // troops are converted to militia, but there is a chance that they will be demoted in the process + if ( i < interrogatedprisoners[PRISONER_ELITE] && Chance(80) ) + ++turnedmilitia_elite; + else if ( i < interrogatedprisoners[PRISONER_ELITE] + interrogatedprisoners[PRISONER_REGULAR] && Chance(80) ) + ++turnedmilitia_regular; + else + ++turnedmilitia_admin; - // we continue so that this guy can not also run back to the queen + // we continue so that this guy cannot also run back to the queen continue; } // chance that prisoner will give us random info about enemy positions @@ -5656,12 +5660,14 @@ void HandlePrisonerProcessingInSector( INT16 sMapX, INT16 sMapY, INT8 bZ ) ++giReinforcementPool; } - if ( turnedmilitia ) + if ( turnedmilitia_elite + turnedmilitia_regular + turnedmilitia_admin ) { // add these guys to the local garrison as green militias - StrategicAddMilitiaToSector(sMapX, sMapY, GREEN_MILITIA, turnedmilitia); + StrategicAddMilitiaToSector(sMapX, sMapY, GREEN_MILITIA, turnedmilitia_admin); + StrategicAddMilitiaToSector(sMapX, sMapY, REGULAR_MILITIA, turnedmilitia_regular); + StrategicAddMilitiaToSector(sMapX, sMapY, ELITE_MILITIA, turnedmilitia_elite); - ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szPrisonerTextStr[STR_PRISONER_TURN_MILITIA], turnedmilitia ); + ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szPrisonerTextStr[STR_PRISONER_TURN_MILITIA], turnedmilitia_elite, turnedmilitia_regular, turnedmilitia_admin ); } if ( revealedpositions ) @@ -5697,12 +5703,8 @@ void HandlePrisonerProcessingInSector( INT16 sMapX, INT16 sMapY, INT8 bZ ) } } - // remove interrogated prisoners... - // safety first... - if ( prisonersinterrogated > pSectorInfo->uiNumberOfPrisonersOfWar ) - pSectorInfo->uiNumberOfPrisonersOfWar = 0; - else - pSectorInfo->uiNumberOfPrisonersOfWar -= prisonersinterrogated; + // remove interrogated prisoners... + ChangeNumberOfPrisoners( pSectorInfo, -interrogatedprisoners[PRISONER_SPECIAL], -interrogatedprisoners[PRISONER_ELITE], -interrogatedprisoners[PRISONER_REGULAR], -interrogatedprisoners[PRISONER_ADMIN] ); } // Flugente: prisons can riot if there aren't enough guards around @@ -5738,9 +5740,15 @@ void HandlePrison( INT16 sMapX, INT16 sMapY, INT8 bZ ) // Are there any prisoners in this prison? SECTORINFO *pSectorInfo = &( SectorInfo[ SECTOR( sMapX, sMapY ) ] ); - - UINT32 numprisoners = pSectorInfo->uiNumberOfPrisonersOfWar; + UINT8 prisonersspecial = 0, prisonerselite = 0, prisonersregular = 0, prisonersadmin = 0; + UINT16 numprisoners = GetNumberOrPrisoners( pSectorInfo, &prisonersspecial, &prisonerselite, &prisonersregular, &prisonersadmin ); + + // for now, simply count specials as elites + ChangeNumberOfPrisoners( pSectorInfo, -prisonersspecial, prisonersspecial, 0, 0 ); + prisonerselite += prisonersspecial; + prisonersspecial = 0; + if ( !numprisoners ) return; @@ -5751,10 +5759,12 @@ void HandlePrison( INT16 sMapX, INT16 sMapY, INT8 bZ ) if( StrategicMap[ sMapX + sMapY * MAP_WORLD_X ].fEnemyControlled == TRUE ) { // add enemies - pSectorInfo->ubNumTroops += numprisoners; + pSectorInfo->ubNumTroops = min(255, pSectorInfo->ubNumTroops + prisonersregular); + pSectorInfo->ubNumElites = min(255, pSectorInfo->ubNumElites + prisonerselite); + pSectorInfo->ubNumAdmins = min(255, pSectorInfo->ubNumAdmins + prisonersadmin); // all prisoners are free, reduce count! - pSectorInfo->uiNumberOfPrisonersOfWar = 0; + DeleteAllPrisoners(pSectorInfo); ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szPrisonerTextStr[STR_PRISONER_ARMY_FREED_PRISON], wSectorName ); @@ -5793,11 +5803,7 @@ void HandlePrison( INT16 sMapX, INT16 sMapY, INT8 bZ ) fBeginRiot = TRUE; // we now have to determine the combined strength of the prisoners - UINT32 prisonerriotvalue = 0; - for ( UINT32 i = 0; i < numprisoners; ++i ) - { - prisonerriotvalue += 100; - } + UINT32 prisonerriotvalue = 125 * prisonerselite + 100 * prisonersregular + 75 * prisonersadmin; if ( prisonerriotvalue > prisonguardvalue ) { @@ -5807,11 +5813,22 @@ void HandlePrison( INT16 sMapX, INT16 sMapY, INT8 bZ ) if ( fBeginRiot ) { - // add enemies - pSectorInfo->ubNumTroops += numprisoners; + FLOAT prisonertoguardratio = 1.0f; + if ( prisonguardvalue ) + prisonertoguardratio = (FLOAT)(prisonerriotvalue / prisonguardvalue); - // all prisoners are free, reduce count! - pSectorInfo->uiNumberOfPrisonersOfWar = 0; + // in a riot, prisoners escape and are added to the sector as enemies. Not all might escape - the worse the prisoner/guard ratio, the more escape + UINT8 escapedadmins = min( Random(prisonersadmin + prisonersadmin * prisonertoguardratio) , prisonersadmin); + UINT8 escapedregulars = min( Random(prisonersregular + prisonersregular * prisonertoguardratio) , prisonersregular); + UINT8 escapedelites = min( Random(prisonerselite + prisonerselite * prisonertoguardratio) , prisonerselite); + + // add enemies + pSectorInfo->ubNumTroops = min(255, pSectorInfo->ubNumTroops + escapedregulars); + pSectorInfo->ubNumElites = min(255, pSectorInfo->ubNumElites + escapedelites); + pSectorInfo->ubNumAdmins = min(255, pSectorInfo->ubNumAdmins + escapedadmins); + + // reduce prisoner count! + ChangeNumberOfPrisoners( pSectorInfo, -prisonersspecial, -escapedelites, -escapedregulars, -escapedadmins ); ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szPrisonerTextStr[STR_PRISONER_RIOT], wSectorName ); } diff --git a/Strategic/Campaign Types.h b/Strategic/Campaign Types.h index a35ef3f2..2e908ff7 100644 --- a/Strategic/Campaign Types.h +++ b/Strategic/Campaign Types.h @@ -412,6 +412,16 @@ extern UINT8 gszTerrain[NUM_TRAVTERRAIN_TYPES][15]; //Used by ubGarrisonID when a sector doesn't point to a garrison. Used by strategic AI only. #define NO_GARRISON 255 +// Flugente: types of prisoners +typedef enum +{ + PRISONER_ADMIN = 0, + PRISONER_REGULAR, + PRISONER_ELITE, + PRISONER_SPECIAL, + PRISONER_MAX, +} PrisonerType; + typedef struct SECTORINFO { //information pertaining to this sector @@ -479,7 +489,7 @@ typedef struct SECTORINFO BOOLEAN fCampaignSector; #endif - UINT32 uiNumberOfPrisonersOfWar; + UINT8 uiNumberOfPrisonersOfWar[PRISONER_MAX]; UINT8 uiInterrogationHundredsLeft; INT8 bPadding[ 36 ]; @@ -519,7 +529,7 @@ typedef struct UNDERGROUND_SECTORINFO BOOLEAN fCampaignSector; #endif - UINT32 uiNumberOfPrisonersOfWar; + UINT8 uiNumberOfPrisonersOfWar[PRISONER_MAX]; INT8 bPadding[32]; //no padding left! diff --git a/Tactical/Faces.cpp b/Tactical/Faces.cpp index e48508b5..02f45f68 100644 --- a/Tactical/Faces.cpp +++ b/Tactical/Faces.cpp @@ -2416,8 +2416,8 @@ void HandleRenderFaceAdjustments( FACETYPE *pFace, BOOLEAN fDisplayBuffer, BOOLE case FACILITY_INTERROGATE_PRISONERS: sIconIndex = 23; fDoIcon = TRUE; - //sPtsAvailable = (INT16)( CalculateInterrogationValue(pSoldier, &usMaximumPts )/100 ); - bPtsAvailable = (FLOAT)( CalculateInterrogationValue(pSoldier, &usMaximumPts )/100.0 ); + sPtsAvailable = (INT16)( CalculateInterrogationValue(pSoldier, &usMaximumPts ) ); + //bPtsAvailable = (FLOAT)( CalculateInterrogationValue(pSoldier, &usMaximumPts )/100.0 ); fShowNumber = TRUE; fShowMaximum = TRUE; break; @@ -2452,10 +2452,10 @@ void HandleRenderFaceAdjustments( FACETYPE *pFace, BOOLEAN fDisplayBuffer, BOOLE if ( fShowMaximum ) { - if ( pSoldier->bAssignment == FACILITY_INTERROGATE_PRISONERS ) + /*if ( pSoldier->bAssignment == FACILITY_INTERROGATE_PRISONERS ) swprintf( sString, L"%2.2f/%d", bPtsAvailable, usMaximumPts ); - else - swprintf( sString, L"%d/%d", sPtsAvailable, usMaximumPts ); + else*/ + swprintf( sString, L"%d/%d", sPtsAvailable, usMaximumPts ); } else { diff --git a/Tactical/Overhead.cpp b/Tactical/Overhead.cpp index 74351ec2..1e934907 100644 --- a/Tactical/Overhead.cpp +++ b/Tactical/Overhead.cpp @@ -3665,12 +3665,7 @@ void HandleNPCTeamMemberDeath( SOLDIERTYPE *pSoldierOld ) // Flugente: if this was a prisoner of war, reduce their sector count by 1 if ( pSoldierOld->bSoldierFlagMask & SOLDIER_POW_PRISON ) - { - // get sector - SECTORINFO *pSector = &SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ]; - if ( pSector ) - pSector->uiNumberOfPrisonersOfWar = max(0, pSector->uiNumberOfPrisonersOfWar - 1); - } + KillOnePrisoner( &SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ] ); } else if ( pSoldierOld->bTeam == MILITIA_TEAM ) { @@ -6548,15 +6543,16 @@ void PrisonerMessageBoxCallBack( UINT8 ubExitValue ) ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, szPrisonerTextStr[STR_PRISONER_RELEASED] ); } - UINT32 prisonerstobemoved = 0; + UINT16 prisonerstobemoved = 0; + UINT8 prisonersspecial = 0, prisonerselite = 0, prisonersregular = 0, prisonersadmin = 0; BOOLEAN success = FALSE; if ( !gbWorldSectorZ ) { SECTORINFO *pSectorInfo = &( SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ] ); - prisonerstobemoved = pSectorInfo->uiNumberOfPrisonersOfWar; + prisonerstobemoved = GetNumberOrPrisoners( pSectorInfo, &prisonersspecial, &prisonerselite, &prisonersregular, &prisonersadmin ); - pSectorInfo->uiNumberOfPrisonersOfWar = 0; + DeleteAllPrisoners( pSectorInfo ); if ( usSectorID > 0) { @@ -6566,7 +6562,7 @@ void PrisonerMessageBoxCallBack( UINT8 ubExitValue ) { success = TRUE; - pPrisonSectorInfo->uiNumberOfPrisonersOfWar += prisonerstobemoved; + ChangeNumberOfPrisoners( pPrisonSectorInfo, prisonersspecial, prisonerselite, prisonersregular, prisonersadmin ); CHAR16 wString[ 64 ]; GetShortSectorString( SECTORX(usSectorID), SECTORY(usSectorID), wString ); @@ -6578,9 +6574,9 @@ void PrisonerMessageBoxCallBack( UINT8 ubExitValue ) { UNDERGROUND_SECTORINFO *pSectorInfo = FindUnderGroundSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ ); - prisonerstobemoved = pSectorInfo->uiNumberOfPrisonersOfWar; + prisonerstobemoved = GetNumberOrPrisoners( pSectorInfo, &prisonersspecial, &prisonerselite, &prisonersregular, &prisonersadmin ); - pSectorInfo->uiNumberOfPrisonersOfWar = 0; + DeleteAllPrisoners( pSectorInfo ); if ( usSectorID > 0) { @@ -6590,7 +6586,7 @@ void PrisonerMessageBoxCallBack( UINT8 ubExitValue ) { success = TRUE; - pPrisonSectorInfo->uiNumberOfPrisonersOfWar += prisonerstobemoved; + ChangeNumberOfPrisoners( pPrisonSectorInfo, prisonersspecial, prisonerselite, prisonersregular, prisonersadmin ); CHAR16 wString[ 64 ]; GetShortSectorString( SECTORX(usSectorID), SECTORY(usSectorID), wString ); @@ -6633,9 +6629,9 @@ void RemoveCapturedEnemiesFromSectorInfo( INT16 sMapX, INT16 sMapY, INT8 bMapZ ) case SOLDIER_CLASS_ARMY: ubNumPrisonerTroop++; break; case SOLDIER_CLASS_ELITE: ubNumPrisonerElite++; break; default: - // if none of the above classes, ignore this one - continue; - break; + // if none of the above classes, ignore this one + continue; + break; } ++ubNumPrisoners; @@ -6716,13 +6712,13 @@ void RemoveCapturedEnemiesFromSectorInfo( INT16 sMapX, INT16 sMapY, INT8 bMapZ ) { SECTORINFO *pSectorInfo = &( SectorInfo[ SECTOR( sMapX, sMapY ) ] ); - pSectorInfo->uiNumberOfPrisonersOfWar += ubNumPrisoners; + ChangeNumberOfPrisoners(pSectorInfo, 0, ubNumPrisonerElite, ubNumPrisonerTroop, ubNumPrisonerAdmin); } else { UNDERGROUND_SECTORINFO *pSectorInfo = FindUnderGroundSector( sMapX, sMapY, bMapZ ); - pSectorInfo->uiNumberOfPrisonersOfWar += ubNumPrisoners; + ChangeNumberOfPrisoners(pSectorInfo, 0, ubNumPrisonerElite, ubNumPrisonerTroop, ubNumPrisonerAdmin); } if ( ubNumPrisoners ) @@ -10195,3 +10191,85 @@ BOOLEAN IsProfileInUse(UINT8 usTeam, INT8 aType, UINT16 aNr) return FALSE; } + +UINT16 GetNumberOrPrisoners( SECTORINFO *pSectorInfo, UINT8* apSpecial, UINT8* apElite, UINT8* apRegular, UINT8* apAdmin ) +{ + if ( !pSectorInfo ) + return 0; + + *apSpecial = pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_SPECIAL]; + *apElite = pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ELITE]; + *apRegular = pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_REGULAR]; + *apAdmin = pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ADMIN]; + + return (UINT16)(pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_SPECIAL] + pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ELITE] + pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_REGULAR] + pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ADMIN]); +} + +UINT16 GetNumberOrPrisoners( UNDERGROUND_SECTORINFO *pSectorInfo, UINT8* apSpecial, UINT8* apElite, UINT8* apRegular, UINT8* apAdmin ) +{ + if ( !pSectorInfo ) + return 0; + + *apSpecial = pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_SPECIAL]; + *apElite = pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ELITE]; + *apRegular = pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_REGULAR]; + *apAdmin = pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ADMIN]; + + return (UINT16)(pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_SPECIAL] + pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ELITE] + pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_REGULAR] + pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ADMIN]); +} + +void ChangeNumberOfPrisoners( SECTORINFO *pSectorInfo, INT16 aSpecial, INT16 aElite, INT16 aRegular, INT16 aAdmin ) +{ + if ( !pSectorInfo ) + return; + + pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_SPECIAL] = max(0, min(255, pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_SPECIAL] + aSpecial) ); + pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ELITE] = max(0, min(255, pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ELITE] + aElite) ); + pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_REGULAR] = max(0, min(255, pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_REGULAR] + aRegular) ); + pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ADMIN] = max(0, min(255, pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ADMIN] + aAdmin) ); +} + +void ChangeNumberOfPrisoners( UNDERGROUND_SECTORINFO *pSectorInfo, INT16 aSpecial, INT16 aElite, INT16 aRegular, INT16 aAdmin ) +{ + if ( !pSectorInfo ) + return; + + pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_SPECIAL] = max(0, min(255, pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_SPECIAL] + aSpecial) ); + pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ELITE] = max(0, min(255, pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ELITE] + aElite) ); + pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_REGULAR] = max(0, min(255, pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_REGULAR] + aRegular) ); + pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ADMIN] = max(0, min(255, pSectorInfo->uiNumberOfPrisonersOfWar[PRISONER_ADMIN] + aAdmin) ); +} + +void DeleteAllPrisoners( SECTORINFO *pSectorInfo ) +{ + if ( !pSectorInfo ) + return; + + for (int i = PRISONER_ADMIN; i < PRISONER_MAX; ++i) + pSectorInfo->uiNumberOfPrisonersOfWar[i] = 0; +} + +void DeleteAllPrisoners( UNDERGROUND_SECTORINFO *pSectorInfo ) +{ + if ( !pSectorInfo ) + return; + + for (int i = PRISONER_ADMIN; i < PRISONER_MAX; ++i) + pSectorInfo->uiNumberOfPrisonersOfWar[i] = 0; +} + +// used when the player kills a prisoner. We kill of high-value prisoners first, to punish this kind of behaviour +void KillOnePrisoner( SECTORINFO *pSectorInfo ) +{ + if ( !pSectorInfo ) + return; + + for (int i = PRISONER_SPECIAL; i >= PRISONER_ADMIN; --i) + { + if ( pSectorInfo->uiNumberOfPrisonersOfWar[i] ) + { + pSectorInfo->uiNumberOfPrisonersOfWar[i] -= 1; + break; + } + } +} \ No newline at end of file diff --git a/Tactical/Overhead.h b/Tactical/Overhead.h index 0f9606a8..211e598c 100644 --- a/Tactical/Overhead.h +++ b/Tactical/Overhead.h @@ -6,6 +6,7 @@ #include "Soldier Control.h" #include "overhead types.h" #include "soldier find.h" +#include "Campaign Types.h" // added by Flugente for SECTORINFO and UNDERGROUND_SECTORINFO #define ADD_SOLDIER_NO_PROFILE_ID 200 #define MAX_REALTIME_SPEED_VAL 10 @@ -364,5 +365,18 @@ BOOLEAN AllowedToStealFromTeamMate( UINT8 aAccessorID, UINT8 aTargetID ); // Flugente: is an soldier profile already used? BOOLEAN IsProfileInUse(UINT8 usTeam, INT8 aType, UINT16 aNr); +// Flugente: functions altering a sector's prisoners +UINT16 GetNumberOrPrisoners( SECTORINFO *pSectorInfo, UINT8* apSpecial, UINT8* apElite, UINT8* apRegular, UINT8* apAdmin ); +UINT16 GetNumberOrPrisoners( UNDERGROUND_SECTORINFO *pSectorInfo, UINT8* apSpecial, UINT8* apElite, UINT8* apRegular, UINT8* apAdmin ); + +void ChangeNumberOfPrisoners( SECTORINFO *pSectorInfo, INT16 aSpecial, INT16 aElite, INT16 aRegular, INT16 aAdmin ); +void ChangeNumberOfPrisoners( UNDERGROUND_SECTORINFO *pSectorInfo, INT16 aSpecial, INT16 aElite, INT16 aRegular, INT16 aAdmin ); + +void DeleteAllPrisoners( SECTORINFO *pSectorInfo ); +void DeleteAllPrisoners( UNDERGROUND_SECTORINFO *pSectorInfo ); + +// used when the player kills a prisoner. We kill of high-value prisoners first, to punish this kind of behaviour +void KillOnePrisoner( SECTORINFO *pSectorInfo ); + #endif diff --git a/Tactical/Soldier Control.cpp b/Tactical/Soldier Control.cpp index 8f7306b3..5aab05cd 100644 --- a/Tactical/Soldier Control.cpp +++ b/Tactical/Soldier Control.cpp @@ -15520,7 +15520,8 @@ BOOLEAN SOLDIERTYPE::CanProcessPrisoners() { SECTORINFO *pSectorInfo = &( SectorInfo[ SECTOR( this->sSectorX, this->sSectorY ) ] ); - if ( pSectorInfo->uiNumberOfPrisonersOfWar > 0 ) + UINT8 tmp1 = 0, tmp2 = 0, tmp3 = 0, tmp4 = 0; + if ( GetNumberOrPrisoners(pSectorInfo, &tmp1, &tmp2, &tmp3, &tmp4) > 0 ) return TRUE; } diff --git a/Tactical/Soldier Init List.cpp b/Tactical/Soldier Init List.cpp index dd6b4f9f..cdb36ccc 100644 --- a/Tactical/Soldier Init List.cpp +++ b/Tactical/Soldier Init List.cpp @@ -2818,7 +2818,8 @@ void SectorAddPrisonersofWar( INT16 sMapX, INT16 sMapY, INT16 sMapZ ) return; // only continue if there are prisoners in this sector that need to be placed - UINT32 numprisoners = pSector->uiNumberOfPrisonersOfWar; + UINT8 tmp1 = 0, tmp2 = 0, tmp3 = 0, tmp4 = 0; + UINT16 numprisoners = GetNumberOrPrisoners(pSector, &tmp1, &tmp2, &tmp3, &tmp4); if ( !numprisoners ) return; @@ -2842,7 +2843,7 @@ void SectorAddPrisonersofWar( INT16 sMapX, INT16 sMapY, INT16 sMapZ ) // we can't spawn if all civilian slots are already taken (we leave a bit of reserve for more important civs) UINT8 maxcivs = max(0, gGameExternalOptions.ubGameMaximumNumberOfCivilians - 3); - for (UINT8 i = numberofpows; i < numprisoners; ++i) + for (UINT16 i = numberofpows; i < numprisoners; ++i) { if ( numberofcivs < maxcivs ) { diff --git a/Utils/_ChineseText.cpp b/Utils/_ChineseText.cpp index 7766a665..10fb2fdd 100644 --- a/Utils/_ChineseText.cpp +++ b/Utils/_ChineseText.cpp @@ -7557,12 +7557,12 @@ STR16 szFoodTextStr[]= L"区域供水不可行,食物和生存系统已被关闭"//L"Sectorwide canteen filling not possible, Food System is off!" }; -STR16 szPrisonerTextStr[]= +STR16 szPrisonerTextStr[]= // TODO.Translate { - L"%d 名俘虏已被审讯", //L"%d prisoners were interrogated.", + L"%d elites, %d regulars and %d amins were interrogated.", L"%d 名俘虏已支付赎金", //L"%d prisoners paid ransom money.", L"%d 名俘虏已供出同伙位置", //L"%d prisoners revealed enemy positions.", - L"%d 名俘虏已加入我方阵营", //L"%d prisoners joined our cause.", + L"%d elites, %d regulars and %d amins joined our cause.", L"俘虏掀起大规模暴动!在 %s 监狱!", //L"Prisoners start a massive riot in %s!", L"俘虏被押送前往 %s 监狱", //L"The army now occupies the prison in %s, the prisoners were freed!", L"俘虏已被释放!", //L"Prisoners have been released!", diff --git a/Utils/_DutchText.cpp b/Utils/_DutchText.cpp index c2a3e37d..d886be8e 100644 --- a/Utils/_DutchText.cpp +++ b/Utils/_DutchText.cpp @@ -7555,10 +7555,10 @@ STR16 szFoodTextStr[]= // TODO.Translate STR16 szPrisonerTextStr[]= { - L"%d prisoners were interrogated.", + L"%d elites, %d regulars and %d amins were interrogated.", L"%d prisoners paid ransom money.", L"%d prisoners revealed enemy positions.", - L"%d prisoners joined our cause.", + L"%d elites, %d regulars and %d amins joined our cause.", L"Prisoners start a massive riot in %s!", L"%d prisoners were sent to %s!", L"Prisoners have been released!", diff --git a/Utils/_EnglishText.cpp b/Utils/_EnglishText.cpp index e8d70d6b..b66b88fe 100644 --- a/Utils/_EnglishText.cpp +++ b/Utils/_EnglishText.cpp @@ -7543,10 +7543,10 @@ STR16 szFoodTextStr[]= STR16 szPrisonerTextStr[]= { - L"%d prisoners were interrogated.", + L"%d elites, %d regulars and %d amins were interrogated.", L"%d prisoners paid ransom money.", L"%d prisoners revealed enemy positions.", - L"%d prisoners joined our cause.", + L"%d elites, %d regulars and %d amins joined our cause.", L"Prisoners start a massive riot in %s!", L"%d prisoners were sent to %s!", L"Prisoners have been released!", diff --git a/Utils/_FrenchText.cpp b/Utils/_FrenchText.cpp index d896d25a..0ada9651 100644 --- a/Utils/_FrenchText.cpp +++ b/Utils/_FrenchText.cpp @@ -7539,10 +7539,10 @@ STR16 szFoodTextStr[]= // TODO.Translate STR16 szPrisonerTextStr[]= { - L"%d prisoners were interrogated.", + L"%d elites, %d regulars and %d amins were interrogated.", L"%d prisoners paid ransom money.", L"%d prisoners revealed enemy positions.", - L"%d prisoners joined our cause.", + L"%d elites, %d regulars and %d amins joined our cause.", L"Prisoners start a massive riot in %s!", L"%d prisoners were sent to %s!", L"Prisoners have been released!", diff --git a/Utils/_GermanText.cpp b/Utils/_GermanText.cpp index 74f00aa7..104ca496 100644 --- a/Utils/_GermanText.cpp +++ b/Utils/_GermanText.cpp @@ -7365,10 +7365,10 @@ STR16 szFoodTextStr[]= STR16 szPrisonerTextStr[]= { - L"%d Gefangenge wurden verhört.", + L"%d Elite-, %d Reguläre und %d Hilfssoldaten wurden verhört.", L"%d Gefangene wurden gegen Lösegeld freigelassen.", L"%d Gefangene haben uns Truppenstandorte verraten.", - L"%d Gefangene schliessen sich uns an.", + L"%d Elite-, %d Reguläre und %d Hilfssoldaten laufen zu uns über.", L"Gefangenenaufstand in %s!", L"%d Gefangene wurden nach %s geschickt!", L"Gefangene freigelassen!", diff --git a/Utils/_ItalianText.cpp b/Utils/_ItalianText.cpp index a9e15c56..7dca0471 100644 --- a/Utils/_ItalianText.cpp +++ b/Utils/_ItalianText.cpp @@ -7541,10 +7541,10 @@ STR16 szFoodTextStr[]= // TODO.Translate STR16 szPrisonerTextStr[]= { - L"%d prisoners were interrogated.", + L"%d elites, %d regulars and %d amins were interrogated.", L"%d prisoners paid ransom money.", L"%d prisoners revealed enemy positions.", - L"%d prisoners joined our cause.", + L"%d elites, %d regulars and %d amins joined our cause.", L"Prisoners start a massive riot in %s!", L"%d prisoners were sent to %s!", L"Prisoners have been released!", diff --git a/Utils/_PolishText.cpp b/Utils/_PolishText.cpp index 1f8b9665..48b011b9 100644 --- a/Utils/_PolishText.cpp +++ b/Utils/_PolishText.cpp @@ -7561,10 +7561,10 @@ STR16 szFoodTextStr[]= // TODO.Translate STR16 szPrisonerTextStr[]= { - L"%d prisoners were interrogated.", + L"%d elites, %d regulars and %d amins were interrogated.", L"%d prisoners paid ransom money.", L"%d prisoners revealed enemy positions.", - L"%d prisoners joined our cause.", + L"%d elites, %d regulars and %d amins joined our cause.", L"Prisoners start a massive riot in %s!", L"%d prisoners were sent to %s!", L"Prisoners have been released!", diff --git a/Utils/_RussianText.cpp b/Utils/_RussianText.cpp index 7f2bc4b3..6c972521 100644 --- a/Utils/_RussianText.cpp +++ b/Utils/_RussianText.cpp @@ -7539,18 +7539,18 @@ STR16 szFoodTextStr[]= L"Sectorwide canteen filling not possible, Food System is off!" }; -STR16 szPrisonerTextStr[]= +STR16 szPrisonerTextStr[]= // TODO.Translate { - L"%d prisoners were interrogated.", // TODO.Translate + L"%d elites, %d regulars and %d amins were interrogated.", L"%d prisoners paid ransom money.", L"%d prisoners revealed enemy positions.", - L"%d prisoners joined our cause.", + L"%d elites, %d regulars and %d amins joined our cause.", L"Prisoners start a massive riot in %s!", L"%d prisoners were sent to %s!", L"Prisoners have been released!", L"The army now occupies the prison in %s, the prisoners were freed!", L"The enemy refuses to surrender!", - L"The enemy refuses to take you as prisoners - they prefer you dead!", // TODO.Translate + L"The enemy refuses to take you as prisoners - they prefer you dead!", L"This behaviour is set OFF in your ini settings.", }; diff --git a/Utils/_TaiwaneseText.cpp b/Utils/_TaiwaneseText.cpp index 607aa881..75953748 100644 --- a/Utils/_TaiwaneseText.cpp +++ b/Utils/_TaiwaneseText.cpp @@ -7559,10 +7559,10 @@ STR16 szFoodTextStr[]= // TODO.Translate STR16 szPrisonerTextStr[]= { - L"%d prisoners were interrogated.", + L"%d elites, %d regulars and %d amins were interrogated.", L"%d prisoners paid ransom money.", L"%d prisoners revealed enemy positions.", - L"%d prisoners joined our cause.", + L"%d elites, %d regulars and %d amins joined our cause.", L"Prisoners start a massive riot in %s!", L"%d prisoners were sent to %s!", L"Prisoners have been released!",