0.10.24 some magic related bugs

Post here if you need help getting started with Daggerfall Unity or just want to clarify a potential bug. Questions about playing or modding classic Daggerfall should be posted to Community.
Post Reply
npc
Posts: 5
Joined: Fri Aug 07, 2020 12:12 pm

0.10.24 some magic related bugs

Post by npc »

DFU 0.10.24
vanilla DF from DaggerfallSetup-2.16.0.zip

Thanks for making DFU. DF was the first game I ever bought, it has a special place in my heart.

Here are some bugs. I'm also trying to learn a little bit of C#, so I tried to locate the issues in the source-code and wrote down ideas on how to fix them, but I'm such a coding rookie that my "fixes" could be complete nonsense. So maybe all I did was make this more annoying to read... enjoy!
There are also some magic related suggestions at the bottom.



1) incomplete spell effect
Description:
The description of the spell effect "Elemental Resistance <element>" say "Target takes half damage if spell is unsuccessful." which doesn't seem to happen in DFU (not tested in vanilla DF).
To reproduce:
It requires a lot of in-game testing to overcome the random spread of spell damage. Reading the source code is easier.
To test in-game, Fire Daedras will reliably shoot fireballs, the damage spread is very big though and there is partial resistance too, so many data points must be collected.
With the mod "unleveled mobs" the dungeon "The Coven of Elyzyn" in Daggerfall almost always spawn 1+ Fire Daedra near the entrance (any Coven type of dungeon should work, but Elyzyn is nice due to the big entrance room).
Possible fix:
In FormulaHelper.cs (line 1457) it says

Code: Select all

percentDamageOrDuration = 100;
...
return Mathf.Clamp(percentDamageOrDuration, 0, 100);
by inserting something like

Code: Select all

if (target.HasResistanceFlag(elementType) && percentDamageOrDuration > 50)
	percentDamageOrDuration = 50;
just above the "return" line, the damage should be capped at 50% for the active Elemental Resistance <element> effects.



2) levitation speed bugs
Description:
While levitating, pressing the up-button and moving forward while facing up, results in a 2x upwards speed.
Pressing the up-button and moving forward while facing downwards results in 0x speed downwards. (edit: no bug)
It's possible to levitate faster forward by aiming 45 degree to the side and then press forward + side strafe.
The forward/backward swimspeed is reduced by facing the camera upwards/downwards.
All these bugs seem connected.
To reproduce:
Cast a levitation spell and try the up/down bug near a tall building or wall, so there is a visible reference point.
Any landmarks on the ground will do for measuring the forward levitation speed with/without side-strafing.
For swimming go to a dungeon like "the Citadel of Coppersley" in Daggerfall, it has water ~20m from the entrance.
Possible issue:
I think all of this comes from a combination of things in LevitateMotor.cs
forward/backwards movement (line 71)

Code: Select all

AddMovement(playerCamera.transform.forward);
...
AddMovement(-playerCamera.transform.forward);
and right/left movement (line 77)

Code: Select all

AddMovement(playerCamera.transform.right);
...
AddMovement(-playerCamera.transform.right);
and up/down movement (line 83)

Code: Select all

upDownVector += Vector3.up;
...
upDownVector += Vector3.down;
...
AddMovement(upDownVector, true);
there are many calls to AddMovement(direction) and there they are all added together (line 139)

Code: Select all

moveDirection += direction * moveSpeed;
which looks like the reason for the levitation speed bugs.
For the swimming bug the cause is probably (line 117 for swimming and line 132 for water-walking)

Code: Select all

direction.y = 0;
Here direction is a Vector3 coming from a playerCamera.transform that has a magnitude of 1.
Forefully setting direction.y to 0 like this can lead to a magnitude below 1, meaning that the x and z axis movement speed are still being impacted by the camera facing.
Possible fix:
All these bugs should be solvable by the same fix. And.. also, it would feel more modern if the diving depth (while swimming) could be controlled by the camera facing, so I tried to include that in the fix (or actually, y-axis movement from camera facing is no longer prevented). But this is of course a different behaviour from vanilla DF so I can understand if this wants to be kept in for legacy reasons.

Instead of using multiple AddMovement(direction) calls, the direction vectors could be added together first and then be normalized to set the magnitude back to 1, then only a single AddMovement(direction) call is needed, I think this kind of approach could work.

Code: Select all

direction = Vector3.zero
direction += ...;	//where ... are stuff like camera angle and up/down/right/left movement
direction.Normalize();  //is this how it's done? it should set the magnitude to 1
if (playerSwimming)
	{
	bool overEncumbered = ...;		//long expression, not copying
	if (overEncumbered && ...)		//long expression
		direction.y = -1;		//sinking, sideways movement not effected
	}
AddMovement(direction, true);
This was pretty tricky and maybe this kind of fix will just create new bugs, idk. Also, swimming near a water surface will likely create a lot of jerky pull-swimmer-back-down movement, which could get very annoying.
Comment:
I recently watched a youtube video by "What's a Creel" called "Branchless programming" on how to run code faster. It was too advanced for me, but it made me think more about processing speeds. I think that lifting out the "if (playerSwimming)" part like this could help the code go a little faster when not in water (and water is supposed to make the player slower anyway, isn't it?)



3) riding and jumping spells
Description:
The jump spell effect works while riding.
To reproduce:
Buy a horse, buy a jumping spell. Mount up and jump between rooftops.
Possible fix:
No fixing allowed, this is too much fun!



4) spell durations are 1 round too short
Description:
A self-targetting spell have durations reduced by 1 round.
duration 1 round (1+1per20L) lasts for 0-5 seconds, no UI spell icon shown
duration 2 rounds (2+1per20L) lasts for 0-5 seconds, UI icon is shown
duration 3 rounds (3+1per20L) lasts for 5-10 seconds, UI icon is shown
To reproduce:
The Light (candle) spell is nice for this, to avoid relying on the UI spell icon for visual ques.
Possible issue:
In EntityEffectManager.cs (line 2084) when a player casts a self-targetting spell it calls AssignBundle() which does this (line 583)

Code: Select all

effect.MagicRound();
This only seem to reduce the duration of the spell by 1 round, as far as I can see. When DoMagicRound() is called on the normal tick, it too will call .MagicRound(), which reduces the duration by 1 again. So during a spells first round its duration seems to be reduced by 2 steps.
Possible fix:
I guess that removing line 583 will fix this.



5) damage to an NPC's Fatigue does nothing
Description:
NPCs are not hindered by Fatigue damage. This is vanilla DF behavior (tested), but it has to be a bug.
To reproduce:
Make "Damage Fatigue", "Continuous Damage Fatigue" and "Transfer Fatigue" spells, then attack stuff.
Comment:
The biggest problem here is that "fixing" Damage Fatigue is likely to end up with a "paralyze" or "pacify" behaviour, and we already have these effects. When the players Fatigue reaches zero, it leads to death. Having it like that for NPC's would be a bad idea because the Fatigue pool is likely smaller than the Health pool for high level entities. Fatigue damage is great when used against a player, just not by the player.
There should be room for a "slowness" or "immobilize" effect in DF, that still allow the victim to attack. I was tempted to suggest that behaviour for "Damage Fatigue", but a spell called Sleep should not behave like that.
I feel like the Sleep spell (and Hand of Sleep) should have been designed with the "pacify humanoid" effect and the "damage fatigue" effect should simply not have been available to the player at all. But it is what it is.

Fatigue damage with "area at range" will not harm the player btw (this is a special case though, probably a sideeffect from the hack in DaggerFallEntityBehaviour.cs (line 112) for the mageguild-sleep-spell-quest).



