Skip to content
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

Added ATOW Toughness Rule And Updated Fatigue And Injury Logic #6574

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
20 changes: 15 additions & 5 deletions MekHQ/data/universe/defaultspa.xml
Original file line number Diff line number Diff line change
Expand Up @@ -464,10 +464,20 @@
<ability>
<lookupName>flaw_glass_jaw</lookupName>
<displayName>Glass Jaw (ATOW)</displayName>
<desc>All injuries suffered and fatigue gained is doubled</desc>
<desc>All injuries suffered and fatigue gained is doubled. Fatigue gain from sustaining injuries is not doubled.</desc>
<xpCost>-300</xpCost>
<weight>1</weight>
<skillPrereq/>
<removeAbilities>atow_toughness</removeAbilities>
</ability>
<ability>
<lookupName>atow_toughness</lookupName>
<displayName>Toughness (ATOW)</displayName>
<desc>All injuries suffered are reduced by 75% and Fatigue gain is halved. Fatigue gain from sustaining injuries is not halved.</desc>
<xpCost>300</xpCost>
<weight>1</weight>
<skillPrereq/>
<removeAbilities>flaw_glass_jaw</removeAbilities>
</ability>
<ability>
<lookupName>eagle_eyes</lookupName>
Expand Down Expand Up @@ -541,9 +551,9 @@
<weight>1</weight>
<desc>Unit Reputation is decreased by 1 if this character is the campaign commander.

A pilot who has Combat Sense rolls three dice per initiative check, keeping the top two rolls.
A pilot who has Combat Sense rolls three dice per initiative check, keeping the top two rolls.

If individual initiative is enabled, this penalty applies only to the pilot's unit. Otherwise, the penalty is applied only if the pilot's unit is the force commander.
If individual initiative is enabled, this penalty applies only to the pilot's unit. Otherwise, the penalty is applied only if the pilot's unit is the force commander.
</desc>
<skillPrereq/>
<removeAbilities>atow_combat_sense</removeAbilities>
Expand All @@ -554,9 +564,9 @@ If individual initiative is enabled, this penalty applies only to the pilot's un
<weight>1</weight>
<desc>Unit Reputation is increased by 1 if this character is the campaign commander.

A pilot who has Combat Sense rolls three dice per initiative check, keeping the top two rolls.
A pilot who has Combat Sense rolls three dice per initiative check, keeping the top two rolls.

If individual initiative is enabled, this bonus applies only to the pilot's unit. Otherwise, the bonus is applied only if the pilot's unit is the force commander.
If individual initiative is enabled, this bonus applies only to the pilot's unit. Otherwise, the bonus is applied only if the pilot's unit is the force commander.
</desc>
<skillPrereq>
<skill>Gunnery/Mek::Veteran</skill>
Expand Down
35 changes: 27 additions & 8 deletions MekHQ/src/mekhq/campaign/ResolveScenarioTracker.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@
*/
package mekhq.campaign;

import static java.lang.Math.ceil;
import static mekhq.campaign.mission.Scenario.T_SPACE;
import static mekhq.campaign.parts.enums.PartQuality.QUALITY_D;
import static mekhq.campaign.personnel.PersonnelOptions.ATOW_TOUGHNESS;
import static mekhq.campaign.personnel.PersonnelOptions.FLAW_GLASS_JAW;

import java.io.File;
Expand Down Expand Up @@ -841,7 +843,7 @@ private void processLargeCraft(Unit ship, Entity en, List<Person> personnel, Uni
currentHits = 6;
}
int newHits = Math.max(0, currentHits - existingHits);
casualties = (int) Math.ceil(Compute.getFullCrewSize(en) * (newHits / 6.0));
casualties = (int) ceil(Compute.getFullCrewSize(en) * (newHits / 6.0));
// Now reduce the casualties if some "hits" were caused by ejection
casualties = Math.max(0, casualties - rescuedCrew);

