Custom Skills

Custom Skills adds new player skills without code. One <Skill> row holds everything: the Skill.txt-style numbers, what the server does on cast (single target, area, cone, line, buff, heal), the item that teaches it, and the client look (cast animation, sounds, icon, tooltip text and visual layers).

The server adds each skill to its skill table, like a Skill.txt row, and sends the rest to the client at login (and to everyone online after /reload plugins) through Game Data Sync. No client or server rebuild: visuals are built from layers and a catalog of vanilla effects, and you can add your own textures, sounds and models as plain files in the client Data folder. The icon is client art too; a missing icon shows as a coloured tile with the skill's initials.

File Location#

Data/Plugins/Characters/CustomSkills.xml

Missing file = no custom skills. The file is read after Skill.txt at GameServer start.

Dependencies#

Depends OnPurpose
Skill.txtSkill ids used there cannot be reused. ReqWeapon / ReqAmmo use the same bitmask
Item.xmlThe learn item must exist (Slot="-1", class columns)
CustomItemVisual.xmlModel for a new learn item
CustomCombo.xmlAttack skills must be listed under <SecondarySkills> to combo
SkillTweaks.xmlA Mounted override there wins over the one here
Effect.xmlNumeric effect ids for <OnHit> and <Buff>
Game Data SyncShips the skill table to the client (type 38)

Reloading#

  • /reload plugins (or GameServer menu Reload → Plugins, or Server Manager) re-reads the file. Players already online receive the new skill table within a few seconds (20 players per second) - no relog. New sounds, textures and models load on their client right then.
  • /reload skill re-reads Skill.txt and this file and also pushes the new table to online players.
  • A <Skill> removed from the file is removed from the server skill table on reload. Removing every skill (or Enabled="0") sends an empty table, so clients drop the old visuals.

Testing a Skill (GM)#

CommandEffect
/cskill listLists the loaded custom skills (id + name)
/cskill learn <id>Adds the skill to your skill list - no learn item needed. Class / evolution rules still apply
/cskill forget <id>Removes it again

Needs a GameMaster.xml entry (level 1 or higher). Typical loop: edit the XML, /reload plugins, cast the skill, repeat.

Errors#

  • Server: every problem in the XML is logged with the skill id, the layer number (counted from the top of <Fx>, starting at 1) and what is wrong, for example Error: skill 282 layer 4 Texture="..\x.jpg": path may not contain ".." - ignored. Errors show in red in the GameServer window and the Server Manager log.
  • Client: effect names, texture / sound / model names and files are checked by the client when the table arrives. A missing file or an unknown name is skipped (never a crash), logged to the debug console, and the count + first problem show once in the chat: 2 custom skill problem(s) - first: [CustomSkill] skill 281: Texture file 'Data\Effect\X\glow.OZJ' not found. Players with an outdated client see the same line.

Structure#

<CustomSkills Enabled="1">
  <Skill Id="273" Name="Meteor Storm" Damage="110" Mana="105" AG="20" Range="6" DarkWizard="2" ...>
    <Learn Item="15,39"/>
    <Behaviour Type="AreaSelf" Radius="4" MaxTargets="10" Hits="3" HitDelay="440" HitInterval="220"/>
    <OnHit Effect="stun" Duration="2" Chance="30"/>
    <Cast Anim="gigantic_storm"/>
    <Fx>
      <Glow At="hand" Start="0" Length="400" Size="60" Size2="160" Color="255,120,40"/>
      <Sound Name="meteorite" Start="0"/>
    </Fx>
  </Skill>
</CustomSkills>

CustomSkills#

AttributeTypeDefaultEffect
Enabled0/110 = no custom skills are loaded

Max 64 skills. Extra rows are ignored with a log line.

Skill#

