-
Notifications
You must be signed in to change notification settings - Fork 232
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Character Advancement #1353
Comments
Originally in GitLab by @Fyorl PrototypesSome example advancement primitives that were prototyped are included below: 1. Feature grant // Cunning Action
{
class: "Rogue.uuid",
level: 2,
feature: "CunningAction.uuid"
}
// Draconic Resilience
{
class: "DraconicBloodline.uuid",
level: 1,
feature: "DraconicResilience.uuid"
} 2. Optional feature grant // Steady Aim
{
class: "Rogue.uuid",
level: 3,
feature: "SteadyAim.uuid",
optional: true
} 3. Optional feature replacement // Nature's Veil
{
class: "Ranger.uuid",
level: 10,
feature: "NaturesVeil.uuid",
replaces: "HideInPlainSight.uuid",
optional: true
}
// Primal Companion
{
class: "BeastMaster.uuid",
level: 3,
feature: "PrimalCompanion.uuid",
replaces: "RangersCompanion.uuid",
optional: true
} 4. Feature upgrade // Channel Divinity
{
class: "Cleric.uuid",
level: 6,
feature: "ChannelDivinity.uuid",
upgrades: [{
key: "data.uses.max",
value: 2
}]
}
{
class: "Cleric.uuid",
level: 18,
feature: "ChannelDivinity.uuid",
upgrades: [{
key: "data.uses.max",
value: 3
}]
}
// Psionic Power
{
class: "PsiWarrior.uuid",
level: 5,
feature: "PsionicPower.uuid",
upgrades: [{
key: "data.formula",
value: "1d8"
}]
} 5. Feature pool // Fighting Style
{
class: "Fighter.uuid",
level: 1,
feature: "FightingStyle.uuid",
choices: 1,
pool: ["Archery.uuid", "Defense.uuid", ...] // Possibly discoverable
}
// Arcane Shot
{
class: "ArcaneArcher.uuid",
level: 3,
feature: "ArcaneShot.uuid",
choices: 2,
pool: ["BanishingArrow.uuid", "EnfeeblingArrow.uuid", ...]
}
// Eldritch Invocations
{
class: "Warlock.uuid",
level: 2,
feature: "EldritchInvocations.uuid",
choices: 2,
pool: ["DevilsSight.uuid", "AgonizingBlast.uuid", ...]
} 6. Feature pool addition // Fighting Style
{
class: "Champion.uuid",
level: 10,
feature: "FightingStyle.uuid",
additions: 1,
pool: [...] // Same options as before
}
// Eldritch Invocations
{
class: "Warlock.uuid",
level: 5,
feature: "EldritchInvocations.uuid",
additions: 1,
// Same options as before plus additional options that only become available at this level
pool: [..., "ImprovedPactWeapon.uuid", "CloakOfFlies.uuid"]
}
// Channel Divinity
{
class: "OathOfVengeance.uuid",
level: 3,
feature: "ChannelDivinity.uuid",
additions: 2,
// The number of additions is equal to the size of the pool to indicate that we get all of them
pool: ["AbjureEnemy.uuid", "VowOfEmnity.uuid"]
} 7. Feature pool replacement // Combat Superiority
{
class: "BattleMaster.uuid",
levels: [4, 6, 8, 12, 14, 16, 19], // This could be flattened instead
feature: "CombatSuperiority.uuid",
replacements: 1,
// Replacing a manoeuvre is an optional rule from Tasha's
optional: true
}
// Eldritch Invocations
{
class: "Warlock.uuid",
levels: [3, 4, 5, 6, 7, 8, 9, ...],
feature: "EldritchInvocations.uuid",
replacements: 1
} As was rightly pointed out, where we refer to 'feature' above, could just as easily apply to an item of any type not just @akrigline Had some additional refinement: {
characterLevel: 1,
classLevel: 1,
type: 'item',
class: "Champion.uuid",
advancementData: {
item: "CombatSuperiority.uuid"
}
} The distinction between character level and class level is probably important, and we likely need both. Additionally, where a class or subclass is referenced above as a |
Originally in GitLab by @Fyorl We are missing primitives for most proficiency grants, though some of the work has been done already as part of backgrounds that we can hopefully reuse in some way:
|
Originally in GitLab by @akrigline Some considerations for the base
|
Originally in GitLab by @akrigline Our intial advancment work will focus on the existing mechanisms that allow class features to be 'granted' on levelup. Proposed data format: {
"advancement": {
"level": 1, // assuming we derive that this is driven by class level vs character level
"type": "itemGrant",
"advancementData": {
"itemUuid": "Some.Item.uuid",
}
}
}
|
Originally in GitLab by @akrigline Thinking about the idea of class level and character level distinction, this is only really applicable to Class advancement and only for proficiency grants a character gets from secondary classes. I'm wondering if we should simply derive whether the advancement applies to 'parent class level' or 'parent actor level'. For multiclassing cases a simple checkbox might remove the need for this distinction, "Only for Primary Class". |
Originally in GitLab by @arbron I think there should be one section for type specific configuration and a second section for user selection: {
"level": 1,
"type": "itemChoice",
"configuration": {
"options": {
"first": "Some.Item.UUID",
"second": "Other.Item.UUID"
}
},
"value": {
"selected": "first"
}
} This will make it easy to isolate the options that a GM configures versus what the player has selected. |
Originally in GitLab by @aaclayton I do think we still need to discuss whether we store the chosen values from advancement decisions on the individual items which provided them or on the base actor. There are merits of each. I agree with Jeff about storing an inner object of type-specific configuration, although I think that's what @akrigline was going for with |
Originally in GitLab by @arbron Some thoughts on the various types of advancements we might like to eventually offer: Item Grants
Item Choices
Hit Points
Traits
Ability Score Improvement
Scale Values
Expertise
|
Originally in GitLab by @arbron All advancement items that are added to classes should have an extra option to determine whether they are available always, only on the primary class, or only on multiclassing. This should make it easy to set up saving throw and other proficiencies that behave differently depending on multiclassing. |
Originally in GitLab by @akrigline In cases where there are multiple items granted (or multiple expertises/ASI/Traits, etc), is each individual one an object within the array of advancements or do we pile them up?
vs
I think having each individual advancement 'point' in its own advancement entry is cleaner, but the UX of editing all of them individually could be a pain. |
Originally in GitLab by @akrigline Yeah, |
Originally in GitLab by @akrigline Something to note about all of these advancement enabled items: There should be no distinction between "GM View" and "Player View" for the item editing as both will see it. |
Originally in GitLab by @arbron The nice thing about being able to group is it would allows us to group features that are granted together. Like if someone wanted to use this system for automatically granting spells to clerics when they gain a new spell level, their advancement might have one entry for "Features" and another for "Spells" creating a nice, clear grouping. |
Originally in GitLab by @Fyorl I think there's merit, from a UX perspective, of clearly separating the editing of the configuration of choices, vs. the editing of those choices themselves. In this case the 'GM View' is where we edit the configuration, and the 'Player View' is where we see that configuration laid out. It's not planned for stage 1 of this work, but I imagine in future that the player view will be where we allow for earlier advancement choices that were made to be modified. For an existing example of this, we can look at class skills (and a lesser extent, the saving throws): When I, as a player, open that interface up, I can see that I am able to edit the eligible class skills, which has no effect other than to configure the list I am presented with when I click to edit the chosen class skills. As accurate as the labelling is, I think this is a very weird user experience. If this were P&P, I would look up my class in the Player's Handbook, and it would tell me to pick 2 skills from a list. I can't edit that list because I can't edit the Player's Handbook, and I don't think a player should be presented with that ability to edit it either. When this functionality was initially presented, there was some similar feedback: https://gitlab.com/foundrynet/dnd5e/-/merge_requests/318#note_618811658 and it feels like allowing players to edit the advancement configuration of their class once it's on their sheet is a larger version of the above, because players are now able to edit things that, from their perspective, should be set in stone. The easiest solution is to only allow GMs to edit advancement data, but we should also consider whether advancement data should be editable on owned items at all. If we don't allow editing on owned items, then we don't need to restrict editing to GMs, we can restrict it to those with owner permission of the (unowned) item. But then the only way to edit advancement for an existing character would be to edit the unowned class item, delete the owned one from the sheet, then drop a fresh copy of the original class item to the sheet. That's not viable if we store advancement choices on the item, as those choices would be lost, it would require us to store these choices on the actor instead. If we do allow for editing the owned item, then we can store choices on the item again, but we have to restrict who can edit the advancement configuration to GMs only, in order to avoid the UX issues above (that I claim are a problem). |
Originally in GitLab by @aaclayton I think I agree with Kim's proposal that we would have: Unowned Items: allow editing of the advancement configuration, but does not allow making advancement choices I think this is the cleanest way to split it without needing to develop separate or specialized logic. |
Originally in GitLab by @Fyorl I've tried to sum up the discussion and decisions so far. Please let me know if I've missed anything.
Some open questions:
|
Originally in GitLab by @Fyorl Seems reasonable to allow for multiple item grants to be grouped together since we want to allow for choices from several options, and the former can be written in terms of the latter. For example: Picking from several options: {
type: "item",
choices: 2,
items: [A, B, C]
} Gaining all options: {
type: "item",
choices: 2,
items: [A, B] // The number of choices equals the length of the options, so you gain them all.
} And you can then infer that you get them all by omitting the {
type: "item",
items: [A, B]
} |
Originally in GitLab by @arbron One thing to consider is things that allow you to select from a single pool at multiple different levels. We should be able to specify choices-per-level.
|
Originally in GitLab by @arbron I think the unowned/owned distinction is a good place to start, but later we can maybe add an edit button that allows for switching into an edit mode to configure owned items (similar to how TidySheet has a lock button to prevent certain edits). |
Originally in GitLab by @akrigline I do not agree that owned items should have configuration disabled for all users. As far as I know there is no technical limitation to doing so and preventing it will make the UX worse for GMs ("Oh wait that's supposed to be a level 5 feature let me fix it really quick") and Players who know what they're doing ("My GM has allowed me to add level 4 optional features to my class"). Disabling the configuration for players once it's an owned item... I can see both ways but personally I would be annoyed if I had to pester my GM to fix something wrong. If this were a module, it would probably have a setting "Restrict editing to Trusted Players". Separating the configuration UI from the election UI should be sufficient. |
Originally in GitLab by @akrigline Consider that most of the Elections a player will make will happen during the level up prompts, diving into the item itself is something that I assume will be rarer once advancement is fully fleshed out. If it is necessary, something has probably gone wrong and it would be unfortunate to put artificial blockers on fixing such a thing. |
Originally in GitLab by @Fyorl I've opted to create only one issue for part (4) here which focuses on item grants. I had less of a clear picture about the other types and didn't want to commit to them yet, and I believe item grants comprise the vast bulk of character advancement, while the others are pretty much entirely the purview of level 1. Some of them are also partially covered by the Backgrounds work and it wasn't immediately obvious to me yet how we want to separate that out. |
Originally in GitLab by @Fyorl As long as the UI for editing the advancement configuration is not in the same place or mixed-in with the UI for viewing the advancement or editing advancement choices (when we eventually implement that), then it's probably fine. An edit toggle would probably also be fine so long as users aren't confused about what they're editing (i.e. they're not editing their choices, they're editing the advancement configuration itself). |
Originally in GitLab by @akrigline I'm thinking each level should be its own advancement object, even in cases where the pool of items is the same? Usually the pool expands on itself i.e. invocations. So rough example warlock advancement to me should have:
|
Originally in GitLab by @akrigline We will want to have some data sanitation guards on Embedded Item creation if we store choices for the advancement on the item that removes those choices when the item is added to an actor. |
Originally in GitLab by @clay.sweetser Just curious - will this system support the addition of custom advancement types by modules? |
Originally in GitLab by @arbron Yes, all a module will have to do is create a new subclass of the |
Originally in GitLab by @playest Just a side note, you can use
which render as: {
"some": "json" // with comments
} instead of: {
"some": "json" // with comments
} |
Originally in GitLab by @playest I'm really glad you are thinking about all of this. I have given it some thoughts and I found this epic much later so I realize that I may have gotten too far with my ideas :/ Feel free to ignore everything, but who knows, may it will help you. At least, it will show you that people care :) Anyway! Here they are! AdvancementFor the purpose of this I will use the term "document" (which is a term internally used by Foundry) to designate feature, class, subclass, feat, races, subraces, background, items, anything that can be added to the character sheet basically. If you have a better term for this feel free to talk about it and I may edit this in accordance. I will use the term "advancement" to designate the character creation process or the leveling up process which should be the same in my opinion. If you have a better term for this feel free to talk about it and I may edit this in accordance. In general, we want to make it easier for the player to build a valid character without forbidding any combination of documents. If they want to put something invalid on their sheet (like 2 races) they should be able to. I personally think that all of theses documents should have some kind of advancement tab. Why not have an item that gives you proficiency once you reached a certain level for example? I'll admit it's a little weird but it may open the door to amazing modules and automation. Efforts should go into 3 directions :
DataThe links between the documents must be stored somewhere. I see two choices here:
I wont go into the "Advancement Path" thing here because I think it's unnecessary but we may want to explore this possibility in the future. A character is defined by:
I think that everything in this list is or has a feature:
A advancement document can be either inside:
Which means we theoretically have the following tree structure:
interface CharacterSheet {
classes: Class[],
feats: Feature[],
boons: Feature[],
}
interface Class {
subclasses: Subclasses[],
features: Feature[],
}
interface Background {
features: Feature[],
}
interface Race {
subraces: Subrace[],
features: Feature[],
}
interface Subrace {
features: Feature[],
}
interface Subclasses {
features: Feature[],
}
interface Feature {
// Something
} We could enforce all of those types a create as many documents types as there is lines elements in this tree but in my opinion it would be better to treat everything the same way: as a super-feature (this term is obviously subject to change). A super-feature differs from a feature in that it may be "connected" to another super-feature and can be activated by what I call an advancement trigger. A super-feature is represented as a list of choices that can be in 3 states: dormant, waiting, processed.
A choice is a tuple of two elements:
A choice has 2 state : not-made, made and not-interested.
Here is are TS types that could be used to represent that: interface CharacterSheet {
superFeatures: SuperFeature[],
/** What is contained in the "Features" tab in the current character sheet */
features: Feature[],
}
interface SuperFeature {
name: string,
level?: number,
state: SuperFeatureState,
choiceRule: ChoiceRule,
choices: Choice[],
}
type Choice = SuperFeature | AdvancementAction;
type SuperFeatureState = "dormant" | "waiting" | "processed";
type ChoiceRule = ChooseAll | ChooseSome | ChooseGroups | ChooseSomeWithMandatory;
interface ChooseAll {
chooseAll: true,
}
interface ChooseSome {
/** How many choice can be chosen in the `choices array`. Means something like "Choose one in..." or "Choose two in..." */
howMany: number,
}
interface ChooseSomeWithMandatory {
mandatory: number[],
howMany: number,
}
interface ChooseGroups {
/** The numbers specify the indices in the `choices` array in the parent SuperFeature. Could be something like [ [1, 2], [1, 3], [2, 3] ] */
groups: number[][],
}
type AdvancementAction = (GroupedAdvancementAction | BasicAdvancementAction) & { level?: number };
type BasicAdvancementAction = GainProficiency | GainFeature | GainLanguage | GainEquipement | GainCurrency | GainAbilityPoints | GainBaseSpeed | GainHitDice | GainMaxHp;
interface GroupedAdvancementAction {
name: string,
advancementActions: BasicAdvancementAction[]
};
interface GainProficiency {
skill: string,
}
interface GainFeature {
feature: string,
}
interface GainLanguage {
language: string,
}
interface GainEquipement {
itemName: string,
}
interface GainCurrency {
gp: number,
}
interface GainHitDice {
hitDiceGain: number,
type: "d4" | "d6" | "d8" | "d10" | "d12"
}
interface GainMaxHp {
maxHpGain: number,
}
interface GainBaseSpeed {
type: "walk" | "fly" | "burrow" | "climb" | "swim",
distance: number,
}
interface GainAbilityPoints {
attribute: Attributes,
bonus: number,
}
interface GainSavingThrow {
savingThrow: Attributes,
}
type Attributes = "strength" | "dexterity" | "constitution" | "intelligence" | "wisdom" | "charisma";
/** Some basic feature that already exists in the game */
interface Feature {
// We put only those 2 fields for this example
name: string,
type: FeatureType,
}
type FeatureType = "feature" | "race" | "subrace" | "class" | "subclass" | "feat" | "boon"; And how a sample could look like (see at the end of this file): let myCleric: CharacterSheet = {
features: [], // empty, fill this array is not the point of this example, this will be done by the advancement workflow
superFeatures: [
{
name: "Choose Background",
state: "dormant",
choiceRule: { howMany: 1 },
choices: [
{
name: "Acolyte",
state: "dormant",
choiceRule: { chooseAll: true },
choices: [
{
name: "Languages",
state: "dormant",
choiceRule: { howMany: 2 },
choices: [
{ language: "common" },
{ language: "dwarvish" },
{ language: "elvish" },
{ language: "draconic" },
// I'm not gonna list all languages here...
]
},
{
name: "Skill Proficiencies",
advancementActions: [
{ skill: "insight" },
{ skill: "religion" }
]
},
{
name: "Equipement",
state: "dormant",
choiceRule: { chooseAll: true },
choices: [
{ itemName: "holy symbol" },
{
name: "Prayer book or Prayer wheel",
state: "dormant",
choiceRule: { howMany: 1 },
choices: [
{ itemName: "prayer book" },
{ itemName: "prayer wheel" },
]
},
{ itemName: "stick of incense x 5" },
{ itemName: "vestments" },
{ itemName: "common clothes" },
{ gp: 15 }
]
},
{
name: "Shelter of the Faithful",
state: "dormant",
choiceRule: { chooseAll: true },
choices: [{ feature: "Shelter of the Faithful" }]
}
]
},
{
name: "Non-SRD Background",
state: "dormant",
choiceRule: { chooseAll: true },
choices: [
{
name: "Languages",
state: "dormant",
choiceRule: { howMany: 1 },
choices: [
{ language: "common" },
{ language: "dwarvish" }
]
},
{
name: "Skill Proficiencies",
advancementActions: [
{ skill: "arcana" },
{ skill: "acrobatics" }
]
}
]
},
]
},
{
name: "Choose Race",
state: "dormant",
choiceRule: { howMany: 1 },
choices: [
{
name: "Elf",
state: "dormant",
choiceRule: { chooseAll: true },
choices: [
{
name: "Ability Score Increase",
advancementActions: [{ attribute: "dexterity", bonus: 2 }]
},
{
name: "Speed",
advancementActions: [{ type: "walk", distance: 30 }]
},
{ feature: "Keen Senses" },
{
name: "Languages",
advancementActions: [
{ language: "common" },
{ language: "elvish" }
]
}
// and other stuff
]
},
{
name: "Human",
state: "dormant",
choiceRule: { chooseAll: true },
choices: [
{
name: "Ability Score Increase",
advancementActions: [
{ attribute: "strength", bonus: 1 },
{ attribute: "dexterity", bonus: 1 },
{ attribute: "constitution", bonus: 1 },
{ attribute: "intelligence", bonus: 1 },
{ attribute: "wisdom", bonus: 1 },
{ attribute: "charisma", bonus: 1 },
]
},
{
name: "Speed",
advancementActions: [{ type: "walk", distance: 30 }]
},
{ feature: "Keen Senses" },
{
name: "Languages",
state: "dormant",
choiceRule: {
mandatory: [0], // 0 is the index of "common" in the choices array below
howMany: 2 // including the mandatory choices
},
choices: [
{ language: "common" },
{ language: "dwarvish" },
{ language: "elvish" },
{ language: "draconic" },
// I'm not gonna list all languages here...
]
}
// and other stuff
]
}
]
},
{
name: "Choose Class",
state: "dormant",
choiceRule: { howMany: 1 },
choices: [
{
name: "Fighter",
state: "dormant",
choiceRule: { chooseAll: true },
choices: [
{
name: "Hit points",
advancementActions: [{ hitDiceGain: 1, type: "d10" }, { maxHpGain: 10 }]
},
{
name: "Armors",
advancementActions: [{ skill: "all armors" }, { skill: "shields" }]
},
{
name: "Weapons",
advancementActions: [{ skill: "simple weapons" }, { skill: "martial weapons" }]
},
{
name: "Skills",
state: "dormant",
choiceRule: { howMany: 2 },
choices: [
{ skill: "acrobatics" },
{ skill: "animal handling" },
{ skill: "athletics" },
{ skill: "history" },
{ skill: "insight" },
{ skill: "intimidation" },
{ skill: "perception" },
{ skill: "survival" },
]
},
// enough with the non levelled stuff, let's try to do levelled features
{
name: "Second Wind",
level: 1,
advancementActions: [{ feature: "Second Wind" }]
},
{
name: "Fighting Style",
level: 1,
state: "dormant",
choiceRule: { howMany: 1 },
choices: [
{ feature: "Archery" },
{ feature: "Defense" },
{ feature: "Dueling" },
{ feature: "Great Weapon Fighting" },
{ feature: "Protection" },
{ feature: "Two Weapon Fighting" },
]
},
{
name: "Action Surge",
level: 2,
advancementActions: [{ feature: "Action Surge" }]
},
{
level: 3,
name: "Martial Archtype",
choiceRule: { howMany: 1 },
state: "dormant",
choices: [
{
name: "Champion",
choiceRule: { chooseAll: true },
state: "dormant",
choices: [
{ level: 3, feature: "Improved Critical" },
{ level: 7, feature: "Remarkable Athlete" },
]
},
{
name: "Non-SRD Subclass for Fighter",
advancementActions: [{ feature: "Placeholder for subclass" }]
}
]
}
]
}
]
}
]
}; EditI have not a lot to say here. WorkflowWeird CasesI try to think of weird cases when building something because I feel that if I manage to deal with those cases the normal cases will be more than correctly managed. Of course, sometime you have to give up on one of those weird cases to simplify the task but we are not here yet. So here are some weird use case that could be managed:
Advancements triggersAn advancement trigger should be able to propose to:
Other considerations
IdeasAn elegant way to deal with subclasses could be to represent them with a class document that takes its level from an other class. |
Originally in GitLab by @Fyorl Thank you for your comprehensive and thoughtful input on this. You have, unfortunately, missed the boat a little as this work is well underway but hopefully I can reassure you that many of the things you brought up were considered as part of our initial design work. I feel I should also mention that part of our design philosophy is to try to keep scope as minimal as possible to ensure we create a well thought-out, solid foundation that can be iterated on, rather than attempting to cover every possible use case with one huge, complex system. Therefore, it is unlikely everything you've mentioned will be accommodated for in the initial version, but the system will be improved upon gradually in subsequent releases. |
Originally in GitLab by @playest You're right, I think it's safe to say I missed the boat. I guess I bought Foudry too late ^^
Very good design philosophy :) Good luck! |
Originally in GitLab by @Fyorl
Too late for this piece of work, perhaps, but if you're interested in contributing to the dnd5e system, I can recommend you wait for when we have locked down scope for the next milestone and see if there's anything you'd like to get involved with there. We do try to review a handful of MRs that are off-scope each milestone but there's no guarantee we can get to any particular one. You can review our CONTRIBUTING.md for more details. |
Originally in GitLab by @playest I'm definitely interested in contributing. I'll take a look at the CONTRIBUTING.md. How can I be updated when you will have locked down the scope? Do you have a timeline? |
Originally in GitLab by @Fyorl I don't actually have a very good answer for you there. At some point after 1.6 is released we will scope out 1.7 at which point we'll create a new milestone (or modify an existing one), and then start assigning issues and epics to it. I will see if @akrigline has any better advice for you on that front. |
Originally in GitLab by @Fyorl
Introduction
I've put together a draft of the pieces of the character advancement epic, and some of the design questions that might need to be answered as part of each. If we can agree on this list then they can be split out into individual issues that can hopefully be worked on with some degree of parallelism.
Some design decisions that were agreed on already:
class
item.type
, and can be handled by its own custom handler.Pieces
1. Advancement configuration UI. We need a place on the
class
item sheet where a user can see and configure the advancement objects for that class. That might be a new tab, an additional dialog, or something else. Note that the actual rendering of each type of advancement object will be handled by a specific handler for that advancement object type.As a part of this we will need a clear way to determine whether we are in an editing context or a viewing context. This might take the form of an explicit toggle, checking for a
GM
user, or checking whether the item is owned or unowned.2. Character advancement UI. We already have a level-up prompt which should be a good place to start. It needs to support going backwards and forwards through each of the advancement objects configured for that level-up. We should consider supporting jumping to an arbitrary stage as well as a simple 'Forward' and 'Back'.
It is possible that a player gains more than one level at once, or they are starting their character at a higher level, so the prompt should support collecting all the objects available for all of the levels gained, and should present them in the correct order.
As choices are made through the advancement prompt, a working copy of the actor needs to be maintained so that further steps can react to changes accordingly. This should support a player jumping back to a previous step, changing something, and potentially invalidating some later choices.
Once a player has chosen to finalise those choices, they should be written to the sheet in a permanent fashion. We will not support undoing those changes at this stage, except for the normal methods of deleting items, etc.
As with (1), this piece does not involve actually rendering any advancement objects, it just provides a framework for them to be rendered into.
3. Advancement object API. Each type of advancement 'primitive' available to a character needs to be represented by its own discrete data schema. We should consider whether we want to wrap these in their own classes. We might have an abstract base
Advancement
class that can be implemented by subclasses representing each of the different advancement types, for example.However it is designed, we need a way to handle the following operations:
Not all of the above operations necessarily need to be part of the API, but they do need to be handled somewhere.
4. Advancement objects. Each type of advancement primitive needs to be realised and plugged into the framework above.
Further Comments
The pieces above have a number for ease of reference but don't necessarily imply an order that they need to be completed in.
I don't believe we should tackle Spellcasting as part of this work. We may integrate it later, but I don't think we should consider it for the initial design.
After having worked through this list, it looks like it could be quite useful to do the work for subclass items first (#1080), or at least try to keep them in mind throughout the process as they will likely inform the design of quite a few areas.
The text was updated successfully, but these errors were encountered: