#ifdef PRECOMPILEDHEADERS #include "Tactical All.h" #else #include #include #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; 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++) { // 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 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 ( 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 ); }