mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@2498 3b4a5df2-a311-0410-b5c6-a8a6f20db521
1658 lines
47 KiB
C++
1658 lines
47 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 "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"
|
|
#include "interface utils.h"
|
|
#include "Game Event Hook.h"
|
|
#include "Map Information.h"
|
|
#include "history.h"
|
|
#include "personnel.h"
|
|
#include "environment.h"
|
|
#include "Player Command.h"
|
|
#include "strategic.h"
|
|
#endif
|
|
|
|
#include "connect.h"
|
|
#ifdef JA2EDITOR
|
|
extern BOOLEAN gfProfileDataLoaded;
|
|
#endif
|
|
|
|
//forward declarations of common classes to eliminate includes
|
|
class OBJECTTYPE;
|
|
class SOLDIERTYPE;
|
|
|
|
|
|
|
|
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 ];
|
|
MERCPROFILEGEAR gMercProfileGear[ NUM_PROFILES ];
|
|
|
|
extern UINT8 gubItemDroppableFlag[NUM_INV_SLOTS];
|
|
|
|
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
|
|
5, //PROF_SNIPER
|
|
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;
|
|
STR8 pFileName = "BINARYDATA\\Prof.dat";
|
|
|
|
STR8 pFileName1_Normal = "BINARYDATA\\Prof_Novice_NormalGuns.dat";
|
|
STR8 pFileName2_Normal = "BINARYDATA\\Prof_Experienced_NormalGuns.dat";
|
|
STR8 pFileName3_Normal = "BINARYDATA\\Prof_Expert_NormalGuns.dat";
|
|
STR8 pFileName4_Normal = "BINARYDATA\\Prof_Insane_NormalGuns.dat";
|
|
|
|
STR8 pFileName1_Tons = "BINARYDATA\\Prof_Novice_TonsOfGuns.dat";
|
|
STR8 pFileName2_Tons = "BINARYDATA\\Prof_Experienced_TonsOfGuns.dat";
|
|
STR8 pFileName3_Tons = "BINARYDATA\\Prof_Expert_TonsOfGuns.dat";
|
|
STR8 pFileName4_Tons = "BINARYDATA\\Prof_Insane_TonsOfGuns.dat";
|
|
|
|
UINT32 uiLoop, uiLoop2;//, uiLoop3;
|
|
UINT16 usItem;//, usNewGun, usAmmo, usNewAmmo;
|
|
|
|
if (gGameExternalOptions.fAlwaysUseProfDat == FALSE)
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fptr = FileOpen(pFileName, FILE_ACCESS_READ, FALSE );
|
|
}
|
|
|
|
|
|
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++)
|
|
{
|
|
// Changed by ADB, rev 1513
|
|
//if( !gMercProfiles[uiLoop].Load(fptr, true))
|
|
if( !gMercProfiles[uiLoop].Load(fptr, true, true, true))
|
|
{
|
|
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("FAILED to Read Merc Profiles from File %d %s",uiLoop, pFileName) );
|
|
FileClose( fptr );
|
|
return(FALSE);
|
|
}
|
|
|
|
/* CHRISL: For now, we should only overwrite prof.dat in the new inventory system. Old system should still use
|
|
prof.dat until we're sure we want to replace it with the xml file.*/
|
|
if(UsingNewInventorySystem() == true){
|
|
// Start by resetting all profile inventory values to 0
|
|
gMercProfiles[uiLoop].clearInventory();
|
|
gMercProfiles[uiLoop].ubInvUndroppable = 0;
|
|
// Next, go through and assign everything but lbe gear
|
|
for(uiLoop2=INV_START_POS; uiLoop2<NUM_INV_SLOTS; uiLoop2++)
|
|
{
|
|
if(gMercProfileGear[uiLoop].inv[uiLoop2] != NONE)
|
|
{
|
|
gMercProfiles[uiLoop].inv[uiLoop2] = gMercProfileGear[uiLoop].inv[uiLoop2];
|
|
gMercProfiles[uiLoop].bInvStatus[uiLoop2] = gMercProfileGear[uiLoop].iStatus[uiLoop2];
|
|
if(uiLoop2 > 5)
|
|
gMercProfiles[uiLoop].bInvNumber[uiLoop2] = gMercProfileGear[uiLoop].iNumber[uiLoop2];
|
|
else
|
|
gMercProfiles[uiLoop].bInvNumber[uiLoop2] = 1;
|
|
}
|
|
//CHRISL: Moved outside first condition we we set ubInvUndroppable regardless of having an item
|
|
if(gMercProfileGear[uiLoop].iDrop[uiLoop2] == 0 && uiLoop > 56){
|
|
gMercProfiles[uiLoop].ubInvUndroppable |= gubItemDroppableFlag[uiLoop2];
|
|
}
|
|
}
|
|
// Last, go through and assign LBE items. Only needed for new inventory system
|
|
if((UsingNewInventorySystem() == true))
|
|
{
|
|
for(uiLoop2=0; uiLoop2<5; uiLoop2++)
|
|
{
|
|
UINT32 uiLoop3 = uiLoop2 + VESTPOCKPOS;
|
|
if(gMercProfileGear[uiLoop].lbe[uiLoop2] != NONE){
|
|
gMercProfiles[uiLoop].inv[uiLoop3] = gMercProfileGear[uiLoop].lbe[uiLoop2];
|
|
gMercProfiles[uiLoop].bInvStatus[uiLoop3] = gMercProfileGear[uiLoop].lStatus[uiLoop2];
|
|
gMercProfiles[uiLoop].bInvNumber[uiLoop3] = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//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 < gMercProfiles[uiLoop].inv.size(); 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 < gMercProfiles[ uiLoop ].inv.size(); 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 < gMercProfiles[uiLoop].inv.size(); 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< gMercProfiles[ uiLoop ].inv.size(); 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
|
|
if(!is_networked)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;
|
|
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;
|
|
}
|
|
|
|
CreateItem(usNewItem, 100, &gTempObject);
|
|
|
|
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 ], &gTempObject );
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
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;
|
|
}
|
|
|
|
CreateItem(usNewItem, 100, &gTempObject);
|
|
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 ], &gTempObject );
|
|
}
|
|
}
|
|
}
|
|
|
|
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((double)pProfile->bMarksmanship, 3) / 10000)) +
|
|
1.5 * (pow((double)pProfile->bMedical, 3) / 10000) +
|
|
(pow((double)pProfile->bMechanical, 3) / 10000) +
|
|
(pow((double)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;
|
|
|
|
BOOLEAN success;
|
|
|
|
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!
|
|
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.ubDirection = pSoldier->ubDirection;
|
|
|
|
if ( pSoldier->flags.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->stats.bLife = pSoldier->stats.bLife;
|
|
pNewSoldier->stats.bLifeMax = pSoldier->stats.bLifeMax;
|
|
pNewSoldier->stats.bAgility = pSoldier->stats.bAgility;
|
|
pNewSoldier->stats.bLeadership = pSoldier->stats.bLeadership;
|
|
pNewSoldier->stats.bDexterity = pSoldier->stats.bDexterity;
|
|
pNewSoldier->stats.bStrength = pSoldier->stats.bStrength;
|
|
pNewSoldier->stats.bWisdom = pSoldier->stats.bWisdom;
|
|
pNewSoldier->stats.bExpLevel = pSoldier->stats.bExpLevel;
|
|
pNewSoldier->stats.bMarksmanship = pSoldier->stats.bMarksmanship;
|
|
pNewSoldier->stats.bMedical = pSoldier->stats.bMedical;
|
|
pNewSoldier->stats.bMechanical = pSoldier->stats.bMechanical;
|
|
pNewSoldier->stats.bExplosive = pSoldier->stats.bExplosive;
|
|
pNewSoldier->stats.bScientific = pSoldier->stats.bScientific;
|
|
pNewSoldier->bLastRenderVisibleValue = pSoldier->bLastRenderVisibleValue;
|
|
pNewSoldier->bVisible = pSoldier->bVisible;
|
|
// 0verhaul: Need to pass certain flags over. COWERING is one of them. Others to be determined.
|
|
|
|
// copy uiStatusFlags, etc. - hayden :)
|
|
if (is_networked)
|
|
{
|
|
pNewSoldier->flags.uiStatusFlags = pSoldier->flags.uiStatusFlags;
|
|
pNewSoldier->ubProfile = pSoldier->ubProfile;
|
|
}
|
|
else
|
|
{
|
|
pNewSoldier->flags.uiStatusFlags |= pSoldier->flags.uiStatusFlags & (SOLDIER_COWERING | SOLDIER_MUTE | SOLDIER_GASSED);
|
|
}
|
|
|
|
|
|
if ( ubTeam == gbPlayerNum )
|
|
{
|
|
pNewSoldier->bVisible= 1;
|
|
}
|
|
|
|
//CHRISL: Rather then resorting the profile, which recreates all the items, what if we simply try and sort the
|
|
// objects that are already attached to the RPC we're hiring?
|
|
//if(UsingNewInventorySystem() == true)
|
|
{
|
|
// Start by direct copy of all BODYPOS items (armor, hands, head and LBE)
|
|
for(cnt = 0; cnt < (UINT32)BODYPOSFINAL; cnt++)
|
|
{
|
|
pNewSoldier->inv[cnt] = pSoldier->inv[cnt];
|
|
}
|
|
// Next, direct copy of the gunsling and knife pockets
|
|
pNewSoldier->inv[GUNSLINGPOCKPOS] = pSoldier->inv[GUNSLINGPOCKPOS];
|
|
pNewSoldier->inv[KNIFEPOCKPOS] = pSoldier->inv[KNIFEPOCKPOS];
|
|
// Then, try to autoplace everything else
|
|
for(cnt = BIGPOCKSTART; cnt < pNewSoldier->inv.size(); cnt++ )
|
|
{
|
|
if(pSoldier->inv[cnt].exists() == true)
|
|
{
|
|
success = PlaceInAnyPocket(pNewSoldier, &pSoldier->inv[cnt], FALSE);
|
|
if(!success)
|
|
{
|
|
PlaceObject( pNewSoldier, 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 );
|
|
|
|
if (!pNewSoldier)
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if ( ubCharNum == SLAY )
|
|
{
|
|
if(gGameExternalOptions.fEnableSlayForever == TRUE)
|
|
{
|
|
if(gMercProfiles[ ubCharNum ].sSalary == 0)
|
|
gMercProfiles[ ubCharNum ].sSalary = gMercProfiles[ 7 ].sSalary;
|
|
if(gMercProfiles[ ubCharNum ].uiWeeklySalary == 0)
|
|
gMercProfiles[ ubCharNum ].uiWeeklySalary = gMercProfiles[ 7 ].uiWeeklySalary;
|
|
if(gMercProfiles[ ubCharNum ].uiBiWeeklySalary == 0)
|
|
gMercProfiles[ ubCharNum ].uiBiWeeklySalary = gMercProfiles[ 7 ].uiBiWeeklySalary;
|
|
pNewSoldier->iTotalContractLength = 7;
|
|
}
|
|
// 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 ].exists() == false )
|
|
{
|
|
// 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 ].exists() == true )
|
|
{
|
|
// need to move second hand item out first
|
|
AutoPlaceObject( pNewSoldier, &(pNewSoldier->inv[ SECONDHANDPOS ]), FALSE );
|
|
}
|
|
}
|
|
// swap item to hand
|
|
SwapObjs( pNewSoldier, bSlot, HANDPOS, TRUE );
|
|
}
|
|
}
|
|
|
|
if ( ubCharNum == IRA )
|
|
{
|
|
// trigger 0th PCscript line
|
|
TriggerNPCRecord( IRA, 0 );
|
|
}
|
|
|
|
// Set whatkind of merc am i
|
|
pNewSoldier->ubWhatKindOfMercAmI = MERC_TYPE__NPC;
|
|
|
|
if ( ubCharNum == SLAY && gGameExternalOptions.fEnableSlayForever == TRUE )
|
|
{
|
|
pNewSoldier->ubWhatKindOfMercAmI = MERC_TYPE__AIM_MERC;
|
|
}
|
|
|
|
//
|
|
//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->flags.uiStatusFlags & SOLDIER_ROBOT )
|
|
{
|
|
pNewSoldier->UpdateRobotControllerGivenRobot( );
|
|
}
|
|
|
|
// 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 ].ubMiscFlags3 |= PROFILE_MISC_FLAG3_PERMANENT_INSERTION_CODE;
|
|
gMercProfiles[ ubCharNum ].usStrategicInsertionData = pSoldier->sGridNo;
|
|
gMercProfiles[ ubCharNum ].fUseProfileInsertionInfo = TRUE;
|
|
gMercProfiles[ ubCharNum ].ubStrategicInsertionCode = INSERTION_CODE_GRIDNO;
|
|
|
|
// 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->stats.bLife;
|
|
pProfile->bLifeMax = pSoldier->stats.bLifeMax;
|
|
pProfile->bAgility = pSoldier->stats.bAgility;
|
|
pProfile->bLeadership = pSoldier->stats.bLeadership;
|
|
pProfile->bDexterity = pSoldier->stats.bDexterity;
|
|
pProfile->bStrength = pSoldier->stats.bStrength;
|
|
pProfile->bWisdom = pSoldier->stats.bWisdom;
|
|
pProfile->bExpLevel = pSoldier->stats.bExpLevel;
|
|
pProfile->bMarksmanship = pSoldier->stats.bMarksmanship;
|
|
pProfile->bMedical = pSoldier->stats.bMedical;
|
|
pProfile->bMechanical = pSoldier->stats.bMechanical;
|
|
pProfile->bExplosive = pSoldier->stats.bExplosive;
|
|
pProfile->bScientific = pSoldier->stats.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;
|
|
*/
|
|
|
|
pNewProfile->bInvStatus = gMercProfiles[ ubSrcProfile ].bInvStatus;
|
|
pNewProfile->bInvNumber = gMercProfiles[ ubSrcProfile ].bInvNumber;
|
|
pNewProfile->inv = gMercProfiles[ ubSrcProfile ].inv;
|
|
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->stats.bStrength = pNewProfile->bStrength + pNewProfile->bStrengthDelta;
|
|
pSoldier->stats.bDexterity = pNewProfile->bDexterity + pNewProfile->bDexterityDelta;
|
|
pSoldier->stats.bAgility = pNewProfile->bAgility + pNewProfile->bAgilityDelta;
|
|
pSoldier->stats.bWisdom = pNewProfile->bWisdom + pNewProfile->bWisdomDelta;
|
|
pSoldier->stats.bExpLevel = pNewProfile->bExpLevel + pNewProfile->bExpLevelDelta;
|
|
pSoldier->stats.bLeadership = pNewProfile->bLeadership + pNewProfile->bLeadershipDelta;
|
|
|
|
pSoldier->stats.bMarksmanship = pNewProfile->bMarksmanship + pNewProfile->bMarksmanshipDelta;
|
|
pSoldier->stats.bMechanical = pNewProfile->bMechanical + pNewProfile->bMechanicDelta;
|
|
pSoldier->stats.bMedical = pNewProfile->bMedical + pNewProfile->bMedicalDelta;
|
|
pSoldier->stats.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 );
|
|
}
|