One thing that really annoys me with wands (and potions too!) is that you are limited to using the caster levels defined in IPRP_spells.2da
If you want a spell to be wandable (or on any item with Cast Spell property) you have to add a line for it.
This is not the case with for example, On-hit: Cast Spell, which happily allows you to set the caster level.
I'm working towards a major overhaul of crafting/enchanting for our server, and wands were definitely in my sights. What i wanted was the possibility for me to set any spell to be added to a wand at any level with any metamagic (not necessarily all spells or levels or metamagics or combinations thereof, but at least have the option to pick and choose without adding new entries to the 2da for every one i want).
For example, if i wanted Magic Missile to be castable from a wand i can select 1 or 2 caster levels as defined in the 2da. If i want more, i have to add them to the 2da. And that's necessary for every spell that i would want more options for, and no chance for metamagic.
So, i started looking for ways to allow this to work.
The obvious starting point is instead of adding Cast Spell : <spell>, use Cast Spell: Activate Item (or Unique Power - they are pretty similar). Then using tag based scripting to determine what happens next. Crafted wands would store the spell, its caster level, and metamagic in local vars on the wand. The wand's item description would be modified to state which spell was on it.
The wand would have the spell it should cast on it stored in a local var, along with caster level and metamagics.
First problem: GetSpellCastItem() returned the correct object, but totally failed to retrieve any local vars from it. Ok, strange, switched to using GetItemActivated() and that worked fine. I now had local vars to work with.
Second problem: Well, not a problem, but it would take some code to determine whether the target is valid (lookup spell target value from spells.2da and see whether it can hit a creature, self only, or location) and decide whether the spell should fire or just give feedback that its an invalid target and reimburse the charge cost.
Third problem: This one was annoying. ActionCastItemAtObject is crap... if its a PC calling it, and you use bCheat=TRUE, it totally ignores the caster level you pass. It also appears to ignore metamagic values as well. I think it all works for NPCs, just presume its a PC only issue. So i got creative, which leads us to...
Fourth problem: I had the wand script store the caster level on the PC in a var then modified the spell script (in the test case, magic missile) to check for this var on the PC (if you don't fix a caster level, it assumes some default vault, not sure what it was, but more than 10). If it existed, it would take that as the caster level, if not, it would use the normal GetCasterLevel() function. Great! And things worked... except, you activate the item, its a 6 second wait, then another 6 seconds as the spell fires.... 2 rounds to use the wand instead of 1. Ok, there is a fix for this....
Fifth problem: Set bInstant=TRUE. Activate the wand, still 6 seconds for that, but the spell fires instantly... cool. Ill try queuing up a few then....
Sixth problem: Buggeration. AssignCommand of course puts the ActionCastSpell at the back of the queue.... so you click and you click, and it just keeps activating the wand but no spell fires, until its run all the activations... then the spells fire. But we know a fix for this don't we johnny?
Seventh problem: ActionDoCommand shoves things to the front of the queue, and single use it worked fine. But again, queuing, same problem. In fact worse, because for some reason it failed to take note of my caster level var and seemed to cast at max caster level.
It was time for a new approach, and i thought i had it. Screw using ActionCastSpellAtObject. Use ExecuteScript! Things looked good, queueing worked, everything except for...
Eighth problem: SpellId... can't be got, but that's ok, i've got that. Modified the script to check for the var i had set, and if exists to use that for spellid... i forsee a problem down the line with Acid Fog (spell ID 0) but that can be hacked around.
But there is one more issue...
Ninth problem: ResistSpell (and by extension MyResistSpell) returns -1 if the script calling it is not a spell script. Well, technically it is, but since its not being called as a proper spell, it decides to that i must be mad wanting to use ResistSpell in something it thinks isn't a spell script and doesn't perform a check. Its understandable, if its not coming in like a proper spell, it can't check to see what the spell level of the spell is, and i don't see a function to tell a script that its a spell, and which spell. There is a GetSpellID, but no SetSpellID...
There is a work around... it basically the same as i've done with a hack to make Rangers/Paladins full spellcasters. Hijack a function with a wrapper and make a hardcoded function only be called if it should be used, otherwise use a custom function. In this case, if it can detect its being called from a wand, don't call ResistSpell (or MyResistSpell) but call a custom function to determine if the target resists the spell.
And this is where i am... and thinking its already too much to bother trying further. There are some minor issues as well, but can be got round or lived with. For example, activating a wand just shows the default item activation icon... but this could be changed by showing a wand icon by adding a new entry that does the same as item activation but call it wand activation. Same goes for potions.
But it looks like the way to finish off this work would be to edit every spell that could be wandable/potionable to contain the hacks for casting the spells via ExecuteScript.
It looks possible.... but probably too much work.
Anyway, thought i would share the results of my work. Maybe someone will find some inspiration in it, learn something new, or perhaps have a clever idea for doing it all in a different way. ![]()





Retour en haut






