mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
Added missing #includes Added LUA scripting and console Changed the way tracers are visualized, so they work more like real tracers instead of a light fountain Fixed signedness of many grid variables used in GetMouseMapPos calls Fixed enemy weapon choosing: Sometimes a mortar is chosen but later rejected, but the grenade class was not reset. Caused assertion failure Added checks so enemies don't try to chuck RPG grenades with their hands Now possible to shoot a someone in the head if he's in water Fixed InitSightArrays to also clear soldier interrupt duel points. This was causing an assertion failure elsewhere in the code because the interrupt list still had soldiers on it sometimes when this function was called. Soldiers are much less willing to forfeit their turn over an attempt to use more APs than they have Removed early setting of muzzle flash. This would allow enemies to get an interrupt before you even fired. Fixed item dropping by AI. If AI tried to drop something while standing it would cause deadlock Change to greatly speed up closing the sector inventory window in an unloaded sector Added conditional compile flag to always give robot weapon ready advantage, even for 360 degree sighting Check builddefines.h for the conditional flags. Of greatest interest might be LUA_CONSOLE. This will cause the game to bring up a command console when run. However this console is severely lacking in many areas. If anybody knows of an open-source terminal/console that could be used instead, it would be appreciated. The existing console does bad things when you try to close it, and since it counts as a separate app, it pauses the game while it has focus. LUA scripting is very limited, basically just proof of concept. There is one global variable, the Soldiers array. An array index gives you the soldier in that slot in the currently loaded sector. The soldier has a few things that can be accessed: name (short name); fullname (long name); grid (current grid #, can be changed); walkto(grid) (function to walk to another grid); runto(grid) (function to run to another grid) git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@924 3b4a5df2-a311-0410-b5c6-a8a6f20db521
11604 lines
308 KiB
C++
11604 lines
308 KiB
C++
// WANNE 2 <changed some lines>
|
|
#ifdef PRECOMPILEDHEADERS
|
|
#include "Strategic All.h"
|
|
#include "GameSettings.h"
|
|
#else
|
|
#include "Assignments.h"
|
|
#include "Soldier Control.h"
|
|
#include "Item Types.h"
|
|
#include "Strategic.h"
|
|
#include "Items.h"
|
|
#include "Overhead.h"
|
|
#include "Game Clock.h"
|
|
#include "stdlib.h"
|
|
#include "Message.h"
|
|
#include "Font Control.h"
|
|
#include "Map Screen Interface.h"
|
|
#include "Soldier Profile Type.h"
|
|
#include "Soldier Profile.h"
|
|
#include "Campaign.h"
|
|
#include "Queen Command.h"
|
|
#include "strategicmap.h"
|
|
#include "Text.h"
|
|
#include "dialogue control.h"
|
|
#include "NPC.h"
|
|
#include "Strategic Town Loyalty.h"
|
|
#include "animation control.h"
|
|
#include "mapscreen.h"
|
|
#include "Squads.h"
|
|
#include "Map Screen Helicopter.h"
|
|
#include "PopUpBox.h"
|
|
#include "Vehicles.h"
|
|
#include "Strategic Merc Handler.h"
|
|
#include "Merc Contract.h"
|
|
#include "Map Screen Interface Map.h"
|
|
#include "Strategic Movement.h"
|
|
#include "laptop.h"
|
|
#include "Finances.h"
|
|
#include "LaptopSave.h"
|
|
#include "renderworld.h"
|
|
#include "Interface Control.h"
|
|
#include "Interface.h"
|
|
#include "Soldier Find.h"
|
|
#include "ai.h"
|
|
#include "utilities.h"
|
|
#include "random.h"
|
|
#include "line.h"
|
|
#include "Soldier Add.h"
|
|
#include "GameSettings.h"
|
|
#include "Isometric Utils.h"
|
|
#include "Soldier Macros.h"
|
|
#include "Explosion Control.h"
|
|
#include "SkillCheck.h"
|
|
#include "Quests.h"
|
|
#include "Town Militia.h"
|
|
#include "Map Screen Interface Border.h"
|
|
#include "math.h"
|
|
#include "SkillCheck.h"
|
|
#include "Strategic Pathing.h"
|
|
#include "Game Event Hook.h"
|
|
#include "Strategic Event Handler.h"
|
|
#include "Map Information.h"
|
|
#include "Strategic Status.h"
|
|
#include "history.h"
|
|
#include "Map Screen Interface Map Inventory.h"
|
|
#include "interface dialogue.h"
|
|
#endif
|
|
|
|
#include "MilitiaSquads.h"
|
|
|
|
// various reason an assignment can be aborted before completion
|
|
enum{
|
|
NO_MORE_MED_KITS = 40,
|
|
INSUF_DOCTOR_SKILL,
|
|
NO_MORE_TOOL_KITS,
|
|
INSUF_REPAIR_SKILL,
|
|
|
|
NUM_ASSIGN_ABORT_REASONS
|
|
};
|
|
|
|
enum{
|
|
REPAIR_MENU_VEHICLE1 = 0,
|
|
REPAIR_MENU_VEHICLE2,
|
|
REPAIR_MENU_VEHICLE3,
|
|
// REPAIR_MENU_SAM_SITE,
|
|
REPAIR_MENU_ROBOT,
|
|
REPAIR_MENU_ITEMS,
|
|
REPAIR_MENU_CANCEL,
|
|
};
|
|
|
|
enum{
|
|
VEHICLE_MENU_VEHICLE1 = 0,
|
|
VEHICLE_MENU_VEHICLE2,
|
|
VEHICLE_MENU_VEHICLE3,
|
|
VEHICLE_MENU_CANCEL,
|
|
};
|
|
|
|
|
|
enum {
|
|
REPAIR_HANDS_AND_ARMOR = 0,
|
|
REPAIR_HEADGEAR,
|
|
REPAIR_POCKETS,
|
|
NUM_REPAIR_PASS_TYPES,
|
|
};
|
|
|
|
#define FINAL_REPAIR_PASS REPAIR_POCKETS
|
|
|
|
|
|
typedef struct REPAIR_PASS_SLOTS_TYPE
|
|
{
|
|
UINT8 ubChoices; // how many valid choices there are in this pass
|
|
INT8 bSlot[ 12 ]; // list of slots to be repaired in this pass
|
|
} REPAIR_PASS_SLOTS_TYPE;
|
|
|
|
|
|
REPAIR_PASS_SLOTS_TYPE gRepairPassSlotList[ NUM_REPAIR_PASS_TYPES ] =
|
|
{ // pass # choices slots repaired in this pass
|
|
{ /* hands and armor */ 5, HANDPOS, SECONDHANDPOS, VESTPOS, HELMETPOS, LEGPOS, -1, -1, -1, -1, -1, -1, -1 },
|
|
{ /* headgear */ 2, HEAD1POS, HEAD2POS, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
|
|
{ /* pockets */ 12, BIGPOCK1POS, BIGPOCK2POS, BIGPOCK3POS, BIGPOCK4POS, SMALLPOCK1POS, SMALLPOCK2POS, SMALLPOCK3POS, SMALLPOCK4POS, SMALLPOCK5POS, SMALLPOCK6POS, SMALLPOCK7POS, SMALLPOCK8POS },
|
|
};
|
|
|
|
extern STR16 sRepairsDoneString[];
|
|
|
|
// PopUp Box Handles
|
|
INT32 ghAssignmentBox = -1;
|
|
INT32 ghEpcBox = -1;
|
|
INT32 ghSquadBox = -1;
|
|
INT32 ghVehicleBox = -1;
|
|
INT32 ghRepairBox = -1;
|
|
INT32 ghTrainingBox = -1;
|
|
INT32 ghAttributeBox = -1;
|
|
INT32 ghRemoveMercAssignBox = -1;
|
|
INT32 ghContractBox = -1;
|
|
INT32 ghMoveBox = -1;
|
|
//INT32 ghUpdateBox = -1;
|
|
|
|
// the x,y position of assignment pop up in tactical
|
|
INT16 gsAssignmentBoxesX, gsAssignmentBoxesY;
|
|
|
|
|
|
// assignment menu mouse regions
|
|
MOUSE_REGION gAssignmentMenuRegion[ MAX_ASSIGN_STRING_COUNT ];
|
|
MOUSE_REGION gTrainingMenuRegion[ MAX_TRAIN_STRING_COUNT ];
|
|
MOUSE_REGION gAttributeMenuRegion[ MAX_ATTRIBUTE_STRING_COUNT ];
|
|
MOUSE_REGION gSquadMenuRegion[ MAX_SQUAD_MENU_STRING_COUNT ];
|
|
MOUSE_REGION gContractMenuRegion[ MAX_CONTRACT_MENU_STRING_COUNT ];
|
|
MOUSE_REGION gRemoveMercAssignRegion[ MAX_REMOVE_MERC_COUNT ];
|
|
MOUSE_REGION gEpcMenuRegion[ MAX_EPC_MENU_STRING_COUNT ];
|
|
MOUSE_REGION gRepairMenuRegion[ 20 ];
|
|
|
|
// mouse region for vehicle menu
|
|
MOUSE_REGION gVehicleMenuRegion[ 20 ];
|
|
|
|
MOUSE_REGION gAssignmentScreenMaskRegion;
|
|
|
|
BOOLEAN fShownAssignmentMenu = FALSE;
|
|
BOOLEAN fShowVehicleMenu = FALSE;
|
|
BOOLEAN fShowRepairMenu = FALSE;
|
|
BOOLEAN fShownContractMenu = FALSE;
|
|
|
|
BOOLEAN fFirstClickInAssignmentScreenMask = FALSE;
|
|
|
|
// render pre battle interface?
|
|
extern BOOLEAN gfRenderPBInterface;
|
|
extern BOOLEAN fMapScreenBottomDirty;
|
|
extern SOLDIERTYPE *pMilitiaTrainerSoldier;
|
|
|
|
// in the mapscreen?
|
|
extern BOOLEAN fInMapMode;
|
|
|
|
// we are in fact training?..then who temmates, or self?
|
|
INT8 gbTrainingMode = -1;
|
|
|
|
// who is the highlighted guy
|
|
extern UINT16 gusUIFullTargetID;
|
|
|
|
// showing town info?
|
|
extern BOOLEAN fShowTownInfo;
|
|
|
|
extern INT32 giMapBorderButtons[];
|
|
|
|
extern BOOLEAN fProcessingAMerc;
|
|
extern SOLDIERTYPE *pProcessingSoldier ;
|
|
|
|
BOOLEAN gfAddDisplayBoxToWaitingQueue = FALSE;
|
|
|
|
// redraw character list
|
|
extern BOOLEAN fDrawCharacterList;
|
|
|
|
extern BOOLEAN fSelectedListOfMercsForMapScreen[ MAX_CHARACTER_COUNT ];
|
|
|
|
SOLDIERTYPE *gpDismissSoldier = NULL;
|
|
|
|
BOOLEAN gfReEvaluateEveryonesNothingToDo = FALSE;
|
|
|
|
/*
|
|
// the amount time must be on assignment before it can have any effect
|
|
#define MINUTES_FOR_ASSIGNMENT_TO_COUNT 45
|
|
|
|
// number we divide the total pts accumlated per day by for each assignment period
|
|
#define ASSIGNMENT_UNITS_PER_DAY 24
|
|
|
|
// base skill to deal with an emergency
|
|
#define BASE_MEDICAL_SKILL_TO_DEAL_WITH_EMERGENCY 20
|
|
|
|
// multiplier for skill needed for each point below OKLIFE
|
|
#define MULTIPLIER_FOR_DIFFERENCE_IN_LIFE_VALUE_FOR_EMERGENCY 4
|
|
|
|
// number of pts needed for each point below OKLIFE
|
|
#define POINT_COST_PER_HEALTH_BELOW_OKLIFE 2
|
|
|
|
// how many points of healing each hospital patients gains per hour in the hospital
|
|
#define HOSPITAL_HEALING_RATE 5 // a top merc doctor can heal about 4 pts/hour maximum, but that's spread among patients!
|
|
|
|
// increase to reduce repair pts, or vice versa
|
|
#define REPAIR_RATE_DIVISOR 2500
|
|
// increase to reduce doctoring pts, or vice versa
|
|
#define DOCTORING_RATE_DIVISOR 2400 // at 2400, the theoretical maximum is 150 full healing pts/day
|
|
|
|
// cost to unjam a weapon in repair pts
|
|
#define REPAIR_COST_PER_JAM 2
|
|
|
|
// divisor for rate of self-training
|
|
#define SELF_TRAINING_DIVISOR 1000
|
|
// the divisor for rate of training bonus due to instructors influence
|
|
#define INSTRUCTED_TRAINING_DIVISOR 3000
|
|
|
|
// this controls how fast town militia gets trained
|
|
#define TOWN_TRAINING_RATE 4
|
|
|
|
#define MAX_MILITIA_TRAINERS_PER_SECTOR 2
|
|
|
|
// militia training bonus for EACH level of teaching skill (percentage points)
|
|
#define TEACH_BONUS_TO_TRAIN 30
|
|
// militia training bonus for RPC (percentage points)
|
|
#define RPC_BONUS_TO_TRAIN 10
|
|
|
|
// the bonus to training in marksmanship in the Alma gun range sector
|
|
#define GUN_RANGE_TRAINING_BONUS 25
|
|
|
|
// breath bonus divider
|
|
#define BREATH_BONUS_DIVIDER 10
|
|
|
|
// the min rating that is need to teach a fellow teammate
|
|
#define MIN_RATING_TO_TEACH 25
|
|
|
|
// activity levels for natural healing ( the higher the number, the slower the natural recover rate
|
|
#define LOW_ACTIVITY_LEVEL 1
|
|
#define MEDIUM_ACTIVITY_LEVEL 4
|
|
#define HIGH_ACTIVITY_LEVEL 12
|
|
*/
|
|
/*
|
|
// the min breath to stay awake
|
|
#define MIN_BREATH_TO_STAY_AWAKE 15
|
|
|
|
// average number of hours a merc needs to sleep per day
|
|
#define AVG_NUMBER_OF_HOURS_OF_SLEEP_NEEDED 7
|
|
*/
|
|
|
|
/* Assignment distance limits removed. Sep/11/98. ARM
|
|
#define MAX_DISTANCE_FOR_DOCTORING 5
|
|
#define MAX_DISTANCE_FOR_REPAIR 5
|
|
#define MAX_DISTANCE_FOR_TRAINING 5
|
|
*/
|
|
|
|
/*
|
|
// controls how easily SAM sites are repaired
|
|
// NOTE: A repairman must generate a least this many points / hour to be ABLE to repair a SAM site at all!
|
|
#define SAM_SITE_REPAIR_DIVISOR 10
|
|
|
|
// minimum condition a SAM site must be in to be fixable
|
|
#define MIN_CONDITION_TO_FIX_SAM 20
|
|
*/
|
|
|
|
|
|
// how many points worth of tool kits does the character have?
|
|
UINT16 ToolKitPoints(SOLDIERTYPE *pSoldier);
|
|
|
|
// how many points worth of doctoring does the character have in his medical kits ?
|
|
UINT16 TotalMedicalKitPoints(SOLDIERTYPE *pSoldier);
|
|
|
|
// handle doctor in this sector
|
|
void HandleDoctorsInSector( INT16 sX, INT16 sY, INT8 bZ );
|
|
|
|
// handle any repair man in sector
|
|
void HandleRepairmenInSector( INT16 sX, INT16 sY, INT8 bZ );
|
|
|
|
// heal characters in this sector with this doctor
|
|
void HealCharacters( SOLDIERTYPE *pDoctor, INT16 sX, INT16 sY, INT8 bZ );
|
|
|
|
// update characters who might done healing but are still patients
|
|
void UpdatePatientsWhoAreDoneHealing( void );
|
|
|
|
// returns minimum medical skill necessary to treat this patient
|
|
UINT8 GetMinHealingSkillNeeded( SOLDIERTYPE *pPatient );
|
|
|
|
// heal patient, given doctor and total healing pts available to doctor at this time
|
|
UINT16 HealPatient( SOLDIERTYPE *pPatient, SOLDIERTYPE * pDoctor, UINT16 usHundredthsHealed );
|
|
|
|
// can item be repaired?
|
|
BOOLEAN IsItemRepairable( UINT16 usItem, INT8 bStatus );
|
|
|
|
// does another merc have a repairable item on them?
|
|
INT8 FindRepairableItemOnOtherSoldier( SOLDIERTYPE * pSoldier, UINT8 ubPassType );
|
|
|
|
// repair stuff
|
|
void HandleRepairBySoldier( SOLDIERTYPE *pSoldier );
|
|
|
|
// rest the character
|
|
void RestCharacter( SOLDIERTYPE *pSoldier );
|
|
// fatigue the character
|
|
void FatigueCharacter( SOLDIERTYPE *pSoldier );
|
|
|
|
// a list of which sectors have characters
|
|
BOOLEAN fSectorsWithSoldiers[ MAP_WORLD_X * MAP_WORLD_Y ][ 4 ];
|
|
|
|
// can soldier repair robot
|
|
BOOLEAN CanCharacterRepairRobot( SOLDIERTYPE *pSoldier );
|
|
|
|
// can the character repair this vehicle?
|
|
BOOLEAN CanCharacterRepairVehicle( SOLDIERTYPE *pSoldier, INT32 iVehicleId );
|
|
|
|
// handle training of character in sector
|
|
void HandleTrainingInSector( INT16 sMapX, INT16 sMapY, INT8 bZ );
|
|
|
|
// QSort compare function for town training
|
|
int TownTrainerQsortCompare(const void *pArg1, const void *pArg2);
|
|
|
|
// this function will actually pass on the pts to the mercs stat
|
|
void TrainSoldierWithPts( SOLDIERTYPE *pSoldier, INT16 sTrainPts );
|
|
|
|
// train militia in this sector with this soldier
|
|
BOOLEAN TrainTownInSector( SOLDIERTYPE *pTrainer, INT16 sMapX, INT16 sMapY, INT16 sTrainingPts );
|
|
|
|
// is the character between secotrs in mvt
|
|
BOOLEAN CharacterIsBetweenSectors( SOLDIERTYPE *pSoldier );
|
|
|
|
// update soldier life
|
|
void UpDateSoldierLife( SOLDIERTYPE *pSoldier );
|
|
|
|
// handle natural healing for all mercs on players team
|
|
void HandleNaturalHealing( void );
|
|
|
|
// handle natural healing for any individual grunt
|
|
void HandleHealingByNaturalCauses( SOLDIERTYPE *pSoldier );
|
|
|
|
/*
|
|
// auto sleep mercs
|
|
BOOLEAN AutoSleepMerc( SOLDIERTYPE *pSoldier );
|
|
*/
|
|
|
|
// assignment screen mask
|
|
void AssignmentScreenMaskBtnCallback(MOUSE_REGION * pRegion, INT32 iReason );
|
|
|
|
// glow area for contract region?
|
|
BOOLEAN fGlowContractRegion = FALSE;
|
|
|
|
|
|
void HandleShadingOfLinesForSquadMenu( void );
|
|
void HandleShadingOfLinesForVehicleMenu( void );
|
|
void HandleShadingOfLinesForRepairMenu( void );
|
|
void HandleShadingOfLinesForTrainingMenu( void );
|
|
void HandleShadingOfLinesForAttributeMenus( void );
|
|
|
|
// post message about contract
|
|
void PostContractMessage( SOLDIERTYPE *pCharacter, INT32 iContract );
|
|
|
|
// post a terminate message
|
|
void PostTerminateMessage( SOLDIERTYPE *pCharacter );
|
|
|
|
BOOLEAN DisplayVehicleMenu( SOLDIERTYPE *pSoldier );
|
|
BOOLEAN DisplayRepairMenu( SOLDIERTYPE *pSoldier );
|
|
|
|
// create menus
|
|
void CreateEPCBox( void );
|
|
void CreateSquadBox( void );
|
|
void CreateVehicleBox();
|
|
void CreateRepairBox( void );
|
|
|
|
/*
|
|
// get how fast the person regains sleep
|
|
INT8 GetRegainDueToSleepNeeded( SOLDIERTYPE *pSoldier, INT32 iRateOfReGain );
|
|
*/
|
|
|
|
void PositionCursorForTacticalAssignmentBox( void );
|
|
|
|
// can this soldier be healed by this doctor?
|
|
BOOLEAN CanSoldierBeHealedByDoctor( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pDoctor, BOOLEAN fIgnoreAssignment, BOOLEAN fThisHour, BOOLEAN fSkipKitCheck, BOOLEAN fSkipSkillCheck );
|
|
UINT8 GetNumberThatCanBeDoctored( SOLDIERTYPE *pDoctor, BOOLEAN fThisHour, BOOLEAN fSkipKitCheck, BOOLEAN fSkipSkillCheck );
|
|
void CheckForAndHandleHospitalPatients( void );
|
|
void HealHospitalPatient( SOLDIERTYPE *pPatient, UINT16 usHealingPtsLeft );
|
|
|
|
void MakeSureToolKitIsInHand( SOLDIERTYPE *pSoldier );
|
|
BOOLEAN MakeSureMedKitIsInHand( SOLDIERTYPE *pSoldier );
|
|
|
|
void RepositionMouseRegions( void );
|
|
void CheckAndUpdateTacticalAssignmentPopUpPositions( void );
|
|
void HandleRestFatigueAndSleepStatus( void );
|
|
BOOLEAN CharacterIsTakingItEasy( SOLDIERTYPE *pSoldier );
|
|
void RepairMenuBtnCallback( MOUSE_REGION * pRegion, INT32 iReason );
|
|
BOOLEAN CanCharacterDoctorButDoesntHaveMedKit( SOLDIERTYPE *pSoldier );
|
|
BOOLEAN CanCharacterRepairButDoesntHaveARepairkit( SOLDIERTYPE *pSoldier );
|
|
|
|
// robot replated stuff
|
|
BOOLEAN IsRobotInThisSector( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ );
|
|
SOLDIERTYPE * GetRobotSoldier( void );
|
|
UINT8 RepairRobot( SOLDIERTYPE *pRobot, UINT8 ubRepairPts, BOOLEAN *pfNothingLeftToRepair );
|
|
UINT8 HandleRepairOfRobotBySoldier( SOLDIERTYPE *pSoldier, UINT8 ubRepairPts, BOOLEAN *pfNothingLeftToRepair );
|
|
BOOLEAN HandleAssignmentExpansionAndHighLightForAssignMenu( SOLDIERTYPE *pSoldier );
|
|
BOOLEAN HandleAssignmentExpansionAndHighLightForTrainingMenu( void );
|
|
BOOLEAN HandleShowingOfMovementBox( void );
|
|
//BOOLEAN HandleShowingOfUpBox( void );
|
|
void ReportTrainersTraineesWithoutPartners( void );
|
|
BOOLEAN ValidTrainingPartnerInSameSectorOnAssignmentFound( SOLDIERTYPE *pSoldier, INT8 bTargetAssignment, INT8 bTargetStat );
|
|
|
|
extern void AddSectorForSoldierToListOfSectorsThatCompletedMilitiaTraining( SOLDIERTYPE *pSoldier );
|
|
|
|
extern BOOLEAN SectorIsImpassable( INT16 sSector );
|
|
|
|
extern BOOLEAN CanChangeSleepStatusForCharSlot( INT8 bCharNumber );
|
|
|
|
extern UINT32 VirtualSoldierDressWound( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pVictim, OBJECTTYPE *pKit, INT16 sKitPts, INT16 sStatus );
|
|
|
|
// only 2 trainers are allowed per sector, so this function counts the # in a guy's sector
|
|
INT8 CountMilitiaTrainersInSoldiersSector( SOLDIERTYPE * pSoldier );
|
|
|
|
|
|
// notify player of assignment attempt failure
|
|
void NotifyPlayerOfAssignmentAttemptFailure( INT8 bAssignment );
|
|
|
|
BOOLEAN PlayerSoldierTooTiredToTravel( SOLDIERTYPE *pSoldier );
|
|
|
|
void AssignmentAborted( SOLDIERTYPE *pSoldier, UINT8 ubReason );
|
|
|
|
UINT8 CalcSoldierNeedForSleep( SOLDIERTYPE *pSoldier );
|
|
|
|
UINT32 GetLastSquadListedInSquadMenu( void );
|
|
|
|
BOOLEAN IsAnythingAroundForSoldierToRepair( SOLDIERTYPE * pSoldier );
|
|
BOOLEAN HasCharacterFinishedRepairing( SOLDIERTYPE * pSoldier );
|
|
BOOLEAN DoesCharacterHaveAnyItemsToRepair( SOLDIERTYPE * pSoldier, INT8 bHighestPass );
|
|
|
|
BOOLEAN CanCharacterRepairAnotherSoldiersStuff( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOtherSoldier );
|
|
|
|
// can this character EVER train militia?
|
|
BOOLEAN BasicCanCharacterTrainMilitia( SOLDIERTYPE *pCharacter );
|
|
|
|
SOLDIERTYPE *GetSelectedAssignSoldier( BOOLEAN fNullOK );
|
|
|
|
BOOLEAN RepairObject( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pOwner, OBJECTTYPE * pObj, UINT8 * pubRepairPtsLeft );
|
|
void RepairItemsOnOthers( SOLDIERTYPE *pSoldier, UINT8 *pubRepairPtsLeft );
|
|
BOOLEAN UnjamGunsOnSoldier( SOLDIERTYPE *pOwnerSoldier, SOLDIERTYPE *pRepairSoldier, UINT8 *pubRepairPtsLeft );
|
|
|
|
/* No point in allowing SAM site repair any more. Jan/13/99. ARM
|
|
BOOLEAN IsTheSAMSiteInSectorRepairable( INT16 sSectorX, INT16 sSectorY, INT16 sSectorZ );
|
|
BOOLEAN SoldierInSameSectorAsSAM( SOLDIERTYPE *pSoldier );
|
|
BOOLEAN CanSoldierRepairSAM( SOLDIERTYPE *pSoldier, INT8 bRepairPoints );
|
|
BOOLEAN IsSoldierCloseEnoughToSAMControlPanel( SOLDIERTYPE *pSoldier );
|
|
*/
|
|
|
|
/* Assignment distance limits removed. Sep/11/98. ARM
|
|
BOOLEAN IsSoldierCloseEnoughToADoctor( SOLDIERTYPE *pPatient );
|
|
*/
|
|
|
|
#ifdef JA2BETAVERSION
|
|
void VerifyTownTrainingIsPaidFor( void );
|
|
#endif
|
|
|
|
|
|
|
|
|
|
void InitSectorsWithSoldiersList( void )
|
|
{
|
|
// init list of sectors
|
|
memset( &fSectorsWithSoldiers, 0, sizeof( fSectorsWithSoldiers ) );
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void BuildSectorsWithSoldiersList( void )
|
|
{
|
|
SOLDIERTYPE *pSoldier, *pTeamSoldier;
|
|
INT32 cnt=0;
|
|
|
|
pSoldier = MercPtrs[ 0 ];
|
|
|
|
// fills array with pressence of player controlled characters
|
|
for ( pTeamSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ pSoldier -> bTeam ].bLastID; cnt++,pTeamSoldier++)
|
|
{
|
|
if(pTeamSoldier -> bActive)
|
|
{
|
|
fSectorsWithSoldiers[ pTeamSoldier -> sSectorX + pTeamSoldier -> sSectorY * MAP_WORLD_X ][ pTeamSoldier -> bSectorZ ] = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ChangeSoldiersAssignment( SOLDIERTYPE *pSoldier, INT8 bAssignment )
|
|
{
|
|
// This is the most basic assignment-setting function. It must be called before setting any subsidiary
|
|
// values like fFixingRobot. It will clear all subsidiary values so we don't leave the merc in a messed
|
|
// up state!
|
|
|
|
pSoldier->bAssignment = bAssignment;
|
|
/// don't kill iVehicleId, though, 'cause militia training tries to put guys back in their vehicles when it's done(!)
|
|
|
|
pSoldier->fFixingSAMSite = FALSE;
|
|
pSoldier->fFixingRobot = FALSE;
|
|
pSoldier->bVehicleUnderRepairID = -1;
|
|
|
|
if ( ( bAssignment == DOCTOR ) || ( bAssignment == PATIENT ) || ( bAssignment == ASSIGNMENT_HOSPITAL ) )
|
|
{
|
|
AddStrategicEvent( EVENT_BANDAGE_BLEEDING_MERCS, GetWorldTotalMin() + 1, 0 );
|
|
}
|
|
|
|
// update character info, and the team panel
|
|
fCharacterInfoPanelDirty = TRUE;
|
|
fTeamPanelDirty = TRUE;
|
|
|
|
// merc may have come on/off duty, make sure map icons are updated
|
|
fMapPanelDirty = TRUE;
|
|
}
|
|
|
|
|
|
BOOLEAN BasicCanCharacterAssignment( SOLDIERTYPE * pSoldier, BOOLEAN fNotInCombat )
|
|
{
|
|
// global conditions restricting all assignment changes
|
|
if ( SectorIsImpassable( (INT16) SECTOR( pSoldier->sSectorX, pSoldier->sSectorY ) ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if ( fNotInCombat && pSoldier->bActive && pSoldier->bInSector && gTacticalStatus.fEnemyInSector )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
BOOLEAN CanSoldierAssignment( SOLDIERTYPE *pSoldier, INT8 bAssignment )
|
|
{
|
|
switch( bAssignment )
|
|
{
|
|
case( DOCTOR ):
|
|
return( CanCharacterDoctor( pSoldier ) );
|
|
break;
|
|
case( PATIENT ):
|
|
return( CanCharacterPatient( pSoldier ) );
|
|
break;
|
|
case( REPAIR ):
|
|
return( CanCharacterRepair( pSoldier ) );
|
|
break;
|
|
case( TRAIN_TOWN ):
|
|
return( CanCharacterTrainMilitia( pSoldier ) );
|
|
break;
|
|
case( TRAIN_SELF ):
|
|
return( CanCharacterTrainStat( pSoldier, pSoldier -> bTrainStat, TRUE, FALSE ) );
|
|
break;
|
|
case( TRAIN_TEAMMATE ):
|
|
return( CanCharacterTrainStat( pSoldier, pSoldier -> bTrainStat, FALSE, TRUE ) );
|
|
break;
|
|
case TRAIN_BY_OTHER:
|
|
return( CanCharacterTrainStat( pSoldier, pSoldier -> bTrainStat, TRUE, FALSE ) );
|
|
break;
|
|
case( VEHICLE ):
|
|
return( CanCharacterVehicle( pSoldier ) );
|
|
break;
|
|
default:
|
|
return( (CanCharacterSquad( pSoldier, bAssignment ) == CHARACTER_CAN_JOIN_SQUAD ) );
|
|
break;
|
|
}
|
|
}
|
|
*/
|
|
|
|
|
|
|
|
BOOLEAN CanCharacterDoctorButDoesntHaveMedKit( SOLDIERTYPE *pSoldier )
|
|
{
|
|
if ( !BasicCanCharacterAssignment( pSoldier, TRUE ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// make sure character is alive and conscious
|
|
if( pSoldier -> bLife < OKLIFE )
|
|
{
|
|
// dead or unconscious...
|
|
return ( FALSE );
|
|
}
|
|
|
|
// has medical skill?
|
|
if( pSoldier -> bMedical <= 0 )
|
|
{
|
|
// no skill whatsoever
|
|
return ( FALSE );
|
|
}
|
|
|
|
// in transit?
|
|
if( IsCharacterInTransit( pSoldier ) == TRUE )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
|
|
// character on the move?
|
|
if( CharacterIsBetweenSectors( pSoldier ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if( pSoldier -> ubWhatKindOfMercAmI == MERC_TYPE__EPC )
|
|
{
|
|
// epcs can't do this
|
|
return( FALSE );
|
|
}
|
|
|
|
// check in helicopter in hostile sector
|
|
if( pSoldier -> bAssignment == VEHICLE )
|
|
{
|
|
if( ( iHelicopterVehicleId != -1 ) && ( pSoldier -> iVehicleId == iHelicopterVehicleId ) )
|
|
{
|
|
// enemies in sector
|
|
if( NumEnemiesInSector( pSoldier -> sSectorX, pSoldier -> sSectorY ) > 0 )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
// is character capable of 'playing' doctor?
|
|
// check that character is alive, conscious, has medical skill and equipment
|
|
BOOLEAN CanCharacterDoctor( SOLDIERTYPE *pSoldier )
|
|
{
|
|
BOOLEAN fFoundMedKit = FALSE;
|
|
INT8 bPocket = 0;
|
|
|
|
if ( !BasicCanCharacterAssignment( pSoldier, TRUE ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if( CanCharacterDoctorButDoesntHaveMedKit( pSoldier ) == FALSE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// find med kit
|
|
for (bPocket = HANDPOS; bPocket <= SMALLPOCK8POS; bPocket++)
|
|
{
|
|
// doctoring is allowed using either type of med kit (but first aid kit halves doctoring effectiveness)
|
|
if( IsMedicalKitItem( &( pSoldier -> inv[ bPocket ] ) ) )
|
|
{
|
|
fFoundMedKit = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( fFoundMedKit == FALSE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// all criteria fit, can doctor
|
|
return ( TRUE );
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN IsAnythingAroundForSoldierToRepair( SOLDIERTYPE * pSoldier )
|
|
{
|
|
INT32 iCounter;
|
|
|
|
|
|
// items?
|
|
if ( DoesCharacterHaveAnyItemsToRepair( pSoldier, FINAL_REPAIR_PASS ) )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
|
|
// robot?
|
|
if ( CanCharacterRepairRobot( pSoldier ) )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
|
|
// vehicles?
|
|
if ( pSoldier->bSectorZ == 0 )
|
|
{
|
|
for ( iCounter = 0; iCounter < ubNumberOfVehicles; iCounter++ )
|
|
{
|
|
if ( pVehicleList[ iCounter ].fValid == TRUE )
|
|
{
|
|
// the helicopter, is NEVER repairable...
|
|
if ( iCounter != iHelicopterVehicleId )
|
|
{
|
|
if ( IsThisVehicleAccessibleToSoldier( pSoldier, iCounter ) )
|
|
{
|
|
if( CanCharacterRepairVehicle( pSoldier, iCounter ) == TRUE )
|
|
{
|
|
// there is a repairable vehicle here
|
|
return( TRUE );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN HasCharacterFinishedRepairing( SOLDIERTYPE * pSoldier )
|
|
{
|
|
BOOLEAN fCanStillRepair;
|
|
|
|
// NOTE: This must detect situations where the vehicle/robot has left the sector, in which case we want the
|
|
// guy to say "assignment done", so we return that he can no longer repair
|
|
|
|
// check if we are repairing a vehicle
|
|
if ( pSoldier->bVehicleUnderRepairID != -1 )
|
|
{
|
|
fCanStillRepair = CanCharacterRepairVehicle( pSoldier, pSoldier->bVehicleUnderRepairID );
|
|
}
|
|
// check if we are repairing a robot
|
|
else if( pSoldier -> fFixingRobot )
|
|
{
|
|
fCanStillRepair = CanCharacterRepairRobot( pSoldier );
|
|
}
|
|
else // repairing items
|
|
{
|
|
fCanStillRepair = DoesCharacterHaveAnyItemsToRepair( pSoldier, FINAL_REPAIR_PASS );
|
|
}
|
|
|
|
// if it's no longer damaged, we're finished!
|
|
return( !fCanStillRepair );
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN DoesCharacterHaveAnyItemsToRepair( SOLDIERTYPE *pSoldier, INT8 bHighestPass )
|
|
{
|
|
INT8 bPocket;
|
|
UINT8 ubItemsInPocket, ubObjectInPocketCounter;
|
|
INT8 bLoop;
|
|
SOLDIERTYPE * pOtherSoldier;
|
|
OBJECTTYPE * pObj;
|
|
UINT8 ubPassType;
|
|
|
|
|
|
// check for jams
|
|
for (bPocket = HELMETPOS; bPocket <= SMALLPOCK8POS; bPocket++)
|
|
{
|
|
ubItemsInPocket = pSoldier -> inv[ bPocket ].ubNumberOfObjects;
|
|
// unjam any jammed weapons
|
|
// run through pocket and repair
|
|
for( ubObjectInPocketCounter = 0; ubObjectInPocketCounter < ubItemsInPocket; ubObjectInPocketCounter++ )
|
|
{
|
|
// jammed gun?
|
|
if ( ( Item[ pSoldier -> inv[ bPocket ].usItem ].usItemClass == IC_GUN ) && ( pSoldier -> inv[ bPocket ].bGunAmmoStatus < 0 ) )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
}
|
|
|
|
// now check for items to repair
|
|
for( bPocket = HELMETPOS; bPocket <= SMALLPOCK8POS; bPocket++ )
|
|
{
|
|
pObj = &(pSoldier->inv[ bPocket ]);
|
|
|
|
ubItemsInPocket = pObj->ubNumberOfObjects;
|
|
|
|
// run through pocket
|
|
for( ubObjectInPocketCounter = 0; ubObjectInPocketCounter < ubItemsInPocket; ubObjectInPocketCounter++ )
|
|
{
|
|
// if it's repairable and NEEDS repairing
|
|
if ( IsItemRepairable( pObj->usItem, pObj->bStatus[ubObjectInPocketCounter] ) )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
|
|
// have to check for attachments...
|
|
for ( bLoop = 0; bLoop < MAX_ATTACHMENTS; bLoop++ )
|
|
{
|
|
if ( pObj->usAttachItem[ bLoop ] != NOTHING )
|
|
{
|
|
// if it's repairable and NEEDS repairing
|
|
if ( IsItemRepairable( pObj->usAttachItem[ bLoop ], pObj->bAttachStatus[ bLoop ] ) )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// if we wanna check for the items belonging to others in the sector
|
|
if ( bHighestPass != - 1 )
|
|
{
|
|
// now look for items to repair on other mercs
|
|
for( bLoop = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; bLoop < gTacticalStatus.Team[ gbPlayerNum ].bLastID; bLoop++ )
|
|
{
|
|
pOtherSoldier = MercPtrs[ bLoop ];
|
|
|
|
if ( CanCharacterRepairAnotherSoldiersStuff( pSoldier, pOtherSoldier ) )
|
|
{
|
|
// okay, seems like a candidate! Check if he has anything that needs unjamming or repairs
|
|
|
|
for ( bPocket = HANDPOS; bPocket <= SMALLPOCK8POS; bPocket++ )
|
|
{
|
|
// the object a weapon? and jammed?
|
|
if ( ( Item[ pOtherSoldier->inv[ bPocket ].usItem ].usItemClass == IC_GUN ) && ( pOtherSoldier->inv[ bPocket ].bGunAmmoStatus < 0 ) )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
|
|
// repair everyone's hands and armor slots first, then headgear, and pockets last
|
|
for ( ubPassType = REPAIR_HANDS_AND_ARMOR; ubPassType <= ( UINT8 ) bHighestPass; ubPassType++ )
|
|
{
|
|
bPocket = FindRepairableItemOnOtherSoldier( pOtherSoldier, ubPassType );
|
|
if ( bPocket != NO_SLOT )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN BasicCanCharacterRepair( SOLDIERTYPE * pSoldier )
|
|
{
|
|
if ( !BasicCanCharacterAssignment( pSoldier, TRUE ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// make sure character is alive and oklife
|
|
if( pSoldier -> bLife < OKLIFE )
|
|
{
|
|
// dead or unconscious...
|
|
return ( FALSE );
|
|
}
|
|
|
|
// has repair skill?
|
|
if( pSoldier -> bMechanical <= 0 )
|
|
{
|
|
// no skill whatsoever
|
|
return ( FALSE );
|
|
}
|
|
|
|
// in transit?
|
|
if( IsCharacterInTransit( pSoldier ) == TRUE )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
|
|
// character on the move?
|
|
if( CharacterIsBetweenSectors( pSoldier ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if( pSoldier -> ubWhatKindOfMercAmI == MERC_TYPE__EPC )
|
|
{
|
|
// epcs can't do this
|
|
return( FALSE );
|
|
}
|
|
|
|
// check in helicopter in hostile sector
|
|
if( pSoldier -> bAssignment == VEHICLE )
|
|
{
|
|
if( ( iHelicopterVehicleId != -1 ) && ( pSoldier -> iVehicleId == iHelicopterVehicleId ) )
|
|
{
|
|
// enemies in sector
|
|
if( NumEnemiesInSector( pSoldier -> sSectorX, pSoldier -> sSectorY ) > 0 )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOLEAN CanCharacterRepairButDoesntHaveARepairkit( SOLDIERTYPE *pSoldier )
|
|
{
|
|
if ( BasicCanCharacterRepair( pSoldier ) == FALSE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// make sure he actually doesn't have a toolkit
|
|
if ( FindToolkit( pSoldier ) != NO_SLOT )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
// can character be assigned as repairman?
|
|
// check that character is alive, oklife, has repair skill, and equipment, etc.
|
|
BOOLEAN CanCharacterRepair( SOLDIERTYPE *pSoldier )
|
|
{
|
|
INT8 bPocket = 0;
|
|
BOOLEAN fToolKitFound = FALSE;
|
|
|
|
if ( !BasicCanCharacterAssignment( pSoldier, TRUE ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if ( BasicCanCharacterRepair( pSoldier ) == FALSE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// make sure he has a toolkit
|
|
if ( FindToolkit( pSoldier ) == NO_SLOT )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// anything around to fix?
|
|
if ( !IsAnythingAroundForSoldierToRepair( pSoldier ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// NOTE: This will not detect situations where character lacks the SKILL to repair the stuff that needs repairing...
|
|
// So, in that situation, his assignment will NOT flash, but a message to that effect will be reported every hour.
|
|
|
|
// all criteria fit, can repair
|
|
return ( TRUE );
|
|
}
|
|
|
|
|
|
// can character be set to patient?
|
|
BOOLEAN CanCharacterPatient( SOLDIERTYPE *pSoldier )
|
|
{
|
|
if ( !BasicCanCharacterAssignment( pSoldier, TRUE ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// Robot must be REPAIRED to be "healed", not doctored
|
|
if( ( pSoldier -> uiStatusFlags & SOLDIER_VEHICLE ) || AM_A_ROBOT( pSoldier ) )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
|
|
if( pSoldier -> bAssignment == ASSIGNMENT_POW )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
|
|
// is character alive and not in perfect health?
|
|
if( ( pSoldier -> bLife <= 0 ) || ( pSoldier -> bLife == pSoldier -> bLifeMax ) )
|
|
{
|
|
// dead or in perfect health
|
|
return ( FALSE );
|
|
}
|
|
|
|
// in transit?
|
|
if( IsCharacterInTransit( pSoldier ) == TRUE )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
|
|
// character on the move?
|
|
if( CharacterIsBetweenSectors( pSoldier ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// check in helicopter in hostile sector
|
|
if( pSoldier -> bAssignment == VEHICLE )
|
|
{
|
|
if( ( iHelicopterVehicleId != -1 ) && ( pSoldier -> iVehicleId == iHelicopterVehicleId ) )
|
|
{
|
|
// enemies in sector
|
|
if( NumEnemiesInSector( pSoldier -> sSectorX, pSoldier -> sSectorY ) > 0 )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
}
|
|
|
|
// alive and can be healed
|
|
return ( TRUE );
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN BasicCanCharacterTrainMilitia( SOLDIERTYPE *pSoldier )
|
|
{
|
|
// is the character capable of training a town?
|
|
// they must be alive/conscious and in the sector with the town
|
|
BOOLEAN fSamSitePresent = FALSE;
|
|
|
|
if ( !BasicCanCharacterAssignment( pSoldier, TRUE ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// make sure character is alive and conscious
|
|
if( pSoldier -> bLife < OKLIFE )
|
|
{
|
|
// dead or unconscious...
|
|
return ( FALSE );
|
|
}
|
|
|
|
// underground training is not allowed (code doesn't support and it's a reasonable enough limitation)
|
|
if( pSoldier -> bSectorZ != 0 )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// is there a town in the character's current sector?
|
|
if( StrategicMap[ CALCULATE_STRATEGIC_INDEX( pSoldier->sSectorX, pSoldier->sSectorY ) ].bNameId == BLANK_SECTOR )
|
|
{
|
|
fSamSitePresent = IsThisSectorASAMSector( pSoldier -> sSectorX, pSoldier -> sSectorY, pSoldier -> bSectorZ );
|
|
|
|
// check if sam site
|
|
if( fSamSitePresent == FALSE )
|
|
{
|
|
// nope
|
|
return ( FALSE );
|
|
}
|
|
}
|
|
|
|
if( NumEnemiesInAnySector( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
// check in helicopter in hostile sector
|
|
if( pSoldier -> bAssignment == VEHICLE )
|
|
{
|
|
if( ( iHelicopterVehicleId != -1 ) && ( pSoldier -> iVehicleId == iHelicopterVehicleId ) )
|
|
{
|
|
// enemies in sector
|
|
if( NumEnemiesInSector( pSoldier -> sSectorX, pSoldier -> sSectorY ) > 0 )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
}
|
|
|
|
// in transit?
|
|
if( IsCharacterInTransit( pSoldier ) == TRUE )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
|
|
// character on the move?
|
|
if( CharacterIsBetweenSectors( pSoldier ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if( pSoldier -> ubWhatKindOfMercAmI == MERC_TYPE__EPC )
|
|
{
|
|
// epcs can't do this
|
|
return( FALSE );
|
|
}
|
|
|
|
if ( ( pSoldier->uiStatusFlags & SOLDIER_VEHICLE ) || AM_A_ROBOT( pSoldier ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// has leadership skill?
|
|
if( pSoldier -> bLeadership <= 0 )
|
|
{
|
|
// no skill whatsoever
|
|
return ( FALSE );
|
|
}
|
|
|
|
|
|
// can train militia
|
|
return( TRUE );
|
|
}
|
|
|
|
// Kaiden: Roaming Militia Training:
|
|
// Commenting out the check for:
|
|
// IsMilitiaTrainableFromSoldiersSectorMaxed(
|
|
// At this point, we don't care if it's full yet
|
|
|
|
BOOLEAN CanCharacterTrainMilitia( SOLDIERTYPE *pSoldier )
|
|
{
|
|
|
|
if (gGameExternalOptions.gfmusttrainroaming
|
|
&& (GetWorldDay( ) >= gGameExternalOptions.guiAllowMilitiaGroupsDelay)
|
|
&& (!IsThisSectorASAMSector(pSoldier->sSectorX,pSoldier->sSectorY,0 )))
|
|
{
|
|
if( BasicCanCharacterTrainMilitia( pSoldier ) &&
|
|
MilitiaTrainingAllowedInSector( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ ) &&
|
|
DoesSectorMercIsInHaveSufficientLoyaltyToTrainMilitia( pSoldier ) &&
|
|
/*( IsMilitiaTrainableFromSoldiersSectorMaxed( pSoldier ) == FALSE ) && */
|
|
( CountMilitiaTrainersInSoldiersSector( pSoldier ) < gGameExternalOptions.ubMaxMilitiaTrainersPerSector ) )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
else
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( BasicCanCharacterTrainMilitia( pSoldier ) &&
|
|
MilitiaTrainingAllowedInSector( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ ) &&
|
|
DoesSectorMercIsInHaveSufficientLoyaltyToTrainMilitia( pSoldier ) &&
|
|
( IsMilitiaTrainableFromSoldiersSectorMaxed( pSoldier,ELITE_MILITIA ) == FALSE ) &&
|
|
( CountMilitiaTrainersInSoldiersSector( pSoldier ) < gGameExternalOptions.ubMaxMilitiaTrainersPerSector ) )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
else
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN DoesTownHaveRatingToTrainMilitia( INT8 bTownId )
|
|
{
|
|
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Assignments1");
|
|
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"Assignments1");
|
|
// min loyalty rating?
|
|
if( ( gTownLoyalty[ bTownId ].ubRating < gGameExternalOptions.iMinLoyaltyToTrain ) )
|
|
{
|
|
// nope
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN DoesSectorMercIsInHaveSufficientLoyaltyToTrainMilitia( SOLDIERTYPE *pSoldier )
|
|
{
|
|
INT8 bTownId = 0;
|
|
BOOLEAN fSamSitePresent = FALSE;
|
|
|
|
|
|
// underground training is not allowed (code doesn't support and it's a reasonable enough limitation)
|
|
if( pSoldier -> bSectorZ != 0 )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
bTownId = GetTownIdForSector( pSoldier->sSectorX, pSoldier->sSectorY );
|
|
|
|
// is there a town really here
|
|
if( bTownId == BLANK_SECTOR )
|
|
{
|
|
fSamSitePresent = IsThisSectorASAMSector( pSoldier -> sSectorX, pSoldier -> sSectorY, pSoldier -> bSectorZ );
|
|
|
|
// if there is a sam site here
|
|
if( fSamSitePresent )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
// does this town have sufficient loyalty to train militia
|
|
if( DoesTownHaveRatingToTrainMilitia( bTownId ) == FALSE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
|
|
INT8 CountMilitiaTrainersInSoldiersSector( SOLDIERTYPE * pSoldier )
|
|
{
|
|
INT8 bLoop;
|
|
SOLDIERTYPE * pOtherSoldier;
|
|
INT8 bCount = 0;
|
|
|
|
for ( bLoop = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; bLoop <= gTacticalStatus.Team[ gbPlayerNum ].bLastID; bLoop++ )
|
|
{
|
|
pOtherSoldier = MercPtrs[ bLoop ];
|
|
if ( pSoldier != pOtherSoldier && pOtherSoldier->bActive && pOtherSoldier->bLife >= OKLIFE && pOtherSoldier->sSectorX == pSoldier->sSectorX && pOtherSoldier->sSectorY == pSoldier->sSectorY && pSoldier->bSectorZ == pOtherSoldier->bSectorZ )
|
|
{
|
|
if (pOtherSoldier->bAssignment == TRAIN_TOWN )
|
|
{
|
|
bCount++;
|
|
}
|
|
}
|
|
}
|
|
return( bCount );
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN IsMilitiaTrainableFromSoldiersSectorMaxed( SOLDIERTYPE *pSoldier, INT8 iMilitiaType )
|
|
{
|
|
INT8 bTownId = 0;
|
|
BOOLEAN fSamSitePresent = FALSE;
|
|
|
|
|
|
if( pSoldier->bSectorZ != 0 )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
|
|
bTownId = GetTownIdForSector( pSoldier->sSectorX, pSoldier->sSectorY );
|
|
|
|
// is there a town really here
|
|
if( bTownId == BLANK_SECTOR )
|
|
{
|
|
fSamSitePresent = IsThisSectorASAMSector( pSoldier -> sSectorX, pSoldier -> sSectorY, pSoldier -> bSectorZ );
|
|
|
|
// if there is a sam site here
|
|
if( fSamSitePresent )
|
|
{
|
|
if( IsSAMSiteFullOfMilitia( pSoldier->sSectorX, pSoldier->sSectorY,iMilitiaType ) )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
return( FALSE );
|
|
}
|
|
return( FALSE );
|
|
}
|
|
|
|
// this considers *ALL* safe sectors of the town, not just the one soldier is in
|
|
if( IsTownFullMilitia( bTownId, iMilitiaType ) )
|
|
{
|
|
// town is full of militia
|
|
return( TRUE );
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
BOOLEAN CanCharacterTrainStat( SOLDIERTYPE *pSoldier, INT8 bStat, BOOLEAN fTrainSelf, BOOLEAN fTrainTeammate )
|
|
{
|
|
// is the character capable of training this stat? either self or as trainer
|
|
|
|
if ( !BasicCanCharacterAssignment( pSoldier, TRUE ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// alive and conscious
|
|
if( pSoldier -> bLife < OKLIFE )
|
|
{
|
|
// dead or unconscious...
|
|
return ( FALSE );
|
|
}
|
|
|
|
// underground training is not allowed (code doesn't support and it's a reasonable enough limitation)
|
|
if( pSoldier -> bSectorZ != 0 )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// check in helicopter in hostile sector
|
|
if( pSoldier -> bAssignment == VEHICLE )
|
|
{
|
|
if( ( iHelicopterVehicleId != -1 ) && ( pSoldier -> iVehicleId == iHelicopterVehicleId ) )
|
|
{
|
|
// enemies in sector
|
|
if( NumEnemiesInSector( pSoldier -> sSectorX, pSoldier -> sSectorY ) > 0 )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
}
|
|
|
|
if( pSoldier -> ubWhatKindOfMercAmI == MERC_TYPE__EPC )
|
|
{
|
|
// epcs can't do this
|
|
return( FALSE );
|
|
}
|
|
|
|
// check stat values, 0 means no chance in hell
|
|
switch( bStat )
|
|
{
|
|
case ( STRENGTH ):
|
|
// strength
|
|
if ( pSoldier->bStrength < gGameExternalOptions.ubTrainingSkillMin )
|
|
return FALSE;
|
|
else if( ( ( pSoldier -> bStrength < gGameExternalOptions.ubMinSkillToTeach ) && ( fTrainTeammate ) ) )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
else if( ( pSoldier -> bStrength >= gGameExternalOptions.ubTrainingSkillMax ) && ( fTrainSelf ) )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
break;
|
|
case( DEXTERITY ):
|
|
// dexterity
|
|
if ( pSoldier->bDexterity < gGameExternalOptions.ubTrainingSkillMin )
|
|
return FALSE;
|
|
else if( ( ( pSoldier -> bDexterity < gGameExternalOptions.ubMinSkillToTeach ) && ( fTrainTeammate ) ) )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
else if( ( pSoldier -> bDexterity >= gGameExternalOptions.ubTrainingSkillMax )&&( fTrainSelf ) )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
break;
|
|
case( AGILITY ):
|
|
// agility
|
|
if ( pSoldier->bAgility < gGameExternalOptions.ubTrainingSkillMin )
|
|
return FALSE;
|
|
else if( ( ( pSoldier -> bAgility < gGameExternalOptions.ubMinSkillToTeach ) && ( fTrainTeammate ) ) )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
else if( ( pSoldier -> bAgility >= gGameExternalOptions.ubTrainingSkillMax )&&( fTrainSelf ) )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
|
|
break;
|
|
case( HEALTH ):
|
|
// health
|
|
if ( pSoldier->bLifeMax < gGameExternalOptions.ubTrainingSkillMin )
|
|
return FALSE;
|
|
else if( ( ( pSoldier -> bLifeMax < gGameExternalOptions.ubMinSkillToTeach ) && ( fTrainTeammate ) ) )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
else if( ( pSoldier -> bLifeMax >= gGameExternalOptions.ubTrainingSkillMax )&&( fTrainSelf ) )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
|
|
break;
|
|
case( MARKSMANSHIP ):
|
|
// marksmanship
|
|
if ( pSoldier->bMarksmanship < gGameExternalOptions.ubTrainingSkillMin )
|
|
return FALSE;
|
|
else if( ( ( pSoldier -> bMarksmanship < gGameExternalOptions.ubMinSkillToTeach ) && ( fTrainTeammate ) ) )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
else if( ( pSoldier -> bMarksmanship >= gGameExternalOptions.ubTrainingSkillMax )&&( fTrainSelf ) )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
|
|
break;
|
|
case( MEDICAL ):
|
|
// medical
|
|
if ( pSoldier->bMedical < gGameExternalOptions.ubTrainingSkillMin )
|
|
return FALSE;
|
|
else if( ( ( pSoldier -> bMedical < gGameExternalOptions.ubMinSkillToTeach ) && ( fTrainTeammate ) ) )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
else if( ( pSoldier -> bMedical >= gGameExternalOptions.ubTrainingSkillMax )&&( fTrainSelf ) )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
|
|
break;
|
|
case( MECHANICAL ):
|
|
// mechanical
|
|
if ( pSoldier->bMechanical < gGameExternalOptions.ubTrainingSkillMin )
|
|
return FALSE;
|
|
else if( ( ( pSoldier -> bMechanical < gGameExternalOptions.ubMinSkillToTeach ) && ( fTrainTeammate ) ) )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
else if( ( pSoldier -> bMechanical >= gGameExternalOptions.ubTrainingSkillMax )&&( fTrainSelf ) )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
break;
|
|
case( LEADERSHIP ):
|
|
// leadership
|
|
if ( pSoldier->bLeadership < gGameExternalOptions.ubTrainingSkillMin )
|
|
return FALSE;
|
|
else if( ( ( pSoldier -> bLeadership < gGameExternalOptions.ubMinSkillToTeach ) && ( fTrainTeammate ) ) )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
else if( ( pSoldier -> bLeadership >= gGameExternalOptions.ubTrainingSkillMax )&&( fTrainSelf ) )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
break;
|
|
case( EXPLOSIVE_ASSIGN ):
|
|
// explosives
|
|
if ( pSoldier->bExplosive < gGameExternalOptions.ubTrainingSkillMin )
|
|
return FALSE;
|
|
else if( ( ( pSoldier -> bExplosive < gGameExternalOptions.ubMinSkillToTeach ) && ( fTrainTeammate ) ) )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
else if( ( pSoldier -> bExplosive >= gGameExternalOptions.ubTrainingSkillMax )&&( fTrainSelf ) )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
break;
|
|
}
|
|
|
|
// in transit?
|
|
if( IsCharacterInTransit( pSoldier ) == TRUE )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
|
|
// character on the move?
|
|
if( CharacterIsBetweenSectors( pSoldier ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// stat is ok and character alive and conscious
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOLEAN CanCharacterOnDuty( SOLDIERTYPE *pSoldier )
|
|
{
|
|
// can character commit themselves to on duty?
|
|
|
|
// only need to be alive and well to do so right now
|
|
// alive and conscious
|
|
if( pSoldier -> bLife < OKLIFE )
|
|
{
|
|
// dead or unconscious...
|
|
return ( FALSE );
|
|
}
|
|
|
|
if ( !BasicCanCharacterAssignment( pSoldier, FALSE ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// check in helicopter in hostile sector
|
|
if( pSoldier -> bAssignment == VEHICLE )
|
|
{
|
|
if( ( iHelicopterVehicleId != -1 ) && ( pSoldier -> iVehicleId == iHelicopterVehicleId ) )
|
|
{
|
|
// enemies in sector
|
|
if( NumEnemiesInSector( pSoldier -> sSectorX, pSoldier -> sSectorY ) > 0 )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
}
|
|
// in transit?
|
|
if( IsCharacterInTransit( pSoldier ) == TRUE )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
|
|
|
|
// ARM: New rule: can't change squads or exit vehicles between sectors!
|
|
if( pSoldier -> fBetweenSectors )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
|
|
/*
|
|
if( pSoldier -> fBetweenSectors )
|
|
{
|
|
if( pSoldier -> bAssignment == VEHICLE )
|
|
{
|
|
if( GetNumberInVehicle( pSoldier -> iVehicleId ) == 1 )
|
|
{
|
|
// can't change, go away
|
|
return( FALSE );
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN CanCharacterPractise( SOLDIERTYPE *pSoldier )
|
|
{
|
|
// can character practise right now?
|
|
|
|
if ( !BasicCanCharacterAssignment( pSoldier, TRUE ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// only need to be alive and well to do so right now
|
|
// alive and conscious
|
|
if( pSoldier -> bLife < OKLIFE )
|
|
{
|
|
// dead or unconscious...
|
|
return ( FALSE );
|
|
}
|
|
|
|
if( pSoldier -> bSectorZ != 0 )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// in transit?
|
|
if( IsCharacterInTransit( pSoldier ) == TRUE )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
|
|
// character on the move?
|
|
if( CharacterIsBetweenSectors( pSoldier ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// check in helicopter in hostile sector
|
|
if( pSoldier -> bAssignment == VEHICLE )
|
|
{
|
|
if( ( iHelicopterVehicleId != -1 ) && ( pSoldier -> iVehicleId == iHelicopterVehicleId ) )
|
|
{
|
|
// enemies in sector
|
|
if( NumEnemiesInSector( pSoldier -> sSectorX, pSoldier -> sSectorY ) > 0 )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
}
|
|
|
|
if( pSoldier -> ubWhatKindOfMercAmI == MERC_TYPE__EPC )
|
|
{
|
|
// epcs can't do this
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
// can practise
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOLEAN CanCharacterTrainTeammates( SOLDIERTYPE *pSoldier )
|
|
{
|
|
INT32 cnt = 0;
|
|
SOLDIERTYPE *pTeamSoldier = NULL;
|
|
|
|
// can character train at all
|
|
if( CanCharacterPractise( pSoldier ) == FALSE )
|
|
{
|
|
// nope
|
|
return( FALSE );
|
|
}
|
|
|
|
// if alone in sector, can't enter the attributes submenu at all
|
|
if ( PlayerMercsInSector( ( UINT8 ) pSoldier->sSectorX, ( UINT8 ) pSoldier->sSectorY, pSoldier->bSectorZ ) == 0 )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// ARM: we allow this even if there are no students assigned yet. Flashing is warning enough.
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOLEAN CanCharacterBeTrainedByOther( SOLDIERTYPE *pSoldier )
|
|
{
|
|
INT32 iCounter = 0;
|
|
|
|
// can character train at all
|
|
if( CanCharacterPractise( pSoldier ) == FALSE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// if alone in sector, can't enter the attributes submenu at all
|
|
if ( PlayerMercsInSector( ( UINT8 ) pSoldier->sSectorX, ( UINT8 ) pSoldier->sSectorY, pSoldier->bSectorZ ) == 0 )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// ARM: we now allow this even if there are no trainers assigned yet. Flashing is warning enough.
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
|
|
// can character sleep right now?
|
|
BOOLEAN CanCharacterSleep( SOLDIERTYPE *pSoldier, BOOLEAN fExplainWhyNot )
|
|
{
|
|
CHAR16 sString[ 128 ];
|
|
|
|
// dead or dying?
|
|
if( pSoldier -> bLife < OKLIFE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// vehicle or robot?
|
|
if( ( pSoldier -> uiStatusFlags & SOLDIER_VEHICLE ) || AM_A_ROBOT( pSoldier ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// in transit?
|
|
if( IsCharacterInTransit( pSoldier ) == TRUE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// POW?
|
|
if( pSoldier -> bAssignment == ASSIGNMENT_POW )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
// traveling?
|
|
if ( pSoldier->fBetweenSectors )
|
|
{
|
|
// if walking
|
|
if ( pSoldier->bAssignment != VEHICLE )
|
|
{
|
|
// can't sleep while walking or driving a vehicle
|
|
if( fExplainWhyNot )
|
|
{
|
|
// on the move, can't sleep
|
|
swprintf( sString, zMarksMapScreenText[ 5 ], pSoldier->name );
|
|
DoScreenIndependantMessageBox( sString, MSG_BOX_FLAG_OK, NULL );
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
else // in a vehicle
|
|
{
|
|
// if this guy has to drive ('cause nobody else can)
|
|
if ( SoldierMustDriveVehicle( pSoldier, pSoldier->iVehicleId, FALSE ) )
|
|
{
|
|
// can't sleep while walking or driving a vehicle
|
|
if( fExplainWhyNot )
|
|
{
|
|
// is driving, can't sleep
|
|
swprintf( sString, zMarksMapScreenText[ 7 ], pSoldier->name );
|
|
DoScreenIndependantMessageBox( sString, MSG_BOX_FLAG_OK, NULL );
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
}
|
|
}
|
|
else // in a sector
|
|
{
|
|
// if not above it all...
|
|
if ( !SoldierAboardAirborneHeli( pSoldier ) )
|
|
{
|
|
// if he's in the loaded sector, and it's hostile or in combat
|
|
if( pSoldier->bInSector && ( ( gTacticalStatus.uiFlags & INCOMBAT ) || gTacticalStatus.fEnemyInSector ) )
|
|
{
|
|
if( fExplainWhyNot )
|
|
{
|
|
DoScreenIndependantMessageBox( Message[ STR_SECTOR_NOT_CLEARED ], MSG_BOX_FLAG_OK, NULL );
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
// on surface, and enemies are in the sector
|
|
if( ( pSoldier->bSectorZ == 0 ) && ( NumEnemiesInAnySector( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ ) > 0 ) )
|
|
{
|
|
if( fExplainWhyNot )
|
|
{
|
|
DoScreenIndependantMessageBox( Message[ STR_SECTOR_NOT_CLEARED ], MSG_BOX_FLAG_OK, NULL );
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// not tired?
|
|
if( pSoldier->bBreathMax >= BREATHMAX_FULLY_RESTED )
|
|
{
|
|
if( fExplainWhyNot )
|
|
{
|
|
swprintf( sString, zMarksMapScreenText[ 4 ], pSoldier->name );
|
|
DoScreenIndependantMessageBox( sString, MSG_BOX_FLAG_OK, NULL );
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
// can sleep
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOLEAN CanCharacterBeAwakened( SOLDIERTYPE *pSoldier, BOOLEAN fExplainWhyNot )
|
|
{
|
|
CHAR16 sString[ 128 ];
|
|
|
|
// if dead tired
|
|
if( ( pSoldier -> bBreathMax <= BREATHMAX_ABSOLUTE_MINIMUM ) && !pSoldier->fMercCollapsedFlag )
|
|
{
|
|
// should be collapsed, then!
|
|
pSoldier->fMercCollapsedFlag = TRUE;
|
|
}
|
|
|
|
// merc collapsed due to being dead tired, you can't wake him up until he recovers substantially
|
|
if ( pSoldier->fMercCollapsedFlag == TRUE )
|
|
{
|
|
if ( fExplainWhyNot )
|
|
{
|
|
swprintf( sString, zMarksMapScreenText[ 6 ], pSoldier->name );
|
|
DoScreenIndependantMessageBox( sString, MSG_BOX_FLAG_OK, NULL );
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
// can be awakened
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOLEAN CanCharacterVehicle( SOLDIERTYPE *pSoldier )
|
|
{
|
|
// can character enter/leave vehicle?
|
|
|
|
if ( !BasicCanCharacterAssignment( pSoldier, TRUE ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// only need to be alive and well to do so right now
|
|
// alive and conscious
|
|
if( pSoldier -> bLife < OKLIFE )
|
|
{
|
|
// dead or unconscious...
|
|
return ( FALSE );
|
|
}
|
|
|
|
// in transit?
|
|
if( IsCharacterInTransit( pSoldier ) == TRUE )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
|
|
// character on the move?
|
|
if( CharacterIsBetweenSectors( pSoldier ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// underground?
|
|
if( pSoldier->bSectorZ != 0 )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// check in helicopter in hostile sector
|
|
if( pSoldier -> bAssignment == VEHICLE )
|
|
{
|
|
if( ( iHelicopterVehicleId != -1 ) && ( pSoldier -> iVehicleId == iHelicopterVehicleId ) )
|
|
{
|
|
// enemies in sector
|
|
if( NumEnemiesInSector( pSoldier -> sSectorX, pSoldier -> sSectorY ) > 0 )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
}
|
|
|
|
// any accessible vehicles in soldier's sector (excludes those between sectors, etc.)
|
|
if( AnyAccessibleVehiclesInSoldiersSector( pSoldier ) == FALSE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// have to be in mapscreen (strictly for visual reasons - we don't want them just vanishing if in tactical)
|
|
if( fInMapMode == FALSE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// if we're in BATTLE in the current sector, disallow
|
|
if ( gTacticalStatus.fEnemyInSector )
|
|
{
|
|
if ( ( pSoldier -> sSectorX == gWorldSectorX ) && ( pSoldier -> sSectorY == gWorldSectorY ) && ( pSoldier -> bSectorZ == gbWorldSectorZ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
INT8 CanCharacterSquad( SOLDIERTYPE *pSoldier, INT8 bSquadValue )
|
|
{
|
|
// can character join this squad?
|
|
INT16 sX, sY, sZ;
|
|
|
|
|
|
Assert( bSquadValue < ON_DUTY );
|
|
|
|
if ( pSoldier->bAssignment == bSquadValue )
|
|
{
|
|
return( CHARACTER_CANT_JOIN_SQUAD_ALREADY_IN_IT );
|
|
}
|
|
|
|
// is the character alive and well?
|
|
if( pSoldier -> bLife < OKLIFE )
|
|
{
|
|
// dead or unconscious...
|
|
return ( CHARACTER_CANT_JOIN_SQUAD );
|
|
}
|
|
|
|
// in transit?
|
|
if( IsCharacterInTransit( pSoldier ) == TRUE )
|
|
{
|
|
return ( CHARACTER_CANT_JOIN_SQUAD );
|
|
}
|
|
|
|
if ( pSoldier->bAssignment == ASSIGNMENT_POW )
|
|
{
|
|
// not allowed to be put on a squad
|
|
return( CHARACTER_CANT_JOIN_SQUAD );
|
|
}
|
|
|
|
/* Driver can't abandon vehicle between sectors - OBSOLETE - nobody is allowed to change squads between sectors now!
|
|
if( pSoldier -> fBetweenSectors )
|
|
{
|
|
if( pSoldier -> bAssignment == VEHICLE )
|
|
{
|
|
if( GetNumberInVehicle( pSoldier -> iVehicleId ) == 1 )
|
|
{
|
|
// can't change, go away
|
|
return( CHARACTER_CANT_JOIN_SQUAD );
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
// see if the squad us at the same x,y,z
|
|
SectorSquadIsIn( bSquadValue, &sX, &sY, &sZ );
|
|
|
|
// check sector x y and z, if not same, cannot join squad
|
|
if( ( sX != pSoldier -> sSectorX ) || ( sY != pSoldier -> sSectorY ) || ( sZ != pSoldier -> bSectorZ ) )
|
|
{
|
|
// is there anyone on this squad?
|
|
if( NumberOfPeopleInSquad( bSquadValue ) > 0 )
|
|
{
|
|
return ( CHARACTER_CANT_JOIN_SQUAD_TOO_FAR );
|
|
}
|
|
}
|
|
|
|
if( IsThisSquadOnTheMove( bSquadValue ) == TRUE )
|
|
{
|
|
// can't join while squad is moving
|
|
return( CHARACTER_CANT_JOIN_SQUAD_SQUAD_MOVING );
|
|
}
|
|
|
|
if ( DoesVehicleExistInSquad( bSquadValue ) )
|
|
{
|
|
// sorry can't change to this squad that way!
|
|
return( CHARACTER_CANT_JOIN_SQUAD_VEHICLE );
|
|
}
|
|
|
|
if ( NumberOfPeopleInSquad( bSquadValue ) >= NUMBER_OF_SOLDIERS_PER_SQUAD )
|
|
{
|
|
return( CHARACTER_CANT_JOIN_SQUAD_FULL );
|
|
}
|
|
|
|
return ( CHARACTER_CAN_JOIN_SQUAD );
|
|
}
|
|
|
|
BOOLEAN IsCharacterInTransit( SOLDIERTYPE *pSoldier )
|
|
{
|
|
|
|
// valid character?
|
|
if( pSoldier == NULL )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
|
|
|
|
// check if character is currently in transit
|
|
if( pSoldier -> bAssignment == IN_TRANSIT )
|
|
{
|
|
// yep
|
|
return ( TRUE );
|
|
}
|
|
|
|
// no
|
|
return ( FALSE );
|
|
}
|
|
|
|
|
|
void UpdateAssignments()
|
|
{
|
|
INT8 sX,sY, bZ;
|
|
|
|
// init sectors with soldiers list
|
|
InitSectorsWithSoldiersList( );
|
|
|
|
// build list
|
|
BuildSectorsWithSoldiersList( );
|
|
|
|
// handle natural healing
|
|
HandleNaturalHealing( );
|
|
|
|
// handle any patients in the hospital
|
|
CheckForAndHandleHospitalPatients( );
|
|
|
|
// see if any grunt or trainer just lost student/teacher
|
|
ReportTrainersTraineesWithoutPartners( );
|
|
|
|
// clear out the update list
|
|
ClearSectorListForCompletedTrainingOfMilitia( );
|
|
|
|
|
|
// rest resting mercs, fatigue active mercs,
|
|
// check for mercs tired enough go to sleep, and wake up well-rested mercs
|
|
HandleRestFatigueAndSleepStatus( );
|
|
|
|
|
|
#ifdef JA2BETAVERSION
|
|
// put this BEFORE training gets handled to avoid detecting an error everytime a sector completes training
|
|
VerifyTownTrainingIsPaidFor();
|
|
#endif
|
|
|
|
// run through sectors and handle each type in sector
|
|
for(sX = 0 ; sX < MAP_WORLD_X; sX++ )
|
|
{
|
|
for( sY =0; sY < MAP_WORLD_X; sY++ )
|
|
{
|
|
for( bZ = 0; bZ < 4; bZ++)
|
|
{
|
|
// handle militia squads movings and creating (not an assignment)
|
|
if(!bZ && sX < 17 && sY < 17 && sX > 0 && sY > 0)UpdateMilitiaSquads( sX, sY );
|
|
// is there anyone in this sector?
|
|
if( fSectorsWithSoldiers[ sX + sY * MAP_WORLD_X ][ bZ ] == TRUE )
|
|
{
|
|
// handle any doctors
|
|
HandleDoctorsInSector( sX, sY, bZ );
|
|
|
|
// handle any repairmen
|
|
HandleRepairmenInSector( sX, sY, bZ );
|
|
|
|
// handle any training
|
|
HandleTrainingInSector( sX, sY, bZ );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// check to see if anyone is done healing?
|
|
UpdatePatientsWhoAreDoneHealing( );
|
|
|
|
|
|
// check if we have anyone who just finished their assignment
|
|
if( gfAddDisplayBoxToWaitingQueue )
|
|
{
|
|
AddDisplayBoxToWaitingQueue( );
|
|
gfAddDisplayBoxToWaitingQueue = FALSE;
|
|
}
|
|
|
|
|
|
HandleContinueOfTownTraining( );
|
|
|
|
// check if anyone is on an assignment where they have nothing to do
|
|
ReEvaluateEveryonesNothingToDo();
|
|
|
|
// update mapscreen
|
|
fCharacterInfoPanelDirty = TRUE;
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
}
|
|
|
|
|
|
|
|
#ifdef JA2BETAVERSION
|
|
void VerifyTownTrainingIsPaidFor( void )
|
|
{
|
|
INT32 iCounter = 0;
|
|
SOLDIERTYPE *pSoldier = NULL;
|
|
|
|
|
|
for( iCounter = 0; iCounter < MAX_CHARACTER_COUNT; iCounter++ )
|
|
{
|
|
// valid character?
|
|
if( gCharactersList[ iCounter ].fValid == FALSE )
|
|
{
|
|
// nope
|
|
continue;
|
|
}
|
|
|
|
pSoldier = &Menptr[ gCharactersList[ iCounter ].usSolID ];
|
|
|
|
if( pSoldier->bActive && ( pSoldier->bAssignment == TRAIN_TOWN ) )
|
|
{
|
|
// make sure that sector is paid up!
|
|
if( SectorInfo[ SECTOR( pSoldier -> sSectorX, pSoldier -> sSectorY ) ].fMilitiaTrainingPaid == FALSE )
|
|
{
|
|
// NOPE! We've got a bug somewhere
|
|
StopTimeCompression();
|
|
|
|
// report the error
|
|
DoScreenIndependantMessageBox( L"ERROR: Unpaid militia training. Describe *how* you're re-assigning mercs, how many/where/when! Send *prior* save!", MSG_BOX_FLAG_OK, NULL );
|
|
|
|
// avoid repeating this
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
UINT8 FindNumberInSectorWithAssignment( INT16 sX, INT16 sY, INT8 bAssignment )
|
|
{
|
|
// run thought list of characters find number with this assignment
|
|
SOLDIERTYPE *pSoldier, *pTeamSoldier;
|
|
INT32 cnt=0;
|
|
INT32 iCounter=0;
|
|
INT8 bNumberOfPeople = 0;
|
|
|
|
// set psoldier as first in merc ptrs
|
|
pSoldier = MercPtrs[0];
|
|
|
|
// go through list of characters, find all who are on this assignment
|
|
for ( pTeamSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ pSoldier -> bTeam ].bLastID; cnt++,pTeamSoldier++)
|
|
{
|
|
if( pTeamSoldier -> bActive )
|
|
{
|
|
if( ( pTeamSoldier -> sSectorX == sX ) && ( pTeamSoldier -> sSectorY == sY ) &&( pTeamSoldier -> bAssignment == bAssignment ) )
|
|
{
|
|
// increment number of people who are on this assignment
|
|
if(pTeamSoldier -> bActive)
|
|
bNumberOfPeople++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return( bNumberOfPeople );
|
|
}
|
|
|
|
UINT8 GetNumberThatCanBeDoctored( SOLDIERTYPE *pDoctor, BOOLEAN fThisHour, BOOLEAN fSkipKitCheck, BOOLEAN fSkipSkillCheck )
|
|
{
|
|
int cnt;
|
|
SOLDIERTYPE *pSoldier = MercPtrs[0], *pTeamSoldier = NULL;
|
|
UINT8 ubNumberOfPeople = 0;
|
|
|
|
|
|
// go through list of characters, find all who are patients/doctors healable by this doctor
|
|
for ( cnt = 0, pTeamSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ pSoldier -> bTeam ].bLastID; cnt++,pTeamSoldier++)
|
|
{
|
|
if( pTeamSoldier -> bActive )
|
|
{
|
|
if( CanSoldierBeHealedByDoctor( pTeamSoldier, pDoctor, FALSE, fThisHour, fSkipKitCheck, fSkipSkillCheck ) == TRUE )
|
|
{
|
|
// increment number of doctorable patients/doctors
|
|
ubNumberOfPeople++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return( ubNumberOfPeople );
|
|
}
|
|
|
|
|
|
SOLDIERTYPE *AnyDoctorWhoCanHealThisPatient( SOLDIERTYPE *pPatient, BOOLEAN fThisHour )
|
|
{
|
|
int cnt;
|
|
SOLDIERTYPE *pSoldier = MercPtrs[0], *pTeamSoldier = NULL;
|
|
|
|
|
|
// go through list of characters, find all who are patients/doctors healable by this doctor
|
|
for ( cnt = 0, pTeamSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ pSoldier -> bTeam ].bLastID; cnt++,pTeamSoldier++)
|
|
{
|
|
// doctor?
|
|
if( ( pTeamSoldier -> bActive ) && ( pTeamSoldier->bAssignment == DOCTOR ) )
|
|
{
|
|
if( CanSoldierBeHealedByDoctor( pPatient, pTeamSoldier, FALSE, fThisHour, FALSE, FALSE ) == TRUE )
|
|
{
|
|
// found one
|
|
return( pTeamSoldier );
|
|
}
|
|
}
|
|
}
|
|
|
|
// there aren't any doctors, or the ones there can't do the job
|
|
return( NULL );
|
|
}
|
|
|
|
|
|
UINT16 CalculateHealingPointsForDoctor(SOLDIERTYPE *pDoctor, UINT16 *pusMaxPts, BOOLEAN fMakeSureKitIsInHand )
|
|
{
|
|
UINT16 usHealPts = 0;
|
|
UINT16 usKitPts = 0;
|
|
INT8 bMedFactor;
|
|
|
|
// make sure he has a medkit in his hand, and preferably make it a medical bag, not a first aid kit
|
|
if( fMakeSureKitIsInHand )
|
|
{
|
|
if ( !MakeSureMedKitIsInHand( pDoctor ) )
|
|
{
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
// calculate effective doctoring rate (adjusted for drugs, alcohol, etc.)
|
|
usHealPts = ( EffectiveMedical( pDoctor ) * (( EffectiveDexterity( pDoctor ) + EffectiveWisdom( pDoctor ) ) / 2) * (100 + ( 5 * EffectiveExpLevel( pDoctor) ) ) ) / gGameExternalOptions.ubDoctoringRateDivisor;
|
|
|
|
// calculate normal doctoring rate - what it would be if his stats were "normal" (ignoring drugs, fatigue, equipment condition)
|
|
// and equipment was not a hindrance
|
|
*pusMaxPts = ( pDoctor -> bMedical * (( pDoctor -> bDexterity + pDoctor -> bWisdom ) / 2 ) * (100 + ( 5 * pDoctor->bExpLevel) ) ) / gGameExternalOptions.ubDoctoringRateDivisor;
|
|
|
|
// adjust for fatigue
|
|
ReducePointsForFatigue( pDoctor, &usHealPts );
|
|
|
|
// count how much medical supplies we have
|
|
usKitPts = 100 * TotalMedicalKitPoints( pDoctor );
|
|
|
|
// if we don't have enough medical KIT points, reduce what we can heal
|
|
if (usKitPts < usHealPts)
|
|
{
|
|
usHealPts = usKitPts;
|
|
}
|
|
|
|
// get the type of medkit being used
|
|
bMedFactor = IsMedicalKitItem( &( pDoctor -> inv[ HANDPOS ] ) );
|
|
|
|
if( bMedFactor != 0 )
|
|
{
|
|
// no med kit left?
|
|
// if he's working with only a first aid kit, the doctoring rate is halved!
|
|
// for simplicity, we're ignoring the situation where a nearly empty medical bag in is hand and the rest are just first aid kits
|
|
usHealPts /= bMedFactor;
|
|
}
|
|
else
|
|
{
|
|
usHealPts = 0;
|
|
}
|
|
|
|
|
|
// return healing pts value
|
|
return( usHealPts );
|
|
}
|
|
|
|
|
|
UINT8 CalculateRepairPointsForRepairman(SOLDIERTYPE *pSoldier, UINT16 *pusMaxPts, BOOLEAN fMakeSureKitIsInHand )
|
|
{
|
|
UINT16 usRepairPts;
|
|
UINT16 usKitPts;
|
|
UINT8 ubKitEffectiveness;
|
|
|
|
// make sure toolkit in hand?
|
|
if( fMakeSureKitIsInHand )
|
|
{
|
|
MakeSureToolKitIsInHand( pSoldier );
|
|
}
|
|
|
|
// can't repair at all without a toolkit
|
|
if (!Item[pSoldier -> inv[HANDPOS].usItem].toolkit )
|
|
{
|
|
*pusMaxPts = 0;
|
|
return(0);
|
|
}
|
|
|
|
// calculate effective repair rate (adjusted for drugs, alcohol, etc.)
|
|
usRepairPts = (EffectiveMechanical( pSoldier ) * EffectiveDexterity( pSoldier ) * (100 + ( 5 * EffectiveExpLevel( pSoldier) ) ) ) / ( gGameExternalOptions.ubRepairRateDivisor * gGameExternalOptions.ubAssignmentUnitsPerDay );
|
|
|
|
// calculate normal repair rate - what it would be if his stats were "normal" (ignoring drugs, fatigue, equipment condition)
|
|
// and equipment was not a hindrance
|
|
*pusMaxPts = ( pSoldier -> bMechanical * pSoldier -> bDexterity * (100 + ( 5 * pSoldier->bExpLevel) ) ) / ( gGameExternalOptions.ubRepairRateDivisor * gGameExternalOptions.ubAssignmentUnitsPerDay );
|
|
|
|
|
|
// adjust for fatigue
|
|
ReducePointsForFatigue( pSoldier, &usRepairPts );
|
|
|
|
|
|
// figure out what shape his "equipment" is in ("coming" in JA3: Viagra - improves the "shape" your "equipment" is in)
|
|
usKitPts = ToolKitPoints( pSoldier );
|
|
|
|
// if kit(s) in extremely bad shape
|
|
if ( usKitPts < 25 )
|
|
{
|
|
ubKitEffectiveness = 50;
|
|
}
|
|
// if kit(s) in pretty bad shape
|
|
else if ( usKitPts < 50 )
|
|
{
|
|
ubKitEffectiveness = 75;
|
|
}
|
|
else
|
|
{
|
|
ubKitEffectiveness = 100;
|
|
}
|
|
|
|
// adjust for equipment
|
|
usRepairPts = (usRepairPts * ubKitEffectiveness) / 100;
|
|
|
|
|
|
// return current repair pts
|
|
return(( UINT8 )usRepairPts);
|
|
}
|
|
|
|
|
|
UINT16 ToolKitPoints(SOLDIERTYPE *pSoldier)
|
|
{
|
|
UINT16 usKitpts=0;
|
|
UINT8 ubPocket;
|
|
|
|
// add up kit points
|
|
for (ubPocket=HANDPOS; ubPocket <= SMALLPOCK8POS; ubPocket++)
|
|
{
|
|
if( Item[pSoldier -> inv[ ubPocket ].usItem].toolkit )
|
|
{
|
|
usKitpts += TotalPoints( &( pSoldier -> inv[ ubPocket ] ) );
|
|
}
|
|
}
|
|
|
|
return( usKitpts );
|
|
}
|
|
|
|
|
|
UINT16 TotalMedicalKitPoints(SOLDIERTYPE *pSoldier)
|
|
{
|
|
UINT8 ubPocket;
|
|
UINT16 usKitpts=0;
|
|
|
|
// add up kit points of all medkits
|
|
for (ubPocket = HANDPOS; ubPocket <= SMALLPOCK8POS; ubPocket++)
|
|
{
|
|
// NOTE: Here, we don't care whether these are MEDICAL BAGS or FIRST AID KITS!
|
|
if ( IsMedicalKitItem( &( pSoldier -> inv[ ubPocket ] ) ) )
|
|
{
|
|
usKitpts += TotalPoints( &( pSoldier -> inv[ ubPocket ] ) );
|
|
}
|
|
}
|
|
|
|
return( usKitpts );
|
|
}
|
|
|
|
|
|
void HandleDoctorsInSector( INT16 sX, INT16 sY, INT8 bZ )
|
|
{
|
|
SOLDIERTYPE *pSoldier, *pTeamSoldier;
|
|
INT32 cnt=0;
|
|
INT32 iCounter=0;
|
|
|
|
// set psoldier as first in merc ptrs
|
|
pSoldier = MercPtrs[0];
|
|
|
|
// will handle doctor/patient relationship in sector
|
|
|
|
// go through list of characters, find all doctors in sector
|
|
for ( pTeamSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ pSoldier -> bTeam ].bLastID; cnt++,pTeamSoldier++)
|
|
{
|
|
if(pTeamSoldier -> bActive)
|
|
{
|
|
if( ( pTeamSoldier -> sSectorX == sX ) && ( pTeamSoldier -> sSectorY == sY ) && ( pTeamSoldier -> bSectorZ == bZ ) )
|
|
{
|
|
if ( ( pTeamSoldier -> bAssignment == DOCTOR ) && ( pTeamSoldier->fMercAsleep == FALSE ) )
|
|
{
|
|
MakeSureMedKitIsInHand( pTeamSoldier );
|
|
// character is in sector, check if can doctor, if so...heal people
|
|
if ( CanCharacterDoctor( pTeamSoldier ) && EnoughTimeOnAssignment( pTeamSoldier ) )
|
|
{
|
|
HealCharacters( pTeamSoldier, sX, sY, bZ );
|
|
}
|
|
}
|
|
/*
|
|
if( ( pTeamSoldier -> bAssignment == DOCTOR ) && ( pTeamSoldier->fMercAsleep == FALSE ) )
|
|
{
|
|
MakeSureMedKitIsInHand( pTeamSoldier );
|
|
}
|
|
|
|
// character is in sector, check if can doctor, if so...heal people
|
|
if( CanCharacterDoctor( pTeamSoldier ) && ( pTeamSoldier -> bAssignment == DOCTOR ) && ( pTeamSoldier->fMercAsleep == FALSE ) && EnoughTimeOnAssignment( pTeamSoldier ) )
|
|
{
|
|
HealCharacters( pTeamSoldier, sX, sY, bZ );
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
}
|
|
|
|
// total healing pts for this sector, now heal people
|
|
return;
|
|
}
|
|
|
|
|
|
void UpdatePatientsWhoAreDoneHealing( void )
|
|
{
|
|
INT32 cnt = 0;
|
|
SOLDIERTYPE *pSoldier = NULL, *pTeamSoldier = NULL;
|
|
|
|
// set as first in list
|
|
pSoldier = MercPtrs[0];
|
|
|
|
for ( pTeamSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ pSoldier -> bTeam ].bLastID; cnt++,pTeamSoldier++)
|
|
{
|
|
// active soldier?
|
|
if( pTeamSoldier->bActive )
|
|
{
|
|
// patient who doesn't need healing
|
|
if( ( pTeamSoldier->bAssignment == PATIENT ) &&( pTeamSoldier->bLife == pTeamSoldier->bLifeMax ) )
|
|
{
|
|
AssignmentDone( pTeamSoldier, TRUE, TRUE );
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
void HealCharacters( SOLDIERTYPE *pDoctor, INT16 sX, INT16 sY, INT8 bZ )
|
|
{
|
|
// heal all patients in this sector
|
|
UINT16 usAvailableHealingPts = 0;
|
|
UINT16 usRemainingHealingPts = 0;
|
|
UINT16 usUsedHealingPts = 0;
|
|
UINT16 usEvenHealingAmount = 0;
|
|
UINT16 usMax =0;
|
|
UINT8 ubTotalNumberOfPatients = 0;
|
|
SOLDIERTYPE *pSoldier = MercPtrs[0], *pTeamSoldier = NULL, *pWorstHurtSoldier = NULL;
|
|
INT32 cnt = 0;
|
|
UINT16 usOldLeftOvers = 0;
|
|
|
|
|
|
// now find number of healable mercs in sector that are wounded
|
|
ubTotalNumberOfPatients = GetNumberThatCanBeDoctored( pDoctor, HEALABLE_THIS_HOUR, FALSE, FALSE );
|
|
|
|
// if there is anybody who can be healed right now
|
|
if( ubTotalNumberOfPatients > 0 )
|
|
{
|
|
// get available healing pts
|
|
usAvailableHealingPts = CalculateHealingPointsForDoctor( pDoctor, &usMax, TRUE );
|
|
usRemainingHealingPts = usAvailableHealingPts;
|
|
|
|
// find how many healing points can be evenly distributed to each wounded, healable merc
|
|
usEvenHealingAmount = usRemainingHealingPts / ubTotalNumberOfPatients;
|
|
|
|
|
|
// heal each of the healable mercs by this equal amount
|
|
for ( cnt = 0, pTeamSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ pSoldier -> bTeam ].bLastID; cnt++,pTeamSoldier++)
|
|
{
|
|
if( pTeamSoldier -> bActive )
|
|
{
|
|
if( CanSoldierBeHealedByDoctor( pTeamSoldier, pDoctor, FALSE, HEALABLE_THIS_HOUR, FALSE, FALSE ) == TRUE )
|
|
{
|
|
// can heal and is patient, heal them
|
|
usRemainingHealingPts -= HealPatient( pTeamSoldier, pDoctor, usEvenHealingAmount );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// if we have any remaining pts
|
|
if ( usRemainingHealingPts > 0)
|
|
{
|
|
// split those up based on need - lowest life patients get them first
|
|
do
|
|
{
|
|
// find the worst hurt patient
|
|
pWorstHurtSoldier = NULL;
|
|
|
|
for ( cnt = 0, pTeamSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ pSoldier -> bTeam ].bLastID; cnt++,pTeamSoldier++)
|
|
{
|
|
if( pTeamSoldier -> bActive )
|
|
{
|
|
if( CanSoldierBeHealedByDoctor( pTeamSoldier, pDoctor, FALSE, HEALABLE_THIS_HOUR, FALSE, FALSE ) == TRUE )
|
|
{
|
|
if( pWorstHurtSoldier == NULL )
|
|
{
|
|
pWorstHurtSoldier = pTeamSoldier;
|
|
}
|
|
else
|
|
{
|
|
// check to see if this guy is hurt worse than anyone previous?
|
|
if( pTeamSoldier -> bLife < pWorstHurtSoldier -> bLife )
|
|
{
|
|
// he is now the worse hurt guy
|
|
pWorstHurtSoldier = pTeamSoldier;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if( pWorstHurtSoldier != NULL )
|
|
{
|
|
// heal the worst hurt guy
|
|
usOldLeftOvers = usRemainingHealingPts;
|
|
usRemainingHealingPts -= HealPatient( pWorstHurtSoldier, pDoctor, usRemainingHealingPts );
|
|
|
|
// couldn't expend any pts, leave
|
|
if( usRemainingHealingPts == usOldLeftOvers )
|
|
{
|
|
usRemainingHealingPts = 0;
|
|
}
|
|
}
|
|
} while( ( usRemainingHealingPts > 0 ) && ( pWorstHurtSoldier != NULL ) );
|
|
}
|
|
|
|
|
|
usUsedHealingPts = usAvailableHealingPts - usRemainingHealingPts;
|
|
|
|
// increment skills based on healing pts used
|
|
StatChange(pDoctor, MEDICALAMT, (UINT16) (usUsedHealingPts / 100), FALSE);
|
|
StatChange(pDoctor, DEXTAMT, (UINT16) (usUsedHealingPts / 100), FALSE);
|
|
StatChange(pDoctor, WISDOMAMT, (UINT16) (usUsedHealingPts / 100), FALSE);
|
|
}
|
|
|
|
|
|
// if there's nobody else here who can EVER be helped by this doctor (regardless of whether they got healing this hour)
|
|
if( GetNumberThatCanBeDoctored( pDoctor, HEALABLE_EVER, FALSE, FALSE ) == 0 )
|
|
{
|
|
// then this doctor has done all that he can do, but let's find out why and tell player the reason
|
|
|
|
// try again, but skip the med kit check!
|
|
if( GetNumberThatCanBeDoctored( pDoctor, HEALABLE_EVER, TRUE, FALSE ) > 0 )
|
|
{
|
|
// he could doctor somebody, but can't because he doesn't have a med kit!
|
|
AssignmentAborted( pDoctor, NO_MORE_MED_KITS );
|
|
}
|
|
// try again, but skip the skill check!
|
|
else if( GetNumberThatCanBeDoctored( pDoctor, HEALABLE_EVER, FALSE, TRUE ) > 0 )
|
|
{
|
|
// he could doctor somebody, but can't because he doesn't have enough skill!
|
|
AssignmentAborted( pDoctor, INSUF_DOCTOR_SKILL );
|
|
}
|
|
else
|
|
{
|
|
// all patients should now be healed - truly DONE!
|
|
AssignmentDone( pDoctor, TRUE, TRUE );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* Assignment distance limits removed. Sep/11/98. ARM
|
|
BOOLEAN IsSoldierCloseEnoughToADoctor( SOLDIERTYPE *pPatient )
|
|
{
|
|
// run through all doctors in sector, if it is loaded
|
|
// if no - one is close enough and there is a doctor assigned in sector, inform player
|
|
BOOLEAN fDoctorInSector = FALSE;
|
|
BOOLEAN fDoctorCloseEnough = FALSE;
|
|
SOLDIERTYPE *pSoldier = NULL;
|
|
INT32 iCounter = 0;
|
|
CHAR16 sString[ 128 ];
|
|
|
|
if( ( pPatient->sSectorX != gWorldSectorX ) || ( pPatient->sSectorY != gWorldSectorY ) || ( pPatient->bSectorZ != gbWorldSectorZ ) )
|
|
{
|
|
// not currently loaded
|
|
return( TRUE );
|
|
}
|
|
|
|
for( iCounter = 0; iCounter < MAX_CHARACTER_COUNT; iCounter++ )
|
|
{
|
|
pSoldier = &Menptr[ iCounter ];
|
|
|
|
if( pSoldier->bActive )
|
|
{
|
|
|
|
// are they two of these guys in the same sector?
|
|
if( ( pSoldier->sSectorX == pPatient->sSectorX ) && ( pSoldier->sSectorY == pPatient->sSectorY ) && ( pSoldier->bSectorZ == pPatient->bSectorZ ) )
|
|
{
|
|
|
|
// is a doctor
|
|
if( pSoldier->bAssignment == DOCTOR )
|
|
{
|
|
|
|
// the doctor is in the house
|
|
fDoctorInSector = TRUE;
|
|
|
|
// can this patient be healed by the doctor?
|
|
if( CanSoldierBeHealedByDoctor( pPatient, pSoldier, TRUE, HEALABLE_EVER, FALSE, FALSE ) == TRUE )
|
|
{
|
|
// yep
|
|
fDoctorCloseEnough = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// there are doctors here but noone can heal this guy
|
|
if( ( fDoctorInSector ) && ( fDoctorCloseEnough == FALSE ) )
|
|
{
|
|
swprintf( sString, pDoctorWarningString[ 0 ] , pPatient->name );
|
|
DoScreenIndependantMessageBox( sString, MSG_BOX_FLAG_OK, NULL);
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
*/
|
|
|
|
|
|
BOOLEAN CanSoldierBeHealedByDoctor( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pDoctor, BOOLEAN fIgnoreAssignment, BOOLEAN fThisHour, BOOLEAN fSkipKitCheck, BOOLEAN fSkipSkillCheck )
|
|
{
|
|
INT16 sDistance = 0;
|
|
|
|
// must be an active guy
|
|
if (pSoldier -> bActive == FALSE)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
// must be a patient or a doctor
|
|
if( ( pSoldier -> bAssignment != PATIENT ) && ( pSoldier -> bAssignment != DOCTOR ) && ( fIgnoreAssignment == FALSE ) )
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
// if dead or unhurt
|
|
if ( (pSoldier -> bLife == 0) || (pSoldier -> bLife == pSoldier -> bLifeMax ) )
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
// if we care about how long it's been, and he hasn't been on a healable assignment long enough
|
|
if( fThisHour && ( EnoughTimeOnAssignment( pSoldier ) == FALSE ) && ( fIgnoreAssignment == FALSE ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// must be in the same sector
|
|
if( ( pSoldier -> sSectorX != pDoctor -> sSectorX ) || ( pSoldier -> sSectorY != pDoctor -> sSectorY ) || ( pSoldier -> bSectorZ != pDoctor -> bSectorZ ) )
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
// can't be between sectors (possible to get here if ignoring assignment)
|
|
if ( pSoldier->fBetweenSectors )
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
// if doctor's skill is unsufficient to save this guy
|
|
if ( !fSkipSkillCheck && ( pDoctor -> bMedical < GetMinHealingSkillNeeded( pSoldier ) ) )
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
if ( !fSkipKitCheck && ( FindMedKit( pDoctor ) == NO_SLOT ) )
|
|
{
|
|
// no medical kit to use!
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
UINT8 GetMinHealingSkillNeeded( SOLDIERTYPE *pPatient )
|
|
{
|
|
// get the minimum skill to handle a character under OKLIFE
|
|
|
|
if( pPatient -> bLife < OKLIFE )
|
|
{
|
|
// less than ok life, return skill needed
|
|
return( gGameExternalOptions.ubBaseMedicalSkillToDealWithEmergency + ( gGameExternalOptions.ubMultiplierForDifferenceInLifeValueForEmergency * ( OKLIFE - pPatient -> bLife ) ) );
|
|
}
|
|
else
|
|
{
|
|
// only need some skill
|
|
return ( 1 );
|
|
}
|
|
}
|
|
|
|
|
|
UINT16 HealPatient( SOLDIERTYPE *pPatient, SOLDIERTYPE * pDoctor, UINT16 usHundredthsHealed )
|
|
{
|
|
// heal patient and return the number of healing pts used
|
|
UINT16 usHealingPtsLeft;
|
|
UINT16 usTotalFullPtsUsed = 0;
|
|
UINT16 usTotalHundredthsUsed = 0;
|
|
INT8 bPointsToUse = 0;
|
|
INT8 bPointsUsed = 0;
|
|
INT8 bPointsHealed = 0;
|
|
INT8 bPocket = 0;
|
|
INT8 bMedFactor;
|
|
// INT8 bOldPatientLife = pPatient -> bLife;
|
|
|
|
|
|
pPatient->sFractLife += usHundredthsHealed;
|
|
usTotalHundredthsUsed = usHundredthsHealed; // we'll subtract any unused amount later if we become fully healed...
|
|
|
|
// convert fractions into full points
|
|
usHealingPtsLeft = pPatient->sFractLife / 100;
|
|
pPatient->sFractLife %= 100;
|
|
|
|
// if we haven't accumulated any full points yet
|
|
if (usHealingPtsLeft == 0)
|
|
{
|
|
return( usTotalHundredthsUsed );
|
|
}
|
|
|
|
|
|
/* ARM - Eliminated. We now have other methods of properly using doctors to auto-bandage bleeding,
|
|
// using the correct kits points instead of this 1 pt. "special"
|
|
|
|
// stop all bleeding of patient..for 1 pt (it's fast). But still use up normal kit pts to do it
|
|
if (pPatient -> bBleeding > 0)
|
|
{
|
|
usHealingPtsLeft--;
|
|
usTotalFullPtsUsed++;
|
|
|
|
// get points needed to heal him to dress bleeding wounds
|
|
bPointsToUse = pPatient -> bBleeding;
|
|
|
|
// go through doctor's pockets and heal, starting at with his in-hand item
|
|
// the healing pts are based on what type of medkit is in his hand, so we HAVE to start there first!
|
|
for (bPocket = HANDPOS; bPocket <= SMALLPOCK8POS; bPocket++)
|
|
{
|
|
bMedFactor = IsMedicalKitItem( &( pDoctor -> inv[ bPocket ] ) );
|
|
if ( bMedFactor > 0 )
|
|
{
|
|
// ok, we have med kit in this pocket, use it
|
|
|
|
// The medFactor here doesn't affect how much the doctor can heal (that's already factored into lower healing pts)
|
|
// but it does effect how fast the medkit is used up! First aid kits disappear at double their doctoring rate!
|
|
bPointsUsed = (INT8) UseKitPoints( &( pDoctor -> inv[ bPocket ] ), (UINT16) (bPointsToUse * bMedFactor), pDoctor );
|
|
bPointsHealed = bPointsUsed / bMedFactor;
|
|
|
|
bPointsToUse -= bPointsHealed;
|
|
pPatient -> bBleeding -= bPointsHealed;
|
|
|
|
// if we're done all we're supposed to, or the guy's no longer bleeding, bail
|
|
if ( ( bPointsToUse <= 0 ) || ( pPatient -> bBleeding == 0 ) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
// if below ok life, heal these first at double point cost
|
|
if( pPatient -> bLife < OKLIFE )
|
|
{
|
|
// get points needed to heal him to OKLIFE
|
|
bPointsToUse = gGameExternalOptions.ubPointCostPerHealthBelowOkLife * ( OKLIFE - pPatient -> bLife );
|
|
|
|
// if he needs more than we have, reduce to that
|
|
if( bPointsToUse > usHealingPtsLeft )
|
|
{
|
|
bPointsToUse = ( INT8 )usHealingPtsLeft;
|
|
}
|
|
|
|
// go through doctor's pockets and heal, starting at with his in-hand item
|
|
// the healing pts are based on what type of medkit is in his hand, so we HAVE to start there first!
|
|
for (bPocket = HANDPOS; bPocket <= SMALLPOCK8POS; bPocket++)
|
|
{
|
|
bMedFactor = IsMedicalKitItem( &( pDoctor -> inv[ bPocket ] ) );
|
|
if ( bMedFactor > 0 )
|
|
{
|
|
// ok, we have med kit in this pocket, use it
|
|
|
|
// The medFactor here doesn't affect how much the doctor can heal (that's already factored into lower healing pts)
|
|
// but it does effect how fast the medkit is used up! First aid kits disappear at double their doctoring rate!
|
|
bPointsUsed = (INT8) UseKitPoints( &( pDoctor -> inv[ bPocket ] ), (UINT16) (bPointsToUse * bMedFactor), pDoctor );
|
|
bPointsHealed = bPointsUsed / bMedFactor;
|
|
|
|
bPointsToUse -= bPointsHealed;
|
|
usHealingPtsLeft -= bPointsHealed;
|
|
usTotalFullPtsUsed += bPointsHealed;
|
|
|
|
// heal person the amount / POINT_COST_PER_HEALTH_BELOW_OKLIFE
|
|
pPatient -> bLife += (bPointsHealed / gGameExternalOptions.ubPointCostPerHealthBelowOkLife);
|
|
|
|
// if we're done all we're supposed to, or the guy's at OKLIFE, bail
|
|
if ( ( bPointsToUse <= 0 ) || ( pPatient -> bLife >= OKLIFE ) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// critical conditions handled, now apply normal healing
|
|
|
|
if (pPatient -> bLife < pPatient -> bLifeMax)
|
|
{
|
|
bPointsToUse = ( pPatient -> bLifeMax - pPatient -> bLife );
|
|
|
|
// if guy is hurt more than points we have...heal only what we have
|
|
if( bPointsToUse > usHealingPtsLeft )
|
|
{
|
|
bPointsToUse = ( INT8 )usHealingPtsLeft;
|
|
}
|
|
|
|
// go through doctor's pockets and heal, starting at with his in-hand item
|
|
// the healing pts are based on what type of medkit is in his hand, so we HAVE to start there first!
|
|
for (bPocket = HANDPOS; bPocket <= SMALLPOCK8POS; bPocket++)
|
|
{
|
|
bMedFactor = IsMedicalKitItem( &( pDoctor -> inv[ bPocket ] ) );
|
|
if ( bMedFactor > 0 )
|
|
{
|
|
// ok, we have med kit in this pocket, use it (use only half if it's worth double)
|
|
|
|
// The medFactor here doesn't affect how much the doctor can heal (that's already factored into lower healing pts)
|
|
// but it does effect how fast the medkit is used up! First aid kits disappear at double their doctoring rate!
|
|
bPointsUsed = (INT8) UseKitPoints( &( pDoctor -> inv[ bPocket ] ), (UINT16) (bPointsToUse * bMedFactor), pDoctor );
|
|
bPointsHealed = bPointsUsed / bMedFactor;
|
|
|
|
bPointsToUse -= bPointsHealed;
|
|
usHealingPtsLeft -= bPointsHealed;
|
|
usTotalFullPtsUsed += bPointsHealed;
|
|
|
|
pPatient -> bLife += bPointsHealed;
|
|
|
|
// if we're done all we're supposed to, or the guy's fully healed, bail
|
|
if ( ( bPointsToUse <= 0 ) || ( pPatient -> bLife == pPatient -> bLifeMax ) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// if this patient is fully healed
|
|
if( pPatient->bLife == pPatient->bLifeMax )
|
|
{
|
|
// don't count unused full healing points as being used
|
|
usTotalHundredthsUsed -= (100 * usHealingPtsLeft);
|
|
|
|
// wipe out fractions of extra life, and DON'T count them as used
|
|
usTotalHundredthsUsed -= pPatient->sFractLife;
|
|
pPatient->sFractLife = 0;
|
|
|
|
/* ARM Removed. This is duplicating the check in UpdatePatientsWhoAreDoneHealing(), guy would show up twice!
|
|
// if it isn't the doctor himself)
|
|
if( ( pPatient != pDoctor )
|
|
{
|
|
AssignmentDone( pPatient, TRUE, TRUE );
|
|
}
|
|
*/
|
|
}
|
|
|
|
return ( usTotalHundredthsUsed );
|
|
}
|
|
|
|
|
|
void CheckForAndHandleHospitalPatients( void )
|
|
{
|
|
SOLDIERTYPE *pSoldier, *pTeamSoldier;
|
|
INT32 cnt=0;
|
|
|
|
if( fSectorsWithSoldiers[ HOSPITAL_SECTOR_X + HOSPITAL_SECTOR_Y * MAP_WORLD_X ][ 0 ] == FALSE )
|
|
{
|
|
// nobody in the hospital sector... leave
|
|
return;
|
|
}
|
|
|
|
// set pSoldier as first in merc ptrs
|
|
pSoldier = MercPtrs[0];
|
|
|
|
// go through list of characters, find all who are on this assignment
|
|
for ( pTeamSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ pSoldier -> bTeam ].bLastID; cnt++,pTeamSoldier++)
|
|
{
|
|
if( pTeamSoldier -> bActive )
|
|
{
|
|
if ( pTeamSoldier -> bAssignment == ASSIGNMENT_HOSPITAL )
|
|
{
|
|
if ( ( pTeamSoldier -> sSectorX == HOSPITAL_SECTOR_X ) && ( pTeamSoldier -> sSectorY == HOSPITAL_SECTOR_Y ) && ( pTeamSoldier -> bSectorZ == 0 ) )
|
|
{
|
|
// heal this character
|
|
HealHospitalPatient( pTeamSoldier, gGameExternalOptions.ubHospitalHealingRate );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void HealHospitalPatient( SOLDIERTYPE *pPatient, UINT16 usHealingPtsLeft )
|
|
{
|
|
INT8 bPointsToUse;
|
|
|
|
if (usHealingPtsLeft <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
/* Stopping hospital patients' bleeding must be handled immediately, not during a regular hourly check
|
|
// stop all bleeding of patient..for 1 pt.
|
|
if (pPatient -> bBleeding > 0)
|
|
{
|
|
usHealingPtsLeft--;
|
|
pPatient -> bBleeding = 0;
|
|
}
|
|
*/
|
|
|
|
// if below ok life, heal these first at double cost
|
|
if( pPatient -> bLife < OKLIFE )
|
|
{
|
|
// get points needed to heal him to OKLIFE
|
|
bPointsToUse = gGameExternalOptions.ubPointCostPerHealthBelowOkLife * ( OKLIFE - pPatient -> bLife );
|
|
|
|
// if he needs more than we have, reduce to that
|
|
if( bPointsToUse > usHealingPtsLeft )
|
|
{
|
|
bPointsToUse = ( INT8 )usHealingPtsLeft;
|
|
}
|
|
|
|
usHealingPtsLeft -= bPointsToUse;
|
|
|
|
// heal person the amount / POINT_COST_PER_HEALTH_BELOW_OKLIFE
|
|
pPatient -> bLife += ( bPointsToUse / gGameExternalOptions.ubPointCostPerHealthBelowOkLife );
|
|
}
|
|
|
|
// critical condition handled, now solve normal healing
|
|
|
|
if ( pPatient -> bLife < pPatient -> bLifeMax )
|
|
{
|
|
bPointsToUse = ( pPatient -> bLifeMax - pPatient -> bLife );
|
|
|
|
// if guy is hurt more than points we have...heal only what we have
|
|
if( bPointsToUse > usHealingPtsLeft )
|
|
{
|
|
bPointsToUse = ( INT8 )usHealingPtsLeft;
|
|
}
|
|
|
|
usHealingPtsLeft -= bPointsToUse;
|
|
|
|
// heal person the amount
|
|
pPatient -> bLife += bPointsToUse;
|
|
}
|
|
|
|
// if this patient is fully healed
|
|
if ( pPatient -> bLife == pPatient -> bLifeMax )
|
|
{
|
|
AssignmentDone( pPatient, TRUE, TRUE );
|
|
}
|
|
}
|
|
|
|
|
|
void HandleRepairmenInSector( INT16 sX, INT16 sY, INT8 bZ )
|
|
{
|
|
SOLDIERTYPE *pSoldier, *pTeamSoldier;
|
|
INT32 cnt=0;
|
|
INT32 iCounter=0;
|
|
|
|
// set psoldier as first in merc ptrs
|
|
pSoldier = MercPtrs[0];
|
|
|
|
// will handle doctor/patient relationship in sector
|
|
|
|
// go through list of characters, find all doctors in sector
|
|
for ( pTeamSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ pSoldier -> bTeam ].bLastID; cnt++,pTeamSoldier++)
|
|
{
|
|
if( pTeamSoldier -> bActive )
|
|
{
|
|
if( ( pTeamSoldier -> sSectorX == sX ) && ( pTeamSoldier -> sSectorY == sY ) && ( pTeamSoldier -> bSectorZ == bZ) )
|
|
{
|
|
if ( ( pTeamSoldier -> bAssignment == REPAIR ) && ( pTeamSoldier->fMercAsleep == FALSE ) )
|
|
{
|
|
MakeSureToolKitIsInHand( pTeamSoldier );
|
|
// character is in sector, check if can repair
|
|
if ( CanCharacterRepair( pTeamSoldier ) && ( EnoughTimeOnAssignment( pTeamSoldier ) ) )
|
|
{
|
|
HandleRepairBySoldier( pTeamSoldier );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/* No point in allowing SAM site repair any more. Jan/13/99. ARM
|
|
INT8 HandleRepairOfSAMSite( SOLDIERTYPE *pSoldier, INT8 bPointsAvailable, BOOLEAN * pfNothingLeftToRepair )
|
|
{
|
|
INT8 bPtsUsed = 0;
|
|
INT16 sStrategicSector = 0;
|
|
|
|
if( IsThisSectorASAMSector( pSoldier -> sSectorX, pSoldier -> sSectorY, pSoldier -> bSectorZ ) == FALSE )
|
|
{
|
|
return( bPtsUsed );
|
|
}
|
|
else if( ( pSoldier -> sSectorX == gWorldSectorX ) && ( pSoldier -> bSectorZ == gbWorldSectorZ )&&( pSoldier -> sSectorY == gWorldSectorY ) )
|
|
{
|
|
if( CanSoldierRepairSAM( pSoldier, bPointsAvailable ) == FALSE )
|
|
{
|
|
return( bPtsUsed );
|
|
}
|
|
}
|
|
|
|
// repair the SAM
|
|
|
|
sStrategicSector = CALCULATE_STRATEGIC_INDEX( pSoldier->sSectorX, pSoldier->sSectorY );
|
|
|
|
// do we have more than enough?
|
|
if( 100 - StrategicMap[ sStrategicSector ].bSAMCondition >= bPointsAvailable / SAM_SITE_REPAIR_DIVISOR )
|
|
{
|
|
// no, use up all we have
|
|
StrategicMap[ sStrategicSector ].bSAMCondition += bPointsAvailable / SAM_SITE_REPAIR_DIVISOR;
|
|
bPtsUsed = bPointsAvailable - ( bPointsAvailable % SAM_SITE_REPAIR_DIVISOR );
|
|
|
|
// SAM site may have been put back into working order...
|
|
UpdateAirspaceControl( );
|
|
}
|
|
else
|
|
{
|
|
// yep
|
|
bPtsUsed = SAM_SITE_REPAIR_DIVISOR * ( 100 - StrategicMap[ sStrategicSector ].bSAMCondition );
|
|
StrategicMap[ sStrategicSector ].bSAMCondition = 100;
|
|
|
|
//ARM: NOTE THAT IF THIS CODE IS EVER RE-ACTIVATED, THE SAM GRAPHICS SHOULD CHANGE NOT WHEN THE SAM SITE RETURNS TO
|
|
// FULL STRENGTH (condition 100), but as soon as it reaches MIN_CONDITION_TO_FIX_SAM!!!
|
|
|
|
// Bring Hit points back up to full, adjust graphic to full graphic.....
|
|
UpdateSAMDoneRepair( pSoldier -> sSectorX, pSoldier -> sSectorY, pSoldier -> bSectorZ );
|
|
}
|
|
|
|
if ( StrategicMap[ sStrategicSector ].bSAMCondition == 100 )
|
|
{
|
|
*pfNothingLeftToRepair = TRUE;
|
|
}
|
|
else
|
|
{
|
|
*pfNothingLeftToRepair = FALSE;
|
|
}
|
|
return( bPtsUsed );
|
|
}
|
|
*/
|
|
|
|
|
|
|
|
INT8 FindRepairableItemOnOtherSoldier( SOLDIERTYPE * pSoldier, UINT8 ubPassType )
|
|
{
|
|
INT8 bLoop, bLoop2;
|
|
REPAIR_PASS_SLOTS_TYPE *pPassList;
|
|
INT8 bSlotToCheck;
|
|
OBJECTTYPE * pObj;
|
|
|
|
|
|
Assert( ubPassType < NUM_REPAIR_PASS_TYPES );
|
|
|
|
pPassList = &( gRepairPassSlotList[ ubPassType ] );
|
|
|
|
for ( bLoop = 0; bLoop < pPassList->ubChoices; bLoop++ )
|
|
{
|
|
bSlotToCheck = pPassList->bSlot[ bLoop ];
|
|
Assert( bSlotToCheck != -1 );
|
|
|
|
pObj = &( pSoldier->inv[ bSlotToCheck ] );
|
|
for ( bLoop2 = 0; bLoop2 < pSoldier->inv[ bSlotToCheck ].ubNumberOfObjects; bLoop2++ )
|
|
{
|
|
if ( IsItemRepairable( pObj->usItem, pObj->bStatus[bLoop2] ) )
|
|
{
|
|
return( bSlotToCheck );
|
|
}
|
|
}
|
|
|
|
// have to check for attachments...
|
|
for ( bLoop2 = 0; bLoop2 < MAX_ATTACHMENTS; bLoop2++ )
|
|
{
|
|
if ( pObj->usAttachItem[ bLoop2 ] != NOTHING )
|
|
{
|
|
if ( IsItemRepairable( pObj->usAttachItem[ bLoop2 ], pObj->bAttachStatus[ bLoop2 ] ) )
|
|
{
|
|
return( bSlotToCheck );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return( NO_SLOT );
|
|
}
|
|
|
|
|
|
|
|
void DoActualRepair( SOLDIERTYPE * pSoldier, UINT16 usItem, INT8 * pbStatus, UINT8 * pubRepairPtsLeft )
|
|
{
|
|
INT16 sRepairCostAdj;
|
|
UINT16 usDamagePts, usPtsFixed;
|
|
|
|
// get item's repair ease, for each + point is 10% easier, each - point is 10% harder to repair
|
|
sRepairCostAdj = 100 - ( 10 * Item[ usItem ].bRepairEase );
|
|
|
|
// make sure it ain't somehow gone too low!
|
|
if (sRepairCostAdj < 10)
|
|
{
|
|
sRepairCostAdj = 10;
|
|
}
|
|
|
|
// repairs on electronic items take twice as long if the guy doesn't have the skill
|
|
// if ( ( Item[ usItem ].fFlags & ITEM_ELECTRONIC ) && ( !( HAS_SKILL_TRAIT( pSoldier, ELECTRONICS ) ) ) )
|
|
if ( ( Item[ usItem ].electronic ) && ( !( HAS_SKILL_TRAIT( pSoldier, ELECTRONICS ) ) ) )
|
|
{
|
|
sRepairCostAdj *= 2;
|
|
}
|
|
|
|
// how many points of damage is the item down by?
|
|
usDamagePts = 100 - *pbStatus;
|
|
|
|
// adjust that by the repair cost adjustment percentage
|
|
usDamagePts = (usDamagePts * sRepairCostAdj) / 100;
|
|
|
|
// do we have enough pts to fully repair the item?
|
|
if ( *pubRepairPtsLeft >= usDamagePts )
|
|
{
|
|
// fix it to 100%
|
|
*pbStatus = 100;
|
|
*pubRepairPtsLeft -= usDamagePts;
|
|
}
|
|
else // not enough, partial fix only, if any at all
|
|
{
|
|
// fix what we can - add pts left adjusted by the repair cost
|
|
usPtsFixed = ( *pubRepairPtsLeft * 100 ) / sRepairCostAdj;
|
|
|
|
// if we have enough to actually fix anything
|
|
// NOTE: a really crappy repairman with only 1 pt/hr CAN'T repair electronics or difficult items!
|
|
if (usPtsFixed > 0)
|
|
{
|
|
*pbStatus += usPtsFixed;
|
|
|
|
// make sure we don't somehow end up over 100
|
|
if ( *pbStatus > 100 )
|
|
{
|
|
*pbStatus = 100;
|
|
}
|
|
}
|
|
|
|
*pubRepairPtsLeft = 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN RepairObject( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pOwner, OBJECTTYPE * pObj, UINT8 * pubRepairPtsLeft )
|
|
{
|
|
UINT8 ubLoop, ubItemsInPocket;
|
|
BOOLEAN fSomethingWasRepaired = FALSE;
|
|
|
|
|
|
ubItemsInPocket = pObj->ubNumberOfObjects;
|
|
|
|
for ( ubLoop = 0; ubLoop < ubItemsInPocket; ubLoop++ )
|
|
{
|
|
// if it's repairable and NEEDS repairing
|
|
if ( IsItemRepairable( pObj->usItem, pObj->bStatus[ubLoop] ) )
|
|
{
|
|
// repairable, try to repair it
|
|
|
|
//void DoActualRepair( SOLDIERTYPE * pSoldier, UINT16 usItem, INT8 * pbStatus, UINT8 * pubRepairPtsLeft )
|
|
DoActualRepair( pSoldier, pObj->usItem, &(pObj->bStatus[ ubLoop ]), pubRepairPtsLeft );
|
|
|
|
fSomethingWasRepaired = TRUE;
|
|
|
|
if ( pObj->bStatus[ ubLoop ] == 100 )
|
|
{
|
|
// report it as fixed
|
|
if ( pSoldier == pOwner )
|
|
{
|
|
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[ STR_REPAIRED ], pSoldier->name, ItemNames[ pObj->usItem ] );
|
|
}
|
|
else
|
|
{
|
|
// NOTE: may need to be changed for localized versions
|
|
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, gzLateLocalizedString[ 35 ], pSoldier->name, pOwner->name, ItemNames[ pObj->usItem ] );
|
|
}
|
|
}
|
|
|
|
if ( *pubRepairPtsLeft == 0 )
|
|
{
|
|
// we're out of points!
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// now check for attachments
|
|
for ( ubLoop = 0; ubLoop < MAX_ATTACHMENTS; ubLoop++ )
|
|
{
|
|
if ( pObj->usAttachItem[ ubLoop ] != NOTHING )
|
|
{
|
|
if ( IsItemRepairable( pObj->usAttachItem[ ubLoop ], pObj->bAttachStatus[ ubLoop ] ) )
|
|
{
|
|
// repairable, try to repair it
|
|
|
|
DoActualRepair( pSoldier, pObj->usAttachItem[ ubLoop ], &(pObj->bAttachStatus[ ubLoop ]), pubRepairPtsLeft );
|
|
|
|
fSomethingWasRepaired = TRUE;
|
|
|
|
if ( pObj->bAttachStatus[ ubLoop ] == 100 )
|
|
{
|
|
// report it as fixed
|
|
if ( pSoldier == pOwner )
|
|
{
|
|
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, Message[ STR_REPAIRED ], pSoldier->name, ItemNames[ pObj->usAttachItem[ ubLoop ] ] );
|
|
}
|
|
else
|
|
{
|
|
// NOTE: may need to be changed for localized versions
|
|
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, gzLateLocalizedString[ 35 ], pSoldier->name, pOwner->name, ItemNames[ pObj->usAttachItem[ ubLoop ] ] );
|
|
}
|
|
}
|
|
|
|
if ( *pubRepairPtsLeft == 0 )
|
|
{
|
|
// we're out of points!
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return( fSomethingWasRepaired );
|
|
}
|
|
|
|
|
|
void HandleRepairBySoldier( SOLDIERTYPE *pSoldier )
|
|
{
|
|
UINT16 usMax=0;
|
|
UINT8 ubRepairPtsLeft =0;
|
|
UINT8 ubItemsInPocket = 0;
|
|
UINT8 ubObjectInPocketCounter = 0;
|
|
UINT8 ubInitialRepairPts = 0;
|
|
UINT8 ubRepairPtsUsed = 0;
|
|
INT8 bPocket =0;
|
|
BOOLEAN fNothingLeftToRepair = FALSE;
|
|
INT8 bLoop, bLoopStart, bLoopEnd;
|
|
BOOLEAN fAnyOfSoldiersOwnItemsWereFixed = FALSE;
|
|
OBJECTTYPE * pObj;
|
|
|
|
|
|
// grab max number of repair pts open to this soldier
|
|
ubRepairPtsLeft = CalculateRepairPointsForRepairman( pSoldier, &usMax, TRUE );
|
|
|
|
// no points
|
|
if ( ubRepairPtsLeft == 0 )
|
|
{
|
|
AssignmentDone( pSoldier, TRUE, TRUE );
|
|
return;
|
|
}
|
|
|
|
// remember what we've started off with
|
|
ubInitialRepairPts = ubRepairPtsLeft;
|
|
|
|
// check if we are repairing a vehicle
|
|
if ( pSoldier->bVehicleUnderRepairID != -1 )
|
|
{
|
|
if ( CanCharacterRepairVehicle( pSoldier, pSoldier->bVehicleUnderRepairID ) )
|
|
{
|
|
// attempt to fix vehicle
|
|
ubRepairPtsLeft -= RepairVehicle( pSoldier->bVehicleUnderRepairID, ubRepairPtsLeft, &fNothingLeftToRepair );
|
|
}
|
|
}
|
|
// check if we are repairing a robot
|
|
else if( pSoldier->fFixingRobot )
|
|
{
|
|
if ( CanCharacterRepairRobot( pSoldier ) )
|
|
{
|
|
// repairing the robot is very slow & difficult
|
|
ubRepairPtsLeft /= 2;
|
|
ubInitialRepairPts /= 2;
|
|
|
|
if( !( HAS_SKILL_TRAIT( pSoldier, ELECTRONICS ) ) )
|
|
{
|
|
ubRepairPtsLeft /= 2;
|
|
ubInitialRepairPts /= 2;
|
|
}
|
|
|
|
// robot
|
|
ubRepairPtsLeft -= HandleRepairOfRobotBySoldier( pSoldier, ubRepairPtsLeft, &fNothingLeftToRepair );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fAnyOfSoldiersOwnItemsWereFixed = UnjamGunsOnSoldier( pSoldier, pSoldier, &ubRepairPtsLeft );
|
|
|
|
// repair items on self
|
|
for( bLoop = 0; bLoop < 2; bLoop++ )
|
|
{
|
|
if ( bLoop == 0 )
|
|
{
|
|
bLoopStart = SECONDHANDPOS;
|
|
bLoopEnd = SMALLPOCK8POS;
|
|
}
|
|
else
|
|
{
|
|
bLoopStart = HELMETPOS;
|
|
bLoopEnd = HEAD2POS;
|
|
}
|
|
|
|
// now repair objects running from left hand to small pocket
|
|
for( bPocket = bLoopStart; bPocket <= bLoopEnd; bPocket++ )
|
|
{
|
|
pObj = &(pSoldier->inv[ bPocket ]);
|
|
|
|
if ( RepairObject( pSoldier, pSoldier, pObj, &ubRepairPtsLeft ) )
|
|
{
|
|
fAnyOfSoldiersOwnItemsWereFixed = TRUE;
|
|
|
|
// quit looking if we're already out
|
|
if ( ubRepairPtsLeft == 0 )
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// if he fixed something of his, and now has no more of his own items to fix
|
|
if ( fAnyOfSoldiersOwnItemsWereFixed && !DoesCharacterHaveAnyItemsToRepair( pSoldier, -1 ) )
|
|
{
|
|
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, sRepairsDoneString[ 0 ], pSoldier->name );
|
|
|
|
// let player react
|
|
StopTimeCompression();
|
|
}
|
|
|
|
|
|
// repair items on others
|
|
RepairItemsOnOthers( pSoldier, &ubRepairPtsLeft );
|
|
}
|
|
|
|
// what are the total amount of pts used by character?
|
|
ubRepairPtsUsed = ubInitialRepairPts - ubRepairPtsLeft;
|
|
if( ubRepairPtsUsed > 0 )
|
|
{
|
|
// improve stats
|
|
StatChange( pSoldier, MECHANAMT, ( UINT16 ) (ubRepairPtsUsed / 2), FALSE );
|
|
StatChange( pSoldier, DEXTAMT, ( UINT16 ) (ubRepairPtsUsed / 2), FALSE );
|
|
|
|
// check if kit damaged/depleted
|
|
if( ( Random( 100 ) ) < (UINT32) (ubRepairPtsUsed * 5) ) // CJC: added a x5 as this wasn't going down anywhere fast enough
|
|
{
|
|
// kit item damaged/depleted, burn up points of toolkit..which is in right hand
|
|
UseKitPoints( &( pSoldier -> inv[ HANDPOS ] ), 1, pSoldier );
|
|
}
|
|
}
|
|
|
|
|
|
// if he really done
|
|
if ( HasCharacterFinishedRepairing( pSoldier ) )
|
|
{
|
|
// yup, that's all folks
|
|
AssignmentDone( pSoldier, TRUE, TRUE );
|
|
}
|
|
else // still has stuff to repair
|
|
{
|
|
// if nothing got repaired, there's a problem
|
|
if ( ubRepairPtsUsed == 0 )
|
|
{
|
|
// see if not having a toolkit is the problem
|
|
if ( FindToolkit( pSoldier ) == NO_SLOT )
|
|
{
|
|
// he could (maybe) repair something, but can't because he doesn't have a tool kit!
|
|
AssignmentAborted( pSoldier, NO_MORE_TOOL_KITS );
|
|
}
|
|
else
|
|
{
|
|
// he can't repair anything because he doesn't have enough skill!
|
|
AssignmentAborted( pSoldier, INSUF_REPAIR_SKILL );
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN IsItemRepairable( UINT16 usItem, INT8 bStatus )
|
|
{
|
|
// check to see if item can/needs to be repaired
|
|
// if ( ( bStatus < 100) && ( Item[ usItem ].fFlags & ITEM_REPAIRABLE ) )
|
|
if ( ( bStatus < 100) && ( Item[ usItem ].repairable ) )
|
|
{
|
|
// yep
|
|
return ( TRUE );
|
|
}
|
|
|
|
// nope
|
|
return ( FALSE );
|
|
}
|
|
|
|
|
|
void HandleRestAndFatigueInSector( INT16 sMapX, INT16 sMapY, INT8 bMapZ )
|
|
{
|
|
// this will handle all sleeping characters in this sector
|
|
SOLDIERTYPE *pSoldier, *pTeamSoldier;
|
|
INT32 cnt=0;
|
|
|
|
pSoldier = MercPtrs[0];
|
|
|
|
// go through list of characters, find all sleepers in sector
|
|
for ( pTeamSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ pSoldier -> bTeam ].bLastID; cnt++,pTeamSoldier++)
|
|
{
|
|
if( ( pTeamSoldier -> bActive ) && ( pSoldier -> bAssignment != ASSIGNMENT_POW ) )
|
|
{
|
|
if( ( pTeamSoldier -> sSectorX == sMapX ) && ( pTeamSoldier -> sSectorY == sMapY ) && ( pTeamSoldier -> bSectorZ == bMapZ ) )
|
|
{
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
INT8 GetRegainDueToSleepNeeded( SOLDIERTYPE *pSoldier, INT32 iRateOfReGain )
|
|
{
|
|
// look at persons regain rate,
|
|
// if they infact loses sleep, make sure it doesn't go below the current rate
|
|
INT8 bRate = 0;
|
|
UINT8 ubNeedForSleep = 0;
|
|
|
|
// get profile id and then grab sleep need value
|
|
ubNeedForSleep = gMercProfiles[ pSoldier -> ubProfile ].ubNeedForSleep;
|
|
|
|
bRate = ( AVG_NUMBER_OF_HOURS_OF_SLEEP_NEEDED - ( INT8 )ubNeedForSleep );
|
|
|
|
if( bRate >= iRateOfReGain )
|
|
{
|
|
bRate = ( - iRateOfReGain ) + 1;
|
|
}
|
|
return( bRate );
|
|
}
|
|
*/
|
|
|
|
|
|
|
|
void RestCharacter( SOLDIERTYPE *pSoldier )
|
|
{
|
|
// handle the sleep of this character, update bBreathMax based on sleep they have
|
|
INT8 bMaxBreathRegain = 0;
|
|
|
|
bMaxBreathRegain = 50 / CalcSoldierNeedForSleep( pSoldier );
|
|
|
|
// if breath max is below the "really tired" threshold
|
|
if( pSoldier -> bBreathMax < BREATHMAX_PRETTY_TIRED )
|
|
{
|
|
// real tired, rest rate is 50% higher (this is to prevent absurdly long sleep times for totally exhausted mercs)
|
|
bMaxBreathRegain = ( bMaxBreathRegain * 3 / 2 );
|
|
}
|
|
|
|
pSoldier -> bBreathMax += bMaxBreathRegain;
|
|
|
|
|
|
if( pSoldier -> bBreathMax > 100 )
|
|
{
|
|
pSoldier -> bBreathMax = 100;
|
|
}
|
|
else if( pSoldier -> bBreathMax < BREATHMAX_ABSOLUTE_MINIMUM )
|
|
{
|
|
pSoldier -> bBreathMax = BREATHMAX_ABSOLUTE_MINIMUM;
|
|
}
|
|
|
|
pSoldier -> bBreath = pSoldier -> bBreathMax;
|
|
|
|
|
|
if ( pSoldier-> bBreathMax >= BREATHMAX_CANCEL_TIRED )
|
|
{
|
|
pSoldier->fComplainedThatTired = FALSE;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void FatigueCharacter( SOLDIERTYPE *pSoldier )
|
|
{
|
|
// fatigue character
|
|
INT32 iPercentEncumbrance;
|
|
INT32 iBreathLoss;
|
|
INT8 bMaxBreathLoss = 0, bDivisor = 1;
|
|
|
|
|
|
// vehicle or robot?
|
|
if( ( pSoldier -> uiStatusFlags & SOLDIER_VEHICLE ) || AM_A_ROBOT( pSoldier ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// check if in transit, do not wear out
|
|
if( IsCharacterInTransit( pSoldier ) == TRUE )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// POW?
|
|
if( pSoldier -> bAssignment == ASSIGNMENT_POW )
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
bDivisor = 24 - CalcSoldierNeedForSleep( pSoldier );
|
|
bMaxBreathLoss = 50 / bDivisor;
|
|
|
|
if( bMaxBreathLoss < 2 )
|
|
{
|
|
bMaxBreathLoss = 2;
|
|
}
|
|
|
|
//KM: Added encumbrance calculation to soldiers moving on foot. Anything above 100% will increase
|
|
// rate of fatigue. 200% encumbrance will cause soldiers to tire twice as quickly.
|
|
if( pSoldier->fBetweenSectors && pSoldier->bAssignment != VEHICLE )
|
|
{ //Soldier is on foot and travelling. Factor encumbrance into fatigue rate.
|
|
iPercentEncumbrance = CalculateCarriedWeight( pSoldier );
|
|
if( iPercentEncumbrance > 100 )
|
|
{
|
|
iBreathLoss = (bMaxBreathLoss * iPercentEncumbrance / 100);
|
|
bMaxBreathLoss = (INT8)min( 127, iBreathLoss );
|
|
}
|
|
}
|
|
|
|
// if breath max is below the "really tired" threshold
|
|
if( pSoldier -> bBreathMax < BREATHMAX_PRETTY_TIRED )
|
|
{
|
|
// real tired, fatigue rate is 50% higher
|
|
bMaxBreathLoss = ( bMaxBreathLoss * 3 / 2 );
|
|
}
|
|
|
|
|
|
pSoldier -> bBreathMax -= bMaxBreathLoss;
|
|
|
|
if( pSoldier -> bBreathMax > 100 )
|
|
{
|
|
pSoldier -> bBreathMax = 100;
|
|
}
|
|
else if( pSoldier -> bBreathMax < BREATHMAX_ABSOLUTE_MINIMUM )
|
|
{
|
|
pSoldier -> bBreathMax = BREATHMAX_ABSOLUTE_MINIMUM;
|
|
}
|
|
|
|
// current breath can't exceed maximum
|
|
if( pSoldier -> bBreath > pSoldier -> bBreathMax )
|
|
{
|
|
pSoldier -> bBreath = pSoldier -> bBreathMax;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
// ONCE PER HOUR, will handle ALL kinds of training (self, teaching, and town) in this sector
|
|
void HandleTrainingInSector( INT16 sMapX, INT16 sMapY, INT8 bZ )
|
|
{
|
|
SOLDIERTYPE *pTrainer;
|
|
SOLDIERTYPE *pStudent;
|
|
UINT8 ubStat;
|
|
BOOLEAN fAtGunRange = FALSE;
|
|
UINT32 uiCnt=0;
|
|
INT16 sTotalTrainingPts = 0;
|
|
INT16 sTrainingPtsDueToInstructor = 0;
|
|
SOLDIERTYPE *pStatTrainerList[ NUM_TRAINABLE_STATS ]; // can't have more "best" trainers than trainable stats
|
|
INT16 sBestTrainingPts;
|
|
INT16 sTownTrainingPts;
|
|
TOWN_TRAINER_TYPE TownTrainer[ MAX_CHARACTER_COUNT ];
|
|
UINT8 ubTownTrainers;
|
|
UINT16 usMaxPts;
|
|
BOOLEAN fSamSiteInSector = FALSE;
|
|
BOOLEAN fTrainingCompleted = FALSE;
|
|
|
|
|
|
// find out if a sam site here
|
|
fSamSiteInSector = IsThisSectorASAMSector( sMapX, sMapY, 0 );
|
|
|
|
// Training in underground sectors is disallowed by the interface code, so there should never be any
|
|
if (bZ != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// if sector not under our control, has enemies in it, or is currently in combat mode
|
|
if (!SectorOursAndPeaceful( sMapX, sMapY, bZ ))
|
|
{
|
|
// then training is canceled for this hour.
|
|
// This is partly logical, but largely to prevent newly trained militia from appearing in mid-battle
|
|
return;
|
|
}
|
|
|
|
// are we training in the sector with gun range in Alma?
|
|
if ( (sMapX == GUN_RANGE_X) && (sMapY == GUN_RANGE_Y) && (bZ == GUN_RANGE_Z) )
|
|
{
|
|
fAtGunRange = TRUE;
|
|
}
|
|
|
|
// init trainer list
|
|
memset( pStatTrainerList, 0, sizeof( pStatTrainerList ) );
|
|
|
|
// build list of teammate trainers in this sector.
|
|
|
|
// Only the trainer with the HIGHEST training ability in each stat is effective. This is mainly to avoid having to
|
|
// sort them from highest to lowest if some form of trainer degradation formula was to be used for multiple trainers.
|
|
|
|
// for each trainable stat
|
|
for (ubStat = 0; ubStat < NUM_TRAINABLE_STATS; ubStat++)
|
|
{
|
|
sBestTrainingPts = -1;
|
|
|
|
// search team for active instructors in this sector
|
|
for ( uiCnt = 0, pTrainer = MercPtrs[ uiCnt ]; uiCnt <= gTacticalStatus.Team[ MercPtrs[0] -> bTeam ].bLastID; uiCnt++, pTrainer++)
|
|
{
|
|
if( pTrainer -> bActive && ( pTrainer -> sSectorX == sMapX ) && ( pTrainer -> sSectorY == sMapY ) && ( pTrainer -> bSectorZ == bZ) )
|
|
{
|
|
// if he's training teammates in this stat
|
|
if( ( pTrainer -> bAssignment == TRAIN_TEAMMATE ) && ( pTrainer -> bTrainStat == ubStat) && ( EnoughTimeOnAssignment( pTrainer ) ) && ( pTrainer->fMercAsleep == FALSE ) )
|
|
{
|
|
sTrainingPtsDueToInstructor = GetBonusTrainingPtsDueToInstructor( pTrainer, NULL, ubStat, fAtGunRange, &usMaxPts );
|
|
|
|
// if he's the best trainer so far for this stat
|
|
if (sTrainingPtsDueToInstructor > sBestTrainingPts)
|
|
{
|
|
// then remember him as that, and the points he scored
|
|
pStatTrainerList[ ubStat ] = pTrainer;
|
|
sBestTrainingPts = sTrainingPtsDueToInstructor;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// now search team for active self-trainers in this sector
|
|
for ( uiCnt = 0, pStudent = MercPtrs[ uiCnt ]; uiCnt <= gTacticalStatus.Team[ MercPtrs[0] -> bTeam ].bLastID; uiCnt++, pStudent++)
|
|
{
|
|
// see if this merc is active and in the same sector
|
|
if( ( pStudent -> bActive) && ( pStudent -> sSectorX == sMapX ) && ( pStudent -> sSectorY == sMapY ) && ( pStudent -> bSectorZ == bZ ) )
|
|
{
|
|
// if he's training himself (alone, or by others), then he's a student
|
|
if ( ( pStudent -> bAssignment == TRAIN_SELF ) || ( pStudent -> bAssignment == TRAIN_BY_OTHER ) )
|
|
{
|
|
if ( EnoughTimeOnAssignment( pStudent ) && ( pStudent->fMercAsleep == FALSE ) )
|
|
{
|
|
// figure out how much the grunt can learn in one training period
|
|
sTotalTrainingPts = GetSoldierTrainingPts( pStudent, pStudent -> bTrainStat, fAtGunRange, &usMaxPts );
|
|
|
|
// if he's getting help
|
|
if ( pStudent -> bAssignment == TRAIN_BY_OTHER )
|
|
{
|
|
// grab the pointer to the (potential) trainer for this stat
|
|
pTrainer = pStatTrainerList[ pStudent -> bTrainStat ];
|
|
|
|
// if this stat HAS a trainer in sector at all
|
|
if (pTrainer != NULL)
|
|
{
|
|
/* Assignment distance limits removed. Sep/11/98. ARM
|
|
// if this sector either ISN'T currently loaded, or it is but the trainer is close enough to the student
|
|
if ( ( sMapX != gWorldSectorX ) || ( sMapY != gWorldSectorY ) || ( pStudent -> bSectorZ != gbWorldSectorZ ) ||
|
|
( PythSpacesAway( pStudent -> sGridNo, pTrainer -> sGridNo ) < MAX_DISTANCE_FOR_TRAINING ) && ( EnoughTimeOnAssignment( pTrainer ) ) )
|
|
*/
|
|
// NB this EnoughTimeOnAssignment() call is redundent since it is called up above
|
|
//if ( EnoughTimeOnAssignment( pTrainer ) )
|
|
{
|
|
// valid trainer is available, this gives the student a large training bonus!
|
|
sTrainingPtsDueToInstructor = GetBonusTrainingPtsDueToInstructor( pTrainer, pStudent, pStudent -> bTrainStat, fAtGunRange, &usMaxPts );
|
|
|
|
StatChange(pTrainer,LDRAMT,sTrainingPtsDueToInstructor,FALSE);
|
|
StatChange(pTrainer,WISDOMAMT,sTrainingPtsDueToInstructor,FALSE);
|
|
|
|
// add the bonus to what merc can learn on his own
|
|
sTotalTrainingPts += sTrainingPtsDueToInstructor;
|
|
}
|
|
}
|
|
}
|
|
|
|
// now finally train the grunt
|
|
TrainSoldierWithPts( pStudent, sTotalTrainingPts );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// check if we're doing a sector where militia can be trained
|
|
if( ( (StrategicMap[ sMapX + ( sMapY * MAP_WORLD_X ) ].bNameId != BLANK_SECTOR ) || ( fSamSiteInSector == TRUE ) ) && (bZ == 0) )
|
|
{
|
|
// init town trainer list
|
|
memset( TownTrainer, 0, sizeof( TownTrainer ) );
|
|
ubTownTrainers = 0;
|
|
|
|
// build list of all the town trainers in this sector and their training pts
|
|
for ( uiCnt = 0, pTrainer = MercPtrs[ uiCnt ]; uiCnt <= gTacticalStatus.Team[ MercPtrs[0] -> bTeam ].bLastID; uiCnt++,pTrainer++)
|
|
{
|
|
if( pTrainer -> bActive && ( pTrainer -> sSectorX == sMapX ) && ( pTrainer -> sSectorY == sMapY ) && ( pTrainer -> bSectorZ == bZ ) )
|
|
{
|
|
if( ( pTrainer -> bAssignment == TRAIN_TOWN ) && ( EnoughTimeOnAssignment( pTrainer ) ) && ( pTrainer->fMercAsleep == FALSE ) )
|
|
{
|
|
sTownTrainingPts = GetTownTrainPtsForCharacter( pTrainer, &usMaxPts );
|
|
|
|
// if he's actually worth anything
|
|
if( sTownTrainingPts > 0 )
|
|
{
|
|
// remember this guy as a town trainer
|
|
TownTrainer[ubTownTrainers].sTrainingPts = sTownTrainingPts;
|
|
TownTrainer[ubTownTrainers].pSoldier = pTrainer;
|
|
ubTownTrainers++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// if we have more than one
|
|
if (ubTownTrainers > 1)
|
|
{
|
|
// sort the town trainer list from best trainer to worst
|
|
qsort( TownTrainer, ubTownTrainers, sizeof(TOWN_TRAINER_TYPE), TownTrainerQsortCompare);
|
|
}
|
|
|
|
// for each trainer, in sorted order from the best to the worst
|
|
for (uiCnt = 0; uiCnt < ubTownTrainers; uiCnt++)
|
|
{
|
|
// top trainer has full effect (divide by 1), then divide by 2, 4, 8, etc.
|
|
//sTownTrainingPts = TownTrainer[ uiCnt ].sTrainingPts / (UINT16) pow(2, uiCnt);
|
|
// CJC: took this out and replaced with limit of 2 guys per sector
|
|
sTownTrainingPts = TownTrainer[ uiCnt ].sTrainingPts;
|
|
|
|
if (sTownTrainingPts > 0)
|
|
{
|
|
fTrainingCompleted = TrainTownInSector( TownTrainer[ uiCnt ].pSoldier, sMapX, sMapY, sTownTrainingPts );
|
|
|
|
if ( fTrainingCompleted )
|
|
{
|
|
// there's no carryover into next session for extra training (cause player might cancel), so break out of loop
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
int TownTrainerQsortCompare(const void *pArg1, const void *pArg2)
|
|
{
|
|
if (((TOWN_TRAINER_TYPE *)pArg1) -> sTrainingPts > ((TOWN_TRAINER_TYPE *)pArg2) -> sTrainingPts)
|
|
{
|
|
return(-1);
|
|
}
|
|
else
|
|
if (((TOWN_TRAINER_TYPE *)pArg1) -> sTrainingPts < ((TOWN_TRAINER_TYPE *)pArg2) -> sTrainingPts)
|
|
{
|
|
return(1);
|
|
}
|
|
else
|
|
{
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
|
|
INT16 GetBonusTrainingPtsDueToInstructor( SOLDIERTYPE *pInstructor, SOLDIERTYPE *pStudent, INT8 bTrainStat, BOOLEAN fAtGunRange, UINT16 *pusMaxPts )
|
|
{
|
|
// return the bonus training pts of this instructor with this student,...if student null, simply assignment student skill of 0 and student wisdom of 100
|
|
INT16 sTrainingPts = 0;
|
|
INT8 bTraineeEffWisdom = 0;
|
|
INT8 bTraineeNatWisdom = 0;
|
|
INT8 bTraineeSkill = 0;
|
|
INT8 bTrainerEffSkill = 0;
|
|
INT8 bTrainerNatSkill = 0;
|
|
INT8 bTrainingBonus = 0;
|
|
INT8 bOpinionFactor;
|
|
|
|
// assume training impossible for max pts
|
|
*pusMaxPts = 0;
|
|
|
|
if( pInstructor == NULL )
|
|
{
|
|
// no instructor, leave
|
|
return ( 0 );
|
|
}
|
|
|
|
|
|
switch( bTrainStat )
|
|
{
|
|
case( STRENGTH ):
|
|
bTrainerEffSkill = EffectiveStrength ( pInstructor );
|
|
bTrainerNatSkill = pInstructor->bStrength;
|
|
break;
|
|
case( DEXTERITY ):
|
|
bTrainerEffSkill = EffectiveDexterity ( pInstructor );
|
|
bTrainerNatSkill = pInstructor->bDexterity;
|
|
break;
|
|
case( AGILITY ):
|
|
bTrainerEffSkill = EffectiveAgility( pInstructor );
|
|
bTrainerNatSkill = pInstructor->bAgility;
|
|
break;
|
|
case( HEALTH ):
|
|
bTrainerEffSkill = pInstructor -> bLifeMax;
|
|
bTrainerNatSkill = pInstructor->bLifeMax;
|
|
break;
|
|
case( LEADERSHIP ):
|
|
bTrainerEffSkill = EffectiveLeadership( pInstructor );
|
|
bTrainerNatSkill = pInstructor->bLeadership;
|
|
break;
|
|
case( MARKSMANSHIP ):
|
|
bTrainerEffSkill = EffectiveMarksmanship( pInstructor );
|
|
bTrainerNatSkill = pInstructor->bMarksmanship;
|
|
break;
|
|
case( EXPLOSIVE_ASSIGN ):
|
|
bTrainerEffSkill = EffectiveExplosive( pInstructor );
|
|
bTrainerNatSkill = pInstructor->bExplosive;
|
|
break;
|
|
case( MEDICAL ):
|
|
bTrainerEffSkill = EffectiveMedical( pInstructor );
|
|
bTrainerNatSkill = pInstructor->bMedical;
|
|
break;
|
|
case( MECHANICAL ):
|
|
bTrainerEffSkill = EffectiveMechanical( pInstructor );
|
|
bTrainerNatSkill = pInstructor->bMechanical;
|
|
break;
|
|
// NOTE: Wisdom can't be trained!
|
|
default:
|
|
// BETA message
|
|
#ifdef JA2BETAVERSION
|
|
ScreenMsg( FONT_ORANGE, MSG_BETAVERSION, L"GetBonusTrainingPtsDueToInstructor: ERROR - Unknown bTrainStat %d", bTrainStat);
|
|
#endif
|
|
return(0);
|
|
}
|
|
|
|
|
|
// if there's no student
|
|
if( pStudent == NULL )
|
|
{
|
|
// assume these default values
|
|
bTraineeEffWisdom = 100;
|
|
bTraineeNatWisdom = 100;
|
|
bTraineeSkill = 0;
|
|
bOpinionFactor = 0;
|
|
}
|
|
else
|
|
{
|
|
// set student's variables
|
|
bTraineeEffWisdom = EffectiveWisdom ( pStudent );
|
|
bTraineeNatWisdom = pStudent->bWisdom;
|
|
|
|
// for trainee's stat skill, must use the natural value, not the effective one, to avoid drunks training beyond cap
|
|
switch( bTrainStat )
|
|
{
|
|
case( STRENGTH ):
|
|
bTraineeSkill = pStudent -> bStrength;
|
|
break;
|
|
case( DEXTERITY ):
|
|
bTraineeSkill = pStudent -> bDexterity;
|
|
break;
|
|
case( AGILITY ):
|
|
bTraineeSkill = pStudent -> bAgility;
|
|
break;
|
|
case( HEALTH ):
|
|
bTraineeSkill = pStudent -> bLifeMax;
|
|
break;
|
|
case( LEADERSHIP ):
|
|
bTraineeSkill = pStudent -> bLeadership;
|
|
break;
|
|
case( MARKSMANSHIP ):
|
|
bTraineeSkill = pStudent -> bMarksmanship;
|
|
break;
|
|
case( EXPLOSIVE_ASSIGN ):
|
|
bTraineeSkill = pStudent -> bExplosive;
|
|
break;
|
|
case( MEDICAL ):
|
|
bTraineeSkill = pStudent -> bMedical;
|
|
break;
|
|
case( MECHANICAL ):
|
|
bTraineeSkill = pStudent -> bMechanical;
|
|
break;
|
|
// NOTE: Wisdom can't be trained!
|
|
default:
|
|
// BETA message
|
|
#ifdef JA2BETAVERSION
|
|
ScreenMsg( FONT_ORANGE, MSG_BETAVERSION, L"GetBonusTrainingPtsDueToInstructor: ERROR - Unknown bTrainStat %d", bTrainStat);
|
|
#endif
|
|
return(0);
|
|
}
|
|
|
|
// if trainee skill 0 or at/beyond the training cap, can't train
|
|
//Orig: if ( ( bTraineeSkill == 0 ) || ( bTraineeSkill >= TRAINING_RATING_CAP ) )
|
|
// Madd
|
|
if ( bTraineeSkill < gGameExternalOptions.ubTrainingSkillMin || bTraineeSkill >= gGameExternalOptions.ubTrainingSkillMax )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// factor in their mutual relationship
|
|
bOpinionFactor = gMercProfiles[ pStudent->ubProfile ].bMercOpinion[ pInstructor->ubProfile ];
|
|
bOpinionFactor += gMercProfiles[ pInstructor->ubProfile ].bMercOpinion[ pStudent->ubProfile ] / 2;
|
|
}
|
|
|
|
|
|
// check to see if student better than/equal to instructor's effective skill, if so, return 0
|
|
// don't use natural skill - if the guy's too doped up to tell what he know, student learns nothing until sobriety returns!
|
|
if( bTraineeSkill >= bTrainerEffSkill )
|
|
{
|
|
return ( 0 );
|
|
}
|
|
|
|
// calculate effective training pts
|
|
sTrainingPts = ( bTrainerEffSkill - bTraineeSkill ) * ( bTraineeEffWisdom + ( EffectiveWisdom( pInstructor ) + EffectiveLeadership( pInstructor ) ) / 2 ) / gGameExternalOptions.ubInstructedTrainingDivisor;
|
|
|
|
// calculate normal training pts - what it would be if his stats were "normal" (ignoring drugs, fatigue)
|
|
*pusMaxPts = ( bTrainerNatSkill - bTraineeSkill ) * ( bTraineeNatWisdom + ( pInstructor->bWisdom + pInstructor->bLeadership ) / 2 ) / gGameExternalOptions.ubInstructedTrainingDivisor;
|
|
|
|
// put in a minimum (that can be reduced due to instructor being tired?)
|
|
if (*pusMaxPts == 0)
|
|
{
|
|
// we know trainer is better than trainee, make sure they are at least 10 pts better
|
|
if ( bTrainerEffSkill > bTraineeSkill + 10 )
|
|
{
|
|
sTrainingPts = 1;
|
|
*pusMaxPts = 1;
|
|
}
|
|
}
|
|
|
|
// check for teaching skill bonuses
|
|
if( gMercProfiles[ pInstructor -> ubProfile ].bSkillTrait == TEACHING )
|
|
{
|
|
bTrainingBonus += gGameExternalOptions.ubTeachBonusToTrain;
|
|
}
|
|
if( gMercProfiles[ pInstructor -> ubProfile ].bSkillTrait2 == TEACHING )
|
|
{
|
|
bTrainingBonus += gGameExternalOptions.ubTeachBonusToTrain;
|
|
}
|
|
|
|
// teaching bonus is counted as normal, but gun range bonus is not
|
|
*pusMaxPts += ( ( ( bTrainingBonus + bOpinionFactor ) * *pusMaxPts ) / 100 );
|
|
|
|
// get special bonus if we're training marksmanship and we're in the gun range sector in Alma
|
|
if ( ( bTrainStat == MARKSMANSHIP ) && fAtGunRange )
|
|
{
|
|
bTrainingBonus += gGameExternalOptions.ubGunRangeTrainingBonus;
|
|
}
|
|
|
|
// adjust for any training bonuses and for the relationship
|
|
sTrainingPts += ( ( ( bTrainingBonus + bOpinionFactor ) * sTrainingPts ) / 100 );
|
|
|
|
// adjust for instructor fatigue
|
|
ReducePointsForFatigue( pInstructor, (UINT16 *)&sTrainingPts );
|
|
|
|
return( sTrainingPts );
|
|
}
|
|
|
|
|
|
INT16 GetSoldierTrainingPts( SOLDIERTYPE *pSoldier, INT8 bTrainStat, BOOLEAN fAtGunRange, UINT16 *pusMaxPts )
|
|
{
|
|
INT16 sTrainingPts = 0;
|
|
INT8 bTrainingBonus = 0;
|
|
INT8 bSkill = 0;
|
|
|
|
// assume training impossible for max pts
|
|
*pusMaxPts = 0;
|
|
|
|
// use NATURAL not EFFECTIVE values here
|
|
switch( bTrainStat )
|
|
{
|
|
case( STRENGTH ):
|
|
bSkill = pSoldier -> bStrength;
|
|
break;
|
|
case( DEXTERITY ):
|
|
bSkill = pSoldier -> bDexterity;
|
|
break;
|
|
case( AGILITY ):
|
|
bSkill = pSoldier -> bAgility;
|
|
break;
|
|
case( HEALTH ):
|
|
bSkill = pSoldier -> bLifeMax;
|
|
break;
|
|
case( LEADERSHIP ):
|
|
bSkill = pSoldier -> bLeadership;
|
|
break;
|
|
case( MARKSMANSHIP ):
|
|
bSkill = pSoldier -> bMarksmanship;
|
|
break;
|
|
case( EXPLOSIVE_ASSIGN ):
|
|
bSkill = pSoldier -> bExplosive;
|
|
break;
|
|
case( MEDICAL ):
|
|
bSkill = pSoldier -> bMedical;
|
|
break;
|
|
case( MECHANICAL ):
|
|
bSkill = pSoldier -> bMechanical;
|
|
break;
|
|
// NOTE: Wisdom can't be trained!
|
|
default:
|
|
// BETA message
|
|
#ifdef JA2BETAVERSION
|
|
ScreenMsg( FONT_ORANGE, MSG_BETAVERSION, L"GetSoldierTrainingPts: ERROR - Unknown bTrainStat %d", bTrainStat);
|
|
#endif
|
|
return(0);
|
|
}
|
|
|
|
// if skill 0 or at/beyond the training cap, can't train
|
|
if ( ( bSkill < gGameExternalOptions.ubTrainingSkillMin) || ( bSkill >= gGameExternalOptions.ubTrainingSkillMax ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
// calculate normal training pts - what it would be if his stats were "normal" (ignoring drugs, fatigue)
|
|
*pusMaxPts = __max( ( ( pSoldier->bWisdom * ( gGameExternalOptions.ubTrainingSkillMax - bSkill ) ) / gGameExternalOptions.ubSelfTrainingDivisor ), 1 );
|
|
|
|
// calculate effective training pts
|
|
sTrainingPts = __max( ( ( EffectiveWisdom( pSoldier ) * ( gGameExternalOptions.ubTrainingSkillMax - bSkill ) ) / gGameExternalOptions.ubSelfTrainingDivisor ), 1 );
|
|
|
|
// get special bonus if we're training marksmanship and we're in the gun range sector in Alma
|
|
if ( ( bTrainStat == MARKSMANSHIP ) && fAtGunRange )
|
|
{
|
|
bTrainingBonus += gGameExternalOptions.ubGunRangeTrainingBonus;
|
|
}
|
|
|
|
// adjust for any training bonuses
|
|
sTrainingPts += ( ( bTrainingBonus * sTrainingPts ) / 100 );
|
|
|
|
// adjust for fatigue
|
|
ReducePointsForFatigue( pSoldier, (UINT16 *)&sTrainingPts );
|
|
|
|
return( sTrainingPts );
|
|
}
|
|
|
|
INT16 GetSoldierStudentPts( SOLDIERTYPE *pSoldier, INT8 bTrainStat, BOOLEAN fAtGunRange, UINT16 *pusMaxPts )
|
|
{
|
|
INT16 sTrainingPts = 0;
|
|
INT8 bTrainingBonus = 0;
|
|
INT8 bSkill = 0;
|
|
|
|
INT16 sBestTrainingPts, sTrainingPtsDueToInstructor;
|
|
UINT16 usMaxTrainerPts, usBestMaxTrainerPts;
|
|
UINT32 uiCnt;
|
|
SOLDIERTYPE * pTrainer;
|
|
|
|
// assume training impossible for max pts
|
|
*pusMaxPts = 0;
|
|
|
|
// use NATURAL not EFFECTIVE values here
|
|
switch( bTrainStat )
|
|
{
|
|
case( STRENGTH ):
|
|
bSkill = pSoldier -> bStrength;
|
|
break;
|
|
case( DEXTERITY ):
|
|
bSkill = pSoldier -> bDexterity;
|
|
break;
|
|
case( AGILITY ):
|
|
bSkill = pSoldier -> bAgility;
|
|
break;
|
|
case( HEALTH ):
|
|
bSkill = pSoldier -> bLifeMax;
|
|
break;
|
|
case( LEADERSHIP ):
|
|
bSkill = pSoldier -> bLeadership;
|
|
break;
|
|
case( MARKSMANSHIP ):
|
|
bSkill = pSoldier -> bMarksmanship;
|
|
break;
|
|
case( EXPLOSIVE_ASSIGN ):
|
|
bSkill = pSoldier -> bExplosive;
|
|
break;
|
|
case( MEDICAL ):
|
|
bSkill = pSoldier -> bMedical;
|
|
break;
|
|
case( MECHANICAL ):
|
|
bSkill = pSoldier -> bMechanical;
|
|
break;
|
|
// NOTE: Wisdom can't be trained!
|
|
default:
|
|
// BETA message
|
|
#ifdef JA2BETAVERSION
|
|
ScreenMsg( FONT_ORANGE, MSG_BETAVERSION, L"GetSoldierTrainingPts: ERROR - Unknown bTrainStat %d", bTrainStat);
|
|
#endif
|
|
return(0);
|
|
}
|
|
|
|
// if skill 0 or at/beyond the training cap, can't train
|
|
if ( bSkill < gGameExternalOptions.ubTrainingSkillMin || bSkill >= gGameExternalOptions.ubTrainingSkillMax )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
// calculate normal training pts - what it would be if his stats were "normal" (ignoring drugs, fatigue)
|
|
*pusMaxPts = __max( ( ( pSoldier->bWisdom * ( gGameExternalOptions.ubTrainingSkillMax - bSkill ) ) / gGameExternalOptions.ubSelfTrainingDivisor ), 1 );
|
|
|
|
// calculate effective training pts
|
|
sTrainingPts = __max( ( ( EffectiveWisdom( pSoldier ) * ( gGameExternalOptions.ubTrainingSkillMax - bSkill ) ) / gGameExternalOptions.ubSelfTrainingDivisor ), 1 );
|
|
|
|
// get special bonus if we're training marksmanship and we're in the gun range sector in Alma
|
|
if ( ( bTrainStat == MARKSMANSHIP ) && fAtGunRange )
|
|
{
|
|
bTrainingBonus += gGameExternalOptions.ubGunRangeTrainingBonus;
|
|
}
|
|
|
|
// adjust for any training bonuses
|
|
sTrainingPts += ( ( bTrainingBonus * sTrainingPts ) / 100 );
|
|
|
|
// adjust for fatigue
|
|
ReducePointsForFatigue( pSoldier, (UINT16 *)&sTrainingPts );
|
|
|
|
|
|
// now add in stuff for trainer
|
|
|
|
// for each trainable stat
|
|
sBestTrainingPts = -1;
|
|
|
|
// search team for active instructors in this sector
|
|
for ( uiCnt = 0, pTrainer = MercPtrs[ uiCnt ]; uiCnt <= gTacticalStatus.Team[ MercPtrs[0] -> bTeam ].bLastID; uiCnt++, pTrainer++)
|
|
{
|
|
if( pTrainer->bActive && ( pTrainer->sSectorX == pSoldier->sSectorX ) && ( pTrainer->sSectorY == pSoldier->sSectorY ) && ( pTrainer->bSectorZ == pSoldier->bSectorZ) )
|
|
{
|
|
// if he's training teammates in this stat
|
|
// NB skip the EnoughTime requirement to display what the value should be even if haven't been training long yet...
|
|
if ( ( pTrainer->bAssignment == TRAIN_TEAMMATE ) && ( pTrainer->bTrainStat == bTrainStat) && ( pTrainer->fMercAsleep == FALSE ) )
|
|
{
|
|
sTrainingPtsDueToInstructor = GetBonusTrainingPtsDueToInstructor( pTrainer, pSoldier, bTrainStat, fAtGunRange, &usMaxTrainerPts );
|
|
|
|
// if he's the best trainer so far for this stat
|
|
if (sTrainingPtsDueToInstructor > sBestTrainingPts)
|
|
{
|
|
// then remember him as that, and the points he scored
|
|
sBestTrainingPts = sTrainingPtsDueToInstructor;
|
|
usBestMaxTrainerPts = usMaxTrainerPts;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( sBestTrainingPts != -1 )
|
|
{
|
|
// add the bonus to what merc can learn on his own
|
|
sTrainingPts += sBestTrainingPts;
|
|
*pusMaxPts += usBestMaxTrainerPts;
|
|
}
|
|
|
|
return( sTrainingPts );
|
|
}
|
|
|
|
|
|
|
|
void TrainSoldierWithPts( SOLDIERTYPE *pSoldier, INT16 sTrainPts )
|
|
{
|
|
UINT8 ubChangeStat = 0;
|
|
|
|
if( sTrainPts <= 0 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
BOOLEAN addWis = FALSE;
|
|
// which stat to modify?
|
|
switch( pSoldier -> bTrainStat )
|
|
{
|
|
case( STRENGTH ):
|
|
ubChangeStat = STRAMT;
|
|
break;
|
|
case( DEXTERITY ):
|
|
ubChangeStat = DEXTAMT;
|
|
break;
|
|
case( AGILITY ):
|
|
ubChangeStat = AGILAMT;
|
|
break;
|
|
case( HEALTH ):
|
|
ubChangeStat = HEALTHAMT;
|
|
break;
|
|
case( LEADERSHIP ):
|
|
ubChangeStat = LDRAMT;
|
|
addWis = TRUE;
|
|
break;
|
|
case( MARKSMANSHIP ):
|
|
ubChangeStat = MARKAMT;
|
|
addWis = TRUE;
|
|
break;
|
|
case( EXPLOSIVE_ASSIGN ):
|
|
ubChangeStat = EXPLODEAMT;
|
|
addWis = TRUE;
|
|
break;
|
|
case( MEDICAL ):
|
|
ubChangeStat = MEDICALAMT;
|
|
addWis = TRUE;
|
|
break;
|
|
case( MECHANICAL ):
|
|
ubChangeStat = MECHANAMT;
|
|
addWis = TRUE;
|
|
break;
|
|
// NOTE: Wisdom can't be trained!
|
|
default:
|
|
// BETA message
|
|
#ifdef JA2BETAVERSION
|
|
ScreenMsg( FONT_ORANGE, MSG_BETAVERSION, L"TrainSoldierWithPts: ERROR - Unknown bTrainStat %d", pSoldier -> bTrainStat);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
// give this merc a few chances to increase a stat (TRUE means it's training, reverse evolution doesn't apply)
|
|
StatChange( pSoldier, ubChangeStat, sTrainPts, FROM_TRAINING );
|
|
if (addWis)
|
|
StatChange( pSoldier, WISDOMAMT, sTrainPts/2, FROM_TRAINING );
|
|
|
|
}
|
|
|
|
|
|
// will train a town in sector by character
|
|
BOOLEAN TrainTownInSector( SOLDIERTYPE *pTrainer, INT16 sMapX, INT16 sMapY, INT16 sTrainingPts )
|
|
{
|
|
SECTORINFO *pSectorInfo = &( SectorInfo[ SECTOR( sMapX, sMapY ) ] );
|
|
UINT8 ubTownId = 0;
|
|
INT16 sCnt = 0;
|
|
INT8 bChance = 0;
|
|
BOOLEAN fSamSiteInSector = FALSE;
|
|
|
|
|
|
// find out if a sam site here
|
|
fSamSiteInSector = IsThisSectorASAMSector( sMapX, sMapY, 0 );
|
|
|
|
// get town index
|
|
ubTownId = StrategicMap[ pTrainer -> sSectorX + pTrainer -> sSectorY * MAP_WORLD_X ].bNameId;
|
|
if( fSamSiteInSector == FALSE )
|
|
{
|
|
Assert(ubTownId != BLANK_SECTOR);
|
|
}
|
|
|
|
// trainer gains leadership - training argument is FALSE, because the trainer is not the one training!
|
|
StatChange( pTrainer, LDRAMT, (UINT16) ( 1 + ( sTrainingPts / 200 ) ), FALSE );
|
|
StatChange( pTrainer, WISDOMAMT, (UINT16) ( 1 + ( sTrainingPts / 400 ) ), FALSE );
|
|
|
|
|
|
// increase town's training completed percentage
|
|
pSectorInfo -> ubMilitiaTrainingPercentDone += (sTrainingPts / 100);
|
|
pSectorInfo -> ubMilitiaTrainingHundredths += (sTrainingPts % 100);
|
|
|
|
if (pSectorInfo -> ubMilitiaTrainingHundredths >= 100)
|
|
{
|
|
pSectorInfo -> ubMilitiaTrainingPercentDone++;
|
|
pSectorInfo -> ubMilitiaTrainingHundredths -= 100;
|
|
}
|
|
|
|
// NOTE: Leave this at 100, change TOWN_TRAINING_RATE if necessary. This value gets reported to player as a %age!
|
|
if( pSectorInfo -> ubMilitiaTrainingPercentDone >= 100 )
|
|
{
|
|
// zero out training completion - there's no carryover to the next training session
|
|
pSectorInfo -> ubMilitiaTrainingPercentDone = 0;
|
|
pSectorInfo -> ubMilitiaTrainingHundredths = 0;
|
|
|
|
// make the player pay again next time he wants to train here
|
|
pSectorInfo -> fMilitiaTrainingPaid = FALSE;
|
|
|
|
TownMilitiaTrainingCompleted( pTrainer, sMapX, sMapY );
|
|
|
|
// training done
|
|
return( TRUE );
|
|
}
|
|
else
|
|
{
|
|
// not done
|
|
return ( FALSE );
|
|
}
|
|
}
|
|
|
|
|
|
INT16 GetTownTrainPtsForCharacter( SOLDIERTYPE *pTrainer, UINT16 *pusMaxPts )
|
|
{
|
|
INT16 sTotalTrainingPts = 0;
|
|
INT8 bTrainingBonus = 0;
|
|
// UINT8 ubTownId = 0;
|
|
|
|
// calculate normal training pts - what it would be if his stats were "normal" (ignoring drugs, fatigue)
|
|
*pusMaxPts = ( pTrainer -> bWisdom + pTrainer -> bLeadership + ( 10 * pTrainer -> bExpLevel ) ) * gGameExternalOptions.ubTownMilitiaTrainingRate;
|
|
|
|
// calculate effective training points (this is hundredths of pts / hour)
|
|
// typical: 300/hr, maximum: 600/hr
|
|
sTotalTrainingPts = ( EffectiveWisdom( pTrainer ) + EffectiveLeadership ( pTrainer ) + ( 10 * EffectiveExpLevel ( pTrainer ) ) ) * gGameExternalOptions.ubTownMilitiaTrainingRate;
|
|
|
|
// check for teaching bonuses
|
|
if( gMercProfiles[ pTrainer -> ubProfile ].bSkillTrait == TEACHING )
|
|
{
|
|
bTrainingBonus += gGameExternalOptions.ubTeachBonusToTrain;
|
|
}
|
|
if( gMercProfiles[ pTrainer -> ubProfile ].bSkillTrait2 == TEACHING )
|
|
{
|
|
bTrainingBonus += gGameExternalOptions.ubTeachBonusToTrain;
|
|
}
|
|
|
|
// RPCs get a small training bonus for being more familiar with the locals and their customs/needs than outsiders
|
|
if( pTrainer->ubProfile >= FIRST_RPC )
|
|
{
|
|
bTrainingBonus += gGameExternalOptions.ubRpcBonusToTrainMilitia;
|
|
}
|
|
|
|
// adjust for teaching bonus (a percentage)
|
|
sTotalTrainingPts += ( ( bTrainingBonus * sTotalTrainingPts ) / 100 );
|
|
// teach bonus is considered "normal" - it's always there
|
|
*pusMaxPts += ( ( bTrainingBonus * *pusMaxPts ) / 100 );
|
|
|
|
|
|
// adjust for fatigue of trainer
|
|
ReducePointsForFatigue( pTrainer, (UINT16 *)&sTotalTrainingPts );
|
|
|
|
|
|
/* ARM: Decided this didn't make much sense - the guys I'm training damn well BETTER be loyal - and screw the rest!
|
|
// get town index
|
|
ubTownId = StrategicMap[ pTrainer -> sSectorX + pTrainer -> sSectorY * MAP_WORLD_X ].bNameId;
|
|
Assert(ubTownId != BLANK_SECTOR);
|
|
|
|
// adjust for town loyalty
|
|
sTotalTrainingPts = (sTotalTrainingPts * gTownLoyalty[ ubTownId ].ubRating) / 100;
|
|
*/
|
|
|
|
return( sTotalTrainingPts );
|
|
}
|
|
|
|
|
|
void MakeSoldiersTacticalAnimationReflectAssignment( SOLDIERTYPE *pSoldier )
|
|
{
|
|
// soldier is in tactical, world loaded, he's OKLIFE
|
|
if( ( pSoldier -> bInSector ) && gfWorldLoaded && ( pSoldier -> bLife >= OKLIFE ) )
|
|
{
|
|
// Set animation based on his assignment
|
|
if ( pSoldier -> bAssignment == DOCTOR )
|
|
{
|
|
SoldierInSectorDoctor( pSoldier, pSoldier -> usStrategicInsertionData );
|
|
}
|
|
else if ( pSoldier -> bAssignment == PATIENT )
|
|
{
|
|
SoldierInSectorPatient( pSoldier, pSoldier -> usStrategicInsertionData );
|
|
}
|
|
else if ( pSoldier -> bAssignment == REPAIR )
|
|
{
|
|
SoldierInSectorRepair( pSoldier, pSoldier -> usStrategicInsertionData );
|
|
}
|
|
else
|
|
{
|
|
if ( pSoldier->usAnimState != WKAEUP_FROM_SLEEP && !(pSoldier->bOldAssignment < ON_DUTY ) )
|
|
{
|
|
// default: standing
|
|
ChangeSoldierState( pSoldier, STANDING, 1, TRUE );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void AssignmentAborted( SOLDIERTYPE *pSoldier, UINT8 ubReason )
|
|
{
|
|
Assert( ubReason < NUM_ASSIGN_ABORT_REASONS );
|
|
|
|
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, gzLateLocalizedString[ ubReason ], pSoldier->name );
|
|
|
|
StopTimeCompression();
|
|
|
|
// update mapscreen
|
|
fCharacterInfoPanelDirty = TRUE;
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
}
|
|
|
|
|
|
|
|
void AssignmentDone( SOLDIERTYPE *pSoldier, BOOLEAN fSayQuote, BOOLEAN fMeToo )
|
|
{
|
|
if ( ( pSoldier -> bInSector ) && ( gfWorldLoaded ) )
|
|
{
|
|
if ( pSoldier -> bAssignment == DOCTOR )
|
|
{
|
|
if ( guiCurrentScreen == GAME_SCREEN )
|
|
{
|
|
ChangeSoldierState( pSoldier, END_DOCTOR, 1, TRUE );
|
|
}
|
|
else
|
|
{
|
|
ChangeSoldierState( pSoldier, STANDING, 1, TRUE );
|
|
}
|
|
|
|
}
|
|
else if ( pSoldier -> bAssignment == REPAIR )
|
|
{
|
|
if ( guiCurrentScreen == GAME_SCREEN )
|
|
{
|
|
ChangeSoldierState( pSoldier, END_REPAIRMAN, 1, TRUE );
|
|
}
|
|
else
|
|
{
|
|
ChangeSoldierState( pSoldier, STANDING, 1, TRUE );
|
|
}
|
|
}
|
|
else if ( pSoldier -> bAssignment == PATIENT )
|
|
{
|
|
if ( guiCurrentScreen == GAME_SCREEN )
|
|
{
|
|
ChangeSoldierStance( pSoldier, ANIM_CROUCH );
|
|
}
|
|
else
|
|
{
|
|
ChangeSoldierState( pSoldier, STANDING, 1, TRUE );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( pSoldier->bAssignment == ASSIGNMENT_HOSPITAL )
|
|
{
|
|
// hack - reset AbsoluteFinalDestination in case it was left non-nowhere
|
|
pSoldier->sAbsoluteFinalDestination = NOWHERE;
|
|
}
|
|
|
|
if ( fSayQuote )
|
|
{
|
|
if ( ( fMeToo == FALSE ) && (pSoldier->bAssignment == TRAIN_TOWN ) )
|
|
{
|
|
TacticalCharacterDialogue( pSoldier, QUOTE_ASSIGNMENT_COMPLETE );
|
|
|
|
if( pSoldier -> bAssignment == TRAIN_TOWN )
|
|
{
|
|
AddSectorForSoldierToListOfSectorsThatCompletedMilitiaTraining( pSoldier );
|
|
}
|
|
}
|
|
}
|
|
|
|
// don't bother telling us again about guys we already know about
|
|
if ( !( pSoldier->usQuoteSaidExtFlags & SOLDIER_QUOTE_SAID_DONE_ASSIGNMENT ) )
|
|
{
|
|
pSoldier->usQuoteSaidExtFlags |= SOLDIER_QUOTE_SAID_DONE_ASSIGNMENT;
|
|
|
|
if ( fSayQuote )
|
|
{
|
|
if ( pSoldier->bAssignment == DOCTOR || pSoldier->bAssignment == REPAIR ||
|
|
pSoldier->bAssignment == PATIENT || pSoldier->bAssignment == ASSIGNMENT_HOSPITAL )
|
|
{
|
|
TacticalCharacterDialogue( pSoldier, QUOTE_ASSIGNMENT_COMPLETE );
|
|
}
|
|
}
|
|
|
|
|
|
AddReasonToWaitingListQueue( ASSIGNMENT_FINISHED_FOR_UPDATE );
|
|
AddSoldierToWaitingListQueue( pSoldier );
|
|
|
|
// trigger a single call AddDisplayBoxToWaitingQueue for assignments done
|
|
gfAddDisplayBoxToWaitingQueue = TRUE;
|
|
}
|
|
|
|
// update mapscreen
|
|
fCharacterInfoPanelDirty = TRUE;
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
}
|
|
|
|
BOOLEAN CharacterIsBetweenSectors( SOLDIERTYPE *pSoldier )
|
|
{
|
|
// is the character on the move
|
|
if( pSoldier == NULL )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
else
|
|
{
|
|
return( pSoldier -> fBetweenSectors );
|
|
}
|
|
}
|
|
|
|
|
|
void HandleNaturalHealing( void )
|
|
{
|
|
SOLDIERTYPE *pSoldier, *pTeamSoldier;
|
|
INT32 cnt=0;
|
|
INT32 iCounter=0;
|
|
INT8 bNumberOfPeople = 0;
|
|
|
|
// set psoldier as first in merc ptrs
|
|
pSoldier = MercPtrs[0];
|
|
|
|
// go through list of characters, find all who are on this assignment
|
|
for ( pTeamSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ pSoldier -> bTeam ].bLastID; cnt++,pTeamSoldier++)
|
|
{
|
|
if( pTeamSoldier -> bActive )
|
|
{
|
|
// mechanical members don't regenerate!
|
|
if( !( pTeamSoldier -> uiStatusFlags & SOLDIER_VEHICLE ) && !( AM_A_ROBOT( pTeamSoldier ) ) )
|
|
{
|
|
HandleHealingByNaturalCauses( pTeamSoldier );
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
// handle healing of this soldier by natural causes.
|
|
void HandleHealingByNaturalCauses( SOLDIERTYPE *pSoldier )
|
|
{
|
|
UINT32 uiPercentHealth = 0;
|
|
INT8 bActivityLevelDivisor = 0;
|
|
|
|
|
|
// check if soldier valid
|
|
if( pSoldier == NULL )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// dead
|
|
if( pSoldier -> bLife == 0 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// lost any pts?
|
|
if( pSoldier -> bLife == pSoldier -> bLifeMax )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// any bleeding pts - can' recover if still bleeding!
|
|
if( pSoldier -> bBleeding != 0 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
// not bleeding and injured...
|
|
|
|
if( pSoldier -> bAssignment == ASSIGNMENT_POW )
|
|
{
|
|
// use high activity level to simulate stress, torture, poor conditions for healing
|
|
bActivityLevelDivisor = gGameExternalOptions.ubHighActivityLevel;
|
|
}
|
|
if( ( pSoldier -> fMercAsleep == TRUE ) || ( pSoldier -> bAssignment == PATIENT ) || ( pSoldier -> bAssignment == ASSIGNMENT_HOSPITAL ) )
|
|
{
|
|
bActivityLevelDivisor = gGameExternalOptions.ubLowActivityLevel;
|
|
}
|
|
else if ( pSoldier->bAssignment < ON_DUTY )
|
|
{
|
|
// if time is being compressed, and the soldier is not moving strategically
|
|
if ( IsTimeBeingCompressed() && !PlayerIDGroupInMotion( pSoldier->ubGroupID ) )
|
|
{
|
|
// basically resting
|
|
bActivityLevelDivisor = gGameExternalOptions.ubLowActivityLevel;
|
|
}
|
|
else
|
|
{
|
|
// either they're on the move, or they're being tactically active
|
|
bActivityLevelDivisor = gGameExternalOptions.ubHighActivityLevel;
|
|
}
|
|
}
|
|
else // this includes being in a vehicle - that's neither very strenous, nor very restful
|
|
{
|
|
bActivityLevelDivisor = gGameExternalOptions.ubMediumActivityLevel;
|
|
}
|
|
|
|
|
|
// what percentage of health is he down to
|
|
uiPercentHealth = ( pSoldier->bLife * 100 ) / pSoldier->bLifeMax;
|
|
|
|
// gain that many hundredths of life points back, divided by the activity level modifier
|
|
pSoldier->sFractLife += ( INT16 ) ( uiPercentHealth / bActivityLevelDivisor );
|
|
|
|
// now update the real life values
|
|
UpDateSoldierLife( pSoldier );
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void UpDateSoldierLife( SOLDIERTYPE *pSoldier )
|
|
{
|
|
// update soldier life, make sure we don't go out of bounds
|
|
pSoldier -> bLife += pSoldier -> sFractLife / 100;
|
|
|
|
// keep remaining fract of life
|
|
pSoldier -> sFractLife %= 100;
|
|
|
|
// check if we have gone too far
|
|
if( pSoldier -> bLife >= pSoldier -> bLifeMax )
|
|
{
|
|
// reduce
|
|
pSoldier -> bLife = pSoldier -> bLifeMax;
|
|
pSoldier -> sFractLife = 0;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
// merc is tired, put to sleep
|
|
BOOLEAN AutoSleepMerc( SOLDIERTYPE *pSoldier )
|
|
{
|
|
if( pSoldier == NULL )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
|
|
// already asleep
|
|
if( pSoldier -> fMercAsleep == TRUE )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
|
|
if( pSoldier -> bBreathMax > MIN_BREATH_TO_STAY_AWAKE )
|
|
{
|
|
if( ( pSoldier -> bAssignment < ON_DUTY ) )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
|
|
if( pSoldier -> bLife < OKLIFE )
|
|
{
|
|
// can't sleep
|
|
return ( FALSE );
|
|
}
|
|
|
|
|
|
// if was forced to stay awake, leave
|
|
if( pSoldier -> fForcedToStayAwake == TRUE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"%s", pMercFellAsleepString[ 0 ], pSoldier -> name );
|
|
}
|
|
|
|
|
|
// store old assignment
|
|
pSoldier -> bOldAssignment = pSoldier -> bAssignment;
|
|
|
|
|
|
if( pSoldier -> bAssignment < ON_DUTY )
|
|
{
|
|
RemoveCharacterFromASquad( pSoldier, pSoldier -> bAssignment );
|
|
}
|
|
|
|
if( SetMercAsleep( pSoldier, FALSE ) )
|
|
{
|
|
// change soldier state
|
|
SoldierInSectorSleep( pSoldier, pSoldier -> usStrategicInsertionData );
|
|
|
|
// update mapscreen
|
|
fCharacterInfoPanelDirty = TRUE;
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
|
|
return( TRUE );
|
|
}
|
|
else
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
*/
|
|
|
|
|
|
|
|
void CheckIfSoldierUnassigned( SOLDIERTYPE *pSoldier )
|
|
{
|
|
if( pSoldier -> bAssignment == NO_ASSIGNMENT )
|
|
{
|
|
// unassigned
|
|
AddCharacterToAnySquad( pSoldier );
|
|
|
|
if( ( gfWorldLoaded ) && ( pSoldier->bInSector ) )
|
|
{
|
|
ChangeSoldierState( pSoldier, STANDING, 1, TRUE );
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void CreateDestroyMouseRegionsForAssignmentMenu( void )
|
|
{
|
|
static BOOLEAN fCreated = FALSE;
|
|
UINT32 iCounter = 0;
|
|
INT32 iFontHeight = 0;
|
|
INT32 iBoxXPosition = 0;
|
|
INT32 iBoxYPosition = 0;
|
|
SOLDIERTYPE *pSoldier = NULL;
|
|
SGPPoint pPosition;
|
|
INT32 iBoxWidth = 0;
|
|
SGPRect pDimensions;
|
|
static BOOLEAN fShowRemoveMenu = FALSE;
|
|
|
|
|
|
// will create/destroy mouse regions for the map screen assignment main menu
|
|
// check if we can only remove character from team..not assign
|
|
if( ( bSelectedAssignChar != -1 )|| ( fShowRemoveMenu == TRUE ) )
|
|
{
|
|
if( fShowRemoveMenu == TRUE )
|
|
{
|
|
// dead guy handle menu stuff
|
|
fShowRemoveMenu = fShowAssignmentMenu | fShowContractMenu;
|
|
|
|
CreateDestroyMouseRegionsForRemoveMenu( );
|
|
|
|
return;
|
|
}
|
|
if( ( Menptr[gCharactersList[bSelectedAssignChar].usSolID].bLife == 0 ) || ( Menptr[gCharactersList[bSelectedAssignChar].usSolID].bAssignment == ASSIGNMENT_POW ) )
|
|
{
|
|
// dead guy handle menu stuff
|
|
fShowRemoveMenu = fShowAssignmentMenu | fShowContractMenu;
|
|
|
|
CreateDestroyMouseRegionsForRemoveMenu( );
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
if( ( fShowAssignmentMenu == TRUE ) && ( fCreated == FALSE ) )
|
|
{
|
|
|
|
gfIgnoreScrolling = FALSE;
|
|
|
|
if( ( fShowAssignmentMenu ) && ( guiCurrentScreen == MAP_SCREEN ) )
|
|
{
|
|
SetBoxPosition( ghAssignmentBox, AssignmentPosition );
|
|
}
|
|
|
|
pSoldier = GetSelectedAssignSoldier( FALSE );
|
|
|
|
if( pSoldier -> ubWhatKindOfMercAmI == MERC_TYPE__EPC )
|
|
{
|
|
// grab height of font
|
|
iFontHeight = GetLineSpace( ghEpcBox ) + GetFontHeight( GetBoxFont( ghEpcBox ) );
|
|
|
|
// get x.y position of box
|
|
GetBoxPosition( ghEpcBox, &pPosition);
|
|
|
|
// grab box x and y position
|
|
iBoxXPosition = pPosition.iX;
|
|
iBoxYPosition = pPosition.iY;
|
|
|
|
// get dimensions..mostly for width
|
|
GetBoxSize( ghEpcBox, &pDimensions );
|
|
|
|
// get width
|
|
iBoxWidth = pDimensions.iRight;
|
|
|
|
SetCurrentBox( ghEpcBox );
|
|
}
|
|
else
|
|
{
|
|
// grab height of font
|
|
iFontHeight = GetLineSpace( ghAssignmentBox ) + GetFontHeight( GetBoxFont( ghAssignmentBox ) );
|
|
|
|
// get x.y position of box
|
|
GetBoxPosition( ghAssignmentBox, &pPosition);
|
|
|
|
// grab box x and y position
|
|
iBoxXPosition = pPosition.iX;
|
|
iBoxYPosition = pPosition.iY;
|
|
|
|
// get dimensions..mostly for width
|
|
GetBoxSize( ghAssignmentBox, &pDimensions );
|
|
|
|
// get width
|
|
iBoxWidth = pDimensions.iRight;
|
|
|
|
SetCurrentBox( ghAssignmentBox );
|
|
}
|
|
|
|
|
|
// define regions
|
|
for( iCounter = 0; iCounter < GetNumberOfLinesOfTextInBox( ghAssignmentBox ); iCounter++ )
|
|
{
|
|
// add mouse region for each line of text..and set user data
|
|
MSYS_DefineRegion( &gAssignmentMenuRegion[ iCounter ], ( INT16 )( iBoxXPosition ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghAssignmentBox ) + ( iFontHeight ) * iCounter ), ( INT16 )( iBoxXPosition + iBoxWidth ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghAssignmentBox ) + ( iFontHeight ) * ( iCounter + 1 ) ), MSYS_PRIORITY_HIGHEST - 4 ,
|
|
MSYS_NO_CURSOR, AssignmentMenuMvtCallBack, AssignmentMenuBtnCallback );
|
|
|
|
MSYS_SetRegionUserData( &gAssignmentMenuRegion[ iCounter ], 0, iCounter );
|
|
}
|
|
|
|
// created
|
|
fCreated = TRUE;
|
|
|
|
// unhighlight all strings in box
|
|
UnHighLightBox( ghAssignmentBox );
|
|
CheckAndUpdateTacticalAssignmentPopUpPositions( );
|
|
|
|
PositionCursorForTacticalAssignmentBox( );
|
|
}
|
|
else if( ( fShowAssignmentMenu == FALSE ) && ( fCreated == TRUE ) )
|
|
{
|
|
// destroy
|
|
for( iCounter = 0; iCounter < GetNumberOfLinesOfTextInBox( ghAssignmentBox ); iCounter++ )
|
|
{
|
|
MSYS_RemoveRegion( &gAssignmentMenuRegion[ iCounter ] );
|
|
}
|
|
|
|
fShownAssignmentMenu = FALSE;
|
|
|
|
// not created
|
|
fCreated = FALSE;
|
|
SetRenderFlags( RENDER_FLAG_FULL );
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void CreateDestroyMouseRegionForVehicleMenu( void )
|
|
{
|
|
static BOOLEAN fCreated = FALSE;
|
|
|
|
UINT32 uiMenuLine = 0;
|
|
INT32 iVehicleId = 0;
|
|
INT32 iFontHeight = 0;
|
|
INT32 iBoxXPosition = 0;
|
|
INT32 iBoxYPosition = 0;
|
|
SGPPoint pPosition, pPoint;
|
|
INT32 iBoxWidth = 0;
|
|
SGPRect pDimensions;
|
|
SOLDIERTYPE *pSoldier = NULL;
|
|
|
|
|
|
if( fShowVehicleMenu )
|
|
{
|
|
GetBoxPosition( ghAssignmentBox, &pPoint);
|
|
|
|
// get dimensions..mostly for width
|
|
GetBoxSize( ghAssignmentBox, &pDimensions );
|
|
|
|
// vehicle position
|
|
VehiclePosition.iX = pPoint.iX + pDimensions.iRight;
|
|
|
|
SetBoxPosition( ghVehicleBox , VehiclePosition );
|
|
}
|
|
|
|
|
|
if( ( fShowVehicleMenu == TRUE ) && ( fCreated == FALSE ) )
|
|
{
|
|
// grab height of font
|
|
iFontHeight = GetLineSpace( ghVehicleBox ) + GetFontHeight( GetBoxFont( ghVehicleBox ) );
|
|
|
|
// get x.y position of box
|
|
GetBoxPosition( ghVehicleBox, &pPosition);
|
|
|
|
// grab box x and y position
|
|
iBoxXPosition = pPosition.iX;
|
|
iBoxYPosition = pPosition.iY;
|
|
|
|
// get dimensions..mostly for width
|
|
GetBoxSize( ghVehicleBox, &pDimensions );
|
|
SetBoxSecondaryShade( ghVehicleBox, FONT_YELLOW );
|
|
|
|
// get width
|
|
iBoxWidth = pDimensions.iRight;
|
|
|
|
SetCurrentBox( ghVehicleBox );
|
|
|
|
pSoldier = GetSelectedAssignSoldier( FALSE );
|
|
|
|
// run through list of vehicles in sector
|
|
for ( iVehicleId = 0; iVehicleId < ubNumberOfVehicles; iVehicleId++ )
|
|
{
|
|
if ( pVehicleList[ iVehicleId ].fValid == TRUE )
|
|
{
|
|
if ( IsThisVehicleAccessibleToSoldier( pSoldier, iVehicleId ) )
|
|
{
|
|
// add mouse region for each accessible vehicle
|
|
MSYS_DefineRegion( &gVehicleMenuRegion[ uiMenuLine ], ( INT16 )( iBoxXPosition ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghAssignmentBox ) + ( iFontHeight ) * uiMenuLine ), ( INT16 )( iBoxXPosition + iBoxWidth ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghAssignmentBox ) + ( iFontHeight ) * ( uiMenuLine + 1 ) ), MSYS_PRIORITY_HIGHEST - 4 ,
|
|
MSYS_NO_CURSOR, VehicleMenuMvtCallback, VehicleMenuBtnCallback );
|
|
|
|
MSYS_SetRegionUserData( &gVehicleMenuRegion[ uiMenuLine ], 0, uiMenuLine );
|
|
// store vehicle ID in the SECOND user data
|
|
MSYS_SetRegionUserData( &gVehicleMenuRegion[ uiMenuLine ], 1, iVehicleId );
|
|
|
|
uiMenuLine++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// cancel line
|
|
MSYS_DefineRegion( &gVehicleMenuRegion[ uiMenuLine ], ( INT16 )( iBoxXPosition ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghAssignmentBox ) + ( iFontHeight ) * uiMenuLine ), ( INT16 )( iBoxXPosition + iBoxWidth ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghAssignmentBox ) + ( iFontHeight ) * ( uiMenuLine + 1 ) ), MSYS_PRIORITY_HIGHEST - 4 ,
|
|
MSYS_NO_CURSOR, VehicleMenuMvtCallback, VehicleMenuBtnCallback );
|
|
MSYS_SetRegionUserData( &gVehicleMenuRegion[ uiMenuLine ], 0, VEHICLE_MENU_CANCEL );
|
|
|
|
// created
|
|
fCreated = TRUE;
|
|
|
|
// pause game
|
|
PauseGame( );
|
|
|
|
// unhighlight all strings in box
|
|
UnHighLightBox( ghVehicleBox );
|
|
|
|
fCreated = TRUE;
|
|
|
|
HandleShadingOfLinesForVehicleMenu( );
|
|
}
|
|
else if( ( ( fShowVehicleMenu == FALSE ) || ( fShowAssignmentMenu == FALSE ) ) && ( fCreated == TRUE ) )
|
|
{
|
|
fCreated = FALSE;
|
|
|
|
// remove these regions
|
|
for( uiMenuLine = 0; uiMenuLine < GetNumberOfLinesOfTextInBox( ghVehicleBox ); uiMenuLine++ )
|
|
{
|
|
MSYS_RemoveRegion( &gVehicleMenuRegion[ uiMenuLine ] );
|
|
}
|
|
|
|
fShowVehicleMenu = FALSE;
|
|
|
|
SetRenderFlags( RENDER_FLAG_FULL );
|
|
|
|
HideBox( ghVehicleBox );
|
|
|
|
if ( fShowAssignmentMenu )
|
|
{
|
|
// remove highlight on the parent menu
|
|
UnHighLightBox( ghAssignmentBox );
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void HandleShadingOfLinesForVehicleMenu( void )
|
|
{
|
|
SOLDIERTYPE *pSoldier = NULL;
|
|
INT32 iVehicleId;
|
|
UINT32 uiMenuLine = 0;
|
|
|
|
|
|
if ( ( fShowVehicleMenu == FALSE ) || ( ghVehicleBox == - 1 ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
pSoldier = GetSelectedAssignSoldier( FALSE );
|
|
|
|
// run through list of vehicles
|
|
for ( iVehicleId = 0; iVehicleId < ubNumberOfVehicles; iVehicleId++ )
|
|
{
|
|
if ( pVehicleList[ iVehicleId ].fValid == TRUE )
|
|
{
|
|
// inaccessible vehicles aren't listed at all!
|
|
if ( IsThisVehicleAccessibleToSoldier( pSoldier, iVehicleId ) )
|
|
{
|
|
if ( IsEnoughSpaceInVehicle( iVehicleId ) )
|
|
{
|
|
// legal vehicle, leave it green
|
|
UnShadeStringInBox( ghVehicleBox, uiMenuLine );
|
|
UnSecondaryShadeStringInBox( ghVehicleBox, uiMenuLine );
|
|
}
|
|
else
|
|
{
|
|
// unjoinable vehicle - yellow
|
|
SecondaryShadeStringInBox( ghVehicleBox, uiMenuLine );
|
|
}
|
|
|
|
uiMenuLine++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void VehicleMenuBtnCallback( MOUSE_REGION * pRegion, INT32 iReason )
|
|
{
|
|
// btn callback handler for assignment region
|
|
INT32 iValue = -1, iVehicleID;
|
|
SOLDIERTYPE * pSoldier;
|
|
|
|
|
|
iValue = MSYS_GetRegionUserData( pRegion, 0 );
|
|
|
|
if (iReason & MSYS_CALLBACK_REASON_LBUTTON_UP)
|
|
{
|
|
if( iValue == VEHICLE_MENU_CANCEL )
|
|
{
|
|
fShowVehicleMenu = FALSE;
|
|
UnHighLightBox( ghAssignmentBox );
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
fCharacterInfoPanelDirty = TRUE;
|
|
return;
|
|
}
|
|
|
|
pSoldier = GetSelectedAssignSoldier( FALSE );
|
|
iVehicleID = MSYS_GetRegionUserData( pRegion, 1 );
|
|
|
|
// inaccessible vehicles shouldn't be listed in the menu!
|
|
Assert( IsThisVehicleAccessibleToSoldier( pSoldier, iVehicleID ) );
|
|
|
|
if ( IsEnoughSpaceInVehicle( iVehicleID ) )
|
|
{
|
|
PutSoldierInVehicle( pSoldier, ( INT8 ) iVehicleID );
|
|
}
|
|
else
|
|
{
|
|
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, gzLateLocalizedString[ 18 ], zVehicleName[ pVehicleList[ iVehicleID ].ubVehicleType ] );
|
|
}
|
|
|
|
fShowAssignmentMenu = FALSE;
|
|
|
|
// update mapscreen
|
|
fTeamPanelDirty = TRUE;
|
|
fCharacterInfoPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
|
|
giAssignHighLine = -1;
|
|
|
|
SetAssignmentForList( VEHICLE, ( INT8 ) iVehicleID );
|
|
}
|
|
}
|
|
|
|
|
|
void VehicleMenuMvtCallback(MOUSE_REGION * pRegion, INT32 iReason )
|
|
{
|
|
// mvt callback handler for assignment region
|
|
INT32 iValue = -1;
|
|
|
|
iValue = MSYS_GetRegionUserData( pRegion, 0 );
|
|
|
|
if (iReason & MSYS_CALLBACK_REASON_GAIN_MOUSE )
|
|
{
|
|
if( iValue != VEHICLE_MENU_CANCEL )
|
|
{
|
|
// no shaded(disabled) lines actually appear in vehicle menus
|
|
if( GetBoxShadeFlag( ghVehicleBox, iValue ) == FALSE )
|
|
{
|
|
// highlight vehicle line
|
|
HighLightBoxLine( ghVehicleBox, iValue );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// highlight cancel line
|
|
HighLightBoxLine( ghVehicleBox, GetNumberOfLinesOfTextInBox( ghVehicleBox ) - 1 );
|
|
}
|
|
}
|
|
else if (iReason & MSYS_CALLBACK_REASON_LOST_MOUSE )
|
|
{
|
|
// unhighlight all strings in box
|
|
UnHighLightBox( ghVehicleBox );
|
|
|
|
HandleShadingOfLinesForVehicleMenu( );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN DisplayRepairMenu( SOLDIERTYPE *pSoldier )
|
|
{
|
|
INT32 iVehicleIndex=0;
|
|
INT32 hStringHandle=0;
|
|
|
|
|
|
// run through list of vehicles in sector and add them to pop up box
|
|
// first, clear pop up box
|
|
RemoveBox(ghRepairBox);
|
|
ghRepairBox = -1;
|
|
|
|
CreateRepairBox();
|
|
SetCurrentBox(ghRepairBox);
|
|
|
|
// PLEASE NOTE: make sure any changes you do here are reflected in all 3 routines which must remain in synch:
|
|
// CreateDestroyMouseRegionForRepairMenu(), DisplayRepairMenu(), and HandleShadingOfLinesForRepairMenu().
|
|
|
|
if( pSoldier->bSectorZ == 0 )
|
|
{
|
|
// run through list of vehicles and see if any in sector
|
|
for ( iVehicleIndex = 0; iVehicleIndex < ubNumberOfVehicles; iVehicleIndex++ )
|
|
{
|
|
if ( pVehicleList[ iVehicleIndex ].fValid == TRUE )
|
|
{
|
|
// don't even list the helicopter, because it's NEVER repairable...
|
|
if ( iVehicleIndex != iHelicopterVehicleId )
|
|
{
|
|
if ( IsThisVehicleAccessibleToSoldier( pSoldier, iVehicleIndex ) )
|
|
{
|
|
AddMonoString( (UINT32 *)&hStringHandle,pVehicleStrings[ pVehicleList[ iVehicleIndex ].ubVehicleType ] );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* No point in allowing SAM site repair any more. Jan/13/99. ARM
|
|
// is there a SAM SITE Here?
|
|
if( ( IsThisSectorASAMSector( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ ) == TRUE ) && ( IsTheSAMSiteInSectorRepairable( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ ) ) )
|
|
{
|
|
// SAM site
|
|
AddMonoString(&hStringHandle, pRepairStrings[ 1 ] );
|
|
}
|
|
*/
|
|
|
|
|
|
// is the ROBOT here?
|
|
if( IsRobotInThisSector( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ ) )
|
|
{
|
|
// robot
|
|
AddMonoString((UINT32 *)&hStringHandle, pRepairStrings[ 3 ] );
|
|
}
|
|
|
|
|
|
// items
|
|
AddMonoString((UINT32 *)&hStringHandle, pRepairStrings[ 0 ] );
|
|
|
|
|
|
// cancel
|
|
AddMonoString((UINT32 *)&hStringHandle, pRepairStrings[ 2 ] );
|
|
|
|
SetBoxFont(ghRepairBox, MAP_SCREEN_FONT);
|
|
SetBoxHighLight(ghRepairBox, FONT_WHITE);
|
|
SetBoxShade(ghRepairBox, FONT_GRAY7);
|
|
SetBoxForeground(ghRepairBox, FONT_LTGREEN);
|
|
SetBoxBackground(ghRepairBox, FONT_BLACK);
|
|
|
|
// resize box to text
|
|
ResizeBoxToText( ghRepairBox );
|
|
|
|
CheckAndUpdateTacticalAssignmentPopUpPositions( );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void HandleShadingOfLinesForRepairMenu( void )
|
|
{
|
|
SOLDIERTYPE *pSoldier = NULL;
|
|
INT32 iVehicleIndex = 0;
|
|
INT32 iCount = 0;
|
|
|
|
|
|
if( ( fShowRepairMenu == FALSE ) || ( ghRepairBox == -1 ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
pSoldier = GetSelectedAssignSoldier( FALSE );
|
|
|
|
|
|
// PLEASE NOTE: make sure any changes you do here are reflected in all 3 routines which must remain in synch:
|
|
// CreateDestroyMouseRegionForRepairMenu(), DisplayRepairMenu(), and HandleShadingOfLinesForRepairMenu().
|
|
|
|
if ( pSoldier->bSectorZ == 0 )
|
|
{
|
|
for ( iVehicleIndex = 0; iVehicleIndex < ubNumberOfVehicles; iVehicleIndex++ )
|
|
{
|
|
if ( pVehicleList[ iVehicleIndex ].fValid == TRUE )
|
|
{
|
|
// don't even list the helicopter, because it's NEVER repairable...
|
|
if ( iVehicleIndex != iHelicopterVehicleId )
|
|
{
|
|
if ( IsThisVehicleAccessibleToSoldier( pSoldier, iVehicleIndex ) )
|
|
{
|
|
if( CanCharacterRepairVehicle( pSoldier, iVehicleIndex ) == TRUE )
|
|
{
|
|
// unshade vehicle line
|
|
UnShadeStringInBox( ghRepairBox, iCount );
|
|
}
|
|
else
|
|
{
|
|
// shade vehicle line
|
|
ShadeStringInBox( ghRepairBox, iCount );
|
|
}
|
|
|
|
iCount++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* No point in allowing SAM site repair any more. Jan/13/99. ARM
|
|
if( ( IsThisSectorASAMSector( pSoldier -> sSectorX, pSoldier -> sSectorY, pSoldier -> bSectorZ ) == TRUE ) && ( IsTheSAMSiteInSectorRepairable( pSoldier -> sSectorX, pSoldier -> sSectorY, pSoldier -> bSectorZ ) ) )
|
|
{
|
|
// handle enable disable of repair sam option
|
|
if( CanSoldierRepairSAM( pSoldier, SAM_SITE_REPAIR_DIVISOR ) )
|
|
{
|
|
// unshade SAM line
|
|
UnShadeStringInBox( ghRepairBox, iCount );
|
|
}
|
|
else
|
|
{
|
|
// shade SAM line
|
|
ShadeStringInBox( ghRepairBox, iCount );
|
|
}
|
|
|
|
iCount++;
|
|
}
|
|
*/
|
|
|
|
|
|
if( IsRobotInThisSector( pSoldier -> sSectorX, pSoldier -> sSectorY, pSoldier -> bSectorZ ) )
|
|
{
|
|
// handle shading of repair robot option
|
|
if( CanCharacterRepairRobot( pSoldier ) )
|
|
{
|
|
// unshade robot line
|
|
UnShadeStringInBox( ghRepairBox, iCount );
|
|
}
|
|
else
|
|
{
|
|
// shade robot line
|
|
ShadeStringInBox( ghRepairBox, iCount );
|
|
}
|
|
|
|
iCount++;
|
|
}
|
|
|
|
|
|
if ( DoesCharacterHaveAnyItemsToRepair( pSoldier, FINAL_REPAIR_PASS ) )
|
|
{
|
|
// unshade items line
|
|
UnShadeStringInBox( ghRepairBox, iCount );
|
|
}
|
|
else
|
|
{
|
|
// shade items line
|
|
ShadeStringInBox( ghRepairBox, iCount );
|
|
}
|
|
|
|
iCount++;
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void CreateDestroyMouseRegionForRepairMenu( void )
|
|
{
|
|
static BOOLEAN fCreated = FALSE;
|
|
|
|
UINT32 uiCounter = 0;
|
|
INT32 iCount = 0;
|
|
INT32 iFontHeight = 0;
|
|
INT32 iBoxXPosition = 0;
|
|
INT32 iBoxYPosition = 0;
|
|
SGPPoint pPosition;
|
|
INT32 iBoxWidth = 0;
|
|
SGPRect pDimensions;
|
|
SOLDIERTYPE *pSoldier = NULL;
|
|
INT32 iVehicleIndex = 0;
|
|
|
|
|
|
if( ( fShowRepairMenu == TRUE ) && ( fCreated == FALSE ) )
|
|
{
|
|
CheckAndUpdateTacticalAssignmentPopUpPositions( );
|
|
|
|
if( ( fShowRepairMenu ) && ( guiCurrentScreen == MAP_SCREEN ) )
|
|
{
|
|
//SetBoxPosition( ghRepairBox ,RepairPosition);
|
|
}
|
|
|
|
// grab height of font
|
|
iFontHeight = GetLineSpace( ghRepairBox ) + GetFontHeight( GetBoxFont( ghRepairBox ) );
|
|
|
|
// get x.y position of box
|
|
GetBoxPosition( ghRepairBox, &pPosition);
|
|
|
|
// grab box x and y position
|
|
iBoxXPosition = pPosition.iX;
|
|
iBoxYPosition = pPosition.iY;
|
|
|
|
// get dimensions..mostly for width
|
|
GetBoxSize( ghRepairBox, &pDimensions );
|
|
|
|
// get width
|
|
iBoxWidth = pDimensions.iRight;
|
|
|
|
SetCurrentBox( ghRepairBox );
|
|
|
|
|
|
pSoldier = GetSelectedAssignSoldier( FALSE );
|
|
|
|
// PLEASE NOTE: make sure any changes you do here are reflected in all 3 routines which must remain in synch:
|
|
// CreateDestroyMouseRegionForRepairMenu(), DisplayRepairMenu(), and HandleShadingOfLinesForRepairMenu().
|
|
|
|
if ( pSoldier->bSectorZ == 0 )
|
|
{
|
|
// vehicles
|
|
for ( iVehicleIndex = 0; iVehicleIndex < ubNumberOfVehicles; iVehicleIndex++ )
|
|
{
|
|
if ( pVehicleList[ iVehicleIndex ].fValid == TRUE )
|
|
{
|
|
// don't even list the helicopter, because it's NEVER repairable...
|
|
if ( iVehicleIndex != iHelicopterVehicleId )
|
|
{
|
|
// other vehicles *in the sector* are listed, but later shaded dark if they're not repairable
|
|
if ( IsThisVehicleAccessibleToSoldier( pSoldier, iVehicleIndex ) )
|
|
{
|
|
// add mouse region for each line of text..and set user data
|
|
MSYS_DefineRegion( &gRepairMenuRegion[ iCount ], ( INT16 )( iBoxXPosition ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghAssignmentBox ) + ( iFontHeight ) * iCount ), ( INT16 )( iBoxXPosition + iBoxWidth ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghAssignmentBox ) + ( iFontHeight ) * ( iCount + 1 ) ), MSYS_PRIORITY_HIGHEST - 4 ,
|
|
MSYS_NO_CURSOR, RepairMenuMvtCallback, RepairMenuBtnCallback );
|
|
|
|
MSYS_SetRegionUserData( &gRepairMenuRegion[ iCount ], 0, iCount );
|
|
// 2nd user data is the vehicle index, which can easily be different from the region index!
|
|
MSYS_SetRegionUserData( &gRepairMenuRegion[ iCount ], 1, iVehicleIndex );
|
|
iCount++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* No point in allowing SAM site repair any more. Jan/13/99. ARM
|
|
// SAM site
|
|
if( ( IsThisSectorASAMSector( pSoldier -> sSectorX, pSoldier -> sSectorY, pSoldier -> bSectorZ ) == TRUE ) && ( IsTheSAMSiteInSectorRepairable( pSoldier -> sSectorX, pSoldier -> sSectorY, pSoldier -> bSectorZ ) ) )
|
|
{
|
|
MSYS_DefineRegion( &gRepairMenuRegion[ iCount ], ( INT16 )( iBoxXPosition ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghAssignmentBox ) + ( iFontHeight ) * iCount ), ( INT16 )( iBoxXPosition + iBoxWidth ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghAssignmentBox ) + ( iFontHeight ) * ( iCount + 1 ) ), MSYS_PRIORITY_HIGHEST - 4 ,
|
|
MSYS_NO_CURSOR, RepairMenuMvtCallback, RepairMenuBtnCallback );
|
|
|
|
MSYS_SetRegionUserData( &gRepairMenuRegion[ iCount ], 0, REPAIR_MENU_SAM_SITE );
|
|
iCount++;
|
|
}
|
|
*/
|
|
|
|
|
|
// robot
|
|
if( IsRobotInThisSector( pSoldier -> sSectorX, pSoldier -> sSectorY, pSoldier -> bSectorZ ) )
|
|
{
|
|
MSYS_DefineRegion( &gRepairMenuRegion[ iCount ], ( INT16 )( iBoxXPosition ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghAssignmentBox ) + ( iFontHeight ) * iCount ), ( INT16 )( iBoxXPosition + iBoxWidth ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghAssignmentBox ) + ( iFontHeight ) * ( iCount + 1 ) ), MSYS_PRIORITY_HIGHEST - 4 ,
|
|
MSYS_NO_CURSOR, RepairMenuMvtCallback, RepairMenuBtnCallback );
|
|
|
|
MSYS_SetRegionUserData( &gRepairMenuRegion[ iCount ], 0, iCount );
|
|
MSYS_SetRegionUserData( &gRepairMenuRegion[ iCount ], 1, REPAIR_MENU_ROBOT );
|
|
iCount++;
|
|
}
|
|
|
|
|
|
// items
|
|
MSYS_DefineRegion( &gRepairMenuRegion[ iCount ], ( INT16 )( iBoxXPosition ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghAssignmentBox ) + ( iFontHeight ) * iCount ), ( INT16 )( iBoxXPosition + iBoxWidth ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghAssignmentBox ) + ( iFontHeight ) * ( iCount + 1 ) ), MSYS_PRIORITY_HIGHEST - 4 ,
|
|
MSYS_NO_CURSOR, RepairMenuMvtCallback, RepairMenuBtnCallback );
|
|
|
|
MSYS_SetRegionUserData( &gRepairMenuRegion[ iCount ], 0, iCount );
|
|
MSYS_SetRegionUserData( &gRepairMenuRegion[ iCount ], 1, REPAIR_MENU_ITEMS );
|
|
iCount++;
|
|
|
|
|
|
// cancel
|
|
MSYS_DefineRegion( &gRepairMenuRegion[ iCount ], ( INT16 )( iBoxXPosition ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghAssignmentBox ) + ( iFontHeight ) * iCount ), ( INT16 )( iBoxXPosition + iBoxWidth ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghAssignmentBox ) + ( iFontHeight ) * ( iCount + 1 ) ), MSYS_PRIORITY_HIGHEST - 4 ,
|
|
MSYS_NO_CURSOR, RepairMenuMvtCallback, RepairMenuBtnCallback );
|
|
|
|
MSYS_SetRegionUserData( &gRepairMenuRegion[ iCount ], 0, iCount );
|
|
MSYS_SetRegionUserData( &gRepairMenuRegion[ iCount ], 1, REPAIR_MENU_CANCEL );
|
|
|
|
|
|
PauseGame( );
|
|
|
|
// unhighlight all strings in box
|
|
UnHighLightBox( ghRepairBox );
|
|
|
|
fCreated = TRUE;
|
|
}
|
|
else if( ( ( fShowRepairMenu == FALSE ) || ( fShowAssignmentMenu == FALSE ) ) && ( fCreated == TRUE ) )
|
|
{
|
|
fCreated = FALSE;
|
|
|
|
// remove these regions
|
|
for( uiCounter = 0; uiCounter < GetNumberOfLinesOfTextInBox( ghRepairBox ); uiCounter++ )
|
|
{
|
|
MSYS_RemoveRegion( &gRepairMenuRegion[ uiCounter ] );
|
|
}
|
|
|
|
fShowRepairMenu = FALSE;
|
|
|
|
SetRenderFlags( RENDER_FLAG_FULL );
|
|
|
|
HideBox( ghRepairBox );
|
|
|
|
if ( fShowAssignmentMenu )
|
|
{
|
|
// remove highlight on the parent menu
|
|
UnHighLightBox( ghAssignmentBox );
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void RepairMenuBtnCallback( MOUSE_REGION * pRegion, INT32 iReason )
|
|
{
|
|
// btn callback handler for assignment region
|
|
INT32 iValue = -1;
|
|
SOLDIERTYPE *pSoldier = NULL;
|
|
INT32 iRepairWhat;
|
|
|
|
|
|
iValue = MSYS_GetRegionUserData( pRegion, 0 );
|
|
|
|
// ignore clicks on disabled lines
|
|
if( GetBoxShadeFlag( ghRepairBox, iValue ) == TRUE )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// WHAT is being repaired is stored in the second user data argument
|
|
iRepairWhat = MSYS_GetRegionUserData( pRegion, 1 );
|
|
|
|
|
|
pSoldier = GetSelectedAssignSoldier( FALSE );
|
|
|
|
|
|
if ( pSoldier && pSoldier->bActive && ( iReason & MSYS_CALLBACK_REASON_LBUTTON_UP ) )
|
|
{
|
|
if( ( iRepairWhat >= REPAIR_MENU_VEHICLE1 ) && ( iRepairWhat <= REPAIR_MENU_VEHICLE3 ) )
|
|
{
|
|
// repair VEHICLE
|
|
|
|
pSoldier->bOldAssignment = pSoldier->bAssignment;
|
|
|
|
if( ( pSoldier->bAssignment != REPAIR )|| ( pSoldier -> fFixingRobot ) || ( pSoldier -> fFixingSAMSite ) )
|
|
{
|
|
SetTimeOfAssignmentChangeForMerc( pSoldier );
|
|
}
|
|
|
|
if( pSoldier->bOldAssignment == VEHICLE )
|
|
{
|
|
TakeSoldierOutOfVehicle( pSoldier );
|
|
}
|
|
|
|
// remove from squad
|
|
RemoveCharacterFromSquads( pSoldier );
|
|
MakeSureToolKitIsInHand( pSoldier );
|
|
|
|
ChangeSoldiersAssignment( pSoldier, REPAIR );
|
|
|
|
pSoldier -> bVehicleUnderRepairID = ( INT8 ) iRepairWhat;
|
|
|
|
MakeSureToolKitIsInHand( pSoldier );
|
|
|
|
// assign to a movement group
|
|
AssignMercToAMovementGroup( pSoldier );
|
|
|
|
// set assignment for group
|
|
SetAssignmentForList( ( INT8 ) REPAIR, 0 );
|
|
fShowAssignmentMenu = FALSE;
|
|
|
|
}
|
|
/* No point in allowing SAM site repair any more. Jan/13/99. ARM
|
|
else if( iRepairWhat == REPAIR_MENU_SAM_SITE )
|
|
{
|
|
// repair SAM site
|
|
|
|
// remove from squad
|
|
RemoveCharacterFromSquads( pSoldier );
|
|
MakeSureToolKitIsInHand( pSoldier );
|
|
|
|
if( ( pSoldier->bAssignment != REPAIR )|| ( pSoldier -> fFixingSAMSite == FALSE ) )
|
|
{
|
|
SetTimeOfAssignmentChangeForMerc( pSoldier );
|
|
}
|
|
|
|
ChangeSoldiersAssignment( pSoldier, REPAIR );
|
|
pSoldier -> fFixingSAMSite = TRUE;
|
|
|
|
// the second argument is irrelevant here, function looks at pSoldier itself to know what's being repaired
|
|
SetAssignmentForList( ( INT8 ) REPAIR, 0 );
|
|
fShowAssignmentMenu = FALSE;
|
|
|
|
MakeSureToolKitIsInHand( pSoldier );
|
|
|
|
// assign to a movement group
|
|
AssignMercToAMovementGroup( pSoldier );
|
|
}
|
|
*/
|
|
else if( iRepairWhat == REPAIR_MENU_ROBOT )
|
|
{
|
|
// repair ROBOT
|
|
pSoldier->bOldAssignment = pSoldier->bAssignment;
|
|
|
|
// remove from squad
|
|
if( pSoldier->bOldAssignment == VEHICLE )
|
|
{
|
|
TakeSoldierOutOfVehicle( pSoldier );
|
|
}
|
|
|
|
RemoveCharacterFromSquads( pSoldier );
|
|
MakeSureToolKitIsInHand( pSoldier );
|
|
|
|
if( ( pSoldier->bAssignment != REPAIR )|| ( pSoldier -> fFixingRobot == FALSE ) )
|
|
{
|
|
SetTimeOfAssignmentChangeForMerc( pSoldier );
|
|
}
|
|
|
|
ChangeSoldiersAssignment( pSoldier, REPAIR );
|
|
pSoldier->fFixingRobot = TRUE;
|
|
|
|
// the second argument is irrelevant here, function looks at pSoldier itself to know what's being repaired
|
|
SetAssignmentForList( ( INT8 ) REPAIR, 0 );
|
|
fShowAssignmentMenu = FALSE;
|
|
|
|
MakeSureToolKitIsInHand( pSoldier );
|
|
|
|
// assign to a movement group
|
|
AssignMercToAMovementGroup( pSoldier );
|
|
}
|
|
else if( iRepairWhat == REPAIR_MENU_ITEMS )
|
|
{
|
|
// items
|
|
SetSoldierAssignment( pSoldier, REPAIR, FALSE, FALSE, -1 );
|
|
|
|
// the second argument is irrelevant here, function looks at pSoldier itself to know what's being repaired
|
|
SetAssignmentForList( ( INT8 ) REPAIR, 0 );
|
|
fShowAssignmentMenu = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// CANCEL
|
|
fShowRepairMenu = FALSE;
|
|
}
|
|
|
|
// update mapscreen
|
|
fCharacterInfoPanelDirty = TRUE;
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
|
|
giAssignHighLine = -1;
|
|
}
|
|
}
|
|
|
|
|
|
void RepairMenuMvtCallback(MOUSE_REGION * pRegion, INT32 iReason )
|
|
{
|
|
// mvt callback handler for assignment region
|
|
INT32 iValue = -1;
|
|
|
|
iValue = MSYS_GetRegionUserData( pRegion, 0 );
|
|
|
|
if (iReason & MSYS_CALLBACK_REASON_GAIN_MOUSE )
|
|
{
|
|
if( iValue < REPAIR_MENU_CANCEL )
|
|
{
|
|
if( GetBoxShadeFlag( ghRepairBox, iValue ) == FALSE )
|
|
{
|
|
// highlight choice
|
|
HighLightBoxLine( ghRepairBox, iValue );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// highlight cancel line
|
|
HighLightBoxLine( ghRepairBox, GetNumberOfLinesOfTextInBox( ghRepairBox ) - 1 );
|
|
}
|
|
}
|
|
else if (iReason & MSYS_CALLBACK_REASON_LOST_MOUSE )
|
|
{
|
|
// unhighlight all strings in box
|
|
UnHighLightBox( ghRepairBox );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void MakeSureToolKitIsInHand( SOLDIERTYPE *pSoldier )
|
|
{
|
|
INT8 bPocket = 0;
|
|
|
|
// if there isn't a toolkit in his hand
|
|
if( !Item[pSoldier -> inv[ HANDPOS].usItem].toolkit )
|
|
{
|
|
// run through rest of inventory looking for toolkits, swap the first one into hand if found
|
|
for (bPocket = SECONDHANDPOS; bPocket <= SMALLPOCK8POS; bPocket++)
|
|
{
|
|
if( Item[pSoldier -> inv[ bPocket ].usItem].toolkit )
|
|
{
|
|
SwapObjs( &pSoldier -> inv[ HANDPOS ], &pSoldier -> inv[ bPocket ] );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOLEAN MakeSureMedKitIsInHand( SOLDIERTYPE *pSoldier )
|
|
{
|
|
INT8 bPocket = 0;
|
|
BOOLEAN fFoundOne = FALSE;
|
|
|
|
|
|
fTeamPanelDirty = TRUE;
|
|
|
|
// if there is a MEDICAL BAG in his hand, we're set
|
|
if ( Item[pSoldier -> inv[ HANDPOS ].usItem].medicalkit )
|
|
{
|
|
return(TRUE);
|
|
}
|
|
|
|
// run through rest of inventory looking 1st for MEDICAL BAGS, swap the first one into hand if found
|
|
for (bPocket = SECONDHANDPOS; bPocket <= SMALLPOCK8POS; bPocket++)
|
|
{
|
|
if ( Item[pSoldier -> inv[ bPocket ].usItem].medicalkit )
|
|
{
|
|
fCharacterInfoPanelDirty = TRUE;
|
|
SwapObjs( &pSoldier -> inv[ HANDPOS ], &pSoldier -> inv[ bPocket ] );
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
// we didn't find a medical bag, so settle for a FIRST AID KIT
|
|
if ( Item[pSoldier -> inv[ HANDPOS ].usItem].firstaidkit )
|
|
{
|
|
return(TRUE);
|
|
}
|
|
|
|
// run through rest of inventory looking 1st for MEDICAL BAGS, swap the first one into hand if found
|
|
for (bPocket = SECONDHANDPOS; bPocket <= SMALLPOCK8POS; bPocket++)
|
|
{
|
|
if ( Item[pSoldier -> inv[ bPocket ].usItem].firstaidkit )
|
|
{
|
|
// if( ( Item[ pSoldier -> inv[ HANDPOS ].usItem ].fFlags & IF_TWOHANDED_GUN ) && ( bPocket >= SMALLPOCK1POS ) )
|
|
if( ( Item[ pSoldier -> inv[ HANDPOS ].usItem ].twohanded ) && ( bPocket >= SMALLPOCK1POS ) )
|
|
{
|
|
// first move from hand to second hand
|
|
SwapObjs( &pSoldier -> inv[ HANDPOS ], &pSoldier -> inv[ SECONDHANDPOS ] );
|
|
|
|
// dirty mapscreen and squad panels
|
|
fCharacterInfoPanelDirty = TRUE;
|
|
fInterfacePanelDirty = DIRTYLEVEL2;
|
|
}
|
|
|
|
SwapObjs( &pSoldier -> inv[ HANDPOS ], &pSoldier -> inv[ bPocket ] );
|
|
|
|
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
// no medkit items in possession!
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
|
|
void HandleShadingOfLinesForAssignmentMenus( void )
|
|
{
|
|
SOLDIERTYPE *pSoldier = NULL;
|
|
|
|
// updates which menus are selectable based on character status
|
|
|
|
|
|
if( ( fShowAssignmentMenu == FALSE ) || ( ghAssignmentBox == - 1 ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
pSoldier = GetSelectedAssignSoldier( FALSE );
|
|
|
|
if ( pSoldier && pSoldier->bActive )
|
|
{
|
|
if( pSoldier -> ubWhatKindOfMercAmI == MERC_TYPE__EPC )
|
|
{
|
|
// patient
|
|
if( CanCharacterPatient( pSoldier ) )
|
|
{
|
|
// unshade patient line
|
|
UnShadeStringInBox( ghEpcBox, EPC_MENU_PATIENT );
|
|
}
|
|
else
|
|
{
|
|
// shade patient line
|
|
ShadeStringInBox( ghEpcBox, EPC_MENU_PATIENT );
|
|
}
|
|
|
|
|
|
if( CanCharacterOnDuty( pSoldier ) )
|
|
{
|
|
// unshade on duty line
|
|
UnShadeStringInBox( ghEpcBox, EPC_MENU_ON_DUTY );
|
|
}
|
|
else
|
|
{
|
|
// shade on duty line
|
|
ShadeStringInBox( ghEpcBox, EPC_MENU_ON_DUTY );
|
|
}
|
|
|
|
if( CanCharacterVehicle( pSoldier ) )
|
|
{
|
|
// unshade vehicle line
|
|
UnShadeStringInBox( ghEpcBox, EPC_MENU_VEHICLE );
|
|
}
|
|
else
|
|
{
|
|
// shade vehicle line
|
|
ShadeStringInBox( ghEpcBox, EPC_MENU_VEHICLE );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// doctor
|
|
if( CanCharacterDoctor( pSoldier ) )
|
|
{
|
|
// unshade doctor line
|
|
UnShadeStringInBox( ghAssignmentBox, ASSIGN_MENU_DOCTOR );
|
|
UnSecondaryShadeStringInBox( ghAssignmentBox, ASSIGN_MENU_DOCTOR );
|
|
}
|
|
else
|
|
{
|
|
// only missing a med kit
|
|
if( CanCharacterDoctorButDoesntHaveMedKit( pSoldier ) )
|
|
{
|
|
SecondaryShadeStringInBox( ghAssignmentBox, ASSIGN_MENU_DOCTOR );
|
|
}
|
|
else
|
|
{
|
|
// shade doctor line
|
|
ShadeStringInBox( ghAssignmentBox, ASSIGN_MENU_DOCTOR );
|
|
}
|
|
|
|
}
|
|
|
|
// repair
|
|
if( CanCharacterRepair( pSoldier ) )
|
|
{
|
|
// unshade repair line
|
|
UnShadeStringInBox( ghAssignmentBox, ASSIGN_MENU_REPAIR );
|
|
UnSecondaryShadeStringInBox( ghAssignmentBox, ASSIGN_MENU_REPAIR );
|
|
}
|
|
else
|
|
{
|
|
// only missing a tool kit
|
|
if( CanCharacterRepairButDoesntHaveARepairkit( pSoldier ) )
|
|
{
|
|
SecondaryShadeStringInBox( ghAssignmentBox, ASSIGN_MENU_REPAIR );
|
|
}
|
|
else
|
|
{
|
|
// shade repair line
|
|
ShadeStringInBox( ghAssignmentBox, ASSIGN_MENU_REPAIR );
|
|
}
|
|
}
|
|
|
|
|
|
// patient
|
|
if( CanCharacterPatient( pSoldier ) )
|
|
{
|
|
// unshade patient line
|
|
UnShadeStringInBox( ghAssignmentBox, ASSIGN_MENU_PATIENT );
|
|
}
|
|
else
|
|
{
|
|
// shade patient line
|
|
ShadeStringInBox( ghAssignmentBox, ASSIGN_MENU_PATIENT );
|
|
}
|
|
|
|
|
|
if( CanCharacterOnDuty( pSoldier ) )
|
|
{
|
|
// unshade on duty line
|
|
UnShadeStringInBox( ghAssignmentBox, ASSIGN_MENU_ON_DUTY );
|
|
}
|
|
else
|
|
{
|
|
// shade on duty line
|
|
ShadeStringInBox( ghAssignmentBox, ASSIGN_MENU_ON_DUTY );
|
|
}
|
|
|
|
|
|
if( CanCharacterPractise( pSoldier ) )
|
|
{
|
|
// unshade train line
|
|
UnShadeStringInBox( ghAssignmentBox, ASSIGN_MENU_TRAIN );
|
|
}
|
|
else
|
|
{
|
|
// shade train line
|
|
ShadeStringInBox( ghAssignmentBox, ASSIGN_MENU_TRAIN );
|
|
}
|
|
|
|
|
|
if( CanCharacterVehicle( pSoldier ) )
|
|
{
|
|
// unshade vehicle line
|
|
UnShadeStringInBox( ghAssignmentBox, ASSIGN_MENU_VEHICLE );
|
|
}
|
|
else
|
|
{
|
|
// shade vehicle line
|
|
ShadeStringInBox( ghAssignmentBox, ASSIGN_MENU_VEHICLE );
|
|
}
|
|
}
|
|
}
|
|
|
|
// squad submenu
|
|
HandleShadingOfLinesForSquadMenu( );
|
|
|
|
// vehicle submenu
|
|
HandleShadingOfLinesForVehicleMenu( );
|
|
|
|
// repair submenu
|
|
HandleShadingOfLinesForRepairMenu( );
|
|
|
|
// training submenu
|
|
HandleShadingOfLinesForTrainingMenu( );
|
|
|
|
// training attributes submenu
|
|
HandleShadingOfLinesForAttributeMenus( );
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void DetermineWhichAssignmentMenusCanBeShown( void )
|
|
{
|
|
BOOLEAN fCharacterNoLongerValid = FALSE;
|
|
SOLDIERTYPE *pSoldier = NULL;
|
|
|
|
if ( (guiTacticalInterfaceFlags & INTERFACE_MAPSCREEN ) )
|
|
{
|
|
if( fShowMapScreenMovementList == TRUE )
|
|
{
|
|
if( bSelectedDestChar == -1 )
|
|
{
|
|
fCharacterNoLongerValid = TRUE;
|
|
HandleShowingOfMovementBox( );
|
|
}
|
|
else
|
|
{
|
|
fShowMapScreenMovementList = FALSE;
|
|
fCharacterNoLongerValid = TRUE;
|
|
}
|
|
}
|
|
/*
|
|
else if( fShowUpdateBox )
|
|
{
|
|
//handle showing of the merc update box
|
|
HandleShowingOfUpBox( );
|
|
}
|
|
*/
|
|
else if( bSelectedAssignChar == -1 )
|
|
{
|
|
fCharacterNoLongerValid = TRUE;
|
|
}
|
|
|
|
// update the assignment positions
|
|
UpdateMapScreenAssignmentPositions( );
|
|
}
|
|
|
|
// determine which assign menu needs to be shown
|
|
if( ( ( fShowAssignmentMenu == FALSE ) )||( fCharacterNoLongerValid == TRUE ) )
|
|
{
|
|
// reset show assignment menus
|
|
fShowAssignmentMenu = FALSE;
|
|
fShowVehicleMenu = FALSE;
|
|
fShowRepairMenu = FALSE;
|
|
|
|
// destroy mask, if needed
|
|
CreateDestroyScreenMaskForAssignmentAndContractMenus( );
|
|
|
|
|
|
// destroy menu if needed
|
|
CreateDestroyMouseRegionForVehicleMenu( );
|
|
CreateDestroyMouseRegionsForAssignmentMenu( );
|
|
CreateDestroyMouseRegionsForTrainingMenu( );
|
|
CreateDestroyMouseRegionsForAttributeMenu( );
|
|
CreateDestroyMouseRegionsForSquadMenu( TRUE );
|
|
CreateDestroyMouseRegionForRepairMenu( );
|
|
|
|
// hide all boxes being shown
|
|
if ( IsBoxShown( ghEpcBox ) )
|
|
{
|
|
HideBox( ghEpcBox );
|
|
fTeamPanelDirty = TRUE;
|
|
gfRenderPBInterface = TRUE;
|
|
}
|
|
if ( IsBoxShown( ghAssignmentBox ) )
|
|
{
|
|
HideBox( ghAssignmentBox );
|
|
fTeamPanelDirty = TRUE;
|
|
gfRenderPBInterface = TRUE;
|
|
}
|
|
if ( IsBoxShown( ghTrainingBox ) )
|
|
{
|
|
HideBox( ghTrainingBox );
|
|
fTeamPanelDirty = TRUE;
|
|
gfRenderPBInterface = TRUE;
|
|
}
|
|
if ( IsBoxShown( ghRepairBox ) )
|
|
{
|
|
HideBox( ghRepairBox );
|
|
fTeamPanelDirty = TRUE;
|
|
gfRenderPBInterface = TRUE;
|
|
}
|
|
if ( IsBoxShown( ghAttributeBox ) )
|
|
{
|
|
HideBox( ghAttributeBox );
|
|
fTeamPanelDirty = TRUE;
|
|
gfRenderPBInterface = TRUE;
|
|
}
|
|
if ( IsBoxShown( ghVehicleBox ) )
|
|
{
|
|
HideBox( ghVehicleBox );
|
|
fTeamPanelDirty = TRUE;
|
|
gfRenderPBInterface = TRUE;
|
|
}
|
|
|
|
// do we really want ot hide this box?
|
|
if( fShowContractMenu == FALSE )
|
|
{
|
|
if ( IsBoxShown( ghRemoveMercAssignBox ) )
|
|
{
|
|
HideBox( ghRemoveMercAssignBox );
|
|
fTeamPanelDirty = TRUE;
|
|
gfRenderPBInterface = TRUE;
|
|
}
|
|
}
|
|
//HideBox( ghSquadBox );
|
|
|
|
|
|
//SetRenderFlags(RENDER_FLAG_FULL);
|
|
|
|
// no menus, leave
|
|
return;
|
|
}
|
|
|
|
// update the assignment positions
|
|
UpdateMapScreenAssignmentPositions( );
|
|
|
|
// create mask, if needed
|
|
CreateDestroyScreenMaskForAssignmentAndContractMenus( );
|
|
|
|
|
|
// created assignment menu if needed
|
|
CreateDestroyMouseRegionsForAssignmentMenu( );
|
|
CreateDestroyMouseRegionsForTrainingMenu( );
|
|
CreateDestroyMouseRegionsForAttributeMenu( );
|
|
CreateDestroyMouseRegionsForSquadMenu( TRUE );
|
|
CreateDestroyMouseRegionForRepairMenu( );
|
|
|
|
|
|
if( ( ( Menptr[gCharactersList[ bSelectedInfoChar ].usSolID].bLife == 0 )||( Menptr[gCharactersList[bSelectedInfoChar].usSolID].bAssignment == ASSIGNMENT_POW ) ) && ( (guiTacticalInterfaceFlags & INTERFACE_MAPSCREEN ) ) )
|
|
{
|
|
// show basic assignment menu
|
|
ShowBox( ghRemoveMercAssignBox );
|
|
}
|
|
else
|
|
{
|
|
pSoldier = GetSelectedAssignSoldier( FALSE );
|
|
|
|
if( pSoldier -> ubWhatKindOfMercAmI == MERC_TYPE__EPC )
|
|
{
|
|
ShowBox( ghEpcBox );
|
|
}
|
|
else
|
|
{
|
|
// show basic assignment menu
|
|
|
|
ShowBox( ghAssignmentBox );
|
|
}
|
|
}
|
|
|
|
// TRAINING menu
|
|
if( fShowTrainingMenu == TRUE )
|
|
{
|
|
HandleShadingOfLinesForTrainingMenu( );
|
|
ShowBox( ghTrainingBox );
|
|
}
|
|
else
|
|
{
|
|
if( IsBoxShown( ghTrainingBox ) )
|
|
{
|
|
HideBox( ghTrainingBox );
|
|
fTeamPanelDirty = TRUE;
|
|
fMapPanelDirty = TRUE;
|
|
gfRenderPBInterface = TRUE;
|
|
// SetRenderFlags(RENDER_FLAG_FULL);
|
|
}
|
|
}
|
|
|
|
// REPAIR menu
|
|
if( fShowRepairMenu == TRUE )
|
|
{
|
|
HandleShadingOfLinesForRepairMenu( );
|
|
ShowBox( ghRepairBox );
|
|
}
|
|
else
|
|
{
|
|
// hide box
|
|
if( IsBoxShown( ghRepairBox ) )
|
|
{
|
|
HideBox( ghRepairBox );
|
|
fTeamPanelDirty = TRUE;
|
|
fMapPanelDirty = TRUE;
|
|
gfRenderPBInterface = TRUE;
|
|
// SetRenderFlags(RENDER_FLAG_FULL);
|
|
}
|
|
}
|
|
|
|
// ATTRIBUTE menu
|
|
if( fShowAttributeMenu == TRUE )
|
|
{
|
|
HandleShadingOfLinesForAttributeMenus( );
|
|
ShowBox( ghAttributeBox );
|
|
}
|
|
else
|
|
{
|
|
if( IsBoxShown( ghAttributeBox ) )
|
|
{
|
|
HideBox( ghAttributeBox );
|
|
fTeamPanelDirty = TRUE;
|
|
fMapPanelDirty = TRUE;
|
|
gfRenderPBInterface = TRUE;
|
|
// SetRenderFlags(RENDER_FLAG_FULL);
|
|
}
|
|
|
|
}
|
|
|
|
// VEHICLE menu
|
|
if( fShowVehicleMenu == TRUE )
|
|
{
|
|
ShowBox( ghVehicleBox );
|
|
}
|
|
else
|
|
{
|
|
if( IsBoxShown( ghVehicleBox ) )
|
|
{
|
|
HideBox( ghVehicleBox );
|
|
fTeamPanelDirty = TRUE;
|
|
fMapPanelDirty = TRUE;
|
|
gfRenderPBInterface = TRUE;
|
|
// SetRenderFlags(RENDER_FLAG_FULL);
|
|
}
|
|
}
|
|
|
|
CreateDestroyMouseRegionForVehicleMenu( );
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void CreateDestroyScreenMaskForAssignmentAndContractMenus( void )
|
|
{
|
|
|
|
static BOOLEAN fCreated = FALSE;
|
|
// will create a screen mask to catch mouse input to disable assignment menus
|
|
|
|
// not created, create
|
|
if( ( fCreated == FALSE ) && ( ( fShowAssignmentMenu == TRUE )||( fShowContractMenu == TRUE ) || ( fShowTownInfo == TRUE) ) )
|
|
{
|
|
MSYS_DefineRegion( &gAssignmentScreenMaskRegion, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, MSYS_PRIORITY_HIGHEST - 4 ,
|
|
MSYS_NO_CURSOR, MSYS_NO_CALLBACK, AssignmentScreenMaskBtnCallback );
|
|
|
|
// created
|
|
fCreated = TRUE;
|
|
|
|
if ( !(guiTacticalInterfaceFlags & INTERFACE_MAPSCREEN ) )
|
|
{
|
|
MSYS_ChangeRegionCursor( &gAssignmentScreenMaskRegion, 0 );
|
|
}
|
|
|
|
}
|
|
else if( ( fCreated == TRUE ) && ( fShowAssignmentMenu == FALSE )&&( fShowContractMenu == FALSE ) && ( fShowTownInfo == FALSE ) )
|
|
{
|
|
// created, get rid of it
|
|
MSYS_RemoveRegion( &gAssignmentScreenMaskRegion );
|
|
|
|
// not created
|
|
fCreated = FALSE;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void AssignmentScreenMaskBtnCallback(MOUSE_REGION * pRegion, INT32 iReason )
|
|
{
|
|
// btn callback handler for assignment screen mask region
|
|
|
|
if( ( iReason & MSYS_CALLBACK_REASON_LBUTTON_UP ) || ( iReason & MSYS_CALLBACK_REASON_RBUTTON_UP ) )
|
|
{
|
|
if( fFirstClickInAssignmentScreenMask == TRUE )
|
|
{
|
|
fFirstClickInAssignmentScreenMask = FALSE;
|
|
return;
|
|
}
|
|
|
|
// button event, stop showing menus
|
|
fShowAssignmentMenu = FALSE;
|
|
|
|
fShowVehicleMenu = FALSE;
|
|
|
|
fShowContractMenu = FALSE;
|
|
|
|
// stop showing town mine info
|
|
fShowTownInfo = FALSE;
|
|
|
|
// reset contract character and contract highlight line
|
|
giContractHighLine =-1;
|
|
bSelectedContractChar = -1;
|
|
fGlowContractRegion = FALSE;
|
|
|
|
|
|
// update mapscreen
|
|
fTeamPanelDirty = TRUE;
|
|
fCharacterInfoPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
|
|
gfRenderPBInterface = TRUE;
|
|
SetRenderFlags( RENDER_FLAG_FULL );
|
|
|
|
}
|
|
return;
|
|
}
|
|
|
|
void ClearScreenMaskForMapScreenExit( void )
|
|
{
|
|
|
|
// reset show assignment menu
|
|
fShowAssignmentMenu = FALSE;
|
|
|
|
// update the assignment positions
|
|
UpdateMapScreenAssignmentPositions( );
|
|
|
|
// stop showing town mine info too
|
|
fShowTownInfo = FALSE;
|
|
|
|
// destroy mask, if needed
|
|
CreateDestroyScreenMaskForAssignmentAndContractMenus( );
|
|
|
|
// destroy assignment menu if needed
|
|
CreateDestroyMouseRegionsForAssignmentMenu( );
|
|
CreateDestroyMouseRegionsForTrainingMenu( );
|
|
CreateDestroyMouseRegionsForAttributeMenu( );
|
|
CreateDestroyMouseRegionsForSquadMenu( TRUE );
|
|
CreateDestroyMouseRegionForRepairMenu( );
|
|
|
|
return;
|
|
}
|
|
|
|
void CreateDestroyMouseRegions( void )
|
|
{
|
|
static BOOLEAN fCreated = FALSE;
|
|
UINT32 iCounter = 0;
|
|
INT32 iFontHeight = 0;
|
|
INT32 iBoxXPosition = 0;
|
|
INT32 iBoxYPosition = 0;
|
|
SGPPoint pPosition;
|
|
INT32 iBoxWidth = 0;
|
|
SGPRect pDimensions;
|
|
|
|
// will create/destroy mouse regions for the map screen assignment main menu
|
|
|
|
|
|
// do we show the remove menu
|
|
if( fShowRemoveMenu )
|
|
{
|
|
CreateDestroyMouseRegionsForRemoveMenu( );
|
|
return;
|
|
}
|
|
|
|
if( ( fShowAssignmentMenu == TRUE ) && ( fCreated == FALSE ) )
|
|
{
|
|
|
|
// grab height of font
|
|
iFontHeight = GetLineSpace( ghAssignmentBox ) + GetFontHeight( GetBoxFont( ghAssignmentBox ) );
|
|
|
|
// get x.y position of box
|
|
GetBoxPosition( ghAssignmentBox, &pPosition);
|
|
|
|
// grab box x and y position
|
|
iBoxXPosition = pPosition.iX;
|
|
iBoxYPosition = pPosition.iY;
|
|
|
|
// get dimensions..mostly for width
|
|
GetBoxSize( ghAssignmentBox, &pDimensions );
|
|
|
|
// get width
|
|
iBoxWidth = pDimensions.iRight;
|
|
|
|
SetCurrentBox( ghAssignmentBox );
|
|
|
|
// define regions
|
|
for( iCounter = 0; iCounter < GetNumberOfLinesOfTextInBox( ghAssignmentBox ); iCounter++ )
|
|
{
|
|
// add mouse region for each line of text..and set user data
|
|
|
|
|
|
MSYS_DefineRegion( &gAssignmentMenuRegion[ iCounter ], ( INT16 )( iBoxXPosition ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghAssignmentBox ) + ( iFontHeight ) * iCounter ), ( INT16 )( iBoxXPosition + iBoxWidth ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghAssignmentBox ) + ( iFontHeight ) * ( iCounter + 1 ) ), MSYS_PRIORITY_HIGHEST - 4 ,
|
|
MSYS_NO_CURSOR, AssignmentMenuMvtCallBack, AssignmentMenuBtnCallback );
|
|
|
|
// set user defines
|
|
MSYS_SetRegionUserData( &gAssignmentMenuRegion[ iCounter ], 0, iCounter );
|
|
}
|
|
|
|
// created
|
|
fCreated = TRUE;
|
|
|
|
// pause game
|
|
PauseGame( );
|
|
|
|
fMapPanelDirty = TRUE;
|
|
fCharacterInfoPanelDirty= TRUE;
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
|
|
// unhighlight all strings in box
|
|
UnHighLightBox( ghAssignmentBox );
|
|
|
|
}
|
|
else if( ( fShowAssignmentMenu == FALSE ) && ( fCreated == TRUE ) )
|
|
{
|
|
// destroy
|
|
for( iCounter = 0; iCounter < GetNumberOfLinesOfTextInBox( ghAssignmentBox ); iCounter++ )
|
|
{
|
|
MSYS_RemoveRegion( &gAssignmentMenuRegion[ iCounter ] );
|
|
}
|
|
|
|
RestorePopUpBoxes();
|
|
|
|
// not created
|
|
fCreated = FALSE;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
void CreateDestroyMouseRegionsForContractMenu( void )
|
|
{
|
|
static BOOLEAN fCreated = FALSE;
|
|
UINT32 iCounter = 0;
|
|
INT32 iFontHeight = 0;
|
|
INT32 iBoxXPosition = 0;
|
|
INT32 iBoxYPosition = 0;
|
|
SGPPoint pPosition;
|
|
INT32 iBoxWidth = 0;
|
|
SGPRect pDimensions;
|
|
static BOOLEAN fShowRemoveMenu = FALSE;
|
|
|
|
// will create/destroy mouse regions for the map screen Contract main menu
|
|
// will create/destroy mouse regions for the map screen assignment main menu
|
|
// check if we can only remove character from team..not assign
|
|
if( ( bSelectedContractChar != -1 )|| ( fShowRemoveMenu == TRUE ) )
|
|
{
|
|
if( fShowRemoveMenu == TRUE )
|
|
{
|
|
// dead guy handle menu stuff
|
|
fShowRemoveMenu = fShowContractMenu;
|
|
|
|
// ATE: Added this setting of global variable 'cause
|
|
// it will cause an assert failure in GetSelectedAssignSoldier()
|
|
bSelectedAssignChar = bSelectedContractChar;
|
|
|
|
CreateDestroyMouseRegionsForRemoveMenu( );
|
|
|
|
return;
|
|
}
|
|
if( Menptr[gCharactersList[bSelectedContractChar].usSolID].bLife == 0 )
|
|
{
|
|
|
|
// dead guy handle menu stuff
|
|
fShowRemoveMenu = fShowContractMenu;
|
|
|
|
// ATE: Added this setting of global variable 'cause
|
|
// it will cause an assert failure in GetSelectedAssignSoldier()
|
|
bSelectedAssignChar = bSelectedContractChar;
|
|
|
|
CreateDestroyMouseRegionsForRemoveMenu( );
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
if( ( fShowContractMenu == TRUE ) && ( fCreated == FALSE ) )
|
|
{
|
|
if( bSelectedContractChar == -1 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( fShowContractMenu )
|
|
{
|
|
SetBoxPosition( ghContractBox , ContractPosition );
|
|
}
|
|
// grab height of font
|
|
iFontHeight = GetLineSpace( ghContractBox ) + GetFontHeight( GetBoxFont( ghContractBox ) );
|
|
|
|
// get x.y position of box
|
|
GetBoxPosition( ghContractBox, &pPosition);
|
|
|
|
// grab box x and y position
|
|
iBoxXPosition = pPosition.iX;
|
|
iBoxYPosition = pPosition.iY;
|
|
|
|
// get dimensions..mostly for width
|
|
GetBoxSize( ghContractBox, &pDimensions );
|
|
|
|
// get width
|
|
iBoxWidth = pDimensions.iRight;
|
|
|
|
SetCurrentBox( ghContractBox );
|
|
|
|
// define regions
|
|
for( iCounter = 0; iCounter < GetNumberOfLinesOfTextInBox( ghContractBox ); iCounter++ )
|
|
{
|
|
// add mouse region for each line of text..and set user data
|
|
|
|
|
|
MSYS_DefineRegion( &gContractMenuRegion[ iCounter ], ( INT16 )( iBoxXPosition ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghContractBox ) + ( iFontHeight ) * iCounter ), ( INT16 )( iBoxXPosition + iBoxWidth ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghContractBox ) + ( iFontHeight ) * ( iCounter + 1 ) ), MSYS_PRIORITY_HIGHEST - 4 ,
|
|
MSYS_NO_CURSOR, ContractMenuMvtCallback, ContractMenuBtnCallback );
|
|
|
|
// set user defines
|
|
MSYS_SetRegionUserData( &gContractMenuRegion[ iCounter ], 0, iCounter );
|
|
}
|
|
|
|
// created
|
|
fCreated = TRUE;
|
|
|
|
// pause game
|
|
PauseGame( );
|
|
|
|
// unhighlight all strings in box
|
|
UnHighLightBox( ghContractBox );
|
|
|
|
}
|
|
else if( ( fShowContractMenu == FALSE ) && ( fCreated == TRUE ) )
|
|
{
|
|
// destroy
|
|
for( iCounter = 0; iCounter < GetNumberOfLinesOfTextInBox( ghContractBox ); iCounter++ )
|
|
{
|
|
MSYS_RemoveRegion( &gContractMenuRegion[ iCounter ] );
|
|
}
|
|
|
|
fShownContractMenu = FALSE;
|
|
//if( ( fProcessingAMerc ) && ( pProcessingSoldier ) )
|
|
//{
|
|
// if( (UINT32)(pProcessingSoldier->iEndofContractTime) == GetWorldTotalMin() )
|
|
// {
|
|
// StrategicRemoveMerc( pProcessingSoldier, MERC_FIRED );
|
|
// pProcessingSoldier = NULL;
|
|
// fProcessingAMerc = FALSE;
|
|
// }
|
|
//}
|
|
|
|
fMapPanelDirty = TRUE;
|
|
fCharacterInfoPanelDirty= TRUE;
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
|
|
RestorePopUpBoxes( );
|
|
|
|
// not created
|
|
fCreated = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void CreateDestroyMouseRegionsForTrainingMenu( void )
|
|
{
|
|
static BOOLEAN fCreated = FALSE;
|
|
UINT32 iCounter = 0;
|
|
INT32 iFontHeight = 0;
|
|
INT32 iBoxXPosition = 0;
|
|
INT32 iBoxYPosition = 0;
|
|
SGPPoint pPosition;
|
|
INT32 iBoxWidth = 0;
|
|
SGPRect pDimensions;
|
|
|
|
// will create/destroy mouse regions for the map screen assignment main menu
|
|
|
|
|
|
|
|
if( ( fShowTrainingMenu == TRUE ) && ( fCreated == FALSE ) )
|
|
{
|
|
|
|
if( ( fShowTrainingMenu ) && ( guiCurrentScreen == MAP_SCREEN ) )
|
|
{
|
|
SetBoxPosition( ghTrainingBox, TrainPosition );
|
|
}
|
|
|
|
HandleShadingOfLinesForTrainingMenu( );
|
|
|
|
CheckAndUpdateTacticalAssignmentPopUpPositions( );
|
|
|
|
// grab height of font
|
|
iFontHeight = GetLineSpace( ghTrainingBox ) + GetFontHeight( GetBoxFont( ghTrainingBox ) );
|
|
|
|
// get x.y position of box
|
|
GetBoxPosition( ghTrainingBox, &pPosition);
|
|
|
|
// grab box x and y position
|
|
iBoxXPosition = pPosition.iX;
|
|
iBoxYPosition = pPosition.iY;
|
|
|
|
// get dimensions..mostly for width
|
|
GetBoxSize( ghTrainingBox, &pDimensions );
|
|
SetBoxSecondaryShade( ghTrainingBox, FONT_YELLOW );
|
|
|
|
// get width
|
|
iBoxWidth = pDimensions.iRight;
|
|
|
|
SetCurrentBox( ghTrainingBox );
|
|
|
|
// define regions
|
|
for( iCounter = 0; iCounter < GetNumberOfLinesOfTextInBox( ghTrainingBox ); iCounter++ )
|
|
{
|
|
// add mouse region for each line of text..and set user data
|
|
|
|
|
|
MSYS_DefineRegion( &gTrainingMenuRegion[ iCounter ], ( INT16 )( iBoxXPosition ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghTrainingBox ) + ( iFontHeight ) * iCounter ), ( INT16 )( iBoxXPosition + iBoxWidth ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghTrainingBox ) + ( iFontHeight ) * ( iCounter + 1 ) ), MSYS_PRIORITY_HIGHEST - 3 ,
|
|
MSYS_NO_CURSOR, TrainingMenuMvtCallBack, TrainingMenuBtnCallback );
|
|
|
|
// set user defines
|
|
MSYS_SetRegionUserData( &gTrainingMenuRegion[ iCounter ], 0, iCounter );
|
|
}
|
|
|
|
// created
|
|
fCreated = TRUE;
|
|
|
|
// unhighlight all strings in box
|
|
UnHighLightBox( ghTrainingBox );
|
|
|
|
}
|
|
else if( ( ( fShowAssignmentMenu == FALSE ) || ( fShowTrainingMenu == FALSE ) ) && ( fCreated == TRUE ) )
|
|
{
|
|
// destroy
|
|
for( iCounter = 0; iCounter < GetNumberOfLinesOfTextInBox( ghTrainingBox ); iCounter++ )
|
|
{
|
|
MSYS_RemoveRegion( &gTrainingMenuRegion[ iCounter ] );
|
|
}
|
|
|
|
// stop showing training menu
|
|
if( fShowAssignmentMenu == FALSE )
|
|
{
|
|
fShowTrainingMenu = FALSE;
|
|
}
|
|
|
|
RestorePopUpBoxes( );
|
|
|
|
fMapPanelDirty = TRUE;
|
|
fCharacterInfoPanelDirty= TRUE;
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
HideBox( ghTrainingBox );
|
|
SetRenderFlags( RENDER_FLAG_FULL );
|
|
|
|
// not created
|
|
fCreated = FALSE;
|
|
|
|
if ( fShowAssignmentMenu )
|
|
{
|
|
// remove highlight on the parent menu
|
|
UnHighLightBox( ghAssignmentBox );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void CreateDestroyMouseRegionsForAttributeMenu( void )
|
|
{
|
|
static BOOLEAN fCreated = FALSE;
|
|
UINT32 iCounter = 0;
|
|
INT32 iFontHeight = 0;
|
|
INT32 iBoxXPosition = 0;
|
|
INT32 iBoxYPosition = 0;
|
|
SGPPoint pPosition;
|
|
INT32 iBoxWidth = 0;
|
|
SGPRect pDimensions;
|
|
|
|
// will create/destroy mouse regions for the map screen attribute menu
|
|
|
|
|
|
|
|
if( ( fShowAttributeMenu == TRUE ) && ( fCreated == FALSE ) )
|
|
{
|
|
|
|
if( ( fShowAssignmentMenu ) && ( guiCurrentScreen == MAP_SCREEN ) )
|
|
{
|
|
SetBoxPosition( ghAssignmentBox, AssignmentPosition );
|
|
}
|
|
|
|
HandleShadingOfLinesForAttributeMenus( );
|
|
CheckAndUpdateTacticalAssignmentPopUpPositions( );
|
|
|
|
// grab height of font
|
|
iFontHeight = GetLineSpace( ghAttributeBox ) + GetFontHeight( GetBoxFont( ghAttributeBox ) );
|
|
|
|
// get x.y position of box
|
|
GetBoxPosition( ghAttributeBox, &pPosition);
|
|
|
|
// grab box x and y position
|
|
iBoxXPosition = pPosition.iX;
|
|
iBoxYPosition = pPosition.iY;
|
|
|
|
// get dimensions..mostly for width
|
|
GetBoxSize( ghAttributeBox, &pDimensions );
|
|
|
|
// get width
|
|
iBoxWidth = pDimensions.iRight;
|
|
|
|
SetCurrentBox( ghAttributeBox );
|
|
|
|
// define regions
|
|
for( iCounter = 0; iCounter < GetNumberOfLinesOfTextInBox( ghAttributeBox ); iCounter++ )
|
|
{
|
|
// add mouse region for each line of text..and set user data
|
|
|
|
|
|
MSYS_DefineRegion( &gAttributeMenuRegion[ iCounter ], ( INT16 )( iBoxXPosition ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghAttributeBox ) + ( iFontHeight ) * iCounter ), ( INT16 )( iBoxXPosition + iBoxWidth ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghAttributeBox ) + ( iFontHeight ) * ( iCounter + 1 ) ), MSYS_PRIORITY_HIGHEST - 2 ,
|
|
MSYS_NO_CURSOR, AttributeMenuMvtCallBack, AttributesMenuBtnCallback );
|
|
|
|
// set user defines
|
|
MSYS_SetRegionUserData( &gAttributeMenuRegion[ iCounter ], 0, iCounter );
|
|
}
|
|
|
|
// created
|
|
fCreated = TRUE;
|
|
|
|
// unhighlight all strings in box
|
|
UnHighLightBox( ghAttributeBox );
|
|
|
|
}
|
|
else if( ( ( fShowAssignmentMenu == FALSE ) || ( fShowTrainingMenu == FALSE ) ||( fShowAttributeMenu == FALSE) ) && ( fCreated == TRUE ) )
|
|
{
|
|
// destroy
|
|
for( iCounter = 0; iCounter < GetNumberOfLinesOfTextInBox( ghAttributeBox ); iCounter++ )
|
|
{
|
|
MSYS_RemoveRegion( &gAttributeMenuRegion[ iCounter ] );
|
|
}
|
|
|
|
// stop showing training menu
|
|
if( ( fShowAssignmentMenu == FALSE )||( fShowTrainingMenu == FALSE ) || ( fShowAttributeMenu == FALSE))
|
|
{
|
|
fShowAttributeMenu = FALSE;
|
|
gfRenderPBInterface = TRUE;
|
|
}
|
|
|
|
|
|
RestorePopUpBoxes( );
|
|
|
|
fMapPanelDirty = TRUE;
|
|
fCharacterInfoPanelDirty= TRUE;
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
HideBox( ghAttributeBox );
|
|
SetRenderFlags( RENDER_FLAG_FULL );
|
|
|
|
// not created
|
|
fCreated = FALSE;
|
|
|
|
if ( fShowTrainingMenu )
|
|
{
|
|
// remove highlight on the parent menu
|
|
UnHighLightBox( ghTrainingBox );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void CreateDestroyMouseRegionsForRemoveMenu( void )
|
|
{
|
|
static BOOLEAN fCreated = FALSE;
|
|
UINT32 iCounter = 0;
|
|
INT32 iFontHeight = 0;
|
|
INT32 iBoxXPosition = 0;
|
|
INT32 iBoxYPosition = 0;
|
|
SGPPoint pPosition;
|
|
INT32 iBoxWidth = 0;
|
|
SGPRect pDimensions;
|
|
|
|
// will create/destroy mouse regions for the map screen attribute menu
|
|
if( ( ( fShowAssignmentMenu == TRUE ) || ( fShowContractMenu == TRUE ) ) && ( fCreated == FALSE ) )
|
|
{
|
|
|
|
if( fShowContractMenu )
|
|
{
|
|
SetBoxPosition( ghContractBox , ContractPosition );
|
|
}
|
|
else
|
|
{
|
|
SetBoxPosition( ghAssignmentBox , AssignmentPosition );
|
|
}
|
|
|
|
if( fShowContractMenu )
|
|
{
|
|
// set box position to contract box position
|
|
SetBoxPosition( ghRemoveMercAssignBox , ContractPosition );
|
|
}
|
|
else
|
|
{
|
|
// set box position to contract box position
|
|
SetBoxPosition( ghRemoveMercAssignBox , AssignmentPosition );
|
|
}
|
|
|
|
CheckAndUpdateTacticalAssignmentPopUpPositions( );
|
|
|
|
// grab height of font
|
|
iFontHeight = GetLineSpace( ghRemoveMercAssignBox ) + GetFontHeight( GetBoxFont( ghRemoveMercAssignBox ) );
|
|
|
|
// get x.y position of box
|
|
GetBoxPosition( ghRemoveMercAssignBox, &pPosition);
|
|
|
|
// grab box x and y position
|
|
iBoxXPosition = pPosition.iX;
|
|
iBoxYPosition = pPosition.iY;
|
|
|
|
// get dimensions..mostly for width
|
|
GetBoxSize( ghRemoveMercAssignBox, &pDimensions );
|
|
|
|
// get width
|
|
iBoxWidth = pDimensions.iRight;
|
|
|
|
SetCurrentBox( ghRemoveMercAssignBox );
|
|
|
|
// define regions
|
|
for( iCounter = 0; iCounter < GetNumberOfLinesOfTextInBox( ghRemoveMercAssignBox ); iCounter++ )
|
|
{
|
|
// add mouse region for each line of text..and set user data
|
|
|
|
|
|
MSYS_DefineRegion( &gRemoveMercAssignRegion[ iCounter ], ( INT16 )( iBoxXPosition ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghAttributeBox ) + ( iFontHeight ) * iCounter ), ( INT16 )( iBoxXPosition + iBoxWidth ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghAttributeBox ) + ( iFontHeight ) * ( iCounter + 1 ) ), MSYS_PRIORITY_HIGHEST - 2 ,
|
|
MSYS_NO_CURSOR, RemoveMercMenuMvtCallBack, RemoveMercMenuBtnCallback );
|
|
|
|
// set user defines
|
|
MSYS_SetRegionUserData( &gRemoveMercAssignRegion[ iCounter ], 0, iCounter );
|
|
}
|
|
|
|
// created
|
|
fCreated = TRUE;
|
|
|
|
// unhighlight all strings in box
|
|
UnHighLightBox( ghRemoveMercAssignBox );
|
|
|
|
}
|
|
else if( ( fShowAssignmentMenu == FALSE ) && ( fCreated == TRUE ) && ( fShowContractMenu == FALSE ) )
|
|
{
|
|
// destroy
|
|
for( iCounter = 0; iCounter < GetNumberOfLinesOfTextInBox( ghRemoveMercAssignBox ); iCounter++ )
|
|
{
|
|
MSYS_RemoveRegion( &gRemoveMercAssignRegion[ iCounter ] );
|
|
}
|
|
|
|
fShownContractMenu = FALSE;
|
|
|
|
// stop showing menu
|
|
if( fShowRemoveMenu == FALSE )
|
|
{
|
|
fShowAttributeMenu = FALSE;
|
|
fMapPanelDirty = TRUE;
|
|
gfRenderPBInterface = TRUE;
|
|
|
|
}
|
|
|
|
|
|
RestorePopUpBoxes( );
|
|
|
|
fMapPanelDirty = TRUE;
|
|
fCharacterInfoPanelDirty= TRUE;
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
|
|
// turn off the GLOBAL fShowRemoveMenu flag!!!
|
|
fShowRemoveMenu = FALSE;
|
|
// and the assignment menu itself!!!
|
|
fShowAssignmentMenu = FALSE;
|
|
|
|
// not created
|
|
fCreated = FALSE;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
void CreateDestroyMouseRegionsForSquadMenu( BOOLEAN fPositionBox )
|
|
{
|
|
static BOOLEAN fCreated = FALSE;
|
|
UINT32 iCounter = 0;
|
|
INT32 iFontHeight = 0;
|
|
INT32 iBoxXPosition = 0;
|
|
INT32 iBoxYPosition = 0;
|
|
SGPPoint pPosition;
|
|
INT32 iBoxWidth = 0;
|
|
SGPRect pDimensions;
|
|
|
|
|
|
// will create/destroy mouse regions for the map screen attribute menu
|
|
|
|
if( ( fShowSquadMenu == TRUE ) && ( fCreated == FALSE ) )
|
|
{
|
|
// create squad box
|
|
CreateSquadBox( );
|
|
GetBoxSize( ghAssignmentBox, &pDimensions );
|
|
|
|
CheckAndUpdateTacticalAssignmentPopUpPositions( );
|
|
|
|
// grab height of font
|
|
iFontHeight = GetLineSpace( ghSquadBox ) + GetFontHeight( GetBoxFont( ghSquadBox ) );
|
|
|
|
// get x.y position of box
|
|
GetBoxPosition( ghSquadBox, &pPosition);
|
|
|
|
|
|
// grab box x and y position
|
|
iBoxXPosition = pPosition.iX;
|
|
iBoxYPosition = pPosition.iY;
|
|
|
|
// get dimensions..mostly for width
|
|
GetBoxSize( ghSquadBox, &pDimensions );
|
|
|
|
// get width
|
|
iBoxWidth = pDimensions.iRight;
|
|
|
|
SetCurrentBox( ghSquadBox );
|
|
|
|
// define regions
|
|
for( iCounter = 0; iCounter < GetNumberOfLinesOfTextInBox( ghSquadBox ) - 1; iCounter++ )
|
|
{
|
|
// add mouse region for each line of text..and set user data
|
|
MSYS_DefineRegion( &gSquadMenuRegion[ iCounter ], ( INT16 )( iBoxXPosition ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghSquadBox ) + ( iFontHeight ) * iCounter ), ( INT16 )( iBoxXPosition + iBoxWidth ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghSquadBox ) + ( iFontHeight ) * ( iCounter + 1 ) ), MSYS_PRIORITY_HIGHEST - 2 ,
|
|
MSYS_NO_CURSOR, SquadMenuMvtCallBack, SquadMenuBtnCallback );
|
|
|
|
MSYS_SetRegionUserData( &gSquadMenuRegion[ iCounter ], 0, iCounter );
|
|
}
|
|
|
|
// now create cancel region
|
|
MSYS_DefineRegion( &gSquadMenuRegion[ iCounter ], ( INT16 )( iBoxXPosition ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghSquadBox ) + ( iFontHeight ) * iCounter ), ( INT16 )( iBoxXPosition + iBoxWidth ), ( INT16 )( iBoxYPosition + GetTopMarginSize( ghSquadBox ) + ( iFontHeight ) * ( iCounter + 1 ) ), MSYS_PRIORITY_HIGHEST - 2 ,
|
|
MSYS_NO_CURSOR, SquadMenuMvtCallBack, SquadMenuBtnCallback );
|
|
|
|
MSYS_SetRegionUserData( &gSquadMenuRegion[ iCounter ], 0, SQUAD_MENU_CANCEL );
|
|
|
|
|
|
// created
|
|
fCreated = TRUE;
|
|
|
|
// show the box
|
|
ShowBox( ghSquadBox );
|
|
|
|
// unhighlight all strings in box
|
|
UnHighLightBox( ghSquadBox );
|
|
|
|
// update based on current squad
|
|
HandleShadingOfLinesForSquadMenu( );
|
|
}
|
|
else if( ( ( fShowAssignmentMenu == FALSE ) || ( fShowSquadMenu == FALSE ) ) && ( fCreated == TRUE ) )
|
|
{
|
|
// destroy
|
|
for( iCounter = 0; iCounter < GetNumberOfLinesOfTextInBox( ghSquadBox ); iCounter++ )
|
|
{
|
|
MSYS_RemoveRegion( &gSquadMenuRegion[ iCounter ] );
|
|
}
|
|
|
|
fShowSquadMenu = FALSE;
|
|
|
|
// remove squad box
|
|
RemoveBox(ghSquadBox);
|
|
ghSquadBox = -1;
|
|
|
|
RestorePopUpBoxes( );
|
|
|
|
fMapPanelDirty = TRUE;
|
|
fCharacterInfoPanelDirty= TRUE;
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
SetRenderFlags( RENDER_FLAG_FULL );
|
|
|
|
// not created
|
|
fCreated = FALSE;
|
|
fMapPanelDirty = TRUE;
|
|
|
|
if ( fShowAssignmentMenu )
|
|
{
|
|
// remove highlight on the parent menu
|
|
UnHighLightBox( ghAssignmentBox );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void AssignmentMenuMvtCallBack(MOUSE_REGION * pRegion, INT32 iReason )
|
|
{
|
|
// mvt callback handler for assignment region
|
|
INT32 iValue = -1;
|
|
SOLDIERTYPE *pSoldier;
|
|
|
|
iValue = MSYS_GetRegionUserData( pRegion, 0 );
|
|
|
|
|
|
pSoldier = GetSelectedAssignSoldier( FALSE );
|
|
|
|
if( HandleAssignmentExpansionAndHighLightForAssignMenu( pSoldier ) == TRUE )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (iReason & MSYS_CALLBACK_REASON_GAIN_MOUSE )
|
|
{
|
|
// is the line shaded?..if so, don't highlight
|
|
if( pSoldier -> ubWhatKindOfMercAmI == MERC_TYPE__EPC )
|
|
{
|
|
if( GetBoxShadeFlag( ghEpcBox, iValue ) == FALSE )
|
|
{
|
|
HighLightBoxLine( ghEpcBox, iValue );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( GetBoxShadeFlag( ghAssignmentBox, iValue ) == FALSE )
|
|
{
|
|
HighLightBoxLine( ghAssignmentBox, iValue );
|
|
}
|
|
}
|
|
}
|
|
else if (iReason & MSYS_CALLBACK_REASON_LOST_MOUSE )
|
|
{
|
|
if( pSoldier -> ubWhatKindOfMercAmI == MERC_TYPE__EPC )
|
|
{
|
|
// unhighlight all strings in box
|
|
UnHighLightBox( ghEpcBox );
|
|
}
|
|
else
|
|
{
|
|
// unhighlight all strings in box
|
|
UnHighLightBox( ghAssignmentBox );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void RemoveMercMenuMvtCallBack(MOUSE_REGION * pRegion, INT32 iReason )
|
|
{
|
|
// mvt callback handler for assignment region
|
|
INT32 iValue = -1;
|
|
|
|
iValue = MSYS_GetRegionUserData( pRegion, 0 );
|
|
|
|
if (iReason & MSYS_CALLBACK_REASON_GAIN_MOUSE )
|
|
{
|
|
// highlight string
|
|
|
|
// get the string line handle
|
|
// is the line shaded?..if so, don't highlight
|
|
if( GetBoxShadeFlag( ghRemoveMercAssignBox, iValue ) == FALSE )
|
|
{
|
|
HighLightBoxLine( ghRemoveMercAssignBox, iValue );
|
|
}
|
|
}
|
|
else if (iReason & MSYS_CALLBACK_REASON_LOST_MOUSE )
|
|
{
|
|
// unhighlight all strings in box
|
|
UnHighLightBox( ghRemoveMercAssignBox );
|
|
}
|
|
}
|
|
|
|
|
|
void ContractMenuMvtCallback(MOUSE_REGION * pRegion, INT32 iReason )
|
|
{
|
|
// mvt callback handler for Contract region
|
|
INT32 iValue = -1;
|
|
|
|
iValue = MSYS_GetRegionUserData( pRegion, 0 );
|
|
|
|
if (iReason & MSYS_CALLBACK_REASON_GAIN_MOUSE )
|
|
{
|
|
// highlight string
|
|
|
|
if( iValue != CONTRACT_MENU_CURRENT_FUNDS )
|
|
{
|
|
if( GetBoxShadeFlag( ghContractBox, iValue ) == FALSE )
|
|
{
|
|
// get the string line handle
|
|
HighLightBoxLine( ghContractBox, iValue );
|
|
}
|
|
}
|
|
}
|
|
else if (iReason & MSYS_CALLBACK_REASON_LOST_MOUSE )
|
|
{
|
|
// unhighlight all strings in box
|
|
UnHighLightBox( ghContractBox );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void SquadMenuMvtCallBack(MOUSE_REGION * pRegion, INT32 iReason )
|
|
{
|
|
// mvt callback handler for assignment region
|
|
INT32 iValue = -1;
|
|
|
|
iValue = MSYS_GetRegionUserData( pRegion, 0 );
|
|
|
|
if (iReason & MSYS_CALLBACK_REASON_GAIN_MOUSE )
|
|
{
|
|
// highlight string
|
|
|
|
if( iValue != SQUAD_MENU_CANCEL )
|
|
{
|
|
if( GetBoxShadeFlag( ghSquadBox, iValue ) == FALSE )
|
|
{
|
|
// get the string line handle
|
|
HighLightBoxLine( ghSquadBox, iValue );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// highlight cancel line
|
|
HighLightBoxLine( ghSquadBox, GetNumberOfLinesOfTextInBox( ghSquadBox ) - 1 );
|
|
}
|
|
}
|
|
else if (iReason & MSYS_CALLBACK_REASON_LOST_MOUSE )
|
|
{
|
|
// unhighlight all strings in box
|
|
UnHighLightBox( ghSquadBox );
|
|
|
|
// update based on current squad
|
|
HandleShadingOfLinesForSquadMenu( );
|
|
}
|
|
}
|
|
|
|
|
|
void RemoveMercMenuBtnCallback( MOUSE_REGION * pRegion, INT32 iReason )
|
|
{
|
|
// btn callback handler for contract region
|
|
INT32 iValue = -1;
|
|
SOLDIERTYPE * pSoldier = NULL;
|
|
|
|
|
|
pSoldier = GetSelectedAssignSoldier( FALSE );
|
|
|
|
iValue = MSYS_GetRegionUserData( pRegion, 0 );
|
|
|
|
if (iReason & MSYS_CALLBACK_REASON_LBUTTON_UP)
|
|
{
|
|
switch( iValue )
|
|
{
|
|
case( REMOVE_MERC_CANCEL ):
|
|
|
|
// stop showing menus
|
|
fShowAssignmentMenu = FALSE;
|
|
fShowContractMenu = FALSE;
|
|
|
|
// reset characters
|
|
bSelectedAssignChar = -1;
|
|
bSelectedContractChar = -1;
|
|
giAssignHighLine = -1;
|
|
|
|
// dirty regions
|
|
fCharacterInfoPanelDirty = TRUE;
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
gfRenderPBInterface = TRUE;
|
|
|
|
|
|
// stop contratc glow if we are
|
|
fGlowContractRegion = FALSE;
|
|
giContractHighLine = -1;
|
|
|
|
break;
|
|
case( REMOVE_MERC ):
|
|
StrategicRemoveMerc( pSoldier );
|
|
|
|
// dirty region
|
|
fCharacterInfoPanelDirty = TRUE;
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
gfRenderPBInterface = TRUE;
|
|
|
|
// stop contratc glow if we are
|
|
fGlowContractRegion = FALSE;
|
|
giContractHighLine = -1;
|
|
|
|
// reset selected characters
|
|
bSelectedAssignChar = -1;
|
|
bSelectedContractChar = -1;
|
|
giAssignHighLine = -1;
|
|
|
|
// stop showing menus
|
|
fShowAssignmentMenu = FALSE;
|
|
fShowContractMenu = FALSE;
|
|
|
|
//Def: 10/13/99: When a merc is either dead or a POW, the Remove Merc popup comes up instead of the
|
|
// Assign menu popup. When the the user removes the merc, we need to make sure the assignment menu
|
|
//doesnt come up ( because the both assign menu and remove menu flags are needed for the remove pop up to appear
|
|
//dont ask why?!! )
|
|
fShownContractMenu = FALSE;
|
|
fShownAssignmentMenu = FALSE;
|
|
fShowRemoveMenu = FALSE;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void BeginRemoveMercFromContract( SOLDIERTYPE *pSoldier )
|
|
{
|
|
// This function will setup the quote, then start dialogue beginning the actual leave sequence
|
|
if( ( pSoldier->bLife > 0 ) && ( pSoldier->bAssignment != ASSIGNMENT_POW ) )
|
|
{
|
|
if( ( pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__MERC ) || ( pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__NPC ) )
|
|
{
|
|
HandleImportantMercQuote( pSoldier, QUOTE_RESPONSE_TO_MIGUEL_SLASH_QUOTE_MERC_OR_RPC_LETGO );
|
|
|
|
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_LOCK_INTERFACE,0 ,MAP_SCREEN ,0 ,0 ,0 );
|
|
TacticalCharacterDialogueWithSpecialEvent( pSoldier, 0, DIALOGUE_SPECIAL_EVENT_CONTRACT_ENDING, 1,0 );
|
|
|
|
}
|
|
else
|
|
// quote is different if he's fired in less than 48 hours
|
|
if( ( GetWorldTotalMin() - pSoldier->uiTimeOfLastContractUpdate ) < 60 * 48 )
|
|
{
|
|
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_LOCK_INTERFACE,1 ,MAP_SCREEN ,0 ,0 ,0 );
|
|
if( ( pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__AIM_MERC ) )
|
|
{
|
|
// Only do this if they want to renew.....
|
|
if ( WillMercRenew( pSoldier, FALSE ) )
|
|
{
|
|
HandleImportantMercQuote( pSoldier, QUOTE_DEPART_COMMET_CONTRACT_NOT_RENEWED_OR_TERMINATED_UNDER_48 );
|
|
}
|
|
}
|
|
|
|
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_LOCK_INTERFACE,0 ,MAP_SCREEN ,0 ,0 ,0 );
|
|
TacticalCharacterDialogueWithSpecialEvent( pSoldier, 0, DIALOGUE_SPECIAL_EVENT_CONTRACT_ENDING, 1,0 );
|
|
|
|
}
|
|
else
|
|
{
|
|
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_LOCK_INTERFACE,1 ,MAP_SCREEN ,0 ,0 ,0 );
|
|
if( ( pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__AIM_MERC ) )
|
|
{
|
|
// Only do this if they want to renew.....
|
|
if ( WillMercRenew( pSoldier, FALSE ) )
|
|
{
|
|
HandleImportantMercQuote( pSoldier, QUOTE_DEPARTING_COMMENT_CONTRACT_NOT_RENEWED_OR_48_OR_MORE );
|
|
}
|
|
}
|
|
else if( ( pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__MERC ) || ( pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__NPC ) )
|
|
{
|
|
HandleImportantMercQuote( pSoldier, QUOTE_RESPONSE_TO_MIGUEL_SLASH_QUOTE_MERC_OR_RPC_LETGO );
|
|
}
|
|
|
|
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_LOCK_INTERFACE,0 ,MAP_SCREEN ,0 ,0 ,0 );
|
|
TacticalCharacterDialogueWithSpecialEvent( pSoldier, 0, DIALOGUE_SPECIAL_EVENT_CONTRACT_ENDING, 1,0 );
|
|
}
|
|
|
|
if( ( GetWorldTotalMin() - pSoldier->uiTimeOfLastContractUpdate ) < 60 * 3 )
|
|
{
|
|
// this will cause him give us lame excuses for a while until he gets over it
|
|
// 3-6 days (but the first 1-2 days of that are spent "returning" home)
|
|
gMercProfiles[ pSoldier->ubProfile ].ubDaysOfMoraleHangover = (UINT8) (3 + Random(4));
|
|
|
|
// if it's an AIM merc, word of this gets back to AIM... Bad rep.
|
|
if( pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__AIM_MERC )
|
|
{
|
|
ModifyPlayerReputation(REPUTATION_EARLY_FIRING);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
void MercDismissConfirmCallBack( UINT8 bExitValue )
|
|
{
|
|
if ( bExitValue == MSG_BOX_RETURN_YES )
|
|
{
|
|
// Setup history code
|
|
gpDismissSoldier->ubLeaveHistoryCode = HISTORY_MERC_FIRED;
|
|
|
|
BeginRemoveMercFromContract( gpDismissSoldier );
|
|
}
|
|
}
|
|
|
|
|
|
void ContractMenuBtnCallback( MOUSE_REGION * pRegion, INT32 iReason )
|
|
{
|
|
// btn callback handler for contract region
|
|
INT32 iValue = -1;
|
|
BOOLEAN fOkToClose = FALSE;
|
|
SOLDIERTYPE * pSoldier = NULL;
|
|
|
|
|
|
if ( (guiTacticalInterfaceFlags & INTERFACE_MAPSCREEN ) )
|
|
{
|
|
pSoldier = &Menptr[ gCharactersList[ bSelectedInfoChar ].usSolID ];
|
|
}
|
|
else
|
|
{
|
|
// can't renew contracts from tactical!
|
|
}
|
|
|
|
Assert( pSoldier && pSoldier->bActive );
|
|
|
|
|
|
iValue = MSYS_GetRegionUserData( pRegion, 0 );
|
|
|
|
if (iReason & MSYS_CALLBACK_REASON_RBUTTON_UP)
|
|
{
|
|
fOkToClose = TRUE;
|
|
}
|
|
|
|
if (iReason & MSYS_CALLBACK_REASON_LBUTTON_UP)
|
|
{
|
|
if( GetBoxShadeFlag( ghContractBox, iValue ) == TRUE )
|
|
{
|
|
// not valid
|
|
return;
|
|
}
|
|
|
|
|
|
if( iValue == CONTRACT_MENU_CANCEL )
|
|
{
|
|
// reset contract character and contract highlight line
|
|
giContractHighLine =-1;
|
|
bSelectedContractChar = -1;
|
|
fGlowContractRegion = FALSE;
|
|
|
|
fShowContractMenu = FALSE;
|
|
// dirty region
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
fCharacterInfoPanelDirty = TRUE;
|
|
gfRenderPBInterface = TRUE;
|
|
|
|
if ( gfInContractMenuFromRenewSequence )
|
|
{
|
|
BeginRemoveMercFromContract( pSoldier );
|
|
}
|
|
return;
|
|
}
|
|
|
|
// else handle based on contract
|
|
|
|
switch( iValue )
|
|
{
|
|
case( CONTRACT_MENU_DAY ):
|
|
MercContractHandling( pSoldier, CONTRACT_EXTEND_1_DAY );
|
|
PostContractMessage( pSoldier, CONTRACT_EXTEND_1_DAY );
|
|
fOkToClose = TRUE;
|
|
break;
|
|
case( CONTRACT_MENU_WEEK ):
|
|
MercContractHandling( pSoldier, CONTRACT_EXTEND_1_WEEK );
|
|
PostContractMessage( pSoldier, CONTRACT_EXTEND_1_WEEK );
|
|
fOkToClose = TRUE;
|
|
break;
|
|
case( CONTRACT_MENU_TWO_WEEKS ):
|
|
MercContractHandling( pSoldier, CONTRACT_EXTEND_2_WEEK );
|
|
PostContractMessage( pSoldier, CONTRACT_EXTEND_2_WEEK );
|
|
fOkToClose = TRUE;
|
|
break;
|
|
|
|
case( CONTRACT_MENU_TERMINATE ):
|
|
gpDismissSoldier = pSoldier;
|
|
|
|
// If in the renewal sequence.. do right away...
|
|
// else put up requester.
|
|
if ( gfInContractMenuFromRenewSequence )
|
|
{
|
|
MercDismissConfirmCallBack( MSG_BOX_RETURN_YES );
|
|
}
|
|
else
|
|
{
|
|
DoMapMessageBox( MSG_BOX_BASIC_STYLE, gzLateLocalizedString[ 48 ], MAP_SCREEN, MSG_BOX_FLAG_YESNO, MercDismissConfirmCallBack );
|
|
}
|
|
|
|
fOkToClose = TRUE;
|
|
|
|
break;
|
|
}
|
|
|
|
pProcessingSoldier = NULL;
|
|
fProcessingAMerc = FALSE;
|
|
}
|
|
|
|
|
|
if( fOkToClose == TRUE )
|
|
{
|
|
// reset contract character and contract highlight line
|
|
giContractHighLine =-1;
|
|
bSelectedContractChar = -1;
|
|
fGlowContractRegion = FALSE;
|
|
fShowContractMenu = FALSE;
|
|
|
|
// dirty region
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
fCharacterInfoPanelDirty = TRUE;
|
|
gfRenderPBInterface = TRUE;
|
|
}
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void TrainingMenuMvtCallBack(MOUSE_REGION * pRegion, INT32 iReason )
|
|
{
|
|
// mvt callback handler for assignment region
|
|
INT32 iValue = -1;
|
|
|
|
iValue = MSYS_GetRegionUserData( pRegion, 0 );
|
|
|
|
if( HandleAssignmentExpansionAndHighLightForTrainingMenu( ) == TRUE )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (iReason & MSYS_CALLBACK_REASON_GAIN_MOUSE )
|
|
{
|
|
// highlight string
|
|
|
|
// do not highlight current balance
|
|
if( GetBoxShadeFlag( ghTrainingBox, iValue ) == FALSE )
|
|
{
|
|
// get the string line handle
|
|
HighLightBoxLine( ghTrainingBox, iValue );
|
|
}
|
|
}
|
|
else if (iReason & MSYS_CALLBACK_REASON_LOST_MOUSE )
|
|
{
|
|
// unhighlight all strings in box
|
|
UnHighLightBox( ghTrainingBox );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void AttributeMenuMvtCallBack(MOUSE_REGION * pRegion, INT32 iReason )
|
|
{
|
|
// mvt callback handler for assignment region
|
|
INT32 iValue = -1;
|
|
|
|
iValue = MSYS_GetRegionUserData( pRegion, 0 );
|
|
|
|
if (iReason & MSYS_CALLBACK_REASON_GAIN_MOUSE )
|
|
{
|
|
// highlight string
|
|
if( GetBoxShadeFlag( ghAttributeBox, iValue ) == FALSE )
|
|
{
|
|
// get the string line handle
|
|
HighLightBoxLine( ghAttributeBox, iValue );
|
|
}
|
|
}
|
|
else if (iReason & MSYS_CALLBACK_REASON_LOST_MOUSE )
|
|
{
|
|
// unhighlight all strings in box
|
|
UnHighLightBox( ghAttributeBox );
|
|
}
|
|
}
|
|
|
|
|
|
void SquadMenuBtnCallback( MOUSE_REGION * pRegion, INT32 iReason )
|
|
{
|
|
// btn callback handler for assignment region
|
|
INT32 iValue = -1;
|
|
SOLDIERTYPE * pSoldier = NULL;
|
|
CHAR16 sString[ 128 ];
|
|
INT8 bCanJoinSquad;
|
|
/* ARM: Squad menu is now disabled for anyone between sectors
|
|
UINT8 ubNextX, ubNextY, ubPrevX, ubPrevY;
|
|
UINT32 uiTraverseTime, uiArriveTime;
|
|
INT32 iOldSquadValue = -1;
|
|
BOOLEAN fCharacterWasBetweenSectors = FALSE;
|
|
*/
|
|
|
|
|
|
pSoldier = GetSelectedAssignSoldier( FALSE );
|
|
|
|
iValue = MSYS_GetRegionUserData( pRegion, 0 );
|
|
|
|
if (iReason & MSYS_CALLBACK_REASON_LBUTTON_UP)
|
|
{
|
|
if( iValue == SQUAD_MENU_CANCEL )
|
|
{
|
|
// stop displaying, leave
|
|
fShowSquadMenu = FALSE;
|
|
|
|
// unhighlight the assignment box
|
|
UnHighLightBox( ghAssignmentBox );
|
|
|
|
// dirty region
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
fCharacterInfoPanelDirty = TRUE;
|
|
gfRenderPBInterface = TRUE;
|
|
|
|
return;
|
|
}
|
|
|
|
bCanJoinSquad = CanCharacterSquad( pSoldier, ( INT8 )iValue );
|
|
// can the character join this squad? (If already in it, accept that as a legal choice and exit menu)
|
|
if ( ( bCanJoinSquad == CHARACTER_CAN_JOIN_SQUAD ) ||
|
|
( bCanJoinSquad == CHARACTER_CANT_JOIN_SQUAD_ALREADY_IN_IT ) )
|
|
{
|
|
if ( bCanJoinSquad == CHARACTER_CAN_JOIN_SQUAD )
|
|
{
|
|
// able to add, do it
|
|
|
|
/* ARM: Squad menu is now disabled for anyone between sectors
|
|
// old squad character was in
|
|
iOldSquadValue = SquadCharacterIsIn( pSoldier );
|
|
|
|
// grab if char was between sectors
|
|
fCharacterWasBetweenSectors = pSoldier -> fBetweenSectors;
|
|
|
|
if( fCharacterWasBetweenSectors )
|
|
{
|
|
if( pSoldier -> bAssignment == VEHICLE )
|
|
{
|
|
if( GetNumberInVehicle( pSoldier -> iVehicleId ) == 1 )
|
|
{
|
|
// can't change, go away
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( pSoldier -> ubGroupID )
|
|
{
|
|
GetGroupPosition(&ubNextX, &ubNextY, &ubPrevX, &ubPrevY, &uiTraverseTime, &uiArriveTime, pSoldier -> ubGroupID );
|
|
}
|
|
*/
|
|
pSoldier->bOldAssignment = pSoldier->bAssignment;
|
|
|
|
if( pSoldier->bOldAssignment == VEHICLE )
|
|
{
|
|
TakeSoldierOutOfVehicle( pSoldier );
|
|
}
|
|
|
|
AddCharacterToSquad( pSoldier, ( INT8 )iValue );
|
|
|
|
if( pSoldier->bOldAssignment == VEHICLE )
|
|
{
|
|
SetSoldierExitVehicleInsertionData( pSoldier, pSoldier->iVehicleId );
|
|
}
|
|
|
|
//Clear any desired squad assignments -- seeing the player has physically changed it!
|
|
pSoldier -> ubNumTraversalsAllowedToMerge = 0;
|
|
pSoldier -> ubDesiredSquadAssignment = NO_ASSIGNMENT;
|
|
|
|
|
|
/* ARM: Squad menu is now disabled for anyone between sectors
|
|
if( fCharacterWasBetweenSectors )
|
|
{
|
|
// grab location of old squad and set this value for new squad
|
|
if( iOldSquadValue != -1 )
|
|
{
|
|
GetSquadPosition( &ubNextX, &ubNextY, &ubPrevX, &ubPrevY, &uiTraverseTime, &uiArriveTime, ( UINT8 )iOldSquadValue );
|
|
}
|
|
|
|
SetGroupPosition( ubNextX, ubNextY, ubPrevX, ubPrevY, uiTraverseTime, uiArriveTime, pSoldier -> ubGroupID );
|
|
}
|
|
*/
|
|
|
|
MakeSoldiersTacticalAnimationReflectAssignment( pSoldier );
|
|
}
|
|
|
|
// stop displaying, leave
|
|
fShowAssignmentMenu = FALSE;
|
|
giAssignHighLine = -1;
|
|
|
|
// dirty region
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
fCharacterInfoPanelDirty = TRUE;
|
|
gfRenderPBInterface = TRUE;
|
|
}
|
|
else
|
|
{
|
|
BOOLEAN fDisplayError = TRUE;
|
|
|
|
switch( bCanJoinSquad )
|
|
{
|
|
case CHARACTER_CANT_JOIN_SQUAD_SQUAD_MOVING:
|
|
swprintf( sString, pMapErrorString[ 36 ], pSoldier->name, pLongAssignmentStrings[ iValue ] );
|
|
break;
|
|
case CHARACTER_CANT_JOIN_SQUAD_VEHICLE:
|
|
swprintf( sString, pMapErrorString[ 37 ], pSoldier->name );
|
|
break;
|
|
case CHARACTER_CANT_JOIN_SQUAD_TOO_FAR:
|
|
swprintf( sString, pMapErrorString[ 20 ], pSoldier->name, pLongAssignmentStrings[ iValue ] );
|
|
break;
|
|
case CHARACTER_CANT_JOIN_SQUAD_FULL:
|
|
swprintf( sString, pMapErrorString[ 19 ], pSoldier->name, pLongAssignmentStrings[ iValue ] );
|
|
break;
|
|
default:
|
|
// generic "you can't join this squad" msg
|
|
swprintf( sString, pMapErrorString[ 38 ], pSoldier->name, pLongAssignmentStrings[ iValue ] );
|
|
break;
|
|
}
|
|
|
|
if ( fDisplayError )
|
|
{
|
|
DoScreenIndependantMessageBox( sString, MSG_BOX_FLAG_OK, NULL);
|
|
}
|
|
|
|
}
|
|
|
|
// set this assignment for the list too
|
|
SetAssignmentForList( ( INT8 ) iValue, 0 );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
void TrainingMenuBtnCallback( MOUSE_REGION * pRegion, INT32 iReason )
|
|
{
|
|
// btn callback handler for assignment region
|
|
INT32 iValue = -1;
|
|
SOLDIERTYPE * pSoldier = NULL;
|
|
INT8 bTownId;
|
|
CHAR16 sString[ 128 ];
|
|
CHAR16 sStringA[ 128 ];
|
|
BOOLEAN fCanTrainMilitia = TRUE;
|
|
|
|
|
|
pSoldier = GetSelectedAssignSoldier( FALSE );
|
|
|
|
iValue = MSYS_GetRegionUserData( pRegion, 0 );
|
|
|
|
if( ( iReason & MSYS_CALLBACK_REASON_LBUTTON_DWN ) || ( iReason & MSYS_CALLBACK_REASON_RBUTTON_DWN ) )
|
|
{
|
|
if ( (guiTacticalInterfaceFlags & INTERFACE_MAPSCREEN ) && !fShowMapInventoryPool )
|
|
{
|
|
UnMarkButtonDirty( giMapBorderButtons[ MAP_BORDER_TOWN_BTN ] );
|
|
}
|
|
}
|
|
|
|
if (iReason & MSYS_CALLBACK_REASON_LBUTTON_UP)
|
|
{
|
|
if( fShowAttributeMenu )
|
|
{
|
|
// cancel attribute submenu
|
|
fShowAttributeMenu = FALSE;
|
|
// rerender tactical stuff
|
|
gfRenderPBInterface = TRUE;
|
|
|
|
return;
|
|
}
|
|
|
|
switch( iValue )
|
|
{
|
|
case( TRAIN_MENU_SELF):
|
|
|
|
// practise in stat
|
|
gbTrainingMode = TRAIN_SELF;
|
|
|
|
// show menu
|
|
fShowAttributeMenu = TRUE;
|
|
DetermineBoxPositions( );
|
|
|
|
break;
|
|
case( TRAIN_MENU_TOWN):
|
|
if( BasicCanCharacterTrainMilitia(pSoldier) )
|
|
{
|
|
bTownId = GetTownIdForSector( pSoldier->sSectorX, pSoldier->sSectorY );
|
|
|
|
// if it's a town sector (the following 2 errors can't happen at non-town SAM sites)
|
|
if( bTownId != BLANK_SECTOR )
|
|
{
|
|
// can we keep militia in this town?
|
|
if( MilitiaTrainingAllowedInSector( pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ ) == FALSE )
|
|
{
|
|
swprintf( sString, pMapErrorString[ 31 ], pTownNames[ bTownId ] );
|
|
DoScreenIndependantMessageBox( sString, MSG_BOX_FLAG_OK, NULL );
|
|
break;
|
|
}
|
|
|
|
// is the current loyalty high enough to train some?
|
|
if( DoesSectorMercIsInHaveSufficientLoyaltyToTrainMilitia( pSoldier ) == FALSE )
|
|
{
|
|
DoScreenIndependantMessageBox( zMarksMapScreenText[ 20 ], MSG_BOX_FLAG_OK, NULL );
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
// Kaiden: Roaming Militia Training:
|
|
if(IsMilitiaTrainableFromSoldiersSectorMaxed( pSoldier, ELITE_MILITIA ))
|
|
if (!gGameExternalOptions.gfmusttrainroaming)
|
|
fCanTrainMilitia = FALSE;
|
|
else if (GetWorldDay( ) < gGameExternalOptions.guiAllowMilitiaGroupsDelay)
|
|
fCanTrainMilitia = FALSE;
|
|
else if (IsThisSectorASAMSector(pSoldier->sSectorX,pSoldier->sSectorY,0 ))
|
|
fCanTrainMilitia = FALSE;
|
|
else
|
|
fCanTrainMilitia = TRUE;
|
|
|
|
|
|
if(!fCanTrainMilitia)
|
|
{
|
|
if( bTownId == BLANK_SECTOR )
|
|
{
|
|
// SAM site
|
|
GetShortSectorString( pSoldier->sSectorX, pSoldier->sSectorY, sStringA );
|
|
swprintf( sString, zMarksMapScreenText[ 21 ], sStringA );
|
|
}
|
|
else
|
|
{
|
|
// town
|
|
swprintf( sString, zMarksMapScreenText[ 21 ], pTownNames[ bTownId ] );
|
|
}
|
|
|
|
DoScreenIndependantMessageBox( sString, MSG_BOX_FLAG_OK, NULL );
|
|
break;
|
|
}
|
|
|
|
if ( CountMilitiaTrainersInSoldiersSector( pSoldier ) >= gGameExternalOptions.ubMaxMilitiaTrainersPerSector )
|
|
{
|
|
swprintf( sString, gzLateLocalizedString[ 47 ], gGameExternalOptions.ubMaxMilitiaTrainersPerSector );
|
|
DoScreenIndependantMessageBox( sString, MSG_BOX_FLAG_OK, NULL );
|
|
break;
|
|
}
|
|
|
|
|
|
// PASSED ALL THE TESTS - ALLOW SOLDIER TO TRAIN MILITIA HERE
|
|
|
|
pSoldier -> bOldAssignment = pSoldier -> bAssignment;
|
|
|
|
if( ( pSoldier->bAssignment != TRAIN_TOWN ) )
|
|
{
|
|
SetTimeOfAssignmentChangeForMerc( pSoldier );
|
|
}
|
|
|
|
MakeSoldiersTacticalAnimationReflectAssignment( pSoldier );
|
|
|
|
// stop showing menu
|
|
fShowAssignmentMenu = FALSE;
|
|
giAssignHighLine = -1;
|
|
|
|
// remove from squad
|
|
|
|
if( pSoldier->bOldAssignment == VEHICLE )
|
|
{
|
|
TakeSoldierOutOfVehicle( pSoldier );
|
|
}
|
|
RemoveCharacterFromSquads( pSoldier );
|
|
|
|
ChangeSoldiersAssignment( pSoldier, TRAIN_TOWN );
|
|
|
|
// assign to a movement group
|
|
AssignMercToAMovementGroup( pSoldier );
|
|
if( SectorInfo[ SECTOR( pSoldier -> sSectorX, pSoldier -> sSectorY ) ].fMilitiaTrainingPaid == FALSE )
|
|
{
|
|
// show a message to confirm player wants to charge cost
|
|
HandleInterfaceMessageForCostOfTrainingMilitia( pSoldier );
|
|
}
|
|
else
|
|
{
|
|
SetAssignmentForList( TRAIN_TOWN, 0 );
|
|
}
|
|
|
|
gfRenderPBInterface = TRUE;
|
|
|
|
}
|
|
break;
|
|
case( TRAIN_MENU_TEAMMATES):
|
|
|
|
if( CanCharacterTrainTeammates( pSoldier ) == TRUE )
|
|
{
|
|
// train teammates
|
|
gbTrainingMode = TRAIN_TEAMMATE;
|
|
|
|
// show menu
|
|
fShowAttributeMenu = TRUE;
|
|
DetermineBoxPositions( );
|
|
}
|
|
break;
|
|
case( TRAIN_MENU_TRAIN_BY_OTHER ):
|
|
|
|
if( CanCharacterBeTrainedByOther( pSoldier ) == TRUE )
|
|
{
|
|
// train teammates
|
|
gbTrainingMode = TRAIN_BY_OTHER;
|
|
|
|
// show menu
|
|
fShowAttributeMenu = TRUE;
|
|
DetermineBoxPositions( );
|
|
}
|
|
break;
|
|
case( TRAIN_MENU_CANCEL ):
|
|
// stop showing menu
|
|
fShowTrainingMenu = FALSE;
|
|
|
|
// unhighlight the assignment box
|
|
UnHighLightBox( ghAssignmentBox );
|
|
|
|
// reset list
|
|
ResetSelectedListForMapScreen( );
|
|
gfRenderPBInterface = TRUE;
|
|
|
|
break;
|
|
}
|
|
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
}
|
|
else if( iReason & MSYS_CALLBACK_REASON_RBUTTON_UP )
|
|
{
|
|
if( fShowAttributeMenu )
|
|
{
|
|
// cancel attribute submenu
|
|
fShowAttributeMenu = FALSE;
|
|
// rerender tactical stuff
|
|
gfRenderPBInterface = TRUE;
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void AttributesMenuBtnCallback( MOUSE_REGION * pRegion, INT32 iReason )
|
|
{
|
|
// btn callback handler for assignment region
|
|
INT32 iValue = -1;
|
|
SOLDIERTYPE * pSoldier = NULL;
|
|
|
|
|
|
pSoldier = GetSelectedAssignSoldier( FALSE );
|
|
|
|
iValue = MSYS_GetRegionUserData( pRegion, 0 );
|
|
|
|
|
|
if (iReason & MSYS_CALLBACK_REASON_LBUTTON_UP)
|
|
{
|
|
if( iValue == ATTRIB_MENU_CANCEL )
|
|
{
|
|
// cancel, leave
|
|
|
|
// stop showing menu
|
|
fShowAttributeMenu = FALSE;
|
|
|
|
// unhighlight the training box
|
|
UnHighLightBox( ghTrainingBox );
|
|
}
|
|
else if( CanCharacterTrainStat( pSoldier, ( INT8 )( iValue ), ( BOOLEAN )( ( gbTrainingMode == TRAIN_SELF ) || ( gbTrainingMode == TRAIN_BY_OTHER ) ), ( BOOLEAN )( gbTrainingMode == TRAIN_TEAMMATE ) ) )
|
|
{
|
|
pSoldier->bOldAssignment = pSoldier->bAssignment;
|
|
|
|
if( ( pSoldier->bAssignment != gbTrainingMode ) )
|
|
{
|
|
SetTimeOfAssignmentChangeForMerc( pSoldier );
|
|
}
|
|
|
|
// set stat to train
|
|
pSoldier -> bTrainStat = ( INT8 )iValue;
|
|
|
|
MakeSoldiersTacticalAnimationReflectAssignment( pSoldier );
|
|
|
|
// stop showing ALL menus
|
|
fShowAssignmentMenu = FALSE;
|
|
giAssignHighLine = -1;
|
|
|
|
// remove from squad/vehicle
|
|
if( pSoldier->bOldAssignment == VEHICLE )
|
|
{
|
|
TakeSoldierOutOfVehicle( pSoldier );
|
|
}
|
|
RemoveCharacterFromSquads( pSoldier );
|
|
|
|
// train stat
|
|
ChangeSoldiersAssignment( pSoldier, gbTrainingMode );
|
|
|
|
// assign to a movement group
|
|
AssignMercToAMovementGroup( pSoldier );
|
|
|
|
// set assignment for group
|
|
SetAssignmentForList( gbTrainingMode, ( INT8 )iValue );
|
|
}
|
|
|
|
// rerender tactical stuff
|
|
gfRenderPBInterface = TRUE;
|
|
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
}
|
|
|
|
};
|
|
|
|
void AssignmentMenuBtnCallback( MOUSE_REGION * pRegion, INT32 iReason )
|
|
{
|
|
// btn callback handler for assignment region
|
|
INT32 iValue = -1;
|
|
CHAR16 sString[ 128 ];
|
|
|
|
SOLDIERTYPE * pSoldier = NULL;
|
|
|
|
|
|
pSoldier = GetSelectedAssignSoldier( FALSE );
|
|
|
|
iValue = MSYS_GetRegionUserData( pRegion, 0 );
|
|
|
|
|
|
if (iReason & MSYS_CALLBACK_REASON_LBUTTON_UP)
|
|
{
|
|
|
|
if( ( fShowAttributeMenu )||( fShowTrainingMenu ) || ( fShowRepairMenu ) || ( fShowVehicleMenu ) ||( fShowSquadMenu ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
UnHighLightBox( ghAssignmentBox );
|
|
|
|
if( pSoldier -> ubWhatKindOfMercAmI == MERC_TYPE__EPC )
|
|
{
|
|
switch( iValue )
|
|
{
|
|
case( EPC_MENU_ON_DUTY ):
|
|
if( CanCharacterOnDuty( pSoldier ) )
|
|
{
|
|
// put character on a team
|
|
fShowSquadMenu = TRUE;
|
|
fShowTrainingMenu = FALSE;
|
|
fShowVehicleMenu = FALSE;
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
|
|
}
|
|
break;
|
|
case( EPC_MENU_PATIENT ):
|
|
// can character doctor?
|
|
if( CanCharacterPatient( pSoldier ) )
|
|
{
|
|
|
|
/* Assignment distance limits removed. Sep/11/98. ARM
|
|
if( IsSoldierCloseEnoughToADoctor( pSoldier ) == FALSE )
|
|
{
|
|
return;
|
|
}
|
|
*/
|
|
|
|
pSoldier->bOldAssignment = pSoldier->bAssignment;
|
|
|
|
if( ( pSoldier->bAssignment != PATIENT ) )
|
|
{
|
|
SetTimeOfAssignmentChangeForMerc( pSoldier );
|
|
}
|
|
|
|
// stop showing menu
|
|
fShowAssignmentMenu = FALSE;
|
|
giAssignHighLine = -1;
|
|
|
|
MakeSoldiersTacticalAnimationReflectAssignment( pSoldier );
|
|
|
|
// set dirty flag
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
|
|
// remove from squad
|
|
|
|
if ( pSoldier->bOldAssignment == VEHICLE )
|
|
{
|
|
TakeSoldierOutOfVehicle( pSoldier );
|
|
}
|
|
RemoveCharacterFromSquads( pSoldier );
|
|
ChangeSoldiersAssignment( pSoldier, PATIENT );
|
|
AssignMercToAMovementGroup( pSoldier );
|
|
|
|
// set assignment for group
|
|
SetAssignmentForList( ( INT8 ) PATIENT, 0 );
|
|
}
|
|
break;
|
|
|
|
case( EPC_MENU_VEHICLE ):
|
|
if ( CanCharacterVehicle( pSoldier ) )
|
|
{
|
|
if( DisplayVehicleMenu( pSoldier ) )
|
|
{
|
|
fShowVehicleMenu = TRUE;
|
|
ShowBox( ghVehicleBox );
|
|
}
|
|
else
|
|
{
|
|
fShowVehicleMenu = FALSE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case( EPC_MENU_REMOVE ):
|
|
|
|
fShowAssignmentMenu = FALSE;
|
|
UnEscortEPC( pSoldier );
|
|
break;
|
|
|
|
case( EPC_MENU_CANCEL ):
|
|
fShowAssignmentMenu = FALSE;
|
|
giAssignHighLine = -1;
|
|
|
|
// set dirty flag
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
|
|
// reset list of characters
|
|
ResetSelectedListForMapScreen( );
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch( iValue )
|
|
{
|
|
case( ASSIGN_MENU_ON_DUTY ):
|
|
if( CanCharacterOnDuty( pSoldier ) )
|
|
{
|
|
// put character on a team
|
|
fShowSquadMenu = TRUE;
|
|
fShowTrainingMenu = FALSE;
|
|
fShowVehicleMenu = FALSE;
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
fShowRepairMenu = FALSE;
|
|
}
|
|
break;
|
|
case( ASSIGN_MENU_DOCTOR ):
|
|
|
|
// can character doctor?
|
|
if( CanCharacterDoctor( pSoldier ) )
|
|
{
|
|
// stop showing menu
|
|
fShowAssignmentMenu = FALSE;
|
|
giAssignHighLine = -1;
|
|
|
|
|
|
pSoldier -> bOldAssignment = pSoldier -> bAssignment;
|
|
|
|
if( ( pSoldier->bAssignment != DOCTOR ) )
|
|
{
|
|
SetTimeOfAssignmentChangeForMerc( pSoldier );
|
|
}
|
|
|
|
// remove from squad
|
|
|
|
if( pSoldier->bOldAssignment == VEHICLE )
|
|
{
|
|
TakeSoldierOutOfVehicle( pSoldier );
|
|
}
|
|
RemoveCharacterFromSquads( pSoldier );
|
|
|
|
ChangeSoldiersAssignment( pSoldier, DOCTOR );
|
|
|
|
MakeSureMedKitIsInHand( pSoldier );
|
|
AssignMercToAMovementGroup( pSoldier );
|
|
|
|
MakeSoldiersTacticalAnimationReflectAssignment( pSoldier );
|
|
|
|
// set dirty flag
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
|
|
|
|
// set assignment for group
|
|
SetAssignmentForList( ( INT8 ) DOCTOR, 0 );
|
|
}
|
|
else if( CanCharacterDoctorButDoesntHaveMedKit( pSoldier ) )
|
|
{
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
swprintf( sString, zMarksMapScreenText[ 19 ], pSoldier->name );
|
|
|
|
DoScreenIndependantMessageBox( sString , MSG_BOX_FLAG_OK, NULL );
|
|
}
|
|
|
|
break;
|
|
case( ASSIGN_MENU_PATIENT ):
|
|
|
|
// can character patient?
|
|
if( CanCharacterPatient( pSoldier ) )
|
|
{
|
|
|
|
/* Assignment distance limits removed. Sep/11/98. ARM
|
|
if( IsSoldierCloseEnoughToADoctor( pSoldier ) == FALSE )
|
|
{
|
|
return;
|
|
}
|
|
*/
|
|
|
|
pSoldier -> bOldAssignment = pSoldier -> bAssignment;
|
|
|
|
if( ( pSoldier->bAssignment != PATIENT ) )
|
|
{
|
|
SetTimeOfAssignmentChangeForMerc( pSoldier );
|
|
}
|
|
|
|
MakeSoldiersTacticalAnimationReflectAssignment( pSoldier );
|
|
|
|
// stop showing menu
|
|
fShowAssignmentMenu = FALSE;
|
|
giAssignHighLine = -1;
|
|
|
|
// set dirty flag
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
|
|
// remove from squad
|
|
|
|
if( pSoldier->bOldAssignment == VEHICLE )
|
|
{
|
|
TakeSoldierOutOfVehicle( pSoldier );
|
|
}
|
|
RemoveCharacterFromSquads( pSoldier );
|
|
ChangeSoldiersAssignment( pSoldier, PATIENT );
|
|
|
|
AssignMercToAMovementGroup( pSoldier );
|
|
|
|
// set assignment for group
|
|
SetAssignmentForList( ( INT8 ) PATIENT, 0 );
|
|
|
|
}
|
|
break;
|
|
|
|
case( ASSIGN_MENU_VEHICLE ):
|
|
if ( CanCharacterVehicle( pSoldier ) )
|
|
{
|
|
if( DisplayVehicleMenu( pSoldier ) )
|
|
{
|
|
fShowVehicleMenu = TRUE;
|
|
ShowBox( ghVehicleBox );
|
|
}
|
|
else
|
|
{
|
|
fShowVehicleMenu = FALSE;
|
|
}
|
|
}
|
|
break;
|
|
case( ASSIGN_MENU_REPAIR ):
|
|
if( CanCharacterRepair( pSoldier ) )
|
|
{
|
|
|
|
fShowSquadMenu = FALSE;
|
|
fShowTrainingMenu = FALSE;
|
|
fShowVehicleMenu = FALSE;
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
|
|
pSoldier -> bOldAssignment = pSoldier -> bAssignment;
|
|
|
|
|
|
if( pSoldier -> bSectorZ ==0 )
|
|
{
|
|
fShowRepairMenu = FALSE;
|
|
|
|
if( DisplayRepairMenu( pSoldier ) )
|
|
{
|
|
fShowRepairMenu = TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
else if( CanCharacterRepairButDoesntHaveARepairkit( pSoldier ) )
|
|
{
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
swprintf( sString, zMarksMapScreenText[ 18 ], pSoldier->name );
|
|
|
|
DoScreenIndependantMessageBox( sString , MSG_BOX_FLAG_OK, NULL );
|
|
}
|
|
break;
|
|
case( ASSIGN_MENU_TRAIN ):
|
|
if( CanCharacterPractise( pSoldier ) )
|
|
{
|
|
fShowTrainingMenu = TRUE;
|
|
DetermineBoxPositions( );
|
|
fShowSquadMenu = FALSE;
|
|
fShowVehicleMenu = FALSE;
|
|
fShowRepairMenu = FALSE;
|
|
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
}
|
|
break;
|
|
case( ASSIGN_MENU_CANCEL ):
|
|
fShowAssignmentMenu = FALSE;
|
|
giAssignHighLine = -1;
|
|
|
|
// set dirty flag
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
|
|
// reset list of characters
|
|
ResetSelectedListForMapScreen( );
|
|
break;
|
|
}
|
|
}
|
|
gfRenderPBInterface = TRUE;
|
|
|
|
}
|
|
else if( iReason & MSYS_CALLBACK_REASON_RBUTTON_UP )
|
|
{
|
|
if( ( fShowAttributeMenu )||( fShowTrainingMenu ) || ( fShowRepairMenu ) || ( fShowVehicleMenu ) ||( fShowSquadMenu ) )
|
|
{
|
|
fShowAttributeMenu = FALSE;
|
|
fShowTrainingMenu = FALSE;
|
|
fShowRepairMenu = FALSE;
|
|
fShowVehicleMenu = FALSE;
|
|
fShowSquadMenu = FALSE;
|
|
|
|
// rerender tactical stuff
|
|
gfRenderPBInterface = TRUE;
|
|
|
|
// set dirty flag
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void RestorePopUpBoxes( void )
|
|
{
|
|
ContractPosition.iX = OrigContractPosition.iX;
|
|
AttributePosition.iX = OrigAttributePosition.iX;
|
|
SquadPosition.iX = OrigSquadPosition.iX ;
|
|
AssignmentPosition.iX = OrigAssignmentPosition.iX ;
|
|
TrainPosition.iX = OrigTrainPosition.iX;
|
|
VehiclePosition.iX = OrigVehiclePosition.iX;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void CreateSquadBox( void )
|
|
{
|
|
// will create a pop up box for squad selection
|
|
SGPPoint pPoint;
|
|
SGPRect pDimensions;
|
|
UINT32 hStringHandle;
|
|
UINT32 uiCounter;
|
|
CHAR16 sString[ 64 ];
|
|
UINT32 uiMaxSquad;
|
|
|
|
|
|
// create basic box
|
|
CreatePopUpBox(&ghSquadBox, SquadDimensions, SquadPosition, (POPUP_BOX_FLAG_CLIP_TEXT|POPUP_BOX_FLAG_RESIZE ));
|
|
|
|
// which buffer will box render to
|
|
SetBoxBuffer(ghSquadBox, FRAME_BUFFER);
|
|
|
|
// border type?
|
|
SetBorderType(ghSquadBox,guiPOPUPBORDERS);
|
|
|
|
// background texture
|
|
SetBackGroundSurface(ghSquadBox, guiPOPUPTEX);
|
|
|
|
// margin sizes
|
|
SetMargins( ghSquadBox, 6, 6, 4, 4 );
|
|
|
|
// space between lines
|
|
SetLineSpace(ghSquadBox, 2);
|
|
|
|
// set current box to this one
|
|
SetCurrentBox( ghSquadBox );
|
|
|
|
|
|
uiMaxSquad = GetLastSquadListedInSquadMenu();
|
|
|
|
// add strings for box
|
|
for(uiCounter=0; uiCounter <= uiMaxSquad; uiCounter++)
|
|
{
|
|
// get info about current squad and put in string
|
|
swprintf( sString, L"%s ( %d/%d )", pSquadMenuStrings[uiCounter], NumberOfPeopleInSquad( ( INT8 )uiCounter ), NUMBER_OF_SOLDIERS_PER_SQUAD );
|
|
AddMonoString(&hStringHandle, sString );
|
|
|
|
// make sure it is unhighlighted
|
|
UnHighLightLine(hStringHandle);
|
|
}
|
|
|
|
// add cancel line
|
|
AddMonoString(&hStringHandle, pSquadMenuStrings[ NUMBER_OF_SQUADS ]);
|
|
|
|
// set font type
|
|
SetBoxFont(ghSquadBox, MAP_SCREEN_FONT);
|
|
|
|
// set highlight color
|
|
SetBoxHighLight(ghSquadBox, FONT_WHITE);
|
|
|
|
// unhighlighted color
|
|
SetBoxForeground(ghSquadBox, FONT_LTGREEN);
|
|
|
|
// the secondary shade color
|
|
SetBoxSecondaryShade( ghSquadBox, FONT_YELLOW );
|
|
|
|
// background color
|
|
SetBoxBackground(ghSquadBox, FONT_BLACK);
|
|
|
|
// shaded color..for darkened text
|
|
SetBoxShade( ghSquadBox, FONT_GRAY7 );
|
|
|
|
// resize box to text
|
|
ResizeBoxToText( ghSquadBox );
|
|
|
|
DetermineBoxPositions( );
|
|
|
|
GetBoxPosition( ghSquadBox, &pPoint);
|
|
GetBoxSize( ghSquadBox, &pDimensions );
|
|
|
|
if( giBoxY + pDimensions.iBottom > 479 )
|
|
{
|
|
pPoint.iY = SquadPosition.iY = 479 - pDimensions.iBottom;
|
|
}
|
|
|
|
SetBoxPosition( ghSquadBox, pPoint );
|
|
}
|
|
|
|
void CreateEPCBox( void )
|
|
{
|
|
// will create a pop up box for squad selection
|
|
SGPPoint pPoint;
|
|
SGPRect pDimensions;
|
|
UINT32 hStringHandle;
|
|
INT32 iCount;
|
|
|
|
// create basic box
|
|
CreatePopUpBox(&ghEpcBox, SquadDimensions, AssignmentPosition, (POPUP_BOX_FLAG_CLIP_TEXT|POPUP_BOX_FLAG_RESIZE|POPUP_BOX_FLAG_CENTER_TEXT ));
|
|
|
|
// which buffer will box render to
|
|
SetBoxBuffer(ghEpcBox, FRAME_BUFFER);
|
|
|
|
// border type?
|
|
SetBorderType(ghEpcBox,guiPOPUPBORDERS);
|
|
|
|
// background texture
|
|
SetBackGroundSurface(ghEpcBox, guiPOPUPTEX);
|
|
|
|
// margin sizes
|
|
SetMargins( ghEpcBox, 6, 6, 4, 4 );
|
|
|
|
// space between lines
|
|
SetLineSpace(ghEpcBox, 2);
|
|
|
|
// set current box to this one
|
|
SetCurrentBox( ghEpcBox );
|
|
|
|
for(iCount=0; iCount < MAX_EPC_MENU_STRING_COUNT; iCount++)
|
|
{
|
|
AddMonoString(&hStringHandle, pEpcMenuStrings[ iCount]);
|
|
}
|
|
|
|
// set font type
|
|
SetBoxFont(ghEpcBox, MAP_SCREEN_FONT);
|
|
|
|
// set highlight color
|
|
SetBoxHighLight(ghEpcBox, FONT_WHITE);
|
|
|
|
// unhighlighted color
|
|
SetBoxForeground(ghEpcBox, FONT_LTGREEN);
|
|
|
|
// background color
|
|
SetBoxBackground(ghEpcBox, FONT_BLACK);
|
|
|
|
// shaded color..for darkened text
|
|
SetBoxShade( ghEpcBox, FONT_GRAY7 );
|
|
|
|
// resize box to text
|
|
ResizeBoxToText( ghEpcBox );
|
|
|
|
GetBoxPosition( ghEpcBox, &pPoint);
|
|
|
|
GetBoxSize( ghEpcBox, &pDimensions );
|
|
|
|
if( giBoxY + pDimensions.iBottom > 479 )
|
|
{
|
|
pPoint.iY = AssignmentPosition.iY = 479 - pDimensions.iBottom;
|
|
}
|
|
|
|
SetBoxPosition( ghEpcBox, pPoint );
|
|
}
|
|
|
|
|
|
|
|
void HandleShadingOfLinesForSquadMenu( void )
|
|
{
|
|
// find current squad and set that line the squad box a lighter green
|
|
UINT32 uiCounter;
|
|
SOLDIERTYPE *pSoldier = NULL;
|
|
UINT32 uiMaxSquad;
|
|
INT8 bResult;
|
|
|
|
|
|
if ( ( fShowSquadMenu == FALSE ) || ( ghSquadBox == -1 ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
pSoldier = GetSelectedAssignSoldier( FALSE );
|
|
|
|
uiMaxSquad = GetLastSquadListedInSquadMenu();
|
|
|
|
for( uiCounter = 0; uiCounter <= uiMaxSquad; uiCounter++ )
|
|
{
|
|
if ( pSoldier != NULL )
|
|
{
|
|
bResult = CanCharacterSquad( pSoldier, (INT8) uiCounter );
|
|
}
|
|
|
|
// if no soldier, or a reason which doesn't have a good explanatory message
|
|
if ( ( pSoldier == NULL ) || ( bResult == CHARACTER_CANT_JOIN_SQUAD ) )
|
|
{
|
|
// darken /disable line
|
|
ShadeStringInBox( ghSquadBox, uiCounter );
|
|
}
|
|
else
|
|
{
|
|
if ( bResult == CHARACTER_CAN_JOIN_SQUAD )
|
|
{
|
|
// legal squad, leave it green
|
|
UnShadeStringInBox( ghSquadBox, uiCounter );
|
|
UnSecondaryShadeStringInBox( ghSquadBox, uiCounter );
|
|
}
|
|
else
|
|
{
|
|
// unjoinable squad - yellow
|
|
SecondaryShadeStringInBox( ghSquadBox, uiCounter );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void PostContractMessage( SOLDIERTYPE *pCharacter, INT32 iContract )
|
|
{
|
|
|
|
// do nothing
|
|
return;
|
|
|
|
// send a message stating that offer of contract extension made
|
|
//MapScreenMessage(FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Offered to extend %s's contract by another %s.", pCharacter -> name, pContractExtendStrings[ iContract ] );
|
|
|
|
return;
|
|
}
|
|
|
|
void PostTerminateMessage( SOLDIERTYPE *pCharacter )
|
|
{
|
|
|
|
// do nothing
|
|
return;
|
|
|
|
// send a message stating that termination of contract done
|
|
//MapScreenMessage(FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"%s's contract has been terminated.", pCharacter -> name );
|
|
|
|
}
|
|
|
|
BOOLEAN DisplayVehicleMenu( SOLDIERTYPE *pSoldier )
|
|
{
|
|
BOOLEAN fVehiclePresent=FALSE;
|
|
INT32 iCounter=0;
|
|
INT32 hStringHandle=0;
|
|
|
|
// first, clear pop up box
|
|
RemoveBox(ghVehicleBox);
|
|
ghVehicleBox = -1;
|
|
|
|
CreateVehicleBox();
|
|
SetCurrentBox(ghVehicleBox);
|
|
|
|
// run through list of vehicles in sector and add them to pop up box
|
|
for ( iCounter = 0; iCounter < ubNumberOfVehicles; iCounter++ )
|
|
{
|
|
if ( pVehicleList[iCounter].fValid == TRUE )
|
|
{
|
|
if ( IsThisVehicleAccessibleToSoldier( pSoldier, iCounter ) )
|
|
{
|
|
AddMonoString((UINT32 *)&hStringHandle, pVehicleStrings[ pVehicleList[ iCounter ].ubVehicleType ]);
|
|
fVehiclePresent = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// cancel string (borrow the one in the squad menu)
|
|
AddMonoString((UINT32 *)&hStringHandle, pSquadMenuStrings[ SQUAD_MENU_CANCEL ]);
|
|
|
|
SetBoxFont(ghVehicleBox, MAP_SCREEN_FONT);
|
|
SetBoxHighLight(ghVehicleBox, FONT_WHITE);
|
|
SetBoxForeground(ghVehicleBox, FONT_LTGREEN);
|
|
SetBoxBackground(ghVehicleBox, FONT_BLACK);
|
|
|
|
return fVehiclePresent;
|
|
}
|
|
|
|
void CreateVehicleBox()
|
|
{
|
|
CreatePopUpBox(&ghVehicleBox, VehicleDimensions, VehiclePosition, (POPUP_BOX_FLAG_CLIP_TEXT|POPUP_BOX_FLAG_CENTER_TEXT|POPUP_BOX_FLAG_RESIZE ));
|
|
SetBoxBuffer(ghVehicleBox, FRAME_BUFFER);
|
|
SetBorderType(ghVehicleBox,guiPOPUPBORDERS);
|
|
SetBackGroundSurface(ghVehicleBox, guiPOPUPTEX);
|
|
SetMargins( ghVehicleBox, 6, 6, 4, 4 );
|
|
SetLineSpace(ghVehicleBox, 2);
|
|
}
|
|
|
|
|
|
void CreateRepairBox( void )
|
|
{
|
|
CreatePopUpBox(&ghRepairBox, RepairDimensions, RepairPosition, (POPUP_BOX_FLAG_CLIP_TEXT|POPUP_BOX_FLAG_CENTER_TEXT|POPUP_BOX_FLAG_RESIZE ));
|
|
SetBoxBuffer(ghRepairBox, FRAME_BUFFER);
|
|
SetBorderType(ghRepairBox,guiPOPUPBORDERS);
|
|
SetBackGroundSurface(ghRepairBox, guiPOPUPTEX);
|
|
SetMargins( ghRepairBox, 6, 6, 4, 4 );
|
|
SetLineSpace(ghRepairBox, 2);
|
|
}
|
|
|
|
|
|
void CreateContractBox( SOLDIERTYPE *pCharacter )
|
|
{
|
|
UINT32 hStringHandle;
|
|
UINT32 uiCounter;
|
|
CHAR16 sString[ 50 ];
|
|
CHAR16 sDollarString[ 50 ];
|
|
|
|
ContractPosition.iX = OrigContractPosition.iX;
|
|
|
|
if( giBoxY != 0 )
|
|
{
|
|
ContractPosition.iX = giBoxY;
|
|
}
|
|
|
|
CreatePopUpBox(&ghContractBox, ContractDimensions, ContractPosition, (POPUP_BOX_FLAG_CLIP_TEXT|POPUP_BOX_FLAG_RESIZE ));
|
|
SetBoxBuffer(ghContractBox, FRAME_BUFFER);
|
|
SetBorderType(ghContractBox,guiPOPUPBORDERS);
|
|
SetBackGroundSurface(ghContractBox, guiPOPUPTEX);
|
|
SetMargins( ghContractBox, 6, 6, 4, 4 );
|
|
SetLineSpace(ghContractBox, 2);
|
|
|
|
// set current box to this one
|
|
SetCurrentBox( ghContractBox );
|
|
|
|
// not null character?
|
|
if( pCharacter != NULL )
|
|
{
|
|
for(uiCounter=0; uiCounter < MAX_CONTRACT_MENU_STRING_COUNT; uiCounter++)
|
|
{
|
|
switch( uiCounter )
|
|
{
|
|
case( CONTRACT_MENU_CURRENT_FUNDS ):
|
|
/*
|
|
// add current balance after title string
|
|
swprintf( sDollarString, L"%d", LaptopSaveInfo.iCurrentBalance);
|
|
InsertCommasForDollarFigure( sDollarString );
|
|
InsertDollarSignInToString( sDollarString );
|
|
swprintf( sString, L"%s %s", pContractStrings[uiCounter], sDollarString );
|
|
AddMonoString(&hStringHandle, sString);
|
|
*/
|
|
AddMonoString(&hStringHandle, pContractStrings[uiCounter]);
|
|
break;
|
|
case( CONTRACT_MENU_DAY ):
|
|
|
|
if( pCharacter -> ubWhatKindOfMercAmI != MERC_TYPE__AIM_MERC )
|
|
{
|
|
swprintf( sDollarString, L"%d", 0 );
|
|
}
|
|
else
|
|
{
|
|
swprintf( sDollarString, L"%d", gMercProfiles[ pCharacter -> ubProfile ].sSalary );
|
|
}
|
|
InsertCommasForDollarFigure( sDollarString );
|
|
InsertDollarSignInToString( sDollarString );
|
|
swprintf( sString, L"%s ( %s )", pContractStrings[uiCounter], sDollarString);
|
|
AddMonoString(&hStringHandle, sString);
|
|
break;
|
|
case( CONTRACT_MENU_WEEK ):
|
|
|
|
if( pCharacter -> ubWhatKindOfMercAmI != MERC_TYPE__AIM_MERC )
|
|
{
|
|
swprintf( sDollarString, L"%d", 0 );
|
|
}
|
|
else
|
|
{
|
|
swprintf( sDollarString, L"%d", gMercProfiles[ pCharacter -> ubProfile ].uiWeeklySalary );
|
|
}
|
|
|
|
InsertCommasForDollarFigure( sDollarString );
|
|
InsertDollarSignInToString( sDollarString );
|
|
swprintf( sString, L"%s ( %s )", pContractStrings[uiCounter], sDollarString );
|
|
AddMonoString(&hStringHandle, sString);
|
|
break;
|
|
case( CONTRACT_MENU_TWO_WEEKS ):
|
|
|
|
if( pCharacter -> ubWhatKindOfMercAmI != MERC_TYPE__AIM_MERC )
|
|
{
|
|
swprintf( sDollarString, L"%d", 0 );
|
|
}
|
|
else
|
|
{
|
|
swprintf( sDollarString, L"%d", gMercProfiles[ pCharacter -> ubProfile ].uiBiWeeklySalary );
|
|
}
|
|
|
|
|
|
InsertCommasForDollarFigure( sDollarString );
|
|
InsertDollarSignInToString( sDollarString );
|
|
swprintf( sString, L"%s ( %s )", pContractStrings[uiCounter], sDollarString);
|
|
AddMonoString(&hStringHandle, sString);
|
|
break;
|
|
default:
|
|
AddMonoString(&hStringHandle, pContractStrings[uiCounter] );
|
|
break;
|
|
}
|
|
UnHighLightLine(hStringHandle);
|
|
}
|
|
}
|
|
|
|
|
|
SetBoxFont(ghContractBox, MAP_SCREEN_FONT);
|
|
SetBoxHighLight(ghContractBox, FONT_WHITE);
|
|
SetBoxForeground(ghContractBox, FONT_LTGREEN);
|
|
SetBoxBackground(ghContractBox, FONT_BLACK);
|
|
|
|
// shaded color..for darkened text
|
|
SetBoxShade( ghContractBox, FONT_GRAY7 );
|
|
|
|
if( pCharacter != NULL )
|
|
{
|
|
// now set the color for the current balance value
|
|
SetBoxLineForeground( ghContractBox, 0, FONT_YELLOW );
|
|
}
|
|
|
|
// resize box to text
|
|
ResizeBoxToText( ghContractBox );
|
|
|
|
}
|
|
|
|
void CreateAttributeBox( void )
|
|
{
|
|
UINT32 hStringHandle;
|
|
UINT32 uiCounter;
|
|
|
|
// will create attribute pop up menu for mapscreen assignments
|
|
|
|
|
|
AttributePosition.iX = OrigAttributePosition.iX;
|
|
|
|
if( giBoxY != 0 )
|
|
{
|
|
AttributePosition.iY = giBoxY;
|
|
}
|
|
|
|
// update screen assignment positions
|
|
UpdateMapScreenAssignmentPositions( );
|
|
|
|
// create basic box
|
|
CreatePopUpBox(&ghAttributeBox, AttributeDimensions, AttributePosition, (POPUP_BOX_FLAG_CLIP_TEXT|POPUP_BOX_FLAG_CENTER_TEXT|POPUP_BOX_FLAG_RESIZE ));
|
|
|
|
// which buffer will box render to
|
|
SetBoxBuffer(ghAttributeBox, FRAME_BUFFER);
|
|
|
|
// border type?
|
|
SetBorderType(ghAttributeBox,guiPOPUPBORDERS);
|
|
|
|
// background texture
|
|
SetBackGroundSurface(ghAttributeBox, guiPOPUPTEX);
|
|
|
|
// margin sizes
|
|
SetMargins( ghAttributeBox, 6, 6, 4, 4 );
|
|
|
|
// space between lines
|
|
SetLineSpace(ghAttributeBox, 2);
|
|
|
|
// set current box to this one
|
|
SetCurrentBox( ghAttributeBox );
|
|
|
|
|
|
|
|
// add strings for box
|
|
for(uiCounter=0; uiCounter < MAX_ATTRIBUTE_STRING_COUNT; uiCounter++)
|
|
{
|
|
AddMonoString(&hStringHandle, pAttributeMenuStrings[uiCounter]);
|
|
|
|
// make sure it is unhighlighted
|
|
UnHighLightLine(hStringHandle);
|
|
}
|
|
|
|
// set font type
|
|
SetBoxFont(ghAttributeBox, MAP_SCREEN_FONT);
|
|
|
|
// set highlight color
|
|
SetBoxHighLight(ghAttributeBox, FONT_WHITE);
|
|
|
|
// unhighlighted color
|
|
SetBoxForeground(ghAttributeBox, FONT_LTGREEN);
|
|
|
|
// background color
|
|
SetBoxBackground(ghAttributeBox, FONT_BLACK);
|
|
|
|
// shaded color..for darkened text
|
|
SetBoxShade( ghAttributeBox, FONT_GRAY7 );
|
|
|
|
// resize box to text
|
|
ResizeBoxToText( ghAttributeBox );
|
|
|
|
|
|
}
|
|
|
|
void CreateTrainingBox( void )
|
|
{
|
|
UINT32 hStringHandle;
|
|
UINT32 uiCounter;
|
|
|
|
// will create attribute pop up menu for mapscreen assignments
|
|
|
|
TrainPosition.iX = OrigTrainPosition.iX;
|
|
|
|
if( giBoxY != 0 )
|
|
{
|
|
TrainPosition.iY = giBoxY + ( ASSIGN_MENU_TRAIN * GetFontHeight( MAP_SCREEN_FONT ) );
|
|
}
|
|
|
|
// create basic box
|
|
CreatePopUpBox(&ghTrainingBox, TrainDimensions, TrainPosition, (POPUP_BOX_FLAG_CLIP_TEXT|POPUP_BOX_FLAG_CENTER_TEXT|POPUP_BOX_FLAG_RESIZE ));
|
|
|
|
// which buffer will box render to
|
|
SetBoxBuffer(ghTrainingBox, FRAME_BUFFER);
|
|
|
|
// border type?
|
|
SetBorderType(ghTrainingBox,guiPOPUPBORDERS);
|
|
|
|
// background texture
|
|
SetBackGroundSurface(ghTrainingBox, guiPOPUPTEX);
|
|
|
|
// margin sizes
|
|
SetMargins(ghTrainingBox, 6, 6, 4, 4 );
|
|
|
|
// space between lines
|
|
SetLineSpace(ghTrainingBox, 2);
|
|
|
|
// set current box to this one
|
|
SetCurrentBox( ghTrainingBox );
|
|
|
|
|
|
// add strings for box
|
|
for(uiCounter=0; uiCounter < MAX_TRAIN_STRING_COUNT; uiCounter++)
|
|
{
|
|
AddMonoString(&hStringHandle, pTrainingMenuStrings[uiCounter]);
|
|
|
|
// make sure it is unhighlighted
|
|
UnHighLightLine(hStringHandle);
|
|
}
|
|
|
|
// set font type
|
|
SetBoxFont(ghTrainingBox, MAP_SCREEN_FONT);
|
|
|
|
// set highlight color
|
|
SetBoxHighLight(ghTrainingBox, FONT_WHITE);
|
|
|
|
// unhighlighted color
|
|
SetBoxForeground(ghTrainingBox, FONT_LTGREEN);
|
|
|
|
// background color
|
|
SetBoxBackground(ghTrainingBox, FONT_BLACK);
|
|
|
|
// shaded color..for darkened text
|
|
SetBoxShade( ghTrainingBox, FONT_GRAY7 );
|
|
|
|
// resize box to text
|
|
ResizeBoxToText( ghTrainingBox );
|
|
|
|
DetermineBoxPositions( );
|
|
|
|
}
|
|
|
|
|
|
void CreateAssignmentsBox( void )
|
|
{
|
|
UINT32 hStringHandle;
|
|
UINT32 uiCounter;
|
|
CHAR16 sString[ 128 ];
|
|
SOLDIERTYPE *pSoldier = NULL;
|
|
|
|
|
|
// will create attribute pop up menu for mapscreen assignments
|
|
|
|
AssignmentPosition.iX = OrigAssignmentPosition.iX;
|
|
|
|
if( giBoxY != 0 )
|
|
{
|
|
AssignmentPosition.iY = giBoxY;
|
|
}
|
|
|
|
|
|
pSoldier = GetSelectedAssignSoldier( TRUE );
|
|
// pSoldier NULL is legal here! Gets called during every mapscreen initialization even when nobody is assign char
|
|
|
|
// create basic box
|
|
CreatePopUpBox(&ghAssignmentBox, AssignmentDimensions, AssignmentPosition, (POPUP_BOX_FLAG_CLIP_TEXT|POPUP_BOX_FLAG_CENTER_TEXT|POPUP_BOX_FLAG_RESIZE ));
|
|
|
|
// which buffer will box render to
|
|
SetBoxBuffer(ghAssignmentBox, FRAME_BUFFER);
|
|
|
|
// border type?
|
|
SetBorderType(ghAssignmentBox,guiPOPUPBORDERS);
|
|
|
|
// background texture
|
|
SetBackGroundSurface(ghAssignmentBox, guiPOPUPTEX);
|
|
|
|
// margin sizes
|
|
SetMargins(ghAssignmentBox, 6, 6, 4, 4 );
|
|
|
|
// space between lines
|
|
SetLineSpace(ghAssignmentBox, 2);
|
|
|
|
// set current box to this one
|
|
SetCurrentBox( ghAssignmentBox );
|
|
|
|
// add strings for box
|
|
for(uiCounter=0; uiCounter < MAX_ASSIGN_STRING_COUNT; uiCounter++)
|
|
{
|
|
// if we have a soldier, and this is the squad line
|
|
if( ( uiCounter == ASSIGN_MENU_ON_DUTY ) && ( pSoldier != NULL ) && ( pSoldier->bAssignment < ON_DUTY ) )
|
|
{
|
|
// show his squad # in brackets
|
|
swprintf( sString, L"%s(%d)", pAssignMenuStrings[uiCounter], pSoldier->bAssignment + 1 );
|
|
}
|
|
else
|
|
{
|
|
swprintf( sString, pAssignMenuStrings[uiCounter] );
|
|
}
|
|
|
|
AddMonoString(&hStringHandle, sString );
|
|
|
|
// make sure it is unhighlighted
|
|
UnHighLightLine(hStringHandle);
|
|
}
|
|
|
|
// set font type
|
|
SetBoxFont(ghAssignmentBox, MAP_SCREEN_FONT);
|
|
|
|
// set highlight color
|
|
SetBoxHighLight(ghAssignmentBox, FONT_WHITE);
|
|
|
|
// unhighlighted color
|
|
SetBoxForeground(ghAssignmentBox, FONT_LTGREEN);
|
|
|
|
// background color
|
|
SetBoxBackground(ghAssignmentBox, FONT_BLACK);
|
|
|
|
// shaded color..for darkened text
|
|
SetBoxShade( ghAssignmentBox, FONT_GRAY7 );
|
|
SetBoxSecondaryShade( ghAssignmentBox, FONT_YELLOW );
|
|
|
|
// resize box to text
|
|
ResizeBoxToText( ghAssignmentBox );
|
|
|
|
DetermineBoxPositions( );
|
|
}
|
|
|
|
|
|
void CreateMercRemoveAssignBox( void )
|
|
{
|
|
// will create remove mercbox to be placed in assignment area
|
|
|
|
UINT32 hStringHandle;
|
|
UINT32 uiCounter;
|
|
// create basic box
|
|
CreatePopUpBox(&ghRemoveMercAssignBox, AssignmentDimensions, AssignmentPosition, (POPUP_BOX_FLAG_CLIP_TEXT|POPUP_BOX_FLAG_CENTER_TEXT|POPUP_BOX_FLAG_RESIZE ));
|
|
|
|
// which buffer will box render to
|
|
SetBoxBuffer(ghRemoveMercAssignBox, FRAME_BUFFER);
|
|
|
|
// border type?
|
|
SetBorderType(ghRemoveMercAssignBox,guiPOPUPBORDERS);
|
|
|
|
// background texture
|
|
SetBackGroundSurface(ghRemoveMercAssignBox, guiPOPUPTEX);
|
|
|
|
// margin sizes
|
|
SetMargins( ghRemoveMercAssignBox, 6, 6, 4, 4 );
|
|
|
|
// space between lines
|
|
SetLineSpace(ghRemoveMercAssignBox, 2);
|
|
|
|
// set current box to this one
|
|
SetCurrentBox( ghRemoveMercAssignBox );
|
|
|
|
// add strings for box
|
|
for(uiCounter=0; uiCounter < MAX_REMOVE_MERC_COUNT; uiCounter++)
|
|
{
|
|
AddMonoString(&hStringHandle, pRemoveMercStrings[uiCounter]);
|
|
|
|
// make sure it is unhighlighted
|
|
UnHighLightLine(hStringHandle);
|
|
}
|
|
|
|
// set font type
|
|
SetBoxFont(ghRemoveMercAssignBox, MAP_SCREEN_FONT);
|
|
|
|
// set highlight color
|
|
SetBoxHighLight(ghRemoveMercAssignBox, FONT_WHITE);
|
|
|
|
// unhighlighted color
|
|
SetBoxForeground(ghRemoveMercAssignBox, FONT_LTGREEN);
|
|
|
|
// background color
|
|
SetBoxBackground(ghRemoveMercAssignBox, FONT_BLACK);
|
|
|
|
// shaded color..for darkened text
|
|
SetBoxShade( ghRemoveMercAssignBox, FONT_GRAY7 );
|
|
|
|
// resize box to text
|
|
ResizeBoxToText( ghRemoveMercAssignBox );
|
|
}
|
|
|
|
|
|
BOOLEAN CreateDestroyAssignmentPopUpBoxes( void )
|
|
{
|
|
static BOOLEAN fCreated= FALSE;
|
|
VSURFACE_DESC vs_desc;
|
|
VOBJECT_DESC VObjectDesc;
|
|
|
|
|
|
if( ( fShowAssignmentMenu == TRUE ) && ( fCreated == FALSE ) )
|
|
{
|
|
VObjectDesc.fCreateFlags=VOBJECT_CREATE_FROMFILE;
|
|
FilenameForBPP("INTERFACE\\popup.sti", VObjectDesc.ImageFile);
|
|
CHECKF(AddVideoObject(&VObjectDesc, &guiPOPUPBORDERS));
|
|
|
|
vs_desc.fCreateFlags = VSURFACE_CREATE_FROMFILE | VSURFACE_SYSTEM_MEM_USAGE;
|
|
strcpy(vs_desc.ImageFile, "INTERFACE\\popupbackground.pcx");
|
|
CHECKF(AddVideoSurface(&vs_desc, &guiPOPUPTEX));
|
|
|
|
// these boxes are always created while in mapscreen...
|
|
CreateEPCBox( );
|
|
// WANNE 2 <ab>
|
|
CreateAssignmentsBox( );
|
|
CreateTrainingBox( );
|
|
CreateAttributeBox();
|
|
CreateVehicleBox();
|
|
CreateRepairBox( );
|
|
|
|
UpdateMapScreenAssignmentPositions( );
|
|
|
|
fCreated = TRUE;
|
|
}
|
|
else if( ( fShowAssignmentMenu == FALSE ) && ( fCreated == TRUE ) )
|
|
{
|
|
DeleteVideoObjectFromIndex(guiPOPUPBORDERS);
|
|
DeleteVideoSurfaceFromIndex(guiPOPUPTEX);
|
|
|
|
RemoveBox(ghAttributeBox);
|
|
ghAttributeBox = -1;
|
|
|
|
RemoveBox(ghVehicleBox);
|
|
ghVehicleBox = -1;
|
|
|
|
RemoveBox(ghAssignmentBox);
|
|
ghAssignmentBox = -1;
|
|
|
|
RemoveBox(ghEpcBox);
|
|
ghEpcBox = -1;
|
|
|
|
RemoveBox(ghRepairBox);
|
|
ghRepairBox = -1;
|
|
|
|
RemoveBox(ghTrainingBox);
|
|
ghTrainingBox = -1;
|
|
|
|
fCreated = FALSE;
|
|
gfIgnoreScrolling = FALSE;
|
|
RebuildCurrentSquad( );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
|
|
void DetermineBoxPositions( void )
|
|
{
|
|
// depending on how many boxes there are, reposition as needed
|
|
SGPPoint pPoint;
|
|
SGPPoint pNewPoint;
|
|
SGPRect pDimensions;
|
|
SOLDIERTYPE *pSoldier = NULL;
|
|
|
|
|
|
if( ( fShowAssignmentMenu == FALSE ) || ( ghAssignmentBox == -1 ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
pSoldier = GetSelectedAssignSoldier( TRUE );
|
|
// pSoldier NULL is legal here! Gets called during every mapscreen initialization even when nobody is assign char
|
|
if ( pSoldier == NULL )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( (guiTacticalInterfaceFlags & INTERFACE_MAPSCREEN ) )
|
|
{
|
|
GetBoxPosition( ghAssignmentBox, &pPoint );
|
|
gsAssignmentBoxesX = ( INT16 )pPoint.iX;
|
|
gsAssignmentBoxesY = ( INT16 )pPoint.iY;
|
|
}
|
|
|
|
pPoint.iX = gsAssignmentBoxesX;
|
|
pPoint.iY = gsAssignmentBoxesY;
|
|
|
|
if( pSoldier -> ubWhatKindOfMercAmI == MERC_TYPE__EPC )
|
|
{
|
|
SetBoxPosition( ghEpcBox, pPoint );
|
|
GetBoxSize( ghEpcBox, &pDimensions );
|
|
}
|
|
else
|
|
{
|
|
SetBoxPosition( ghAssignmentBox, pPoint );
|
|
GetBoxSize( ghAssignmentBox, &pDimensions );
|
|
}
|
|
|
|
|
|
// hang it right beside the assignment/EPC box menu
|
|
pNewPoint.iX = pPoint.iX + pDimensions.iRight;
|
|
pNewPoint.iY = pPoint.iY;
|
|
|
|
if( ( fShowSquadMenu == TRUE ) && ( ghSquadBox != -1 ) )
|
|
{
|
|
SetBoxPosition( ghSquadBox, pNewPoint );
|
|
}
|
|
|
|
if( ( fShowRepairMenu == TRUE ) && ( ghRepairBox != -1 ) )
|
|
{
|
|
CreateDestroyMouseRegionForRepairMenu( );
|
|
pNewPoint.iY += ( ( GetFontHeight( MAP_SCREEN_FONT ) + 2 ) * ASSIGN_MENU_REPAIR );
|
|
|
|
SetBoxPosition( ghRepairBox, pNewPoint );
|
|
}
|
|
|
|
if( ( fShowTrainingMenu == TRUE ) && ( ghTrainingBox != -1 ) )
|
|
{
|
|
pNewPoint.iY += ( ( GetFontHeight( MAP_SCREEN_FONT ) + 2 ) * ASSIGN_MENU_TRAIN );
|
|
SetBoxPosition( ghTrainingBox, pNewPoint );
|
|
TrainPosition.iX = pNewPoint.iX;
|
|
TrainPosition.iY = pNewPoint.iY;
|
|
OrigTrainPosition.iY = pNewPoint.iY;
|
|
OrigTrainPosition.iX = pNewPoint.iX;
|
|
|
|
GetBoxSize( ghTrainingBox, &pDimensions );
|
|
GetBoxPosition( ghTrainingBox, &pPoint );
|
|
|
|
if( ( fShowAttributeMenu == TRUE ) && ( ghAttributeBox != -1 ) )
|
|
{
|
|
// hang it right beside the training box menu
|
|
pNewPoint.iX = pPoint.iX + pDimensions.iRight;
|
|
pNewPoint.iY = pPoint.iY;
|
|
SetBoxPosition( ghAttributeBox, pNewPoint );
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void SetTacticalPopUpAssignmentBoxXY( void )
|
|
{
|
|
INT16 sX, sY;
|
|
SOLDIERTYPE *pSoldier;
|
|
|
|
|
|
//get the soldier
|
|
pSoldier = GetSelectedAssignSoldier( FALSE );
|
|
|
|
// grab soldier's x,y screen position
|
|
GetSoldierScreenPos( pSoldier, &sX, &sY );
|
|
|
|
if( sX < 0 )
|
|
{
|
|
sX = 0;
|
|
}
|
|
|
|
gsAssignmentBoxesX = sX + 30;
|
|
|
|
if( sY < 0 )
|
|
{
|
|
sY = 0;
|
|
}
|
|
|
|
gsAssignmentBoxesY = sY;
|
|
|
|
|
|
// WANNE 2
|
|
// ATE: Check if we are past tactical viewport....
|
|
// Use estimate width's/heights
|
|
if ( ( gsAssignmentBoxesX + 100 ) > SCREEN_WIDTH )
|
|
{
|
|
//gsAssignmentBoxesX = 540;
|
|
gsAssignmentBoxesX = SCREEN_WIDTH - 100;
|
|
}
|
|
|
|
// WANNE 2
|
|
if ( ( gsAssignmentBoxesY + 130 ) > (SCREEN_HEIGHT - 160) )
|
|
{
|
|
gsAssignmentBoxesY = SCREEN_HEIGHT - 290;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void RepositionMouseRegions( void )
|
|
{
|
|
INT16 sDeltaX, sDeltaY;
|
|
INT32 iCounter = 0;
|
|
|
|
if( fShowAssignmentMenu == TRUE )
|
|
{
|
|
sDeltaX = gsAssignmentBoxesX - gAssignmentMenuRegion[ 0 ].RegionTopLeftX;
|
|
sDeltaY = ( INT16 ) ( gsAssignmentBoxesY - gAssignmentMenuRegion[ 0 ].RegionTopLeftY + GetTopMarginSize( ghAssignmentBox ) );
|
|
|
|
// find the delta from the old to the new, and alter values accordingly
|
|
for( iCounter = 0; iCounter < ( INT32 )GetNumberOfLinesOfTextInBox( ghAssignmentBox ); iCounter++ )
|
|
{
|
|
gAssignmentMenuRegion[ iCounter ].RegionTopLeftX += sDeltaX;
|
|
gAssignmentMenuRegion[ iCounter ].RegionTopLeftY += sDeltaY;
|
|
|
|
gAssignmentMenuRegion[ iCounter ].RegionBottomRightX += sDeltaX;
|
|
gAssignmentMenuRegion[ iCounter ].RegionBottomRightY += sDeltaY;
|
|
}
|
|
|
|
gfPausedTacticalRenderFlags = RENDER_FLAG_FULL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void CheckAndUpdateTacticalAssignmentPopUpPositions( void )
|
|
{
|
|
SGPRect pDimensions, pDimensions2, pDimensions3;
|
|
SGPPoint pPoint;
|
|
INT16 sLongest;
|
|
SOLDIERTYPE *pSoldier = NULL;
|
|
|
|
|
|
if( fShowAssignmentMenu == FALSE )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( (guiTacticalInterfaceFlags & INTERFACE_MAPSCREEN ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
//get the soldier
|
|
pSoldier = GetSelectedAssignSoldier( FALSE );
|
|
|
|
if( pSoldier -> ubWhatKindOfMercAmI == MERC_TYPE__EPC )
|
|
{
|
|
GetBoxSize( ghEpcBox, &pDimensions2 );
|
|
}
|
|
else
|
|
{
|
|
GetBoxSize( ghAssignmentBox, &pDimensions2 );
|
|
}
|
|
|
|
if( fShowRepairMenu == TRUE )
|
|
{
|
|
GetBoxSize( ghRepairBox, &pDimensions );
|
|
|
|
// WANNE 2
|
|
if( gsAssignmentBoxesX + pDimensions2.iRight + pDimensions.iRight >= SCREEN_WIDTH )
|
|
{
|
|
gsAssignmentBoxesX = ( INT16 ) ( (SCREEN_WIDTH - 1) - ( pDimensions2.iRight + pDimensions.iRight ) );
|
|
SetRenderFlags( RENDER_FLAG_FULL );
|
|
}
|
|
|
|
if( pDimensions2.iBottom > pDimensions.iBottom )
|
|
{
|
|
sLongest = ( INT16 )pDimensions2.iBottom + ( ( GetFontHeight( MAP_SCREEN_FONT ) + 2 ) * ASSIGN_MENU_REPAIR );
|
|
}
|
|
else
|
|
{
|
|
sLongest = ( INT16 )pDimensions.iBottom + ( ( GetFontHeight( MAP_SCREEN_FONT ) + 2 ) * ASSIGN_MENU_REPAIR );
|
|
}
|
|
|
|
// WANNE 2
|
|
if( gsAssignmentBoxesY + sLongest >= (SCREEN_HEIGHT - 120) )
|
|
{
|
|
gsAssignmentBoxesY = ( INT16 )( (SCREEN_HEIGHT - 121) - ( sLongest ) );
|
|
SetRenderFlags( RENDER_FLAG_FULL );
|
|
}
|
|
|
|
pPoint.iX = gsAssignmentBoxesX + pDimensions2.iRight;
|
|
pPoint.iY = gsAssignmentBoxesY + ( ( GetFontHeight( MAP_SCREEN_FONT ) + 2 ) * ASSIGN_MENU_REPAIR );
|
|
|
|
SetBoxPosition( ghRepairBox, pPoint );
|
|
}
|
|
else if( fShowSquadMenu == TRUE )
|
|
{
|
|
GetBoxSize( ghSquadBox, &pDimensions );
|
|
|
|
|
|
if( gsAssignmentBoxesX + pDimensions2.iRight + pDimensions.iRight >= SCREEN_WIDTH )
|
|
{
|
|
gsAssignmentBoxesX = ( INT16 ) ( (SCREEN_WIDTH - 1) - ( pDimensions2.iRight + pDimensions.iRight ) );
|
|
SetRenderFlags( RENDER_FLAG_FULL );
|
|
}
|
|
|
|
if( pDimensions2.iBottom > pDimensions.iBottom )
|
|
{
|
|
sLongest = ( INT16 )pDimensions2.iBottom;
|
|
}
|
|
else
|
|
{
|
|
sLongest = ( INT16 )pDimensions.iBottom;
|
|
}
|
|
|
|
// WANNE 2
|
|
if( gsAssignmentBoxesY + sLongest >= (SCREEN_HEIGHT - 120) )
|
|
{
|
|
gsAssignmentBoxesY = ( INT16 )( (SCREEN_HEIGHT - 121) - ( sLongest ) );
|
|
SetRenderFlags( RENDER_FLAG_FULL );
|
|
}
|
|
|
|
pPoint.iX = gsAssignmentBoxesX + pDimensions2.iRight;
|
|
pPoint.iY = gsAssignmentBoxesY;
|
|
|
|
SetBoxPosition( ghSquadBox, pPoint );
|
|
}
|
|
else if( fShowAttributeMenu == TRUE )
|
|
{
|
|
GetBoxSize( ghTrainingBox, &pDimensions );
|
|
GetBoxSize( ghAttributeBox, &pDimensions3 );
|
|
|
|
// WANNE 2
|
|
if( gsAssignmentBoxesX + pDimensions2.iRight + pDimensions.iRight + pDimensions3.iRight >= SCREEN_WIDTH )
|
|
{
|
|
gsAssignmentBoxesX = ( INT16 ) ( (SCREEN_WIDTH - 1) - ( pDimensions2.iRight + pDimensions.iRight + pDimensions3.iRight ) );
|
|
SetRenderFlags( RENDER_FLAG_FULL );
|
|
}
|
|
|
|
// WANNE 2
|
|
if( gsAssignmentBoxesY + pDimensions3.iBottom + ( GetFontHeight( MAP_SCREEN_FONT ) * ASSIGN_MENU_TRAIN ) >= (SCREEN_HEIGHT - 120) )
|
|
{
|
|
gsAssignmentBoxesY = ( INT16 )( (SCREEN_HEIGHT - 121) - ( pDimensions3.iBottom ) );
|
|
SetRenderFlags( RENDER_FLAG_FULL );
|
|
}
|
|
|
|
pPoint.iX = gsAssignmentBoxesX + pDimensions2.iRight + pDimensions.iRight;
|
|
pPoint.iY = gsAssignmentBoxesY;
|
|
|
|
pPoint.iY += ( ( GetFontHeight( MAP_SCREEN_FONT ) + 2 ) * ASSIGN_MENU_TRAIN );
|
|
SetBoxPosition( ghAttributeBox, pPoint );
|
|
|
|
pPoint.iX = gsAssignmentBoxesX + pDimensions2.iRight;
|
|
pPoint.iY = gsAssignmentBoxesY;
|
|
|
|
pPoint.iY += ( ( GetFontHeight( MAP_SCREEN_FONT ) + 2 ) * ASSIGN_MENU_TRAIN );
|
|
|
|
SetBoxPosition( ghTrainingBox, pPoint );
|
|
|
|
|
|
}
|
|
else if( fShowTrainingMenu == TRUE )
|
|
{
|
|
GetBoxSize( ghTrainingBox, &pDimensions );
|
|
|
|
// WANNE 2
|
|
if( gsAssignmentBoxesX + pDimensions2.iRight + pDimensions.iRight >= SCREEN_WIDTH )
|
|
{
|
|
gsAssignmentBoxesX = ( INT16 ) ( (SCREEN_WIDTH - 1) - ( pDimensions2.iRight + pDimensions.iRight ) );
|
|
SetRenderFlags( RENDER_FLAG_FULL );
|
|
}
|
|
|
|
// WANNE 2
|
|
if( gsAssignmentBoxesY + pDimensions2.iBottom + ( ( GetFontHeight( MAP_SCREEN_FONT ) + 2 ) * ASSIGN_MENU_TRAIN ) >= (SCREEN_HEIGHT - 120) )
|
|
{
|
|
gsAssignmentBoxesY = ( INT16 )( (SCREEN_HEIGHT - 121) - ( pDimensions2.iBottom ) - ( ( GetFontHeight( MAP_SCREEN_FONT ) + 2 ) * ASSIGN_MENU_TRAIN ) );
|
|
SetRenderFlags( RENDER_FLAG_FULL );
|
|
}
|
|
|
|
|
|
|
|
pPoint.iX = gsAssignmentBoxesX + pDimensions2.iRight;
|
|
pPoint.iY = gsAssignmentBoxesY;
|
|
pPoint.iY += ( ( GetFontHeight( MAP_SCREEN_FONT ) + 2 ) * ASSIGN_MENU_TRAIN );
|
|
|
|
SetBoxPosition( ghTrainingBox, pPoint );
|
|
}
|
|
else
|
|
{
|
|
// WANNE 2
|
|
// just the assignment box
|
|
if( gsAssignmentBoxesX + pDimensions2.iRight >= SCREEN_WIDTH )
|
|
{
|
|
gsAssignmentBoxesX = ( INT16 ) ( (SCREEN_WIDTH - 1) - ( pDimensions2.iRight ) );
|
|
SetRenderFlags( RENDER_FLAG_FULL );
|
|
}
|
|
|
|
if( gsAssignmentBoxesY + pDimensions2.iBottom >= (SCREEN_HEIGHT - 120) )
|
|
{
|
|
gsAssignmentBoxesY = ( INT16 )( (SCREEN_HEIGHT - 121) - ( pDimensions2.iBottom ) );
|
|
SetRenderFlags( RENDER_FLAG_FULL );
|
|
}
|
|
|
|
pPoint.iX = gsAssignmentBoxesX;
|
|
pPoint.iY = gsAssignmentBoxesY;
|
|
|
|
if( pSoldier -> ubWhatKindOfMercAmI == MERC_TYPE__EPC)
|
|
{
|
|
SetBoxPosition( ghEpcBox, pPoint );
|
|
}
|
|
else
|
|
{
|
|
SetBoxPosition( ghAssignmentBox, pPoint );
|
|
}
|
|
}
|
|
|
|
RepositionMouseRegions( );
|
|
}
|
|
|
|
|
|
|
|
void PositionCursorForTacticalAssignmentBox( void )
|
|
{
|
|
// position cursor over y of on duty in tactical assignments
|
|
SGPPoint pPosition;
|
|
SGPRect pDimensions;
|
|
INT32 iFontHeight;
|
|
|
|
// get x.y position of box
|
|
GetBoxPosition( ghAssignmentBox, &pPosition);
|
|
|
|
// get dimensions..mostly for width
|
|
GetBoxSize( ghAssignmentBox, &pDimensions );
|
|
|
|
iFontHeight = GetLineSpace( ghAssignmentBox ) + GetFontHeight( GetBoxFont( ghAssignmentBox ) );
|
|
|
|
// WANNE 2
|
|
if( gGameSettings.fOptions[ TOPTION_DONT_MOVE_MOUSE ] == FALSE )
|
|
{
|
|
//SimulateMouseMovement( pPosition.iX + pDimensions.iRight - 6, pPosition.iY + ( iFontHeight / 2 ) + 2 );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void HandleRestFatigueAndSleepStatus( void )
|
|
{
|
|
INT32 iCounter = 0, iNumberOnTeam = 0;
|
|
SOLDIERTYPE * pSoldier;
|
|
BOOLEAN fReasonAdded = FALSE;
|
|
BOOLEAN fBoxSetUp = FALSE;
|
|
BOOLEAN fMeToo = FALSE;
|
|
|
|
|
|
iNumberOnTeam =gTacticalStatus.Team[ OUR_TEAM ].bLastID;
|
|
|
|
// run through all player characters and handle their rest, fatigue, and going to sleep
|
|
for( iCounter = 0; iCounter < iNumberOnTeam; iCounter++ )
|
|
{
|
|
pSoldier = &Menptr[ iCounter ];
|
|
|
|
if( pSoldier -> bActive )
|
|
{
|
|
if( ( pSoldier -> uiStatusFlags & SOLDIER_VEHICLE ) || AM_A_ROBOT( pSoldier ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if( ( pSoldier -> bAssignment == ASSIGNMENT_POW ) || ( pSoldier -> bAssignment == IN_TRANSIT ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// if character CAN sleep, he doesn't actually have to be put asleep to get some rest,
|
|
// many other assignments and conditions allow for automatic recovering from fatigue.
|
|
if( CharacterIsTakingItEasy( pSoldier ) )
|
|
{
|
|
// let them rest some
|
|
RestCharacter( pSoldier );
|
|
}
|
|
else
|
|
{
|
|
// wear them down
|
|
FatigueCharacter( pSoldier );
|
|
}
|
|
|
|
|
|
// CHECK FOR MERCS GOING TO SLEEP
|
|
|
|
// if awake
|
|
if ( !pSoldier->fMercAsleep )
|
|
{
|
|
// if dead tired
|
|
if( pSoldier -> bBreathMax <= BREATHMAX_ABSOLUTE_MINIMUM )
|
|
{
|
|
// if between sectors, don't put tired mercs to sleep... will be handled when they arrive at the next sector
|
|
if ( pSoldier->fBetweenSectors )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// he goes to sleep, provided it's at all possible (it still won't happen in a hostile sector, etc.)
|
|
if( SetMercAsleep( pSoldier, FALSE ) )
|
|
{
|
|
if( ( pSoldier -> bAssignment < ON_DUTY ) || ( pSoldier -> bAssignment == VEHICLE ) )
|
|
{
|
|
// on a squad/vehicle, complain, then drop
|
|
TacticalCharacterDialogue( pSoldier, QUOTE_NEED_SLEEP );
|
|
TacticalCharacterDialogueWithSpecialEvent( pSoldier, QUOTE_NEED_SLEEP, DIALOGUE_SPECIAL_EVENT_SLEEP, 1,0 );
|
|
fMeToo = TRUE;
|
|
}
|
|
|
|
// guy collapses
|
|
pSoldier -> fMercCollapsedFlag = TRUE;
|
|
}
|
|
}
|
|
// if pretty tired, and not forced to stay awake
|
|
else if( ( pSoldier -> bBreathMax < BREATHMAX_PRETTY_TIRED ) && ( pSoldier -> fForcedToStayAwake == FALSE ) )
|
|
{
|
|
// if not on squad/ in vehicle
|
|
if( ( pSoldier -> bAssignment >= ON_DUTY ) && ( pSoldier -> bAssignment != VEHICLE ) )
|
|
{
|
|
// try to go to sleep on your own
|
|
if( SetMercAsleep( pSoldier, FALSE ) )
|
|
{
|
|
if( gGameSettings.fOptions[ TOPTION_SLEEPWAKE_NOTIFICATION ] )
|
|
{
|
|
// if the first one
|
|
if( fReasonAdded == FALSE )
|
|
{
|
|
// tell player about it
|
|
AddReasonToWaitingListQueue( ASLEEP_GOING_AUTO_FOR_UPDATE );
|
|
TacticalCharacterDialogueWithSpecialEvent( pSoldier, 0, DIALOGUE_SPECIAL_EVENT_SHOW_UPDATE_MENU, 0,0 );
|
|
|
|
fReasonAdded = TRUE;
|
|
}
|
|
|
|
AddSoldierToWaitingListQueue( pSoldier );
|
|
fBoxSetUp = TRUE;
|
|
}
|
|
|
|
// seems unnecessary now? ARM
|
|
pSoldier -> bOldAssignment = pSoldier -> bAssignment;
|
|
}
|
|
}
|
|
else // tired, in a squad / vehicle
|
|
{
|
|
// if he hasn't complained yet
|
|
if ( !pSoldier->fComplainedThatTired )
|
|
{
|
|
// say quote
|
|
if( fMeToo == FALSE )
|
|
{
|
|
TacticalCharacterDialogue( pSoldier, QUOTE_NEED_SLEEP );
|
|
fMeToo = TRUE;
|
|
}
|
|
else
|
|
{
|
|
TacticalCharacterDialogue( pSoldier, QUOTE_ME_TOO );
|
|
}
|
|
|
|
pSoldier->fComplainedThatTired = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if( fBoxSetUp )
|
|
{
|
|
UnPauseGameDuringNextQuote( );
|
|
AddDisplayBoxToWaitingQueue( );
|
|
fBoxSetUp = FALSE;
|
|
}
|
|
|
|
fReasonAdded = FALSE;
|
|
|
|
|
|
// now handle waking (needs seperate list queue, that's why it has its own loop)
|
|
for( iCounter = 0; iCounter < iNumberOnTeam; iCounter++ )
|
|
{
|
|
pSoldier = &Menptr[ iCounter ];
|
|
|
|
if( pSoldier -> bActive )
|
|
{
|
|
if( ( pSoldier -> uiStatusFlags & SOLDIER_VEHICLE ) || AM_A_ROBOT( pSoldier ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if( ( pSoldier -> bAssignment == ASSIGNMENT_POW ) || ( pSoldier -> bAssignment == IN_TRANSIT ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// guys between sectors CAN wake up while between sectors (sleeping in vehicle)...
|
|
|
|
|
|
// CHECK FOR MERCS WAKING UP
|
|
|
|
if ( pSoldier->bBreathMax >= BREATHMAX_CANCEL_COLLAPSE )
|
|
{
|
|
// reset the collapsed flag well before reaching the wakeup state
|
|
pSoldier -> fMercCollapsedFlag = FALSE;
|
|
}
|
|
|
|
|
|
// if asleep
|
|
if ( pSoldier -> fMercAsleep )
|
|
{
|
|
// but has had enough rest?
|
|
if( pSoldier -> bBreathMax >= BREATHMAX_FULLY_RESTED )
|
|
{
|
|
// try to wake merc up
|
|
if( SetMercAwake( pSoldier, FALSE, FALSE ) )
|
|
{
|
|
// if not on squad/ in vehicle, tell player about it
|
|
if( ( pSoldier -> bAssignment >= ON_DUTY ) && ( pSoldier -> bAssignment != VEHICLE ) )
|
|
{
|
|
if( gGameSettings.fOptions[ TOPTION_SLEEPWAKE_NOTIFICATION ] )
|
|
{
|
|
if( fReasonAdded == FALSE )
|
|
{
|
|
AddReasonToWaitingListQueue( ASSIGNMENT_RETURNING_FOR_UPDATE );
|
|
fReasonAdded = TRUE;
|
|
}
|
|
|
|
AddSoldierToWaitingListQueue( pSoldier );
|
|
fBoxSetUp = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if( fBoxSetUp )
|
|
{
|
|
UnPauseGameDuringNextQuote( );
|
|
AddDisplayBoxToWaitingQueue( );
|
|
fBoxSetUp = FALSE;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN CanCharacterRepairVehicle( SOLDIERTYPE *pSoldier, INT32 iVehicleId )
|
|
{
|
|
// is the vehicle valid?
|
|
if( VehicleIdIsValid( iVehicleId ) == FALSE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// is vehicle destroyed?
|
|
if( pVehicleList[ iVehicleId ].fDestroyed )
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
// is it damaged at all?
|
|
if ( !DoesVehicleNeedAnyRepairs( iVehicleId ) )
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
// it's not Skyrider's helicopter (which isn't damagable/repairable)
|
|
if ( iVehicleId == iHelicopterVehicleId )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// same sector, neither is between sectors, and OK To Use (player owns it) ?
|
|
if ( !IsThisVehicleAccessibleToSoldier( pSoldier, iVehicleId ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
/* Assignment distance limits removed. Sep/11/98. ARM
|
|
// if currently loaded sector, are we close enough?
|
|
if( ( pSoldier->sSectorX == gWorldSectorX ) && ( pSoldier->sSectorY == gWorldSectorY ) && ( pSoldier->bSectorZ == gbWorldSectorZ ) )
|
|
{
|
|
if( PythSpacesAway( pSoldier -> sGridNo, pVehicleList[ iVehicleId ].sGridNo ) > MAX_DISTANCE_FOR_REPAIR )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
*/
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN IsRobotInThisSector( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ )
|
|
{
|
|
SOLDIERTYPE *pSoldier;
|
|
|
|
pSoldier = GetRobotSoldier( );
|
|
|
|
if ( pSoldier != NULL )
|
|
{
|
|
if( ( pSoldier -> sSectorX == sSectorX ) && ( pSoldier -> sSectorY == sSectorY ) && ( pSoldier -> bSectorZ == bSectorZ ) && ( pSoldier -> fBetweenSectors == FALSE ) )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
|
|
SOLDIERTYPE * GetRobotSoldier( void )
|
|
{
|
|
SOLDIERTYPE *pSoldier = NULL, *pTeamSoldier = NULL;
|
|
INT32 cnt=0;
|
|
|
|
// set pSoldier as first in merc ptrs
|
|
pSoldier = MercPtrs[0];
|
|
|
|
// go through list of characters, find all who are on this assignment
|
|
for ( pTeamSoldier = MercPtrs[ cnt ]; cnt <= gTacticalStatus.Team[ pSoldier -> bTeam ].bLastID; cnt++,pTeamSoldier++)
|
|
{
|
|
if( pTeamSoldier -> bActive )
|
|
{
|
|
if( AM_A_ROBOT( pTeamSoldier ) )
|
|
{
|
|
return (pTeamSoldier);
|
|
}
|
|
}
|
|
}
|
|
|
|
return( NULL );
|
|
}
|
|
|
|
|
|
BOOLEAN CanCharacterRepairRobot( SOLDIERTYPE *pSoldier )
|
|
{
|
|
SOLDIERTYPE *pRobot = NULL;
|
|
|
|
// do we in fact have the robot on the team?
|
|
pRobot = GetRobotSoldier( );
|
|
if( pRobot == NULL )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// if robot isn't damaged at all
|
|
if( pRobot -> bLife == pRobot -> bLifeMax )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// is the robot in the same sector
|
|
if( IsRobotInThisSector( pSoldier -> sSectorX, pSoldier -> sSectorY, pSoldier -> bSectorZ ) == FALSE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
/* Assignment distance limits removed. Sep/11/98. ARM
|
|
// if that sector is currently loaded, check distance to robot
|
|
if( ( pSoldier -> sSectorX == gWorldSectorX ) && ( pSoldier -> sSectorY == gWorldSectorY ) && ( pSoldier -> bSectorZ == gbWorldSectorZ ) )
|
|
{
|
|
if( PythSpacesAway( pSoldier -> sGridNo, pRobot -> sGridNo ) > MAX_DISTANCE_FOR_REPAIR )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
*/
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
|
|
UINT8 HandleRepairOfRobotBySoldier( SOLDIERTYPE *pSoldier, UINT8 ubRepairPts, BOOLEAN *pfNothingLeftToRepair )
|
|
{
|
|
SOLDIERTYPE *pRobot = NULL;
|
|
|
|
pRobot = GetRobotSoldier( );
|
|
|
|
// do the actual repairs
|
|
return( RepairRobot( pRobot, ubRepairPts, pfNothingLeftToRepair ) );
|
|
}
|
|
|
|
|
|
UINT8 RepairRobot( SOLDIERTYPE *pRobot, UINT8 ubRepairPts, BOOLEAN *pfNothingLeftToRepair )
|
|
{
|
|
UINT8 ubPointsUsed = 0;
|
|
|
|
|
|
// is it "dead" ?
|
|
if( pRobot -> bLife == 0 )
|
|
{
|
|
*pfNothingLeftToRepair = TRUE;
|
|
return( ubPointsUsed );
|
|
}
|
|
|
|
// is it "unhurt" ?
|
|
if( pRobot -> bLife == pRobot -> bLifeMax )
|
|
{
|
|
*pfNothingLeftToRepair = TRUE;
|
|
return( ubPointsUsed );
|
|
}
|
|
|
|
// if we have enough or more than we need
|
|
if( pRobot -> bLife + ubRepairPts >= pRobot -> bLifeMax )
|
|
{
|
|
ubPointsUsed = ( pRobot -> bLifeMax - pRobot -> bLife );
|
|
pRobot -> bLife = pRobot -> bLifeMax;
|
|
}
|
|
else
|
|
{
|
|
// not enough, do what we can
|
|
ubPointsUsed = ubRepairPts;
|
|
pRobot -> bLife += ubRepairPts;
|
|
}
|
|
|
|
if ( pRobot->bLife == pRobot->bLifeMax )
|
|
{
|
|
*pfNothingLeftToRepair = TRUE;
|
|
}
|
|
else
|
|
{
|
|
*pfNothingLeftToRepair = FALSE;
|
|
}
|
|
|
|
return( ubPointsUsed );
|
|
}
|
|
|
|
|
|
void SetSoldierAssignment( SOLDIERTYPE *pSoldier, INT8 bAssignment, INT32 iParam1, INT32 iParam2, INT32 iParam3 )
|
|
{
|
|
switch( bAssignment )
|
|
{
|
|
case( ASSIGNMENT_HOSPITAL ):
|
|
if( CanCharacterPatient( pSoldier ) )
|
|
{
|
|
|
|
pSoldier -> bOldAssignment = pSoldier -> bAssignment;
|
|
pSoldier->bBleeding = 0;
|
|
|
|
// set dirty flag
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
|
|
// remove from squad
|
|
|
|
RemoveCharacterFromSquads( pSoldier );
|
|
|
|
// remove from any vehicle
|
|
if( pSoldier->bOldAssignment == VEHICLE )
|
|
{
|
|
TakeSoldierOutOfVehicle( pSoldier );
|
|
}
|
|
|
|
if( ( pSoldier->bAssignment != ASSIGNMENT_HOSPITAL ) )
|
|
{
|
|
SetTimeOfAssignmentChangeForMerc( pSoldier );
|
|
}
|
|
|
|
|
|
RebuildCurrentSquad( );
|
|
|
|
ChangeSoldiersAssignment( pSoldier, ASSIGNMENT_HOSPITAL );
|
|
|
|
AssignMercToAMovementGroup( pSoldier );
|
|
}
|
|
break;
|
|
case( PATIENT ):
|
|
if( CanCharacterPatient( pSoldier ) )
|
|
{
|
|
// set as doctor
|
|
|
|
/* Assignment distance limits removed. Sep/11/98. ARM
|
|
if( IsSoldierCloseEnoughToADoctor( pSoldier ) == FALSE )
|
|
{
|
|
return;
|
|
}
|
|
*/
|
|
|
|
pSoldier -> bOldAssignment = pSoldier -> bAssignment;
|
|
|
|
|
|
// set dirty flag
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
|
|
// remove from squad
|
|
RemoveCharacterFromSquads( pSoldier );
|
|
|
|
// remove from any vehicle
|
|
if( pSoldier->bOldAssignment == VEHICLE )
|
|
{
|
|
TakeSoldierOutOfVehicle( pSoldier );
|
|
}
|
|
|
|
if( ( pSoldier->bAssignment != PATIENT ) )
|
|
{
|
|
SetTimeOfAssignmentChangeForMerc( pSoldier );
|
|
}
|
|
|
|
ChangeSoldiersAssignment( pSoldier, PATIENT );
|
|
|
|
AssignMercToAMovementGroup( pSoldier );
|
|
}
|
|
|
|
break;
|
|
case( DOCTOR ):
|
|
if( CanCharacterDoctor( pSoldier ) )
|
|
{
|
|
|
|
pSoldier -> bOldAssignment = pSoldier -> bAssignment;
|
|
|
|
|
|
// set dirty flag
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
gfRenderPBInterface = TRUE;
|
|
|
|
// remove from squad
|
|
RemoveCharacterFromSquads( pSoldier );
|
|
|
|
// remove from any vehicle
|
|
if( pSoldier->bOldAssignment == VEHICLE )
|
|
{
|
|
TakeSoldierOutOfVehicle( pSoldier );
|
|
}
|
|
|
|
if( ( pSoldier->bAssignment != DOCTOR ) )
|
|
{
|
|
SetTimeOfAssignmentChangeForMerc( pSoldier );
|
|
}
|
|
|
|
ChangeSoldiersAssignment( pSoldier, DOCTOR );
|
|
|
|
MakeSureMedKitIsInHand( pSoldier );
|
|
AssignMercToAMovementGroup( pSoldier );
|
|
}
|
|
break;
|
|
case( TRAIN_TOWN ):
|
|
if( CanCharacterTrainMilitia( pSoldier ) )
|
|
{
|
|
// train militia
|
|
pSoldier -> bOldAssignment = pSoldier -> bAssignment;
|
|
|
|
// set dirty flag
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
|
|
// remove from squad
|
|
RemoveCharacterFromSquads( pSoldier );
|
|
|
|
// remove from any vehicle
|
|
if( pSoldier->bOldAssignment == VEHICLE )
|
|
{
|
|
TakeSoldierOutOfVehicle( pSoldier );
|
|
}
|
|
|
|
if( ( pSoldier->bAssignment != TRAIN_TOWN ) )
|
|
{
|
|
SetTimeOfAssignmentChangeForMerc( pSoldier );
|
|
}
|
|
|
|
ChangeSoldiersAssignment( pSoldier, TRAIN_TOWN );
|
|
|
|
if( pMilitiaTrainerSoldier == NULL )
|
|
{
|
|
if( SectorInfo[ SECTOR( pSoldier -> sSectorX, pSoldier -> sSectorY ) ].fMilitiaTrainingPaid == FALSE )
|
|
{
|
|
// show a message to confirm player wants to charge cost
|
|
HandleInterfaceMessageForCostOfTrainingMilitia( pSoldier );
|
|
}
|
|
}
|
|
|
|
AssignMercToAMovementGroup( pSoldier );
|
|
// set dirty flag
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
gfRenderPBInterface = TRUE;
|
|
}
|
|
break;
|
|
case( TRAIN_SELF ):
|
|
if( CanCharacterTrainStat( pSoldier, ( INT8 )iParam1, TRUE, FALSE ) )
|
|
{
|
|
// train stat
|
|
pSoldier -> bOldAssignment = pSoldier -> bAssignment;
|
|
|
|
// remove from squad
|
|
RemoveCharacterFromSquads( pSoldier );
|
|
|
|
// remove from any vehicle
|
|
if( pSoldier->bOldAssignment == VEHICLE )
|
|
{
|
|
TakeSoldierOutOfVehicle( pSoldier );
|
|
}
|
|
|
|
if( ( pSoldier->bAssignment != TRAIN_SELF ) )
|
|
{
|
|
SetTimeOfAssignmentChangeForMerc( pSoldier );
|
|
}
|
|
|
|
ChangeSoldiersAssignment( pSoldier, TRAIN_SELF );
|
|
|
|
AssignMercToAMovementGroup( pSoldier );
|
|
|
|
// set stat to train
|
|
pSoldier -> bTrainStat = ( INT8 )iParam1;
|
|
|
|
// set dirty flag
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
gfRenderPBInterface = TRUE;
|
|
}
|
|
break;
|
|
case( TRAIN_TEAMMATE ):
|
|
if( CanCharacterTrainStat( pSoldier, ( INT8 )iParam1, FALSE, TRUE ) )
|
|
{
|
|
|
|
pSoldier -> bOldAssignment = pSoldier -> bAssignment;
|
|
// remove from squad
|
|
RemoveCharacterFromSquads( pSoldier );
|
|
|
|
// remove from any vehicle
|
|
if( pSoldier->bOldAssignment == VEHICLE )
|
|
{
|
|
TakeSoldierOutOfVehicle( pSoldier );
|
|
}
|
|
|
|
if( ( pSoldier->bAssignment != TRAIN_TEAMMATE ) )
|
|
{
|
|
SetTimeOfAssignmentChangeForMerc( pSoldier );
|
|
}
|
|
|
|
ChangeSoldiersAssignment( pSoldier, TRAIN_TEAMMATE );
|
|
AssignMercToAMovementGroup( pSoldier );
|
|
|
|
// set stat to train
|
|
pSoldier -> bTrainStat = ( INT8 )iParam1;
|
|
|
|
// set dirty flag
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
gfRenderPBInterface = TRUE;
|
|
}
|
|
break;
|
|
case( TRAIN_BY_OTHER ):
|
|
if( CanCharacterTrainStat( pSoldier, ( INT8 )iParam1, TRUE, FALSE ) )
|
|
{
|
|
// train stat
|
|
pSoldier -> bOldAssignment = pSoldier -> bAssignment;
|
|
|
|
// remove from squad
|
|
RemoveCharacterFromSquads( pSoldier );
|
|
|
|
// remove from any vehicle
|
|
if( pSoldier->bOldAssignment == VEHICLE )
|
|
{
|
|
TakeSoldierOutOfVehicle( pSoldier );
|
|
}
|
|
|
|
if( ( pSoldier->bAssignment != TRAIN_BY_OTHER ) )
|
|
{
|
|
SetTimeOfAssignmentChangeForMerc( pSoldier );
|
|
}
|
|
|
|
ChangeSoldiersAssignment( pSoldier, TRAIN_BY_OTHER );
|
|
|
|
AssignMercToAMovementGroup( pSoldier );
|
|
|
|
// set stat to train
|
|
pSoldier -> bTrainStat = ( INT8 )iParam1;
|
|
|
|
// set dirty flag
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
gfRenderPBInterface = TRUE;
|
|
}
|
|
break;
|
|
case( REPAIR ):
|
|
if( CanCharacterRepair( pSoldier ) )
|
|
{
|
|
pSoldier -> bOldAssignment = pSoldier -> bAssignment;
|
|
|
|
// remove from squad
|
|
RemoveCharacterFromSquads( pSoldier );
|
|
|
|
// remove from any vehicle
|
|
if( pSoldier->bOldAssignment == VEHICLE )
|
|
{
|
|
TakeSoldierOutOfVehicle( pSoldier );
|
|
}
|
|
|
|
if( ( pSoldier->bAssignment != REPAIR ) ||( pSoldier ->fFixingSAMSite != ( UINT8 )iParam1 ) || ( pSoldier ->fFixingRobot != ( UINT8 )iParam2 ) || ( pSoldier ->bVehicleUnderRepairID != ( UINT8 )iParam3 ) )
|
|
{
|
|
SetTimeOfAssignmentChangeForMerc( pSoldier );
|
|
}
|
|
|
|
ChangeSoldiersAssignment( pSoldier, REPAIR );
|
|
MakeSureToolKitIsInHand( pSoldier );
|
|
AssignMercToAMovementGroup( pSoldier );
|
|
pSoldier -> fFixingSAMSite = ( UINT8 )iParam1;
|
|
pSoldier -> fFixingRobot = ( UINT8 )iParam2;
|
|
pSoldier -> bVehicleUnderRepairID = ( INT8 )iParam3;
|
|
}
|
|
break;
|
|
case( VEHICLE ):
|
|
if( CanCharacterVehicle( pSoldier ) && IsThisVehicleAccessibleToSoldier( pSoldier, iParam1 ) )
|
|
{
|
|
if ( IsEnoughSpaceInVehicle( (INT8) iParam1 ) )
|
|
{
|
|
pSoldier -> bOldAssignment = pSoldier -> bAssignment;
|
|
|
|
// set dirty flag
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
gfRenderPBInterface = TRUE;
|
|
|
|
|
|
if( pSoldier->bOldAssignment == VEHICLE )
|
|
{
|
|
TakeSoldierOutOfVehicle( pSoldier );
|
|
}
|
|
|
|
// remove from squad
|
|
RemoveCharacterFromSquads( pSoldier );
|
|
|
|
if( PutSoldierInVehicle( pSoldier, ( INT8 )( iParam1 ) ) == FALSE )
|
|
{
|
|
AddCharacterToAnySquad( pSoldier );
|
|
}
|
|
else
|
|
{
|
|
if( ( pSoldier->bAssignment != VEHICLE ) || ( pSoldier ->iVehicleId != ( UINT8 )iParam1 ) )
|
|
{
|
|
SetTimeOfAssignmentChangeForMerc( pSoldier );
|
|
}
|
|
|
|
pSoldier -> iVehicleId = iParam1;
|
|
ChangeSoldiersAssignment( pSoldier, VEHICLE );
|
|
AssignMercToAMovementGroup( pSoldier );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, gzLateLocalizedString[ 18 ], zVehicleName[ pVehicleList[ iParam1 ].ubVehicleType ] );
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
/* No point in allowing SAM site repair any more. Jan/13/99. ARM
|
|
BOOLEAN CanSoldierRepairSAM( SOLDIERTYPE *pSoldier, INT8 bRepairPoints)
|
|
{
|
|
INT16 sGridNoA = 0, sGridNoB = 0;
|
|
|
|
// is the soldier in the sector as the SAM
|
|
if( SoldierInSameSectorAsSAM( pSoldier ) == FALSE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// is the soldier close enough to the control panel?
|
|
if( IsSoldierCloseEnoughToSAMControlPanel( pSoldier ) == FALSE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
//can it be fixed?
|
|
if( IsTheSAMSiteInSectorRepairable( pSoldier -> sSectorX, pSoldier -> sSectorY, pSoldier -> bSectorZ ) == FALSE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// is he good enough? (Because of the division of repair pts in SAM repair formula, a guy with any less that this
|
|
// can't make any headway
|
|
if (bRepairPoints < SAM_SITE_REPAIR_DIVISOR )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOLEAN IsTheSAMSiteInSectorRepairable( INT16 sSectorX, INT16 sSectorY, INT16 sSectorZ )
|
|
{
|
|
INT32 iCounter = 0;
|
|
INT8 bSAMCondition;
|
|
|
|
|
|
// is the guy above ground, if not, it can't be fixed, now can it?
|
|
if( sSectorZ != 0 )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
for( iCounter = 0; iCounter < NUMBER_OF_SAMS; iCounter++ )
|
|
{
|
|
if( pSamList[ iCounter ] == SECTOR( sSectorX, sSectorY ) )
|
|
{
|
|
bSAMCondition = StrategicMap[ CALCULATE_STRATEGIC_INDEX( sSectorX, sSectorY ) ].bSAMCondition;
|
|
|
|
if( ( bSAMCondition < 100 ) && ( bSAMCondition >= MIN_CONDITION_TO_FIX_SAM ) )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
else
|
|
{
|
|
// it's not broken at all, or it's beyond repair
|
|
return( FALSE );
|
|
}
|
|
}
|
|
}
|
|
|
|
// none found
|
|
return( FALSE );
|
|
}
|
|
|
|
BOOLEAN SoldierInSameSectorAsSAM( SOLDIERTYPE *pSoldier )
|
|
{
|
|
INT32 iCounter = 0;
|
|
|
|
// is the soldier on the surface?
|
|
if( pSoldier -> bSectorZ != 0 )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// now check each sam site in the list
|
|
for( iCounter = 0; iCounter < NUMBER_OF_SAMS; iCounter++ )
|
|
{
|
|
if( pSamList[ iCounter] == SECTOR( pSoldier -> sSectorX, pSoldier -> sSectorY ) )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
BOOLEAN IsSoldierCloseEnoughToSAMControlPanel( SOLDIERTYPE *pSoldier )
|
|
{
|
|
|
|
INT32 iCounter = 0;
|
|
|
|
// now check each sam site in the list
|
|
for( iCounter = 0; iCounter < NUMBER_OF_SAMS; iCounter++ )
|
|
{
|
|
if( pSamList[ iCounter ] == SECTOR( pSoldier -> sSectorX, pSoldier -> sSectorY ) )
|
|
{
|
|
// Assignment distance limits removed. Sep/11/98. ARM
|
|
// if( ( PythSpacesAway( pSamGridNoAList[ iCounter ], pSoldier -> sGridNo ) < MAX_DISTANCE_FOR_REPAIR )||( PythSpacesAway( pSamGridNoBList[ iCounter ], pSoldier -> sGridNo ) < MAX_DISTANCE_FOR_REPAIR ) )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
*/
|
|
|
|
|
|
|
|
BOOLEAN HandleAssignmentExpansionAndHighLightForAssignMenu( SOLDIERTYPE *pSoldier )
|
|
{
|
|
if( fShowSquadMenu )
|
|
{
|
|
// squad menu up?..if so, highlight squad line the previous menu
|
|
if( pSoldier -> ubWhatKindOfMercAmI == MERC_TYPE__EPC )
|
|
{
|
|
HighLightBoxLine( ghEpcBox, EPC_MENU_ON_DUTY );
|
|
}
|
|
else
|
|
{
|
|
HighLightBoxLine( ghAssignmentBox, ASSIGN_MENU_ON_DUTY );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
else if( fShowTrainingMenu )
|
|
{
|
|
// highlight train line the previous menu
|
|
HighLightBoxLine( ghAssignmentBox, ASSIGN_MENU_TRAIN );
|
|
return( TRUE );
|
|
}
|
|
else if( fShowRepairMenu )
|
|
{
|
|
// highlight repair line the previous menu
|
|
HighLightBoxLine( ghAssignmentBox, ASSIGN_MENU_REPAIR );
|
|
return( TRUE );
|
|
}
|
|
else if( fShowVehicleMenu )
|
|
{
|
|
// highlight vehicle line the previous menu
|
|
HighLightBoxLine( ghAssignmentBox, ASSIGN_MENU_VEHICLE );
|
|
return( TRUE );
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
BOOLEAN HandleAssignmentExpansionAndHighLightForTrainingMenu( void )
|
|
{
|
|
if( fShowAttributeMenu )
|
|
{
|
|
switch ( gbTrainingMode )
|
|
{
|
|
case TRAIN_SELF:
|
|
HighLightBoxLine( ghTrainingBox, TRAIN_MENU_SELF );
|
|
return( TRUE );
|
|
case TRAIN_TEAMMATE:
|
|
HighLightBoxLine( ghTrainingBox, TRAIN_MENU_TEAMMATES );
|
|
return( TRUE );
|
|
case TRAIN_BY_OTHER:
|
|
HighLightBoxLine( ghTrainingBox, TRAIN_MENU_TRAIN_BY_OTHER );
|
|
return( TRUE );
|
|
|
|
default:
|
|
Assert( FALSE );
|
|
break;
|
|
}
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
BOOLEAN HandleShowingOfUpBox( void )
|
|
{
|
|
|
|
// if the list is being shown, then show it
|
|
if( fShowUpdateBox == TRUE )
|
|
{
|
|
MarkAllBoxesAsAltered( );
|
|
ShowBox( ghUpdateBox );
|
|
return( TRUE );
|
|
}
|
|
else
|
|
{
|
|
if( IsBoxShown( ghUpdateBox ) )
|
|
{
|
|
HideBox( ghUpdateBox );
|
|
fMapPanelDirty = TRUE;
|
|
gfRenderPBInterface = TRUE;
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
fCharacterInfoPanelDirty = TRUE;
|
|
}
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
*/
|
|
|
|
|
|
|
|
BOOLEAN HandleShowingOfMovementBox( void )
|
|
{
|
|
|
|
// if the list is being shown, then show it
|
|
if( fShowMapScreenMovementList == TRUE )
|
|
{
|
|
MarkAllBoxesAsAltered( );
|
|
ShowBox( ghMoveBox );
|
|
return( TRUE );
|
|
}
|
|
else
|
|
{
|
|
if( IsBoxShown( ghMoveBox ) )
|
|
{
|
|
HideBox( ghMoveBox );
|
|
fMapPanelDirty = TRUE;
|
|
gfRenderPBInterface = TRUE;
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
fCharacterInfoPanelDirty = TRUE;
|
|
}
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
void HandleShadingOfLinesForTrainingMenu( void )
|
|
{
|
|
SOLDIERTYPE *pSoldier = NULL;
|
|
INT32 iCounter = 0;
|
|
|
|
|
|
// check if valid
|
|
if( ( fShowTrainingMenu == FALSE ) || ( ghTrainingBox == - 1 ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
pSoldier = GetSelectedAssignSoldier( FALSE );
|
|
|
|
// can character practise?
|
|
if( CanCharacterPractise( pSoldier ) == FALSE )
|
|
{
|
|
ShadeStringInBox( ghTrainingBox, TRAIN_MENU_SELF );
|
|
}
|
|
else
|
|
{
|
|
UnShadeStringInBox( ghTrainingBox, TRAIN_MENU_SELF );
|
|
}
|
|
|
|
|
|
// can character EVER train militia?
|
|
if( BasicCanCharacterTrainMilitia( pSoldier ) )
|
|
{
|
|
// can he train here, now?
|
|
if( CanCharacterTrainMilitia( pSoldier ) )
|
|
{
|
|
// unshade train militia line
|
|
UnShadeStringInBox( ghTrainingBox, TRAIN_MENU_TOWN );
|
|
UnSecondaryShadeStringInBox( ghTrainingBox, TRAIN_MENU_TOWN );
|
|
}
|
|
else
|
|
{
|
|
SecondaryShadeStringInBox( ghTrainingBox, TRAIN_MENU_TOWN );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// shade train militia line
|
|
ShadeStringInBox( ghTrainingBox, TRAIN_MENU_TOWN );
|
|
}
|
|
|
|
|
|
// can character train teammates?
|
|
if( CanCharacterTrainTeammates( pSoldier ) == FALSE )
|
|
{
|
|
ShadeStringInBox( ghTrainingBox, TRAIN_MENU_TEAMMATES );
|
|
}
|
|
else
|
|
{
|
|
UnShadeStringInBox( ghTrainingBox, TRAIN_MENU_TEAMMATES );
|
|
}
|
|
|
|
|
|
// can character be trained by others?
|
|
if( CanCharacterBeTrainedByOther( pSoldier ) == FALSE )
|
|
{
|
|
ShadeStringInBox( ghTrainingBox, TRAIN_MENU_TRAIN_BY_OTHER );
|
|
}
|
|
else
|
|
{
|
|
UnShadeStringInBox( ghTrainingBox, TRAIN_MENU_TRAIN_BY_OTHER );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void HandleShadingOfLinesForAttributeMenus( void )
|
|
{
|
|
// will do the same as updateassignments...but with training pop up box strings
|
|
SOLDIERTYPE *pSoldier;
|
|
INT8 bAttrib =0;
|
|
BOOLEAN fStatTrainable;
|
|
|
|
|
|
if( ( fShowTrainingMenu == FALSE ) || ( ghTrainingBox == - 1 ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( ( fShowAttributeMenu == FALSE ) || ( ghAttributeBox == - 1 ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
pSoldier = GetSelectedAssignSoldier( FALSE );
|
|
|
|
for( bAttrib = 0; bAttrib < ATTRIB_MENU_CANCEL; bAttrib++ )
|
|
{
|
|
switch ( gbTrainingMode )
|
|
{
|
|
case TRAIN_SELF:
|
|
fStatTrainable = CanCharacterTrainStat( pSoldier, bAttrib, TRUE, FALSE );
|
|
break;
|
|
case TRAIN_TEAMMATE:
|
|
// DO allow trainers to be assigned without any partners (students)
|
|
fStatTrainable = CanCharacterTrainStat( pSoldier, bAttrib, FALSE, TRUE );
|
|
break;
|
|
case TRAIN_BY_OTHER:
|
|
// DO allow students to be assigned without any partners (trainers)
|
|
fStatTrainable = CanCharacterTrainStat( pSoldier, bAttrib, TRUE, FALSE );
|
|
break;
|
|
default:
|
|
Assert( FALSE );
|
|
fStatTrainable = FALSE;
|
|
break;
|
|
}
|
|
|
|
if ( fStatTrainable )
|
|
{
|
|
// also unshade stat
|
|
UnShadeStringInBox( ghAttributeBox, bAttrib );
|
|
}
|
|
else
|
|
{
|
|
// shade stat
|
|
ShadeStringInBox( ghAttributeBox, bAttrib );
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void ResetAssignmentsForAllSoldiersInSectorWhoAreTrainingTown( SOLDIERTYPE *pSoldier )
|
|
{
|
|
INT16 sSectorX = 0, sSectorY = 0;
|
|
INT32 iNumberOnTeam = 0, iCounter = 0;
|
|
SOLDIERTYPE *pCurSoldier = NULL;
|
|
|
|
iNumberOnTeam = gTacticalStatus.Team[ OUR_TEAM ].bLastID;
|
|
|
|
for( iCounter = 0; iCounter < iNumberOnTeam; iCounter++ )
|
|
{
|
|
pCurSoldier = &Menptr[ iCounter ];
|
|
|
|
if( ( pCurSoldier -> bActive ) && ( pCurSoldier -> bLife >= OKLIFE ) )
|
|
{
|
|
if( pCurSoldier -> bAssignment == TRAIN_TOWN )
|
|
{
|
|
if( ( pCurSoldier -> sSectorX == pSoldier -> sSectorX ) && ( pCurSoldier -> sSectorY == pSoldier -> sSectorY ) && ( pSoldier -> bSectorZ == 0 ) )
|
|
{
|
|
AddCharacterToAnySquad( pCurSoldier );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void ReportTrainersTraineesWithoutPartners( void )
|
|
{
|
|
SOLDIERTYPE *pTeamSoldier = NULL;
|
|
INT32 iCounter = 0, iNumberOnTeam = 0;
|
|
BOOLEAN fFound =FALSE;
|
|
|
|
|
|
iNumberOnTeam = gTacticalStatus.Team[ OUR_TEAM ].bLastID;
|
|
|
|
// check for each instructor
|
|
for( iCounter = 0; iCounter < iNumberOnTeam; iCounter++ )
|
|
{
|
|
pTeamSoldier = &Menptr[ iCounter ];
|
|
|
|
if( ( pTeamSoldier -> bAssignment == TRAIN_TEAMMATE ) && ( pTeamSoldier -> bLife > 0 ) )
|
|
{
|
|
if ( !ValidTrainingPartnerInSameSectorOnAssignmentFound( pTeamSoldier, TRAIN_BY_OTHER, pTeamSoldier->bTrainStat ) )
|
|
{
|
|
AssignmentDone( pTeamSoldier, TRUE, TRUE );
|
|
}
|
|
}
|
|
}
|
|
|
|
// check each trainee
|
|
for( iCounter = 0; iCounter < iNumberOnTeam; iCounter++ )
|
|
{
|
|
pTeamSoldier = &Menptr[ iCounter ];
|
|
|
|
if( ( pTeamSoldier -> bAssignment == TRAIN_BY_OTHER ) && ( pTeamSoldier -> bLife > 0 ) )
|
|
{
|
|
if ( !ValidTrainingPartnerInSameSectorOnAssignmentFound( pTeamSoldier, TRAIN_TEAMMATE, pTeamSoldier->bTrainStat ) )
|
|
{
|
|
AssignmentDone( pTeamSoldier, TRUE, TRUE );
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
BOOLEAN SetMercAsleep( SOLDIERTYPE *pSoldier, BOOLEAN fGiveWarning )
|
|
{
|
|
if( CanCharacterSleep( pSoldier, fGiveWarning ) )
|
|
{
|
|
// put him to sleep
|
|
PutMercInAsleepState( pSoldier );
|
|
|
|
// successful
|
|
return( TRUE );
|
|
}
|
|
else
|
|
{
|
|
// can't sleep for some other reason
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN PutMercInAsleepState( SOLDIERTYPE *pSoldier )
|
|
{
|
|
if( pSoldier -> fMercAsleep == FALSE )
|
|
{
|
|
if( ( gfWorldLoaded ) && ( pSoldier->bInSector ) )
|
|
{
|
|
if( guiCurrentScreen == GAME_SCREEN )
|
|
{
|
|
ChangeSoldierState( pSoldier, GOTO_SLEEP, 1, TRUE );
|
|
}
|
|
else
|
|
{
|
|
ChangeSoldierState( pSoldier, SLEEPING, 1, TRUE );
|
|
}
|
|
}
|
|
|
|
// set merc asleep
|
|
pSoldier -> fMercAsleep = TRUE;
|
|
|
|
// refresh panels
|
|
fCharacterInfoPanelDirty = TRUE;
|
|
fTeamPanelDirty = TRUE;
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOLEAN SetMercAwake( SOLDIERTYPE *pSoldier, BOOLEAN fGiveWarning, BOOLEAN fForceHim )
|
|
{
|
|
// forcing him skips all normal checks!
|
|
if ( !fForceHim )
|
|
{
|
|
if ( !CanCharacterBeAwakened( pSoldier, fGiveWarning ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
PutMercInAwakeState( pSoldier );
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOLEAN PutMercInAwakeState( SOLDIERTYPE *pSoldier )
|
|
{
|
|
if ( pSoldier->fMercAsleep )
|
|
{
|
|
if ( ( gfWorldLoaded ) && ( pSoldier->bInSector ) )
|
|
{
|
|
if ( guiCurrentScreen == GAME_SCREEN )
|
|
{
|
|
ChangeSoldierState( pSoldier, WKAEUP_FROM_SLEEP, 1, TRUE );
|
|
}
|
|
else
|
|
{
|
|
ChangeSoldierState( pSoldier, STANDING, 1, TRUE );
|
|
}
|
|
}
|
|
|
|
// set merc awake
|
|
pSoldier->fMercAsleep = FALSE;
|
|
|
|
// refresh panels
|
|
fCharacterInfoPanelDirty = TRUE;
|
|
fTeamPanelDirty = TRUE;
|
|
|
|
// determine if merc is being forced to stay awake
|
|
if ( pSoldier->bBreathMax < BREATHMAX_PRETTY_TIRED )
|
|
{
|
|
pSoldier->fForcedToStayAwake = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pSoldier->fForcedToStayAwake = FALSE;
|
|
}
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOLEAN IsThereASoldierInThisSector( INT16 sSectorX, INT16 sSectorY, INT8 bSectorZ )
|
|
{
|
|
if( fSectorsWithSoldiers[ sSectorX + sSectorY * MAP_WORLD_X ][ bSectorZ ] == TRUE )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
// set the time this soldier's assignment changed
|
|
void SetTimeOfAssignmentChangeForMerc( SOLDIERTYPE *pSoldier )
|
|
{
|
|
// if someone is being taken off of HOSPITAL then track how much
|
|
// of payment wasn't used up
|
|
if ( pSoldier->bAssignment == ASSIGNMENT_HOSPITAL )
|
|
{
|
|
giHospitalRefund += CalcPatientMedicalCost( pSoldier );
|
|
pSoldier->bHospitalPriceModifier = 0;
|
|
}
|
|
|
|
// set time of last assignment change
|
|
pSoldier->uiLastAssignmentChangeMin = GetWorldTotalMin( );
|
|
|
|
// assigning new PATIENTs gives a DOCTOR something to do, etc., so set flag to recheck them all.
|
|
// CAN'T DO IT RIGHT AWAY IN HERE 'CAUSE WE TYPICALLY GET CALLED *BEFORE* bAssignment GETS SET TO NEW VALUE!!
|
|
gfReEvaluateEveryonesNothingToDo = TRUE;
|
|
|
|
return;
|
|
}
|
|
|
|
// have we spent enough time on assignment for it to count?
|
|
BOOLEAN EnoughTimeOnAssignment( SOLDIERTYPE *pSoldier )
|
|
{
|
|
if( GetWorldTotalMin() - pSoldier->uiLastAssignmentChangeMin >= (UINT32)gGameExternalOptions.ubMinutesForAssignmentToCount )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
BOOLEAN AnyMercInGroupCantContinueMoving( GROUP *pGroup )
|
|
{
|
|
PLAYERGROUP *pPlayer;
|
|
SOLDIERTYPE *pSoldier;
|
|
BOOLEAN fMeToo = FALSE;
|
|
BOOLEAN fGroupMustStop = FALSE;
|
|
|
|
|
|
Assert( pGroup );
|
|
Assert( pGroup->fPlayer );
|
|
|
|
pPlayer = pGroup->pPlayerList;
|
|
|
|
while( pPlayer )
|
|
{
|
|
// if group has player list... and a valid first soldier
|
|
if( pPlayer && pPlayer->pSoldier )
|
|
{
|
|
pSoldier = pPlayer->pSoldier;
|
|
|
|
if ( PlayerSoldierTooTiredToTravel( pSoldier ) )
|
|
{
|
|
// NOTE: we only complain about it if it's gonna force the group to stop moving!
|
|
fGroupMustStop = TRUE;
|
|
|
|
// say quote
|
|
if( fMeToo == FALSE )
|
|
{
|
|
HandleImportantMercQuote( pSoldier, QUOTE_NEED_SLEEP );
|
|
fMeToo = TRUE;
|
|
}
|
|
else
|
|
{
|
|
HandleImportantMercQuote( pSoldier, QUOTE_ME_TOO );
|
|
}
|
|
|
|
// put him to bed
|
|
PutMercInAsleepState( pSoldier );
|
|
|
|
// player can't wake him up right away
|
|
pSoldier->fMercCollapsedFlag = TRUE;
|
|
}
|
|
}
|
|
|
|
pPlayer = pPlayer->next;
|
|
}
|
|
|
|
return( fGroupMustStop );
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN PlayerSoldierTooTiredToTravel( SOLDIERTYPE *pSoldier )
|
|
{
|
|
Assert( pSoldier );
|
|
|
|
// if this guy ever needs sleep at all
|
|
if ( CanChangeSleepStatusForSoldier( pSoldier ) )
|
|
{
|
|
// if walking, or only remaining possible driver for a vehicle group
|
|
if ( ( pSoldier->bAssignment != VEHICLE ) || SoldierMustDriveVehicle( pSoldier, pSoldier->iVehicleId, TRUE ) )
|
|
{
|
|
// if awake, but so tired they can't move/drive anymore
|
|
if ( ( !pSoldier->fMercAsleep ) && ( pSoldier->bBreathMax < BREATHMAX_GOTTA_STOP_MOVING ) )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
|
|
// asleep, and can't be awakened?
|
|
if ( ( pSoldier->fMercAsleep ) && !CanCharacterBeAwakened( pSoldier, FALSE ) )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN AssignMercToAMovementGroup( SOLDIERTYPE *pSoldier )
|
|
{
|
|
// if merc doesn't have a group or is in a vehicle or on a squad assign to group
|
|
INT8 bGroupId = 0;
|
|
|
|
// on a squad?
|
|
if( pSoldier->bAssignment < ON_DUTY )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// in a vehicle?
|
|
if( pSoldier->bAssignment == VEHICLE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// in transit
|
|
if( pSoldier->bAssignment == IN_TRANSIT )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// in a movement group?
|
|
if( pSoldier->ubGroupID != 0 )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// create group
|
|
bGroupId = CreateNewPlayerGroupDepartingFromSector( ( UINT8 )( pSoldier->sSectorX ), ( UINT8 )( pSoldier->sSectorY ) );
|
|
|
|
if( bGroupId )
|
|
{
|
|
// add merc
|
|
AddPlayerToGroup( bGroupId, pSoldier );
|
|
|
|
// success
|
|
return( TRUE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
void NotifyPlayerOfAssignmentAttemptFailure( INT8 bAssignment )
|
|
{
|
|
// notify player
|
|
if ( guiCurrentScreen != MSG_BOX_SCREEN )
|
|
{
|
|
DoScreenIndependantMessageBox( pMapErrorString[ 18 ], MSG_BOX_FLAG_OK, NULL);
|
|
}
|
|
else
|
|
{
|
|
// use screen msg instead!
|
|
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, pMapErrorString[ 18 ] );
|
|
}
|
|
|
|
if ( bAssignment == TRAIN_TOWN )
|
|
{
|
|
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, pMapErrorString[ 48 ] );
|
|
}
|
|
}
|
|
|
|
|
|
BOOLEAN HandleSelectedMercsBeingPutAsleep( BOOLEAN fWakeUp, BOOLEAN fDisplayWarning )
|
|
{
|
|
BOOLEAN fSuccess = TRUE;
|
|
INT32 iCounter = 0;
|
|
SOLDIERTYPE *pSoldier = NULL;
|
|
UINT8 ubNumberOfSelectedSoldiers = 0;
|
|
CHAR16 sString[ 128 ];
|
|
|
|
|
|
for( iCounter = 0; iCounter < MAX_CHARACTER_COUNT; iCounter++ )
|
|
{
|
|
pSoldier = NULL;
|
|
|
|
// if the current character in the list is valid...then grab soldier pointer for the character
|
|
if( gCharactersList[ iCounter ].fValid )
|
|
{
|
|
// get the soldier pointer
|
|
pSoldier = &Menptr[ gCharactersList[ iCounter ].usSolID ];
|
|
|
|
if( pSoldier->bActive == FALSE )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if( iCounter == bSelectedInfoChar )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if( IsEntryInSelectedListSet( ( INT8 )iCounter ) == FALSE )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// don't try to put vehicles, robots, to sleep if they're also selected
|
|
if ( CanChangeSleepStatusForCharSlot( (INT8) iCounter ) == FALSE )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// up the total number of soldiers
|
|
ubNumberOfSelectedSoldiers++;
|
|
|
|
if( fWakeUp )
|
|
{
|
|
// try to wake merc up
|
|
if( SetMercAwake( pSoldier, FALSE, FALSE ) == FALSE )
|
|
{
|
|
fSuccess = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// set this soldier asleep
|
|
if( SetMercAsleep( pSoldier, FALSE ) == FALSE )
|
|
{
|
|
fSuccess = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// if there was anyone processed, check for success and inform player of failure
|
|
if( ubNumberOfSelectedSoldiers )
|
|
{
|
|
if( fSuccess == FALSE )
|
|
{
|
|
if( fWakeUp )
|
|
{
|
|
// inform player not everyone could be woke up
|
|
swprintf( sString, pMapErrorString[ 27 ] );
|
|
}
|
|
else
|
|
{
|
|
// inform player not everyone could be put to sleep
|
|
swprintf( sString, pMapErrorString[ 26 ]);
|
|
}
|
|
|
|
if( fDisplayWarning )
|
|
{
|
|
DoScreenIndependantMessageBox( sString, MSG_BOX_FLAG_OK, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
return( fSuccess );
|
|
}
|
|
|
|
BOOLEAN IsAnyOneOnPlayersTeamOnThisAssignment( INT8 bAssignment )
|
|
{
|
|
INT32 iCounter = 0;
|
|
SOLDIERTYPE *pSoldier = NULL;
|
|
|
|
|
|
for( iCounter = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; iCounter <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; iCounter++ )
|
|
{
|
|
// get the current soldier
|
|
pSoldier = &Menptr[ iCounter ];
|
|
|
|
// active?
|
|
if( pSoldier->bActive == FALSE )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if( pSoldier->bAssignment == bAssignment )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
void RebuildAssignmentsBox( void )
|
|
{
|
|
// destroy and recreate assignments box
|
|
if ( ghAssignmentBox != -1 )
|
|
{
|
|
RemoveBox( ghAssignmentBox );
|
|
ghAssignmentBox = -1;
|
|
}
|
|
|
|
// WANNE 2 <ab>
|
|
CreateAssignmentsBox( );
|
|
}
|
|
|
|
|
|
|
|
void BandageBleedingDyingPatientsBeingTreated( )
|
|
{
|
|
INT32 iCounter = 0;
|
|
SOLDIERTYPE *pSoldier = NULL;
|
|
SOLDIERTYPE *pDoctor = NULL;
|
|
INT32 iKitSlot;
|
|
OBJECTTYPE *pKit = NULL;
|
|
UINT16 usKitPts;
|
|
UINT32 uiKitPtsUsed;
|
|
BOOLEAN fSomeoneStillBleedingDying = FALSE;
|
|
|
|
|
|
for( iCounter = gTacticalStatus.Team[ OUR_TEAM ].bFirstID; iCounter <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; iCounter++ )
|
|
{
|
|
// get the soldier
|
|
pSoldier = &Menptr[ iCounter ];
|
|
|
|
// check if the soldier is currently active?
|
|
if( pSoldier->bActive == FALSE )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// and he is bleeding or dying
|
|
if( ( pSoldier->bBleeding ) || ( pSoldier->bLife < OKLIFE ) )
|
|
{
|
|
// if soldier is receiving care
|
|
if( ( pSoldier->bAssignment == PATIENT ) || ( pSoldier->bAssignment == ASSIGNMENT_HOSPITAL ) || ( pSoldier->bAssignment == DOCTOR ) )
|
|
{
|
|
// if in the hospital
|
|
if ( pSoldier->bAssignment == ASSIGNMENT_HOSPITAL )
|
|
{
|
|
// this is instantaneous, and doesn't use up any bandages!
|
|
|
|
// stop bleeding automatically
|
|
pSoldier->bBleeding = 0;
|
|
|
|
if ( pSoldier->bLife < OKLIFE )
|
|
{
|
|
pSoldier->bLife = OKLIFE;
|
|
}
|
|
}
|
|
else // assigned to DOCTOR/PATIENT
|
|
{
|
|
// see if there's a doctor around who can help him
|
|
pDoctor = AnyDoctorWhoCanHealThisPatient( pSoldier, HEALABLE_EVER );
|
|
if ( pDoctor != NULL )
|
|
{
|
|
iKitSlot = FindObjClass( pDoctor, IC_MEDKIT );
|
|
if( iKitSlot != NO_SLOT )
|
|
{
|
|
pKit = &( pDoctor->inv[ iKitSlot ] );
|
|
|
|
usKitPts = TotalPoints( pKit );
|
|
if( usKitPts )
|
|
{
|
|
uiKitPtsUsed = VirtualSoldierDressWound( pDoctor, pSoldier, pKit, usKitPts, usKitPts );
|
|
UseKitPoints( pKit, (UINT16)uiKitPtsUsed, pDoctor );
|
|
|
|
// if he is STILL bleeding or dying
|
|
if( ( pSoldier->bBleeding ) || ( pSoldier->bLife < OKLIFE ) )
|
|
{
|
|
fSomeoneStillBleedingDying = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// this event may be posted many times because of multiple assignment changes. Handle it only once per minute!
|
|
DeleteAllStrategicEventsOfType( EVENT_BANDAGE_BLEEDING_MERCS );
|
|
|
|
if ( fSomeoneStillBleedingDying )
|
|
{
|
|
AddStrategicEvent( EVENT_BANDAGE_BLEEDING_MERCS, GetWorldTotalMin() + 1, 0 );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void ReEvaluateEveryonesNothingToDo()
|
|
{
|
|
INT32 iCounter = 0;
|
|
SOLDIERTYPE *pSoldier = NULL;
|
|
BOOLEAN fNothingToDo;
|
|
|
|
|
|
for( iCounter = 0; iCounter <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; iCounter++ )
|
|
{
|
|
pSoldier = &Menptr[ iCounter ];
|
|
|
|
if( pSoldier->bActive )
|
|
{
|
|
switch( pSoldier->bAssignment )
|
|
{
|
|
case DOCTOR:
|
|
fNothingToDo = !CanCharacterDoctor( pSoldier ) || ( GetNumberThatCanBeDoctored( pSoldier, HEALABLE_EVER, FALSE, FALSE ) == 0 );
|
|
break;
|
|
|
|
case PATIENT:
|
|
fNothingToDo = !CanCharacterPatient( pSoldier ) || ( AnyDoctorWhoCanHealThisPatient( pSoldier, HEALABLE_EVER ) == NULL );
|
|
break;
|
|
|
|
case ASSIGNMENT_HOSPITAL:
|
|
fNothingToDo = !CanCharacterPatient( pSoldier );
|
|
break;
|
|
|
|
case REPAIR:
|
|
fNothingToDo = !CanCharacterRepair( pSoldier ) || HasCharacterFinishedRepairing( pSoldier );
|
|
break;
|
|
|
|
case TRAIN_TOWN:
|
|
fNothingToDo = !CanCharacterTrainMilitia( pSoldier );
|
|
break;
|
|
|
|
case TRAIN_SELF:
|
|
fNothingToDo = !CanCharacterTrainStat( pSoldier, pSoldier->bTrainStat, TRUE, FALSE );
|
|
break;
|
|
|
|
case TRAIN_TEAMMATE:
|
|
fNothingToDo = !CanCharacterTrainStat( pSoldier, pSoldier->bTrainStat, FALSE, TRUE ) ||
|
|
!ValidTrainingPartnerInSameSectorOnAssignmentFound( pSoldier, TRAIN_BY_OTHER, pSoldier->bTrainStat );
|
|
break;
|
|
|
|
case TRAIN_BY_OTHER:
|
|
fNothingToDo = !CanCharacterTrainStat( pSoldier, pSoldier->bTrainStat, TRUE, FALSE ) ||
|
|
!ValidTrainingPartnerInSameSectorOnAssignmentFound( pSoldier, TRAIN_TEAMMATE, pSoldier->bTrainStat );
|
|
break;
|
|
|
|
case VEHICLE:
|
|
default: // squads
|
|
fNothingToDo = FALSE;
|
|
break;
|
|
}
|
|
|
|
|
|
// if his flag is wrong
|
|
if ( fNothingToDo != pSoldier->fDoneAssignmentAndNothingToDoFlag )
|
|
{
|
|
// update it!
|
|
pSoldier->fDoneAssignmentAndNothingToDoFlag = fNothingToDo;
|
|
|
|
// update mapscreen's character list display
|
|
fDrawCharacterList = TRUE;
|
|
}
|
|
|
|
// if he now has something to do, reset the quote flag
|
|
if ( !fNothingToDo )
|
|
{
|
|
pSoldier->usQuoteSaidExtFlags &= ~SOLDIER_QUOTE_SAID_DONE_ASSIGNMENT;
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
// re-evaluation completed
|
|
gfReEvaluateEveryonesNothingToDo = FALSE;
|
|
|
|
|
|
// redraw the map, in case we're showing teams, and someone just came on duty or off duty, their icon needs updating
|
|
fMapPanelDirty = TRUE;
|
|
}
|
|
|
|
|
|
|
|
void SetAssignmentForList( INT8 bAssignment, INT8 bParam )
|
|
{
|
|
INT32 iCounter = 0;
|
|
SOLDIERTYPE *pSelectedSoldier = NULL;
|
|
SOLDIERTYPE *pSoldier = NULL;
|
|
BOOLEAN fItWorked;
|
|
BOOLEAN fRemoveFromSquad = TRUE;
|
|
BOOLEAN fNotifiedOfFailure = FALSE;
|
|
INT8 bCanJoinSquad;
|
|
|
|
// if not in mapscreen, there is no functionality available to change multiple assignments simultaneously!
|
|
if ( !( guiTacticalInterfaceFlags & INTERFACE_MAPSCREEN ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// pSelectedSoldier is currently used only for REPAIR, and this block of code is copied from RepairMenuBtnCallback()
|
|
if( bSelectedAssignChar != -1 )
|
|
{
|
|
if( gCharactersList[ bSelectedAssignChar ].fValid == TRUE )
|
|
{
|
|
pSelectedSoldier = &Menptr[ gCharactersList[ bSelectedAssignChar ].usSolID ];
|
|
}
|
|
}
|
|
|
|
Assert( pSelectedSoldier && pSelectedSoldier->bActive );
|
|
|
|
|
|
// sets assignment for the list
|
|
for( iCounter = 0; iCounter < MAX_CHARACTER_COUNT; iCounter++ )
|
|
{
|
|
if( ( gCharactersList[ iCounter ].fValid ) &&
|
|
( fSelectedListOfMercsForMapScreen[ iCounter ] == TRUE ) &&
|
|
( iCounter != bSelectedAssignChar ) &&
|
|
!(Menptr[ gCharactersList[ iCounter ].usSolID].uiStatusFlags & SOLDIER_VEHICLE ) )
|
|
{
|
|
pSoldier = MercPtrs[ gCharactersList[ iCounter ].usSolID ];
|
|
|
|
// assume it's NOT gonna work
|
|
fItWorked = FALSE;
|
|
|
|
switch( bAssignment )
|
|
{
|
|
case( DOCTOR ):
|
|
// can character doctor?
|
|
if( CanCharacterDoctor( pSoldier ) )
|
|
{
|
|
// set as doctor
|
|
pSoldier->bOldAssignment = pSoldier->bAssignment;
|
|
SetSoldierAssignment( pSoldier, DOCTOR, 0,0,0 );
|
|
fItWorked = TRUE;
|
|
}
|
|
break;
|
|
case( PATIENT ):
|
|
// can character patient?
|
|
if( CanCharacterPatient( pSoldier ) )
|
|
{
|
|
// set as patient
|
|
pSoldier->bOldAssignment = pSoldier->bAssignment;
|
|
SetSoldierAssignment( pSoldier, PATIENT, 0,0,0 );
|
|
fItWorked = TRUE;
|
|
}
|
|
break;
|
|
case( VEHICLE ):
|
|
if( CanCharacterVehicle( pSoldier ) && IsThisVehicleAccessibleToSoldier( pSoldier, bParam ) )
|
|
{
|
|
// if ( IsEnoughSpaceInVehicle( bParam ) )
|
|
{
|
|
// if the vehicle is FULL, then this will return FALSE!
|
|
fItWorked = PutSoldierInVehicle( pSoldier, bParam );
|
|
// failure produces its own error popup
|
|
fNotifiedOfFailure = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
case( REPAIR ):
|
|
if( CanCharacterRepair( pSoldier ) )
|
|
{
|
|
BOOLEAN fCanFixSpecificTarget = TRUE;
|
|
|
|
// make sure he can repair the SPECIFIC thing being repaired too (must be in its sector, for example)
|
|
|
|
/*
|
|
if ( pSelectedSoldier->fFixingSAMSite )
|
|
{
|
|
fCanFixSpecificTarget = CanSoldierRepairSAM( pSoldier, SAM_SITE_REPAIR_DIVISOR );
|
|
}
|
|
else
|
|
*/
|
|
if ( pSelectedSoldier->bVehicleUnderRepairID != -1 )
|
|
{
|
|
fCanFixSpecificTarget = CanCharacterRepairVehicle( pSoldier, pSelectedSoldier->bVehicleUnderRepairID );
|
|
}
|
|
else if( pSoldier->fFixingRobot )
|
|
{
|
|
fCanFixSpecificTarget = CanCharacterRepairRobot( pSoldier );
|
|
}
|
|
|
|
if ( fCanFixSpecificTarget )
|
|
{
|
|
// set as repair
|
|
pSoldier->bOldAssignment = pSoldier->bAssignment;
|
|
SetSoldierAssignment( pSoldier, REPAIR, pSelectedSoldier->fFixingSAMSite, pSelectedSoldier->fFixingRobot, pSelectedSoldier->bVehicleUnderRepairID );
|
|
fItWorked = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
case( TRAIN_SELF ):
|
|
if( CanCharacterTrainStat( pSoldier, bParam , TRUE, FALSE ) )
|
|
{
|
|
pSoldier->bOldAssignment = pSoldier->bAssignment;
|
|
SetSoldierAssignment( pSoldier, TRAIN_SELF, bParam, 0,0 );
|
|
fItWorked = TRUE;
|
|
}
|
|
break;
|
|
case( TRAIN_TOWN ):
|
|
if( CanCharacterTrainMilitia( pSoldier ) )
|
|
{
|
|
pSoldier->bOldAssignment = pSoldier->bAssignment;
|
|
SetSoldierAssignment( pSoldier, TRAIN_TOWN, 0, 0, 0 );
|
|
fItWorked = TRUE;
|
|
}
|
|
break;
|
|
case( TRAIN_TEAMMATE ):
|
|
if( CanCharacterTrainStat( pSoldier, bParam, FALSE, TRUE ) )
|
|
{
|
|
pSoldier->bOldAssignment = pSoldier->bAssignment;
|
|
SetSoldierAssignment( pSoldier, TRAIN_TEAMMATE, bParam, 0,0 );
|
|
fItWorked = TRUE;
|
|
}
|
|
break;
|
|
case TRAIN_BY_OTHER:
|
|
if( CanCharacterTrainStat( pSoldier, bParam, TRUE, FALSE ) )
|
|
{
|
|
pSoldier->bOldAssignment = pSoldier->bAssignment;
|
|
SetSoldierAssignment( pSoldier, TRAIN_BY_OTHER, bParam, 0,0 );
|
|
fItWorked = TRUE;
|
|
}
|
|
break;
|
|
|
|
case( SQUAD_1 ):
|
|
case( SQUAD_2 ):
|
|
case( SQUAD_3 ):
|
|
case( SQUAD_4 ):
|
|
case( SQUAD_5 ):
|
|
case( SQUAD_6 ):
|
|
case( SQUAD_7 ):
|
|
case( SQUAD_8 ):
|
|
case( SQUAD_9 ):
|
|
case( SQUAD_10 ):
|
|
case( SQUAD_11 ):
|
|
case( SQUAD_12 ):
|
|
case( SQUAD_13 ):
|
|
case( SQUAD_14 ):
|
|
case( SQUAD_15 ):
|
|
case( SQUAD_16 ):
|
|
case( SQUAD_17 ):
|
|
case( SQUAD_18 ):
|
|
case( SQUAD_19 ):
|
|
case( SQUAD_20 ):
|
|
bCanJoinSquad = CanCharacterSquad( pSoldier, ( INT8 )bAssignment );
|
|
|
|
// if already in it, don't repor that as an error...
|
|
if ( ( bCanJoinSquad == CHARACTER_CAN_JOIN_SQUAD ) ||
|
|
( bCanJoinSquad == CHARACTER_CANT_JOIN_SQUAD_ALREADY_IN_IT ) )
|
|
{
|
|
if ( bCanJoinSquad == CHARACTER_CAN_JOIN_SQUAD )
|
|
{
|
|
pSoldier->bOldAssignment = pSoldier->bAssignment;
|
|
|
|
// is the squad between sectors
|
|
if( Squad[ bAssignment ][ 0 ] )
|
|
{
|
|
if( Squad[ bAssignment ][ 0 ]->fBetweenSectors )
|
|
{
|
|
// between sectors, remove from old mvt group
|
|
if ( pSoldier->bOldAssignment >= ON_DUTY )
|
|
{
|
|
// remove from group
|
|
// the guy wasn't in a sqaud, but moving through a sector?
|
|
if ( pSoldier->ubGroupID != 0 )
|
|
{
|
|
// now remove from mvt group
|
|
RemovePlayerFromGroup( pSoldier->ubGroupID, pSoldier );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if( pSoldier->bOldAssignment == VEHICLE )
|
|
{
|
|
TakeSoldierOutOfVehicle( pSoldier );
|
|
}
|
|
// remove from current squad, if any
|
|
RemoveCharacterFromSquads( pSoldier );
|
|
|
|
// able to add, do it
|
|
AddCharacterToSquad( pSoldier, bAssignment );
|
|
}
|
|
|
|
fItWorked = TRUE;
|
|
fRemoveFromSquad = FALSE; // already done, would screw it up!
|
|
}
|
|
break;
|
|
|
|
default:
|
|
// remove from current vehicle/squad, if any
|
|
if( pSoldier->bAssignment == VEHICLE )
|
|
{
|
|
TakeSoldierOutOfVehicle( pSoldier );
|
|
}
|
|
RemoveCharacterFromSquads( pSoldier );
|
|
|
|
AddCharacterToAnySquad( pSoldier );
|
|
|
|
fItWorked = TRUE;
|
|
fRemoveFromSquad = FALSE; // already done, would screw it up!
|
|
break;
|
|
}
|
|
|
|
if ( fItWorked )
|
|
{
|
|
if ( fRemoveFromSquad )
|
|
{
|
|
// remove him from his old squad if he was on one
|
|
RemoveCharacterFromSquads( pSoldier );
|
|
}
|
|
|
|
MakeSoldiersTacticalAnimationReflectAssignment( pSoldier );
|
|
}
|
|
else
|
|
{
|
|
// didn't work - report it once
|
|
if( !fNotifiedOfFailure )
|
|
{
|
|
fNotifiedOfFailure = TRUE;
|
|
NotifyPlayerOfAssignmentAttemptFailure( bAssignment );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// reset list
|
|
// ResetSelectedListForMapScreen( );
|
|
|
|
|
|
// check if we should start/stop flashing any mercs' assignment strings after these changes
|
|
gfReEvaluateEveryonesNothingToDo = TRUE;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
BOOLEAN IsCharacterAliveAndConscious( SOLDIERTYPE *pCharacter )
|
|
{
|
|
// is the character alive and conscious?
|
|
if( pCharacter -> bLife < CONSCIOUSNESS )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
return ( TRUE );
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN ValidTrainingPartnerInSameSectorOnAssignmentFound( SOLDIERTYPE *pTargetSoldier, INT8 bTargetAssignment, INT8 bTargetStat )
|
|
{
|
|
INT32 iCounter = 0;
|
|
SOLDIERTYPE *pSoldier = NULL;
|
|
BOOLEAN fFound = FALSE;
|
|
INT16 sTrainingPts = 0;
|
|
BOOLEAN fAtGunRange = FALSE;
|
|
UINT16 usMaxPts;
|
|
|
|
|
|
// this function only makes sense for training teammates or by others, not for self training which doesn't require partners
|
|
Assert( ( bTargetAssignment == TRAIN_TEAMMATE ) || ( bTargetAssignment == TRAIN_BY_OTHER ) );
|
|
|
|
for( iCounter = 0; iCounter <= gTacticalStatus.Team[ OUR_TEAM ].bLastID; iCounter++ )
|
|
{
|
|
pSoldier = &Menptr[ iCounter ];
|
|
|
|
if ( pSoldier->bActive )
|
|
{
|
|
// if the guy is not the target, has the assignment we want, is training the same stat, and is in our sector, alive
|
|
// and is training the stat we want
|
|
if( ( pSoldier != pTargetSoldier ) &&
|
|
( pSoldier -> bAssignment == bTargetAssignment ) &&
|
|
// CJC: this seems incorrect in light of the check for bTargetStat and in any case would
|
|
// cause a problem if the trainer was assigned and we weren't!
|
|
//( pSoldier -> bTrainStat == pTargetSoldier -> bTrainStat ) &&
|
|
( pSoldier -> sSectorX == pTargetSoldier -> sSectorX ) &&
|
|
( pSoldier -> sSectorY == pTargetSoldier -> sSectorY ) &&
|
|
( pSoldier -> bSectorZ == pTargetSoldier -> bSectorZ ) &&
|
|
( pSoldier -> bTrainStat == bTargetStat ) &&
|
|
( pSoldier -> bLife > 0 ) )
|
|
{
|
|
// so far so good, now let's see if the trainer can really teach the student anything new
|
|
|
|
// are we training in the sector with gun range in Alma?
|
|
if ( ( pSoldier -> sSectorX == GUN_RANGE_X ) && (pSoldier -> sSectorY == GUN_RANGE_Y ) && ( pSoldier -> bSectorZ == GUN_RANGE_Z ) )
|
|
{
|
|
fAtGunRange = TRUE;
|
|
}
|
|
|
|
if ( pSoldier -> bAssignment == TRAIN_TEAMMATE )
|
|
{
|
|
// pSoldier is the instructor, target is the student
|
|
sTrainingPts = GetBonusTrainingPtsDueToInstructor( pSoldier, pTargetSoldier, bTargetStat, fAtGunRange, &usMaxPts );
|
|
}
|
|
else
|
|
{
|
|
// target is the instructor, pSoldier is the student
|
|
sTrainingPts = GetBonusTrainingPtsDueToInstructor( pTargetSoldier, pSoldier, bTargetStat, fAtGunRange, &usMaxPts );
|
|
}
|
|
|
|
if ( sTrainingPts > 0 )
|
|
{
|
|
// yes, then he makes a valid training partner for us!
|
|
return( TRUE );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// no one found
|
|
return( FALSE );
|
|
}
|
|
|
|
void UnEscortEPC( SOLDIERTYPE *pSoldier )
|
|
{
|
|
if ( guiTacticalInterfaceFlags & INTERFACE_MAPSCREEN )
|
|
{
|
|
BOOLEAN fGotInfo;
|
|
UINT16 usQuoteNum;
|
|
UINT16 usFactToSetToTrue;
|
|
|
|
SetupProfileInsertionDataForSoldier( pSoldier );
|
|
|
|
fGotInfo = GetInfoForAbandoningEPC( pSoldier->ubProfile, &usQuoteNum, &usFactToSetToTrue );
|
|
if ( fGotInfo )
|
|
{
|
|
// say quote usQuoteNum
|
|
gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags |= PROFILE_MISC_FLAG_FORCENPCQUOTE;
|
|
TacticalCharacterDialogue( pSoldier, usQuoteNum );
|
|
// the flag will be turned off in the remove-epc event
|
|
//gMercProfiles[ pSoldier->ubProfile ].ubMiscFlags &= ~PROFILE_MISC_FLAG_FORCENPCQUOTE;
|
|
SetFactTrue( usFactToSetToTrue );
|
|
}
|
|
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_REMOVE_EPC, pSoldier->ubProfile, 0, 0, 0, 0 );
|
|
|
|
HandleFactForNPCUnescorted( pSoldier->ubProfile );
|
|
|
|
if ( pSoldier->ubProfile == JOHN )
|
|
{
|
|
SOLDIERTYPE * pSoldier2;
|
|
|
|
// unrecruit Mary as well
|
|
pSoldier2 = FindSoldierByProfileID( MARY, TRUE );
|
|
if ( pSoldier2 )
|
|
{
|
|
SetupProfileInsertionDataForSoldier( pSoldier2 );
|
|
fGotInfo = GetInfoForAbandoningEPC( MARY, &usQuoteNum, &usFactToSetToTrue );
|
|
if ( fGotInfo )
|
|
{
|
|
// say quote usQuoteNum
|
|
gMercProfiles[ MARY ].ubMiscFlags |= PROFILE_MISC_FLAG_FORCENPCQUOTE;
|
|
TacticalCharacterDialogue( pSoldier2, usQuoteNum );
|
|
// the flag will be turned off in the remove-epc event
|
|
//gMercProfiles[ MARY ].ubMiscFlags &= ~PROFILE_MISC_FLAG_FORCENPCQUOTE;
|
|
SetFactTrue( usFactToSetToTrue );
|
|
}
|
|
|
|
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_REMOVE_EPC, MARY, 0, 0, 0, 0 );
|
|
}
|
|
}
|
|
else if ( pSoldier->ubProfile == MARY )
|
|
{
|
|
SOLDIERTYPE * pSoldier2;
|
|
|
|
// unrecruit John as well
|
|
pSoldier2 = FindSoldierByProfileID( JOHN, TRUE );
|
|
if ( pSoldier2 )
|
|
{
|
|
SetupProfileInsertionDataForSoldier( pSoldier2 );
|
|
fGotInfo = GetInfoForAbandoningEPC( JOHN, &usQuoteNum, &usFactToSetToTrue );
|
|
if ( fGotInfo )
|
|
{
|
|
// say quote usQuoteNum
|
|
gMercProfiles[ JOHN ].ubMiscFlags |= PROFILE_MISC_FLAG_FORCENPCQUOTE;
|
|
TacticalCharacterDialogue( pSoldier2, usQuoteNum );
|
|
// the flag will be turned off in the remove-epc event
|
|
//gMercProfiles[ JOHN ].ubMiscFlags &= ~PROFILE_MISC_FLAG_FORCENPCQUOTE;
|
|
SetFactTrue( usFactToSetToTrue );
|
|
}
|
|
SpecialCharacterDialogueEvent( DIALOGUE_SPECIAL_EVENT_REMOVE_EPC, JOHN, 0, 0, 0, 0 );
|
|
}
|
|
}
|
|
// stop showing menu
|
|
giAssignHighLine = -1;
|
|
|
|
// set dirty flag
|
|
fTeamPanelDirty = TRUE;
|
|
fMapScreenBottomDirty = TRUE;
|
|
fCharacterInfoPanelDirty = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// how do we handle this if it's the right sector?
|
|
TriggerNPCWithGivenApproach( pSoldier->ubProfile, APPROACH_EPC_IN_WRONG_SECTOR, TRUE );
|
|
}
|
|
}
|
|
|
|
|
|
BOOLEAN CharacterIsTakingItEasy( SOLDIERTYPE *pSoldier )
|
|
{
|
|
// actually asleep?
|
|
if ( pSoldier -> fMercAsleep == TRUE )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
|
|
// if able to sleep
|
|
if ( CanCharacterSleep( pSoldier, FALSE ) )
|
|
{
|
|
// on duty, but able to catch naps (either not traveling, or not the driver of the vehicle)
|
|
// The actual checks for this are in the "can he sleep" check above
|
|
if ( ( pSoldier -> bAssignment < ON_DUTY ) || ( pSoldier -> bAssignment == VEHICLE ) )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
|
|
// and healing up?
|
|
if ( ( pSoldier -> bAssignment == PATIENT ) || ( pSoldier -> bAssignment == ASSIGNMENT_HOSPITAL ) )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
|
|
// on a real assignment, but done with it?
|
|
if ( pSoldier -> fDoneAssignmentAndNothingToDoFlag )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
|
|
|
|
// on assignment, or walking/driving & unable to sleep
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
|
|
UINT8 CalcSoldierNeedForSleep( SOLDIERTYPE *pSoldier )
|
|
{
|
|
UINT8 ubNeedForSleep;
|
|
UINT8 ubPercentHealth;
|
|
|
|
|
|
// base comes from profile
|
|
ubNeedForSleep = gMercProfiles[ pSoldier -> ubProfile ].ubNeedForSleep;
|
|
|
|
|
|
ubPercentHealth = pSoldier->bLife / pSoldier->bLifeMax;
|
|
|
|
if ( ubPercentHealth < 75 )
|
|
{
|
|
ubNeedForSleep++;
|
|
|
|
if ( ubPercentHealth < 50 )
|
|
{
|
|
ubNeedForSleep++;
|
|
|
|
if ( ubPercentHealth < 25 )
|
|
{
|
|
ubNeedForSleep += 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
// reduce for each Night Ops or Martial Arts trait
|
|
ubNeedForSleep -= NUM_SKILL_TRAITS( pSoldier, NIGHTOPS );
|
|
ubNeedForSleep -= NUM_SKILL_TRAITS( pSoldier, MARTIALARTS );
|
|
|
|
if ( ubNeedForSleep < 4 )
|
|
{
|
|
ubNeedForSleep = 4;
|
|
}
|
|
|
|
if ( ubNeedForSleep > 12 )
|
|
{
|
|
ubNeedForSleep = 12;
|
|
}
|
|
|
|
return( ubNeedForSleep );
|
|
}
|
|
|
|
|
|
|
|
UINT32 GetLastSquadListedInSquadMenu( void )
|
|
{
|
|
UINT32 uiMaxSquad;
|
|
|
|
uiMaxSquad = GetLastSquadActive( ) + 1;
|
|
|
|
if ( uiMaxSquad >= NUMBER_OF_SQUADS )
|
|
{
|
|
uiMaxSquad = NUMBER_OF_SQUADS - 1;
|
|
}
|
|
|
|
return( uiMaxSquad );
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN CanCharacterRepairAnotherSoldiersStuff( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOtherSoldier )
|
|
{
|
|
if ( pOtherSoldier == pSoldier )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
if ( !pOtherSoldier->bActive )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
if ( pOtherSoldier->bLife == 0 )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
if ( pOtherSoldier->sSectorX != pSoldier->sSectorX ||
|
|
pOtherSoldier->sSectorY != pSoldier->sSectorY ||
|
|
pOtherSoldier->bSectorZ != pSoldier->bSectorZ )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if ( pOtherSoldier->fBetweenSectors )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if ( ( pOtherSoldier->bAssignment == IN_TRANSIT ) ||
|
|
( pOtherSoldier->bAssignment == ASSIGNMENT_POW ) ||
|
|
( pSoldier->uiStatusFlags & SOLDIER_VEHICLE ) ||
|
|
( AM_A_ROBOT( pSoldier ) ) ||
|
|
( pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__EPC ) ||
|
|
( pOtherSoldier->bAssignment == ASSIGNMENT_DEAD ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
|
|
SOLDIERTYPE *GetSelectedAssignSoldier( BOOLEAN fNullOK )
|
|
{
|
|
SOLDIERTYPE *pSoldier = NULL;
|
|
|
|
if ( (guiTacticalInterfaceFlags & INTERFACE_MAPSCREEN ) )
|
|
{
|
|
// mapscreen version
|
|
if( ( bSelectedAssignChar >= 0 ) && ( bSelectedAssignChar < MAX_CHARACTER_COUNT ) &&
|
|
( gCharactersList[ bSelectedAssignChar ].fValid ) )
|
|
{
|
|
pSoldier = &Menptr[ gCharactersList[ bSelectedAssignChar ].usSolID ];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// tactical version
|
|
pSoldier = &Menptr[ gusUIFullTargetID ];
|
|
}
|
|
|
|
if ( !fNullOK )
|
|
{
|
|
Assert( pSoldier );
|
|
}
|
|
|
|
if ( pSoldier != NULL )
|
|
{
|
|
// better be an active person, not a vehicle
|
|
Assert( pSoldier->bActive );
|
|
Assert( !( pSoldier->uiStatusFlags & SOLDIER_VEHICLE ) );
|
|
}
|
|
|
|
return( pSoldier );
|
|
}
|
|
|
|
|
|
|
|
void ResumeOldAssignment( SOLDIERTYPE *pSoldier )
|
|
{
|
|
BOOLEAN fOldAssignmentInvalid = FALSE;
|
|
|
|
|
|
// ARM: I don't think the whole "old assignment" idea is a very good one, and I doubt the code that maintains that
|
|
// variable is very foolproof, plus what meaning does the old assignemnt have later, anyway?
|
|
// so I'd rather just settle for putting him into any squad:
|
|
fOldAssignmentInvalid = TRUE;
|
|
|
|
/*
|
|
if ( pSoldier->bOldAssignment == pSoldier->bAssigment )
|
|
{
|
|
// no good: we rely on this to make sure guys training militia STOP training militia!
|
|
fOldAssignmentInvalid = TRUE;
|
|
}
|
|
else if( pSoldier->bOldAssignment == VEHICLE )
|
|
{
|
|
SetSoldierAssignment( pSoldier, ( INT8 )( pSoldier->bOldAssignment ), ( pSoldier->iVehicleId ), 0, 0 );
|
|
|
|
// it might not work - check
|
|
if ( pSoldier->bAssignment != VEHICLE )
|
|
{
|
|
fOldAssignmentInvalid = TRUE;
|
|
}
|
|
}
|
|
else if( pSoldier->bOldAssignment < ON_DUTY )
|
|
{
|
|
if( AddCharacterToSquad( pSoldier, pSoldier->bOldAssignment ) == FALSE )
|
|
{
|
|
fOldAssignmentInvalid = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fOldAssignmentInvalid = TRUE;
|
|
}
|
|
*/
|
|
|
|
if ( fOldAssignmentInvalid )
|
|
{
|
|
AddCharacterToAnySquad( pSoldier );
|
|
}
|
|
|
|
|
|
// make sure the player has time to OK this before proceeding
|
|
StopTimeCompression();
|
|
|
|
// assignment has changed, redraw left side as well as the map (to update on/off duty icons)
|
|
fTeamPanelDirty = TRUE;
|
|
fCharacterInfoPanelDirty = TRUE;
|
|
fMapPanelDirty = TRUE;
|
|
}
|
|
|
|
|
|
|
|
void RepairItemsOnOthers( SOLDIERTYPE *pSoldier, UINT8 *pubRepairPtsLeft )
|
|
{
|
|
UINT8 ubPassType;
|
|
INT8 bLoop;
|
|
INT8 bPocket;
|
|
SOLDIERTYPE * pOtherSoldier;
|
|
SOLDIERTYPE * pBestOtherSoldier;
|
|
INT8 bPriority, bBestPriority = -1;
|
|
BOOLEAN fSomethingWasRepairedThisPass;
|
|
|
|
|
|
// repair everyone's hands and armor slots first, then headgear, and pockets last
|
|
for ( ubPassType = REPAIR_HANDS_AND_ARMOR; ubPassType <= FINAL_REPAIR_PASS; ubPassType++ )
|
|
{
|
|
fSomethingWasRepairedThisPass = FALSE;
|
|
|
|
|
|
// look for jammed guns on other soldiers in sector and unjam them
|
|
for( bLoop = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; bLoop < gTacticalStatus.Team[ gbPlayerNum ].bLastID; bLoop++ )
|
|
{
|
|
pOtherSoldier = MercPtrs[ bLoop ];
|
|
|
|
// check character is valid, alive, same sector, not between, has inventory, etc.
|
|
if ( CanCharacterRepairAnotherSoldiersStuff( pSoldier, pOtherSoldier ) )
|
|
{
|
|
if ( UnjamGunsOnSoldier( pOtherSoldier, pSoldier, pubRepairPtsLeft ) )
|
|
{
|
|
fSomethingWasRepairedThisPass = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
while ( *pubRepairPtsLeft > 0 )
|
|
{
|
|
bBestPriority = -1;
|
|
pBestOtherSoldier = NULL;
|
|
|
|
// now look for items to repair on other mercs
|
|
for( bLoop = gTacticalStatus.Team[ gbPlayerNum ].bFirstID; bLoop < gTacticalStatus.Team[ gbPlayerNum ].bLastID; bLoop++ )
|
|
{
|
|
pOtherSoldier = MercPtrs[ bLoop ];
|
|
|
|
// check character is valid, alive, same sector, not between, has inventory, etc.
|
|
if ( CanCharacterRepairAnotherSoldiersStuff( pSoldier, pOtherSoldier ) )
|
|
{
|
|
// okay, seems like a candidate!
|
|
if ( FindRepairableItemOnOtherSoldier( pOtherSoldier, ubPassType ) != NO_SLOT )
|
|
{
|
|
bPriority = pOtherSoldier->bExpLevel;
|
|
if ( bPriority > bBestPriority )
|
|
{
|
|
bBestPriority = bPriority;
|
|
pBestOtherSoldier = pOtherSoldier;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// did we find anyone to repair on this pass?
|
|
if ( pBestOtherSoldier != NULL )
|
|
{
|
|
// yes, repair all items (for this pass type!) on this soldier that need repair
|
|
do
|
|
{
|
|
bPocket = FindRepairableItemOnOtherSoldier( pBestOtherSoldier, ubPassType );
|
|
if ( bPocket != NO_SLOT )
|
|
{
|
|
if ( RepairObject( pSoldier, pBestOtherSoldier, &(pBestOtherSoldier->inv[ bPocket ]), pubRepairPtsLeft ) )
|
|
{
|
|
fSomethingWasRepairedThisPass = TRUE;
|
|
}
|
|
}
|
|
}
|
|
while ( bPocket != NO_SLOT && *pubRepairPtsLeft > 0 );
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( fSomethingWasRepairedThisPass && !DoesCharacterHaveAnyItemsToRepair( pSoldier, ubPassType ) )
|
|
{
|
|
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, sRepairsDoneString[ 1 + ubPassType ], pSoldier->name );
|
|
|
|
// let player react
|
|
StopTimeCompression();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN UnjamGunsOnSoldier( SOLDIERTYPE *pOwnerSoldier, SOLDIERTYPE *pRepairSoldier, UINT8 *pubRepairPtsLeft )
|
|
{
|
|
BOOLEAN fAnyGunsWereUnjammed = FALSE;
|
|
INT8 bPocket;
|
|
|
|
|
|
// try to unjam everything before beginning any actual repairs.. successful unjamming costs 2 points per weapon
|
|
for (bPocket = HANDPOS; bPocket <= SMALLPOCK8POS; bPocket++)
|
|
{
|
|
// the object a weapon? and jammed?
|
|
if ( ( Item[ pOwnerSoldier->inv[ bPocket ].usItem ].usItemClass == IC_GUN ) && ( pOwnerSoldier->inv[ bPocket ].bGunAmmoStatus < 0 ) )
|
|
{
|
|
if ( *pubRepairPtsLeft >= gGameExternalOptions.ubRepairCostPerJam )
|
|
{
|
|
*pubRepairPtsLeft -= gGameExternalOptions.ubRepairCostPerJam;
|
|
|
|
pOwnerSoldier->inv [ bPocket ].bGunAmmoStatus *= -1;
|
|
|
|
// MECHANICAL/DEXTERITY GAIN: Unjammed a gun
|
|
StatChange( pRepairSoldier, MECHANAMT, 5, FALSE );
|
|
StatChange( pRepairSoldier, DEXTAMT, 5, FALSE );
|
|
|
|
// report it as unjammed
|
|
if ( pRepairSoldier == pOwnerSoldier )
|
|
{
|
|
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, gzLateLocalizedString[ 53 ], pRepairSoldier->name, ItemNames[ pOwnerSoldier->inv[ bPocket ].usItem ] );
|
|
}
|
|
else
|
|
{
|
|
// NOTE: may need to be changed for localized versions
|
|
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, gzLateLocalizedString[ 54 ], pRepairSoldier->name, pOwnerSoldier->name, ItemNames[ pOwnerSoldier->inv[ bPocket ].usItem ] );
|
|
}
|
|
|
|
fAnyGunsWereUnjammed = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// out of points, we're done for now
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ( fAnyGunsWereUnjammed );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|