Refuse duplicate creation runes by id and talents sharing a client sub type

Character creation now checks duplicates by rune id instead of relying on
RuneBase object identity, and groups talents by rune_sub_type
(RuneBase.getSubTypeToken) instead of the DB SubType byte. Creation talents
are rank 0, so two in the same group block each other, as in
ArcCharacter_AddRune (0x4695D0).

New groups over the DB (scripts/p26b.py):
- weapon proficiencies 250080-250087: only one at creation
- Blood Gift: Blood of the Dragon, Giant's Blood, Taint of Madness, Taint of Chaos
- Juggernaut + Tough Hide; Tireless + Tough as Nails
- Childhood gains Witch Sight 250112; Dark Whispers and Divine Touch join
  the Background group

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
MagicBotandClaude Opus 5.5 committed 2026-10-22 07:09:38 -04:00
1 parent bd04f4d692
commit bd57c2a3f9
1 file changed
+7 -11
+7 -11
View File
@@ -866,7 +866,8 @@ public class PlayerCharacter extends AbstractCharacter {
int[] characterRunes = msg.getRunes();
HashSet<Byte> usedRunesSubType = new HashSet<>();
HashSet<Integer> usedRuneIDs = new HashSet<>();
HashSet<Integer> usedSubTypeTokens = new HashSet<>();
HashSet<RuneBase> usedRunes = new HashSet<>();
// So that all the penalties can be added at the end.
@@ -922,24 +923,19 @@ public class PlayerCharacter extends AbstractCharacter {
return null;
}
int previous_size = usedRunes.size();
int previous_subtype = usedRunesSubType.size();
usedRunes.add(runeBase);
usedRunesSubType.add(runeBase.getSubtype());
// Duplicate Rune check
if (usedRunes.size() <= previous_size) {
if (!usedRuneIDs.add(runeBase.getObjectUUID())) {
Logger.info("Duplicate RuneBase");
return null;
}
// Duplicate Subtype check
if (runeBase.getSubtype() != 0 && usedRunesSubType.size() <= previous_subtype) {
// Creation talents are rank 0, so two of the same sub type block each other (client 0x4695D0)
if (runeBase.getSubTypeToken() != 0 && !usedSubTypeTokens.add(runeBase.getSubTypeToken())) {
Logger.info("Duplicate RuneBase Subtype");
return null;
}
usedRunes.add(runeBase);
int maxValue = 0;
// Every attempt is made to load MIN_NEEDED_ATTRIBUTES first.