diff --git a/megamek/i18n/megamek/client/messages.properties b/megamek/i18n/megamek/client/messages.properties index 2850e7bfbca..288bd562cdb 100644 --- a/megamek/i18n/megamek/client/messages.properties +++ b/megamek/i18n/megamek/client/messages.properties @@ -1189,6 +1189,7 @@ CustomMechDialog.OffboardDistance=Offboard units need to be at least one mapshee CustomMechDialog.RandomSkill=Random Skill CustomMechDialog.RandomName=Random Name CustomMechDialog.RandomCallsign=Random Callsign +CustomMechDialog.chkClanner=Clanner CustomMechDialog.setCompanyMaster=Set as company-level master ({0}M / {1}S free) CustomMechDialog.setCompanyMaster1=Set as company-level master ({0}M free) CustomMechDialog.setIndependentMaster=Set as independent master ({0} free) diff --git a/megamek/src/megamek/client/bot/MoveOption.java b/megamek/src/megamek/client/bot/MoveOption.java index b816add3567..a4e4dd74301 100644 --- a/megamek/src/megamek/client/bot/MoveOption.java +++ b/megamek/src/megamek/client/bot/MoveOption.java @@ -268,15 +268,14 @@ public boolean changeToPhysical() { return false; } } - boolean isClan = getEntity().isClan(); + if ((last == null) || (last.getMovementType(true) == EntityMovementType.MOVE_ILLEGAL)) { return false; - } - if ((last.getType() != MoveStepType.FORWARDS) - || (isClan - && getGame().getOptions().booleanOption(OptionsConstants.ALLOWED_NO_CLAN_PHYSICAL) && (getEntity() - .getSwarmAttackerId() == Entity.NONE))) { + } else if ((last.getType() != MoveStepType.FORWARDS) + || (getEntity().getCrew().isClanner() + && getGame().getOptions().booleanOption(OptionsConstants.ALLOWED_NO_CLAN_PHYSICAL) + && (getEntity().getSwarmAttackerId() == Entity.NONE))) { return false; } // TODO: this just takes the first target diff --git a/megamek/src/megamek/client/bot/princess/BasicPathRanker.java b/megamek/src/megamek/client/bot/princess/BasicPathRanker.java index 5e8040f8b86..28d5693a34b 100644 --- a/megamek/src/megamek/client/bot/princess/BasicPathRanker.java +++ b/megamek/src/megamek/client/bot/princess/BasicPathRanker.java @@ -579,9 +579,8 @@ protected RankedPath rankPath(MovePath path, Game game, int maxRange, // If I cannot kick because I am a clan unit and "No physical // attacks for the clans" // is enabled, set maximum physical damage for this path to zero. - if (game.getOptions() - .booleanOption(OptionsConstants.ALLOWED_NO_CLAN_PHYSICAL) && - path.getEntity().isClan()) { + if (game.getOptions().booleanOption(OptionsConstants.ALLOWED_NO_CLAN_PHYSICAL) + && path.getEntity().getCrew().isClanner()) { damageEstimate.physicalDamage = 0; } diff --git a/megamek/src/megamek/client/generator/RandomNameGenerator.java b/megamek/src/megamek/client/generator/RandomNameGenerator.java index 99fbb23159a..4e646c744ca 100644 --- a/megamek/src/megamek/client/generator/RandomNameGenerator.java +++ b/megamek/src/megamek/client/generator/RandomNameGenerator.java @@ -141,38 +141,24 @@ public RandomNameGenerator() { /** * This is used to generate a name for MegaMek only that uses the chosen faction * @param gender the gender to generate the name for + * @param clanner if the name is for a clanner * @return a string containing the randomly generated name */ - public String generate(Gender gender) { - return generate(gender, getChosenFaction()); - } - - /** - * Generate a name for MegaMek only, using the clan name hack - * - * This is a hack used for MegaMek, where we assume any chosen faction with a name containing the - * String "clan" is a clan faction. - * @param gender the gender to generate the name for - * @param faction the faction code to use, which is the generator's name where possible - * @return a string containing the randomly generated name - */ - public String generate(Gender gender, String faction) { - // this is a total hack, but for now lets assume that if the faction name contains - // the word "clan" we should only spit out first names - return generate(gender, faction.toLowerCase().contains("clan"), faction); + public String generate(Gender gender, boolean clanner) { + return generate(gender, clanner, getChosenFaction()); } /** * Generate a single random name for MegaMek only * * @param gender the gender to generate the name for - * @param isClan true if the name should be for a clanner, otherwise false + * @param clanner if the name is for a clanner * @param faction a string containing the faction key with which to generate the name from. * If the faction is not a key for the factionSurnames Map, * it will instead generate based on the General list * @return a string containing the randomly generated name */ - public String generate(Gender gender, boolean isClan, String faction) { + public String generate(Gender gender, boolean clanner, String faction) { String name = UNNAMED_FULL_NAME; if (initialized) { // This checks to see if we've got a name map for the faction. If we do not, then we @@ -181,14 +167,14 @@ public String generate(Gender gender, boolean isClan, String faction) { // If the key isn't set by either case above, then the name is generated based on the // default faction key faction = factionEthnicCodes.containsKey(faction) ? faction - : ((isClan && (factionEthnicCodes.containsKey(KEY_DEFAULT_CLAN))) + : ((clanner && (factionEthnicCodes.containsKey(KEY_DEFAULT_CLAN))) ? KEY_DEFAULT_CLAN : KEY_DEFAULT_FACTION); final int ethnicCode = factionEthnicCodes.get(faction).randomItem(); final int givenNameEthnicCode = factionGivenNames.get(faction).get(ethnicCode).randomItem(); name = (gender.isFemale() ? femaleGivenNames : maleGivenNames).get(givenNameEthnicCode).randomItem(); - if (!isClan) { + if (!clanner) { name += " " + surnames.get(ethnicCode).randomItem(); } } @@ -197,20 +183,16 @@ public String generate(Gender gender, boolean isClan, String faction) { /** * @param gender the gender to generate the name for - * @param faction the specified faction code + * @param clanner if the person is a clanner * @param ethnicCode the specified ethnic code * @return a string containing the randomly generated name */ - public String generateWithEthnicCode(Gender gender, String faction, int ethnicCode) { + public String generateWithEthnicCode(Gender gender, boolean clanner, int ethnicCode) { String name = UNNAMED_FULL_NAME; if (initialized) { - // this is a total hack, but for now lets assume that if the faction name contains - // the word "clan" we should only spit out first names - boolean isClan = faction.toLowerCase().equals("clan"); - name = (gender.isFemale() ? femaleGivenNames : maleGivenNames).get(ethnicCode).randomItem(); - if (!isClan) { + if (!clanner) { name += " " + surnames.get(ethnicCode).randomItem(); } } @@ -221,7 +203,7 @@ public String generateWithEthnicCode(Gender gender, String faction, int ethnicCo * Generate a single random name split between a given name and surname * * @param gender the gender to generate the name for - * @param isClan true if the name should be for a clanner, otherwise false + * @param clanner if the person is a clanner * @param faction a string containing the faction key with which to generate the name from. * If the faction is not a key for the factionSurnames Map, * it will instead generate based on the General list @@ -229,7 +211,7 @@ public String generateWithEthnicCode(Gender gender, String faction, int ethnicCo * with the given name at String[0] * and the surname at String[1] */ - public String[] generateGivenNameSurnameSplit(Gender gender, boolean isClan, String faction) { + public String[] generateGivenNameSurnameSplit(Gender gender, boolean clanner, String faction) { String[] name = { UNNAMED, UNNAMED_SURNAME }; if (initialized) { // This checks to see if we've got a name map for the faction. If we do not, then we @@ -238,31 +220,31 @@ public String[] generateGivenNameSurnameSplit(Gender gender, boolean isClan, Str // If the key isn't set by either case above, then the name is generated based on the // default faction key faction = factionEthnicCodes.containsKey(faction) ? faction - : ((isClan && (factionEthnicCodes.containsKey(KEY_DEFAULT_CLAN))) + : ((clanner && (factionEthnicCodes.containsKey(KEY_DEFAULT_CLAN))) ? KEY_DEFAULT_CLAN : KEY_DEFAULT_FACTION); final int ethnicCode = factionEthnicCodes.get(faction).randomItem(); final int givenNameEthnicCode = factionGivenNames.get(faction).get(ethnicCode).randomItem(); name[0] = (gender.isFemale() ? femaleGivenNames : maleGivenNames).get(givenNameEthnicCode).randomItem(); - name[1] = isClan ? "" : surnames.get(ethnicCode).randomItem(); + name[1] = clanner ? "" : surnames.get(ethnicCode).randomItem(); } return name; } /** * @param gender the gender to generate the name for - * @param isClan true if the name should be for a clanner, otherwise false + * @param clanner if the person is a clanner * @param ethnicCode the specified ethnic code * @return - a String[] containing the name, * with the given name at String[0] * and the surname at String[1] */ - public String[] generateGivenNameSurnameSplitWithEthnicCode(Gender gender, boolean isClan, int ethnicCode) { + public String[] generateGivenNameSurnameSplitWithEthnicCode(Gender gender, boolean clanner, int ethnicCode) { String[] name = { UNNAMED, UNNAMED_SURNAME }; if (initialized) { name[0] = (gender.isFemale() ? femaleGivenNames : maleGivenNames).get(ethnicCode).randomItem(); - name[1] = isClan ? "" : surnames.get(ethnicCode).randomItem(); + name[1] = clanner ? "" : surnames.get(ethnicCode).randomItem(); } return name; } diff --git a/megamek/src/megamek/client/generator/skillGenerators/AbstractSkillGenerator.java b/megamek/src/megamek/client/generator/skillGenerators/AbstractSkillGenerator.java index 954627cf97a..0550c679bb1 100644 --- a/megamek/src/megamek/client/generator/skillGenerators/AbstractSkillGenerator.java +++ b/megamek/src/megamek/client/generator/skillGenerators/AbstractSkillGenerator.java @@ -27,10 +27,8 @@ import java.io.Serializable; -public abstract class AbstractSkillGenerator implements Serializable { +public abstract class AbstractSkillGenerator { //region Variable Declarations - private static final long serialVersionUID = 8475341940660043659L; - private final SkillGeneratorMethod method; private SkillLevel level; private SkillGeneratorType type; @@ -89,7 +87,7 @@ public void setRandomSkills(final Entity entity) { * Generates random skills based on an entity crewmember by crewmember, and then assigns the * values to the crew before sorting them. * @param entity the Entity whose skills are to be randomly set - * @param forceClan forces the type to be clan if the entity is a clan unit + * @param forceClan forces the type to be clan if the crew are led by a clanner */ public void setRandomSkills(final Entity entity, final boolean forceClan) { for (int i = 0; i < entity.getCrew().getSlotCount(); i++) { @@ -109,7 +107,7 @@ public void setRandomSkills(final Entity entity, final boolean forceClan) { } /** - * Generates random skills for an entity based on the current settings of the random skills + * Generates random skills for an entity based on the current settings of the random skill * generator, but does not assign those new skills to that entity * @param entity the Entity to generate a random skill array for * @return an integer array containing the (Gunnery, Piloting) skill values, or an alternative @@ -120,7 +118,7 @@ public int[] generateRandomSkills(final Entity entity) { } /** - * Generates random skills for an entity based on the current settings of the random skills + * Generates random skills for an entity based on the current settings of the random skill * generator, but does not assign those new skills to that entity. The return value MUST be * cleaned with cleanReturn for this setup to work properly. * @param entity the Entity to generate a random skill array for @@ -128,7 +126,22 @@ public int[] generateRandomSkills(final Entity entity) { * @return an integer array containing the (Gunnery, Piloting) skill values, or an alternative * pairing if applicable [(Gunnery, Anti-'Mech) for infantry] */ - public abstract int[] generateRandomSkills(final Entity entity, final boolean forceClan); + public int[] generateRandomSkills(final Entity entity, final boolean forceClan) { + return generateRandomSkills(entity, entity.getCrew().isClanner(), forceClan); + } + + /** + * Generates random skills for an entity based on the current settings of the random skill + * generator, but does not assign those new skills to that entity. The return value MUST be + * cleaned with cleanReturn for this setup to work properly. + * @param entity the Entity to generate a random skill array for + * @param clanner if the crew to generate a random skills array for are clanners + * @param forceClan forces the type to be clan if the crew are clanners + * @return an integer array containing the (Gunnery, Piloting) skill values, or an alternative + * pairing if applicable [(Gunnery, Anti-'Mech) for infantry] + */ + public abstract int[] generateRandomSkills(final Entity entity, final boolean clanner, + final boolean forceClan); /** * This cleans up the return value before the final return, and by doing so to handling two diff --git a/megamek/src/megamek/client/generator/skillGenerators/ConstantSkillGenerator.java b/megamek/src/megamek/client/generator/skillGenerators/ConstantSkillGenerator.java index 39bd0125a47..709b57e3583 100644 --- a/megamek/src/megamek/client/generator/skillGenerators/ConstantSkillGenerator.java +++ b/megamek/src/megamek/client/generator/skillGenerators/ConstantSkillGenerator.java @@ -22,10 +22,6 @@ import megamek.common.Entity; public class ConstantSkillGenerator extends AbstractSkillGenerator { - //region Variable Declarations - private static final long serialVersionUID = -7927373286417045956L; - //endregion Variable Declarations - //region Constructors public ConstantSkillGenerator() { this(SkillGeneratorMethod.CONSTANT); @@ -36,16 +32,9 @@ protected ConstantSkillGenerator(final SkillGeneratorMethod method) { } //endregion Constructors - /** - * This returns the unmodified default random skill value, which is a set of constants - * - * @param entity the Entity to generate a random skill array for - * @param forceClan forces the type to be clan if the entity is a clan unit - * @return an integer array containing the (Gunnery, Piloting) skill values, or an alternative - * pairing if applicable [(Gunnery, Anti-'Mech) for infantry] - */ @Override - public int[] generateRandomSkills(final Entity entity, final boolean forceClan) { + public int[] generateRandomSkills(final Entity entity, final boolean clanner, + final boolean forceClan) { return cleanReturn(entity, getLevel().getDefaultSkillValues()); } } diff --git a/megamek/src/megamek/client/generator/skillGenerators/ModifiedConstantSkillGenerator.java b/megamek/src/megamek/client/generator/skillGenerators/ModifiedConstantSkillGenerator.java index 65c1ba0aa38..eef93bca1c4 100644 --- a/megamek/src/megamek/client/generator/skillGenerators/ModifiedConstantSkillGenerator.java +++ b/megamek/src/megamek/client/generator/skillGenerators/ModifiedConstantSkillGenerator.java @@ -23,10 +23,6 @@ import megamek.common.enums.SkillLevel; public class ModifiedConstantSkillGenerator extends ConstantSkillGenerator { - //region Variable Declarations - private static final long serialVersionUID = -3276792082665884815L; - //endregion Variable Declarations - //region Constructors public ModifiedConstantSkillGenerator() { super(SkillGeneratorMethod.MODIFIED_CONSTANT); @@ -34,13 +30,14 @@ public ModifiedConstantSkillGenerator() { //endregion Constructors @Override - public int[] generateRandomSkills(final Entity entity, final boolean forceClan) { + public int[] generateRandomSkills(final Entity entity, final boolean clanner, + final boolean forceClan) { if (getType().isManeiDomini()) { // JHS72 pg. 121, they are always considered elite return SkillLevel.ELITE.getDefaultSkillValues(); } - final int[] skills = super.generateRandomSkills(entity, forceClan); + final int[] skills = super.generateRandomSkills(entity, clanner, forceClan); // Now we need to make all kinds of adjustments based on the table on pg. 40 of TW // Infantry Anti-'Mech skill should be one higher unless foot @@ -54,7 +51,7 @@ public int[] generateRandomSkills(final Entity entity, final boolean forceClan) } // Now lets handle clanners - if (getType().isClan() || (forceClan && entity.isClan())) { + if (getType().isClan() || (forceClan && clanner)) { // 'Mechs and Battle Armour are better (but not ProtoMechs), // Tanks are worse, while Gunnery is worse for Infantry, Conventional Fighters // and Small Craft diff --git a/megamek/src/megamek/client/generator/skillGenerators/ModifiedTotalWarfareSkillGenerator.java b/megamek/src/megamek/client/generator/skillGenerators/ModifiedTotalWarfareSkillGenerator.java index 8608c8a3336..69f7cec85aa 100644 --- a/megamek/src/megamek/client/generator/skillGenerators/ModifiedTotalWarfareSkillGenerator.java +++ b/megamek/src/megamek/client/generator/skillGenerators/ModifiedTotalWarfareSkillGenerator.java @@ -23,10 +23,6 @@ import megamek.common.*; public class ModifiedTotalWarfareSkillGenerator extends TotalWarfareSkillGenerator { - //region Variable Declarations - private static final long serialVersionUID = -4805975255577570411L; - //endregion Variable Declarations - //region Constructors public ModifiedTotalWarfareSkillGenerator() { super(SkillGeneratorMethod.MODIFIED_TOTAL_WARFARE); @@ -34,8 +30,9 @@ public ModifiedTotalWarfareSkillGenerator() { //endregion Constructors @Override - protected int determineBonus(final Entity entity, final boolean forceClan) { - final SkillGeneratorType type = (forceClan && entity.isClan()) ? SkillGeneratorType.CLAN : getType(); + protected int determineBonus(final Entity entity, final boolean clanner, + final boolean forceClan) { + final SkillGeneratorType type = (forceClan && clanner) ? SkillGeneratorType.CLAN : getType(); int bonus = 0; if (type.isClan()) { diff --git a/megamek/src/megamek/client/generator/skillGenerators/TaharqaSkillGenerator.java b/megamek/src/megamek/client/generator/skillGenerators/TaharqaSkillGenerator.java index 9c1e45d264b..9e1bc054812 100644 --- a/megamek/src/megamek/client/generator/skillGenerators/TaharqaSkillGenerator.java +++ b/megamek/src/megamek/client/generator/skillGenerators/TaharqaSkillGenerator.java @@ -25,10 +25,6 @@ import megamek.common.enums.SkillLevel; public class TaharqaSkillGenerator extends TotalWarfareSkillGenerator { - //region Variable Declarations - private static final long serialVersionUID = -7334417837623003013L; - //endregion Variable Declarations - //region Constructors public TaharqaSkillGenerator() { super(SkillGeneratorMethod.TAHARQA); @@ -38,12 +34,14 @@ public TaharqaSkillGenerator() { /** * The base skill level for each entity is determined separately in Taharqa's Method * @param entity the Entity to generate a random skill array for - * @param forceClan forces the type to be clan if the entity is a clan unit + * @param clanner if the crew to generate a random skills array for are clanners + * @param forceClan forces the type to be clan if the crew are clanners * @return an integer array containing the (Gunnery, Piloting) skill values, or an alternative * pairing if applicable [(Gunnery, Anti-'Mech) for infantry] */ @Override - public int[] generateRandomSkills(final Entity entity, final boolean forceClan) { + public int[] generateRandomSkills(final Entity entity, final boolean clanner, + final boolean forceClan) { int bonus; switch (getLevel()) { case ULTRA_GREEN: @@ -94,6 +92,6 @@ public int[] generateRandomSkills(final Entity entity, final boolean forceClan) level = SkillLevel.LEGENDARY; } - return generateRandomSkills(level, entity, forceClan); + return generateRandomSkills(level, entity, clanner, forceClan); } } diff --git a/megamek/src/megamek/client/generator/skillGenerators/TotalWarfareSkillGenerator.java b/megamek/src/megamek/client/generator/skillGenerators/TotalWarfareSkillGenerator.java index 7fd4f0e1704..17ffe3f91f7 100644 --- a/megamek/src/megamek/client/generator/skillGenerators/TotalWarfareSkillGenerator.java +++ b/megamek/src/megamek/client/generator/skillGenerators/TotalWarfareSkillGenerator.java @@ -28,8 +28,6 @@ public class TotalWarfareSkillGenerator extends AbstractSkillGenerator { //region Variable Declarations - private static final long serialVersionUID = 1120383901354362683L; - protected static final int[][] SKILL_LEVELS = new int[][] { { 7, 6, 5, 4, 4, 3, 2, 1, 0, 0 }, { 7, 7, 6, 6, 5, 4, 3, 2, 1, 0 } }; @@ -46,13 +44,14 @@ protected TotalWarfareSkillGenerator(final SkillGeneratorMethod method) { //endregion Constructors @Override - public int[] generateRandomSkills(final Entity entity, final boolean forceClan) { - return generateRandomSkills(getLevel(), entity, forceClan); + public int[] generateRandomSkills(final Entity entity, final boolean clanner, + final boolean forceClan) { + return generateRandomSkills(getLevel(), entity, clanner, forceClan); } protected int[] generateRandomSkills(final SkillLevel level, final Entity entity, - final boolean forceClan) { - final int bonus = determineBonus(entity, forceClan); + final boolean clanner, final boolean forceClan) { + final int bonus = determineBonus(entity, clanner, forceClan); final int gunneryRoll = Compute.d6(1) + bonus; final int pilotingRoll = Compute.d6(1) + bonus; @@ -101,11 +100,13 @@ protected int[] generateRandomSkills(final SkillLevel level, final Entity entity /** * @param entity the entity whose crew skill is being rolled - * @param forceClan whether to force clan generation for a clan entity + * @param clanner if the crew is led by a clanner + * @param forceClan forces the type to be clan if the crew are led by a clanner * @return the bonus to use on the Random Skills Table (Expanded) roll */ - protected int determineBonus(final Entity entity, final boolean forceClan) { - if (getType().isClan() || (forceClan && entity.isClan())) { + protected int determineBonus(final Entity entity, final boolean clanner, + final boolean forceClan) { + if (getType().isClan() || (forceClan && clanner)) { if (entity instanceof Mech) { return 2; } else if (entity instanceof Tank) { diff --git a/megamek/src/megamek/client/ratgenerator/CrewDescriptor.java b/megamek/src/megamek/client/ratgenerator/CrewDescriptor.java index 9a35a380444..856f3f41218 100644 --- a/megamek/src/megamek/client/ratgenerator/CrewDescriptor.java +++ b/megamek/src/megamek/client/ratgenerator/CrewDescriptor.java @@ -326,6 +326,6 @@ public void setPiloting(int piloting) { } public Crew createCrew(CrewType crewType) { - return new Crew(crewType, name, 1, gunnery, piloting, gender, null); + return new Crew(crewType, name, 1, gunnery, piloting, gender, assignment.getFactionRec().isClan(), null); } } diff --git a/megamek/src/megamek/client/ui/swing/CustomMechDialog.java b/megamek/src/megamek/client/ui/swing/CustomMechDialog.java index e06ad75a5eb..2a251f82dd2 100644 --- a/megamek/src/megamek/client/ui/swing/CustomMechDialog.java +++ b/megamek/src/megamek/client/ui/swing/CustomMechDialog.java @@ -1120,6 +1120,7 @@ public void actionPerformed(ActionEvent actionEvent) { entity.getCrew().setName(name, i); entity.getCrew().setNickname(nick, i); entity.getCrew().setGender(gender, i); + entity.getCrew().setClanner(panCrewMember[i].isClanner(), i); entity.getCrew().setPortrait(panCrewMember[i].getPortrait().clone(), i); if (backup >= 0) { if (i == entity.getCrew().getCrewType().getPilotPos()) { diff --git a/megamek/src/megamek/client/ui/swing/CustomPilotView.java b/megamek/src/megamek/client/ui/swing/CustomPilotView.java index 1830b41b986..b244ebdf383 100644 --- a/megamek/src/megamek/client/ui/swing/CustomPilotView.java +++ b/megamek/src/megamek/client/ui/swing/CustomPilotView.java @@ -49,6 +49,7 @@ public class CustomPilotView extends JPanel { private final JCheckBox chkMissing = new JCheckBox(Messages.getString("CustomMechDialog.chkMissing")); private final JTextField fldName = new JTextField(20); private final JTextField fldNick = new JTextField(20); + private final JCheckBox chkClanner = new JCheckBox(Messages.getString("CustomMechDialog.chkClanner")); private final JTextField fldGunnery = new JTextField(3); private final JTextField fldGunneryL = new JTextField(3); private final JTextField fldGunneryM = new JTextField(3); @@ -96,12 +97,12 @@ public CustomPilotView(CustomMechDialog parent, Entity entity, int slot, boolean portrait = entity.getCrew().getPortrait(slot); portraitButton.setIcon(entity.getCrew().getPortrait(slot).getImageIcon()); - add(portraitButton, GBC.std().gridheight(2)); + add(portraitButton, GBC.std().gridheight(4)); JButton button = new JButton(Messages.getString("CustomMechDialog.RandomName")); button.addActionListener(e -> { gender = RandomGenderGenerator.generate(); - fldName.setText(RandomNameGenerator.getInstance().generate(gender, entity.getOwner().getName())); + fldName.setText(RandomNameGenerator.getInstance().generate(gender, isClanner(), entity.getOwner().getName())); }); add(button, GBC.eop()); @@ -122,6 +123,9 @@ public CustomPilotView(CustomMechDialog parent, Entity entity, int slot, boolean }); add(button, GBC.eop()); + add(chkClanner, GBC.eop()); + chkClanner.setSelected(entity.getCrew().isClanner(slot)); + label = new JLabel(Messages.getString("CustomMechDialog.labName"), SwingConstants.RIGHT); add(label, GBC.std()); add(fldName, GBC.eol()); @@ -283,6 +287,7 @@ public boolean accept(Entity unitEntity) { if (!editable) { fldName.setEnabled(false); fldNick.setEnabled(false); + chkClanner.setEnabled(false); fldGunnery.setEnabled(false); fldGunneryL.setEnabled(false); fldGunneryM.setEnabled(false); @@ -346,6 +351,10 @@ public String getNickname() { public Gender getGender() { return gender; } + + public boolean isClanner() { + return chkClanner.isSelected(); + } public int getGunnery() { return Integer.parseInt(fldGunnery.getText()); diff --git a/megamek/src/megamek/client/ui/swing/RandomArmyDialog.java b/megamek/src/megamek/client/ui/swing/RandomArmyDialog.java index ead050f161f..25a4a160eb9 100644 --- a/megamek/src/megamek/client/ui/swing/RandomArmyDialog.java +++ b/megamek/src/megamek/client/ui/swing/RandomArmyDialog.java @@ -907,16 +907,18 @@ public void setVisible(boolean show) { private void autoSetSkillsAndName(Entity e) { ClientPreferences cs = PreferenceManager.getClientPreferences(); + + Arrays.fill(e.getCrew().getClanners(), e.isClan()); if (cs.useAverageSkills()) { - m_client.getSkillGenerator().setRandomSkills(e, true); + m_client.getSkillGenerator().setRandomSkills(e); } for (int i = 0; i < e.getCrew().getSlotCount(); i++) { if (cs.generateNames()) { Gender gender = RandomGenderGenerator.generate(); e.getCrew().setGender(gender, i); - e.getCrew().setName(RandomNameGenerator.getInstance() - .generate(gender, (String) m_chPlayer.getSelectedItem()), i); + e.getCrew().setName(RandomNameGenerator.getInstance().generate(gender, + e.getCrew().isClanner(i), (String) m_chPlayer.getSelectedItem()), i); } } } diff --git a/megamek/src/megamek/client/ui/swing/RandomNameDialog.java b/megamek/src/megamek/client/ui/swing/RandomNameDialog.java index ce396e90ac0..90a8e78d2a6 100644 --- a/megamek/src/megamek/client/ui/swing/RandomNameDialog.java +++ b/megamek/src/megamek/client/ui/swing/RandomNameDialog.java @@ -155,10 +155,11 @@ public void actionPerformed(ActionEvent ev) { Gender gender = RandomGenderGenerator.generate(); ent.getCrew().setGender(gender, i); if (comboHistoricalEthnicity.getSelectedIndex() == 0) { - ent.getCrew().setName(RandomNameGenerator.getInstance().generate(gender), i); + ent.getCrew().setName(RandomNameGenerator.getInstance().generate(gender, + ent.getCrew().isClanner(i)), i); } else { ent.getCrew().setName(RandomNameGenerator.getInstance().generateWithEthnicCode( - gender, (String) comboFaction.getSelectedItem(), + gender, ent.getCrew().isClanner(i), comboHistoricalEthnicity.getSelectedIndex()), i); } } diff --git a/megamek/src/megamek/client/ui/swing/dialog/MegaMekUnitSelectorDialog.java b/megamek/src/megamek/client/ui/swing/dialog/MegaMekUnitSelectorDialog.java index 078df249802..bfa39eda923 100644 --- a/megamek/src/megamek/client/ui/swing/dialog/MegaMekUnitSelectorDialog.java +++ b/megamek/src/megamek/client/ui/swing/dialog/MegaMekUnitSelectorDialog.java @@ -36,6 +36,7 @@ import javax.swing.*; import java.awt.*; +import java.util.Arrays; import java.util.Map; public class MegaMekUnitSelectorDialog extends AbstractUnitSelectorDialog { @@ -112,6 +113,7 @@ protected void select(boolean close) { e.setOwner(client.getLocalPlayer()); client.sendAddEntity(e); } + if (close) { setVisible(false); } @@ -120,8 +122,9 @@ protected void select(boolean close) { private void autoSetSkillsAndName(Entity e, Player player) { ClientPreferences cs = PreferenceManager.getClientPreferences(); + Arrays.fill(e.getCrew().getClanners(), e.isClan()); if (cs.useAverageSkills()) { - clientGUI.getClient().getSkillGenerator().setRandomSkills(e, true); + clientGUI.getClient().getSkillGenerator().setRandomSkills(e); } for (int i = 0; i < e.getCrew().getSlotCount(); i++) { @@ -129,8 +132,8 @@ private void autoSetSkillsAndName(Entity e, Player player) { Gender gender = RandomGenderGenerator.generate(); e.getCrew().setGender(gender, i); e.getCrew().setName((player != null) - ? RandomNameGenerator.getInstance().generate(gender, player.getName()) - : RandomNameGenerator.getInstance().generate(gender), i); + ? RandomNameGenerator.getInstance().generate(gender, e.getCrew().isClanner(i), player.getName()) + : RandomNameGenerator.getInstance().generate(gender, e.getCrew().isClanner(i)), i); } } } diff --git a/megamek/src/megamek/client/ui/swing/lobby/LobbyActions.java b/megamek/src/megamek/client/ui/swing/lobby/LobbyActions.java index 3eedfc27ab3..1a435734958 100644 --- a/megamek/src/megamek/client/ui/swing/lobby/LobbyActions.java +++ b/megamek/src/megamek/client/ui/swing/lobby/LobbyActions.java @@ -439,7 +439,7 @@ void setRandomSkills(Collection entities) { } for (final Entity entity : entities) { final Client client = lobby.getLocalClient(entity); - client.getSkillGenerator().setRandomSkills(entity, true); + client.getSkillGenerator().setRandomSkills(entity); } sendUpdates(entities); } @@ -456,7 +456,7 @@ void setRandomNames(Collection entities) { for (int i = 0; i < e.getCrew().getSlotCount(); i++) { Gender gender = RandomGenderGenerator.generate(); e.getCrew().setGender(gender, i); - e.getCrew().setName(RandomNameGenerator.getInstance().generate(gender, e.getOwner().getName()), i); + e.getCrew().setName(RandomNameGenerator.getInstance().generate(gender, e.getCrew().isClanner(i), e.getOwner().getName()), i); } } sendUpdates(entities); @@ -477,7 +477,7 @@ void setRandomCallsigns(Collection entities) { } sendUpdates(entities); } - + /** * Asks for a name and creates a new top-level force of that name. */ @@ -489,7 +489,7 @@ void forceCreateEmpty() { } client().sendAddForce(Force.createToplevelForce(name, localPlayer()), new ArrayList<>()); } - + /** * Asks for a name and creates a new top-level force of that name with the * selected entities in it. diff --git a/megamek/src/megamek/common/Crew.java b/megamek/src/megamek/common/Crew.java index 500d4f52b9b..919f371185a 100644 --- a/megamek/src/megamek/common/Crew.java +++ b/megamek/src/megamek/common/Crew.java @@ -15,7 +15,6 @@ */ package megamek.common; -import megamek.client.generator.RandomGenderGenerator; import megamek.common.enums.Gender; import megamek.common.icons.Portrait; import megamek.common.options.IOption; @@ -48,6 +47,7 @@ public class Crew implements Serializable { private final String[] names; private final String[] nicknames; private final Gender[] genders; + private final boolean[] clanners; private final Portrait[] portraits; private final int[] gunnery; @@ -58,10 +58,10 @@ public class Crew implements Serializable { private final boolean[] unconscious; private final boolean[] dead; - //Allow for the possibility that the unit is fielded with less than full crew. + // Allow for the possibility that the unit is fielded with less than full crew. private final boolean[] missing; - //The following only apply to the entire crew. + // The following only apply to the entire crew. private boolean doomed; // scheduled to die at end of phase private boolean ejected; @@ -158,6 +158,7 @@ public class Crew implements Serializable { public static final String MAP_BLOODNAME = "bloodname"; public static final String MAP_PHENOTYPE = "phenotype"; //endregion extraData inner map keys + /** * The number of hits that a pilot can take before he dies. */ @@ -176,68 +177,7 @@ public class Crew implements Serializable { * @param crewType the crew type to use. */ public Crew(CrewType crewType) { - this(crewType, "Unnamed", crewType.getCrewSlots(), 4, 5, Gender.FEMALE, null); - } - - /** - * @param name the name of the crew or commander. - * @param size the crew size. - * @param gunnery the crew's Gunnery skill. - * @param piloting the crew's Piloting or Driving skill. - * @deprecated by multi-crew cockpit support. Replaced by {@link #Crew(CrewType, String, int, int, int, Gender, Map)}. - * - * Creates a basic crew for a self-piloted unit. Using this constructor for a naval vessel will - * result in a secondary target modifier for additional targets past the first. - */ - @Deprecated - public Crew(String name, int size, int gunnery, int piloting) { - this(CrewType.SINGLE, name, size, gunnery, gunnery, gunnery, piloting, null); - } - - /** - * @param crewType the type of crew - * @param name the name of the crew or commander. - * @param size the crew size. - * @param gunnery the crew's Gunnery skill. - * @param piloting the crew's Piloting or Driving skill. - * @deprecated by gender support. Replaced by {@link #Crew(CrewType, String, int, int, int, Gender, Map)}. - */ - @Deprecated //18-Feb-2020 as part of the addition of gender to MegaMek - public Crew(CrewType crewType, String name, int size, int gunnery, int piloting) { - this(crewType, name, size, gunnery, gunnery, gunnery, piloting, null); - } - - /** - * @param crewType the type of crew. - * @param name the name of the crew or commander. - * @param size the crew size. - * @param gunneryL the crew's "laser" Gunnery skill. - * @param gunneryM the crew's "missile" Gunnery skill. - * @param gunneryB the crew's "ballistic" Gunnery skill. - * @param piloting the crew's Piloting or Driving skill. - * @deprecated by gender support. Replaced by {@link #Crew(CrewType, String, int, int, int, int, int, Gender, Map)}. - */ - @Deprecated //18-Feb-2020 as part of the addition of gender to MegaMek - public Crew(CrewType crewType, String name, int size, int gunneryL, int gunneryM, int gunneryB, - int piloting) { - this(crewType, name, size, gunneryL, gunneryM, gunneryB, piloting, null); - } - - /** - * @param crewType the type of crew. - * @param name the name of the crew or commander. - * @param size the crew size. - * @param gunneryL the crew's "laser" Gunnery skill. - * @param gunneryM the crew's "missile" Gunnery skill. - * @param gunneryB the crew's "ballistic" Gunnery skill. - * @param piloting the crew's Piloting or Driving skill. - * @param extraData any extra data passed to be stored with this Crew. - * @deprecated by gender support. Replaced by {@link #Crew(CrewType, String, int, int, int, int, int, Gender, Map)}. - */ - @Deprecated //18-Feb-2020 as part of the addition of gender to MegaMek - public Crew(CrewType crewType, String name, int size, int gunneryL, int gunneryM, int gunneryB, - int piloting, Map> extraData) { - this(crewType, name, size, gunneryL, gunneryM, gunneryB, piloting, RandomGenderGenerator.generate(), extraData); + this(crewType, "Unnamed", crewType.getCrewSlots(), 4, 5, Gender.FEMALE, false, null); } /** @@ -247,11 +187,12 @@ public Crew(CrewType crewType, String name, int size, int gunneryL, int gunneryM * @param gunnery the crew's Gunnery skill. * @param piloting the crew's Piloting or Driving skill. * @param gender the gender of the crew or commander + * @param clanner if the crew or commander is a clanner * @param extraData any extra data passed to be stored with this Crew. */ public Crew(CrewType crewType, String name, int size, int gunnery, int piloting, Gender gender, - Map> extraData) { - this(crewType, name, size, gunnery, gunnery, gunnery, piloting, gender, extraData); + boolean clanner, Map> extraData) { + this(crewType, name, size, gunnery, gunnery, gunnery, piloting, gender, clanner, extraData); } /** @@ -263,10 +204,12 @@ public Crew(CrewType crewType, String name, int size, int gunnery, int piloting, * @param gunneryB the crew's "ballistic" Gunnery skill. * @param piloting the crew's Piloting or Driving skill. * @param gender the gender of the crew or commander + * @param clanner if the crew or commander is a clanner * @param extraData any extra data passed to be stored with this Crew. */ public Crew(CrewType crewType, String name, int size, int gunneryL, int gunneryM, int gunneryB, - int piloting, Gender gender, Map> extraData) { + int piloting, Gender gender, boolean clanner, + Map> extraData) { this.crewType = crewType; this.size = Math.max(size, crewType.getCrewSlots()); this.currentSize = size; @@ -281,6 +224,8 @@ public Crew(CrewType crewType, String name, int size, int gunneryL, int gunneryM genders = new Gender[slots]; Arrays.fill(getGenders(), Gender.RANDOMIZE); setGender(gender, 0); + clanners = new boolean[slots]; + Arrays.fill(getClanners(), clanner); portraits = new Portrait[slots]; for (int i = 0; i < slots; i++) { setPortrait(new Portrait(), i); @@ -383,6 +328,22 @@ public void setGender(final Gender gender, final int pos) { getGenders()[pos] = gender; } + public boolean[] getClanners() { + return clanners; + } + + public boolean isClanner() { + return getClanners()[0]; + } + + public boolean isClanner(final int position) { + return (position < getClanners().length) ? getClanners()[position] : isClanner(); + } + + public void setClanner(final boolean clanner, final int position) { + getClanners()[position] = clanner; + } + public Portrait[] getPortraits() { return portraits; } diff --git a/megamek/src/megamek/common/Entity.java b/megamek/src/megamek/common/Entity.java index dbd9d60785c..72bf26e854e 100644 --- a/megamek/src/megamek/common/Entity.java +++ b/megamek/src/megamek/common/Entity.java @@ -10042,8 +10042,9 @@ && hasWorkingMisc(MiscType.F_TOOLS, } // check game options - if (game.getOptions().booleanOption(OptionsConstants.ALLOWED_NO_CLAN_PHYSICAL) && isClan() - && !hasINarcPodsAttached() && (getSwarmAttackerId() == NONE)) { + if (game.getOptions().booleanOption(OptionsConstants.ALLOWED_NO_CLAN_PHYSICAL) + && getCrew().isClanner() && !hasINarcPodsAttached() + && (getSwarmAttackerId() == NONE)) { return false; } diff --git a/megamek/src/megamek/common/LAMPilot.java b/megamek/src/megamek/common/LAMPilot.java index bc15d41e20a..be04cc3f5f0 100644 --- a/megamek/src/megamek/common/LAMPilot.java +++ b/megamek/src/megamek/common/LAMPilot.java @@ -39,12 +39,13 @@ public class LAMPilot extends Crew { public LAMPilot(LandAirMech lam) { this(lam, RandomNameGenerator.UNNAMED_FULL_NAME, 4, 5, - 4, 5, Gender.RANDOMIZE, null); + 4, 5, Gender.RANDOMIZE, false, null); } - public LAMPilot(LandAirMech lam, String name, int gunneryMech, int pilotingMech, int gunneryAero, - int pilotingAero, Gender gender, Map> extraData) { - super(CrewType.SINGLE, name, 1, gunneryMech, pilotingMech, gender, extraData); + public LAMPilot(LandAirMech lam, String name, int gunneryMech, int pilotingMech, + int gunneryAero, int pilotingAero, Gender gender, boolean clanner, + Map> extraData) { + super(CrewType.SINGLE, name, 1, gunneryMech, pilotingMech, gender, clanner, extraData); this.lam = lam; this.gunneryAero = gunneryAero; this.pilotingAero = pilotingAero; @@ -68,7 +69,7 @@ public static LAMPilot convertToLAMPilot(LandAirMech lam, Crew crew) { Map> extraData = new HashMap<>(); extraData.put(0, crew.getExtraDataForCrewMember(0)); LAMPilot pilot = new LAMPilot(lam, crew.getName(), crew.getGunnery(), crew.getPiloting(), - crew.getGunnery(), crew.getPiloting(), crew.getGender(), extraData); + crew.getGunnery(), crew.getPiloting(), crew.getGender(), crew.isClanner(), extraData); pilot.setNickname(crew.getNickname(), 0); pilot.setPortrait(crew.getPortrait(0).clone(), 0); pilot.setGunneryL(crew.getGunneryL(), 0); @@ -270,9 +271,8 @@ public String getSkillsAsString(int pos, boolean showPiloting, boolean rpgSkills @Override public Vector getDescVector(boolean gunneryOnly) { Vector vDesc = new Vector<>(); - Report r; - r = new Report(); + Report r = new Report(); r.type = Report.PUBLIC; r.add(getName(0)); if (getSlotCount() > 1) { diff --git a/megamek/src/megamek/common/MULParser.java b/megamek/src/megamek/common/MULParser.java index 63f182993e3..1569ef3b03e 100644 --- a/megamek/src/megamek/common/MULParser.java +++ b/megamek/src/megamek/common/MULParser.java @@ -116,6 +116,7 @@ public class MULParser { private static final String PICKUP_ID = "pickUpId"; private static final String NICK = "nick"; private static final String GENDER = "gender"; + private static final String CLANNER = "clanner"; private static final String CAT_PORTRAIT = "portraitCat"; private static final String FILE_PORTRAIT = "portraitFile"; private static final String GUNNERY = "gunnery"; @@ -1247,6 +1248,10 @@ private void setPilotAttributes(final @Nullable GameOptions options, final Crew crew.setGender(Gender.parseFromString(attributes.get(GENDER)), slot); } + if ((attributes.containsKey(CLANNER)) && !attributes.get(CLANNER).isBlank()) { + crew.setClanner(Boolean.parseBoolean(attributes.get(CLANNER)), slot); + } + if ((attributes.containsKey(CAT_PORTRAIT)) && !attributes.get(CAT_PORTRAIT).isBlank()) { crew.getPortrait(slot).setCategory(attributes.get(CAT_PORTRAIT)); } diff --git a/megamek/src/megamek/common/Mech.java b/megamek/src/megamek/common/Mech.java index 608f7976782..eea5f994848 100644 --- a/megamek/src/megamek/common/Mech.java +++ b/megamek/src/megamek/common/Mech.java @@ -5949,8 +5949,7 @@ public TargetRoll getStealthModifier(int range, Entity ae) { */ @Override public boolean isRepairable() { - // A Mech is repairable if it is salvageable, - // and its CT internals are not gone. + // A Mech is repairable if it is salvageable, and its CT internals are not gone. int loc_is = this.getInternal(Mech.LOC_CT); return isSalvage() && (loc_is != IArmorState.ARMOR_DOOMED) && (loc_is != IArmorState.ARMOR_DESTROYED); @@ -5958,21 +5957,23 @@ public boolean isRepairable() { @Override public boolean canCharge() { - // Mechs can charge, unless they are Clan and the "no clan physicals" - // option is set + // Mechs can charge, unless they are Clan and the "no clan physicals" option is set return super.canCharge() - && !(game.getOptions().booleanOption(OptionsConstants.ALLOWED_NO_CLAN_PHYSICAL) && isClan()); + && !(game.getOptions().booleanOption(OptionsConstants.ALLOWED_NO_CLAN_PHYSICAL) + && getCrew().isClanner()); } @Override public boolean canDFA() { - // Mechs can DFA, unless they are Clan and the "no clan physicals" - // option is set + // Mechs can DFA, unless they are Clan and the "no clan physicals" option is set return super.canDFA() - && !(game.getOptions().booleanOption(OptionsConstants.ALLOWED_NO_CLAN_PHYSICAL) && isClan()); + && !(game.getOptions().booleanOption(OptionsConstants.ALLOWED_NO_CLAN_PHYSICAL) + && getCrew().isClanner()); } - // gives total number of sinks + /** + * @return the total number of sinks + */ public int getNumberOfSinks() { int sinks = 0; for (Mounted mounted : getMisc()) { diff --git a/megamek/src/megamek/common/actions/FindClubAction.java b/megamek/src/megamek/common/actions/FindClubAction.java index 66a95c91a4f..edd406faf60 100644 --- a/megamek/src/megamek/common/actions/FindClubAction.java +++ b/megamek/src/megamek/common/actions/FindClubAction.java @@ -61,7 +61,8 @@ public static boolean canMechFindClub(Game game, int entityId) { } // Check game options - if (game.getOptions().booleanOption(OptionsConstants.ALLOWED_NO_CLAN_PHYSICAL) && entity.isClan()) { + if (game.getOptions().booleanOption(OptionsConstants.ALLOWED_NO_CLAN_PHYSICAL) + && entity.getCrew().isClanner()) { return false; } @@ -77,7 +78,7 @@ public static boolean canMechFindClub(Game game, int entityId) { } // also, need shoulders and hands - // Claws can subtitue as hands --Torren + // Claws can substitute as hands --Torren if (!entity.hasWorkingSystem(Mech.ACTUATOR_SHOULDER, Mech.LOC_RARM) || !entity.hasWorkingSystem(Mech.ACTUATOR_SHOULDER, Mech.LOC_LARM) || (!entity.hasWorkingSystem(Mech.ACTUATOR_HAND, Mech.LOC_RARM) && !((Mech) entity).hasClaw(Mech.LOC_RARM)) @@ -91,11 +92,6 @@ public static boolean canMechFindClub(Game game, int entityId) { } // and last, check if you already have a club, greedy - if (entity.getClubs().size() > 0) { - return false; - } - - return true; + return entity.getClubs().isEmpty(); } - } diff --git a/megamek/src/megamek/common/options/OptionsConstants.java b/megamek/src/megamek/common/options/OptionsConstants.java index 8e7f4f56263..d7be728fdb3 100644 --- a/megamek/src/megamek/common/options/OptionsConstants.java +++ b/megamek/src/megamek/common/options/OptionsConstants.java @@ -321,7 +321,7 @@ public class OptionsConstants { public static final String ALLOWED_ERA_BASED = "era_based"; public static final String ALLOWED_ALLOW_ILLEGAL_UNITS= "allow_illegal_units"; public static final String ALLOWED_CLAN_IGNORE_EQ_LIMITS= "clan_ignore_eq_limits"; - public static final String ALLOWED_NO_CLAN_PHYSICAL= "no_clan_physical"; + public static final String ALLOWED_NO_CLAN_PHYSICAL = "no_clan_physical"; public static final String ALLOWED_ALLOW_NUKES= "allow_nukes"; public static final String ALLOWED_REALLY_ALLOW_NUKES= "really_allow_nukes"; diff --git a/megamek/src/megamek/server/ScenarioLoader.java b/megamek/src/megamek/server/ScenarioLoader.java index 9078471fde5..5553310f524 100644 --- a/megamek/src/megamek/server/ScenarioLoader.java +++ b/megamek/src/megamek/server/ScenarioLoader.java @@ -602,18 +602,18 @@ private Entity parseEntityLine(String s) throws ScenarioLoaderException { if ((parts.length > 4) && parts[4].matches("-?\\d+")) { e.setCrew(new Crew(e.getCrew().getCrewType(), parts[1], 1, Integer.parseInt(parts[2]), Integer.parseInt(parts[3]), - Gender.parseFromString(parts[4]), null)); - i = 5; // direction will be part 5, as the scenario has the gender of its pilots included + Gender.parseFromString(parts[4]), Boolean.parseBoolean(parts[5]), null)); + i = 6; // direction will be part 6, as the scenario has the gender of its pilots included } else { e.setCrew(new Crew(e.getCrew().getCrewType(), parts[1], 1, Integer.parseInt(parts[2]), Integer.parseInt(parts[3]), - RandomGenderGenerator.generate(), null)); + RandomGenderGenerator.generate(), e.isClan(), null)); i = 4; // direction will be part 4, as the scenario does not contain gender } // This uses the i value to ensure it is calculated correctly if (parts.length >= 7) { - String direction = parts[i++].toUpperCase(Locale.ROOT); //grab value at i, then increment + String direction = parts[i++].toUpperCase(Locale.ROOT); // grab value at i, then increment switch (direction) { case "N": e.setFacing(0);