Spells, enchantments and other custom effects
Spells
In data/mods/Magiclysm
there is a template spell, copied here for your perusal:
{
// This spell exists in json as a template for contributors to see the possible values of the spell
"id": "example_template", // id of the spell, used internally. not translated
"type": "SPELL",
"name": "Template Spell", // name of the spell that shows in game
"description": "This is a template to show off all the available values",
"valid_targets": ["hostile", "ground", "self", "ally"], // if a valid target is not included, you cannot cast the spell on that target.
"effect": "shallow_pit", // effects are coded in C++. A list will be provided below of possible effects that have been coded.
"effect_str": "template", // special. see below
"extra_effects": [{ "id": "fireball", "hit_self": false, "max_level": 3 }], // this allows you to cast multiple spells with only one spell
"affected_body_parts": [
"HEAD",
"TORSO",
"MOUTH",
"EYES",
"ARM_L",
"ARM_R",
"HAND_R",
"HAND_L",
"LEG_L",
"FOOT_L",
"FOOT_R"
], // body parts affected by effects
"spell_class": "NONE", //
"base_casting_time": 100, // this is the casting time (in moves)
"base_energy_cost": 10, // the amount of energy (of the requisite type) to cast the spell
"energy_source": "MANA", // the type of energy used to cast the spell. types are: MANA, BIONIC, HP, STAMINA, FATIGUE, NONE (none will not use mana)
"components": [requirement_id] // an id from a requirement, like the ones you use for crafting. spell components require to cast.
"difficulty": 12, // the difficulty to learn/cast the spell
"max_level": 10, // maximum level you can achieve in the spell
"min_damage": 0, // minimum damage (or "starting" damage)
"max_damage": 100, // maximum damage the spell can achieve
"damage_increment": 2.5, // to get damage (and any of the other below stats) multiply this by spell's level and add to minimum damage
"min_aoe": 0, // area of effect (currently not implemented)
"max_aoe": 5,
"aoe_increment": 0.1,
"min_range": 1, // range of the spell
"max_range": 10,
"range_increment": 2,
"min_dot": 0, // damage over time (currently not implemented)
"max_dot": 2,
"dot_increment": 0.1,
"min_duration": 0, // duration of spell effect (if the spell has a special effect)
"max_duration": 1000,
"duration_increment": 4,
"min_pierce": 0, // how much of the spell pierces armor (currently not implemented)
"max_pierce": 1,
"pierce_increment": 0.1,
"field_id": "fd_blood", // the string id of the field (currently hardcoded)
"field_chance": 100, // one_in( field_chance ) chance of spawning a field per tile in aoe
"min_field_intensity": 10, // field intensity of fields generated
"max_field_intensity": 10,
"field_intensity_increment": 1,
"field_intensity_variance": 0.1, // the field can range in intensity from -variance as a percent to +variance as a percent i.e. this spell would be 9-11
"sound_type": "combat", // the type of sound. possible types are: background, weather, music, movement, speech, activity, destructive_activity, alarm, combat, alert, order
"sound_description": "a whoosh", // the sound description. in the form of "You hear %s" by default it is "an explosion"
"sound_ambient": true, // whether or not this is treated as an ambient sound or not
"sound_id": "misc", // the sound id
"sound_variant": "shockwave" // the sound variant
}
Most of the default values for the above are either 0 or “NONE”, so you may leave out most of the values if they do not pertain to your spell.
When deciding values for some of these, it is important to note that some of the formulae are not linear. For example, this is the formula for spell failure chance:
( ( ( ( spell_level - spell_difficulty ) * 2 + intelligence + spellcraft_skill ) - 30 ) / 30 ) ^ 2
Meaning a spell with difficulty 0 cast by a player with 8 intelligence, 0 spellcraft, and level 0 in the spell will have a 53% spell failure chance. On the other hand, a player with 12 intelligence, 6 spellcraft, and level 6 in the same spell will have a 0% spell failure chance.
However, experience gain is a little more complicated to calculate. The formula for how much experience you need to get to a level is below:
e ^ ( ( level + 62.5 ) * 0.146661 ) ) - 6200
Currently Implemented Spell Flags
-
PERMANENT
- items or creatures spawned with this spell do not disappear and die as normal -
IGNORE_WALLS
- spell’s aoe goes through walls -
SWAP_POS
- teleports the caster to the target location when used by a ranged spell, switching places with any creature that might be in the way -
HOSTILE_SUMMON
- summon spell always spawns a hostile monster -
HOSTILE_50
- summoned monster spawns friendly 50% of the time -
SILENT
- spell makes no noise at target -
NO_EXPLOSION_VFX
- spell has no visual explosion -
LOUD
- spell makes extra noise at target -
VERBAL
- spell makes noise at caster location, mouth encumbrance affects fail % -
SOMATIC
- arm encumbrance affects fail % and casting time (slightly) -
NO_HANDS
- hands do not affect spell energy cost -
UNSAFE_TELEPORT
- teleport spell risks killing the caster or others -
NO_LEGS
- legs do not affect casting time -
CONCENTRATE
- focus affects spell fail % -
RANDOM_AOE
- picks random number between min+increment*level and max instead of normal behavior -
RANDOM_DAMAGE
- picks random number between min+increment*level and max instead of normal behavior -
RANDOM_DURATION
- picks random number between min+increment*level and max instead of normal behavior -
RANDOM_TARGET
- picks a random valid target within your range instead of normal behavior. -
MUTATE_TRAIT
- overrides the mutate spell_effect to use a specific trait_id instead of a category -
WONDER
- instead of casting each of the extra_spells, it picks N of them and casts them (where N is std::min( damage(), number_of_spells )) -
PAIN_NORESIST
- pain altering spells can’t be resisted (like with the deadened trait) -
NO_FAIL
- this spell cannot fail when you cast it
Currently Implemented Effects and special rules
-
pain_split
- makes all of your limbs’ damage even out. -
move_earth
- “digs” at the target location. some terrain is not diggable this way. -
target_attack
- deals damage to a target (ignores walls). Negative damage heals the target. If “effect_str” is included, it will add that effect (defined elsewhere in json) to the targets if able, to the body parts defined in affected_body_parts. Any aoe will manifest as a circular area centered on the target, and will only deal damage to valid_targets. (aoe does not ignore walls) -
projectile_attack
- similar to target_attack, except the projectile you shoot will stop short at impassable terrain. If “effect_str” is included, it will add that effect (defined elsewhere in json) to the targets if able, to the body parts defined in affected_body_parts. -
cone_attack
- fires a cone toward the target up to your range. The arc of the cone in degrees is aoe. Stops at walls. If “effect_str” is included, it will add that effect (defined elsewhere in json) to the targets if able, to the body parts defined in affected_body_parts. -
line_attack
- fires a line with width aoe toward the target, being blocked by walls on the way. If “effect_str” is included, it will add that effect (defined elsewhere in json) to the targets if able, to the body parts defined in affected_body_parts. -
spawn_item
- spawns an item that will disappear at the end of its duration. Default duration is 0. Damage determines quantity. -
teleport_random
- teleports the player randomly range spaces with aoe variation -
recover_energy
- recovers an energy source (defined in the effect_str, shown below) equal to damage of the spell
- “MANA”
- “STAMINA”
- “FATIGUE”
- “PAIN”
- “BIONIC”
-
ter_transform
- transform the terrain and furniture in an area centered at the target. The chance of any one of the points in the area of effect changing is one_in( damage ). The effect_str is the id of a ter_furn_transform. -
vomit
- any creature within its area of effect will instantly vomit, if it’s able to do so. -
timed_event
- adds a timed event to the player only. valid timed events: “help”, “wanted”, “robot_attack”, “spawn_wyrms”, “amigara”, “roots_die”, “temple_open”, “temple_flood”, “temple_spawn”, “dim”, “artifact_light” NOTE: This was added only for artifact active effects. support is limited, use at your own risk. -
explosion
- an explosion is centered on the target, with power damage() and factor aoe()/10 -
flashbang
- a flashbang effect is centered on the target, with poewr damage() and factor aoe()/10 -
mod_moves
- adds damage() moves to the target. can be negative to “freeze” the target for that amount of time -
map
- maps the overmap centered on the player out to a radius of aoe() -
morale
- gives a morale effect to all npcs or avatar within aoe, with value damage(). decay_start is duration() / 10. -
charm_monster
- charms a monster that has less hp than damage() for approximately duration() -
mutate
- mutates the target(s). if effect_str is defined, mutates toward that category instead of picking at random. the “MUTATE_TRAIT” flag allows effect_str to be a specific trait instead of a category. damage() / 100 is the percent chance the mutation will be successful (a value of 10000 represents 100.00%) -
bash
- bashes the terrain at the target. uses damage() as the strength of the bash. -
dash
- moves the player to the target tile, can leave behind fields. -
WONDER
- Unlike the above, this is not an “effect” but a “flag”. This alters the behavior of the parent spell drastically: The spell itself doesn’t cast, but its damage and range information is used in order to cast the extra_effects. N of the extra_effects will be chosen at random to be cast, where N is the current damage of the spell (stacks with RANDOM_DAMAGE flag) and the message of the spell cast by this spell will also be displayed. If this spell’s message is not wanted to be displayed, make sure the message is an empty string. -
RANDOM_TARGET
- A special spell flag (like wonder) that forces the spell to choose a random valid target within range instead of the caster choosing the target. This also affects extra_effects.
For Spells that have an attack type, these are the available damage types:
fire
acid
bash
bio
- internal damage such as poisoncold
cut
electric
stab
none
- this damage type goes through armor altogether. it is the default.
Spells that level up
Spells that change effects as they level up must have a min and max effect and an increment. The min effect is what the spell will do at level 0, and the max effect is where it stops growing. The increment is how much it changes per level. For example:
"min_range": 1,
"max_range": 25,
"range_increment": 5,
Min and max values must always have the same sign, but it can be negative eg. in the case of spells that use a negative ‘recover’ effect to cause pain or stamina damage. For example:
{
"id": "stamina_damage",
"type": "SPELL",
"name": "Tired",
"description": "decreases stamina",
"valid_targets": ["hostile"],
"min_damage": -2000,
"max_damage": -10000,
"damage_increment": -3000,
"max_level": 10,
"effect": "recover_energy",
"effect_str": "STAMINA"
}
Learning Spells
There are two ways of granting spells that is implemented: Mutating can grant a spell with the “spells_learned” field which also lets you specify the level granted. Otherwise you can learn a spell from an item through a use_action, which is also the only way to train a spell other than using it. Examples of both are shown below:
{
"id": "DEBUG_spellbook",
"type": "GENERIC",
"name": "A Technomancer's Guide to Debugging C:DDA",
"description": "static std::string description( spell sp ) const;",
"weight": 1,
"volume": "1 ml",
"symbol": "?",
"color": "magenta",
"use_action": {
"type": "learn_spell",
"spells": [ "debug_hp", "debug_stamina", "example_template", "debug_bionic", "pain_split", "fireball" ] // this is a list of spells you can learn from the item
}
},
You can study this spellbook for a rate of ~1 experience per turn depending on intelligence, spellcraft, and focus.
"spells_learned": [ [ "debug_hp", 1 ], [ "debug_stamina", 1 ], [ "example_template", 1 ], [ "pain_split", 1 ] ],
Spells in professions and NPC classes
You can add a “spell” member to professions or an NPC class definition like so:
"spells": [ { "id": "summon_zombie", "level": 0 }, { "id": "magic_missile", "level": 10 } ]
NOTE: This makes it possible to learn spells that conflict with a class. It also does not give the prompt to gain the class. Be judicious upon adding this to a profession!
Spells in monsters
You can assign a spell as a special attack for a monster.
{ "type": "spell", "spell_id": "burning_hands", "spell_level": 10, "cooldown": 10 }
- spell_id: the id for the spell being cast.
- spell_level: the level at which the spell is cast. Spells cast by monsters do not gain levels like player spells.
- cooldown: how often the monster can cast this spell
Enchantments
Enchantments make it possible to specify custom effects provided by item, bionic or mutation.
Fields
id
(string) Unique identifier for this enchantment.
has
(string) How an enchantment determines if it is in the right location in order to qualify for being active.
This field is relevant only for items.
Values:
HELD
(default) - when in your inventoryWIELD
- when wielded in your handWORN
- when worn as armor
condition
(string) How an enchantment determines if you are in the right environments in order for the enchantment to qualify for being active.
Values:
ALWAYS
(default) - Always activeUNDERGROUND
- When the owner of the item is below Z-level 0UNDERWATER
- When the owner is in swimmable terrainACTIVE
- whenever the item, mutation, bionic, or whatever the enchantment is attached to is active.
emitter
(string) Identifier of an emitter that’s active as long as this enchantment is active. Default: no emitter.
ench_effects
(array) Grants effects of specified intensity as long as this enchantment is active.
Syntax for single entry:
{
// (required) Identifier of the effect
"effect": "effect_identifier",
// (required) Intensity. Setting to 1 works for effects that do not actually have intensities.
"intensity": 2
}
hit_you_effect
(array) List of spells that may be cast when enchantment is active and character melee attacks a creature.
Syntax for single entry:
{
// (required) Identifier of the spell
"id": "spell_identifier",
// If true, the spell is centered on the character's location.
// If false, the spell is centered on the attacking creature.
// Default: false
"hit_self": false,
// Chance to trigger, one in X.
// Default: 1
"once_in": 1,
// Message for when the spell is triggered for you.
// %1$s is your name, %2$s is creature's
// Default: no message
"message": "You pierce %2$s with Magic Piercing!",
// Message for when the spell in triggered for an NPC.
// %1$s is their name, %2$s is creature's
// Default: no message
"npc_message": "%1$s pierces %2$s with Magic Piercing!",
// TODO: broken?
"min_level": 1,
// TODO: broken?
"max_level": 2
}
hit_me_effect
(array) List of spells that may be cast when enchantment is active and character gets melee attacked by a creature.
Same syntax as for hit_you_effect
.
mutations
(array) List of mutations temporarily granted while enchantment is active.
intermittent_activation
(object) Rules that specify random effects which occur while enchantment is active.
Syntax:
{
// List of checks to run on every turn while enchantment is active.
"effects": [
{
// Average activation frequency.
// The exact chance to pass is "one in (X converted to turns)" per turn.
"frequency": "5 minutes",
// List of spells to cast if the check passed.
"spell_effects": [
{
// (required) Identifier of the spell
"id": "nasty_random_effect",
// TODO: broken?
"min_level": 1,
// TODO: broken?
"max_level": 5
// TODO: other fields appear to be loaded, but unused
}
]
}
]
}
values
(array) List of miscellaneous character/item values to modify.
Syntax for single entry:
{
// (required) Value ID to modify, refer to list below.
"value": "VALUE_ID_STRING",
// Additive bonus. Optional integer number, default is 0.
// May be ignored for some values.
"add": 13,
// Multiplicative bonus. Optional, default is 0.
"multiply": -0.3
}
Additive bonus is applied separately from multiplicative, like so:
bonus = add + base_value * multiply
Thus, a multiply
value of -0.8 is -80%, and a multiply
of 2.5 is +250%. When modifying integer
values, final bonus is rounded towards 0 (truncated).
When multiple enchantments (e.g. one from an item and one from a bionic) modify the same value, their bonuses are added together without rounding, then the sum is rounded (if necessary) before being applied to the base value.
Since there’s no limit on number of enchantments the character can have at a time, the final calculated values have hardcoded bounds to prevent unintended behavior.
IDs of modifiable values
Character values
STRENGTH
Strength stat. base_value
here is the base stat value. The final value cannot go below 0.
DEXTERITY
Dexterity stat. base_value
here is the base stat value. The final value cannot go below 0.
PERCEPTION
Perception stat. base_value
here is the base stat value. The final value cannot go below 0.
INTELLIGENCE
Intelligence stat. base_value
here is the base stat value. The final value cannot go below 0.
SPEED
Character speed. base_value
here is character speed including pain/hunger/weight penalties. Final
speed value cannot go below 25% of base speed.
ATTACK_COST
Melee attack cost. The lower, the better. base_value
here is attack cost for given weapon
including modifiers from stats and skills. The final value cannot go below 25.
MOVE_COST
Movement cost. base_value
here is tile movement cost including modifiers from clothing and traits.
The final value cannot go below 20.
METABOLISM
Metabolic rate. This modifier ignores add
field. base_value
here is PLAYER_HUNGER_RATE
modified by traits. The final value cannot go below 0.
MANA_CAP
Mana capacity. base_value
here is character’s base mana capacity modified by traits. The final
value cannot go below 0.
MANA_REGEN
Mana regeneration rate. This modifier ignores add
field. base_value
here is character’s base
mana gain rate modified by traits. The final value cannot go below 0.
STAMINA_CAP
Stamina capacity. This modifier ignores add
field. base_value
here is character’s base stamina
capacity modified by traits. The final value cannot go below 10% of PLAYER_MAX_STAMINA
.
STAMINA_REGEN
Stamina regeneration rate. This modifier ignores add
field. base_value
here is character’s base
stamina gain rate modified by mouth encumbrance. The final value cannot go below 0.
THIRST
Thirst gain rate. This modifier ignores add
field. base_value
here is character’s base thirst
gain rate. The final value cannot go below 0.
FATIGUE
Fatigue gain rate. This modifier ignores add
field. base_value
here is character’s base fatigue
gain rate. The final value cannot go below 0.
BONUS_DODGE
Additional dodges per turn before dodge penalty kicks in. base_value
here is character’s base
dodges per turn before penalty (usually 1). The final value can go below 0, which results in penalty
to dodge roll.
ARMOR_X
Incoming damage modifier. Applied after Active Defense System bionic but before the damage is
absorbed by items. Note that base_value
here is incoming damage value of corresponding type, so
positive add
and greater than 1 mul
will increase damage received by the character. Each
damage type has its own enchant value:
ARMOR_ACID
ARMOR_BASH
ARMOR_BIO
ARMOR_BULLET
ARMOR_COLD
ARMOR_CUT
ARMOR_ELEC
ARMOR_HEAT
ARMOR_STAB
Item values
ITEM_ATTACK_COST
Attack cost (melee or throwing) for this item. Ignores condition / location, and is always active.
base_value
here is base item attack cost. Note that the final value cannot go below 0.
ITEM_DAMAGE_X
Melee damage of this item. Ignores condition / location, and is always active. base_value
here is
base item damage of corresponding type. Note that the final value cannot go below 0. Only some
damage types are supported:
ITEM_DAMAGE_BASH
ITEM_DAMAGE_CUT
ITEM_DAMAGE_STAB
ITEM_ARMOR_X
Incoming damage modifier for this item, applied before the damage is absorbed by the item. Note that
base_value
here is incoming damage value of corresponding type, so positive add
and greater than
1 mul
will increase damage received by the character. Each damage type has its own enchant
value:
ITEM_ARMOR_ACID
ITEM_ARMOR_BASH
ITEM_ARMOR_BIO
ITEM_ARMOR_BULLET
ITEM_ARMOR_COLD
ITEM_ARMOR_CUT
ITEM_ARMOR_ELEC
ITEM_ARMOR_HEAT
ITEM_ARMOR_STAB
Examples
[
{
"//": "On-hit effect for ink glands mutation, implemented via enchantment.",
"type": "enchantment",
"id": "MEP_INK_GLAND_SPRAY",
"hit_me_effect": [
{
"id": "generic_blinding_spray_1",
"hit_self": false,
"once_in": 15,
"message": "Your ink glands spray some ink into %2$s's eyes.",
"npc_message": "%1$s's ink glands spay some ink into %2$s's eyes."
}
]
},
{
"//": "This one would look good on a katana for an anime mod.",
"type": "enchantment",
"id": "ENCH_ULTIMATE_ASSKICK",
"has": "WIELD",
"condition": "ALWAYS",
"ench_effects": [{ "effect": "invisibility", "intensity": 1 }],
"hit_you_effect": [{ "id": "AEA_FIREBALL" }],
"hit_me_effect": [{ "id": "AEA_HEAL" }],
"mutations": ["KILLER", "PARKOUR"],
"values": [{ "value": "STRENGTH", "multiply": 1.1, "add": -5 }],
"intermittent_activation": {
"effects": [
{
"frequency": "1 hour",
"spell_effects": [
{ "id": "AEA_ADRENALINE" }
]
}
]
}
}
]