1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-06 09:09:40 +02:00

Fix configs, update docs, resolve discovered regressions

This commit is contained in:
Ivan Savenko
2025-06-11 17:25:03 +03:00
parent bbe6c415c2
commit 022b0f731c
28 changed files with 305 additions and 124 deletions

View File

@@ -85,6 +85,10 @@
"ENEMY_DEFENCE_REDUCTION":
{
},
"FEARFUL":
{
},
"FIRE_SHIELD":
{
@@ -112,6 +116,14 @@
"FREE_SHOOTING":
{
},
"FULL_MAP_DARKNESS":
{
},
"FULL_MAP_SCOUTING":
{
},
"GARGOYLE":
{
@@ -237,10 +249,6 @@
"creatureNature" : true
},
"MECHANICAL":
{
},
"OPENING_BATTLE_SPELL":
{
},
@@ -278,6 +286,10 @@
{
"creatureNature" : true
},
"SKELETON_TRANSFORMER_TARGET":
{
},
"SHOOTER":
{
@@ -355,6 +367,10 @@
{
},
"TRANSMUTATION_IMMUNITY":
{
},
"UNDEAD":
{
"creatureNature" : true,
@@ -369,6 +385,10 @@
"hidden": true
},
"VULNERABLE_FROM_BACK":
{
},
"WIDE_BREATH":
{
},

View File

@@ -94,7 +94,13 @@
"val" : 10,
"propagator": "BATTLE_WIDE",
"propagationUpdater" : "BONUS_OWNER_UPDATER",
"limiters" : [ "OPPOSITE_SIDE", "LIVING" ]
"limiters" : [
"OPPOSITE_SIDE",
{
"type" : "HAS_ANOTHER_BONUS_LIMITER",
"parameters" : [ "LIVING" ]
}
]
},
"fearfulImmune" :
{

View File

@@ -317,7 +317,7 @@
/// movement points hero can get on start of the turn when on land, depending on speed of slowest creature (0-based list)
"movementPointsLand" : [ 1500, 1500, 1500, 1500, 1560, 1630, 1700, 1760, 1830, 1900, 1960, 2000 ],
/// movement points hero can get on start of the turn when on sea, depending on speed of slowest creature (0-based list)
"movementPointsSea" : [ 1500 ]
"movementPointsSea" : [ 1500 ],
/// Base scouting range for hero without any range modifiers
"baseScoutingRange" : 5,
@@ -350,7 +350,7 @@
"spellResearchCostExponentPerResearch": [ 1.25, 1.25, 1.25, 1.25, 1.25 ],
// Base scouting range for town without any range modifiers
"baseScoutingRange" : 5,
"baseScoutingRange" : 5
},
"combat":

View File

@@ -94,7 +94,8 @@
{ "skill" : "artillery", "level": "basic" }
],
"specialty" : {
"creature" : "ballista"
"creature" : "ballista",
"creatureLevel" : 5
}
},
"tyris":

View File

@@ -24,7 +24,8 @@
{ "skill" : "offence", "level": "basic" }
],
"specialty" : {
"creature" : "ballista"
"creature" : "ballista",
"creatureLevel" : 5
}
},
"dace":

View File

@@ -108,7 +108,8 @@
{ "skill" : "artillery", "level": "basic" }
],
"specialty" : {
"creature" : "ballista"
"creature" : "ballista",
"creatureLevel" : 5
}
},
"broghild":

View File

@@ -98,7 +98,8 @@
{ "skill" : "logistics", "level": "basic" }
],
"specialty" : {
"creature" : "ballista"
"creature" : "ballista",
"creatureLevel" : 5
}
},
"nymus":

View File

@@ -24,7 +24,8 @@
{ "skill" : "artillery", "level": "basic" }
],
"specialty" : {
"creature" : "ballista"
"creature" : "ballista",
"creatureLevel" : 5
}
},
"jabarkas":

View File

@@ -71,7 +71,8 @@
{ "skill" : "tactics", "level": "basic" }
],
"specialty" : {
"creature" : "ballista"
"creature" : "ballista",
"creatureLevel" : 5
}
},
"fafner":

