diff --git a/Console/Console_VS2013.vcxproj b/Console/Console_VS2013.vcxproj index decd1930..436e2019 100644 --- a/Console/Console_VS2013.vcxproj +++ b/Console/Console_VS2013.vcxproj @@ -47,7 +47,7 @@ StaticLibrary true NotSet - v100 + v120 StaticLibrary diff --git a/Editor/Editor_VS2013.vcxproj b/Editor/Editor_VS2013.vcxproj index 445edf22..775c5bc4 100644 --- a/Editor/Editor_VS2013.vcxproj +++ b/Editor/Editor_VS2013.vcxproj @@ -90,7 +90,7 @@ StaticLibrary true NotSet - v100 + v120 StaticLibrary diff --git a/GameSettings.cpp b/GameSettings.cpp index 20bfd0e6..59eb4ca4 100644 --- a/GameSettings.cpp +++ b/GameSettings.cpp @@ -872,7 +872,7 @@ void LoadGameExternalOptions() // Buggler: setting to show/hide skills/traits in AIM & MERC hiring page gGameExternalOptions.fShowSkillsInHirePage = iniReader.ReadBoolean("Recruitment Settings", "SHOW_SKILLS_IN_HIRING_PAGE", FALSE); - gGameExternalOptions.ubMercRandomStats = iniReader.ReadInteger("Recruitment Settings", "MERCS_RANDOM_STATS", 0, 0, 3); + gGameExternalOptions.ubMercRandomStats = iniReader.ReadInteger("Recruitment Settings", "MERCS_RANDOM_STATS", 0, 0, 4); gGameExternalOptions.fMercRandomBellDistribution = iniReader.ReadBoolean("Recruitment Settings", "MERCS_RANDOM_BELL_DISTRIBUTION", TRUE); gGameExternalOptions.ubMercRandomStatsRange = iniReader.ReadInteger("Recruitment Settings", "MERCS_RANDOM_STAT_RANGE", 10, 0, 50); gGameExternalOptions.ubMercRandomExpRange = iniReader.ReadInteger("Recruitment Settings", "MERCS_RANDOM_EXP_RANGE", 1, 0, 4); diff --git a/Laptop/Laptop_VS2013.vcxproj b/Laptop/Laptop_VS2013.vcxproj index 1bd5f9de..096bea99 100644 --- a/Laptop/Laptop_VS2013.vcxproj +++ b/Laptop/Laptop_VS2013.vcxproj @@ -195,7 +195,7 @@ StaticLibrary true NotSet - v100 + v120 StaticLibrary diff --git a/ModularizedTacticalAI/ModularizedTacticalAI_VS2013.vcxproj b/ModularizedTacticalAI/ModularizedTacticalAI_VS2013.vcxproj index 961e8b1a..cd6d5f0c 100644 --- a/ModularizedTacticalAI/ModularizedTacticalAI_VS2013.vcxproj +++ b/ModularizedTacticalAI/ModularizedTacticalAI_VS2013.vcxproj @@ -49,7 +49,7 @@ StaticLibrary NotSet - v100 + v120 StaticLibrary diff --git a/Standard Gaming Platform/SGP_VS2013.vcxproj b/Standard Gaming Platform/SGP_VS2013.vcxproj index 9f850e45..f824da53 100644 --- a/Standard Gaming Platform/SGP_VS2013.vcxproj +++ b/Standard Gaming Platform/SGP_VS2013.vcxproj @@ -150,7 +150,7 @@ StaticLibrary true NotSet - v100 + v120 StaticLibrary diff --git a/Strategic/Strategic_VS2013.vcxproj b/Strategic/Strategic_VS2013.vcxproj index 2c5d48d2..4adfaff9 100644 --- a/Strategic/Strategic_VS2013.vcxproj +++ b/Strategic/Strategic_VS2013.vcxproj @@ -148,7 +148,7 @@ StaticLibrary true NotSet - v100 + v120 StaticLibrary diff --git a/Tactical/RandomMerc.cpp b/Tactical/RandomMerc.cpp new file mode 100644 index 00000000..e6f8f27a --- /dev/null +++ b/Tactical/RandomMerc.cpp @@ -0,0 +1,1072 @@ +#ifdef PRECOMPILEDHEADERS + #include "Tactical All.h" +#else + #include + #include + #include "stdlib.h" + #include "debug.h" + #include "math.h" + #include "worlddef.h" + #include "renderworld.h" + + #include "Random.h" + #include "Campaign.h" +#endif + +#include + +#include "XML.h" + +//Jenilee: full randomization of mercs, including traits, gear kits and all statistics. +//to use, set MERCS_RANDOM_STATS to 4 in JA2_Options.ini. + +//the randomizer uses a set of 1-3 roles per merc that define their general character. +enum rolesets_t +{ + ROLE_GENERIC = 0, + ROLE_MEDIC = 1, + ROLE_MECHANIC, + ROLE_EXPLOSIVES_EXPERT, + ROLE_LEADER, + ROLE_COMBAT_SNIPER, + ROLE_COMBAT_HUNTER, + ROLE_COMBAT_RIFLEMAN, + ROLE_COMBAT_MARTIAL_ARTIST, + ROLE_COMBAT_GUNSLINGER, + ROLE_COMBAT_HEAVY_WEAPONS, + ROLE_COMBAT_GRENADIER +}; + +//types of camo for armor generation +enum camotypes_t +{ + CAMO_ARMOR = 1, + CAMO_URBAN, + CAMO_WOODLAND, + CAMO_DESERT, + CAMO_STEALTH +}; + +//types of face items +enum random_faceitems_t +{ + FACEITEM_GAS_MASK = 1, + FACEITEM_NVG, + FACEITEM_SPECTACLES, + FACEITEM_HEADSET +}; + +UINT8* roles[15]; //roles are saved in this array + +//these vectors store suitable items for randomization +std::vector gear_helmets; +std::vector gear_vests; +std::vector gear_leggings; +std::vector gear_plates; +std::vector gear_faceitems; +std::vector gear_lbe; +std::vector gear_weapons; +std::vector gear_magazines; +std::vector gear_attachments; +std::vector gear_misc; + +//prototypes +bool GenerateRoleSet(UINT8 role_name, UINT8 hlt, UINT8 dex, UINT8 agi, UINT8 str, UINT8 wis, UINT8 mrk, UINT8 ldr, UINT8 mec, UINT8 exp, UINT8 med); + +//generate the stat distributions per role, to be used in the roll tables, and read in pointers to items +void InitRandomMercs() +{ + // HLT DEX AGI STR WIS MRK LDR MEC EXP MED + GenerateRoleSet(ROLE_GENERIC, 15, 12, 17, 12, 11, 16, 4, 4, 4, 5); + + GenerateRoleSet(ROLE_MEDIC, 8, 18, 16, 5, 14, 15, 3, 2, 2, 17); + GenerateRoleSet(ROLE_MECHANIC, 9, 17, 15, 5, 15, 17, 1, 18, 1, 2); + GenerateRoleSet(ROLE_EXPLOSIVES_EXPERT, 8, 19, 14, 6, 13, 16, 2, 2, 19, 1); + GenerateRoleSet(ROLE_LEADER, 10, 6, 15, 10, 18, 18, 18, 1, 1, 3); + + GenerateRoleSet(ROLE_COMBAT_GRENADIER, 12, 8, 21, 19, 11, 21, 1, 1, 5, 1); + GenerateRoleSet(ROLE_COMBAT_SNIPER, 12, 11, 20, 11, 12, 28, 1, 2, 1, 2); + GenerateRoleSet(ROLE_COMBAT_HUNTER, 11, 11, 23, 10, 13, 25, 1, 1, 1, 4); + GenerateRoleSet(ROLE_COMBAT_RIFLEMAN, 15, 10, 22, 14, 9, 23, 2, 1, 1, 3); + GenerateRoleSet(ROLE_COMBAT_MARTIAL_ARTIST, 12, 23, 22, 12, 13, 14, 1, 1, 1, 1); + GenerateRoleSet(ROLE_COMBAT_GUNSLINGER, 14, 12, 24, 11, 12, 22, 1, 1, 1, 2); + GenerateRoleSet(ROLE_COMBAT_HEAVY_WEAPONS, 14, 8, 20, 18, 10, 22, 1, 1, 5, 1); + // HLT DEX AGI STR WIS MRK LDR MEC EXP MED + + //populate random gear list + for (int i = 0;i < MAXITEMS; i++) + { + INVTYPE* item = &Item[i]; + + if (item->usItemClass == IC_AMMO) //ammo is not affected by all the other filters + { + gear_magazines.push_back(item); + } + + if (item->usPrice < 1 || item->ubCoolness < 1) //if it has no price or coolness we don't want it + continue; + + if (StoreInventory[i][0] < 1) //if BobbyRay doesn't sell it then we won't use it either + continue; + + if (item->usItemClass == IC_ARMOUR) + { + ARMOURTYPE* armor = &Armour[item->ubClassIndex]; + + if (armor->ubArmourClass == ARMOURCLASS_HELMET) + gear_helmets.push_back(item); + else if (armor->ubArmourClass == ARMOURCLASS_VEST) + gear_vests.push_back(item); + else if (armor->ubArmourClass == ARMOURCLASS_LEGGINGS) + gear_leggings.push_back(item); + else if (armor->ubArmourClass == ARMOURCLASS_PLATE) + gear_plates.push_back(item); + } + else if (item->usItemClass == IC_FACE) + { + gear_faceitems.push_back(item); + } + else if (item->usItemClass == IC_LBEGEAR) + { + gear_lbe.push_back(item); + } + else if (item->usItemClass == IC_GUN || item->usItemClass == IC_BLADE || item->usItemClass == IC_THROWING_KNIFE || item->usItemClass == IC_LAUNCHER) + { + gear_weapons.push_back(item); + } + else if (item->usItemClass == IC_MISC) + { + gear_attachments.push_back(item); + } + else if (item->usItemClass == IC_BLADE || item->usItemClass == IC_THROWING_KNIFE || item->usItemClass == IC_THROWN || item->usItemClass == IC_PUNCH || item->usItemClass == IC_APPLIABLE || + item->usItemClass == IC_MONEY || item->usItemClass == IC_GRENADE || item->usItemClass == IC_BOMB || item->usItemClass == IC_MEDKIT || item->usItemClass == IC_KIT) + { + gear_misc.push_back(item); + } + } +} + +//clean up +void ExitRandomMercs() +{ + for (UINT8 i = 0;i < 15; i++) + { + if (roles[i]) + delete[] roles[i]; + } +} + +//generate roll tables for roles +bool GenerateRoleSet(UINT8 role_name, UINT8 hlt, UINT8 dex, UINT8 agi, UINT8 str, UINT8 wis, UINT8 mrk, UINT8 ldr, UINT8 mec, UINT8 exp, UINT8 med) +{ + if ((hlt + dex + agi + str + wis + mrk + ldr+ mec + exp + med) > 100) + return false; //total roll table sum must be 100 + + UINT8* set = new UINT8[100]; + UINT8 counter = 0; + + for (; med > 0; med--) { set[counter++] = MEDICALAMT; } + for (; dex > 0; dex--) { set[counter++] = DEXTAMT; } + for (; agi > 0; agi--) { set[counter++] = AGILAMT; } + for (; str > 0; str--) { set[counter++] = STRAMT; } + for (; wis > 0; wis--) { set[counter++] = WISDOMAMT; } + for (; mrk > 0; mrk--) { set[counter++] = MARKAMT; } + for (; ldr > 0; ldr--) { set[counter++] = LDRAMT; } + for (; mec > 0; mec--) { set[counter++] = MECHANAMT; } + for (; exp > 0; exp--) { set[counter++] = EXPLODEAMT; } + while (counter < 100) { set[counter++] = HEALTHAMT; } //health is filler stat + + roles[role_name] = set; + + return true; +} + +//this function will increase the specified stat and checks for boundaries +UINT8 IncreaseStat(MERCPROFILESTRUCT* merc, UINT8 stat) +{ + if (stat == HEALTHAMT) { if (merc->bLifeMax < 100) { merc->bLifeMax++; merc->bLife = merc->bLifeMax; } } + else if (stat == DEXTAMT) { if (merc->bDexterity < 100) { merc->bDexterity++; } } + else if (stat == AGILAMT) { if (merc->bAgility < 100) { merc->bAgility++; } } + else if (stat == STRAMT) { if (merc->bStrength < 100) { merc->bStrength++; } } + else if (stat == WISDOMAMT) { if (merc->bWisdom < 100) { merc->bWisdom++; } } + else if (stat == MARKAMT) { if (merc->bMarksmanship < 100) { merc->bMarksmanship++; } } + else if (stat == LDRAMT) { if (merc->bLeadership < 100) { merc->bLeadership++; } } + else if (stat == MECHANAMT) { if (merc->bMechanical < 100) { merc->bMechanical++; } } + else if (stat == EXPLODEAMT) { if (merc->bExplosive < 100) { merc->bExplosive++; } } + else if (stat == MEDICALAMT) { if (merc->bMedical < 100) { merc->bMedical++; } } + + return 1; +} + +//get a random number from the specified roll table +UINT8 GetRandomNumberForRole(UINT8 role_name) +{ + UINT8 rnd = Random(100); + return roles[role_name][rnd]; +} + +//returns the amount of combat traits we have +FLOAT CountCombatTraits(std::vector* traits) +{ + FLOAT amount = 0; + + for (std::vector::iterator it = traits->begin(); it != traits->end(); it++) + { + if (*it == AUTO_WEAPONS_NT || + *it == HEAVY_WEAPONS_NT || + *it == SNIPER_NT || + *it == RANGER_NT || + *it == GUNSLINGER_NT || + *it == DEMOLITIONS_NT) + { + amount += 1.0f; + } + + if (*it == MARTIAL_ARTS_NT || + *it == MELEE_NT || + *it == THROWING_NT) + { + amount += 0.5f; + } + } + + return amount; +} + +//returns the amount of times we have trait x (since some have 2 tiers) +UINT8 HasTrait(std::vector* traits, UINT8 trait_to_check) +{ + UINT8 amount = 0; + + for (std::vector::iterator it = traits->begin(); it != traits->end(); it++) + { + if (*it == trait_to_check) + amount++; + } + + return amount; +} + +//returns whether we have role x +BOOLEAN HasRole(std::vector* roles, UINT8 role_to_check) +{ + bool exists = false; + + for (std::vector::iterator it = roles->begin(); it != roles->end(); it++) + { + if (*it == role_to_check) + exists = true; + } + + return exists; +} + +//decide which roles this merc will have +std::vector GrantRoles(UINT8 num_roles_to_add) +{ + std::vector roles; + + while (num_roles_to_add > 0) + { + UINT8 combat_role = Random(2); + UINT8 new_role = 0; + + if (combat_role == 1) + new_role = Random(7) + 5; + else + new_role = Random(4) + 1; + + if (!HasRole(&roles, new_role)) + { + num_roles_to_add--; + roles.push_back(new_role); + } + } + + return roles; +} + +//check which roles we qualify for. you are far more likely to obtain traits for which you have the associated role. skill checks are higher for the second level of a trait +UINT8 TestForTrait(UINT8 trait_to_attempt, MERCPROFILESTRUCT* merc, std::vector* roles, std::vector* traits) +{ + UINT16 success_rate = 0; // 1/1000th! NOT percentage! + + if (trait_to_attempt < 1 || trait_to_attempt > 19) // don't bother + return 0; + + if (trait_to_attempt > 9 && HasTrait(traits, trait_to_attempt) > 0) //can only have a minor trait once! + return 0; + + if (trait_to_attempt < 10 && HasTrait(traits, trait_to_attempt) > 1) //can only have a major trait twice! + return 0; + + switch (trait_to_attempt) + { + case AUTO_WEAPONS_NT: + if (HasTrait(traits, AUTO_WEAPONS_NT) > 0) + success_rate = 0 + (HasRole(roles, ROLE_COMBAT_RIFLEMAN) * 200) + ((merc->bMarksmanship > 50) ? 100 : 0) + ((merc->bMarksmanship > 70) ? 100 : 0); + else + success_rate = 0 + (HasRole(roles, ROLE_COMBAT_RIFLEMAN) * 800) + ((merc->bMarksmanship > 30) ? 100 : 0) + ((merc->bMarksmanship > 40) ? 100 : 0); + break; + case HEAVY_WEAPONS_NT: + if (HasTrait(traits, HEAVY_WEAPONS_NT) > 0) + success_rate = 0 + (HasRole(roles, ROLE_COMBAT_HEAVY_WEAPONS) * 200) + ((merc->bStrength > 70) ? 100 : 0) + ((merc->bStrength > 80) ? 100 : 0); + else + success_rate = 0 + (HasRole(roles, ROLE_COMBAT_HEAVY_WEAPONS) * 800) + ((merc->bStrength > 40) ? 100 : 0) + ((merc->bStrength > 60) ? 100 : 0); + break; + case SNIPER_NT: + if (HasTrait(traits, SNIPER_NT) > 0) + success_rate = 0 + (HasRole(roles, ROLE_COMBAT_SNIPER) * 200) + ((merc->bMarksmanship > 85) ? 100 : 0) + ((merc->bMarksmanship > 90) ? 100 : 0) + ((merc->bMarksmanship > 95) ? 200 : 0); + else + success_rate = 0 + (HasRole(roles, ROLE_COMBAT_SNIPER) * 800) + ((merc->bMarksmanship > 70) ? 100 : 0) + ((merc->bMarksmanship > 80) ? 100 : 0); + break; + case RANGER_NT: + if (HasTrait(traits, RANGER_NT) > 0) + success_rate = 0 + (HasRole(roles, ROLE_COMBAT_HUNTER) * 200) + ((merc->bMarksmanship > 70) ? 100 : 0) + ((merc->bAgility > 70) ? 100 : 0); + else + success_rate = 0 + (HasRole(roles, ROLE_COMBAT_HUNTER) * 800) + ((merc->bMarksmanship > 40) ? 100 : 0) + ((merc->bAgility > 40) ? 100 : 0); + break; + case GUNSLINGER_NT: + if (HasTrait(traits, GUNSLINGER_NT) > 0) + success_rate = 0 + (HasRole(roles, ROLE_COMBAT_GUNSLINGER) * 200) + ((merc->bMarksmanship > 70) ? 100 : 0) + ((merc->bMarksmanship > 80) ? 100 : 0) + ((merc->bMarksmanship > 90) ? 100 : 0); + else + success_rate = 0 + (HasRole(roles, ROLE_COMBAT_GUNSLINGER) * 800) + ((merc->bMarksmanship > 40) ? 100 : 0) + ((merc->bMarksmanship > 60) ? 100 : 0); + break; + case MARTIAL_ARTS_NT: + if (HasTrait(traits, MARTIAL_ARTS_NT) > 0) + success_rate = 0 + (HasRole(roles, ROLE_COMBAT_MARTIAL_ARTIST) * 200) + ((merc->bDexterity > 70) ? 150 : 0) + ((merc->bDexterity > 80) ? 150 : 0); + else + success_rate = 0 + (HasRole(roles, ROLE_COMBAT_MARTIAL_ARTIST) * 800) + ((merc->bDexterity > 40) ? 150 : 0) + ((merc->bDexterity > 60) ? 100 : 0); + break; + case SQUADLEADER_NT: + if (HasTrait(traits, SQUADLEADER_NT) > 0) + success_rate = 0 + (HasRole(roles, ROLE_LEADER) * 200) + ((merc->bLeadership > 70) ? 150 : 0) + ((merc->bLeadership > 80) ? 150 : 0) + ((merc->bLeadership > 90) ? 150 : 0); + else + success_rate = 0 + (HasRole(roles, ROLE_LEADER) * 800) + ((merc->bLeadership > 40) ? 200 : 0) + ((merc->bLeadership > 50) ? 150 : 0); + break; + case TECHNICIAN_NT: + if (HasTrait(traits, TECHNICIAN_NT) > 0) + success_rate = 0 + (HasRole(roles, ROLE_MECHANIC) * 200) + ((merc->bMechanical > 70) ? 100 : 0) + ((merc->bDexterity > 60) ? 100 : 0) + ((merc->bDexterity > 75) ? 150 : 0) + ((merc->bMechanical > 85) ? 150 : 0); + else + success_rate = 0 + (HasRole(roles, ROLE_MECHANIC) * 800) + ((merc->bMechanical > 35) ? 100 : 0); + break; + case DOCTOR_NT: + if (HasTrait(traits, DOCTOR_NT) > 0) + success_rate = 0 + (HasRole(roles, ROLE_MEDIC) * 200) + ((merc->bMedical > 70) ? 150 : 0) + ((merc->bDexterity > 60) ? 150 : 0) + ((merc->bMedical > 85) ? 150 : 0) + ((merc->bDexterity > 75) ? 150 : 0); + else + success_rate = 0 + (HasRole(roles, ROLE_MEDIC) * 800) + ((merc->bMedical > 35) ? 100 : 0); + break; + case AMBIDEXTROUS_NT: + success_rate = 50 + (HasRole(roles, ROLE_COMBAT_GUNSLINGER) * 100) + ((merc->bDexterity > 60) ? 100 : 0) + ((merc->bDexterity > 80) ? 100 : 0) + ((merc->bDexterity > 90) ? 100 : 0); + break; + case MELEE_NT: + success_rate = 50 + ((merc->bDexterity > 30) ? 50 : 0) + ((merc->bDexterity > 60) ? 200 : 0); + break; + case THROWING_NT: + success_rate = 50 + ((merc->bDexterity > 30) ? 100 : 0) + ((merc->bDexterity > 60) ? 200 : 0); + break; + case NIGHT_OPS_NT: + success_rate = 200; + break; + case STEALTHY_NT: + success_rate = 200; + break; + case ATHLETICS_NT: + success_rate = 70 + ((merc->bAgility > 50) ? 100 : 0) + ((merc->bAgility > 70) ? 200 : 0) + ((merc->bAgility > 90) ? 200 : 0); + break; + case BODYBUILDING_NT: + success_rate = 70 + ((merc->bStrength > 30) ? 100 : 0) + ((merc->bStrength > 60) ? 200 : 0) + ((merc->bStrength > 90) ? 200 : 0); + break; + case DEMOLITIONS_NT: + success_rate = 0 + (HasRole(roles, ROLE_EXPLOSIVES_EXPERT) * 800) + (HasRole(roles, ROLE_COMBAT_GRENADIER) * 800) + ((merc->bExplosive > 30) ? 200 : 0) + ((merc->bStrength > 35) ? 200 : 0); + break; + case TEACHING_NT: + success_rate = 10 + (HasRole(roles, ROLE_LEADER) * 300) + ((merc->bLeadership > 40) ? 200 : 0) + ((merc->bLeadership > 70) ? 200 : 0); + break; + case SCOUTING_NT: + success_rate = 70 + (HasRole(roles, ROLE_COMBAT_HUNTER) * 150) + (HasRole(roles, ROLE_COMBAT_SNIPER) * 80); + break; + } + + if (success_rate > Random(1000)) + return trait_to_attempt; + else + return 0; +} + +//clear this merc's kit +void GearKitClear(UINT8 profid, UINT8 kit_number) +{ + gMercProfileGear[profid][kit_number].clearInventory(); +} + +//set price for this kit +void GearKitSetPrice(UINT8 profid, UINT8 kit_number, INT16 price) +{ + gMercProfileGear[profid][kit_number].AbsolutePrice = price; +} + +//get the specified slot +INVTYPE* GearGetSlot(UINT8 profid, UINT8 kit_number, UINT8 slot) +{ + return &Item[ gMercProfileGear[profid][kit_number].inv[slot] ]; +} + +//set the specified slot +UINT16 GearSetSlot(UINT8 profid, UINT8 kit_number, UINT8 slot, INVTYPE* item, UINT8 quantity = 1, UINT8 status = 100) +{ + if (item == NULL) + return 0; + + gMercProfileGear[profid][kit_number].inv[slot] = item->uiIndex; + gMercProfileGear[profid][kit_number].iStatus[slot] = status; + gMercProfileGear[profid][kit_number].iNumber[slot] = quantity; + gMercProfileGear[profid][kit_number].iDrop[slot] = 0; + + return item->usPrice; +} + +//generate a random LBE item (this is mostly used as a parachute function) +INVTYPE* GearGetRandomLBE(INT8 min_coolness = -1, INT8 max_coolness = -1, UINT8 lbe_type = -1) +{ + std::vector candidates; + + for (std::vector::iterator it = gear_lbe.begin(); it != gear_lbe.end(); it++) + { + LBETYPE* lbe = &LoadBearingEquipment[(*it)->ubClassIndex]; + if (lbe == NULL) + return NULL; + + if (HasItemFlag((*it)->uiIndex, SCUBA_BOTTLE)) + continue; + + if (min_coolness > -1 && (*it)->ubCoolness < min_coolness) continue; + if (max_coolness > -1 && (*it)->ubCoolness > max_coolness) continue; + if (lbe_type != -1 && lbe->lbeClass != lbe_type) continue; + + candidates.push_back(*it); + } + + if (candidates.size() < 1) + return NULL; + + return candidates[Random(candidates.size())]; +} + +//generate a random face item for our merc +INVTYPE* GearGetRandomFaceItem(INT8 min_coolness = -1, INT8 max_coolness = -1, UINT8 item_type = -1) +{ + std::vector candidates; + + for (std::vector::iterator it = gear_faceitems.begin(); it != gear_faceitems.end(); it++) + { + if (min_coolness > -1 && (*it)->ubCoolness < min_coolness) continue; + if (max_coolness > -1 && (*it)->ubCoolness > max_coolness) continue; + + if (HasItemFlag((*it)->uiIndex, SCUBA_MASK)) + continue; + + if (item_type == FACEITEM_GAS_MASK && (*it)->gasmask < 1) continue; + if (item_type == FACEITEM_SPECTACLES && (*it)->brightlightvisionrangebonus < 1) continue; + if (item_type == FACEITEM_NVG && (*it)->nightvisionrangebonus < 1) continue; + if (item_type == FACEITEM_HEADSET && (*it)->hearingrangebonus < 1) continue; + + candidates.push_back(*it); + } + + if (candidates.size() < 1) + return NULL; + + return candidates[Random(candidates.size())]; +} + +//generate a random armor item based on slot and camo type selected (the idea is all 3 pieces of armor should have similar camo) +INVTYPE* GearGetRandomArmor(std::vector* pointer, INT8 min_coolness = -1, INT8 max_coolness = -1, INT8 preferred_camo = -1, INT8 min_camo = -1) +{ + if (pointer == NULL) + return NULL; + + std::vector candidates; + + for (std::vector::iterator it = pointer->begin(); it != pointer->end(); it++) + { + if (min_coolness > -1 && (*it)->ubCoolness < min_coolness) continue; + if (max_coolness > -1 && (*it)->ubCoolness > max_coolness) continue; + + if (HasItemFlag((*it)->uiIndex, SCUBA_BOTTLE)) + continue; + + if (HasItemFlag((*it)->uiIndex, SCUBA_MASK)) + continue; + + if (HasItemFlag((*it)->uiIndex, SCUBA_FINS)) + continue; + + ARMOURTYPE* armor = &Armour[(*it)->ubClassIndex]; + if (armor == NULL) + break; + + if (preferred_camo == CAMO_ARMOR && armor->ubProtection < min_camo) continue; + if (preferred_camo == CAMO_URBAN && (*it)->urbanCamobonus < min_camo) continue; + if (preferred_camo == CAMO_WOODLAND && (*it)->camobonus < min_camo) continue; + if (preferred_camo == CAMO_DESERT && (*it)->desertCamobonus < min_camo) continue; + if (preferred_camo == CAMO_STEALTH && (*it)->stealthbonus < min_camo) continue; + + candidates.push_back(*it); + } + + if (candidates.size() < 1) + return GearGetRandomArmor(pointer, -1, 1); //get some random, basic armor instead. + + return candidates[Random(candidates.size())]; +} + +//generate a random weapon of requested type, class and BR coolness +INVTYPE* GearGetRandomWeapon(INT8 min_coolness = -1, INT8 max_coolness = -1, INT8 weapon_type = -1, INT8 weapon_class = -1) +{ + std::vector candidates; + + for (std::vector::iterator it = gear_weapons.begin(); it != gear_weapons.end(); it++) + { + WEAPONTYPE* weapon = &Weapon[(*it)->ubClassIndex]; + if (weapon == NULL) + return NULL; + + if (min_coolness > -1 && (*it)->ubCoolness < min_coolness) continue; + if (max_coolness > -1 && (*it)->ubCoolness > max_coolness) continue; + if (weapon_type != -1 && weapon->ubWeaponType != weapon_type) continue; + if (weapon_class != -1 && weapon->ubWeaponClass != weapon_class) continue; + + candidates.push_back(*it); + } + + if (candidates.size() < 1) + return NULL; + + return candidates[Random(candidates.size())]; +} + +//generate random weapon, but take the merc's role into account. snipers get sniper rifles, etc. +INVTYPE* GearGetRandomWeaponForRole(std::vector* roles, std::vector* traits, INT8 min_coolness = -1, INT8 max_coolness = -1) +{ + if (!traits || traits->size() < 1) //guy has NO traits. just give him a pistol or something + return GearGetRandomWeapon(min_coolness, max_coolness, GUN_PISTOL, -1); + + UINT8 tries_left = 5; + + while (tries_left-- > 0) + { + UINT8 random_trait = traits->at( Random(traits->size()) ); + + switch (random_trait) + { + case AUTO_WEAPONS_NT: + if (HasTrait(traits, AUTO_WEAPONS_NT) > 1 && Random(10) < 4) + return GearGetRandomWeapon(min_coolness, max_coolness, GUN_LMG, -1); + else + return GearGetRandomWeapon(min_coolness, max_coolness, GUN_AS_RIFLE, -1); + break; + + case SNIPER_NT: + return GearGetRandomWeapon(min_coolness, max_coolness, GUN_SN_RIFLE, -1); + break; + + case RANGER_NT: + if (Random(2) < 1) + return GearGetRandomWeapon(min_coolness, max_coolness, GUN_SHOTGUN, -1); + else + return GearGetRandomWeapon(min_coolness, max_coolness, GUN_RIFLE, -1); + break; + + case GUNSLINGER_NT: + return GearGetRandomWeapon(min_coolness + 1, max_coolness + 1, GUN_PISTOL, -1); + break; + } + } + + //fall through to random selection + UINT random_weapon = Random(10); + + if (random_weapon < 4) + return GearGetRandomWeapon(min_coolness, max_coolness, GUN_AS_RIFLE, -1); + else if (random_weapon < 7) + return GearGetRandomWeapon(min_coolness, max_coolness, GUN_SMG, -1); + else + return GearGetRandomWeapon(min_coolness, max_coolness, GUN_SHOTGUN, -1); +} + +//find magazine type that suits our weapon +INVTYPE* GearFindAmmoForWeapon(WEAPONTYPE* weapon) +{ + if (!weapon) + return NULL; + + std::vector candidates; + + for (std::vector::iterator it = gear_magazines.begin(); it != gear_magazines.end(); it++) + { + MAGTYPE* mag = &Magazine[(*it)->ubClassIndex]; + + if (mag->ubMagType != AMMO_MAGAZINE) + continue; + + AMMOTYPE* at = &AmmoTypes[mag->ubAmmoType]; + if (at) + { + if (at->standardIssue < 1 || at->highExplosive > 0) + continue; + } + + if (mag->ubCalibre == weapon->ubCalibre) + { + if (mag->ubMagSize == weapon->ubMagSize) + { + candidates.push_back(*it); + } + } + } + + if (candidates.size() < 1) + return NULL; + + return candidates[Random(candidates.size())]; +} + +//find attachments that match our weapon, that we are allowed to select +std::vector GearFindAttachmentsForWeapon(INVTYPE* weapon, BOOL attach_grip, BOOL attach_muzzle, BOOL attach_laser, BOOL attach_sight, BOOL attach_underbarrel) +{ + std::vector result; + std::vector candidates[5]; + + if (!weapon) + return result; + + for (std::vector::iterator it = gear_attachments.begin(); it != gear_attachments.end(); it++) + { + INVTYPE* item = *it; + + if (item->attachment < 1) + continue; + + if (!ValidAttachment(item->uiIndex, weapon->uiIndex)) + continue; + + if (attach_grip && item->attachmentclass == AC_BIPOD) candidates[0].push_back(item); + if (attach_grip && item->attachmentclass == AC_FOREGRIP) candidates[0].push_back(item); + if (attach_muzzle && item->attachmentclass == AC_MUZZLE) candidates[1].push_back(item); + if (attach_laser && item->attachmentclass == AC_LASER) candidates[2].push_back(item); + if (attach_sight && item->attachmentclass == AC_SIGHT) candidates[3].push_back(item); + if (attach_sight && item->attachmentclass == AC_SCOPE) candidates[3].push_back(item); + if (attach_underbarrel && item->attachmentclass == AC_UNDERBARREL) candidates[4].push_back(item); + } + + for (int i = 0; i < 5; i++) + { + if (candidates[i].size() > 0) + { + result.push_back(candidates[i][ Random(candidates[i].size()) ]); + } + } + + return result; +} + +//find items that this role could use (medkits for doctors, etc) +std::vector GearFindItemsForRole(std::vector* roles, std::vector* traits) +{ + std::vector result; + INT8 tracker[9] = {0}; + + for (std::vector::iterator it = gear_misc.begin(); it != gear_misc.end(); it++) + { + INVTYPE* item = *it; + INT8 chance = 0; + + if (item->glgrenade > 0) + continue; + + if (item->attachmentclass == AC_GRENADE || item->attachmentclass == AC_ROCKET) + continue; + + chance = Random(100) - (HasTrait(traits, MARTIAL_ARTS_NT) * 25) - 2; + if (item->usItemClass == IC_PUNCH && chance < 0 && tracker[0] < 1) { result.push_back(item); tracker[0]++; } + + chance = Random(100) - (HasTrait(traits, MELEE_NT) * 25) - 2; + if (item->usItemClass == IC_BLADE && chance < 0 && tracker[1] < 1) { result.push_back(item); tracker[1]++; } + + chance = Random(100) - (HasTrait(traits, THROWING_NT) * 25) - 2; + if (item->usItemClass == IC_THROWING_KNIFE && chance < 0 && tracker[2] < 2) { result.push_back(item); tracker[2]++; } + + chance = Random(100) - (HasTrait(traits, DEMOLITIONS_NT) * 45) - 1; + if (item->usItemClass == IC_BOMB && chance < 0 && tracker[3] < 1) { result.push_back(item); tracker[3]++; } + + chance = Random(100) - (HasTrait(traits, DOCTOR_NT) * 40) - 1; + if (item->usItemClass == IC_MEDKIT && chance < 0 && tracker[4] < 2) { result.push_back(item); tracker[4]++; } + + chance = Random(100) - (HasTrait(traits, TECHNICIAN_NT) * 40) - 1; + if (item->usItemClass == IC_KIT && chance < 0 && tracker[5] < 2) { result.push_back(item); tracker[5]++; } + + chance = Random(100) - 3; + if (item->usItemClass == IC_APPLIABLE && chance < 0 && tracker[6] < 2) { result.push_back(item); tracker[6]++; } + + chance = Random(100) - 3; + if (item->usItemClass == IC_MONEY && chance < 0 && tracker[7] < 1) { result.push_back(item); tracker[7]++; } + + chance = Random(100) - (HasTrait(traits, DEMOLITIONS_NT) * 30) - 5; + if (item->usItemClass == IC_GRENADE && chance < 0 && tracker[8] < 3) { result.push_back(item); tracker[8]++; } + } + + return result; +} + +//LBE helper stuff +UINT16 LBECountPocketsOfSize(LBETYPE* lbe, UINT16 size) +{ + UINT16 count = 0; + + for (std::vector::iterator it = lbe->lbePocketIndex.begin(); it != lbe->lbePocketIndex.end(); it++) + { + count += LBEPocketType[*it].ItemCapacityPerSize[size]; + } + + return count; +} + +//LBE helper stuff +UINT16 LBEGetItemSize(INVTYPE* item) +{ + if (!item) + return 0; + + return item->ItemSize; +} + +//attempt to find an LBE item that can fit all the specified items at once +INVTYPE* LBEFindSuitableLBE(std::map storage, UINT16 lbe_type) +{ + std::vector candidates; + + for (std::vector::iterator it = gear_lbe.begin(); it != gear_lbe.end(); it++) + { + LBETYPE* lbe = &LoadBearingEquipment[(*it)->ubClassIndex]; + + if (lbe->lbeClass != lbe_type) + continue; + + if (lbe) + { + bool valid = true; + + for (std::map::iterator sub_it = storage.begin(); sub_it != storage.end(); sub_it++) + { + if (LBECountPocketsOfSize(lbe, sub_it->first) < sub_it->second) + valid = false; + } + + if (valid) + { + candidates.push_back(*it); + } + } + } + + if (candidates.size() < 1) + return NULL; + + return candidates[Random(candidates.size())]; +} + +//sort helper function +BOOL sort_cmp(UINT16 i, UINT16 j) { return (i < j); } + +//this is the main randomization function that calls almost all the other functions. +void RandomizeMerc(UINT8 profile_id, MERCPROFILESTRUCT* merc) +{ + //reset merc's stats to basic values so we can increase them + merc->bExpLevel = 1; + merc->bAgility = 1; + merc->bLifeMax = 1; merc->bLife = merc->bLifeMax; + merc->bDexterity = 1; + merc->bStrength = 1; + merc->bWisdom = 1; + merc->bMarksmanship = 1; + merc->bLeadership = 0; + merc->bMechanical = 0; + merc->bExplosive = 0; + merc->bMedical = 0; + memset(merc->bSkillTraits, 0, sizeof(merc->bSkillTraits)); + + //determine character level and points (absolute maximum = 666 points) + merc->bExpLevel = Random(9) + 1; + INT16 points = 350 + (merc->bExpLevel * 20) + Random(150); + + //determine roles and traits + UINT8 roles_to_grant = 1 + Random((UINT16)((float)merc->bExpLevel / 2.0f)); + if (roles_to_grant > 3) roles_to_grant = 3; + UINT8 max_major_traits = 2 + Random((UINT16)((float)merc->bExpLevel / 2.0f)) + Random(2); if (max_major_traits > 5) max_major_traits = 5; + UINT8 max_minor_traits = 2 + Random((UINT16)((float)merc->bExpLevel / 2.0f)) + Random(2); if (max_minor_traits > 3) max_minor_traits = 3; + FLOAT max_combat_traits = 4.5f; + + std::vector roles = GrantRoles(roles_to_grant); + std::vector traits; + + //spend our points budget + UINT16 tries = 0; + + while (tries++ < 1000) + { + if (points < 1) + break; + + UINT8 decider = Random(100); + + if (decider < 30) //30% chance to assign a totally random stat + { + UINT8 result = IncreaseStat(merc, GetRandomNumberForRole(roles[ROLE_GENERIC])); + if (result > 0) + points -= result; + } + else //business as usual, find a random role we have and assign a point to one of its attributes + { + UINT8 role_to_increase = Random(roles.size()); + UINT8 result = IncreaseStat(merc, GetRandomNumberForRole(roles[role_to_increase])); + if (result > 0) + points -= result; + } + } + + //test for major traits + for (int i = 1; i < 10; i++) + { + UINT8 trait = TestForTrait(i, merc, &roles, &traits); + if (trait > 0 && traits.size() < max_major_traits && CountCombatTraits(&traits) < max_combat_traits) + { + traits.push_back(trait); + + trait = TestForTrait(i, merc, &roles, &traits); //test for second level + if (trait > 0 && traits.size() < max_major_traits && CountCombatTraits(&traits) < max_combat_traits) + { + traits.push_back(trait); + } + } + } + + //test for minor traits + for (int i = 10; i < 20; i++) { UINT8 trait = TestForTrait(i, merc, &roles, &traits); if (trait > 0 && traits.size() < max_minor_traits && CountCombatTraits(&traits) < max_combat_traits) { traits.push_back(trait); } } + + //assign us the traits we earned + UINT8 num_traits = 0; + for (std::vector::iterator it = traits.begin(); it != traits.end(); it++) + { + merc->bSkillTraits[num_traits++] = *it; + } + + //make sure some stats are at a BARE minimum + if (merc->bLifeMax < 60) { merc->bLifeMax = 60 + Random(20); merc->bLife = merc->bLifeMax; } + if (merc->bAgility < 60) merc->bAgility = 60 + Random(20); + if (merc->bStrength < 40) merc->bStrength = 40 + Random(30); + if (merc->bMarksmanship < 60) merc->bMarksmanship = 60 + Random(20); + if (merc->bDexterity < 40) merc->bDexterity = 40 + Random(20); + if (merc->bWisdom < 50) merc->bWisdom = 50 + Random(20); + + //calculate how much this soldier will make + FLOAT salary = -100; + + salary += (merc->bExpLevel - 1) * 150; + salary += merc->bAgility * 1.2f; + salary += merc->bLifeMax * 1.0f; + salary += merc->bDexterity * 1.0f; + salary += merc->bStrength * 1.0f; + salary += merc->bWisdom * 1.0f; + salary += merc->bMarksmanship * 1.3f; + salary += merc->bLeadership * 1.0f; + salary += merc->bMechanical * 1.0f; + salary += merc->bExplosive * 1.0f; + salary += merc->bMedical * 1.0f; + salary += traits.size() * 40.0f; + salary += CountCombatTraits(&traits) * 50.0f; //combat traits count double. + + merc->sSalary = (INT16)salary; + merc->sTrueSalary = merc->sSalary; + merc->uiWeeklySalary = (UINT32)(salary * 6.0f); + merc->uiBiWeeklySalary = (UINT32)(salary * 11.0f); + merc->sMedicalDepositAmount = 0; //disabled now. + merc->bMedicalDeposit = false; + + //generate gear kits for the merc + for (UINT8 kit_id = 0;kit_id < 5; kit_id++) + { + std::map storage[3]; //this will hold all the items we need to store in LBE. + + GearKitClear(profile_id, kit_id); + + UINT16 kit_cost = 0; + INT8 min_kit_level = (kit_id / 2) + (merc->bExpLevel / 4); if (min_kit_level < 1) min_kit_level = 1; + INT8 max_kit_level = 1 + (kit_id) + (merc->bExpLevel / 4); if (max_kit_level > 7) max_kit_level = 7; + + //assign armor + UINT8 preferred_camo = Random(5) + 1; + kit_cost += GearSetSlot(profile_id, kit_id, HELMETPOS, GearGetRandomArmor(&gear_helmets, min_kit_level, max_kit_level, preferred_camo, (preferred_camo == CAMO_ARMOR) ? 10 : 5)); + kit_cost += GearSetSlot(profile_id, kit_id, VESTPOS, GearGetRandomArmor(&gear_vests, min_kit_level, max_kit_level, preferred_camo, (preferred_camo == CAMO_ARMOR) ? 25 : 5)); + kit_cost += GearSetSlot(profile_id, kit_id, LEGPOS, GearGetRandomArmor(&gear_leggings, min_kit_level, max_kit_level, preferred_camo, (preferred_camo == CAMO_ARMOR) ? 10 : 5)); + + UINT8 head1 = Random(24) - (merc->bExpLevel / 3) - max_kit_level; + if (head1 < 1) + kit_cost += GearSetSlot(profile_id, kit_id, HEAD1POS, GearGetRandomFaceItem(min_kit_level, max_kit_level, FACEITEM_GAS_MASK)); + else if (head1 < 4) + kit_cost += GearSetSlot(profile_id, kit_id, HEAD1POS, GearGetRandomFaceItem(min_kit_level, max_kit_level, FACEITEM_HEADSET)); + else if (HasRole(&roles, ROLE_LEADER) && head1 < 15) //leaders get an extra chance to get a headset + kit_cost += GearSetSlot(profile_id, kit_id, HEAD1POS, GearGetRandomFaceItem(min_kit_level, max_kit_level, FACEITEM_HEADSET)); + + //assign face gear + UINT8 head2 = Random(24) - (merc->bExpLevel / 3) - max_kit_level; + if (head2 < 1) + kit_cost += GearSetSlot(profile_id, kit_id, HEAD2POS, GearGetRandomFaceItem(min_kit_level, max_kit_level, FACEITEM_NVG)); + else if (HasTrait(&traits, STEALTHY_NT) && head2 < 3) + kit_cost += GearSetSlot(profile_id, kit_id, HEAD2POS, GearGetRandomFaceItem(min_kit_level, max_kit_level, FACEITEM_NVG)); + else if (HasTrait(&traits, NIGHT_OPS_NT) && head2 < 5) + kit_cost += GearSetSlot(profile_id, kit_id, HEAD2POS, GearGetRandomFaceItem(min_kit_level, max_kit_level, FACEITEM_NVG)); + else if (head2 < 5) + kit_cost += GearSetSlot(profile_id, kit_id, HEAD2POS, GearGetRandomFaceItem(min_kit_level, max_kit_level, FACEITEM_SPECTACLES)); + + if (kit_id == 0) //kit 1 is always a pistol + { + kit_cost += GearSetSlot(profile_id, kit_id, HANDPOS, GearGetRandomWeapon(min_kit_level, max_kit_level, GUN_PISTOL, -1)); + } + else if (kit_id == 1 || kit_id == 2) //kit 2 and 3 are randomly a shotgun, machinepistol or smg + { + UINT8 rnd = Random(2); + + if (rnd == 1) + kit_cost += GearSetSlot(profile_id, kit_id, HANDPOS, GearGetRandomWeapon(min_kit_level, max_kit_level - 1, GUN_SHOTGUN, -1)); + else if (rnd == 2) + kit_cost += GearSetSlot(profile_id, kit_id, HANDPOS, GearGetRandomWeapon(min_kit_level, max_kit_level - 1, GUN_M_PISTOL, -1)); + else + kit_cost += GearSetSlot(profile_id, kit_id, HANDPOS, GearGetRandomWeapon(min_kit_level, max_kit_level - 1, GUN_SMG, -1)); + } + else //last 2 kits hold role specific weapons if applicable. + { + kit_cost += GearSetSlot(profile_id, kit_id, HANDPOS, GearGetRandomWeaponForRole(&roles, &traits, min_kit_level, max_kit_level)); + } + + //deal out potential sidearm, ammo and attachments to the main weapon + INVTYPE* hand_item = GearGetSlot(profile_id, kit_id, HANDPOS); + + if (hand_item) + { + WEAPONTYPE* weapon = &Weapon[hand_item->ubClassIndex]; + BOOL got_second_pistol = false; + + //ambidexterity has a chance of giving them a second pistol, if they have one. + if (weapon->ubWeaponType == GUN_PISTOL && Random(5) < 3 && HasTrait(&traits, AMBIDEXTROUS_NT)) + { + kit_cost += GearSetSlot(profile_id, kit_id, SECONDHANDPOS, hand_item); + got_second_pistol = true; + } + + //ammo + INVTYPE* ammo = GearFindAmmoForWeapon(weapon); + if (ammo) + { + MAGTYPE* mag = &Magazine[ammo->ubClassIndex]; + UINT8 bullets = (UINT8)(Random(50) + 50) + ((got_second_pistol) ? 30 : 0); + UINT8 mags = (UINT8)(bullets / mag->ubMagSize); if (mags < 1) mags = 1; if (mags > 8) mags = 8; + UINT8 mags_per_slot = (UINT8)(60 / mag->ubMagSize); if (mags_per_slot < 1) mags_per_slot = 1; if (mags_per_slot > 4) mags_per_slot = 4; + UINT8 pos = 0; + UINT8 runs = 0; + + while (mags > 0) + { + if (mags < mags_per_slot) + mags_per_slot = mags; + + kit_cost += GearSetSlot(profile_id, kit_id, SMALLPOCK17POS + pos, ammo, mags_per_slot); + for (int i = 0; i < mags_per_slot; i++) { storage[0][ LBEGetItemSize(ammo) ]++; } + + mags -= mags_per_slot; + pos++; + runs++; + + if (runs > 2) + break; + } + } + + //sidearm for snipers/rifle users (50% chance), and sometimes to just someone randomly (10% chance). + if (((weapon->ubWeaponType == GUN_SN_RIFLE || weapon->ubWeaponType == GUN_SN_RIFLE) && Random(2) < 1) || (Random(10) < 1 && weapon->ubWeaponType != GUN_PISTOL)) + { + INVTYPE* pistol = GearGetRandomWeapon(min_kit_level, max_kit_level - 1, GUN_PISTOL, -1); + + if (pistol) + { + kit_cost += GearSetSlot(profile_id, kit_id, SECONDHANDPOS, pistol); + storage[1][ LBEGetItemSize(pistol) ]++; + + weapon = &Weapon[pistol->ubClassIndex]; + ammo = GearFindAmmoForWeapon(weapon); + + if (ammo) + { + kit_cost += GearSetSlot(profile_id, kit_id, MEDPOCK2POS, ammo, 2); + for (int i = 0; i < 2; i++) { storage[0][ LBEGetItemSize(ammo) ]++; } + } + } + } + + //attachments + INT8 attach_grip = (BOOL)(Random(8) - Random((merc->bExpLevel / 2)) - Random(kit_id) - 1); + INT8 attach_muzzle = (BOOL)(Random(20) - Random((merc->bExpLevel / 2)) - Random(kit_id) - 0); + INT8 attach_laser = (BOOL)(Random(15) - Random((merc->bExpLevel / 2)) - Random(kit_id) - 1); + INT8 attach_sight = (BOOL)(Random(10) - Random((merc->bExpLevel / 2)) - Random(kit_id) - 1); + INT8 attach_underbarrel = (BOOL)(Random(15) - Random((merc->bExpLevel / 2)) - Random(kit_id) - 0); + std::vector attachments = GearFindAttachmentsForWeapon(hand_item, (BOOL)(attach_grip < 0), (BOOL)(attach_muzzle < 0), (BOOL)(attach_laser < 0), (BOOL)(attach_sight < 0), (BOOL)(attach_underbarrel < 0)); + + UINT8 count = 0; + for (std::vector::iterator it = attachments.begin(); it != attachments.end(); it++) + { + kit_cost += GearSetSlot(profile_id, kit_id, SMALLPOCK23POS + count++, (*it)); + storage[2][ LBEGetItemSize(*it) ]++; + } + } + + //assign random stuff based on role etc + std::vector misc_items = GearFindItemsForRole(&roles, &traits); + + UINT8 count = 0; + for (std::vector::iterator it = misc_items.begin(); it != misc_items.end(); it++) + { + kit_cost += GearSetSlot(profile_id, kit_id, SMALLPOCK1POS + count++, (*it)); + storage[1][ LBEGetItemSize(*it) ] += 1; + } + + //LBE: + //storage[0] holds the sizes and counts for ammo. => vest + //storage[1] holds the sizes and counts for potential sidearm and "kits" => combat pack + //storage[2] holds the sizes and counts for attachments => thigh packs + + INVTYPE* lbe_vest = LBEFindSuitableLBE(storage[0], VEST_PACK); + INVTYPE* lbe_cpack = LBEFindSuitableLBE(storage[1], COMBAT_PACK); + INVTYPE* lbe_thigh = LBEFindSuitableLBE(storage[2], THIGH_PACK); + + if (lbe_vest) + kit_cost += GearSetSlot(profile_id, kit_id, VESTPOCKPOS, lbe_vest); + + if (lbe_cpack) + kit_cost += GearSetSlot(profile_id, kit_id, CPACKPOCKPOS, lbe_cpack); + + if (lbe_thigh) + kit_cost += GearSetSlot(profile_id, kit_id, LTHIGHPOCKPOS, lbe_thigh); + + //sometimes we get the second thigh slot + if ((Random(10) - max_kit_level) < 5) kit_cost += GearSetSlot(profile_id, kit_id, RTHIGHPOCKPOS, GearGetRandomLBE(min_kit_level, max_kit_level, THIGH_PACK)); + + //tally up costs of kit + kit_cost = kit_cost * (1 + (max_kit_level / 10)); + GearKitSetPrice(profile_id, kit_id, kit_cost); + + //make sure this is set to the price of the FIRST gear set and you'll be fine. + if (kit_id == 0) + merc->usOptionalGearCost = kit_cost; + } +} + diff --git a/Tactical/Soldier Profile.cpp b/Tactical/Soldier Profile.cpp index 8731bb4b..ba19b219 100644 --- a/Tactical/Soldier Profile.cpp +++ b/Tactical/Soldier Profile.cpp @@ -106,6 +106,12 @@ extern UINT8 gubItemDroppableFlag[NUM_INV_SLOTS]; RANDOM_STATS_VALUES gRandomStatsValue[NUM_PROFILES]; void RandomStats(); void RandomStartSalary(); + +//Jenilee +extern void RandomizeMerc(UINT8 profile_id, MERCPROFILESTRUCT* merc); +extern void InitRandomMercs(); +extern void ExitRandomMercs(); + INT32 RandomAbsoluteRange( INT32 iValue, INT32 iMin, INT32 iMax, INT32 iRange, BOOLEAN fBellCurve ); INT8 RandomPercentRange( UINT8 iPRange, BOOLEAN fBellCurve ); @@ -584,6 +590,19 @@ void RandomStats() } } } + // Jenilee: 4th method (see also RandomMerc.cpp) + else if (gGameExternalOptions.ubMercRandomStats == 4) + { + InitRandomMercs(); + + for ( cnt = 0; cnt < NUM_PROFILES; cnt++ ) + { + pProfile = &(gMercProfiles[cnt]); + RandomizeMerc(cnt, pProfile); + } + + ExitRandomMercs(); + } } void RandomStartSalary() diff --git a/Tactical/Tactical_VS2005.vcproj b/Tactical/Tactical_VS2005.vcproj index ab03a80c..85893eff 100644 --- a/Tactical/Tactical_VS2005.vcproj +++ b/Tactical/Tactical_VS2005.vcproj @@ -892,6 +892,10 @@ RelativePath=".\Rain.cpp" > + + diff --git a/Tactical/Tactical_VS2008.vcproj b/Tactical/Tactical_VS2008.vcproj index b33e0b55..ca10aa90 100644 --- a/Tactical/Tactical_VS2008.vcproj +++ b/Tactical/Tactical_VS2008.vcproj @@ -894,6 +894,10 @@ RelativePath="Rain.cpp" > + + diff --git a/Tactical/Tactical_VS2010.vcxproj b/Tactical/Tactical_VS2010.vcxproj index 309b6560..1d6faac2 100644 --- a/Tactical/Tactical_VS2010.vcxproj +++ b/Tactical/Tactical_VS2010.vcxproj @@ -162,6 +162,7 @@ + diff --git a/Tactical/Tactical_VS2010.vcxproj.filters b/Tactical/Tactical_VS2010.vcxproj.filters index b2e742b5..fec1b39a 100644 --- a/Tactical/Tactical_VS2010.vcxproj.filters +++ b/Tactical/Tactical_VS2010.vcxproj.filters @@ -656,5 +656,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/Tactical/Tactical_VS2013.vcxproj b/Tactical/Tactical_VS2013.vcxproj index 693e9c04..96ab145b 100644 --- a/Tactical/Tactical_VS2013.vcxproj +++ b/Tactical/Tactical_VS2013.vcxproj @@ -162,6 +162,7 @@ + @@ -252,7 +253,7 @@ StaticLibrary true NotSet - v100 + v120 StaticLibrary diff --git a/Tactical/Tactical_VS2013.vcxproj.filters b/Tactical/Tactical_VS2013.vcxproj.filters index b2e742b5..fec1b39a 100644 --- a/Tactical/Tactical_VS2013.vcxproj.filters +++ b/Tactical/Tactical_VS2013.vcxproj.filters @@ -656,5 +656,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/TacticalAI/TacticalAI_VS2013.vcxproj b/TacticalAI/TacticalAI_VS2013.vcxproj index e72f45b8..67be2a4e 100644 --- a/TacticalAI/TacticalAI_VS2013.vcxproj +++ b/TacticalAI/TacticalAI_VS2013.vcxproj @@ -57,7 +57,7 @@ StaticLibrary true NotSet - v100 + v120 StaticLibrary diff --git a/TileEngine/TileEngine_VS2013.vcxproj b/TileEngine/TileEngine_VS2013.vcxproj index c14353d6..595991b8 100644 --- a/TileEngine/TileEngine_VS2013.vcxproj +++ b/TileEngine/TileEngine_VS2013.vcxproj @@ -116,7 +116,7 @@ StaticLibrary true NotSet - v100 + v120 StaticLibrary diff --git a/Utils/Utils_VS2013.vcxproj b/Utils/Utils_VS2013.vcxproj index c909f291..38dda35d 100644 --- a/Utils/Utils_VS2013.vcxproj +++ b/Utils/Utils_VS2013.vcxproj @@ -146,7 +146,7 @@ StaticLibrary true NotSet - v100 + v120 StaticLibrary diff --git a/ext/VFS/build/7z_VS2013.vcxproj b/ext/VFS/build/7z_VS2013.vcxproj index 46ff29a5..f80b70e4 100644 --- a/ext/VFS/build/7z_VS2013.vcxproj +++ b/ext/VFS/build/7z_VS2013.vcxproj @@ -103,7 +103,7 @@ StaticLibrary true NotSet - v100 + v120 StaticLibrary diff --git a/ext/VFS/build/VFS_VS2013.vcxproj b/ext/VFS/build/VFS_VS2013.vcxproj index d968e7f5..faf0b807 100644 --- a/ext/VFS/build/VFS_VS2013.vcxproj +++ b/ext/VFS/build/VFS_VS2013.vcxproj @@ -108,7 +108,7 @@ StaticLibrary true NotSet - v100 + v120 StaticLibrary diff --git a/ext/export/ja2export_VS2013.vcxproj b/ext/export/ja2export_VS2013.vcxproj index 870d2e41..bd4e7554 100644 --- a/ext/export/ja2export_VS2013.vcxproj +++ b/ext/export/ja2export_VS2013.vcxproj @@ -25,7 +25,7 @@ Application true NotSet - v100 + v120 Application diff --git a/ext/libpng/projects/visualc71/libpng_VS2013.vcxproj b/ext/libpng/projects/visualc71/libpng_VS2013.vcxproj index e07e7050..c086e091 100644 --- a/ext/libpng/projects/visualc71/libpng_VS2013.vcxproj +++ b/ext/libpng/projects/visualc71/libpng_VS2013.vcxproj @@ -58,7 +58,7 @@ StaticLibrary true NotSet - v100 + v120 StaticLibrary diff --git a/ext/libpng/projects/visualc71/zlib_VS2013.vcxproj b/ext/libpng/projects/visualc71/zlib_VS2013.vcxproj index 986ba6fd..b730da14 100644 --- a/ext/libpng/projects/visualc71/zlib_VS2013.vcxproj +++ b/ext/libpng/projects/visualc71/zlib_VS2013.vcxproj @@ -69,7 +69,7 @@ StaticLibrary true NotSet - v100 + v120 StaticLibrary diff --git a/ja2_VS2013.vcxproj b/ja2_VS2013.vcxproj index 80c95dac..5f1fbde4 100644 --- a/ja2_VS2013.vcxproj +++ b/ja2_VS2013.vcxproj @@ -33,7 +33,7 @@ Application true NotSet - v100 + v120 Application diff --git a/lua/lua_VS2013.vcxproj b/lua/lua_VS2013.vcxproj index 54817860..6c0182a8 100644 --- a/lua/lua_VS2013.vcxproj +++ b/lua/lua_VS2013.vcxproj @@ -57,7 +57,7 @@ StaticLibrary true NotSet - v100 + v120 StaticLibrary