Support [movetype][special_note] and [language]special_note_damage_type_*

Refactor special notes for abilities, attack types, movetypes and weapon specials

An easier way of setting special notes in the most common use-cases. Text given
in the following attributes will be collected and added to the special notes
for units and unit types (some of these were added in the previous commit):

* [ability tag name]special_note=
* [language]special_note_damage_type_TYPE=
* [movetype][special_note]note=
* [attack][specials][special tag name]special_note=

It's no longer necessary to put these notes in each unit_type's .cfg file, and
the macros for doing so are now deprecated.

C++ changes
-----

Simplify both unit_type::special_notes and unit::unit_special_notes. Add
utils::stable_unique, similar to std::unique but accepts non-ordered input and
preserves the order in the output.

Remove unit_type::has_special_notes() - callers can instead call
special_notes() and then check if the returned vector is empty, which removes
the need for duplicating code in unit_type.

Trade-off: the new [language]special_note_damage_type_TYPE is likely deprecated in 1.19.
-----

Adding [language]special_note_damage_type_TYPE= uses the same existing design
as [language]type_TYPE=, however both are hacks that don't fit the general
style of WML. It could be better to define a new [damage_type] tag that
supercedes both and also provides a place for specifying the damage icon;
however that won't be done in time for the API freeze for 1.16.

Doing it in the way that this commit does it is a hack, but it's one where
replacing it with the better solution in 1.18 will affect very few UMCs (only
those that define additional damage types). Even in the UMCs that would be
affected, it would likely only be a few changes in a single central file.

Trade-off: NOTE_DEFENSE_CAP is not auto-added
-----

It might be better to auto-add NOTE_DEFENSE_CAP when movetype.cpp detects that
the type has capped values. However as NOTE_SPIRIT already requires
[movetype][special_note], it's simple to use the same mechanism. If we decide
to change it to being auto-added, the current commit greatly reduces the number
of places that would need to change again, as it's now in the [movetype]
instead of the many [unit_type]s using that movetype.
This commit is contained in:
Steve Cotton 2021-05-29 14:29:45 +02:00 committed by Steve Cotton
parent 3568b5ff66
commit 0fdf52058b
75 changed files with 182 additions and 176 deletions

View file

@ -14,7 +14,6 @@
gender=male
usage=mixed fighter
description=_ "Under Darken Volks tutelage, Malin has become adept at wielding necromancy both as a tool to raise an army of undead, and as a means to increase his own, personal power. Malins focus on improving his magical prowess has left little time for him to improve his swordsmanship, but he still holds on to his short sword as his melee weapon of choice."
{NOTE_ARCANE}
{DEFENSE_ANIM "units/apprentice-necromancer-defend.png" "units/apprentice-necromancer.png" {SOUND_LIST:HUMAN_HIT} }
die_sound={SOUND_LIST:HUMAN_DIE}
[attack]

View file

@ -15,7 +15,6 @@
cost=50
usage=mixed fighter
description= _ "Although Malins sword has grown rusty from lack of proper care, he continues to use it for melee combat, perhaps more as a keepsake than an effective weapon. His increasing skill with magic, however, is more than enough to compensate."
{NOTE_ARCANE}
die_sound={SOUND_LIST:HUMAN_DIE}
{DEFENSE_ANIM "units/dark-mage-defend.png" "units/dark-mage.png" {SOUND_LIST:HUMAN_HIT} }
[attack]

View file

@ -25,7 +25,6 @@
cost=35
usage=scout
description= _ "Once great warriors across the plains, these mounted riders atop their skeletal horses were raised from the ground by unholy magic to spread fear and destruction."
{NOTE_DEFENSE_CAP}
die_sound=skeleton-big-die.ogg
[attack]
name=axe

View file

@ -17,7 +17,6 @@
cost=50
usage=fighter
description= _ "The greatest of the men of the plains, Horse Lords are heads of their houses and are respected by all, friend or foe. Their sword can kill most ordinary enemies, and their morning star crushes those who are left."
{NOTE_DEFENSE_CAP}
die_sound=horse-die.ogg
[attack]
name=greatsword

View file

@ -16,7 +16,6 @@
cost=25
usage=fighter
description= _ "The nobles of the men of the plains are trained with the rest of the horsemen to become great warriors. However, they are also trained in commanding their comrades, and they are the ones that become captains of the armies of the Clans."
{NOTE_DEFENSE_CAP}
die_sound=horse-die.ogg
[attack]
name=sword

View file

@ -17,7 +17,6 @@
usage=fighter
description= _ "Leaders of the plains, Mounted Warriors are skilled with the use of the sword and the morning star. Riding horses, they are able to move around the battlefield with great speed, and can provide much needed assistance to different fronts."
die_sound=horse-die.ogg
{NOTE_DEFENSE_CAP}
[attack]
name=greatsword
#textdomain wesnoth-units

View file

@ -31,7 +31,6 @@
cost=19
usage=scout
description= _ "Once great warriors thundering across the plains, these mounted riders atop their skeletal horses were raised from the grave by unholy magic to spread fear and destruction."
{NOTE_DEFENSE_CAP}
die_sound={SOUND_LIST:SKELETON_DIE}
[abilities]
{ABILITY_SUBMERGE}

View file

@ -25,7 +25,6 @@
cost=35
usage=scout
description= _ "Once great warriors across the plains, these mounted riders atop their skeletal horses were raised from the ground by unholy magic to spread fear and destruction."
{NOTE_DEFENSE_CAP}
die_sound=skeleton-big-die.ogg
[attack]
name=axe

View file

@ -31,7 +31,6 @@
cost=19
usage=scout
description= _ "Once great warriors thundering across the plains, these mounted riders atop their skeletal horses were raised from the grave by unholy magic to spread fear and destruction."
{NOTE_DEFENSE_CAP}
die_sound={SOUND_LIST:SKELETON_DIE}
[abilities]
{ABILITY_SUBMERGE}

View file

@ -25,7 +25,6 @@
cost=16
usage=scout
description=""
{NOTE_DEFENSE_CAP}
[abilities]
{ABILITY_SUBMERGE}
[/abilities]

View file

@ -18,7 +18,6 @@
cost=100
usage=mixed fighter
description= _ "An experienced lich can easily tap into the power of the spirit world and throw freezing lightning to devastating effect, or drain the very life force from a body. The power available to a lich like this is awesome to behold. Anyone who encounters an Ancient Lich likely has far worse things to worry about than death!"
{NOTE_ARCANE}
die_sound=lich-die.ogg
{DEFENSE_ANIM "units/ancient-lich/ancient-lich-defend.png" "units/ancient-lich/ancient-lich.png" {SOUND_LIST:LICH_HIT} }
[movement_costs]

View file

@ -77,7 +77,6 @@
do_not_list=no
#textdomain wesnoth-units
description= _ "Except for those with almost supernatural skill, the highest rank a runecrafter can rise to is that of the Dwarvish Runemaster. Striking blows nearly as powerful as those of the best warriors, they would be fearsome without their craft, but with it they are also nigh on invincible, since their runes cause the physical blows of their enemies to deal less damage than would be expected."
{NOTE_ARCANE}
{DEFENSE_ANIM "units/karrag-defend.png" "units/karrag.png" {SOUND_LIST:LICH_HIT} }
die_sound=lich-die.ogg
# empty attack tag to prevent overwriting the hammer attack

