Mobiles
This guide builds one script that spawns a mobile from a template, reads and
adjusts its skills, and explains how templates decide a mobile's gender,
appearance and equipment. It uses the mobile module
and real template ids from
src/Moongate.Server/Assets/Templates/Mobiles/.
Mobiles are referenced by serial, just like items.
Note
All mobile.* mutations run on the game-loop thread. The examples live inside
a world_ready handler, which is already on the loop — see
How scripting works.
Spawn from a template
mobile.create_from_template
takes a template id, a map id and an (x, y, z) position. It creates the mobile
and its equipment in one call, and returns the new serial (or nil when the
template is unknown).
local guard = mobile.create_from_template("warrior_guard_male_npc", 1, 1420, 1690, 0)
warrior_guard_male_npc is a real shipped template. It comes fully outfitted —
plate armour and a halberd — because its YAML declares an Equipment: list that
the factory resolves and equips on spawn.
How a template is built
Templates are declarative YAML. The warrior_guard_male_npc entry looks like
this (abridged):
- Id: warrior_guard_male_npc
BaseMobile: base_human_npc
Strength: 100
Dexterity: 125
Intelligence: 25
Skills:
Anatomy: 1200
Tactics: 1200
Swordsmanship: 1200
Appearance:
Body: 400
Equipment:
- Item: plate_chest
Layer: InnerTorso
- Item: halberd
Layer: TwoHanded
LootTableId: guard.warrior
A few things happen when this is loaded and spawned:
BaseMobileinheritance.base_human_npcsupplies defaults (a base body, skin/hair, a basic shirt-and-shoes outfit). The derived template is merged onto it: empty strings fall back to the base,Tagsconcatenate,Equipment(andVariants) are replaced wholesale when the derived template declares any, and a numeric stat overrides the base only when it differs from the DTO default. So the guard keeps the base human look but raises Strength/Dexterity/Intelligence and swaps in plate.- Skills are stored in tenths, so
Swordsmanship: 1200means a skill of 120.0. - Equipment is resolved item-by-item onto the named layers.
Gender
Every template has a gender, chosen per spawn by the factory:
Template Gender |
Result |
|---|---|
Male (the default) |
always male |
Female |
always female |
Random |
a coin-flip between male and female on each spawn |
warrior_guard_male_npc uses the default, so it always spawns male; the shard
also ships a separate warrior_guard_female_npc with Gender: Female. Setting
Gender: Random on a template instead lets one id produce both.
Variants
A template may also declare variants — weighted alternates picked once per
spawn. Each variant has a Weight and may override the gender, loot table,
appearance and equipment; anything it leaves out falls back to the template.
The factory picks one variant by weight on every spawn, so a single id can yield
a coherent mix of looks:
Variants:
- Name: veteran
Weight: 3
- Name: recruit
Weight: 1
Gender: Random
LootTableId: guard.rookie
With these weights a spawn is a veteran three times out of four and a recruit one time in four. (The shipped guard and undead templates keep things simple and do not use variants, but the mechanism is always available.)
Skills: read and write
Read a skill with
mobile.get_skill and write one with
mobile.set_skill. Values are in
tenths, and the skill can be named or a
skill_name constant.
local swords = mobile.get_skill(guard, "Swordsmanship")
log.info("swords = {0}", swords) -- 1200 -> 120.0
mobile.set_skill(guard, skill_name.Tactics, 1000) -- 100.0
Dump every skill at once with
mobile.skills:
for name, value in pairs(mobile.skills(guard)) do
log.debug("{0} = {1}", name, value)
end
The complete script
-- scripts/main.lua
events.on("world_ready", function()
-- Spawn a fully equipped town guard.
local guard = mobile.create_from_template("warrior_guard_male_npc", 1, 1420, 1690, 0)
if not guard then
log.warn("guard template not found")
return
end
local m = mobile.get(guard)
log.info("{0} the {1} spawned at ({2},{3})", m.name, m.gender, m.x, m.y)
-- Read a starting skill (stored in tenths).
log.info("swords = {0}", mobile.get_skill(guard, "Swordsmanship"))
-- Raise a couple of skills.
mobile.set_skill(guard, skill_name.Tactics, 1000) -- 100.0
mobile.set_skill(guard, "Anatomy", 1000)
-- Spawn a tougher monster nearby, too.
local knight = mobile.create_from_template("skeletal_knight_npc", 1, 1425, 1695, 0)
if knight then
log.info("skeletal knight {0} spawned", knight)
end
end)
The knight you spawned carries a undead.knight loot table — the
Loot guide shows how loot tables turn into items.