A few spellcasting mod development issues

Discuss coding questions, pull requests, and implementation details.
User avatar
DunnyOfPenwick
Posts: 63
Joined: Wed Apr 14, 2021 1:58 am
Location: Southeast US

A few spellcasting mod development issues

Post by DunnyOfPenwick »

I bumped into some issues when writing the Create Atronach Spell mod recently and thought I would share.
  • The spell requires appropriate material components to be in the character inventory to cast, but I could see no way to check for this until the entityEffect.Start() method was called. Adding a requirement check method to EntityEffect might help here; if requirements are not met, the spell is disabled in the spellbook.
  • There is no atronach corresponding to the Magic element type, but the button is always enabled by default in the SpellMaker.
  • By-touch/target-at-range assume the spell is a damaging spell requiring an enemy target. There might not be any payload as such attached to the spell. Also, I don't see any way to prevent a missile from being created when casting at-range spells. There might be cases (like Telekinesis) where a missile is undesirable.

User avatar
Magicono43
Posts: 682
Joined: Tue Nov 06, 2018 7:06 am

Re: A few spellcasting mod development issues

Post by Magicono43 »

Happen to have a repo for this mod's source code? I'm currently working on a "Summon Entity" spell effect in my overhaul project fork and am curious to see how you did your custom spell in this instance. My efforts so far have a summoned rat that is destroyed when the spell effect duration ends. Thanks.

User avatar
DunnyOfPenwick
Posts: 63
Joined: Wed Apr 14, 2021 1:58 am
Location: Southeast US

Re: A few spellcasting mod development issues

Post by DunnyOfPenwick »

I don't have a repo at the moment, but I will try to create one.

I guess if I'm going to contribute to an open source game like DFU I should probably have one.

User avatar
Magicono43
Posts: 682
Joined: Tue Nov 06, 2018 7:06 am

Re: A few spellcasting mod development issues

Post by Magicono43 »

DunnyOfPenwick wrote: Sat Jun 19, 2021 4:17 pm I don't have a repo at the moment, but I will try to create one.

I guess if I'm going to contribute to an open source game like DFU I should probably have one.
Yeah, I personally find having the code easily available makes it both easier for the original code writer as well as easy access for anyone looking to improve/learn from that code as well, I currently just use Github, not anything fancy, just a somewhat easy to use place to see commit history as well as access files and such.

User avatar
DunnyOfPenwick
Posts: 63
Joined: Wed Apr 14, 2021 1:58 am
Location: Southeast US

Re: A few spellcasting mod development issues

Post by DunnyOfPenwick »

I'm currently working on another mod (Illusory Decoy) and have made some changes to the Create Atronach mod.

I'll probably create the github repo tomorrow. I'll drop you another reply when I do.

User avatar
Magicono43
Posts: 682
Joined: Tue Nov 06, 2018 7:06 am

Re: A few spellcasting mod development issues

Post by Magicono43 »

Cool, take your time, sounds like a cool new spell effect, hope it goes well even with the current limits of the modding system.

User avatar
Interkarma
Posts: 6513
Joined: Sun Mar 22, 2015 1:51 am

Re: A few spellcasting mod development issues

Post by Interkarma »

DunnyOfPenwick wrote: Mon Jun 14, 2021 5:04 pm The spell requires appropriate material components to be in the character inventory to cast, but I could see no way to check for this until the entityEffect.Start() method was called. Adding a requirement check method to EntityEffect might help here; if requirements are not met, the spell is disabled in the spellbook.
You can check for the items at Start(). If the player isn't holding required items then output a message and End() the effect. If you don't want the player to burn their spellpoints by failing without materials, then you could refund cost of the effect back to spellpoints using FormulaHelper.CalculateEffectCosts() and casterEntity.IncreaseMagicka() before ending effect.

This also means other effects combined with this one will execute and cost as normal. You really don't want one effect blocking the whole spell. With up to 3x effects per spell, players have a habit of combining things in unusual ways. There's plenty of ways to get in trouble with this, I know this from experience. :)

DunnyOfPenwick wrote: Mon Jun 14, 2021 5:04 pm There is no atronach corresponding to the Magic element type, but the button is always enabled by default in the SpellMaker.
Magic elements are for determining resistances when cast at another entity. Effect variants are for creating different styles of the same effect. For an Atronach summoning, limit this to ElementTypes.Magic in effect properties and use variant effects instead: "Create Atronach - Fire", "Create Atronach - Frost", etc.

DunnyOfPenwick wrote: Mon Jun 14, 2021 5:04 pm
  • By-touch/target-at-range assume the spell is a damaging spell requiring an enemy target. There might not be any payload as such attached to the spell. Also, I don't see any way to prevent a missile from being created when casting at-range spells. There might be cases (like Telekinesis) where a missile is undesirable.
Targeting by touch or by range are specifically for targeting other entities. If you don't want to target entities then use TargetTypes.CasterOnly in effect properties and target world objects however you want in the payload. Look to DispelUndead for an example that uses custom targeting. DetectTreasure is another effect that uses custom targeting for world objects instead of entities. These both use GetNearbyObjects() but you could do custom raycasts, etc. to target whatever you want based on how the effect is intended to work.

