Baz has the input window half so I’ll take the other thing you mentioned. Skills firing that the actor hasn’t learned yet is a separate problem. The engine does almost nothing to stop it on its own.
There’s no engine level check for whether an actor has learned a skill when the action runs. The only place that check lives in a stock project is the skill list window. That window builds itself from the actor skill list.
Window_SkillList.prototype.makeItemList = function() {
if (this._actor) {
this._data = this._actor.skills().filter(item => this.includes(item));
}
...
};
Once a skill id has reached a Game_Action nothing revisits the question. canUse only asks about weapon type and cost and whether the skill is sealed.
Game_BattlerBase.prototype.meetsSkillConditions = function(skill) {
return (
this.meetsUsableItemConditions(skill) &&
this.isSkillWtypeOk(skill) &&
this.canPaySkillCost(skill) &&
!this.isSkillSealed(skill.id) &&
!this.isSkillTypeSealed(skill.stypeId)
);
};
There’s no learned test anywhere in there. Any plugin that turns an input sequence straight into a skill id has to make that check itself. If the author never did then every combo in the table is castable from turn one.
There’s a second layer to it if the plugin finishes the combo through forceAction. forceAction builds its action with a forcing flag set. isValid short circuits on that flag before it ever reaches canUse. Grep your own rpg_objects.js for isValid and you will see the shape.
Game_Action.prototype.isValid = function() {
return (this._forcing && this.item()) || this.subject().canUse(this.item());
};
Fair warning that the line above is the MZ wording because that is the copy I can quote exactly. The left hand term is written slightly differently in MV. The structure is the same in both and the structure is the part that matters. A forced action satisfies the left side and the canUse call on the right never runs. That means the cost check and the sealed check get skipped along with everything else.
The patch is small either way. Put something like this in a small plugin of your own loaded below the combo plugin.
Game_Actor.prototype.canUseComboSkill = function(skillId) {
const skill = $dataSkills[skillId];
return !!skill && this.hasSkill(skillId) && this.canUse(skill);
};
Then call it before the combo is accepted and swallow the input when it comes back false. I used hasSkill rather than isLearnedSkill on purpose. isLearnedSkill only counts skills the actor learned by level or by item. hasSkill also counts skills granted by equipment and traits. That’s usually what you want for a combo list.
Here’s one quick way to tell which of the two you’re actually hitting. Give a test actor a combo whose skill costs more MP than they have and run it. If it fires anyway you’re in the forceAction case. If it refuses on cost but still lets through skills nobody learned then it’s only the missing learned check. That guard above is the whole fix.