The player is in a zone and presses an ability key. This page follows that cast through the server, then looks at the creatures on the other side of the fight, and what happens when one dies.
A spell cast
-
The client sends a cast message.
CastSpellHandler(apps/bezgelor_protocol/lib/bezgelor_protocol/handler/cast_spell_handler.ex), in the player's connection process, reads which ability it is and sends it to the zone:Zone.Instance.cast_spell/3, a cast. -
The zone instance, which owns the player's spell state, hands the request to
BezgelorWorld.Spell.Caster(apps/bezgelor_world/lib/bezgelor_world/spell/caster.ex). -
Spell.Casterdecides everything about the cast: whether it is allowed (cooldowns, resources, range and the like), how long it takes, which units it hits and what each spell effect does to them. - It doesn't do any of it itself. It returns a list of actions, plain data such as "send this packet to everyone in the zone", "take 120 health from this creature", "call me back in 1.5 seconds for the cast's end", "put this aura on that player".
-
The zone carries the actions out: it sends the packets (
ServerSpellStart,ServerSpellGo,ServerCombatLogand the rest), applies damage and auras, and sets timers withProcess.send_after, which arrive later as ordinary messages in the zone's mailbox.
The split in steps 3 to 5 is deliberate. Spell.Caster is made of pure functions: given the caster's state
and the request, it returns the new state and the actions, and touches nothing else (no processes, no database,
no network). That makes it easy to test, since a test can run a whole cast without starting a zone, and it keeps
the rule "only the zone changes the zone" simple to follow. Many of the world server's systems are built the
same way: a pure module that decides, and the zone process that acts.
Where spells come from
Spells are data, not code. The client's own tables, extracted into apps/bezgelor_data/priv/data and held in
memory (Behind the scenes), describe every ability: Spell4 (the spell: cast time,
cooldown, costs, targeting), Spell4Effects (what it does, effect by effect), Spell4Telegraph and
TelegraphDamage (the shapes on the ground). Spell4 rows are looked up by id; the
Caster interprets them.
Each effect type is handled by a function: damage and healing (including damage over time), vital changes,
proxies that trigger other spells, crowd control, property modifiers, quest objectives, teleports, mounts,
taxis and others. Spell.SupportEffects and Spell.AuraEffects hold the less common ones, and
Spell.EffectCoverage counts every effect the server runs, so the admin pages can show which effect types
players reach that we don't handle yet. Damage numbers come
from Spell.DamageCalculator.
Telegraphs
Most WildStar abilities hit an area drawn on the ground, the telegraph, rather
than a single target. BezgelorCore.Telegraph (apps/bezgelor_core/lib/bezgelor_core/telegraph.ex), ported
from NexusForever, places a telegraph at the caster's position and facing and answers "is this unit inside?" for
each shape the client uses: circle, ring, square, cross, cone, pie, rectangle and long cone. The Caster uses it
to pick the units an ability hits.
Creatures
Creatures live in the zone too. Zone.Creatures (apps/bezgelor_world/lib/bezgelor_world/zone/creatures.ex)
holds their state, and each creature's behaviour is a small state machine in BezgelorCore.AI: idle,
wandering, patrolling, in combat, evading back to its spawn point, dead. A creature in combat keeps a
threat table of who has hurt it most.
Zone.CreatureCombat runs the fighting on every zone tick: an aggressive creature attacks a player who comes
within 15 units, chases its target, swings at it, and gives up and walks home (leash)
when it is pulled more than 40 units from where the fight started. Creatures cast their abilities through the
same Spell.Caster as players, so a creature's spell follows the same rules as a player's. Values like these
ranges, where neither the client's tables nor NexusForever settle them, are listed with their reasons in
docs/design/designed-values.md.
Dungeon and raid bosses add scripts: BezgelorWorld.Scripts.* modules, and encounter blocks in the instance
files under apps/bezgelor_data/priv/data/instances/, bound to creatures and maps by
BezgelorWorld.Script.Registry. How they are built and tested is on
How we build, test and tune instances.
Death, loot and experience
When damage brings a creature to zero health, the zone credits the kill:
-
Loot:
Zone.Loot(zone/loot.ex) drops the loot as small units on the ground that the players can pick up, with group rules (need and greed rolls, round robin, master loot) and overflow to mail when bags are full. What drops is decided by the pure modulesBezgelorWorld.Loot.Profile,RollerandRules. -
Experience:
BezgelorWorld.KillExperience(kill_experience.ex) works out the experience for the kill from the creature's difficulty and the level difference. Neither the client's tables nor NexusForever give this amount, so the formula is designed from what the original developers said and players measured; the module explains it. -
Quest credit:
Zone.PlayerQuestsadvances any quest objective that counts this kill.
Some time later the zone sends itself a respawn message and the creature comes back.
When a player dies, the client shows its death screen, and the player can wake at the nearest Holo-Crypt or,
in some places, where they fell (BezgelorWorld.Death, BezgelorWorld.HoloCrypt).
Quests
Each player's quests live with the player in the zone (Zone.PlayerQuests, zone/player_quests.ex). The rules
for a quest log are pure functions in BezgelorWorld.Quest.QuestLog; what each objective type means is
documented in the semantic registry. Every change is written to the database at
once through BezgelorWorld.Quest.Store (Quest.DbStore in the server, an in-memory store in tests), so
leaving one zone and entering the next never loses progress.
Where to look
-
apps/bezgelor_world/lib/bezgelor_world/spell/: the Caster and its helpers (caster.ex,auras.ex,damage_calculator.ex, ...). -
apps/bezgelor_core/lib/bezgelor_core/telegraph.ex,ai.ex. -
apps/bezgelor_world/lib/bezgelor_world/zone/creatures.ex,creature_combat.ex,loot.ex,player_quests.ex. -
apps/bezgelor_world/lib/bezgelor_world/kill_experience.ex,quest/. -
apps/bezgelor_world/test/e2e/: headless players casting, fighting and looting against the real protocol.
Next: Behind the scenes.