For a really novel example of a custom effect, check out my Vanity Clone full moon easter egg. This effect creates a hovering paper doll, animates a swirling ball of custom missiles, and blasts foes (created by a quest) with those swirling missiles. It even heals the player if they stay near to the clone. You really can do almost anything you like with effects if you put your mind to it. Here's the effect source code.

It mostly helps to just work within the framework and think about spells and effects in a Daggerfally way, rather than subvert something in a way it wasn't intended (e.g. elements for variants). And don't forget that players will combine effects in unexpected ways. The framework tries to coordinate everything but it's still possible to get in trouble when an effect takes over too much. Examples of this in core are Teleport and Open - they both like to have full control and don't play well with other effects.

Magicono43 wrote: Sat Jun 19, 2021 1:43 am My efforts so far have a summoned rat that is destroyed when the spell effect duration ends.
I'm not sure how that would happen. There's nothing inherently tying effect duration to created foes. If you want a summoned foe to persist, the effect itself doesn't even need a Duration component. Just create the foe in payload and end the effect.

GameObjectHelper.CreateFoeSpawner() is a good helper just to drop an enemy entity into the world. The spawner will self-destroy once all foes are placed. This doesn't need to be tied to the effect duration at all.

User avatar
Magicono43
Posts: 682
Joined: Tue Nov 06, 2018 7:06 am

Re: A few spellcasting mod development issues

Post by Magicono43 »

Interkarma wrote: Sat Jun 19, 2021 11:29 pm I'm not sure how that would happen. There's nothing inherently tying effect duration to created foes. If you want a summoned foe to persist, the effect itself doesn't even need a Duration component. Just create the foe in payload and end the effect.

GameObjectHelper.CreateFoeSpawner() is a good helper just to drop an enemy entity into the world. The spawner will self-destroy once all foes are placed. This doesn't need to be tied to the effect duration at all.
Yeah in this case I do want the effect to work with a limited duration, think of how it works in Oblivion, where you summon the entity and the spell effect on the player ends when either the summoned entity dies, or the duration of the spell effect runs out and the enemy "dies" effectively. I had to add a custom variable to allow for the summoned entity object to be kept tracked, and then when the effect ends that object will be promptly destroyed from the world, that's the idea at least, I'm doing this in my custom project fork of DFU btw.

I would like to use the CreateFoeSpawner method, as it is code-wise much cleaner to use and ties away many potential loose ends, but my issue with using it for a "summon spell" is that it does not work as I would sort of expect say a conjuration spell to work in Oblivion, where the summoned enemy is put somewhere in-front of the caster, FoeSpawner sort of makes the feedback of the summon not immediate as the enemy is not allowed to appear within the sight-line of the player, sort of making the summon only appear behind a nearby corner, or when you turn the camera around a bit and see them suddenly appear where you were previously looking, etc. Maybe I could modify the FoeSpawner method somewhat, or make an overload or something to allow for the behavior I would like where the player camera does not matter where the enemy will appear, that could potentially be an easier way to do it, thanks for the idea.

User avatar
Interkarma
Posts: 6513
Joined: Sun Mar 22, 2015 1:51 am

Re: A few spellcasting mod development issues

Post by Interkarma »

My misunderstanding. From your comment, it sounded like the despawning was undesirable, thus my confusion about how that would even happen. :)

Yeah, direct placement is best if you don't want the enemy placed somewhere around player.

Another way to handle expiry is to attach a bespoke component to enemy gameobject to expire it after a certain amount of gametime has elapsed. It's simple, but would break after save/reload though. I'll see if I can think of something better for you.

User avatar
Interkarma
Posts: 6513
Joined: Sun Mar 22, 2015 1:51 am

Re: A few spellcasting mod development issues

Post by Interkarma »

Magicono43 wrote: Sun Jun 20, 2021 12:34 am I had to add a custom variable to allow for the summoned entity object to be kept tracked, and then when the effect ends that object will be promptly destroyed from the world, that's the idea at least, I'm doing this in my custom project fork of DFU btw.
Here's a way of doing this with no changes to core by using secondary custom effect to "retire" spawned entity.
  1. Create your foe gameobject directly and spawn in front of player based on however you want to do this. At this point, you have a complete enemy gameobject with their own entity effect manager attached.
  2. After your primary effect places the foe, also directly assign a secondary custom effect using foe's effect manager and bypassing resistance. The only purpose of this secondary effect is to track time and kill/despawn the enemy entity at the end.
The primary effect is what your players see and cast. The secondary effect is assigned only by primary effect, it's hidden by setting properties to disallow spellmaker, etc. The secondary effect will be serialized/deserialized as normal and you don't need to track the entity beyond their initial creation. You just emit them into world, assign the effect to kill them later, and let it all roll on.

Let me know if that doesn't make sense. I'd be happy to put together a quick example to demo. We're also derailing DunnyOfPenwick's topic somewhat. :)

Post Reply