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);
Code: Select all
if (target.HasResistanceFlag(elementType) && percentDamageOrDuration > 50)
percentDamageOrDuration = 50;
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);
Code: Select all
AddMovement(playerCamera.transform.right);
...
AddMovement(-playerCamera.transform.right);
Code: Select all
upDownVector += Vector3.up;
...
upDownVector += Vector3.down;
...
AddMovement(upDownVector, true);
Code: Select all
moveDirection += direction * moveSpeed;
For the swimming bug the cause is probably (line 117 for swimming and line 132 for water-walking)
Code: Select all
direction.y = 0;
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);
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();
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();
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
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)
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));
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;
Code: Select all
totalGoldCostOut += MathF.Max(0,goldCost); //MathF.Max wants floats, so this might not work, idk
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.