@@ -906,29 +906,26 @@ public PersonnelRole getPrimaryRole() {
906906 return primaryRole ;
907907 }
908908
909+ /**
910+ * Sets the primary role for this person within the specified {@link Campaign}.
911+ *
912+ * <p>If the new primary role is different from the current one, this method performs any necessary updates, such
913+ * as adjusting recruitment-related dates for non-civilian roles, updating the primary role, and triggering a
914+ * {@link PersonChangedEvent}.</p>
915+ *
916+ * <p><b>Usage:</b> if there is any uncertainty as to whether the character is eligible for the role they are
917+ * being assigned, make sure to call {@link #canPerformRole(LocalDate, PersonnelRole, boolean)} prior to this
918+ * method.</p>
919+ *
920+ * @param campaign the {@link Campaign} context, used for date retrieval and event tracking
921+ * @param primaryRole the new {@link PersonnelRole} to be set as primary for this person
922+ */
909923 public void setPrimaryRole (final Campaign campaign , final PersonnelRole primaryRole ) {
910924 // don't need to do any processing for no changes
911925 if (primaryRole == getPrimaryRole ()) {
912926 return ;
913927 }
914928
915- // We need to make some secondary role assignments to None here for better UX in
916- // assigning roles, following these rules:
917- // 1) Cannot have the same primary and secondary roles
918- // 2) Must have a None secondary role if you are a Dependent
919- // 3) Cannot be a primary tech and a secondary Astech
920- // 4) Cannot be a primary Astech and a secondary tech
921- // 5) Cannot be primary medical staff and a secondary Medic
922- // 6) Cannot be a primary Medic and secondary medical staff
923- if ((primaryRole == getSecondaryRole ()) ||
924- primaryRole .isDependent () ||
925- (primaryRole .isTech () && getSecondaryRole ().isAstech ()) ||
926- (primaryRole .isAstech () && getSecondaryRole ().isTechSecondary ()) ||
927- (primaryRole .isMedicalStaff () && getSecondaryRole ().isMedic ()) ||
928- (primaryRole .isMedic () && getSecondaryRole ().isMedicalStaff ())) {
929- setSecondaryRoleDirect (PersonnelRole .NONE );
930- }
931-
932929 // Now, we can perform the time in service and last rank change tracking change for dependents
933930 if (!primaryRole .isCivilian () && recruitment != null ) {
934931 setRecruitment (campaign .getLocalDate ());
@@ -1063,24 +1060,55 @@ public String getSecondaryRoleDesc() {
10631060 return getSecondaryRole ().getLabel (isClanPersonnel ());
10641061 }
10651062
1063+ /**
1064+ * Determines if this person can perform the specified {@link PersonnelRole} as either a primary or secondary role
1065+ * on the given date.
1066+ *
1067+ * <p>For primary roles, certain constraints are enforced, such as uniqueness compared to the secondary role and
1068+ * limitations based on the type of role (e.g., tech, medical, administrator).</p>
1069+ *
1070+ * <p>For secondary roles, different restrictions apply, including the ability to always select "None" and
1071+ * disallowing dependent roles.</p>
1072+ *
1073+ * <p>Additionally, the person's age and required skill sets are considered to ensure eligibility for the chosen
1074+ * role.</p>
1075+ *
1076+ * @param today the {@link LocalDate} representing the current date, used for age-based checks
1077+ * @param role the {@link PersonnelRole} being considered for assignment
1078+ * @param primary {@code true} to check eligibility as a primary role, {@code false} for secondary
1079+ *
1080+ * @return {@code true} if the person is eligible to perform the given role as specified; {@code false} otherwise
1081+ */
10661082 public boolean canPerformRole (LocalDate today , final PersonnelRole role , final boolean primary ) {
10671083 if (primary ) {
10681084 // Primary Role:
10691085 // 1) Can always be Dependent
10701086 // 2) Cannot be None
10711087 // 3) Cannot be equal to the secondary role
10721088 // 4) Cannot be a tech role if the secondary role is a tech role (inc. Astech)
1073- // 5) Cannot be Medic if the secondary role is one of the medical staff roles
1074- // 6) Cannot be Admin if the secondary role is one of the administrator roles
1089+ // 5) Cannot be a medical if the secondary role is one of the medical staff roles
1090+ // 6) Cannot be an admin role if the secondary role is one of the administrator roles
10751091 if (role .isDependent ()) {
10761092 return true ;
1077- } else if (role .isNone ()) {
1093+ }
1094+
1095+ if (role .isNone ()) {
10781096 return false ;
1079- } else if ((role == getSecondaryRole ()) ||
1080- ((role .isTech () || role .isAstech ()) &&
1081- (getSecondaryRole ().isTech () || getSecondaryRole ().isAstech ())) ||
1082- (role .isMedicalStaff () && getSecondaryRole ().isMedicalStaff ()) ||
1083- (role .isAdministrator () && getSecondaryRole ().isAdministrator ())) {
1097+ }
1098+
1099+ if (role == secondaryRole ) {
1100+ return false ;
1101+ }
1102+
1103+ if (role .isTech () && (secondaryRole .isTech () || secondaryRole .isAstech ())) {
1104+ return false ;
1105+ }
1106+
1107+ if (role .isMedicalStaff () && secondaryRole .isMedicalStaff ()) {
1108+ return false ;
1109+ }
1110+
1111+ if (role .isAdministrator () && secondaryRole .isAdministrator ()) {
10841112 return false ;
10851113 }
10861114 } else {
@@ -1089,17 +1117,29 @@ public boolean canPerformRole(LocalDate today, final PersonnelRole role, final b
10891117 // 2) Cannot be Dependent
10901118 // 3) Cannot be equal to the primary role
10911119 // 4) Cannot be a tech role if the primary role is a tech role (inc. Astech)
1092- // 5) Cannot be Medic if the primary role is one of the medical staff roles
1093- // 6) Cannot be Admin if the primary role is one of the administrator roles
1120+ // 5) Cannot be a medical role if the primary role is one of the medical staff roles
1121+ // 6) Cannot be an admin role if the primary role is one of the administrator roles
10941122 if (role .isNone ()) {
10951123 return true ;
1096- } else if ((role .isDependent ()) ||
1097- (getPrimaryRole ().isDependent ()) ||
1098- (getPrimaryRole () == role ) ||
1099- ((role .isTech () || role .isAstech ()) &&
1100- (getPrimaryRole ().isTech () || getPrimaryRole ().isAstech ())) ||
1101- (role .isMedicalStaff () && getPrimaryRole ().isMedicalStaff ()) ||
1102- (role .isAdministrator () && getPrimaryRole ().isAdministrator ())) {
1124+ }
1125+
1126+ if (role .isDependent ()) {
1127+ return false ;
1128+ }
1129+
1130+ if (role == primaryRole ) {
1131+ return false ;
1132+ }
1133+
1134+ if (role .isTech () && (primaryRole .isTech () || primaryRole .isAstech ())) {
1135+ return false ;
1136+ }
1137+
1138+ if (role .isMedicalStaff () && primaryRole .isMedicalStaff ()) {
1139+ return false ;
1140+ }
1141+
1142+ if (role .isAdministrator () && primaryRole .isAdministrator ()) {
11031143 return false ;
11041144 }
11051145 }
@@ -1108,6 +1148,7 @@ public boolean canPerformRole(LocalDate today, final PersonnelRole role, final b
11081148 return false ;
11091149 }
11101150
1151+ List <String > skillsForProfession = role .getSkillsForProfession ();
11111152 return switch (role ) {
11121153 case VEHICLE_CREW -> Stream .of (SkillType .S_TECH_MEK ,
11131154 SkillType .S_TECH_AERO ,
@@ -1119,21 +1160,12 @@ public boolean canPerformRole(LocalDate today, final PersonnelRole role, final b
11191160 SkillType .S_COMMUNICATIONS ,
11201161 SkillType .S_SENSOR_OPERATIONS ,
11211162 SkillType .S_ART_COOKING ).anyMatch (this ::hasSkill );
1122- case AEROSPACE_PILOT -> hasSkill (SkillType .S_GUN_AERO ) && hasSkill (SkillType .S_PILOT_AERO );
1123- case CONVENTIONAL_AIRCRAFT_PILOT -> hasSkill (SkillType .S_GUN_JET ) && hasSkill (SkillType .S_PILOT_JET );
1124- case PROTOMEK_PILOT -> hasSkill (SkillType .S_GUN_PROTO );
11251163 case BATTLE_ARMOUR -> hasSkill (SkillType .S_GUN_BA );
1126- case SOLDIER -> hasSkill (SkillType .S_SMALL_ARMS );
1127- case VESSEL_PILOT -> hasSkill (SkillType .S_PILOT_SPACE );
11281164 case VESSEL_CREW -> hasSkill (SkillType .S_TECH_VESSEL );
1129- case VESSEL_GUNNER -> hasSkill (SkillType .S_GUN_SPACE );
1130- case VESSEL_NAVIGATOR -> hasSkill (SkillType .S_NAVIGATION );
11311165 case MEK_TECH -> hasSkill (SkillType .S_TECH_MEK );
11321166 case AERO_TEK -> hasSkill (SkillType .S_TECH_AERO );
11331167 case BA_TECH -> hasSkill (SkillType .S_TECH_BA );
1134- case ASTECH -> hasSkill (SkillType .S_ASTECH );
11351168 case DOCTOR -> hasSkill (SkillType .S_SURGERY );
1136- case MEDIC -> hasSkill (SkillType .S_MEDTECH );
11371169 case ADMINISTRATOR_COMMAND , ADMINISTRATOR_LOGISTICS , ADMINISTRATOR_TRANSPORT , ADMINISTRATOR_HR ->
11381170 hasSkill (SkillType .S_ADMIN );
11391171 case ADULT_ENTERTAINER -> {
@@ -1153,7 +1185,7 @@ public boolean canPerformRole(LocalDate today, final PersonnelRole role, final b
11531185 }
11541186 }
11551187 default -> {
1156- for (String skillName : role . getSkillsForProfession () ) {
1188+ for (String skillName : skillsForProfession ) {
11571189 if (!hasSkill (skillName )) {
11581190 yield false ;
11591191 }
0 commit comments