View file

@ -23,7 +23,6 @@
cost=30
usage=mixed fighter
description= _ "Named Eyestalks for obvious reasons, these plant-like creatures can focus their gaze onto an unsuspecting victim to draw life energy straight out of them to replenish their own. While almost defenseless against melee attacks, its deadly gaze from afar is not to be underestimated."
{NOTE_ARCANE}
{DEFENSE_ANIM "units/eyestalk-attack-1.png" "units/eyestalk.png" wose-hit.ogg }
[abilities]
{ABILITY_REGENERATES}

View file

@ -23,7 +23,6 @@
{ABILITY_LEADERSHIP}
[/abilities]
description= _ "Leaders of the border guards, mounted commanders command the garrisons that keep peace in the outermost provinces of Wesnoth. As effective leaders and powerful warriors, these men patrol the countryside and eliminate any and all threats to peace in the frontier villages."
{NOTE_DEFENSE_CAP}
die_sound=horse-die.ogg
[attack]
name=lance

View file

@ -23,7 +23,6 @@
{ABILITY_LEADERSHIP}
[/abilities]
description= _ "At scarcely 17 or 18 years of age, squires are not yet full knights, but still have the knowledge and skill to master their mounts whilst in full panoply. Talented squires are sometimes given command of small units in Wesnoth' s army, where they gain experience leading fellow troops and honing their prowess in battle."
{NOTE_DEFENSE_CAP}
die_sound=horse-die.ogg
[attack]
name=spear

View file

@ -24,7 +24,6 @@
{ABILITY_LEADERSHIP}
[/abilities]
description= _ "Switching seamlessly between lance and mace, mounted generals boast tremendous skill in individual combat and can hold their own against even the most powerful opposition. They are masters of their mounts, able to cover great distances quickly on their patrols, and have keen eyes for detecting and eliminating all manner of perilous dangers. Their greatest strength, however, lies in their ability to inspire great courage in their men, who fight fearlessly and tenaciously under their command."
{NOTE_DEFENSE_CAP}
die_sound=horse-die.ogg
[attack]
name=lance

View file

@ -13,7 +13,6 @@
alignment=neutral
cost=20
description= _ "A swirl of dust and desert sand, quick as a wind, impossible to spot when resting and as dangerous as sand storm when riled."
{NOTE_ARCANE}
{DEFENSE_ANIM "units/monsters/dust-devil.png" "units/monsters/dust-devil.png" wose-hit.ogg }
die_sound=groan.wav
movement_type=undeadfly

View file

@ -20,7 +20,6 @@
usage=null
do_not_list=yes
description= _ "Divine Avatars only appear in time of great need. Forms of the Gods themselves, made real in this world for a time, blessed are those who are lucky enough to view such images of power and perfection."
{NOTE_ARCANE}
{DEFENSE_ANIM "halo/eloh-halo-bottom.png~BLIT(halo/eloh-halo-back.png)~BLIT(units/quenoth/eloh.png,0,0)" "halo/eloh-halo-bottom.png~BLIT(halo/eloh-halo-back.png)~BLIT(units/quenoth/eloh.png,0,0)" magicmissile.wav}
die_sound=magic-holy-miss-2.ogg
[attack]

View file

@ -11,7 +11,6 @@
level=3
do_not_list=yes
description= _ "Divine Incarnations are said to be the closest thing to a gods actual presence in this world. They can be both awe-inspiring and terrifying."
{NOTE_ARCANE}
[attack]
damage=9
[/attack]

View file

@ -20,7 +20,6 @@
{UTBS_ABILITY_HEALS}
[/abilities]
description= _ "Faerie and elven magic have oft been aptly associated with life, from which they draw the majority of their power. However, with the death of much of Irdyas flora, the Quenoth Elves were forced to seek another source for their sorcery. In time, they learned to harness the power of the suns Sela and Naia - the twin stars that had razed the forests of Irdya to ashes, yet still spring forth the energy required for sparking life. Those who master this new magic sing of the dual nature of these embodiments of fire: flames that are both life and lifes demise."
{NOTE_ARCANE}
die_sound={SOUND_LIST:ELF_FEMALE_HIT}
[attack]
name=touch

View file

@ -23,7 +23,6 @@
{ABILITY_ILLUMINATES}
[/abilities]
description= _ "In times past, those who stepped beyond the boundary of the worlds of elf and faerie were called Sylphs, mystics with unparalleled knowledge of the secrets of the natural sphere. However, in the harsh new world, the path into the realm of the faerie became no longer a journey into the heart of nature, but a diverging path between light and darkness. Those elves who embrace the burning suns as the fulcrum of life and death learn also to harness their power, transforming into beings imbued with radiant fire. These Sun Sylphs very much embody the power that they wield: light that heals and protects, and flames that smolder with destruction."
{NOTE_ARCANE}
die_sound={SOUND_LIST:ELF_FEMALE_HIT}
[attack]
name=touch

View file

@ -16,7 +16,5 @@
description= _ "It is one of the greater mercies of creation that a human soul is immutable, and cannot be destroyed. However, the many things a necromancer can do, despite this, are entirely horrifying.
Trapped within a shroud of vile enchantments, a spirit likens unto the wind in the sails of a ship. The contrivance that results from this prison is an unfailing servant, which can be bound to whatever task their master sees fit."
{NOTE_SPIRIT}
{NOTE_ARCANE}
{NOTE_ETHEREAL}
[/unit_type]

View file

@ -18,7 +18,6 @@
[/hides]
[/abilities]
description= _ "The purpose of the masks that these creatures wear is unknown, as is the countenance that they obscure. These terrible forms are rarely seen by the living, and those who live to speak of them had no leisure to study their foe."
{NOTE_SPIRIT}
{NOTE_ETHEREAL}
[special_note]
note=_"SPECIAL_NOTE^Unlike normal Nightgaunts, Ethereal Nightgaunts cannot hide at night."

View file

@ -21,7 +21,6 @@
description= _ "When light came into the world and gave form to the unknown, fear was forced to retreat into darkness. Since that day, the shadows of the world have held terror for humanity, though it knows not why.
That is a question which is easily answered by a necromancer."
{NOTE_SPIRIT}
{NOTE_ETHEREAL}
[special_note]
note=_"SPECIAL_NOTE^ Unlike normal Shadows, Ethereal Shadows cannot hide at night."

View file

@ -14,6 +14,5 @@
description= _ "Sometimes called the hollow men, spectres form the right arm of their masters power. These abominations are a rightful terror to the living, and keep a sleepless vigil over their masters domain.
The creation of these is no mean feat; the real danger in encountering one is that it is likely only the harbinger of a much more dangerous force that will follow in its wake."
{NOTE_SPIRIT}
{NOTE_ETHEREAL}
[/unit_type]

View file

@ -15,6 +15,5 @@
description= _ "These tortured forms of what were once warriors are among the most terrifying things a necromancer can create, for a sword will cleave right through them, as through air itself. What inspires such fear is the thought that these beasts are invincible, a belief that is actually far from the truth.
Because of this, a means was made by which the enchantments that drive these creatures could renew themselves through the very thing which threatened them."
{NOTE_SPIRIT}
{NOTE_ETHEREAL}
[/unit_type]

View file