Expand Down Expand Up @@ -1079,7 +1081,7 @@ private void processPrisonerCapture(List<TestUnit> unitsToProcess) {
currentHits = entity.getCrew().getHits();
}
int newHits = Math.max(0, currentHits - existingHits);
casualties = (int) Math.ceil(Compute.getFullCrewSize(entity) * (newHits / 6.0));
casualties = (int) ceil(Compute.getFullCrewSize(entity) * (newHits / 6.0));
}

for (Person person : crew) {
Expand Down Expand Up @@ -1547,25 +1549,33 @@ public void resolveScenario(ScenarioStatus resolution, String report) {
int statusHits = status.getHits();
int priorHits = person.getHits();
int newHits = statusHits - priorHits;
int extraHits = 0;
int adjustedHits = 0;

boolean hasGlassJaw = person.getOptions().booleanOption(FLAW_GLASS_JAW);
boolean hasToughness = person.getOptions().booleanOption(ATOW_TOUGHNESS);
boolean hasGlassJawAndToughness = hasGlassJaw && hasToughness;

if (hasGlassJaw) {
extraHits = newHits;
if (hasGlassJaw && !hasGlassJawAndToughness) {
adjustedHits = newHits * 2;
} else if (hasToughness && !hasGlassJawAndToughness) {
adjustedHits = (int) ceil(newHits * 0.75);
}

if (campaign.getCampaignOptions().isUseInjuryFatigue()) {
int fatigueRate = campaign.getCampaignOptions().getFatigueRate();
int fatigueIncrease = (hasGlassJaw ? fatigueRate * 2 : fatigueRate) * (newHits + extraHits);
int fatigueIncrease = newHits * fatigueRate;

if ((hasGlassJaw || hasToughness) && !hasGlassJawAndToughness) {
fatigueIncrease = adjustedHits;
}

person.changeFatigue(fatigueIncrease);

// The status update from this instance of changeFatigue is handled later
}

person.setHitsPrior(priorHits);
person.setHits(statusHits + extraHits);
person.setHits(statusHits + adjustedHits);
}

if (status.wasDeployed()) {
Expand Down Expand Up @@ -1595,9 +1605,18 @@ public void resolveScenario(ScenarioStatus resolution, String report) {

if (!status.isDead()) {
int fatigueChangeRate = campaign.getCampaignOptions().getFatigueRate();

boolean hasGlassJaw = person.getOptions().booleanOption(FLAW_GLASS_JAW);
boolean hasToughness = person.getOptions().booleanOption(ATOW_TOUGHNESS);
boolean hasGlassJawAndToughness = hasGlassJaw && hasToughness;

if (hasGlassJaw && !hasGlassJawAndToughness) {
fatigueChangeRate = fatigueChangeRate * 2;
} else if (hasToughness && !hasGlassJawAndToughness) {
fatigueChangeRate = (int) ceil(fatigueChangeRate * 0.75);
}

person.changeFatigue(hasGlassJaw ? fatigueChangeRate * 2 : fatigueChangeRate);
person.changeFatigue(fatigueChangeRate);

if (campaign.getCampaignOptions().isUseFatigue()) {
Fatigue.processFatigueActions(campaign, person);
Expand Down
2 changes: 2 additions & 0 deletions MekHQ/src/mekhq/campaign/personnel/PersonnelOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public class PersonnelOptions extends PilotOptions {
public static final String TECH_FIXER = "tech_fixer";
public static final String TECH_MAINTAINER = "tech_maintainer";
public static final String FLAW_GLASS_JAW = "flaw_glass_jaw";
public static final String ATOW_TOUGHNESS = "atow_toughness";

@Override
public void initialize() {
Expand Down Expand Up @@ -107,6 +108,7 @@ public void initialize() {
addOption(l3a, TECH_FIXER, false);
addOption(l3a, TECH_MAINTAINER, false);
addOption(l3a, FLAW_GLASS_JAW, false);
addOption(l3a, ATOW_TOUGHNESS, false);

addOption(edge, EDGE_MEDICAL, true);
addOption(edge, EDGE_REPAIR_BREAK_PART, true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
package mekhq.campaign.personnel.education;

import static java.lang.Math.round;
import static mekhq.campaign.personnel.PersonnelOptions.ATOW_TOUGHNESS;
import static mekhq.campaign.personnel.PersonnelOptions.FLAW_GLASS_JAW;
import static mekhq.campaign.personnel.skills.SkillType.EXP_GREEN;
import static mekhq.utilities.ReportingUtilities.CLOSING_SPAN_TAG;
Expand Down Expand Up @@ -170,8 +171,17 @@ private static void performTraining(Campaign campaign, Force force, Person comma

for (Person trainee : unit.getActiveCrew()) {
if (campaign.getCampaignOptions().isUseFatigue()) {
int fatigueChangeRate = campaign.getCampaignOptions().getFatigueRate();
int fatigueChangeRate = campaign.getCampaignOptions().getFatigueRate() * 2;

boolean hasGlassJaw = trainee.getOptions().booleanOption(FLAW_GLASS_JAW);
boolean hasToughness = trainee.getOptions().booleanOption(ATOW_TOUGHNESS);
boolean hasGlassJawAndToughness = hasGlassJaw && hasToughness;

if (hasGlassJaw && !hasGlassJawAndToughness) {
fatigueChangeRate = fatigueChangeRate * 2;
} else if (hasToughness && !hasGlassJawAndToughness) {
fatigueChangeRate = (int) round(fatigueChangeRate * 0.5);
}

trainee.changeFatigue(fatigueChangeRate * (hasGlassJaw ? 4 : 2));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@
import static java.lang.Math.ceil;
import static java.lang.Math.max;
import static java.lang.Math.min;
import static java.lang.Math.round;
import static megamek.codeUtilities.MathUtility.clamp;
import static megamek.codeUtilities.ObjectUtility.getRandomItem;
import static megamek.common.Compute.d6;
import static mekhq.campaign.force.ForceType.SECURITY;
import static mekhq.campaign.personnel.PersonnelOptions.ATOW_TOUGHNESS;
import static mekhq.campaign.personnel.PersonnelOptions.FLAW_GLASS_JAW;
import static mekhq.campaign.personnel.enums.PersonnelRole.DEPENDENT;
import static mekhq.campaign.personnel.enums.PersonnelRole.NONE;
Expand All @@ -60,10 +62,10 @@
import mekhq.campaign.mission.AtBContract;
import mekhq.campaign.mission.enums.AtBMoraleLevel;
import mekhq.campaign.personnel.Person;
import mekhq.campaign.personnel.skills.Skill;
import mekhq.campaign.personnel.skills.SkillType;
import mekhq.campaign.personnel.enums.PersonnelRole;
import mekhq.campaign.personnel.enums.PersonnelStatus;
import mekhq.campaign.personnel.skills.Skill;
import mekhq.campaign.personnel.skills.SkillType;
import mekhq.campaign.personnel.turnoverAndRetention.Fatigue;
import mekhq.campaign.randomEvents.prisoners.enums.EventResultEffect;
import mekhq.campaign.randomEvents.prisoners.enums.PrisonerEvent;
Expand Down Expand Up @@ -786,7 +788,7 @@ private String eventEffectFatigueOne(EventResult result) {
}

final boolean isGuard = result.isGuard();
final int magnitude = result.magnitude();
int magnitude = result.magnitude();

Person target = getRandomTarget(isGuard);

Expand All @@ -795,7 +797,16 @@ private String eventEffectFatigueOne(EventResult result) {
}

boolean hasGlassJaw = target.getOptions().booleanOption(FLAW_GLASS_JAW);
target.changeFatigue(hasGlassJaw ? magnitude * 2 : magnitude);
boolean hasToughness = target.getOptions().booleanOption(ATOW_TOUGHNESS);
boolean hasGlassJawAndToughness = hasGlassJaw && hasToughness;

if (hasGlassJaw && !hasGlassJawAndToughness) {
magnitude = magnitude * 2;
} else if (hasToughness && !hasGlassJawAndToughness) {
magnitude = (int) round(magnitude * 0.5);
}

target.changeFatigue(magnitude);

if (campaign.getCampaignOptions().isUseFatigue()) {
Fatigue.processFatigueActions(campaign, target);
Expand Down Expand Up @@ -847,7 +858,18 @@ private String eventEffectFatigueAll(EventResult result) {

for (Person target : targets) {
boolean hasGlassJaw = target.getOptions().booleanOption(FLAW_GLASS_JAW);
target.changeFatigue(hasGlassJaw ? magnitude * 2 : magnitude);
boolean hasToughness = target.getOptions().booleanOption(ATOW_TOUGHNESS);
boolean hasGlassJawAndToughness = hasGlassJaw && hasToughness;

int fatigueGain = magnitude;

if (hasGlassJaw && !hasGlassJawAndToughness) {
fatigueGain = magnitude * 2;
} else if (hasToughness && !hasGlassJawAndToughness) {
fatigueGain = (int) round(magnitude * 0.5);
}

target.changeFatigue(fatigueGain);

if (campaign.getCampaignOptions().isUseFatigue()) {
Fatigue.processFatigueActions(campaign, target);
Expand Down Expand Up @@ -1074,9 +1096,19 @@ private String eventEffectUniquePoison(EventResult result) {
for (int i = 0; i < targetCount; i++) {
Person target = getRandomItem(potentialTargets);

int fatigueChange = d6(magnitude);
int fatigueGain = d6(magnitude);

boolean hasGlassJaw = target.getOptions().booleanOption(FLAW_GLASS_JAW);
target.changeFatigue(hasGlassJaw ? fatigueChange * 2 : fatigueChange);
boolean hasToughness = target.getOptions().booleanOption(ATOW_TOUGHNESS);
boolean hasGlassJawAndToughness = hasGlassJaw && hasToughness;

if (hasGlassJaw && !hasGlassJawAndToughness) {
fatigueGain = magnitude * 2;
} else if (hasToughness && !hasGlassJawAndToughness) {
fatigueGain = (int) round(magnitude * 0.5);
}

target.changeFatigue(fatigueGain);

if (campaign.getCampaignOptions().isUseFatigue()) {
Fatigue.processFatigueActions(campaign, target);
Expand Down
15 changes: 13 additions & 2 deletions MekHQ/src/mekhq/campaign/stratcon/StratconRulesManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import static mekhq.campaign.mission.ScenarioMapParameters.MapLocation.LowAtmosphere;
import static mekhq.campaign.mission.ScenarioMapParameters.MapLocation.Space;
import static mekhq.campaign.mission.ScenarioMapParameters.MapLocation.SpecificGroundTerrain;
import static mekhq.campaign.personnel.PersonnelOptions.ATOW_TOUGHNESS;
import static mekhq.campaign.personnel.PersonnelOptions.FLAW_GLASS_JAW;
import static mekhq.campaign.personnel.skills.SkillType.S_ADMIN;
import static mekhq.campaign.personnel.skills.SkillType.S_TACTICS;
Expand Down Expand Up @@ -1564,11 +1565,21 @@ private static void scanNeighboringCoords(StratconCoords coords, int forceID, Ca
*/
private static void increaseFatigue(int forceID, Campaign campaign) {
for (UUID unit : campaign.getForce(forceID).getAllUnits(false)) {
int fatigueChangeRate = campaign.getCampaignOptions().getFatigueRate();
for (Person person : campaign.getUnit(unit).getCrew()) {
int fatigueChangeRate = campaign.getCampaignOptions().getFatigueRate();
int fatigueChange = fatigueChangeRate;

boolean hasGlassJaw = person.getOptions().booleanOption(FLAW_GLASS_JAW);
boolean hasToughness = person.getOptions().booleanOption(ATOW_TOUGHNESS);
boolean hasGlassJawAndToughness = hasGlassJaw && hasToughness;

if (hasGlassJaw && !hasGlassJawAndToughness) {
fatigueChange = fatigueChangeRate * 2;
} else if (hasToughness && !hasGlassJawAndToughness) {
fatigueChange = (int) round(fatigueChangeRate * 0.5);
}

person.changeFatigue(hasGlassJaw ? fatigueChangeRate * 2 : fatigueChangeRate);
person.changeFatigue(fatigueChange);

if (campaign.getCampaignOptions().isUseFatigue()) {
Fatigue.processFatigueActions(campaign, person);
Expand Down
Loading