瀏覽代碼

Feed the four activity-acquired lore books their acquisition counter

Stolen Intelligence, A Man with No Name, Unveiling and Revelation are not
collected from the world. They are handed out by a counter -- Zavala
rank-up packages, Gambit Prime bounties, one page a week for visiting Eris
Morn, and the weekly Lost Sector bounty four times over. Their node value
slot is that counter, so the category gates on it and the number it shows
is entries obtained, which for these four is the same quantity as activity
completions. It is not a claim count and was never meant to be.

That is why nothing else ever revealed them. The whole account value bank
was written non-zero, the flag bank swept below the record range, the
profile and character banks with it, and the family5 override path reaches
the same index by raw slot and outranks the bank. There was no separate
gate to find.

It also explains Revelation, which completes every chapter at 1 like the
books that work and yet behaved like the cumulative ones. It is neither --
it is activity-gated, a third case, and grouping it by chapter values was
always going to mislead.

Ecdysis was a different fault entirely: the claim store rewrites
record_claimable.bin as claimable AND NOT claimed on every claim, so a
chapter that is claimed leaves the set for good. Losing its first chapter
dropped the collected count to eight and hid the ninth, which looked like a
missing last chapter and was a missing first one.
Millie 2 周之前
父節點
當前提交
c5b1709ac1

+ 1 - 1
Sunrise/src/state/build_data/nodes/node_catalog.cpp

@@ -162,7 +162,7 @@ std::size_t apply_category_gates(std::span<std::int32_t> objectiveValues, bool r
             }
         }
         if (objectiveValues[node.valueIndex] == 0) {
-            objectiveValues[node.valueIndex] = sameAsBar ? -1 : 1;
+            objectiveValues[node.valueIndex] = -1;
             ++set;
         }
     }

+ 72 - 1
Sunrise/src/state/record_claims/record_claims.cpp

@@ -585,6 +585,12 @@ std::size_t apply_node_progress(std::span<std::int32_t> objectiveValues) noexcep
             // entirely while the count keyed on it.
             std::int32_t chapters = 0;
             std::int32_t collected = 0;
+            // A cumulative book's chapter n completes at value n rather than 1, and every one of
+            // them compares against this node's counter, so it must carry the real total or the
+            // chapters stay hidden. A book whose chapters all complete at 1 needs nothing here --
+            // Dust reads 0 with all nine collected and every chapter still claimable -- so those
+            // keep the sentinel and their bar stays honest.
+            bool cumulative = false;
             build_data::records::Definition parent{};
             bool haveParent = false;
             for (std::size_t child = 0; child < node.childCount; ++child) {
@@ -614,6 +620,22 @@ std::size_t apply_node_progress(std::span<std::int32_t> objectiveValues) noexcep
                     || claimable_locked(record.completionFlagIndex)) {
                     ++collected;
                 }
+                {
+                    const auto entry = std::lower_bound(
+                        objective_slot_table::kRecords.begin(),
+                        objective_slot_table::kRecords.end(), record.completionFlagIndex,
+                        [](const objective_slot_table::RecordEntry& row,
+                           std::uint16_t flag) noexcept { return row.flagIndex < flag; });
+                    if (entry != objective_slot_table::kRecords.end()
+                        && entry->flagIndex == record.completionFlagIndex
+                        && entry->objectiveCount != 0) {
+                        const std::size_t at = entry->firstObjective;
+                        if (at < objective_slot_table::kObjectives.size()
+                            && objective_slot_table::kObjectives[at].completionValue > 1) {
+                            cumulative = true;
+                        }
+                    }
+                }
             }
 
             // The bar reads the value index the parent record's own expression names, read out of
@@ -657,7 +679,56 @@ std::size_t apply_node_progress(std::span<std::int32_t> objectiveValues) noexcep
                 // locked, which is what claiming-only produced. It is only reached when the slot
                 // is not also the book's bar: the guard above skips it when they coincide, and for
                 // those ten the slot is the bar and has to keep counting claims.
-                state->values[node.valueIndex] = chapters;
+                // This slot is the book's collected counter and it gates the chapters: chapter
+                // n is only offered once it reads n, so -1 hides every chapter and 1 offers only
+                // the first. It carries the collected total, and -1 only when nothing has been
+                // collected -- which still satisfies the category's not-zero gate, so the book
+                // opens with a blank bar rather than a false count.
+                // A cumulative book needs its collected total somewhere its chapters can read.
+                // Where the node's own slot is also the bar, putting it there would show collected
+                // as a claim count -- which is wrong, the bar counts claims. Those books have a
+                // second slot and it takes the counter instead, leaving the bar alone.
+                const bool ownSlotIsBar =
+                    parentSlot == static_cast<std::int32_t>(node.valueIndex);
+                std::uint16_t counterSlot = node.valueIndex;
+                if (ownSlotIsBar
+                    && node.parentValueIndex != build_data::nodes::kUnavailableValueIndex) {
+                    counterSlot = node.parentValueIndex;
+                }
+                // Four books are not collected from the world at all -- they are handed out by
+                // an activity or vendor counter, one entry at a time:
+                //   Stolen Intelligence  Zavala rank-up packages
+                //   A Man with No Name   Gambit Prime bounties
+                //   Unveiling            one page a week for visiting Eris Morn
+                //   Revelation           the weekly Lost Sector bounty, four times
+                // Their node value slot is that counter, not a claim count, which is why the
+                // category gates on it and why no other slot in any bank ever revealed them --
+                // the whole account value bank, the flag bank below the record range, the profile
+                // and character banks and the family5 override path were all swept looking for a
+                // separate gate that does not exist. Entries obtained and activity completions
+                // are the same number for these four, so the collected total belongs here and the
+                // parent triumph showing it is faithful rather than a compromise. Revelation sits
+                // in this group despite completing every chapter at 1: it is activity-gated, not
+                // cumulative, which is why it never behaved like the books it otherwise matches.
+                constexpr std::array<std::uint16_t, 4> kActivityAcquired{
+                    823U,  // Stolen Intelligence
+                    839U,  // Unveiling
+                    850U,  // A Man with No Name
+                    853U,  // Revelation
+                };
+                for (const std::uint16_t acquired : kActivityAcquired) {
+                    if (acquired == node.definitionIndex && collected > 0
+                        && static_cast<std::size_t>(node.valueIndex) < state->values.size()) {
+                        state->values[node.valueIndex] = collected;
+                    }
+                }
+                                if (cumulative && collected > 0
+                    && static_cast<std::int32_t>(counterSlot)
+                           < objective_slot_table::kRecordObjectiveRangeStart
+                    && static_cast<std::size_t>(counterSlot) < state->values.size()) {
+                    state->values[counterSlot] = collected;
+                }
+
                 ++state->written;
             }
             // Eight books name no value at field 136 and so have no table entry, but their parent