@ -14,6 +14,4 @@
[/movement_costs]
experience=30
description= _ "Haunts are the tortured souls of those who have died suddenly and never been laid to rest. Paralyzed by the shock of their death, they are cursed to forever haunt the place of their death and relive their final moments over and over and over."
{NOTE_SPIRIT}
{NOTE_ARCANE}
[/unit_type]

View file

@ -16,7 +16,6 @@
cost=62
usage=fighter
description= _ "No one is quite sure how spider liches are created, but they are a horrific sight to behold. Crawling around on huge skeletal legs, and wielding huge magical staves, these abominations are fearsome undead foes. "
{NOTE_ARCANE}
die_sound=lich-die.ogg
[attack]
name=touch

View file

@ -32,7 +32,6 @@
cost=19
usage=scout
description= _ "Once great warriors across the plains, these mounted riders atop their skeletal horses were raised from the sands by unholy magic to spread fear and destruction."
{NOTE_DEFENSE_CAP}
die_sound={SOUND_LIST:SKELETON_DIE}
[attack]
name=axe

View file

@ -32,7 +32,7 @@ A poisoned unit cannot be cured of its poison by a healer, and must seek the car
[/heals]
#enddef
#define UTBS_ABILITY_EXTRA_HEAL
#define UTBS_ABILITY_EXTRA_HEAL_NO_NOTES
[heals]
value=8
id=healing
@ -43,7 +43,36 @@ A poisoned unit cannot be cured of its poison by a healer, and must seek the car
A unit cared for by this healer may heal up to 8 HP per turn, or stop poison from taking effect for that turn.
A poisoned unit cannot be cured of its poison by a healer, and must seek the care of a village or a unit that can cure."
affect_self=no
poison=slowed
[affect_adjacent]
[filter]
[not]
status=dehydration_slowed_by_healer
[/not]
[/filter]
[/affect_adjacent]
[/heals]
#enddef
#define UTBS_ABILITY_EXTRA_HEAL
{UTBS_ABILITY_EXTRA_HEAL_NO_NOTES}
[+heals]
special_note=_"This unit is capable of basic healing and slowing dehydration."
[/heals]
#enddef
#define UTBS_ABILITY_SUPER_HEAL_NO_NOTES
[heals]
value=12
id=healing
affect_allies=yes
name= _ "heals +12"
female_name= _ "female^heals +12"
description= _ "This unit combines herbal remedies with magic to heal units more quickly than is normally possible on the battlefield.
A unit cared for by this healer may heal up to 12 HP per turn, or stop poison from taking effect for that turn.
A poisoned unit cannot be cured of its poison by a healer, and must seek the care of a village or a unit that can cure."
affect_self=no
poison=slowed
[affect_adjacent]
@ -57,26 +86,9 @@ A poisoned unit cannot be cured of its poison by a healer, and must seek the car
#enddef
#define UTBS_ABILITY_SUPER_HEAL
[heals]
value=12
id=healing
affect_allies=yes
name= _ "heals +12"
female_name= _ "female^heals +12"
description= _ "This unit combines herbal remedies with magic to heal units more quickly than is normally possible on the battlefield.
A unit cared for by this healer may heal up to 12 HP per turn, or stop poison from taking effect for that turn.
A poisoned unit cannot be cured of its poison by a healer, and must seek the care of a village or a unit that can cure."
{UTBS_ABILITY_SUPER_HEAL_NO_NOTES}
[+heals]
special_note=_"This unit is capable of basic healing and slowing dehydration."
affect_self=no
poison=slowed
[affect_adjacent]
[filter]
[not]
status=dehydration_slowed_by_healer
[/not]
[/filter]
[/affect_adjacent]
[/heals]
#enddef
@ -87,17 +99,15 @@ A poisoned unit cannot be cured of its poison by a healer, and must seek the car
#enddef
#define UTBS_ABILITY_CURES
{ABILITY_UNPOISON}
{UTBS_NOTE_CURES}
{INTERNAL:ABILITY_UNPOISON_NO_NOTES}
{UTBS_ABILITY_EXTRA_HEAL}
{NOTE_ABILITY_REMOVE heals}
{UTBS_NOTE_CURES}
#enddef
#define UTBS_ABILITY_SUPER_CURES
{ABILITY_UNPOISON}
{UTBS_NOTE_CURES}
{INTERNAL:ABILITY_UNPOISON_NO_NOTES}
{UTBS_ABILITY_SUPER_HEAL}
{NOTE_ABILITY_REMOVE heals}
{UTBS_NOTE_CURES}
#enddef
#textdomain wesnoth-utbs

View file

@ -1,8 +1,7 @@
#textdomain wesnoth-help
# Ability macros to be included in the SingleWML description of a unit.
#define ABILITY_HEALS
# Canned definition of the heal+4 ability to be included in an [abilities] clause.
#define INTERNAL:ABILITY_HEALS_NO_NOTES
[heals]
value=4
id=healing
@ -13,7 +12,6 @@
A unit cared for by this healer may heal up to 4 HP per turn, or stop poison from taking effect for that turn.
This ability will not cure an affected unit of poison, however, only delay its effect."
special_note={INTERNAL:SPECIAL_NOTES_HEALS}
affect_self=no
poison=slowed
[affect_adjacent]
@ -21,7 +19,15 @@ This ability will not cure an affected unit of poison, however, only delay its e
[/heals]
#enddef
#define ABILITY_EXTRA_HEAL
#define ABILITY_HEALS
# Canned definition of the heal+4 ability to be included in an [abilities] clause.
{INTERNAL:ABILITY_HEALS_NO_NOTES}
[+heals]
special_note={INTERNAL:SPECIAL_NOTES_HEALS}
[/heals]
#enddef
#define INTERNAL:ABILITY_EXTRA_HEAL_NO_NOTES
[heals]
value=8
id=healing
@ -32,7 +38,6 @@ This ability will not cure an affected unit of poison, however, only delay its e
A unit cared for by this healer may heal up to 8 HP per turn, or stop poison from taking effect for that turn.
This ability will not cure an affected unit of poison, however, only delay its effect."
special_note={INTERNAL:SPECIAL_NOTES_EXTRA_HEAL}
affect_self=no
poison=slowed
[affect_adjacent]
@ -40,7 +45,14 @@ This ability will not cure an affected unit of poison, however, only delay its e
[/heals]
#enddef
#define ABILITY_UNPOISON
#define ABILITY_EXTRA_HEAL
{INTERNAL:ABILITY_EXTRA_HEAL_NO_NOTES}
[+heals]
special_note={INTERNAL:SPECIAL_NOTES_EXTRA_HEAL}
[/heals]
#enddef
#define INTERNAL:ABILITY_UNPOISON_NO_NOTES
# Canned definition of the cure-poison ability to be included
# in an [abilities] clause.
[heals]
@ -49,7 +61,6 @@ This ability will not cure an affected unit of poison, however, only delay its e
name= _ "cures"
female_name= _ "female^cures"
description= _ "A curer can cure a unit of poison, although that unit will receive no additional healing on the turn it is cured of the poison."
special_note={INTERNAL:SPECIAL_NOTES_UNPOISON}
affect_self=no
poison=cured
[affect_adjacent]
@ -57,15 +68,21 @@ This ability will not cure an affected unit of poison, however, only delay its e
[/heals]
#enddef
#define ABILITY_UNPOISON
{INTERNAL:ABILITY_UNPOISON_NO_NOTES}
[+heals]
special_note={INTERNAL:SPECIAL_NOTES_UNPOISON}
[/heals]
#enddef
#define ABILITY_CURES
# Canned definition of the cure ability (which entails heal+8) to be
# included in an [abilities] clause..
{ABILITY_UNPOISON}
{INTERNAL:ABILITY_UNPOISON_NO_NOTES}
{INTERNAL:ABILITY_EXTRA_HEAL_NO_NOTES}
[+heals]
special_note={INTERNAL:SPECIAL_NOTES_CURES}
[/heals]
{ABILITY_EXTRA_HEAL}
{NOTE_ABILITY_REMOVE heals}
#enddef
#define ABILITY_REGENERATES