6) exceeding the carry weight limit
Description:
When a Fortify Strength spell ends, being over the carry capacity has no consequence. This is the vanilla DF behaviour apparently (tested), but it must be a bug.
To reproduce:
A short duration spell that buffs strength, and some heavy stuff to pick up. Then run around.
Possible issue:
There is some code in EntityEffectManager.cs inside DoMagicRound() (line 1681) that seems to handle removing attribute changing effects. But there is no check to detect if this have any consequences.



7) re-cast button does not remember an aborted spell
Description:
In vanilla DF, when aborting a spell, it still remembers it as the last spell used. In DFU only a spell that was actually casted will be remembered. Personally I prefer the vanilla behaviour.
To reproduce:
Cast spell A. Ready spell B (a non-self-targetting spell). Abort B. Pressing the recast button casts spell A.
Possible fix:
EntityEffectManager.cs (line 265) handles aborting spells and looks like

Code: Select all

AbortReadySpell();
replacing it with this might fix it

Code: Select all

lastSpell = readySpell;
AbortReadySpell();


8) spell maker "per x Levels" cost quirk
Description:
The spell cost calculations has a super tiny flaw. There are two (afaik) spell effects that behave differently when "per x levels" is increased, these are "Fortify Attribute" and "Transfer". They have a gradual cost decrease when the x in "per x levels" increases, all the other effects behave like in DFU.

Code: Select all

			Fortify Attribute (magnitude cost 120)	Transfer (magnitude cost 100)
			+120 gold at per 1 levels		+100 gold at per 1 levels
			+60 gold at per 2 levels		+48 gold at per 2 levels
			+40 gold at per 3 levels		+32 gold at per 3 levels
			+28 gold at per 4 levels		+24 gold at per 4 levels
			+24 gold at per 5 levels		+20 gold at per 5 levels
			+20 gold at per 6 levels		+16 gold at per 6 levels
			+16 gold at per 7 levels		+12 gold at per 7 levels
			+12 gold at per 8 levels		+8 gold at per 9 levels
			+8 gold at per 11 levels		+4 gold at per 13 levels
			+4 gold at per 16 levels
Their durations show this gradual behaviour too, but I'm not showing that data here, the mechanics are the same anyway.
This is not about the gold though, the goldCost is used to calculate the SP required to cast the spell

Code: Select all

spellPointCostOut = goldCostOut * (110 - skillValue) / 400;  //FormulaHelper.cs (line 2167)
To reproduce:
Make a "Fortify Attribute" or "Transfer" spell in vanilla DF
Comment:
I have no idea why only these two effects are like this. Was it old code left behind, or new code being tested? There is however a precedent for using this and personally I think this have an appeal, especially when it comes to spell durations (long durations on levitation or slowfall tend to be very annoying so I always reduce them).

I don't quite understand the DFU source-code, but I think the relevant equation is in FormulaHelper.cs (line 2204)

Code: Select all

goldCost = trunc(costs.OffsetGold + costs.CostA * starting + costs.CostB * trunc(increase / perLevel));
It looks like removing the 2nd trunc() would provide the gradual behaviour to all durations, chances and magnitudes for all spells.



9) a potential negative-gold-cost bug for spells that can happen if a mod changes the cost values for a spell effect
Description:
Modding can change a spell effects cost values to negative numbers, which someone might use. The SP cost is always at least 5, so that part is not a problem. But the gold cost can go negative, which will then give the player gold for creating the spell (tested).
example: properties.DurationCosts = MakeEffectCosts(80, 120, -500);
To reproduce:
Make a mod that give a spell a negative cost value (what, you don't want to? pssh)
Possible fix:
FormulaHelper.cs (line 2053) is where the cost values for spell effects are added up

Code: Select all

totalGoldCostOut += goldCost;
using this instead

Code: Select all

totalGoldCostOut += MathF.Max(0,goldCost);    //MathF.Max wants floats, so this might not work, idk
should prevent a negative cost value from being added, and still allow the other cost values to function normally



Suggestions:

10a) easier modding of spell cost values
So many spell effects go unused because they underperform relative to their SP cost.
I have looked at moding them myself, every effect file seems to need an override, and the Pacify effect is really tricky due to its 4 subvariants that I just don't understand how to get at.
To make the modding of spell-effect-cost-values easier and maybe less prone to conflicts with other mods that fiddle with spell effects, would it be possible to move all spell-effect-cost-values to a single overridable list of numbers somewhere instead? It would be boring work, but I think this could really help modders make magic in DFU more varied.