View File

@@ -10,6 +10,32 @@
"type" : "boolean",
"description" : "If set to true, all instances of this bonus will be hidden in UI"
},
"creatureNature" : {
"type" : "boolean",
"description" : "If set to true, this bonus will be considered 'creature nature' bonus, and such creature won't be automatically granted LIVING bonus"
},
"description" : {
"type" : "string"
},
"subtypeDescriptions" : {
"type" : "object",
"description" : "Custom description string for bonus subtype",
"additionalProperties" : {
"type" : "string"
}
},
"valueDescriptions" : {
"type" : "object",
"description" : "Custom description string for bonus value",
"additionalProperties" : {
"type" : "string"
}
},
"graphics" : {
"type" : "object",
"additionalProperties" : false,
@@ -38,22 +64,6 @@
}
}
}
},
"subtypeDescriptions" : {
"type" : "object",
"description" : "Custom description string for bonus subtype",
"additionalProperties" : {
"type" : "string"
}
},
"valueDescriptions" : {
"type" : "object",
"description" : "Custom description string for bonus value",
"additionalProperties" : {
"type" : "string"
}
}
}
}

View File

@@ -37,6 +37,78 @@
}
}
]
},
"updater" :
{
"anyOf" : [
{
"type" : "string",
"enum" : [ "TIMES_HERO_LEVEL", "TIMES_STACK_LEVEL", "DIVIDE_STACK_LEVEL", "BONUS_OWNER_UPDATER", "TIMES_HERO_LEVEL_DIVIDE_STACK_LEVEL" ]
},
{
"description" : "GROWS_WITH_LEVEL updater",
"type" : "object",
"required" : ["type", "valPer20", "stepSize"],
"additionalProperties" : false,
"properties" : {
"type" : {
"type" : "string",
"const" : "GROWS_WITH_LEVEL",
},
"valPer20" : {
"type" : "integer",
"description" : "Bonus value for each 20 steps"
},
"stepSize" : {
"type" : "integer",
"minimum" : 1,
"description" : "Size of each step, in levels"
}
}
},
{
"description" : "TIMES_HERO_LEVEL updater",
"type" : "object",
"required" : ["type"],
"additionalProperties" : false,
"properties" : {
"type" : {
"type" : "string",
"const" : "TIMES_HERO_LEVEL",
},
"stepSize" : {
"type" : "integer",
"minimum" : 1,
"description" : "Size of each step, in levels"
}
}
},
{
"description" : "TIMES_STACK_SIZE updater",
"type" : "object",
"required" : ["type"],
"additionalProperties" : false,
"properties" : {
"type" : {
"type" : "string",
"const" : "TIMES_STACK_SIZE",
},
"stepSize" : {
"type" : "integer",
"minimum" : 1,
"description" : "Size of each step, in levels"
},
"minimum" : {
"type" : "integer",
"description" : "Minimal bonus value"
},
"maximum" : {
"type" : "integer",
"description" : "Maximal bonus value"
}
}
}
]
}
},
"additionalProperties" : false,
@@ -69,56 +141,10 @@
"enum" : [ "BATTLE_WIDE", "VISITED_TOWN_AND_VISITOR", "PLAYER_PROPAGATOR", "HERO", "TEAM_PROPAGATOR", "GLOBAL_EFFECT" ]
},
"updater" : {
"anyOf" : [
{
"type" : "string",
"enum" : [ "TIMES_HERO_LEVEL", "TIMES_STACK_LEVEL", "DIVIDE_STACK_LEVEL", "BONUS_OWNER_UPDATER", "TIMES_HERO_LEVEL_DIVIDE_STACK_LEVEL" ]
},
{
"description" : "updater",
"type" : "object",
"required" : ["type", "parameters"],
"additionalProperties" : false,
"properties" : {
"type" : {
"type" : "string",
"enum" : [ "GROWS_WITH_LEVEL" ],
"description" : "type"
},
"parameters" : {
"type" : "array",
"description" : "parameters",
"additionalItems" : true
}
}
}
]
"$ref" : "#/definitions/updater"
},
"propagationUpdater" : {
"anyOf" : [
{
"type" : "string",
"enum" : [ "TIMES_HERO_LEVEL", "TIMES_STACK_LEVEL", "ARMY_MOVEMENT", "BONUS_OWNER_UPDATER" ]
},
{
"description" : "propagationUpdater",
"type" : "object",
"required" : ["type", "parameters"],
"additionalProperties" : false,
"properties" : {
"type" : {
"type" : "string",
"enum" : [ "GROWS_WITH_LEVEL", "ARMY_MOVEMENT" ],
"description" : "type"
},
"parameters" : {
"type" : "array",
"description" : "parameters",
"additionalItems" : true
}
}
}
]
"$ref" : "#/definitions/updater"
},
"limiters" : {
"$ref" : "#/definitions/nestedLimiter",

View File

@@ -47,7 +47,10 @@
"minimalPrimarySkills" : { "type" : "array" },
"movementCostBase" : { "type" : "number" },
"movementPointsLand" : { "type" : "array" },
"movementPointsSea" : { "type" : "array" }
"movementPointsSea" : { "type" : "array" },
"specialtyCreatureGrowth" : { "type" : "number" },
"specialtySecondarySkillGrowth" : { "type" : "number" },
"baseScoutingRange" : { "type" : "number" }
}
},
"towns" : {
@@ -59,7 +62,8 @@
"spellResearch" : { "type" : "boolean" },
"spellResearchCost" : { "type" : "array" },
"spellResearchPerDay" : { "type" : "array" },
"spellResearchCostExponentPerResearch" : { "type" : "array" }
"spellResearchCostExponentPerResearch" : { "type" : "array" },
"baseScoutingRange" : { "type" : "number" }
}
},
"combat": {

View File

@@ -136,6 +136,14 @@
"secondary" : {
"type" : "string",
"description" : "Shortcut for defining secondary skill specialty, using standard H3 rules."
},
"creatureLevel" : {
"type" : "integer",
"description" : "Assumed creature level for creature specialty"
},
"stepSize" : {
"type" : "integer",
"description" : "How creature or secondary skill specialty should grow per each step. Default is 5"
}
}
},

