Do you think you can separate some of your tweaks into other specific mods? For example, I'd like Produce Flame as a standalone mod! Also, how does it scale as you level?
The scaling is still default, I'm not really a mod creator i just did this one to see if i could. I also uploaded a misc. file of how the game structures its spells if you want to try it out for yourself.
I am loving the mod and I may have made a few tweaks of my own. Inspecting your files allowed me to track down what I needed to make some other 5e Spells Cantrips also be BonusActions and then I had an idea. Would you happen to know what I would need to do to the code for, say the cantrip 'Bladeward' or 'Resistance', to work as a reaction. It can't be as simple as setting the value of cost to ReactionActionCost:1, right? It has to know when it needs to be triggered. I essentially want it to react the same way the spell "Shield" would trigger. Any ideas?
Im not 100% certain with this scenario, Im still new to modding but you may be able to compare the lines of code for the spell/cantrip you want as a reaction to one that already is a reaction and see whats missing and might be able to just copy it over, not sure if this will work for all spell/cantrips though
on a another mod page, I was shown the HexDataBrowser and this neat little website shows me the internal machinations of how the coding looks like for various things like spells, passives, gear, etc. My latest obsession has been to figure out how to add additional passives to modded gear and this thing has been phenomenal.
Since my post, I have learned a a lot more. As you suggested, in theory, if I were to look up the code for the Shield spell, for example, I could copy the entire code and put it right underneath the Bladeward cantrip. Then, I simply change the name to 'Shout_Bladeward_Wizard', DisplayName to 'Bladeward', drop the spellslot, change the icon, drop the RootFolder so inGame Shield isn't affected, and then change the BOOST to be ApplyStatus(BLADE_WARD,100,1) instead. But that is the running theory. I will test it out tonight to see what happens.
I think I underestimated the simplicity of just simply "creating another version". The coding for the Shield spell is not a one to one parallel of a utility cantrip. I suspect it take a lot more than just adding an additional entry in the shout.txt file.
At this point, it would have to be an additional custom spell which I have no idea how to do from scratch buuuuuuuuuuuuut, there is another modder who wrote up a program that could allow us to do with ease. Not sure if you saw Polymath or not, but this is quite the tool. It should make modding a breeze like making an additional spell that works like shield but instead it casts Blade ward.
Alternatively, what one could also do is just copy the coding for the Status Shield (not the spell. the status) over to a Status.txt file and in the data line for BOOSTS, add the Bladeward boost as well. So that way, even if that doesn't somehow make the attack miss and it still lands, if it is a physical attack, you will only take half damage. So theoretically it would look like this: new entry "SHIELD" type "StatusData" data "DisplayNameEnglish" "Shield" data "RootFolder" "Patch3\Public\Shared" data "StatusType" "BOOST" data "DisplayName" "h78836f0fg29b9g4a48gabb4g62884633dc78;2" data "DescriptionEnglish" "Immune to Magic Missile. <LSTag Tooltip="ArmourClass">Armour Class</LSTag> is increased by 5. Also, take half physical damage if the attack still lands." data "Description" "h9cacbac7g1ccbg4d5bg9118gf4554f12068d;1" data "Icon" "Spell_Shield" data "StackId" "SHIELD" data "Boosts" "AC(5);IF(IsSpellChildOrVariantFromContext('Projectile_MagicMissile')):DamageReduction(Force,Flat,100);WeaponDamageResistance(Bludgeoning);WeaponDamageResistance(Slashing);WeaponDamageResistance(Piercing)" data "StatusGroups" "SG_RemoveOnRespec" data "StatusEffect" "19c84d1e-8de6-4361-88ec-0f64c15d52b1" data "StackType" "Ignore"
I am positive someone more experienced than I could look at this and cut out data lines that aren't needed but what I do know is the most important data line is the Boosts line.
I didn't see one in your mod. But in any event, I was able to use PolyMath to create a custom version of the spell. Here is the code for it: new entry "CUST_BladeWardShield" type "SpellData" data "DisplayNameEnglish" "Blade Ward Shield" data "DescriptionEnglish" "Take half damage of physical attacks as a reaction. data "RootFolder" "SharedDev" data "SpellType" "Shout" data "UseCosts" "ReactionActionPoint:1" data "SpellProperties" "ApplyStatus(BLADE_WARD,100,1)" data "Icon" "Spell_Abjuration_BladeWard" data "DisplayName" "haf20ce0cgacb3g4be2ga74eg72c5173ff14e" data "DisplayNameDescription" "h21fa38a5gf718g4fd6g9989g0abf04f789bf" data "DescriptionParams" "5" data "TooltipStatusApply" "ApplyStatus(SHIELD,100,1)" data "CastSound" "Spell_Cast_Buff_BladeWard_L1to3" data "SpellAnimation" "9122eb08-93f1-4010-a275-f5ae3ec7c76e;2860e825-ec12-4008-8471-d797fc00abc4;b6540e92-9e06-4695-9d8e-552d5eac45c2;5301d674-b7da-47b6-b4cf-2802ba33a9e9;86b3cf93-21fb-4a3d-bed9-97d0a567d084" data "VerbalIntent" "Utility" data "SpellFlags" "HasVerbalComponent;HasSomaticComponent;IsSpell;IsLinkedSpellContainer" data "CastTextEvent" "Cast" data "TargetConditions" "Self()" data "Level" "1" data "SpellSchool" "Abjuration" data "MemoryCost" "1.0" data "InterruptPrototype" "Interrupt_Shield_Wizard" I added it to your Shouts.txt and I wanted to see if I can just add it right away instead of going through the level up screen so I ran AddSpell(GetHostCharacter(), "CUST_BladeWardShield") in the Script Extender Console and it added it to the Reactions menu. It also put a copy of it in the Cantrips Menu Hotbar which effectively does nothing. What's interesting is that it gives you the Blade Ward icon in the Hotbar but it shoes up as the Shield spell in the Reactions menu. I just haven't gotten a chance to test it yet. I will tonight tho.
so the game has a data folder that acts as the default state for things like armour, weapons, spells ect... so when a mod wants to change something that already exists in the game they will just take the files from the games data folder that they need and make a custom version of that for their mod, (with creating new things i haven't done it so I'm not 100% certain on that front) I've posted a Zip with all the files in the games data folder, all my mod does is create a custom version of these files for the things i wanted and i left out the rest, this might be of some help for what you're trying to do.
Oh I see what you mean. I downloaded your Data Zip looked at the Interrupt.exe and was unable to find the coding for the Shield spell. Very weird. I double checked the Spell_Shout.txt to see if it was there because Shield is technically classified as a Shout and it wasn't in there either.
Also, I tested it at I noticed some weird anomalies with the game in general. for some reason, a lot of interrupt spells are triggering a "reroll?" prompt for successful saves. And less so for unsuccessful saves. The few times I was able to trigger the Custom Blade Ward spell, it buffed the AC like Shield does but I still got hit. So when I inspected the combat log, I noticed that the prompt was triggering for unsuccessful Attack rolls (which I don't need it to trigger then). Additionally, the damage roll showed the following math: "Damage = 1 + 3 = 14." What the what? But I kept looking at other attacks and only one damage roll showed half damage out of like 5 attacks.
But thank you for providing the DATA zip because now I can see how Interrupts are supposed to work. I compared Shield Master to what I found in HexDataBrowser and it is giving me a better idea of how the infrastructure works. With what I have now, I am getting inconsistencies (and that may be more so of this weird bug I am experiencing where interrupt prompts are appearing for successful saves) So back to the drawing board.
Ok, so.....I finally made some progress. Turning a spell into a reaction (in this case a cantrip) is more difficult than simply changing the "costs". In fact, each Reaction spell/ability, is composed of three parts: Passives, Statuses, and Interrupts. Passives are what characters need to have. This is normally tied to class level progression. i.e. Reach level 2, get Passive Ability "Blade Ward Shield" new entry "BladeWardShield_Passive" type "PassiveData" data "DisplayName" "haf20ce0cgacb3g4be2ga74eg72c5173ff14e;1" data "DisplayNameDescription" "h21fa38a5gf718g4fd6g9989g0abf04f789bf;1" data "Icon" "Spell_Abjuration_BladeWard" data "Boosts" "UnlockInterrupt(Interrupt_Bladeward)" Once you have the Passive, you automatically unlock the Reaction in your Reaction menu. In order for it to know when it needs to trigger, it needs an an Interrupt prototype. new entry "Interrupt_Bladeward" type "InterruptData" data "DisplayName" "haf20ce0cgacb3g4be2ga74eg72c5173ff14e;1" data "Description" "h21fa38a5gf718g4fd6g9989g0abf04f789bf;1" data "Icon" "Spell_Abjuration_BladeWard" data "InterruptContext" "OnPreDamage" data "InterruptContextScope" "Self" data "Container" "YesNoDecision" data "Conditions" "not IsDamageTypePsychic() and IsAbleToReact(context.Observer) and Self(context.Target,context.Observer) and not AnyEntityIsItem()" data "Properties" "Boost_Bladeward" data "Cost" "ReactionActionPoint:1" data "InterruptDefaultValue" "Ask;Enabled" data "EnableCondition" "not HasStatus('SG_Polymorph') or Tagged('MINDFLAYER') or HasStatus('SG_Disguise')" data "EnableContext" "OnStatusApplied;OnStatusRemoved" It contains values in there that determines the conditions that trigger it to kick in. and if the parameters are met, it turns around and gives you a Status Boost. new entry "Boost_Bladeward" type "StatusData" data "StatusType" "BOOST" data "DisplayName" "haf20ce0cgacb3g4be2ga74eg72c5173ff14e;1" data "DisplayNameDescription" "h21fa38a5gf718g4fd6g9989g0abf04f789bf;1" data "Icon" "Spell_Abjuration_BladeWard" data "Boosts" "ApplyStatus(BLADE_WARD,100,1)" data "RemoveEvents" "OnDamage" data "StatusPropertyFlags" "DisableOverhead;DisablePortraitIndicator;DisableCombatlog"
So I added three additional TXT files to your mod and added the passive manually since it is a custom spell, there is no natural way for me to get this otherwise. So I gave it to three of my lowest AC characters via Console Command AddPassive(GetHostCharacter(), "BladeWardShield_Passive") AddPassive("S_Player_Gale_ad9af97d-75da-406a-ae13-7071c563f604", "BladeWardShield_Passive") AddPassive("S_Player_Jaheira_91b6b200-7d00-4d62-8dc9-99e8339dfa1a", "BladeWardShield_Passive") My Tav is a draconic Sorcerer. All of them got the cantrip. All of them got attacked. All of them got the prompt like normal....but it only halved the damage for ONE of them. and that was for my Tav. Gale and Jaheira got the full brunt of the physical attacks.
I-I don't know.....what is happening here.... I kinda give up. This is the closest I could get it. Feel free to take it and test it for yourself. Cuz I am done. I am literally still on my first campaign. I have no business sticking my nose into modding this early when I still haven't completed my first campaign run. So I am going to put it down and get back to finishing my story.
By chance, did you also change the Spellcasting modifier to be set to a Class's Spellcasting modifier instead of INT (I am talking about Firebolt specifically here but in general these spells that need accuracy should adapt to the class so that way they are not useless. I got three Elves in my camp that have Firebolt and THEY CAN'T AIM FOR SH!T!! LOL)?
EDIT: oh you know what......nvm. I see why it is happening now. Happen to find this factoid on the wiki
High Elf and High Half-Elf versions are from the Wizard spell list and scale hit rate off of Intelligence. You need to explicitly choose the class version to scale off of a separate stat.
EDIT 2: oh wow. Just doing a little more digging and it turns out it is possible to affect the racial cantrips for the High Elves to look at the highest stat instead.
17 comments
Since my post, I have learned a a lot more. As you suggested, in theory, if I were to look up the code for the Shield spell, for example, I could copy the entire code and put it right underneath the Bladeward cantrip. Then, I simply change the name to 'Shout_Bladeward_Wizard', DisplayName to 'Bladeward', drop the spellslot, change the icon, drop the RootFolder so inGame Shield isn't affected, and then change the BOOST to be ApplyStatus(BLADE_WARD,100,1) instead. But that is the running theory. I will test it out tonight to see what happens.
At this point, it would have to be an additional custom spell which I have no idea how to do from scratch buuuuuuuuuuuuut, there is another modder who wrote up a program that could allow us to do with ease. Not sure if you saw Polymath or not, but this is quite the tool. It should make modding a breeze like making an additional spell that works like shield but instead it casts Blade ward.
Alternatively, what one could also do is just copy the coding for the Status Shield (not the spell. the status) over to a Status.txt file and in the data line for BOOSTS, add the Bladeward boost as well. So that way, even if that doesn't somehow make the attack miss and it still lands, if it is a physical attack, you will only take half damage. So theoretically it would look like this:
new entry "SHIELD"
type "StatusData"
data "DisplayNameEnglish" "Shield"
data "RootFolder" "Patch3\Public\Shared"
data "StatusType" "BOOST"
data "DisplayName" "h78836f0fg29b9g4a48gabb4g62884633dc78;2"
data "DescriptionEnglish" "Immune to Magic Missile. <LSTag Tooltip="ArmourClass">Armour Class</LSTag> is increased by 5. Also, take half physical damage if the attack still lands."
data "Description" "h9cacbac7g1ccbg4d5bg9118gf4554f12068d;1"
data "Icon" "Spell_Shield"
data "StackId" "SHIELD"
data "Boosts" "AC(5);IF(IsSpellChildOrVariantFromContext('Projectile_MagicMissile')):DamageReduction(Force,Flat,100);WeaponDamageResistance(Bludgeoning);WeaponDamageResistance(Slashing);WeaponDamageResistance(Piercing)"
data "StatusGroups" "SG_RemoveOnRespec"
data "StatusEffect" "19c84d1e-8de6-4361-88ec-0f64c15d52b1"
data "StackType" "Ignore"
I am positive someone more experienced than I could look at this and cut out data lines that aren't needed but what I do know is the most important data line is the Boosts line.
new entry "CUST_BladeWardShield"
I added it to your Shouts.txt and I wanted to see if I can just add it right away instead of going through the level up screen so I rantype "SpellData"
data "DisplayNameEnglish" "Blade Ward Shield"
data "DescriptionEnglish" "Take half damage of physical attacks as a reaction.
data "RootFolder" "SharedDev"
data "SpellType" "Shout"
data "UseCosts" "ReactionActionPoint:1"
data "SpellProperties" "ApplyStatus(BLADE_WARD,100,1)"
data "Icon" "Spell_Abjuration_BladeWard"
data "DisplayName" "haf20ce0cgacb3g4be2ga74eg72c5173ff14e"
data "DisplayNameDescription" "h21fa38a5gf718g4fd6g9989g0abf04f789bf"
data "DescriptionParams" "5"
data "TooltipStatusApply" "ApplyStatus(SHIELD,100,1)"
data "CastSound" "Spell_Cast_Buff_BladeWard_L1to3"
data "SpellAnimation" "9122eb08-93f1-4010-a275-f5ae3ec7c76e;2860e825-ec12-4008-8471-d797fc00abc4;b6540e92-9e06-4695-9d8e-552d5eac45c2;5301d674-b7da-47b6-b4cf-2802ba33a9e9;86b3cf93-21fb-4a3d-bed9-97d0a567d084"
data "VerbalIntent" "Utility"
data "SpellFlags" "HasVerbalComponent;HasSomaticComponent;IsSpell;IsLinkedSpellContainer"
data "CastTextEvent" "Cast"
data "TargetConditions" "Self()"
data "Level" "1"
data "SpellSchool" "Abjuration"
data "MemoryCost" "1.0"
data "InterruptPrototype" "Interrupt_Shield_Wizard"
AddSpell(GetHostCharacter(), "CUST_BladeWardShield")
in the Script Extender Console and it added it to the Reactions menu. It also put a copy of it in the Cantrips Menu Hotbar which effectively does nothing. What's interesting is that it gives you the Blade Ward icon in the Hotbar but it shoes up as the Shield spell in the Reactions menu. I just haven't gotten a chance to test it yet. I will tonight tho.Also, I tested it at I noticed some weird anomalies with the game in general. for some reason, a lot of interrupt spells are triggering a "reroll?" prompt for successful saves. And less so for unsuccessful saves. The few times I was able to trigger the Custom Blade Ward spell, it buffed the AC like Shield does but I still got hit. So when I inspected the combat log, I noticed that the prompt was triggering for unsuccessful Attack rolls (which I don't need it to trigger then). Additionally, the damage roll showed the following math: "Damage = 1 + 3 = 14." What the what? But I kept looking at other attacks and only one damage roll showed half damage out of like 5 attacks.
But thank you for providing the DATA zip because now I can see how Interrupts are supposed to work. I compared Shield Master to what I found in HexDataBrowser and it is giving me a better idea of how the infrastructure works. With what I have now, I am getting inconsistencies (and that may be more so of this weird bug I am experiencing where interrupt prompts are appearing for successful saves) So back to the drawing board.
new entry "BladeWardShield_Passive"
Once you have the Passive, you automatically unlock the Reaction in your Reaction menu. In order for it to know when it needs to trigger, it needs an an Interrupt prototype.type "PassiveData"
data "DisplayName" "haf20ce0cgacb3g4be2ga74eg72c5173ff14e;1"
data "DisplayNameDescription" "h21fa38a5gf718g4fd6g9989g0abf04f789bf;1"
data "Icon" "Spell_Abjuration_BladeWard"
data "Boosts" "UnlockInterrupt(Interrupt_Bladeward)"
new entry "Interrupt_Bladeward"
It contains values in there that determines the conditions that trigger it to kick in. and if the parameters are met, it turns around and gives you a Status Boost.type "InterruptData"
data "DisplayName" "haf20ce0cgacb3g4be2ga74eg72c5173ff14e;1"
data "Description" "h21fa38a5gf718g4fd6g9989g0abf04f789bf;1"
data "Icon" "Spell_Abjuration_BladeWard"
data "InterruptContext" "OnPreDamage"
data "InterruptContextScope" "Self"
data "Container" "YesNoDecision"
data "Conditions" "not IsDamageTypePsychic() and IsAbleToReact(context.Observer) and Self(context.Target,context.Observer) and not AnyEntityIsItem()"
data "Properties" "Boost_Bladeward"
data "Cost" "ReactionActionPoint:1"
data "InterruptDefaultValue" "Ask;Enabled"
data "EnableCondition" "not HasStatus('SG_Polymorph') or Tagged('MINDFLAYER') or HasStatus('SG_Disguise')"
data "EnableContext" "OnStatusApplied;OnStatusRemoved"
new entry "Boost_Bladeward"
type "StatusData"
data "StatusType" "BOOST"
data "DisplayName" "haf20ce0cgacb3g4be2ga74eg72c5173ff14e;1"
data "DisplayNameDescription" "h21fa38a5gf718g4fd6g9989g0abf04f789bf;1"
data "Icon" "Spell_Abjuration_BladeWard"
data "Boosts" "ApplyStatus(BLADE_WARD,100,1)"
data "RemoveEvents" "OnDamage"
data "StatusPropertyFlags" "DisableOverhead;DisablePortraitIndicator;DisableCombatlog"
So I added three additional TXT files to your mod and added the passive manually since it is a custom spell, there is no natural way for me to get this otherwise. So I gave it to three of my lowest AC characters via Console Command
AddPassive(GetHostCharacter(), "BladeWardShield_Passive")
My Tav is a draconic Sorcerer. All of them got the cantrip. All of them got attacked. All of them got the prompt like normal....but it only halved the damage for ONE of them. and that was for my Tav. Gale and Jaheira got the full brunt of the physical attacks.AddPassive("S_Player_Gale_ad9af97d-75da-406a-ae13-7071c563f604", "BladeWardShield_Passive")
AddPassive("S_Player_Jaheira_91b6b200-7d00-4d62-8dc9-99e8339dfa1a", "BladeWardShield_Passive")
I-I don't know.....what is happening here.... I kinda give up. This is the closest I could get it. Feel free to take it and test it for yourself. Cuz I am done. I am literally still on my first campaign. I have no business sticking my nose into modding this early when I still haven't completed my first campaign run. So I am going to put it down and get back to finishing my story.
EDIT: oh you know what......nvm. I see why it is happening now. Happen to find this factoid on the wiki
EDIT 2: oh wow. Just doing a little more digging and it turns out it is possible to affect the racial cantrips for the High Elves to look at the highest stat instead.