10b) easier modding of spell level behaviour
The (x)+(y per level) spell mechanic is really poor and totally breaks down at higher player levels. While I think there is a merit to keep the vanilla DF behaviour intact, it would be nice if this math was easy to override with a mod (or is it already? I'm too unskilled to tell) so that a more balanced power curve can be used instead (like +1 spell-power-level on each 1,3,6,10,15,21,28 player levels as an example).



11) range "area around caster" is pretty small
"Spell range: Area around caster" feels too small to be worth using. Right now, it's has a kamikaze range that requires running into danger. Increasing its radius with the "Touch range" distance seems appropriate to me, it still won't be particularly useful.
If testing the "area around caster" range, be mindful of the regular savingThrow vs magic that can and will occur.



12) allow fractional values during spell cost calculations
Maybe calculating the cost of spells could use fractions so that a +0.5 cost is possible. This will prevent abuses like (1-2)+(1-2)perLevel for the same SP cost as (1-1)+(1-1)perLevel. I see no value in preserving that behaviour.
It has always irked me that the Fireball spell is ineffcient, instead of its 1-7 perLevel it could have used 1-8 or 2-7 for the same SP cost.
Last edited by npc on Sat Aug 08, 2020 3:14 pm, edited 1 time in total.

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

Re: 0.10.24 some magic related bugs

Post by Interkarma »

Hey there, welcome to the forums. :)

I value all the time and detail you've provided here. I don't normally engage with "shotgun" topics, as the conversation ends up winding unproductively around several different subjects and can't be discretely managed. However, I'll try to provide some feedback here on each item. If you're after creating a bug report specifically, please create one single topic per subject so the conversation can be focused and individually resolved later if it's determined to be a bug.

npc wrote: Fri Aug 07, 2020 1:40 pm 1) incomplete spell effect
Description:
The description of the spell effect "Elemental Resistance <element>" say "Target takes half damage if spell is unsuccessful." which doesn't seem to happen in DFU (not tested in vanilla DF).
Spell text descriptions are often misleading, as is information on UESP and elsewhere. The saving throw code was reverse engineered by Allofich and included no such logic to halve damage when Chance roll fails. I have great confidence Allofich would have implemented this if it was actually happening in classic.

If Elemental Resistance succeeds, the incoming effect is scrubbed. If it fails, the effect is handed off to native resistances and saving throw logic, which can partially or fully reduce damage/duration based on those mechanics.

2) levitation speed bugs
This is more of a refinement than a bug exactly. Happy to take this on board and review at a later date.

3) riding and jumping spells
Yep, we added horse jumping (not present in classic). You can levitate with a horse in classic and DFU, and it only seems fair to let jumping spell work too. No plans on changing this one.

4) spell durations are 1 round too short
This matches classic, only what's happening isn't immediately intuitive. Magic rounds are aligned precisely with game minutes and tick once every 5 seconds against the same clock. If you cast a 1-round spell at the exact start of a game minute, it will last the full 5 seconds. If you cast a 1-round spell with only moments remaining in magic round, that's all you get. To put it another way, the first magic round is always the game minute you're currently inside of and will end at the same time that game minute ends. The first round can be anywhere from practically 0 seconds to 5 seconds in duration. Best just to make spells with more than 1 round or recast quickly to stack rounds onto incumbent.

5) damage to an NPC's Fatigue does nothing
This matches classic. There's no defined behavior for fatigue loss on mobile NPCs and enemies entities. That would require open conversation to change and is best delivered by a mod at this stage.