View file

@ -1,6 +1,6 @@
#textdomain wesnoth-help
#define SPECIAL_NOTES
#deprecated 2 1.17 Use [special_note]note= tags instead to apply special notes, or use the {NOTE_*} macros (note the singular).
#deprecated 4 Use [special_note]note= tags instead to apply special notes, or use the {NOTE_*} macros (note the singular).
"
"+_"Special Notes:"#enddef
@ -19,6 +19,10 @@ _"Spirits have very unusual resistances to damage, and move quite slowly over op
#define INTERNAL:SPECIAL_NOTES_ARCANE
_"This units arcane attack deals tremendous damage to magical creatures, and even some to mundane creatures."#enddef
[language]
special_note_damage_type_arcane={INTERNAL:SPECIAL_NOTES_ARCANE}
[/language]
#define INTERNAL:SPECIAL_NOTES_HEALS
_"This unit is capable of basic healing."#enddef
@ -105,30 +109,19 @@ _"This unit has a defense cap on certain terrain types — it cannot achieve a h
# wmlscope: stop ignoring
# New versions start here!
#define NOTE_REMOVE
#deprecated 4 This does not work on notes added by abilities, weapon specials or damage types
[+special_note]
remove=yes
[/special_note]
#enddef
#define NOTE_ABILITY_REMOVE ABILITY
[+{ABILITY}]
special_note=""
[/{ABILITY}]
#enddef
#define NOTE_SPIRIT
[special_note]
note={INTERNAL:SPECIAL_NOTES_SPIRIT}
[/special_note]
#deprecated 4 This note is now added automatically.
#enddef
#define NOTE_ARCANE
[special_note]
note={INTERNAL:SPECIAL_NOTES_ARCANE}
[/special_note]
#deprecated 4 This note is now added automatically.
#enddef
#define NOTE_HEALS
@ -244,19 +237,17 @@ _"This unit has a defense cap on certain terrain types — it cannot achieve a h
#enddef
#define NOTE_DEFENSE_CAP
[special_note]
note={INTERNAL:SPECIAL_NOTES_DEFENSE_CAP}
[/special_note]
#deprecated 4 This note is now added automatically.
#enddef
# Deprecated versions here
#define SPECIAL_NOTES_SPIRIT
#deprecated 2 1.17 Use {NOTE_SPIRIT} instead (note the singular), which generates a [special_note] tag.
#deprecated 2 1.17 This note is now added automatically.
{INTERNAL:SPECIAL_NOTES_SPIRIT}#enddef
#define SPECIAL_NOTES_ARCANE
#deprecated 2 1.17 Use {NOTE_ARCANE} instead (note the singular), which generates a [special_note] tag.
#deprecated 2 1.17 This note is now added automatically.
{INTERNAL:SPECIAL_NOTES_ARCANE}#enddef
#define SPECIAL_NOTES_HEALS
@ -372,5 +363,5 @@ _"This unit has a defense cap on certain terrain types — it cannot achieve a h
{INTERNAL:SPECIAL_NOTES_POISON}#enddef
#define SPECIAL_NOTES_DEFENSE_CAP
#deprecated 2 1.17 Use {NOTE_DEFENSE_CAP} instead (note the singular), which generates a [special_note] tag.
#deprecated 2 1.17 This note is now added automatically.
{INTERNAL:SPECIAL_NOTES_DEFENSE_CAP}#enddef

View file

@ -676,6 +676,9 @@ The life span of the wose is unknown, although the most ancient members of this
cold=100
arcane=80
[/resistance]
[special_note]
note={INTERNAL:SPECIAL_NOTES_DEFENSE_CAP}
[/special_note]
[/movetype]
[movetype]
@ -1187,6 +1190,9 @@ The life span of the wose is unknown, although the most ancient members of this
cold=30
arcane=110
[/resistance]
[special_note]
note={INTERNAL:SPECIAL_NOTES_SPIRIT}
[/special_note]
[/movetype]
#only used in some UMC

View file

@ -17,7 +17,6 @@
cost=55
usage=mixed fighter
description= _ "In the context of Elven magic, the notion of enchanting is a little bit misleading since it almost always refers to manipulation of an objects essence for the purpose of divination or insight. A favorite among the corresponding enchantresses is imbuing their natural surroundings with the breath of the arcane, yielding secret groves that exist at the juncture between the corporeal and ethereal worlds. These mysterious domains are kept by their equally enigmatic caretakers, who mostly keep to themselves away from prying eyes. Though rather reserved and unsociable, these elves are well-regarded by most of their kin and sometimes called upon for guidance especially in unusual or peculiar matters."
{NOTE_ARCANE}
die_sound={SOUND_LIST:ELF_FEMALE_HIT}
[resistance]
arcane=90

View file

@ -18,7 +18,6 @@
description= _ "While the duality of Elven magic manifests itself most strongly in the split paths between the corporeal and arcane worlds, the same dichotomy is reflected in the ranks of Elven nobility. In part due to their use of faerie fire, most lords find themselves strongly aligned with enchantresses, thus associating themselves with the aspects of insight and destruction. Though not the same thing as wisdom, a lords intuition is usually to be respected, and his wrath, feared. This only grows more true with age, as time brings acuity to the elfs mind and senses.
Outsiders notions that an upper class of High Lords exists is usually a fallacy resulting from the great disparity in both perception and power that these experienced elves possess. In actuality, the hierarchy of Elvish rule differs between enclaves and situationally between times of peace and war. The only thing that can be said for certain is that the acumen of these lords is invaluable for maintaining the prosperity of Elvish rule, whether or not they sit at the top of the chain of command."
{NOTE_ARCANE}
die_sound={SOUND_LIST:ELF_HIT}
[defend]
start_time=-151

View file

@ -18,7 +18,6 @@
description= _ "Succession among the Elvish nobility is a complex process that varies somewhat between the different enclaves of Elvenkind. Typically, the future leaders of the elves are tasked with governing the three-fold aspects of Elvish society: warriors and rangers who defend the forests, peaceable civilians who shy away from combat altogether, and the collective group of healers and mystics who study the art of faerie magic. Being able to reconcile the differences between these factions and effectively lead their people requires considerable personal merit and a deep insight into elves of all kinds. To this end, lords are typically the only male elves who are allowed to learn any amount of faerie magic, which is traditionally taught solely to female shamans.
Though some enclaves, such as the northern Lintanir grove, maintain their nobility via bloodline, others such as the mighty Wesmere elves elect new lords on each new generation. In either case, the nobles position is rarely an absolute one, and they are expected to lead more by diplomacy and wisdom rather than force."
{NOTE_ARCANE}
die_sound={SOUND_LIST:ELF_HIT}
{DEFENSE_ANIM_RANGE "units/elves-wood/lord-defend.png" "units/elves-wood/lord.png" {SOUND_LIST:ELF_HIT} melee}
{DEFENSE_ANIM_RANGE "units/elves-wood/lord-magic-defend.png" "units/elves-wood/lord-magic.png" {SOUND_LIST:ELF_HIT} ranged}

