This guide goes over how I created these Dungeons and Dragons-inspired spells, incantation and abilities using modding tools, as well as some of the design choices behind them. Hopefully the information I share here will be helpful for those interested in creating their own custom spells.
Tools and Resources I Used
General Tools:
- DSMapStudio: Database and text editing. Probably the tool you'll be using the most
- UXM Selective Unpacker: Unpacks all Elden Ring data files.
- WitchyBND: Packs and unpacks the archival files that were unpacked by the UXM Selective Unpacker.
- Elden Ring HKS Repository: HavokScript files
- ?ServerName? Discord Channel: Discord Channel for modding FromSoftware games
Particle/FXR Editing:
- FXR IDs: A list of all particles effects in Elden Ring, along with some descriptions
- Node.js: Javascript runtime environment
- FXR Playground: Online tool to edit FXRs
- CCCode/EvenTorset's FXR Javascript Library: Javascript library that will be used to edit FXRs (mainly recoloring)
I also recommend watching Rusty's The Definitive Guide to Elden Ring Bullet Editing before continuing this guide.
Parameters and Fields
I edited the following parameters for this mod:
- AtkParam_PC: Governs hitboxes and their damages.
- Bullet: Governs motion and size of projectiles. References AtkParam_PC for damage and can reference spEffects.
- EquipParamGoods: For this mod, I used this to edit an item's icon. Usually, you would edit this parameter if you're editing consumables.
- EquipParamWeapon: Defines weapon damage and any spEffects they apply.
- Magic: Defines the bullets or spEffects that incantations and sorceries generate. Also defines FP, stamina and stat requirements to cast them
- SpEffectParam: Defines the various effects that apply on player. Mostly focused on auxiliary effects such as buffs, debuffs and status effects. Usually referenced by bullets, but it can also be referenced by AtkParams.
Of these, the parameters I edited the most were AtkParam_PC, Bullet and SpEffectParam.
When it comes to bullet editing, the one field I want to highlight is Damage Hit Duration (dmgHitRecordLifeTime). According to DSMapStudio's own description, Damage Hit Duration is the "Damage hit history survival time," which honestly doesn't tell us much. Another definition, from the Souls Modding wiki, defines dmgHitRecordLifeTime as the "frequency (in seconds) that (penetrating) bullets can apply damage or special effects." In other words, Damage Hit Duration defines the tick rate for features such as status effect buildup or damage over time. For example, Poison Mist builds up poison at a rate of 20 poison per 0.2 seconds, thanks to the incantation's bullets (10722000 and 10722001) both having dmgHitRecordLifeTime values of 0.2. The delay between a bullet activating and the bullet's spEffect activating is also equivalent to the Damage Hit Duration. If you set Damage Hit Duration to 2 seconds, you will have to wait 2 seconds between the bullet appearing and the spEffect activating.
In spEffect, two fields I want to highlight are Duration (effectEndurance) and Trigger Interval (motionInterval). Duration defines how long the spEffect lasts, while Trigger Interval defines how often (in seconds) the spEffect is reapplied. spEffects also determines the status buildup per tick, though not the tick rate itself (remember, tick rate is determined in a bullet's Damage Hit Duration field).
Let's take the Rot Pot's spEffect (1703000) for example. That spEffect's duration is 90 seconds, while the Trigger Interval is 1 second. Therefore, when Scarlet Rot is proc'd, the Rot Pot spEffect will, for 90 seconds, deal 0.18% Max HP + 15 damage per second (see fields changeHpRate and changeHpPoint for those damage values). While Scarlet Rot is active, Scarlet Rot cannot build up for 90 seconds and will take 90 for the Scarlet Rot meter to drain. Freezing Pot's spEffect (500360), on the other hand, has a Duration of 30 seconds and a Trigger Interval of 99 seconds. Therefore, when frostbite is proc'd, Freezing Pot's spEffect will, for 30 seconds, increase damage absorption, but also only deal 10% Max HP + 30 damage once per proc. While frostbite is active, frostbite cannot build up for 30 seconds, and it will take that same time for the frostbite meter to drain. The 99 second Trigger Interval is there to prevent the damage stuff from triggering more than once per proc.
Translating D&D Damages to Elden Ring
Some Dungeons and Dragons damages, such as fire and lightning, have obvious counterparts in Elden Ring. Other damages, such as Necrotic, do not. Furthermore, certain concepts such as Poison don't translate neatly between the two, as Poison is a damage type in DnD, while Poison is merely a status effect in Elden Ring. This being Elden Ring, I decided to make DnD damages such as Cold and Poison behave more like status effects. In other words, if a DnD spell dealt Poison damage, I made it's Elden Ring counterpart build up poison instead. Overall, the DnD damage to Elden Ring conversion was as follows:
- Bludgeoning: Strike
- Piercing: Thrust
- Slashing: Slash
- Cold: Frostbite buildup
- Fire: Fire
- Lightning: Lightning
- Thunder: Standard
- Acid: Deadly poison buildup
- Poison: Poison buildup
- Radiant: Holy
- Necrotic: Scarlet Rot buildup
- Force: Magic
- Psychic: Magic
The idea to link necrotic damage to Scarlet Rot buildup was taken from Geoho6's Elden Ring Incantation to 5e conversion project. How a status effect built up depended how their DnD equivalent worked. If their DnD counterpart dealt damage at the start of a turn, then players and enemies would receive a buildup equivalent to being instantly hit with a status pot. If their DnD counterpart dealt damage at the end of a turn, then players and enemies would receive a buildup amount equivalent to a status pot, but spread out over 6 seconds. For example, if a DnD spell dealt Necrotic damage at the start of a turn, then affected entities would instantly receive 300 Scarlet Rot build up (the same amount as a Rot Pot) as soon as they touch the spell. If said DnD spell dealt Necrotic damage at the end of a turn, then affected entities would instead receive 50 Scarlet Rot build up every second. Remember status build up stops once said status triggers e.g. you can't build up Scarlet Rot when Scarlet Rot is triggered, but you can still build up other status effects.
Some DnD spells also modify Armor Class. Thus, when it came to porting AC modifications from DnD into Elden Ring, I used the following scenario as a reference:
- Defender AC: 11
- Attacker's attack roll bonus: +6
With 11 AC, an attacker with a +6 bonus will have an 80% chance of hitting the defender. With advantage, the attacker has a 96% chance of hitting (20% increase), while with disadvantage, the attacker will have a 64% chance of hitting (20% decrease). The reason for choosing 20% in particular is that in Elden Ring, frostbitten enemies take 20% more damage.
Concentration Mechanic
In Dungeons & Dragons, certain spells require concentration for them to remain active. A player can lose concentration if they cast another spell that requires concentration.
In Elden Ring, a similar mechanic exists with the whole body/aura/weapon buff mechanic, in that players are not allowed to use more than one buff from same buff category. What category a buff belongs to is defined in spEffectParam, specifically the spCategory field. spEffects with spCategory 151 are body buffs, 160 are aura buffs, 162 are right-handed weapon buffs and 163 are left-handed weapon buffs.
Bullets can also be limited based on what group they belong. What group a bullet belongs to are defined by the Create Limit Group ID (createLimitGroupId) field. The BulletCreateLimitParam table defines how many bullets from a group can exist at once. For all the concentration spells in this mod (Hunger of Hadar, Spirit Guardians, Haste, Cloud of Daggers), I set their group IDs to 20, an unused bullet group that limits the number of bullets from said group to 1.
Glintstone Missiles (Magic Missiles)
Modifying Glintstone Stars so that it looks more like Magic Missiles involved changing the color the the Glintstone projectiles from blue to red. Instead of recoloring the existing Glintstone Star FXR particles, though, I decided to instead mod the particles from the Golden Land skill (440623 and 440624, the former being the projectile particle, the latter being the impact particle).
Before editing the FXR files, I installed Node.js. Then I installed CCCode/EvenTorset's FXR Javascript library and unpacked sfxbnd_commoneffects.ffxbnd.dcx with WitchyBND. Then I went inside the sfxbnd_commoneffects\effect folder and copy and pasted f000440623.fxr and f00044064.fxr inside the Node.js folder. Afterwards, I created the following Javascript code inside the Node.js folder:
import fs from 'node:fs/promises'
import { FXR, Game } from '@cccode/fxr'
// Parse file, make sure to set the right game. For SFX 440624, use f000440624.fxr.
const fxr = FXR.read(await fs.readFile('f000440623.fxr'), Game.EldenRing)
const targetColor = [1, 0.45, 0.44]
fxr.root.recolor(([r, g, b, a]) => {
// Colors in FXRs are allowed to go above 1, and it usually just adds a bloom
// effect to the particles. We need to scale it back down to the 0-1 range
// for these calculations, and then scale it back to what it was after.
const scale = Math.max(r, g, b, 1)
r /= scale
g /= scale
b /= scale
// Calculate HSV value and saturation
const min = Math.min(r, g, b)
const max = Math.max(r, g, b)
let s = max > 0 ? (max - min) / max : 0
// Linear interpolation between the HSV "value" (max) and the target color
// based on the saturation of the original color.
r = max * (1 - s) + targetColor[0] * s
g = max * (1 - s) + targetColor[1] * s
b = max * (1 - s) + targetColor[2] * s
// Scale the values to match the original brightness of the effect.
r *= scale
g *= scale
b *= scale
// Return the modified color with the original alpha.
return [r, g, b, a]
})
const output = fxr.toArrayBuffer(Game.EldenRing)
await fs.writeFile('f000440623_edit.fxr', Buffer.from(fxr.toArrayBuffer(Game.EldenRing)))
After creating the Javascript file (named fxr_recolor.js), I created the following batch file (you can't simply drag the Javascript file on top of node.exe):
node fxr_recolor.js
pause
Running the batch file created a new file named f000440623_edit.fxr. I then deleted the original .FXR file, removed the _edit suffix from the new .FXR file name and copy and pasted the new .FXR file inside the sfxbnd_commoneffects\effect folder, overriding the original f000440623.fxr file in the process. Then I recreated sfxbnd_commoneffects.ffxbnd.dcx by packing the sfxbnd_commoneffects with WitchtyBND. It takes a long time to repack sfxbnd_commoneffects.ffxbnd.dcx. Thus, during the testing stage, I went inside the _witchy-ffxbnd.xml file WitchBND generated while unpacking the .DCX file and changed the compression from DCX_KRAK to DCX_DFLT_11000_44_9_15. Using DCX_DFLT_11000_44_9_15 increases the .DCX file size in exchange for a faster packing time, so be sure to change back to DCX_KRAK when you're ready to upload your mod.
Glintstone Stars bullets come in 2 general stages. The first stage, corresponding to bullets 10404000, 10404001 and 10404002 uncharged (10404050, 10404051 and 10404052 charged) is the bullet emitter stage. The next stage, corresponding to bullets 10404003 through 10404011 uncharged (10404053 through 10404061 charged), correspond to the projectile stages. Glinstone Stars are already pretty accurate, but I still tried increasing their accuracy, as Magic Missiles never miss. To do that, I went to the projectile bullets and set the homing angles (homingAngle) to be at least 180. I'm honestly not 100% sure how the homingAngle property works, so finding the right values involved a lot of guessing and checking. Thankfully, it is possible to hot load parameters with DSMapStudio by going to Game -> Hot Reload Params -> All Params, so guessing and checking was pretty quick.
Fervor of Fia (Hunger of Hadar)
Hunger of Hadar deals cold damage to entities caught inside at the start of the term and acid damage to entities caught inside at the end of the turn. Thus, when recreating the spell in Elden Ring, I made Fervor of Fia deal 380 frost buildup instantly, but only 42 deadly poison buildup per second to entities inside the cloud (Fetid Pots deal 250 deadly poison buildup, so 250/6 ~ 42).
The bullets for Fia's Mist, the spell Fervor of Fia is replacing, already reference an existing SpEffectParam (1502000). Of course, Fervor of Fia deal two status effects, not one, so I had to create a second SpEffect (1502001). I made 1502001 be the frost buildup spEffect, with values copied from the Freezing Pot spEffect, while 1502000 was made to be the deadly poison spEffect, with values copied from the Fetid Pot spEffect. As mentioned earlier, I wanted the deadly poison buildup to be gradual. Thus, the value for Aux Inflict +: Poison (poizonAttackPower) was set to 42 instead of 250.

Note that 10502000 is the projectile bullet and not the cloud bullet (10502001). Also, the cloud bullet has a Damage Hit Duration of 0.1 seconds, which I had mistakenly set. Given that, as I said before, the buildup interval is 1 second, it seems as though the parent bullet's Damage Hit Duration overrides those of its successors. It should also be noted that both 10502000 and 10502001 reference the same spEffect entries. I don't why I had to do this, but if I didn't (e.g. having spEffect references in 10502001 but not 10502000), then none of the spEffects triggered.
Hunger of Hadar also slows entities by 50%. You will need to edit a couple HavokScript files, specifically c0000.hks (player) and c9997.hks (enemies), so that they change player speeds depending on the SpEffect active. I first created a new spEffectParam (ID 1502002) named "50% Speed," with duration and trigger intervals of 1 second. Then I opened c0000.hks and pasted the following block of code:
if env(GetSpEffectID, 1502002) == TRUE then
act(SetMovementScaleMult, 0.5) -- Slows player movement by 50%
end
inside the following functions:
- Rolling_onUpdate()
- Rolling_Selftrans_onUpdate()
- DefaultBackStep_onUpdate()
- Move_onUpdate()
- AttackRightBackstep_onUpdate()
- AttackDualBackStep_onUpdate()
- AttackBothBackstep_onUpdate()
- Act_Jump()
c9997.hks is a bit simpler. In that file, I created the following block of code (h/t Vawser):
function SlowEnemies() -- Fia's Mist SpEffect slowing down 50%
if env(GetSpEffectID, 1502002) == TRUE then
act(SetMovementScaleMult, 0.5)
end
end
Then I typed "SlowEnemies()" inside the Update() function. Thus, the Update() function looked like the following:
function Update()
g_FrameCount = g_FrameCount + 1
act(Unknown9999)
if env(GetSpEffectID, 5980) == TRUE then
act(Unknown2027)
end
if env(IsSpeaking) == TRUE and GetVariable("LipSyncBlend00") <= 0 then
SetVariable("LipSyncBlend00", 0.10000000149011612)
SetVariable("IndexLipSync", GetNextIndexLipSync(ANIME_ID_GENERAL_LIP_SYNC, 0, 9, 1, 0, "IndexLipSync", false))
Fire("W_LipSync")
end
if env(IsSpeaking) == TRUE and GetVariable("TalkHeadBlend00") <= 0 and TRUE == IsExistAnime(ANIME_ID_TALK_HEAD_BLEND) then
SetVariable("TalkHeadBlend00", 0.10000000149011612)
Fire("W_TalkHeadBlend00")
end
SoulDropUp()
GolemConfusion()
ParryResist()
SlowEnemies() --New line
end
As a side note, the player's speed is about 1.20 m/s walking, 3.20 m/s jogging and 4.81 m/s running. This is obtained by eyeballing the walking/joggning/running animations in DSAnimStudio. The animation IDs for walking, jogging and running are 20000, 20100 and 20200 respectively.
Eldritch Burst (Eldritch Blast)
Replacing Frenzied Burst with Eldritch Burst (Eldritch Blast) seemed obvious due to how similar in concept they both were. The difference though was that Frenzied Burst fired only 1 projectile, while Eldritch Blast can fire up to 3 projectiles. Thus, to make Frenzied Burst fire multiple projectiles, I had to transform the Frenzied Burst bullet from a projectile into an emitter.
First, I created two new bullets: Frenzied Burst 2 (10732001) and Frenzied Burst residue (10732002). Frenzied Burst 2 was the new projectile, the bullet that would be doing damage. I copied most of the fields from the original Frenzied Burst bullet into Frenzied Burst 2. Returning to the original Frenzied Burst bullet (10732000), I set the bullet emitter ID to Frenzied Burst 2, and set both the minimum and maximum shooter intervals (intervalCreateTimeMin and intervalCreateTimeMax respectively) to 0.2 seconds. To make sure the emitter stayed in front the player's face, all the velocity fields (Initial Velocity, Max Velocity, Min Velocity) were set to 0. The original Frenzied Burst bullet already had a duration of 0.5 seconds. Thus, with this interval and duration, the emitter fired two (2) Frenzied Burst 2 bullets. For the charged version (10732050), I wanted Eldritch Burst to fire three projectiles. Thus, while I mostly copied over 10732000's fields, I also set the duration for the charged version's bullet to 0.7 seconds.
As its name implies, the Frenzied Burst residue bullet (10732002) is the black residue left over from the Eldritch Burst attack. Using the FXR ID table I linked to earlier, I decided to use the black smoke the appears when a Cemetery Shade teleports (FXR ID 636681). To make the residue appear, I set the Hit Bullet ID (HitBulletID) field inside Frenzied Burst 2 to reference the residue. Then, inside the residue bullet, I set the Projectile SFX to be 636681.
Eldritch Blast deals force (aka magic) damage and has no drawbacks, so having madness buildup and fire damage wouldn't have been accurate. To remove madness, I removed all the spEffect entries from the original Frenzied Burst bullets. To get the repelling blast effect, I changed the AtkParam_PC damage level to 7 (Stagger to Floor). Staying inside AtkParam_PC, I also tried increasing the Knockback Distance from 0.7 to 4.5. However, it seems like Knockback Distance only applies when hitting enemies who are guarding/holding their shields up. For non-guarding enemies, it feels like the pushing distance is only affected by damage level type.
Radiant/Necrotic Spirits (Spirit Guardians)
Radiant Spirits (replaces urgent heal) and Necrotic Spirits (replaces Cure Poison) were based off of the Radiant and Necrotic versions of the Spirit Guardian spell, respectively. Being concentration spells, I set their bullet group IDs to 20. To make the Radiant/Necrotic Spirit bullets follow the player at around chest height, I set the Follow Type (FollowType) to 5. As mentioned earlier, spells whose DnD equivalent dealt necrotic damage will cause Scarlet Rot buildup in Elden Ring.
Necrotic Spirits replaced Cure Poison. To make it a status effect spell, I unchecked Self Target to its AtkParam_PC entry (64400) and Trigger For Self in its spEffect (1644000). Spirit Guardians deals damage at the start of a turn, so, for Necrotic Spirits, I had the spell deal 300 Scarlet Rot in its spEffectParam. With the Necrotic Spirits/Cure Poison bullet having a Damage Hit Duration of 0.5 seconds, this meant this 300 Scarlet Rot would essentially be applied instantly. Overall, the Cure Poison spEffect was modified as follows:

Because enemies move slower inside the Spirit Guardians aura, I had the Necrotic/Radiant Spirit bullets reference the 50% speed spEffect (1502002) that I had created earlier for Fervor of Fia. Finally, I changed the Necrotic Spirit's Projectile SFX to an unused FXR (4890), replacing that FXR with a recolored Divine Fortification particle. The Javascript code for the recolored Divine Fortification was as follows (also needed f000004742.fxr to be inside the Node.js folder):
import fs from 'node:fs/promises'
import { FXR, Game, State, } from '@cccode/fxr'
const fxr = FXR.read(await fs.readFile('f000004742.fxr'), Game.EldenRing)
const targetColor = [0.64, 1.00, 0.89]
fxr.root.recolor(([r, g, b, a]) => {
const scale = Math.max(r, g, b, 1)
r /= scale
g /= scale
b /= scale
const min = Math.min(r, g, b)
const max = Math.max(r, g, b)
let s = max > 0 ? (max - min) / max : 0
r = max * (1 - s) + targetColor[0] * s
g = max * (1 - s) + targetColor[1] * s
b = max * (1 - s) + targetColor[2] * s
r *= scale
g *= scale
b *= scale
return [r, g, b, a]
})
await fs.writeFile('f000004890_edit.fxr', Buffer.from(fxr.toArrayBuffer(Game.EldenRing)))
Finally, I wanted Radiant Spirit's incantation icon to complement Necrotic Spirits/Cure Poison's icon. In turn, I went to Urgent Heal's EquipParamGoods entry and changed the Icon ID to 6709 (Lightning Fortification).
Assassin's Haste (Haste)
As mentioned earlier, buffs and debuffs are based on a scenario where an attacker with a +6 attack roll attacks a defender with 11 AC. Haste gives targets +2 AC. With a +6 attack roll, the chance of landing a hit on a 13 AC defender drops from 80% to 70%. Thus, when translated to Elden Ring, players take 12.5% less damage when (Assassin) Hastened.
Haste also give targets an additional action on each turn. One way to translate this into real-time would be to increase the attack speed. Unfortunately, I'm not sure how to do that or if it's even possible through HavokScript editing. An alternative would be to increase the stamina recovery rate. To determine how much this recovery should be, I used the attack chain of a Greatsword as a reference.
A Greatsword two-handed R1 attack chain has three attacks that take a total of 4.33 seconds (130 frames) to complete, using 81 stamina in the process. At 81 stamina, the recovery time at 45 stamina/second is 1.80 seconds, which means that the total time for get three Greatsword swings in and to fully recover the stamina is 6.13 seconds. Thus, if one wanted to get in 4 swings, instead of 3 swings, over that 6.13 seconds, the time to recover 81 stamina should be reduced to 0.70 seconds, which in turn meant a 115.7 stamina/second recovery time.
This spell modified two existing Assasin's Approach spEffectParams: 1651000 and 1651002 (Assassin's Haste Buffs). 1651000 was initiated by the Assassin's Haste bullet, while 1651002 was turned into the cycle spEffect for 1651000. In other words, as long as 1651000 was active, the buffs inside 1651002 would be triggered.
When cancelled, whether naturally after 60 seconds or by casting another group 20 bullet, the player will enter paralysis, a reference to how targets become lethargic when Haste ends. In this mod, though, you might notice a 4 second delay between when the Haste ends and when paralysis starts. This is because for some reason, actions with invincibility frames such as dodges, backstabs and ripostes will interrupt the spEffect if the spEffect's duration is shorter than said action. In most spEffect cases, this isn't an issue. For the case of Assassin's Haste, though, this means players could experience paralysis after doing something as simple as dodging if the duration is set too low. Checking the Apply through No Damage (isIgnoreNoDamage) option also doesn't seem to solve this issue despite its name implying it could. The only workaround I found was setting 1651000 to be 4 seconds long, which, with the exception of a few riposte animations, is longer than most iFrame actions.
Finally, I had Assassin's Haste increase movement speed by 50%, which meant creating a new spEffectParam (1502003) and having it be referenced in the Assassin's Haste bullet. Once again, I edited c0000.hks to apply the speed boost effect when 1502003 is active.
Blessing's Boom (Glyph of Warding)
Blessing's Boom, loosely inspired by the Glyph of Warding, is an incantation that replaces Blessing's Boon. There are three bullets. The first bullet (10643000) is the casting bullet. It's mainly a visual bullet that shows the casting particles, but it also generates a second bullet (10643001) on the ground when it expires after 0.1 seconds. 10643000 stays where it was cast, thanks to its 0 velocity. Because 10643000 was an existing bullet already used by Blessing's Boon, the only modification I made was to uncheck Is Hit Both Teams (isHitBothTeam), to prevent self-detonation, and set the AtkParam ID to a dummy, non-damaging AtkParam.
The second bullet (10643001) is the landmine itself, a static 6-meter wide bullet that will detonate when an enemy walks inside. When an enemy walks inside, 10643001 will then generate bullet 10643002, the explosion bullet. To make 10643001 actually detonate upon enemy contact, I unchecked Is Penetrate Character (isPenetrateChr) while keeping Is Penetrate Object (isPenetrateObj) and Is Penetrate Map (isPenetrateMap) checked. Keeping isPenetrateObj object unchecked prevents objects from detonating the bullet, while unchecking isPenetrateMap prevents the ground from detonating the bullet (in contrast, all three "Is Penetrate.." fields were checked for 10643000). No spEffects were needed for this to work. So, for all three bullets, I blanked the Target SpEffect ID fields. I also set Damage Hit Duration for 10643001 and 10643002 to 0.01 seconds, because Damage Hit Duration field seemed to affect the explosion delay.
Both 10643001 and 10643002 references AtkParam_PC 64300, which I had modified to not be triggered by the player and to deal damage to enemies. More specifically, I changed the damage values for that AtkParam, unchecked the Self Target (selfTarget) option and checked the Oppose Target (opposeTarget) and Friendly Target (friendlyTarget) options.

Blessing of Melina
There isn't any official DnD spell that works like Melina's healing tree incantation (though one exists in this this homebrew expansion).
To transform the Blessing of the Erdtree incantation into Melina's incantation, I went to that incantation's AtkParam_PC and checked the Self Target row. Then I went to the incantation's first bullet (10643100), changed the spEffect from the default value to -1 and Damage Hit Duration from 9999 to 1. Within the second bullet (10643100), I removed the Blessing of the Erdtree spEffect (1643101), leaving only the Blessing of the Erdtree - HP Regen spEffect (475). I also copied over the values from the Melina's healing incantation bullet (2180506) onto 1643101. For spEffect 475, I copied the values from the spEffect of Melina's healing incantation.
Dagger Storm (Cloud of Daggers)
Dagger Storm replaces the Thunderbolt Ash of War and consists of three bullets. The first bullet (2080) launches the project, and was also edited to reference a non-damaging AtkParam_PC (301600841). When 2080 expires, a second bullet (2081) was generated. Bullet 2081, with a Launch Elevation Angle of -90, launches directly down into the ground. With Is Penetrate Map unchecked, 2081 generates the third bullet (2082) when it hits the ground. Bullet 2082 is the spinning vortex itself, dealing damage to anyone, including the player, that enters. Note bullet 2082 also references an spEffect that doesn't do anything, an oversight on my part.
Dagger Storm contains a modified Zamor Ice Storm whirlwind particle (FXR ID 523878), shrunk to fit bullet 2082's 2 meter radius. The following Javascript code was used to shrink the FXR:
import fs from 'node:fs/promises'
import { FXR, Game } from '@cccode/fxr'
const fxr = FXR.read(await fs.readFile('f000523878.fxr'), Game.EldenRing)
// Scale the effect by some factor
fxr.root.scale(0.75)
//300380 is an unused FXR
await fs.writeFile('f000300380_edit.fxr', Buffer.from(fxr.toArrayBuffer(Game.EldenRing)))
As noted in the comments, 300380 is an unused VFX, hence the reason for naming the new file f000300380.fxr.
Sun-and-Flame Stance (Sunbeam)
Sun-and-Flame Stance replaces the Comet Azur portion of the Night-and-Flame Stance Ash of War with a beam of holy damage. Recoloring Comet Azur involved recoloring a bunch of FXR files (450470, 526250, 526251, 526252, 526253, 526254 and 526255). Additionally, to edit out all the purple nebula textures, I had to decompile the FXR files with WitchyBND and edit their .XML files. More specifically, I replaced all instance of "34050" (which corresponds to s34050_a.tpf, the purple nebula's texture file) with "34030", a black-and-white texture also used in Comet Azur. After that, I converted the .XML file back to a .FXR file using WitchyBND.
By default, the Sun-and-Flame beam applies Elden Ring's Darkness effect on enemies. If you're familiar with D&D, though, you know that Sunbeam's blinding effect doesn't deaggro affected entities, but instead debuffs them, forcing said entities to attack at an disadvantage and having their opponents attack them with an advantage. To create this more DnD-accurate blindness effect, I created two new spEffects (1653004 and 1653005) by copying the two original Darkness spEffects (1653000 and 1653001 respectively). For 1653004, the only thing changed from 1653000 was setting Chain SpEffect ID (replaceSpEffectId) to 1653005.
For 1653005, the things I changed from 1653001 were Duration (increased from 1 to 60), Delete Criteria Damage (deleteCriteriaDamage) (changed from 1 to 0) and State Info (stateInfo) (changed from 267 to 0). If Delete Criteria Damage was set to 1, then the spEffect would've ended early upon hit. Setting State Info to 267 (AI Eye Angle) caused enemies to deaggro. 1653005 also contained all the enemy debuffs (deal 20% less damage, take 20% more damage for 60 seconds).
To enable DnD-style blindness with Sun-and-Flame stance, go to bullets 2216, 2217 and 2218 and changed the spEffect values from 1653000 to 1653004.
Spectral Rejection
Spectral Rejections was inspired by the Zephyr Connection passive feature in Baldur's Gate 3. In other words, the Spectral Lance Ash of War was modified to explode on impact, causing area of effect damage. To get the area of effect damage, I changed the Hit Bullet ID for Spectral Lance's bullet (2930) from -1 to the Rejection bullet (10640050). As a personal preference, I also removed Spectral Lance's impact SFX (440782), a white, smokey particle. Finally, I added physical damage to Spectral Lance's AtkParam_PC entry (64005)
Needle Azur
Needle Azur deals extra damage against enemies below 50% health. This feature was inspired by the Prey Upon the Weak feature in Baldur's Gate 3. To create this effect, I first created a new SpEffect that I named "Low HP Bonus Damage" (ID 20406). Inside 20406, I set Duration to 0.5, Trigger Interval to 1.0 and Trigger at HP Below % (conditionHp) field to 50. If motion interval is set too low, then the spEffect will trigger multiple times upon crossing the 50% HP threshold, dealing extra damage (h/t MyMaidisKitchenAid on the ?ServerName? Discord channel for pointing this out).
For damages, I set Current HP % (changeHpRate) to 10 and Current HP + (changeHpPoint) to 50. Under the "Trigger for..." fields, I made sure only Trigger for Opponent (effectTargetOpposeTarget) was checked. I also set State Info (stateInfo) to 48 (Increase Damage), thought that probably was not necessary (the extra damage effect also worked when stateInfo was set to 0).
2 comments