6) exceeding the carry weight limit
This is intentional. We don't penalise player if they contrive to pick up too much stuff. Not being able to pick up anything further and having to manage inventory is enough.

7) re-cast button does not remember an aborted spell
I wasn't aware of this one. Happy to take it on board as a future refinement/fix if this is what happens in classic.

8) spell maker "per x Levels" cost quirk
All spell casting costs and gold cost outcomes match classic so far as I'm aware, and were matched at time of implementation. I'll take a look at this one later to see if costings are unintentionally divergent from classic for these effects.

9) a potential negative-gold-cost bug for spells that can happen if a mod changes the cost values for a spell effect
Well, mods can break all kinds of things. :) We clamp spellpoint costs, can't hurt to clamp gold costs also.


10a) easier modding of spell cost values
10b) easier modding of spell level behaviour
Effects can be overridden to change their behaviour entirely, including costs. I agree it would be nice for the spell effect costs formula to be overridable. There's some work required around this to unify with enchantment durability costs on equip for custom effects. I'll make a note to open this one to delegate override later.

11) range "area around caster" is pretty small
If this is testing smaller than classic, happy to increase radius.

12) allow fractional values during spell cost calculations
I have no plans to dramatically change the magic system from how it's implemented. Again, mods can override almost everything and deliver completely custom effects and novel payloads not found in classic.


Thank you for taking the time to post and providing so much detail. While many of these items aren't bugs or fall more into a modding/refiement category, I'll add your points around the other items into my internal queue and review later.

Cheers! :)

npc
Posts: 5
Joined: Fri Aug 07, 2020 12:12 pm

Re: 0.10.24 some magic related bugs

Post by npc »

4) spell durations are 1 round too short
This matches classic, only what's happening isn't immediately intuitive. Magic rounds are aligned precisely with game minutes and tick once every 5 seconds against the same clock. If you cast a 1-round spell at the exact start of a game minute, it will last the full 5 seconds. If you cast a 1-round spell with only moments remaining in magic round, that's all you get. To put it another way, the first magic round is always the game minute you're currently inside of and will end at the same time that game minute ends. The first round can be anywhere from practically 0 seconds to 5 seconds in duration. Best just to make spells with more than 1 round or recast quickly to stack rounds onto incumbent.
I still think there is a bug here. I made a new duration test, just to make sure.

Spell durations for the Light effect, comparing vanilla DF and DFU
Testing with a level 1 character in both games
Light (1+1per20L) - 2 in game minutes, 5-10 IRL seconds (DFU [0.10.24] - 1 in game minute, 0-5 IRL seconds)
Light (1+1per1L) - 3 in game minutes, 10-15 IRL seconds (DFU [0.10.24] - 1 in game minute, 0-5 IRL seconds)
Light (2+1per20L) - 3 in game minutes, 10-15 IRL seconds (DFU [0.10.24] - 1 in game minute, 0-5 IRL seconds)
Light (3+1per20L) - 4 in game minutes, 15-20 IRL seconds (DFU[0.10.24] - 2 in game minutes, 5-10 IRL seconds)

So I was wrong, there is a 2 round difference.

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

Re: 0.10.24 some magic related bugs

Post by Interkarma »

npc wrote: Fri Aug 07, 2020 5:23 pm I still think there is a bug here. I made a new duration test, just to make sure.
I've setup a similar test environment and agree with your conclusion. After a review, I've resolved three interrelated issues with spell expiration.
  1. In EntityEffect.SetDuration(), the floored duration per level multiplier must not be lower than one. Player can lose 1 round here depending on spell settings and level.
  2. In EntityEffectManager.DoMagicRound(), the spell is expired if it reaches 0 rounds remaining immediately after ticking magic round. This should only be happening on the subsequent tick, resulting in player losing 1 round here for all spells.
  3. HUDActiveSpells.ShowIcon() was expiring icon when rounds remaining == 0. This should be >= 0 or HUD icon is removed early in final round.
Testing again in classic vs. DFU now shows parity under the same conditions. Thanks for the spot. :)