View file

@ -17,7 +17,6 @@
cost=32
usage=mixed fighter
description= _ "Elven magic most commonly diverges among two paths — manipulation of the natural, or corporeal world, and divination into the arcane plane. The latter, as a power that is difficult to control and ill-understood even by most of its practitioners, is not often sought after by the Elves. Wielders of the arcane face significant risk in studying the volatile nature of their discipline and quickly learn to respect the disruptive power of their craft. This destructive nature most commonly manifests itself as gouts of faerie fire, which is among the most readily mastered skills for an Elvish sorceress. While a rather superficial application of this art, the Elves nonetheless hold the arcane flame in high regard and are careful to utilize it with judicious caution."
{NOTE_ARCANE}
die_sound={SOUND_LIST:ELF_FEMALE_HIT}
[resistance]
arcane=100

View file

@ -19,7 +19,6 @@
cost=67
usage=mixed fighter
description= _ "Tremendously powerful in unfathomable ways, the sage-like Sylphs are masters of manipulating the bridge between the mundane and arcane worlds. Long years spent peering into the ethereal realm have eroded the ability of these elves to view the physical world; in return, they are granted an abstract sight, gaining the ability to view one or even several different aspects of realitys essence. Like the many shards of a broken mirror, the myriad fractures of the material world reflect the light of the arcane through its many different facets. Careful practice allows one to follow these strands of light from pane to pane, observing how the outcome of physical reality evolves with each choice made of free will. While direct weaving of the connecting fabric is usually impossible to achieve, indirect manipulation is feasible by machination in the corporeal plane where the reflection of the arcane plane is strongest. The ability of a Sylph to locate these reflection pools and steer them is one of her greatest — and most feared — abilities."
{NOTE_ARCANE}
die_sound={SOUND_LIST:ELF_FEMALE_HIT}
[resistance]
arcane=80

View file

@ -18,7 +18,6 @@
cost=58
usage=fighter
description= _ "Grand Knights have reached the acme of skill with sword and lance. Wearing full plate, and riding steeds bred more for power than for speed, these warriors form the core of any serious cavalry force. A grand knight at the head of a charge is a terrifying sight for infantry, and is often enough to break right through a defensive line."
{NOTE_DEFENSE_CAP}
die_sound=horse-die.ogg
[attack]
name=sword

View file

@ -17,7 +17,6 @@
cost=38
usage=fighter
description= _ "Horsemen of skill and discipline are promoted to Knights. Veterans of combat, they have seen the often-fatal results of a failed charge, and have learnt discretion in its use. Knights, therefore, carry swords in their armament, and practice tactics which, although requiring of much more patience, are less risky than a charge. Their lances are still at the ready, however, and growing experience with these weapons makes them deadlier at the tilt."
{NOTE_DEFENSE_CAP}
die_sound=horse-die.ogg
[attack]
name=sword

View file

@ -17,7 +17,6 @@
cost=44
usage=fighter
description= _ "Lancers are among the bravest and most feared riders in all of Wesnoth. Clad in minimal armor, they free themselves to ride swiftly, faster than any of their peers. The daring tactics they employ are like a double-edged sword, for they often win either glory or a swift death. Lancers excel in hunting down infantrymen who have made the mistake of breaking formation, and in piercing defensive lines. However, they have limited use in defense."
{NOTE_DEFENSE_CAP}
die_sound=horse-die.ogg
[attack]
name=lance

View file

@ -20,8 +20,6 @@
description= _ "Knights of the highest virtue, Paladins have sworn their strength not to king and crown, but to ideals themselves; of chivalry, and the stewardship of everything that is good. They may serve in the armies of the world, but their first loyalties often lie with groups of their own making; secret, monastic orders that cross political and cultural boundaries. Rulers are sometimes wary of them, for the paladins loyalty is only as strong as the lieges apparent virtue. This has led the more darkly ambitious to either attempt to defame and disperse these groups, or more rarely, to conjure elaborate deceptions to keep these otherwise staunchly loyal troops in service.
Full paladins are generally not quite as fearsome as the Grand Knights that champion most armies, but they are first-class fighters nonetheless. Additionally, their wisdom and piety grants these warrior monks certain curious abilities; a paladin is very powerful in fighting magical or unnatural things, and most have some skill at medicine and healing."
{NOTE_ARCANE}
{NOTE_DEFENSE_CAP}
die_sound=horse-die.ogg
[resistance]
arcane=40

View file

@ -16,7 +16,6 @@
cost=23
usage=fighter
description= _ "Often hailing from the wilder and untamed regions of Wesnoth, Horsemen are trained from childhood to ride and to follow a strict code of honor. A charge made by a horseman is a powerful though risky tactic, the worth of which has been proven time and time again on the battlefield. Horsemen excel against most infantry, especially those who have fallen out of line, but must take care against both spearmen and archers for whom their large size provide inviting targets."
{NOTE_DEFENSE_CAP}
die_sound=horse-die.ogg
[attack]

View file

@ -18,7 +18,6 @@
#extra resistance for these units
usage=scout
description= _ "Cavaliers are masters at the use of both sword and crossbow from horseback. Their combination of striking power and mobility is fearsome, and they have a reputation for dash and aggressiveness to match it. The daring deeds of Cavaliers are the subject of many a tale and song."
{NOTE_DEFENSE_CAP}
die_sound=horse-die.ogg
[movement_anim]
start_time=0

View file

@ -19,7 +19,6 @@
description= _ "Cavalrymen are distinguished from horsemen by their tactics and equipment. A cavalryman wears heavier armor, and carries a sword and shield, rather than a lance. Their tactics do not include charging; instead they maneuver to slash with a sword, using both horse and rider as an effective tool of melee.
Cavalrymen are very useful for taking and holding positions on open ground, for screening friendly soldiers, and also for scouting work."
{NOTE_DEFENSE_CAP}
die_sound=horse-die.ogg
[movement_anim]
start_time=0

View file

@ -17,7 +17,6 @@
#extra resistance for these units
usage=scout
description= _ "The more talented cavalrymen in the armies of Wesnoth are trained in the use of the crossbow, and matched with much more powerful steeds. Well-armored, and skilled in the use of their swords, these soldiers can drive forward and hold the ground they take. Their mobility and resilience make them of great value on the battlefield."
{NOTE_DEFENSE_CAP}
die_sound=horse-die.ogg
[movement_anim]
start_time=0

View file

@ -21,7 +21,6 @@ Though not trained for combat, they are a potent ally against magical or unnatur
[special_note]
note= _ "Compared to other mages, White Mages have a higher resistance to arcane attacks."
[/special_note]
{NOTE_ARCANE}
die_sound={SOUND_LIST:HUMAN_DIE}
{DEFENSE_ANIM "units/human-magi/white-mage-defend.png" "units/human-magi/white-mage.png" {SOUND_LIST:HUMAN_OLD_HIT} }
[abilities]

View file

