# Retail skill-training confirmation Date: 2026-07-13 ## Scope This note covers the confirmation shown when an untrained skill is promoted to trained by spending skill credits. It does **not** apply when experience is added to an already trained or specialized skill; those raises are sent immediately. ## Named retail sources - `gmSkillUI::TrainSkillDialogCallback @ 0x0049C210` - `gmSkillUI::TrainSkill @ 0x0049C5F0` - `gmSkillUI::RaiseSelection @ 0x0049C8C0` - `DialogFactory::MakeCallbackDialogInCurrentUI @ 0x00478430` - literal `data_7A7864`: `Are you sure you want to spend %d credits to train %s?` The dialog property keys are shared with the existing DialogFactory port: ```text 0x8E dialog type (1 = ConfirmationDialog) 0x92 confirmation result written by ConfirmationDialog 0xC5 message StringInfo 0x10000040 selected skill id 0x10000041 skill-credit cost ``` ## Pseudocode ```text gmSkillUI.TrainSkill(playerQualities): if selectedSkill == 0: return false skillName = SkillSystem.InqSkillName(selectedSkill) creditCost = GetCostToRaise(playerQualities) message = format( "Are you sure you want to spend %d credits to train %s?", creditCost, skillName) data = PropertyCollection() data[0x8E] = 1 // ConfirmationDialog data[0xC5] = message data[0x10000040] = selectedSkill data[0x10000041] = creditCost DialogFactory.MakeCallbackDialogInCurrentUI( data, gmSkillUI.TrainSkillDialogCallback) return true gmSkillUI.TrainSkillDialogCallback(data): if data.bool(0x92) is not true: return skillId = data.uint(0x10000040) creditCost = data.uint(0x10000041) if skillId != 0 and creditCost != 0: CM_Train.Event_TrainSkillAdvancementClass(skillId, creditCost) ``` `gmSkillUI::RaiseSelection` branches on advancement class. Untrained skills enter `TrainSkill`; trained/specialized skills call `CM_Train::Event_TrainSkill` directly with the XP cost. Therefore a confirmation on every skill XP raise would be a retail divergence. ## Cross-reference - ACE `GameActionTrainSkill.Handle` reads exactly two fields, skill id and credits spent, then calls `HandleActionTrainSkill`. - Chorizite's generated native client bindings expose `CM_Train::Event_TrainSkillAdvancementClass(UInt32 skill, UInt32 credits)` and separately expose `CM_Train::Event_TrainSkill(UInt32 skill, UInt32 xp)`. These corroborate the callback's two stored properties and the distinction between training a skill and adding XP to a trained skill. The named retail client remains the behavioral oracle for when the dialog appears.