From 060a09ead0a5939a4b3cfefb834203b681fb209d Mon Sep 17 00:00:00 2001 From: SpaceViking Date: Mon, 26 Mar 2007 01:47:14 +0000 Subject: [PATCH] Code changes to allow more slots for IMPs. Allow dead IMPs to be replaced. Add another way to progress in the game (sectors visited). git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@798 3b4a5df2-a311-0410-b5c6-a8a6f20db521 --- GameSettings.cpp | 67 ++++++- GameSettings.h | 12 +- Laptop/CharProfile.cpp | 6 +- Laptop/IMP Begin Screen.cpp | 39 ++-- Laptop/IMP Compile Character.cpp | 72 +++---- Laptop/IMP Confirm.cpp | 19 +- Laptop/IMP Finish.cpp | 19 +- Laptop/IMP HomePage.cpp | 10 +- Laptop/IMP MainPage.cpp | 310 +++++++++++++++++++++++++------ Laptop/IMP MainPage.h | 28 ++- Laptop/IMP Voices.cpp | 163 +++++----------- Laptop/IMP Voices.h | 2 - Laptop/LaptopSave.h | 2 +- Strategic/Merc Contract.cpp | 7 + Utils/INIReader.cpp | 15 ++ Utils/INIReader.h | 1 + Utils/_EnglishText.cpp | 4 +- 17 files changed, 525 insertions(+), 251 deletions(-) diff --git a/GameSettings.cpp b/GameSettings.cpp index 2302deff..55a44ff8 100644 --- a/GameSettings.cpp +++ b/GameSettings.cpp @@ -295,6 +295,16 @@ void InitGameOptions() #define PROGRESS_PORTION_INCOME 50 +// The following are for fixing problems when reading the .ini file +#define COUNT_STANDARD_MALE_SLOTS 3 +#define FIRST_STANDARD_MALE_SLOT 51 +#define COUNT_STANDARD_FEMALE_SLOTS 3 +#define FIRST_STANDARD_FEMALE_SLOT 54 + + +extern INT32 CountFilledIMPSlots( INT8 iSex ); +extern INT32 CountEmptyIMPSlots( INT8 iSex ); + // Snap: Read options from an INI file in the default of custom Data directory void LoadGameExternalOptions() { @@ -304,9 +314,60 @@ void LoadGameExternalOptions() //################# Laptop Settings ################# - // WANNE: Maximum number of imp characters (0 to 6) + // WDS: Allow flexible numbers of IMPs of each sex gGameExternalOptions.iMaxIMPCharacters = iniReader.ReadInteger("JA2 Laptop Settings","MAX_IMP_CHARACTERS",1); + gGameExternalOptions.iIMPMaleCharacterCount = iniReader.ReadInteger("JA2 Laptop Settings","IMP_MALE_CHARACTER_COUNT", COUNT_STANDARD_MALE_SLOTS, 1, NUM_PROFILES); + gGameExternalOptions.iIMPFemaleCharacterCount = iniReader.ReadInteger("JA2 Laptop Settings","IMP_FEMALE_CHARACTER_COUNT", COUNT_STANDARD_FEMALE_SLOTS, 1, NUM_PROFILES); + if (gGameExternalOptions.iIMPMaleCharacterCount + gGameExternalOptions.iIMPFemaleCharacterCount > NUM_PROFILES) + { + gGameExternalOptions.iIMPMaleCharacterCount = COUNT_STANDARD_MALE_SLOTS; + gGameExternalOptions.iIMPFemaleCharacterCount = COUNT_STANDARD_FEMALE_SLOTS; + } + + // + // Note: put -1 between male/female slots and -1 at end. This allows everything to be + // counted dynamically quite easily. Note that all the code assumes there is AT + // LEAST ONE slot for each sex. If that changes the code will have to be updated. + // + // Because errors in these values can really goof things up we will try to fix up bad + // values and use the defaults instead. + // + int idx; + char caMaleCountStr [] = "IMP_MALE_%d"; + char caFemaleCountStr [] = "IMP_FEMALE_%d"; + char caCountStr[20]; + + gGameExternalOptions.iaIMPSlots = (UINT32*)MemAlloc( (gGameExternalOptions.iIMPMaleCharacterCount + gGameExternalOptions.iIMPFemaleCharacterCount + 2) * sizeof( UINT32 ) ); + for (idx = 0; idx < gGameExternalOptions.iIMPMaleCharacterCount; ++idx) + { + sprintf( caCountStr, caMaleCountStr, idx+1); + gGameExternalOptions.iaIMPSlots[idx] = iniReader.ReadInteger("JA2 Laptop Settings",caCountStr, -1, -1, NUM_PROFILES-1); + if (gGameExternalOptions.iaIMPSlots[idx] < 0) + { + if (idx < COUNT_STANDARD_MALE_SLOTS) + gGameExternalOptions.iaIMPSlots[idx] = FIRST_STANDARD_MALE_SLOT+idx; + else + // This is bad so just use the last standard slot # + gGameExternalOptions.iaIMPSlots[idx] = FIRST_STANDARD_MALE_SLOT+COUNT_STANDARD_MALE_SLOTS-1; + } + } + gGameExternalOptions.iaIMPSlots[gGameExternalOptions.iIMPMaleCharacterCount] = -1; + for (idx = 0; idx < gGameExternalOptions.iIMPFemaleCharacterCount; ++idx) + { + sprintf( caCountStr, caFemaleCountStr, idx+1); + gGameExternalOptions.iaIMPSlots[idx+gGameExternalOptions.iIMPMaleCharacterCount+1] = iniReader.ReadInteger("JA2 Laptop Settings",caCountStr, -1, -1, NUM_PROFILES-1); + if (gGameExternalOptions.iaIMPSlots[idx] < 0) + { + if (idx < COUNT_STANDARD_FEMALE_SLOTS) + gGameExternalOptions.iaIMPSlots[idx] = FIRST_STANDARD_FEMALE_SLOT+idx; + else + // This is bad so just use the last standard slot # + gGameExternalOptions.iaIMPSlots[idx] = FIRST_STANDARD_FEMALE_SLOT+COUNT_STANDARD_FEMALE_SLOTS-1; + } + } + gGameExternalOptions.iaIMPSlots[gGameExternalOptions.iIMPFemaleCharacterCount+gGameExternalOptions.iIMPMaleCharacterCount+1] = -1; + //Character generation gGameExternalOptions.iMinAttribute = iniReader.ReadInteger("JA2 Laptop Settings","MIN_ATTRIBUTE_POINT",35); gGameExternalOptions.iMaxAttribute = iniReader.ReadInteger("JA2 Laptop Settings","MAX_ATTRIBUTE_POINT",90); @@ -411,13 +472,15 @@ void LoadGameExternalOptions() gGameExternalOptions.ubGameProgressPortionKills = iniReader.ReadInteger("JA2 Gameplay Settings","GAME_PROGRESS_KILLS",25); gGameExternalOptions.ubGameProgressPortionControl = iniReader.ReadInteger("JA2 Gameplay Settings","GAME_PROGRESS_CONTROL",25); gGameExternalOptions.ubGameProgressPortionIncome = iniReader.ReadInteger("JA2 Gameplay Settings","GAME_PROGRESS_INCOME",50); + gGameExternalOptions.ubGameProgressPortionVisited = iniReader.ReadInteger("JA2 Gameplay Settings","GAME_PROGRESS_VISITED",0); // Any way to warn on this? - if (gGameExternalOptions.ubGameProgressPortionKills + gGameExternalOptions.ubGameProgressPortionControl + gGameExternalOptions.ubGameProgressPortionIncome != 100) + if (gGameExternalOptions.ubGameProgressPortionKills + gGameExternalOptions.ubGameProgressPortionControl + gGameExternalOptions.ubGameProgressPortionIncome + gGameExternalOptions.ubGameProgressPortionVisited != 100) { gGameExternalOptions.ubGameProgressPortionKills = 25; gGameExternalOptions.ubGameProgressPortionControl = 25; gGameExternalOptions.ubGameProgressPortionIncome = 50; + gGameExternalOptions.ubGameProgressPortionVisited = 0; } //Global game events diff --git a/GameSettings.h b/GameSettings.h index 53c9dd22..8d998d76 100644 --- a/GameSettings.h +++ b/GameSettings.h @@ -146,8 +146,15 @@ typedef struct BOOLEAN fSellAll; INT16 iPriceModifier; - INT32 iMaxIMPMaleCharacters; - INT32 iMaxIMPCharacters; + // WDS: Allow flexible numbers of IMPs of each sex + INT32 iIMPMaleCharacterCount; // Count of how many there are + INT32 iIMPFemaleCharacterCount; + INT32 iMaxIMPCharacters; // Limit of how many to allow + // + // iaIMPSlots is an array of the slots (in prof.dat) to use for IMPs. + // + UINT32 *iaIMPSlots; + INT32 iMinAttribute; INT32 iMaxAttribute; INT32 iImpAttributePoints; @@ -264,6 +271,7 @@ typedef struct UINT32 ubGameProgressPortionKills; UINT32 ubGameProgressPortionControl; UINT32 ubGameProgressPortionIncome; + UINT32 ubGameProgressPortionVisited; // Event settings diff --git a/Laptop/CharProfile.cpp b/Laptop/CharProfile.cpp index b4ff8167..173f698a 100644 --- a/Laptop/CharProfile.cpp +++ b/Laptop/CharProfile.cpp @@ -90,7 +90,7 @@ INT32 giIMPButtonImage[1]; // visted subpages BOOLEAN fVisitedIMPSubPages[ IMP_NUM_PAGES ]; extern INT32 iCurrentPortrait; -extern INT32 iCurrentVoices; +extern INT32 iCurrentVoice; extern INT32 giMaxPersonalityQuizQuestion; extern BOOLEAN fStartOverFlag; @@ -107,9 +107,9 @@ extern void SetAttributes( void ); void GameInitCharProfile() { - LaptopSaveInfo.iVoiceId = 0; + LaptopSaveInfo.iIMPIndex = 0; iCurrentPortrait = 0; - iCurrentVoices = 0; +// iCurrentVoice = 0; iPortraitNumber = 0; return; diff --git a/Laptop/IMP Begin Screen.cpp b/Laptop/IMP Begin Screen.cpp index 3f673612..3be3a475 100644 --- a/Laptop/IMP Begin Screen.cpp +++ b/Laptop/IMP Begin Screen.cpp @@ -332,6 +332,7 @@ void RemoveIMPBeginScreenButtons( void ) } + void BtnIMPBeginScreenDoneCallback(GUI_BUTTON *btn,INT32 reason) { @@ -371,6 +372,7 @@ void BtnIMPBeginScreenDoneCallback(GUI_BUTTON *btn,INT32 reason) } */ + // WDS: Allow flexible numbers of IMPs of each sex if (bProceed == TRUE) { // check to see if a name has been selected, if not, do not allow player to proceed with more char generation @@ -378,18 +380,18 @@ void BtnIMPBeginScreenDoneCallback(GUI_BUTTON *btn,INT32 reason) { if (bGenderFlag == IMP_MALE) { - if (GetFilledIMPSlots(MALE) >= 3) + if (CountEmptyIMPSlots(MALE) == 0) { - // You cannot have more than 3 I.M.P characters with the same gender on your team. + // You cannot have more than the male max I.M.P characters on your team. DoLapTopMessageBox( MSG_BOX_IMP_STYLE, pImpPopUpStrings[ 9 ], LAPTOP_SCREEN, MSG_BOX_FLAG_OK, NULL); bProceed = FALSE; } } else if (bGenderFlag == IMP_FEMALE) { - if (GetFilledIMPSlots(FEMALE) >= 3) + if (CountEmptyIMPSlots(FEMALE) == 0) { - // You cannot have more than 3 I.M.P characters with the same gender on your team. + // You cannot have more than the female max I.M.P characters on your team. DoLapTopMessageBox( MSG_BOX_IMP_STYLE, pImpPopUpStrings[ 9 ], LAPTOP_SCREEN, MSG_BOX_FLAG_OK, NULL); bProceed = FALSE; } @@ -1313,7 +1315,8 @@ BOOLEAN CheckCharacterInputForEgg( void ) iPersonality = NO_PERSONALITYTRAIT; iAttitude = ATT_ASSHOLE; iCurrentImpPage = IMP_FINISH; - LaptopSaveInfo.iVoiceId = 1; + LaptopSaveInfo.iCurrentVoice = 1; + LaptopSaveInfo.iCharIndex = 1; iPortraitNumber = 2; return TRUE; } @@ -1337,7 +1340,8 @@ BOOLEAN CheckCharacterInputForEgg( void ) iPersonality = NO_PERSONALITYTRAIT; iAttitude = ATT_FRIENDLY; iCurrentImpPage = IMP_FINISH; - LaptopSaveInfo.iVoiceId = 1; + LaptopSaveInfo.iCurrentVoice = 1; + LaptopSaveInfo.iCharIndex = 1; iPortraitNumber = 1; return TRUE; } @@ -1361,7 +1365,8 @@ BOOLEAN CheckCharacterInputForEgg( void ) iPersonality = NO_PERSONALITYTRAIT; iAttitude = ATT_FRIENDLY; iCurrentImpPage = IMP_FINISH; - LaptopSaveInfo.iVoiceId = 2; + LaptopSaveInfo.iCurrentVoice = 2; + LaptopSaveInfo.iCharIndex = 2; iPortraitNumber = 1; return TRUE; } @@ -1388,7 +1393,8 @@ BOOLEAN CheckCharacterInputForEgg( void ) iPersonality = NO_PERSONALITYTRAIT; iAttitude = ATT_AGGRESSIVE; iCurrentImpPage = IMP_FINISH; - LaptopSaveInfo.iVoiceId = 1; + LaptopSaveInfo.iCurrentVoice = 1; + LaptopSaveInfo.iCharIndex = 1; iPortraitNumber = 4; return TRUE; } @@ -1415,7 +1421,8 @@ BOOLEAN CheckCharacterInputForEgg( void ) iPersonality = NO_PERSONALITYTRAIT; iAttitude = ATT_ARROGANT; iCurrentImpPage = IMP_FINISH; - LaptopSaveInfo.iVoiceId = 1; + LaptopSaveInfo.iCurrentVoice = 1; + LaptopSaveInfo.iCharIndex = 1; iPortraitNumber = 2; return TRUE; } @@ -1442,7 +1449,8 @@ BOOLEAN CheckCharacterInputForEgg( void ) iPersonality = NO_PERSONALITYTRAIT; iAttitude = ATT_AGGRESSIVE; iCurrentImpPage = IMP_FINISH; - LaptopSaveInfo.iVoiceId = 1; + LaptopSaveInfo.iCurrentVoice = 1; + LaptopSaveInfo.iCharIndex = 1; iPortraitNumber = 4; return TRUE; } @@ -1469,7 +1477,8 @@ BOOLEAN CheckCharacterInputForEgg( void ) iPersonality = NO_PERSONALITYTRAIT; iAttitude = ATT_LONER; iCurrentImpPage = IMP_FINISH; - LaptopSaveInfo.iVoiceId = 1; + LaptopSaveInfo.iCurrentVoice = 1; + LaptopSaveInfo.iCharIndex = 1; iPortraitNumber = 3; return TRUE; } @@ -1493,7 +1502,8 @@ BOOLEAN CheckCharacterInputForEgg( void ) iPersonality = PSYCHO; iAttitude = ATT_ASSHOLE; iCurrentImpPage = IMP_FINISH; - LaptopSaveInfo.iVoiceId = 1; + LaptopSaveInfo.iCurrentVoice = 1; + LaptopSaveInfo.iCharIndex = 1; iPortraitNumber = 2; //DEF: temp @@ -1549,7 +1559,8 @@ BOOLEAN CheckCharacterInputForEgg( void ) iPersonality = NO_PERSONALITYTRAIT; iAttitude = ATT_LONER; iCurrentImpPage = IMP_FINISH; - LaptopSaveInfo.iVoiceId = 1; + LaptopSaveInfo.iCurrentVoice = 1; + LaptopSaveInfo.iCharIndex = 1; iPortraitNumber = 3; return TRUE; } @@ -1578,7 +1589,7 @@ BOOLEAN CheckCharacterInputForEgg( void ) iPersonality = NO_PERSONALITYTRAIT; iAttitude = ATT_LONER; iCurrentImpPage = IMP_FINISH; - LaptopSaveInfo.iVoiceId = 1; + LaptopSaveInfo.iIMPIndex = 54; iPortraitNumber = 5; return (TRUE ); } diff --git a/Laptop/IMP Compile Character.cpp b/Laptop/IMP Compile Character.cpp index 08f972ab..7b0f1441 100644 --- a/Laptop/IMP Compile Character.cpp +++ b/Laptop/IMP Compile Character.cpp @@ -133,51 +133,51 @@ void CreateACharacterFromPlayerEnteredStats( void ) // copy over full name - wcscpy( gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].zName, pFullName ); + wcscpy( gMercProfiles[ LaptopSaveInfo.iIMPIndex ].zName, pFullName ); // the nickname - wcscpy( gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].zNickname, pNickName ); + wcscpy( gMercProfiles[ LaptopSaveInfo.iIMPIndex ].zNickname, pNickName ); // gender if ( fCharacterIsMale == TRUE ) { // male - gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].bSex = MALE; + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].bSex = MALE; } else { // female - gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].bSex = FEMALE; + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].bSex = FEMALE; } // attributes - gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].bLifeMax = ( INT8 )iHealth; - gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].bLife = ( INT8 )iHealth; - gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].bAgility = ( INT8 )iAgility; - gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].bStrength = ( INT8 )iStrength; - gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].bDexterity = ( INT8 )iDexterity; - gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].bWisdom = ( INT8 )iWisdom; - gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].bLeadership = ( INT8 )iLeadership; + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].bLifeMax = ( INT8 )iHealth; + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].bLife = ( INT8 )iHealth; + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].bAgility = ( INT8 )iAgility; + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].bStrength = ( INT8 )iStrength; + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].bDexterity = ( INT8 )iDexterity; + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].bWisdom = ( INT8 )iWisdom; + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].bLeadership = ( INT8 )iLeadership; // skills - gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].bMarksmanship = ( INT8 )iMarksmanship; - gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].bMedical = ( INT8 )iMedical; - gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].bMechanical = ( INT8 )iMechanical; - gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].bExplosive = ( INT8 )iExplosives; + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].bMarksmanship = ( INT8 )iMarksmanship; + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].bMedical = ( INT8 )iMedical; + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].bMechanical = ( INT8 )iMechanical; + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].bExplosive = ( INT8 )iExplosives; // personality - gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].bPersonalityTrait = ( INT8 )iPersonality; + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].bPersonalityTrait = ( INT8 )iPersonality; // attitude - gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].bAttitude = ( INT8 )iAttitude; + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].bAttitude = ( INT8 )iAttitude; - gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].bExpLevel = 1; + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].bExpLevel = 1; // set time away - gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].bMercStatus = 0; + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].bMercStatus = 0; @@ -428,7 +428,7 @@ void ValidateSkillsList( void ) // remove from the generated traits list any traits that don't match // the character's skills - pProfile = &(gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ]); + pProfile = &(gMercProfiles[ LaptopSaveInfo.iIMPIndex ]); if ( pProfile->bMechanical == 0 ) { // without mechanical, electronics is useless @@ -717,18 +717,18 @@ void SelectMercFace( void ) // this procedure will select the approriate face for the merc and save offsets // grab face filename -// strcpy( gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].ubUnusedFaceFileName , pPlayerSelectedFaceFileNames[ iPortraitNumber ]); +// strcpy( gMercProfiles[ LaptopSaveInfo.iIMPIndex ].ubUnusedFaceFileName , pPlayerSelectedFaceFileNames[ iPortraitNumber ]); // now the offsets - gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].ubFaceIndex = 200 + ( UINT8 )iPortraitNumber; + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].ubFaceIndex = 200 + ( UINT8 )iPortraitNumber; // eyes - gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].usEyesX = sFacePositions[ iPortraitNumber ][ 0 ]; - gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].usEyesY = sFacePositions[ iPortraitNumber ][ 1 ]; + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].usEyesX = sFacePositions[ iPortraitNumber ][ 0 ]; + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].usEyesY = sFacePositions[ iPortraitNumber ][ 1 ]; // mouth - gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].usMouthX = sFacePositions[ iPortraitNumber ][ 2 ]; - gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].usMouthY = sFacePositions[ iPortraitNumber ][ 3 ]; + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].usMouthX = sFacePositions[ iPortraitNumber ][ 2 ]; + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].usMouthY = sFacePositions[ iPortraitNumber ][ 3 ]; // set merc skins and hair color SetMercSkinAndHairColors( ); @@ -918,10 +918,10 @@ void SetMercSkinAndHairColors( void ) } // now set them - strcpy( gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].HAIR, sHairStrings[ sHairColor ] ); - strcpy( gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].SKIN, sSkinStrings[ sSkinColor ] ); - strcpy( gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].PANTS, sPantStrings[ sPantColor ] ); - strcpy( gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].VEST, sShirtStrings[ sShirtColor ] ); + strcpy( gMercProfiles[ LaptopSaveInfo.iIMPIndex ].HAIR, sHairStrings[ sHairColor ] ); + strcpy( gMercProfiles[ LaptopSaveInfo.iIMPIndex ].SKIN, sSkinStrings[ sSkinColor ] ); + strcpy( gMercProfiles[ LaptopSaveInfo.iIMPIndex ].PANTS, sPantStrings[ sPantColor ] ); + strcpy( gMercProfiles[ LaptopSaveInfo.iIMPIndex ].VEST, sShirtStrings[ sShirtColor ] ); } @@ -947,7 +947,7 @@ void HandleMercStatsForChangesInFace( ) // Madd - don't override the skills - override the body type instead if( ShouldThisMercHaveABigBody() && iSkillA != MARTIALARTS && iSkillB != MARTIALARTS ) { - gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].ubBodyType = BIGMALE; + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].ubBodyType = BIGMALE; //if( iSkillA == MARTIALARTS ) //{ @@ -960,13 +960,13 @@ void HandleMercStatsForChangesInFace( ) } else { - gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].ubBodyType = REGMALE; + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].ubBodyType = REGMALE; } } else { // female - gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].ubBodyType = REGFEMALE; + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].ubBodyType = REGFEMALE; if( iSkillA == MARTIALARTS ) { @@ -980,8 +980,8 @@ void HandleMercStatsForChangesInFace( ) // skill trait - gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].bSkillTrait = ( INT8 )iSkillA; - gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].bSkillTrait2 = ( INT8 )iSkillB; + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].bSkillTrait = ( INT8 )iSkillA; + gMercProfiles[ LaptopSaveInfo.iIMPIndex ].bSkillTrait2 = ( INT8 )iSkillB; } @@ -991,7 +991,7 @@ BOOLEAN ShouldThisMercHaveABigBody( void ) // Madd - don't limit it by portrait //if ( ( iPortraitNumber == 0 ) || ( iPortraitNumber == 6 ) || ( iPortraitNumber == 7 ) ) //{ - if ( gMercProfiles[ PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ].bStrength >= 75 ) + if ( gMercProfiles[ LaptopSaveInfo.iIMPIndex ].bStrength >= 75 ) { return( TRUE ); } diff --git a/Laptop/IMP Confirm.cpp b/Laptop/IMP Confirm.cpp index 64124fa8..b52dc8b0 100644 --- a/Laptop/IMP Confirm.cpp +++ b/Laptop/IMP Confirm.cpp @@ -226,7 +226,7 @@ BOOLEAN AddCharacterToPlayersTeam( void ) memset(&HireMercStruct, 0, sizeof(MERC_HIRE_STRUCT)); // WANNE NEW: Any changes here. I don't think so - HireMercStruct.ubProfileID = ( UINT8 )( PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ) ; + HireMercStruct.ubProfileID = ( UINT8 )( LaptopSaveInfo.iIMPIndex ) ; if( fLoadingCharacterForPreviousImpProfile == FALSE ) { @@ -296,12 +296,12 @@ void BtnIMPConfirmYes(GUI_BUTTON *btn,INT32 reason) LaptopSaveInfo.fIMPCompletedFlag = TRUE; // charge the player - AddTransactionToPlayersBook(IMP_PROFILE, (UINT8)(PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId), GetWorldTotalMin( ), - ( COST_OF_PROFILE ) ); + AddTransactionToPlayersBook(IMP_PROFILE, (UINT8)(LaptopSaveInfo.iIMPIndex), GetWorldTotalMin( ), - ( COST_OF_PROFILE ) ); AddHistoryToPlayersLog( HISTORY_CHARACTER_GENERATED, 0,GetWorldTotalMin( ), -1, -1 ); AddCharacterToPlayersTeam( ); // write the created imp merc - WriteOutCurrentImpCharacter( ( UINT8 )( PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ) ); + WriteOutCurrentImpCharacter( ( UINT8 )( LaptopSaveInfo.iIMPIndex ) ); fButtonPendingFlag = TRUE; iCurrentImpPage = IMP_HOME_PAGE; @@ -315,14 +315,14 @@ void BtnIMPConfirmYes(GUI_BUTTON *btn,INT32 reason) //Kaiden: And here is my Answer to the IMP E-mails only // profiling the last IMP made. You get the results immediately - AddEmail(IMP_EMAIL_PROFILE_RESULTS, IMP_EMAIL_PROFILE_RESULTS_LENGTH, IMP_PROFILE_RESULTS, GetWorldTotalMin( ), PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ); + AddEmail(IMP_EMAIL_PROFILE_RESULTS, IMP_EMAIL_PROFILE_RESULTS_LENGTH, IMP_PROFILE_RESULTS, GetWorldTotalMin( ), LaptopSaveInfo.iIMPIndex ); //RenderCharProfile( ); ResetCharacterStats(); //Display a popup msg box telling the user when and where the merc will arrive - //DisplayPopUpBoxExplainingMercArrivalLocationAndTime( PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ); + //DisplayPopUpBoxExplainingMercArrivalLocationAndTime( LaptopSaveInfo.iIMPIndex ); //reset the id of the last merc so we dont get the DisplayPopUpBoxExplainingMercArrivalLocationAndTime() pop up box in another screen by accident LaptopSaveInfo.sLastHiredMerc.iIdOfMerc = -1; @@ -770,7 +770,7 @@ BOOLEAN LoadImpCharacter( STR nickName ) // read in the profile - if (!FileRead(hFile, &iProfileId,sizeof( INT32 ), &uiBytesRead)) + if (!FileRead(hFile, &iProfileId, sizeof( INT32 ), &uiBytesRead)) { DoLapTopMessageBox( MSG_BOX_IMP_STYLE, pImpPopUpStrings[ 7 ], LAPTOP_SCREEN, MSG_BOX_FLAG_OK, NULL); return FALSE; @@ -789,7 +789,7 @@ BOOLEAN LoadImpCharacter( STR nickName ) // We can create the new imp, beacuse we found an empty slot if (iProfileId != -1) { - LaptopSaveInfo.iVoiceId = iProfileId - PLAYER_GENERATED_CHARACTER_ID; + LaptopSaveInfo.iIMPIndex = iProfileId; // read in the profile if (!FileRead(hFile, &gMercProfiles[ iProfileId ] ,sizeof( MERCPROFILESTRUCT ), &uiBytesRead)) @@ -816,7 +816,7 @@ BOOLEAN LoadImpCharacter( STR nickName ) fLoadingCharacterForPreviousImpProfile = TRUE; AddTransactionToPlayersBook(IMP_PROFILE,0, GetWorldTotalMin( ), - ( COST_OF_PROFILE ) ); AddHistoryToPlayersLog( HISTORY_CHARACTER_GENERATED, 0,GetWorldTotalMin( ), -1, -1 ); - LaptopSaveInfo.iVoiceId = iProfileId - PLAYER_GENERATED_CHARACTER_ID; + LaptopSaveInfo.iIMPIndex = iProfileId; AddCharacterToPlayersTeam( ); // WANNE: Email is sent immediatly after the imp was created. So no need to send it later again //AddFutureDayStrategicEvent( EVENT_DAY2_ADD_EMAIL_FROM_IMP, 60 * 7, 0, 2 ); @@ -831,6 +831,9 @@ BOOLEAN LoadImpCharacter( STR nickName ) // close file FileClose(hFile); + // WDS: Allow flexible numbers of IMPs of each sex + // note: check this + // You cannot have more than 3 I.M.P characters with the same gender on your team. DoLapTopMessageBox( MSG_BOX_IMP_STYLE, pImpPopUpStrings[ 9 ], LAPTOP_SCREEN, MSG_BOX_FLAG_OK, NULL); return FALSE; diff --git a/Laptop/IMP Finish.cpp b/Laptop/IMP Finish.cpp index 97f8b0d8..cec9c852 100644 --- a/Laptop/IMP Finish.cpp +++ b/Laptop/IMP Finish.cpp @@ -52,12 +52,12 @@ UINT32 uiVoiceSound = 0; // image handle UINT32 guiCHARACTERPORTRAIT; extern INT32 iCurrentPortrait; -extern INT32 iCurrentVoices; +extern INT32 iCurrentVoice; // function definitions void CreateIMPFinishButtons( void ); void DeleteIMPFinishButtons( void ); -BOOLEAN RenderCharProfileFinishFace( void ); +//BOOLEAN RenderCharProfileFinishFace( void ); void RenderCharFullName( void ); BOOLEAN LoadCharacterPortrait( void ); void DestroyCharacterPortrait( void ); @@ -215,7 +215,7 @@ void CreateIMPFinishButtons( void ) SpecifyButtonIcon( giIMPFinishButton[ 4 ], guiCHARACTERPORTRAIT, 0, 33, 23, FALSE ); - swprintf( sString, pImpButtonText[ 5 ], iCurrentVoices + 1 ); + swprintf( sString, pImpButtonText[ 5 ], GetVoiceCountFromVoiceSlot(iCurrentVoice)); // the voice button giIMPFinishButtonImage[5]= LoadButtonImage( "LAPTOP\\button_8.sti" ,-1,0,-1,1,-1 ); @@ -493,17 +493,18 @@ void BtnIMPFinishVoiceCallback(GUI_BUTTON *btn,INT32 reason) } } +/* +WDS - Unused? BOOLEAN RenderCharProfileFinishFace( void ) { - -// render the portrait of the current picture - VOBJECT_DESC VObjectDesc; + // render the portrait of the current picture + VOBJECT_DESC VObjectDesc; HVOBJECT hHandle; UINT32 uiGraphicHandle; if( fCharacterIsMale == TRUE ) { - switch( LaptopSaveInfo.iVoiceId ) + switch( LaptopSaveInfo.iCurrentVoice ) { case( 0 ): // first portrait @@ -562,7 +563,7 @@ BOOLEAN RenderCharProfileFinishFace( void ) } else { - switch( LaptopSaveInfo.iVoiceId ) + switch( LaptopSaveInfo.iCurrentVoice ) { case( 0 ): // first portrait @@ -628,7 +629,7 @@ BOOLEAN RenderCharProfileFinishFace( void ) return( TRUE ); } - +*/ void RenderCharFullName( void ) { diff --git a/Laptop/IMP HomePage.cpp b/Laptop/IMP HomePage.cpp index 6a8fbeaf..a0a748ea 100644 --- a/Laptop/IMP HomePage.cpp +++ b/Laptop/IMP HomePage.cpp @@ -405,7 +405,7 @@ void ProcessPlayerInputActivationString( void ) return; } - if (GetFilledIMPSlots(-1) < gGameExternalOptions.iMaxIMPCharacters) + if (CountFilledIMPSlots(-1) < gGameExternalOptions.iMaxIMPCharacters) { // Kaiden: Need to reset skills, attributes and personalities with the new UB Method. ResetSkillsAttributesAndPersonality( ); @@ -427,7 +427,7 @@ void ProcessPlayerInputActivationString( void ) return; } - if (GetFilledIMPSlots(-1) < gGameExternalOptions.iMaxIMPCharacters) + if (CountFilledIMPSlots(-1) < gGameExternalOptions.iMaxIMPCharacters) { if (LoadImpCharacter( IMP_MERC_FILENAME ) == TRUE) { @@ -435,7 +435,7 @@ void ProcessPlayerInputActivationString( void ) ResetActivationStringTextBox(); //DoLapTopMessageBox( MSG_BOX_IMP_STYLE, pImpPopUpStrings[ 11 ], LAPTOP_SCREEN, MSG_BOX_FLAG_OK, NULL); - AddEmail(IMP_EMAIL_PROFILE_RESULTS, IMP_EMAIL_PROFILE_RESULTS_LENGTH, IMP_PROFILE_RESULTS, GetWorldTotalMin( ), PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ); + AddEmail(IMP_EMAIL_PROFILE_RESULTS, IMP_EMAIL_PROFILE_RESULTS_LENGTH, IMP_PROFILE_RESULTS, GetWorldTotalMin( ), LaptopSaveInfo.iIMPIndex ); } } else @@ -453,7 +453,7 @@ void ProcessPlayerInputActivationString( void ) return; } - if (GetFilledIMPSlots(-1) < gGameExternalOptions.iMaxIMPCharacters) + if (CountFilledIMPSlots(-1) < gGameExternalOptions.iMaxIMPCharacters) { if (LoadImpCharacter( charPlayerActivationString ) == TRUE) { @@ -461,7 +461,7 @@ void ProcessPlayerInputActivationString( void ) ResetActivationStringTextBox(); //DoLapTopMessageBox( MSG_BOX_IMP_STYLE, pImpPopUpStrings[ 11 ], LAPTOP_SCREEN, MSG_BOX_FLAG_OK, NULL); - AddEmail(IMP_EMAIL_PROFILE_RESULTS, IMP_EMAIL_PROFILE_RESULTS_LENGTH, IMP_PROFILE_RESULTS, GetWorldTotalMin( ), PLAYER_GENERATED_CHARACTER_ID + LaptopSaveInfo.iVoiceId ); + AddEmail(IMP_EMAIL_PROFILE_RESULTS, IMP_EMAIL_PROFILE_RESULTS_LENGTH, IMP_PROFILE_RESULTS, GetWorldTotalMin( ), LaptopSaveInfo.iIMPIndex ); } } else diff --git a/Laptop/IMP MainPage.cpp b/Laptop/IMP MainPage.cpp index f3d9b671..9c6a4d4c 100644 --- a/Laptop/IMP MainPage.cpp +++ b/Laptop/IMP MainPage.cpp @@ -39,7 +39,6 @@ INT32 giIMPMainPageButton[6]; INT32 giIMPMainPageButtonImage[6]; -extern INT32 iCurrentVoices; // mouse regions for not entablable warning MOUSE_REGION pIMPMainPageMouseRegions[ 4 ]; @@ -83,6 +82,186 @@ BOOLEAN CheckIfFinishedCharacterGeneration( void ); INT32 iCurrentProfileMode = IMP__REGISTRY; +extern INT32 iCurrentVoice; + +// Return a count of how many IMP slots there are in total +INT32 CountIMPSlots() +{ + INT32 idx; + // Keep a static count so we only count once + static INT32 iMaxIMPs = -1; + if (iMaxIMPs != -1) + return iMaxIMPs; + + iMaxIMPs = 0; + // Count the males + for (idx = GetFirstMaleSlot(); idx <= GetLastMaleSlot(); ++idx) + { + ++iMaxIMPs; + } + // Count the females + for (idx = GetFirstFemaleSlot(); idx <= GetLastFemaleSlot(); ++idx) + { + ++iMaxIMPs; + } + Assert(iMaxIMPs > 0); + return iMaxIMPs; +} + +INT32 GetFirstSlot(INT8 iSex) +{ + if (iSex == MALE) + return GetFirstMaleSlot(); + else if (iSex == FEMALE) + return GetFirstFemaleSlot(); + else { + return GetFirstMaleSlot(); + } +} + +INT32 GetLastSlot(INT8 iSex) +{ + if (iSex == MALE) + return GetLastMaleSlot(); + else if (iSex == FEMALE) + return GetLastFemaleSlot(); + else { + return GetLastFemaleSlot(); + } +} + +INT32 GetFirstFreeSlot(INT8 iSex) { + INT32 iStart = GetFirstSlot(iSex); + INT32 iEnd = GetLastSlot(iSex); + INT32 idx; + + for (idx = iStart; idx <= iEnd; ++idx) + { + if (IsIMPSlotFree(gGameExternalOptions.iaIMPSlots[idx]) == TRUE) + return idx; + } + return -1; +} + + +// Return a count of how many IMP slots there are for males +INT32 CountMaleIMPSlots() { + INT32 idx; + // Keep a static count so we only count once + static INT32 iMaxMaleIMPS = -1; + if (iMaxMaleIMPS != -1) + return iMaxMaleIMPS; + + iMaxMaleIMPS = 0; + for (idx = GetFirstMaleSlot(); idx <= GetLastMaleSlot(); ++idx) + // Count the males + { + ++iMaxMaleIMPS; + } + Assert(iMaxMaleIMPS > 0); + return iMaxMaleIMPS; +} +INT32 GetFirstMaleSlot() { + Assert(gGameExternalOptions.iaIMPSlots[0] != -1); + return 0; +} +INT32 GetLastMaleSlot() { + // Keep a static count so we only count once + static INT32 idx = -1; + if (idx != -1) + return idx; + + idx = 0; + // Skip the males + while (gGameExternalOptions.iaIMPSlots[idx] != -1) + { + ++idx; + } + --idx; + Assert(idx >= 0); + Assert(gGameExternalOptions.iaIMPSlots[idx] != -1); + return idx; +} + +// Return a count of how many IMP slots there are for females +INT32 CountFemaleIMPSlots() { + INT32 idx; + // Keep a static count so we only count once + static INT32 iMaxFemaleIMPS = -1; + if (iMaxFemaleIMPS != -1) + return iMaxFemaleIMPS; + + iMaxFemaleIMPS = 0; + for (idx = GetFirstFemaleSlot(); idx <= GetLastFemaleSlot(); ++idx) + // Count the males + { + ++iMaxFemaleIMPS; + } + Assert(iMaxFemaleIMPS > 0); + return iMaxFemaleIMPS; +} +INT32 GetFirstFemaleSlot() { + // Keep a static count so we only count once + static INT32 idx = -1; + if (idx != -1) + return idx; + + idx = 0; + // Skip the males + while (gGameExternalOptions.iaIMPSlots[idx] != -1) + { + ++idx; + } + ++idx; + Assert(idx >= 0); + Assert(gGameExternalOptions.iaIMPSlots[idx] != -1); + return idx; +} +INT32 GetLastFemaleSlot() { + // Keep a static count so we only count once + static INT32 idx = -1; + if (idx != -1) + return idx; + + idx = 0; + // Skip the males + while (gGameExternalOptions.iaIMPSlots[idx] != -1) + { + ++idx; + } + ++idx; + // Skip the females + while (gGameExternalOptions.iaIMPSlots[idx] != -1) + { + ++idx; + } + --idx; + Assert(idx >= 0); + Assert(gGameExternalOptions.iaIMPSlots[idx] != -1); + return idx; +} + +INT32 GetVoiceCountFromVoiceSlot(INT32 iSlot) { + if (iSlot <= GetLastMaleSlot()) + return iSlot - GetFirstMaleSlot() + 1; + else + return iSlot - GetFirstFemaleSlot() + 1; +} + + +BOOLEAN IsIMPSlotFree(INT32 iIMPId) +{ + if ((iIMPId >= 0) && (iIMPId < NUM_PROFILES) && + ((wcscmp(gMercProfiles[iIMPId].zName, L"") == 0) || + (gMercProfiles[iIMPId].bMercStatus == MERC_IS_DEAD))) + { + return TRUE; + } + else + { + return FALSE; + } +} void EnterIMPMainPage( void ) @@ -285,7 +464,7 @@ void CreateIMPMainPageButtons( void ) if( iCurrentProfileMode != IMP__VOICE && iCurrentProfileMode != IMP__PORTRAIT ) { - swprintf( sString, pImpButtonText[ 5 ], iCurrentVoices + 1 ); + swprintf( sString, pImpButtonText[ 5 ], GetVoiceCountFromVoiceSlot(iCurrentVoice) ); } else { @@ -799,97 +978,120 @@ void IMPMainPageNotSelectableBtnCallback(MOUSE_REGION * pRegion, INT32 iReason ) } // WANNE NEW -INT32 GetFilledIMPSlots( INT8 iSex ) +// WDS: Allow flexible numbers of IMPs of each sex +INT32 CountFilledIMPSlots( INT8 iSex ) { INT32 i; INT32 iCount = 0; INT32 iStart; INT32 iEnd; - // Only count the free imp male slots - if (iSex == MALE) - { - iStart = PLAYER_GENERATED_CHARACTER_ID; - iEnd = iStart + 3; - } - // Only count the free imp female slots - else if (iSex == FEMALE) - { - iStart = PLAYER_GENERATED_CHARACTER_ID + 3; - iEnd = iStart + 3; - } - // Count all free imp slots - else - { - iStart = PLAYER_GENERATED_CHARACTER_ID; - iEnd = PLAYER_GENERATED_CHARACTER_ID + 6; - } + iStart = GetFirstSlot(iSex); + iEnd = GetLastSlot(iSex); - for (i = iStart; i < iEnd; i++) + // Count the used slots + for (i = iStart; i <= iEnd; ++i) { - // We found a free slot - if (wcscmp(gMercProfiles[i].zName, L"") != 0) + if ((gGameExternalOptions.iaIMPSlots[i] != -1) && + (!IsIMPSlotFree(gGameExternalOptions.iaIMPSlots[i]))) { - iCount++; + ++iCount; } } - // Return the number of free imp slots + // Return the count of filled imp slots return iCount; } + +INT32 CountEmptyIMPSlots( INT8 iSex ) +{ + INT32 i; + INT32 iCount = 0; + INT32 iStart; + INT32 iEnd; + + iStart = GetFirstSlot(iSex); + iEnd = GetLastSlot(iSex); + + // Count the free slots + for (i = iStart; i <= iEnd; ++i) + { + if (IsIMPSlotFree(gGameExternalOptions.iaIMPSlots[i])) + { + ++iCount; + } + } + + // Return the count of free imp slots + return iCount; +} + + +INT32 GetSexOfIMP(INT32 iIMPId) +{ + INT32 ui; + for (ui = 0; ui < CountIMPSlots(); ++ui) + { + if (gGameExternalOptions.iaIMPSlots[ui] == iIMPId) + { + if (ui <= GetLastMaleSlot()) + return MALE; + else + return FEMALE; + } + } + Assert(FALSE); + return MALE; +} + + // WANNE NEW INT32 GetFreeIMPSlot(INT32 iIMPId, INT32 iDefaultIMPId) { INT32 iStart; INT32 iEnd; INT32 i; - INT32 iFreeSlot = -1; - BOOLEAN bFoundDefaultIMP = FALSE; + + UINT32 iSex = GetSexOfIMP(iIMPId); if (iIMPId != -1) { // We have a default imp id (90210 or nickname) if (iDefaultIMPId != -1) { - if (wcscmp(gMercProfiles[iDefaultIMPId].zName, L"") == 0) + if (IsIMPSlotFree(iDefaultIMPId)) { - iFreeSlot = iDefaultIMPId; - return iFreeSlot; + return iDefaultIMPId; } } // The default IMP id is already used, find next free imp id - if (bFoundDefaultIMP == FALSE) + // Female + if (iSex == FEMALE) { - // Female - if (iIMPId >= PLAYER_GENERATED_CHARACTER_ID + 3) - { - iStart = PLAYER_GENERATED_CHARACTER_ID + 3; - iEnd = PLAYER_GENERATED_CHARACTER_ID + 6; - } - // Male - else - { - iStart = PLAYER_GENERATED_CHARACTER_ID; - iEnd = PLAYER_GENERATED_CHARACTER_ID + 3; - } + iStart = GetFirstFemaleSlot(); + iEnd = GetLastFemaleSlot(); + } + else if (iSex == MALE) + { + iStart = GetFirstMaleSlot(); + iEnd = GetLastMaleSlot(); + } - // Find a free imp slot - for (i = iStart; i < iEnd; i++) + // Find a free imp slot + for (i = iStart; i <= iEnd; ++i) + { + // Found a free imp slot + if (IsIMPSlotFree(gGameExternalOptions.iaIMPSlots[i])) { - // Found a free imp slot - if (wcscmp(gMercProfiles[i].zName, L"") == 0) - { - iFreeSlot = i; - break; - } + return gGameExternalOptions.iaIMPSlots[i]; } } - } - return iFreeSlot; + /* Didn't find one */ + return -1; } diff --git a/Laptop/IMP MainPage.h b/Laptop/IMP MainPage.h index bbf136de..dcd89ebb 100644 --- a/Laptop/IMP MainPage.h +++ b/Laptop/IMP MainPage.h @@ -8,10 +8,36 @@ void EnterIMPMainPage( void ); void HandleIMPMainPage( void ); void NextProfilingMode( void ); void ShadeUnSelectableButtons( void ); +BOOLEAN IsIMPSlotFree(INT32 iIMPId); // WANNE NEW INT32 GetFreeIMPSlot(INT32 iIMPId, INT32 iDefaultIMPId); -INT32 GetFilledIMPSlots( INT8 iSex ); + +// WDS: Allow flexible numbers of IMPs of each sex +INT32 CountFilledIMPSlots( INT8 iSex ); +INT32 CountEmptyIMPSlots( INT8 iSex ); + +// Return a count of how many IMP slots there are +INT32 CountIMPSlots(); +INT32 CountMaleIMPSlots(); +INT32 CountFemaleIMPSlots(); + +// Get the first/last slots +INT32 GetFirstSlot(INT8 iSex); +INT32 GetLastSlot(INT8 iSex); +INT32 GetFirstFreeSlot(INT8 iSex); +INT32 GetFirstMaleSlot(); +INT32 GetLastMaleSlot(); +INT32 GetFirstFemaleSlot(); +INT32 GetLastFemaleSlot(); + +// This returns a count of how any slots along we are in the potential +// slot list. Usable for displaying on the "Voice" button in the interface +// and probably not much else. +INT32 GetVoiceCountFromVoiceSlot(INT32 iSlot); + +// Given an IMP slot # (0 to NUM_PROFILES-1) return MALE or FEMALE +INT32 GetSexOfIMP(INT32 iIMPId); extern INT32 iCurrentProfileMode; diff --git a/Laptop/IMP Voices.cpp b/Laptop/IMP Voices.cpp index d54bfc43..4454d7ff 100644 --- a/Laptop/IMP Voices.cpp +++ b/Laptop/IMP Voices.cpp @@ -21,15 +21,7 @@ #include "text.h" #endif -//current and last pages - -// WANNE NEW: Set iLastVoice dynamically, skip used voices -INT32 iCurrentVoices = 0; - -INT32 iVoiceId = 0; - -//INT32 iVoiceId = 0; - +INT32 iCurrentVoice = 0; UINT32 uiVocVoiceSound = 0; // buttons needed for the IMP Voices screen @@ -69,9 +61,15 @@ void EnterIMPVoices( void ) fVoiceBVisited = FALSE; fVoiceCVisited = FALSE; - // Set the initialize voice - iVoiceId = -1; - IncrementVoice(); + // Set the initial voice + if (fCharacterIsMale == TRUE) + { + iCurrentVoice = GetFirstFreeSlot(MALE); + } + else + { + iCurrentVoice = GetFirstFreeSlot(FEMALE); + } // create buttons CreateIMPVoicesButtons( ); @@ -141,98 +139,75 @@ void HandleIMPVoices( void ) return; } -BOOLEAN IsIMPSlotFree(INT32 iIMPId) + + +// WDS: Allow flexible numbers of IMPs of each sex +// Ensure the voice is within the valid range +void FixVoiceRange() { - if (wcscmp(gMercProfiles[iIMPId].zName, L"") == 0) + if (fCharacterIsMale == TRUE) { - return TRUE; + if (iCurrentVoice > GetLastMaleSlot()) + iCurrentVoice = GetFirstMaleSlot(); + else if (iCurrentVoice < GetFirstMaleSlot()) + iCurrentVoice = GetLastMaleSlot(); } else { - return FALSE; + if (iCurrentVoice > GetLastFemaleSlot()) + iCurrentVoice = GetFirstFemaleSlot(); + else if (iCurrentVoice < GetFirstFemaleSlot()) + iCurrentVoice = GetLastFemaleSlot(); } } + // WANNE NEW void IncrementVoice( void ) { INT32 iIMPIndex = -1; - INT32 iOffset; INT32 i; - iVoiceId++; + iCurrentVoice++; + FixVoiceRange(); - if (iVoiceId > 2) - iVoiceId = 0; - - if (fCharacterIsMale == TRUE) - iOffset = 0; - else - iOffset = 3; - - // Just to be save (so we use no endless loop) - for (i = 0; i < 20; i++) + // Just to be safe (so we use no endless loop) + for (i = 0; i < CountIMPSlots(); i++) { - if (IsIMPSlotFree(PLAYER_GENERATED_CHARACTER_ID + iOffset + iVoiceId) == TRUE) + if (IsIMPSlotFree(gGameExternalOptions.iaIMPSlots[iCurrentVoice]) == TRUE) { - // This is the free imp index - iIMPIndex = PLAYER_GENERATED_CHARACTER_ID + iOffset + iVoiceId; + // This is a free imp index + iIMPIndex = gGameExternalOptions.iaIMPSlots[iCurrentVoice]; break; } - iVoiceId++; - - // Upper range -> Reset to 0 - if (iVoiceId > 2) - iVoiceId = 0; + iCurrentVoice++; + FixVoiceRange(); } - - // Set the voice id of the free slot - iCurrentVoices = iIMPIndex - iOffset - PLAYER_GENERATED_CHARACTER_ID; - iVoiceId = iCurrentVoices; - - return; } void DecrementVoice( void ) { INT32 iIMPIndex = -1; - INT32 iOffset; INT32 i; - iVoiceId--; + iCurrentVoice--; + FixVoiceRange(); - if (iVoiceId < 0) - iVoiceId = 2; - - if (fCharacterIsMale == TRUE) - iOffset = 0; - else - iOffset = 3; - - // Just to be save (so we use no endless loop) - for (i = 0; i < 20; i++) + // Just to be safe (so we use no endless loop) + for (i = 0; i < CountIMPSlots(); i++) { - if (IsIMPSlotFree(PLAYER_GENERATED_CHARACTER_ID + iOffset + iVoiceId) == TRUE) + if (IsIMPSlotFree(gGameExternalOptions.iaIMPSlots[iCurrentVoice]) == TRUE) { // This is the free imp index - iIMPIndex = PLAYER_GENERATED_CHARACTER_ID + iOffset + iVoiceId; + iIMPIndex = gGameExternalOptions.iaIMPSlots[iCurrentVoice]; break; } - iVoiceId--; - - // Upper range -> Reset to 0 - if (iVoiceId < 0) - iVoiceId = 2; + iCurrentVoice--; + FixVoiceRange(); } - - // Set the voice id of the free slot - iCurrentVoices = iIMPIndex - iOffset - PLAYER_GENERATED_CHARACTER_ID; - iVoiceId = iCurrentVoices; - - return; } @@ -436,14 +411,8 @@ void BtnIMPVoicesDoneCallback(GUI_BUTTON *btn,INT32 reason) // set voice id, to grab character slot // WANNE 10: - if( fCharacterIsMale == TRUE ) - { - LaptopSaveInfo.iVoiceId = iCurrentVoices; - } - else - { - LaptopSaveInfo.iVoiceId = iCurrentVoices + 3; - } + // WDS: Allow flexible numbers of IMPs of each sex + LaptopSaveInfo.iIMPIndex = gGameExternalOptions.iaIMPSlots[iCurrentVoice]; // set button up image pending fButtonPendingFlag = TRUE; @@ -468,45 +437,13 @@ BOOLEAN CameBackToVoicePageButNotFinished() UINT32 PlayVoice( void ) { -// CHAR16 sString[ 64 ]; + INT32 iSlot = gGameExternalOptions.iaIMPSlots[iCurrentVoice]; + char caVoiceSample[] = "Speech\\%03d_001.wav"; - // gender? + Assert((iSlot >= 0) && (iSlot <= 999)); + sprintf(caVoiceSample, caVoiceSample, iSlot); - if( fCharacterIsMale == TRUE ) - { - switch( iCurrentVoices ) - { - case( 0 ): - return( PlayJA2SampleFromFile( "Speech\\051_001.wav", RATE_11025, MIDVOLUME, 1 , MIDDLEPAN ) ); - break; - case( 1 ): - return( PlayJA2SampleFromFile( "Speech\\052_001.wav", RATE_11025, MIDVOLUME, 1 , MIDDLEPAN ) ); - break; - case( 2 ): - return( PlayJA2SampleFromFile( "Speech\\053_001.wav", RATE_11025, MIDVOLUME, 1 , MIDDLEPAN ) ); - break; - case( 3 ): - return( PlayJA2SampleFromFile( "Speech\\057_001.wav", RATE_11025, MIDVOLUME, 1 , MIDDLEPAN ) ); - break; - } - } - else - { - switch( iCurrentVoices ) - { - case( 0 ): - return( PlayJA2SampleFromFile( "Speech\\054_001.wav", RATE_11025, MIDVOLUME, 1 , MIDDLEPAN ) ); - break; - case( 1 ): - return( PlayJA2SampleFromFile( "Speech\\055_001.wav", RATE_11025, MIDVOLUME, 1 , MIDDLEPAN ) ); - break; - case( 2 ): - return( PlayJA2SampleFromFile( "Speech\\056_001.wav", RATE_11025, MIDVOLUME, 1 , MIDDLEPAN ) ); - break; - } - - } - return 0; + return( PlayJA2SampleFromFile( caVoiceSample, RATE_11025, MIDVOLUME, 1 , MIDDLEPAN ) ); } @@ -559,7 +496,7 @@ void RenderVoiceIndex( void ) INT16 sX, sY; // render the voice index value on the the blank portrait - swprintf( sString, L"%s %d", pIMPVoicesStrings[ 0 ], iCurrentVoices + 1 ); + swprintf( sString, L"%s %d", pIMPVoicesStrings[ 0 ], GetVoiceCountFromVoiceSlot(iCurrentVoice)); FindFontCenterCoordinates( 290 + LAPTOP_UL_X, 0, 100, 0, sString, FONT12ARIAL, &sX, &sY ); diff --git a/Laptop/IMP Voices.h b/Laptop/IMP Voices.h index 00544ee9..afb731ae 100644 --- a/Laptop/IMP Voices.h +++ b/Laptop/IMP Voices.h @@ -1,12 +1,10 @@ #ifndef __IMP_VOICES_H #define __IMP_VOICES_H - void EnterIMPVoices( void ); void RenderIMPVoices( void ); void ExitIMPVoices( void ); void HandleIMPVoices( void ); UINT32 PlayVoice( void ); -extern INT32 iVoiceId; #endif \ No newline at end of file diff --git a/Laptop/LaptopSave.h b/Laptop/LaptopSave.h index ead55d8a..e17efa7c 100644 --- a/Laptop/LaptopSave.h +++ b/Laptop/LaptopSave.h @@ -134,7 +134,7 @@ typedef struct UINT16 usInventoryListLength[BOBBY_RAY_LISTS]; - INT32 iVoiceId; + INT32 iIMPIndex; UINT8 ubHaveBeenToBobbyRaysAtLeastOnceWhileUnderConstruction; diff --git a/Strategic/Merc Contract.cpp b/Strategic/Merc Contract.cpp index 1439946f..b4fac297 100644 --- a/Strategic/Merc Contract.cpp +++ b/Strategic/Merc Contract.cpp @@ -969,6 +969,13 @@ BOOLEAN StrategicRemoveMerc( SOLDIERTYPE *pSoldier ) // stop time compression so player can react to the departure StopTimeCompression(); + // WDS: This allows for replacing dead IMP mercs. See "BtnIMPBeginScreenDoneCallback" in "IMP Begin Screen.cpp" + if( ( pSoldier->ubWhatKindOfMercAmI == MERC_TYPE__PLAYER_CHARACTER ) && + ( gMercProfiles[ pSoldier->ubProfile ].bMercStatus == MERC_IS_DEAD ) ) { + // Replace the name with an empty string + wcsncpy( gMercProfiles[ pSoldier->ubProfile ].zName, L"", 1 ); + } + // ATE: update team panels.... UpdateTeamPanelAssignments( ); diff --git a/Utils/INIReader.cpp b/Utils/INIReader.cpp index 7a1ba447..99a5ed3d 100644 --- a/Utils/INIReader.cpp +++ b/Utils/INIReader.cpp @@ -5,6 +5,7 @@ // Kaiden: INI reading function definitions: + CIniReader::CIniReader(const char* szFileName) { // Snap: Look for the INI file in the custom Data directory. @@ -24,6 +25,20 @@ int CIniReader::ReadInteger(const char* szSection, const char* szKey, int iDefau } +int CIniReader::ReadInteger(const char* szSection, const char* szKey, int iDefaultValue, int iMinValue, int iMaxValue) +{ + int i = GetPrivateProfileInt(szSection, szKey, iDefaultValue, m_szFileName); + if (i < iMinValue) + return iMinValue; + else if (i > iMaxValue) + return iMaxValue; + return i; +} + + int ReadInteger(const char* szSection, const char* szKey, int iDefaultValue, int iMinValue, int iMaxValue); + + + float CIniReader::ReadFloat(const char* szSection, const char* szKey, float fltDefaultValue) { char szResult[255]; diff --git a/Utils/INIReader.h b/Utils/INIReader.h index cdaad07b..e39fe858 100644 --- a/Utils/INIReader.h +++ b/Utils/INIReader.h @@ -11,6 +11,7 @@ class CIniReader public: CIniReader(const char* szFileName); int ReadInteger(const char* szSection, const char* szKey, int iDefaultValue); + int ReadInteger(const char* szSection, const char* szKey, int iDefaultValue, int iMinValue, int iMaxValue); float ReadFloat(const char* szSection, const char* szKey, float fltDefaultValue); bool ReadBoolean(const char* szSection, const char* szKey, bool bolDefaultValue); char* ReadString(const char* szSection, const char* szKey, const char* szDefaultValue); diff --git a/Utils/_EnglishText.cpp b/Utils/_EnglishText.cpp index e7f094dc..e5d312f1 100644 --- a/Utils/_EnglishText.cpp +++ b/Utils/_EnglishText.cpp @@ -2080,6 +2080,8 @@ STR16 pMercContractOverStrings[] = // Text used on IMP Web Pages +// WDS: Allow flexible numbers of IMPs of each sex +// note: I only updated the English text to remove "three" below STR16 pImpPopUpStrings[] = { L"Invalid authorization code", @@ -2091,7 +2093,7 @@ STR16 pImpPopUpStrings[] = L"Profile already completed.", L"Cannot load I.M.P. character from disk.", L"You have already reached the maximum number of I.M.P. characters.", - L"You have already three I.M.P characters with the same gender on your team.", + L"You have already the maximum number of I.M.P characters with that gender on your team.", L"You cannot afford the I.M.P character.", L"The new I.M.P character has joined your team.", };