@ -23,7 +23,6 @@ Following a strict code of piety and honor, these men and women work tirelessly
[special_note]
note= _ "Compared to other mages, Mages of Light have a higher resistance to arcane attacks."
[/special_note]
{NOTE_ARCANE}
die_sound={SOUND_LIST:HUMAN_OLD_DIE}
{DEFENSE_ANIM "units/human-magi/white-cleric-defend.png" "units/human-magi/white-cleric.png" {SOUND_LIST:HUMAN_OLD_HIT} }
[abilities]

View file

@ -21,7 +21,6 @@
cost=57
usage=healer
description= _ "Years of devotion may endow a priestess with great wisdom on the workings of the world, and grants some the favor of the light. The power thus given to these ladies of the water is a recurring motif in tale and song; such as the that of the knights of the silver spire, cornered and slain to a man at the banks of the Alavynne, but who rode again the next day, in full number, and wrought the downfall of the crimson duke."
{NOTE_ARCANE}
die_sound=mermaid-die.ogg
{DEFENSE_ANIM "units/merfolk/diviner-defend2.png" "units/merfolk/diviner-defend1.png" mermaid-hit.ogg }
[abilities]

View file

@ -19,7 +19,6 @@
cost=38
usage=healer
description= _ "Among merfolk, mysticism is generally left to the mermaids, who are more inclined to it. It is they who dedicate themselves to the ideal of bringing peace and life to the world, and to the arts which make that possible. Their piety also grants them certain powers, allowing them to guard their people against magical or unnatural things."
{NOTE_ARCANE}
die_sound=mermaid-die.ogg
{DEFENSE_ANIM "units/merfolk/priestess-defend2.png" "units/merfolk/priestess-defend1.png" mermaid-hit.ogg }
[abilities]

View file

@ -99,7 +99,6 @@
movement=9
cost=18
description=_ "Some horses have a white color, and they are merely white horses. But there exist a special breed, found only in the wild woods, that are White Horses. As if blessed by the faerie world, they have a grace and agility not found in their more common relatives."
{NOTE_DEFENSE_CAP}
{DEFENSE_ANIM "units/monsters/horse/horse-defend-2.png{HORSE_WHITE_IPF}" "units/monsters/horse/horse-defend-1.png{HORSE_WHITE_IPF}" {SOUND_LIST:HORSE_HIT} }
[attack_anim]
[filter_attack]

View file

@ -23,7 +23,6 @@
cost=25
usage=scout
description=_ "The true nature of Black Horses is impossible to discern, but the fire in their eyes and the unnerving, unnatural sound of their calls suggest they are malevolent spirits."
{NOTE_DEFENSE_CAP}
die_sound=horse-die.ogg
[defense]
village=60

View file

@ -18,7 +18,6 @@
cost=25
usage=scout
description=_ "Great Horses need a better description."
{NOTE_DEFENSE_CAP}
die_sound=horse-die.ogg
[defense]
village=60

View file

@ -191,7 +191,6 @@
profile=portraits/undead/zombie-horse.png
{UNIT_BODY_SOULLESS_STATS mounted 6 28}
{UNIT_BODY_SOULLESS_GRAPHICS soulless-horse}
{NOTE_DEFENSE_CAP}
[/variation]
[variation]
@ -201,7 +200,6 @@
profile=portraits/undead/zombie-rider.png
{UNIT_BODY_SOULLESS_STATS mounted 5 33}
{UNIT_BODY_SOULLESS_GRAPHICS soulless-mounted}
{NOTE_DEFENSE_CAP}
[/variation]
[variation]

View file

@ -213,7 +213,6 @@
profile=portraits/undead/zombie-horse.png
{UNIT_BODY_WALKING_CORPSE_STATS mounted 6 18}
{UNIT_BODY_WALKING_CORPSE_GRAPHICS zombie-horse}
{NOTE_DEFENSE_CAP}
[/variation]
[variation]
@ -223,7 +222,6 @@
profile=portraits/undead/zombie-rider.png
{UNIT_BODY_WALKING_CORPSE_STATS mounted 5 21}
{UNIT_BODY_WALKING_CORPSE_GRAPHICS zombie-mounted}
{NOTE_DEFENSE_CAP}
[/variation]
[variation]

View file

@ -16,7 +16,6 @@
cost=100
usage=mixed fighter
description= _ "A lich that accrues enough power over its newfound immortal lifespan becomes one who can stain souls with despair and sow ruin across the world. Invariably in command of a nigh-limitless horde of risen warriors and undead monsters, a lich of this order has a mastery of dark sorcery that can bring dread to the most storied magi of human and elven kind. Such a figure usually marks a dark and bloody chapter in history, and in those times of need, it is only through the tireless efforts of the most valiant heroes that the rise of an Ancient Lich has not led to the shadows ruling the world for the rest of time."
{NOTE_ARCANE}
die_sound=lich-die.ogg
{DEFENSE_ANIM "units/undead-necromancers/ancient-lich-defend.png" "units/undead-necromancers/ancient-lich.png" {SOUND_LIST:LICH_HIT} }
[movement_costs]

View file

@ -22,7 +22,6 @@
description= _ "To attract any practitioners, the lure of black magic must be a great prize indeed, for anyone caught practicing the art in the civilized world is subject to a death sentence. And yet there are those who pursue this art, for the prize offered is nothing less than immortality. Hidden away in secret cults, or initiated into the dark orders of the underworld, the training which these fanatics must endure often drives them to exhaustion and enfeeblement.
In such condition, their only weapon is the craft they have so committed themselves to learning."
{NOTE_ARCANE}
die_sound={SOUND_LIST:HUMAN_DIE}
{DEFENSE_ANIM "units/undead-necromancers/adept-defend-2.png" "units/undead-necromancers/adept-defend-1.png" {SOUND_LIST:HUMAN_HIT} }
[attack]

View file

@ -18,7 +18,6 @@
description= _ "The dread inspired by black magic is enhanced by the secrecy and fell rumors which surround it. Dark sorcerers have begun to unlock the secrets of life and death, the latter of which is all too easy to inflict. This labor gives the first glimmerings of the connection between the soul and inert matter, and the first successful experiments in manipulating this bond. The terrible unknown that lurks beyond death is glimpsed, and will inevitably be fathomed.
Despite any design they may have of using this to wrest their own immortality from natures grasp, the first results of their work have immediate, and unpleasant applications. The life they breathe into dead matter can create servants for them, servants which will work, but which will also kill, and will never question their masters. These creations have a loyalty any tyrant would dream of, and it is tempting to those with even the slightest desire for power."
{NOTE_ARCANE}
die_sound={SOUND_LIST:HUMAN_DIE}
{DEFENSE_ANIM "units/undead-necromancers/dark-sorcerer-defend.png" "units/undead-necromancers/dark-sorcerer.png" {SOUND_LIST:HUMAN_OLD_HIT} }
[recruiting_anim]
@ -150,7 +149,6 @@ Despite any design they may have of using this to wrest their own immortality fr
description= _ "The dread inspired by black magic comes chiefly from how little is known about it by the common man. Dark sorceresses have begun to unlock the secrets of life and death, the latter of which is all too easy to inflict. This labor gives the first glimmerings of the connection between the soul and inert matter, and the first successful experiments in manipulating this bond. The terrible unknown that lurks beyond death is glimpsed, and will inevitably be fathomed.
Despite any design they may have of using this to wrest their own immortality from natures grasp, the first results of their work have immediate, and unpleasant applications. The life they breathe into dead matter can create servants for them, servants which will work, but which will also kill, and will never question their mistress. These creations have a loyalty any tyrant would dream of, and it is tempting to those with even the merest desire for power."
{NOTE_ARCANE}
die_sound={SOUND_LIST:HUMAN_FEMALE_DIE}
{DEFENSE_ANIM "units/undead-necromancers/dark-sorcerer+female-defend.png" "units/undead-necromancers/dark-sorcerer+female.png" {SOUND_LIST:HUMAN_FEMALE_HIT} }
[recruiting_anim]

