Make the BCard (type, subtype) pair one key - #2325
Merged
Merged
Conversation
A BCard subtype only means something next to its type - every type reuses
11/12/21..52 - so CardType and AdditionalTypes had to be kept in step by an
identifier convention nothing checks, and the reading code cast the subtype
back to a byte to compare it. Comparing a Defence card against
AdditionalTypes.Damage.MeleeIncreased compiled: both are 21.
The pair is the identity, so BCardEffect is one flat enum keyed
type * 100 + subtype. Names are carried over unchanged from the nested
enums, so no naming work is lost.
That turns the fold in BattleStatsProvider from a switch over types with an
if/else ladder per subtype into a table: 68 rows, one per effect, and adding
one is a row rather than a branch in the right arm of the right switch.
documentation/dat/BCard.dat.md records what BCard.dat declares, next to the
five parser docs already there, and BCardVocabularyTests checks BCardEffect
against it the way LogLanguageTests checks language keys against the
resources - the always-on direction that no member is invented, and the
opt-in one, marked OPTIONAL-TEST like CheckEveryLanguageValueSet, that every
declared effect is named.
What that turns up, all of it pre-existing:
231 declared effects have no name, over 51 of the 129 types. Type 28 has
two of ten: sheep hunting, acorn throwing, pet training experience and
the extra-essence chance are all unnamed.
22 members are declared by no BCard.dat on record - every member of types
130 and 131, whose highest VNUM is 129.
1 type, 61, has vocabulary that nothing could reach: CardType has no
member for it, so AdditionalTypes.Type61 paired with nothing. It is
Type61* in the flat enum and reachable.
Tested: builds with 0 warnings, suite green as CI runs it - 984 tests, 2 new.
The opt-in test fails by design, listing all 231 with their client sentence.
Not played in game: BattleStatsProvider's numbers are covered by the existing
battle tests, which pass unchanged.
|
Warning Review limit reachedNext included review available in 7 minutes. View limit detailsLimit details: You’ve used all 2 included reviews currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (13)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
erwan-joly
marked this pull request as ready for review
August 27, 2026 12:38
This was referenced Aug 28, 2026
erwan-joly
pushed a commit
that referenced
this pull request
Aug 28, 2026
…tionalTypes (#2333) #2325 deleted `AdditionalTypes.cs` and replaced the (type, subtype) pair with a single `BCardEffect` key. #2321 merged right after it, carrying a `VitalityService` written against the old API, and the two are individually green and broken together: `error CS0246: AdditionalTypes could not be found`, fourteen times, on every build since. Ported: `card.Effect()` instead of casting `card.SubType` to a per-type enum, and the flattened members - `BCardEffect.QuestAdditionalHpPercent`, `BCardEffect.MaxHpmpMaximumHpIncreased` and the rest. The two switches become one because the key already carries the type, with the same early filter in front so `ScaleByLevel` is still only called for the two types that matter. The test moved the same way and no longer names a subtype by hand: `BCardEffect.MaxHpmpMaximumHpIncreased.Type()` / `.SubType()`. Behaviour is unchanged - every case maps one to one. Tested: build 0 errors 0 warnings; `dotnet test --filter TestCategory!=OPTIONAL-TEST` green, 1013 passed. Not played: the NosCore servers are not run here. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
denislauri1999
added a commit
to denislauri1999/NosCore
that referenced
this pull request
Aug 28, 2026
NosCoreIO#2325 ha cancellato `AdditionalTypes` sostituendo la coppia (tipo, sottotipo) con la chiave unica `BCardEffect`, quindi il ciclo di `InflictCardsAsync` non compilava piu' dopo la fusione. Portato allo stesso modo di `VitalityService` in NosCoreIO#2333: `bCard.Effect()` invece del cast del sottotipo, e `BCardEffect.BuffChanceCausing` / `BuffChanceRemoving` al posto dei due membri dell'enum sparito. Il test non nomina piu' un sottotipo a mano: `effect.Type()` e `effect.SubType()`. E `HitQueueTests` ha preso il parametro `IVitalityService` che master ha aggiunto al costruttore di `HitQueue`. Build pulita, 1021 test verdi col filtro della CI. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Draft, to show the shape. Nothing here is load-bearing yet — say the word and I'll split it, rename things, or take the parser side further.
Why the current shape hurts
A subtype only means something next to its type: every type reuses
11/12/21…52. That leaves three problems:CardTypeandAdditionalTypesare two hierarchies held together by an identifier convention nothing checks. Type 61 proves it —CardTypehas no member for it at all (// 61-80 Missingno = 61,is commented out), so theType61enum Name the 19 BCard types nothing could refer to #2324 added paired with nothing and no code could reach it.sub == (byte)AdditionalTypes.Damage.MeleeIncreasedagainst aDefencecard compiles fine — both are 21.What this does
The pair is the identity, so it becomes one value —
type * 100 + subtype, readable as-is in a debugger (2811 = type 28, subtype 11):Every name is carried over unchanged from the nested enums, so none of #2324's naming work is lost — 1074 members,
AdditionalTypesdeleted.The fold in
BattleStatsProviderstops being branches:108 lines of
switch/else ifbecome 68 table rows — one per effect, and a new effect is a row rather than a branch in the right arm of the right switch.HitQueue,DeathBCardHandlerandCaptureServiceconvert the same way;CaptureService's predicate goes from two casts tob.Effect() == BCardEffect.CaptureCaptureAnimal.The alignment test
documentation/dat/BCard.dat.mdrecords whatBCard.datdeclares — 1283 effects with the client sentence for each — sitting next to the five parser docs already in that folder.BCardVocabularyTeststhen checksBCardEffectagainst it exactly the wayLogLanguageTestschecks language keys against the resources:EveryEffectIsInTheVocabularyEveryNamedRowMatchesItsEffectEveryDeclaredEffectIsNamedOPTIONAL-TEST, likeCheckEveryLanguageValueSetThe third one is opt-in for the same reason the translation one is: the vocabulary isn't finished. It fails by design and prints the work left, with the client's own words:
What it turns up
All pre-existing, none of it changed here:
BCard.daton record — every member of types 130 and 131. The parser folder's file stops at VNUM 129 (an older copy on disk stops at 115), so either Name the 19 BCard types nothing could refer to #2324's author had a newer client than the one we parse, or those are invented. Worth deciding before anything reads them.Type61*), where before nothing could name it.Testing
BattleStatsProvider's numbers and pass unchanged, which is what says the fold still folds the same way.Deliberately not here
RegisterAssemblyTypesscan.BCard.datin the parser so the doc regenerates itself; today I generated it once from the parser folder.