AttributeTypeDefaultEffect
Id80-299-Skill id. Must not exist in Skill.txt. Free in a stock Skill.txt: 80-199 and 271-299. 300+ is the master skill range and is refused
Namestring (31 chars)Custom SkillSkill name
Damageint0Base skill damage, like the Skill.txt Damage column (max = 1.5x)
DamagePerEnergyint0+1 skill damage per N energy. 0 = off
DamagePerStrengthint0+1 skill damage per N strength. 0 = off
DamagePerDexterityint0+1 skill damage per N agility. 0 = off
Manaint0Mana per cast
AGint0AG per cast
Rangeint6Cast range in tiles. Targeted skills walk into range first
Delayms0Fixed cooldown. 0 = attack / magic speed decides
Elementnamenoneice / poison / lightning / fire / earth / wind / water
ReqLevelint0Level needed to learn and cast. Character level stops at 400: "level 470" = ReqLevel="400" + ReqMasterLevel="70"
ReqStrength / ReqDexterity / ReqEnergy / ReqLeadershipint0Stats needed to learn and cast
ReqMasterLevelint0Master level needed to learn (learn time only)
ReqSkillskill idnoneSkill that must already be known to learn this one (learn time only)
ReqWeaponbitmask0Equipment needed to cast. Same bits as Skill.txt. 0 = none
ReqAmmo0/101 = arrows / bolts with durability needed
DarkWizard, DarkKnight, FairyElf, MagicGladiator, DarkLord, Summoner, RageFighter0-300 = cannot learn, 1 = any evolution, 2 = second class and up, 3 = third class. At least one class must be set
Physical0/101 = attack speed sets the cast rate and the skill always deals weapon damage. 0 = magic speed
MeleeMultiplier0/101 = the class skill multiplier applies: DK rate for Dark Knights, DL rate for Dark Lords (like Fire Burst), RF rate for Rage Fighters (like Phoenix Shot), 200% for others
Mountedallow / deny / defaultallowCast while riding. default = vanilla mounted rules
AutoRepeat0/111 = auto-attack keeps casting it. Buff and Heal skills never repeat
Iconstring (31 chars)-Sprite in the client atlas Data/Interface/UI/atlas/customskill.xml, without the customskill/ prefix. New icons with Tools\AtlasPacker (see Tools): -unpack <client>\Data\Interface\UI\atlas\customskill.xml MyIcons, add your PNGs, then MyIcons customskill customskill -out <client>\Data\Interface\UI\atlas
Descstring (199 chars)-Tooltip text, wrapped over several lines

Damage type follows the class: Dark Wizard, Magic Gladiator and Summoner deal magic damage, everyone else physical. Physical="1" always deals weapon damage (a Magic Gladiator casting a Physical="1" skill hits like a knight).

Learn#

<Learn Item="15,39"/>
AttributeTypeEffect
Itemgroup,indexItem that teaches the skill (right-click). Missing or bad = no learn item, logged

Learning checks, in order: the item's class columns in Item.xml, the skill's Req* stats and level, ReqMasterLevel, ReqSkill, then the skill's class columns. Each refusal tells the player why. The item's own Require* values in Item.xml are display-only.

Do not reuse an item that already teaches a vanilla skill: the vanilla skill wins.

Behaviour#

What the server does on cast.

TypeHitsSize attributes
Single (default)The target only-
AreaTargetCircle around the targetRadius
AreaGroundCircle around the aimed ground tile. With a monster under the cursor, centred on that monsterRadius
AreaSelfCircle around the casterRadius
ConeWedge in front of the caster, narrow at the casterLength, Width (far end)
LineStraight band in front of the casterLength, Width
BuffEffect on the caster (and party, see <Buff>)Radius = party range
HealThe party member under the cursor (else the caster), then the nearest other members within Radius of themRadius
AttributeTypeRangeDefaultEffect
Typename-SingleSee above. Unknown type = skill skipped
Radiustiles0-2550A radius of R reaches tile R
Lengthtiles0-2554Cone / Line length
Widthtiles0-2553Cone far edge / Line width
MaxTargetsint1-208 (Heal: 3)Enemies hit. Heal: members healed, max 5
Hitsint1-101Hits per target
HitDelayms0-30000Delay before the first hit. Match it to the visual impact. Heal: before the first heal
HitIntervalms50+150Time between hits. Heal: between one member and the next
ExtraHitChance%0-1000Chance per hit to land one more hit 80 ms later

OnHit#

Optional status effect on hit. Any behaviour.

