Files
source/Tactical/Soldier Profile.cpp
T

1547 lines
43 KiB
C++

#ifdef PRECOMPILEDHEADERS
#include "Tactical All.h"
#else
#include <stdio.h>
#include <string.h>
#include "wcheck.h"
#include "stdlib.h"
#include "debug.h"
#include "math.h"
#include "worlddef.h"
#include "worldman.h"
#include "renderworld.h"
#include "Soldier Control.h"
#include "Animation Control.h"
#include "Animation Data.h"
#include "Isometric Utils.h"
#include "Event Pump.h"
#include "Timer Control.h"
#include "Render Fun.h"
#include "Render Dirty.h"
#include "mousesystem.h"
#include "interface.h"
#include "sysutil.h"
#include "FileMan.h"
#include "points.h"
#include "Random.h"
#include "ai.h"
#include "Interactive Tiles.h"
#include "soldier ani.h"
#include "english.h"
#include "overhead.h"
#include "Soldier Profile.h"
#include "Game Clock.h"
#include "assignments.h"
#include "Dialogue Control.h"
#include "soldier create.h"
#include "soldier add.h"
#include "opplist.h"
#include "weapons.h"
#include "Strategic Town Loyalty.h"
#include "squads.h"
#include "Tactical Save.h"
#include "Quests.h"
#include "aim.h"
#include "Interface Dialogue.h"
#include "GameSettings.h"
#include "strategic town reputation.h"
#endif
#ifdef JA2EDITOR
extern BOOLEAN gfProfileDataLoaded;
#endif
BOOLEAN gfPotentialTeamChangeDuringDeath = FALSE;
#define MIN_BLINK_FREQ 3000
#define MIN_EXPRESSION_FREQ 2000
#define SET_PROFILE_GAINS2 500, 500, 500, 500, 500, 500, 500, 500, 500
MERCPROFILESTRUCT gMercProfiles[ NUM_PROFILES ];
INT8 gbSkillTraitBonus[NUM_SKILLTRAITS] =
{
0, //NO_SKILLTRAIT
25, //LOCKPICKING
15, //HANDTOHAND
15, //ELECTRONICS
15, //NIGHTOPS
12, //THROWING
15, //TEACHING
15, //HEAVY_WEAPS
0, //AUTO_WEAPS
15, //STEALTHY
0, //AMBIDEXT
0, //THIEF // UNUSED!
30, //MARTIALARTS
30, //KNIFING
15, //ONROOF
0, //CAMOUFLAGED
0, //CAMOUFLAGED_URBAN
0, //CAMOUFLAGED_DESERT
0, //CAMOUFLAGED_SNOW
};
UINT8 gubBasicInventoryPositions[] = {
HELMETPOS,
VESTPOS,
LEGPOS,
HANDPOS,
BIGPOCK1POS,
BIGPOCK2POS,
BIGPOCK3POS,
BIGPOCK4POS
};
#define NUM_TERRORISTS 6
UINT8 gubTerrorists[NUM_TERRORISTS + 1] =
{
DRUGGIST,
SLAY,
ANNIE,
CHRIS,
TIFFANY,
T_REX,
0
};
UINT8 gubNumTerrorists = 0;
#define NUM_TERRORIST_POSSIBLE_LOCATIONS 5
INT16 gsTerroristSector[NUM_TERRORISTS][NUM_TERRORIST_POSSIBLE_LOCATIONS][2] =
{
// Elgin... preplaced
{
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 }
},
// Slay
{
{ 9, MAP_ROW_F },
{ 14, MAP_ROW_I },
{ 1, MAP_ROW_G },
{ 2, MAP_ROW_G },
{ 8, MAP_ROW_G }
},
// Matron
{
{ 14, MAP_ROW_I },
{ 6, MAP_ROW_C },
{ 2, MAP_ROW_B },
{ 11, MAP_ROW_L },
{ 8, MAP_ROW_G }
},
// Imposter
{
{ 1, MAP_ROW_G },
{ 9, MAP_ROW_F },
{ 11, MAP_ROW_L },
{ 8, MAP_ROW_G },
{ 2, MAP_ROW_G }
},
// Tiffany
{
{ 14, MAP_ROW_I },
{ 2, MAP_ROW_G },
{ 14, MAP_ROW_H },
{ 6, MAP_ROW_C },
{ 2, MAP_ROW_B }
},
// Rexall
{
{ 9, MAP_ROW_F },
{ 14, MAP_ROW_H },
{ 2, MAP_ROW_H },
{ 1, MAP_ROW_G },
{ 2, MAP_ROW_B }
}
};
INT16 gsRobotGridNo;
#define NUM_ASSASSINS 6
UINT8 gubAssassins[NUM_ASSASSINS] =
{
JIM,
JACK,
OLAF,
RAY,
OLGA,
TYRONE
};
#define NUM_ASSASSIN_POSSIBLE_TOWNS 5
INT8 gbAssassinTown[NUM_ASSASSINS][NUM_ASSASSIN_POSSIBLE_TOWNS] =
{
// Jim
{ CAMBRIA, DRASSEN, ALMA, BALIME, GRUMM },
// Jack
{ CHITZENA, ESTONI, ALMA, BALIME, GRUMM },
// Olaf
{ DRASSEN, ESTONI, ALMA, CAMBRIA, BALIME },
// Ray
{ CAMBRIA, OMERTA, BALIME, GRUMM, DRASSEN },
// Olga
{ CHITZENA, OMERTA, CAMBRIA, ALMA, GRUMM },
// Tyrone
{ CAMBRIA, BALIME, ALMA, GRUMM, DRASSEN },
};
UINT16 CalcCompetence( MERCPROFILESTRUCT * pProfile );
INT16 CalcMedicalDeposit( MERCPROFILESTRUCT * pProfile );
extern void HandleEndDemoInCreatureLevel( );
void DecideActiveTerrorists( void );
extern SOLDIERTYPE *gpSMCurrentMerc;
extern BOOLEAN gfRerenderInterfaceFromHelpText;
BOOLEAN LoadMercProfiles(void)
{
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"LoadMercProfiles");
// FILE *fptr;
HWFILE fptr;
char *pFileName = "BINARYDATA\\Prof.dat";
char *pFileName1_Normal = "BINARYDATA\\Prof_Novice_NormalGuns.dat";
char *pFileName2_Normal = "BINARYDATA\\Prof_Experienced_NormalGuns.dat";
char *pFileName3_Normal = "BINARYDATA\\Prof_Expert_NormalGuns.dat";
char *pFileName4_Normal = "BINARYDATA\\Prof_Insane_NormalGuns.dat";
char *pFileName1_Tons = "BINARYDATA\\Prof_Novice_TonsOfGuns.dat";
char *pFileName2_Tons = "BINARYDATA\\Prof_Experienced_TonsOfGuns.dat";
char *pFileName3_Tons = "BINARYDATA\\Prof_Expert_TonsOfGuns.dat";
char *pFileName4_Tons = "BINARYDATA\\Prof_Insane_TonsOfGuns.dat";
UINT32 uiLoop, uiLoop2;//, uiLoop3;
UINT16 usItem;//, usNewGun, usAmmo, usNewAmmo;
UINT32 uiNumBytesRead;
switch ( gGameOptions.ubDifficultyLevel)
{
case DIF_LEVEL_EASY:
if ( gGameOptions.fGunNut )
fptr = FileOpen(pFileName1_Tons, FILE_ACCESS_READ, FALSE );
else
fptr = FileOpen(pFileName1_Normal, FILE_ACCESS_READ, FALSE );
break;
case DIF_LEVEL_MEDIUM:
if ( gGameOptions.fGunNut )
fptr = FileOpen(pFileName2_Tons, FILE_ACCESS_READ, FALSE );
else
fptr = FileOpen(pFileName2_Normal, FILE_ACCESS_READ, FALSE );
break;
case DIF_LEVEL_HARD:
if ( gGameOptions.fGunNut )
fptr = FileOpen(pFileName3_Tons, FILE_ACCESS_READ, FALSE );
else
fptr = FileOpen(pFileName3_Normal, FILE_ACCESS_READ, FALSE );
break;
case DIF_LEVEL_INSANE:
if ( gGameOptions.fGunNut )
fptr = FileOpen(pFileName4_Tons, FILE_ACCESS_READ, FALSE );
else
fptr = FileOpen(pFileName4_Normal, FILE_ACCESS_READ, FALSE );
break;
default:
fptr = FileOpen(pFileName, FILE_ACCESS_READ, FALSE );
break;
}
if( !fptr )
{
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("FAILED to LoadMercProfiles from file %s", pFileName) );
return(FALSE);
}
for(uiLoop=0; uiLoop< NUM_PROFILES; uiLoop++)
{
if( JA2EncryptedFileRead( fptr, &gMercProfiles[uiLoop], sizeof( MERCPROFILESTRUCT ), &uiNumBytesRead ) != 1)
{
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("FAILED to Read Merc Profiles from File %d %s",uiLoop, pFileName) );
FileClose( fptr );
return(FALSE);
}
//if the Dialogue exists for the merc, allow the merc to be hired
if( DialogueDataFileExistsForProfile( (UINT8)uiLoop, 0, FALSE, NULL ) )
{
gMercProfiles[uiLoop].bMercStatus = 0;
}
else
gMercProfiles[uiLoop].bMercStatus = MERC_HAS_NO_TEXT_FILE;
// if the merc has a medical deposit
if( gMercProfiles[ uiLoop ].bMedicalDeposit )
{
gMercProfiles[uiLoop].sMedicalDepositAmount = CalcMedicalDeposit( &gMercProfiles[uiLoop]);
}
else
gMercProfiles[uiLoop].sMedicalDepositAmount = 0;
// ATE: New, face display indipendent of ID num now
// Setup face index value
// Default is the ubCharNum
gMercProfiles[uiLoop].ubFaceIndex = (UINT8)uiLoop;
/*
if ( !gGameOptions.fGunNut )
{
// CJC: replace guns in profile if they aren't available
for ( uiLoop2 = 0; uiLoop2 < NUM_INV_SLOTS; uiLoop2++ )
{
usItem = gMercProfiles[uiLoop].inv[ uiLoop2 ];
if ( ( Item[ usItem ].usItemClass & IC_GUN ) && ExtendedGunListGun( usItem ) )
{
usNewGun = StandardGunListReplacement( usItem );
if ( usNewGun != NOTHING )
{
gMercProfiles[uiLoop].inv[ uiLoop2 ] = usNewGun;
// must search through inventory and replace ammo accordingly
for ( uiLoop3 = 0; uiLoop3 < NUM_INV_SLOTS; uiLoop3++ )
{
usAmmo = gMercProfiles[ uiLoop ].inv[ uiLoop3 ];
if ( (Item[ usAmmo ].usItemClass & IC_AMMO) )
{
usNewAmmo = FindReplacementMagazineIfNecessary( usItem, usAmmo, usNewGun );
if (usNewAmmo != NOTHING )
{
// found a new magazine, replace...
gMercProfiles[ uiLoop ].inv[ uiLoop3 ] = usNewAmmo;
}
}
}
}
}
}
} // end of if not gun nut
*/
//ATE: Calculate some inital attractiveness values for buddy's inital equipment...
// Look for gun and armour
gMercProfiles[uiLoop].bMainGunAttractiveness = -1;
gMercProfiles[uiLoop].bArmourAttractiveness = -1;
for ( uiLoop2 = 0; uiLoop2 < NUM_INV_SLOTS; uiLoop2++ )
{
usItem = gMercProfiles[uiLoop].inv[ uiLoop2 ];
if ( usItem != NOTHING )
{
// Check if it's a gun
if ( Item[ usItem ].usItemClass & IC_GUN )
{
gMercProfiles[uiLoop].bMainGunAttractiveness = Weapon[ usItem ].ubDeadliness;
}
// If it's armour
if ( Item[ usItem ].usItemClass & IC_ARMOUR )
{
gMercProfiles[uiLoop].bArmourAttractiveness = min(128,Armour[ Item[ usItem ].ubClassIndex ].ubProtection);
}
}
}
// OK, if we are a created slot, this will get overriden at some time..
//add up the items the merc has for the usOptionalGearCost
gMercProfiles[ uiLoop ].usOptionalGearCost = 0;
for ( uiLoop2 = 0; uiLoop2< NUM_INV_SLOTS; uiLoop2++ )
{
if ( gMercProfiles[ uiLoop ].inv[ uiLoop2 ] != NOTHING )
{
//get the item
usItem = gMercProfiles[ uiLoop ].inv[ uiLoop2 ];
//add the cost
gMercProfiles[ uiLoop ].usOptionalGearCost += Item[ usItem ].usPrice;
}
}
//These variables to get loaded in
gMercProfiles[ uiLoop ].fUseProfileInsertionInfo = FALSE;
gMercProfiles[ uiLoop ].sGridNo = 0;
// ARM: this is also being done inside the profile editor, but put it here too, so this project's code makes sense
gMercProfiles[ uiLoop ].bHatedCount[0] = gMercProfiles[ uiLoop ].bHatedTime[0];
gMercProfiles[ uiLoop ].bHatedCount[1] = gMercProfiles[ uiLoop ].bHatedTime[1];
gMercProfiles[ uiLoop ].bLearnToHateCount = gMercProfiles[ uiLoop ].bLearnToHateTime;
gMercProfiles[ uiLoop ].bLearnToLikeCount = gMercProfiles[ uiLoop ].bLearnToLikeTime;
}
// SET SOME DEFAULT LOCATIONS FOR STARTING NPCS
FileClose( fptr );
// decide which terrorists are active
DecideActiveTerrorists();
// initialize mercs' status
StartSomeMercsOnAssignment( );
// initial recruitable mercs' reputation in each town
InitializeProfilesForTownReputation( );
#ifdef JA2EDITOR
gfProfileDataLoaded = TRUE;
#endif
// no better place..heh?.. will load faces for profiles that are 'extern'.....won't have soldiertype instances
InitalizeStaticExternalNPCFaces( );
// car portrait values
LoadCarPortraitValues( );
DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"LoadMercProfiles done");
return(TRUE);
}
#define MAX_ADDITIONAL_TERRORISTS 4
void DecideActiveTerrorists( void )
{
UINT8 ubLoop, ubLoop2;
UINT8 ubTerrorist;
UINT8 ubNumAdditionalTerrorists, ubNumTerroristsAdded = 0;
UINT32 uiChance, uiLocationChoice;
BOOLEAN fFoundSpot;
INT16 sTerroristPlacement[MAX_ADDITIONAL_TERRORISTS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
#ifdef CRIPPLED_VERSION
return;
#endif
// one terrorist will always be Elgin
// determine how many more terrorists - 2 to 4 more
// using this stochastic process(!), the chances for terrorists are:
// EASY: 3, 9% 4, 42% 5, 49%
// MEDIUM: 3, 25% 4, 50% 5, 25%
// HARD: 3, 49% 4, 42% 5, 9%
switch( gGameOptions.ubDifficultyLevel )
{
case DIF_LEVEL_EASY:
uiChance = 70;
break;
case DIF_LEVEL_INSANE:
uiChance = 30;
break;
default:
uiChance = 50;
break;
}
if ( gGameExternalOptions.fEnableAllTerrorists )
uiChance = 100;
// add at least 2 more
ubNumAdditionalTerrorists = 2;
for (ubLoop = 0; ubLoop < (MAX_ADDITIONAL_TERRORISTS - 2); ubLoop++)
{
if (Random( 100 ) < uiChance)
{
ubNumAdditionalTerrorists++;
}
}
// ifdefs added by CJC
#ifdef JA2TESTVERSION
ubNumAdditionalTerrorists = 4;
#endif
while ( ubNumTerroristsAdded < ubNumAdditionalTerrorists )
{
ubLoop = 1; // start at beginning of array (well, after Elgin)
// NB terrorist ID of 0 indicates end of array
while ( ubNumTerroristsAdded < ubNumAdditionalTerrorists && gubTerrorists[ ubLoop ] != 0 )
{
ubTerrorist = gubTerrorists[ ubLoop ];
// random 40% chance of adding this terrorist if not yet placed
if ( ( gMercProfiles[ ubTerrorist ].sSectorX == 0 ) && ( Random( 100 ) < 40 ) )
{
fFoundSpot = FALSE;
// Since there are 5 spots per terrorist and a maximum of 5 terrorists, we
// are guaranteed to be able to find a spot for each terrorist since there
// aren't enough other terrorists to use up all the spots for any one
// terrorist
do
{
// pick a random spot, see if it's already been used by another terrorist
uiLocationChoice = Random( NUM_TERRORIST_POSSIBLE_LOCATIONS );
for (ubLoop2 = 0; ubLoop2 < ubNumTerroristsAdded; ubLoop2++)
{
if (sTerroristPlacement[ubLoop2][0] == gsTerroristSector[ubLoop][uiLocationChoice][0] )
{
if (sTerroristPlacement[ubLoop2][1] == gsTerroristSector[ubLoop][uiLocationChoice][1] )
{
continue;
}
}
}
fFoundSpot = TRUE;
} while( !fFoundSpot );
// place terrorist!
gMercProfiles[ ubTerrorist ].sSectorX = gsTerroristSector[ ubLoop ][ uiLocationChoice ][ 0 ];
gMercProfiles[ ubTerrorist ].sSectorY = gsTerroristSector[ ubLoop ][ uiLocationChoice ][ 1 ];
gMercProfiles[ ubTerrorist ].bSectorZ = 0;
sTerroristPlacement[ ubNumTerroristsAdded ][ 0 ] = gMercProfiles[ ubTerrorist ].sSectorX;
sTerroristPlacement[ ubNumTerroristsAdded ][ 1 ] = gMercProfiles[ ubTerrorist ].sSectorY;
ubNumTerroristsAdded++;
}
ubLoop++;
}
// start over if necessary
}
// set total terrorists outstanding in Carmen's info byte
gMercProfiles[ 78 ].bNPCData = 1 + ubNumAdditionalTerrorists;
// store total terrorists
gubNumTerrorists = 1 + ubNumAdditionalTerrorists;
}
void MakeRemainingTerroristsTougher( void )
{
UINT8 ubRemainingTerrorists = 0, ubLoop;
UINT16 usNewItem, usOldItem;
OBJECTTYPE Object;
UINT8 ubRemainingDifficulty;
for ( ubLoop = 0; ubLoop < NUM_TERRORISTS; ubLoop++ )
{
if ( gMercProfiles[ gubTerrorists[ ubLoop ] ].bMercStatus != MERC_IS_DEAD && gMercProfiles[ gubTerrorists[ ubLoop ] ].sSectorX != 0 && gMercProfiles[ gubTerrorists[ ubLoop ] ].sSectorY != 0 )
{
if ( gubTerrorists[ ubLoop ] == SLAY )
{
if ( FindSoldierByProfileID( SLAY, TRUE ) != NULL )
{
// Slay on player's team, doesn't count towards remaining terrorists
continue;
}
}
ubRemainingTerrorists++;
}
}
ubRemainingDifficulty = (60 / gubNumTerrorists) * (gubNumTerrorists - ubRemainingTerrorists);
switch( gGameOptions.ubDifficultyLevel )
{
case DIF_LEVEL_MEDIUM:
ubRemainingDifficulty = (ubRemainingDifficulty * 13) / 10;
break;
case DIF_LEVEL_HARD:
ubRemainingDifficulty = (ubRemainingDifficulty * 16) / 10;
break;
case DIF_LEVEL_INSANE:
ubRemainingDifficulty = (ubRemainingDifficulty * 19) / 10;
break;
default:
break;
}
if ( ubRemainingDifficulty < 14 )
{
// nothing
return;
}
else if ( ubRemainingDifficulty < 28 )
{
// mini grenade
usOldItem = NOTHING;
usNewItem = MINI_GRENADE;
}
else if ( ubRemainingDifficulty < 42)
{
// hand grenade
usOldItem = MINI_GRENADE;
usNewItem = HAND_GRENADE;
}
else if ( ubRemainingDifficulty < 56)
{
// mustard
usOldItem = HAND_GRENADE;
usNewItem = MUSTARD_GRENADE;
}
else if ( ubRemainingDifficulty < 70)
{
// LAW
usOldItem = MUSTARD_GRENADE;
usNewItem = ROCKET_LAUNCHER;
}
else
{
// LAW and hand grenade
usOldItem = NOTHING;
usNewItem = HAND_GRENADE;
}
DeleteObj( &Object );
Object.usItem = usNewItem;
Object.bStatus[ 0 ] = 100;
for ( ubLoop = 0; ubLoop < NUM_TERRORISTS; ubLoop++ )
{
if ( gMercProfiles[ gubTerrorists[ ubLoop ] ].bMercStatus != MERC_IS_DEAD && gMercProfiles[ gubTerrorists[ ubLoop ] ].sSectorX != 0 && gMercProfiles[ gubTerrorists[ ubLoop ] ].sSectorY != 0 )
{
if ( gubTerrorists[ ubLoop ] == SLAY )
{
if ( FindSoldierByProfileID( SLAY, TRUE ) != NULL )
{
// Slay on player's team, doesn't count towards remaining terrorists
continue;
}
}
if ( usOldItem != NOTHING )
{
RemoveObjectFromSoldierProfile( gubTerrorists[ ubLoop ], usOldItem );
}
PlaceObjectInSoldierProfile( gubTerrorists[ ubLoop ], &Object );
}
}
}
void DecideOnAssassin( void )
{
UINT8 ubAssassinPossibility[NUM_ASSASSINS] = { NO_PROFILE, NO_PROFILE, NO_PROFILE, NO_PROFILE, NO_PROFILE, NO_PROFILE };
UINT8 ubAssassinsPossible = 0;
UINT8 ubLoop, ubLoop2;
UINT8 ubTown;
#ifdef CRIPPLED_VERSION
return;
#endif
ubTown = GetTownIdForSector( gWorldSectorX, gWorldSectorY );
for ( ubLoop = 0; ubLoop < NUM_ASSASSINS; ubLoop++ )
{
// make sure alive and not placed already
if ( gMercProfiles[ gubAssassins[ ubLoop ] ].bMercStatus != MERC_IS_DEAD && gMercProfiles[ gubAssassins[ ubLoop ] ].sSectorX == 0 && gMercProfiles[ gubAssassins[ ubLoop ] ].sSectorY == 0 )
{
// check this merc to see if the town is a possibility
for ( ubLoop2 = 0; ubLoop2 < NUM_ASSASSIN_POSSIBLE_TOWNS; ubLoop2++ )
{
if ( gbAssassinTown[ ubLoop ][ ubLoop2 ] == ubTown )
{
ubAssassinPossibility[ ubAssassinsPossible ] = gubAssassins[ ubLoop ];
ubAssassinsPossible++;
}
}
}
}
if ( ubAssassinsPossible != 0 )
{
ubLoop = ubAssassinPossibility[ Random( ubAssassinsPossible ) ];
gMercProfiles[ ubLoop ].sSectorX = gWorldSectorX;
gMercProfiles[ ubLoop ].sSectorY = gWorldSectorY;
AddStrategicEvent( EVENT_REMOVE_ASSASSIN, GetWorldTotalMin() + 60 * ( 3 + Random( 3 ) ), ubLoop );
}
}
void MakeRemainingAssassinsTougher( void )
{
UINT8 ubRemainingAssassins = 0, ubLoop;
UINT16 usNewItem, usOldItem;
OBJECTTYPE Object;
UINT8 ubRemainingDifficulty;
for ( ubLoop = 0; ubLoop < NUM_ASSASSINS; ubLoop++ )
{
if ( gMercProfiles[ gubAssassins[ ubLoop ] ].bMercStatus != MERC_IS_DEAD )
{
ubRemainingAssassins++;
}
}
ubRemainingDifficulty = (60 / NUM_ASSASSINS) * (NUM_ASSASSINS - ubRemainingAssassins);
switch( gGameOptions.ubDifficultyLevel )
{
case DIF_LEVEL_MEDIUM:
ubRemainingDifficulty = (ubRemainingDifficulty * 13) / 10;
break;
case DIF_LEVEL_HARD:
ubRemainingDifficulty = (ubRemainingDifficulty * 16) / 10;
break;
case DIF_LEVEL_INSANE:
ubRemainingDifficulty = (ubRemainingDifficulty * 19) / 10;
break;
default:
break;
}
if ( ubRemainingDifficulty < 14 )
{
// nothing
return;
}
else if ( ubRemainingDifficulty < 28 )
{
// mini grenade
usOldItem = NOTHING;
usNewItem = MINI_GRENADE;
}
else if ( ubRemainingDifficulty < 42)
{
// hand grenade
usOldItem = MINI_GRENADE;
usNewItem = HAND_GRENADE;
}
else if ( ubRemainingDifficulty < 56)
{
// mustard
usOldItem = HAND_GRENADE;
usNewItem = MUSTARD_GRENADE;
}
else if ( ubRemainingDifficulty < 70)
{
// LAW
usOldItem = MUSTARD_GRENADE;
usNewItem = ROCKET_LAUNCHER;
}
else
{
// LAW and hand grenade
usOldItem = NOTHING;
usNewItem = HAND_GRENADE;
}
DeleteObj( &Object );
Object.usItem = usNewItem;
Object.bStatus[ 0 ] = 100;
for ( ubLoop = 0; ubLoop < NUM_ASSASSINS; ubLoop++ )
{
if ( gMercProfiles[ gubAssassins[ ubLoop ] ].bMercStatus != MERC_IS_DEAD )
{
if ( usOldItem != NOTHING )
{
RemoveObjectFromSoldierProfile( gubAssassins[ ubLoop ], usOldItem );
}
PlaceObjectInSoldierProfile( gubAssassins[ ubLoop ], &Object );
}
}
}
void StartSomeMercsOnAssignment(void)
{
UINT32 uiCnt;
MERCPROFILESTRUCT *pProfile;
UINT32 uiChance;
// some randomly picked A.I.M. mercs will start off "on assignment" at the beginning of each new game
for( uiCnt = 0; uiCnt < AIM_AND_MERC_MERCS; uiCnt++)
{
if( !IsProfileIdAnAimOrMERCMerc( (UINT8)uiCnt ) )
{
continue;
}
pProfile = &(gMercProfiles[ uiCnt ]);
// calc chance to start on assignment
uiChance = 5 * pProfile->bExpLevel;
if (Random(100) < uiChance)
{
pProfile->bMercStatus = MERC_WORKING_ELSEWHERE;
pProfile->uiDayBecomesAvailable = 1 + Random(6 + (pProfile->bExpLevel / 2) ); // 1-(6 to 11) days
}
else
{
pProfile->bMercStatus = MERC_OK;
pProfile->uiDayBecomesAvailable = 0;
}
pProfile->uiPrecedentQuoteSaid = 0;
pProfile->ubDaysOfMoraleHangover = 0;
}
}
void SetProfileFaceData( UINT8 ubCharNum, UINT8 ubFaceIndex, UINT16 usEyesX, UINT16 usEyesY, UINT16 usMouthX, UINT16 usMouthY )
{
gMercProfiles[ ubCharNum ].ubFaceIndex = ubFaceIndex;
gMercProfiles[ ubCharNum ].usEyesX = usEyesX;
gMercProfiles[ ubCharNum ].usEyesY = usEyesY;
gMercProfiles[ ubCharNum ].usMouthX = usMouthX;
gMercProfiles[ ubCharNum ].usMouthY = usMouthY;
}
UINT16 CalcCompetence( MERCPROFILESTRUCT * pProfile )
{
UINT32 uiStats, uiSkills, uiActionPoints, uiSpecialSkills;
UINT16 usCompetence;
// count life twice 'cause it's also hit points
// mental skills are halved 'cause they're actually not that important within the game
uiStats = ((2 * pProfile->bLifeMax) + pProfile->bStrength + pProfile->bAgility + pProfile->bDexterity + ((pProfile->bLeadership + pProfile->bWisdom) / 2)) / 3;
// marksmanship is very important, count it double
uiSkills = (UINT32) ((2 * (pow(pProfile->bMarksmanship, 3) / 10000)) +
1.5 * (pow(pProfile->bMedical, 3) / 10000) +
(pow(pProfile->bMechanical, 3) / 10000) +
(pow(pProfile->bExplosive, 3) / 10000));
// action points
uiActionPoints = 5 + (((10 * pProfile->bExpLevel +
3 * pProfile->bAgility +
2 * pProfile->bLifeMax +
2 * pProfile->bDexterity) + 20) / 40);
// count how many he has, don't care what they are
uiSpecialSkills = ((pProfile->bSkillTrait != 0) ? 1 : 0) + ((pProfile->bSkillTrait2 != 0) ? 1 : 0);
usCompetence = (UINT16) ((pow((double)pProfile->bExpLevel, 0.2) * uiStats * uiSkills * (uiActionPoints - 6) * (1 + (0.05 * (FLOAT)uiSpecialSkills))) / 1000);
// this currently varies from about 10 (Flo) to 1200 (Gus)
return(usCompetence);
}
INT16 CalcMedicalDeposit( MERCPROFILESTRUCT * pProfile )
{
UINT16 usDeposit;
// this rounds off to the nearest hundred
usDeposit = (((5 * CalcCompetence(pProfile)) + 50) / 100) * 100;
return(usDeposit);
}
SOLDIERTYPE * FindSoldierByProfileID( UINT8 ubProfileID, BOOLEAN fPlayerMercsOnly )
{
UINT8 ubLoop, ubLoopLimit;
SOLDIERTYPE * pSoldier;
if (fPlayerMercsOnly)
{
ubLoopLimit = gTacticalStatus.Team[0].bLastID;
}
else
{
ubLoopLimit = MAX_NUM_SOLDIERS;
}
for (ubLoop = 0, pSoldier = MercPtrs[0]; ubLoop < ubLoopLimit; ubLoop++, pSoldier++)
{
if (pSoldier->bActive && pSoldier->ubProfile == ubProfileID)
{
return( pSoldier );
}
}
return( NULL );
}
SOLDIERTYPE *ChangeSoldierTeam( SOLDIERTYPE *pSoldier, UINT8 ubTeam )
{
UINT8 ubID;
SOLDIERTYPE *pNewSoldier = NULL;
SOLDIERCREATE_STRUCT MercCreateStruct;
UINT32 cnt;
INT16 sOldGridNo;
UINT8 ubOldID;
UINT32 uiOldUniqueId;
UINT32 uiSlot;
SOLDIERTYPE *pGroupMember;
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("ChangeSoldierTeam"));
if (gfInTalkPanel)
{
DeleteTalkingMenu();
}
// Save merc id for this guy...
ubID = pSoldier->ubID;
ubOldID = ubID;
uiOldUniqueId = pSoldier->uiUniqueSoldierIdValue;
sOldGridNo = pSoldier->sGridNo;
// Remove him from the game!
InternalTacticalRemoveSoldier( ubID, FALSE );
// Create a new one!
memset( &MercCreateStruct, 0, sizeof( MercCreateStruct ) );
MercCreateStruct.bTeam = ubTeam;
MercCreateStruct.ubProfile = pSoldier->ubProfile;
MercCreateStruct.bBodyType = pSoldier->ubBodyType;
MercCreateStruct.sSectorX = pSoldier->sSectorX;
MercCreateStruct.sSectorY = pSoldier->sSectorY;
MercCreateStruct.bSectorZ = pSoldier->bSectorZ;
MercCreateStruct.sInsertionGridNo = pSoldier->sGridNo;
MercCreateStruct.bDirection = pSoldier->bDirection;
if ( pSoldier->uiStatusFlags & SOLDIER_VEHICLE )
{
MercCreateStruct.ubProfile = NO_PROFILE;
MercCreateStruct.fUseGivenVehicle = TRUE;
MercCreateStruct.bUseGivenVehicleID = pSoldier->bVehicleID;
}
if ( ubTeam == gbPlayerNum )
{
MercCreateStruct.fPlayerMerc = TRUE;
}
if ( TacticalCreateSoldier( &MercCreateStruct, &ubID ) )
{
pNewSoldier = MercPtrs[ ubID ];
// Copy vital stats back!
pNewSoldier->bLife = pSoldier->bLife;
pNewSoldier->bLifeMax = pSoldier->bLifeMax;
pNewSoldier->bAgility = pSoldier->bAgility;
pNewSoldier->bLeadership = pSoldier->bLeadership;
pNewSoldier->bDexterity = pSoldier->bDexterity;
pNewSoldier->bStrength = pSoldier->bStrength;
pNewSoldier->bWisdom = pSoldier->bWisdom;
pNewSoldier->bExpLevel = pSoldier->bExpLevel;
pNewSoldier->bMarksmanship = pSoldier->bMarksmanship;
pNewSoldier->bMedical = pSoldier->bMedical;
pNewSoldier->bMechanical = pSoldier->bMechanical;
pNewSoldier->bExplosive = pSoldier->bExplosive;
pNewSoldier->bScientific = pSoldier->bScientific;
pNewSoldier->bLastRenderVisibleValue = pSoldier->bLastRenderVisibleValue;
pNewSoldier->bVisible = pSoldier->bVisible;
if ( ubTeam == gbPlayerNum )
{
pNewSoldier->bVisible = 1;
}
// Copy over any items....
for ( cnt = 0; cnt < NUM_INV_SLOTS; cnt++ )
{
pNewSoldier->inv[ cnt ] = pSoldier->inv[ cnt ];
}
// OK, loop through all active merc slots, change
// Change ANY attacker's target if they were once on this guy.....
for ( uiSlot = 0; uiSlot < guiNumMercSlots; uiSlot++ )
{
pGroupMember = MercSlots[ uiSlot ];
if ( pGroupMember != NULL )
{
if ( pGroupMember->ubTargetID == pSoldier->ubID )
{
pGroupMember->ubTargetID = pNewSoldier->ubID;
}
}
}
// Set insertion gridNo
pNewSoldier->sInsertionGridNo = sOldGridNo;
if ( gfPotentialTeamChangeDuringDeath )
{
HandleCheckForDeathCommonCode( pSoldier );
}
if ( gfWorldLoaded && pSoldier->bInSector
//pSoldier->sSectorX == gWorldSectorX && pSoldier->sSectorY == gWorldSectorY && pSoldier->bSectorZ == gbWorldSectorZ
)
{
AddSoldierToSectorNoCalculateDirectionUseAnimation( ubID, pSoldier->usAnimState, pSoldier->usAniCode );
HandleSight(pNewSoldier, SIGHT_LOOK | SIGHT_RADIO);
}
// fix up the event queue...
// ChangeSoldierIDInQueuedEvents( ubOldID, uiOldUniqueId, pNewSoldier->ubID, pNewSoldier->uiUniqueSoldierIdValue );
if ( pNewSoldier->ubProfile != NO_PROFILE )
{
if ( ubTeam == gbPlayerNum )
{
gMercProfiles[ pNewSoldier->ubProfile ].ubMiscFlags |= PROFILE_MISC_FLAG_RECRUITED;
}
else
{
gMercProfiles[ pNewSoldier->ubProfile ].ubMiscFlags &= (~PROFILE_MISC_FLAG_RECRUITED);
}
}
}
// AT the low level check if this poor guy is in inv panel, else
// remove....
if ( gsCurInterfacePanel == SM_PANEL && gpSMCurrentMerc == pSoldier )
{
// Switch....
SetCurrentInterfacePanel( TEAM_PANEL );
}
return( pNewSoldier );
}
BOOLEAN RecruitRPC( UINT8 ubCharNum )
{
SOLDIERTYPE *pSoldier, *pNewSoldier;
// Get soldier pointer
pSoldier = FindSoldierByProfileID( ubCharNum, FALSE );
if (!pSoldier)
{
return( FALSE );
}
// OK, set recruit flag..
gMercProfiles[ ubCharNum ].ubMiscFlags |= PROFILE_MISC_FLAG_RECRUITED;
// Add this guy to our team!
pNewSoldier = ChangeSoldierTeam( pSoldier, gbPlayerNum );
// handle set up any RPC's that will leave us in time
if ( ubCharNum == SLAY )
{
// slay will leave in a week
pNewSoldier->iEndofContractTime = GetWorldTotalMin() + ( 7 * 24 * 60 );
KickOutWheelchair( pNewSoldier );
}
else if ( ubCharNum == DYNAMO && gubQuest[ QUEST_FREE_DYNAMO ] == QUESTINPROGRESS )
{
EndQuest( QUEST_FREE_DYNAMO, pSoldier->sSectorX, pSoldier->sSectorY );
}
// handle town loyalty adjustment
HandleTownLoyaltyForNPCRecruitment( pNewSoldier );
// Try putting them into the current squad
if ( AddCharacterToSquad( pNewSoldier, (INT8)CurrentSquad( ) ) == FALSE )
{
AddCharacterToAnySquad( pNewSoldier );
}
ResetDeadSquadMemberList( pNewSoldier->bAssignment );
DirtyMercPanelInterface( pNewSoldier, DIRTYLEVEL2 );
if ( pNewSoldier->inv[ HANDPOS ].usItem == NOTHING )
{
// empty handed - swap in first available weapon
INT8 bSlot;
bSlot = FindObjClass( pNewSoldier, IC_WEAPON );
if ( bSlot != NO_SLOT )
{
// if ( Item[ pNewSoldier->inv[ bSlot ].usItem ].fFlags & ITEM_TWO_HANDED )
if ( Item[ pNewSoldier->inv[ bSlot ].usItem ].twohanded )
{
if ( bSlot != SECONDHANDPOS && pNewSoldier->inv[ SECONDHANDPOS ].usItem != NOTHING )
{
// need to move second hand item out first
AutoPlaceObject( pNewSoldier, &(pNewSoldier->inv[ SECONDHANDPOS ]), FALSE );
}
}
// swap item to hand
SwapObjs( &(pNewSoldier->inv[ bSlot ]), &(pNewSoldier->inv[ HANDPOS ]) );
}
}
if ( ubCharNum == IRA )
{
// trigger 0th PCscript line
TriggerNPCRecord( IRA, 0 );
}
// Set whatkind of merc am i
pNewSoldier->ubWhatKindOfMercAmI = MERC_TYPE__NPC;
//
//add a history log that tells the user that a npc has joined the team
//
// ( pass in pNewSoldier->sSectorX cause if its invalid, -1, n/a will appear as the sector in the history log )
AddHistoryToPlayersLog( HISTORY_RPC_JOINED_TEAM, pNewSoldier->ubProfile, GetWorldTotalMin(), pNewSoldier->sSectorX, pNewSoldier->sSectorY );
//remove the merc from the Personnel screens departed list ( if they have never been hired before, its ok to call it )
RemoveNewlyHiredMercFromPersonnelDepartedList( pSoldier->ubProfile );
return( TRUE );
}
BOOLEAN RecruitEPC( UINT8 ubCharNum )
{
SOLDIERTYPE *pSoldier, *pNewSoldier;
// Get soldier pointer
pSoldier = FindSoldierByProfileID( ubCharNum, FALSE );
if (!pSoldier)
{
return( FALSE );
}
// OK, set recruit flag..
gMercProfiles[ ubCharNum ].ubMiscFlags |= PROFILE_MISC_FLAG_EPCACTIVE;
gMercProfiles[ ubCharNum ].ubMiscFlags3 &= ~PROFILE_MISC_FLAG3_PERMANENT_INSERTION_CODE;
// Add this guy to our team!
pNewSoldier = ChangeSoldierTeam( pSoldier, gbPlayerNum );
pNewSoldier->ubWhatKindOfMercAmI = MERC_TYPE__EPC;
// Try putting them into the current squad
if ( AddCharacterToSquad( pNewSoldier, (INT8)CurrentSquad( ) ) == FALSE )
{
AddCharacterToAnySquad( pNewSoldier );
}
ResetDeadSquadMemberList( pNewSoldier->bAssignment );
DirtyMercPanelInterface( pNewSoldier, DIRTYLEVEL2 );
// Make the interface panel dirty..
// This will dirty the panel next frame...
gfRerenderInterfaceFromHelpText = TRUE;
// If we are a robot, look to update controller....
if ( pNewSoldier->uiStatusFlags & SOLDIER_ROBOT )
{
UpdateRobotControllerGivenRobot( pNewSoldier );
}
// Set whatkind of merc am i
pNewSoldier->ubWhatKindOfMercAmI = MERC_TYPE__EPC;
UpdateTeamPanelAssignments( );
return( TRUE );
}
BOOLEAN UnRecruitEPC( UINT8 ubCharNum )
{
SOLDIERTYPE *pSoldier, *pNewSoldier;
// Get soldier pointer
pSoldier = FindSoldierByProfileID( ubCharNum, FALSE );
if (!pSoldier)
{
return( FALSE );
}
if (pSoldier->ubWhatKindOfMercAmI != MERC_TYPE__EPC)
{
return( FALSE );
}
if ( pSoldier->bAssignment < ON_DUTY )
{
ResetDeadSquadMemberList( pSoldier->bAssignment );
}
// Rmeove from squad....
RemoveCharacterFromSquads( pSoldier );
// O< check if this is the only guy in the sector....
if ( gusSelectedSoldier == pSoldier->ubID )
{
gusSelectedSoldier = NOBODY;
}
// OK, UN set recruit flag..
gMercProfiles[ ubCharNum ].ubMiscFlags &= (~PROFILE_MISC_FLAG_EPCACTIVE);
// update sector values to current
// check to see if this person should disappear from the map after this
if ( (ubCharNum == JOHN || ubCharNum == MARY) && pSoldier->sSectorX == 13 && pSoldier->sSectorY == MAP_ROW_B && pSoldier->bSectorZ == 0 )
{
gMercProfiles[ ubCharNum ].sSectorX = 0;
gMercProfiles[ ubCharNum ].sSectorY = 0;
gMercProfiles[ ubCharNum ].bSectorZ = 0;
}
else
{
gMercProfiles[ ubCharNum ].sSectorX = pSoldier->sSectorX;
gMercProfiles[ ubCharNum ].sSectorY = pSoldier->sSectorY;
gMercProfiles[ ubCharNum ].bSectorZ = pSoldier->bSectorZ;
}
// how do we decide whether or not to set this?
gMercProfiles[ ubCharNum ].fUseProfileInsertionInfo = TRUE;
gMercProfiles[ ubCharNum ].ubMiscFlags3 |= PROFILE_MISC_FLAG3_PERMANENT_INSERTION_CODE;
// Add this guy to CIV team!
pNewSoldier = ChangeSoldierTeam( pSoldier, CIV_TEAM );
UpdateTeamPanelAssignments( );
return( TRUE );
}
INT8 WhichBuddy( UINT8 ubCharNum, UINT8 ubBuddy )
{
MERCPROFILESTRUCT * pProfile;
INT8 bLoop;
pProfile = &( gMercProfiles[ ubCharNum ] );
for (bLoop = 0; bLoop < 3; bLoop++)
{
if ( pProfile->bBuddy[bLoop] == ubBuddy )
{
return( bLoop );
}
}
return( -1 );
}
INT8 WhichHated( UINT8 ubCharNum, UINT8 ubHated )
{
MERCPROFILESTRUCT * pProfile;
INT8 bLoop;
pProfile = &( gMercProfiles[ ubCharNum ] );
for (bLoop = 0; bLoop < 3; bLoop++)
{
if ( pProfile->bHated[bLoop] == ubHated )
{
return( bLoop );
}
}
return( -1 );
}
BOOLEAN IsProfileATerrorist( UINT8 ubProfile )
{
if ( ubProfile == 83 || ubProfile == 111 ||
ubProfile == 64 || ubProfile == 112 ||
ubProfile == 82 || ubProfile == 110 )
{
return( TRUE );
}
else
{
return( FALSE );
}
}
BOOLEAN IsProfileAHeadMiner( UINT8 ubProfile )
{
if ( ubProfile == 106 || ubProfile == 148 ||
ubProfile == 156 || ubProfile == 157 ||
ubProfile == 158 )
{
return( TRUE );
}
else
{
return( FALSE );
}
}
void UpdateSoldierPointerDataIntoProfile( BOOLEAN fPlayerMercs )
{
UINT32 uiCount;
SOLDIERTYPE *pSoldier = NULL;
MERCPROFILESTRUCT * pProfile;
BOOLEAN fDoCopy = FALSE;
for( uiCount=0; uiCount < guiNumMercSlots; uiCount++)
{
pSoldier = MercSlots[ uiCount ];
if ( pSoldier != NULL )
{
if ( pSoldier->ubProfile != NO_PROFILE )
{
fDoCopy = FALSE;
// If we are above player mercs
if ( fPlayerMercs )
{
if ( pSoldier->ubProfile < FIRST_RPC || pSoldier->ubProfile >= GASTON )
{
fDoCopy = TRUE;
}
}
else
{
if ( pSoldier->ubProfile >= FIRST_RPC && pSoldier->ubProfile < GASTON )
{
fDoCopy = TRUE;
}
}
if ( fDoCopy )
{
// get profile...
pProfile = &( gMercProfiles[ pSoldier->ubProfile ] );
// Copy....
pProfile->bLife = pSoldier->bLife;
pProfile->bLifeMax = pSoldier->bLifeMax;
pProfile->bAgility = pSoldier->bAgility;
pProfile->bLeadership = pSoldier->bLeadership;
pProfile->bDexterity = pSoldier->bDexterity;
pProfile->bStrength = pSoldier->bStrength;
pProfile->bWisdom = pSoldier->bWisdom;
pProfile->bExpLevel = pSoldier->bExpLevel;
pProfile->bMarksmanship = pSoldier->bMarksmanship;
pProfile->bMedical = pSoldier->bMedical;
pProfile->bMechanical = pSoldier->bMechanical;
pProfile->bExplosive = pSoldier->bExplosive;
pProfile->bScientific = pSoldier->bScientific;
}
}
}
}
}
BOOLEAN DoesMercHaveABuddyOnTheTeam( UINT8 ubMercID )
{
UINT8 ubCnt;
INT8 bBuddyID;
// loop through the list of people the merc is buddies with
for(ubCnt=0; ubCnt< 3; ubCnt++)
{
//see if the merc has a buddy on the team
bBuddyID = gMercProfiles[ ubMercID ].bBuddy[ubCnt];
//If its not a valid 'buddy'
if( bBuddyID < 0 )
continue;
if( IsMercOnTeam( bBuddyID ) )
{
if( !IsMercDead( bBuddyID ) )
{
return( TRUE );
}
}
}
return( FALSE );
}
BOOLEAN MercIsHot( SOLDIERTYPE * pSoldier )
{
if ( pSoldier->ubProfile != NO_PROFILE && gMercProfiles[ pSoldier->ubProfile ].bPersonalityTrait == HEAT_INTOLERANT )
{
if ( SectorTemperature( GetWorldMinutesInDay(), pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ ) > 0 )
{
return( TRUE );
}
}
return( FALSE );
}
SOLDIERTYPE * SwapLarrysProfiles( SOLDIERTYPE * pSoldier )
{
UINT8 ubSrcProfile;
UINT8 ubDestProfile;
MERCPROFILESTRUCT * pNewProfile;
ubSrcProfile = pSoldier->ubProfile;
if ( ubSrcProfile == LARRY_NORMAL)
{
ubDestProfile = LARRY_DRUNK;
}
else if ( ubSrcProfile == LARRY_DRUNK )
{
ubDestProfile = LARRY_NORMAL;
}
else
{
// I don't think so!
return( pSoldier );
}
pNewProfile = &gMercProfiles[ ubDestProfile ];
pNewProfile->ubMiscFlags2 = gMercProfiles[ ubSrcProfile ].ubMiscFlags2;
pNewProfile->ubMiscFlags = gMercProfiles[ ubSrcProfile ].ubMiscFlags;
pNewProfile->sSectorX = gMercProfiles[ ubSrcProfile ].sSectorX;
pNewProfile->sSectorY = gMercProfiles[ ubSrcProfile ].sSectorY;
pNewProfile->uiDayBecomesAvailable = gMercProfiles[ ubSrcProfile ].uiDayBecomesAvailable;
pNewProfile->usKills = gMercProfiles[ ubSrcProfile ].usKills;
pNewProfile->usAssists = gMercProfiles[ ubSrcProfile ].usAssists;
pNewProfile->usShotsFired = gMercProfiles[ ubSrcProfile ].usShotsFired;
pNewProfile->usShotsHit = gMercProfiles[ ubSrcProfile ].usShotsHit;
pNewProfile->usBattlesFought = gMercProfiles[ ubSrcProfile ].usBattlesFought;
pNewProfile->usTimesWounded = gMercProfiles[ ubSrcProfile ].usTimesWounded;
pNewProfile->usTotalDaysServed = gMercProfiles[ ubSrcProfile ].usTotalDaysServed;
pNewProfile->bResigned = gMercProfiles[ ubSrcProfile ].bResigned;
pNewProfile->bActive = gMercProfiles[ ubSrcProfile ].bActive;
pNewProfile->fUseProfileInsertionInfo = gMercProfiles[ ubSrcProfile ].fUseProfileInsertionInfo;
pNewProfile->sGridNo = gMercProfiles[ ubSrcProfile ].sGridNo;
pNewProfile->ubQuoteActionID = gMercProfiles[ ubSrcProfile ].ubQuoteActionID;
pNewProfile->ubLastQuoteSaid = gMercProfiles[ ubSrcProfile ].ubLastQuoteSaid;
pNewProfile->ubStrategicInsertionCode = gMercProfiles[ ubSrcProfile ].ubStrategicInsertionCode;
pNewProfile->bMercStatus = gMercProfiles[ ubSrcProfile ].bMercStatus;
pNewProfile->bSectorZ = gMercProfiles[ ubSrcProfile ].bSectorZ;
pNewProfile->usStrategicInsertionData = gMercProfiles[ ubSrcProfile ].usStrategicInsertionData;
pNewProfile->sTrueSalary = gMercProfiles[ ubSrcProfile ].sTrueSalary;
pNewProfile->ubMiscFlags3 = gMercProfiles[ ubSrcProfile ].ubMiscFlags3;
pNewProfile->ubDaysOfMoraleHangover = gMercProfiles[ ubSrcProfile ].ubDaysOfMoraleHangover;
pNewProfile->ubNumTimesDrugUseInLifetime = gMercProfiles[ ubSrcProfile ].ubNumTimesDrugUseInLifetime;
pNewProfile->uiPrecedentQuoteSaid = gMercProfiles[ ubSrcProfile ].uiPrecedentQuoteSaid;
pNewProfile->sPreCombatGridNo = gMercProfiles[ ubSrcProfile ].sPreCombatGridNo;
// CJC: this is causing problems so just skip the transfer of exp...
/*
pNewProfile->sLifeGain = gMercProfiles[ ubSrcProfile ].sLifeGain;
pNewProfile->sAgilityGain = gMercProfiles[ ubSrcProfile ].sAgilityGain;
pNewProfile->sDexterityGain = gMercProfiles[ ubSrcProfile ].sDexterityGain;
pNewProfile->sStrengthGain = gMercProfiles[ ubSrcProfile ].sStrengthGain;
pNewProfile->sLeadershipGain = gMercProfiles[ ubSrcProfile ].sLeadershipGain;
pNewProfile->sWisdomGain = gMercProfiles[ ubSrcProfile ].sWisdomGain;
pNewProfile->sExpLevelGain = gMercProfiles[ ubSrcProfile ].sExpLevelGain;
pNewProfile->sMarksmanshipGain = gMercProfiles[ ubSrcProfile ].sMarksmanshipGain;
pNewProfile->sMedicalGain = gMercProfiles[ ubSrcProfile ].sMedicalGain;
pNewProfile->sMechanicGain = gMercProfiles[ ubSrcProfile ].sMechanicGain;
pNewProfile->sExplosivesGain = gMercProfiles[ ubSrcProfile ].sExplosivesGain;
pNewProfile->bLifeDelta = gMercProfiles[ ubSrcProfile ].bLifeDelta;
pNewProfile->bAgilityDelta = gMercProfiles[ ubSrcProfile ].bAgilityDelta;
pNewProfile->bDexterityDelta = gMercProfiles[ ubSrcProfile ].bDexterityDelta;
pNewProfile->bStrengthDelta = gMercProfiles[ ubSrcProfile ].bStrengthDelta;
pNewProfile->bLeadershipDelta = gMercProfiles[ ubSrcProfile ].bLeadershipDelta;
pNewProfile->bWisdomDelta = gMercProfiles[ ubSrcProfile ].bWisdomDelta;
pNewProfile->bExpLevelDelta = gMercProfiles[ ubSrcProfile ].bExpLevelDelta;
pNewProfile->bMarksmanshipDelta = gMercProfiles[ ubSrcProfile ].bMarksmanshipDelta;
pNewProfile->bMedicalDelta = gMercProfiles[ ubSrcProfile ].bMedicalDelta;
pNewProfile->bMechanicDelta = gMercProfiles[ ubSrcProfile ].bMechanicDelta;
pNewProfile->bExplosivesDelta = gMercProfiles[ ubSrcProfile ].bExplosivesDelta;
*/
memcpy( pNewProfile->bInvStatus, gMercProfiles[ ubSrcProfile ].bInvStatus , sizeof( UINT8) * 19 );
memcpy( pNewProfile->bInvStatus, gMercProfiles[ ubSrcProfile ].bInvStatus , sizeof( UINT8) * 19 );
memcpy( pNewProfile->inv , gMercProfiles[ ubSrcProfile ].inv , sizeof( UINT16 ) * 19 );
memcpy( pNewProfile->bMercTownReputation , gMercProfiles[ ubSrcProfile ].bMercTownReputation , sizeof( UINT8 ) * 20 );
// remove face
DeleteSoldierFace( pSoldier );
pSoldier->ubProfile = ubDestProfile;
// create new face
pSoldier->iFaceIndex = InitSoldierFace( pSoldier );
// replace profile in group
ReplaceSoldierProfileInPlayerGroup( pSoldier->ubGroupID, ubSrcProfile, ubDestProfile );
pSoldier->bStrength = pNewProfile->bStrength + pNewProfile->bStrengthDelta;
pSoldier->bDexterity = pNewProfile->bDexterity + pNewProfile->bDexterityDelta;
pSoldier->bAgility = pNewProfile->bAgility + pNewProfile->bAgilityDelta;
pSoldier->bWisdom = pNewProfile->bWisdom + pNewProfile->bWisdomDelta;
pSoldier->bExpLevel = pNewProfile->bExpLevel + pNewProfile->bExpLevelDelta;
pSoldier->bLeadership = pNewProfile->bLeadership + pNewProfile->bLeadershipDelta;
pSoldier->bMarksmanship = pNewProfile->bMarksmanship + pNewProfile->bMarksmanshipDelta;
pSoldier->bMechanical = pNewProfile->bMechanical + pNewProfile->bMechanicDelta;
pSoldier->bMedical = pNewProfile->bMedical + pNewProfile->bMedicalDelta;
pSoldier->bExplosive = pNewProfile->bExplosive + pNewProfile->bExplosivesDelta;
if ( pSoldier->ubProfile == LARRY_DRUNK )
{
SetFactTrue( FACT_LARRY_CHANGED );
}
else
{
SetFactFalse( FACT_LARRY_CHANGED );
}
DirtyMercPanelInterface( pSoldier, DIRTYLEVEL2 );
return( pSoldier );
}
BOOLEAN DoesNPCOwnBuilding( SOLDIERTYPE *pSoldier, INT16 sGridNo )
{
UINT8 ubRoomInfo;
// Get room info
ubRoomInfo = gubWorldRoomInfo[ sGridNo ];
if ( ubRoomInfo == NO_ROOM )
{
return( FALSE );
}
// Are we an NPC?
if ( pSoldier->bTeam != CIV_TEAM )
{
return( FALSE );
}
// OK, check both ranges
if ( ubRoomInfo >= gMercProfiles[ pSoldier->ubProfile ].ubRoomRangeStart[ 0 ] &&
ubRoomInfo <= gMercProfiles[ pSoldier->ubProfile ].ubRoomRangeEnd[ 0 ] )
{
return( TRUE );
}
if ( ubRoomInfo >= gMercProfiles[ pSoldier->ubProfile ].ubRoomRangeStart[ 1 ] &&
ubRoomInfo <= gMercProfiles[ pSoldier->ubProfile ].ubRoomRangeEnd[ 1 ] )
{
return( TRUE );
}
return( FALSE );
}
BOOLEAN IsProfileIdAnAimOrMERCMerc( UINT8 ubProfileID )
{
if( ubProfileID < BIFF ||
( ubProfileID >= BIFF && ubProfileID <= BUBBA ) ||
ubProfileID >= GASTON )
{
return( TRUE );
}
return( FALSE );
}