View file

@ -22,7 +22,6 @@
description= _ "A lich is the physical embodiment of black magics first goal: the quest to achieve immortality. Though a great deal is sacrificed in the rebirth, in becoming a lich one cheats death of that which truly gives it terror. For it is the mind that is retained, and the spirit which follows, though the body may wither away.
It is not known, save perhaps by the inner circles of necromancy, whether life is prolonged indefinitely or simply extended. The fact that this question can be raised at all is a testament to the magnitude of what their order has achieved."
{NOTE_ARCANE}
die_sound=lich-die.ogg
{DEFENSE_ANIM "units/undead-necromancers/lich-defend.png" "units/undead-necromancers/lich.png" {SOUND_LIST:LICH_HIT} }
[movement_costs]

View file

@ -19,7 +19,6 @@
description= _ "One of the pinnacles of what is considered black magic is the art of necromancy, the terrible ability to awaken the dead with false life. This discovery alone caused humanitys condemnation of black magic, for the nightmarish things it has made real have given fear a vast new arsenal.
This ability, in all aspects, is the first step towards cheating death of its ultimate prize."
{NOTE_ARCANE}
die_sound={SOUND_LIST:HUMAN_OLD_DIE}
{DEFENSE_ANIM "units/undead-necromancers/necromancer-defend.png" "units/undead-necromancers/necromancer.png" {SOUND_LIST:HUMAN_OLD_HIT} }
[attack]

View file

@ -28,7 +28,6 @@
cost=28
usage=scout
description= _ "Riding the bones of ostrich-like large birds once used as mounts by a lost civilization, the skeletal Chocobones can move faster than most cavalry units."
{NOTE_DEFENSE_CAP}
die_sound={SOUND_LIST:SKELETON_DIE}
{DEFENSE_ANIM "units/undead-skeletal/chocobone-defend-2.png" "units/undead-skeletal/chocobone-defend-1.png" {SOUND_LIST:SKELETON_HIT} }
[attack]

View file

@ -15,8 +15,6 @@
cost=19
usage=scout
description= _ "Enslaved within a shroud of enchantments, a trapped spirit may be likened to the wind in the sails of a ship. This damned vessel becomes an unfailing servant which can be bound to whatever task their master sees fit."
{NOTE_SPIRIT}
{NOTE_ARCANE}
die_sound=wail-long.wav
[defend]
start_time=-126

View file

@ -16,7 +16,6 @@
cost=52
usage=scout
description= _ "The purpose of the masks that these creatures wear is unknown, as is the countenance that they obscure. These terrible forms are rarely seen by the living, and those who live to speak of them had no leisure to study their foe."
{NOTE_SPIRIT}
die_sound=wail-long.wav
{DEFENSE_ANIM "units/undead/nightgaunt-defend.png" "units/undead/nightgaunt.png" wail.wav }
[abilities]

View file

@ -17,7 +17,6 @@
description= _ "When light came into the world and gave form to the unknown, fear was forced to retreat into darkness. Since that day, the shadows of the world have held terror for humanity, though it knows not why.
That is a question which is easily answered by a necromancer."
{NOTE_SPIRIT}
die_sound=wail-long.wav
[abilities]
{ABILITY_NIGHTSTALK}

View file

@ -19,8 +19,6 @@
description= _ "Sometimes called the hollow men, spectres form the right arm of their masters powers. They are an unholy terror to the living, for they are quite as deadly as their appearance suggests.
The creation of these is itself no mean feat, but the real danger in encountering one is that it is likely only the harbinger of a much more dangerous force that will follow in its wake."
{NOTE_SPIRIT}
{NOTE_ARCANE}
die_sound=wail-long.wav
[standing_anim]
start_time=0

View file

@ -15,8 +15,6 @@
cost=38
usage=scout
description= _ "These shades of what were once warriors are among the most terrifying things a necromancer can create, for a sword will cleave right through them as if through air, seemingly without doing harm. It is the thought that these foes are invincible which is so frightening, a notion that is fortunately far from the truth."
{NOTE_SPIRIT}
{NOTE_ARCANE}
die_sound=wail-long.wav
[attack]
name=baneblade

View file

@ -25,6 +25,11 @@
name="vision_costs"
{ANY_KEY int}
[/tag]
[tag]
name="special_note"
max="infinite"
{REQUIRED_KEY note t_string}
[/tag]
[/tag]
# For adding a new terrain type or resistance type, forgetting to add a default is probably an error.

View file

@ -560,9 +560,9 @@ std::string unit_topic_generator::operator()() const {
// Print the detailed description about the unit.
ss << "\n\n" << detailed_description;
if(type_.has_special_notes()) {
if(const auto notes = type_.special_notes(); !notes.empty()) {
ss << "\n\n" << _("Special Notes:") << '\n';
for(const auto& note : type_.special_notes()) {
for(const auto& note : notes) {
ss << "" << note << '\n';
}
}

View file

@ -90,6 +90,16 @@ const t_string& symbol_table::operator[](const char* key) const
return (*this)[std::string(key)];
}
utils::string_map::const_iterator symbol_table::find(const std::string& key) const
{
return strings_.find(key);
}
utils::string_map::const_iterator symbol_table::end() const
{
return strings_.end();
}
bool load_language_list()
{
config cfg;

View file

@ -67,8 +67,19 @@ typedef std::vector<language_def> language_list;
struct symbol_table
{
/**
* Look up the string mappings given in [language] tags. If the key is not
* found, fall back to returning a string that's only meant for developers
* to see.
*/
const t_string& operator[](const std::string& key) const;
const t_string& operator[](const char* key) const;
/**
* Look up the string mappings given in [language] tags. If the key is not
* found, returns symbol_table::end().
*/
utils::string_map::const_iterator find(const std::string& key) const;
utils::string_map::const_iterator end() const;
};
//table of strings which are displayed to the user. Maps ids -> text.

View file

@ -518,6 +518,7 @@ void swap(movetype & a, movetype & b)
swap(a.defense_, b.defense_);
std::swap(a.resist_, b.resist_);
std::swap(a.flying_, b.flying_);
std::swap(a.special_notes_, b.special_notes_);
}
movetype & movetype::operator=(const movetype & that)
@ -801,7 +802,8 @@ movetype::movetype() :
jamming_(mvj_params_, &vision_),
defense_(),
resist_(),
flying_(false)
flying_(false),
special_notes_()
{
}
@ -819,6 +821,10 @@ movetype::movetype(const config & cfg) :
{
// 1.15 will support both "flying" and "flies", with "flies" being deprecated
flying_ = cfg["flying"].to_bool(flying_);
for(const config& sn : cfg.child_range("special_note")) {
special_notes_.push_back(sn["note"]);
}
}
@ -831,7 +837,8 @@ movetype::movetype(const movetype & that) :
jamming_(that.jamming_, &vision_),
defense_(that.defense_),
resist_(that.resist_),
flying_(that.flying_)
flying_(that.flying_),
special_notes_(that.special_notes_)
{
}
@ -844,7 +851,8 @@ movetype::movetype(movetype && that) :
jamming_(std::move(that.jamming_), &vision_),
defense_(std::move(that.defense_)),
resist_(std::move(that.resist_)),
flying_(std::move(that.flying_))
flying_(std::move(that.flying_)),
special_notes_(std::move(that.special_notes_))
{
}
@ -920,4 +928,8 @@ void movetype::write(config & cfg) const
if ( flying_ )
cfg["flying"] = true;
for(const auto& note : special_notes_) {
cfg.add_child("special_note", config{"note", note});
}
}

View file

@ -310,7 +310,25 @@ public:
/**
* Merges the given config over the existing data, the config should have zero or more
* children named "movement_costs", "defense", etc.
* children named "movement_costs", "defense", etc. Only those children will be affected
* (in the case of movement and vision the cascaded values in vision and jamming will also
* be affected).
*
* If @a overwrite is true, the new values will replace the old ones. If it's false, the
* new values are relative improvements or maluses which will be applied on top of the old
* values.
*
* If the old values included defense caps and @a overwrite is false, the calculations are
* done with absolute values and then changed back to the old sign. This means that merge()
* doesn't create or remove defense caps when @a overwrite is false.
*
* If @a new_cfg["flying"] is provided, it overrides the old value, regardless of the value
* of @a overwrite.
*
* This neither adds nor removes special notes. One purpose of this function is to have
* [unit_type][movement_costs] partially overwrite data from [unit_type]movetype=, and it
* would be unhelpful if an unrelated [unit_type][special_note] cleared the movetype's
* special notes.
*/
void merge(const config & new_cfg, bool overwrite=true);
@ -324,6 +342,9 @@ public:
/** The set of applicable effects for movement types */
static const std::set<std::string> effects;
/** Contents of any [special_note] tags */
const std::vector<t_string>& special_notes() const { return special_notes_; }
/** Writes the movement type data to the provided config. */
void write(config & cfg) const;
@ -335,4 +356,5 @@ private:
resistances resist_;
bool flying_;
std::vector<t_string> special_notes_;
};