View File

@@ -274,6 +274,10 @@
"description" : "List of configuration files for artifacts",
"$ref" : "#/definitions/fileListOrObject"
},
"spellSchools" : {
"description" : "List of configuration files for spell schools",
"$ref" : "#/definitions/fileListOrObject"
},
"spells" : {
"description" : "List of configuration files for spells",
"$ref" : "#/definitions/fileListOrObject"

View File

@@ -126,6 +126,12 @@ Restores specific percentage of mana pool for affected heroes on new turn. If he
- val: percentage of spell points to restore
### SKELETON_TRANSFORMER_TARGET
Unit affected by this bonus will be transformed into creature other than Skeleton when placed into Skeleton Transformer
- subtype: type of creature to which this unit should be converted
### NONEVIL_ALIGNMENT_MIX
Allows mixing of creaturs of neutral and good factions in affected armies without penalty to morale (Angelic Alliance effect)
@@ -149,6 +155,7 @@ If the hero has no free space for the target creature but has space for its upgr
- addInfo: Requried total level of Necromancer power for this bonus to be active (val of all bonuses of this type)
Example (from Cloak Of The Undead King):
```json
{
"type" : "IMPROVED_NECROMANCY",
@@ -445,7 +452,7 @@ Creature nature bonus. Affected unit is considered to not be alive and not affec
### MECHANICAL
Creature nature bonus. Affected unit is considered to not be alive and not affected by morale and certain spells but should be repairable from engineers (factory).
Creature nature bonus. Affected unit is considered to not be alive and not affected by morale and certain spells but should be repairable from engineers (HotA Factory).
### GARGOYLE
@@ -453,7 +460,7 @@ Creature nature bonus. Affected unit is considered to be a gargoyle and not affe
### UNDEAD
Creature nature bonus. Affected unit is considered to be undead, which makes it immune to many effects, and also reduce morale of allied living units.
Creature nature bonus. Affected unit is considered to be undead, which makes it immune to many effects, not affected by morale, and also reduce morale of allied living units.
### SIEGE_WEAPON
@@ -463,7 +470,7 @@ Creature nature bonus. Affected unit is considered to be a siege machine and can
### DRAGON_NATURE
Affected unit is dragon. This bonus proved no effect, but is used as limiter several effects.
Affected unit is dragon. This bonus provides no effects on its own, but is used as limiter for Mutare specialty
### KING
@@ -471,10 +478,6 @@ Affected unit will take more damage from units under Slayer spell effect
- val: required skill mastery of Slayer spell to affect this unit
### FEARLESS
Affected unit is immune to Fear ability
### NO_LUCK
Affected units can not receive good or bad luck
@@ -525,7 +528,7 @@ Affected unit will deal more damage based on movement distance (Champions)
### VULNERABLE_FROM_BACK
Affected unit will receive more damage when attacked from behind. Attacked unit will not turn around to face the attacker
When affected unit is attacked from behind, it will receive more damage when attacked and will not turn around to face the attacker
- val: additional damage for attacks from behind, percentage (0-100)
@@ -681,6 +684,10 @@ Affected units have chance to transform attacked unit to other creature type
- transmutationPerUnit: transformed unit will have same number of units as original stack
- addInfo: creature to transform to. If not set, creature will transform to same unit as attacker
### TRANSMUTATION_IMMUNITY
Affected unit is immune to TRANSMUTATION bonus effects
### SUMMON_GUARDIANS
When battle starts, affected units will be surrounded from all side with summoned units
@@ -817,7 +824,9 @@ Affected unit has chance to deal double damage on attack (Death Knight)
### FEAR
If enemy army has creatures affected by this bonus, they will skip their turn with 10% chance (Azure Dragon). Blocked by FEARLESS bonus.
Units affected by this bonus have a chance to skip their turn and freeze in fear (Azure Dragon).
- val: chance to trigger, percentage
### HEALER
@@ -1104,10 +1113,6 @@ Dummy bonus that acts as marker for Dendroid's Bind ability
- addInfo: ID of stack that have bound the unit
### SYNERGY_TARGET
Dummy skill for alternative upgrades mod
### THIEVES_GUILD_ACCESS
Increases amount of information available in affected thieves guild (in town or in adventure map tavern). Does not affects adventure map object "Den of Thieves". You may want to use PLAYER_PROPAGATOR with this bonus to make its effect player wide.

View File

@@ -0,0 +1,53 @@
# Battlefield Format
WARNING: currently custom bonus types can only be used for custom "traits", for example to use them in limiters. At the moment it is not possible to provide custom mechanics for such bonus
```json
{
// If set to true, this bonus will be hidden in creature view
"hidden" : false,
// If set to true, this bonus will be considered a "creature nature" bonus
// If creature has no creature nature bonuses, it is considered to be a LIVING creature
"creatureNature" : false,
// Generic human-readable description of this bonus
// Visible in creature window
// Can be overriden in creature abilities or artifact bonuses
"description" : "{Bonus Name}\nBonus description",
"graphics" : {
// Generic icon of this bonus
// Visible in creature window
// Can be overriden in creature abilities or artifact bonuses
"icon" : "path/to/icon.png",
// Custom icons for specific subtypes of this bonus
"subtypeIcons" : {
"spellSchool.air" : "",
"spellSchool.water" : "",
},
// Custom icons for specific values of this bonus
// Note that values must be strings and wrapped in quotes
"valueIcons" : {
"1" : "",
"2" : "",
}
},
// Custom descriptions for specific subtypes of this bonus
"subtypeDescriptions" : {
"spellSchool.air" : ""
"spellSchool.water" : "",
},
// Custom descriptions for specific values of this bonus
// Note that values must be strings and wrapped in quotes
"valueDescriptions" : {
"1" : ""
"2" : ""
}
}
}
```

View File

@@ -0,0 +1,16 @@
# Spell School Format
WARNING: currently custom spell schools are only partially supported:
- it is possible to use custom spell schools in bonus system
- it is possible to make skill for specializing in such spell
- it is possible to specify border decorations for mastery level of such spell in spellbook
- it is NOT possible to add "bookmark" filter for spellbook for spells of such school
```json
// Internal field for H3 schools. Do not use for mods
"index" : "",
// animation file with spell borders for spell mastery levels
"schoolBorders" : "SplevA"
```

View File

@@ -8,9 +8,9 @@
*
*/
#include "StdInc.h"
#include "CBonusTypeHandler.h"
#include "CCreatureHandler.h"
#include "CBonusTypeHandler.h"
#include "ResourceSet.h"
#include "entities/faction/CFaction.h"
#include "entities/faction/CTownHandler.h"

View File

@@ -9,20 +9,19 @@
*/
#include "StdInc.h"
#include "CSkillHandler.h"
#include <cctype>
#include "CSkillHandler.h"
#include "IGameSettings.h"
#include "GameLibrary.h"
#include "bonuses/Updaters.h"
#include "constants/StringConstants.h"
#include "filesystem/Filesystem.h"
#include "json/JsonBonus.h"
#include "json/JsonUtils.h"
#include "modding/IdentifierStorage.h"
#include "texts/CGeneralTextHandler.h"
#include "texts/CLegacyConfigParser.h"
#include "GameLibrary.h"
#include "json/JsonBonus.h"
#include "json/JsonUtils.h"
VCMI_LIB_NAMESPACE_BEGIN
@@ -259,7 +258,7 @@ std::shared_ptr<CSkill> CSkillHandler::loadFromJson(const std::string & scope, c
if (bonusNode.isStruct())
{
auto bonus = JsonUtils::parseBonus(bonusNode);
bonus->val = LIBRARY->engineSettings()->getInteger(EGameSettings::HEROES_SPECIALTY_SECONDARY_SKILL_GROWTH);
bonus->val = 0; // set by HeroHandler on specialty load
bonus->updater = std::make_shared<TimesHeroLevelUpdater>();
bonus->valType = BonusValueType::PERCENT_TO_TARGET_TYPE;
bonus->targetSourceType = BonusSource::SECONDARY_SKILL;

View File

@@ -17,7 +17,7 @@
#include "../GameLibrary.h"
#include "../IGameSettings.h"
#include "spells/SpellSchoolHandler.h"
#include "../spells/SpellSchoolHandler.h"
VCMI_LIB_NAMESPACE_BEGIN

View File

@@ -34,7 +34,6 @@ const std::map<std::string, TLimiterPtr> bonusLimiterMap =
{"SHOOTER_ONLY", std::make_shared<HasAnotherBonusLimiter>(BonusType::SHOOTER)},
{"DRAGON_NATURE", std::make_shared<HasAnotherBonusLimiter>(BonusType::DRAGON_NATURE)},
{"IS_UNDEAD", std::make_shared<HasAnotherBonusLimiter>(BonusType::UNDEAD)},
{"LIVING", std::make_shared<HasAnotherBonusLimiter>(BonusType::LIVING)},
{"CREATURE_NATIVE_TERRAIN", std::make_shared<CreatureTerrainLimiter>()},
{"CREATURE_FACTION", std::make_shared<AllOfLimiter>(std::initializer_list<TLimiterPtr>{std::make_shared<CreatureLevelLimiter>(), std::make_shared<FactionLimiter>()})},
{"SAME_FACTION", std::make_shared<FactionLimiter>()},

View File

@@ -816,7 +816,6 @@ public:
IMP = 42, // for Deity of Fire
FAMILIAR = 43, // for Deity of Fire
SKELETON = 56, // for Skeleton Transformer
BONE_DRAGON = 68, // for Skeleton Transformer
TROGLODYTES = 70, // for Abandoned Mine
MEDUSA = 76, // for Siege UI workaround
AIR_ELEMENTAL = 112, // for tests

View File

@@ -140,13 +140,23 @@ void CHeroHandler::loadHeroSkills(CHero * hero, const JsonNode & node) const
}
}
/// creates standard H3 hero specialty for creatures
std::vector<std::shared_ptr<Bonus>> CHeroHandler::createCreatureSpecialty(CreatureID cid) const
std::vector<std::shared_ptr<Bonus>> CHeroHandler::createCreatureSpecialty(CreatureID cid, int fixedLevel, int growthPerStep) const
{
std::vector<std::shared_ptr<Bonus>> result;
const auto & specCreature = *cid.toCreature();
int level = specCreature.hasBonusOfType(BonusType::SIEGE_WEAPON) ? 5 : specCreature.getLevel();
if (fixedLevel == 0)
fixedLevel = specCreature.getLevel();
if (fixedLevel == 0)
{
fixedLevel = 5;
logMod->warn("Creature '%s' of level 0 has hero with generic specialty! Please specify level explicitly or give creature non-zero level", specCreature.getJsonKey());
}
if (growthPerStep == 0)
growthPerStep = LIBRARY->engineSettings()->getInteger(EGameSettings::HEROES_SPECIALTY_CREATURE_GROWTH);
{
auto bonus = std::make_shared<Bonus>();
bonus->limiter.reset(new CCreatureTypeLimiter(specCreature, true));
@@ -160,17 +170,17 @@ std::vector<std::shared_ptr<Bonus>> CHeroHandler::createCreatureSpecialty(Creatu
auto bonus = std::make_shared<Bonus>();
bonus->type = BonusType::PRIMARY_SKILL;
bonus->subtype = BonusSubtypeID(skill);
bonus->val = LIBRARY->engineSettings()->getInteger(EGameSettings::HEROES_SPECIALTY_CREATURE_GROWTH);
bonus->val = growthPerStep;
bonus->valType = BonusValueType::PERCENT_TO_TARGET_TYPE;
bonus->targetSourceType = BonusSource::CREATURE_ABILITY;
bonus->limiter.reset(new CCreatureTypeLimiter(specCreature, true));
bonus->updater.reset(new TimesHeroLevelUpdater(level));
bonus->updater.reset(new TimesHeroLevelUpdater(fixedLevel));
result.push_back(bonus);
}
return result;
}
std::vector<std::shared_ptr<Bonus>> CHeroHandler::createSecondarySkillSpecialty(SecondarySkill skillID) const
std::vector<std::shared_ptr<Bonus>> CHeroHandler::createSecondarySkillSpecialty(SecondarySkill skillID, int growthPerStep) const
{
std::vector<std::shared_ptr<Bonus>> result;
const auto & skillPtr = LIBRARY->skillh->objects[skillID.getNum()];
@@ -178,8 +188,15 @@ std::vector<std::shared_ptr<Bonus>> CHeroHandler::createSecondarySkillSpecialty(
if (skillPtr->specialtyTargetBonuses.empty())
logMod->warn("Skill '%s' does not supports generic specialties!", skillPtr->getJsonKey());
if (growthPerStep == 0)
growthPerStep = LIBRARY->engineSettings()->getInteger(EGameSettings::HEROES_SPECIALTY_SECONDARY_SKILL_GROWTH);
for (const auto & bonus : skillPtr->specialtyTargetBonuses)
result.push_back(std::make_shared<Bonus>(*bonus));
{
auto bonusCopy = std::make_shared<Bonus>(*bonus);
bonusCopy->val = growthPerStep;
result.push_back(bonusCopy);
}
return result;
}
@@ -228,9 +245,13 @@ void CHeroHandler::loadHeroSpecialty(CHero * hero, const JsonNode & node) const
//creature specialty - alias for simplicity
if(!specialtyNode["creature"].isNull())
{
LIBRARY->identifiers()->requestIdentifier("creature", specialtyNode["creature"], [this, hero, prepSpec](si32 creature)
const JsonNode & creatureNode = specialtyNode["creature"];
int targetLevel = specialtyNode["creatureLevel"].Integer();
int stepSize = specialtyNode["stepSize"].Integer();
LIBRARY->identifiers()->requestIdentifier("creature", creatureNode, [this, hero, prepSpec, targetLevel, stepSize](si32 creature)
{
for (const auto & bonus : createCreatureSpecialty(CreatureID(creature)))
for (const auto & bonus : createCreatureSpecialty(CreatureID(creature), targetLevel, stepSize))
hero->specialty.push_back(prepSpec(bonus));
});
}
@@ -238,9 +259,12 @@ void CHeroHandler::loadHeroSpecialty(CHero * hero, const JsonNode & node) const
//secondary skill specialty - alias for simplicity
if(!specialtyNode["secondary"].isNull())
{
LIBRARY->identifiers()->requestIdentifier("secondarySkill", specialtyNode["secondary"], [this, hero, prepSpec](si32 creature)
const JsonNode & skillNode = specialtyNode["secondary"];
int stepSize = specialtyNode["stepSize"].Integer();
LIBRARY->identifiers()->requestIdentifier("secondarySkill", skillNode, [this, hero, prepSpec, stepSize](si32 creature)
{
for (const auto & bonus : createSecondarySkillSpecialty(SecondarySkill(creature)))
for (const auto & bonus : createSecondarySkillSpecialty(SecondarySkill(creature), stepSize))
hero->specialty.push_back(prepSpec(bonus));
});
}

View File

@@ -32,8 +32,8 @@ class DLL_LINKAGE CHeroHandler : public CHandlerBase<HeroTypeID, HeroType, CHero
void loadExperience();
std::vector<std::shared_ptr<Bonus>> createCreatureSpecialty(CreatureID cid) const;
std::vector<std::shared_ptr<Bonus>> createSecondarySkillSpecialty(SecondarySkill skillID) const;
std::vector<std::shared_ptr<Bonus>> createCreatureSpecialty(CreatureID cid, int fixedLevel, int growthPerStep) const;
std::vector<std::shared_ptr<Bonus>> createSecondarySkillSpecialty(SecondarySkill skillID, int growthPerStep) const;
public:
ui32 level(TExpType experience) const; //calculates level corresponding to given experience amount

View File

@@ -9,7 +9,6 @@
*/
#include "StdInc.h"
#include "CBonusTypeHandler.h"
#include "JsonBonus.h"
#include "JsonValidator.h"
@@ -19,6 +18,7 @@
#include "../bonuses/Limiters.h"
#include "../bonuses/Propagators.h"
#include "../bonuses/Updaters.h"
#include "../CBonusTypeHandler.h"
#include "../constants/StringConstants.h"
#include "../modding/IdentifierStorage.h"

View File

@@ -1047,13 +1047,14 @@ CStackBasicDescriptor CGHeroInstance::calculateNecromancy (const BattleResult &b
{
const CCreature * c = casualty.first.toCreature();
double raisedFromCasualty = std::min(c->getMaxHealth() / raisedUnitHealth, 1.0) * casualty.second * raisedUnitsPercentage;
raisedUnits += raisedFromCasualty;
if (bestCreature != selectedCreature)
raisedUnits += raisedFromCasualty * 2 / 3 / 100;
else
raisedUnits += raisedFromCasualty / 100;
}
if (bestCreature != selectedCreature)
return CStackBasicDescriptor(selectedCreature, std::max(static_cast<int>(raisedUnits * 2 / 3), 1));
else
return CStackBasicDescriptor(selectedCreature, std::max(static_cast<int>(raisedUnits), 1));
return CStackBasicDescriptor(selectedCreature, std::max(static_cast<int>(raisedUnits), 1));
}
int CGHeroInstance::getSightRadius() const

View File

@@ -11,8 +11,9 @@
#include "StdInc.h"
#include "CGTownInstance.h"
#include "IGameSettings.h"
#include "TownBuildingInstance.h"
#include "../IGameSettings.h"
#include "../spells/CSpellHandler.h"
#include "../bonuses/Bonus.h"
#include "../battle/IBattleInfoCallback.h"

View File

@@ -8,12 +8,12 @@
*
*/
#include "StdInc.h"
#include "CBonusTypeHandler.h"
#include "rewardswidget.h"
#include "ui_rewardswidget.h"
#include "../lib/GameLibrary.h"
#include "../lib/CSkillHandler.h"
#include "../lib/spells/CSpellHandler.h"
#include "../lib/CBonusTypeHandler.h"
#include "../lib/CCreatureHandler.h"
#include "../lib/constants/StringConstants.h"
#include "../lib/entities/artifact/CArtifact.h"