Files
source/Strategic/Facilities.cpp
T
Wanne f010769397 *************************
* HAM 3.6 (by Headrock) *
*************************
- Info: Needed GameDir files for HAM 3.6 are not committed yet to the SVN GameDir. Will do that in the next few days
- For more infos on HAM 3.6 check out: http://www.ja-galaxy-forum.com/board/ubbthreads.php?ubb=showflat&Number=244808&page=0&fpart=1


git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@3323 3b4a5df2-a311-0410-b5c6-a8a6f20db521
2010-02-20 15:49:46 +00:00

1734 lines
66 KiB
C++

//////////////////////////////////////////////////////////////////
// HEADROCK HAM 3.5: Facilities
//
// This file contains functions that test facility data (read
// from XML) whenever necessary. See XML_Facilities.cpp and
// XML_FacilityTypes.cpp for the reading XML functions.
//////////////////////////////////////////////////////////////////
#include "builddefines.h"
#ifdef PRECOMPILEDHEADERS
#include "Strategic All.h"
#include "GameSettings.h"
#else
#include "Campaign Types.h"
#include "Facilities.h"
#include "Soldier Control.h"
#include "Map Screen Interface.h"
#include "Overhead.h"
#include "Assignments.h"
#include "GameSettings.h"
#include "LaptopSave.h"
#include "finances.h"
#include "Text.h"
#include "Strategic Town Loyalty.h"
#include "Strategic Mines.h"
#include "SkillCheck.h"
#include "Random.h"
#include "strategicmap.h"
#include "Game Clock.h"
#include "Campaign.h"
#include "Drugs And Alcohol.cpp"
#include "Soldier Control.cpp"
#include "MilitiaSquads.h"
#include "Tactical Save.h"
#endif
INT16 gsSkyriderCostModifier;
// HEADROCK HAM 3.6: Strategic info variable, total of costs accumulated for the use of facilities today. Deducted
// from account and reset at midnight, unless player can't pay (in which case, carries over to the next day).
// This variable is SAVED and LOADED.
INT32 giTotalOwedForFacilityOperationsToday = 0;
BOOLEAN gfOutstandingFacilityDebt = TRUE;
// This function returns a specific modifier out of the FacilityTypes array. Modifiers exist inside an assignment
// sub-array, so the final result depends on the assignment the soldier is performing. The difference between
// this and simply reading data from the facility array is that in this case, "AMBIENT" effects are also included,
// which take effect regardless of the assignment.
INT16 GetFacilityModifier( UINT8 ubModifierType, UINT8 ubFacilityType, UINT8 ubAssignmentType )
{
INT16 sAssignmentModifier;
INT16 sAmbientModifier;
// Are we checking an actual assignment at a specific facility?
if (ubAssignmentType != FAC_AMBIENT &&
ubFacilityType > 0 )
{
switch (ubModifierType)
{
case FACILITY_PERFORMANCE_MOD:
sAssignmentModifier = gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].usPerformance;
sAmbientModifier = gFacilityTypes[ubFacilityType].AssignmentData[0].usPerformance;
sAssignmentModifier = 100 + ((sAssignmentModifier-100) + (sAmbientModifier-100));
return (sAssignmentModifier);
case FACILITY_FATIGUE_MOD:
sAssignmentModifier = gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].usFatigue;
sAmbientModifier = gFacilityTypes[ubFacilityType].AssignmentData[0].usFatigue;
sAssignmentModifier = 100 + ((sAssignmentModifier-100) + (sAmbientModifier-100));
return (sAssignmentModifier);
case FACILITY_SLEEP_MOD:
sAssignmentModifier = gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].usSleep;
sAmbientModifier = gFacilityTypes[ubFacilityType].AssignmentData[0].usSleep;
sAssignmentModifier = 100 + ((sAssignmentModifier-100) + (sAmbientModifier-100));
return (sAssignmentModifier);
case FACILITY_KIT_DEGRADE_MOD:
sAssignmentModifier = gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].usKitDegrade;
sAmbientModifier = gFacilityTypes[ubFacilityType].AssignmentData[0].usKitDegrade;
sAssignmentModifier = 100 + ((sAssignmentModifier-100) + (sAmbientModifier-100));
return (sAssignmentModifier);
case FACILITY_MAX_MORALE:
sAssignmentModifier = gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].ubMaximumMorale;
sAmbientModifier = gFacilityTypes[ubFacilityType].AssignmentData[0].ubMaximumMorale;
sAssignmentModifier = __min(sAssignmentModifier, sAmbientModifier);
return (sAssignmentModifier);
case FACILITY_MAX_BREATH:
sAssignmentModifier = gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].ubMaximumBreath;
sAmbientModifier = gFacilityTypes[ubFacilityType].AssignmentData[0].ubMaximumBreath;
sAssignmentModifier = __min(sAssignmentModifier, sAmbientModifier);
return (sAssignmentModifier);
case FACILITY_DETECT_IMMEDIATE:
sAssignmentModifier = gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].ubDetectEnemiesImmediate;
sAmbientModifier = gFacilityTypes[ubFacilityType].AssignmentData[0].ubDetectEnemiesImmediate;
sAssignmentModifier = __max(sAssignmentModifier, sAmbientModifier);
return (sAssignmentModifier);
case FACILITY_DETECT_DYNAMIC:
sAssignmentModifier = gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].fDetectEnemiesDynamic;
sAmbientModifier = gFacilityTypes[ubFacilityType].AssignmentData[0].fDetectEnemiesDynamic;
sAssignmentModifier = __max(sAssignmentModifier, sAmbientModifier);
return (sAssignmentModifier);
case FACILITY_DETECT_LONGRANGE:
sAssignmentModifier = gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].fDetectEnemiesLongrange;
sAmbientModifier = gFacilityTypes[ubFacilityType].AssignmentData[0].fDetectEnemiesLongrange;
sAssignmentModifier = __max(sAssignmentModifier, sAmbientModifier);
return (sAssignmentModifier);
case FACILITY_DETECT_ANYWHERE:
sAssignmentModifier = gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].fDetectEnemiesAnywhere;
sAmbientModifier = gFacilityTypes[ubFacilityType].AssignmentData[0].fDetectEnemiesAnywhere;
sAssignmentModifier = __max(sAssignmentModifier, sAmbientModifier);
return (sAssignmentModifier);
case FACILITY_COUNT_INWILD:
sAssignmentModifier = gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].fCountEnemiesInWild;
sAmbientModifier = gFacilityTypes[ubFacilityType].AssignmentData[0].fCountEnemiesInWild;
sAssignmentModifier = __max(sAssignmentModifier, sAmbientModifier);
return (sAssignmentModifier);
case FACILITY_COUNT_INCITIES:
sAssignmentModifier = gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].fCountEnemiesInCities;
sAmbientModifier = gFacilityTypes[ubFacilityType].AssignmentData[0].fCountEnemiesInCities;
sAssignmentModifier = __max(sAssignmentModifier, sAmbientModifier);
return (sAssignmentModifier);
case FACILITY_SKYRIDER_COST_MOD:
sAssignmentModifier = gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].sSkyriderCostModifier;
sAmbientModifier = gFacilityTypes[ubFacilityType].AssignmentData[0].sSkyriderCostModifier;
sAssignmentModifier = sAssignmentModifier + sAmbientModifier;
return (sAssignmentModifier);
case FACILITY_MINE_INCOME_MOD:
sAssignmentModifier = gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].usMineIncomeModifier;
sAmbientModifier = gFacilityTypes[ubFacilityType].AssignmentData[0].usMineIncomeModifier;
sAssignmentModifier = 100 + ((sAssignmentModifier-100) + (sAmbientModifier-100));
return (sAssignmentModifier);
default:
return (0);
}
}
// Only ambient effect please
else
{
switch (ubModifierType)
{
case FACILITY_PERFORMANCE_MOD:
sAmbientModifier = gFacilityTypes[ubFacilityType].AssignmentData[0].usPerformance;
return (sAmbientModifier);
case FACILITY_FATIGUE_MOD:
sAmbientModifier = gFacilityTypes[ubFacilityType].AssignmentData[0].usFatigue;
return (sAmbientModifier);
case FACILITY_SLEEP_MOD:
sAmbientModifier = gFacilityTypes[ubFacilityType].AssignmentData[0].usSleep;
return (sAmbientModifier);
case FACILITY_KIT_DEGRADE_MOD:
sAmbientModifier = gFacilityTypes[ubFacilityType].AssignmentData[0].usKitDegrade;
return (sAmbientModifier);
case FACILITY_MAX_MORALE:
sAmbientModifier = gFacilityTypes[ubFacilityType].AssignmentData[0].ubMaximumMorale;
return (sAmbientModifier);
case FACILITY_MAX_BREATH:
sAmbientModifier = gFacilityTypes[ubFacilityType].AssignmentData[0].ubMaximumBreath;
return (sAmbientModifier);
case FACILITY_DETECT_IMMEDIATE:
sAmbientModifier = gFacilityTypes[ubFacilityType].AssignmentData[0].ubDetectEnemiesImmediate;
return (sAmbientModifier);
case FACILITY_DETECT_DYNAMIC:
sAmbientModifier = gFacilityTypes[ubFacilityType].AssignmentData[0].fDetectEnemiesDynamic;
return (sAmbientModifier);
case FACILITY_DETECT_LONGRANGE:
sAmbientModifier = gFacilityTypes[ubFacilityType].AssignmentData[0].fDetectEnemiesLongrange;
return (sAmbientModifier);
case FACILITY_DETECT_ANYWHERE:
sAmbientModifier = gFacilityTypes[ubFacilityType].AssignmentData[0].fDetectEnemiesAnywhere;
return (sAmbientModifier);
case FACILITY_COUNT_INWILD:
sAmbientModifier = gFacilityTypes[ubFacilityType].AssignmentData[0].fCountEnemiesInWild;
return (sAmbientModifier);
case FACILITY_COUNT_INCITIES:
sAmbientModifier = gFacilityTypes[ubFacilityType].AssignmentData[0].fCountEnemiesInCities;
return (sAmbientModifier);
case FACILITY_SKYRIDER_COST_MOD:
sAmbientModifier = gFacilityTypes[ubFacilityType].AssignmentData[0].sSkyriderCostModifier;
return (sAmbientModifier);
case FACILITY_MINE_INCOME_MOD:
sAmbientModifier = gFacilityTypes[ubFacilityType].AssignmentData[0].usMineIncomeModifier;
return (sAmbientModifier);
default:
return (0);
}
}
}
// This is a handler function that runs through every facility in the soldier's sector, retrieving one type of
// modifier from each facility.
INT16 GetSectorModifier( SOLDIERTYPE *pSoldier, UINT8 ubModifierType )
{
INT16 sCurrent;
INT16 Result;
UINT8 ubSectorID = SECTOR(pSoldier->sSectorX, pSoldier->sSectorY);
INT8 bAssignmentType = GetSoldierFacilityAssignmentIndex(pSoldier);
// Set "default" value.
switch (ubModifierType)
{
case FACILITY_PERFORMANCE_MOD:
case FACILITY_FATIGUE_MOD:
case FACILITY_SLEEP_MOD:
case FACILITY_KIT_DEGRADE_MOD:
case FACILITY_MINE_INCOME_MOD:
Result = 100;
break;
case FACILITY_MAX_MORALE:
case FACILITY_MAX_BREATH:
Result = 100;
break;
case FACILITY_DETECT_IMMEDIATE:
case FACILITY_DETECT_DYNAMIC:
case FACILITY_DETECT_LONGRANGE:
case FACILITY_DETECT_ANYWHERE:
case FACILITY_COUNT_INWILD:
case FACILITY_COUNT_INCITIES:
Result = 0;
break;
case FACILITY_SKYRIDER_COST_MOD:
Result = 0;
break;
}
for (UINT16 cnt = 0; cnt < NUM_FACILITY_TYPES; cnt++)
{
if (gFacilityLocations[ubSectorID][cnt].fFacilityHere)
{
if ( bAssignmentType != -1)
{
// Soldier has a facility-based assignment. Is he working this type of facility?
if ((UINT8)pSoldier->sFacilityTypeOperated == (UINT8)cnt)
{
sCurrent = GetFacilityModifier( ubModifierType, (UINT8)cnt, (UINT8)bAssignmentType );
}
else // He's operating another type of facility. Get only the ambient effect.
{
sCurrent = GetFacilityModifier( ubModifierType, (UINT8)cnt, FAC_AMBIENT );
}
}
else
{
// Soldier is not doing facility-specific work. Get only the ambient effect.
sCurrent = GetFacilityModifier( ubModifierType, (UINT8)cnt, FAC_AMBIENT );
}
// Calculate overall result so far. Calculation method is based on the modifier we're looking for.
switch (ubModifierType)
{
case FACILITY_PERFORMANCE_MOD:
case FACILITY_FATIGUE_MOD:
case FACILITY_SLEEP_MOD:
case FACILITY_KIT_DEGRADE_MOD:
case FACILITY_MINE_INCOME_MOD:
Result = 100 + ((100-Result) + (100-sCurrent));
break;
case FACILITY_MAX_MORALE:
case FACILITY_MAX_BREATH:
Result = __min(Result, sCurrent);
break;
case FACILITY_DETECT_IMMEDIATE:
case FACILITY_DETECT_DYNAMIC:
case FACILITY_DETECT_LONGRANGE:
case FACILITY_DETECT_ANYWHERE:
case FACILITY_COUNT_INWILD:
case FACILITY_COUNT_INCITIES:
Result = __max(Result, sCurrent);
break;
case FACILITY_SKYRIDER_COST_MOD:
Result += sCurrent;
break;
}
}
}
return (Result);
}
//////////////////////////////////////////////////
// This function reads the status of intelligence gathering currently being done by your mercs. They work at special
// facilities that can enable enemy detection in certain sectors.
//
// There are several detection methods, and they allow/disallow detection in different groups of sectors.
// DETECT_ENEMIES_IMMEDIATE: Detection in sectors near to where the merc is working.
// DETECT_ENEMIES_DYNAMIC: Detection in sectors where Mobile Militia are allowed to roam.
// DETECT_ENEMIES_LONGRANGE: Detection in all explored sectors.
// DETECT_ENEMIES_ANYWHERE: Detect enemy units all over the map.
// Also there are two Counting methods, which allow reading the exact number of troops in specific sectors.
// COUNT_ENEMIES_IN_WILD: Can count enemy numbers in non-city sectors only.
// COUNT_ENEMIES_IN_CITIES: Can counter enemy numbers in city sectors only.
//
// This function runs through each working merc, and flags all the appropriate sectors. Later on, the program reads
// these flags when it wants to find out whether an enemy unit is visible on the map, and whether the exact number of
// enemies in that unit is also shown.
void UpdateStrategicDetectionLevel( )
{
SOLDIERTYPE * pSoldier;
UINT8 ubCounter = 0;
// Reset the detection flag in SectorInfo for all sectors.
for (UINT16 X = 0; X < 256; X++)
{
// Reset sector detection flags.
SectorInfo[X].ubDetectionLevel = 0;
}
// Flag to hold the current detection level before calculating its effects on the detection mask.
UINT8 ubStrategicDetectionLevel = 0;
// Run through list of player-characters
while(gCharactersList[ubCounter].fValid)
{
pSoldier = MercPtrs[ gCharactersList[ ubCounter ].usSolID ];
// Is character truly valid?
if( !( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) &&
pSoldier->bSectorZ == 0 &&
pSoldier->stats.bLife >= OKLIFE &&
!(pSoldier->flags.fMercAsleep) )
{
UINT8 ubSector = SECTOR(pSoldier->sSectorX, pSoldier->sSectorY);
UINT8 ubFacilityType = (UINT8)pSoldier->sFacilityTypeOperated;
if (GetSoldierFacilityAssignmentIndex( pSoldier ) == -1)
{
// Skip this soldier, he is not performing a facility assignment.
ubCounter++;
continue;
}
UINT8 ubAssignmentType = (UINT8)GetSoldierFacilityAssignmentIndex( pSoldier );
// Test to see whether the character is properly set up at this facility.
if ( CanCharacterFacility( pSoldier, ubFacilityType, ubAssignmentType ) &&
GetWorldTotalMin() - pSoldier->uiLastAssignmentChangeMin >= (UINT32)gGameExternalOptions.ubMinutesForAssignmentToCount )
{
// Make sure facility type is valid.
Assert(ubFacilityType < MAX_NUM_FACILITY_TYPES);
if (!(gFacilityLocations[ubSector][ubFacilityType].fFacilityHere))
{
// Somehow, the character is working in a nonexistant facility. Odd. Skip him.
ubCounter++;
continue;
}
/////////////////////////////////////////////////////////
// Begin testing for facility detection bonuses.
// Does game allow Dynamic Roaming Militia?
if (gGameExternalOptions.fDynamicRestrictRoaming)
{
// Does facility allow Dynamic Detection?
if (GetFacilityModifier(FACILITY_DETECT_DYNAMIC, ubFacilityType, ubAssignmentType))
{
ubStrategicDetectionLevel |= (1 << DETECT_ENEMIES_DYNAMIC);
}
}
// Does facility allow Long-Range Detection?
if (GetFacilityModifier(FACILITY_DETECT_LONGRANGE, ubFacilityType, ubAssignmentType))
{
ubStrategicDetectionLevel |= (1 << DETECT_ENEMIES_LONGRANGE);
}
// Does facility allow Omniscient Detection?
if (GetFacilityModifier(FACILITY_DETECT_ANYWHERE, ubFacilityType, ubAssignmentType))
{
ubStrategicDetectionLevel |= (1 << DETECT_ENEMIES_ANYWHERE);
}
// Does facility allow Counting Enemies in the Wilderness?
if (GetFacilityModifier(FACILITY_COUNT_INWILD, ubFacilityType, ubAssignmentType))
{
ubStrategicDetectionLevel |= (1 << COUNT_ENEMIES_IN_WILD);
}
// Does facility allow Counting Enemies in the Wilderness?
if (GetFacilityModifier(FACILITY_COUNT_INCITIES, ubFacilityType, ubAssignmentType))
{
ubStrategicDetectionLevel |= (1 << COUNT_ENEMIES_IN_CITIES);
}
// "Immediate" detection allows spotting enemies within a certain radius of the facility.
UINT16 usImmediateDetectionRange = (UINT16)GetFacilityModifier(FACILITY_DETECT_IMMEDIATE, ubFacilityType, ubAssignmentType);
if (usImmediateDetectionRange)
{
// Loop through all nearby sectors.
UINT8 sMapX;
UINT8 sMapY;
for (sMapX = pSoldier->sSectorX - usImmediateDetectionRange; sMapX <= pSoldier->sSectorX + usImmediateDetectionRange; sMapX++)
{
for (sMapY = pSoldier->sSectorY - usImmediateDetectionRange; sMapY <= pSoldier->sSectorY + usImmediateDetectionRange; sMapY++)
{
if (sMapX <= 0 || sMapX >= MAP_WORLD_X - 1 ||
sMapY <= 0 || sMapY >= MAP_WORLD_Y - 1 )
{
// Sector out of bounds.
continue;
}
if (abs(pSoldier->sSectorX - sMapX) <= usImmediateDetectionRange &&
abs(pSoldier->sSectorY - sMapY) <= usImmediateDetectionRange)
{
// Sector within range. Update its detection flag.
SectorInfo[SECTOR(sMapX, sMapY)].ubDetectionLevel |= 1;
}
}
}
}
}
}
ubCounter++;
}
// Some flags have been set. Run through all sectors and apply this.
for (UINT16 X = 0; X < 256; X++)
{
// Reset detection level first
SectorInfo[X].ubDetectionLevel = 0;
if (ubStrategicDetectionLevel & (1<<DETECT_ENEMIES_DYNAMIC))
{
// Is sector allowed for militia roaming?
if (IsSectorRoamingAllowed( X ) )
{
// Enemy is in a militia-allowed area, and is always visible.
SectorInfo[X].ubDetectionLevel |= 1;
}
}
if (ubStrategicDetectionLevel & (1<<DETECT_ENEMIES_LONGRANGE))
{
if( GetSectorFlagStatus( SECTORX(X), SECTORY(X), 0, SF_ALREADY_VISITED ) == TRUE )
{
SectorInfo[X].ubDetectionLevel |= 1;
}
}
if (ubStrategicDetectionLevel & (1<<DETECT_ENEMIES_ANYWHERE))
{
SectorInfo[X].ubDetectionLevel |= 1;
}
// ENEMY COUNTING:
if (ubStrategicDetectionLevel & (1<<COUNT_ENEMIES_IN_WILD)||
ubStrategicDetectionLevel & (1<<COUNT_ENEMIES_IN_CITIES))
{
if (GetTownIdForSector( SECTORX(X), SECTORY(X) ) == BLANK_SECTOR &&
ubStrategicDetectionLevel & (1<<COUNT_ENEMIES_IN_WILD))
{
SectorInfo[X].ubDetectionLevel |= (1<<2);
}
else if (GetTownIdForSector( SECTORX(X), SECTORY(X) ) != BLANK_SECTOR &&
ubStrategicDetectionLevel & (1<<COUNT_ENEMIES_IN_CITIES))
{
SectorInfo[X].ubDetectionLevel |= (1<<2);
}
}
}
}
// This function runs hourly and on gameload. It recalculates a modifier to Skyrider's per-sector flight costs,
// for every awake+resting character in a sector with a facility that modifies the cost.
void UpdateSkyriderCostModifier()
{
SOLDIERTYPE * pSoldier;
UINT8 ubCounter = 0;
// Start by resetting the Skyrider Cost variable.
gsSkyriderCostModifier = 0;
while(gCharactersList[ubCounter].fValid)
{
pSoldier = MercPtrs[ gCharactersList[ ubCounter ].usSolID ];
// Is character truly valid?
if( !( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) &&
pSoldier->bSectorZ == 0 &&
pSoldier->stats.bLife >= OKLIFE &&
!(pSoldier->flags.fMercAsleep) )
{
UINT8 ubSector = SECTOR(pSoldier->sSectorX, pSoldier->sSectorY);
UINT8 ubFacilityType = (UINT8)pSoldier->sFacilityTypeOperated;
if (GetSoldierFacilityAssignmentIndex( pSoldier ) == -1)
{
// Skip this soldier, he is not performing a facility assignment.
ubCounter++;
continue;
}
UINT8 ubAssignmentType = GetSoldierFacilityAssignmentIndex( pSoldier );
// Is character using a facility?
if ( CanCharacterFacility( pSoldier, ubFacilityType, ubAssignmentType ) &&
GetWorldTotalMin() - pSoldier->uiLastAssignmentChangeMin >= (UINT32)gGameExternalOptions.ubMinutesForAssignmentToCount )
{
// Make sure facility type is valid.
Assert(ubFacilityType < MAX_NUM_FACILITY_TYPES);
if (!(gFacilityLocations[ubSector][ubFacilityType].fFacilityHere))
{
// Somehow, the character is working in a nonexistant facility. Odd. Skip him.
ubCounter++;
continue;
}
// Does facility change Skyrider Costs at all?
gsSkyriderCostModifier += GetFacilityModifier( FACILITY_SKYRIDER_COST_MOD, ubFacilityType, ubAssignmentType );
}
}
ubCounter++;
}
}
// HEADROCK HAM 3.6: Goes through all characters "STAFFING" a facility, and checks to see whether they alter any
// strategic variables.
void UpdateGlobalVariablesFromFacilities( void )
{
UpdateStrategicDetectionLevel( );
UpdateSkyriderCostModifier( );
UpdateFacilityUsageCosts( );
}
// This function runs hourly. It calculates the total cost of all facilities being operated currently,
// and adds them to a global "debt" variable that tracks expenditure. At the end of the day, the debt is deducted from
// the player's account.
void UpdateFacilityUsageCosts( )
{
SOLDIERTYPE * pSoldier;
UINT8 ubCounter = 0;
INT16 sCost = 0;
while(gCharactersList[ubCounter].fValid)
{
pSoldier = MercPtrs[ gCharactersList[ ubCounter ].usSolID ];
// Is character truly valid?
if( !( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) &&
pSoldier->bSectorZ == 0 &&
pSoldier->stats.bLife >= OKLIFE &&
!(pSoldier->flags.fMercAsleep) )
{
UINT8 ubSector = SECTOR(pSoldier->sSectorX, pSoldier->sSectorY);
UINT8 ubFacilityType = (UINT8)pSoldier->sFacilityTypeOperated;
if (GetSoldierFacilityAssignmentIndex( pSoldier ) == -1)
{
// Skip this soldier, he is not performing a facility assignment.
ubCounter++;
continue;
}
UINT8 ubAssignmentType = GetSoldierFacilityAssignmentIndex( pSoldier );
// Is character using a facility?
if ( CanCharacterFacility( pSoldier, ubFacilityType, ubAssignmentType ) &&
GetWorldTotalMin() - pSoldier->uiLastAssignmentChangeMin >= (UINT32)gGameExternalOptions.ubMinutesForAssignmentToCount )
{
// Make sure facility type is valid.
Assert(ubFacilityType < MAX_NUM_FACILITY_TYPES);
if (!(gFacilityLocations[ubSector][ubFacilityType].fFacilityHere))
{
// Somehow, the character is working in a nonexistant facility. Odd. Skip him.
ubCounter++;
continue;
}
sCost = gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].sCostPerHour;
if (sCost > 0)
{
/////////////////////////////////////////////////////////
// Increase debt for operating this facility
giTotalOwedForFacilityOperationsToday += gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].sCostPerHour;
}
else if (sCost < 0)
{
/////////////////////////////////////////////////////////
// Put money directly into the player's account
LaptopSaveInfo.iCurrentBalance += (-1 * sCost);
}
}
}
ubCounter++;
}
}
// HEADROCK HAM 3.6: This function runs once at the end of each day.
// It handles debt accrued by operation facilities. If there is enough money to pay the debt off, this
// is done automatically. If only part of the money is available, or none of it, your account is emptied and all
// "expensive" facility work ends immediately. You also suffer a loyalty hit across Arulco based on how much money
// you owe. Facility work cannot continue before the debt is paid off!
void HandleDailyPaymentFacilityDebt( void )
{
CHAR16 sString[256];
INT32 iToPay = 0;
if (LaptopSaveInfo.iCurrentBalance >= giTotalOwedForFacilityOperationsToday)
{
// Pay total debt.
iToPay = giTotalOwedForFacilityOperationsToday;
gfOutstandingFacilityDebt = FALSE;
}
else if (LaptopSaveInfo.iCurrentBalance < giTotalOwedForFacilityOperationsToday)
{
if (LaptopSaveInfo.iCurrentBalance > 0)
{
// Still have some money in the bank. Pay it.
iToPay = LaptopSaveInfo.iCurrentBalance;
swprintf( sString, New113HAMMessage[14], iToPay, giTotalOwedForFacilityOperationsToday - iToPay );
DoScreenIndependantMessageBox( sString, MSG_BOX_FLAG_OK, NULL );
HandleFacilityDebtLoyaltyHit();
ResetAllExpensiveFacilityAssignments();
gfOutstandingFacilityDebt = TRUE;
}
else if (LaptopSaveInfo.iCurrentBalance <= 0)
{
// No money to pay!
iToPay = 0;
swprintf( sString, New113HAMMessage[15], giTotalOwedForFacilityOperationsToday);
DoScreenIndependantMessageBox( sString, MSG_BOX_FLAG_OK, NULL );
HandleFacilityDebtLoyaltyHit();
ResetAllExpensiveFacilityAssignments();
gfOutstandingFacilityDebt = TRUE;
}
}
if (iToPay > 0)
{
AddTransactionToPlayersBook( FACILITY_OPERATIONS, 0, GetWorldTotalMin(), -( iToPay ) );
giTotalOwedForFacilityOperationsToday -= iToPay;
}
}
// HEADROCK HAM 3.6: This functionruns a player-requested payoff of facility debt. It is only possible if the player
// has enough money in his account to pay off the ENTIRE debt. The function is called when a player tries to assign
// a merc to facility duty while an outstanding debt exists. Debts are only outstanding if they failed to be paid off
// during the previous midnight.
void HandleManualPaymentFacilityDebt( void )
{
INT32 iToPay = 0;
// Is there any debt at all?
if (giTotalOwedForFacilityOperationsToday > 0)
{
// This function should ONLY be called if there's enough money in the bank to pay off the entire debt.
Assert( LaptopSaveInfo.iCurrentBalance >= giTotalOwedForFacilityOperationsToday );
// Pay total debt.
iToPay = giTotalOwedForFacilityOperationsToday;
AddTransactionToPlayersBook( FACILITY_OPERATIONS, 0, GetWorldTotalMin(), -( iToPay ) );
giTotalOwedForFacilityOperationsToday = 0;
gfOutstandingFacilityDebt = FALSE;
}
}
// HEADROCK HAM 3.6: Apply income bonuses from Facility Work to a specific mine.
INT32 MineIncomeModifierFromFacility( UINT8 ubMine )
{
Assert (ubMine > 0 && ubMine < MAX_NUMBER_OF_MINES);
SOLDIERTYPE *pSoldier;
INT32 iModifier = 0;
UINT8 ubCounter = 0;
while (gCharactersList[ubCounter].fValid)
{
pSoldier = MercPtrs[ gCharactersList[ ubCounter ].usSolID ];
// Is character truly valid?
if( !( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) &&
pSoldier->bSectorZ == 0 &&
pSoldier->stats.bLife >= OKLIFE &&
!(pSoldier->flags.fMercAsleep) )
{
UINT8 ubSector = SECTOR(pSoldier->sSectorX, pSoldier->sSectorY);
UINT8 ubFacilityType = (UINT8)pSoldier->sFacilityTypeOperated;
if (GetSoldierFacilityAssignmentIndex( pSoldier ) == -1)
{
// Skip this soldier, he is not performing a facility assignment.
ubCounter++;
continue;
}
UINT8 ubAssignmentType = GetSoldierFacilityAssignmentIndex( pSoldier );
// Is character using a facility?
if ( CanCharacterFacility( pSoldier, ubFacilityType, ubAssignmentType ) &&
GetWorldTotalMin() - pSoldier->uiLastAssignmentChangeMin >= (UINT32)gGameExternalOptions.ubMinutesForAssignmentToCount )
{
if (GetFacilityModifier( FACILITY_MINE_INCOME_MOD, ubFacilityType, ubAssignmentType ) && // Facility adjusts mine income
(gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].fOnlyLocalMineAffected == 0 || // All mines affected
GetMineIndexForSector( pSoldier->sSectorX, pSoldier->sSectorY ) == ubMine ) ) // This mine is here
{
iModifier += (gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].usMineIncomeModifier - 100);
}
}
}
ubCounter++;
}
return iModifier;
}
// This function converts a soldier's current assignment into a single Facility Assignment Type Index.
// The Assignment Type Index is used for referencing various data and effects associated with performing a
// SPECIFIC assignment with the help of a SPECIFIC facility. It's basically a reference number for the gFacilityTypes
// array.
INT8 GetSoldierFacilityAssignmentIndex( SOLDIERTYPE *pSoldier )
{
// Read soldier's assignment
INT8 bAssignment = pSoldier->bAssignment;
INT8 bAssignmentIndex = -1; // Return variable. -1 = Non-facility assignment.
if (bAssignment <= ON_DUTY ||
bAssignment == PATIENT ||
bAssignment == VEHICLE ||
bAssignment == IN_TRANSIT ||
bAssignment == TRAIN_TOWN ||
bAssignment == TRAIN_MOBILE ||
bAssignment > FACILITY_REST )
{
// Soldier is performing a distinctly NON-FACILITY assignment.
return (-1);
}
if (pSoldier->sFacilityTypeOperated == -1)
{
// Soldier is not set to work at a facility...
return (-1);
}
switch (bAssignment)
{
case DOCTOR:
bAssignmentIndex = FAC_DOCTOR;
break;
case PATIENT:
bAssignmentIndex = FAC_PATIENT;
break;
case REPAIR:
// Determine which kind of repair is he performing
if ( pSoldier->bVehicleUnderRepairID != -1 )
{
bAssignmentIndex = FAC_REPAIR_VEHICLE;
}
else if ( pSoldier->flags.fFixingRobot )
{
bAssignmentIndex = FAC_REPAIR_ROBOT;
}
else
{
bAssignmentIndex = FAC_REPAIR_ITEMS;
}
break;
case TRAIN_SELF:
switch (pSoldier->bTrainStat)
{
case STRENGTH:
bAssignmentIndex = FAC_PRACTICE_STRENGTH;
break;
case DEXTERITY:
bAssignmentIndex = FAC_PRACTICE_DEXTERITY;
break;
case AGILITY:
bAssignmentIndex = FAC_PRACTICE_AGILITY;
break;
case HEALTH:
bAssignmentIndex = FAC_PRACTICE_HEALTH;
break;
case MARKSMANSHIP:
bAssignmentIndex = FAC_PRACTICE_MARKSMANSHIP;
break;
case MEDICAL:
bAssignmentIndex = FAC_PRACTICE_MEDICAL;
break;
case MECHANICAL:
bAssignmentIndex = FAC_PRACTICE_MECHANICAL;
break;
case LEADERSHIP:
bAssignmentIndex = FAC_PRACTICE_LEADERSHIP;
break;
case EXPLOSIVE_ASSIGN:
bAssignmentIndex = FAC_PRACTICE_EXPLOSIVES;
break;
}
break;
case TRAIN_TEAMMATE:
switch (pSoldier->bTrainStat)
{
case STRENGTH:
bAssignmentIndex = FAC_TRAINER_STRENGTH;
break;
case DEXTERITY:
bAssignmentIndex = FAC_TRAINER_DEXTERITY;
break;
case AGILITY:
bAssignmentIndex = FAC_TRAINER_AGILITY;
break;
case HEALTH:
bAssignmentIndex = FAC_TRAINER_HEALTH;
break;
case MARKSMANSHIP:
bAssignmentIndex = FAC_TRAINER_MARKSMANSHIP;
break;
case MEDICAL:
bAssignmentIndex = FAC_TRAINER_MEDICAL;
break;
case MECHANICAL:
bAssignmentIndex = FAC_TRAINER_MECHANICAL;
break;
case LEADERSHIP:
bAssignmentIndex = FAC_TRAINER_LEADERSHIP;
break;
case EXPLOSIVE_ASSIGN:
bAssignmentIndex = FAC_TRAINER_EXPLOSIVES;
break;
}
break;
case TRAIN_BY_OTHER:
switch (pSoldier->bTrainStat)
{
case STRENGTH:
bAssignmentIndex = FAC_STUDENT_STRENGTH;
break;
case DEXTERITY:
bAssignmentIndex = FAC_STUDENT_DEXTERITY;
break;
case AGILITY:
bAssignmentIndex = FAC_STUDENT_AGILITY;
break;
case HEALTH:
bAssignmentIndex = FAC_STUDENT_HEALTH;
break;
case MARKSMANSHIP:
bAssignmentIndex = FAC_STUDENT_MARKSMANSHIP;
break;
case MEDICAL:
bAssignmentIndex = FAC_STUDENT_MEDICAL;
break;
case MECHANICAL:
bAssignmentIndex = FAC_STUDENT_MECHANICAL;
break;
case LEADERSHIP:
bAssignmentIndex = FAC_STUDENT_LEADERSHIP;
break;
case EXPLOSIVE_ASSIGN:
bAssignmentIndex = FAC_STUDENT_EXPLOSIVES;
break;
}
break;
case FACILITY_STAFF:
bAssignmentIndex = FAC_STAFF;
break;
case FACILITY_REST:
bAssignmentIndex = FAC_REST;
break;
default:
bAssignmentIndex = -1;
}
return (bAssignmentIndex);
}
// This function runs a specific kind of RISK associated with a facility. The character's stats may affect the result.
INT16 FacilityRiskResult( SOLDIERTYPE *pSoldier, UINT8 ubRiskType, UINT8 ubFacilityType, UINT8 ubAssignmentType )
{
INT16 Result = 0;
UINT8 ubChance;
INT8 bBaseEffect;
UINT8 ubRange;
// Read risk data directly from facility array.
ubChance = gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].Risk[ubRiskType].ubChance;
bBaseEffect = gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].Risk[ubRiskType].bBaseEffect;
ubRange = gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].Risk[ubRiskType].ubRange;
// For now, only these variables can effect risk outcome. In the future there may be more effects, like traits
// and personality, or even sex.
UINT8 ubStrength = EffectiveStrength( pSoldier );
UINT8 ubAgility = EffectiveAgility( pSoldier );
UINT8 ubDexterity = EffectiveDexterity( pSoldier );
UINT8 ubHealth = __min(pSoldier->stats.bLife, pSoldier->stats.bLifeMax);
UINT8 ubWisdom = EffectiveWisdom( pSoldier );
UINT8 ubLeadership = EffectiveLeadership( pSoldier );
UINT8 ubExplosives = EffectiveExplosive( pSoldier );
UINT8 ubExpLevel = EffectiveExpLevel( pSoldier );
UINT8 ubLocalLoyalty = 0;
if (GetTownIdForSector( pSoldier->sSectorX, pSoldier->sSectorY ) != BLANK_SECTOR )
{
ubLocalLoyalty = gTownLoyalty[ GetTownIdForSector( pSoldier->sSectorX, pSoldier->sSectorY ) ].ubRating;
}
else
{
ubLocalLoyalty = 0;
}
///////////////
INT8 bAbsoluteMaxResult;
INT8 bAbsoluteMinResult;
// Calculate absolute maximum variance. The result can never be outside these.
if (bBaseEffect < 0)
{
bAbsoluteMaxResult = __min((bBaseEffect + ubRange), -1);
bAbsoluteMinResult = bBaseEffect - ubRange;
}
else if (bBaseEffect > 0)
{
bAbsoluteMaxResult = bBaseEffect + ubRange;
bAbsoluteMinResult = __max(1, (bBaseEffect - ubRange));
}
else
{
bAbsoluteMaxResult = bBaseEffect + ubRange;
bAbsoluteMinResult = bBaseEffect - ubRange;
}
INT8 bCombinedStats;
// Begin calculating the effect of skills on increasing/reducing final result. Use a mix of stats to reach a range
// of 0 to 100.
switch (ubRiskType)
{
case RISK_STRENGTH:
bCombinedStats = (INT8)__min(100, (ubWisdom * 0.2) + (ubAgility * 0.3) + (ubExpLevel * 5));
break;
case RISK_DEXTERITY:
bCombinedStats = (INT8)__min(100, (ubWisdom * 0.4) + (ubExpLevel * 6));
break;
case RISK_AGILITY:
bCombinedStats = (INT8)__min(100, (ubWisdom * 0.2) + (ubExpLevel * 8));
break;
case RISK_HEALTH:
bCombinedStats = (INT8)__min(100, (ubWisdom * 0.5) + (ubExpLevel * 5));
break;
case RISK_WISDOM:
bCombinedStats = (INT8)__min(100, (ubWisdom * 0.6) + (ubExpLevel * 4));
break;
case RISK_MARKSMANSHIP:
bCombinedStats = (INT8)__min(100, (ubWisdom * 0.2) + (ubAgility * 0.4) + (ubExpLevel * 4));
break;
case RISK_MEDICAL:
bCombinedStats = (INT8)__min(100, (ubWisdom * 0.3) + (ubDexterity * 0.4) + (ubExpLevel * 3));
break;
case RISK_MECHANICAL:
bCombinedStats = (INT8)__min(100, (ubWisdom * 0.3) + (ubDexterity * 0.5) + (ubExpLevel * 2));
break;
case RISK_LEADERSHIP:
bCombinedStats = (INT8)__min(100, (ubWisdom * 0.4) + (ubLeadership * 0.3) + (ubExpLevel * 3));
break;
case RISK_EXPLOSIVES:
bCombinedStats = (INT8)__min(100, (ubWisdom * 0.2) + (ubAgility * 0.3) + (ubDexterity * 0.3) + (ubExpLevel * 2));
break;
case RISK_INJURY:
bCombinedStats = (INT8)__min(100, (ubWisdom * 0.2) + (ubDexterity * 0.2) + (ubAgility * 0.4) + (ubExpLevel * 2));
break;
case RISK_MORALE:
bCombinedStats = (INT8)__min(100, (ubWisdom * 0.2) + (ubLeadership * 0.4) + (ubExpLevel * 4));
break;
case RISK_FATIGUE:
bCombinedStats = (INT8)__min(100, (ubAgility * 0.1) + (ubStrength * 0.3) + (ubHealth * 0.2) + (ubExpLevel * 5));
break;
case RISK_DRUNK:
bCombinedStats = (INT8)__min(100, (ubWisdom * 0.5) + (ubHealth * 0.3) + (ubExpLevel * 2));
break;
case RISK_LOYALTY_LOCAL:
bCombinedStats = (INT8)__min(100, (ubWisdom * 0.2) + (ubLeadership * 0.3) + (ubStrength * 0.1) + (ubExpLevel * 2) + (ubLocalLoyalty * 0.2) );
break;
case RISK_LOYALTY_GLOBAL:
bCombinedStats = (INT8)__min(100, (ubWisdom * 0.3) + (ubLeadership * 0.3) + (ubExpLevel * 2) + (ubLocalLoyalty * 0.2));
break;
}
if (bCombinedStats == 100)
{
// Character is as skilled as possible. Automatic "best" result.
return (bAbsoluteMaxResult);
}
if (bCombinedStats == 0)
{
// Character is completely inept? Strange. Automatic "worst" result.
return (bAbsoluteMinResult);
}
// we now have a range of 0 to 100. Let's apply an externalized modifier of 0 to -100.
bCombinedStats -= gGameExternalOptions.ubFacilityDangerRate;
// The chance of triggering an event is also based on stats.
if (bBaseEffect > 0 )
{
// Chance increases with good stats, decreased with bad stats.
ubChance = ubChance + ((bCombinedStats * ubChance) / 100 );
}
else if (bBaseEffect < 0 )
{
// Chance decreases with good stats, increases with bad stats.
ubChance = ubChance - ((bCombinedStats * ubChance) / 100 );
}
else
{
// Chance is unaffected
}
// Alright, let's see if the event is triggered.
if (PreRandom(gGameExternalOptions.usFacilityEventRarity)>ubChance)
{
// Chance failed to trigger.
return (0);
}
else
{
// Let's find out how bad/good the result is.
// By now, the Combined Stats variable is anywhere between -100 and +100.
// We use this to move the Base Effect point from its original location, effectively giving us a better
// or worse result based on our stats.
bBaseEffect += (bCombinedStats * (ubRange+1)) / 100;
bBaseEffect = __min(bBaseEffect, bAbsoluteMaxResult);
bBaseEffect = __max(bBaseEffect, bAbsoluteMinResult);
// The deviation is also affected by our stats.
ubRange -= abs((bCombinedStats * (ubRange+1)) / 100); // If the Base Effect has moved any, then the range shrinks accordingly.
// Effectively what happens is that skilled characters will get better results more consistently, and avoid
// bad results consistently as well.
// The opposite is also true - characters with insufficient skills tend to get worse results consistently,
// and rarely (if ever) get the best results possible.
//The final result is:
Result = bBaseEffect + ((PreRandom((ubRange*2)+1)) - ubRange);
// Naturally, the character can't ever breach the range of possible results as defined by the facility data.
Result = __min(Result, bAbsoluteMaxResult);
Result = __max(Result, bAbsoluteMinResult);
return (Result);
}
}
void HandleHourlyRisks()
{
INT32 iCounter = 0;
SOLDIERTYPE *pSoldier;
while (gCharactersList[iCounter].fValid)
{
pSoldier = MercPtrs[ gCharactersList[ iCounter ].usSolID ];
// Is character truly valid?
if( !( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) &&
pSoldier->bSectorZ == 0 &&
pSoldier->stats.bLife >= OKLIFE &&
!(pSoldier->flags.fMercAsleep) )
{
// Run this character's risks.
HandleRisksForSoldier( pSoldier );
}
iCounter++;
}
}
void HandleRisksForSoldier( SOLDIERTYPE *pSoldier )
{
INT32 iCounter = 0;
INT32 iCounterB = 0;
UINT8 ubFacilityType = 0;
UINT8 ubAssignmentType = 0;
if (pSoldier->sFacilityTypeOperated != -1)
{
// Soldier is working at a specific facility. Risks associated with this specific facility and assignment
// have priority.
ubAssignmentType = GetSoldierFacilityAssignmentIndex( pSoldier );
ubFacilityType = (UINT8)pSoldier->sFacilityTypeOperated;
HandleRisksForSoldierFacilityAssignment( pSoldier, ubFacilityType, ubAssignmentType );
}
// Test for triggers related to any AMBIENT facility in the same sector.
for (iCounterB; iCounterB < NUM_FACILITY_TYPES; iCounterB++)
{
if (gFacilityLocations[SECTOR(pSoldier->sSectorX, pSoldier->sSectorY)][iCounterB].fFacilityHere)
{
// Test this facility for ambient effects.
HandleRisksForSoldierFacilityAssignment( pSoldier, iCounterB, FAC_AMBIENT );
}
}
}
void HandleRisksForSoldierFacilityAssignment( SOLDIERTYPE *pSoldier, UINT8 ubFacilityType, UINT8 ubAssignmentType )
{
INT32 iCounter = 0;
INT32 Result = 0;
INT32 iNewValue = 0;
CHAR16 sString[256];
CHAR16 szSectorGrid[10];
SGPRect pCenteringRect= {0, 0, 640, INV_INTERFACE_START_Y };
UINT8 ubTownID = 0;
BOOLEAN fOperatingFacility = (GetSoldierFacilityAssignmentIndex( pSoldier ) == -1) ? FALSE : TRUE;
BOOLEAN fBadResult = FALSE;
UINT16 usColor = FONT_MCOLOR_LTRED;
for (iCounter; iCounter < NUM_RISKS; iCounter++)
{
fBadResult = FALSE;
if (gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].Risk[iCounter].ubChance > 0)
{
if (iCounter == RISK_LOYALTY_LOCAL)
{
ubTownID = GetTownIdForSector( pSoldier->sSectorX, pSoldier->sSectorY );
if (ubTownID == BLANK_SECTOR)
{
// No town here, so this risk doesn't have any effect anyway...
continue;
}
}
Result = FacilityRiskResult( pSoldier, iCounter, ubFacilityType, ubAssignmentType);
if (Result != 0)
{
switch (iCounter)
{
case RISK_STRENGTH:
if (Result > 0)
{
// Soldier doesn't gain stat points directly, instead he gets a number of chances
// equal to Result*SubPointsPerLevel. Optimally this leads to gaining a number of
// levels equal to result, but this isn't always the case.
Result *= gGameExternalOptions.usStrengthSubpointsToImprove;
StatChange( pSoldier, STRAMT, Result, TRUE );
}
else
{
// Soldier is suffering direct stat damage.
pSoldier->stats.bStrength = __max(1,pSoldier->stats.bStrength + Result);
gMercProfiles[ pSoldier->ubProfile ].bStrength = pSoldier->stats.bStrength;
// make this stat RED for a while...
pSoldier->timeChanges.uiChangeStrengthTime = GetJA2Clock();
pSoldier->usValueGoneUp &= ~( STRENGTH_INCREASE );
fBadResult = TRUE;
// Log message
BuildStatChangeString( sString, pSoldier->name, FALSE, Result, STRAMT );
ScreenMsg( usColor, MSG_INTERFACE, sString );
// Do Screen Message and stop time.
GetShortSectorString( pSoldier->sSectorX, pSoldier->sSectorY, szSectorGrid );
if (!fOperatingFacility)
swprintf( sString, gzFacilityErrorMessage[17], pSoldier->name, gzFacilityRiskResultStrings[0], szSectorGrid );
else
swprintf( sString, gzFacilityErrorMessage[18], pSoldier->name, gzFacilityRiskResultStrings[0], gFacilityTypes[ubFacilityType].szFacilityName, szSectorGrid );
DoScreenIndependantMessageBox( sString, MSG_BOX_FLAG_OK, NULL );
StopTimeCompression();
}
break;
case RISK_AGILITY:
if (Result > 0)
{
// Soldier doesn't gain stat points directly, instead he gets a number of chances
// equal to Result*SubPointsPerLevel. Optimally this leads to gaining a number of
// levels equal to result, but this isn't always the case.
Result *= gGameExternalOptions.usAgilitySubpointsToImprove;
StatChange( pSoldier, AGILAMT, Result, TRUE );
}
else
{
// Soldier is suffering direct stat damage.
pSoldier->stats.bAgility = __max(1,pSoldier->stats.bAgility + Result);
gMercProfiles[ pSoldier->ubProfile ].bAgility = pSoldier->stats.bAgility;
// make this stat RED for a while...
pSoldier->timeChanges.uiChangeAgilityTime = GetJA2Clock();
pSoldier->usValueGoneUp &= ~( AGIL_INCREASE );
fBadResult = TRUE;
// Log message
BuildStatChangeString( sString, pSoldier->name, FALSE, Result, AGILAMT );
ScreenMsg( usColor, MSG_INTERFACE, sString );
// Do Screen Message and stop time.
GetShortSectorString( pSoldier->sSectorX, pSoldier->sSectorY, szSectorGrid );
if (!fOperatingFacility)
swprintf( sString, gzFacilityErrorMessage[17], pSoldier->name, gzFacilityRiskResultStrings[1], szSectorGrid );
else
swprintf( sString, gzFacilityErrorMessage[18], pSoldier->name, gzFacilityRiskResultStrings[1], gFacilityTypes[ubFacilityType].szFacilityName, szSectorGrid );
DoScreenIndependantMessageBox( sString, MSG_BOX_FLAG_OK, NULL );
StopTimeCompression();
}
break;
case RISK_DEXTERITY:
if (Result > 0)
{
// Soldier doesn't gain stat points directly, instead he gets a number of chances
// equal to Result*SubPointsPerLevel. Optimally this leads to gaining a number of
// levels equal to result, but this isn't always the case.
Result *= gGameExternalOptions.usDexteritySubpointsToImprove;
StatChange( pSoldier, DEXTAMT, Result, TRUE );
}
else
{
// Soldier is suffering direct stat damage.
pSoldier->stats.bDexterity = __max(1,pSoldier->stats.bDexterity + Result);
gMercProfiles[ pSoldier->ubProfile ].bDexterity = pSoldier->stats.bDexterity;
// make this stat RED for a while...
pSoldier->timeChanges.uiChangeDexterityTime = GetJA2Clock();
pSoldier->usValueGoneUp &= ~( DEX_INCREASE );
fBadResult = TRUE;
// Log message
BuildStatChangeString( sString, pSoldier->name, FALSE, Result, DEXTAMT );
ScreenMsg( usColor, MSG_INTERFACE, sString );
// Do Screen Message and stop time.
GetShortSectorString( pSoldier->sSectorX, pSoldier->sSectorY, szSectorGrid );
if (!fOperatingFacility)
swprintf( sString, gzFacilityErrorMessage[17], pSoldier->name, gzFacilityRiskResultStrings[2], szSectorGrid );
else
swprintf( sString, gzFacilityErrorMessage[18], pSoldier->name, gzFacilityRiskResultStrings[2], gFacilityTypes[ubFacilityType].szFacilityName, szSectorGrid );
DoScreenIndependantMessageBox( sString, MSG_BOX_FLAG_OK, NULL );
StopTimeCompression();
}
break;
case RISK_WISDOM:
if (Result > 0)
{
// Soldier doesn't gain stat points directly, instead he gets a number of chances
// equal to Result*SubPointsPerLevel. Optimally this leads to gaining a number of
// levels equal to result, but this isn't always the case.
Result *= gGameExternalOptions.usWisdomSubpointsToImprove;
StatChange( pSoldier, WISDOMAMT, Result, TRUE );
}
else
{
// Soldier is suffering direct stat damage.
pSoldier->stats.bWisdom = __max(1,pSoldier->stats.bWisdom + Result);
gMercProfiles[ pSoldier->ubProfile ].bWisdom = pSoldier->stats.bWisdom;
// make this stat RED for a while...
pSoldier->timeChanges.uiChangeWisdomTime = GetJA2Clock();
pSoldier->usValueGoneUp &= ~( WIS_INCREASE );
fBadResult = TRUE;
// Log message
BuildStatChangeString( sString, pSoldier->name, FALSE, Result, WISDOMAMT );
ScreenMsg( usColor, MSG_INTERFACE, sString );
// Do Screen Message and stop time.
GetShortSectorString( pSoldier->sSectorX, pSoldier->sSectorY, szSectorGrid );
if (!fOperatingFacility)
swprintf( sString, gzFacilityErrorMessage[17], pSoldier->name, gzFacilityRiskResultStrings[3], szSectorGrid );
else
swprintf( sString, gzFacilityErrorMessage[18], pSoldier->name, gzFacilityRiskResultStrings[3], gFacilityTypes[ubFacilityType].szFacilityName, szSectorGrid );
DoScreenIndependantMessageBox( sString, MSG_BOX_FLAG_OK, NULL );
StopTimeCompression();
}
break;
case RISK_HEALTH:
if (Result > 0)
{
// Soldier doesn't gain stat points directly, instead he gets a number of chances
// equal to Result*SubPointsPerLevel. Optimally this leads to gaining a number of
// levels equal to result, but this isn't always the case.
Result *= gGameExternalOptions.usHealthSubpointsToImprove;
StatChange( pSoldier, HEALTHAMT, Result, TRUE );
}
else
{
// Soldier is suffering direct stat damage.
pSoldier->stats.bLifeMax = __max(1,pSoldier->stats.bLifeMax + Result);
gMercProfiles[ pSoldier->ubProfile ].bLifeMax = pSoldier->stats.bLifeMax;
// make this stat RED for a while...
pSoldier->timeChanges.uiChangeHealthTime = GetJA2Clock();
pSoldier->usValueGoneUp &= ~( HEALTH_INCREASE );
pSoldier->stats.bLife += Result;
if (pSoldier->stats.bLife < OKLIFE)
{
HandleTakeDamageDeath( pSoldier, 0, TAKE_DAMAGE_BLOODLOSS );
}
fBadResult = TRUE;
// Log message
BuildStatChangeString( sString, pSoldier->name, FALSE, Result, HEALTHAMT );
ScreenMsg( usColor, MSG_INTERFACE, sString );
if (pSoldier->stats.bLife >= OKLIFE)
{
// Do Screen Message and stop time.
GetShortSectorString( pSoldier->sSectorX, pSoldier->sSectorY, szSectorGrid );
if (!fOperatingFacility)
swprintf( sString, gzFacilityErrorMessage[17], pSoldier->name, gzFacilityRiskResultStrings[4], szSectorGrid );
else
swprintf( sString, gzFacilityErrorMessage[18], pSoldier->name, gzFacilityRiskResultStrings[4], gFacilityTypes[ubFacilityType].szFacilityName, szSectorGrid );
DoScreenIndependantMessageBox( sString, MSG_BOX_FLAG_OK, NULL );
StopTimeCompression();
}
else if(pSoldier->stats.bLife < OKLIFE && pSoldier->stats.bLife > 0)
{
// Soldier's health is driven very low. Automatically removed from duty.
// Do Screen Message and stop time.
GetShortSectorString( pSoldier->sSectorX, pSoldier->sSectorY, szSectorGrid );
if (!fOperatingFacility)
swprintf( sString, gzFacilityErrorMessage[28], pSoldier->name, szSectorGrid );
else
swprintf( sString, gzFacilityErrorMessage[29], pSoldier->name, gFacilityTypes[ubFacilityType].szFacilityName, szSectorGrid );
AddCharacterToAnySquad( pSoldier );
DoScreenIndependantMessageBox( sString, MSG_BOX_FLAG_OK, NULL );
StopTimeCompression();
}
}
break;
case RISK_MARKSMANSHIP:
if (Result > 0)
{
// Soldier doesn't gain stat points directly, instead he gets a number of chances
// equal to Result*SubPointsPerLevel. Optimally this leads to gaining a number of
// levels equal to result, but this isn't always the case.
Result *= gGameExternalOptions.usMarksmanshipSubpointsToImprove;
StatChange( pSoldier, MARKAMT, Result, TRUE );
}
else
{
// Soldier is suffering direct stat damage.
pSoldier->stats.bMarksmanship = __max(1,pSoldier->stats.bMarksmanship + Result);
gMercProfiles[ pSoldier->ubProfile ].bMarksmanship = pSoldier->stats.bMarksmanship;
// make this stat RED for a while...
pSoldier->timeChanges.uiChangeMarksmanshipTime = GetJA2Clock();
pSoldier->usValueGoneUp &= ~( MRK_INCREASE );
fBadResult = TRUE;
// Log message
BuildStatChangeString( sString, pSoldier->name, FALSE, Result, MARKAMT );
ScreenMsg( usColor, MSG_INTERFACE, sString );
// Do Screen Message and stop time.
GetShortSectorString( pSoldier->sSectorX, pSoldier->sSectorY, szSectorGrid );
if (!fOperatingFacility)
swprintf( sString, gzFacilityErrorMessage[17], pSoldier->name, gzFacilityRiskResultStrings[5], szSectorGrid );
else
swprintf( sString, gzFacilityErrorMessage[18], pSoldier->name, gzFacilityRiskResultStrings[5], gFacilityTypes[ubFacilityType].szFacilityName, szSectorGrid );
DoScreenIndependantMessageBox( sString, MSG_BOX_FLAG_OK, NULL );
StopTimeCompression();
}
break;
case RISK_LEADERSHIP:
if (Result > 0)
{
// Soldier doesn't gain stat points directly, instead he gets a number of chances
// equal to Result*SubPointsPerLevel. Optimally this leads to gaining a number of
// levels equal to result, but this isn't always the case.
Result *= gGameExternalOptions.usLeadershipSubpointsToImprove;
StatChange( pSoldier, LDRAMT, Result, TRUE );
}
else
{
// Soldier is suffering direct stat damage.
pSoldier->stats.bLeadership = __max(1,pSoldier->stats.bLeadership + Result);
gMercProfiles[ pSoldier->ubProfile ].bLeadership = pSoldier->stats.bLeadership;
// make this stat RED for a while...
pSoldier->timeChanges.uiChangeLeadershipTime = GetJA2Clock();
pSoldier->usValueGoneUp &= ~( LDR_INCREASE );
fBadResult = TRUE;
// Log message
BuildStatChangeString( sString, pSoldier->name, FALSE, Result, LDRAMT );
ScreenMsg( usColor, MSG_INTERFACE, sString );
// Do Screen Message and stop time.
GetShortSectorString( pSoldier->sSectorX, pSoldier->sSectorY, szSectorGrid );
if (!fOperatingFacility)
swprintf( sString, gzFacilityErrorMessage[17], pSoldier->name, gzFacilityRiskResultStrings[6], szSectorGrid );
else
swprintf( sString, gzFacilityErrorMessage[18], pSoldier->name, gzFacilityRiskResultStrings[6], gFacilityTypes[ubFacilityType].szFacilityName, szSectorGrid );
DoScreenIndependantMessageBox( sString, MSG_BOX_FLAG_OK, NULL );
StopTimeCompression();
}
break;
case RISK_MECHANICAL:
if (Result > 0)
{
// Soldier doesn't gain stat points directly, instead he gets a number of chances
// equal to Result*SubPointsPerLevel. Optimally this leads to gaining a number of
// levels equal to result, but this isn't always the case.
Result *= gGameExternalOptions.usMechanicalSubpointsToImprove;
StatChange( pSoldier, MECHANAMT, Result, TRUE );
}
else
{
// Soldier is suffering direct stat damage.
pSoldier->stats.bMechanical = __max(1,pSoldier->stats.bMechanical + Result);
gMercProfiles[ pSoldier->ubProfile ].bMechanical = pSoldier->stats.bMechanical;
// make this stat RED for a while...
pSoldier->timeChanges.uiChangeMechanicalTime = GetJA2Clock();
pSoldier->usValueGoneUp &= ~( MECH_INCREASE );
fBadResult = TRUE;
// Log message
BuildStatChangeString( sString, pSoldier->name, FALSE, Result, MECHANAMT );
ScreenMsg( usColor, MSG_INTERFACE, sString );
// Do Screen Message and stop time.
GetShortSectorString( pSoldier->sSectorX, pSoldier->sSectorY, szSectorGrid );
if (!fOperatingFacility)
swprintf( sString, gzFacilityErrorMessage[17], pSoldier->name, gzFacilityRiskResultStrings[7], szSectorGrid );
else
swprintf( sString, gzFacilityErrorMessage[18], pSoldier->name, gzFacilityRiskResultStrings[7], gFacilityTypes[ubFacilityType].szFacilityName, szSectorGrid );
DoScreenIndependantMessageBox( sString, MSG_BOX_FLAG_OK, NULL );
StopTimeCompression();
}
break;
case RISK_MEDICAL:
if (Result > 0)
{
// Soldier doesn't gain stat points directly, instead he gets a number of chances
// equal to Result*SubPointsPerLevel. Optimally this leads to gaining a number of
// levels equal to result, but this isn't always the case.
Result *= gGameExternalOptions.usMedicalSubpointsToImprove;
StatChange( pSoldier, MEDICALAMT, Result, TRUE );
}
else
{
// Soldier is suffering direct stat damage.
pSoldier->stats.bMedical = __max(1,pSoldier->stats.bMedical + Result);
gMercProfiles[ pSoldier->ubProfile ].bMedical = pSoldier->stats.bMedical;
// make this stat RED for a while...
pSoldier->timeChanges.uiChangeMedicalTime = GetJA2Clock();
pSoldier->usValueGoneUp &= ~( MED_INCREASE );
fBadResult = TRUE;
// Log message
BuildStatChangeString( sString, pSoldier->name, FALSE, Result, MEDICALAMT );
ScreenMsg( usColor, MSG_INTERFACE, sString );
// Do Screen Message and stop time.
GetShortSectorString( pSoldier->sSectorX, pSoldier->sSectorY, szSectorGrid );
if (!fOperatingFacility)
swprintf( sString, gzFacilityErrorMessage[17], pSoldier->name, gzFacilityRiskResultStrings[8], szSectorGrid );
else
swprintf( sString, gzFacilityErrorMessage[18], pSoldier->name, gzFacilityRiskResultStrings[8], gFacilityTypes[ubFacilityType].szFacilityName, szSectorGrid );
DoScreenIndependantMessageBox( sString, MSG_BOX_FLAG_OK, NULL );
StopTimeCompression();
}
break;
case RISK_EXPLOSIVES:
if (Result > 0)
{
// Soldier doesn't gain stat points directly, instead he gets a number of chances
// equal to Result*SubPointsPerLevel. Optimally this leads to gaining a number of
// levels equal to result, but this isn't always the case.
Result *= gGameExternalOptions.usExplosivesSubpointsToImprove;
StatChange( pSoldier, EXPLODEAMT, Result, TRUE );
}
else
{
// Soldier is suffering direct stat damage.
pSoldier->stats.bExplosive = __max(1,pSoldier->stats.bExplosive + Result);
gMercProfiles[ pSoldier->ubProfile ].bExplosive = pSoldier->stats.bExplosive;
// make this stat RED for a while...
pSoldier->timeChanges.uiChangeExplosivesTime = GetJA2Clock();
pSoldier->usValueGoneUp &= ~( EXP_INCREASE );
fBadResult = TRUE;
// Log message
BuildStatChangeString( sString, pSoldier->name, FALSE, Result, EXPLODEAMT );
ScreenMsg( usColor, MSG_INTERFACE, sString );
// Do Screen Message and stop time.
GetShortSectorString( pSoldier->sSectorX, pSoldier->sSectorY, szSectorGrid );
if (!fOperatingFacility)
swprintf( sString, gzFacilityErrorMessage[17], pSoldier->name, gzFacilityRiskResultStrings[9], szSectorGrid );
else
swprintf( sString, gzFacilityErrorMessage[18], pSoldier->name, gzFacilityRiskResultStrings[9], gFacilityTypes[ubFacilityType].szFacilityName, szSectorGrid );
DoScreenIndependantMessageBox( sString, MSG_BOX_FLAG_OK, NULL );
StopTimeCompression();
}
break;
case RISK_INJURY:
// This can only be a negative effect... for now.
if (Result < 0)
{
// Soldier is suffering direct unbandaged injury.
pSoldier->SoldierTakeDamage( 0, abs(Result), abs(Result), TAKE_DAMAGE_BLOODLOSS, NOBODY, NOWHERE, 0, FALSE );
fBadResult = TRUE;
if (pSoldier->stats.bLife > 0)
{
if (pSoldier->bBleeding > MIN_BLEEDING_THRESHOLD)
{
// Log message
GetShortSectorString( pSoldier->sSectorX, pSoldier->sSectorY, szSectorGrid );
swprintf( sString, gzFacilityErrorMessage[31], pSoldier->name, szSectorGrid );
ScreenMsg( usColor, MSG_INTERFACE, sString );
// Do Screen Message, stop time, and take character off duty immediately.
GetShortSectorString( pSoldier->sSectorX, pSoldier->sSectorY, szSectorGrid );
if (!fOperatingFacility)
swprintf( sString, gzFacilityErrorMessage[19], pSoldier->name, szSectorGrid );
else
swprintf( sString, gzFacilityErrorMessage[20], pSoldier->name, gFacilityTypes[ubFacilityType].szFacilityName, szSectorGrid );
AddCharacterToAnySquad( pSoldier );
DoScreenIndependantMessageBox( sString, MSG_BOX_FLAG_OK, NULL );
StopTimeCompression();
}
else
{
// Log message
GetShortSectorString( pSoldier->sSectorX, pSoldier->sSectorY, szSectorGrid );
swprintf( sString, gzFacilityErrorMessage[30], pSoldier->name, szSectorGrid );
ScreenMsg( usColor, MSG_INTERFACE, sString );
// Soldier isn't bleeding too bad. Let the player know, but don't take any action.
// Do Screen Message and stop time.
GetShortSectorString( pSoldier->sSectorX, pSoldier->sSectorY, szSectorGrid );
if (!fOperatingFacility)
swprintf( sString, gzFacilityErrorMessage[21], pSoldier->name, szSectorGrid );
else
swprintf( sString, gzFacilityErrorMessage[22], pSoldier->name, gFacilityTypes[ubFacilityType].szFacilityName, szSectorGrid );
DoScreenIndependantMessageBox( sString, MSG_BOX_FLAG_OK, NULL );
StopTimeCompression();
}
}
}
break;
case RISK_MORALE:
pSoldier->aiData.bMorale = __min(100,__max(0, pSoldier->aiData.bMorale + Result));
pSoldier->aiData.bStrategicMoraleMod = __min(50,__max(-50, pSoldier->aiData.bStrategicMoraleMod + Result));
RefreshSoldierMorale( pSoldier );
break;
case RISK_FATIGUE:
pSoldier->bBreathMax = __min(100,__max(0, pSoldier->bBreathMax + Result));
pSoldier->bBreath = pSoldier->bBreathMax;
break;
case RISK_DRUNK:
// Has soldier just drunk enough to make him drunk off his head?
if (GetDrunkLevel(pSoldier) == BORDERLINE)
{
// Log message
swprintf( sString, gzFacilityErrorMessage[27], pSoldier->name );
ScreenMsg( usColor, MSG_INTERFACE, sString );
}
// Add effects
if ( ( pSoldier->drugs.bFutureDrugEffect[ DRUG_TYPE_ALCOHOL ] + ubDrugEffect[ DRUG_TYPE_ALCOHOL ] ) < 127 )
{
pSoldier->drugs.bFutureDrugEffect[ DRUG_TYPE_ALCOHOL ] += ubDrugEffect[ DRUG_TYPE_ALCOHOL ];
}
pSoldier->drugs.bDrugEffectRate[ DRUG_TYPE_ALCOHOL ] = ubDrugTravelRate[ DRUG_TYPE_ALCOHOL ];
// Reset once we sleep...
pSoldier->drugs.bTimesDrugUsedSinceSleep[ DRUG_TYPE_ALCOHOL ]++;
// Increment side effects..
if ( ( pSoldier->drugs.bDrugSideEffect[ DRUG_TYPE_ALCOHOL ] + ubDrugSideEffect[ DRUG_TYPE_ALCOHOL ] ) < 127 )
{
pSoldier->drugs.bDrugSideEffect[ DRUG_TYPE_ALCOHOL ] += ( ubDrugSideEffect[ DRUG_TYPE_ALCOHOL ] );
}
// Stop side effects until were done....
pSoldier->drugs.bDrugSideEffectRate[ DRUG_TYPE_ALCOHOL ] = 0;
// ATE: Make guy collapse from heart attack if too much stuff taken....
if ( pSoldier->drugs.bDrugSideEffectRate[ DRUG_TYPE_ALCOHOL ] > ( ubDrugSideEffect[ DRUG_TYPE_ALCOHOL ] * 3 ) )
{
if ( pSoldier->ubProfile == LARRY_NORMAL )
{
pSoldier = SwapLarrysProfiles( pSoldier );
}
else if ( pSoldier->ubProfile == LARRY_DRUNK )
{
gMercProfiles[ LARRY_DRUNK ].bNPCData = 0;
}
// Keel over...
DeductPoints( pSoldier, 0, 10000 );
// Permanently lower certain stats...
pSoldier->stats.bWisdom = __max(1, pSoldier->stats.bWisdom-5);
pSoldier->stats.bDexterity = __max(1, pSoldier->stats.bDexterity-5);
pSoldier->stats.bStrength = __max(1, pSoldier->stats.bStrength-5);
// export stat changes to profile
gMercProfiles[ pSoldier->ubProfile ].bWisdom = pSoldier->stats.bWisdom;
gMercProfiles[ pSoldier->ubProfile ].bDexterity = pSoldier->stats.bDexterity;
gMercProfiles[ pSoldier->ubProfile ].bStrength = pSoldier->stats.bStrength;
// make those stats RED for a while...
pSoldier->timeChanges.uiChangeWisdomTime = GetJA2Clock();
pSoldier->usValueGoneUp &= ~( WIS_INCREASE );
pSoldier->timeChanges.uiChangeDexterityTime = GetJA2Clock();
pSoldier->usValueGoneUp &= ~( DEX_INCREASE );
pSoldier->timeChanges.uiChangeStrengthTime = GetJA2Clock();
pSoldier->usValueGoneUp &= ~( STRENGTH_INCREASE );
}
break;
case RISK_LOYALTY_LOCAL:
Result *= GAIN_PTS_PER_LOYALTY_PT; // Transform points into actual loyalty.
if (Result > 0)
{
IncrementTownLoyalty( ubTownID, Result );
}
else
{
DecrementTownLoyalty( ubTownID, abs(Result) );
// Log message
if (!fOperatingFacility)
swprintf( sString, gzFacilityErrorMessage[23], pTownNames[ubTownID], pSoldier->name );
else
swprintf( sString, gzFacilityErrorMessage[24], pTownNames[ubTownID], pSoldier->name, gFacilityTypes[ubFacilityType].szFacilityName );
ScreenMsg( usColor, MSG_INTERFACE, sString );
}
break;
case RISK_LOYALTY_GLOBAL:
Result *= GAIN_PTS_PER_LOYALTY_PT; // Transform points into actual loyalty.
if (Result > 0)
{
IncrementTownLoyaltyEverywhere( Result );
}
else
{
DecrementTownLoyaltyEverywhere( abs(Result) );
// Log message
GetShortSectorString( pSoldier->sSectorX, pSoldier->sSectorY, szSectorGrid );
if (!fOperatingFacility)
swprintf( sString, gzFacilityErrorMessage[25], pSoldier->name, szSectorGrid );
else
swprintf( sString, gzFacilityErrorMessage[26], pSoldier->name, szSectorGrid, gFacilityTypes[ubFacilityType].szFacilityName );
ScreenMsg( usColor, MSG_INTERFACE, sString );
}
break;
default:
break;
}
if (fBadResult)
{
StopTimeCompression();
}
}
}
}
}
INT32 GetTotalFacilityHourlyCosts( BOOLEAN fPositive )
{
SOLDIERTYPE *pSoldier;
INT32 iTotal = 0;
UINT8 ubCounter = 0;
// Run through list of player-characters
while(gCharactersList[ubCounter].fValid)
{
pSoldier = MercPtrs[ gCharactersList[ ubCounter ].usSolID ];
// Is character truly valid?
if( !( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) &&
pSoldier->bSectorZ == 0 &&
pSoldier->stats.bLife >= OKLIFE &&
!(pSoldier->flags.fMercAsleep) )
{
UINT8 ubAssignmentType = GetSoldierFacilityAssignmentIndex( pSoldier );
if (ubAssignmentType == -1)
{
// Skip this character.
ubCounter++;
continue;
}
UINT8 ubSector = SECTOR(pSoldier->sSectorX, pSoldier->sSectorY);
UINT8 ubFacilityType = (UINT8)pSoldier->sFacilityTypeOperated;
if (!fPositive && // We want facilities that cost money to operate
gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].sCostPerHour > 0) // This facility costs money
{
iTotal += gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].sCostPerHour;
}
else if (fPositive && // We want facilities that GENERATE money
gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].sCostPerHour < 0)
{
// Flip the value to positive
iTotal += (-1 * gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].sCostPerHour);
}
}
ubCounter++;
}
return (iTotal);
}
void InitFacilities()
{
// Initialize facility debt.
giTotalOwedForFacilityOperationsToday = 0;
gfOutstandingFacilityDebt = FALSE;
}