View file

@ -23,6 +23,7 @@
#include "game_config.hpp"
#include "game_errors.hpp" //thrown sometimes
//#include "gettext.hpp"
#include "language.hpp" // for string_table
#include "log.hpp"
#include "units/abilities.hpp"
#include "units/animation.hpp"
@ -491,25 +492,11 @@ t_string unit_type::unit_description() const
}
}
bool unit_type::has_special_notes() const
{
if(!special_notes_.empty()) return true;
for(const config::any_child ability : abilities_cfg().all_children_range()) {
if(ability.cfg.has_attribute("special_note")) {
return true;
}
}
for(const auto& attack : attacks()) {
for(const config::any_child ability : attack.specials().all_children_range()) {
if(ability.cfg.has_attribute("special_note")) {
return true;
}
}
}
return false;
std::vector<t_string> unit_type::special_notes() const {
return combine_special_notes(special_notes_, abilities_cfg(), attacks(), movement_type());
}
void append_special_note(std::vector<t_string>& notes, const t_string& new_note) {
static void append_special_note(std::vector<t_string>& notes, const t_string& new_note) {
if(new_note.empty()) return;
std::string_view note_plain = new_note.c_str();
utils::trim(note_plain);
@ -519,22 +506,29 @@ void append_special_note(std::vector<t_string>& notes, const t_string& new_note)
notes.push_back(new_note);
}
std::vector<t_string> unit_type::special_notes() const {
std::vector<t_string> combine_special_notes(const std::vector<t_string> direct, const config& abilities, const_attack_itors attacks, const movetype& mt)
{
std::vector<t_string> notes;
for(const config::any_child ability : abilities_cfg().all_children_range()) {
for(const auto& note : direct) {
append_special_note(notes, note);
}
for(const config::any_child ability : abilities.all_children_range()) {
if(ability.cfg.has_attribute("special_note")) {
append_special_note(notes, ability.cfg["special_note"].t_str());
}
}
for(const auto& attack : attacks()) {
for(const auto& attack : attacks) {
for(const config::any_child ability : attack.specials().all_children_range()) {
if(ability.cfg.has_attribute("special_note")) {
append_special_note(notes, ability.cfg["special_note"].t_str());
}
}
if(auto attack_type_note = string_table.find("special_note_damage_type_" + attack.type()); attack_type_note != string_table.end()) {
append_special_note(notes, attack_type_note->second);
}
for(const auto& note : special_notes_) {
append_special_note(notes, note);
}
for(const auto& move_note : mt.special_notes()) {
append_special_note(notes, move_note);
}
return notes;
}

View file

@ -36,7 +36,6 @@ class game_config_view;
typedef std::map<std::string, movetype> movement_type_map;
void append_special_note(std::vector<t_string>& notes, const t_string& new_note);
/**
* A single unit type that the player may recruit.
@ -151,7 +150,15 @@ public:
// NOTE: this used to be a const object reference, but it messed up with the
// translation engine upon changing the language in the same session.
t_string unit_description() const;
bool has_special_notes() const;
/**
* Returns only the notes defined by [unit_type][special_note] tags, excluding
* any that would be found from abilities, attacks, etc.
*/
std::vector<t_string> direct_special_notes() const { return special_notes_; }
/**
* Returns all notes that should be displayed in the help page for this type,
* including those found in abilities and attacks.
*/
std::vector<t_string> special_notes() const;
int hitpoints() const { return hitpoints_; }
double hp_bar_scaling() const { return hp_bar_scaling_; }
@ -441,3 +448,11 @@ struct unit_experience_accelerator {
private:
int old_value_;
};
/**
* Common logic for unit_type::special_notes() and unit::special_notes(). Adds
* any notes from the sources given as arguments, and filters out duplicates.
*
* @return the special notes for a unit or unit_type.
*/
std::vector<t_string> combine_special_notes(const std::vector<t_string> direct, const config& abilities, const_attack_itors attacks, const movetype& mt);

View file

@ -899,7 +899,7 @@ void unit::advance_to(const unit_type& u_type, bool use_traits)
type_ = &new_type;
type_name_ = new_type.type_name();
description_ = new_type.unit_description();
special_notes_ = new_type.special_notes();
special_notes_ = new_type.direct_special_notes();
undead_variation_ = new_type.undead_variation();
max_experience_ = new_type.experience_needed(true);
level_ = new_type.level();
@ -2640,23 +2640,7 @@ void unit::clear_changed_attributes()
}
std::vector<t_string> unit::unit_special_notes() const {
std::vector<t_string> notes;
for(const config::any_child ability : abilities().all_children_range()) {
if(ability.cfg.has_attribute("special_note")) {
append_special_note(notes, ability.cfg["special_note"].t_str());
}
}
for(const auto& attack : attacks()) {
for(const config::any_child ability : attack.specials().all_children_range()) {
if(ability.cfg.has_attribute("special_note")) {
append_special_note(notes, ability.cfg["special_note"].t_str());
}
}
}
for(const auto& note : special_notes_) {
append_special_note(notes, note);
}
return notes;
return combine_special_notes(special_notes_, abilities(), attacks(), movement_type());
}
// Filters unimportant stats from the unit config and returns a checksum of