mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@8846 3b4a5df2-a311-0410-b5c6-a8a6f20db521
2029 lines
78 KiB
C++
2029 lines
78 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.h"
|
|
#include "Interface.h"
|
|
#include "message.h"
|
|
#include "Morale.h"
|
|
#include "Points.h"
|
|
#include "Soldier Control.h"
|
|
#include "Isometric Utils.h"
|
|
#include "MilitiaSquads.h"
|
|
#include "Tactical Save.h"
|
|
#endif
|
|
|
|
INT16 gsSkyriderCostModifier;
|
|
// HEADROCK HAM 3.6: Strategic info variable, total of income/costs accumulated for the use of facilities today.
|
|
// Account settle 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 giTotalEarnedForFacilityOperationsToday = 0;
|
|
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);
|
|
|
|
// Flugente: not needed anywhere atm
|
|
case FACILITY_CANTINA_MOD:
|
|
sAssignmentModifier = gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].sCantinaFoodModifier;
|
|
sAmbientModifier = gFacilityTypes[ubFacilityType].AssignmentData[0].sCantinaFoodModifier;
|
|
sAssignmentModifier = 100 + ((sAssignmentModifier-100) + (sAmbientModifier-100));
|
|
return (sAssignmentModifier);
|
|
|
|
case FACILITY_PRISON_MOD:
|
|
sAssignmentModifier = gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].usPrisonBaseLimit;
|
|
sAmbientModifier = gFacilityTypes[ubFacilityType].AssignmentData[0].usPrisonBaseLimit;
|
|
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 + ((Result-100) + (sCurrent-100));
|
|
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 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
|
|
// sevenfm: this will disable enemy detection using facility, and detection levels are already zeroed in this function
|
|
//SectorInfo[X].ubDetectionLevel = 0;
|
|
|
|
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 = (UINT8)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 = (UINT8)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)
|
|
{
|
|
/////////////////////////////////////////////////////////
|
|
// Increase income for operating this facility
|
|
|
|
giTotalEarnedForFacilityOperationsToday += (-1 * gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].sCostPerHour);
|
|
}
|
|
|
|
}
|
|
}
|
|
ubCounter++;
|
|
}
|
|
}
|
|
|
|
void HandleDailyPaymentFacilityIncome( void )
|
|
{
|
|
// Pay total income.
|
|
AddTransactionToPlayersBook( FACILITY_OPERATIONS, 0, GetWorldTotalMin(), giTotalEarnedForFacilityOperationsToday );
|
|
giTotalEarnedForFacilityOperationsToday = 0;
|
|
}
|
|
|
|
// 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 = (UINT8)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 (pSoldier->sFacilityTypeOperated == -1)
|
|
{
|
|
// Soldier is not set to work at a facility...
|
|
return (-1);
|
|
}
|
|
|
|
// switch of ALL possible facility assignments
|
|
switch (bAssignment)
|
|
{
|
|
case FACILITY_DOCTOR:
|
|
bAssignmentIndex = FAC_DOCTOR;
|
|
break;
|
|
case FACILITY_PATIENT:
|
|
bAssignmentIndex = FAC_PATIENT;
|
|
break;
|
|
case FACILITY_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;
|
|
default:
|
|
bAssignmentIndex = -1;
|
|
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;
|
|
default:
|
|
bAssignmentIndex = -1;
|
|
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;
|
|
default:
|
|
bAssignmentIndex = -1;
|
|
break;
|
|
}
|
|
break;
|
|
case FACILITY_STAFF:
|
|
bAssignmentIndex = FAC_STAFF;
|
|
break;
|
|
case FACILITY_EAT:
|
|
bAssignmentIndex = FAC_FOOD;
|
|
break;
|
|
case FACILITY_REST:
|
|
bAssignmentIndex = FAC_REST;
|
|
break;
|
|
case FACILITY_INTERROGATE_PRISONERS:
|
|
bAssignmentIndex = FAC_INTERROGATE_PRISONERS;
|
|
break;
|
|
case FACILITY_PRISON_SNITCH:
|
|
bAssignmentIndex = FAC_PRISON_SNITCH;
|
|
break;
|
|
case FACILITY_SPREAD_PROPAGANDA:
|
|
bAssignmentIndex = FAC_SPREAD_PROPAGANDA;
|
|
break;
|
|
case FACILITY_SPREAD_PROPAGANDA_GLOBAL:
|
|
bAssignmentIndex = FAC_SPREAD_PROPAGANDA_GLOBAL;
|
|
break;
|
|
case FACILITY_GATHER_RUMOURS:
|
|
bAssignmentIndex = FAC_GATHER_RUMOURS;
|
|
break;
|
|
case FACILITY_STRATEGIC_MILITIA_MOVEMENT:
|
|
bAssignmentIndex = FAC_STRATEGIC_MILITIA_MOVEMENT;
|
|
break;
|
|
default:
|
|
// Soldier is performing a distinctly NON-FACILITY assignment.
|
|
bAssignmentIndex = -1;
|
|
break;
|
|
}
|
|
|
|
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;
|
|
|
|
INT32 iChance;
|
|
INT16 bBaseEffect;
|
|
UINT16 ubRange;
|
|
|
|
// Read risk data directly from facility array.
|
|
iChance = gFacilityTypes[ubFacilityType].AssignmentData[ubAssignmentType].Risk[ubRiskType].usChance;
|
|
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.
|
|
INT16 ubStrength = EffectiveStrength( pSoldier, FALSE );
|
|
INT16 ubAgility = EffectiveAgility( pSoldier, FALSE );
|
|
INT16 ubDexterity = EffectiveDexterity( pSoldier, FALSE );
|
|
UINT8 ubHealth = __min(pSoldier->stats.bLife, pSoldier->stats.bLifeMax);
|
|
INT16 ubWisdom = EffectiveWisdom( pSoldier );
|
|
UINT8 ubLeadership = EffectiveLeadership( pSoldier );
|
|
UINT8 ubExplosives = EffectiveExplosive( pSoldier );
|
|
UINT8 ubExpLevel = EffectiveExpLevel( pSoldier, FALSE);
|
|
UINT8 ubLocalLoyalty = 0;
|
|
if (GetTownIdForSector( pSoldier->sSectorX, pSoldier->sSectorY ) != BLANK_SECTOR )
|
|
{
|
|
ubLocalLoyalty = gTownLoyalty[ GetTownIdForSector( pSoldier->sSectorX, pSoldier->sSectorY ) ].ubRating;
|
|
}
|
|
else
|
|
{
|
|
ubLocalLoyalty = 0;
|
|
}
|
|
|
|
///////////////
|
|
INT16 sAbsoluteMaxResult;
|
|
INT16 sAbsoluteMinResult;
|
|
|
|
// Calculate absolute maximum variance. The result can never be outside these.
|
|
if (bBaseEffect < 0)
|
|
{
|
|
sAbsoluteMaxResult = __min((bBaseEffect + ubRange), -1);
|
|
sAbsoluteMinResult = bBaseEffect - ubRange;
|
|
}
|
|
else if (bBaseEffect > 0)
|
|
{
|
|
sAbsoluteMaxResult = bBaseEffect + ubRange;
|
|
sAbsoluteMinResult = __max(1, (bBaseEffect - ubRange));
|
|
}
|
|
else
|
|
{
|
|
sAbsoluteMaxResult = bBaseEffect + ubRange;
|
|
sAbsoluteMinResult = bBaseEffect - ubRange;
|
|
}
|
|
|
|
INT16 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 = (INT16)__min(100, (ubWisdom * 0.2) + (ubAgility * 0.3) + (ubExpLevel * 5));
|
|
break;
|
|
case RISK_DEXTERITY:
|
|
bCombinedStats = (INT16)__min(100, (ubWisdom * 0.4) + (ubExpLevel * 6));
|
|
break;
|
|
case RISK_AGILITY:
|
|
bCombinedStats = (INT16)__min(100, (ubWisdom * 0.2) + (ubExpLevel * 8));
|
|
break;
|
|
case RISK_HEALTH:
|
|
bCombinedStats = (INT16)__min(100, (ubWisdom * 0.5) + (ubExpLevel * 5));
|
|
break;
|
|
case RISK_WISDOM:
|
|
bCombinedStats = (INT16)__min(100, (ubWisdom * 0.6) + (ubExpLevel * 4));
|
|
break;
|
|
case RISK_MARKSMANSHIP:
|
|
bCombinedStats = (INT16)__min(100, (ubWisdom * 0.2) + (ubAgility * 0.4) + (ubExpLevel * 4));
|
|
break;
|
|
case RISK_MEDICAL:
|
|
bCombinedStats = (INT16)__min(100, (ubWisdom * 0.3) + (ubDexterity * 0.4) + (ubExpLevel * 3));
|
|
break;
|
|
case RISK_MECHANICAL:
|
|
bCombinedStats = (INT16)__min(100, (ubWisdom * 0.3) + (ubDexterity * 0.5) + (ubExpLevel * 2));
|
|
break;
|
|
case RISK_LEADERSHIP:
|
|
bCombinedStats = (INT16)__min(100, (ubWisdom * 0.4) + (ubLeadership * 0.3) + (ubExpLevel * 3));
|
|
break;
|
|
case RISK_EXPLOSIVES:
|
|
bCombinedStats = (INT16)__min(100, (ubWisdom * 0.2) + (ubAgility * 0.3) + (ubDexterity * 0.3) + (ubExpLevel * 2));
|
|
break;
|
|
case RISK_INJURY:
|
|
bCombinedStats = (INT16)__min(100, (ubWisdom * 0.2) + (ubDexterity * 0.2) + (ubAgility * 0.4) + (ubExpLevel * 2));
|
|
break;
|
|
case RISK_MORALE:
|
|
bCombinedStats = (INT16)__min(100, (ubWisdom * 0.2) + (ubLeadership * 0.4) + (ubExpLevel * 4));
|
|
break;
|
|
case RISK_FATIGUE:
|
|
bCombinedStats = (INT16)__min(100, (ubAgility * 0.1) + (ubStrength * 0.3) + (ubHealth * 0.2) + (ubExpLevel * 4));
|
|
break;
|
|
case RISK_DRUNK:
|
|
bCombinedStats = (INT16)__min(100, (ubWisdom * 0.5) + (ubHealth * 0.3) + (ubExpLevel * 2));
|
|
break;
|
|
case RISK_LOYALTY_LOCAL:
|
|
bCombinedStats = (INT16)__min(100, (ubWisdom * 0.2) + (ubLeadership * 0.3) + (ubStrength * 0.1) + (ubExpLevel * 2) + (ubLocalLoyalty * 0.2) );
|
|
break;
|
|
case RISK_LOYALTY_GLOBAL:
|
|
bCombinedStats = (INT16)__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 (sAbsoluteMaxResult);
|
|
}
|
|
if (bCombinedStats <= 0)
|
|
{
|
|
// Character is completely inept? Strange. Automatic "worst" result.
|
|
return (sAbsoluteMinResult);
|
|
}
|
|
|
|
// 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.
|
|
iChance = iChance + ((bCombinedStats * iChance) / 100 );
|
|
}
|
|
else if (bBaseEffect < 0 )
|
|
{
|
|
// Chance decreases with good stats, increases with bad stats.
|
|
iChance = iChance - ((bCombinedStats * iChance) / 100 );
|
|
}
|
|
else
|
|
{
|
|
// Chance is unaffected
|
|
}
|
|
|
|
// Limit iChance into a 0 to 50000 range.
|
|
iChance = __max(0, __min(iChance, 50000));
|
|
|
|
// Alright, let's see if the event is triggered.
|
|
if (PreRandom(gGameExternalOptions.usFacilityEventRarity)>(UINT32)iChance)
|
|
{
|
|
// 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, sAbsoluteMaxResult);
|
|
bBaseEffect = __max(bBaseEffect, sAbsoluteMinResult);
|
|
|
|
// 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, sAbsoluteMaxResult);
|
|
Result = __max(Result, sAbsoluteMinResult);
|
|
|
|
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 && GetSoldierFacilityAssignmentIndex( pSoldier ) != -1)
|
|
{
|
|
// Soldier is working at a specific facility. Risks associated with this specific facility and assignment
|
|
// have priority.
|
|
ubAssignmentType = (UINT8)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].usChance > 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.
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
// SANDRO - if our stat is damaged through facility event, make it healable
|
|
if ( (-1*Result) > (pSoldier->stats.bStrength - 1))
|
|
Result = -1*(pSoldier->stats.bStrength - 1);
|
|
pSoldier->stats.bStrength += Result;
|
|
if ( gGameOptions.fNewTraitSystem && (Result <= 0) )
|
|
{
|
|
pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_STRENGTH ] -= Result;
|
|
}
|
|
else
|
|
{
|
|
// make this stat RED for a while...
|
|
pSoldier->timeChanges.uiChangeStrengthTime = GetJA2Clock();
|
|
pSoldier->usValueGoneUp &= ~( STRENGTH_INCREASE );
|
|
}
|
|
// Update Profile
|
|
gMercProfiles[ pSoldier->ubProfile ].bStrength = pSoldier->stats.bStrength;
|
|
|
|
// merc records - stat damaged
|
|
if( Result < 0 )
|
|
gMercProfiles[ pSoldier->ubProfile ].records.usTimesStatDamaged++;
|
|
|
|
gMercProfiles[ pSoldier->ubProfile ].records.usFacilityAccidents++;
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
fBadResult = TRUE;
|
|
|
|
// Log message
|
|
BuildStatChangeString( sString, pSoldier->GetName(), 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->GetName(), gzFacilityRiskResultStrings[0], szSectorGrid );
|
|
else
|
|
swprintf( sString, gzFacilityErrorMessage[18], pSoldier->GetName(), 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.
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
// SANDRO - if our stat is damaged through facility event, make it healable
|
|
if ( (-1*Result) > (pSoldier->stats.bAgility - 1))
|
|
Result = -1*(pSoldier->stats.bAgility - 1);
|
|
pSoldier->stats.bAgility += Result;
|
|
if ( gGameOptions.fNewTraitSystem && (Result <= 0) )
|
|
{
|
|
pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_AGILITY ] -= Result;
|
|
}
|
|
else
|
|
{
|
|
// make this stat RED for a while...
|
|
pSoldier->timeChanges.uiChangeAgilityTime = GetJA2Clock();
|
|
pSoldier->usValueGoneUp &= ~( AGIL_INCREASE );
|
|
}
|
|
// Update Profile
|
|
gMercProfiles[ pSoldier->ubProfile ].bAgility = pSoldier->stats.bAgility;
|
|
|
|
// merc records - stat damaged
|
|
if( Result < 0 )
|
|
gMercProfiles[ pSoldier->ubProfile ].records.usTimesStatDamaged++;
|
|
|
|
gMercProfiles[ pSoldier->ubProfile ].records.usFacilityAccidents++;
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
fBadResult = TRUE;
|
|
|
|
// Log message
|
|
BuildStatChangeString( sString, pSoldier->GetName(), 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->GetName(), gzFacilityRiskResultStrings[1], szSectorGrid );
|
|
else
|
|
swprintf( sString, gzFacilityErrorMessage[18], pSoldier->GetName(), 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.
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
// SANDRO - if our stat is damaged through facility event, make it healable
|
|
if ( (-1*Result) > (pSoldier->stats.bDexterity - 1))
|
|
Result = -1*(pSoldier->stats.bDexterity - 1);
|
|
pSoldier->stats.bDexterity += Result;
|
|
if ( gGameOptions.fNewTraitSystem && (Result <= 0) )
|
|
{
|
|
pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_DEXTERITY ] -= Result;
|
|
}
|
|
else
|
|
{
|
|
// make this stat RED for a while...
|
|
pSoldier->timeChanges.uiChangeDexterityTime = GetJA2Clock();
|
|
pSoldier->usValueGoneUp &= ~( DEX_INCREASE );
|
|
}
|
|
// Update Profile
|
|
gMercProfiles[ pSoldier->ubProfile ].bDexterity = pSoldier->stats.bDexterity;
|
|
|
|
// merc records - stat damaged
|
|
if( Result < 0 )
|
|
gMercProfiles[ pSoldier->ubProfile ].records.usTimesStatDamaged++;
|
|
|
|
gMercProfiles[ pSoldier->ubProfile ].records.usFacilityAccidents++;
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
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->GetName(), gzFacilityRiskResultStrings[2], szSectorGrid );
|
|
else
|
|
swprintf( sString, gzFacilityErrorMessage[18], pSoldier->GetName(), 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.
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
// SANDRO - if our stat is damaged through facility event, make it healable
|
|
if ( (-1*Result) > (pSoldier->stats.bWisdom - 1))
|
|
Result = -1*(pSoldier->stats.bWisdom - 1);
|
|
pSoldier->stats.bWisdom += Result;
|
|
if ( gGameOptions.fNewTraitSystem && (Result <= 0) )
|
|
{
|
|
pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_WISDOM ] -= Result;
|
|
}
|
|
else
|
|
{
|
|
// make this stat RED for a while...
|
|
pSoldier->timeChanges.uiChangeWisdomTime = GetJA2Clock();
|
|
pSoldier->usValueGoneUp &= ~( WIS_INCREASE );
|
|
}
|
|
// Update Profile
|
|
gMercProfiles[ pSoldier->ubProfile ].bWisdom = pSoldier->stats.bWisdom;
|
|
|
|
// merc records - stat damaged
|
|
if( Result < 0 )
|
|
gMercProfiles[ pSoldier->ubProfile ].records.usTimesStatDamaged++;
|
|
|
|
gMercProfiles[ pSoldier->ubProfile ].records.usFacilityAccidents++;
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
fBadResult = TRUE;
|
|
|
|
// Log message
|
|
BuildStatChangeString( sString, pSoldier->GetName(), 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->GetName(), gzFacilityRiskResultStrings[3], szSectorGrid );
|
|
else
|
|
swprintf( sString, gzFacilityErrorMessage[18], pSoldier->GetName(), 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.
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
// SANDRO - if our stat is damaged through facility event, make it healable
|
|
if ( (-1*Result) > (pSoldier->stats.bLifeMax - 1))
|
|
Result = -1*(pSoldier->stats.bLifeMax - 1);
|
|
pSoldier->stats.bLifeMax += Result;
|
|
pSoldier->stats.bLife += Result;
|
|
if ( gGameOptions.fNewTraitSystem && (Result <= 0) )
|
|
{
|
|
pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_HEALTH ] -= Result;
|
|
}
|
|
else
|
|
{
|
|
// make this stat RED for a while...
|
|
pSoldier->timeChanges.uiChangeHealthTime = GetJA2Clock();
|
|
pSoldier->usValueGoneUp &= ~( HEALTH_INCREASE );
|
|
}
|
|
// Update Profile
|
|
gMercProfiles[ pSoldier->ubProfile ].bLifeMax = pSoldier->stats.bLifeMax;
|
|
|
|
// merc records - stat damaged
|
|
if( Result < 0 )
|
|
gMercProfiles[ pSoldier->ubProfile ].records.usTimesStatDamaged++;
|
|
|
|
gMercProfiles[ pSoldier->ubProfile ].records.usFacilityAccidents++;
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
if (pSoldier->stats.bLife < OKLIFE)
|
|
{
|
|
HandleTakeDamageDeath( pSoldier, 0, TAKE_DAMAGE_BLOODLOSS );
|
|
}
|
|
fBadResult = TRUE;
|
|
|
|
// Log message
|
|
BuildStatChangeString( sString, pSoldier->GetName(), 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->GetName(), gzFacilityRiskResultStrings[4], szSectorGrid );
|
|
else
|
|
swprintf( sString, gzFacilityErrorMessage[18], pSoldier->GetName(), 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->GetName(), szSectorGrid );
|
|
else
|
|
swprintf( sString, gzFacilityErrorMessage[29], pSoldier->GetName(), 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.
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
// SANDRO - if our stat is damaged through facility event, make it healable
|
|
if ( (-1*Result) > (pSoldier->stats.bMarksmanship - 1))
|
|
Result = -1*(pSoldier->stats.bMarksmanship - 1);
|
|
pSoldier->stats.bMarksmanship += Result;
|
|
if ( gGameOptions.fNewTraitSystem && (Result <= 0) )
|
|
{
|
|
pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_MARKSMANSHIP ] -= Result;
|
|
}
|
|
else
|
|
{
|
|
// make this stat RED for a while...
|
|
pSoldier->timeChanges.uiChangeMarksmanshipTime = GetJA2Clock();
|
|
pSoldier->usValueGoneUp &= ~( MRK_INCREASE );
|
|
}
|
|
// Update Profile
|
|
gMercProfiles[ pSoldier->ubProfile ].bMarksmanship = pSoldier->stats.bMarksmanship;
|
|
|
|
// merc records - stat damaged
|
|
if( Result < 0 )
|
|
gMercProfiles[ pSoldier->ubProfile ].records.usTimesStatDamaged++;
|
|
|
|
gMercProfiles[ pSoldier->ubProfile ].records.usFacilityAccidents++;
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
fBadResult = TRUE;
|
|
|
|
// Log message
|
|
BuildStatChangeString( sString, pSoldier->GetName(), 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->GetName(), gzFacilityRiskResultStrings[5], szSectorGrid );
|
|
else
|
|
swprintf( sString, gzFacilityErrorMessage[18], pSoldier->GetName(), 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.
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
// SANDRO - if our stat is damaged through facility event, make it healable
|
|
if ( (-1*Result) > (pSoldier->stats.bLeadership - 1))
|
|
Result = -1*(pSoldier->stats.bLeadership - 1);
|
|
pSoldier->stats.bLeadership += Result;
|
|
if ( gGameOptions.fNewTraitSystem && (Result <= 0) )
|
|
{
|
|
pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_LEADERSHIP ] -= Result;
|
|
}
|
|
else
|
|
{
|
|
// make this stat RED for a while...
|
|
pSoldier->timeChanges.uiChangeLeadershipTime = GetJA2Clock();
|
|
pSoldier->usValueGoneUp &= ~( LDR_INCREASE );
|
|
}
|
|
// Update Profile
|
|
gMercProfiles[ pSoldier->ubProfile ].bLeadership = pSoldier->stats.bLeadership;
|
|
|
|
// merc records - stat damaged
|
|
if( Result < 0 )
|
|
gMercProfiles[ pSoldier->ubProfile ].records.usTimesStatDamaged++;
|
|
|
|
gMercProfiles[ pSoldier->ubProfile ].records.usFacilityAccidents++;
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
fBadResult = TRUE;
|
|
|
|
// Log message
|
|
BuildStatChangeString( sString, pSoldier->GetName(), 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->GetName(), gzFacilityRiskResultStrings[6], szSectorGrid );
|
|
else
|
|
swprintf( sString, gzFacilityErrorMessage[18], pSoldier->GetName(), 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.
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
// SANDRO - if our stat is damaged through facility event, make it healable
|
|
if ( (-1*Result) > (pSoldier->stats.bMechanical - 1))
|
|
Result = -1*(pSoldier->stats.bMechanical - 1);
|
|
pSoldier->stats.bMechanical += Result;
|
|
if ( gGameOptions.fNewTraitSystem && (Result <= 0) )
|
|
{
|
|
pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_MECHANICAL ] -= Result;
|
|
}
|
|
else
|
|
{
|
|
// make this stat RED for a while...
|
|
pSoldier->timeChanges.uiChangeMechanicalTime = GetJA2Clock();
|
|
pSoldier->usValueGoneUp &= ~( MECH_INCREASE );
|
|
}
|
|
// Update Profile
|
|
gMercProfiles[ pSoldier->ubProfile ].bMechanical = pSoldier->stats.bMechanical;
|
|
|
|
// merc records - stat damaged
|
|
if( Result < 0 )
|
|
gMercProfiles[ pSoldier->ubProfile ].records.usTimesStatDamaged++;
|
|
|
|
gMercProfiles[ pSoldier->ubProfile ].records.usFacilityAccidents++;
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
fBadResult = TRUE;
|
|
|
|
// Log message
|
|
BuildStatChangeString( sString, pSoldier->GetName(), 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->GetName(), gzFacilityRiskResultStrings[7], szSectorGrid );
|
|
else
|
|
swprintf( sString, gzFacilityErrorMessage[18], pSoldier->GetName(), 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.
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
// SANDRO - if our stat is damaged through facility event, make it healable
|
|
if ( (-1*Result) > (pSoldier->stats.bMedical - 1))
|
|
Result = -1*(pSoldier->stats.bMedical - 1);
|
|
pSoldier->stats.bMedical += Result;
|
|
if ( gGameOptions.fNewTraitSystem && (Result <= 0) )
|
|
{
|
|
pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_MEDICAL ] -= Result;
|
|
}
|
|
else
|
|
{
|
|
// make this stat RED for a while...
|
|
pSoldier->timeChanges.uiChangeMedicalTime = GetJA2Clock();
|
|
pSoldier->usValueGoneUp &= ~( MED_INCREASE );
|
|
}
|
|
// Update Profile
|
|
gMercProfiles[ pSoldier->ubProfile ].bMedical = pSoldier->stats.bMedical;
|
|
|
|
// merc records - stat damaged
|
|
if( Result < 0 )
|
|
gMercProfiles[ pSoldier->ubProfile ].records.usTimesStatDamaged++;
|
|
|
|
gMercProfiles[ pSoldier->ubProfile ].records.usFacilityAccidents++;
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
fBadResult = TRUE;
|
|
|
|
// Log message
|
|
BuildStatChangeString( sString, pSoldier->GetName(), 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->GetName(), gzFacilityRiskResultStrings[8], szSectorGrid );
|
|
else
|
|
swprintf( sString, gzFacilityErrorMessage[18], pSoldier->GetName(), 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.
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
// SANDRO - if our stat is damaged through facility event, make it healable
|
|
if ( (-1*Result) > (pSoldier->stats.bExplosive - 1))
|
|
Result = -1*(pSoldier->stats.bExplosive - 1);
|
|
pSoldier->stats.bExplosive += Result;
|
|
if ( gGameOptions.fNewTraitSystem && (Result <= 0) )
|
|
{
|
|
pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_EXPLOSIVES ] -= Result;
|
|
}
|
|
else
|
|
{
|
|
// make this stat RED for a while...
|
|
pSoldier->timeChanges.uiChangeExplosivesTime = GetJA2Clock();
|
|
pSoldier->usValueGoneUp &= ~( EXP_INCREASE );
|
|
}
|
|
// Update Profile
|
|
gMercProfiles[ pSoldier->ubProfile ].bExplosive = pSoldier->stats.bExplosive;
|
|
|
|
// merc records - stat damaged
|
|
if( Result < 0 )
|
|
gMercProfiles[ pSoldier->ubProfile ].records.usTimesStatDamaged++;
|
|
|
|
gMercProfiles[ pSoldier->ubProfile ].records.usFacilityAccidents++;
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
fBadResult = TRUE;
|
|
|
|
// Log message
|
|
BuildStatChangeString( sString, pSoldier->GetName(), 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->GetName(), gzFacilityRiskResultStrings[9], szSectorGrid );
|
|
else
|
|
swprintf( sString, gzFacilityErrorMessage[18], pSoldier->GetName(), 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;
|
|
|
|
// SANDRO - add to merc records - facility accidents counter
|
|
gMercProfiles[ pSoldier->ubProfile ].records.usFacilityAccidents++;
|
|
|
|
if (pSoldier->stats.bLife > 0)
|
|
{
|
|
if (pSoldier->bBleeding > MIN_BLEEDING_THRESHOLD)
|
|
{
|
|
// Log message
|
|
GetShortSectorString( pSoldier->sSectorX, pSoldier->sSectorY, szSectorGrid );
|
|
swprintf( sString, gzFacilityErrorMessage[31], pSoldier->GetName(), 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->GetName(), szSectorGrid );
|
|
else
|
|
swprintf( sString, gzFacilityErrorMessage[20], pSoldier->GetName(), 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->GetName(), 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->GetName(), szSectorGrid );
|
|
else
|
|
swprintf( sString, gzFacilityErrorMessage[22], pSoldier->GetName(), 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 );
|
|
// SANDRO - add to merc records - facility accidents counter
|
|
if ( Result < 0 )
|
|
gMercProfiles[ pSoldier->ubProfile ].records.usFacilityAccidents++;
|
|
break;
|
|
case RISK_FATIGUE:
|
|
pSoldier->bBreathMax = __min(100,__max(0, pSoldier->bBreathMax + Result));
|
|
pSoldier->bBreath = pSoldier->bBreathMax;
|
|
// SANDRO - add to merc records - facility accidents counter
|
|
if ( Result < 0 )
|
|
gMercProfiles[ pSoldier->ubProfile ].records.usFacilityAccidents++;
|
|
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->GetName() );
|
|
ScreenMsg( usColor, MSG_INTERFACE, sString );
|
|
}
|
|
|
|
// Add effects
|
|
CreateItem( ALCOHOL, Item[ALCOHOL].usPortionSize, &gTempObject );
|
|
|
|
ApplyConsumable( pSoldier, &gTempObject, TRUE, FALSE );
|
|
|
|
//pSoldier->AddDrugValues( DRUG_TYPE_ALCOHOL, Drug[DRUG_TYPE_ALCOHOL].ubDrugEffect, Drug[DRUG_TYPE_ALCOHOL].ubDrugTravelRate, Drug[DRUG_TYPE_ALCOHOL].ubDrugSideEffect );
|
|
|
|
/*// ATE: Make guy collapse from heart attack if too much stuff taken....
|
|
if ( pSoldier->drugs.bDrugSideEffectRate[ DRUG_TYPE_ALCOHOL ] > ( Drug[DRUG_TYPE_ALCOHOL].ubDrugSideEffect * 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 );
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////
|
|
// SANDRO - if our stat is damaged through facility event, make it healable
|
|
// Permanently lower certain stats...
|
|
if ( gGameOptions.fNewTraitSystem )
|
|
{
|
|
// WISDOM decrease
|
|
if ( pSoldier->stats.bWisdom > 5 )
|
|
{
|
|
pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_WISDOM ] += 5;
|
|
pSoldier->stats.bWisdom -= 5;
|
|
}
|
|
else
|
|
{
|
|
pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_WISDOM ] += (pSoldier->stats.bWisdom - 1);
|
|
pSoldier->stats.bWisdom = 1;
|
|
}
|
|
// DEXTERITY decrease
|
|
if ( pSoldier->stats.bDexterity > 5 )
|
|
{
|
|
pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_DEXTERITY ] += 5;
|
|
pSoldier->stats.bDexterity -= 5;
|
|
}
|
|
else
|
|
{
|
|
pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_DEXTERITY ] += (pSoldier->stats.bDexterity - 1);
|
|
pSoldier->stats.bDexterity = 1;
|
|
}
|
|
// STRENGTH decrease
|
|
if ( pSoldier->stats.bStrength > 5 )
|
|
{
|
|
pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_STRENGTH ] += 5;
|
|
pSoldier->stats.bStrength -= 5;
|
|
}
|
|
else
|
|
{
|
|
pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_STRENGTH ] += (pSoldier->stats.bStrength - 1);
|
|
pSoldier->stats.bStrength = 1;
|
|
}
|
|
// AGILITY decrease
|
|
if ( pSoldier->stats.bAgility > 5 )
|
|
{
|
|
pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_AGILITY ] += 5;
|
|
pSoldier->stats.bAgility -= 5;
|
|
}
|
|
else
|
|
{
|
|
pSoldier->ubCriticalStatDamage[ DAMAGED_STAT_AGILITY ] += (pSoldier->stats.bAgility - 1);
|
|
pSoldier->stats.bAgility = 1;
|
|
}
|
|
}
|
|
else // old system
|
|
{
|
|
pSoldier->stats.bAgility = __max(1, pSoldier->stats.bWisdom-5);
|
|
pSoldier->stats.bDexterity = __max(1, pSoldier->stats.bDexterity-5);
|
|
pSoldier->stats.bStrength = __max(1, pSoldier->stats.bStrength-5);
|
|
pSoldier->stats.bAgility = __max(1, pSoldier->stats.bAgility-5);
|
|
|
|
// make those stats RED for a while...
|
|
// SANDRO - we don't need to do this with new system, as we simply show all damaged stats in red until healed
|
|
pSoldier->timeChanges.uiChangeWisdomTime = GetJA2Clock();
|
|
pSoldier->usValueGoneUp &= ~( WIS_INCREASE );
|
|
pSoldier->timeChanges.uiChangeDexterityTime = GetJA2Clock();
|
|
pSoldier->usValueGoneUp &= ~( DEX_INCREASE );
|
|
pSoldier->timeChanges.uiChangeStrengthTime = GetJA2Clock();
|
|
pSoldier->usValueGoneUp &= ~( STRENGTH_INCREASE );
|
|
pSoldier->timeChanges.uiChangeAgilityTime = GetJA2Clock();
|
|
pSoldier->usValueGoneUp &= ~( AGIL_INCREASE );
|
|
}
|
|
|
|
// 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;
|
|
gMercProfiles[ pSoldier->ubProfile ].bAgility = pSoldier->stats.bAgility;
|
|
|
|
fBadResult = TRUE; // stop the time, call a doctor, we had a heart attack!
|
|
|
|
// merc records - stat damaged
|
|
gMercProfiles[ pSoldier->ubProfile ].records.usTimesStatDamaged++;
|
|
gMercProfiles[ pSoldier->ubProfile ].records.usFacilityAccidents++;
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
}*/
|
|
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->GetName() );
|
|
else
|
|
swprintf( sString, gzFacilityErrorMessage[24], pTownNames[ubTownID], pSoldier->GetName(), gFacilityTypes[ubFacilityType].szFacilityName );
|
|
ScreenMsg( usColor, MSG_INTERFACE, sString );
|
|
|
|
// SANDRO - add to merc records - facility accidents counter
|
|
if ( Result < 0 )
|
|
gMercProfiles[ pSoldier->ubProfile ].records.usFacilityAccidents++;
|
|
}
|
|
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->GetName(), szSectorGrid );
|
|
else
|
|
swprintf( sString, gzFacilityErrorMessage[26], pSoldier->GetName(), szSectorGrid, gFacilityTypes[ubFacilityType].szFacilityName );
|
|
ScreenMsg( usColor, MSG_INTERFACE, sString );
|
|
|
|
// SANDRO - add to merc records - facility accidents counter
|
|
if ( Result < 0 )
|
|
gMercProfiles[ pSoldier->ubProfile ].records.usFacilityAccidents++;
|
|
}
|
|
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 != NULL &&
|
|
pSoldier->stats.bLife >= OKLIFE &&
|
|
!(pSoldier->flags.fMercAsleep) )
|
|
{
|
|
INT8 ubAssignmentType = GetSoldierFacilityAssignmentIndex( pSoldier );
|
|
if (ubAssignmentType == -1)
|
|
{
|
|
// Skip this character.
|
|
ubCounter++;
|
|
continue;
|
|
}
|
|
|
|
//UINT8 ubSector = SECTOR(pSoldier->sSectorX, pSoldier->sSectorY);
|
|
INT16 ubFacilityType = pSoldier->sFacilityTypeOperated;
|
|
|
|
if (!fPositive && ubFacilityType != -1 && // 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 && ubFacilityType != -1 && // 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 accounts.
|
|
giTotalEarnedForFacilityOperationsToday = 0;
|
|
giTotalOwedForFacilityOperationsToday = 0;
|
|
gfOutstandingFacilityDebt = FALSE;
|
|
}
|