mirror of
https://github.com/vcmi/vcmi.git
synced 2024-11-28 08:48:48 +02:00
vcmi: skill-agnostic first aid
Now first aid is passive battle spell, and skill just bumps specific spell power for this spell. Everything about healing is handled into Heal spell effect.
This commit is contained in:
parent
a0987313ba
commit
84f53485e2
@ -110,15 +110,6 @@ void BattleEffectsController::startAction(const BattleAction* action)
|
||||
break;
|
||||
}
|
||||
|
||||
//displaying special abilities
|
||||
auto actionTarget = action->getTarget(owner.curInt->cb.get());
|
||||
switch(action->actionType)
|
||||
{
|
||||
case EActionType::STACK_HEAL:
|
||||
displayEffect(EBattleEffect::REGENERATION, "REGENER", actionTarget.at(0).hexValue);
|
||||
break;
|
||||
}
|
||||
|
||||
owner.waitForAnimationCondition(EAnimationEvents::ACTION, false);
|
||||
}
|
||||
|
||||
|
@ -78,7 +78,19 @@
|
||||
"index": 147,
|
||||
"level": 0,
|
||||
"faction": "neutral",
|
||||
"abilities": { "heals" : { "type" : "HEALER" } },
|
||||
"abilities":
|
||||
{
|
||||
"heals" : {
|
||||
"type" : "HEALER" ,
|
||||
"subtype" : "spell.firstAid"
|
||||
},
|
||||
"power" : {
|
||||
"type" : "SPECIFIC_SPELL_POWER",
|
||||
"subtype" : "spell.firstAid",
|
||||
"val" : 10,
|
||||
"valueType" : "BASE_NUMBER"
|
||||
}
|
||||
},
|
||||
"graphics" :
|
||||
{
|
||||
"animation": "SMTENT.DEF"
|
||||
|
@ -152,11 +152,12 @@
|
||||
"specialty" : {
|
||||
"bonuses" : {
|
||||
"firstAid" : {
|
||||
"subtype" : "skill.firstAid",
|
||||
"type" : "SECONDARY_SKILL_PREMY",
|
||||
"subtype" : "spell.firstAid",
|
||||
"type" : "SPECIFIC_SPELL_POWER",
|
||||
"updater" : "TIMES_HERO_LEVEL",
|
||||
"val" : 5,
|
||||
"valueType" : "PERCENT_TO_BASE"
|
||||
"valueType" : "PERCENT_TO_TARGET_TYPE",
|
||||
"targetSourceType" : "SECONDARY_SKILL"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -214,11 +214,12 @@
|
||||
"specialty" : {
|
||||
"bonuses" : {
|
||||
"firstAid" : {
|
||||
"subtype" : "skill.firstAid",
|
||||
"type" : "SECONDARY_SKILL_PREMY",
|
||||
"subtype" : "spell.firstAid",
|
||||
"type" : "SPECIFIC_SPELL_POWER",
|
||||
"updater" : "TIMES_HERO_LEVEL",
|
||||
"val" : 5,
|
||||
"valueType" : "PERCENT_TO_BASE"
|
||||
"valueType" : "PERCENT_TO_TARGET_TYPE",
|
||||
"targetSourceType" : "SECONDARY_SKILL"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -220,11 +220,12 @@
|
||||
"specialty" : {
|
||||
"bonuses" : {
|
||||
"firstAid" : {
|
||||
"subtype" : "skill.firstAid",
|
||||
"type" : "SECONDARY_SKILL_PREMY",
|
||||
"subtype" : "spell.firstAid",
|
||||
"type" : "SPECIFIC_SPELL_POWER",
|
||||
"updater" : "TIMES_HERO_LEVEL",
|
||||
"val" : 5,
|
||||
"valueType" : "PERCENT_TO_BASE"
|
||||
"valueType" : "PERCENT_TO_TARGET_TYPE",
|
||||
"targetSourceType" : "SECONDARY_SKILL"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -786,8 +786,8 @@
|
||||
"base" : {
|
||||
"effects" : {
|
||||
"main" : {
|
||||
"subtype" : "skill.firstAid",
|
||||
"type" : "SECONDARY_SKILL_PREMY",
|
||||
"subtype" : "spell.firstAid",
|
||||
"type" : "SPECIFIC_SPELL_POWER",
|
||||
"valueType" : "BASE_NUMBER"
|
||||
},
|
||||
"ctrl" : {
|
||||
@ -800,17 +800,17 @@
|
||||
},
|
||||
"basic" : {
|
||||
"effects" : {
|
||||
"main" : { "val" : 50 }
|
||||
"main" : { "val" : 40 }
|
||||
}
|
||||
},
|
||||
"advanced" : {
|
||||
"effects" : {
|
||||
"main" : { "val" : 75 }
|
||||
"main" : { "val" : 65 }
|
||||
}
|
||||
},
|
||||
"expert" : {
|
||||
"effects" : {
|
||||
"main" : { "val" : 100 }
|
||||
"main" : { "val" : 90 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,5 +45,61 @@
|
||||
"bonus.GARGOYLE" : "absolute"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"firstAid" : {
|
||||
"targetType" : "CREATURE",
|
||||
"type": "ability",
|
||||
"name": "First Aid",
|
||||
"school" : {},
|
||||
"level": 1,
|
||||
"power": 10,
|
||||
"defaultGainChance": 0,
|
||||
"gainChance": {},
|
||||
"animation":{
|
||||
"affect":["SP12_"]
|
||||
},
|
||||
|
||||
"sounds": {
|
||||
"cast": "REGENER"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"description" : "",
|
||||
"aiValue" : 0,
|
||||
"power" : 10,
|
||||
"cost" : 0,
|
||||
"targetModifier":{"smart":true},
|
||||
"battleEffects":{
|
||||
"heal":{
|
||||
"type":"core:heal",
|
||||
"healLevel":"heal",
|
||||
"healPower":"permanent",
|
||||
"optional":true
|
||||
}
|
||||
},
|
||||
"range" : "0"
|
||||
},
|
||||
"none" :{
|
||||
"power" : 10
|
||||
},
|
||||
"basic" :{
|
||||
"power" : 50
|
||||
},
|
||||
"advanced" :{
|
||||
"power" : 75
|
||||
},
|
||||
"expert" :{
|
||||
"power" : 100
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"positive": true
|
||||
},
|
||||
"targetCondition" : {
|
||||
"nonMagical" : true,
|
||||
"noneOf" : {
|
||||
"bonus.SIEGE_WEAPON" : "absolute"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -389,6 +389,7 @@ bool TargetCondition::isReceptive(const Mechanics * m, const battle::Unit * targ
|
||||
|
||||
void TargetCondition::serializeJson(JsonSerializeFormat & handler, const ItemFactory * itemFactory)
|
||||
{
|
||||
bool isNonMagical = false;
|
||||
if(handler.saving)
|
||||
{
|
||||
logGlobal->error("Spell target condition saving is not supported");
|
||||
@ -399,13 +400,18 @@ void TargetCondition::serializeJson(JsonSerializeFormat & handler, const ItemFac
|
||||
normal.clear();
|
||||
negation.clear();
|
||||
|
||||
absolute.push_back(itemFactory->createAbsoluteLevel());
|
||||
absolute.push_back(itemFactory->createAbsoluteSpell());
|
||||
normal.push_back(itemFactory->createElemental());
|
||||
normal.push_back(itemFactory->createNormalLevel());
|
||||
normal.push_back(itemFactory->createNormalSpell());
|
||||
negation.push_back(itemFactory->createReceptiveFeature());
|
||||
negation.push_back(itemFactory->createImmunityNegation());
|
||||
|
||||
handler.serializeBool("nonMagical", isNonMagical);
|
||||
if(!isNonMagical)
|
||||
{
|
||||
absolute.push_back(itemFactory->createAbsoluteLevel());
|
||||
normal.push_back(itemFactory->createElemental());
|
||||
normal.push_back(itemFactory->createNormalLevel());
|
||||
normal.push_back(itemFactory->createNormalSpell());
|
||||
negation.push_back(itemFactory->createReceptiveFeature());
|
||||
negation.push_back(itemFactory->createImmunityNegation());
|
||||
}
|
||||
|
||||
{
|
||||
auto anyOf = handler.enterStruct("anyOf");
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
#include "../../NetPacks.h"
|
||||
#include "../../battle/IBattleState.h"
|
||||
#include "../../battle/CUnitState.h"
|
||||
#include "../../battle/CBattleInfoCallback.h"
|
||||
#include "../../battle/Unit.h"
|
||||
#include "../../serializer/JsonSerializeFormat.h"
|
||||
@ -128,6 +129,16 @@ void Heal::prepareHealEffect(int64_t value, BattleUnitsChanged & pack, BattleLog
|
||||
resurrectText.addReplacement(resurrectedCount);
|
||||
logMessage.lines.push_back(std::move(resurrectText));
|
||||
}
|
||||
else if (unitHPgained > 0 && m->caster->getCasterUnitId() >= 0) //Show text about healed HP if healed by unit
|
||||
{
|
||||
MetaString healText;
|
||||
auto casterUnit = dynamic_cast<const battle::CUnitState*>(m->caster)->acquire();
|
||||
healText.addTxt(MetaString::GENERAL_TXT, 414);
|
||||
casterUnit->addNameReplacement(healText, false);
|
||||
state->addNameReplacement(healText, false);
|
||||
healText.addReplacement((int)unitHPgained);
|
||||
logMessage.lines.push_back(std::move(healText));
|
||||
}
|
||||
|
||||
if(unitHPgained > 0)
|
||||
{
|
||||
|
@ -5010,7 +5010,6 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
|
||||
case EActionType::STACK_HEAL: //healing with First Aid Tent
|
||||
{
|
||||
auto wrapper = wrapAction(ba);
|
||||
const CGHeroInstance * attackingHero = gs->curB->battleGetFightingHero(ba.side);
|
||||
const CStack * healer = gs->curB->battleGetStackByID(ba.stackNumber);
|
||||
|
||||
if(target.size() < 1)
|
||||
@ -5021,48 +5020,23 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
|
||||
}
|
||||
|
||||
const battle::Unit * destStack = nullptr;
|
||||
std::shared_ptr<const Bonus> healerAbility = stack->getBonusLocalFirst(Selector::type()(Bonus::HEALER));
|
||||
|
||||
if(target.at(0).unitValue)
|
||||
destStack = target.at(0).unitValue;
|
||||
else
|
||||
destStack = gs->curB->battleGetStackByPos(target.at(0).hexValue);
|
||||
|
||||
if(healer == nullptr || destStack == nullptr || !healer->hasBonusOfType(Bonus::HEALER))
|
||||
if(healer == nullptr || destStack == nullptr || !healerAbility || healerAbility->subtype < 0)
|
||||
{
|
||||
complain("There is either no healer, no destination, or healer cannot heal :P");
|
||||
}
|
||||
else
|
||||
{
|
||||
int64_t toHeal = healer->getCount() * std::max(10, attackingHero->valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::FIRST_AID));
|
||||
|
||||
//TODO: allow resurrection for mods
|
||||
auto state = destStack->acquireState();
|
||||
state->heal(toHeal, EHealLevel::HEAL, EHealPower::PERMANENT);
|
||||
|
||||
if(toHeal == 0)
|
||||
{
|
||||
logGlobal->warn("Nothing to heal");
|
||||
}
|
||||
else
|
||||
{
|
||||
BattleUnitsChanged pack;
|
||||
|
||||
BattleLogMessage message;
|
||||
|
||||
MetaString text;
|
||||
text.addTxt(MetaString::GENERAL_TXT, 414);
|
||||
healer->addNameReplacement(text, false);
|
||||
destStack->addNameReplacement(text, false);
|
||||
text.addReplacement((int)toHeal);
|
||||
message.lines.push_back(text);
|
||||
|
||||
UnitChanges info(state->unitId(), UnitChanges::EOperation::RESET_STATE);
|
||||
info.healthDelta = toHeal;
|
||||
state->save(info.data);
|
||||
pack.changedStacks.push_back(info);
|
||||
sendAndApply(&pack);
|
||||
sendAndApply(&message);
|
||||
}
|
||||
const CSpell * spell = SpellID(healerAbility->subtype).toSpell();
|
||||
spells::BattleCast parameters(gs->curB, healer, spells::Mode::SPELL_LIKE_ATTACK, spell); //We can heal infinitely by first aid tent
|
||||
parameters.setSpellLevel(0);
|
||||
parameters.cast(spellEnv, target);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user