mirror of
https://github.com/vcmi/vcmi.git
synced 2025-07-17 01:32:21 +02:00
Implemented configurable FEAR ability
This commit is contained in:
@ -892,7 +892,7 @@ void CPlayerInterface::battleTriggerEffect(const BattleID & battleID, const Batt
|
||||
|
||||
battleInt->effectsController->battleTriggerEffect(bte);
|
||||
|
||||
if(bte.effect == vstd::to_underlying(BonusType::MANA_DRAIN))
|
||||
if(bte.effect == BonusType::MANA_DRAIN)
|
||||
{
|
||||
const CGHeroInstance * manaDrainedHero = GAME->interface()->cb->getHero(ObjectInstanceID(bte.additionalInfo));
|
||||
battleInt->windowObject->heroManaPointsChanged(manaDrainedHero);
|
||||
|
@ -66,7 +66,7 @@ void BattleEffectsController::battleTriggerEffect(const BattleTriggerEffect & bt
|
||||
return;
|
||||
}
|
||||
//don't show animation when no HP is regenerated
|
||||
switch(static_cast<BonusType>(bte.effect))
|
||||
switch(bte.effect)
|
||||
{
|
||||
case BonusType::HP_REGENERATION:
|
||||
displayEffect(EBattleEffect::REGENERATION, AudioPath::builtin("REGENER"), stack->getPosition(), 0.5);
|
||||
@ -77,7 +77,7 @@ void BattleEffectsController::battleTriggerEffect(const BattleTriggerEffect & bt
|
||||
case BonusType::POISON:
|
||||
displayEffect(EBattleEffect::POISON, AudioPath::builtin("POISON"), stack->getPosition());
|
||||
break;
|
||||
case BonusType::FEAR:
|
||||
case BonusType::FEARFUL:
|
||||
displayEffect(EBattleEffect::FEAR, AudioPath::builtin("FEAR"), stack->getPosition(), 0.5);
|
||||
break;
|
||||
case BonusType::MORALE:
|
||||
|
@ -83,13 +83,20 @@
|
||||
{
|
||||
"type" : "TWO_HEX_ATTACK_BREATH"
|
||||
},
|
||||
"fear" :
|
||||
"fearful" :
|
||||
{
|
||||
"type" : "FEAR"
|
||||
"type" : "FEARFUL",
|
||||
"val" : 10,
|
||||
"propagator": "BATTLE_WIDE",
|
||||
"propagationUpdater" : "BONUS_OWNER_UPDATER",
|
||||
"limiters" : [ "OPPOSITE_SIDE", "LIVING" ]
|
||||
},
|
||||
"fearless" :
|
||||
"fearfulImmune" :
|
||||
{
|
||||
"type" : "FEARLESS"
|
||||
"type" : "FEARFUL",
|
||||
"valueType" : "INDEPENDENT_MAX",
|
||||
"val" : 0
|
||||
|
||||
},
|
||||
"spellImmunity" :
|
||||
{
|
||||
|
@ -186,14 +186,7 @@ ui32 ACreature::getMovementRange(int turn) const
|
||||
|
||||
bool ACreature::isLiving() const //TODO: theoreticaly there exists "LIVING" bonus in stack experience documentation
|
||||
{
|
||||
static const std::string cachingStr = "ACreature::isLiving";
|
||||
static const CSelector selector = 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));
|
||||
|
||||
return !getBonusBearer()->hasBonus(selector, cachingStr);
|
||||
return getBonusBearer()->hasBonusOfType(BonusType::LIVING);
|
||||
}
|
||||
|
||||
|
||||
|
@ -936,6 +936,15 @@ void CCreatureHandler::loadCreatureJson(CCreature * creature, const JsonNode & c
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
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)
|
||||
{
|
||||
creature->faction = FactionID(faction);
|
||||
@ -1076,7 +1085,7 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
|
||||
b.subtype = BonusCustomSubtype::deathStareGorgon;
|
||||
break;
|
||||
case 'F':
|
||||
b.type = BonusType::FEAR; break;
|
||||
b.type = BonusType::FEARFUL; break;
|
||||
case 'g':
|
||||
b.type = BonusType::SPELL_DAMAGE_REDUCTION;
|
||||
b.subtype = BonusSubtypeID(SpellSchool::ANY);
|
||||
@ -1105,7 +1114,7 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
|
||||
case 'D':
|
||||
b.type = BonusType::ADDITIONAL_ATTACK; break;
|
||||
case 'f':
|
||||
b.type = BonusType::FEARLESS; break;
|
||||
b.type = BonusType::FEARFUL; break;
|
||||
case 'F':
|
||||
b.type = BonusType::FLYING; break;
|
||||
case 'm':
|
||||
|
@ -91,8 +91,8 @@ class JsonNode;
|
||||
BONUS_NAME(DEFENSIVE_STANCE) /* val - bonus to defense while defending */ \
|
||||
BONUS_NAME(ATTACKS_ALL_ADJACENT) /*eg. hydra*/ \
|
||||
BONUS_NAME(MORE_DAMAGE_FROM_SPELL) /*value - damage increase in %, subtype - spell id*/ \
|
||||
BONUS_NAME(FEAR) \
|
||||
BONUS_NAME(FEARLESS) \
|
||||
BONUS_NAME(FEARFUL) \
|
||||
BONUS_NAME(LIVING) \
|
||||
BONUS_NAME(NO_DISTANCE_PENALTY) \
|
||||
BONUS_NAME(ENCHANTER)/* for Enchanter spells, val - skill level, subtype - spell id, additionalInfo - cooldown */ \
|
||||
BONUS_NAME(HEALER) \
|
||||
|
@ -33,6 +33,7 @@ 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>()},
|
||||
|
@ -1191,7 +1191,7 @@ void GameStatePackVisitor::visitBattleTriggerEffect(BattleTriggerEffect & pack)
|
||||
{
|
||||
CStack * st = gs.getBattle(pack.battleID)->getStack(pack.stackID);
|
||||
assert(st);
|
||||
switch(static_cast<BonusType>(pack.effect))
|
||||
switch(pack.effect)
|
||||
{
|
||||
case BonusType::HP_REGENERATION:
|
||||
{
|
||||
@ -1218,11 +1218,11 @@ void GameStatePackVisitor::visitBattleTriggerEffect(BattleTriggerEffect & pack)
|
||||
case BonusType::ENCHANTER:
|
||||
case BonusType::MORALE:
|
||||
break;
|
||||
case BonusType::FEAR:
|
||||
case BonusType::FEARFUL:
|
||||
st->fear = true;
|
||||
break;
|
||||
default:
|
||||
logNetwork->error("Unrecognized trigger effect type %d", pack.effect);
|
||||
logNetwork->error("Unrecognized trigger effect type %d", static_cast<int>(pack.effect));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -488,7 +488,7 @@ struct DLL_LINKAGE BattleTriggerEffect : public CPackForClient
|
||||
{
|
||||
BattleID battleID = BattleID::NONE;
|
||||
int stackID = 0;
|
||||
int effect = 0; //use corresponding Bonus type
|
||||
BonusType effect = BonusType::NONE;
|
||||
int val = 0;
|
||||
int additionalInfo = 0;
|
||||
|
||||
|
@ -279,7 +279,7 @@ const CStack * BattleFlowProcessor::getNextStack(const CBattleInfoCallback & bat
|
||||
BattleTriggerEffect bte;
|
||||
bte.battleID = battle.getBattle()->getBattleID();
|
||||
bte.stackID = stack->unitId();
|
||||
bte.effect = vstd::to_underlying(BonusType::HP_REGENERATION);
|
||||
bte.effect = BonusType::HP_REGENERATION;
|
||||
|
||||
const int32_t lostHealth = stack->getMaxHealth() - stack->getFirstHPleft();
|
||||
if(stack->hasBonusOfType(BonusType::HP_REGENERATION))
|
||||
@ -529,7 +529,7 @@ bool BattleFlowProcessor::rollGoodMorale(const CBattleInfoCallback & battle, con
|
||||
BattleTriggerEffect bte;
|
||||
bte.battleID = battle.getBattle()->getBattleID();
|
||||
bte.stackID = next->unitId();
|
||||
bte.effect = vstd::to_underlying(BonusType::MORALE);
|
||||
bte.effect = BonusType::MORALE;
|
||||
bte.val = 1;
|
||||
bte.additionalInfo = 0;
|
||||
gameHandler->sendAndApply(bte); //play animation
|
||||
@ -667,7 +667,7 @@ void BattleFlowProcessor::stackTurnTrigger(const CBattleInfoCallback & battle, c
|
||||
BattleTriggerEffect bte;
|
||||
bte.battleID = battle.getBattle()->getBattleID();
|
||||
bte.stackID = st->unitId();
|
||||
bte.effect = -1;
|
||||
bte.effect = BonusType::NONE;
|
||||
bte.val = 0;
|
||||
bte.additionalInfo = 0;
|
||||
if (st->alive())
|
||||
@ -710,7 +710,7 @@ void BattleFlowProcessor::stackTurnTrigger(const CBattleInfoCallback & battle, c
|
||||
bte.val = std::max (b->val - 10, -(st->valOfBonuses(BonusType::POISON)));
|
||||
if (bte.val < b->val) //(negative) poison effect increases - update it
|
||||
{
|
||||
bte.effect = vstd::to_underlying(BonusType::POISON);
|
||||
bte.effect = BonusType::POISON;
|
||||
gameHandler->sendAndApply(bte);
|
||||
}
|
||||
}
|
||||
@ -724,28 +724,21 @@ void BattleFlowProcessor::stackTurnTrigger(const CBattleInfoCallback & battle, c
|
||||
vstd::amin(manaDrained, opponentHero->mana);
|
||||
if(manaDrained)
|
||||
{
|
||||
bte.effect = vstd::to_underlying(BonusType::MANA_DRAIN);
|
||||
bte.effect = BonusType::MANA_DRAIN;
|
||||
bte.val = manaDrained;
|
||||
bte.additionalInfo = opponentHero->id.getNum(); //for sanity
|
||||
gameHandler->sendAndApply(bte);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (st->isLiving() && !st->hasBonusOfType(BonusType::FEARLESS))
|
||||
if (st->hasBonusOfType(BonusType::FEARFUL))
|
||||
{
|
||||
int chance = st->valOfBonuses(BonusType::FEARFUL);
|
||||
ObjectInstanceID opponentArmyID = battle.battleGetArmyObject(battle.otherSide(st->unitSide()))->id;
|
||||
bool fearsomeCreature = false;
|
||||
for (const CStack * stack : battle.battleGetAllStacks(true))
|
||||
|
||||
if (gameHandler->randomizer->rollCombatAbility(opponentArmyID, chance))
|
||||
{
|
||||
if (battle.battleMatchOwner(st, stack) && stack->alive() && stack->hasBonusOfType(BonusType::FEAR))
|
||||
{
|
||||
fearsomeCreature = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fearsomeCreature && gameHandler->randomizer->rollCombatAbility(opponentArmyID, 10)) //fixed 10%
|
||||
{
|
||||
bte.effect = vstd::to_underlying(BonusType::FEAR);
|
||||
bte.effect = BonusType::FEARFUL;
|
||||
gameHandler->sendAndApply(bte);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user