AttributeTypeDefaultEffect
Effectname or idnonestun / freeze (or ice) / poison / sleep / blind, or an Effect.xml id
Durationseconds2Effect time
Chance%100Rolled per hit
Value1 / Value2int0Effect values. Ignored for poison (vanilla poison ticks)

Normal immunity and element resistance still apply.

Buff#

Only read for Type="Buff". Required: a Buff skill with no valid Effect is skipped.

AttributeTypeDefaultEffect
Effectname or id-damage / defense / life / critical (the Greater Damage / Defense / Life / Critical Damage buffs), or an Effect.xml id
Durationseconds60Buff time
Value1 / Value2int0Buff values
Party0/101 = also party members on the same map within Radius tiles (6 when Radius is 0)

Heal#

Only read for Type="Heal". Vanilla Party Heal rules.

AttributeTypeDefaultEffect
Baseint5Flat life healed
EnergyDivint5Adds Energy / EnergyDiv. 0 = Base only
Falloff%20Each next member gets this much less of the first heal (20 = 100%, 80%, 60%)

No party = the caster only. A party member must be in cast range. In Chaos Castle and the Silent map (40) only the caster can be healed.

Cast#

<Cast Anim="gigantic_storm"/>

Anim = caster animation (23 chars). Default: attack when Physical="1", else magic.

Animation names

magic (random hand cast), attack (weapon swing), magic1, magic2, weapon1, weapon2, elf, teleport, flash, inferno, hellfire, lightning_orb, chain_lightning, drain_life, summon, sleep, gigantic_storm, flame_strike, lightning_shock, sword1..sword5, wheel, fury_strike, death_stab, spear, power_slash, rush, strike, death_cannon, blow_of_destruction, hell_begin, hell_start, one_flash, darkhorse, dl_teleport, removal, vitality, swell_of_mp, recover, fist, bow, crossbow, thrust, stamp, giantswing, darkside_ready, darkside_attack, dragonkick, dragonlore, phoenix_shot, att_up_ourforces, hp_up_ourforces.

A vanilla skill name also works and uses that skill's clip: decay, ice_storm, meteorite, evil_spirit, fire_ball, aqua_beam, hell_fire, twisting_slash, rageful_blow, impale, fire_scream, fire_burst, chaotic_diseier, electric_spark, earthquake, strike_of_destruction, mana_rays, swell_life, killing_blow, beast_uppercut, chain_drive, dragon_slasher, dragon_roar.

Riding: spells with a seated version switch to it. Most clips speed up with attack / magic speed. Fixed speed: blow_of_destruction, recover, swell_of_mp, vitality, hell_start, dl_teleport, darkhorse, att_up_ourforces, hp_up_ourforces, removal.

Fx#

Up to 16 timed visual layers per skill (extra layers ignored with a log line). Each child element is one layer; the element name is the layer kind. Visuals only: they never deal damage.

LayerDrawsMain attributes
<Ring>Ground circleradius Size → Size2, band Width
<Beam>Ribbon At → To (To="targets" = one per enemy)width Size
<Arc>Blade sweep in front of the casterradius Size, angle Size2 (degrees), band Width, Height
<Burst>Spark burstCount sparks
<Flash>Explosion flashscale Size (100 = normal)
<Bolt>Lightning At → To (To must be target / targets)-
<Pillar>Light columnwidth Size, height Size2
<Glow>Glow spritesize Size → Size2, Texture
<Missile>Orb flying At → To over Lengthsee Missile below
<Shake>Screen shake near the casterstrength Size (100 = quake)
<Sound>SoundName (see Sound names) or File (your own .wav)
<Model>A vanilla effect from the catalogName (see Effect catalog)

Unknown layer names are skipped with a log line.

Common attributes

