X2_s3_onhitcast, or, On Hit Spell Cast: Unique Power

While I did find at least one old thread about this, I didn’t feel like necroposting, so…

I wanna write some On Hit Spell Cast: Unique Powers. It’s said that this invokes x2_s3_onhitcast. Is this fact hard-coded into the engine, or is there some obscure sequence of (user-definable) event triggers that does this?

I’ve overridden a bunch of events, so you know, one likes to be sure.

That’s the script for the spell in the spells.2da (line 700 I believe). It’s not hard coded.

Oh, fair enough. That makes sense.

I’m trying to see how far I can get without modifying resource files, so for the time being a 2da definition is “hard-coded.” We’ll see how long my willpower holds out on that one.

Anyway, thanks for the info.

You can modify the script without modifying the 2da.

The toolset will force you to save it as a local copy, which only affects your module. If you don’t like the changes, deleting the local copy will reinstate the default script.

In other cases, though, there’s no reason to be afraid of modifying 2da files, or even creating new ones. It’s powerful, yet very simple in principle, especially if you use the community Excel tools like Yata or whatever. Again, you put your modified 2da in a top hak, so it only affects your module, and can be removed to regress to vanilla.

In this particular case, though, modifying the script is easier.

Editing a .2da file may seem simple in principle if you’ve done it before but to someone who’s never edited one they can seem very intimidating… If only adding a few custom things it might be simple but if adding 30+ songs like I wanted to do, it seemed like it was going to be pretty complicated to me! All that custom naming and making sure file names are in the right slots scared me away from .2da editing.

Tag-based scripting is your friend. Make an item, assign it the OnHit:CastSpell - Unique Power itemproperty, and give a unique tag. Next, create a script named whatever tag you gave the item and then code what happens in that script (see x2_it_example) for more information.

No need to edit a 2DA.

I spent a while thinking about why I don’t find tag-based indirect evaluation a very appealing approach. My initial instinct was just, the scripting language is sort of C–, like you don’t realize how much you miss malloc until you don’t have it, which has put me in a very “primitive” C state of mind. Which is to say, enumerating cases with switch and if/else.

Then my next thought was about the performance cost of indirect evaluation, since evaluating other scripts by string name seems like it would be even worse than object vtables. But you know, it isn’t 2002 anymore—though I do think excessive devotion to vtables is why processors get faster, while the computing experience stays the same. (Indirect evaluation carries with it a bunch of other problems, like branch prediction always failing, the instruction pipeline always being discarded, and potentially poor cache locality.)

Ultimately, though, unless I’m missing something really obvious, there doesn’t seem to be a way to create folders/directories/categories of scripts. I’d rather have if/else blocks on tags, tag substrings, and persistent variables, than a proliferation of small scripts.

To each their own, though.

As for 2da files, I suppose I’ll see if I end up needing to edit them. I view it as a bit of a last resort, since I believe constraint breeds creativity.

As a generalisation, I agree that it pays to minimise the number of scripts. The EE toolset handles large numbers better than the original (which used to grind to a halt) but it’s still tedious to find scriptlets in a very long list of clutter.

As previously mentioned, in this case there’s absolutely no need to change the 2da or create a tag-based script. You can put tag- or variable- based logic in a local version of the default script. A well-written monolithic script with many cases is no problem since it’s so easy to search for a case.

Having said that, it’s occassionally convenient to have a tag-based script for a unique power item, if there aren’t too many in the module.

A matter of taste, up to a point.

I was suggesting tag-based because it organizes all the item events under the individual item. However, if its only the OnHitCastSpell: Unique Power then it is much simpler - and tidier - to just edit x2_s3_onhitcast. Just be sure not to delete the top bit that’s already in the script.

Maybe some over thinking going on. NWscript code is compiled to byte code which is run on a virtual machine in the engine. That machine does not have things like branch prediction or pipelines. It’s a simple stack based machine. Trying to write scripts that worry about those features in the real cpu which is running the game engine underneath is not really worth it.

ExecuteScript() is plenty fast that you don’t need to worry about it. It basically doesn’t cost enough to care. But there is a limit of like 8 levels so if you have a deep nesting of scripts executing other scripts executing other scripts you need to watch for that. It fails silently.

As to the folders etc, yeah that’s true. The module is a flat set of files. That’s why people tend to use naming conventions.

As mentioned by others, there’s no need to edit the 2da for this. Just edit the x2_s3_onhitcast script.

I think yes and no on overthinking. Let’s say we had a writing prompt, “an adventurer breaks into a sealed tomb and finds the undead creatures inside have kept it immaculate, and indeed, the adventurer sees skeletons and zombies cleaning the walls and sarcophagi.” I think we’d all come up with very different stories—starting with the adventurer’s sex. Maybe one person would write about how boredom has taken hold of them, maybe another would write a story about a necromancer who hates dust, maybe another would write about how this was the burial chambers for a castle’s servants, maybe another would be about how they’ve found religion and think sacred places should be treated with respect.

And if you were to reflect on the writing choices you made, you might think, for this particular bit I was inspired by The Lord of the Rings, or Earthsea, or Frankenstein, or Gulliver’s Travels, or Cat’s Cradle, or whatever.

Half the stories would be in first-person, half would be third-person, and someone would inevitably write in second-person. Some stories would be past tense, some would be present tense, and maybe some cheeky writer would try for an imperfect tense. (And Ursula le Guin would use mixed past and present tense.)

I wouldn’t view any of this as overthinking, not least because reflecting on the choices you made is worthwhile. And it’s definitely worth talking about the choices everyone made. Those choices would, at first order, be instinctual, from all your prior experience reading and writing. Even high-minded stuff like symbolism is usually something that happens midstream, like you instinctively focus on certain things, tease out what drew you to those things, and then start being more explicit about the ways you’re using them.

I know this is a bit roundabout, but I guess my point is, we are mostly talking about style here and style is a subtle thing. I don’t think my style is “right,” or that other styles are “wrong.” I mostly think it’s interesting. People have different tastes, and I was just posting about mine.

And I did say, I don’t think performance was actually what caused my instinct to case-enumeration (or monolithic) style. More than anything else, I tend to find code with a lot of indirect evaluation hard to understand. Which is at the heart of the original question: the fact that x2_s3_onhitcast is invoked from a 2da file of spell definitions would’ve taken a lot of work to figure out on my own. Especially since that’s very different from the way On Use: Unique Power is handled.

You made it pretty clear you were talking about the performance. That’s what I was reacting to. As to style, sure. To each his own, within reason. If you don’t want to use indirection that works for me :slight_smile:

Pretty much all the spells are run by scripts defined in spells.2da. It’s not special to on hit: unique power. That’s just how the spells are done. It’s a lot better than hardcoding it in the engine.