Skip to content

Commit 95eb458

Browse files
authored
Merge pull request #7301 from IllianiBird/pirateAndMercenaryStartingLocationUpdate
Improvement: Updated Faction Starting Location Logic for Mercenary and Pirate Campaigns
2 parents 7802170 + 628c3b3 commit 95eb458

File tree

1 file changed

+124
-52
lines changed

1 file changed

+124
-52
lines changed

MekHQ/src/mekhq/campaign/Campaign.java

Lines changed: 124 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -251,8 +251,8 @@
251251
import mekhq.campaign.universe.factionStanding.FactionAccoladeLevel;
252252
import mekhq.campaign.universe.factionStanding.FactionCensureEvent;
253253
import mekhq.campaign.universe.factionStanding.FactionCensureLevel;
254-
import mekhq.campaign.universe.factionStanding.FactionStandingUltimatum;
255254
import mekhq.campaign.universe.factionStanding.FactionStandingJudgmentType;
255+
import mekhq.campaign.universe.factionStanding.FactionStandingUltimatum;
256256
import mekhq.campaign.universe.factionStanding.FactionStandingUtilities;
257257
import mekhq.campaign.universe.factionStanding.FactionStandings;
258258
import mekhq.campaign.universe.factionStanding.PerformBatchall;
@@ -6607,6 +6607,21 @@ public boolean isPirateCampaign() {
66076607
return faction.getShortName().equals(PIRATE_FACTION_CODE);
66086608
}
66096609

6610+
/**
6611+
* Determines whether the current campaign is a mercenary campaign.
6612+
*
6613+
* <p>This method checks if the faction associated with the campaign is Mercenary, returning {@code true} if it is,
6614+
* and {@code false} otherwise.</p>
6615+
*
6616+
* @return {@code true} if the campaign is Mercenary, {@code false} otherwise.
6617+
*
6618+
* @author Illiani
6619+
* @since 0.50.07
6620+
*/
6621+
public boolean isMercenaryCampaign() {
6622+
return faction.getShortName().equals(MERCENARY_FACTION_CODE);
6623+
}
6624+
66106625
public void setFaction(final Faction faction) {
66116626
setFactionDirect(faction);
66126627
updateTechFactionCode();
@@ -10275,79 +10290,136 @@ public List<Entity> getAllCombatEntities() {
1027510290
return units;
1027610291
}
1027710292

10278-
1027910293
/**
10280-
* Determines the appropriate starting planet for a new campaign.
10294+
* Determines the appropriate starting planet for a new campaign based on campaign type, faction, and various
10295+
* fallback scenarios.
1028110296
*
10282-
* <p>This method first attempts to obtain the starting planet from the campaign's primary method. If no valid
10283-
* system is found, or if the result is "Terra" (which is the default value used when no system is set), it selects
10284-
* a fallback faction's starting planet using the following logic:</p>
10297+
* <p>This method first checks if the campaign is classified as a mercenary or pirate campaign. If so, it
10298+
* delegates responsibility to {@link #getMercenaryOrPirateStartingPlanet(Factions, String)}, which implements
10299+
* special logic to handle those campaign types.</p>
1028510300
*
10286-
* <ul>
10287-
* <li>If the faction is "PIR", a random pirate faction (other than "PIR" itself) with an available starting
10288-
* planet is chosen, if available.</li>
10289-
* <li>If the faction is a clan, the generic "CLAN" faction is used as the fallback.</li>
10290-
* <li>If the faction is mercenary, 75% of the time the campaign will begin on the mercenary faction
10291-
* capital. Otherwise, they will begin on the capital of another playable faction.</li>
10292-
* <li>Otherwise, the default faction (Mercenary) is used as the fallback.</li>
10293-
* </ul>
10301+
* <p>For all other campaign types, it uses the current campaign's faction to attempt to retrieve that faction’s
10302+
* canonical starting system for the current game date. If no valid system can be found (due to, for example, the
10303+
* faction not having a valid capital), the logic falls back to a default faction’s starting planet, and, if
10304+
* necessary, ultimately falls back to the planet Terra as a default universal location.</p>
1029410305
*
10295-
* <p>The returned result is always the system's primary planet.</p>
10306+
* <p>The method also includes special handling for Clan campaigns: if the fallback logic would result in the
10307+
* campaign starting on Terra but the campaign is clan-based, it attempts to relocate the starting planet to
10308+
* Strana Mechty.</p>
1029610309
*
10297-
* @return the {@link Planet} object representing the new campaign's starting planet
10310+
* @return the {@link Planet} instance where the campaign should start
1029810311
*
10299-
* @author Illiani
1030010312
* @since 0.50.07
10313+
* @author Illiani
1030110314
*/
1030210315
public Planet getNewCampaignStartingPlanet() {
1030310316
Factions factions = Factions.getInstance();
1030410317

10305-
PlanetarySystem startingSystem = faction.getStartingPlanet(this, currentDay);
10318+
final String TERRA_ID = "Terra";
10319+
final String CLAN_CODE = "CLAN";
10320+
10321+
Faction startingFaction;
10322+
PlanetarySystem startingSystem;
10323+
10324+
if (isMercenaryCampaign() || isPirateCampaign()) {
10325+
return getMercenaryOrPirateStartingPlanet(factions, TERRA_ID);
10326+
}
10327+
10328+
// Default for non-merc/pirate campaigns
10329+
startingFaction = faction;
10330+
startingSystem = startingFaction.getStartingPlanet(this, currentDay);
1030610331

10332+
// Fallback if the system is unavailable
1030710333
if (startingSystem == null) {
10308-
Faction fallbackFaction = factions.getDefaultFaction();
10309-
startingSystem = fallbackFaction.getStartingPlanet(this, currentDay);
10310-
} else if (startingSystem.getId().equalsIgnoreCase("Terra")) {
10311-
Faction fallbackFaction = factions.getDefaultFaction();
10312-
10313-
if (faction.getShortName().equalsIgnoreCase("PIR")) {
10314-
List<Faction> pirateFactions = new ArrayList<>();
10315-
for (Faction activeFaction : factions.getActiveFactions(currentDay)) {
10316-
if (activeFaction.isPirate() &&
10317-
!activeFaction.getShortName().equalsIgnoreCase("PIR")) {
10318-
pirateFactions.add(activeFaction);
10319-
}
10320-
}
10334+
startingFaction = factions.getDefaultFaction();
10335+
startingSystem = startingFaction.getStartingPlanet(this, currentDay);
10336+
if (startingSystem == null) {
10337+
startingSystem = Systems.getInstance().getSystemById(TERRA_ID);
10338+
}
10339+
}
1032110340

10322-
if (!pirateFactions.isEmpty()) {
10323-
fallbackFaction = ObjectUtility.getRandomItem(pirateFactions);
10341+
// Special case: Clan campaign starting on Terra, swap to Clan homeworld
10342+
if (TERRA_ID.equals(startingSystem.getId()) && isClanCampaign()) {
10343+
Faction clanFaction = factions.getFaction(CLAN_CODE);
10344+
if (clanFaction != null) {
10345+
PlanetarySystem clanSystem = clanFaction.getStartingPlanet(this, currentDay);
10346+
if (clanSystem != null) {
10347+
startingSystem = clanSystem;
1032410348
}
10325-
} else if (faction.isClan()) {
10326-
fallbackFaction = factions.getFaction("CLAN");
10327-
} else if (faction.getShortName().equalsIgnoreCase("MERC")) {
10328-
// Most of the time, mercenary campaigns will begin on their faction capital (Galatea, etc.).
10329-
// However, there is a 25% chance they begin in another faction's territory
10330-
int roll = randomInt(4);
10349+
}
10350+
}
1033110351

10332-
if (roll == 0) {
10333-
fallbackFaction = factions.getFaction("MERC");
10334-
} else {
10335-
List<Faction> recruitingFaction = new ArrayList<>();
10336-
for (Faction activeFaction : factions.getActiveFactions(currentDay)) {
10337-
if (activeFaction.isPlayable() && !activeFaction.isClan() && !activeFaction.isDeepPeriphery()) {
10338-
recruitingFaction.add(activeFaction);
10339-
}
10340-
}
10352+
return startingSystem.getPrimaryPlanet();
10353+
}
10354+
10355+
/**
10356+
* Selects a starting planet for mercenary or pirate campaigns by considering eligible factions, campaign date, and
10357+
* appropriate weighting for periphery factions (if pirate).
10358+
*
10359+
* <p>For mercenary campaigns, the designated mercenary faction is used as the initial fallback. For pirate
10360+
* campaigns, the Tortuga Dominions are preferred, but only if they are active at the campaign's start date;
10361+
* otherwise, the game's configured default faction is used (usually Mercenary, but I opted not to hardcode
10362+
* mercenary here incase the default changes).</p>
10363+
*
10364+
* <p>There is a two-thirds probability that the starting faction will be selected from all factions, subject to
10365+
* several filters (playability, not a Clan, not deep periphery). For pirate campaigns, eligible periphery factions
10366+
* are intentionally added multiple times to the selection pool to increase their likelihood of being chosen
10367+
* (weighted randomness).</p>
10368+
*
10369+
* <p>After the faction is chosen, this method attempts to get that faction’s canonical starting world. If no
10370+
* valid system is found, the logic falls back to Terra, ensuring that the campaign always has a valid starting
10371+
* world even in case of missing data.</p>
10372+
*
10373+
* @param factions The {@link Factions} manager supplying access to all faction data.
10374+
* @param TERRA_ID The globally unique identifier for the planet Terra, used for the ultimate fallback.
10375+
*
10376+
* @return the {@link Planet} used as the campaign start location.
10377+
*
10378+
* @author Illiani
10379+
* @since 0.50.07
10380+
*/
10381+
private Planet getMercenaryOrPirateStartingPlanet(Factions factions, String TERRA_ID) {
10382+
final String TORTUGA_CODE = "TD";
1034110383

10342-
if (!recruitingFaction.isEmpty()) {
10343-
fallbackFaction = ObjectUtility.getRandomItem(recruitingFaction);
10384+
PlanetarySystem startingSystem;
10385+
Faction startingFaction;
10386+
// Determine fallback faction for merc/pirate
10387+
startingFaction = isMercenaryCampaign()
10388+
? factions.getFaction(MERCENARY_FACTION_CODE)
10389+
: factions.getFaction(TORTUGA_CODE);
10390+
10391+
// If pirate fallback is unavailable at the campaign's start date, use the default faction
10392+
if (isPirateCampaign() && !startingFaction.validIn(currentDay)) {
10393+
startingFaction = factions.getDefaultFaction();
10394+
}
10395+
10396+
// 33% chance to start in fallback faction's capital
10397+
if (randomInt(3) != 0) {
10398+
// Pick a random, eligible recruiting faction
10399+
List<Faction> recruitingFactions = new ArrayList<>();
10400+
for (Faction possibleFaction : factions.getActiveFactions(currentDay)) {
10401+
if (possibleFaction.isPlayable() && !possibleFaction.isClan() && !possibleFaction.isDeepPeriphery()) {
10402+
recruitingFactions.add(possibleFaction);
10403+
10404+
// If we're playing a pirate campaign, we want to triple the chance that we start in the periphery
10405+
if (possibleFaction.isPeriphery() && isPirateCampaign()) {
10406+
recruitingFactions.add(possibleFaction);
10407+
recruitingFactions.add(possibleFaction);
1034410408
}
1034510409
}
1034610410
}
10411+
if (!recruitingFactions.isEmpty()) {
10412+
startingFaction = ObjectUtility.getRandomItem(recruitingFactions);
10413+
}
10414+
}
1034710415

10348-
startingSystem = fallbackFaction.getStartingPlanet(this, currentDay);
10416+
startingSystem = startingFaction.getStartingPlanet(this, currentDay);
10417+
if (startingSystem != null) {
10418+
return startingSystem.getPrimaryPlanet();
1034910419
}
1035010420

10351-
return startingSystem.getPrimaryPlanet();
10421+
// Fallback if no startingSystem
10422+
startingSystem = Systems.getInstance().getSystemById(TERRA_ID);
10423+
return startingSystem != null ? startingSystem.getPrimaryPlanet() : null;
1035210424
}
1035310425
}

0 commit comments

Comments
 (0)