mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Demon summon is now a spell. DEMON_SUMMONING bonus has been removed
This commit is contained in:
parent
5b453bf530
commit
9248e06ae0
@ -171,8 +171,6 @@ void BattleActionsController::reorderPossibleActionsPriority(const CStack * stac
|
||||
break;
|
||||
case PossiblePlayerBattleAction::RANDOM_GENIE_SPELL:
|
||||
return 2; break;
|
||||
case PossiblePlayerBattleAction::RISE_DEMONS:
|
||||
return 3; break;
|
||||
case PossiblePlayerBattleAction::SHOOT:
|
||||
return 4; break;
|
||||
case PossiblePlayerBattleAction::ATTACK_AND_RETURN:
|
||||
@ -374,19 +372,6 @@ void BattleActionsController::handleHex(BattleHex myNumber, int eventType)
|
||||
if (shere && ourStack && shere->canBeHealed())
|
||||
legalAction = true;
|
||||
break;
|
||||
case PossiblePlayerBattleAction::RISE_DEMONS:
|
||||
if (shere && ourStack && !shere->alive())
|
||||
{
|
||||
if (!(shere->hasBonusOfType(Bonus::UNDEAD)
|
||||
|| shere->hasBonusOfType(Bonus::NON_LIVING)
|
||||
|| shere->hasBonusOfType(Bonus::GARGOYLE)
|
||||
|| shere->summoned
|
||||
|| shere->isClone()
|
||||
|| shere->hasBonusOfType(Bonus::SIEGE_WEAPON)
|
||||
))
|
||||
legalAction = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (legalAction)
|
||||
localActions.push_back (action);
|
||||
@ -542,13 +527,6 @@ void BattleActionsController::handleHex(BattleHex myNumber, int eventType)
|
||||
newConsoleMsg = (boost::format(CGI->generaltexth->allTexts[419]) % shere->getName()).str(); //Apply first aid to the %s
|
||||
realizeAction = [=](){ owner.giveCommand(EActionType::STACK_HEAL, myNumber); }; //command healing
|
||||
break;
|
||||
case PossiblePlayerBattleAction::RISE_DEMONS:
|
||||
spellcastingCursor = true;
|
||||
realizeAction = [=]()
|
||||
{
|
||||
owner.giveCommand(EActionType::DAEMON_SUMMONING, myNumber);
|
||||
};
|
||||
break;
|
||||
case PossiblePlayerBattleAction::CATAPULT:
|
||||
cursorFrame = Cursor::Combat::SHOOT_CATAPULT;
|
||||
realizeAction = [=](){ owner.giveCommand(EActionType::CATAPULT, myNumber); };
|
||||
|
@ -847,7 +847,7 @@ void BattleStacksController::updateHoveredStacks()
|
||||
continue;
|
||||
|
||||
stackAnimation[stack->ID]->setBorderColor(AnimationControls::getBlueBorder());
|
||||
if (stackAnimation[stack->ID]->framesInGroup(ECreatureAnimType::MOUSEON) > 0)
|
||||
if (stackAnimation[stack->ID]->framesInGroup(ECreatureAnimType::MOUSEON) > 0 && stack->alive())
|
||||
stackAnimation[stack->ID]->playOnce(ECreatureAnimType::MOUSEON);
|
||||
|
||||
}
|
||||
|
@ -139,6 +139,7 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
|
||||
${MAIN_LIB_DIR}/spells/effects/Catapult.cpp
|
||||
${MAIN_LIB_DIR}/spells/effects/Clone.cpp
|
||||
${MAIN_LIB_DIR}/spells/effects/Damage.cpp
|
||||
${MAIN_LIB_DIR}/spells/effects/DemonSummon.cpp
|
||||
${MAIN_LIB_DIR}/spells/effects/Dispel.cpp
|
||||
${MAIN_LIB_DIR}/spells/effects/Effect.cpp
|
||||
${MAIN_LIB_DIR}/spells/effects/Effects.cpp
|
||||
@ -374,6 +375,7 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
|
||||
${MAIN_LIB_DIR}/spells/effects/Catapult.h
|
||||
${MAIN_LIB_DIR}/spells/effects/Clone.h
|
||||
${MAIN_LIB_DIR}/spells/effects/Damage.h
|
||||
${MAIN_LIB_DIR}/spells/effects/DemonSummon.h
|
||||
${MAIN_LIB_DIR}/spells/effects/Dispel.h
|
||||
${MAIN_LIB_DIR}/spells/effects/Effect.h
|
||||
${MAIN_LIB_DIR}/spells/effects/Effects.h
|
||||
|
@ -2240,12 +2240,6 @@
|
||||
"val" : 0,
|
||||
"valueType" : "BASE_NUMBER"
|
||||
},
|
||||
{
|
||||
"subtype" : "creature.vampireLord",
|
||||
"type" : "DAEMON_SUMMONING",
|
||||
"val" : 10,
|
||||
"valueType" : "BASE_NUMBER"
|
||||
},
|
||||
{
|
||||
"addInfo" : 2,
|
||||
"subtype" : "spell.lightningBolt",
|
||||
|
@ -84,14 +84,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
"DAEMON_SUMMONING":
|
||||
{
|
||||
"graphics":
|
||||
{
|
||||
"icon": "zvs/Lib1.res/RiseDemons"
|
||||
}
|
||||
},
|
||||
|
||||
"DARKNESS":
|
||||
{
|
||||
},
|
||||
|
@ -72,12 +72,6 @@
|
||||
"description": "Immune to Champion charge"
|
||||
},
|
||||
|
||||
"DAEMON_SUMMONING":
|
||||
{
|
||||
"name": "Summoner (${subtype.creature})",
|
||||
"description": "Can rise creatures from corpses"
|
||||
},
|
||||
|
||||
"DARKNESS":
|
||||
{
|
||||
"name": "Darkness cover",
|
||||
|
@ -216,12 +216,18 @@
|
||||
"faction": "inferno",
|
||||
"abilities":
|
||||
{
|
||||
"demonSummon" :
|
||||
"summons50HP" :
|
||||
{
|
||||
"type" : "DAEMON_SUMMONING",
|
||||
"subtype" : "creature.demon",
|
||||
"type" : "SPECIFIC_SPELL_POWER",
|
||||
"subtype" : "spell.summonDemons",
|
||||
"val" : 50
|
||||
},
|
||||
"resurrects" :
|
||||
{
|
||||
"type" : "SPELLCASTER",
|
||||
"subtype" : "spell.summonDemons",
|
||||
"val" : 0
|
||||
},
|
||||
"castsAmount" :
|
||||
{
|
||||
"type" : "CASTS",
|
||||
|
@ -430,5 +430,52 @@
|
||||
"bonus.DIRECT_DAMAGE_IMMUNITY" : "normal"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"summonDemons" : {
|
||||
"type": "ability",
|
||||
"targetType" : "CREATURE",
|
||||
"name": "Summon Demons",
|
||||
"school" : {},
|
||||
"level": 2,
|
||||
"power": 50,
|
||||
"defaultGainChance": 0,
|
||||
"gainChance": {},
|
||||
"animation":{
|
||||
},
|
||||
"sounds": {
|
||||
"cast": "RESURECT"
|
||||
},
|
||||
"levels" : {
|
||||
"base": {
|
||||
"description" : "",
|
||||
"aiValue" : 0,
|
||||
"power" : 40,
|
||||
"cost" : 1,
|
||||
"range" : "0",
|
||||
"battleEffects":{
|
||||
"demonSummon":{
|
||||
"id":"demon",
|
||||
"permanent":true,
|
||||
"type":"core:demonSummon"
|
||||
}
|
||||
}
|
||||
},
|
||||
"none" :{},
|
||||
"basic" :{},
|
||||
"advanced" :{},
|
||||
"expert" :{}
|
||||
},
|
||||
"flags" : {
|
||||
"rising": true,
|
||||
"positive": true
|
||||
},
|
||||
"targetCondition" : {
|
||||
"noneOf" : {
|
||||
"bonus.NON_LIVING" : "absolute",
|
||||
"bonus.SIEGE_WEAPON" : "absolute",
|
||||
"bonus.UNDEAD" : "absolute",
|
||||
"bonus.GARGOYLE" : "absolute"
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -232,7 +232,6 @@ std::ostream & operator<<(std::ostream & os, const EActionType actionType)
|
||||
{EActionType::MONSTER_SPELL, "Monster spell"},
|
||||
{EActionType::BAD_MORALE, "Bad morale"},
|
||||
{EActionType::STACK_HEAL, "Stack heal"},
|
||||
{EActionType::DAEMON_SUMMONING, "Daemon summoning"}
|
||||
};
|
||||
|
||||
auto it = actionTypeToString.find(actionType);
|
||||
|
@ -922,7 +922,6 @@ enum class EActionType : int32_t
|
||||
MONSTER_SPELL,
|
||||
BAD_MORALE,
|
||||
STACK_HEAL,
|
||||
DAEMON_SUMMONING
|
||||
};
|
||||
|
||||
DLL_LINKAGE std::ostream & operator<<(std::ostream & os, const EActionType actionType);
|
||||
|
@ -237,7 +237,6 @@ public:
|
||||
BONUS_NAME(MANA_CHANNELING) /*value in %, eg. familiar*/ \
|
||||
BONUS_NAME(SPELL_LIKE_ATTACK) /*subtype - spell, value - spell level; range is taken from spell, but damage from creature; eg. magog*/ \
|
||||
BONUS_NAME(THREE_HEADED_ATTACK) /*eg. cerberus*/ \
|
||||
BONUS_NAME(DAEMON_SUMMONING) /*pit lord, subtype - type of creatures, val - hp per unit*/ \
|
||||
BONUS_NAME(FIRE_IMMUNITY) /*subtype 0 - all, 1 - all except positive, 2 - only damage spells*/ \
|
||||
BONUS_NAME(WATER_IMMUNITY) \
|
||||
BONUS_NAME(EARTH_IMMUNITY) \
|
||||
|
@ -230,8 +230,6 @@ std::vector<PossiblePlayerBattleAction> CBattleInfoCallback::getClientActionsFor
|
||||
}
|
||||
if(stack->hasBonusOfType(Bonus::RANDOM_SPELLCASTER))
|
||||
allowedActionList.push_back(PossiblePlayerBattleAction::RANDOM_GENIE_SPELL);
|
||||
if(stack->hasBonusOfType(Bonus::DAEMON_SUMMONING))
|
||||
allowedActionList.push_back(PossiblePlayerBattleAction::RISE_DEMONS);
|
||||
}
|
||||
if(stack->canShoot())
|
||||
allowedActionList.push_back(PossiblePlayerBattleAction::SHOOT);
|
||||
|
@ -49,7 +49,7 @@ enum class PossiblePlayerBattleAction // actions performed at l-click
|
||||
MOVE_STACK, ATTACK, WALK_AND_ATTACK, ATTACK_AND_RETURN, SHOOT, //OPEN_GATE, //we can open castle gate during siege
|
||||
NO_LOCATION, ANY_LOCATION, OBSTACLE, TELEPORT, SACRIFICE, RANDOM_GENIE_SPELL,
|
||||
FREE_LOCATION, //used with Force Field and Fire Wall - all tiles affected by spell must be free
|
||||
CATAPULT, HEAL, RISE_DEMONS,
|
||||
CATAPULT, HEAL,
|
||||
AIMED_SPELL_CREATURE
|
||||
};
|
||||
|
||||
|
@ -608,9 +608,9 @@ std::vector<Destination> BattleSpellMechanics::getPossibleDestinations(size_t in
|
||||
Target tmp = current;
|
||||
tmp.emplace_back(dest);
|
||||
|
||||
detail::ProblemImpl ingored;
|
||||
detail::ProblemImpl ignored;
|
||||
|
||||
if(canBeCastAt(tmp, ingored))
|
||||
if(canBeCastAt(tmp, ignored))
|
||||
ret.emplace_back(dest);
|
||||
}
|
||||
}
|
||||
@ -630,7 +630,7 @@ bool BattleSpellMechanics::isReceptive(const battle::Unit * target) const
|
||||
return targetCondition->isReceptive(this, target);
|
||||
}
|
||||
|
||||
std::vector<BattleHex> BattleSpellMechanics::rangeInHexes(BattleHex centralHex, bool * outDroppedHexes) const
|
||||
std::vector<BattleHex> BattleSpellMechanics::rangeInHexes(BattleHex centralHex) const
|
||||
{
|
||||
if(isMassive() || !centralHex.isValid())
|
||||
return std::vector<BattleHex>(1, BattleHex::INVALID);
|
||||
|
@ -27,22 +27,36 @@ public:
|
||||
BattleSpellMechanics(const IBattleCast * event, std::shared_ptr<effects::Effects> effects_, std::shared_ptr<IReceptiveCheck> targetCondition_);
|
||||
virtual ~BattleSpellMechanics();
|
||||
|
||||
// TODO: ??? (what's the difference compared to cast?)
|
||||
void applyEffects(ServerCallback * server, const Target & targets, bool indirect, bool ignoreImmunity) const override;
|
||||
|
||||
/// Returns false if spell can not be cast at all, e.g. due to not having any possible target on battlefield
|
||||
bool canBeCast(Problem & problem) const override;
|
||||
|
||||
/// Returns false if spell can not be cast at specifid target
|
||||
bool canBeCastAt(const Target & target, Problem & problem) const override;
|
||||
|
||||
// TODO: ??? (what's the difference compared to applyEffects?)
|
||||
void cast(ServerCallback * server, const Target & target) override final;
|
||||
// TODO: ??? (what's the difference compared to cast?)
|
||||
void castEval(ServerCallback * server, const Target & target) override final;
|
||||
|
||||
/// Returns list of affected stack using currently configured target
|
||||
std::vector<const CStack *> getAffectedStacks(const Target & target) const override final;
|
||||
|
||||
/// Returns list of target types that can be targeted by spell
|
||||
std::vector<AimType> getTargetTypes() const override final;
|
||||
|
||||
/// Returns vector of all possible destinations for specified aim type
|
||||
/// index - ???
|
||||
/// current - ???
|
||||
std::vector<Destination> getPossibleDestinations(size_t index, AimType aimType, const Target & current) const override final;
|
||||
|
||||
/// Returns true if spell can be cast on unit
|
||||
bool isReceptive(const battle::Unit * target) const override;
|
||||
|
||||
std::vector<BattleHex> rangeInHexes(BattleHex centralHex, bool * outDroppedHexes = nullptr) const override;
|
||||
/// Returns list of hexes that are affected by spell assuming cast at centralHex
|
||||
std::vector<BattleHex> rangeInHexes(BattleHex centralHex) const override;
|
||||
|
||||
const Spell * getSpell() const override;
|
||||
|
||||
|
@ -701,9 +701,9 @@ PlayerColor BaseMechanics::getCasterColor() const
|
||||
std::vector<AimType> BaseMechanics::getTargetTypes() const
|
||||
{
|
||||
std::vector<AimType> ret;
|
||||
detail::ProblemImpl ingored;
|
||||
detail::ProblemImpl ignored;
|
||||
|
||||
if(canBeCast(ingored))
|
||||
if(canBeCast(ignored))
|
||||
{
|
||||
auto spellTargetType = owner->getTargetType();
|
||||
|
||||
|
@ -183,7 +183,7 @@ public:
|
||||
virtual bool adaptProblem(ESpellCastProblem::ESpellCastProblem source, Problem & target) const = 0;
|
||||
virtual bool adaptGenericProblem(Problem & target) const = 0;
|
||||
|
||||
virtual std::vector<BattleHex> rangeInHexes(BattleHex centralHex, bool * outDroppedHexes = nullptr) const = 0;
|
||||
virtual std::vector<BattleHex> rangeInHexes(BattleHex centralHex) const = 0;
|
||||
virtual std::vector<const CStack *> getAffectedStacks(const Target & target) const = 0;
|
||||
|
||||
virtual bool canBeCast(Problem & problem) const = 0;
|
||||
|
130
lib/spells/effects/DemonSummon.cpp
Normal file
130
lib/spells/effects/DemonSummon.cpp
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* DemonSummon.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
|
||||
#include "DemonSummon.h"
|
||||
#include "Registry.h"
|
||||
#include "../ISpellMechanics.h"
|
||||
#include "../../NetPacks.h"
|
||||
#include "../../battle/CBattleInfoCallback.h"
|
||||
#include "../../battle/CUnitState.h"
|
||||
#include "../../serializer/JsonSerializeFormat.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
static const std::string EFFECT_NAME = "core:demonSummon";
|
||||
|
||||
namespace spells
|
||||
{
|
||||
namespace effects
|
||||
{
|
||||
|
||||
VCMI_REGISTER_SPELL_EFFECT(DemonSummon, EFFECT_NAME);
|
||||
|
||||
DemonSummon::DemonSummon()
|
||||
: UnitEffect()
|
||||
, creature(0)
|
||||
, permanent(false)
|
||||
{
|
||||
}
|
||||
|
||||
DemonSummon::~DemonSummon() = default;
|
||||
|
||||
void DemonSummon::apply(ServerCallback * server, const Mechanics * m, const EffectTarget & target) const
|
||||
{
|
||||
BattleUnitsChanged pack;
|
||||
|
||||
for(const Destination & dest : target)
|
||||
{
|
||||
const battle::Unit * targetStack = dest.unitValue;
|
||||
|
||||
//we shall have all targets to be stacks
|
||||
if(!targetStack || targetStack->alive() || targetStack->isGhost())
|
||||
{
|
||||
server->complain("No corpse to demonize! Invalid effect target transformation.");
|
||||
continue;
|
||||
}
|
||||
|
||||
auto hex = m->battle()->getAvaliableHex(targetStack->creatureId(), m->casterSide, targetStack->getPosition());
|
||||
|
||||
if(!hex.isValid())
|
||||
{
|
||||
server->complain("No place to put new summon!");
|
||||
break;
|
||||
}
|
||||
|
||||
auto creatureType = creature.toCreature(m->creatures());
|
||||
|
||||
int32_t deadCount = targetStack->unitBaseAmount();
|
||||
int32_t deadTotalHealth = targetStack->getTotalHealth();
|
||||
int32_t raisedMaxHealth = creatureType->getMaxHealth();
|
||||
int32_t raisedTotalHealth = m->applySpellBonus(m->getEffectValue(), targetStack);
|
||||
|
||||
// Can't raise stack with more HP than original stack
|
||||
int32_t maxAmountFromHealth = deadTotalHealth / raisedMaxHealth;
|
||||
// Can't raise stack with more creatures than original stack
|
||||
int32_t maxAmountFromAmount = deadCount;
|
||||
// Can't raise stack with more HP than our spellpower
|
||||
int32_t maxAmountFromSpellpower = raisedTotalHealth / raisedMaxHealth;
|
||||
|
||||
int32_t finalAmount = std::min( { maxAmountFromHealth, maxAmountFromAmount, maxAmountFromSpellpower } );
|
||||
|
||||
if(finalAmount < 1)
|
||||
{
|
||||
server->complain("Summoning didn't summon any!");
|
||||
continue;
|
||||
}
|
||||
|
||||
battle::UnitInfo info;
|
||||
info.id = m->battle()->battleNextUnitId();
|
||||
info.count = finalAmount;
|
||||
info.type = creature;
|
||||
info.side = m->casterSide;
|
||||
info.position = dest.hexValue;
|
||||
info.summoned = !permanent;
|
||||
|
||||
// add newly created creature
|
||||
pack.changedStacks.emplace_back(info.id, UnitChanges::EOperation::ADD);
|
||||
info.save(pack.changedStacks.back().data);
|
||||
|
||||
// and remove corpse to prevent second raising or resurrection
|
||||
pack.changedStacks.emplace_back(targetStack->unitId(), UnitChanges::EOperation::REMOVE);
|
||||
}
|
||||
|
||||
if(!pack.changedStacks.empty())
|
||||
server->apply(&pack);
|
||||
}
|
||||
|
||||
bool DemonSummon::isValidTarget(const Mechanics * m, const battle::Unit * s) const
|
||||
{
|
||||
if(!s->isDead())
|
||||
return false;
|
||||
|
||||
if (s->isGhost())
|
||||
return false;
|
||||
|
||||
auto creatureType = creature.toCreature(m->creatures());
|
||||
|
||||
if (s->getTotalHealth() < creatureType->getMaxHealth())
|
||||
return false;
|
||||
|
||||
return m->isReceptive(s);
|
||||
}
|
||||
|
||||
void DemonSummon::serializeJsonUnitEffect(JsonSerializeFormat & handler)
|
||||
{
|
||||
handler.serializeId("id", creature, CreatureID());
|
||||
handler.serializeBool("permanent", permanent, false);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
44
lib/spells/effects/DemonSummon.h
Normal file
44
lib/spells/effects/DemonSummon.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* DemonSummon.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "UnitEffect.h"
|
||||
#include "../../GameConstants.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
namespace spells
|
||||
{
|
||||
namespace effects
|
||||
{
|
||||
|
||||
class DemonSummon : public UnitEffect
|
||||
{
|
||||
public:
|
||||
DemonSummon();
|
||||
virtual ~DemonSummon();
|
||||
|
||||
void apply(ServerCallback * server, const Mechanics * m, const EffectTarget & target) const override;
|
||||
protected:
|
||||
bool isValidTarget(const Mechanics * m, const battle::Unit * s) const override;
|
||||
|
||||
void serializeJsonUnitEffect(JsonSerializeFormat & handler) override final;
|
||||
|
||||
private:
|
||||
CreatureID creature;
|
||||
|
||||
bool permanent;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
@ -51,19 +51,27 @@ public:
|
||||
Effect();
|
||||
virtual ~Effect();
|
||||
|
||||
// TODO: document me
|
||||
virtual void adjustTargetTypes(std::vector<TargetType> & types) const = 0;
|
||||
|
||||
/// Generates list of hexes affected by spell, if spell were to cast at specified target
|
||||
virtual void adjustAffectedHexes(std::set<BattleHex> & hexes, const Mechanics * m, const Target & spellTarget) const = 0;
|
||||
|
||||
/// Returns whether effect has any valid targets on the battlefield
|
||||
virtual bool applicable(Problem & problem, const Mechanics * m) const;
|
||||
|
||||
/// Returns whether effect is valid and can be applied onto selected target
|
||||
virtual bool applicable(Problem & problem, const Mechanics * m, const EffectTarget & target) const;
|
||||
|
||||
virtual void apply(ServerCallback * server, const Mechanics * m, const EffectTarget & target) const = 0;
|
||||
|
||||
/// Processes input target and generates subset-result that contains only valid targets
|
||||
virtual EffectTarget filterTarget(const Mechanics * m, const EffectTarget & target) const = 0;
|
||||
|
||||
// TODO: document me
|
||||
virtual EffectTarget transformTarget(const Mechanics * m, const Target & aimPoint, const Target & spellTarget) const = 0;
|
||||
|
||||
/// Serializes (or deserializes) parameters of Effect
|
||||
void serializeJson(JsonSerializeFormat & handler);
|
||||
|
||||
static std::shared_ptr<Effect> create(const Registry * registry, const std::string & type);
|
||||
|
@ -63,14 +63,14 @@ bool Heal::isValidTarget(const Mechanics * m, const battle::Unit * unit) const
|
||||
if(!validInGenaral)
|
||||
return false;
|
||||
|
||||
auto insuries = unit->getTotalHealth() - unit->getAvailableHealth();
|
||||
auto injuries = unit->getTotalHealth() - unit->getAvailableHealth();
|
||||
|
||||
if(insuries == 0)
|
||||
if(injuries == 0)
|
||||
return false;
|
||||
|
||||
if(minFullUnits > 0)
|
||||
{
|
||||
auto hpGained = std::min(m->getEffectValue(), insuries);
|
||||
auto hpGained = std::min(m->getEffectValue(), injuries);
|
||||
if(hpGained < minFullUnits * unit->MaxHealth())
|
||||
return false;
|
||||
}
|
||||
|
@ -4472,7 +4472,6 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
|
||||
case EActionType::SHOOT: //shoot
|
||||
case EActionType::CATAPULT: //catapult
|
||||
case EActionType::STACK_HEAL: //healing with First Aid Tent
|
||||
case EActionType::DAEMON_SUMMONING:
|
||||
case EActionType::MONSTER_SPELL:
|
||||
|
||||
if (!stack)
|
||||
@ -5006,58 +5005,6 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EActionType::DAEMON_SUMMONING:
|
||||
//TODO: From Strategija:
|
||||
//Summon Demon is a level 2 spell.
|
||||
{
|
||||
if(target.size() < 1)
|
||||
{
|
||||
complain("Destination required for summon action.");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
const CStack * summoner = gs->curB->battleGetStackByID(ba.stackNumber);
|
||||
const CStack * destStack = gs->curB->battleGetStackByPos(target.at(0).hexValue, false);
|
||||
|
||||
CreatureID summonedType(summoner->getBonusLocalFirst(Selector::type()(Bonus::DAEMON_SUMMONING))->subtype);//in case summoner can summon more than one type of monsters... scream!
|
||||
|
||||
ui64 risedHp = summoner->getCount() * summoner->valOfBonuses(Bonus::DAEMON_SUMMONING, summonedType.toEnum());
|
||||
ui64 targetHealth = destStack->getCreature()->MaxHealth() * destStack->baseAmount;
|
||||
|
||||
ui64 canRiseHp = std::min(targetHealth, risedHp);
|
||||
ui32 canRiseAmount = static_cast<ui32>(canRiseHp / summonedType.toCreature()->MaxHealth());
|
||||
|
||||
battle::UnitInfo info;
|
||||
info.id = gs->curB->battleNextUnitId();
|
||||
info.count = std::min(canRiseAmount, destStack->baseAmount);
|
||||
info.type = summonedType;
|
||||
info.side = summoner->side;
|
||||
info.position = gs->curB->getAvaliableHex(summonedType, summoner->side, destStack->getPosition());
|
||||
info.summoned = false;
|
||||
|
||||
BattleUnitsChanged addUnits;
|
||||
addUnits.changedStacks.emplace_back(info.id, UnitChanges::EOperation::ADD);
|
||||
info.save(addUnits.changedStacks.back().data);
|
||||
|
||||
if(info.count > 0) //there's rare possibility single creature cannot rise desired type
|
||||
{
|
||||
auto wrapper = wrapAction(ba);
|
||||
|
||||
BattleUnitsChanged removeUnits;
|
||||
removeUnits.changedStacks.emplace_back(destStack->unitId(), UnitChanges::EOperation::REMOVE);
|
||||
sendAndApply(&removeUnits);
|
||||
sendAndApply(&addUnits);
|
||||
|
||||
BattleSetStackProperty ssp;
|
||||
ssp.stackID = ba.stackNumber;
|
||||
ssp.which = BattleSetStackProperty::CASTS; //reduce number of casts
|
||||
ssp.val = -1;
|
||||
ssp.absolute = false;
|
||||
sendAndApply(&ssp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EActionType::MONSTER_SPELL:
|
||||
{
|
||||
auto wrapper = wrapAction(ba);
|
||||
@ -5089,7 +5036,7 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(ba.actionType == EActionType::DAEMON_SUMMONING || ba.actionType == EActionType::WAIT || ba.actionType == EActionType::DEFEND
|
||||
if(ba.actionType == EActionType::WAIT || ba.actionType == EActionType::DEFEND
|
||||
|| ba.actionType == EActionType::SHOOT || ba.actionType == EActionType::MONSTER_SPELL)
|
||||
handleDamageFromObstacle(stack);
|
||||
if(ba.stackNumber == gs->curB->activeStack || battleResult.get()) //active stack has moved or battle has finished
|
||||
|
Loading…
Reference in New Issue
Block a user