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

allows to select a previous engineer or new crew member to activate large vessels #5253

Merged
merged 1 commit into from
Nov 29, 2024
Merged
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
16 changes: 13 additions & 3 deletions MekHQ/src/mekhq/campaign/Campaign.java
Original file line number Diff line number Diff line change
Expand Up @@ -2447,19 +2447,29 @@ public List<Person> getTechs(final boolean noZeroMinute) {
return getTechs(noZeroMinute, false);
}

public List<Person> getTechsExpanded() {
return getTechsExpanded(false, false, true);
}

public List<Person> getTechs(final boolean noZeroMinute, final boolean eliteFirst) {
return getTechsExpanded(noZeroMinute, eliteFirst, false);
}

/**
* Returns a list of active technicians.
*
* @param noZeroMinute If TRUE, then techs with no time remaining will be
* excluded from the list.
* @param eliteFirst If TRUE and sorted also TRUE, then return the list sorted
* from best to worst
* @param expanded If TRUE, then include techs with expanded roles (e.g. Tech/Vessel skill)
* @return The list of active {@link Person}s who qualify as technicians
* ({@link Person#isTech()}).
* ({@link Person#isTech()}), or who qualify as expanded technicians ({@link Person#isTechExpanded()}).
*/
public List<Person> getTechs(final boolean noZeroMinute, final boolean eliteFirst) {
public List<Person> getTechsExpanded(final boolean noZeroMinute, final boolean eliteFirst, final boolean expanded) {
final List<Person> techs = getActivePersonnel().stream()
.filter(person -> person.isTech() && (!noZeroMinute || (person.getMinutesLeft() > 0)))
.filter(person -> (expanded ? person.isTechExpanded() : person.isTech())
&& (!noZeroMinute || (person.getMinutesLeft() > 0)))
.collect(Collectors.toList());

// also need to loop through and collect engineers on self-crewed vessels
Expand Down
44 changes: 36 additions & 8 deletions MekHQ/src/mekhq/campaign/personnel/Person.java
Original file line number Diff line number Diff line change
Expand Up @@ -3753,8 +3753,13 @@ public boolean canGun(final Entity entity) {
}

public boolean canTech(final Entity entity) {
if (entity == null) {
return false;
}
if ((entity instanceof Mek) || (entity instanceof ProtoMek)) {
return hasSkill(SkillType.S_TECH_MEK);
} else if (entity instanceof Dropship || entity instanceof Jumpship) {
return hasSkill(SkillType.S_TECH_VESSEL);
} else if (entity instanceof Aero) {
return hasSkill(SkillType.S_TECH_AERO);
} else if (entity instanceof BattleArmor) {
Expand Down Expand Up @@ -3845,24 +3850,34 @@ public int getMinutesLeft() {
public void setMinutesLeft(final int minutesLeft) {
this.minutesLeft = minutesLeft;
if (engineer && (getUnit() != null)) {
// set minutes for all crewmembers
for (Person p : getUnit().getActiveCrew()) {
p.setMinutesLeft(minutesLeft);
}
// set minutes for all crew members, except the engineer to not cause infinite recursion.
getUnit().getActiveCrew()
.stream()
.filter(this::isNotSelf)
.forEach(p -> p.setMinutesLeft(minutesLeft));
}
}

/**
* Checks if the other person is not the same person as this person, easy right?
* @param p Person to check against
* @return true if the person is not the same person as this person
*/
private boolean isNotSelf(Person p) {
return !this.equals(p);
}

public int getOvertimeLeft() {
return overtimeLeft;
}

public void setOvertimeLeft(final int overtimeLeft) {
this.overtimeLeft = overtimeLeft;
if (engineer && (getUnit() != null)) {
// set minutes for all crewmembers
for (Person p : getUnit().getActiveCrew()) {
p.setMinutesLeft(overtimeLeft);
}
getUnit().getActiveCrew()
.stream()
.filter(this::isNotSelf)
.forEach(p -> p.setOvertimeLeft(overtimeLeft));
}
}

Expand Down Expand Up @@ -3901,6 +3916,19 @@ public boolean isTech() {
return isTechMek() || isTechAero() || isTechMechanic() || isTechBA();
}

/**
* Checks if the person is a tech, includes mektek, mechanic, aerotek, BAtek and the non-cannon "large vessel tek"
* @return true if the person is a tech
*/
public boolean isTechExpanded() {
Scoppio marked this conversation as resolved.
Show resolved Hide resolved
return isTechMek() || isTechAero() || isTechMechanic() || isTechBA() || isTechLargeVessel();
}

public boolean isTechLargeVessel() {
boolean hasSkill = hasSkill(SkillType.S_TECH_VESSEL);
return hasSkill && (getPrimaryRole().isVesselCrew() || getSecondaryRole().isVesselCrew());
}

public boolean isTechMek() {
boolean hasSkill = hasSkill(SkillType.S_TECH_MEK);
return hasSkill && (getPrimaryRole().isMekTech() || getSecondaryRole().isMekTech());
Expand Down
16 changes: 12 additions & 4 deletions MekHQ/src/mekhq/campaign/unit/MothballInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
* This class is used to store information about a particular unit that is
* lost when a unit is mothballed, so that it may be restored to as close to
* its prior state as possible when the unit is reactivated.
*
*
* @author NickAragua
*/
public class MothballInfo {
Expand All @@ -61,9 +61,17 @@ private MothballInfo() {
vesselCrew = new ArrayList<>();
}

/**
* Who was the original tech of this vessel?
* @return The original tech
*/
public Person getTech() {
return tech;
}

/**
* Creates a set of mothball info for a given unit
*
*
* @param unit The unit to work with
*/
public MothballInfo(Unit unit) {
Expand All @@ -78,7 +86,7 @@ public MothballInfo(Unit unit) {

/**
* Restore a unit's pilot, assigned tech and force, to the best of our ability
*
*
* @param unit The unit to restore
* @param campaign The campaign in which this is happening
*/
Expand Down Expand Up @@ -158,7 +166,7 @@ public void writeToXML(final PrintWriter pw, int indent) {

/**
* Deserializer method implemented in standard MekHQ pattern.
*
*
* @return Instance of MothballInfo
*/
public static MothballInfo generateInstanceFromXML(Node wn, Version version) {
Expand Down
42 changes: 41 additions & 1 deletion MekHQ/src/mekhq/campaign/unit/Unit.java
Original file line number Diff line number Diff line change
Expand Up @@ -4821,6 +4821,29 @@ public void startMothballing(@Nullable Person mothballTech, boolean isGM) {
}
}

/**
* Returns the engineer responsible for the mothballing or activation of this unit.
* @return Person the previous engineer that worked on this vessel, or an empty object.
*/
public Optional<Person> engineerResponsible() {
// if it is NOT self crewed or it is NOT mothballed, just get the tech
if (!isMothballed() || !isSelfCrewed()) {
return Optional.ofNullable(getTech());
} else {
// if it is self crewed AND is mothballed and has a mothball info, get the tech
if (isSelfCrewed() && isMothballed() && (this.mothballInfo != null)) {
var previousTech = this.mothballInfo.getTech();
var previousTechExists = previousTech != null;
var previousTechIsActive = previousTechExists && previousTech.getStatus().isActive();
if (previousTechIsActive) {
return Optional.of(previousTech);
}
}
}

return Optional.empty();
}

/**
* Completes the mothballing of a unit.
*/
Expand Down Expand Up @@ -4858,8 +4881,25 @@ public void startActivating(@Nullable Person activationTech, boolean isGM) {
// set this person as tech
if (!isSelfCrewed() && (tech != null) && !tech.equals(activationTech)) {
remove(tech, true);
tech = activationTech;
} else if (!isSelfCrewed() && (null == tech)) {
tech = activationTech;
}

if (isSelfCrewed() && !isConventionalInfantry()) {
if (engineerResponsible().isPresent() && engineerResponsible().get().getStatus().isActive()) {
var assignedEngineer = engineerResponsible().get();
addVesselCrew(assignedEngineer);
} else if (activationTech != null && activationTech.isTechLargeVessel()) {
addVesselCrew(activationTech);
} else {
// In this case there is nothing to be done, we cant activate this unit.
return;
}
resetEngineer();
} else {
tech = activationTech;
}
tech = activationTech;

if (!isGM) {
setMothballTime(getMothballOrActivationTime());
Expand Down
4 changes: 2 additions & 2 deletions MekHQ/src/mekhq/gui/CampaignGUI.java
Original file line number Diff line number Diff line change
Expand Up @@ -1614,7 +1614,7 @@ public void refitUnit(Refit r, boolean selectModelName) {
StringBuilder nameBuilder = new StringBuilder(128);
nameBuilder.append("<html>")
.append(tech.getFullName())
.append(", <b>")
.append(", <b>")
.append(SkillType.getColoredExperienceLevelName(tech.getSkillLevel(getCampaign(), false)))
.append("</b> ")
.append(tech.getPrimaryRoleDesc())
Expand Down Expand Up @@ -1722,7 +1722,7 @@ public void refitUnit(Refit r, boolean selectModelName) {
public @Nullable UUID selectTech(Unit u, String desc, boolean ignoreMaintenance) {
String name;
Map<String, Person> techHash = new LinkedHashMap<>();
for (Person tech : getCampaign().getTechs()) {
for (Person tech : getCampaign().getTechsExpanded()) {
if (!tech.isMothballing() && tech.canTech(u.getEntity())) {
int time = tech.getMinutesLeft();
if (!ignoreMaintenance) {
Expand Down
8 changes: 6 additions & 2 deletions MekHQ/src/mekhq/gui/adapter/UnitTableMouseAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ public void actionPerformed(ActionEvent action) {
String quality = (String) JOptionPane.showInputDialog(gui.getFrame(), "Choose the new quality level",
"Set Quality", JOptionPane.PLAIN_MESSAGE, null, possibilities,
PartQuality.QUALITY_D.toName(reverse));

PartQuality q = PartQuality.fromName(quality, reverse);
for (Unit unit : units) {
if (null != unit) {
Expand Down Expand Up @@ -526,7 +526,7 @@ public void actionPerformed(ActionEvent action) {

private @Nullable Person pickTechForMothballOrActivation(Unit unit, String description) {
Person tech = null;
if (!unit.isSelfCrewed()) {
if (!unit.isSelfCrewed() || isSelfCrewedButHasNoTech(unit)) {
UUID id = gui.selectTech(unit, description, true);
if (null != id) {
tech = gui.getCampaign().getPerson(id);
Expand All @@ -544,6 +544,10 @@ public void actionPerformed(ActionEvent action) {
return tech;
}

private boolean isSelfCrewedButHasNoTech(Unit unit) {
return unit.isSelfCrewed() && unit.engineerResponsible().isEmpty();
}

@Override
protected Optional<JPopupMenu> createPopupMenu() {
if (unitTable.getSelectedRowCount() == 0) {
Expand Down
1 change: 1 addition & 0 deletions MekHQ/unittests/mekhq/campaign/CampaignTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ void testGetTechs() {
when(testCampaign.getTechs()).thenCallRealMethod();
when(testCampaign.getTechs(anyBoolean())).thenCallRealMethod();
when(testCampaign.getTechs(anyBoolean(), anyBoolean())).thenCallRealMethod();
when(testCampaign.getTechsExpanded(anyBoolean(), anyBoolean(), anyBoolean())).thenCallRealMethod();

// Test just getting the list of active techs.
List<Person> expected = new ArrayList<>(3);
Expand Down