Expose spell (descriptor) immunities programatically
I've been fooling around with another spell, 'Inevitable Defeat'. It's geared toward the beguiler, and does non-lethal damage for a number of rounds (or until a will save) on a touch attack.
I wanted to try to make it a 'proper' touch spell, where casting it puts you in a 'holding charge' state and you can make as many touch attacks as necessary to actually discharge the spell---or cast, move, then make the attack. It seems like they might be more tactically interesting that way. However, I finally ran into a snag that I think is not just a lack of understanding on my part.
The problem is that the spell is "Mind-Affecting," however, the spell descriptor/immunity system is not set up to handle these sort of touch attack spells. For instance, if Inevitable Defeat is tagged as Mind-Affecting, then e.g. Mind Blank will prevent you from using the spell, because it is---engine-wise---targeting yourself, and won't provide any protection from getting hit by the spell. It also seems there is no way to query whether a target is immune to (e.g.) mind affecting spells in the spell/modifier scripts.
It seems like what happens in these cases is that the conditions just create their own immunity checks (like, testing if stuff is undead and whatnot). But to properly function that means that every condition has to know about every source of immunity, which isn't very nice. Since conditions can already report that they give immunities in a modular way, it'd be nice if that could be queried instead.
Hopefully I haven't missed some existing way to do this.
Edit: Oh, also, although for this spell it could just be solved by making it like most other single touch spells in the game (fizzles on miss), there are some spells that give multiple charges (chill touch might be the only one in ToEE). Those don't have any option but to use the 'holding charge' mechanic.
Some immunity effects are indeed reported by query, such as by: Q_Critter_Is_Immune_ Critical_Hits, Poison, Energy_Drain, Death_Touch.
Unfortunately the current setup does not allow you to easily query immunity for spell descriptors.
I think for such a use case, what you'd do is create an Attack Handler (similar to Chill Touch), that on hit spawns a 2ndary condition 'Inevitable Defeat Hit' on the target which would then trip the immunity handler (or otherwise deal the damage). Note that this 2ndary condition must check for spell resistance in its OnAdd callback (which internally checks immunity as well).
You're right about Mind Blank, that is a bug. @doug1234 heads up, it should probably check if caster is different than attachee.
I do have two conditions defined. The problem (I think) is that only casting a spell (with a proper rules/spells/X.txt) gets checked against immunities.
It occurred to me that there could be a separate spell for the on-hit, and the touch attack handler for the charge would just force the attacker to cast a spell on the target. I'm in the process of testing that out. Not sure if there's some other gotcha for that. Then the spell you target yourself with would not be marked Mind-Affecting, but the hidden one would.
I don't think there's any problem with Mind Blank. Not sure what you meant about that.
If we are going that way, should mind blank not trigger for all harmless spells instead of checking the attachee? That being said, I think mindblank stops all mind effecting spells not just hostile ones. I can double check on that interpretation though.
BTW: Did you look at touch of touch of fatigue dolio? That should also be somewhat similar to what you are doing.
Oh, I see what you mean about mind blank now.
Yes, I did look at touch of fatigue. That's an example where the condition script just does it own immunity check (undead, construct, ooze, plant). So it would act weirdly if someone made a spell that makes you immune to all necromancy spells or something.
So, it doesn't seem like a separate spell will work easily, either. I tried having the touch attack handler do caster.cast_spell(NUM, target), but that seems to require acting within the rules. So, e.g. my character hasn't learned 'Inevitable Defeat Hit', so they can't cast it. If I do learn it, they can cast it, but it uses up a spell slot and the swift action for the round.
Maybe there's a way to do setup/rollback around the cast_spell so that the character can legally cast the spell, and have no turn-based consequences from doing so. But it seems like it'd be a significant kludge. It occurred to me that the 'holding charge' condition could actually be made kind of generic if this worked out. But making it work seems far from ideal.
Sorry for the spam....
I think I finally understand what you were originally suggesting. You were suggesting that immunities shouldn't block the casting of the charge spell on yourself, but then the touch attack should check for spell resistance with the same spell packet, which is how you check for immunity on a target programmatically.
It does seem like that would work. I guess maybe if you didn't want all 'harmless' spells to be allowed by e.g. Mind Blank, something could be added to the spell files to indicate that the self-targeting part is just holding a charge?
Yeah spell harmfullness could use an overhaul. But I think what I proposed is good enough for now.
Looked a bit into RAW for Mind Blank and it looks like it is suppose to block all mind effecting spells including helpful ones. So the way it currently works is correct. That being said we could allow mind effecting spells to be cast by party members if you don't want to go with RAW. To just make this unusual spell work, a small change could be made to mind blank to not provide immunity for it.
Mind blank was really just an example. I suspect the same issue would crop up if you tried to e.g. make Slay Living a touch spell that didn't fizzle on a miss (I assume it isn't already). Then your Death Ward would stop you from casting it on someone else.
One idea I had was to mark the spell as Spell Resistance: No, hoping that would bypass the check. Then I could use spell_resistance_check_force in the touch attack to override it. That doesn't work, though. I guess Mind Blank could also test that flag, but a bunch of other spells would need to be audited, because I think a lot of buffs are marked as 'SR: No' instead of 'Yes (harmless)', because the latter doesn't exist in ToEE. I guess I'm also not sure if a buff would bypass spell resistance in that case, or whether Mind Blank could tell the difference between a regular and forced check. So there are lots of potential problems.
Anyhow, I don't want to impose a ton of work on people just for my random fooling around. These sort of spells aren't significantly less useful if they fizzle on miss. I mainly thought it was a cool aspect of the engine that went under used. (I guess I was also wondering whether Spectral Hand would be possible, which seems like it might require touch spells that work this way).
Edit: Here's another possibility. There's a targeting mode string "Become_Touch". Right now if you use it, it crashes the game. Is it possible to make that work like Personal, but bypass the immunity check? I have no concept of how difficult that is.
Is the "held spell in hand" not using a different condition to model it, or is it the generalized check against spell conditions that causes this?
Yeah, there's a spell resistance/immunity check that happens before any scripts for the spell run.