*************************

* 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
This commit is contained in:
Wanne
2010-02-20 15:49:46 +00:00
parent 53821fcf49
commit f010769397
120 changed files with 16937 additions and 2200 deletions
+2 -1
View File
@@ -1256,7 +1256,8 @@ void TestIncoming4SidesCallback( GUI_BUTTON *btn, INT32 reason )
UINT32 uiWorldMin;
Compression0Callback( ButtonList[ iViewerButton[ COMPRESSION0 ] ], MSYS_CALLBACK_REASON_LBUTTON_UP );
if( ( gsSelSectorX == 0 ) || ( gsSelSectorY == 0 ) )
gsSelSectorX = 9, gsSelSectorY = 1;
// HEADROCK HAM 3.5: Not sure what this function does at all... But this is externalized now anyway.
gsSelSectorX = gGameExternalOptions.ubDefaultArrivalSectorX, gsSelSectorY = gGameExternalOptions.ubDefaultArrivalSectorY;
ubSector = SECTOR( gsSelSectorX, gsSelSectorY );
uiWorldMin = GetWorldTotalMin();
+3553 -316
View File
File diff suppressed because it is too large Load Diff
+54 -5
View File
@@ -26,7 +26,7 @@
#define VEHICLE_REPAIR_POINTS_DIVISOR 10
// HEADROCK HAM 3.6: Added separate Mobile Militia training assignment.
// Assignments Defines
enum{
SQUAD_1 =0,
@@ -57,8 +57,11 @@ enum{
REPAIR,
TRAIN_SELF,
TRAIN_TOWN,
TRAIN_MOBILE, // HEADROCK HAM 3.6: Training mobile militia.
TRAIN_TEAMMATE,
TRAIN_BY_OTHER,
FACILITY_STAFF, // HEADROCK HAM 3.6: Operating a facility for strategic gain.
FACILITY_REST, // HEADROCK HAM 3.6: Facility equivalent of resting (no assignment)
ASSIGNMENT_DEAD,
ASSIGNMENT_UNCONCIOUS, // unused
ASSIGNMENT_POW,
@@ -83,6 +86,16 @@ enum{
// NOTE: Wisdom isn't trainable!
};
// HEADROCK HAM 3.2: Set bitwise flags for locating facilities in current sector (for training/otherwise)
// facilities flags
// HEADROCK HAM 3.4: Removed due to facility externalization.
/*#define AT_HOSPITAL 0x00000001
#define AT_INDUSTRY 0x00000002
#define AT_PRISON 0x00000004
#define AT_MILITARY 0x00000008
#define AT_AIRPORT 0x00000010
#define AT_GUN_RANGE 0x00000020*/
typedef struct TOWN_TRAINER_TYPE
{
@@ -106,6 +119,7 @@ BOOLEAN CanCharacterPatient( SOLDIERTYPE *pCharacter );
// can character train militia?
BOOLEAN CanCharacterTrainMilitia( SOLDIERTYPE *pCharacter );
BOOLEAN CanCharacterTrainMobileMilitia( SOLDIERTYPE *pSoldier );
// can character train stat?..as train self or as trainer?
BOOLEAN CanCharacterTrainStat( SOLDIERTYPE *pSoldier, INT8 bStat, BOOLEAN fTrainSelf, BOOLEAN fTrainTeammate );
@@ -116,6 +130,9 @@ BOOLEAN CanCharacterPractise( SOLDIERTYPE *pCharacter );
// can this character train others?
BOOLEAN CanCharacterTrainTeammates( SOLDIERTYPE *pSoldier );
// HEADROCK HAM 3.6: Can character use a specific facility?
BOOLEAN CanCharacterFacility( SOLDIERTYPE *pSoldier, UINT8 ubFacilityType, UINT8 ubAssignmentType );
// put character on duty?
BOOLEAN CanCharacterOnDuty( SOLDIERTYPE *pCharacter );
@@ -183,16 +200,18 @@ UINT8 CalculateRepairPointsForRepairman(SOLDIERTYPE *pSoldier, UINT16 *pusMaxPts
// get bonus tarining pts due to an instructor for this student
INT16 GetBonusTrainingPtsDueToInstructor( SOLDIERTYPE *pInstructor, SOLDIERTYPE *pStudent, INT8 bTrainStat, BOOLEAN fAtGunRange, UINT16 *pusMaxPts );
// HEADROCK HAM 3.5: Three functions below have lost an argument which is no longer required ("uiAtGunRange", which was "uiAtFacility" in HAM 3.4)
INT16 GetBonusTrainingPtsDueToInstructor( SOLDIERTYPE *pInstructor, SOLDIERTYPE *pStudent, INT8 bTrainStat, UINT16 *pusMaxPts );
// get training pts for this soldier
INT16 GetSoldierTrainingPts( SOLDIERTYPE *pSoldier, INT8 bTrainStat, BOOLEAN fAtGunRange, UINT16 *pusMaxPts );
INT16 GetSoldierTrainingPts( SOLDIERTYPE *pSoldier, INT8 bTrainStat, UINT16 *pusMaxPts );
// pts for being a student for this soldier
INT16 GetSoldierStudentPts( SOLDIERTYPE *pSoldier, INT8 bTrainStat, BOOLEAN fAtGunRange, UINT16 *pusMaxPts );
INT16 GetSoldierStudentPts( SOLDIERTYPE *pSoldier, INT8 bTrainStat, UINT16 *pusMaxPts );
// HEADROCK HAM 3.6: Completely unused.
// reset these soldiers
void ResetAssignmentsForAllSoldiersInSectorWhoAreTrainingTown( SOLDIERTYPE *pSoldier );
//void ResetAssignmentsForAllSoldiersInSectorWhoAreTrainingTown( SOLDIERTYPE *pSoldier );
// Handle assignment done
void AssignmentDone( SOLDIERTYPE *pSoldier, BOOLEAN fSayQuote, BOOLEAN fMeToo );
@@ -207,6 +226,9 @@ extern INT32 ghAttributeBox;
extern INT32 ghRemoveMercAssignBox;
extern INT32 ghContractBox;
extern INT32 ghMoveBox;
// HEADROCK HAM 3.6: Facility Menu, Submenu
extern INT32 ghFacilityBox;
extern INT32 ghFacilityAssignmentBox;
//extern INT32 ghUpdateBox;
@@ -219,6 +241,9 @@ extern MOUSE_REGION gSquadMenuRegion[ ];
extern MOUSE_REGION gContractMenuRegion[ ];
extern MOUSE_REGION gRemoveMercAssignRegion[ ];
extern MOUSE_REGION gVehicleMenuRegion[];
// HEADROCK HAM 3.6: Facility Menu.
extern MOUSE_REGION gFacilityMenuRegion[];
extern MOUSE_REGION gFacilityMenuRegion[];
extern BOOLEAN fShownContractMenu;
extern BOOLEAN fShownAssignmentMenu;
@@ -260,6 +285,16 @@ void CreateDestroyMouseRegionForRepairMenu( void );
void RepairMenuMvtCallback(MOUSE_REGION * pRegion, INT32 iReason );
void RepairMenuBtnCallback( MOUSE_REGION * pRegion, INT32 iReason );
// HEADROCK HAM 3.6: Facility Menu
void CreateDestroyMouseRegionForFacilityMenu( void );
void FacilityMenuMvtCallback(MOUSE_REGION * pRegion, INT32 iReason );
void FacilityMenuBtnCallback( MOUSE_REGION * pRegion, INT32 iReason );
// HEADROCK HAM 3.6: Facility sub-menu
void CreateDestroyMouseRegionsForFacilityAssignmentMenu( void );
void FacilityAssignmentMenuMvtCallBack( MOUSE_REGION * pRegion, INT32 iReason );
void FacilityAssignmentMenuBtnCallback( MOUSE_REGION * pRegion, INT32 iReason );
// contract menu
void CreateDestroyMouseRegionsForContractMenu( void );
void ContractMenuBtnCallback( MOUSE_REGION * pRegion, INT32 iReason );
@@ -334,6 +369,20 @@ void HandleTrainingWakeSynchronize( SOLDIERTYPE *pSoldier );
BOOLEAN FindAnyAwakeTrainers( SOLDIERTYPE *pTrainee );
BOOLEAN FindAnyAwakeTrainees( SOLDIERTYPE *pTrainer );
// HEADROCK HAM 3.6: Functions for testing and reporting reasons why character can't train here.
BOOLEAN CanCharacterTrainMilitiaWithErrorReport( SOLDIERTYPE *pSoldier );
BOOLEAN CanCharacterTrainMobileMilitiaWithErrorReport( SOLDIERTYPE *pSoldier );
// HEADROCK HAM 3.6: Function for testing and reporting reasons why character can't staff a facility.
BOOLEAN CanCharacterFacilityWithErrorReport( SOLDIERTYPE *pSoldier, UINT8 ubFacilityType, UINT8 ubAssignmentType );
void HandleInterfaceMessageForCostOfOperatingFacility( SOLDIERTYPE *pSoldier, UINT8 ubAssignmentType );
void PayFacilityCostsYesNoBoxCallback( UINT8 bExitValue );
void FacilityStaffingRejected( void );
void ResetAllExpensiveFacilityAssignments();
BOOLEAN IsOutstandingFacilityDebtWithErrorReport();
extern INT8 gubFacilityInSubmenu;
extern UINT8 gubFacilityLineForSubmenu;
extern SOLDIERTYPE *gpFacilityStaffer;
#endif
+4 -3
View File
@@ -339,7 +339,8 @@ void RenderSoldierCellHealth( SOLDIERCELL *pCell );
void RenderSoldierCell( SOLDIERCELL *pCell );
void RenderSoldierCellBars( SOLDIERCELL *pCell );
void GenerateDirectionInfos( INT16 sMapX, INT16 sMapY, UINT8* uiDirNumber, UINT16 pMoveDir[4][3], BOOLEAN fWithCities, BOOLEAN fForBattle, BOOLEAN fOnlyCitySectors );
// HEADROCK HAM 3.4: New argument configuration to make use of revamped movement controls
void GenerateDirectionInfos( INT16 sMapX, INT16 sMapY, UINT8* uiDirNumber, UINT16 pMoveDir[4][3], BOOLEAN fForTraining, BOOLEAN fForBattle );
//Dynamic globals -- to conserve memory, all global variables are allocated upon entry
@@ -2146,8 +2147,8 @@ void CreateAutoResolveInterface()
ARCreateMilitiaSquad( &cnt, ubEliteMilitia, ubRegMilitia, ubGreenMilitia, gpAR->ubSectorX, gpAR->ubSectorY);
// Add the militia in the surrounding sectors
GenerateDirectionInfos( gpAR->ubSectorX, gpAR->ubSectorY, &uiDirNumber, pMoveDir,
( GetTownIdForSector( gpAR->ubSectorX, gpAR->ubSectorY ) != BLANK_SECTOR ? TRUE : FALSE ), TRUE, FALSE );
// HEADROCK HAM 3.4: Changed argument configuration.
GenerateDirectionInfos( gpAR->ubSectorX, gpAR->ubSectorY, &uiDirNumber, pMoveDir, FALSE, TRUE );
for( i=0; i<uiDirNumber; i++)
{
INT16 sX = SECTORX( pMoveDir[ i ][0] );
+27 -3
View File
@@ -273,8 +273,28 @@ UNDERGROUND_SECTORINFO* NewUndergroundNode( UINT8 ubSectorX, UINT8 ubSectorY, UI
// setup which know facilities are in which cities
void InitKnowFacilitiesFlags( )
{
SECTORINFO *pSector;
/////////////////////////////////////////////////////////////////
// HEADROCK HAM 3.5: No longer required. Function disconnected.
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//SECTORINFO *pSector;
// HEADROCK HAM 3.4: Externalized. All "known" facilities are read from gFacilityLocations. The
// ones that have (fHidden=0) will be added to the sector info now, and thus visible immediately.
// The others are added only once the player visits those sectors.
/*for(UINT32 cnt=0; (gFacilityLocations[cnt].uiSectorID >= 0 && gFacilityLocations[cnt].uiSectorID <= 256); cnt++ )
{
// Is the current sector valid? Is the facility set to be revealed on game-start?
if (gFacilityLocations[cnt].uiSectorID > 0 && gFacilityLocations[cnt].uiSectorID < 257 &&
gFacilityLocations[cnt].fHidden == 0)
{
// Reveal the facility.
pSector = &SectorInfo[gFacilityLocations[cnt].uiSectorID];
pSector->uiFacilitiesFlags |= (1 << (gFacilityLocations[cnt].uiFacilityType-1));
}
}*/
/* HEADROCK HAM 3.4: Externalized.
// Cambria hospital
pSector = &SectorInfo[SEC_G8];
pSector->uiFacilitiesFlags |= SFCF_HOSPITAL;
@@ -304,6 +324,7 @@ void InitKnowFacilitiesFlags( )
pSector->uiFacilitiesFlags |= SFCF_AIRPORT;
pSector = &SectorInfo[SEC_O4];
pSector->uiFacilitiesFlags |= SFCF_AIRPORT;
*/
return;
}
@@ -603,13 +624,16 @@ void InitNewCampaign()
InitWorld(); // Lesh: generate different world each time using alternative maps
InitMiningLocations();
InitKnowFacilitiesFlags( );
// HEADROCK HAM 3.5: This is no longer required.
//InitKnowFacilitiesFlags( );
BuildUndergroundSectorInfoList();
if (!is_networked)
// allow overhead view of omerta A9 on game onset
SetSectorFlag( startingX, startingY, startingZ, SF_ALREADY_VISITED ); //hayden
// HEADROCK HAM 3.5: Externalized.
SetSectorFlag( gGameExternalOptions.ubDefaultArrivalSectorX, gGameExternalOptions.ubDefaultArrivalSectorY, startingZ, SF_ALREADY_VISITED ); //hayden
//Generates the initial forces in a new campaign. The idea is to randomize numbers and sectors
//so that no two games are the same.
+210 -8
View File
@@ -112,19 +112,214 @@ enum
MAX_MILITIA_LEVELS
};
// facilities flags
// HEADROCK HAM 3.5: No longer needed. Facility types externalized.
/*// facilities flags
#define SFCF_HOSPITAL 0x00000001
#define SFCF_INDUSTRY 0x00000002
#define SFCF_PRISON 0x00000004
#define SFCF_MILITARY 0x00000008
#define SFCF_AIRPORT 0x00000010
#define SFCF_GUN_RANGE 0x00000020
#define SFCF_GUN_RANGE 0x00000020*/
// coordinates of shooting range sector
// HEADROCK HAM 3.4: These are no longer needed anywhere in the code.
/*// coordinates of shooting range sector
#define GUN_RANGE_X 13
#define GUN_RANGE_Y MAP_ROW_H
#define GUN_RANGE_Z 0
// HEADROCK HAM 3.2: New values for the location of an Industrial sector in Grumm H2. This sector boosts repair rates.
#define INDUSTRIAL_X 2
#define INDUSTRIAL_Y MAP_ROW_H
#define INDUSTRIAL_Z 0*/
// HEADROCK HAM 3.4: Facility Locations
typedef struct FACILITYLOCATIONS
{
BOOLEAN fFacilityHere;
UINT8 ubHidden;
}FACILITYLOCATIONS;
enum
{
// Enumerate the different assignments that a facility can emulate.
FAC_AMBIENT = 0,
FAC_STAFF,
FAC_REST,
FAC_REPAIR_ITEMS,
FAC_REPAIR_VEHICLE,
FAC_REPAIR_ROBOT,
FAC_DOCTOR,
FAC_PATIENT,
FAC_PRACTICE_STRENGTH,
FAC_PRACTICE_DEXTERITY,
FAC_PRACTICE_AGILITY,
FAC_PRACTICE_HEALTH,
FAC_PRACTICE_MARKSMANSHIP,
FAC_PRACTICE_MEDICAL,
FAC_PRACTICE_MECHANICAL,
FAC_PRACTICE_LEADERSHIP,
FAC_PRACTICE_EXPLOSIVES,
FAC_STUDENT_STRENGTH,
FAC_STUDENT_DEXTERITY,
FAC_STUDENT_AGILITY,
FAC_STUDENT_HEALTH,
FAC_STUDENT_MARKSMANSHIP,
FAC_STUDENT_MEDICAL,
FAC_STUDENT_MECHANICAL,
FAC_STUDENT_LEADERSHIP,
FAC_STUDENT_EXPLOSIVES,
FAC_TRAINER_STRENGTH,
FAC_TRAINER_DEXTERITY,
FAC_TRAINER_AGILITY,
FAC_TRAINER_HEALTH,
FAC_TRAINER_MARKSMANSHIP,
FAC_TRAINER_MEDICAL,
FAC_TRAINER_MECHANICAL,
FAC_TRAINER_LEADERSHIP,
FAC_TRAINER_EXPLOSIVES,
NUM_FACILITY_ASSIGNMENTS,
};
// Enumerated list of risk types
enum
{
RISK_STRENGTH = 0,
RISK_HEALTH,
RISK_AGILITY,
RISK_DEXTERITY,
RISK_WISDOM,
RISK_MARKSMANSHIP,
RISK_LEADERSHIP,
RISK_EXPLOSIVES,
RISK_MECHANICAL,
RISK_MEDICAL,
RISK_INJURY,
RISK_MORALE,
RISK_FATIGUE,
RISK_DRUNK,
RISK_LOYALTY_LOCAL,
RISK_LOYALTY_GLOBAL,
NUM_RISKS,
};
typedef struct FACILITYRISKTYPE
{
// The risks involved with perfoming an assignment at a specific facility.
UINT8 ubChance; // Chance out of X that this risk will trigger every hour. X is INI-defined and is normally 1000.
INT8 bBaseEffect; // Base result. If negative, result will always be negative. If positive, result will always be positive.
// If 0, result can be either negative or positive.
UINT8 ubRange; // Range of deviation for the base effect.
} FACILITYRISKTYPE;
typedef struct FACILITYASSIGNMENTTYPE
{
// This contains data about performing a specific assignment at a specific facility.
UINT8 ubStaffLimit; // Maximum number of people who can perform this assignment simultaneously
CHAR16 szTooltipText[300]; // Tooltip explaining the assignment in general terms.
INT16 sCostPerHour; // Cost per hour. Can be negative to indicate FLAT PROFIT per hour.
UINT16 usPerformance; // Percentage effectiveness of this assignment compared to non-emulated assignment (100 = normal)
UINT16 usFatigue; // Percentage speed of losing Max Breath (100 = normal)
UINT16 usSleep; // Percentage effectiveness of sleeping on the job (100 = normal)
UINT16 usKitDegrade; // Percentage speed of kit degrade (100 = normal)
UINT8 ubMaximumMorale; // Maximum morale achievable while performing this assignment
UINT8 ubMaximumBreath; // Maximum breath achievable while performing this assignment
UINT8 ubDetectEnemiesImmediate; // Detection of enemies in adjacent sectors, value = range of detection.
BOOLEAN fDetectEnemiesLongrange; // Detection of enemies in explored territory
BOOLEAN fDetectEnemiesDynamic; // Detection of enemies in Mobile Militia areas
BOOLEAN fDetectEnemiesAnywhere; // Detection of enemies all over the map
BOOLEAN fCountEnemiesInWild; // Count number of enemies in wilderness sectors
BOOLEAN fCountEnemiesInCities; // Count number of enemies in city sectors
INT16 sSkyriderCostModifier; // Flat modifier for Skyrider's Cost Per Tile
UINT16 usMineIncomeModifier; // Percentage income adjustment
BOOLEAN fOnlyLocalMineAffected; // Determines whether income modifier applies to local mine only, or all mines.
UINT8 ubMinimumStrength; // Minimum STR Requirement to begin this assignment
UINT8 ubMinimumHealth; // Minimum HLT Requirement to begin this assignment
UINT8 ubMinimumWisdom; // Minimum WIS Requirement to begin this assignment
UINT8 ubMinimumAgility; // Minimum AGI Requirement to begin this assignment
UINT8 ubMinimumDexterity; // Minimum DEX Requirement to begin this assignment
UINT8 ubMinimumMarksmanship; // Minimum MRK Requirement to begin this assignment
UINT8 ubMinimumLeadership; // Minimum LDR Requirement to begin this assignment
UINT8 ubMinimumExplosives; // Minimum EXP Requirement to begin this assignment
UINT8 ubMinimumMechanical; // Minimum MEC Requirement to begin this assignment
UINT8 ubMinimumMedical; // Minimum MED Requirement to begin this assignment
UINT8 ubMinimumLevel; // Minimum LVL Requirement to begin this assignment
UINT8 ubMinimumLoyaltyHere; // Minimum loyalty required in the town where the facility is placed (if any)
UINT8 ubMinimumBreath; // Minimum Breath Requirement to begin this assignment
UINT8 ubMinimumMorale; // Minimum Morale Requirement to begin this assignment
FACILITYRISKTYPE Risk[ NUM_RISKS ]; // Data about risks/chances possible when doing this assignment
} FACILITYASSIGNMENTTYPE;
// HEADROCK HAM 3.5: Facility Type
typedef struct FACILITYTYPE
{
// Basic data about the facility
CHAR16 szFacilityName[30]; // Long facility name
CHAR16 szFacilityShortName[15]; // Short facility name
UINT8 ubTotalStaffLimit; // Total number of people who can work here simultaneously
UINT8 ubMilitiaTrainersAllowed; // Number of Militia trainers allowed simultaneously
UINT8 ubMobileMilitiaTrainersAllowed; // Number of Mobile Militia trainers allowed simultaneously
UINT16 usMilitiaTraining; // Percentage effectiveness of Militia training (100 = normal)
UINT16 usMobileMilitiaTraining; // Percentage effectiveness of Mobile Militia training (100 = normal)
FACILITYASSIGNMENTTYPE AssignmentData[ NUM_FACILITY_ASSIGNMENTS ]; // Data about possible assignments that can be done here
} FACILITYTYPE;
// HEADROCK HAM 3.5: Maximum number of different facility types
#define MAX_NUM_FACILITY_TYPES 255
// HEADROCK HAM 3.5: Number of facilities placed on the map
extern UINT16 NUM_FACILITIES;
// HEADROCK HAM 3.5: Number of facility types read from XML
extern UINT16 NUM_FACILITY_TYPES;
// HEADROCK HAM 3.4: Array to hold facilities in each sector
extern FACILITYLOCATIONS gFacilityLocations[256][MAX_NUM_FACILITY_TYPES];
// HEADROCK HAM 3.5: Array to hold all different facility types
extern FACILITYTYPE gFacilityTypes[MAX_NUM_FACILITY_TYPES];
// HEADROCK HAM 3.6: Bloodcat Placement and Encounter data.
typedef struct BLOODCATPLACEMENT
{
UINT8 PlacementType;
UINT8 ubMinBloodcats;
UINT8 ubMaxBloodcats;
UINT8 ubAmbushChance;
BOOLEAN ubFactionAffiliation;
BOOLEAN fRespawn;
}BLOODCATPLACEMENT;
// HEADROCK HAM 3.6: Array to hold bloodcat placements and user-set bloodcat encounter data. There are 256 of these
// (one for each sector), with 4 sublevels (one for each difficulty)
extern BLOODCATPLACEMENT gBloodcatPlacements[256][4];
// Location of the Bloodcat Lair. There can be only one, as there's a quest that relies on its location. This is a
// sectorID, 0-255.
extern UINT8 gubBloodcatLairSectorId;
// HEADROCK HAM 3.6: Enumerated Bloodcat Placement types
enum
{
BLOODCAT_PLACEMENT_AMBUSH = 0,
BLOODCAT_PLACEMENT_STATIC,
BLOODCAT_PLACEMENT_LAIR,
NUM_BLOODCAT_PLACEMENT_TYPES
};
//Vehicle types
#define FOOT 0x01 //anywhere
@@ -227,8 +422,8 @@ typedef struct SECTORINFO
//throught the sector without entering it.
INT8 bNameId;
INT8 bUSUSED;
INT8 bBloodCats;
INT8 bBloodCatPlacements;
INT8 bBloodCats; // Actual number of bloodcats existing on this map.
INT8 bBloodCatPlacements; // "Maximum" potential bloodcats that can appear on this map.
INT8 UNUSEDbSAMCondition;
UINT8 ubTravelRating; //Represents how travelled a sector is. Typically, the higher the travel rating,
@@ -236,15 +431,22 @@ typedef struct SECTORINFO
//around. This value is used for determining how often items would "vanish" from
//a sector (nice theory, except it isn't being used that way. Stealing is only in towns. ARM)
UINT8 ubNumberOfCivsAtLevel[ MAX_MILITIA_LEVELS ]; // town militia per experience class, 0/1/2 is GREEN/REGULAR/ELITE
UINT16 usUNUSEDMilitiaLevels; // unused (ARM)
UINT8 ubUNUSEDNumberOfJoeBlowCivilians; // unused (ARM)
// HEADROCK HAM 3.6: Adding separate training percentage for MOBILES.
UINT8 ubMobileMilitiaTrainingPercentDone;
UINT8 ubMobileMilitiaTrainingHundredths;
BOOLEAN fMobileMilitiaTrainingPaid;
// Replacing these variables with the ones above. They really are unused.
//UINT16 usUNUSEDMilitiaLevels; // unused (ARM)
//UINT8 ubUNUSEDNumberOfJoeBlowCivilians; // unused (ARM)
UINT32 uiTimeCurrentSectorWasLastLoaded; //Specifies the last time the player was in the sector
UINT8 ubUNUSEDNumberOfEnemiesThoughtToBeHere; // using bLastKnownEnemies instead
UINT32 uiTimeLastPlayerLiberated; //in game seconds (used to prevent the queen from attacking for awhile)
BOOLEAN fSurfaceWasEverPlayerControlled;
UINT8 bFiller1;
// HEADROCK HAM 3.6: Flag to determine whether enemy units in this sector can be seen, and whether their numbers
// should be displayed. One filler was replaced to make room.
UINT8 ubDetectionLevel;
UINT8 bFiller2;
UINT8 bFiller3;
File diff suppressed because it is too large Load Diff
+78
View File
@@ -0,0 +1,78 @@
#ifndef _FACILITIES_H
#define _FACILITIES_H
#include "campaign types.h"
#include "Soldier Control.h"
// Get a specific modifier for a specific assignment at a specific facility. Includes Ambient (non-assignment based)
// effects, if any.
INT16 GetFacilityModifier( UINT8 ubModifierType, UINT8 ubFacilityType, UINT8 ubAssignmentType );
// Get a specific modifier from all facilities in the soldier's sector. This utilizes the above function.
INT16 GetSectorModifier( SOLDIERTYPE *pSoldier, UINT8 ubModifierType );
// Level of awareness to enemy movements, bestowed by facilities
extern void UpdateStrategicDetectionLevel( );
// Adjustment to Skyrider's cost-per-tile, bestowed by facilities
extern void UpdateSkyriderCostModifier( );
extern INT16 gsSkyriderCostModifier; // This variable is SAVED/LOADED
// 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).
extern INT32 giTotalOwedForFacilityOperationsToday; // This variable is SAVED and LOADED.
// Do we have outstanding debts for facility operation?
extern BOOLEAN gfOutstandingFacilityDebt; // This variable is SAVED and LOADED.
// Place this here for facility staffing checks.
extern UINT32 GetWorldTotalMin( );
// These are all the different modifiers we could be checking for.
enum
{
FACILITY_PERFORMANCE_MOD = 0,
FACILITY_SLEEP_MOD,
FACILITY_FATIGUE_MOD,
FACILITY_KIT_DEGRADE_MOD,
FACILITY_MAX_MORALE,
FACILITY_MAX_BREATH,
FACILITY_DETECT_IMMEDIATE,
FACILITY_DETECT_DYNAMIC,
FACILITY_DETECT_LONGRANGE,
FACILITY_DETECT_ANYWHERE,
FACILITY_COUNT_INWILD,
FACILITY_COUNT_INCITIES,
FACILITY_MINE_INCOME_MOD,
FACILITY_SKYRIDER_COST_MOD,
};
// HEADROCK HAM 3.6: Different enemy detection and counting levels
enum
{
DETECT_ENEMIES_DYNAMIC = 0,
DETECT_ENEMIES_LONGRANGE,
DETECT_ENEMIES_ANYWHERE,
COUNT_ENEMIES_IN_WILD,
COUNT_ENEMIES_IN_CITIES,
};
void UpdateGlobalVariablesFromFacilities( void );
void UpdateFacilityUsageCosts( void );
void HandleDailyPaymentFacilityDebt( void );
void HandleManualPaymentFacilityDebt( void );
void HandleHourlyRisks( void );
INT32 MineIncomeModifierFromFacility( UINT8 ubMine );
INT8 GetSoldierFacilityAssignmentIndex( SOLDIERTYPE *pSoldier );
void HandleRisksForSoldier( SOLDIERTYPE *pSoldier );
void HandleRisksForSoldierFacilityAssignment( SOLDIERTYPE *pSoldier, UINT8 ubFacilityType, UINT8 ubAssignmentType );
INT16 FacilityRiskResult( SOLDIERTYPE *pSoldier, UINT8 ubRiskType, UINT8 ubFacilityType, UINT8 ubAssignmentType );
INT32 GetTotalFacilityHourlyCosts( BOOLEAN fPositive );
void InitFacilities();
#endif
+78 -2
View File
@@ -61,6 +61,8 @@
#include "Interface.h"
#include "cheats.h"
#include "Interface Panels.h"
// HEADROCK HAM 3.6: Include for adding facility debt reset
#include "Facilities.h"
#endif
#include "Vehicles.h"
@@ -233,6 +235,64 @@ void InitNPCs( void )
void InitBloodCatSectors()
{
///////////////////////////////////////////////////
// HEADROCK HAM 3.6: Bloodcat Placement Externalization
//
// It is now possible for the user/modder to set the maximum number of bloodcats that may appear in the sector.
// We can now place bloodcats anywhere we'd like (aboveground), stretching the limits of maps without disturbing
// the game. The placements defined here are still the absolute MAXIMUM, so if the map has more placements available
// they will be ignored.
// Please note that if the mapfile has LESS placements than indicated here, then the game will reduce the number of
// placements automatically to fit the MAP, not the XML.
UINT16 x = 0;
UINT8 PlacementType = 0;
UINT8 ubMaxBloodcats = 0;
UINT8 ubDifficulty = gGameOptions.ubDifficultyLevel-1; // This way, novice=0.
INT16 ubLairSectorId = -1; // Location of ONE lair sector (the first one found)
// Clean all bloodcat data.
for( x = 0; x < 256; x++ )
{
SectorInfo[ x ].bBloodCats = 0;
SectorInfo[ x ].bBloodCatPlacements = 0;
}
// Begin loop for every sector.
for (x = 0; x < 256; x++)
{
// Set "maximum placements" value to whatever is defined in the XML file for this difficulty level.
SectorInfo[ x ].bBloodCatPlacements = gBloodcatPlacements[x][ubDifficulty].ubMaxBloodcats;
PlacementType = gBloodcatPlacements[x][0].PlacementType;
// Record the first sector you can find which is defined as a LAIR sector. Only one sector can serve
// this purpose, because the quests rely on it.
if (PlacementType == BLOODCAT_PLACEMENT_LAIR && ubLairSectorId == -1)
{
ubLairSectorId = x;
}
if (PlacementType != 0)
{
// Sector is a lair or static bloodcat sector. Fill it up with actual bloodcats please.
SectorInfo[ x ].bBloodCats = gBloodcatPlacements[x][ubDifficulty].ubMaxBloodcats;
// "Ambush" sectors (PlacementType 0) do not have bloodcats in them until triggered.
}
}
if (ubLairSectorId >= 0)
{
gubBloodcatLairSectorId = (UINT8)ubLairSectorId;
}
else
{
THROWEXCEPTION(L"At least one Bloodcat Lair must be defined in BloodcatPlacements.XML!");
}
/*
INT32 i;
//Hard coded table of bloodcat populations. We don't have
//access to the real population (if different) until we physically
@@ -296,7 +356,7 @@ void InitBloodCatSectors()
SectorInfo[ SEC_N5 ].bBloodCatPlacements = 18;
SectorInfo[ SEC_N5 ].bBloodCats = 18;
break;
}
}*/
}
@@ -334,6 +394,8 @@ void InitStrategicLayer( void )
// make Orta, Tixa, SAM sites not found
InitMapSecrets();
// HEADROCK HAM 3.6: Initialize facilities.
InitFacilities();
// free up any leave list arrays that were left allocated
ShutDownLeaveList( );
@@ -344,7 +406,8 @@ void InitStrategicLayer( void )
SetGameTimeCompressionLevel( TIME_COMPRESS_X0 );
// select A9 Omerta as the initial selected sector
ChangeSelectedMapSector( startingX, startingY, startingZ );
// HEADROCK HAM 3.5: Actually, this is where we set the starting sector based on external variables.
ChangeSelectedMapSector( gGameExternalOptions.ubDefaultArrivalSectorX, gGameExternalOptions.ubDefaultArrivalSectorY, startingZ );
// Reset these flags or mapscreen could be disabled and cause major headache.
fDisableDueToBattleRoster = FALSE;
@@ -498,6 +561,10 @@ BOOLEAN InitNewGame( BOOLEAN fReset )
AddFutureDayStrategicEvent( EVENT_DAY3_ADD_EMAIL_FROM_SPECK, 60*7, 0, uiDaysTimeMercSiteAvailable );
}
// HEADROCK HAM 3.5: Reset LZ to default arrival
gsMercArriveSectorX = gGameExternalOptions.ubDefaultArrivalSectorX;
gsMercArriveSectorY = gGameExternalOptions.ubDefaultArrivalSectorY;
#ifdef CRIPPLED_VERSION
{
UINT32 cnt;
@@ -864,6 +931,15 @@ void ReStartingGame()
//Reload the Merc profiles
LoadMercProfiles( );
if (gGameExternalOptions.fWriteProfileDataToXML)
{
// HEADROCK PROFEX: Create mercprofiles xml output
WriteMercProfiles();
// HEADROCK PROFEX: Create mercopinions xml output
WriteMercOpinions();
}
// Reload quote files
ReloadAllQuoteFiles();
+10
View File
@@ -24,6 +24,8 @@
#include "SaveLoadGame.h"
#include "GameSettings.h"
#include "connect.h"
// HEADROCK HAM 3.5: Add facility code for hourly update of detection levels
#include "Facilities.h"
void HourlyQuestUpdate( void );
void HourlyLarryUpdate( void );
@@ -56,9 +58,17 @@ void HandleHourlyUpdate()
// hourly update of team assignments
UpdateAssignments();
// HEADROCK HAM 3.5: Tells the rest of the program whether we've got mercs working on detecting enemy units.
UpdateStrategicDetectionLevel();
// HEADROCK HAM 3.5: Re-calculates a modifier to Skyrider's flight costs based on mercs working in specific facilities.
UpdateSkyriderCostModifier();
// hourly update of hated/liked mercs
UpdateBuddyAndHatedCounters();
HandleHourlyRisks();
// update morale!
HourlyMoraleUpdate();
+11 -2
View File
@@ -38,6 +38,8 @@
#include "soundman.h"
#include "Isometric Utils.h"
#include "Scheduling.h"
// HEADROCK HAM 3.5: Added facility-based skyrider costs modifier
#include "Facilities.h"
#endif
@@ -527,16 +529,23 @@ INT32 GetCostOfPassageForHelicopter( INT16 sX, INT16 sY )
// check if sector is air controlled or not, if so, then normal cost, otherwise increase the cost
INT32 iCost = 0;
// HEADROCK HAM 3.5: Costs externalized
INT32 iBaseCostPerGreenTile = gGameExternalOptions.usHelicopterBaseCostPerGreenTile;
INT32 iBaseCostPerRedTile = gGameExternalOptions.usHelicopterBaseCostPerRedTile;
// if they don't control it
if( StrategicMap[ CALCULATE_STRATEGIC_INDEX( sX, sY ) ].fEnemyAirControlled == FALSE )
{
iCost = COST_AIRSPACE_SAFE;
iCost = iBaseCostPerGreenTile;
}
else
{
iCost = COST_AIRSPACE_UNSAFE;
iCost = iBaseCostPerRedTile;
}
// HEADROCK HAM 3.5: Apply facility-based modifiers from global integer recalculated hourly
iCost = __max(0, iCost + gsSkyriderCostModifier);
return( iCost );
}
+3 -1
View File
@@ -773,7 +773,9 @@ void ToggleShowMilitiaMode( void )
// no - so put up a message explaining how it works
// if he's already training some
if( IsAnyOneOnPlayersTeamOnThisAssignment( TRAIN_TOWN ) )
// HEADROCK HAM 3.6: Also for Mobile trainers.
if( IsAnyOneOnPlayersTeamOnThisAssignment( TRAIN_TOWN ) ||
IsAnyOneOnPlayersTeamOnThisAssignment( TRAIN_MOBILE ) )
{
// say they'll show up when training is completed
pwString = pMapErrorString[ 28 ];
+105 -16
View File
@@ -68,8 +68,12 @@ want to have the new inventory panel not overlap the message text area. */
#define MESSAGE_SCROLL_AREA_HEIGHT ( MESSAGE_SCROLL_AREA_END_Y - MESSAGE_SCROLL_AREA_START_Y + 1 )
// CHRISL: Use these if we want scroll bar based on left edge of screen
#define MESSAGE_SCROLL_AREA_START_X 330
#define MESSAGE_SCROLL_AREA_END_X 344
// HEADROCK HAM 3.6: Now global variables to be changed when initializing map mode.
// See InitMapScreenInterfaceBottomCoords()
//#define MESSAGE_SCROLL_AREA_START_X 330
//#define MESSAGE_SCROLL_AREA_END_X 344
UINT16 MESSAGE_SCROLL_AREA_START_X;
UINT16 MESSAGE_SCROLL_AREA_END_X;
#define SLIDER_HEIGHT 11
#define SLIDER_WIDTH 11
@@ -184,6 +188,7 @@ void DeleteMapScreenBottomMessageScrollRegion( void );
void DisplayCurrentBalanceForMapBottom( void );
void DisplayCurrentBalanceTitleForMapBottom( void );
void DisplayProjectedDailyMineIncome( void );
void DisplayProjectedDailyExpenses( void ); // HEADROCK HAM 3.6: New expenses window shows running costs today.
void DrawNameOfLoadedSector( void );
void EnableDisableBottomButtonsAndRegions( void );
@@ -296,7 +301,8 @@ void RenderMapScreenInterfaceBottom( BOOLEAN fForceMapscreenFullRender )
// render whole panel
// HEADROCK Changed this line to accept outside influence through the new boolean:
//if ( fForceMapscreenFullRender == TRUE || fMapScreenBottomDirty == TRUE)
if ( fMapScreenBottomDirty )
// HEADROCK HAM 3.6: OK, let's always render this panel, as long as the team inventory screen isn't open.
if ( fMapScreenBottomDirty || !fShowInventoryFlag )
{
// get and blt panel
GetVideoObject(&hHandle, guiMAPBOTTOMPANEL );
@@ -334,12 +340,20 @@ void RenderMapScreenInterfaceBottom( BOOLEAN fForceMapscreenFullRender )
// Headrock: Moved this next line from the above marker ^
fMapScreenBottomDirty = FALSE;
// CHRISL: Don't display messagelist if inventory panel is open
// CHRISL: Only run this condition if we're drawing the message list on the left
// display messages that can be scrolled through
// HEADROCK HAM 3.6: Hmmmm, why not draw them? LEt's just move this whole segment here, shall we?
//if(!fShowInventoryFlag)
DisplayStringsInMapScreenMessageList( );
}
DisplayCompressMode( );
DisplayCurrentBalanceForMapBottom( );
DisplayProjectedDailyMineIncome( );
DisplayProjectedDailyExpenses( );
// draw the name of the loaded sector
DrawNameOfLoadedSector( );
@@ -347,12 +361,7 @@ void RenderMapScreenInterfaceBottom( BOOLEAN fForceMapscreenFullRender )
// display slider on the scroll bar
DisplayScrollBarSlider( );
// CHRISL: Don't display messagelist if inventory panel is open
// CHRISL: Only run this condition if we're drawing the message list on the left
// display messages that can be scrolled through
if(!fShowInventoryFlag)
DisplayStringsInMapScreenMessageList( );
// handle auto scroll
//CheckForAndHandleAutoMessageScroll( );
@@ -427,10 +436,12 @@ BOOLEAN CreateButtonsForMapScreenInterfaceBottom( void )
// BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1,
// (GUI_CALLBACK)BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnMessageDownMapScreenCallback);
// CHRISL: Use these if we want buttons based on left edge of screen
guiMapMessageScrollButtons[ MAP_SCROLL_MESSAGE_UP ] = QuickCreateButton( guiMapMessageScrollButtonsImage[ MAP_SCROLL_MESSAGE_UP ], 331, (SCREEN_HEIGHT - 109),
// HEADROCK HAM 3.6: Message window is now as wide as possible.
guiMapMessageScrollButtons[ MAP_SCROLL_MESSAGE_UP ] = QuickCreateButton( guiMapMessageScrollButtonsImage[ MAP_SCROLL_MESSAGE_UP ], (SCREEN_WIDTH - 306), (SCREEN_HEIGHT - 109),
BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1,
(GUI_CALLBACK)BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnMessageUpMapScreenCallback);
guiMapMessageScrollButtons[ MAP_SCROLL_MESSAGE_DOWN ] = QuickCreateButton( guiMapMessageScrollButtonsImage[ MAP_SCROLL_MESSAGE_DOWN ], 331, (SCREEN_HEIGHT - 28),
guiMapMessageScrollButtons[ MAP_SCROLL_MESSAGE_DOWN ] = QuickCreateButton( guiMapMessageScrollButtonsImage[ MAP_SCROLL_MESSAGE_DOWN ], (SCREEN_WIDTH - 306), (SCREEN_HEIGHT - 28),
BUTTON_TOGGLE, MSYS_PRIORITY_HIGHEST - 1,
(GUI_CALLBACK)BtnGenericMouseMoveButtonCallback, (GUI_CALLBACK)BtnMessageDownMapScreenCallback);
@@ -1334,7 +1345,8 @@ BOOLEAN AllowedToTimeCompress( void )
return( FALSE );
}
if( fShowAssignmentMenu || fShowTrainingMenu || fShowAttributeMenu || fShowSquadMenu || fShowContractMenu || fShowRemoveMenu )
// HEADROCK HAM 3.6: Added Facility Menus
if( fShowAssignmentMenu || fShowTrainingMenu || fShowAttributeMenu || fShowSquadMenu || fShowContractMenu || fShowRemoveMenu || fShowFacilityAssignmentMenu || fShowFacilityMenu )
{
return( FALSE );
}
@@ -1428,7 +1440,9 @@ void DisplayCurrentBalanceTitleForMapBottom( void )
// CHRISL: Replaced X coordinate with dynamic coordinate set from right edge of screen
//VarFindFontCenterCoordinates( (SCREEN_WIDTH - 637), (SCREEN_HEIGHT - 107), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
// CHRISL: Use this if we want to display from the left edge
VarFindFontCenterCoordinates( 359, (SCREEN_HEIGHT - 107), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
//VarFindFontCenterCoordinates( 359, (SCREEN_HEIGHT - 107), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
// HEADROCK HAM 3.6: The balance/income box has been moved to the right side, near the laptop button.
VarFindFontCenterCoordinates( (SCREEN_WIDTH - 278), (SCREEN_HEIGHT - 111), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
// print it
mprintf( sFontX, sFontY, L"%s", sString );
@@ -1439,7 +1453,18 @@ void DisplayCurrentBalanceTitleForMapBottom( void )
// CHRISL: Replaced X coordinate with dynamic coordinate set from right edge of screen
//VarFindFontCenterCoordinates( (SCREEN_WIDTH - 637), (SCREEN_HEIGHT - 61), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
// CHRISL: Use this if we want to display from the left edge
VarFindFontCenterCoordinates( 359, (SCREEN_HEIGHT - 61), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
//VarFindFontCenterCoordinates( 359, (SCREEN_HEIGHT - 61), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
// HEADROCK HAM 3.6: The balance/income box has been moved to the right side, near the laptop button.
VarFindFontCenterCoordinates( (SCREEN_WIDTH - 278), (SCREEN_HEIGHT - 74), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
// print it
mprintf( sFontX, sFontY, L"%s", sString );
swprintf( sString, L"%s", New113HAMMessage[ 20 ] );
// HEADROCK HAM 3.6: Projected expenses for today, with facilities (and in the future, merc contracts) taken into
// account.
VarFindFontCenterCoordinates( (SCREEN_WIDTH - 278), (SCREEN_HEIGHT - 37), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
// print it
mprintf( sFontX, sFontY, L"%s", sString );
@@ -1474,7 +1499,9 @@ void DisplayCurrentBalanceForMapBottom( void )
// CHRISL: Replaced X coordinate with dynamic coordinate set from right edge of screen
//VarFindFontCenterCoordinates( (SCREEN_WIDTH - 637), (SCREEN_HEIGHT - 91), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
// CHRISL: Use this if we want to display from the left edge
VarFindFontCenterCoordinates( 359, (SCREEN_HEIGHT - 91), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
//VarFindFontCenterCoordinates( 359, (SCREEN_HEIGHT - 91), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
// HEADROCK HAM 3.6: The balance/income box has been moved to the right side, near the laptop button.
VarFindFontCenterCoordinates( (SCREEN_WIDTH - 278), (SCREEN_HEIGHT - 95), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
// print it
mprintf( sFontX, sFontY, L"%s", sString );
@@ -1588,7 +1615,9 @@ void DisplayProjectedDailyMineIncome( void )
// CHRISL: Replaced X coordinate with dynamic coordinate set from right edge of screen
//VarFindFontCenterCoordinates( (SCREEN_WIDTH - 637), (SCREEN_HEIGHT - 45), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
// CHRISL: Use this if we want to display from the left edge
VarFindFontCenterCoordinates( 359, (SCREEN_HEIGHT - 45), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
//VarFindFontCenterCoordinates( 359, (SCREEN_HEIGHT - 45), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
// HEADROCK HAM 3.6: The balance/income box has been moved to the right side, near the laptop button.
VarFindFontCenterCoordinates( (SCREEN_WIDTH - 278), (SCREEN_HEIGHT - 58), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
// print it
mprintf( sFontX, sFontY, L"%s", sString );
@@ -1596,6 +1625,58 @@ void DisplayProjectedDailyMineIncome( void )
return;
}
void DisplayProjectedDailyExpenses( void )
{
INT32 iRate = 0;
static INT32 iOldExpensesRate = -1;
CHAR16 sString[ 128 ];
INT16 sFontX, sFontY;
// grab the rate from the financial system
iRate = GetProjectedExpenses( );
if( iRate != iOldExpensesRate )
{
iOldExpensesRate = iRate;
fMapScreenBottomDirty = TRUE;
// if screen was not dirtied, leave
if( fMapBottomDirtied == FALSE )
{
return;
}
}
// set the font buffer
SetFontDestBuffer( FRAME_BUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE );
// set up the font
SetFont( COMPFONT );
if (iRate == 0)
{
SetFontForeground( 183 );
}
else
{
SetFontForeground( FONT_MCOLOR_LTRED );
}
SetFontBackground( FONT_BLACK );
swprintf( sString, L"%d", iRate );
// insert extra characters
InsertCommasForDollarFigure( sString );
InsertDollarSignInToString( sString );
// center it
VarFindFontCenterCoordinates( (SCREEN_WIDTH - 278), (SCREEN_HEIGHT - 21), 78, 10, COMPFONT, &sFontX, &sFontY, sString );
// print it
mprintf( sFontX, sFontY, L"%s", sString );
return;
}
BOOLEAN CommonTimeCompressionChecks( void )
{
@@ -1950,3 +2031,11 @@ void ChangeCurrentMapscreenMessageIndex( UINT8 ubNewMessageIndex )
// refresh screen
fMapScreenBottomDirty = TRUE;
}
void InitMapScreenInterfaceBottomCoords( void )
{
// HEADROCK HAM 3.6: Message window is now as wide as possible.
MESSAGE_SCROLL_AREA_START_X = SCREEN_WIDTH - 307;
MESSAGE_SCROLL_AREA_END_X = SCREEN_WIDTH - 293;
}
+3
View File
@@ -65,4 +65,7 @@ void MapScreenMsgScrollUp( UINT8 ubLinesUp );
void ChangeCurrentMapscreenMessageIndex( UINT8 ubNewMessageIndex );
void MoveToEndOfMapScreenMessageList( void );
// HEADROCK HAM 3.6: Reset coordinates for slider bar and message window
void InitMapScreenInterfaceBottomCoords( void );
#endif
@@ -582,6 +582,8 @@ void CreateDestroyMapInventoryPoolButtons( BOOLEAN fExitFromMapScreen )
fMapPanelDirty = TRUE;
fTeamPanelDirty = TRUE;
fCharacterInfoPanelDirty = TRUE;
// HEADROCK HAM 3.6: Yet again, make sure to refresh the bottom panel on closing.
fMapScreenBottomDirty = TRUE;
//CHRISL: close stack popup and item description windows
DeleteItemStackPopup();
@@ -1471,8 +1473,6 @@ void BeginInventoryPoolPtr( OBJECTTYPE *pInventorySlot )
{
for( UINT32 iNumber = 0 ; iNumber < pInventoryPoolList.size() ; ++iNumber)
{
// WANNE: Fix by Headrock
//if ( pInventoryPoolList[ iNumber ].object.usItem == gItemPointer.usItem )
if ( pInventoryPoolList[ iNumber ].object.usItem == gItemPointer.usItem && pInventoryPoolList[ iNumber ].usFlags & WORLD_ITEM_REACHABLE)
{
iPrice += SellItem( pInventoryPoolList[ iNumber ].object );
+134 -30
View File
@@ -48,6 +48,9 @@
#include "Quests.h"
#include "connect.h"
// HEADROCK HAM 3.5: included for detectionlevels
#include "Facilities.h"
#include "MilitiaSquads.h"
// zoom x and y coords for map scrolling
INT32 iZoomX = 0;
@@ -355,8 +358,9 @@ extern BOOLEAN fMapScreenBottomDirty;
BOOLEAN fFoundTixa = FALSE;
// selected sector
UINT16 sSelMapX = 9;
UINT16 sSelMapY = 1;
// HEADROCK HAM 3.5: Default selected sector doesn't have to be Omerta does it? :)
UINT16 sSelMapX = gGameExternalOptions.ubDefaultArrivalSectorX;
UINT16 sSelMapY = gGameExternalOptions.ubDefaultArrivalSectorY;
// highlighted sector
INT16 gsHighlightSectorX=-1;
@@ -522,6 +526,7 @@ void CreateMilitiaPanelBottomButton( void );
void DeleteMilitiaPanelBottomButton( void );
void MilitiaDoneButtonCallback(GUI_BUTTON *btn,INT32 reason);
void MilitiaAutoButtonCallback(GUI_BUTTON *btn,INT32 reason);
void MilitiaDisbandYesNoBoxCallback( UINT8 bExitValue ); // HEADROCK HAM 3.6: Disband militia callback
void RenderShadingForUnControlledSectors( void );
void DrawTownMilitiaForcesOnMap( void );
void CheckAndUpdateStatesOfSelectedMilitiaSectorButtons( void );
@@ -4381,7 +4386,10 @@ void DisplayDistancesForHelicopter( void )
// calculate the cost of the trip based on the number of safe and unsafe sectors it will pass through
uiTripCost = ( sNumSafeSectors * COST_AIRSPACE_SAFE ) + ( sNumUnSafeSectors * COST_AIRSPACE_UNSAFE );
// HEADROCK HAM 3.5: Externalized Base Cost. Also includes hourly-calculated facility modifier.
UINT32 uiCostGreen = __max(0,gGameExternalOptions.usHelicopterBaseCostPerGreenTile + gsSkyriderCostModifier);
UINT32 uiCostRed = __max(0,gGameExternalOptions.usHelicopterBaseCostPerRedTile + gsSkyriderCostModifier);
uiTripCost = ( sNumSafeSectors * uiCostGreen ) + ( sNumUnSafeSectors * uiCostRed );
swprintf( sString, L"%d", uiTripCost );
InsertCommasForDollarFigure( sString );
@@ -6092,13 +6100,22 @@ void MilitiaDoneButtonCallback(GUI_BUTTON *btn,INT32 reason)
{
btn->uiFlags &= ~( BUTTON_CLICKED_ON );
// reset fact we are in the box
sSelectedMilitiaTown = 0;
fMapPanelDirty = TRUE;
// Go ahead and reset the militia in the selected sector (even if we didn't change it here)
if (gfStrategicMilitiaChangesMade)
// HEADROCK HAM 3.6: Clicking the done button while militia are on the cursor causes a pop-up
// for authorizing DISBANDING those militia.
if (sGreensOnCursor || sRegularsOnCursor || sElitesOnCursor)
{
ResetMilitia();
DoMapMessageBox( MSG_BOX_BASIC_STYLE, pMilitiaString[ 3 ], MAP_SCREEN, MSG_BOX_FLAG_YESNO, MilitiaDisbandYesNoBoxCallback );
}
else
{
// reset fact we are in the box
sSelectedMilitiaTown = 0;
fMapPanelDirty = TRUE;
// Go ahead and reset the militia in the selected sector (even if we didn't change it here)
if (gfStrategicMilitiaChangesMade)
{
ResetMilitia();
}
}
}
}
@@ -6279,13 +6296,17 @@ void CheckAndUpdateStatesOfSelectedMilitiaSectorButtons( void )
iNumberOfRegulars = SectorInfo[ sGlobalMapSector ].ubNumberOfCivsAtLevel[ REGULAR_MILITIA ] + sRegularsOnCursor;
iNumberOfElites = SectorInfo[ sGlobalMapSector ].ubNumberOfCivsAtLevel[ ELITE_MILITIA ] + sElitesOnCursor;
// HEADROCK HAM 3.6: This button is no longer disabled when there are unassigned militia. In fact,
// clicking the button when militia are unassigned will prompt the player to authorize disbanding them.
if( ( sGreensOnCursor > 0 ) || ( sRegularsOnCursor > 0 ) || ( sElitesOnCursor > 0 ) )
{
DisableButton( giMapMilitiaButton[ 4 ] ); // DONE
// DisableButton( giMapMilitiaButton[ 4 ] ); // DONE
SpecifyButtonText( giMapMilitiaButton[ 4 ], pMilitiaButtonString[ 2 ] );
}
else
{
EnableButton( giMapMilitiaButton[ 4 ] ); // DONE
// EnableButton( giMapMilitiaButton[ 4 ] ); // DONE
SpecifyButtonText( giMapMilitiaButton[ 4 ], pMilitiaButtonString[ 1 ] );
}
// greens button
@@ -6445,34 +6466,59 @@ void ClearAnySectorsFlashingNumberOfEnemies()
UINT32 WhatPlayerKnowsAboutEnemiesInSector( INT16 sSectorX, INT16 sSectorY )
{
UINT32 uiSectorFlags = SectorInfo[ SECTOR( sSectorX, sSectorY ) ].uiFlags;
BOOLEAN fDetection = FALSE;
BOOLEAN fCount = FALSE;
Assert(sSectorX > 0 && sSectorY > 0 && sSectorX < 17 && sSectorY < 17);
// if player has militia close enough to scout this sector out, if there are mercs who can scout here, OR
//Special case flag used when players encounter enemies in a sector, then retreat. The number of enemies
//will display on mapscreen until time is compressed. When time is compressed, the flag is cleared, and
//a question mark is displayed to reflect that the player no longer knows.
// HEADROCK HAM 3.5: There are now several ways to control the detection of enemy units. This function has been revamped
// to consider all options. Depending on externalized settings, different conditions yield different results.
//
// Option #1: Vanilla Default.
// It is possible to detect all enemies in explored territory, including cities.
// Militia in an adjacent sector can count how many enemies are there, except standing garrisons.
// Option #2: HAM 3.2. No Detection without Recon.
// Mobile enemy groups are only detected if there are militia in any adjacent sector. Otherwise, they can
// travel through explored sectors without being seen.
//
// Option #3: This is a new feature for HAM 3.5, which ties together with Facility Externalization.
// In simple words, facilities can enhance detection abilities. Facilities that do so may be placed around the
// map in any sector. When a merc with sufficient wisdom is resting here, he increases the detection "level",
// making it easier to detect or even count enemies in distant sectors.
// This option can be combined with either of the two above.
// Detection through active recon.
// Mercs provide recon in the same sector they're in.
// Militia provide recon in any adjacent sector (diagonals included)
// There's also a special case flag used when players encounter enemies in a sector, then retreat. You can only
// see the size of their force while the clock is paused. When unpaused, the flag is reset.
if ( CanMercsScoutThisSector( sSectorX, sSectorY, 0 ) ||
CanNearbyMilitiaScoutThisSector( sSectorX, sSectorY ) ||
( uiSectorFlags & SF_PLAYER_KNOWS_ENEMIES_ARE_HERE ) )
{
// if the enemies are stationary (i.e. mercs attacking a garrison)
if ( NumStationaryEnemiesInSector( sSectorX, sSectorY ) > 0 )
fDetection = TRUE;
// if all enemies are mobile (I.E. not garrison troops)
if ( NumStationaryEnemiesInSector( sSectorX, sSectorY ) == 0 )
{
// inside a garrison - hide their # (show question mark) to match what the PBI is showing
return KNOWS_THEYRE_THERE;
}
else
{
// other situations - show exactly how many there are
return KNOWS_HOW_MANY;
// They're also counted by default.
fCount = TRUE;
}
}
// if the player has visited the sector during this game
// Explored Sector Detection
// Enemy can be detected in any previously-visited sector.
// This is also enabled by some facilities, provided a merc is present and available to do it.
if( GetSectorFlagStatus( sSectorX, sSectorY, 0, SF_ALREADY_VISITED ) == TRUE )
{
// then he always knows about any enemy presence for the remainder of the game, but not exact numbers
return KNOWS_THEYRE_THERE;
// HEADROCK HAM 3.2: When enabled, this INI setting disallows detection of enemy roamers beyond merc/militia
// recon range.
if (!gGameExternalOptions.fNoEnemyDetectionWithoutRecon)
{
// then he always knows about any enemy presence for the remainder of the game, but not exact numbers
fDetection = TRUE;
}
}
// if Skyrider noticed the enemis in the sector recently
@@ -6482,7 +6528,7 @@ UINT32 WhatPlayerKnowsAboutEnemiesInSector( INT16 sSectorX, INT16 sSectorY )
if( IsSkyriderIsFlyingInSector( sSectorX, sSectorY ) )
{
// player remains aware of them as long as Skyrider remains in the sector
return KNOWS_THEYRE_THERE;
fDetection = TRUE;
}
else
{
@@ -6491,9 +6537,32 @@ UINT32 WhatPlayerKnowsAboutEnemiesInSector( INT16 sSectorX, INT16 sSectorY )
}
}
// Facilities can set a flag that allows detection in some sectors. We can read flags directly from the sector
// data to know whether we should show the enemies there. This overrides ANYTHING else.
if (SectorInfo[ SECTOR( sSectorX, sSectorY ) ].ubDetectionLevel & 1)
{
fDetection = TRUE;
}
if (SectorInfo[ SECTOR( sSectorX, sSectorY ) ].ubDetectionLevel & (1<<2) )
{
fCount = TRUE;
}
// no information available
return KNOWS_NOTHING;
if (!fDetection)
{
// no information available
return KNOWS_NOTHING;
}
else if (!fCount)
{
// No accurate information
return KNOWS_THEYRE_THERE;
}
else
{
// Accurate information
return KNOWS_HOW_MANY;
}
}
@@ -7126,3 +7195,38 @@ BOOLEAN CanRedistributeMilitiaInSector( INT16 sClickedSectorX, INT16 sClickedSec
// the fight is elsewhere - ok to redistribute
return( TRUE );
}
// Callback for disbanding militia in the Militia Box
void MilitiaDisbandYesNoBoxCallback( UINT8 bExitValue )
{
// yes
if( bExitValue == MSG_BOX_RETURN_YES )
{
if( sSelectedMilitiaTown != BLANK_SECTOR )
{
// HEADROCK HAM 3.6: Adjust loyalty based on how many militia were disbanded, compared to
// how many can be trained in a single session (max).
UINT32 uiMilitiaToDisband = sGreensOnCursor + (2*sRegularsOnCursor) + (3*sElitesOnCursor);
UINT32 uiTownLoyaltyBonus = (LOYALTY_BONUS_FOR_TOWN_TRAINING * uiMilitiaToDisband) / gGameExternalOptions.iTrainingSquadSize;
// loyalty in this town increases a bit because we obviously care about them...
DecrementTownLoyalty( (UINT8)sSelectedMilitiaTown, uiTownLoyaltyBonus );
}
// zero out numbers on the cursor
sGreensOnCursor = 0;
sRegularsOnCursor = 0;
sElitesOnCursor = 0;
// reset fact we are in the box
sSelectedMilitiaTown = 0;
fMapPanelDirty = TRUE;
// Go ahead and reset the militia in the selected sector
ResetMilitia();
}
else if( bExitValue == MSG_BOX_RETURN_NO )
{
return;
}
return;
}
@@ -340,11 +340,8 @@ void AddTextToTownBox( void )
AddSecondColumnMonoString( &hStringHandle, wString );
// main facilities
swprintf( wString, L"%s:", pwTownInfoStrings[ 8 ] );
AddMonoString( &hStringHandle, wString );
wcscpy(wString, L"");
GetSectorFacilitiesFlags( bCurrentTownMineSectorX, bCurrentTownMineSectorY, wString );
AddSecondColumnMonoString( &hStringHandle, wString );
// HEADROCK HAM 3.6: This function now does all the work of assembling a facility entry.
AddFacilitiesToBox( bCurrentTownMineSectorX, bCurrentTownMineSectorY, &hStringHandle, TRUE );
// the concept of control is only meaningful in sectors where militia can be trained
if ( MilitiaTrainingAllowedInSector( bCurrentTownMineSectorX, bCurrentTownMineSectorY, 0 ) )
@@ -551,6 +548,9 @@ void AddTextToBlankSectorBox( void )
// sector
AddSectorToBox();
// HEADROCK HAM 3.6: Facilities
AddFacilitiesToBox( bCurrentTownMineSectorX, bCurrentTownMineSectorY, &hStringHandle, FALSE );
}
@@ -639,12 +639,64 @@ void AddCommonInfoToBox(void)
AddSecondColumnMonoString( &hStringHandle, wString );
}
// HEADROCK HAM 3.6: Only show these for sectors that have a training facility
BOOLEAN fMilitiaTrainingAllowed = FALSE;
BOOLEAN fMobileTrainingAllowed = FALSE;
// percentage of current militia squad training completed
swprintf( wString, L"%s:", pwTownInfoStrings[ 10 ] );
AddMonoString( &hStringHandle, wString );
swprintf( wString, L"%d%%%%", SectorInfo[ SECTOR( bCurrentTownMineSectorX, bCurrentTownMineSectorY ) ].ubMilitiaTrainingPercentDone );
AddSecondColumnMonoString( &hStringHandle, wString );
// Sector contains Militia training facility?
for (UINT8 ubCounter = 0; ubCounter < MAX_NUM_FACILITY_TYPES; ubCounter++)
{
if (gFacilityLocations[SECTOR(bCurrentTownMineSectorX, bCurrentTownMineSectorY)][ubCounter].fFacilityHere)
{
if (gFacilityTypes[ubCounter].ubMilitiaTrainersAllowed)
{
fMilitiaTrainingAllowed = TRUE;
}
}
}
if (fMilitiaTrainingAllowed)
{
// Show percent completed
swprintf( wString, L"%d%%%%", SectorInfo[ SECTOR( bCurrentTownMineSectorX, bCurrentTownMineSectorY ) ].ubMilitiaTrainingPercentDone );
AddSecondColumnMonoString( &hStringHandle, wString );
}
else
{
// Show N/A
AddSecondColumnMonoString( &hStringHandle, New113HAMMessage[19] );
}
// HEADROCK HAM 3.6: percentage of current Mobile Militia squad training completed
swprintf( wString, L"%s:", pwTownInfoStrings[ 12 ] );
AddMonoString( &hStringHandle, wString );
// Sector contains Mobile training facility?
for (UINT8 ubCounter = 0; ubCounter < MAX_NUM_FACILITY_TYPES; ubCounter++)
{
if (gFacilityLocations[SECTOR(bCurrentTownMineSectorX, bCurrentTownMineSectorY)][ubCounter].fFacilityHere)
{
if (gFacilityTypes[ubCounter].ubMobileMilitiaTrainersAllowed)
{
fMobileTrainingAllowed = TRUE;
}
}
}
if (fMobileTrainingAllowed)
{
// Show percentage completed
swprintf( wString, L"%d%%%%", SectorInfo[ SECTOR( bCurrentTownMineSectorX, bCurrentTownMineSectorY ) ].ubMobileMilitiaTrainingPercentDone );
AddSecondColumnMonoString( &hStringHandle, wString );
}
else
{
// Show N/A
AddSecondColumnMonoString( &hStringHandle, New113HAMMessage[19] );
}
}
+81 -18
View File
@@ -313,6 +313,8 @@ BOOLEAN fShowContractMenu = FALSE;
BOOLEAN fShowRemoveMenu = FALSE;
BOOLEAN fShowMilitiaControlMenu = FALSE; //lal
//BOOLEAN fShowTalkToAllMenu = FALSE;//lal
BOOLEAN fShowFacilityMenu = FALSE; // HEADROCK HAM 3.6: Facility Menu
BOOLEAN fShowFacilityAssignmentMenu = FALSE; // HEADROCK HAM 3.6: Facility Sub-menu
BOOLEAN fRebuildMoveBox = FALSE;
@@ -325,6 +327,12 @@ SGPRect TrainDimensions={0,0,100,95};
SGPPoint TrainPosition={160,150};
SGPRect VehicleDimensions={0,0,80,60};
SGPPoint VehiclePosition={160,150};
// HEADROCK HAM 3.6: Facility Menu Position/Size:
SGPRect FacilityDimensions={0,0,80,60};
SGPPoint FacilityPosition={160,150};
// HEADROCK HAM 3.6: Facility Sub-menu Position/Size:
SGPRect FacilityAssignmentDimensions={0,0,80,60};
SGPPoint FacilityAssignmentPosition={220,150};
SGPPoint RepairPosition={160,150};
SGPRect RepairDimensions={0,0,80,80};
@@ -350,6 +358,8 @@ SGPPoint OrigAssignmentPosition = { 120, 150 };
SGPPoint OrigTrainPosition={160,150};
SGPPoint OrigVehiclePosition={160,150};
SGPPoint OrigMilitiaControlPosition = { 120, 150 }; //lal
SGPPoint OrigFacilityPosition = { 160, 150 }; // HEADROCK HAM 3.6
SGPPoint OrigFacilityAssignmentPosition = { 220,150 }; // HEADROCK HAM 3.6
//SGPPoint OrigTalkToAllPosition = { 160, 150 };
//extern BOOLEAN fMapExitDueToMessageBox;
@@ -542,7 +552,7 @@ BOOLEAN MultipleCharacterListEntriesSelected( void )
void ResetAssignmentsForMercsTrainingUnpaidSectorsInSelectedList( INT8 bAssignment )
void ResetAssignmentsForMercsTrainingUnpaidSectorsInSelectedList( UINT8 ubMilitiaType )
{
INT32 iCounter = 0;
SOLDIERTYPE *pSoldier = NULL;
@@ -563,18 +573,31 @@ void ResetAssignmentsForMercsTrainingUnpaidSectorsInSelectedList( INT8 bAssignme
continue;
}
if( pSoldier->bAssignment == TRAIN_TOWN )
if (ubMilitiaType == TOWN_MILITIA)
{
if ( SectorInfo[ SECTOR( pSoldier->sSectorX, pSoldier->sSectorY ) ].fMilitiaTrainingPaid == FALSE )
if( pSoldier->bAssignment == TRAIN_TOWN )
{
ResumeOldAssignment( pSoldier );
if ( SectorInfo[ SECTOR( pSoldier->sSectorX, pSoldier->sSectorY ) ].fMilitiaTrainingPaid == FALSE )
{
ResumeOldAssignment( pSoldier );
}
}
}
else if (ubMilitiaType == MOBILE_MILITIA)
{
if( pSoldier->bAssignment == TRAIN_MOBILE )
{
if ( SectorInfo[ SECTOR( pSoldier->sSectorX, pSoldier->sSectorY ) ].fMobileMilitiaTrainingPaid == FALSE )
{
ResumeOldAssignment( pSoldier );
}
}
}
}
}
void ResetAssignmentOfMercsThatWereTrainingMilitiaInThisSector( INT16 sSectorX, INT16 sSectorY )
// HEADROCK HAM 3.6: Added argument for Militia Type
void ResetAssignmentOfMercsThatWereTrainingMilitiaInThisSector( INT16 sSectorX, INT16 sSectorY, UINT8 ubMilitiaType )
{
INT32 iCounter = 0;
SOLDIERTYPE *pSoldier = NULL;
@@ -595,11 +618,24 @@ void ResetAssignmentOfMercsThatWereTrainingMilitiaInThisSector( INT16 sSectorX,
continue;
}
if( pSoldier->bAssignment == TRAIN_TOWN )
if( ubMilitiaType == TOWN_MILITIA )
{
if( ( pSoldier->sSectorX == sSectorX ) && ( pSoldier->sSectorY == sSectorY ) && ( pSoldier->bSectorZ == 0 ) )
if( pSoldier->bAssignment == TRAIN_TOWN )
{
ResumeOldAssignment( pSoldier );
if( ( pSoldier->sSectorX == sSectorX ) && ( pSoldier->sSectorY == sSectorY ) && ( pSoldier->bSectorZ == 0 ) )
{
ResumeOldAssignment( pSoldier );
}
}
}
else if (ubMilitiaType == MOBILE_MILITIA )
{
if( pSoldier->bAssignment == TRAIN_MOBILE )
{
if( ( pSoldier->sSectorX == sSectorX ) && ( pSoldier->sSectorY == sSectorY ) && ( pSoldier->bSectorZ == 0 ) )
{
ResumeOldAssignment( pSoldier );
}
}
}
}
@@ -890,6 +926,7 @@ void RestoreBackgroundForAssignmentGlowRegionList( void )
// restore background
RestoreExternBackgroundRect( 66, Y_START - 1, 118 + 1 - 67, yHeight );
// ARM: not good enough! must reblit the whole panel to erase glow chunk restored by help text disappearing!!!
fTeamPanelDirty = TRUE;
@@ -2285,7 +2322,24 @@ void UpdateMapScreenAssignmentPositions( void )
SetBoxPosition( ghRepairBox, pPoint );
}
// HEADROCK HAM 3.6: Facility Menu
if( fShowFacilityMenu )
{
GetBoxPosition( ghFacilityBox, &pPoint);
pPoint.iY = giBoxY + ( GetFontHeight( MAP_SCREEN_FONT ) + 2 ) * ASSIGN_MENU_FACILITY;
SetBoxPosition( ghFacilityBox, pPoint );
}
// HEADROCK HAM 3.6: Facility Sub-menu
if( fShowFacilityAssignmentMenu )
{
GetBoxPosition( ghFacilityAssignmentBox, &pPoint);
pPoint.iY = giBoxY + ( GetFontHeight( MAP_SCREEN_FONT ) + 2 ) * ASSIGN_MENU_FACILITY;
SetBoxPosition( ghFacilityAssignmentBox, pPoint );
}
return;
}
@@ -5655,7 +5709,8 @@ BOOLEAN HandleTimeCompressWithTeamJackedInAndGearedToGo( void )
if (!is_networked)
// select starting sector (A9 - Omerta)
ChangeSelectedMapSector( startingX, startingY, startingZ );
// HEADROCK HAM 3.5: Externalized.
ChangeSelectedMapSector( gGameExternalOptions.ubDefaultArrivalSectorX, gGameExternalOptions.ubDefaultArrivalSectorY, startingZ );
if (is_networked)
{
@@ -5671,22 +5726,30 @@ BOOLEAN HandleTimeCompressWithTeamJackedInAndGearedToGo( void )
else
{
// load starting sector
if ( !SetCurrentWorldSector( startingX, startingY, startingZ ) )
// Externalized
if ( !SetCurrentWorldSector( gGameExternalOptions.ubDefaultArrivalSectorX, gGameExternalOptions.ubDefaultArrivalSectorY, startingZ ) )
{
return( FALSE );
}
gubPBSectorX = startingX;
gubPBSectorY = startingY;
gubPBSectorX = gGameExternalOptions.ubDefaultArrivalSectorX;
gubPBSectorY = gGameExternalOptions.ubDefaultArrivalSectorY;
}
gubPBSectorZ = 0;
//Setup variables in the PBI for this first battle. We need to support the
//non-persistant PBI in case the user goes to mapscreen.
gfBlitBattleSectorLocator = TRUE;
gubPBSectorZ = 0;
gubEnemyEncounterCode = ENTERING_ENEMY_SECTOR_CODE;
// HEADROCK HAM 3.5: Arrival sector externalized. Fix for entering non-hostile sector/
if ( NumEnemiesInAnySector( gubPBSectorX, gubPBSectorY, 0 ) > 0 )
{
gfBlitBattleSectorLocator = TRUE;
gubEnemyEncounterCode = ENTERING_ENEMY_SECTOR_CODE;
}
else
{
gfBlitBattleSectorLocator = FALSE;
gubEnemyEncounterCode = NO_ENCOUNTER_CODE;
}
InitHelicopterEntranceByMercs( );
+21 -3
View File
@@ -113,15 +113,17 @@ enum {
ASSIGN_MENU_VEHICLE,
ASSIGN_MENU_REPAIR,
ASSIGN_MENU_TRAIN,
ASSIGN_MENU_FACILITY, // HEAROCK HAM 3.6: Facility List menu
ASSIGN_MENU_CANCEL,
MAX_ASSIGN_STRING_COUNT,
};
// HEADROCK HAM 3.6: Added new option to train Mobile Militia separately.
// training assignment menu defines
enum {
TRAIN_MENU_SELF,
TRAIN_MENU_TOWN,
TRAIN_MENU_MOBILE,
TRAIN_MENU_TEAMMATES,
TRAIN_MENU_TRAIN_BY_OTHER,
TRAIN_MENU_CANCEL,
@@ -202,6 +204,12 @@ enum{
STOP_YELLOW_SECTOR_LOCATOR,
};
// HEADROCK HAM 3.6: Enums for Militia Training Types
enum{
TOWN_MILITIA = 0,
MOBILE_MILITIA,
NUM_MILITIA_TRAINING_TYPES
};
// dimensions and offset for merc update box
#define UPDATE_MERC_FACE_X_WIDTH 50
@@ -254,6 +262,8 @@ extern BOOLEAN fShowContractMenu ;
extern BOOLEAN fShowRemoveMenu ;
extern BOOLEAN fShowMilitiaControlMenu ; //lal
//extern BOOLEAN fShowTalkToAllMenu ;
extern BOOLEAN fShowFacilityMenu; // HEADROCK HAM 3.6
extern BOOLEAN fShowFacilityAssignmentMenu; // HEADROCK HAM 3.6
extern BOOLEAN fFirstTimeInMapScreen;
extern BOOLEAN fLockOutMapScreenInterface;
@@ -299,6 +309,11 @@ extern SGPRect AssignmentDimensions ;
extern SGPPoint AssignmentPosition ;
extern SGPPoint SquadPosition ;
extern SGPRect SquadDimensions ;
// HEADROCK HAM 3.6: Facility Menu variables
extern SGPPoint FacilityPosition;
extern SGPRect FacilityDimensions;
extern SGPPoint FacilityAssignmentPosition;
extern SGPRect FacilityAssignmentDimensions;
extern SGPPoint RepairPosition;
extern SGPRect RepairDimensions;
@@ -316,6 +331,8 @@ extern SGPPoint OrigAssignmentPosition ;
extern SGPPoint OrigTrainPosition;
extern SGPPoint OrigVehiclePosition;
extern SGPPoint OrigMilitiaControlPosition ; //lal
extern SGPPoint OrigFacilityPosition; // HEADROCK HAM 3.6: Facility Menu
extern SGPPoint OrigFacilityAssignmentPosition; // HEADROCK HAM 3.6
//extern SGPPoint OrigTalkToAllPosition ;
// disble team info panel due to showing of battle roster
@@ -374,7 +391,8 @@ BOOLEAN MultipleCharacterListEntriesSelected( void );
void ToggleEntryInSelectedList( INT8 bEntry );
// reset assignments for mercs on selected list who have this assignment
void ResetAssignmentsForMercsTrainingUnpaidSectorsInSelectedList( INT8 bAssignment );
// HEADROCK HAM 3.6: Argument was unused... adding my own.
void ResetAssignmentsForMercsTrainingUnpaidSectorsInSelectedList( UINT8 ubMilitiaType );
/*
// plot path for selected character list
@@ -553,7 +571,7 @@ BOOLEAN SetUpFastHelpListRegions( INT32 iXPosition[], INT32 iYPosition[], INT32
void InitializeMovingLists( void );
// reset assignment for mercs trainign militia in this sector
void ResetAssignmentOfMercsThatWereTrainingMilitiaInThisSector( INT16 sSectorX, INT16 sSectorY );
void ResetAssignmentOfMercsThatWereTrainingMilitiaInThisSector( INT16 sSectorX, INT16 sSectorY, UINT8 ubMilitiaType );
// the sector move box
+1250 -430
View File
File diff suppressed because it is too large Load Diff
+25 -3
View File
@@ -5,6 +5,7 @@
#include "Types.h"
#include "Soldier Control.h"
#include "campaign types.h"
//#define MAXIMUM_MILITIA_SQUAD_SIZE 30
@@ -18,7 +19,8 @@ void UpdateMilitiaSquads(INT16 sMapX, INT16 sMapY );
void CreateMilitiaSquads(INT16 sMapX, INT16 sMapY );
void MilitiaHelpFromAdjacentSectors( INT16 sMapX, INT16 sMapY );
void GenerateDirectionInfos( INT16 sMapX, INT16 sMapY, UINT8* uiDirNumber, UINT16 pMoveDir[4][3], BOOLEAN fWithCities, BOOLEAN fForBattle, BOOLEAN fOnlyCitySectors );
// HEADROCK HAM 3.4: Now using different arguments for this function. All relevent instances have also been altered.
void GenerateDirectionInfos( INT16 sMapX, INT16 sMapY, UINT8* uiDirNumber, UINT16 pMoveDir[4][3], BOOLEAN fForTraining, BOOLEAN fForBattle );
BOOLEAN MoveOneBestMilitiaMan(INT16 sMapX, INT16 sMapY, INT16 sTMapX, INT16 sTMapY);
void MilitiaFollowPlayer( INT16 sMapX, INT16 sMapY, INT16 sDMapX, INT16 sDMapY );
@@ -29,9 +31,29 @@ extern BOOLEAN gDynamicRestrictMilitia[ 256 ];
// HEADROCK HAM B2.7: Wonder why this function wasn't declared here. It is now, to allow Town Militia.cpp to
// access it.
BOOLEAN CheckStandardConditionsForDirection( INT16 sSMapX, INT16 sSMapY, INT16 sMapX, INT16 sMapY, BOOLEAN fWithCities, BOOLEAN fForBattle, BOOLEAN fOnlyCitySectors );
BOOLEAN CheckStandardConditionsForDirection( INT16 sSMapX, INT16 sSMapY, INT16 sMapX, INT16 sMapY, BOOLEAN fForTraining, BOOLEAN fForBattle );
// HEADROCK HAM B2.7: Generates possible movement directions - this is used only in CreateMilitiaGroup(), and
// makes sure that the target sector has room for more militia.
void GenerateDirectionInfosWithCapacityCheck( INT16 sMapX, INT16 sMapY, UINT8* uiDirNumber, UINT16 pMoveDir[4][3], BOOLEAN fWithCities, BOOLEAN fForBattle, BOOLEAN fOnlyCitySectors );
void GenerateDirectionInfosForTraining( INT16 sMapX, INT16 sMapY, UINT8* uiDirNumber, UINT16 pMoveDir[4][3] );
// HEADROCK HAM 3.4: Stores restriction data from XML, including required cities for each sector to be allowed.
typedef struct DYNAMICRESTRICTIONS
{
INT8 bSectorID;
UINT32 uiReqTownFlags;
} DYNAMICRESTRICTIONS;
// HEADROCK HAM 3.4: New function for simple Roaming Restriction testing.
BOOLEAN IsSectorRoamingAllowed( UINT32 uiSector );
// HEADROCK HAM 3.6: New upgrade check returns the amount of militia that can be upgraded at target sector, in
// "upgrade points"
UINT16 MilitiaUpgradeSlotsCheck( SECTORINFO * pSectorInfo );
// HEADROCK HAM 3.6: This needs to be accessible.
void AddToBlockMoveList(INT16 sMapX, INT16 sMapY);
// And this:
UINT8 CountMilitia(SECTORINFO *pSectorInfo);
#endif
+76 -17
View File
@@ -25,6 +25,8 @@
#include "Tactical Save.h"
#include "interface Dialogue.h"
#include "Random.h"
// HEADROCK HAM 3.6: Added for facility string printing...
#include "PopUpBox.h"
#endif
#include "postalservice.h"
@@ -32,26 +34,70 @@
extern BOOLEAN fMapScreenBottomDirty;
extern CPostalService gPostalService;
void GetSectorFacilitiesFlags( INT16 sMapX, INT16 sMapY, STR16 sFacilitiesString )
void AddFacilitiesToBox( INT16 sMapX, INT16 sMapY, UINT32 *uiHandle, BOOLEAN fCityInfoBox )
{
// will build a string stating current facilities present in sector
if( SectorInfo[ SECTOR( sMapX, sMapY ) ].uiFacilitiesFlags == 0 )
// HEADROCK HAM 3.5: Facilities are now read from XMLs, including their names.
UINT32 cnt = 0;
UINT32 uiNumFacilities = 0;
BOOLEAN fHeaderAdded = FALSE;
CHAR16 szFacilityString[30];
Assert(sMapX > 0 && sMapY > 0 && sMapX < 17 && sMapY < 17);
for ( cnt = 0; cnt < NUM_FACILITY_TYPES; cnt++ )
{
// none
swprintf( sFacilitiesString, L"%s", sFacilitiesStrings[ 0 ] );
if (fCityInfoBox && uiNumFacilities == 0 && !fHeaderAdded )
{
// For a city info box, always show this line on the left side.
swprintf( szFacilityString, L"%s:", pwTownInfoStrings[ 8 ] );
AddMonoString( uiHandle, szFacilityString );
fHeaderAdded = TRUE;
}
// Facility type exists at this location?
if (gFacilityLocations[SECTOR(sMapX,sMapY)][cnt].fFacilityHere)
{
if (gFacilityLocations[SECTOR(sMapX,sMapY)][cnt].ubHidden == 0 ||
(gFacilityLocations[SECTOR(sMapX,sMapY)][cnt].ubHidden == 1 && SectorInfo[SECTOR(sMapX,sMapY)].fSurfaceWasEverPlayerControlled) )
{
if (!fCityInfoBox && uiNumFacilities == 0 && !fHeaderAdded )
{
// For a non-city info box, show this line on the left side only if there's at least one facility.
swprintf( szFacilityString, L"%s:", pwTownInfoStrings[ 8 ] );
AddMonoString( uiHandle, szFacilityString );
}
else if (uiNumFacilities > 0)
{
// Add empty line on the left size to make room for text on the right.
AddMonoString( uiHandle, L"" );
}
AddSecondColumnMonoString( uiHandle, gFacilityTypes[cnt].szFacilityName );
uiNumFacilities++;
}
}
}
if( uiNumFacilities == 0 && fCityInfoBox )
{
// Add "NONE" on the right side. Only happens when the sector is a city.
AddSecondColumnMonoString( uiHandle, sFacilitiesStrings[0] );
return;
}
/* HEADROCK HAM 3.4: Hardcodes removed.
// hospital
if( SectorInfo[ SECTOR( sMapX, sMapY ) ].uiFacilitiesFlags & SFCF_HOSPITAL )
if( SectorInfo[ SECTOR( sMapX, sMapY ) ].uiFacilitiesFlags & (1 << FACILITY_HOSPITAL) )
{
swprintf( sFacilitiesString, L"%s", sFacilitiesStrings[ 1 ] );
swprintf( sFacilitiesString, L"%s", sFacilitiesStrings[ FACILITY_HOSPITAL ] );
}
// industry
if( SectorInfo[ SECTOR( sMapX, sMapY ) ].uiFacilitiesFlags & SFCF_INDUSTRY )
if( SectorInfo[ SECTOR( sMapX, sMapY ) ].uiFacilitiesFlags & (1 << FACILITY_INDUSTRY) )
{
if( wcslen( sFacilitiesString ) == 0 )
{
@@ -59,13 +105,13 @@ void GetSectorFacilitiesFlags( INT16 sMapX, INT16 sMapY, STR16 sFacilitiesString
}
else
{
wcscat( sFacilitiesString, L",");
wcscat( sFacilitiesString, L", ");
wcscat( sFacilitiesString, sFacilitiesStrings[ 2 ]);
}
}
// prison
if( SectorInfo[ SECTOR( sMapX, sMapY ) ].uiFacilitiesFlags & SFCF_PRISON )
if( SectorInfo[ SECTOR( sMapX, sMapY ) ].uiFacilitiesFlags & (1 << FACILITY_PRISON) )
{
if( wcslen( sFacilitiesString ) == 0 )
{
@@ -73,13 +119,27 @@ void GetSectorFacilitiesFlags( INT16 sMapX, INT16 sMapY, STR16 sFacilitiesString
}
else
{
wcscat( sFacilitiesString, L",");
wcscat( sFacilitiesString, L", ");
wcscat( sFacilitiesString, sFacilitiesStrings[ 3 ]);
}
}
// HEADROCK HAM 3.4: What about the military base!
if( SectorInfo[ SECTOR( sMapX, sMapY ) ].uiFacilitiesFlags & (1 << FACILITY_MILITARY) )
{
if( wcslen( sFacilitiesString ) == 0 )
{
swprintf( sFacilitiesString, L"%s", sFacilitiesStrings[ 4 ] );
}
else
{
wcscat( sFacilitiesString, L", ");
wcscat( sFacilitiesString, sFacilitiesStrings[ 4 ]);
}
}
// airport
if( SectorInfo[ SECTOR( sMapX, sMapY ) ].uiFacilitiesFlags & SFCF_AIRPORT )
if( SectorInfo[ SECTOR( sMapX, sMapY ) ].uiFacilitiesFlags & (1 << FACILITY_AIRPORT) )
{
if( wcslen( sFacilitiesString ) == 0 )
{
@@ -87,13 +147,13 @@ void GetSectorFacilitiesFlags( INT16 sMapX, INT16 sMapY, STR16 sFacilitiesString
}
else
{
wcscat( sFacilitiesString, L",");
wcscat( sFacilitiesString, L", ");
wcscat( sFacilitiesString, sFacilitiesStrings[ 5 ]);
}
}
// gun range
if( SectorInfo[ SECTOR( sMapX, sMapY ) ].uiFacilitiesFlags & SFCF_GUN_RANGE )
if( SectorInfo[ SECTOR( sMapX, sMapY ) ].uiFacilitiesFlags & (1 << FACILITY_GUNRANGE) )
{
if( wcslen( sFacilitiesString ) == 0 )
{
@@ -101,12 +161,11 @@ void GetSectorFacilitiesFlags( INT16 sMapX, INT16 sMapY, STR16 sFacilitiesString
}
else
{
wcscat( sFacilitiesString, L",");
wcscat( sFacilitiesString, L", ");
wcscat( sFacilitiesString, sFacilitiesStrings[ 6 ]);
}
}
sFacilitiesString[ wcslen( sFacilitiesString ) ] = 0;
*/
return;
}
+1 -1
View File
@@ -6,7 +6,7 @@
// build main facilities strings for sector
void GetSectorFacilitiesFlags( INT16 sMapX, INT16 sMapY, STR16 sFacilitiesString );
void AddFacilitiesToBox( INT16 sMapX, INT16 sMapY, UINT32 *uiHandle, BOOLEAN fCityInfoBox );
// set sector as enemy controlled
BOOLEAN SetThisSectorAsEnemyControlled( INT16 sMapX, INT16 sMapY, INT8 bMapZ, BOOLEAN fContested );
+16 -12
View File
@@ -210,15 +210,15 @@ UINT8 NumEnemiesInSector( INT16 sSectorX, INT16 sSectorY )
GROUP *pGroup;
UINT8 ubNumTroops;
// HEADROCK: This is a TEMPORARY fix to avoid the assertion error. Not sure this is the best solution,
// probably isn't. But I need this bit to work.
if (sSectorX < MINIMUM_VALID_X_COORDINATE ||
sSectorX > MAXIMUM_VALID_X_COORDINATE ||
sSectorY < MINIMUM_VALID_Y_COORDINATE ||
sSectorY > MAXIMUM_VALID_Y_COORDINATE)
{
return (0);
}
// HEADROCK HAM 3.5: This is a TEMPORARY fix to avoid the assertion error. Not sure this is the best solution,
// probably isn't. But I need this bit to work.
if (sSectorX < MINIMUM_VALID_X_COORDINATE ||
sSectorX > MAXIMUM_VALID_X_COORDINATE ||
sSectorY < MINIMUM_VALID_Y_COORDINATE ||
sSectorY > MAXIMUM_VALID_Y_COORDINATE)
{
return (0);
}
AssertGE( sSectorX, MINIMUM_VALID_X_COORDINATE);
AssertLE( sSectorX, MAXIMUM_VALID_X_COORDINATE );
@@ -503,8 +503,7 @@ BOOLEAN PrepareEnemyForSectorBattle()
// They arrived in multiple groups, so here they come
pThisSector = &SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ];
GenerateDirectionInfos( gWorldSectorX, gWorldSectorY, &ubDirNumber, pusMoveDir,
( GetTownIdForSector( gWorldSectorX, gWorldSectorY ) != BLANK_SECTOR ? TRUE : FALSE ), TRUE, IS_ONLY_IN_CITIES );
GenerateDirectionInfos( gWorldSectorX, gWorldSectorY, &ubDirNumber, pusMoveDir, FALSE, TRUE );
for( unsigned ubIndex = 0; ubIndex < ubDirNumber; ubIndex++ )
{
@@ -788,7 +787,6 @@ BOOLEAN PrepareEnemyForSectorBattle()
continue;
}
// At this point we should not have added more soldiers than are in slots
AssertGT( sNumSlots, 0 );
switch( pSoldier->ubSoldierClass )
@@ -1394,6 +1392,7 @@ void AddPossiblePendingEnemiesToBattle()
if( ubStrategicInsertionCode == 255 )
{
// HEADROCK HAM 3.5: This runs into assertion errors along the map's edge! Should be fixed!
if( NumEnemiesInSector( gWorldSectorX + 1, gWorldSectorY ) )
ubStrategicInsertionCode = INSERTION_CODE_EAST;
else if( NumEnemiesInSector( gWorldSectorX - 1, gWorldSectorY ) )
@@ -1704,6 +1703,11 @@ void AddEnemiesToBattle( GROUP *pGroup, UINT8 ubStrategicInsertionCode, UINT8 ub
}
UpdateMercInSector( pSoldier, gWorldSectorX, gWorldSectorY, 0 );
}
// HEADROCK HAM 3.2: enemy reinforcements arrive with 0 APs.
if (gGameExternalOptions.ubReinforcementsFirstTurnFreeze == 1 || gGameExternalOptions.ubReinforcementsFirstTurnFreeze == 2)
{
pSoldier->bActionPoints = 0;
}
}
}
+3 -2
View File
@@ -1126,8 +1126,9 @@ BOOLEAN CheckFact( UINT16 usFact, UINT8 ubProfileID )
gubFact[usFact] = gMercProfiles[ ARNIE ].bMercStatus != MERC_IS_DEAD;
break;
case FACT_I16_BLOODCATS_KILLED:
gubFact[usFact] = (SectorInfo[ SEC_I16 ].bBloodCats == 0);
// HEADROCK HAM 3.6: No longer necessarily I16.
case FACT_BLOODCAT_LAIR_CLEANED:
gubFact[usFact] = (SectorInfo[ gubBloodcatLairSectorId ].bBloodCats == 0);
break;
case FACT_NPC_BANDAGED_TODAY:
+2 -1
View File
@@ -430,7 +430,8 @@ enum Facts
FACT_KINGPIN_NOT_IN_OFFICE,// 256
FACT_DONT_OWE_KINGPIN_MONEY,// 257
FACT_PC_MARRYING_DARYL_IS_FLO,// 258
FACT_I16_BLOODCATS_KILLED,// 259
// HEADROCK HAM 3.6: Renamed this. It is no longer necessarily at I16.
FACT_BLOODCAT_LAIR_CLEANED,// 259
FACT_NPC_COWERING = 261,
+11 -20
View File
@@ -52,8 +52,7 @@ void GetNumberOfEnemiesInFiveSectors( INT16 sSectorX, INT16 sSectorY, UINT8 *pub
if ( ( GetTownIdForSector( sSectorX, sSectorY ) == OMERTA )&&( gGameOptions.ubDifficultyLevel != DIF_LEVEL_INSANE ) ) //Madd: skip Omerta //Lal: but not on insane ;-)
return;
GenerateDirectionInfos( sSectorX, sSectorY, &ubDirNumber, pusMoveDir,
( GetTownIdForSector( sSectorX, sSectorY ) != BLANK_SECTOR ? TRUE : FALSE ), TRUE, IS_ONLY_IN_CITIES );
GenerateDirectionInfos( sSectorX, sSectorY, &ubDirNumber, pusMoveDir, FALSE, TRUE );
for( ubIndex = 0; ubIndex < ubDirNumber; ubIndex++ )
{
@@ -104,8 +103,7 @@ BOOLEAN IsGroupInARightSectorToReinforce( GROUP *pGroup, INT16 sSectorX, INT16 s
if( !gGameExternalOptions.gfAllowReinforcements )
return FALSE;
GenerateDirectionInfos( sSectorX, sSectorY, &ubDirNumber, pusMoveDir,
( GetTownIdForSector( sSectorX, sSectorY ) != BLANK_SECTOR ? TRUE : FALSE ), TRUE, IS_ONLY_IN_CITIES );
GenerateDirectionInfos( sSectorX, sSectorY, &ubDirNumber, pusMoveDir, FALSE, TRUE );
for( ubIndex = 0; ubIndex < ubDirNumber; ubIndex++ )
if( pGroup->ubSectorX == SECTORX( pusMoveDir[ ubIndex ][ 0 ] ) && pGroup->ubSectorY == SECTORY( pusMoveDir[ ubIndex ][ 0 ] ) )
@@ -120,8 +118,7 @@ UINT8 GetAdjacentSectors( UINT8 pSectors[4], INT16 sSectorX, INT16 sSectorY )
UINT8 ubDirNumber = 0, ubIndex;
UINT8 ubCounter = 0;
GenerateDirectionInfos( sSectorX, sSectorY, &ubDirNumber, pusMoveDir,
( GetTownIdForSector( sSectorX, sSectorY ) != BLANK_SECTOR ? TRUE : FALSE ), TRUE, IS_ONLY_IN_CITIES );
GenerateDirectionInfos( sSectorX, sSectorY, &ubDirNumber, pusMoveDir, FALSE, TRUE );
for( ubIndex = 0; ubIndex < ubDirNumber; ubIndex++ )
pSectors[ ubCounter++ ] = (UINT8)pusMoveDir[ ubIndex ][ 0 ];
@@ -140,8 +137,7 @@ UINT8 CountAllMilitiaInFiveSectors(INT16 sMapX, INT16 sMapY)
if( !gGameExternalOptions.gfAllowReinforcements )
return ubResult;
GenerateDirectionInfos( sMapX, sMapY, &ubDirNumber, pusMoveDir,
( GetTownIdForSector( sMapX, sMapY ) != BLANK_SECTOR ? TRUE : FALSE ), TRUE, IS_ONLY_IN_CITIES );
GenerateDirectionInfos( sMapX, sMapY, &ubDirNumber, pusMoveDir, FALSE, TRUE );
for( ubIndex = 0; ubIndex < ubDirNumber; ubIndex++ )
ubResult += CountAllMilitiaInSector( SECTORX( pusMoveDir[ ubIndex ][ 0 ] ), SECTORY( pusMoveDir[ ubIndex ][ 0 ] ) );
@@ -161,8 +157,7 @@ UINT8 MilitiaInFiveSectorsOfRank( INT16 sMapX, INT16 sMapY, UINT8 ubRank )
if( !gGameExternalOptions.gfAllowReinforcements )
return ubResult;
GenerateDirectionInfos( sMapX, sMapY, &ubDirNumber, pusMoveDir,
( GetTownIdForSector( sMapX, sMapY ) != BLANK_SECTOR ? TRUE : FALSE ), TRUE, IS_ONLY_IN_CITIES );
GenerateDirectionInfos( sMapX, sMapY, &ubDirNumber, pusMoveDir, FALSE, TRUE );
for( ubIndex = 0; ubIndex < ubDirNumber; ubIndex++ )
ubResult += MilitiaInSectorOfRank( SECTORX( pusMoveDir[ ubIndex ][ 0 ] ), SECTORY( pusMoveDir[ ubIndex ][ 0 ] ), ubRank );
@@ -179,12 +174,11 @@ BOOLEAN ARMoveBestMilitiaManFromAdjacentSector(INT16 sMapX, INT16 sMapY)
if( !gGameExternalOptions.gfAllowReinforcements )
return FALSE;
if( CountAllMilitiaInSector( sMapX, sMapY ) >= gGameExternalOptions.guiMaxMilitiaSquadSize ||
if( CountAllMilitiaInSector( sMapX, sMapY ) >= gGameExternalOptions.iMaxMilitiaPerSector ||
CountAllMilitiaInFiveSectors( sMapX, sMapY ) - CountAllMilitiaInSector( sMapX, sMapY ) == 0 )
return FALSE;
GenerateDirectionInfos( sMapX, sMapY, &ubDirNumber, pusMoveDir,
( GetTownIdForSector( sMapX, sMapY ) != BLANK_SECTOR ? TRUE : FALSE ), TRUE, IS_ONLY_IN_CITIES );
GenerateDirectionInfos( sMapX, sMapY, &ubDirNumber, pusMoveDir, FALSE, TRUE );
ubRandom = Random( ubDirNumber );
@@ -209,8 +203,7 @@ BOOLEAN ARRemoveMilitiaMan( INT16 sMapX, INT16 sMapY, UINT8 ubRank )
if( !gGameExternalOptions.gfAllowReinforcements )
return FALSE;
GenerateDirectionInfos( sMapX, sMapY, &ubDirNumber, pusMoveDir,
( GetTownIdForSector( sMapX, sMapY ) != BLANK_SECTOR ? TRUE : FALSE ), TRUE, IS_ONLY_IN_CITIES );
GenerateDirectionInfos( sMapX, sMapY, &ubDirNumber, pusMoveDir, FALSE, TRUE );
for( ; ; )
{
@@ -256,8 +249,7 @@ UINT8 DoReinforcementAsPendingEnemy( INT16 sMapX, INT16 sMapY )
pThisSector = &SectorInfo[ SECTOR( sMapX, sMapY ) ];
GenerateDirectionInfos( sMapX, sMapY, &ubDirNumber, pusMoveDir,
( GetTownIdForSector( sMapX, sMapY ) != BLANK_SECTOR ? TRUE : FALSE ), TRUE, IS_ONLY_IN_CITIES );
GenerateDirectionInfos( sMapX, sMapY, &ubDirNumber, pusMoveDir, FALSE, TRUE );
for( ubIndex = 0; ubIndex < ubDirNumber; ubIndex++ )
{
@@ -328,7 +320,7 @@ UINT8 NumFreeMilitiaSlots()
if( !pSoldier->bActive )
ubNumFreeSlots++;
}
return max( 0 , ubNumFreeSlots - ( gGameExternalOptions.ubGameMaximumNumberOfRebels - gGameExternalOptions.guiMaxMilitiaSquadSize ) );
return max( 0 , ubNumFreeSlots - ( gGameExternalOptions.ubGameMaximumNumberOfRebels - gGameExternalOptions.iMaxMilitiaPerSector ) );
}
UINT8 DoReinforcementAsPendingMilitia( INT16 sMapX, INT16 sMapY, UINT8 *pubRank )
@@ -342,8 +334,7 @@ UINT8 DoReinforcementAsPendingMilitia( INT16 sMapX, INT16 sMapY, UINT8 *pubRank
// pThisSector = &SectorInfo[ SECTOR( sMapX, sMapY ) ];
GenerateDirectionInfos( sMapX, sMapY, &ubDirNumber, pusMoveDir,
( GetTownIdForSector( sMapX, sMapY ) != BLANK_SECTOR ? TRUE : FALSE ), TRUE, IS_ONLY_IN_CITIES );
GenerateDirectionInfos( sMapX, sMapY, &ubDirNumber, pusMoveDir, FALSE, TRUE );
if( CountAllMilitiaInFiveSectors( sMapX, sMapY ) - CountAllMilitiaInSector( sMapX, sMapY ) == 0 )
{
+6 -1
View File
@@ -3704,6 +3704,9 @@ BOOLEAN LoadStrategicAI( HWFILE hFile )
}
if( ubSAIVersion < 18 )
{ //adjust down the number of bloodcats based on difficulty in the two special bloodcat levels
// HEADROCK HAM 3.6: Run the Init function instead.
InitBloodCatSectors();
/*
switch( gGameOptions.ubDifficultyLevel )
{
case DIF_LEVEL_EASY: //50%
@@ -3729,7 +3732,7 @@ BOOLEAN LoadStrategicAI( HWFILE hFile )
SectorInfo[ SEC_I16 ].bBloodCats = 39;
SectorInfo[ SEC_N5 ].bBloodCats = 37;
break;
}
}*/
}
if( ubSAIVersion < 19 )
{
@@ -3753,6 +3756,8 @@ BOOLEAN LoadStrategicAI( HWFILE hFile )
}
if( ubSAIVersion < 22 )
{ //adjust down the number of bloodcats based on difficulty in the two special bloodcat levels
// HEADROCK HAM 3.6: Run the Init function instead.
InitBloodCatSectors();
switch( gGameOptions.ubDifficultyLevel )
{
case DIF_LEVEL_EASY: //50%
+14 -1
View File
@@ -42,6 +42,10 @@
#include "Quests.h"
// HEADROCK HAM B1: Additional Include for Dynamic Roaming Restrictions
#include "MilitiaSquads.h"
// HEADROCK HAM 3.6: Additional include for Facility Operating Deby
#include "Facilities.h"
// HEADROCK HAM 3.6: And another include, for militia upkeep costs.
#include "Town Militia.h"
#endif
@@ -513,10 +517,19 @@ void MercDailyUpdate()
// rebuild list for mapscreen
ReBuildCharactersList( );
// HEADROCK HAM B1: Run a function to redefine Roaming Militia Restrictions.
if (gGameExternalOptions.bDynamicRestrictRoaming)
if (gGameExternalOptions.fDynamicRestrictRoaming)
{
AdjustRoamingRestrictions();
}
// HEADROCK HAM 3.6: Pay debt for operating Facilities today. If can't be paid, apply loyalty hit.
if (giTotalOwedForFacilityOperationsToday)
{
HandleDailyPaymentFacilityDebt();
}
// HEADROCK HAM 3.6: Pay for militia upkeep
HandleMilitiaUpkeepPayment();
}
/*
+38 -7
View File
@@ -21,6 +21,7 @@
#include "Strategic AI.h"
#include "Campaign Types.h"
#include "history.h"
#include "Facilities.h"
#endif
@@ -202,12 +203,27 @@ void InitializeMines( void )
// Alma mine can't run out for quest-related reasons (see Ian)
} while (gMineStatus[ubDepletedMineIndex].fEmpty || (ubDepletedMineIndex == MINE_ALMA));
// HEADROCK HAM 3.1: We can now select which mine runs out, or disable mine shutdown.
if (gGameExternalOptions.fManuallySelectMineShutdown)
{
// Make sure selection isn't 0 (no mine runs out) or invalid (San Mona, Alma)
if (gGameExternalOptions.ubWhichMineRunsOut > 0 &&
gGameExternalOptions.ubWhichMineRunsOut < MAX_NUMBER_OF_MINES &&
gGameExternalOptions.ubWhichMineRunsOut-1 != MINE_SAN_MONA &&
gGameExternalOptions.ubWhichMineRunsOut-1 != MINE_ALMA )
{
// Set depleted mine index.
ubDepletedMineIndex = (gGameExternalOptions.ubWhichMineRunsOut-1);
}
}
for( ubMineIndex = 0; ubMineIndex < MAX_NUMBER_OF_MINES; ubMineIndex++ )
{
pMineStatus = &(gMineStatus[ ubMineIndex ]);
if (ubMineIndex == ubDepletedMineIndex)
// HEADROCK HAM 3.1: We can disable mine shutdown, so make sure the settings aren't telling us to do so.
if (!(gGameExternalOptions.fManuallySelectMineShutdown && gGameExternalOptions.ubWhichMineRunsOut == 0) &&
(ubMineIndex == ubDepletedMineIndex))
{
if ( ubDepletedMineIndex == MINE_DRASSEN )
{
@@ -343,7 +359,7 @@ UINT32 GetMaxPeriodicRemovalFromMine( INT8 bMineIndex )
}
// HEADROCK HAM B1: Affected by external INI option.
return(( gMineStatus[ bMineIndex ].uiMaxRemovalRate * gGameExternalOptions.iMineIncomePercentage ) / 100);
return(( gMineStatus[ bMineIndex ].uiMaxRemovalRate * gGameExternalOptions.usMineIncomePercentage ) / 100);
}
@@ -370,7 +386,7 @@ UINT32 GetMaxDailyRemovalFromMine( INT8 bMineIndex )
uiAmtExtracted = gMineStatus[ bMineIndex ].uiRemainingOreSupply;
}
// HEADROCK HAM B1: Affected by external INI option.
uiAmtExtracted = (uiAmtExtracted * gGameExternalOptions.iMineIncomePercentage) / 100;
uiAmtExtracted = (uiAmtExtracted * gGameExternalOptions.usMineIncomePercentage) / 100;
return(uiAmtExtracted);
}
@@ -660,15 +676,22 @@ void HandleIncomeFromMines( void )
{
INT32 iIncome = 0;
INT8 bCounter = 0;
// HEADROCK HAM 3.6: Modifier from Facilities
INT32 iFacilityModifier = 0;
// mine each mine, check if we own it and such
for( bCounter = 0; bCounter < MAX_NUMBER_OF_MINES; bCounter++ )
{
if (bCounter)
{
// HEADROCK HAM 3.6: Add facility modifier as a percentage
iFacilityModifier = 100 + MineIncomeModifierFromFacility( bCounter );
}
// mine this mine
iIncome += MineAMine( bCounter );
iIncome += (MineAMine( bCounter ) * iFacilityModifier) / 100;
}
// HEADROCK HAM B1: Affected by external INI Option.
iIncome = (iIncome * gGameExternalOptions.iMineIncomePercentage) / 100;
iIncome = (iIncome * gGameExternalOptions.usMineIncomePercentage) / 100;
if( iIncome )
{
AddTransactionToPlayersBook( DEPOSIT_FROM_SILVER_MINE, 0, GetWorldTotalMin( ), iIncome );
@@ -681,6 +704,8 @@ UINT32 PredictDailyIncomeFromAMine( INT8 bMineIndex )
// predict income from this mine, estimate assumes mining situation will not change during next 4 income periods
// (miner loyalty, % town controlled, monster infestation level, and current max removal rate may all in fact change)
UINT32 uiAmtExtracted = 0;
// HEADROCK HAM 3.6: Facilities can now modify income
INT32 iFacilityModifier = 0;
if(PlayerControlsMine(bMineIndex))
{
@@ -693,10 +718,16 @@ UINT32 PredictDailyIncomeFromAMine( INT8 bMineIndex )
// yes reduce to value of mine
uiAmtExtracted = gMineStatus[ bMineIndex ].uiRemainingOreSupply;
}
if (bMineIndex)
{
// HEADROCK HAM 3.6: Facility modifier applied as a percentage
iFacilityModifier = 100 + MineIncomeModifierFromFacility( bMineIndex );
uiAmtExtracted = (uiAmtExtracted * iFacilityModifier) / 100;
}
}
// HEADROCK HAM B1: Affected by external INI Option.
return( ( uiAmtExtracted * gGameExternalOptions.iMineIncomePercentage ) / 100 ) ;
return( ( uiAmtExtracted * gGameExternalOptions.usMineIncomePercentage ) / 100 ) ;
}
@@ -727,7 +758,7 @@ INT32 CalcMaxPlayerIncomeFromMines( void )
iTotal += (MINE_PRODUCTION_NUMBER_OF_PERIODS * gMineStatus[bCounter].uiMaxRemovalRate);
}
// HEADROCK HAM B1: Affected by external INI Option.
iTotal = (iTotal * gGameExternalOptions.iMineIncomePercentage) / 100;
iTotal = (iTotal * gGameExternalOptions.usMineIncomePercentage) / 100;
return( iTotal );
}
+85 -37
View File
@@ -1554,6 +1554,10 @@ void AwardExperienceForTravelling( GROUP * pGroup )
void AddCorpsesToBloodcatLair( INT16 sSectorX, INT16 sSectorY )
{
// HEADROCK HAM 3.6: Note, lair location externalized, but may cause issues because the GridNos here are
// hardcoded... Maybe there will be a better way to solve this in the future, with externalized GridNos.
// At the moment, no changes.
ROTTING_CORPSE_DEFINITION Corpse;
INT16 sXPos, sYPos;
@@ -1884,12 +1888,14 @@ void GroupArrivedAtSector( UINT8 ubGroupID, BOOLEAN fCheckForBattle, BOOLEAN fNe
if( pGroup->pPlayerList->pSoldier->bAssignment < ON_DUTY )
{
// squad
ScreenMsg( FONT_MCOLOR_DKRED, MSG_INTERFACE, pMessageStrings[ MSG_ARRIVE ], pAssignmentStrings[ pGroup->pPlayerList->pSoldier->bAssignment ], pMapVertIndex[ pGroup->pPlayerList->pSoldier->sSectorY ], pMapHortIndex[ pGroup->pPlayerList->pSoldier->sSectorX ]);
// HEADROCK HAM 3.6: Messages are no longer yellow by default.
ScreenMsg( FONT_MCOLOR_LTGREEN, MSG_INTERFACE, pMessageStrings[ MSG_ARRIVE ], pAssignmentStrings[ pGroup->pPlayerList->pSoldier->bAssignment ], pMapVertIndex[ pGroup->pPlayerList->pSoldier->sSectorY ], pMapHortIndex[ pGroup->pPlayerList->pSoldier->sSectorX ]);
}
else
{
// a loner
ScreenMsg( FONT_MCOLOR_DKRED, MSG_INTERFACE, pMessageStrings[ MSG_ARRIVE ], pGroup->pPlayerList->pSoldier->name, pMapVertIndex[ pGroup->pPlayerList->pSoldier->sSectorY ], pMapHortIndex[ pGroup->pPlayerList->pSoldier->sSectorX ] );
// HEADROCK HAM 3.6: Messages are no longer yellow by default.
ScreenMsg( FONT_MCOLOR_LTGREEN, MSG_INTERFACE, pMessageStrings[ MSG_ARRIVE ], pGroup->pPlayerList->pSoldier->name, pMapVertIndex[ pGroup->pPlayerList->pSoldier->sSectorY ], pMapHortIndex[ pGroup->pPlayerList->pSoldier->sSectorX ] );
}
}
}
@@ -1978,7 +1984,8 @@ void GroupArrivedAtSector( UINT8 ubGroupID, BOOLEAN fCheckForBattle, BOOLEAN fNe
// don't print any messages when arriving underground, there's no delay involved
if ( GroupAtFinalDestination( pGroup ) && ( pGroup->ubSectorZ == 0 ) && !fNeverLeft )
{
ScreenMsg( FONT_MCOLOR_DKRED, MSG_INTERFACE, pMessageStrings[ MSG_ARRIVE ], pVehicleStrings[ pVehicleList[ iVehId ].ubVehicleType ], pMapVertIndex[ pGroup->ubSectorY ], pMapHortIndex[ pGroup->ubSectorX ] );
// HEADROCK HAM 3.6: Messages are no longer yellow by default.
ScreenMsg( FONT_MCOLOR_LTGREEN, MSG_INTERFACE, pMessageStrings[ MSG_ARRIVE ], pVehicleStrings[ pVehicleList[ iVehId ].ubVehicleType ], pMapVertIndex[ pGroup->ubSectorY ], pMapHortIndex[ pGroup->ubSectorX ] );
}
}
}
@@ -1997,7 +2004,8 @@ void GroupArrivedAtSector( UINT8 ubGroupID, BOOLEAN fCheckForBattle, BOOLEAN fNe
if ( !pGroup->fVehicle || !IsGroupTheHelicopterGroup( pGroup ) )
{
// ATE: Add a few corpse to the bloodcat lair...
if ( SECTOR( pGroup->ubSectorX, pGroup->ubSectorY ) == SEC_I16 && fFirstTimeInSector )
// HEADROCK: No longer hardcoded to I16
if ( SECTOR( pGroup->ubSectorX, pGroup->ubSectorY ) == gubBloodcatLairSectorId && fFirstTimeInSector )
{
AddCorpsesToBloodcatLair( pGroup->ubSectorX, pGroup->ubSectorY );
}
@@ -4708,13 +4716,20 @@ void RandomizePatrolGroupLocation( GROUP *pGroup )
//roll the dice to see if this will become an ambush random encounter.
BOOLEAN TestForBloodcatAmbush( GROUP *pGroup )
{
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// HEADROCK HAM 3.6: Ambush locations, min/max strength and chance of ambush have all been externalized to XML.
SECTORINFO *pSector;
INT32 iHoursElapsed;
UINT8 ubSectorID;
UINT8 ubChance;
INT8 bDifficultyMaxCats;
INT8 bProgressMaxCats;
UINT8 ubDifficulty = gGameOptions.ubDifficultyLevel-1; // For use by Placements Array. Novice = 0 instead of 1.
UINT8 ubRange;
UINT8 ubRandomCats;
INT8 bNumMercMaxCats;
UINT8 PlacementType; // 0 = Ambush site. 1 = Static placement. 2 = Lair.
UINT8 ubMinBloodcats; // XML minimum.
UINT8 ubMaxBloodcats; // XML maximum.
BOOLEAN fAlreadyAmbushed = FALSE;
if( pGroup->ubSectorZ )
@@ -4725,17 +4740,24 @@ BOOLEAN TestForBloodcatAmbush( GROUP *pGroup )
ubSectorID = (UINT8)SECTOR( pGroup->ubSectorX, pGroup->ubSectorY );
pSector = &SectorInfo[ ubSectorID ];
ubChance = 5 * gGameOptions.ubDifficultyLevel;
// Read chance from XML data, based on difficulty.
ubChance = gBloodcatPlacements[ ubSectorID ][ ubDifficulty ].ubAmbushChance;
iHoursElapsed = __max(0,(GetWorldTotalMin() - pSector->uiTimeCurrentSectorWasLastLoaded) / 60);
// Decrease chance to 0% if sector has been visited this hour. Every hour after that, increase the chance by 1%
// until it reaches the default value again.
ubChance = (UINT8)__min((INT32)ubChance, iHoursElapsed);
ubChance = __max(0,ubChance);
iHoursElapsed = (GetWorldTotalMin() - pSector->uiTimeCurrentSectorWasLastLoaded) / 60;
if( ubSectorID == SEC_N5 || ubSectorID == SEC_I16 )
{ //These are special maps -- we use all placements.
if( pSector->bBloodCats == -1 )
{
pSector->bBloodCats = pSector->bBloodCatPlacements;
}
else if( pSector->bBloodCats > 0 && pSector->bBloodCats < pSector->bBloodCatPlacements )
{ //Slowly have them recuperate if we haven't been here for a long time. The population will
// Determine what type of placement this is.
PlacementType = gBloodcatPlacements[ ubSectorID ][0].PlacementType;
// At lair?
if( PlacementType == BLOODCAT_PLACEMENT_LAIR )
{
// Bloodcats still exist here, but aren't at the optimal number?
if( pSector->bBloodCats > 0 && pSector->bBloodCats < pSector->bBloodCatPlacements )
{
//Slowly have them recuperate if we haven't been here for a long time. The population will
//come back up to the maximum if left long enough.
INT32 iBloodCatDiff;
iBloodCatDiff = pSector->bBloodCatPlacements - pSector->bBloodCats;
@@ -4743,55 +4765,80 @@ BOOLEAN TestForBloodcatAmbush( GROUP *pGroup )
}
//Once 0, the bloodcats will never recupe.
}
else if( pSector->bBloodCats == -1 )
{ //If we haven't been ambushed by bloodcats yet...
if( gfAutoAmbush || PreChance( ubChance ) )
// At ambush sector?
else if( PlacementType == BLOODCAT_PLACEMENT_AMBUSH )
{
//If there's any chance of ambush in this sector, and we beat that chance...
if( ubChance && (gfAutoAmbush || PreChance( ubChance )) )
{
//randomly choose from 5-8, 7-10, 9-12 bloodcats based on easy, normal, and hard, respectively
bDifficultyMaxCats = (INT8)( Random( 4 ) + gGameOptions.ubDifficultyLevel*2 + 3 );
//bDifficultyMaxCats = (INT8)( Random( 4 ) + gGameOptions.ubDifficultyLevel*2 + 3 );
//maximum of 3 bloodcats or 1 for every 6%, 5%, 4% progress based on easy, normal, and hard, respectively
bProgressMaxCats = (INT8)max( CurrentPlayerProgressPercentage() / (7 - gGameOptions.ubDifficultyLevel), 3 );
//make sure bloodcats don't outnumber mercs by a factor greater than 2
bNumMercMaxCats = (INT8)(PlayerMercsInSector( pGroup->ubSectorX, pGroup->ubSectorY, pGroup->ubSectorZ ) * 2);
//bProgressMaxCats = (INT8)max( CurrentPlayerProgressPercentage() / (7 - gGameOptions.ubDifficultyLevel), 3 );
//choose the lowest number of cats calculated by difficulty and progress.
pSector->bBloodCats = (INT8)min( bDifficultyMaxCats, bProgressMaxCats );
//pSector->bBloodCats = (INT8)min( bDifficultyMaxCats, bProgressMaxCats );
///////////////////////////////////////////////////////////////////////////////////////////////////////
// HEADROCK HAM 3.6: Minimum and Maximum are now modder-defined, so pick a random number between them.
// Read Min/Max from XML
ubMaxBloodcats = gBloodcatPlacements[ ubSectorID ][ ubDifficulty ].ubMaxBloodcats;
ubMinBloodcats = gBloodcatPlacements[ ubSectorID ][ ubDifficulty ].ubMinBloodcats;
// Find range between Min and Max
ubRange = ubMaxBloodcats-ubMinBloodcats;
// Adjust range based on current progress.
ubRange = __max(0,( ubRange * CurrentPlayerProgressPercentage() ) / 100);
// Randomize "extra" bloodcats
ubRandomCats = PreRandom(ubRange+1);
// Add "extra" bloodcats to minimum value
ubRandomCats += ubMinBloodcats;
// SET NUMBER OF CATS THAT WILL APPEAR
pSector->bBloodCats = ubRandomCats;
if( gGameOptions.ubDifficultyLevel < DIF_LEVEL_HARD )
{ //if not hard difficulty, ensure cats never outnumber mercs by a factor of 2 (min 3 bloodcats)
{
//At NOVICE/EXPERIENCED difficulty, ensure cats never outnumber mercs by a factor of more than 2.
bNumMercMaxCats = (INT8)(PlayerMercsInSector( pGroup->ubSectorX, pGroup->ubSectorY, pGroup->ubSectorZ ) * 2);
pSector->bBloodCats = (INT8)min( pSector->bBloodCats, bNumMercMaxCats );
pSector->bBloodCats = (INT8)max( pSector->bBloodCats, 3 );
//pSector->bBloodCats = (INT8)max( pSector->bBloodCats, 3 );
}
//ensure that there aren't more bloodcats than placements
pSector->bBloodCats = (INT8)min( pSector->bBloodCats, pSector->bBloodCatPlacements );
// Once again, make absolutely sure we're still within XML-set limits
pSector->bBloodCats = (INT8)min( pSector->bBloodCats, ubMaxBloodcats);
pSector->bBloodCats = (INT8)max( pSector->bBloodCats, ubMinBloodcats);
}
}
else if( ubSectorID != SEC_I16 )
{
if( !gfAutoAmbush && PreChance( 95 ) )
{ //already ambushed here. But 5% chance of getting ambushed again!
else
{
// Chance was 0.
fAlreadyAmbushed = TRUE;
}
}
if( !fAlreadyAmbushed && ubSectorID != SEC_N5 && pSector->bBloodCats > 0 &&
// An ambush is occuring?
if( !fAlreadyAmbushed && PlacementType != BLOODCAT_PLACEMENT_STATIC && pSector->bBloodCats > 0 &&
!pGroup->fVehicle && !NumEnemiesInSector( pGroup->ubSectorX, pGroup->ubSectorY ) )
{
if( ubSectorID != SEC_I16 || !gubFact[ FACT_PLAYER_KNOWS_ABOUT_BLOODCAT_LAIR ] )
// Wilderness ambush, or the player has unwittingly entered the lair?
if( PlacementType == BLOODCAT_PLACEMENT_AMBUSH || !gubFact[ FACT_PLAYER_KNOWS_ABOUT_BLOODCAT_LAIR ] )
{
// Ambush occurs.
gubEnemyEncounterCode = BLOODCAT_AMBUSH_CODE;
}
else
{
// Player knowingly enters lair.
gubEnemyEncounterCode = ENTERING_BLOODCAT_LAIR_CODE;
}
return TRUE;
}
else
{
// No special bloodcat encounter. This ALWAYS happens in STATIC PLACEMENT sectors.
gubEnemyEncounterCode = NO_ENCOUNTER_CODE;
return FALSE;
}
@@ -4808,7 +4855,8 @@ void NotifyPlayerOfBloodcatBattle( UINT8 ubSectorX, UINT8 ubSectorY )
}
else if( gubEnemyEncounterCode == ENTERING_BLOODCAT_LAIR_CODE )
{
wcscpy( str, pMapErrorString[ 13 ] );
GetSectorIDString( ubSectorX, ubSectorY, 0, zTempString, FALSE );
swprintf( str, pMapErrorString[ 13 ], zTempString );
}
if( guiCurrentScreen == MAP_SCREEN )
+24 -1
View File
@@ -35,6 +35,8 @@
#include "Strategic Status.h"
// HEADROCK HAM B1: Added include for Dynamic Roaming Militia
#include "MilitiaSquads.h"
// HEADROCK HAM 3.6: Include for Facility Debt
#include "Facilities.h"
#endif
// the max loyalty rating for any given town
@@ -1817,7 +1819,7 @@ void CheckIfEntireTownHasBeenLiberated( INT8 bTownId, INT16 sSectorX, INT16 sSec
UpdateLastDayOfPlayerActivity( ( UINT16 ) ( GetWorldDay() + 2 ) );
}
// HEADROCK HAM B1: Run a function to redefine Roaming Militia Restrictions on city capture.
if (gGameExternalOptions.bDynamicRestrictRoaming)
if (gGameExternalOptions.fDynamicRestrictRoaming)
{
AdjustRoamingRestrictions();
}
@@ -1994,3 +1996,24 @@ void MaximizeLoyaltyForDeidrannaKilled(void)
SetTownLoyalty(bTownId, 100);
}
}
// HEADROCK HAM 3.6: A loyalty hit based on outstanding debt for facility use.
void HandleFacilityDebtLoyaltyHit( void )
{
// Loyalty hit is 1% per $1000 dollars owed.
INT32 iLoyaltyHit = giTotalOwedForFacilityOperationsToday;
if (giTotalOwedForFacilityOperationsToday > 500)
{
// But no less than 1%, if $500 are owed.
iLoyaltyHit = __max(500,iLoyaltyHit);
}
if (iLoyaltyHit > 1)
{
DecrementTownLoyaltyEverywhere( iLoyaltyHit );
}
}
+3
View File
@@ -204,4 +204,7 @@ void HandleLoyaltyImplicationsOfMercRetreat( INT8 bRetreatCode, INT16 sSectorX,
void MaximizeLoyaltyForDeidrannaKilled( void );
// HEADROCK HAM 3.6: Loyalty hit for owing too much money on facility work
void HandleFacilityDebtLoyaltyHit( void );
#endif
+32
View File
@@ -296,6 +296,10 @@
RelativePath=".\Creature Spreading.h"
>
</File>
<File
RelativePath=".\Facilities.h"
>
</File>
<File
RelativePath=".\Game Clock.h"
>
@@ -470,6 +474,10 @@
RelativePath=".\Creature Spreading.cpp"
>
</File>
<File
RelativePath=".\Facilities.cpp"
>
</File>
<File
RelativePath=".\Game Clock.cpp"
>
@@ -626,14 +634,38 @@
RelativePath=".\XML_Army.cpp"
>
</File>
<File
RelativePath=".\XML_Bloodcats.cpp"
>
</File>
<File
RelativePath=".\XML_DynamicRestrictions.cpp"
>
</File>
<File
RelativePath=".\XML_ExtraItems.cpp"
>
</File>
<File
RelativePath=".\XML_Facilities.cpp"
>
</File>
<File
RelativePath=".\XML_FacilityTypes.cpp"
>
</File>
<File
RelativePath=".\XML_Roaming.cpp"
>
</File>
<File
RelativePath=".\XML_SectorNames.cpp"
>
</File>
<File
RelativePath=".\XML_UniformColors.cpp"
>
</File>
</Filter>
</Files>
<Globals>
+36 -4
View File
@@ -295,6 +295,10 @@
RelativePath="Creature Spreading.h"
>
</File>
<File
RelativePath=".\Facilities.h"
>
</File>
<File
RelativePath="Game Clock.h"
>
@@ -467,6 +471,10 @@
RelativePath="Creature Spreading.cpp"
>
</File>
<File
RelativePath=".\Facilities.cpp"
>
</File>
<File
RelativePath="Game Clock.cpp"
>
@@ -623,15 +631,39 @@
RelativePath="XML_Army.cpp"
>
</File>
<File
RelativePath=".\XML_Bloodcats.cpp"
>
</File>
<File
RelativePath=".\XML_DynamicRestrictions.cpp"
>
</File>
<File
RelativePath=".\XML_ExtraItems.cpp"
>
</File>
<File
RelativePath=".\XML_Facilities.cpp"
>
</File>
<File
RelativePath=".\XML_FacilityTypes.cpp"
>
</File>
<File
RelativePath="XML_Roaming.cpp"
>
</File>
<File
RelativePath=".\XML_SectorNames.cpp"
>
</File>
<File
RelativePath=".\XML_UniformColors.cpp"
>
</File>
</Filter>
<File
RelativePath=".\XML_ExtraItems.cpp"
>
</File>
</Files>
<Globals>
</Globals>
+854 -144
View File
File diff suppressed because it is too large Load Diff
+32 -1
View File
@@ -39,6 +39,11 @@ UINT8 CheckOneMilitiaForPromotion(INT16 sMapX, INT16 sMapY, UINT8 ubCurrentRank,
void BuildMilitiaPromotionsString( STR16 str );
// HEADROCK HAM 3.3: Function to determine best leadership for militia training in a given sector.
// Is used for both town and mobile militia.
// HEADROCK HAM 3.6: Argument for Mobile/Town Militia training
UINT8 FindBestMilitiaTrainingLeadershipInSector ( INT16 sMapX, INT16 sMapY, INT8 usMapZ, UINT8 ubMilitiaType );
// call this if the player attacks his own militia
void HandleMilitiaDefections(INT16 sMapX, INT16 sMapY);
@@ -70,7 +75,8 @@ BOOLEAN IsSAMSiteFullOfMilitia( INT16 sSectorX, INT16 sSectorY, INT8 iMilitiaTyp
void HandleContinueOfTownTraining( void );
// handle completion of assignment byt his soldier too and inform the player
void HandleCompletionOfTownTrainingByGroupWithTrainer( SOLDIERTYPE *pTrainer );
// HEADROCK HAM 3.6: Added argument for Mobile Militia training.
void HandleCompletionOfTownTrainingByGroupWithTrainer( SOLDIERTYPE *pTrainer, UINT8 ubMilitiaType );
// clear the list of training completed sectors
void ClearSectorListForCompletedTrainingOfMilitia( void );
@@ -78,4 +84,29 @@ void ClearSectorListForCompletedTrainingOfMilitia( void );
BOOLEAN MilitiaTrainingAllowedInSector( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ );
BOOLEAN MilitiaTrainingAllowedInTown( INT8 bTownId );
// HEADROCK HAM 3.6: Function to calculate Militia and Mobile Militia training squad size.
UINT8 CalcNumMilitiaTrained(UINT8 ubBestLeadership, BOOLEAN fMobile);
// HEADROCK HAM 3.6: Total upkeep costs for YESTERDAY at midnight. Saved to savegames.
extern UINT32 guiTotalUpkeepForMilitia;
// HEADROCK HAM 3.6: Daily check for upkeep of all militia
void HandleMilitiaUpkeepPayment( void );
// Type to hold number of militia in each sector.
typedef struct MILITIA_LIST_TYPE
{
UINT8 ubSectorId;
UINT8 ubNumTownGreens;
UINT8 ubNumTownRegulars;
UINT8 ubNumTownElites;
UINT8 ubNumMobileGreens;
UINT8 ubNumMobileRegulars;
UINT8 ubNumMobileElites;
} MILITIA_LIST_TYPE;
// HEADROCK HAM 3.6: Calculate upkeep costs for militia
UINT32 CalcMilitiaUpkeep( void );
#endif
+343
View File
@@ -0,0 +1,343 @@
#ifdef PRECOMPILEDHEADERS
#include "Strategic All.h"
#include "XML.h"
#else
#include "builddefines.h"
#include <stdio.h>
#include "XML.h"
#include "expat.h"
#include "string.h"
#include "Campaign Types.h"
#include "FileMan.h"
#include "MemMan.h"
#include "Debug Control.h"
#include "mapscreen.h"
#endif
#define MAX_CHAR_DATA_LENGTH 500
// This array stores all XML-read placement data. There are four arrays for each sector, one array for each difficulty
// level. Please note that the Placement Type is only stored in array 0 (gBloodcatPlacements[x][0].PlacementType). It
// is not possible to have different placement types at different difficulty levels. Yet.
BLOODCATPLACEMENT gBloodcatPlacements[256][4];
// Location of the Bloodcat Lair. There can be only one, as there's a quest that relies on its location. This is a
// sectorID, 0-255.
UINT8 gubBloodcatLairSectorId;
typedef enum
{
BLOODCAT_ELEMENT_NONE = 0,
BLOODCAT_ELEMENT_PLACEMENTS,
BLOODCAT_ELEMENT_SECTOR,
BLOODCAT_ELEMENT,
BLOODCAT_ELEMENT_DIFFICULTY,
BLOODCAT_ELEMENT_DIFFICULTY_DATA,
} BLOODCAT_PARSE_STAGE;
typedef struct
{
BLOODCAT_PARSE_STAGE curElement;
CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1];
UINT8 sCurSectorX;
UINT8 sCurSectorY;
BLOODCATPLACEMENT CurPlacement[4];
UINT8 ubCurDifficulty;
UINT32 currentDepth;
UINT32 maxReadDepth;
} BloodcatsParseData;
static void XMLCALL
BloodcatsStartElementHandle(void *userData, const XML_Char *name, const char **atts)
{
BloodcatsParseData * pData = (BloodcatsParseData *) userData;
if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element?
{
if(strcmp(name, "BLOODCAT_PLACEMENTS") == 0 && pData->curElement == BLOODCAT_ELEMENT_NONE)
{
pData->curElement = BLOODCAT_ELEMENT_PLACEMENTS;
pData->maxReadDepth++; //we are not skipping this element
// Initiate Array by setting first character to 0.
for (UINT16 x = 0; x < 256; x++)
{
for (UINT16 y = 0; y < 4; y++)
{
gBloodcatPlacements[x][y].ubFactionAffiliation = 0;
gBloodcatPlacements[x][y].fRespawn = 0;
gBloodcatPlacements[x][y].PlacementType = 0;
gBloodcatPlacements[x][y].ubAmbushChance = 0;
gBloodcatPlacements[x][y].ubMaxBloodcats = 0;
gBloodcatPlacements[x][y].ubMinBloodcats = 0;
}
}
}
else if(strcmp(name, "SECTOR") == 0 && pData->curElement == BLOODCAT_ELEMENT_PLACEMENTS)
{
pData->curElement = BLOODCAT_ELEMENT_SECTOR;
pData->maxReadDepth++; //we are not skipping this element
}
else if(pData->curElement == BLOODCAT_ELEMENT_SECTOR &&
(strcmp(name, "SectorGrid") == 0 ||
strcmp(name, "ubPlacementType") == 0) )
{
pData->curElement = BLOODCAT_ELEMENT;
pData->maxReadDepth++; //we are not skipping this element
}
else if(pData->curElement == BLOODCAT_ELEMENT_SECTOR &&
strcmp(name, "NOVICE") == 0)
{
pData->curElement = BLOODCAT_ELEMENT_DIFFICULTY;
pData->ubCurDifficulty = 0;
pData->maxReadDepth++; //we are not skipping this element
}
else if(pData->curElement == BLOODCAT_ELEMENT_SECTOR &&
strcmp(name, "EXPERIENCED") == 0)
{
pData->curElement = BLOODCAT_ELEMENT_DIFFICULTY;
pData->ubCurDifficulty = 1;
pData->maxReadDepth++; //we are not skipping this element
}
else if(pData->curElement == BLOODCAT_ELEMENT_SECTOR &&
strcmp(name, "EXPERT") == 0)
{
pData->curElement = BLOODCAT_ELEMENT_DIFFICULTY;
pData->ubCurDifficulty = 2;
pData->maxReadDepth++; //we are not skipping this element
}
else if(pData->curElement == BLOODCAT_ELEMENT_SECTOR &&
strcmp(name, "INSANE") == 0)
{
pData->curElement = BLOODCAT_ELEMENT_DIFFICULTY;
pData->ubCurDifficulty = 3;
pData->maxReadDepth++; //we are not skipping this element
}
else if(pData->curElement == BLOODCAT_ELEMENT_DIFFICULTY &&
(strcmp(name, "ubMinBloodcats") == 0 ||
strcmp(name, "ubMaxBloodcats") == 0 ||
strcmp(name, "ubAmbushChance") == 0 ||
strcmp(name, "ubFactionAffiliation") == 0 ||
strcmp(name, "fRespawn") == 0 ))
{
pData->curElement = BLOODCAT_ELEMENT_DIFFICULTY_DATA;
pData->maxReadDepth++; //we are not skipping this element
}
pData->szCharData[0] = '\0';
}
pData->currentDepth++;
}
static void XMLCALL
BloodcatsCharacterDataHandle(void *userData, const XML_Char *str, int len)
{
BloodcatsParseData * pData = (BloodcatsParseData *) userData;
if(pData->currentDepth <= pData->maxReadDepth && strlen(pData->szCharData) < MAX_CHAR_DATA_LENGTH)
strncat(pData->szCharData,str,__min((unsigned int)len,MAX_CHAR_DATA_LENGTH-strlen(pData->szCharData)));
}
static void XMLCALL
BloodcatsEndElementHandle(void *userData, const XML_Char *name)
{
BloodcatsParseData * pData = (BloodcatsParseData *)userData;
if(pData->currentDepth <= pData->maxReadDepth) //we're at the end of an element that we've been reading
{
if(strcmp(name, "BLOODCAT_PLACEMENTS") == 0)
{
pData->curElement = BLOODCAT_ELEMENT_NONE;
}
else if(strcmp(name, "SECTOR") == 0)
{
pData->curElement = BLOODCAT_ELEMENT_PLACEMENTS;
UINT8 ubSectorId = SECTOR(pData->sCurSectorX, pData->sCurSectorY);
if (ubSectorId >= 0 && ubSectorId < 256)
{
// Set placement type for this sector. Only first array has this set, as it is not difficulty-dependent.
gBloodcatPlacements[ ubSectorId ][0].PlacementType = pData->CurPlacement[0].PlacementType;
for (UINT8 x = 0; x < 4; x++)
{
if (pData->CurPlacement[0].PlacementType == 0)
{
// Ambush placement. Bloodcats will appear in this sector randomly.
gBloodcatPlacements[ ubSectorId ][x].ubMinBloodcats = pData->CurPlacement[x].ubMinBloodcats;
gBloodcatPlacements[ ubSectorId ][x].ubMaxBloodcats = pData->CurPlacement[x].ubMaxBloodcats;
gBloodcatPlacements[ ubSectorId ][x].ubAmbushChance = pData->CurPlacement[x].ubAmbushChance;
gBloodcatPlacements[ ubSectorId ][x].ubFactionAffiliation = 0;
gBloodcatPlacements[ ubSectorId ][x].fRespawn = 0;
}
else if (pData->CurPlacement[0].PlacementType == 1)
{
// Static placement. Bloodcats always appear here, but never respawn, and may be unaggressive
// to enemies.
gBloodcatPlacements[ ubSectorId ][x].ubMinBloodcats = 0;
gBloodcatPlacements[ ubSectorId ][x].ubMaxBloodcats = pData->CurPlacement[x].ubMaxBloodcats;
gBloodcatPlacements[ ubSectorId ][x].ubAmbushChance = 0;
gBloodcatPlacements[ ubSectorId ][x].ubFactionAffiliation = pData->CurPlacement[x].ubFactionAffiliation;
gBloodcatPlacements[ ubSectorId ][x].fRespawn = 0;
}
else if (pData->CurPlacement[0].PlacementType == 2)
{
// Lair sector. There can be only one, and it is affected by the Quest. Bloodcats can regenerate
// their numbers here over time.
gBloodcatPlacements[ ubSectorId ][x].ubMinBloodcats = 0;
gBloodcatPlacements[ ubSectorId ][x].ubMaxBloodcats = pData->CurPlacement[x].ubMaxBloodcats;
gBloodcatPlacements[ ubSectorId ][x].ubAmbushChance = 0;
gBloodcatPlacements[ ubSectorId ][x].ubFactionAffiliation = 0;
gBloodcatPlacements[ ubSectorId ][x].fRespawn = pData->CurPlacement[x].fRespawn;
}
}
}
}
else if(strcmp(name, "SectorGrid") == 0 )
{
UINT8 x, y;
pData->curElement = BLOODCAT_ELEMENT_SECTOR;
y = (UINT8)pData->szCharData[0] & 0x1F;
x = (UINT8)atol(&pData->szCharData[1]);
if ( x > 0 && x <= 16 && y > 0 && y <= 16 )
{
pData->sCurSectorX = x;
pData->sCurSectorY = y;
}
THROWIFFALSE( (SECTOR(x,y) >= 0 && SECTOR(x,y) < 256) , L"Illegal sector number in BloodcatPlacements.XML" );
}
else if(strcmp(name, "ubPlacementType") == 0 )
{
pData->curElement = BLOODCAT_ELEMENT_SECTOR;
// Only set for first array (Difficulty Irrelevant)
pData->CurPlacement[0].PlacementType = (UINT8) atol(pData->szCharData);
}
else if(strcmp(name, "NOVICE") == 0 )
{
// Just return to sector data.
pData->curElement = BLOODCAT_ELEMENT_SECTOR;
}
else if(strcmp(name, "EXPERIENCED") == 0 )
{
// Just return to sector data.
pData->curElement = BLOODCAT_ELEMENT_SECTOR;
}
else if(strcmp(name, "EXPERT") == 0 )
{
// Just return to sector data.
pData->curElement = BLOODCAT_ELEMENT_SECTOR;
}
else if(strcmp(name, "INSANE") == 0 )
{
// Just return to sector data.
pData->curElement = BLOODCAT_ELEMENT_SECTOR;
}
else if(strcmp(name, "ubMinBloodcats") == 0 )
{
pData->curElement = BLOODCAT_ELEMENT_DIFFICULTY;
pData->CurPlacement[pData->ubCurDifficulty].ubMinBloodcats = (UINT8) atol(pData->szCharData);
}
else if(strcmp(name, "ubMaxBloodcats") == 0 )
{
pData->curElement = BLOODCAT_ELEMENT_DIFFICULTY;
pData->CurPlacement[pData->ubCurDifficulty].ubMaxBloodcats = (UINT8) atol(pData->szCharData);
}
else if(strcmp(name, "ubAmbushChance") == 0 )
{
pData->curElement = BLOODCAT_ELEMENT_DIFFICULTY;
pData->CurPlacement[pData->ubCurDifficulty].ubAmbushChance = (UINT8) atol(pData->szCharData);
}
else if(strcmp(name, "ubFactionAffiliation") == 0 )
{
pData->curElement = BLOODCAT_ELEMENT_DIFFICULTY;
pData->CurPlacement[pData->ubCurDifficulty].ubFactionAffiliation = (UINT8) atol(pData->szCharData);
}
else if(strcmp(name, "fRespawn") == 0 )
{
pData->curElement = BLOODCAT_ELEMENT_DIFFICULTY;
pData->CurPlacement[pData->ubCurDifficulty].fRespawn = (UINT8) atol(pData->szCharData);
}
pData->maxReadDepth--;
}
pData->currentDepth--;
}
BOOLEAN ReadInBloodcatPlacements(STR fileName)
{
HWFILE hFile;
UINT32 uiBytesRead;
UINT32 uiFSize;
CHAR8 * lpcBuffer;
XML_Parser parser = XML_ParserCreate(NULL);
BloodcatsParseData pData;
hFile = FileOpen( fileName, FILE_ACCESS_READ, FALSE );
if ( !hFile )
return( FALSE );
uiFSize = FileGetSize(hFile);
lpcBuffer = (CHAR8 *) MemAlloc(uiFSize+1);
//Read in block
if ( !FileRead( hFile, lpcBuffer, uiFSize, &uiBytesRead ) )
{
MemFree(lpcBuffer);
return( FALSE );
}
lpcBuffer[uiFSize] = 0; //add a null terminator
FileClose( hFile );
XML_SetElementHandler(parser, BloodcatsStartElementHandle, BloodcatsEndElementHandle);
XML_SetCharacterDataHandler(parser, BloodcatsCharacterDataHandle);
memset(&pData,0,sizeof(pData));
XML_SetUserData(parser, &pData);
if(!XML_Parse(parser, lpcBuffer, uiFSize, TRUE))
{
CHAR8 errorBuf[511];
sprintf(errorBuf, "XML Parser Error in BloodcatPlacements.xml: %s at line %d", XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser));
LiveMessage(errorBuf);
MemFree(lpcBuffer);
return FALSE;
}
MemFree(lpcBuffer);
XML_ParserFree(parser);
return TRUE;
}
+223
View File
@@ -0,0 +1,223 @@
///////////////////////////////////////////////////////////////////////////////
// HEADROCK HAM 3.4: Dynamic Roaming Restrictions XMLization
//
// This is a new part of the Dynamic Roaming Restrictions system. It reads in
// data about sectors to "un-restrict", and the towns that must be liberated
// for them to be unrestricted. There can be several unrestriction conditions
// for each sector, and only one of the conditions must be true for the sector
// to become allowed.
//
///////////////////////////////////////////////////////////////////////////////
#ifdef PRECOMPILEDHEADERS
#include "Tactical All.h"
#else
#include "sgp.h"
#include "Debug Control.h"
#include "expat.h"
#include "gamesettings.h"
#include "XML.h"
#include "FileMan.h"
#include "campaign types.h"
#include "militiasquads.h"
#include "mapscreen.h"
#endif
// HEADROCK HAM 3.4: Stores restriction data from XML, including required cities for each sector to be allowed.
extern DYNAMICRESTRICTIONS gDynamicRestrictions[5001];
struct
{
PARSE_STAGE curElement;
CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1];
INT16 sCurSectorX;
INT16 sCurSectorY;
UINT32 uiReqTownFlags;
UINT32 maxArraySize;
UINT32 curIndex;
UINT32 currentDepth;
UINT32 maxReadDepth;
}
typedef dynamicroamingParseData;
static void XMLCALL
dynamicroamingStartElementHandle(void *userData, const XML_Char *name, const XML_Char **atts)
{
dynamicroamingParseData * pData = (dynamicroamingParseData *)userData;
if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element?
{
if(strcmp(name, "DYNAMICROAMING") == 0 && pData->curElement == ELEMENT_NONE)
{
// Set all sector IDs to -1 ("unused")
for (UINT16 cnt=0; cnt<5001; cnt++)
{
gDynamicRestrictions[cnt].bSectorID = -1;
}
pData->curElement = ELEMENT_LIST;
pData->maxReadDepth++; //we are not skipping this element
}
else if(strcmp(name, "RESTRICTION") == 0 && pData->curElement == ELEMENT_LIST)
{
pData->curElement = ELEMENT;
pData->uiReqTownFlags = 0;
//DebugMsg(TOPIC_JA2, DBG_LEVEL_3,"MergeStartElementHandle: setting memory for curMerge");
pData->maxReadDepth++; //we are not skipping this element
//pData->curIndex++;
}
else if(pData->curElement == ELEMENT &&
(strcmp(name, "SectorGrid") == 0 ||
strcmp(name, "ReqTown") == 0 ))
{
pData->curElement = ELEMENT_PROPERTY;
pData->maxReadDepth++; //we are not skipping this element
}
pData->szCharData[0] = '\0';
}
pData->currentDepth++;
}
static void XMLCALL
dynamicroamingCharacterDataHandle(void *userData, const XML_Char *str, int len)
{
dynamicroamingParseData * pData = (dynamicroamingParseData *)userData;
if( (pData->currentDepth <= pData->maxReadDepth) &&
(strlen(pData->szCharData) < MAX_CHAR_DATA_LENGTH)
){
strncat(pData->szCharData,str,__min((unsigned int)len,MAX_CHAR_DATA_LENGTH-strlen(pData->szCharData)));
}
}
static void XMLCALL
dynamicroamingEndElementHandle(void *userData, const XML_Char *name)
{
dynamicroamingParseData * pData = (dynamicroamingParseData *)userData;
if(pData->currentDepth <= pData->maxReadDepth) //we're at the end of an element that we've been reading
{
if(strcmp(name, "DYNAMICROAMING") == 0)
{
pData->curElement = ELEMENT_NONE;
}
else if(strcmp(name, "RESTRICTION") == 0)
{
pData->curElement = ELEMENT_LIST;
if (SECTOR(pData->sCurSectorX, pData->sCurSectorY) >= 0 && SECTOR(pData->sCurSectorX, pData->sCurSectorY) < 256)
{
pData->curIndex++;
gDynamicRestrictions[pData->curIndex].bSectorID = SECTOR(pData->sCurSectorX,pData->sCurSectorY);
gDynamicRestrictions[pData->curIndex].uiReqTownFlags |= pData->uiReqTownFlags;
}
}
else if(strcmp(name, "SectorGrid") == 0 )
{
UINT8 x, y;
pData->curElement = ELEMENT;
y = (UINT8)pData->szCharData[0] & 0x1F;
x = (UINT8)atol(&pData->szCharData[1]);
if ( x > 0 && x <= 16 && y > 0 && y <= 16 )
{
pData->sCurSectorX = x;
pData->sCurSectorY = y;
}
}
else if(strcmp(name, "ReqTown") == 0 )
{
if ((UINT8) atol(pData->szCharData) > 0 && (UINT8) atol(pData->szCharData) < NUM_TOWNS )
{
pData->curElement = ELEMENT;
pData->uiReqTownFlags |= (1 << ((UINT8) atol(pData->szCharData) - 1));
}
else
{
pData->uiReqTownFlags = 0;
}
}
pData->maxReadDepth--;
}
pData->currentDepth--;
}
BOOLEAN ReadInDynamicRoamingRestrictions(STR fileName)
{
HWFILE hFile;
UINT32 uiBytesRead;
UINT32 uiFSize;
CHAR8 * lpcBuffer;
XML_Parser parser = XML_ParserCreate(NULL);
dynamicroamingParseData pData;
DebugMsg(TOPIC_JA2, DBG_LEVEL_3, "Loading DynamicRestrictions.xml" );
// Open merges file
hFile = FileOpen( fileName, FILE_ACCESS_READ, FALSE );
if ( !hFile )
return( FALSE );
uiFSize = FileGetSize(hFile);
lpcBuffer = (CHAR8 *) MemAlloc(uiFSize+1);
//Read in block
if ( !FileRead( hFile, lpcBuffer, uiFSize, &uiBytesRead ) )
{
MemFree(lpcBuffer);
return( FALSE );
}
lpcBuffer[uiFSize] = 0; //add a null terminator
FileClose( hFile );
XML_SetElementHandler(parser, dynamicroamingStartElementHandle, dynamicroamingEndElementHandle);
XML_SetCharacterDataHandler(parser, dynamicroamingCharacterDataHandle);
memset(&pData,0,sizeof(pData));
pData.maxArraySize = MAXITEMS;
pData.curIndex = -1;
XML_SetUserData(parser, &pData);
if(!XML_Parse(parser, lpcBuffer, uiFSize, TRUE))
{
CHAR8 errorBuf[511];
sprintf(errorBuf, "XML Parser Error in DynamicRestrictions.xml: %s at line %d", XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser));
LiveMessage(errorBuf);
MemFree(lpcBuffer);
return FALSE;
}
MemFree(lpcBuffer);
XML_ParserFree(parser);
return( TRUE );
}
+217
View File
@@ -0,0 +1,217 @@
///////////////////////////////////////////////////////////////////////////////
// HEADROCK HAM 3.5: Facility Location Externalization
//
// This file reads from an XML called "Facilities.XML". That file contains
// the locations of all facilities such as the "Gun Range", "Industrial",
// "Prison", etcetera. The data is written DIRECTLY into the global SectorInfo
// array, replacing a hardcoded system.
//
///////////////////////////////////////////////////////////////////////////////
#ifdef PRECOMPILEDHEADERS
#include "Tactical All.h"
#else
#include "sgp.h"
#include "Debug Control.h"
#include "expat.h"
#include "gamesettings.h"
#include "XML.h"
#include "FileMan.h"
#include "Campaign Types.h"
#endif
FACILITYLOCATIONS gFacilityLocations[256][MAX_NUM_FACILITY_TYPES];
UINT16 NUM_FACILITIES;
struct
{
PARSE_STAGE curElement;
CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1];
INT16 sCurSectorX;
INT16 sCurSectorY;
UINT8 ubCurFacilityType;
UINT8 ubHidden;
UINT32 maxArraySize;
UINT32 curIndex;
UINT32 currentDepth;
UINT32 maxReadDepth;
}
typedef facilityParseData;
static void XMLCALL
facilityStartElementHandle(void *userData, const XML_Char *name, const XML_Char **atts)
{
facilityParseData * pData = (facilityParseData *)userData;
if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element?
{
if(strcmp(name, "SECTORFACILITIES") == 0 && pData->curElement == ELEMENT_NONE)
{
pData->curElement = ELEMENT_LIST;
pData->maxReadDepth++; //we are not skipping this element
}
else if(strcmp(name, "FACILITY") == 0 && pData->curElement == ELEMENT_LIST)
{
pData->curElement = ELEMENT;
//DebugMsg(TOPIC_JA2, DBG_LEVEL_3,"MergeStartElementHandle: setting memory for curMerge");
pData->maxReadDepth++; //we are not skipping this element
//pData->curIndex++;
}
else if(pData->curElement == ELEMENT &&
(strcmp(name, "SectorGrid") == 0 ||
strcmp(name, "FacilityType") == 0 ||
strcmp(name, "ubHidden") == 0
))
{
pData->curElement = ELEMENT_PROPERTY;
pData->maxReadDepth++; //we are not skipping this element
}
pData->szCharData[0] = '\0';
}
pData->currentDepth++;
}
static void XMLCALL
facilityCharacterDataHandle(void *userData, const XML_Char *str, int len)
{
facilityParseData * pData = (facilityParseData *)userData;
if( (pData->currentDepth <= pData->maxReadDepth) &&
(strlen(pData->szCharData) < MAX_CHAR_DATA_LENGTH)
){
strncat(pData->szCharData,str,__min((unsigned int)len,MAX_CHAR_DATA_LENGTH-strlen(pData->szCharData)));
}
}
static void XMLCALL
facilityEndElementHandle(void *userData, const XML_Char *name)
{
facilityParseData * pData = (facilityParseData *)userData;
if(pData->currentDepth <= pData->maxReadDepth) //we're at the end of an element that we've been reading
{
if(strcmp(name, "SECTORFACILITIES") == 0)
{
pData->curElement = ELEMENT_NONE;
NUM_FACILITIES = pData->curIndex;
}
else if(strcmp(name, "FACILITY") == 0)
{
pData->curIndex++;
pData->curElement = ELEMENT_LIST;
if (pData->ubCurFacilityType != 0)
{
gFacilityLocations[SECTOR(pData->sCurSectorX,pData->sCurSectorY)][pData->ubCurFacilityType].fFacilityHere = TRUE;
gFacilityLocations[SECTOR(pData->sCurSectorX,pData->sCurSectorY)][pData->ubCurFacilityType].ubHidden = pData->ubHidden;
}
}
else if(strcmp(name, "SectorGrid") == 0 )
{
UINT8 x, y;
pData->curElement = ELEMENT;
y = (UINT8)pData->szCharData[0] & 0x1F;
x = (UINT8)atol(&pData->szCharData[1]);
if ( x > 0 && x <= 16 && y > 0 && y <= 16 )
{
pData->sCurSectorX = x;
pData->sCurSectorY = y;
}
}
else if(strcmp(name, "FacilityType") == 0 )
{
pData->curElement = ELEMENT;
pData->ubCurFacilityType = (UINT8) atol(pData->szCharData);
}
else if(strcmp(name, "ubHidden") == 0 )
{
pData->curElement = ELEMENT;
pData->ubHidden = (BOOLEAN) atol(pData->szCharData);
}
pData->maxReadDepth--;
}
pData->currentDepth--;
}
BOOLEAN ReadInSectorFacilities(STR fileName)
{
HWFILE hFile;
UINT32 uiBytesRead;
UINT32 uiFSize;
CHAR8 * lpcBuffer;
XML_Parser parser = XML_ParserCreate(NULL);
facilityParseData pData;
DebugMsg(TOPIC_JA2, DBG_LEVEL_3, "Loading Facilities.xml" );
// Open merges file
hFile = FileOpen( fileName, FILE_ACCESS_READ, FALSE );
if ( !hFile )
return( FALSE );
uiFSize = FileGetSize(hFile);
lpcBuffer = (CHAR8 *) MemAlloc(uiFSize+1);
//Read in block
if ( !FileRead( hFile, lpcBuffer, uiFSize, &uiBytesRead ) )
{
MemFree(lpcBuffer);
return( FALSE );
}
lpcBuffer[uiFSize] = 0; //add a null terminator
FileClose( hFile );
XML_SetElementHandler(parser, facilityStartElementHandle, facilityEndElementHandle);
XML_SetCharacterDataHandler(parser, facilityCharacterDataHandle);
memset(&pData,0,sizeof(pData));
pData.maxArraySize = MAXITEMS;
pData.curIndex = -1;
XML_SetUserData(parser, &pData);
if(!XML_Parse(parser, lpcBuffer, uiFSize, TRUE))
{
CHAR8 errorBuf[511];
sprintf(errorBuf, "XML Parser Error in Facilities.xml: %s at line %d", XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser));
LiveMessage(errorBuf);
MemFree(lpcBuffer);
return FALSE;
}
MemFree(lpcBuffer);
XML_ParserFree(parser);
return( TRUE );
}
File diff suppressed because it is too large Load Diff
-1
View File
@@ -18,7 +18,6 @@
extern INT32 iRestrictedSectorArraySize;
extern UINT32 gRestrictMilitia[256];
typedef enum
{
ROAMING_ELEMENT_NONE = 0,
+232
View File
@@ -0,0 +1,232 @@
#ifdef PRECOMPILEDHEADERS
#include "Strategic All.h"
#include "XML.h"
#else
#include "builddefines.h"
#include <stdio.h>
#include "XML.h"
#include "expat.h"
#include "string.h"
#include "Campaign Types.h"
#include "FileMan.h"
#include "MemMan.h"
#include "Debug Control.h"
#include "mapscreen.h"
#endif
#define MAX_CHAR_DATA_LENGTH 500
// Four different sector names, used at different times.
extern CHAR16 gzSectorNames[256][4][MAX_SECTOR_NAME_LENGTH];
typedef enum
{
SECTORNAME_ELEMENT_NONE = 0,
SECTORNAME_ELEMENT_SECTOR_NAMES,
SECTORNAME_ELEMENT_SECTOR,
SECTORNAME_ELEMENT,
} SECTORNAME_PARSE_STAGE;
typedef struct
{
SECTORNAME_PARSE_STAGE curElement;
CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1];
UINT8 sCurSectorX;
UINT8 sCurSectorY;
CHAR16 szCurUnexploredName[MAX_SECTOR_NAME_LENGTH];
CHAR16 szCurDetailedUnexploredName[MAX_SECTOR_NAME_LENGTH];
CHAR16 szCurExploredName[MAX_SECTOR_NAME_LENGTH];
CHAR16 szCurDetailedExploredName[MAX_SECTOR_NAME_LENGTH];
UINT32 currentDepth;
UINT32 maxReadDepth;
} SectorNameParseData;
static void XMLCALL
SectorNameStartElementHandle(void *userData, const XML_Char *name, const char **atts)
{
SectorNameParseData * pData = (SectorNameParseData *) userData;
if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element?
{
if(strcmp(name, "SECTOR_NAMES") == 0 && pData->curElement == SECTORNAME_ELEMENT_NONE)
{
pData->curElement = SECTORNAME_ELEMENT_SECTOR_NAMES;
pData->maxReadDepth++; //we are not skipping this element
// Initiate Array by setting first character to 0.
for (UINT16 x = 0; x < 256; x++)
{
gzSectorNames[x][0][0]=0;
gzSectorNames[x][1][0]=0;
gzSectorNames[x][2][0]=0;
gzSectorNames[x][3][0]=0;
}
}
else if(strcmp(name, "SECTOR") == 0 && pData->curElement == SECTORNAME_ELEMENT_SECTOR_NAMES)
{
pData->curElement = SECTORNAME_ELEMENT_SECTOR;
pData->maxReadDepth++; //we are not skipping this element
}
else if(pData->curElement == SECTORNAME_ELEMENT_SECTOR &&
(strcmp(name, "SectorGrid") == 0 ||
strcmp(name, "szUnexploredName") == 0 ||
strcmp(name, "szDetailedUnexploredName") == 0 ||
strcmp(name, "szExploredName") == 0 ||
strcmp(name, "szDetailedExploredName") == 0 ))
{
pData->curElement = SECTORNAME_ELEMENT;
pData->maxReadDepth++; //we are not skipping this element
}
pData->szCharData[0] = '\0';
}
pData->currentDepth++;
}
static void XMLCALL
SectorNameCharacterDataHandle(void *userData, const XML_Char *str, int len)
{
SectorNameParseData * pData = (SectorNameParseData *) userData;
if(pData->currentDepth <= pData->maxReadDepth && strlen(pData->szCharData) < MAX_CHAR_DATA_LENGTH)
strncat(pData->szCharData,str,__min((unsigned int)len,MAX_CHAR_DATA_LENGTH-strlen(pData->szCharData)));
}
static void XMLCALL
SectorNameEndElementHandle(void *userData, const XML_Char *name)
{
SectorNameParseData * pData = (SectorNameParseData *)userData;
if(pData->currentDepth <= pData->maxReadDepth) //we're at the end of an element that we've been reading
{
if(strcmp(name, "SECTOR_NAMES") == 0)
{
pData->curElement = SECTORNAME_ELEMENT_NONE;
}
else if(strcmp(name, "SECTOR") == 0)
{
pData->curElement = SECTORNAME_ELEMENT_SECTOR_NAMES;
UINT8 ubSectorId = SECTOR(pData->sCurSectorX, pData->sCurSectorY);
if (ubSectorId >= 0 && ubSectorId < 256)
{
wcscpy(gzSectorNames[ubSectorId][0], pData->szCurUnexploredName);
wcscpy(gzSectorNames[ubSectorId][1], pData->szCurDetailedUnexploredName);
wcscpy(gzSectorNames[ubSectorId][2], pData->szCurExploredName);
wcscpy(gzSectorNames[ubSectorId][3], pData->szCurDetailedExploredName);
}
}
else if(strcmp(name, "SectorGrid") == 0 )
{
UINT8 x, y;
pData->curElement = SECTORNAME_ELEMENT_SECTOR;
y = (UINT8)pData->szCharData[0] & 0x1F;
x = (UINT8)atol(&pData->szCharData[1]);
if ( x > 0 && x <= 16 && y > 0 && y <= 16 )
{
pData->sCurSectorX = x;
pData->sCurSectorY = y;
}
}
else if(strcmp(name, "szUnexploredName") == 0 )
{
pData->curElement = SECTORNAME_ELEMENT_SECTOR;
MultiByteToWideChar( CP_UTF8, 0, pData->szCharData, -1, pData->szCurUnexploredName, sizeof(pData->szCurUnexploredName)/sizeof(pData->szCurUnexploredName[0]) );
pData->szCurUnexploredName[sizeof(pData->szCurUnexploredName)/sizeof(pData->szCurUnexploredName[0]) - 1] = '\0';
}
else if(strcmp(name, "szDetailedUnexploredName") == 0 )
{
pData->curElement = SECTORNAME_ELEMENT_SECTOR;
MultiByteToWideChar( CP_UTF8, 0, pData->szCharData, -1, pData->szCurDetailedUnexploredName, sizeof(pData->szCurDetailedUnexploredName)/sizeof(pData->szCurDetailedUnexploredName[0]) );
pData->szCurDetailedUnexploredName[sizeof(pData->szCurDetailedUnexploredName)/sizeof(pData->szCurDetailedUnexploredName[0]) - 1] = '\0';
}
else if(strcmp(name, "szExploredName") == 0 )
{
pData->curElement = SECTORNAME_ELEMENT_SECTOR;
MultiByteToWideChar( CP_UTF8, 0, pData->szCharData, -1, pData->szCurExploredName, sizeof(pData->szCurExploredName)/sizeof(pData->szCurExploredName[0]) );
pData->szCurExploredName[sizeof(pData->szCurExploredName)/sizeof(pData->szCurExploredName[0]) - 1] = '\0';
}
else if(strcmp(name, "szDetailedExploredName") == 0 )
{
pData->curElement = SECTORNAME_ELEMENT_SECTOR;
MultiByteToWideChar( CP_UTF8, 0, pData->szCharData, -1, pData->szCurDetailedExploredName, sizeof(pData->szCurDetailedExploredName)/sizeof(pData->szCurDetailedExploredName[0]) );
pData->szCurDetailedExploredName[sizeof(pData->szCurDetailedExploredName)/sizeof(pData->szCurDetailedExploredName[0]) - 1] = '\0';
}
pData->maxReadDepth--;
}
pData->currentDepth--;
}
BOOLEAN ReadInSectorNames(STR fileName)
{
HWFILE hFile;
UINT32 uiBytesRead;
UINT32 uiFSize;
CHAR8 * lpcBuffer;
XML_Parser parser = XML_ParserCreate(NULL);
SectorNameParseData pData;
hFile = FileOpen( fileName, FILE_ACCESS_READ, FALSE );
if ( !hFile )
return( FALSE );
uiFSize = FileGetSize(hFile);
lpcBuffer = (CHAR8 *) MemAlloc(uiFSize+1);
//Read in block
if ( !FileRead( hFile, lpcBuffer, uiFSize, &uiBytesRead ) )
{
MemFree(lpcBuffer);
return( FALSE );
}
lpcBuffer[uiFSize] = 0; //add a null terminator
FileClose( hFile );
XML_SetElementHandler(parser, SectorNameStartElementHandle, SectorNameEndElementHandle);
XML_SetCharacterDataHandler(parser, SectorNameCharacterDataHandle);
memset(&pData,0,sizeof(pData));
XML_SetUserData(parser, &pData);
if(!XML_Parse(parser, lpcBuffer, uiFSize, TRUE))
{
CHAR8 errorBuf[511];
sprintf(errorBuf, "XML Parser Error in SectorNames.xml: %s at line %d", XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser));
LiveMessage(errorBuf);
MemFree(lpcBuffer);
return FALSE;
}
MemFree(lpcBuffer);
XML_ParserFree(parser);
return TRUE;
}
+260
View File
@@ -0,0 +1,260 @@
////////////////////////////////////////////////////////////
//
// HEADROCK HAM 3.6:
//
// This code reads an XML called "UniformColors.XML", which tells the program which colors to use for
// "standard" uniforms, including randomly-generated enemies and militia (for now).
//
//////////////////////////////////////////////////////////////
#ifdef PRECOMPILEDHEADERS
#include "Strategic All.h"
#include "XML.h"
#else
#include "builddefines.h"
#include <stdio.h>
#include "XML.h"
#include "expat.h"
#include "string.h"
#include "Campaign Types.h"
#include "FileMan.h"
#include "MemMan.h"
#include "Debug Control.h"
#include "mapscreen.h"
#endif
#define MAX_CHAR_DATA_LENGTH 500
// Error strings for this XML reader
STR16 szUniformErrorStrings[]=
{
L"ENEMY_ADMIN",
L"ENEMY_TROOP",
L"ENEMY_ELITE",
L"MILITIA_ROOKIE",
L"MILITIA_REGULAR",
L"MILITIA_ELITE",
};
// Array to hold uniform data
UNIFORMCOLORS gUniformColors[NUM_UNIFORMS];
typedef enum
{
UNIFORM_ELEMENT_NONE = 0,
UNIFORM_ELEMENT_LIST,
UNIFORM_ELEMENT,
UNIFORM_ELEMENT_DATA,
} UNIFORM_PARSE_STAGE;
typedef struct
{
UNIFORM_PARSE_STAGE curElement;
CHAR8 szCharData[MAX_CHAR_DATA_LENGTH+1];
UINT8 sCurUniform;
PaletteRepID szCurVest;
PaletteRepID szCurPants;
UINT32 currentDepth;
UINT32 maxReadDepth;
} UniformParseData;
// Array for flags making sure that we have ALL uniform data defined.
BOOLEAN UniformDataFound[NUM_UNIFORMS];
static void XMLCALL
UniformStartElementHandle(void *userData, const XML_Char *name, const char **atts)
{
UniformParseData * pData = (UniformParseData *) userData;
if(pData->currentDepth <= pData->maxReadDepth) //are we reading this element?
{
if(strcmp(name, "UNIFORMS") == 0 && pData->curElement == UNIFORM_ELEMENT_NONE)
{
pData->curElement = UNIFORM_ELEMENT_LIST;
pData->maxReadDepth++; //we are not skipping this element
for (UINT8 cnt = 0; cnt < NUM_UNIFORMS; cnt++)
{
// reset array
UniformDataFound[cnt] = FALSE;
}
}
else if(pData->curElement == UNIFORM_ELEMENT_LIST &&
(strcmp(name, "ENEMY_ADMIN") == 0 ||
strcmp(name, "ENEMY_TROOP") == 0 ||
strcmp(name, "ENEMY_ELITE") == 0 ||
strcmp(name, "MILITIA_ROOKIE") == 0 ||
strcmp(name, "MILITIA_REGULAR") == 0 ||
strcmp(name, "MILITIA_ELITE") == 0 ) )
{
if (strcmp(name, "ENEMY_ADMIN") == 0)
{
pData->sCurUniform = UNIFORM_ENEMY_ADMIN;
}
else if (strcmp(name, "ENEMY_TROOP") == 0)
{
pData->sCurUniform = UNIFORM_ENEMY_TROOP;
}
else if (strcmp(name, "ENEMY_ELITE") == 0)
{
pData->sCurUniform = UNIFORM_ENEMY_ELITE;
}
else if (strcmp(name, "MILITIA_ROOKIE") == 0)
{
pData->sCurUniform = UNIFORM_MILITIA_ROOKIE;
}
else if (strcmp(name, "MILITIA_REGULAR") == 0)
{
pData->sCurUniform = UNIFORM_MILITIA_REGULAR;
}
else if (strcmp(name, "MILITIA_ELITE") == 0)
{
pData->sCurUniform = UNIFORM_MILITIA_ELITE;
}
pData->curElement = UNIFORM_ELEMENT;
pData->maxReadDepth++; //we are not skipping this element
}
else if(pData->curElement == UNIFORM_ELEMENT &&
(strcmp(name, "Vest") == 0 ||
strcmp(name, "Pants") == 0 ))
{
pData->curElement = UNIFORM_ELEMENT_DATA;
pData->maxReadDepth++; //we are not skipping this element
}
pData->szCharData[0] = '\0';
}
pData->currentDepth++;
}
static void XMLCALL
UniformCharacterDataHandle(void *userData, const XML_Char *str, int len)
{
UniformParseData * pData = (UniformParseData *) userData;
if(pData->currentDepth <= pData->maxReadDepth && strlen(pData->szCharData) < MAX_CHAR_DATA_LENGTH)
strncat(pData->szCharData,str,__min((unsigned int)len,MAX_CHAR_DATA_LENGTH-strlen(pData->szCharData)));
}
static void XMLCALL
UniformEndElementHandle(void *userData, const XML_Char *name)
{
UniformParseData * pData = (UniformParseData *)userData;
if(pData->currentDepth <= pData->maxReadDepth) //we're at the end of an element that we've been reading
{
if(strcmp(name, "UNIFORMS") == 0)
{
// All entries are mandatory. Exception thrown if an entry was not found
for (UINT8 cnt = 0; cnt < NUM_UNIFORMS; cnt++)
{
if (!UniformDataFound[cnt])
{
CHAR16 sString[256];
swprintf( sString, L"Error in UniformColors.XML: Uniform color for %s not found or not properly defined!", szUniformErrorStrings[ cnt ] );
THROWEXCEPTION( sString );
}
}
pData->curElement = UNIFORM_ELEMENT_NONE;
}
else if(strcmp(name, "ENEMY_ADMIN") == 0 ||
strcmp(name, "ENEMY_TROOP") == 0 ||
strcmp(name, "ENEMY_ELITE") == 0 ||
strcmp(name, "MILITIA_ROOKIE") == 0 ||
strcmp(name, "MILITIA_REGULAR") == 0 ||
strcmp(name, "MILITIA_ELITE") == 0 )
{
pData->curElement = UNIFORM_ELEMENT_LIST;
if (pData->sCurUniform >= UNIFORM_ENEMY_ADMIN && pData->sCurUniform < NUM_UNIFORMS )
{
memcpy( &(gUniformColors[pData->sCurUniform].pants), &(pData->szCurPants), sizeof(PaletteRepID) );
memcpy( &(gUniformColors[pData->sCurUniform].vest), &(pData->szCurVest), sizeof(PaletteRepID) );
UniformDataFound[pData->sCurUniform] = TRUE;
}
}
else if(strcmp(name, "Vest") == 0 )
{
pData->curElement = UNIFORM_ELEMENT;
strcpy(pData->szCurVest, pData->szCharData);
}
else if(strcmp(name, "Pants") == 0 )
{
pData->curElement = UNIFORM_ELEMENT;
strcpy(pData->szCurPants, pData->szCharData);
}
pData->maxReadDepth--;
}
pData->currentDepth--;
}
BOOLEAN ReadInUniforms(STR fileName)
{
HWFILE hFile;
UINT32 uiBytesRead;
UINT32 uiFSize;
CHAR8 * lpcBuffer;
XML_Parser parser = XML_ParserCreate(NULL);
UniformParseData pData;
hFile = FileOpen( fileName, FILE_ACCESS_READ, FALSE );
if ( !hFile )
return( FALSE );
uiFSize = FileGetSize(hFile);
lpcBuffer = (CHAR8 *) MemAlloc(uiFSize+1);
//Read in block
if ( !FileRead( hFile, lpcBuffer, uiFSize, &uiBytesRead ) )
{
MemFree(lpcBuffer);
return( FALSE );
}
lpcBuffer[uiFSize] = 0; //add a null terminator
FileClose( hFile );
XML_SetElementHandler(parser, UniformStartElementHandle, UniformEndElementHandle);
XML_SetCharacterDataHandler(parser, UniformCharacterDataHandle);
memset(&pData,0,sizeof(pData));
XML_SetUserData(parser, &pData);
if(!XML_Parse(parser, lpcBuffer, uiFSize, TRUE))
{
CHAR8 errorBuf[511];
sprintf(errorBuf, "XML Parser Error in UniformColors.xml: %s at line %d", XML_ErrorString(XML_GetErrorCode(parser)), XML_GetCurrentLineNumber(parser));
LiveMessage(errorBuf);
MemFree(lpcBuffer);
return FALSE;
}
MemFree(lpcBuffer);
XML_ParserFree(parser);
return TRUE;
}
+329 -11
View File
@@ -111,6 +111,8 @@
#include "Strategic Status.h"
#include "Soldier Create.h"
#include "Animation Control.h"
// HEADROCK HAM 3.6: Include facilities for assignment display
#include "Facilities.h"
#endif
#include "connect.h" //hayden
@@ -905,6 +907,9 @@ void CreateContractBox( SOLDIERTYPE *pCharacter );
void CreateAssignmentsBox( void );
void CreateTrainingBox( void );
void CreateMercRemoveAssignBox( void );
// HEADROCK HAM 3.6: Facility box, Sub-menu
void CreateFacilityBox( void );
void CreateFacilityAssignmentBox( void );
void DetermineWhichAssignmentMenusCanBeShown( void );
void DetermineWhichMilitiaControlMenusCanBeShown( void ); //lal
@@ -2837,16 +2842,29 @@ void DrawCharacterInfo(INT16 sCharNumber)
// second assignment line
// HEADROCK HAM 3.6: Operating a facility?
if (pSoldier->sFacilityTypeOperated != -1)
{
UINT8 ubFacilityType = (UINT8)pSoldier->sFacilityTypeOperated;
// Print sector ID string
GetShortSectorString( pSoldier->sSectorX, pSoldier->sSectorY, sString );
wcscat( sString, L": " );
wcscat( sString, gFacilityTypes[ubFacilityType].szFacilityShortName );
//wcscpy(sString, gFacilityTypes[ pSoldier->sFacilityTypeOperated ].szFacilityName);
}
// train self / teammate / by other ?
if( ( pSoldier->bAssignment == TRAIN_SELF ) || ( pSoldier->bAssignment == TRAIN_TEAMMATE ) || ( pSoldier->bAssignment == TRAIN_BY_OTHER ) )
else if( ( pSoldier->bAssignment == TRAIN_SELF ) || ( pSoldier->bAssignment == TRAIN_TEAMMATE ) || ( pSoldier->bAssignment == TRAIN_BY_OTHER ) )
{
wcscpy(sString, pAttributeMenuStrings[pSoldier->bTrainStat]);
}
// train town?
else if( pSoldier->bAssignment == TRAIN_TOWN )
// HEADROCK HAM 3.6: Draw for Mobile Trainers as well.
else if( pSoldier->bAssignment == TRAIN_TOWN || pSoldier->bAssignment == TRAIN_MOBILE )
{
wcscpy(sString,pTownNames[GetTownIdForSector( pSoldier->sSectorX, pSoldier->sSectorY ) ] );
}
// repairing?
else if( pSoldier->bAssignment == REPAIR )
{
@@ -3127,6 +3145,136 @@ void DisplayCharacterInfo( void )
// set font buffer
SetFontDestBuffer( guiSAVEBUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE );
// HEADROCK HAM 3.6: "progress" bars showing how near the character is to "leveling up" in any stat. The bar
// is displayed behind the current stat value, as see on the character's info panel.
// This section draws STRATEGIC info pages. Another section is in Interface Panels.cpp and draws TACTICAL info pages.
// The feature is toggled by Options-Menu switch, and its color is determined in the INI files.
if ( gGameSettings.fOptions[TOPTION_STAT_PROGRESS_BARS] )
{
SOLDIERTYPE *pSoldier = MercPtrs[ gCharactersList[bSelectedInfoChar].usSolID ];
UINT8 *pDestBuf;
UINT32 uiDestPitchBYTES = 0;
SGPRect ClipRect;
UINT8 ubBarWidth = 0;
UINT16 usColor = Get16BPPColor( FROMRGB( gGameExternalOptions.ubStatProgressBarsRed, gGameExternalOptions.ubStatProgressBarsGreen, gGameExternalOptions.ubStatProgressBarsBlue ) );
//pDestBuf = LockVideoSurface( FRAME_BUFFER, &uiDestPitchBYTES );
pDestBuf = LockVideoSurface( guiSAVEBUFFER, &uiDestPitchBYTES );
// AGI
if (gMercProfiles[ pSoldier->ubProfile ].sAgilityGain)
{
ubBarWidth = (STAT_WID * (gMercProfiles[ pSoldier->ubProfile ].sAgilityGain+1)) / SubpointsPerPoint(AGILAMT,0);
ClipRect.iTop = (AGL_Y-1);
ClipRect.iBottom = (AGL_Y-1) + STAT_HEI;
ClipRect.iLeft = AGL_X;
ClipRect.iRight = AGL_X + ubBarWidth;
Blt16BPPBufferHatchRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, usColor );
}
// DEX
if (gMercProfiles[ pSoldier->ubProfile ].sDexterityGain)
{
ubBarWidth = (STAT_WID * (gMercProfiles[ pSoldier->ubProfile ].sDexterityGain+1)) / SubpointsPerPoint(DEXTAMT,0);
ClipRect.iTop = (DEX_Y-1);
ClipRect.iBottom = (DEX_Y-1) + STAT_HEI;
ClipRect.iLeft = DEX_X;
ClipRect.iRight = DEX_X + ubBarWidth;
Blt16BPPBufferHatchRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, usColor );
}
// STR
if (gMercProfiles[ pSoldier->ubProfile ].sStrengthGain)
{
ubBarWidth = (STAT_WID * (gMercProfiles[ pSoldier->ubProfile ].sStrengthGain+1)) / SubpointsPerPoint(STRAMT,0);
ClipRect.iTop = (STR_Y-1);
ClipRect.iBottom = (STR_Y-1) + STAT_HEI;
ClipRect.iLeft = STR_X;
ClipRect.iRight = STR_X + ubBarWidth;
Blt16BPPBufferHatchRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, usColor );
}
// WIS
if (gMercProfiles[ pSoldier->ubProfile ].sWisdomGain)
{
ubBarWidth = (STAT_WID * (gMercProfiles[ pSoldier->ubProfile ].sWisdomGain+1)) / SubpointsPerPoint(WISDOMAMT,0);
ClipRect.iTop = (WIS_Y-1);
ClipRect.iBottom = (WIS_Y-1) + STAT_HEI;
ClipRect.iLeft = WIS_X;
ClipRect.iRight = WIS_X + ubBarWidth;
Blt16BPPBufferHatchRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, usColor );
}
// MRK
if (gMercProfiles[ pSoldier->ubProfile ].sMarksmanshipGain)
{
ubBarWidth = (STAT_WID * (gMercProfiles[ pSoldier->ubProfile ].sMarksmanshipGain+1)) / SubpointsPerPoint(MARKAMT,0);
ClipRect.iTop = (MRK_Y-1);
ClipRect.iBottom = (MRK_Y-1) + STAT_HEI;
ClipRect.iLeft = MRK_X;
ClipRect.iRight = MRK_X + ubBarWidth;
Blt16BPPBufferHatchRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, usColor );
}
// LDR
if (gMercProfiles[ pSoldier->ubProfile ].sLeadershipGain)
{
ubBarWidth = (STAT_WID * (gMercProfiles[ pSoldier->ubProfile ].sLeadershipGain+1)) / SubpointsPerPoint(LDRAMT,0);
ClipRect.iTop = (LDR_Y-1);
ClipRect.iBottom = (LDR_Y-1) + STAT_HEI;
ClipRect.iLeft = LDR_X;
ClipRect.iRight = LDR_X + ubBarWidth;
Blt16BPPBufferHatchRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, usColor );
}
// MECH
if (gMercProfiles[ pSoldier->ubProfile ].sMechanicGain)
{
ubBarWidth = (STAT_WID * (gMercProfiles[ pSoldier->ubProfile ].sMechanicGain+1)) / SubpointsPerPoint(MECHANAMT,0);
ClipRect.iTop = (MEC_Y-1);
ClipRect.iBottom = (MEC_Y-1) + STAT_HEI;
ClipRect.iLeft = MEC_X;
ClipRect.iRight = MEC_X + ubBarWidth;
Blt16BPPBufferHatchRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, usColor );
}
// EXPLO
if (gMercProfiles[ pSoldier->ubProfile ].sExplosivesGain)
{
ubBarWidth = (STAT_WID * (gMercProfiles[ pSoldier->ubProfile ].sExplosivesGain+1)) / SubpointsPerPoint(EXPLODEAMT,0);
ClipRect.iTop = (EXP_Y-1);
ClipRect.iBottom = (EXP_Y-1) + STAT_HEI;
ClipRect.iLeft = EXP_X;
ClipRect.iRight = EXP_X + ubBarWidth;
Blt16BPPBufferHatchRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, usColor );
}
// MED
if (gMercProfiles[ pSoldier->ubProfile ].sMedicalGain)
{
ubBarWidth = (STAT_WID * (gMercProfiles[ pSoldier->ubProfile ].sMedicalGain+1)) / SubpointsPerPoint(MEDICALAMT,0);
ClipRect.iTop = (MED_Y-1);
ClipRect.iBottom = (MED_Y-1) + STAT_HEI;
ClipRect.iLeft = MED_X;
ClipRect.iRight = MED_X + ubBarWidth;
Blt16BPPBufferHatchRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, usColor );
}
// EXPLEVEL
if (gMercProfiles[ pSoldier->ubProfile ].sExpLevelGain)
{
ubBarWidth = (STAT_WID * (gMercProfiles[ pSoldier->ubProfile ].sExpLevelGain+1)) / SubpointsPerPoint(EXPERAMT, pSoldier->stats.bExpLevel);
ClipRect.iTop = (LVL_Y-1);
ClipRect.iBottom = (LVL_Y-1) + STAT_HEI;
ClipRect.iLeft = LVL_X;
ClipRect.iRight = LVL_X + ubBarWidth;
Blt16BPPBufferHatchRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, usColor );
}
UnLockVideoSurface( guiSAVEBUFFER );
}
// draw character info and face
DrawCharacterInfo( bSelectedInfoChar );
@@ -4428,12 +4576,16 @@ UINT32 MapScreenHandle(void)
InitPreviousPaths();
// HEADROCK HAM 3.6: Init coordinates for new variable-sized message window
InitMapScreenInterfaceBottomCoords();
// if arrival sector is invalid, reset to A9
if ( ( gsMercArriveSectorX < 1 ) || ( gsMercArriveSectorY < 1 ) ||
( gsMercArriveSectorX > 16 ) || ( gsMercArriveSectorY > 16 ) )
{
gsMercArriveSectorX = 9;
gsMercArriveSectorY = 1;
// HEADROCK HAM 3.5: Externalized coordinates
gsMercArriveSectorX = gGameExternalOptions.ubDefaultArrivalSectorX;
gsMercArriveSectorY = gGameExternalOptions.ubDefaultArrivalSectorY;
}
gfInConfirmMapMoveMode = FALSE;
@@ -4702,7 +4854,8 @@ UINT32 MapScreenHandle(void)
if( AnyMercsHired( ) == FALSE )
{
// select starting sector (A9 - Omerta)
ChangeSelectedMapSector( startingX, startingY, startingZ );
// HEADROCK HAM 3.5: Externalized!
ChangeSelectedMapSector( gGameExternalOptions.ubDefaultArrivalSectorX, gGameExternalOptions.ubDefaultArrivalSectorY, startingZ );
}
else if( ( gWorldSectorX > 0 ) && ( gWorldSectorY > 0 ) && ( gbWorldSectorZ != -1 ) )
{
@@ -4714,7 +4867,8 @@ UINT32 MapScreenHandle(void)
// only select A9 - Omerta IF there is no current selection, otherwise leave it as is
if ( ( sSelMapX == 0 ) || ( sSelMapY == 0 ) || ( iCurrentMapSectorZ == -1 ) )
{
ChangeSelectedMapSector( startingX, startingY, startingZ );
// HEADROCK HAM 3.5: Externalized!
ChangeSelectedMapSector( gGameExternalOptions.ubDefaultArrivalSectorX, gGameExternalOptions.ubDefaultArrivalSectorY, startingZ );
}
}
@@ -5261,7 +5415,8 @@ UINT32 MapScreenHandle(void)
// handle display of inventory pop up
HandleDisplayOfItemPopUpForSector( startingX, startingY, startingZ );
// HEADROCK HAM 3.5: Externalize!
HandleDisplayOfItemPopUpForSector( gGameExternalOptions.ubDefaultArrivalSectorX, gGameExternalOptions.ubDefaultArrivalSectorY, startingZ );
// Display Framerate
DisplayFrameRate( );
@@ -5311,7 +5466,9 @@ UINT32 MapScreenHandle(void)
fCharacterInfoPanelDirty=TRUE;
fMapPanelDirty = TRUE;
fMapScreenBottomDirty = TRUE;
fTeamPanelDirty = TRUE;
fEndShowInventoryFlag = FALSE;
}
@@ -5702,6 +5859,8 @@ void DrawAssignment(INT16 sCharNumber, INT16 sRowIndex, INT32 iFont)
FindFontCenterCoordinates((short)ASSIGN_X + 1, (short)(usVehicleY+(sRowIndex*Y_SIZE)), (short)ASSIGN_WIDTH, (short)Y_SIZE, sString, (long)iFont, &usX, &usY);
}
SOLDIERTYPE *pSoldier = MercPtrs[ gCharactersList[ sCharNumber ].usSolID ];
if( fFlashAssignDone == TRUE )
{
if( Menptr[gCharactersList[sCharNumber].usSolID].flags.fDoneAssignmentAndNothingToDoFlag )
@@ -5710,6 +5869,97 @@ void DrawAssignment(INT16 sCharNumber, INT16 sRowIndex, INT32 iFont)
}
}
if ( gGameSettings.fOptions[TOPTION_STAT_PROGRESS_BARS] &&
(pSoldier->bAssignment >= TRAIN_SELF ||
pSoldier->bAssignment <= TRAIN_BY_OTHER ) &&
pSoldier->bAssignment != TRAIN_TEAMMATE )
{
// HEADROCK HAM 3.6: Draw militia training progress bar
UINT32 uiDestBuffer;
UINT8 *pDestBuf;
UINT32 uiDestPitchBYTES = 0;
SGPRect ClipRect;
UINT8 ubBarWidth;
UINT16 usColor = Get16BPPColor( FROMRGB( gGameExternalOptions.ubStatProgressBarsRed, gGameExternalOptions.ubStatProgressBarsGreen, gGameExternalOptions.ubStatProgressBarsBlue ) );
if( ( fShowAssignmentMenu == TRUE ) && ( fTeamPanelDirty == FALSE ) )
{
uiDestBuffer = FRAME_BUFFER;
}
else
{
uiDestBuffer = guiSAVEBUFFER;
}
pDestBuf = LockVideoSurface( uiDestBuffer, &uiDestPitchBYTES );
UINT8 ubProgress;
UINT16 usMaxProgress;
UINT8 sMapX = (UINT8)pSoldier->sSectorX;
UINT8 sMapY = (UINT8)pSoldier->sSectorY;
if ( pSoldier->bAssignment == TRAIN_TOWN )
{
ubProgress = SectorInfo[SECTOR(sMapX, sMapY)].ubMilitiaTrainingPercentDone;
usMaxProgress = 100;
}
else if ( pSoldier->bAssignment == TRAIN_MOBILE )
{
ubProgress = SectorInfo[SECTOR(sMapX, sMapY)].ubMobileMilitiaTrainingPercentDone;
usMaxProgress = 100;
}
else if ( pSoldier->bAssignment == TRAIN_SELF ||
pSoldier->bAssignment == TRAIN_BY_OTHER )
{
switch (pSoldier->bTrainStat)
{
case STRENGTH:
ubProgress = gMercProfiles[ pSoldier->ubProfile ].sStrengthGain+1;
usMaxProgress = gGameExternalOptions.usStrengthSubpointsToImprove;
break;
case AGILITY:
ubProgress = gMercProfiles[ pSoldier->ubProfile ].sAgilityGain+1;
usMaxProgress = gGameExternalOptions.usAgilitySubpointsToImprove;
break;
case DEXTERITY:
ubProgress = gMercProfiles[ pSoldier->ubProfile ].sDexterityGain+1;
usMaxProgress = gGameExternalOptions.usDexteritySubpointsToImprove;
break;
case HEALTH:
ubProgress = gMercProfiles[ pSoldier->ubProfile ].sLifeGain+1;
usMaxProgress = gGameExternalOptions.usHealthSubpointsToImprove;
break;
case MARKSMANSHIP:
ubProgress = gMercProfiles[ pSoldier->ubProfile ].sMarksmanshipGain+1;
usMaxProgress = gGameExternalOptions.usMarksmanshipSubpointsToImprove;
break;
case LEADERSHIP:
ubProgress = gMercProfiles[ pSoldier->ubProfile ].sLeadershipGain+1;
usMaxProgress = gGameExternalOptions.usLeadershipSubpointsToImprove;
break;
case MECHANICAL:
ubProgress = gMercProfiles[ pSoldier->ubProfile ].sMechanicGain+1;
usMaxProgress = gGameExternalOptions.usMechanicalSubpointsToImprove;
break;
case MEDICAL:
ubProgress = gMercProfiles[ pSoldier->ubProfile ].sMedicalGain+1;
usMaxProgress = gGameExternalOptions.usMedicalSubpointsToImprove;
break;
case EXPLOSIVE_ASSIGN:
ubProgress = gMercProfiles[ pSoldier->ubProfile ].sExplosivesGain+1;
usMaxProgress = gGameExternalOptions.usExplosivesSubpointsToImprove;
break;
}
}
ubBarWidth = (ASSIGN_WIDTH * ubProgress) / usMaxProgress;
ClipRect.iTop = (usY+(Y_OFFSET*sRowIndex+1))-1;
ClipRect.iBottom = ClipRect.iTop + Y_SIZE;
ClipRect.iLeft = ASSIGN_X+2;
ClipRect.iRight = ASSIGN_X + ubBarWidth;
Blt16BPPBufferHatchRectWithColor( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect, usColor );
UnLockVideoSurface( uiDestBuffer );
}
//RestoreExternBackgroundRect(ASSIGN_X-2, ((UINT16)(usY+(Y_OFFSET*sRowIndex+1))), ASSIGN_WIDTH+2, Y_SIZE);
DrawString(sString, (UINT16)usX, ((UINT16)(usY+(Y_OFFSET*sRowIndex+1))), iFont);
}
@@ -6438,6 +6688,12 @@ void GetMapKeyboardInput( UINT32 *puiNewEvent )
fShowAttributeMenu = FALSE;
fMapPanelDirty = TRUE;
}
// stop showing current assignment box
if( fShowFacilityAssignmentMenu == TRUE )
{
fShowFacilityAssignmentMenu = FALSE;
fMapPanelDirty = TRUE;
}
else if( fShowTrainingMenu == TRUE )
{
fShowTrainingMenu = FALSE;
@@ -6450,6 +6706,11 @@ void GetMapKeyboardInput( UINT32 *puiNewEvent )
{
fShowRepairMenu = FALSE;
}
// HEADROCK HAM 3.6: Facility Menu
else if( fShowFacilityMenu == TRUE )
{
fShowFacilityMenu = FALSE;
}
else
{
fShowAssignmentMenu = FALSE;
@@ -10695,6 +10956,12 @@ void RenderMapRegionBackground( void )
ForceUpDateOfBox( ghAttributeBox );
}
// HEADROCK HAM 3.6: Force re-render due to Facility box
if ( ghFacilityAssignmentBox != 1 )
{
ForceUpDateOfBox( ghFacilityAssignmentBox );
}
if ( ghTownMineBox != - 1 )
{
// force update of town mine info boxes
@@ -14970,13 +15237,18 @@ void HandlePostAutoresolveMessages()
void GetMapscreenMercAssignmentString( SOLDIERTYPE *pSoldier, CHAR16 sString[] )
{
if( pSoldier->bAssignment != VEHICLE )
if ( pSoldier->bAssignment == VEHICLE )
{
wcscpy(sString, pAssignmentStrings[ pSoldier->bAssignment ] );
wcscpy( sString, pShortVehicleStrings[ pVehicleList[ pSoldier->iVehicleId ].ubVehicleType ] );
}
else
{
wcscpy( sString, pShortVehicleStrings[ pVehicleList[ pSoldier->iVehicleId ].ubVehicleType ] );
wcscpy(sString, pAssignmentStrings[ pSoldier->bAssignment ] );
}
// If soldier is working at a facility, add an asterisk.
if (pSoldier->sFacilityTypeOperated != -1)
{
wcscat(sString, L"*");
}
}
@@ -15433,6 +15705,7 @@ void RequestToggleMercInventoryPanel( void )
else
{
// Headrock. New line forces InvBottom rerender when the inventory is opened and closed.
fEndShowInventoryFlag = TRUE;
RenderMapScreenInterfaceBottom ( TRUE );
SetRegionFastHelpText( &gCharInfoHandRegion, pMiscMapScreenMouseRegionHelpText[ 0 ] );
}
@@ -15549,3 +15822,48 @@ void MapscreenMarkButtonsDirty()
}
}
}
// HEADROCK HAM 3.6: Get a total of all merc salaries. Used for the new Daily Expenses display.
INT32 GetTotalContractExpenses ( void )
{
if (gGameExternalOptions.ubIncludeContractsInExpenses == 0)
{
// Contract costs are excluded.
return (0);
}
UINT8 ubCounter = 0;
SOLDIERTYPE *pSoldier;
INT32 iTotalCost = 0;
while(gCharactersList[ubCounter].fValid)
{
pSoldier = MercPtrs[ gCharactersList[ ubCounter ].usSolID ];
// salary
if( pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__AIM_MERC )
{
if (gGameExternalOptions.ubIncludeContractsInExpenses == 2)
{
// daily rate
if( pSoldier->bTypeOfLastContract == CONTRACT_EXTEND_2_WEEK )
{
iTotalCost += ( gMercProfiles[ pSoldier->ubProfile ].uiBiWeeklySalary / 14 );
}
if( pSoldier->bTypeOfLastContract == CONTRACT_EXTEND_1_WEEK )
{
iTotalCost += ( gMercProfiles[ pSoldier->ubProfile ].uiWeeklySalary / 7 );
}
else
{
iTotalCost += gMercProfiles[ pSoldier->ubProfile ].sSalary;
}
}
}
else
{
iTotalCost += gMercProfiles[ pSoldier->ubProfile ].sSalary;
}
ubCounter++;
}
return (iTotalCost);
}
+4
View File
@@ -9,6 +9,7 @@
#define MAP_WORLD_Y 18
#define MAX_TOWN_NAME_LENGHT 32
#define MAX_SECTOR_NAME_LENGTH 128
#define MAX_TOWNS 50 //13 //50
#define MAX_TOWN_SECTORS 260 //40 //260
@@ -93,4 +94,7 @@ BOOLEAN InitializeInvPanelCoordsOld( );
BOOLEAN InitializeInvPanelCoordsNew( );
BOOLEAN InitializeInvPanelCoordsVehicle( );
// HEADROCK HAM 3.6: Calculate daily cost for all mercs who have one.
INT32 GetTotalContractExpenses ( void );
#endif
+194 -91
View File
@@ -296,6 +296,9 @@ STR8 pHortStrings[]={
"17",
};
// HEADROCK HAM 3.6: Array to hold user-defined sector names
CHAR16 gzSectorNames[256][4][MAX_SECTOR_NAME_LENGTH];
BOOLEAN ReadInStrategicMapSectorTownNames(STR fileName, BOOLEAN localizedVersion);
void DoneFadeOutAdjacentSector( void );
@@ -1616,8 +1619,9 @@ void InitializeSAMSites( void )
{
UINT32 cnt;
// move the landing zone over to Omerta
gsMercArriveSectorX = 9;
gsMercArriveSectorY = 1;
// HEADROCK HAM 3.5: Externalized coordinates
gsMercArriveSectorX = gGameExternalOptions.ubDefaultArrivalSectorX;
gsMercArriveSectorY = gGameExternalOptions.ubDefaultArrivalSectorY;
// all SAM sites start game in perfect working condition
for ( cnt = 0; cnt < NUMBER_OF_SAMS; cnt++ )
@@ -3009,109 +3013,179 @@ void GetSectorIDString( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ , STR16 zS
}
else
{
bTownNameID = StrategicMap[ CALCULATE_STRATEGIC_INDEX( sSectorX, sSectorY ) ].bNameId;
ubSectorID = (UINT8)SECTOR( sSectorX, sSectorY );
AssertGE(ubSectorID, 0);
AssertLT(ubSectorID,256);
pSector = &SectorInfo[ ubSectorID ];
ubLandType = pSector->ubTraversability[ 4 ];
swprintf( zString, L"%c%d: ", 'A' + sSectorY - 1, sSectorX );
if ( bTownNameID == BLANK_SECTOR )
////////////////////////////////////
// Read and verify XML sector names
BOOLEAN fSectorHasXMLNames = TRUE;
CHAR16 zUnexplored[MAX_SECTOR_NAME_LENGTH];
CHAR16 zDetailedUnexplored[MAX_SECTOR_NAME_LENGTH];
CHAR16 zExplored[MAX_SECTOR_NAME_LENGTH];
CHAR16 zDetailedExplored[MAX_SECTOR_NAME_LENGTH];
wcscpy( zUnexplored, gzSectorNames[ ubSectorID ][0] );
wcscpy( zDetailedUnexplored, gzSectorNames[ ubSectorID ][1] );
wcscpy( zExplored, gzSectorNames[ ubSectorID ][2] );
wcscpy( zDetailedExplored, gzSectorNames[ ubSectorID ][3] );
if (zUnexplored[0] == 0 || zDetailedUnexplored[0] == 0 || zExplored[0] == 0 || zDetailedExplored[0] == 0)
{
// OK, build string id like J11
// are we dealing with the unfound towns?
switch( ubSectorID )
fSectorHasXMLNames = FALSE;
}
if (fSectorHasXMLNames)
{
// HEADROCK HAM 3.6: The program can now read custom names from XML for all above-ground sectors.
// In the event that a specific name or set of names is missing, the program generates a default
// name as it always has.
// I've also updated the SAM Site sectors to rely on SamSite.XML data.
BOOLEAN fVisited = (SectorInfo[ ubSectorID ].uiFlags & SF_ALREADY_VISITED);
BOOLEAN fSAMSiteKnown = FALSE;
// Test for known SAM Site at this location
for (UINT16 x=0; x < MAX_NUMBER_OF_SAMS; x++)
{
case SEC_D2: //Chitzena SAM
if( !fSamSiteFound[ SAM_SITE_ONE ] )
wcscat( zString, pLandTypeStrings[ TROPICS ] );
else if( fDetailed )
wcscat( zString, pLandTypeStrings[ TROPICS_SAM_SITE ] );
else
wcscat( zString, pLandTypeStrings[ SAM_SITE ] );
break;
case SEC_D15: //Drassen SAM
if( !fSamSiteFound[ SAM_SITE_TWO ] )
wcscat( zString, pLandTypeStrings[ SPARSE ] );
else if( fDetailed )
wcscat( zString, pLandTypeStrings[ SPARSE_SAM_SITE ] );
else
wcscat( zString, pLandTypeStrings[ SAM_SITE ] );
break;
case SEC_I8: //Cambria SAM
if( !fSamSiteFound[ SAM_SITE_THREE ] )
wcscat( zString, pLandTypeStrings[ SAND ] );
else if( fDetailed )
wcscat( zString, pLandTypeStrings[ SAND_SAM_SITE ] );
else
wcscat( zString, pLandTypeStrings[ SAM_SITE ] );
break;
default:
wcscat( zString, pLandTypeStrings[ ubLandType ] );
break;
if ( pSamList[x] == ubSectorID )
{
if ( fSamSiteFound[ x ] )
{
fSAMSiteKnown = TRUE;
}
}
}
if (fVisited || fSAMSiteKnown)
{
if (fDetailed)
{
wcscat( zString, zDetailedExplored );
}
else
{
wcscat( zString, zExplored);
}
}
else
{
if (fDetailed)
{
wcscat( zString, zDetailedUnexplored);
}
else
{
wcscat( zString, zUnexplored );
}
}
}
else
{
switch( ubSectorID )
// Default JA2 Name selection
if ( bTownNameID == BLANK_SECTOR )
{
case SEC_B13:
if( fDetailed )
wcscat( zString, pLandTypeStrings[ DRASSEN_AIRPORT_SITE ] );
else
wcscat( zString, pTownNames[ DRASSEN ] );
break;
case SEC_F8:
if( fDetailed )
wcscat( zString, pLandTypeStrings[ CAMBRIA_HOSPITAL_SITE ] );
else
wcscat( zString, pTownNames[ CAMBRIA ] );
break;
case SEC_J9: //Tixa
if( !fFoundTixa )
wcscat( zString, pLandTypeStrings[ SAND ] );
else
wcscat( zString, pTownNames[ TIXA ] );
break;
case SEC_K4: //Orta
if( !fFoundOrta )
wcscat( zString, pLandTypeStrings[ SWAMP ] );
else
wcscat( zString, pTownNames[ ORTA ] );
break;
case SEC_N3:
if( fDetailed )
wcscat( zString, pLandTypeStrings[ MEDUNA_AIRPORT_SITE ] );
else
wcscat( zString, pTownNames[ MEDUNA ] );
break;
default:
if( ubSectorID == SEC_N4 && fSamSiteFound[ SAM_SITE_FOUR ] )
{ //Meduna's SAM site
if( fDetailed )
wcscat( zString, pLandTypeStrings[ MEDUNA_SAM_SITE ] );
// OK, build string id like J11
// are we dealing with the unfound towns?
switch( ubSectorID )
{
case SEC_D2: //Chitzena SAM
if( !fSamSiteFound[ SAM_SITE_ONE ] )
wcscat( zString, pLandTypeStrings[ TROPICS ] );
else if( fDetailed )
wcscat( zString, pLandTypeStrings[ TROPICS_SAM_SITE ] );
else
wcscat( zString, pLandTypeStrings[ SAM_SITE ] );
}
else
{ //All other towns that are known since beginning of the game.
wcscat( zString, pTownNames[ bTownNameID ] );
break;
case SEC_D15: //Drassen SAM
if( !fSamSiteFound[ SAM_SITE_TWO ] )
wcscat( zString, pLandTypeStrings[ SPARSE ] );
else if( fDetailed )
wcscat( zString, pLandTypeStrings[ SPARSE_SAM_SITE ] );
else
wcscat( zString, pLandTypeStrings[ SAM_SITE ] );
break;
case SEC_I8: //Cambria SAM
if( !fSamSiteFound[ SAM_SITE_THREE ] )
wcscat( zString, pLandTypeStrings[ SAND ] );
else if( fDetailed )
wcscat( zString, pLandTypeStrings[ SAND_SAM_SITE ] );
else
wcscat( zString, pLandTypeStrings[ SAM_SITE ] );
break;
default:
wcscat( zString, pLandTypeStrings[ ubLandType ] );
break;
}
}
else
{
switch( ubSectorID )
{
case SEC_B13:
if( fDetailed )
{
switch( ubSectorID )
{ //Append the word, "mine" for town sectors containing a mine.
case SEC_B2:
case SEC_D4:
case SEC_D13:
case SEC_H3:
case SEC_H8:
case SEC_I14:
wcscat( zString, L" " ); //space
wcscat( zString, pwMineStrings[ 0 ] ); //then "Mine"
break;
wcscat( zString, pLandTypeStrings[ DRASSEN_AIRPORT_SITE ] );
else
wcscat( zString, pTownNames[ DRASSEN ] );
break;
case SEC_F8:
if( fDetailed )
wcscat( zString, pLandTypeStrings[ CAMBRIA_HOSPITAL_SITE ] );
else
wcscat( zString, pTownNames[ CAMBRIA ] );
break;
case SEC_J9: //Tixa
if( !fFoundTixa )
wcscat( zString, pLandTypeStrings[ SAND ] );
else
wcscat( zString, pTownNames[ TIXA ] );
break;
case SEC_K4: //Orta
if( !fFoundOrta )
wcscat( zString, pLandTypeStrings[ SWAMP ] );
else
wcscat( zString, pTownNames[ ORTA ] );
break;
case SEC_N3:
if( fDetailed )
wcscat( zString, pLandTypeStrings[ MEDUNA_AIRPORT_SITE ] );
else
wcscat( zString, pTownNames[ MEDUNA ] );
break;
default:
if( ubSectorID == SEC_N4 && fSamSiteFound[ SAM_SITE_FOUR ] )
{ //Meduna's SAM site
if( fDetailed )
wcscat( zString, pLandTypeStrings[ MEDUNA_SAM_SITE ] );
else
wcscat( zString, pLandTypeStrings[ SAM_SITE ] );
}
else
{ //All other towns that are known since beginning of the game.
wcscat( zString, pTownNames[ bTownNameID ] );
if( fDetailed )
{
switch( ubSectorID )
{ //Append the word, "mine" for town sectors containing a mine.
case SEC_B2:
case SEC_D4:
case SEC_D13:
case SEC_H3:
case SEC_H8:
case SEC_I14:
wcscat( zString, L" " ); //space
wcscat( zString, pwMineStrings[ 0 ] ); //then "Mine"
break;
}
}
}
}
break;
break;
}
}
}
}
@@ -4605,8 +4679,26 @@ void UpdateAirspaceControl( void )
GetSectorIDString( gsMercArriveSectorX, gsMercArriveSectorY, 0, sMsgSubString1, FALSE );
// move the landing zone over to Omerta
gsMercArriveSectorX = 9;
gsMercArriveSectorY = 1;
// HEADROCK HAM 3.5: Externalized coordinates
if ( StrategicMap[ CALCULATE_STRATEGIC_INDEX( gGameExternalOptions.ubDefaultArrivalSectorX, gGameExternalOptions.ubDefaultArrivalSectorY ) ].fEnemyAirControlled == FALSE )
{
gsMercArriveSectorX = gGameExternalOptions.ubDefaultArrivalSectorX;
gsMercArriveSectorY = gGameExternalOptions.ubDefaultArrivalSectorY;
}
else
{
for (UINT8 ubSectorX = 1; ubSectorX <= 16; ubSectorX++)
{
for (UINT8 ubSectorY = 1; ubSectorY <=16; ubSectorY++)
{
if ( StrategicMap[ CALCULATE_STRATEGIC_INDEX( ubSectorX, ubSectorY ) ].fEnemyAirControlled == FALSE )
{
gsMercArriveSectorX = ubSectorX;
gsMercArriveSectorY = ubSectorY;
}
}
}
}
// get the name of the new sector
GetSectorIDString( gsMercArriveSectorX, gsMercArriveSectorY, 0, sMsgSubString2, FALSE );
@@ -4615,7 +4707,11 @@ void UpdateAirspaceControl( void )
swprintf( sMsgString, pBullseyeStrings[ 4 ], sMsgSubString1, sMsgSubString2 );
// confirm the change with overlay message
DoScreenIndependantMessageBox( sMsgString, MSG_BOX_FLAG_OK, NULL );
// HEADROCK HAM 3.5: If we do this during SaveLoad, the message box prevents loading the game at all!
if (guiCurrentScreen != SAVE_LOAD_SCREEN)
{
DoScreenIndependantMessageBox( sMsgString, MSG_BOX_FLAG_OK, NULL );
}
// update position of bullseye
fMapPanelDirty = TRUE;
@@ -4627,6 +4723,7 @@ void UpdateAirspaceControl( void )
// ARM: airspace control now affects refueling site availability, so update that too with every change!
UpdateRefuelSiteAvailability( );
}
@@ -5524,6 +5621,12 @@ void HandleSlayDailyEvent( void )
BOOLEAN IsSectorDesert( INT16 sSectorX, INT16 sSectorY )
{
// HEADROCK HAM 3.5: Fix for assertion errors associated with rain checks.
if (sSectorX <= 0 || sSectorY <=0 || sSectorX > 16 || sSectorY > 16)
{
return( FALSE );
}
if ( SectorInfo[ SECTOR(sSectorX, sSectorY) ].ubTraversability[ THROUGH_STRATEGIC_MOVE ] == SAND )
{
// desert
@@ -5669,7 +5772,7 @@ BOOLEAN CheckAndHandleUnloadingOfCurrentWorld()
return FALSE;
}
if( gTacticalStatus.fDidGameJustStart && gWorldSectorX == 9 && gWorldSectorY == 1 && !gbWorldSectorZ )
if( gTacticalStatus.fDidGameJustStart && gWorldSectorX == gGameExternalOptions.ubDefaultArrivalSectorX && gWorldSectorY == gGameExternalOptions.ubDefaultArrivalSectorY && !gbWorldSectorZ )
{
return FALSE;
}