I'm working with BahamutDragon over at https://github.com/BahamutDragon/pcgen/issues/33 to fix some issues with his "Races of the Dragon" definitions for PCGen. The issue we are having right now is that, for example, the Dragonblood Sorcerer set of substitution levels declares that the sorcerer loses the professions and crafting skills as class skills, and gains UMD. As far as we can tell, we are unable to encode this with the current code. This is how we expected it might work:
However, the CSKILL portions seem to be ignored. I see no errors/warnings about it in the output (though there is quite a bit of output, so I might be missing something).
Before I dive into the code too deep, I want to make sure that we aren't missing something, or, if we are, that it might be a quick fix for one of you.
P.S.: Thanks for the great program, and all your hard work!
I'll echo what James said, and note that there are two aspects of things to be discussed... one is how it should work, the other is how we bridge from what we have today. One of the main "hitches" we have is that the entire skill cost analysis that is done in the core today is PCClass-based. Since this Substitution Level makes it effectively by-level (PCClassLevel based - the level to us is a separate object), that infrastructure change is one of the items for us to address.
The other is related to how one defines the skill costs to be "local" to the Class Level. We already have some issues with determining the appropriate skill cost, and have an active proposal for how to fix those issues. So reading is probably a good idea [especially the NEWTAG- entries that it encompasses]. I will note, however, that given enhancements and plans since was discussed, there may be a better way to do it... so read for the context rather than precisely the answer provided.
So here is my naive, pre-"code dive" plan (basically, how I would implement it at a high level).
(I will be using Dragonblood Sorcerer for my examples... if I'm going down too specific of a path because this is the example I have in my head, let me know)
First, when levels are added, any "substitution levels" selected would be flagged as such, and displayed as such (right now, when a Dragonblood Sorcerer level is picked, it still shows up as a Sorcerer level).
Next, on the "Skills" tab, there are 2 directions that can be gone: one way makes things easier for the developer, and makes the user be very deliberate about what they are doing, the other makes the code attempt to "do the right thing" as well as possible. In the first case, the user would have to select each level (potentially in order), and would only be able to use the skill points (and class skill 'list') associated with that level (potentially until they are all used up). This is the safest, and probably "easiest" method to program. The second way would basically use the first skill point available in the list where the current skill is in the "class skill list". For example, say we were entering a level 4 Spellscale Sorcerer, who had taken a regular sorcerer level for 1, and the dragonblood sorcerer level at 4. They switch to the skills page, and at the bottom show 4 levels, 3 sorcerer, 1 Db sorcerer. Say 16, 4, 4, and 4 for skill points. They want to put points into UMD. UMD is only a class skill for their 4th level, so for the first 4 points they put into UMD, it uses the points from their 4th level. However, they want to put more points in, so it then starts taking points from level 1, where points are only worth .5 for UMD.
The second method sounds nice from a user's standpoint, and before I typed it out, I thought it might work ok, but I've realized there are some major issues with it. Because the user isn't being deliberate with their selection, points could be taken from a level that causes later point allocations to cost more than they should, if the earlier points were taken from a different level (I can give an example if anyone doesn't see how this could happen, but I really think that this method is a no-go). I'm leaving this here for discussion sake, and just in case someone else comes up with the same idea.
So that's the idea from the user's perspective, the only part left to discuss at this point is LST file changes. We need a way to make (at least) skills from a substitution level different from the "super" class, to steal a term from programming. In fact, my idea goes right along with the programming idea: By default the substitution level "extends" the level from the base class, and can have modifiers to change it in the necessary ways. Specifically for CSKILLs, I suggest:
for adding skills to the subst. level, and
to remove a skill. The extended version using | to specify multiple would of course work, and just specifying ".CLEAR" would remove all CSKILLS from the level. Similar constructs could be used for other things (I'm thinking bonus feats for example).
As I said, I haven't really looked at much of the code yet, so I'm not sure how easily this can be done, or what underlying flaws it has. Let me know any glaring mistakes, and I will start looking at the code to see how I would go about actually implementing these changes.
On applying skill points, you are correct that it is a rather nasty optimization problem
For the rest of the discussion, I think it would be better to have the discussion on our developers list rather than in this tracker. That way, as I explain things, the rest of the team that is not familiar with those items will also benefit...
Ok, do you want me to repost my plan on that list?
I've answered part of it (the identification part) and provided some framework background for the rest that may cause a bit of rethink before you post