8000 Feature: #4838 Added Faction Standing System by IllianiBird · Pull Request #7071 · MegaMek/mekhq · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Feature: #4838 Added Faction Standing System #7071

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 39 commits into from
May 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
f371ac4
Deprecated FameAndInfamyController.java, moved BatchallFactions.java
IllianiBird May 19, 2025
cbb05ec
Created FactionStanding.java and associated ResourceBundle and Unit T…
IllianiBird May 19, 2025
31dd02e
Created FactionStandings.java
IllianiBird May 19, 2025
c010884
Merge branch 'master' into factionStanding
IllianiBird May 19, 2025
b9988ea
Initial faction standing reporting work
IllianiBird May 19, 2025
8f00fc2
Added more tests, removed 'ally of my enemy' modifier from Starting S…
IllianiBird May 19, 2025
f692e98
Cleaned up some bugs related to degradation and standing level. Clean…
IllianiBird May 19, 2025
c3ac50c
Merge branch 'master' into factionStanding
IllianiBird May 20, 2025
ec30bc7
Post merge fixes
IllianiBird May 20, 2025
960b1a1
Set up the internal campaign options stuff; refactored loading and sa…
IllianiBird May 20, 2025
02da9c2
Merge branch 'systemsTab' into factionStanding
IllianiBird May 20, 2025
0e82202
Added campaign options gui support for Faction Standing
IllianiBird May 20, 2025
b310b89
Merge branch 'master' into factionStanding
IllianiBird May 20, 2025
a7c1d6f
Added constants for Fame gain & loss
IllianiBird May 20, 2025
15f0304
Added constants for Fame gain & loss
IllianiBird May 20, 2025
5484368
Added constants for Fame gain & loss
IllianiBird May 20, 2025
4314b2f
Added a handful of new methods for Fame change
IllianiBird May 20, 2025
4b14f2a
Hooked in batchall refusal
IllianiBird May 20, 2025
460b368
Added some missing tests & legal statement updates
IllianiBird May 21, 2025
c2ec315
Fixed JavaDocs
IllianiBird May 21, 2025
5719f19
Copilot suggestions
IllianiBird May 21, 2025
b1a394e
Added minimum and maximum fame scores
IllianiBird May 21, 2025
b650034
Added minimum and maximum fame scores
IllianiBird May 21, 2025
b4240d1
Rebalanced Fame gains and losses
IllianiBird May 21, 2025
2d2b6b9
Adjusted standings tiers and caps
IllianiBird May 21, 2025
80382ee
Added support for pirate campaigns; spoilers, nobody likes you
IllianiBird May 21, 2025
d77152b
Added support for extinct faction filtering
IllianiBird May 21, 2025
51c89f8
Added support for dynamic Fame changes based on political climate
IllianiBird May 22, 2025
d08e5ae
Added missing getters
IllianiBird May 22, 2025
c36d163
Restored missing Fame initialization
IllianiBird May 22, 2025
91a16ec
Updated Fame & Politics terms to Regard & Climate, updated functionality
IllianiBird May 22, 2025
6c3ef8f
Updated documentation
IllianiBird May 22, 2025
0ff4bf0
Further refinements
IllianiBird May 22, 2025
7b1dfe4
Fixed failing tests
IllianiBird May 22, 2025
31f7512
Incorporated changes from later Faction Standing PRs
IllianiBird May 23, 2025
96c55c0
Merge branch 'master' into factionStanding
IllianiBird May 23, 2025
ead8805
Minor tweak to error log
IllianiBird May 23, 2025
ba2137f
Minor tweak to error log
IllianiBird May 23, 2025
30544cf
Merge branch 'master' into factionStanding
IllianiBird May 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1414,8 +1414,49 @@ lblReputationPerformanceModifierCutOff.tooltip=When using CamOps Reputation all
<br><b>Warning:</b> CamOps was never designed for campaigns lasting as long as those enjoyed by\
\ many users of MekHQ. This results in progressive Reputation bloat over a long enough period.\
<br>\
<br><b>Recommended</b>: This option helps ensure reputation doesn't spiral out of control. Leave\
<br><b>Recommended</b>: This option helps ensure Force Reputation doesn't spiral out of control. Leave\
\ enabled.
factionStanding.title=Faction Standing
lblFactionStanding.text=Faction Standing Options
factionStanding.border="Here a question arises: whether it is better to be loved than feared or the reverse. The answer\
\ is, of course, that it would be best to be both loved and feared. But since the two rarely come together, anyone\
\ compelled to choose will find greater security in being feared than in being loved."\
<br><i>Niccolo Machiavelli,\
<br>The Prince</i>
lblTrackFactionStanding.text=Enable Faction Standing \u270E \u2318 <span style="color:#00008b;">\u2605</span>
lblTrackFactionStanding.tooltip=This option enables the tracking of Faction Standing. Faction Standing represents how\
\ liked you are across the Inner Sphere. Actions such as taking contracts can increase or deminish your Standing. Full\
\ documentation can be found in the docs folder.
lblUseFactionStandingNegotiation.text=Standing Affects Negotiations <span style="color:#00008b;">\u2605</span>
lblUseFactionStandingNegotiation.tooltip=If enabled, contract negotiations will be influenced by your Standing with the\
\ employing Faction.
lblUseFactionStandingResupply.text=Standings Affects Resupplies <span style="color:#00008b;">\u2605</span>
lblUseFactionStandingResupply.tooltip=If enabled, the size of monthly Resupplies will be influenced by your Standing\
\ with your employer.
lblUseFactionStandingCommandCircuit.text=Enable Command Circuit <span style="color:#00008b;">\u2605</span>
lblUseFactionStandingCommandCircuit.tooltip=At high enough Standing, you will be granted access to a faction's Command\
\ Circuit. This significantly decreases travel time while in their territory.
lblUseFactionStandingOutlawed.text=Enable Outlawing <span style="color:#00008b;">\u2605</span>
lblUseFactionStandingOutlawed.tooltip=At very low Standing, a faction may declare you an Outlaw, preventing you from\
\ landing on their planets (unless on a contract against them).
lblUseFactionStandingBatchallRestrictions.text=Enable Batchall Restrictions <span style="color:#00008b;">\u2605</span>
lblUseFactionStandingBatchallRestrictions.tooltip=If your Standing with a Clan faction falls low enough, they will stop\
\ offering you Batchalls.
lblUseFactionStandingRecruitment.text=Standings Affects Recruitment <span style="color:#00008b;">\u2605</span>
lblUseFactionStandingRecruitment.tooltip=Your Standing with a faction influences how willing their people are to join\
\ your campaign and the number of recruits available on their planets.
lblUseFactionStandingBarracksCosts.text=Standing Affects Food & Housing <span style="color:#00008b;">\u2605</span>
lblUseFactionStandingBarracksCosts.tooltip=Your Standing with a faction influences the cost of food and housing while on\
\ their planets and while performing contracts for them.
lblUseFactionStandingUnitMarket.text=Standing Affects the Unit Market <span style="color:#00008b;">\u2605</span>
lblUseFactionStandingUnitMarket.tooltip=Standing with a faction influences how many units appear in the 'Employer Market'\
\ portion of the Unit Market.
lblUseFactionStandingContractPay.text=Standing Affects Contract Pay <span style="color:#00008b;">\u2605</span>
lblUseFactionStandingContractPay.tooltip=If enabled, Standing will slightly affect contract pay.
lblUseFactionStandingSupportPoints.text=Standing Affects Support Points <span style="color:#00008b;">\u2605</span>
lblUseFactionStandingSupportPoints.tooltip=If enabled, your Standing with a faction influences Support Point generation\
\ while on contract for that faction.
# Markets Tab
marketsContentTabs.title=Markets
personnelMarketTab.title=Personnel
personnelMarketTab.border=\u2014 Toilet Paper 22 Tons\
Expand Down
85 changes: 85 additions & 0 deletions MekHQ/resources/mekhq/resources/FactionStandings.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# STANDING LEVELS
## STANDING_LEVEL_0
factionStandingLevel.STANDING_LEVEL_0.i 8000 nnerSphere.label=An Enemy of the State
factionStandingLevel.STANDING_LEVEL_0.innerSphere.description=Hunted by authorities. Any affiliation is grounds for arrest or execution.
factionStandingLevel.STANDING_LEVEL_0.clan.label=An Enemy of the Clan
factionStandingLevel.STANDING_LEVEL_0.clan.description=Branded as a threat to the Clan way of life. Destruction is the only sentence.
factionStandingLevel.STANDING_LEVEL_0.comStar.label=An Anathema
factionStandingLevel.STANDING_LEVEL_0.comStar.description=Declared beyond salvation. All agents are authorized to terminate on sight.
## STANDING_LEVEL_1
factionStandingLevel.STANDING_LEVEL_1.innerSphere.label=Reviled
factionStandingLevel.STANDING_LEVEL_1.innerSphere.description=Your name alone sparks contempt. Few will speak to you, none will trust you.
factionStandingLevel.STANDING_LEVEL_1.clan.label=Dezgra
factionStandingLevel.STANDING_LEVEL_1.clan.description=True scum unworthy of social or battle honors.
factionStandingLevel.STANDING_LEVEL_1.comStar.label=A Blasphemer
factionStandingLevel.STANDING_LEVEL_1.comStar.description=You stand against the Blessed Word. ComStar denounces you as a defiler of faith.
## STANDING_LEVEL_2
factionStandingLevel.STANDING_LEVEL_2.innerSphere.label=Notorious
factionStandingLevel.STANDING_LEVEL_2.innerSphere.description=Feared and whispered about. Your reputation darkens every hangar you enter.
factionStandingLevel.STANDING_LEVEL_2.clan.label=Disgraced
factionStandingLevel.STANDING_LEVEL_2.clan.description=You are remembered only for your insults. No Clan warrior will honor your name.
factionStandingLevel.STANDING_LEVEL_2.comStar.label=An Enemy of Blake
factionStandingLevel.STANDING_LEVEL_2.comStar.description=Branded as an enemy of the faith, your presence invites censure.
## STANDING_LEVEL_3
factionStandingLevel.STANDING_LEVEL_3.innerSphere.label=Distrusted
factionStandingLevel.STANDING_LEVEL_3.innerSphere.description=Few believe in your loyalty. Every job comes with a watchful eye.
factionStandingLevel.STANDING_LEVEL_3.clan.label=Unworthy
factionStandingLevel.STANDING_LEVEL_3.clan.description=Viewed as lacking the steel of a true warrior. Barely tolerated, easily discarded.
factionStandingLevel.STANDING_LEVEL_3.comStar.label=Under Surveillance
factionStandingLevel.STANDING_LEVEL_3.comStar.description=Your movements are recorded, but there is no reason to intervene.
## STANDING_LEVEL_4 (neutral)
factionStandingLevel.STANDING_LEVEL_4.innerSphere.label=Unknown
factionStandingLevel.STANDING_LEVEL_4.innerSphere.description=You are a name without a reputation. No favors, no debts, no one cares.
factionStandingLevel.STANDING_LEVEL_4.clan.label=Unproven
factionStandingLevel.STANDING_LEVEL_4.clan.description=No blood, no honor, no record. You are nothing until tested in combat.
factionStandingLevel.STANDING_LEVEL_4.comStar.label=Unremarkable
factionStandingLevel.STANDING_LEVEL_4.comStar.description=You are unknown to the blessed servants of Blake.
## STANDING_LEVEL_5
factionStandingLevel.STANDING_LEVEL_5.innerSphere.label=An Acknowledged Asset
factionStandingLevel.STANDING_LEVEL_5.innerSphere.description=Your work is known and respected. You've earned a place on the roster.
factionStandingLevel.STANDING_LEVEL_5.clan.label=Proven
factionStandingLevel.STANDING_LEVEL_5.clan.description=You have shown you can fight. The Clans grant you cautious recognition.
factionStandingLevel.STANDING_LEVEL_5.comStar.label=In Good Standing
factionStandingLevel.STANDING_LEVEL_5.comStar.description=You are acknowledged as a useful tool.
## STANDING_LEVEL_6
factionStandingLevel.STANDING_LEVEL_6.innerSphere.label=A Trusted Operator
factionStandingLevel.STANDING_LEVEL_6.innerSphere.description=You deliver results and are trusted to get the job done.
factionStandingLevel.STANDING_LEVEL_6.clan.label=An Ally of the Clan
factionStandingLevel.STANDING_LEVEL_6.clan.description=You have earned respect. Warriors accept you as a worthy combat partner.
factionStandingLevel.STANDING_LEVEL_6.comStar.label=A Trusted Instrument
factionStandingLevel.STANDING_LEVEL_6.comStar.description=You are a reliable agent of the Blessed Order. Your actions serve the Word.
## STANDING_LEVEL_7
factionStandingLevel.STANDING_LEVEL_7.innerSphere.label=A Favored Ally
factionStandingLevel.STANDING_LEVEL_7.innerSphere.description=You are a trusted blade in the endless wars of the Inner Sphere.
factionStandingLevel.STANDING_LEVEL_7.clan.label=A True Warrior
factionStandingLevel.STANDING_LEVEL_7.clan.description=You fight with honor and skill. You are treated as kin by Clan warriors.
factionStandingLevel.STANDING_LEVEL_7.comStar.label=A Blessed Servant
factionStandingLevel.STANDING_LEVEL_7.comStar.description=You are a true servant of the Primus and trusted 6D40 with sacred tasks.
## STANDING_LEVEL_8
factionStandingLevel.STANDING_LEVEL_8.innerSphere.label=A Champion of the Realm
factionStandingLevel.STANDING_LEVEL_8.innerSphere.description=You are a living legend. Songs and stories bear your name.
factionStandingLevel.STANDING_LEVEL_8.clan.label=A Champion of the Clan
factionStandingLevel.STANDING_LEVEL_8.clan.description=You stand as a legend among warriors. Even the Khan knows who you are.
factionStandingLevel.STANDING_LEVEL_8.comStar.label=An Illuminated Agent of the Primus
factionStandingLevel.STANDING_LEVEL_8.comStar.description=You are the will of Blake made flesh. Your actions shape the destiny of the Inner Sphere.
# STANDING CHANGES
factionStandings.change.report=Your <b>Standing</b> with {0} has {1}<b>{2}</b>{3} by {4} <b>Fame</b>. {5}
factionStandings.change.report.milestone.new=You are now {0}<b>{1}</b>{2}.
factionStandings.change.report.milestone.same=You are still {0}<b>{1}</b>{2}.
factionStandings.change.report.unknownFaction=a faction
factionStandings.change.report.clan.check=Clan
factionStandings.change.report.clan.prefix=the
factionStandings.change.increased=increased
factionStandings.change.decreased=decreased
factionStandings.change.report.missingFaction={0}<b>Warning:</b>{1} the mission you just {2} does not have an <b>{3}</b>\
\ recorded. This is perfectly normal for contracts not generated via a MekHQ Digital GM. You should head to the\
\ <b>Faction Standing Report</b> and record this mission via the available buttons. If you don't, this mission will\
\ not count towards <b>Faction Standing</b>.
factionStandings.change.report.climate={0}<b>Warning:</b>{1} the political climate is affecting how factions view you:
factionStandings.change.report.climate.pirate={0}<b>Warning:</b>{1} being a pirate is affecting how factions view you.\
\ Any faction not listed has a {2}<b>{3}</b>{4} modifier to <b>Regard</b>:
factionStandings.change.accepted=accepted
factionStandings.change.completed=completed
factionStandings.change.employer=employer
factionStandings.change.enemy=enemy

77 changes: 59 additions & 18 deletions MekHQ/src/mekhq/campaign/Campaign.java
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,8 @@
import mekhq.campaign.universe.enums.HiringHallLevel;
import mekhq.campaign.universe.eras.Era;
import mekhq.campaign.universe.eras.Eras;
import mekhq.campaign.universe.fameAndInfamy.BatchallFactions;
import mekhq.campaign.universe.factionStanding.BatchallFactions;
import mekhq.campaign.universe.factionStanding.FactionStandings;
import mekhq.campaign.universe.fameAndInfamy.FameAndInfamyController;
import mekhq.campaign.universe.selectors.factionSelectors.AbstractFactionSelector;
import mekhq.campaign.universe.selectors.factionSelectors.DefaultFactionSelector;
Expand Down Expand Up @@ -400,12 +401,13 @@ public class Campaign implements ITechManager {
private int crimeRating;
private int crimePirateModifier;
private LocalDate dateOfLastCrime;
private FactionStandings factionStandings;
private int initiativeBonus;
private int initiativeMaxBonus;
private final CampaignSummary campaignSummary;
private final Quartermaster quartermaster;
private StoryArc storyArc;
private final FameAndInfamyController fameAndInfamy;
private final FameAndInfamyController regardAndInfamy;
private BehaviorSettings autoResolveBehaviorSettings;
private List<UUID> automatedMothballUnits;
private int temporaryPrisonerCapacity;
Expand Down Expand Up @@ -467,6 +469,7 @@ public Campaign() {
retainerEmployerCode = null;
retainerStartDate = null;
reputation = null;
factionStandings = new FactionStandings();
crimeRating = 0;
crimePirateModifier = 0;
dateOfLastCrime = null;
Expand Down Expand Up @@ -504,7 +507,7 @@ public Campaign() {
campaignSummary = new CampaignSummary(this);
quartermaster = new Quartermaster(this);
fieldKitchenWithinCapacity = false;
fameAndInfamy = new FameAndInfamyController();
regardAndInfamy = new FameAndInfamyController();
autoResolveBehaviorSettings = BehaviorSettingsFactory.getInstance().DEFAULT_BEHAVIOR;
automatedMothballUnits = new ArrayList<>();
temporaryPrisonerCapacity = DEFAULT_TEMPORARY_CAPACITY;
Expand Down Expand Up @@ -5057,10 +5060,23 @@ private void processNewDayATB() {

for (AtBContract contract : getActiveAtBContracts()) {
if (campaignOptions.isUseGenericBattleValue()) {
if (contract.getStartDate().equals(getLocalDate())) {
if (getCampaignOptions().isUseGenericBattleValue() &&
BatchallFactions.usesBatchalls(contract.getEnemyCode())) {
contract.setBatchallAccepted(contract.initiateBatchall(this));
if (contract.getStartDate().equals(currentDay)) {
String factionCode = contract.getEnemyCode();
if (BatchallFactions.usesBatchalls(factionCode)) {
if (contract.initiateBatchall(this)) {
contract.setBatchallAccepted(true);
} else {
contract.setBatchallAccepted(false);

if (campaignOptions.isTrackFactionStanding()) {
List<String> reports = factionStandings.processRefusedBatchall(factionCode,
currentDay.getYear());

for (String report : reports) {
addReport(report);
}
}
}
}
}
}
Expand Down Expand Up @@ -5596,6 +5612,8 @@ public boolean newDay() {
// Advance the day by one
final LocalDate yesterday = currentDay;
currentDay = currentDay.plusDays(1);
boolean isFirstOfMonth = currentDay.getDayOfMonth() == 1;
boolean isNewYear = currentDay.getDayOfYear() == 1;

// Check for important dates
if (campaignOptions.isShowLifeEventDialogCelebrations()) {
Expand All @@ -5616,12 +5634,18 @@ public boolean newDay() {
beginReport("<b>" + MekHQ.getMHQOptions().getLongDisplayFormattedDate(getLocalDate()) + "</b>");

// New Year Changes
if (currentDay.getDayOfYear() == 1) {
if (isNewYear) {
// News is reloaded
reloadNews();

// Change Year Game Option
getGameOptions().getOption(OptionsConstants.ALLOWED_YEAR).setValue(getGameYear());

// Degrade Regard
List<String> degradedRegardReports = factionStandings.processRegardDegradation(currentDay.getYear());
for (String report : degradedRegardReports) {
addReport(report);
}
}

readNews();
Expand All @@ -5640,9 +5664,8 @@ public boolean newDay() {
processNewDayPersonnel();

// Needs to be before 'processNewDayATB' so that Dependents can't leave the
// moment they
// arrive via AtB Bonus Events
if ((location.isOnPlanet()) && (currentDay.getDayOfMonth() == 1)) {
// moment they arrive via AtB Bonus Events
if (location.isOnPlanet() && isFirstOfMonth) {
RandomDependents randomDependents = new RandomDependents(this);
randomDependents.processMonthlyRemovalAndAddition();
}
Expand All @@ -5660,14 +5683,14 @@ public boolean newDay() {
processEducationNewDay();
}

if ((campaignOptions.isEnableAutoAwards()) && (currentDay.getDayOfMonth() == 1)) {
if (campaignOptions.isEnableAutoAwards() && isFirstOfMonth) {
AutoAwardsController autoAwardsController = new AutoAwardsController();
autoAwardsController.ManualController(this, false);
}

// Prisoner events can occur on Monday or the 1st of the month depending on the
// type of event
if (currentDay.getDayOfWeek() == DayOfWeek.MONDAY || currentDay.getDayOfMonth() == 1) {
if (currentDay.getDayOfWeek() == DayOfWeek.MONDAY || isFirstOfMonth) {
new PrisonerEventManager(this);
}

Expand All @@ -5685,7 +5708,7 @@ public boolean newDay() {
finances.newDay(this, yesterday, getLocalDate());

// process removal of old personnel data on the first day of each month
if ((campaignOptions.isUsePersonnelRemoval()) && (currentDay.getDayOfMonth() == 1)) {
if (campaignOptions.isUsePersonnelRemoval() && isFirstOfMonth) {
performPersonnelCleanUp();
}

Expand All @@ -5707,6 +5730,12 @@ public boolean newDay() {
new GrayMonday(this, currentDay);
}

// Faction Standing
if (isFirstOfMonth && campaignOptions.isTrackFactionStanding()) {
String report = factionStandings.updateClimateRegard(faction, currentDay);
addReport(report);
}

// This must be the last step before returning true
MekHQ.triggerEvent(new NewDayEvent(this));
return true;
Expand Down Expand Up @@ -6417,6 +6446,14 @@ public void setReputation(ReputationController reputation) {
this.reputation = reputation;
}

public FactionStandings getFactionStandings() {
return factionStandings;
}

public void setFactionStandings(FactionStandings factionStandings) {
this.factionStandings = factionStandings;
}

private void addInMemoryLogHistory(LogEntry le) {
if (!inMemoryLogHistory.isEmpty()) {
while (ChronoUnit.DAYS.between(inMemoryLogHistory.get(0).getDate(), le.getDate()) >
Expand Down Expand Up @@ -6576,7 +6613,7 @@ public List<String> getCurrentObjectives() {
}

public FameAndInfamyController getFameAndInfamy() {
return fameAndInfamy;
return regardAndInfamy;
}

/**
Expand Down Expand Up @@ -6666,6 +6703,10 @@ public void writeToXML(final PrintWriter writer) {
newPersonnelMarket.writePersonnelMarketDataToXML(writer, indent);
MHQXMLUtility.writeSimpleXMLCloseTag(writer, --indent, "newPersonnelMarket");

MHQXMLUtility.writeSimpleXMLOpenTag(writer, indent++, "factionStandings");
factionStandings.writeFactionStandingsToXML(writer, indent);
MHQXMLUtility.writeSimpleXMLCloseTag(writer, --indent, "factionStandings");

// this handles campaigns that predate 49.20
if (campaignStartDate == null) {
setCampaignStartDate(getLocalDate());
Expand Down Expand Up @@ -6767,9 +6808,9 @@ public void writeToXML(final PrintWriter writer) {
storyArc.writeToXml(writer, indent);
}

// Fame and Infamy
if (fameAndInfamy != null) {
fameAndInfamy.writeToXml(writer, indent);
// Regard and Infamy
if (regardAndInfamy != null) {
regardAndInfamy.writeToXml(writer, indent);
}

// Markets
Expand Down
Loading
Loading
0