mirror of
https://github.com/vcmi/vcmi.git
synced 2025-07-05 00:49:09 +02:00
Support for loading custom bonuses, slightly less hardcoded Skeleton
Transformer
This commit is contained in:
@ -585,9 +585,7 @@ void MoraleLuckBox::set(const AFactionMember * node)
|
||||
text = LIBRARY->generaltexth->arraytxt[textId[morale]];
|
||||
boost::algorithm::replace_first(text,"%s",LIBRARY->generaltexth->arraytxt[neutralDescr[morale]-mrlt]);
|
||||
|
||||
if (morale && node && (node->getBonusBearer()->hasBonusOfType(BonusType::UNDEAD)
|
||||
|| node->getBonusBearer()->hasBonusOfType(BonusType::NON_LIVING)
|
||||
|| node->getBonusBearer()->hasBonusOfType(BonusType::MECHANICAL)))
|
||||
if (morale && node && node->unaffectedByMorale())
|
||||
{
|
||||
text += LIBRARY->generaltexth->arraytxt[113]; //unaffected by morale
|
||||
component.value = 0;
|
||||
|
@ -98,14 +98,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
"FEAR":
|
||||
{
|
||||
},
|
||||
|
||||
"FEARLESS":
|
||||
{
|
||||
},
|
||||
|
||||
"FEROCITY":
|
||||
{
|
||||
},
|
||||
@ -123,6 +115,7 @@
|
||||
|
||||
"GARGOYLE":
|
||||
{
|
||||
"creatureNature" : true,
|
||||
},
|
||||
|
||||
"GENERAL_DAMAGE_REDUCTION":
|
||||
@ -179,6 +172,11 @@
|
||||
{
|
||||
},
|
||||
|
||||
"LIVING":
|
||||
{
|
||||
"creatureNature" : true
|
||||
},
|
||||
|
||||
"MANA_CHANNELING":
|
||||
{
|
||||
},
|
||||
@ -195,6 +193,11 @@
|
||||
{
|
||||
},
|
||||
|
||||
"MECHANICAL":
|
||||
{
|
||||
"creatureNature" : true
|
||||
},
|
||||
|
||||
"MIND_IMMUNITY":
|
||||
{
|
||||
},
|
||||
@ -231,6 +234,7 @@
|
||||
|
||||
"NON_LIVING":
|
||||
{
|
||||
"creatureNature" : true
|
||||
},
|
||||
|
||||
"MECHANICAL":
|
||||
@ -270,6 +274,11 @@
|
||||
{
|
||||
},
|
||||
|
||||
"SIEGE_WEAPON":
|
||||
{
|
||||
"creatureNature" : true
|
||||
},
|
||||
|
||||
"SHOOTER":
|
||||
{
|
||||
},
|
||||
@ -348,6 +357,7 @@
|
||||
|
||||
"UNDEAD":
|
||||
{
|
||||
"creatureNature" : true,
|
||||
},
|
||||
|
||||
"UNLIMITED_RETALIATIONS":
|
||||
|
@ -411,33 +411,35 @@ Increases starting amount of shots that unit has in battle
|
||||
|
||||
## Creature abilities
|
||||
|
||||
## Static abilities and immunities
|
||||
## Creature Natures
|
||||
|
||||
### LIVING
|
||||
|
||||
Affected unit is considered to be alive. Automatically granted to any unit that is not UNDEAD, NON_LIVING, MECHANICAL, GARGOYLE, or SIEGE_WEAPON.
|
||||
Affected unit is considered to be alive. Automatically granted to any unit that does not have any other creature nature bonus
|
||||
|
||||
Living units can be affected by TRANSMUTATION, LIFE_DRAIN, and SOUL_STEAL bonuses
|
||||
|
||||
### NON_LIVING
|
||||
|
||||
Affected unit is considered to not be alive and not affected by morale and certain spells
|
||||
Creature nature bonus. Affected unit is considered to not be alive and not affected by morale and certain spells
|
||||
|
||||
### MECHANICAL
|
||||
|
||||
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 (factory).
|
||||
|
||||
### GARGOYLE
|
||||
|
||||
Affected unit is considered to be a gargoyle and not affected by certain spells
|
||||
Creature nature bonus. Affected unit is considered to be a gargoyle and not affected by certain spells
|
||||
|
||||
### UNDEAD
|
||||
|
||||
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, and also reduce morale of allied living units.
|
||||
|
||||
### SIEGE_WEAPON
|
||||
|
||||
Affected unit is considered to be a siege machine and can not be raised, healed, have morale or move. All War Machines should have this bonus.
|
||||
Creature nature bonus. Affected unit is considered to be a siege machine and can not be raised, healed, have morale or move. All War Machines should have this bonus.
|
||||
|
||||
## Static abilities and immunities
|
||||
|
||||
### DRAGON_NATURE
|
||||
|
||||
|
@ -61,6 +61,8 @@ public:
|
||||
*/
|
||||
int moraleValAndBonusList(std::shared_ptr<const BonusList> & bonusList) const;
|
||||
int luckValAndBonusList(std::shared_ptr<const BonusList> & bonusList) const;
|
||||
|
||||
bool unaffectedByMorale() const;
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -69,6 +69,15 @@ int AFactionMember::getMaxDamage(bool ranged) const
|
||||
return getBonusBearer()->valOfBonuses(selector, cachingStr);
|
||||
}
|
||||
|
||||
bool AFactionMember::unaffectedByMorale() const
|
||||
{
|
||||
static const auto unaffectedByMoraleSelector = Selector::type()(BonusType::NON_LIVING).Or(Selector::type()(BonusType::MECHANICAL)).Or(Selector::type()(BonusType::UNDEAD))
|
||||
.Or(Selector::type()(BonusType::SIEGE_WEAPON)).Or(Selector::type()(BonusType::NO_MORALE));
|
||||
|
||||
static const std::string cachingStrUn = "AFactionMember::unaffectedByMoraleSelector";
|
||||
return getBonusBearer()->hasBonus(unaffectedByMoraleSelector, cachingStrUn);
|
||||
}
|
||||
|
||||
int AFactionMember::moraleValAndBonusList(TConstBonusListPtr & bonusList) const
|
||||
{
|
||||
int32_t maxGoodMorale = LIBRARY->engineSettings()->getVector(EGameSettings::COMBAT_GOOD_MORALE_CHANCE).size();
|
||||
@ -81,12 +90,7 @@ int AFactionMember::moraleValAndBonusList(TConstBonusListPtr & bonusList) const
|
||||
return maxGoodMorale;
|
||||
}
|
||||
|
||||
static const auto unaffectedByMoraleSelector = Selector::type()(BonusType::NON_LIVING).Or(Selector::type()(BonusType::MECHANICAL)).Or(Selector::type()(BonusType::UNDEAD))
|
||||
.Or(Selector::type()(BonusType::SIEGE_WEAPON)).Or(Selector::type()(BonusType::NO_MORALE));
|
||||
|
||||
static const std::string cachingStrUn = "AFactionMember::unaffectedByMoraleSelector";
|
||||
auto unaffected = getBonusBearer()->hasBonus(unaffectedByMoraleSelector, cachingStrUn);
|
||||
if(unaffected)
|
||||
if(unaffectedByMorale())
|
||||
{
|
||||
if(bonusList && !bonusList->empty())
|
||||
bonusList = std::make_shared<const BonusList>();
|
||||
|
@ -122,13 +122,23 @@ std::vector<JsonNode> CBonusTypeHandler::loadLegacyData()
|
||||
|
||||
void CBonusTypeHandler::loadObject(std::string scope, std::string name, const JsonNode & data)
|
||||
{
|
||||
if (vstd::contains(bonusNames, name))
|
||||
{
|
||||
//h3 bonus
|
||||
BonusType bonus = stringToBonus(name);
|
||||
|
||||
CBonusType & bt = bonusTypes[vstd::to_underlying(bonus)];
|
||||
|
||||
loadItem(data, bt, name);
|
||||
logBonus->trace("Loaded bonus type %s", name);
|
||||
}
|
||||
else
|
||||
{
|
||||
// new bonus
|
||||
bonusNames.push_back(name);
|
||||
bonusTypes.emplace_back();
|
||||
loadItem(data, bonusTypes.back(), name);
|
||||
logBonus->trace("New bonus type %s", name);
|
||||
}
|
||||
}
|
||||
|
||||
void CBonusTypeHandler::loadObject(std::string scope, std::string name, const JsonNode & data, size_t index)
|
||||
{
|
||||
@ -139,6 +149,7 @@ void CBonusTypeHandler::loadItem(const JsonNode & source, CBonusType & dest, con
|
||||
{
|
||||
dest.identifier = name;
|
||||
dest.hidden = source["hidden"].Bool(); //Null -> false
|
||||
dest.creatureNature = source["creatureNature"].Bool(); //Null -> false
|
||||
|
||||
if (!dest.hidden)
|
||||
LIBRARY->generaltexth->registerString( "vcmi", dest.getDescriptionTextID(), source["description"]);
|
||||
@ -197,6 +208,11 @@ const std::string CBonusTypeHandler::bonusToString(BonusType bonus) const
|
||||
return bonusNames.at(static_cast<int>(bonus));
|
||||
}
|
||||
|
||||
bool CBonusTypeHandler::isCreatureNatureBonus(BonusType bonus) const
|
||||
{
|
||||
return bonusTypes.at(static_cast<int>(bonus)).creatureNature;
|
||||
}
|
||||
|
||||
std::vector<BonusType> CBonusTypeHandler::getAllObjets() const
|
||||
{
|
||||
std::vector<BonusType> ret;
|
||||
|
@ -36,6 +36,7 @@ private:
|
||||
std::map<int, std::string> valueDescriptions;
|
||||
std::string identifier;
|
||||
|
||||
bool creatureNature;
|
||||
bool hidden;
|
||||
};
|
||||
|
||||
@ -56,6 +57,8 @@ public:
|
||||
BonusType stringToBonus(const std::string & name) const;
|
||||
const std::string bonusToString(BonusType bonus) const;
|
||||
|
||||
bool isCreatureNatureBonus(BonusType bonus) const;
|
||||
|
||||
std::vector<BonusType> getAllObjets() const;
|
||||
private:
|
||||
void loadItem(const JsonNode & source, CBonusType & dest, const std::string & name) const;
|
||||
|
@ -8,6 +8,7 @@
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include "CBonusTypeHandler.h"
|
||||
#include "CCreatureHandler.h"
|
||||
|
||||
#include "ResourceSet.h"
|
||||
@ -900,6 +901,7 @@ void CCreatureHandler::loadJsonAnimation(CCreature * cre, const JsonNode & graph
|
||||
|
||||
void CCreatureHandler::loadCreatureJson(CCreature * creature, const JsonNode & config) const
|
||||
{
|
||||
bool hasCreatureNatureBonus = false;
|
||||
creature->animDefName = AnimationPath::fromJson(config["graphics"]["animation"]);
|
||||
|
||||
//FIXME: MOD COMPATIBILITY
|
||||
@ -913,36 +915,13 @@ void CCreatureHandler::loadCreatureJson(CCreature * creature, const JsonNode & c
|
||||
b->source = BonusSource::CREATURE_ABILITY;
|
||||
b->sid = BonusSourceID(creature->getId());
|
||||
b->duration = BonusDuration::PERMANENT;
|
||||
creature->addNewBonus(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(const JsonNode &ability : config["abilities"].Vector())
|
||||
{
|
||||
if(ability.getType() == JsonNode::JsonType::DATA_VECTOR)
|
||||
{
|
||||
logMod->error("Ignored outdated creature ability format in %s", creature->getJsonKey());
|
||||
}
|
||||
else
|
||||
{
|
||||
auto b = JsonUtils::parseBonus(ability);
|
||||
b->source = BonusSource::CREATURE_ABILITY;
|
||||
b->sid = BonusSourceID(creature->getId());
|
||||
b->duration = BonusDuration::PERMANENT;
|
||||
hasCreatureNatureBonus |= LIBRARY->bth->isCreatureNatureBonus(b->type);
|
||||
creature->addNewBonus(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const CSelector livingSelector = Selector::type()(BonusType::UNDEAD)
|
||||
.Or(Selector::type()(BonusType::NON_LIVING))
|
||||
.Or(Selector::type()(BonusType::MECHANICAL))
|
||||
.Or(Selector::type()(BonusType::GARGOYLE))
|
||||
.Or(Selector::type()(BonusType::SIEGE_WEAPON));
|
||||
|
||||
if (!creature->hasBonus(livingSelector))
|
||||
if (!hasCreatureNatureBonus)
|
||||
creature->addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::LIVING, BonusSource::CREATURE_ABILITY, 0, BonusSourceID(creature->getId())));
|
||||
|
||||
LIBRARY->identifiers()->requestIdentifier("faction", config["faction"], [=](si32 faction)
|
||||
|
@ -148,7 +148,7 @@ class JsonNode;
|
||||
BONUS_NAME(DESTRUCTION) /*kills extra units after hit, subtype = 0 - kill percentage of units, 1 - kill amount, val = chance in percent to trigger, additional info - amount/percentage to kill*/ \
|
||||
BONUS_NAME(SPECIAL_CRYSTAL_GENERATION) /*crystal dragon crystal generation*/ \
|
||||
BONUS_NAME(NO_SPELLCAST_BY_DEFAULT) /*spellcast will not be default attack option for this creature*/ \
|
||||
BONUS_NAME(GARGOYLE) /* gargoyle is special than NON_LIVING, cannot be rised or healed */ \
|
||||
BONUS_NAME(DRACONIC_SKELETON) /* for skeleton transformer */ \
|
||||
BONUS_NAME(SPECIAL_ADD_VALUE_ENCHANT) /*specialty spell like Aenin has, increased effect of spell, additionalInfo = value to add*/\
|
||||
BONUS_NAME(SPECIAL_FIXED_VALUE_ENCHANT) /*specialty spell like Melody has, constant spell effect (i.e. 3 luck), additionalInfo = value to fix.*/\
|
||||
BONUS_NAME(THIEVES_GUILD_ACCESS) \
|
||||
|
@ -819,8 +819,6 @@ public:
|
||||
BONE_DRAGON = 68, // for Skeleton Transformer
|
||||
TROGLODYTES = 70, // for Abandoned Mine
|
||||
MEDUSA = 76, // for Siege UI workaround
|
||||
HYDRA = 110, // for Skeleton Transformer
|
||||
CHAOS_HYDRA = 111, // for Skeleton Transformer
|
||||
AIR_ELEMENTAL = 112, // for tests
|
||||
FIRE_ELEMENTAL = 114, // for tests
|
||||
PSYCHIC_ELEMENTAL = 120, // for hardcoded ability
|
||||
|
@ -3239,11 +3239,11 @@ bool CGameHandler::transformInUndead(const IMarket *market, const CGHeroInstance
|
||||
//resulting creature - bone dragons or skeletons
|
||||
CreatureID resCreature = CreatureID::SKELETON;
|
||||
|
||||
if ((s.hasBonusOfType(BonusType::DRAGON_NATURE)
|
||||
&& !(s.hasBonusOfType(BonusType::UNDEAD)))
|
||||
|| (s.getCreatureID() == CreatureID::HYDRA)
|
||||
|| (s.getCreatureID() == CreatureID::CHAOS_HYDRA))
|
||||
if (!s.hasBonusOfType(BonusType::UNDEAD))
|
||||
{
|
||||
if (s.hasBonusOfType(BonusType::DRAGON_NATURE) || s.hasBonusOfType(BonusType::DRACONIC_SKELETON))
|
||||
resCreature = CreatureID::BONE_DRAGON;
|
||||
}
|
||||
changeStackType(StackLocation(army->id, slot), resCreature.toCreature());
|
||||
return true;
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ class CBattleInfoCallback;
|
||||
class BattleHex;
|
||||
class CStack;
|
||||
class PlayerColor;
|
||||
enum class BonusType : uint8_t;
|
||||
enum class BonusType : uint16_t;
|
||||
|
||||
namespace battle
|
||||
{
|
||||
|
Reference in New Issue
Block a user