Skip to content

Quest: Remove CharacterLevel and Reputation from PrerequisiteType enum — game concepts, not Bannou primitives #719

Description

@DonLoquacious

Quest: Remove game-concept prerequisite types from PrerequisiteType enum

Source: STATUS.md § Potential Extensions resolution (2026-03-25), Quest DC#2

Summary

PrerequisiteType enum contains CharacterLevel and Reputation — game implementation concepts baked into a Bannou schema enum. These violate the same composability principle that the FAQ "Why Are There No Skill/Magic/Combat Plugins?" articulates: every game defines "level" and "reputation" differently. These should not be first-class Bannou types.

Current State

Schema (schemas/quest-api.yaml):

PrerequisiteType:
  type: string
  enum: [QuestCompleted, CharacterLevel, Reputation, ItemOwned, CurrencyAmount]

With dedicated fields on PrerequisiteDefinition:

  • minLevel — for CHARACTER_LEVEL type
  • factionCode — for REPUTATION type
  • minReputation — for REPUTATION type

Code (QuestService.Helpers.cs):

  • case PrerequisiteType.CharacterLevel: routes to CheckDynamicPrerequisiteAsync("character_level", ...)
  • case PrerequisiteType.Reputation: routes to CheckDynamicPrerequisiteAsync("reputation", ...)
  • Both silently pass when no provider is registered (graceful degradation = no gate)

Code behavior: These enum values ALREADY route through the dynamic provider path — they're not built-in L2 checks. The enum values are cosmetic; the code treats them as dynamic.

Required Changes

Schema (schemas/quest-api.yaml)

  1. Remove CharacterLevel and Reputation from PrerequisiteType enum
  2. Remove dedicated fields (minLevel, factionCode, minReputation) from PrerequisiteDefinition
  3. Add generic dynamic prerequisite fields to PrerequisiteDefinition:
    • providerName (string, nullable) — identifies which IPrerequisiteProviderFactory to route to
    • code (string, nullable) — the prerequisite code passed to the provider's CheckAsync
    • minValue (integer, nullable) — numeric threshold for the provider to check against
  4. Alternatively: Make PrerequisiteType a Category B opaque string (game-configurable codes) instead of a closed enum, with built-in handlers for known strings ("quest_completed", "currency_amount", "item_owned") and dynamic routing for everything else

Code (QuestService.Helpers.cs)

  1. Remove case PrerequisiteType.CharacterLevel: and case PrerequisiteType.Reputation: — the default: case already routes to CheckDynamicPrerequisiteAsync
  2. Update CheckDynamicPrerequisiteAsync to use the generic fields (providerName, code, minValue)

Internal model (QuestModels.cs)

  1. Remove MinLevel, FactionCode, MinReputation from PrerequisiteDefinitionModel
  2. Add generic fields matching schema changes

Documentation

  1. docs/plugins/QUEST.md — Already updated (DC#2 rewritten, type classification table updated)
  2. docs/maps/QUEST.md — Already updated (dependency table note added)
  3. docs/reference/SERVICE-HIERARCHY.md⚠️ FROZEN. Line 590 incorrectly lists character_level as a built-in type calling ICharacterClient. Needs correction: either remove the row or reclassify as dynamic/game-specific. Requires explicit user approval to edit.
  4. bannou-service/Providers/IPrerequisiteProviderFactory.cs — XML docs incorrectly list character_level as built-in. Correct to reflect dynamic-only routing.

Regeneration

  1. After schema changes: cd scripts && ./generate-models.sh quest + cd scripts && ./generate-service.sh quest

Why This Matters

The silent no-op is a functional gap today — quests with CharacterLevel or Reputation prerequisites have zero enforcement. But the fix is NOT adding a specific provider for these game concepts. The fix is removing the game concepts from the enum and letting games define their own prerequisite types through the dynamic provider path — the infrastructure that already exists and works correctly (see AchievementPrerequisiteProviderFactory as the reference implementation).

Related

  • STATUS.md resolved this as "REJECTED — game concepts, not Bannou primitives"
  • FAQ: WHY-ARE-THERE-NO-SKILL-MAGIC-OR-COMBAT-PLUGINS correctly frames skill/magic prerequisites as thin L5 adapters
  • DIVINITY-GENERATION-ARCHITECTURE.md § "Bag of Kills" shows how capabilities flow through wallets → Seed growth, not through baked-in prerequisite types

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions