diff --git a/GameSettings.cpp b/GameSettings.cpp index 6284ecda..248c3603 100644 --- a/GameSettings.cpp +++ b/GameSettings.cpp @@ -927,6 +927,12 @@ void LoadGameExternalOptions() //tais: percentage that the merc's salary rises when he/she levels up gGameExternalOptions.gMercLevelUpSalaryIncreasePercentage = (FLOAT)iniReader.ReadInteger("Financial Settings","MERC_LEVEL_UP_SALARY_INCREASE_PERCENTAGE",25, 0, 1000); + + // Flugente: mine income can depend on the number or workers we have + gGameExternalOptions.fMineRequiresWorkers = iniReader.ReadBoolean( "Financial Settings", "MINE_REQUIRES_WORKERS", FALSE ); + gGameExternalOptions.dInitialWorkerRate = iniReader.ReadFloat( "Financial Settings", "WORKERRATE_PRESENT_INITIALLY", 0.3f, 0.0f, 1.0f ); + gGameExternalOptions.usWorkerTrainingCost = iniReader.ReadInteger( "Financial Settings", "WORKER_TRAINING_COST", 30, 0, 1000 ); + gGameExternalOptions.usWorkerTrainingPoints = iniReader.ReadInteger( "Financial Settings", "WORKER_TRAINING_POINTS", 100, 1, 250 ); //################# Troubleshooting Settings ################# diff --git a/GameSettings.h b/GameSettings.h index b07bf633..e8d808e5 100644 --- a/GameSettings.h +++ b/GameSettings.h @@ -1296,6 +1296,12 @@ typedef struct FLOAT gMercLevelUpSalaryIncreasePercentage; + // Flugente: mine income can depend on the number or workers we have + BOOLEAN fMineRequiresWorkers; + FLOAT dInitialWorkerRate; + UINT32 usWorkerTrainingCost; + UINT8 usWorkerTrainingPoints; + UINT8 ubChanceTonyAvailable; // silversurfer/SANDRO BOOLEAN fShowSkillsInHirePage; diff --git a/GameVersion.h b/GameVersion.h index c1f74861..a866f4df 100644 --- a/GameVersion.h +++ b/GameVersion.h @@ -21,6 +21,7 @@ extern CHAR16 zTrackingNumber[16]; // Keeps track of the saved game version. Increment the saved game version whenever // you will invalidate the saved game file +#define WORKERS 170 // Flugente: train workers for facilities #define WEATHER_CHANGE 169 // Flugente: sector-specific weather & more weather types #define ASD_INIT_FIX 168 // Flugente: fix for ASD feature introduced with ENEMY_HELICOPTERS #define NONPROFILE_MERCHANTS 167 // Flugente: merchants can be created from non-profile NPCs @@ -88,7 +89,7 @@ extern CHAR16 zTrackingNumber[16]; #define AP100_SAVEGAME_DATATYPE_CHANGE 105 // Before this, we didn't have the 100AP structure changes #define NIV_SAVEGAME_DATATYPE_CHANGE 102 // Before this, we used the old structure system -#define SAVE_GAME_VERSION WEATHER_CHANGE +#define SAVE_GAME_VERSION WORKERS //#define RUSSIANGOLD #ifdef __cplusplus diff --git a/Laptop/finances.cpp b/Laptop/finances.cpp index c508df1a..27f62cba 100644 --- a/Laptop/finances.cpp +++ b/Laptop/finances.cpp @@ -1582,6 +1582,7 @@ void ProcessTransactionString(STR16 pString, FinanceUnitPtr pFinance) case WHO_SUBSCRIPTION: case PMC_CONTRACT: case SAM_REPAIR: + case WORKERS_TRAINED: swprintf( pString, L"%s", pTransactionText[pFinance->ubCode] ); break; } diff --git a/Laptop/finances.h b/Laptop/finances.h index 3b429d3f..5d9974de 100644 --- a/Laptop/finances.h +++ b/Laptop/finances.h @@ -57,6 +57,7 @@ enum WHO_SUBSCRIPTION, // Flugente: subscription do WHO data PMC_CONTRACT, // Flugente: hired militia from a PMC SAM_REPAIR, // Flugente: repair SAM site + WORKERS_TRAINED, // Flugente: train workers TEXT_NUM_FINCANCES }; diff --git a/Strategic/Assignments.cpp b/Strategic/Assignments.cpp index d09db2cb..abca4d19 100644 --- a/Strategic/Assignments.cpp +++ b/Strategic/Assignments.cpp @@ -466,6 +466,8 @@ void HandlePrison( INT16 sMapX, INT16 sMapY, INT8 bZ ); // Flugente: assigned mercs can move equipemnt in city sectors void HandleEquipmentMove( INT16 sMapX, INT16 sMapY, INT8 bZ ); +void HandleTrainWorkers( ); + // Flugente: handle radio scanning assignments void HandleRadioScanInSector( INT16 sMapX, INT16 sMapY, INT8 bZ ); @@ -2547,9 +2549,9 @@ void UpdateAssignments() // Flugente: prisons can riot if there aren't enough guards around if ( !bZ ) HandlePrison( sX, sY, bZ ); + } } } - } // Flugente: individual militia HandleHourlyMilitiaHealing(); @@ -2568,6 +2570,8 @@ void UpdateAssignments() // handle fortification HandleFortification(); + HandleTrainWorkers(); + // check to see if anyone is done healing? UpdatePatientsWhoAreDoneHealing( ); @@ -3251,6 +3255,50 @@ FLOAT GetBestSAMOperatorCTH_Player( INT16 sSectorX, INT16 sSectorY, INT16 sSecto return bestsamcth; } +INT16 GetTrainWorkerPts(SOLDIERTYPE *pSoldier) +{ + // this is not an assignment. Simply being in the sector will allow us to be counted as guards + INT16 val = 0; + + if ( pSoldier->flags.fMercAsleep ) + return 0; + + val = 3 * EffectiveExpLevel( pSoldier ) + EffectiveLeadership( pSoldier ); + + if (gGameOptions.fNewTraitSystem) + { + val += 25 * NUM_SKILL_TRAITS( pSoldier, TEACHING_NT ); + } + else + { + val += 25 * NUM_SKILL_TRAITS( pSoldier, TEACHING_OT ); + } + + // -5% for Aggressive people + if ( DoesMercHavePersonality( pSoldier, CHAR_TRAIT_AGGRESSIVE ) ) + { + val -= 5; + } + // +5% for Phlegmatic people + else if ( DoesMercHavePersonality( pSoldier, CHAR_TRAIT_PHLEGMATIC ) ) + { + val += 5; + } + + // adjust for fatigue + if ( val > 0 ) + { + UINT32 tmp = val; + ReducePointsForFatigue( pSoldier, &tmp ); + + val = tmp; + + return val; + } + + return 0; +} + // anv: handle prisoners exposing snitch as a snitch BOOL HandleSnitchExposition(SOLDIERTYPE *pSoldier) { @@ -7435,6 +7483,60 @@ void HandleEquipmentMove( INT16 sMapX, INT16 sMapY, INT8 bZ ) } } +void HandleTrainWorkers() +{ + UINT32 totalworkersadded = 0; + + SOLDIERTYPE *pSoldier = NULL; + UINT32 uiCnt = 0; + UINT32 firstid = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; + UINT32 lastid = gTacticalStatus.Team[ OUR_TEAM ].bLastID; + for ( uiCnt = firstid, pSoldier = MercPtrs[ uiCnt ]; uiCnt <= lastid; ++uiCnt, ++pSoldier) + { + if( pSoldier->bActive && !pSoldier->bSectorZ && !pSoldier->flags.fMercAsleep ) + { + if( ( pSoldier->bAssignment == TRAIN_WORKERS ) && ( EnoughTimeOnAssignment( pSoldier ) ) ) + { + if ( !SectorOursAndPeaceful( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ ) ) + continue; + + UINT8 ubTownId = StrategicMap[ pSoldier->sSectorX + pSoldier->sSectorY * MAP_WORLD_X ].bNameId; + + // Flugente: adjust for workforce + UINT16 maxworkforce = 0; + UINT16 workforce = GetTownWorkers( ubTownId, maxworkforce); + + if ( workforce < maxworkforce && gGameExternalOptions.usWorkerTrainingPoints > 0 ) + { + UINT8 sector = SECTOR( pSoldier->sSectorX, pSoldier->sSectorY ); + SECTORINFO *pSectorInfo = &(SectorInfo[sector]); + + if ( !pSectorInfo ) + continue; + + INT16 trainpts = pSectorInfo->ubWorkerTrainingHundredths; + + trainpts += GetTrainWorkerPts(pSoldier); + + UINT8 workersadded = trainpts / gGameExternalOptions.usWorkerTrainingPoints; + + totalworkersadded += workersadded; + + AddTownWorkers( ubTownId, workersadded ); + + pSectorInfo->ubWorkerTrainingHundredths = trainpts - gGameExternalOptions.usWorkerTrainingPoints * workersadded; + + StatChange( pSoldier, LDRAMT, 2 * workersadded, TRUE ); + StatChange( pSoldier, EXPERAMT, workersadded, TRUE ); + } + } + } + } + + if ( totalworkersadded * gGameExternalOptions.usWorkerTrainingCost > 0 ) + AddTransactionToPlayersBook( WORKERS_TRAINED, 0, GetWorldTotalMin( ), -(totalworkersadded * gGameExternalOptions.usWorkerTrainingCost) ); +} + // Flugente: fortification void HandleFortification() { @@ -11686,6 +11788,47 @@ void TrainingMenuBtnCallback( MOUSE_REGION * pRegion, INT32 iReason ) } gfRenderPBInterface = TRUE; break; + + case TRAIN_MENU_WORKERS: + + // Check for specific errors why this merc should not be able to train, + // and display a specific error message if one is encountered. + if( !CanCharacterTrainWorkers(pSoldier) ) + { + // Error found. Breaking. Note that the above function DOES display feedback if an error is + // encountered at all. + break; + } + + pSoldier->bOldAssignment = pSoldier->bAssignment; + + if( ( pSoldier->bAssignment != TRAIN_WORKERS ) ) + { + SetTimeOfAssignmentChangeForMerc( pSoldier ); + } + + MakeSoldiersTacticalAnimationReflectAssignment( pSoldier ); + + // stop showing menu + fShowAssignmentMenu = FALSE; + giAssignHighLine = -1; + + // remove from squad + + if( pSoldier->bOldAssignment == VEHICLE ) + { + TakeSoldierOutOfVehicle( pSoldier ); + } + RemoveCharacterFromSquads( pSoldier ); + + ChangeSoldiersAssignment( pSoldier, TRAIN_WORKERS ); + + // assign to a movement group + AssignMercToAMovementGroup( pSoldier ); + SetAssignmentForList( TRAIN_WORKERS, 0 ); + gfRenderPBInterface = TRUE; + break; + case( TRAIN_MENU_TEAMMATES): if( CanCharacterTrainTeammates( pSoldier ) == TRUE ) @@ -15069,6 +15212,49 @@ void SetSoldierAssignment( SOLDIERTYPE *pSoldier, INT8 bAssignment, INT32 iParam gfRenderPBInterface = TRUE; } break; + + case TRAIN_WORKERS: + { + // train mobile militia + pSoldier->bOldAssignment = pSoldier->bAssignment; + + // set dirty flag + fTeamPanelDirty = TRUE; + fMapScreenBottomDirty = TRUE; + + // remove from squad + RemoveCharacterFromSquads( pSoldier ); + + // remove from any vehicle + if( pSoldier->bOldAssignment == VEHICLE ) + { + TakeSoldierOutOfVehicle( pSoldier ); + } + + if( ( pSoldier->bAssignment != TRAIN_WORKERS ) ) + { + SetTimeOfAssignmentChangeForMerc( pSoldier ); + } + + ChangeSoldiersAssignment( pSoldier, TRAIN_WORKERS ); + + if( pMilitiaTrainerSoldier == NULL ) + { + if( SectorInfo[ SECTOR( pSoldier->sSectorX, pSoldier->sSectorY ) ].fMobileMilitiaTrainingPaid == FALSE ) + { + // show a message to confirm player wants to charge cost + HandleInterfaceMessageForCostOfTrainingMilitia( pSoldier ); + } + } + + AssignMercToAMovementGroup( pSoldier ); + // set dirty flag + fTeamPanelDirty = TRUE; + fMapScreenBottomDirty = TRUE; + gfRenderPBInterface = TRUE; + } + break; + case( TRAIN_SELF ): if( CanCharacterTrainStat( pSoldier, ( INT8 )iParam1, TRUE, FALSE ) ) { @@ -15840,6 +16026,17 @@ void HandleShadingOfLinesForTrainingMenu( void ) ShadeStringInBox( ghTrainingBox, TRAIN_MENU_MOBILE ); } + if( CanCharacterTrainWorkers( pSoldier ) ) + { + // unshade train militia line + UnShadeStringInBox( ghTrainingBox, TRAIN_MENU_WORKERS ); + UnSecondaryShadeStringInBox( ghTrainingBox, TRAIN_MENU_WORKERS ); + } + else + { + UnShadeStringInBox( ghTrainingBox, TRAIN_MENU_WORKERS ); + SecondaryShadeStringInBox( ghTrainingBox, TRAIN_MENU_WORKERS ); + } // can character train teammates? if( CanCharacterTrainTeammates( pSoldier ) == FALSE ) @@ -16706,6 +16903,10 @@ void ReEvaluateEveryonesNothingToDo() fNothingToDo = !CanCharacterTrainMobileMilitia( pSoldier ); break; + case TRAIN_WORKERS: + fNothingToDo = !CanCharacterTrainWorkers( pSoldier ); + break; + case TRAIN_SELF: fNothingToDo = !CanCharacterTrainStat( pSoldier, pSoldier->bTrainStat, TRUE, FALSE ); break; @@ -16925,6 +17126,14 @@ void SetAssignmentForList( INT8 bAssignment, INT8 bParam ) fItWorked = TRUE; } break; + case TRAIN_WORKERS: + if( CanCharacterTrainWorkers( pSoldier ) ) + { + pSoldier->bOldAssignment = pSoldier->bAssignment; + SetSoldierAssignment( pSoldier, TRAIN_WORKERS, 0, 0, 0 ); + fItWorked = TRUE; + } + break; case( TRAIN_TEAMMATE ): if( CanCharacterTrainStat( pSoldier, bParam, FALSE, TRUE ) ) { @@ -18431,6 +18640,43 @@ BOOLEAN CanCharacterTrainMobileMilitia( SOLDIERTYPE *pSoldier ) } +BOOLEAN CanCharacterTrainWorkers( SOLDIERTYPE *pSoldier ) +{ + AssertNotNIL(pSoldier); + + if ( !gGameExternalOptions.fMineRequiresWorkers ) + return FALSE; + + if( NumEnemiesInAnySector( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ ) ) + { + return( FALSE ); + } + + // Has leadership skill? + if( pSoldier->stats.bLeadership <= 0 ) + { + // no skill whatsoever + return ( FALSE ); + } + + // Sector Loyalty above minimum? + if( !DoesSectorMercIsInHaveSufficientLoyaltyToTrainMilitia( pSoldier ) ) + { + // Not enough Loyalty... + return ( FALSE ); + } + + INT8 bTownId = GetTownIdForSector( pSoldier->sSectorX, pSoldier->sSectorY ); + + UINT16 maxworkforce = 0; + UINT16 workforce = GetTownWorkers( bTownId, maxworkforce); + + if ( maxworkforce > 0 && workforce < maxworkforce ) + return TRUE; + + return FALSE; +} + BOOLEAN CanCharacterTrainMilitiaWithErrorReport( SOLDIERTYPE *pSoldier ) { // Temp string. diff --git a/Strategic/Assignments.h b/Strategic/Assignments.h index e15742cd..3c7db283 100644 --- a/Strategic/Assignments.h +++ b/Strategic/Assignments.h @@ -85,6 +85,7 @@ enum FACILITY_PATIENT, FACILITY_REPAIR, FORTIFICATION, // Flugente: sectors can be fortified according to external layout plans + TRAIN_WORKERS, NUM_ASSIGNMENTS, }; @@ -179,6 +180,8 @@ BOOLEAN CanCharacterPatient( SOLDIERTYPE *pCharacter ); BOOLEAN CanCharacterTrainMilitia( SOLDIERTYPE *pCharacter ); BOOLEAN CanCharacterTrainMobileMilitia( SOLDIERTYPE *pSoldier ); +BOOLEAN CanCharacterTrainWorkers( SOLDIERTYPE *pSoldier ); + // can character train stat?..as train self or as trainer? BOOLEAN CanCharacterTrainStat( SOLDIERTYPE *pSoldier, INT8 bStat, BOOLEAN fTrainSelf, BOOLEAN fTrainTeammate ); @@ -266,6 +269,9 @@ UINT32 CalculateSnitchInterrogationValue(SOLDIERTYPE *pSoldier, UINT16 *pusMaxPt // Flugente: Determine the best cth with SAMs in a sector, and which merc has that cth if present FLOAT GetBestSAMOperatorCTH_Player( INT16 sSectorX, INT16 sSectorY, INT16 sSectorZ, UINT16 *pubID ); +INT16 GetTrainWorkerPts(SOLDIERTYPE *pSoldier); + + // Flugente: determine max items we can move, and the sector distance // get bonus tarining pts due to an instructor for this student diff --git a/Strategic/Campaign Types.h b/Strategic/Campaign Types.h index 7773be05..115900a1 100644 --- a/Strategic/Campaign Types.h +++ b/Strategic/Campaign Types.h @@ -531,8 +531,9 @@ typedef struct SECTORINFO // Flugente: enemy jeeps UINT8 ubNumJeeps; UINT8 ubJeepsInBattle; - - INT8 bPadding1[2]; + + UINT8 usWorkers; + UINT8 ubWorkerTrainingHundredths; // Flugente: localized weather UINT32 usWeather; diff --git a/Strategic/Map Screen Interface Map.cpp b/Strategic/Map Screen Interface Map.cpp index 6c94de92..769634fd 100644 --- a/Strategic/Map Screen Interface Map.cpp +++ b/Strategic/Map Screen Interface Map.cpp @@ -4568,6 +4568,22 @@ void BlitMineText( INT16 sMapX, INT16 sMapY ) AdjustXForLeftMapEdge(wString, &sScreenX, MapMineLabelsFont); mprintf( ( sScreenX - StringPixLengthArg( MapMineLabelsFont, wcslen(wString), wString ) / 2 ) , sScreenY + ubLineCnt * GetFontHeight( MapMineLabelsFont ), wString ); ++ubLineCnt; + + // Flugente: workforce + if ( gGameExternalOptions.fMineRequiresWorkers ) + { + INT8 bTownId = gMineStatus[ ubMineIndex ].bAssociatedTown; + UINT16 maxworkforce = 0; + UINT16 workforce = GetTownWorkers( bTownId, maxworkforce); + + if ( maxworkforce > 0 ) + { + swprintf( wString, L"%d/%d workers", workforce, maxworkforce ); + AdjustXForLeftMapEdge(wString, &sScreenX, MapMineLabelsFont); + mprintf( ( sScreenX - StringPixLength( wString, MapMineLabelsFont ) / 2 ) , sScreenY + ubLineCnt * GetFontHeight( MapMineLabelsFont ) , wString ); + ++ubLineCnt; + } + } } SetFontDestBuffer( FRAME_BUFFER, MAP_VIEW_START_X, MAP_VIEW_START_Y, MAP_VIEW_START_X+MAP_VIEW_WIDTH+MAP_GRID_X, MAP_VIEW_START_Y+MAP_VIEW_HEIGHT+7, FALSE ); diff --git a/Strategic/Map Screen Interface.h b/Strategic/Map Screen Interface.h index 9bdaae7a..aea5e72c 100644 --- a/Strategic/Map Screen Interface.h +++ b/Strategic/Map Screen Interface.h @@ -177,6 +177,7 @@ enum { TRAIN_MENU_SELF, TRAIN_MENU_TOWN, TRAIN_MENU_MOBILE, + TRAIN_MENU_WORKERS, TRAIN_MENU_TEAMMATES, TRAIN_MENU_TRAIN_BY_OTHER, TRAIN_MENU_CANCEL, diff --git a/Strategic/Player Command.cpp b/Strategic/Player Command.cpp index 9a714639..51cd1fa9 100644 --- a/Strategic/Player Command.cpp +++ b/Strategic/Player Command.cpp @@ -178,6 +178,8 @@ void AddFacilitiesToBox( INT16 sMapX, INT16 sMapY, UINT32 *uiHandle, BOOLEAN fCi return; } +// Flugente: external sector data +extern SECTOR_EXT_DATA SectorExternalData[256][4]; // ALL changes of control to player must be funneled through here! BOOLEAN SetThisSectorAsPlayerControlled( INT16 sMapX, INT16 sMapY, INT8 bMapZ, BOOLEAN fContested ) @@ -401,6 +403,9 @@ BOOLEAN SetThisSectorAsPlayerControlled( INT16 sMapX, INT16 sMapY, INT8 bMapZ, B AddVolunteers( loyalpopulation * gGameExternalOptions.dMilitiaVolunteerGainFactorLiberation ); } + + // Flugente: workforce + SectorInfo[SECTOR( sMapX, sMapY )].usWorkers = SectorExternalData[SECTOR( sMapX, sMapY )][0].maxworkers * gGameExternalOptions.dInitialWorkerRate; } // Flugente: if we take the surface sector for the first time, script-defined actions might happen diff --git a/Strategic/Strategic Mines.cpp b/Strategic/Strategic Mines.cpp index e2d7c855..f4096cb1 100644 --- a/Strategic/Strategic Mines.cpp +++ b/Strategic/Strategic Mines.cpp @@ -535,6 +535,19 @@ INT32 GetAvailableWorkForceForMineForPlayer( INT8 bMineIndex ) iWorkForceSize *= GetTownSectorsUnderControl( bTownId ); iWorkForceSize /= GetTownSectorSize( bTownId ); + // Flugente: workforce + if ( gGameExternalOptions.fMineRequiresWorkers ) + { + UINT16 maxworkforce = 0; + UINT16 workforce = GetTownWorkers( bTownId, maxworkforce); + + if ( maxworkforce > 0 ) + { + iWorkForceSize *= workforce; + iWorkForceSize /= maxworkforce; + } + } + return ( iWorkForceSize ); } diff --git a/Strategic/XML_SectorNames.cpp b/Strategic/XML_SectorNames.cpp index 287e2715..f57231a2 100644 --- a/Strategic/XML_SectorNames.cpp +++ b/Strategic/XML_SectorNames.cpp @@ -97,7 +97,8 @@ SectorNameStartElementHandle(void *userData, const XML_Char *name, const char ** strcmp(name, "rainchance" ) == 0 || strcmp(name, "sandstormchance") == 0 || strcmp(name, "snowchance" ) == 0 || - strcmp(name, "snakechance" ) == 0 )) + strcmp(name, "snakechance" ) == 0 || + strcmp(name, "maxworkers" ) == 0 )) { pData->curElement = ELEMENT_PROPERTY; @@ -218,6 +219,11 @@ SectorNameEndElementHandle(void *userData, const XML_Char *name) SectorExternalData[ubSectorId][1].snakechance = 0; SectorExternalData[ubSectorId][2].snakechance = 0; SectorExternalData[ubSectorId][3].snakechance = 0; + + SectorExternalData[ubSectorId][0].maxworkers = pData->sectordata.maxworkers; + SectorExternalData[ubSectorId][1].maxworkers = 0; + SectorExternalData[ubSectorId][2].maxworkers = 0; + SectorExternalData[ubSectorId][3].maxworkers = 0; if ( !prisonroomvector.empty( ) ) { @@ -241,6 +247,7 @@ SectorNameEndElementHandle(void *userData, const XML_Char *name) pData->sectordata.sandstormchance = 0; pData->sectordata.snowchance = 0; pData->sectordata.snakechance = 0; + pData->sectordata.maxworkers = 0; } else { @@ -305,7 +312,6 @@ SectorNameEndElementHandle(void *userData, const XML_Char *name) pData->curElement = ELEMENT; pData->sectordata.usWaterType = (UINT8)atol( pData->szCharData ); } - else if(strcmp(name, "usNaturalDirt") == 0) { pData->curElement = ELEMENT; @@ -355,6 +361,11 @@ SectorNameEndElementHandle(void *userData, const XML_Char *name) pData->curElement = ELEMENT; pData->sectordata.snakechance = min( 100, (UINT8)atoi( pData->szCharData ) ); } + else if ( strcmp( name, "maxworkers" ) == 0 ) + { + pData->curElement = ELEMENT; + pData->sectordata.maxworkers = (UINT8)atoi( pData->szCharData ); + } pData->maxReadDepth--; } diff --git a/Strategic/strategicmap.cpp b/Strategic/strategicmap.cpp index 5b512f90..21f84271 100644 --- a/Strategic/strategicmap.cpp +++ b/Strategic/strategicmap.cpp @@ -1882,6 +1882,86 @@ UINT8 GetTownSectorsUnderControl( INT8 bTownId ) return(ubSectorsControlled); } +// Flugente: external sector data +extern SECTOR_EXT_DATA SectorExternalData[256][4]; + + +UINT16 GetTownWorkers(INT8 bTownId, UINT16& arusMax) +{ + arusMax = 0; + + UINT16 workerspresent = 0; + + for ( UINT8 sX = 1; sX < MAP_WORLD_X - 1; ++sX ) + { + for ( UINT8 sY = 1; sY < MAP_WORLD_X - 1; ++sY ) + { + UINT16 strategicsector = CALCULATE_STRATEGIC_INDEX( sX, sY ); + + if ( StrategicMap[strategicsector].bNameId == bTownId ) + { + // if we check for the player team, we look for sectors free of the enemy + if ( StrategicMap[strategicsector].fEnemyControlled ) + continue; + + UINT8 sector = SECTOR( sX, sY ); + SECTORINFO *pSectorInfo = &(SectorInfo[sector]); + + if ( !pSectorInfo ) + continue; + + workerspresent += pSectorInfo->usWorkers; + + arusMax += SectorExternalData[sector][0].maxworkers; + } + } + } + + return workerspresent; +} + +void AddTownWorkers( INT8 bTownId, INT16 asAdd ) +{ + for ( UINT8 sX = 1; sX < MAP_WORLD_X - 1; ++sX ) + { + for ( UINT8 sY = 1; sY < MAP_WORLD_X - 1; ++sY ) + { + UINT16 strategicsector = CALCULATE_STRATEGIC_INDEX( sX, sY ); + + if ( StrategicMap[strategicsector].bNameId == bTownId ) + { + // if we check for the player team, we look for sectors free of the enemy + if ( StrategicMap[strategicsector].fEnemyControlled ) + continue; + + UINT8 sector = SECTOR( sX, sY ); + SECTORINFO *pSectorInfo = &(SectorInfo[sector]); + + if ( !pSectorInfo ) + continue; + + if ( asAdd > 0 ) + { + UINT16 add = min( asAdd, SectorExternalData[sector][0].maxworkers - pSectorInfo->usWorkers ); + + asAdd -= add; + pSectorInfo->usWorkers += add; + } + else if ( asAdd < 0 ) + { + UINT16 remove = min( -asAdd, pSectorInfo->usWorkers ); + + asAdd += remove; + pSectorInfo->usWorkers -= remove; + } + + if ( !asAdd ) + return; + } + } + } +} + void InitializeSAMSites( void ) { // move the landing zone over to Omerta @@ -5390,6 +5470,12 @@ BOOLEAN LoadStrategicInfoFromSavedFile( HWFILE hFile ) SectorInfo[sectorID].ubNumTanks = SectorInfo[sectorID].uiInterrogationHundredsLeft[PRISONER_GENERAL]; SectorInfo[sectorID].ubTanksInBattle = SectorInfo[sectorID].uiInterrogationHundredsLeft[PRISONER_CIVILIAN]; } + + if ( guiCurrentSaveGameVersion < WORKERS ) + { + SectorInfo[sectorID].usWorkers = 0; + SectorInfo[sectorID].ubWorkerTrainingHundredths = 0; + } } // uiSize = sizeof( SECTORINFO ) * 256; diff --git a/Strategic/strategicmap.h b/Strategic/strategicmap.h index a2b0ad72..7f78ad7f 100644 --- a/Strategic/strategicmap.h +++ b/Strategic/strategicmap.h @@ -132,6 +132,9 @@ UINT8 GetTownSectorSize( INT8 bTownId ); // get town sector size, that is under play control UINT8 GetTownSectorsUnderControl( INT8 bTownId ); +UINT16 GetTownWorkers(INT8 bTownId, UINT16& arusMax); +void AddTownWorkers( INT8 bTownId, INT16 asAdd ); + // is this sector part of this town BOOLEAN SectorIsPartOfTown( INT8 bTownId, INT16 sSectorX, INT16 sSectorY ); diff --git a/Tactical/Campaign.cpp b/Tactical/Campaign.cpp index 3546fcae..f30e4838 100644 --- a/Tactical/Campaign.cpp +++ b/Tactical/Campaign.cpp @@ -711,7 +711,8 @@ void ChangeStat( MERCPROFILESTRUCT *pProfile, SOLDIERTYPE *pSoldier, UINT8 ubSta //Madd: option to make mercs quiet during training / doctoring / repairing if ( ((pSoldier->bAssignment == TRAIN_BY_OTHER || pSoldier->bAssignment == TRAIN_TEAMMATE || pSoldier->bAssignment == TRAIN_SELF || - pSoldier->bAssignment == FACILITY_STAFF || pSoldier->bAssignment == TRAIN_TOWN || pSoldier->bAssignment == TRAIN_MOBILE ) + pSoldier->bAssignment == FACILITY_STAFF || pSoldier->bAssignment == TRAIN_TOWN || pSoldier->bAssignment == TRAIN_MOBILE + || pSoldier->bAssignment == TRAIN_WORKERS ) && !gGameSettings.fOptions[TOPTION_QUIET_TRAINING]) || (IS_REPAIR(pSoldier->bAssignment) && !gGameSettings.fOptions[TOPTION_QUIET_REPAIRING]) || (IS_DOCTOR(pSoldier->bAssignment) && !gGameSettings.fOptions[TOPTION_QUIET_DOCTORING])) diff --git a/Tactical/Faces.cpp b/Tactical/Faces.cpp index ea4da37e..d968e454 100644 --- a/Tactical/Faces.cpp +++ b/Tactical/Faces.cpp @@ -2285,6 +2285,7 @@ void HandleRenderFaceAdjustments( FACETYPE *pFace, BOOLEAN fDisplayBuffer, BOOLE case TRAIN_MOBILE: case TRAIN_TEAMMATE: case TRAIN_BY_OTHER: + case TRAIN_WORKERS: sIconIndex_Assignment = 3; fDoIcon_Assignment = TRUE; fShowNumber = TRUE; @@ -2308,6 +2309,10 @@ void HandleRenderFaceAdjustments( FACETYPE *pFace, BOOLEAN fDisplayBuffer, BOOLE case( TRAIN_TEAMMATE ): sPtsAvailable = GetBonusTrainingPtsDueToInstructor( MercPtrs[ pFace->ubSoldierID ], NULL , MercPtrs[ pFace->ubSoldierID ]->bTrainStat, &usMaximumPts ); break; + case TRAIN_WORKERS: + fShowMaximum = FALSE; + sPtsAvailable = GetTrainWorkerPts(MercPtrs[ pFace->ubSoldierID ]); + break; } break; @@ -2345,7 +2350,7 @@ void HandleRenderFaceAdjustments( FACETYPE *pFace, BOOLEAN fDisplayBuffer, BOOLE fShowMaximum = TRUE; } break; - + case FACILITY_INTERROGATE_PRISONERS: sIconIndex_Assignment = 13; fDoIcon_Assignment = TRUE; diff --git a/Tactical/Items.h b/Tactical/Items.h index cec39339..5af95d19 100644 --- a/Tactical/Items.h +++ b/Tactical/Items.h @@ -509,7 +509,9 @@ typedef struct UINT8 sandstormchance; // chance that a sandstorm happens in this sector UINT8 snowchance; // chance that it snows in this sector - UINT8 snakechance; // if positive, snakes can attack in water, the higher the number, the more often it happens + UINT8 snakechance; // if positive, snakes can attack in water, the higher the number, the more often it happens + + UINT8 maxworkers; // maximum number of workers in this sector; } SECTOR_EXT_DATA; diff --git a/Utils/_ChineseText.cpp b/Utils/_ChineseText.cpp index 05444ecb..7aad79b8 100644 --- a/Utils/_ChineseText.cpp +++ b/Utils/_ChineseText.cpp @@ -2465,6 +2465,7 @@ STR16 pAssignmentStrings[] = L"病人", // getting medical aid L"修理", // repairing L"Fortify", // build structures according to external layout // TODO.Translate + L"Train W.", }; @@ -2567,6 +2568,7 @@ STR16 pPersonnelAssignmentStrings[] = L"病人", L"修理", L"Fortify sector", // build structures according to external layout // TODO.Translate + L"Train workers", }; @@ -2628,6 +2630,7 @@ STR16 pLongAssignmentStrings[] = L"病人", L"修理", L"Fortify sector", // build structures according to external layout // TODO.Translate + L"Train workers", }; @@ -2950,6 +2953,7 @@ STR16 pTrainingMenuStrings[] = L"锻炼", // train yourself L"民兵", // train the town L"游击队", // L"Mobile Militia", //ham3.6 + L"Train workers", // TODO.Translate L"教练", // train your teammates L"学员", // be trained by an instructor L"取消", // cancel this menu @@ -4535,6 +4539,7 @@ STR16 pTransactionText[] = L"记录捐款费", //L"WHO data subscription", // Flugente: disease L"Kerberus安保公司的费用", //L"Payment to Kerberus",  // Flugente: PMC L"SAM site repair", // Flugente: SAM repair // TODO.Translate + L"Trained workers", // Flugente: train workers }; STR16 pTransactionAlternateText[] = diff --git a/Utils/_DutchText.cpp b/Utils/_DutchText.cpp index f36586f1..2cc381a4 100644 --- a/Utils/_DutchText.cpp +++ b/Utils/_DutchText.cpp @@ -2463,6 +2463,7 @@ STR16 pAssignmentStrings[] = L"Patiënt", // getting medical aid L"Repareer", // repairing L"Fortify", // build structures according to external layout // TODO.Translate + L"Train W.", }; @@ -2565,6 +2566,7 @@ STR16 pPersonnelAssignmentStrings[] = L"Patiënt", // getting medical aid L"Repareer", // repairing L"Fortify sector", // build structures according to external layout // TODO.Translate + L"Train workers", }; @@ -2626,6 +2628,7 @@ STR16 pLongAssignmentStrings[] = L"Patiënt", // getting medical aid L"Repareer", // repairing L"Fortify sector", // build structures according to external layout // TODO.Translate + L"Train workers", }; @@ -2949,6 +2952,7 @@ STR16 pTrainingMenuStrings[] = L"Oefenen", // train yourself L"Militie", // train the town L"Mobile Militia", // TODO.Translate + L"Train workers", // TODO.Translate L"Trainer", // train your teammates L"Student", // be trained by an instructor L"Stop", // cancel this menu @@ -4536,6 +4540,7 @@ STR16 pTransactionText[] = L"WHO data subscription", // Flugente: disease TODO.Translate L"Payment to Kerberus", // Flugente: PMC L"SAM site repair", // Flugente: SAM repair // TODO.Translate + L"Trained workers", // Flugente: train workers }; STR16 pTransactionAlternateText[] = diff --git a/Utils/_EnglishText.cpp b/Utils/_EnglishText.cpp index 27f8a28f..cf968aa3 100644 --- a/Utils/_EnglishText.cpp +++ b/Utils/_EnglishText.cpp @@ -2464,6 +2464,7 @@ STR16 pAssignmentStrings[] = L"Patient", // getting medical aid L"Repair", // repairing L"Fortify", // build structures according to external layout + L"Train W.", }; @@ -2566,6 +2567,7 @@ STR16 pPersonnelAssignmentStrings[] = L"Patient", L"Repair", L"Fortify sector", // build structures according to external layout + L"Train workers", }; @@ -2627,6 +2629,7 @@ STR16 pLongAssignmentStrings[] = L"Patient", L"Repair", L"Fortify sector", // build structures according to external layout + L"Train workers", }; @@ -2948,6 +2951,7 @@ STR16 pTrainingMenuStrings[] = L"Practice", // train yourself L"Militia", // train the town L"Mobile Militia", + L"Train workers", L"Trainer", // train your teammates L"Student", // be trained by an instructor L"Cancel", // cancel this menu @@ -4532,6 +4536,7 @@ STR16 pTransactionText[] = L"WHO data subscription", // Flugente: disease L"Payment to Kerberus", // Flugente: PMC L"SAM site repair", // Flugente: SAM repair + L"Trained workers", // Flugente: train workers }; STR16 pTransactionAlternateText[] = diff --git a/Utils/_FrenchText.cpp b/Utils/_FrenchText.cpp index 3cad96ed..6d404301 100644 --- a/Utils/_FrenchText.cpp +++ b/Utils/_FrenchText.cpp @@ -2472,6 +2472,7 @@ STR16 pAssignmentStrings[] = L"Patient(e)", // getting medical aid L"Réparat.", // repairing L"Fortify", // build structures according to external layout // TODO.Translate + L"Train W.", }; @@ -2574,6 +2575,7 @@ STR16 pPersonnelAssignmentStrings[] = L"Patient", L"Réparation", L"Fortify sector", // build structures according to external layout // TODO.Translate + L"Train workers", }; @@ -2635,6 +2637,7 @@ STR16 pLongAssignmentStrings[] = L"Patient", L"Réparation", L"Fortify sector", // build structures according to external layout // TODO.Translate + L"Train workers", }; @@ -2956,6 +2959,7 @@ STR16 pTrainingMenuStrings[] = L"Formation", // train yourself L"Milice", // train the town L"Milice mobile", + L"Train workers", // TODO.Translate L"Entraîneur", // train your teammates L"Élève", // be trained by an instructor L"Annuler", // cancel this menu @@ -4540,6 +4544,7 @@ STR16 pTransactionText[] = L"WHO data subscription", // Flugente: disease TODO.Translate L"Payment to Kerberus", // Flugente: PMC L"SAM site repair", // Flugente: SAM repair // TODO.Translate + L"Trained workers", // Flugente: train workers }; STR16 pTransactionAlternateText[] = diff --git a/Utils/_GermanText.cpp b/Utils/_GermanText.cpp index 0e8d8181..cbb5bf30 100644 --- a/Utils/_GermanText.cpp +++ b/Utils/_GermanText.cpp @@ -2477,6 +2477,7 @@ STR16 pAssignmentStrings[] = L"Patient", // getting medical aid L"Repar.", // repairing L"Fortify", // build structures according to external layout // TODO.Translate + L"Train W.", }; STR16 pMilitiaString[] = @@ -2575,6 +2576,7 @@ STR16 pPersonnelAssignmentStrings[] = L"Patient", L"Reparieren", L"Fortify sector", // build structures according to external layout // TODO.Translate + L"Train workers", }; // refer to above for comments @@ -2634,6 +2636,7 @@ STR16 pLongAssignmentStrings[] = L"Patient", L"Reparieren", L"Fortify sector", // build structures according to external layout // TODO.Translate + L"Train workers", }; // the contract options @@ -2952,6 +2955,7 @@ STR16 pTrainingMenuStrings[] = L"Üben", // train yourself L"Miliz", // train the town L"Mobile Miliz", + L"Train workers", // TODO.Translate L"Trainer", // train your teammates L"Rekrut", // be trained by an instructor L"Abbrechen", // cancel this menu @@ -4512,6 +4516,7 @@ STR16 pTransactionText[] = L"WHO data subscription", // Flugente: disease TODO.Translate L"Payment to Kerberus", // Flugente: PMC L"SAM site repair", // Flugente: SAM repair // TODO.Translate + L"Trained workers", // Flugente: train workers }; STR16 pTransactionAlternateText[] = diff --git a/Utils/_ItalianText.cpp b/Utils/_ItalianText.cpp index d931db9e..da22144c 100644 --- a/Utils/_ItalianText.cpp +++ b/Utils/_ItalianText.cpp @@ -2458,6 +2458,7 @@ STR16 pAssignmentStrings[] = L"Paziente", // getting medical aid L"Riparare", // repairing L"Fortify", // build structures according to external layout // TODO.Translate + L"Train W.", }; @@ -2560,6 +2561,7 @@ STR16 pPersonnelAssignmentStrings[] = L"Paziente", L"Riparare", L"Fortify sector", // build structures according to external layout // TODO.Translate + L"Train workers", }; @@ -2621,6 +2623,7 @@ STR16 pLongAssignmentStrings[] = L"Paziente", L"Ripara", L"Fortify sector", // build structures according to external layout // TODO.Translate + L"Train workers", }; @@ -2944,6 +2947,7 @@ STR16 pTrainingMenuStrings[] = L"Allenati", // train yourself L"Esercito", // train the town L"Mobile Militia", // TODO.Translate + L"Train workers", // TODO.Translate L"Allenatore", // train your teammates L"Studente", // be trained by an instructor L"Annulla", // cancel this menu @@ -4530,6 +4534,7 @@ STR16 pTransactionText[] = L"WHO data subscription", // Flugente: disease TODO.Translate L"Payment to Kerberus", // Flugente: PMC L"SAM site repair", // Flugente: SAM repair // TODO.Translate + L"Trained workers", // Flugente: train workers }; STR16 pTransactionAlternateText[] = diff --git a/Utils/_PolishText.cpp b/Utils/_PolishText.cpp index e534f334..bf68eaa3 100644 --- a/Utils/_PolishText.cpp +++ b/Utils/_PolishText.cpp @@ -2470,6 +2470,7 @@ STR16 pAssignmentStrings[] = L"Pacjent", // getting medical aid L"Naprawa", // repairing L"Fortify", // build structures according to external layout // TODO.Translate + L"Train W.", }; @@ -2572,6 +2573,7 @@ STR16 pPersonnelAssignmentStrings[] = L"Pacjent", L"Naprawa", L"Fortify sector", // build structures according to external layout // TODO.Translate + L"Train workers", }; @@ -2633,6 +2635,7 @@ STR16 pLongAssignmentStrings[] = L"Pacjent", L"Naprawa", L"Fortify sector", // build structures according to external layout // TODO.Translate + L"Train workers", }; @@ -2954,6 +2957,7 @@ STR16 pTrainingMenuStrings[] = L"Praktyka", // train yourself L"Samoobrona", // train the town L"Mobile Militia", // TODO.Translate + L"Train workers", // TODO.Translate L"Instruktor", // train your teammates L"Uczeń", // be trained by an instructor L"Anuluj", // cancel this menu @@ -4541,6 +4545,7 @@ STR16 pTransactionText[] = L"WHO data subscription", // Flugente: disease TODO.Translate L"Payment to Kerberus", // Flugente: PMC L"SAM site repair", // Flugente: SAM repair // TODO.Translate + L"Trained workers", // Flugente: train workers }; STR16 pTransactionAlternateText[] = diff --git a/Utils/_RussianText.cpp b/Utils/_RussianText.cpp index 4b798d94..e31c86dc 100644 --- a/Utils/_RussianText.cpp +++ b/Utils/_RussianText.cpp @@ -2464,6 +2464,7 @@ STR16 pAssignmentStrings[] = L"Пациент", // getting medical aid L"Ремонт", // repairing L"Fortify", // build structures according to external layout // TODO.Translate + L"Train W.", }; @@ -2566,6 +2567,7 @@ STR16 pPersonnelAssignmentStrings[] = L"Пациент", L"Ремонт", L"Fortify sector", // build structures according to external layout // TODO.Translate + L"Train workers", }; @@ -2627,6 +2629,7 @@ STR16 pLongAssignmentStrings[] = L"Пациент", L"Ремонтирует", L"Fortify sector", // build structures according to external layout // TODO.Translate + L"Train workers", }; @@ -2948,6 +2951,7 @@ STR16 pTrainingMenuStrings[] = L"Практика", // train yourself L"Ополчение", // train the town L"Патрульные", + L"Train workers", // TODO.Translate L"Тренер", // train your teammates L"Ученик", // be trained by an instructor L"Отмена", // cancel this menu @@ -4532,6 +4536,7 @@ STR16 pTransactionText[] = L"ВОЗ, подписка", // Flugente: disease L"Оплата услуг Цербер", // Flugente: PMC L"Стоимость ремонта базы ПВО", // Flugente: SAM repair + L"Trained workers", // Flugente: train workers // TODO.Translate }; STR16 pTransactionAlternateText[] =