User avatar
Hazelnut
Posts: 3016
Joined: Sat Aug 26, 2017 2:46 pm
Contact:

Re: 0.10.24 some magic related bugs

Post by Hazelnut »

Great to have people experienced with classic kicking the tires on DFU and spotting any material differences. Pretty wild first post there npc! :)

BTW if you want some weight penaties you could try using Roleplay & Realism mod that implements speed debuffs for carrying too much. It doesn't prevent having more than encumbrance but you will move like a snail.
See my mod code for examples of how to change various aspects of DFU: https://github.com/ajrb/dfunity-mods

npc
Posts: 5
Joined: Fri Aug 07, 2020 12:12 pm

Re: 0.10.24 some magic related bugs

Post by npc »

I have that mod already :) And I like it a lot.
I saw you give a debuff to SPD when a player is carrying heavy stuff, which is really fair. But it's a bit scary too because Climate&Calories give stat debuffs as well when the player is cold, and they stack. So carrying heavy stuff when cold is pretty dangerous. I turned off Encumberance for now, because I fear Climate&Calories will give me stat debuffs while swimming in dungeons (but I don't actually know if it does, I know it gives debuffs out of water so I just assumed it will give them when in water too). I'm also new to both mods so it's pretty likely I just made a rookie mistake.

User avatar
Ralzar
Posts: 2211
Joined: Mon Oct 07, 2019 4:11 pm
Location: Norway

Re: 0.10.24 some magic related bugs

Post by Ralzar »

Note that Climates&Calories has a specifix set of status text keeping you informed of how encumbered you are.
They generally work very well together, but then I usually don’t pick up a bunch of junk that weghs me down ;)

npc
Posts: 5
Joined: Fri Aug 07, 2020 12:12 pm

Re: 0.10.24 some magic related bugs

Post by npc »

I don't quite understand. I'm pretty sure Daggerfall is an inventory system with an RPG added ontop. Stuff is important! :D

npc
Posts: 5
Joined: Fri Aug 07, 2020 12:12 pm

Re: 0.10.24 some magic related bugs

Post by npc »

1) incomplete spell effect
Description:
The description of the spell effect "Elemental Resistance <element>" say "Target takes half damage if spell is unsuccessful." which doesn't seem to happen in DFU (not tested in vanilla DF).
I had to test this in classic DF just to make sure.

I used a downloadable save file, Tlalac Boram, a level 24 redguard. So I wouldn't have to level up by myself. He has "spell absorption in darkness", but this is fine, since it either works or it doesn't, it wont reduce the damage.

Then I ran off and found myself a Fire Daedra. I think they are level 16, or near that (they got 16d8+10 hitpoints). So a Fireball can be expected to hit for (7x16+1) 113 and Fire Storm for (5x16+20) 100, or close to that.

While using a Elemental Resistance Fire spell (magic items not tested), the first fire spell that hit me dealt 106 pts of damage. Which proved immediately that the spell description is indeed wrong. Another test gave me 120 pts of damage (so they are at least level 17 then, doesn't matter).

Result: Elemental Resistance does NOT cut the damage in half in classic DF. Just like you said. The description is wrong.

User avatar
billyloist
Posts: 48
Joined: Thu Jul 30, 2020 2:07 am

Re: 0.10.24 some magic related bugs

Post by billyloist »

Speaking of magic bugs, I noticed one fun bug that I don't really want to see fixed, but just to point it out. Not sure if this is a well-known quirk already.
During the spell creation, normally many harmful spell effects cannot be set with the target as you, so spells like self-disintegration or self-drain attribute aren't really possible. However, if those effects are combined with Slowfall, it automatically locks the target on you and it's not even possible to change. Thus, you can make any magic effect affect yourself.
There are some fun applications for it, like for example draining your strength to hit weaker and that way you can hit the enemies many more times before they die, so you can train your combat skills a bit more effectively. And combining that with powerful regeneration on touch, you have perfect training dummies!

Post Reply