AttributeDefaultEffect
AtcasterAnchor: caster, caster_feet, hand, target, target_feet, point, targets
TotargetEnd anchor (Beam / Bolt / Missile / Model)
Start0ms after the cast
Length400ms the layer lasts
Size / Size2100 / = SizeWorld units, 100 = 1 tile
Width30Band width / side weave
Height0Raise off the anchor / missile arc
Count12Sparks / rocks
Color / Core255,255,255r,g,b. Core = hot centre / edge colour
TexturelightA preset: light, flare, shiny, spark, magic, lightmarks, spirit, energy, thunder, flame, splash, mist - or your own file, e.g. Effect\MySpell\glow.jpg (see Your own files)
Repeat1Copies of the layer, 1-16
Interval0ms between copies
Spread0Each copy moves to a random spot within this distance of its anchor (not caster / hand)
Orbit0Copies sit evenly on a ring this wide around the anchor, turned at random each cast (all layers of a cast turn together). Missile and <Model Name="arrow"> use Orbit their own way
Seed0Layers with the same Seed (above 0) use the same random spots copy by copy. Give a meteor, its flash and its ring the same Seed / Repeat / Interval / Spread
Rise0Start height above At (missile / model)
FadeIn01 = fade in instead of starting at full strength
Reverse01 = arc sweeps the other way / ring shrinks
Ground01 = lay a glow / flash flat on the ground
Release01 = skipped if the caster casts the same skill again before it starts (vanilla "on release" sound)
Once01 = (Sound) not restarted while the caster's previous copy still plays

Anchors: point is a fixed spot taken at cast time - the aimed tile (AreaGround), the target tile (targeted skills) or the caster tile (others). targets = every enemy inside the hit area (one copy each); for Heal it is the healed members.

Missile

AttributeDefaultEffect
Size100Orb size. 0 = no glow head
Size2= SizeTrail width
Trail0Trail samples (0 = none)
Slant01 = comes in at an angle from behind the caster
Dark01 = dark (subtractive) trail
Streamnonespirit / skull = vanilla Evil Spirit (or skull) stamped at the head, weapon = the caster's own weapon flies it, model = your own model (set by Model)
Model-Your own model file flies the missile, e.g. Effect\MySpell\orb.bmd. Size is then the model scale % (100 = as modelled) and there is no glow head
PosespinWeapon / model stream: spin, stab (hilt first), stab_flip (tip first, the right one for weapons)
Orbit0Copies start evenly on a ring this wide around At
Hold0ms the missile hovers at its start before flying
Stay0ms it stays where it landed, fading
Homing01 = vanilla Fire Burst flight: copies fan out over Width degrees, turn toward To, stop on arrival (Length = max flight time)

Straight flight: leave Width and Height at 0. Repeat = number of missiles.

Effect catalog (<Model Name="...">)

Each name is a real vanilla effect, tested in game and wrapped so it never deals damage on its own (the server deals the skill's damage). Unknown names are skipped and reported (see Errors). New effects are added to the catalog with client releases.

Color recolours most of them: the effect and everything it spawns are multiplied by the colour (255,255,255 = vanilla). Multiplying works best on white / pale effects - turning orange fire blue gives a dark result; use a pale or grey texture for strong recolours.

NameEffect
meteorBurning rock dropped from Rise onto At, bursts into rocks
meteoriteVanilla Meteorite drop
hellfireVanilla Hell Fire ground circle
debrisCount rocks thrown up (max 12)
evil_spirit / skull_spiritVanilla Evil Spirit joints that wander to the To enemies. Count per copy (max 8)
death_stabThe full vanilla Death Stab in Color. Use Length="520"
healVanilla Heal streaks on each At character
arrowThe caster's real bow / crossbow arrow shot at To. Repeat = arrows, Width = fan in degrees, Orbit = start ring
ghostOne Evil Spirit ghost per copy flying At → To along the ground. Width = side swing, Height = above ground, Size = ribbon width, Dark="1" = vanilla shadow look
flameThe vanilla Flame column: particles rising out of the ground at At for Length ms. Count = particles per tick (vanilla 6, max 12), Width = column radius, Size = particle size %, Texture = sprite (default vanilla fire; splash / mist = water), Color = tint
phoenixThe whole vanilla Rage Fighter Phoenix Shot (swing blur, spinning projectile, trail, sparks, impact light) from the caster at the To character. Needs a target. Color tints all of it; 255,255,255 = vanilla. Size = projectile size %
phoenix_orbThe Phoenix Shot projectile alone, from the caster at each To character. Count = projectiles per character (max 5), Width = how far apart they start beside the caster (they converge on the target), Size = size %, Color = tint. Start="280" launches them with the main Phoenix shot
ice_stormVanilla Ice Storm: ice shards fall onto At and burst. Count = shards (vanilla 10, max 20). Silent: add the ice sounds as <Sound> layers (first burst about 700 ms)
infernoVanilla Inferno fire ring (220 radius) around At (caster_feet = vanilla)
twisterVanilla Twister tornado walking from At toward To (about 590 units in 2.4 s)
aqua_beamVanilla Aqua Beam from the caster's hand toward To
novaVanilla Nova burst of spirits around At. Count = charge 0-12 (12 = full). Stays where it was cast
decayVanilla Decay: poison meteors fall onto At and leave a poison cloud. Count = meteors (vanilla 2, max 6). Plays its own landing sound - add only the cast sound
chain_lightningVanilla Chain Lightning hopping through To (targets = the target first, then the nearest next). Count = max links (vanilla 3). Needs a target
lightning_shockVanilla Lightning Shock ball dropping onto At (targets = one per enemy hit). Needs the caster on screen
drain_lifeVanilla Drain Life ghosts from the To character back to the caster (about 2.9 s). Needs a target; one drain per caster at a time
sahamuttVanilla Sahamutt: casting circle at At, the tiger pounces on To and explodes. Count 1-3 = size tier (else the caster's book level), Size = tiger scale %, Width="0" = no casting circle. Plays its own explosion sound
fire_burstVanilla Fire Burst: 3 homing fire missiles from the caster at each To character. Plays its own explosion sound. Needs a target
fire_screamVanilla Fire Scream flame waves from At along the caster's facing (the flames; the dark ground mesh is left out)
earthquakeVanilla Dark Horse Earthquake: shock waves, stone rings and the final crater at At (crater at 1440 ms). Size = ring radius %. Add <Shake Start="1080" Length="360" Size="700"/> for the vanilla quake. Not on a Dark Horse rider with the darkhorse animation (it would play twice)
chaotic_diseierVanilla Chaotic Diseier: dark ghosts streaming into the caster + body sparks
flame_strikeVanilla Flame Strike burning blade in the caster's hand; the sweep only shows with <Cast Anim="flame_strike"/> (put this layer at Start="40")
gigantic_stormVanilla Gigantic Storm: 5 lightning strikes on a ring around At. Size = ring radius % (100 = 200 units)
twisting_slashVanilla Twisting Slash: the caster's own weapon spinning around them. Needs a weapon in hand. One copy only
rageful_blowVanilla Rageful Blow: the weapon slams at At and cracks the ground. Without a weapon: cracks only. Plays its own impact sounds - add only the cast sound
impaleVanilla Impale lance thrust in front of the caster
dragon_roarVanilla Dragon Roar: lava + dragon ground crack on the caster (lava needs <Cast Anim="dragon_roar"/>), volcano + burn on each To (max 3 volcanoes)

Needs a target effects skip ground casts with no target. Needs the caster on screen effects skip copies where the caster is out of view.

Sounds: max 4 different sounds per skill (names or files; more are skipped with a log line).

Your own files#

Textures, sounds and models can be your own files, shipped in the client's Data folder (add them to your client update). Write the path relative to Data:

KindAttributeFormatExample
TextureTexture="..." on any layer.jpg (client file .OZJ) or 32-bit .tga (client file .OZT), max 1024 x 1024Texture="Effect\MySpell\glow.jpg" → Data\Effect\MySpell\glow.OZJ
Sound<Sound File="..."/>.wav (PCM)<Sound File="Sound\MySpell\boom.wav" Start="300"/>
Model<Missile Model="..."/>.bmd; its textures in the same folder<Missile Model="Effect\MySpell\orb.bmd" .../>

Rules: no leading Data\, no .., no drive letters, at most 58 characters. Limits per table: 256 texture files, 64 sound files, 32 model files, 1024 different names / paths in total. A missing or broken file is skipped and reported (see Errors) - the game never closes because of it. Files load when the table arrives (login or /reload plugins).

Sound names

swing (random swoosh), swing1, swing2, swing_light, knight1..knight4, storm, evil, magic, hellfire, ice, flame, flash, explosion, meteorite, thunder, nuke1, nuke2, combo, blood, piercing, ice_arrow, telekinesis, soul_barrier, swell_life, riding_spear, raid_shoot, chain_lightning, lightning_shock, flame_strike, gigantic_storm, blow_of_destruction, rageful_blow, rageful_blow_swing, rageful_blow_impact, chaotic, swell_magic, drain_life, berserker, summon_explosion, requiem, sudden_ice, hit_melee, hit_missile, heal, bow, crossbow, fire_burst, fire_burst_impact, dark_side, dark_side_impact, dragon_slasher.

Shipped Skills#

IdNameClassBehaviourLearn item
273Meteor StormSoul Master, MGAreaSelf, 3 hitsScroll of Meteor Storm (15,39)
274Soul SeekerSoul MasterAreaGround, 4 hitsScroll of Soul Seeker (15,40)
275Blood StormBlade Knight, MGAreaGround, 3 hitsScroll of Blood Storm (15,41)
276Fire BlowBlade KnightAreaTarget, 4 hitsOrb of Fire Blow (12,25)
277Focus ShotElfAreaGround, 4 hits, needs bow / crossbow + ammoOrb of Focus Shot (12,29)
278Party HealingElfHeal, 3 membersOrb of Party Healing (12,51)
279Havok SpearMGAreaGroundScroll of Havok Spear (15,42)
280Wind SoulDLAreaTarget, 3 hitsScroll of Wind Soul (15,43)
281Aqua BeastSummonerAreaGround, 4 hitsScroll of Aqua Beast (15,44)
282Dark Phoenix ShotRage FighterAreaTarget, 4 hitsDark Phoenix Shot Parchment (15,45)

The learn items are in Item.xml with Drop="0": they never drop from monsters. Hand them out through shops, item bags, quests or rewards.

Important Behavior#

  • Bad rows are skipped, the rest load: Id out of range, Id already in Skill.txt, duplicate Id, unknown Behaviour Type, or a Buff skill without an effect. Each is logged under [CustomSkills].
  • Combo: attack skills combo only when listed under <SecondarySkills> in CustomCombo.xml (the shipped file lists 273-277, 279, 280). The combo bonus applies to the first hit on each target.
  • MuHelper: the MuHelper and the offline helper can use custom skills like vanilla ones. Buff skills show in the buff list.
  • Mounted: a Mounted value in SkillTweaks.xml for the same skill id wins over the one here.
  • Area hits use the same circle the client draws: radius R reaches tile R. Area skills stop after MaxTargets enemies.
  • Delayed hits: with HitDelay the damage number appears when the visual lands, not on the cast.
  • AreaGround on a moving monster: the hit circle is centred on the monster's server tile, so hits do not land on empty ground while it walks.
  • Visuals are client-only: changing <Fx>, <Cast>, Icon or Desc needs /reload plugins and a relog. Numbers (damage, mana, range, behaviour) change for everyone on reload.
  • Enabled="0" removes every custom skill from the server table and sends nothing to clients.

Examples#

Blade Knight melee skill: one target, 2 hits, 30% stun.

<Skill Id="281" Name="Crushing Blow" Damage="90" DamagePerStrength="25" Mana="20" AG="10" Range="2"
       ReqLevel="250" ReqStrength="800" DarkKnight="2"
       Physical="1" MeleeMultiplier="1" Icon="crushing_blow"
       Desc="Two heavy blows on one target. 30% chance to stun.">
  <Learn Item="15,44"/>
  <Behaviour Type="Single" Hits="2" HitDelay="200" HitInterval="150"/>
  <OnHit Effect="stun" Duration="2" Chance="30"/>
  <Cast Anim="sword3"/>
  <Fx>
    <Sound Name="knight1" Start="0"/>
    <Flash At="target" Start="200" Size="90" Color="255,200,120"/>
    <Burst At="target" Start="200" Count="10" Color="255,180,90"/>
  </Fx>
</Skill>

For each new learn item, also add the item to Item.xml and give it a model in CustomItemVisual.xml.

Common Issues#

Last updated October 23, 2026