mirror of
https://github.com/vcmi/vcmi.git
synced 2025-11-29 23:07:48 +02:00
(somewhat) configurable adventure map spells
- All adventure map spells have most of their parameters in json. - Parameters of adventure map spells can now be defined separately per each mastery level. - It is now possible to add a new spell that will have effect similar to H3 adventure map spell
This commit is contained in:
@@ -6,9 +6,25 @@
|
||||
"sounds": {
|
||||
"cast": "SUMMBOAT"
|
||||
},
|
||||
"levels" :{
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "X"
|
||||
"range" : "X",
|
||||
"adventureEffect" : {
|
||||
"type" : "summonBoat",
|
||||
"castsPerDay" : 0,
|
||||
"useExistingBoat" : true,
|
||||
"createNewBoat" : false
|
||||
}
|
||||
},
|
||||
"advanced":{
|
||||
"adventureEffect" : {
|
||||
"createNewBoat" : true
|
||||
}
|
||||
},
|
||||
"expert":{
|
||||
"adventureEffect" : {
|
||||
"createNewBoat" : true
|
||||
}
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
@@ -25,7 +41,25 @@
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "X"
|
||||
"range" : "X",
|
||||
"adventureEffect" : {
|
||||
"type" : "removeObject",
|
||||
"castsPerDay" : 0,
|
||||
"rangeX" : 9,
|
||||
"rangeY" : 8,
|
||||
"ignoreFow" : false,
|
||||
"objects" : {
|
||||
"boat" : true
|
||||
}
|
||||
}
|
||||
},
|
||||
"advanced":{
|
||||
"adventureEffect" : {
|
||||
}
|
||||
},
|
||||
"expert":{
|
||||
"adventureEffect" : {
|
||||
}
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
@@ -43,7 +77,10 @@
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0",
|
||||
"effects" : {
|
||||
"adventureEffect" : {
|
||||
"type" : "generic",
|
||||
"castsPerDay" : 0,
|
||||
"bonuses" : {
|
||||
"visionsMonsters" : {
|
||||
"type" : "VISIONS",
|
||||
"subtype" : "visionsMonsters",
|
||||
@@ -52,9 +89,11 @@
|
||||
"valueType" : "INDEPENDENT_MAX"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"advanced":{
|
||||
"effects" : {
|
||||
"adventureEffect" : {
|
||||
"bonuses" : {
|
||||
"visionsMonsters" : {
|
||||
"val" : 2
|
||||
},
|
||||
@@ -65,11 +104,12 @@
|
||||
"val" : 2,
|
||||
"valueType" : "INDEPENDENT_MAX"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
"expert":{
|
||||
"effects" : {
|
||||
"adventureEffect" : {
|
||||
"bonuses" : {
|
||||
"visionsMonsters" : {
|
||||
"val" : 3
|
||||
},
|
||||
@@ -89,6 +129,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"indifferent": true
|
||||
@@ -103,7 +144,33 @@
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "X"
|
||||
"range" : "X",
|
||||
"adventureEffect" : {
|
||||
"type" : "viewWorld",
|
||||
"castsPerDay" : 0,
|
||||
"objects" : {
|
||||
"resource" : true
|
||||
}
|
||||
}
|
||||
},
|
||||
"advanced":{
|
||||
"adventureEffect" : {
|
||||
"objects" : {
|
||||
"resource" : true,
|
||||
"mine" : true,
|
||||
"abandonedMine" : true
|
||||
}
|
||||
}
|
||||
},
|
||||
"expert":{
|
||||
"adventureEffect" : {
|
||||
"objects" : {
|
||||
"resource" : true,
|
||||
"mine" : true,
|
||||
"abandonedMine" : true
|
||||
},
|
||||
"terrain" : true
|
||||
}
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
@@ -120,7 +187,10 @@
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0",
|
||||
"effects" : {
|
||||
"adventureEffect" : {
|
||||
"type" : "generic",
|
||||
"castsPerDay" : 0,
|
||||
"bonuses" : {
|
||||
"stealth" : {
|
||||
"type" : "DISGUISED",
|
||||
"duration" : "ONE_DAY",
|
||||
@@ -128,21 +198,26 @@
|
||||
"valueType" : "INDEPENDENT_MAX"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"advanced":{
|
||||
"effects" : {
|
||||
"adventureEffect" : {
|
||||
"bonuses" : {
|
||||
"stealth" : {
|
||||
"val" : 2
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"expert":{
|
||||
"effects" : {
|
||||
"adventureEffect" : {
|
||||
"bonuses" : {
|
||||
"stealth" : {
|
||||
"val" : 3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"indifferent": true
|
||||
@@ -157,7 +232,31 @@
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "X"
|
||||
"range" : "X",
|
||||
"adventureEffect" : {
|
||||
"type" : "viewWorld",
|
||||
"castsPerDay" : 0,
|
||||
"objects" : {
|
||||
"artifact" : true
|
||||
}
|
||||
}
|
||||
},
|
||||
"advanced":{
|
||||
"adventureEffect" : {
|
||||
"objects" : {
|
||||
"artifact" : true,
|
||||
"hero" : true
|
||||
}
|
||||
}
|
||||
},
|
||||
"expert":{
|
||||
"adventureEffect" : {
|
||||
"objects" : {
|
||||
"artifact" : true,
|
||||
"hero" : true,
|
||||
"town" : true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
@@ -174,7 +273,10 @@
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0",
|
||||
"effects" : {
|
||||
"adventureEffect" : {
|
||||
"type" : "generic",
|
||||
"castsPerDay" : 0,
|
||||
"bonuses" : {
|
||||
"fly" : {
|
||||
"type" : "FLYING_MOVEMENT",
|
||||
"duration" : "ONE_DAY",
|
||||
@@ -182,21 +284,28 @@
|
||||
"valueType" : "INDEPENDENT_MIN"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"advanced":{
|
||||
"effects" : {
|
||||
"adventureEffect" : {
|
||||
"type" : "generic",
|
||||
"bonuses" : {
|
||||
"fly" : {
|
||||
"val" : 20
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"expert":{
|
||||
"effects" : {
|
||||
"adventureEffect" : {
|
||||
"type" : "generic",
|
||||
"bonuses" : {
|
||||
"fly" : {
|
||||
"val" : 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"indifferent": true
|
||||
@@ -212,7 +321,10 @@
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0",
|
||||
"effects" : {
|
||||
"adventureEffect" : {
|
||||
"type" : "generic",
|
||||
"castsPerDay" : 0,
|
||||
"bonuses" : {
|
||||
"waterWalk" : {
|
||||
"type" : "WATER_WALKING",
|
||||
"duration" : "ONE_DAY",
|
||||
@@ -220,21 +332,28 @@
|
||||
"valueType" : "INDEPENDENT_MIN"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"advanced":{
|
||||
"effects" : {
|
||||
"adventureEffect" : {
|
||||
"type" : "generic",
|
||||
"bonuses" : {
|
||||
"waterWalk" : {
|
||||
"val" : 20
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"expert":{
|
||||
"effects" : {
|
||||
"adventureEffect" : {
|
||||
"type" : "generic",
|
||||
"bonuses" : {
|
||||
"waterWalk" : {
|
||||
"val" : 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"indifferent": true
|
||||
@@ -250,7 +369,29 @@
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "X"
|
||||
"range" : "X",
|
||||
"adventureEffect" : {
|
||||
"type" : "dimensionDoor",
|
||||
"movementPointsRequired" : 0,
|
||||
"movementPointsTaken" : 300,
|
||||
"waterLandFailureTakesPoints" : true,
|
||||
"castsPerDay" : 2,
|
||||
"rangeX" : 9,
|
||||
"rangeY" : 8,
|
||||
"ignoreFow" : true,
|
||||
"exposeFow" : true
|
||||
}
|
||||
},
|
||||
"advanced":{
|
||||
"adventureEffect" : {
|
||||
"castsPerDay" : 3
|
||||
}
|
||||
},
|
||||
"expert":{
|
||||
"adventureEffect" : {
|
||||
"castsPerDay" : 4,
|
||||
"movementPointsTaken" : 200
|
||||
}
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
@@ -266,7 +407,29 @@
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "X"
|
||||
"range" : "X",
|
||||
"adventureEffect" : {
|
||||
"type" : "townPortal",
|
||||
"castsPerDay" : 2,
|
||||
"allowTownSelection" : false,
|
||||
"skipOccupiedTowns" : false,
|
||||
"movementPointsRequired" : 300,
|
||||
"movementPointsTaken" : 300
|
||||
}
|
||||
},
|
||||
"advanced":{
|
||||
"adventureEffect" : {
|
||||
"allowTownSelection" : true,
|
||||
"movementPointsRequired" : 200,
|
||||
"movementPointsTaken" : 200
|
||||
}
|
||||
},
|
||||
"expert":{
|
||||
"adventureEffect" : {
|
||||
"allowTownSelection" : true,
|
||||
"movementPointsRequired" : 200,
|
||||
"movementPointsTaken" : 200
|
||||
}
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
|
||||
@@ -268,12 +268,13 @@ set(lib_MAIN_SRCS
|
||||
spells/TargetCondition.cpp
|
||||
spells/ViewSpellInt.cpp
|
||||
|
||||
spells/adventure/AdventureSpellEffect.cpp
|
||||
spells/adventure/AdventureSpellMechanics.cpp
|
||||
spells/adventure/DimensionDoorMechanics.cpp
|
||||
spells/adventure/ScuttleBoatMechanics.cpp
|
||||
spells/adventure/SummonBoatMechanics.cpp
|
||||
spells/adventure/TownPortalMechanics.cpp
|
||||
spells/adventure/ViewWorldMechanics.cpp
|
||||
spells/adventure/DimensionDoorEffect.cpp
|
||||
spells/adventure/RemoveObjectEffect.cpp
|
||||
spells/adventure/SummonBoatEffect.cpp
|
||||
spells/adventure/TownPortalEffect.cpp
|
||||
spells/adventure/ViewWorldEffect.cpp
|
||||
|
||||
spells/effects/Catapult.cpp
|
||||
spells/effects/Clone.cpp
|
||||
@@ -731,11 +732,12 @@ set(lib_MAIN_HEADERS
|
||||
spells/ViewSpellInt.h
|
||||
|
||||
spells/adventure/AdventureSpellMechanics.h
|
||||
spells/adventure/DimensionDoorMechanics.h
|
||||
spells/adventure/ScuttleBoatMechanics.h
|
||||
spells/adventure/SummonBoatMechanics.h
|
||||
spells/adventure/TownPortalMechanics.h
|
||||
spells/adventure/ViewWorldMechanics.h
|
||||
spells/adventure/AdventureSpellEffect.h
|
||||
spells/adventure/DimensionDoorEffect.h
|
||||
spells/adventure/RemoveObjectEffect.h
|
||||
spells/adventure/SummonBoatEffect.h
|
||||
spells/adventure/TownPortalEffect.h
|
||||
spells/adventure/ViewWorldEffect.h
|
||||
|
||||
spells/effects/Catapult.h
|
||||
spells/effects/Clone.h
|
||||
|
||||
@@ -68,10 +68,6 @@ const std::vector<GameSettings::SettingOption> GameSettings::settingProperties =
|
||||
{EGameSettings::CREATURES_JOINING_PERCENTAGE, "creatures", "joiningPercentage" },
|
||||
{EGameSettings::CREATURES_WEEKLY_GROWTH_CAP, "creatures", "weeklyGrowthCap" },
|
||||
{EGameSettings::CREATURES_WEEKLY_GROWTH_PERCENT, "creatures", "weeklyGrowthPercent" },
|
||||
{EGameSettings::DIMENSION_DOOR_EXPOSES_TERRAIN_TYPE, "spells", "dimensionDoorExposesTerrainType" },
|
||||
{EGameSettings::DIMENSION_DOOR_FAILURE_SPENDS_POINTS, "spells", "dimensionDoorFailureSpendsPoints" },
|
||||
{EGameSettings::DIMENSION_DOOR_ONLY_TO_UNCOVERED_TILES, "spells", "dimensionDoorOnlyToUncoveredTiles" },
|
||||
{EGameSettings::DIMENSION_DOOR_TOURNAMENT_RULES_LIMIT, "spells", "dimensionDoorTournamentRulesLimit" },
|
||||
{EGameSettings::DIMENSION_DOOR_TRIGGERS_GUARDS, "spells", "dimensionDoorTriggersGuards" },
|
||||
{EGameSettings::DWELLINGS_ACCUMULATE_WHEN_NEUTRAL, "dwellings", "accumulateWhenNeutral" },
|
||||
{EGameSettings::DWELLINGS_ACCUMULATE_WHEN_OWNED, "dwellings", "accumulateWhenOwned" },
|
||||
|
||||
@@ -41,10 +41,6 @@ enum class EGameSettings
|
||||
CREATURES_JOINING_PERCENTAGE,
|
||||
CREATURES_WEEKLY_GROWTH_CAP,
|
||||
CREATURES_WEEKLY_GROWTH_PERCENT,
|
||||
DIMENSION_DOOR_EXPOSES_TERRAIN_TYPE,
|
||||
DIMENSION_DOOR_FAILURE_SPENDS_POINTS,
|
||||
DIMENSION_DOOR_ONLY_TO_UNCOVERED_TILES,
|
||||
DIMENSION_DOOR_TOURNAMENT_RULES_LIMIT,
|
||||
DIMENSION_DOOR_TRIGGERS_GUARDS,
|
||||
DWELLINGS_ACCUMULATE_WHEN_NEUTRAL,
|
||||
DWELLINGS_ACCUMULATE_WHEN_OWNED,
|
||||
|
||||
@@ -997,6 +997,8 @@ std::shared_ptr<CSpell> CSpellHandler::loadFromJson(const std::string & scope, c
|
||||
levelObject.cumulativeEffects.push_back(b);
|
||||
}
|
||||
|
||||
levelObject.adventureEffect = levelNode["adventureEffect"];
|
||||
|
||||
if(!levelNode["battleEffects"].Struct().empty())
|
||||
{
|
||||
levelObject.battleEffects = levelNode["battleEffects"];
|
||||
|
||||
@@ -101,6 +101,7 @@ public:
|
||||
std::vector<std::shared_ptr<Bonus>> cumulativeEffects; //deprecated
|
||||
|
||||
JsonNode battleEffects;
|
||||
JsonNode adventureEffect;
|
||||
};
|
||||
|
||||
/** \brief Low level accessor. Don`t use it if absolutely necessary
|
||||
|
||||
@@ -27,11 +27,6 @@
|
||||
#include "Problem.h"
|
||||
|
||||
#include "adventure/AdventureSpellMechanics.h"
|
||||
#include "adventure/DimensionDoorMechanics.h"
|
||||
#include "adventure/ScuttleBoatMechanics.h"
|
||||
#include "adventure/SummonBoatMechanics.h"
|
||||
#include "adventure/TownPortalMechanics.h"
|
||||
#include "adventure/ViewWorldMechanics.h"
|
||||
|
||||
#include "BattleSpellMechanics.h"
|
||||
|
||||
@@ -648,28 +643,10 @@ IAdventureSpellMechanics::IAdventureSpellMechanics(const CSpell * s)
|
||||
|
||||
std::unique_ptr<IAdventureSpellMechanics> IAdventureSpellMechanics::createMechanics(const CSpell * s)
|
||||
{
|
||||
switch(s->id.toEnum())
|
||||
{
|
||||
case SpellID::SUMMON_BOAT:
|
||||
return std::make_unique<SummonBoatMechanics>(s);
|
||||
case SpellID::SCUTTLE_BOAT:
|
||||
return std::make_unique<ScuttleBoatMechanics>(s);
|
||||
case SpellID::DIMENSION_DOOR:
|
||||
return std::make_unique<DimensionDoorMechanics>(s);
|
||||
case SpellID::FLY:
|
||||
case SpellID::WATER_WALK:
|
||||
case SpellID::VISIONS:
|
||||
case SpellID::DISGUISE:
|
||||
return std::make_unique<AdventureSpellMechanics>(s); //implemented using bonus system
|
||||
case SpellID::TOWN_PORTAL:
|
||||
return std::make_unique<TownPortalMechanics>(s);
|
||||
case SpellID::VIEW_EARTH:
|
||||
return std::make_unique<ViewEarthMechanics>(s);
|
||||
case SpellID::VIEW_AIR:
|
||||
return std::make_unique<ViewAirMechanics>(s);
|
||||
default:
|
||||
return s->isCombat() ? std::unique_ptr<IAdventureSpellMechanics>() : std::make_unique<AdventureSpellMechanics>(s);
|
||||
}
|
||||
if (s->isCombat())
|
||||
return nullptr;
|
||||
|
||||
return std::make_unique<AdventureSpellMechanics>(s);
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
52
lib/spells/adventure/AdventureSpellEffect.cpp
Normal file
52
lib/spells/adventure/AdventureSpellEffect.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* AdventureSpellEffect.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 "AdventureSpellEffect.h"
|
||||
|
||||
#include "../../json/JsonNode.h"
|
||||
#include "../../mapObjects/CGHeroInstance.h"
|
||||
#include "../../callback/IGameInfoCallback.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
AdventureSpellRangedEffect::AdventureSpellRangedEffect(const JsonNode & config)
|
||||
: rangeX(config["rangeX"].Integer())
|
||||
, rangeY(config["rangeY"].Integer())
|
||||
, ignoreFow(config["ignoreFow"].Bool())
|
||||
{
|
||||
}
|
||||
|
||||
bool AdventureSpellRangedEffect::isTargetInRange(const int3 & pos, const int3 & center) const
|
||||
{
|
||||
int3 diff = pos - center;
|
||||
return diff.x >= -rangeX && diff.x <= rangeX && diff.y >= -rangeY && diff.y <= rangeY;
|
||||
}
|
||||
|
||||
bool AdventureSpellRangedEffect::canBeCastAtImpl(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const
|
||||
{
|
||||
if(!cb->isInTheMap(pos))
|
||||
return false;
|
||||
|
||||
if(caster->getHeroCaster())
|
||||
{
|
||||
int3 casterPosition = caster->getHeroCaster()->getSightCenter();
|
||||
|
||||
if(!isTargetInRange(casterPosition, pos))
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!ignoreFow && !cb->isVisibleFor(pos, caster->getCasterOwner()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
58
lib/spells/adventure/AdventureSpellEffect.h
Normal file
58
lib/spells/adventure/AdventureSpellEffect.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* AdventureSpellEffect.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 "../ISpellMechanics.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
enum class ESpellCastResult : int8_t
|
||||
{
|
||||
OK, // cast successful
|
||||
CANCEL, // cast failed but it is not an error, no mana has been spent
|
||||
PENDING,
|
||||
ERROR // error occurred, for example invalid request from player
|
||||
};
|
||||
|
||||
class AdventureSpellMechanics;
|
||||
|
||||
class IAdventureSpellEffect
|
||||
{
|
||||
public:
|
||||
virtual ~IAdventureSpellEffect() = default;
|
||||
|
||||
virtual ESpellCastResult applyAdventureEffects(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const {return ESpellCastResult::OK;};
|
||||
virtual ESpellCastResult beginCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters, const AdventureSpellMechanics & mechanics) const {return ESpellCastResult::OK;};
|
||||
virtual void endCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const {};
|
||||
virtual bool canBeCastImpl(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster) const {return true;};
|
||||
virtual bool canBeCastAtImpl(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const {return true;};
|
||||
};
|
||||
|
||||
class AdventureSpellEffect final : public IAdventureSpellEffect
|
||||
{
|
||||
public:
|
||||
AdventureSpellEffect() = default;
|
||||
};
|
||||
|
||||
class AdventureSpellRangedEffect : public IAdventureSpellEffect
|
||||
{
|
||||
int rangeX;
|
||||
int rangeY;
|
||||
bool ignoreFow;
|
||||
|
||||
bool isTargetInRange(const int3 & pos, const int3 & center) const;
|
||||
public:
|
||||
AdventureSpellRangedEffect(const JsonNode & config);
|
||||
|
||||
bool canBeCastAtImpl(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const override;
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
@@ -11,17 +11,72 @@
|
||||
#include "StdInc.h"
|
||||
#include "AdventureSpellMechanics.h"
|
||||
|
||||
#include "AdventureSpellEffect.h"
|
||||
#include "DimensionDoorEffect.h"
|
||||
#include "RemoveObjectEffect.h"
|
||||
#include "SummonBoatEffect.h"
|
||||
#include "TownPortalEffect.h"
|
||||
#include "ViewWorldEffect.h"
|
||||
|
||||
#include "../CSpellHandler.h"
|
||||
#include "../Problem.h"
|
||||
|
||||
#include "../../json/JsonBonus.h"
|
||||
#include "../../mapObjects/CGHeroInstance.h"
|
||||
#include "../../networkPacks/PacksForClient.h"
|
||||
#include "../../callback/IGameInfoCallback.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
static std::unique_ptr<IAdventureSpellEffect> createAdventureEffect(const CSpell * s, const JsonNode & node)
|
||||
{
|
||||
const std::string & typeID = node["type"].String();
|
||||
|
||||
if(typeID == "generic")
|
||||
return std::make_unique<AdventureSpellEffect>();
|
||||
if(typeID == "dimensionDoor")
|
||||
return std::make_unique<DimensionDoorEffect>(s, node);
|
||||
if(typeID == "removeObject")
|
||||
return std::make_unique<RemoveObjectEffect>(s, node);
|
||||
if(typeID == "summonBoat")
|
||||
return std::make_unique<SummonBoatEffect>(s, node);
|
||||
if(typeID == "townPortal")
|
||||
return std::make_unique<TownPortalEffect>(s, node);
|
||||
if(typeID == "viewWorld")
|
||||
return std::make_unique<ViewWorldEffect>(s, node);
|
||||
|
||||
return std::make_unique<AdventureSpellEffect>();
|
||||
}
|
||||
|
||||
AdventureSpellMechanics::AdventureSpellMechanics(const CSpell * s)
|
||||
: IAdventureSpellMechanics(s)
|
||||
{
|
||||
for(int level = 0; level < GameConstants::SPELL_SCHOOL_LEVELS; level++)
|
||||
{
|
||||
const JsonNode & config = s->getLevelInfo(level).adventureEffect;
|
||||
|
||||
levelOptions[level].effect = createAdventureEffect(s, config);
|
||||
levelOptions[level].castsPerDay = config["castsPerDay"].Integer();
|
||||
levelOptions[level].castsPerDayXL = config["castsPerDayXL"].Integer();
|
||||
|
||||
levelOptions[level].bonuses = s->getLevelInfo(level).effects;
|
||||
|
||||
for(const auto & elem : config["bonuses"].Struct())
|
||||
{
|
||||
auto b = JsonUtils::parseBonus(elem.second);
|
||||
b->sid = BonusSourceID(s->id);
|
||||
b->source = BonusSource::SPELL_EFFECT;
|
||||
levelOptions[level].bonuses.push_back(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AdventureSpellMechanics::~AdventureSpellMechanics() = default;
|
||||
|
||||
const AdventureSpellMechanics::LevelOptions & AdventureSpellMechanics::getLevel(const spells::Caster * caster) const
|
||||
{
|
||||
int schoolLevel = caster->getSpellSchoolLevel(owner);
|
||||
return levelOptions.at(schoolLevel);
|
||||
}
|
||||
|
||||
bool AdventureSpellMechanics::canBeCast(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster) const
|
||||
@@ -44,24 +99,30 @@ bool AdventureSpellMechanics::canBeCast(spells::Problem & problem, const IGameIn
|
||||
|
||||
if(heroCaster->mana < cost)
|
||||
return false;
|
||||
|
||||
std::stringstream cachingStr;
|
||||
cachingStr << "source_" << vstd::to_underlying(BonusSource::SPELL_EFFECT) << "id_" << owner->id.num;
|
||||
int castsAlreadyPerformedThisTurn = caster->getHeroCaster()->getBonuses(Selector::source(BonusSource::SPELL_EFFECT, BonusSourceID(owner->id)), cachingStr.str())->size();
|
||||
int3 mapSize = cb->getMapSize();
|
||||
bool mapSizeIsAtLeastXL = mapSize.x * mapSize.y * mapSize.z >= GameConstants::TOURNAMENT_RULES_DD_MAP_TILES_THRESHOLD;
|
||||
bool useAlternativeLimit = mapSizeIsAtLeastXL && getLevel(caster).castsPerDayXL != 0;
|
||||
int castsLimit = useAlternativeLimit ? getLevel(caster).castsPerDayXL : getLevel(caster).castsPerDay;
|
||||
|
||||
if(castsLimit > 0 && castsLimit <= castsAlreadyPerformedThisTurn ) //limit casts per turn
|
||||
{
|
||||
MetaString message = MetaString::createFromTextID("core.genrltxt.338");
|
||||
caster->getCasterName(message);
|
||||
problem.add(std::move(message));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return canBeCastImpl(problem, cb, caster);
|
||||
return getLevel(caster).effect->canBeCastImpl(problem, cb, caster);
|
||||
}
|
||||
|
||||
bool AdventureSpellMechanics::canBeCastAt(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const
|
||||
{
|
||||
return canBeCast(problem, cb, caster) && canBeCastAtImpl(problem, cb, caster, pos);
|
||||
}
|
||||
|
||||
bool AdventureSpellMechanics::canBeCastImpl(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AdventureSpellMechanics::canBeCastAtImpl(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const
|
||||
{
|
||||
return true;
|
||||
return canBeCast(problem, cb, caster) && getLevel(caster).effect->canBeCastAtImpl(problem, cb, caster, pos);
|
||||
}
|
||||
|
||||
bool AdventureSpellMechanics::adventureCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
|
||||
@@ -71,7 +132,7 @@ bool AdventureSpellMechanics::adventureCast(SpellCastEnvironment * env, const Ad
|
||||
if(!canBeCastAt(problem, env->getCb(), parameters.caster, parameters.pos))
|
||||
return false;
|
||||
|
||||
ESpellCastResult result = beginCast(env, parameters);
|
||||
ESpellCastResult result = getLevel(parameters.caster).effect->beginCast(env, parameters, *this);
|
||||
|
||||
if(result == ESpellCastResult::OK)
|
||||
performCast(env, parameters);
|
||||
@@ -79,43 +140,21 @@ bool AdventureSpellMechanics::adventureCast(SpellCastEnvironment * env, const Ad
|
||||
return result != ESpellCastResult::ERROR;
|
||||
}
|
||||
|
||||
ESpellCastResult AdventureSpellMechanics::applyAdventureEffects(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
|
||||
void AdventureSpellMechanics::giveBonuses(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
|
||||
{
|
||||
if(owner->hasEffects())
|
||||
{
|
||||
//todo: cumulative effects support
|
||||
const auto schoolLevel = parameters.caster->getSpellSchoolLevel(owner);
|
||||
|
||||
std::vector<Bonus> bonuses;
|
||||
|
||||
owner->getEffects(bonuses, schoolLevel, false, parameters.caster->getEnchantPower(owner));
|
||||
|
||||
for(const Bonus & b : bonuses)
|
||||
for(const auto & b : getLevel(parameters.caster).bonuses)
|
||||
{
|
||||
GiveBonus gb;
|
||||
gb.id = ObjectInstanceID(parameters.caster->getCasterUnitId());
|
||||
gb.bonus = b;
|
||||
gb.bonus = *b;
|
||||
gb.bonus.duration = parameters.caster->getEnchantPower(owner);
|
||||
env->apply(gb);
|
||||
}
|
||||
|
||||
return ESpellCastResult::OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
//There is no generic algorithm of adventure cast
|
||||
env->complain("Unimplemented adventure spell");
|
||||
return ESpellCastResult::ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
ESpellCastResult AdventureSpellMechanics::beginCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
|
||||
{
|
||||
return ESpellCastResult::OK;
|
||||
}
|
||||
|
||||
void AdventureSpellMechanics::endCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
|
||||
{
|
||||
// no-op, only for implementation in derived classes
|
||||
GiveBonus gb;
|
||||
gb.id = ObjectInstanceID(parameters.caster->getCasterUnitId());
|
||||
gb.bonus = Bonus(BonusDuration::ONE_DAY, BonusType::NONE, BonusSource::SPELL_EFFECT, 0, BonusSourceID(owner->id));
|
||||
env->apply(gb);
|
||||
}
|
||||
|
||||
void AdventureSpellMechanics::performCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
|
||||
@@ -128,16 +167,13 @@ void AdventureSpellMechanics::performCast(SpellCastEnvironment * env, const Adve
|
||||
asc.spellID = owner->id;
|
||||
env->apply(asc);
|
||||
|
||||
ESpellCastResult result = applyAdventureEffects(env, parameters);
|
||||
ESpellCastResult result = getLevel(parameters.caster).effect->applyAdventureEffects(env, parameters);
|
||||
|
||||
switch(result)
|
||||
if (result == ESpellCastResult::OK)
|
||||
{
|
||||
case ESpellCastResult::OK:
|
||||
giveBonuses(env, parameters);
|
||||
parameters.caster->spendMana(env, cost);
|
||||
endCast(env, parameters);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
getLevel(parameters.caster).effect->endCast(env, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,32 +14,31 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
enum class ESpellCastResult
|
||||
{
|
||||
OK, // cast successful
|
||||
CANCEL, // cast failed but it is not an error, no mana has been spent
|
||||
PENDING,
|
||||
ERROR // error occurred, for example invalid request from player
|
||||
};
|
||||
class IAdventureSpellEffect;
|
||||
|
||||
class AdventureSpellMechanics : public IAdventureSpellMechanics
|
||||
class AdventureSpellMechanics final : public IAdventureSpellMechanics, boost::noncopyable
|
||||
{
|
||||
struct LevelOptions
|
||||
{
|
||||
std::unique_ptr<IAdventureSpellEffect> effect;
|
||||
std::vector<std::shared_ptr<Bonus>> bonuses;
|
||||
int castsPerDay;
|
||||
int castsPerDayXL;
|
||||
};
|
||||
|
||||
std::array<LevelOptions, GameConstants::SPELL_SCHOOL_LEVELS> levelOptions;
|
||||
|
||||
public:
|
||||
AdventureSpellMechanics(const CSpell * s);
|
||||
~AdventureSpellMechanics();
|
||||
|
||||
const LevelOptions & getLevel(const spells::Caster * caster) const;
|
||||
|
||||
bool canBeCast(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster) const final;
|
||||
bool canBeCastAt(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const final;
|
||||
bool adventureCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const final;
|
||||
|
||||
bool adventureCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const override final;
|
||||
|
||||
protected:
|
||||
///actual adventure cast implementation
|
||||
virtual ESpellCastResult applyAdventureEffects(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const;
|
||||
virtual ESpellCastResult beginCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const;
|
||||
virtual void endCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const;
|
||||
virtual bool canBeCastImpl(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster) const;
|
||||
virtual bool canBeCastAtImpl(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const;
|
||||
|
||||
void giveBonuses(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const;
|
||||
void performCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const;
|
||||
};
|
||||
|
||||
|
||||
125
lib/spells/adventure/DimensionDoorEffect.cpp
Normal file
125
lib/spells/adventure/DimensionDoorEffect.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* DimensionDoorEffect.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 "DimensionDoorEffect.h"
|
||||
|
||||
#include "../CSpellHandler.h"
|
||||
|
||||
#include "../../IGameSettings.h"
|
||||
#include "../../callback/IGameInfoCallback.h"
|
||||
#include "../../mapObjects/CGHeroInstance.h"
|
||||
#include "../../mapping/TerrainTile.h"
|
||||
#include "../../networkPacks/PacksForClient.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
DimensionDoorEffect::DimensionDoorEffect(const CSpell * s, const JsonNode & config)
|
||||
: AdventureSpellRangedEffect(config)
|
||||
, movementPointsRequired(config["movementPointsRequired"].Integer())
|
||||
, movementPointsTaken(config["movementPointsTaken"].Integer())
|
||||
, waterLandFailureTakesPoints(config["waterLandFailureTakesPoints"].Bool())
|
||||
, exposeFow(config["exposeFow"].Bool())
|
||||
{
|
||||
}
|
||||
|
||||
bool DimensionDoorEffect::canBeCastImpl(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster) const
|
||||
{
|
||||
if(!caster->getHeroCaster())
|
||||
return false;
|
||||
|
||||
if(caster->getHeroCaster()->movementPointsRemaining() <= movementPointsRequired)
|
||||
{
|
||||
problem.add(MetaString::createFromTextID("core.genrltxt.125"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DimensionDoorEffect::canBeCastAtImpl(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const
|
||||
{
|
||||
if (!AdventureSpellRangedEffect::canBeCastAtImpl(problem, cb, caster, pos))
|
||||
return false;
|
||||
|
||||
int3 casterPosition = caster->getHeroCaster()->getSightCenter();
|
||||
const TerrainTile * dest = cb->getTileUnchecked(pos);
|
||||
const TerrainTile * curr = cb->getTileUnchecked(casterPosition);
|
||||
|
||||
if(!dest)
|
||||
return false;
|
||||
|
||||
if(!curr)
|
||||
return false;
|
||||
|
||||
if(exposeFow)
|
||||
{
|
||||
if(!dest->isClear(curr))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(dest->blocked())
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ESpellCastResult DimensionDoorEffect::applyAdventureEffects(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
|
||||
{
|
||||
int3 casterPosition = parameters.caster->getHeroCaster()->getSightCenter();
|
||||
const TerrainTile * dest = env->getCb()->getTile(parameters.pos);
|
||||
const TerrainTile * curr = env->getCb()->getTile(casterPosition);
|
||||
|
||||
if(!dest->isClear(curr))
|
||||
{
|
||||
InfoWindow iw;
|
||||
iw.player = parameters.caster->getCasterOwner();
|
||||
|
||||
// tile is either blocked or not possible to move (e.g. water <-> land)
|
||||
if(waterLandFailureTakesPoints)
|
||||
{
|
||||
// SOD: DD to such "wrong" terrain results in mana and move points spending, but fails to move hero
|
||||
iw.text = MetaString::createFromTextID("core.genrltxt.70"); // Dimension Door failed!
|
||||
env->apply(iw);
|
||||
// no return - resources will be spent
|
||||
}
|
||||
else
|
||||
{
|
||||
// HotA: game will show error message without taking mana or move points, even when DD into terra incognita
|
||||
iw.text = MetaString::createFromTextID("vcmi.dimensionDoor.seaToLandError");
|
||||
env->apply(iw);
|
||||
return ESpellCastResult::CANCEL;
|
||||
}
|
||||
}
|
||||
|
||||
SetMovePoints smp;
|
||||
smp.hid = ObjectInstanceID(parameters.caster->getCasterUnitId());
|
||||
if(movementPointsTaken < static_cast<int>(parameters.caster->getHeroCaster()->movementPointsRemaining()))
|
||||
smp.val = parameters.caster->getHeroCaster()->movementPointsRemaining() - movementPointsTaken;
|
||||
else
|
||||
smp.val = 0;
|
||||
env->apply(smp);
|
||||
|
||||
return ESpellCastResult::OK;
|
||||
}
|
||||
|
||||
void DimensionDoorEffect::endCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
|
||||
{
|
||||
int3 casterPosition = parameters.caster->getHeroCaster()->getSightCenter();
|
||||
const TerrainTile * dest = env->getCb()->getTile(parameters.pos);
|
||||
const TerrainTile * curr = env->getCb()->getTile(casterPosition);
|
||||
|
||||
if(dest->isClear(curr))
|
||||
env->moveHero(ObjectInstanceID(parameters.caster->getCasterUnitId()), parameters.caster->getHeroCaster()->convertFromVisitablePos(parameters.pos), EMovementMode::DIMENSION_DOOR);
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* DimensionDoorMechanics.h, part of VCMI engine
|
||||
* DimensionDoorEffect.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
@@ -10,14 +10,19 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AdventureSpellMechanics.h"
|
||||
#include "AdventureSpellEffect.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class DimensionDoorMechanics final : public AdventureSpellMechanics
|
||||
class DimensionDoorEffect final : public AdventureSpellRangedEffect
|
||||
{
|
||||
int movementPointsRequired;
|
||||
int movementPointsTaken;
|
||||
bool waterLandFailureTakesPoints;
|
||||
bool exposeFow;
|
||||
|
||||
public:
|
||||
DimensionDoorMechanics(const CSpell * s);
|
||||
DimensionDoorEffect(const CSpell * s, const JsonNode & config);
|
||||
|
||||
protected:
|
||||
bool canBeCastImpl(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster) const override;
|
||||
@@ -1,166 +0,0 @@
|
||||
/*
|
||||
* DimensionDoorMechanics.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 "DimensionDoorMechanics.h"
|
||||
|
||||
#include "../CSpellHandler.h"
|
||||
|
||||
#include "../../IGameSettings.h"
|
||||
#include "../../callback/IGameInfoCallback.h"
|
||||
#include "../../mapObjects/CGHeroInstance.h"
|
||||
#include "../../mapping/TerrainTile.h"
|
||||
#include "../../networkPacks/PacksForClient.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
DimensionDoorMechanics::DimensionDoorMechanics(const CSpell * s)
|
||||
: AdventureSpellMechanics(s)
|
||||
{
|
||||
}
|
||||
|
||||
bool DimensionDoorMechanics::canBeCastImpl(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster) const
|
||||
{
|
||||
if(!caster->getHeroCaster())
|
||||
return false;
|
||||
|
||||
if(caster->getHeroCaster()->movementPointsRemaining() <= 0) //unlike town portal non-zero MP is enough
|
||||
{
|
||||
problem.add(MetaString::createFromTextID("core.genrltxt.125"));
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto schoolLevel = caster->getSpellSchoolLevel(owner);
|
||||
|
||||
std::stringstream cachingStr;
|
||||
cachingStr << "source_" << vstd::to_underlying(BonusSource::SPELL_EFFECT) << "id_" << owner->id.num;
|
||||
|
||||
int castsAlreadyPerformedThisTurn = caster->getHeroCaster()->getBonuses(Selector::source(BonusSource::SPELL_EFFECT, BonusSourceID(owner->id)), cachingStr.str())->size();
|
||||
int castsLimit = owner->getLevelPower(schoolLevel);
|
||||
|
||||
bool isTournamentRulesLimitEnabled = cb->getSettings().getBoolean(EGameSettings::DIMENSION_DOOR_TOURNAMENT_RULES_LIMIT);
|
||||
if(isTournamentRulesLimitEnabled)
|
||||
{
|
||||
int3 mapSize = cb->getMapSize();
|
||||
|
||||
bool meetsTournamentRulesTwoCastsRequirements = mapSize.x * mapSize.y * mapSize.z >= GameConstants::TOURNAMENT_RULES_DD_MAP_TILES_THRESHOLD && schoolLevel == MasteryLevel::EXPERT;
|
||||
|
||||
castsLimit = meetsTournamentRulesTwoCastsRequirements ? 2 : 1;
|
||||
}
|
||||
|
||||
if(castsAlreadyPerformedThisTurn >= castsLimit) //limit casts per turn
|
||||
{
|
||||
MetaString message = MetaString::createFromTextID("core.genrltxt.338");
|
||||
caster->getCasterName(message);
|
||||
problem.add(std::move(message));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DimensionDoorMechanics::canBeCastAtImpl(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const
|
||||
{
|
||||
if(!cb->isInTheMap(pos))
|
||||
return false;
|
||||
|
||||
if(cb->getSettings().getBoolean(EGameSettings::DIMENSION_DOOR_ONLY_TO_UNCOVERED_TILES))
|
||||
{
|
||||
if(!cb->isVisibleFor(pos, caster->getCasterOwner()))
|
||||
return false;
|
||||
}
|
||||
|
||||
int3 casterPosition = caster->getHeroCaster()->getSightCenter();
|
||||
|
||||
const TerrainTile * dest = cb->getTileUnchecked(pos);
|
||||
const TerrainTile * curr = cb->getTileUnchecked(casterPosition);
|
||||
|
||||
if(!dest)
|
||||
return false;
|
||||
|
||||
if(!curr)
|
||||
return false;
|
||||
|
||||
if(!isInScreenRange(casterPosition, pos))
|
||||
return false;
|
||||
|
||||
if(cb->getSettings().getBoolean(EGameSettings::DIMENSION_DOOR_EXPOSES_TERRAIN_TYPE))
|
||||
{
|
||||
if(!dest->isClear(curr))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(dest->blocked())
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ESpellCastResult DimensionDoorMechanics::applyAdventureEffects(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
|
||||
{
|
||||
const auto schoolLevel = parameters.caster->getSpellSchoolLevel(owner);
|
||||
const int baseCost = env->getCb()->getSettings().getInteger(EGameSettings::HEROES_MOVEMENT_COST_BASE);
|
||||
const int movementCost = baseCost * ((schoolLevel >= 3) ? 2 : 3);
|
||||
|
||||
int3 casterPosition = parameters.caster->getHeroCaster()->getSightCenter();
|
||||
const TerrainTile * dest = env->getCb()->getTile(parameters.pos);
|
||||
const TerrainTile * curr = env->getCb()->getTile(casterPosition);
|
||||
|
||||
if(!dest->isClear(curr))
|
||||
{
|
||||
InfoWindow iw;
|
||||
iw.player = parameters.caster->getCasterOwner();
|
||||
|
||||
// tile is either blocked or not possible to move (e.g. water <-> land)
|
||||
if(env->getCb()->getSettings().getBoolean(EGameSettings::DIMENSION_DOOR_FAILURE_SPENDS_POINTS))
|
||||
{
|
||||
// SOD: DD to such "wrong" terrain results in mana and move points spending, but fails to move hero
|
||||
iw.text = MetaString::createFromTextID("core.genrltxt.70"); // Dimension Door failed!
|
||||
env->apply(iw);
|
||||
// no return - resources will be spent
|
||||
}
|
||||
else
|
||||
{
|
||||
// HotA: game will show error message without taking mana or move points, even when DD into terra incognita
|
||||
iw.text = MetaString::createFromTextID("vcmi.dimensionDoor.seaToLandError");
|
||||
env->apply(iw);
|
||||
return ESpellCastResult::CANCEL;
|
||||
}
|
||||
}
|
||||
|
||||
GiveBonus gb;
|
||||
gb.id = ObjectInstanceID(parameters.caster->getCasterUnitId());
|
||||
gb.bonus = Bonus(BonusDuration::ONE_DAY, BonusType::NONE, BonusSource::SPELL_EFFECT, 0, BonusSourceID(owner->id));
|
||||
env->apply(gb);
|
||||
|
||||
SetMovePoints smp;
|
||||
smp.hid = ObjectInstanceID(parameters.caster->getCasterUnitId());
|
||||
if(movementCost < static_cast<int>(parameters.caster->getHeroCaster()->movementPointsRemaining()))
|
||||
smp.val = parameters.caster->getHeroCaster()->movementPointsRemaining() - movementCost;
|
||||
else
|
||||
smp.val = 0;
|
||||
env->apply(smp);
|
||||
|
||||
return ESpellCastResult::OK;
|
||||
}
|
||||
|
||||
void DimensionDoorMechanics::endCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
|
||||
{
|
||||
int3 casterPosition = parameters.caster->getHeroCaster()->getSightCenter();
|
||||
const TerrainTile * dest = env->getCb()->getTile(parameters.pos);
|
||||
const TerrainTile * curr = env->getCb()->getTile(casterPosition);
|
||||
|
||||
if(dest->isClear(curr))
|
||||
env->moveHero(ObjectInstanceID(parameters.caster->getCasterUnitId()), parameters.caster->getHeroCaster()->convertFromVisitablePos(parameters.pos), EMovementMode::DIMENSION_DOOR);
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* ScuttleBoatMechanics.cpp, part of VCMI engine
|
||||
* RemoveObjectEffect.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
@@ -9,7 +9,7 @@
|
||||
*/
|
||||
|
||||
#include "StdInc.h"
|
||||
#include "ScuttleBoatMechanics.h"
|
||||
#include "RemoveObjectEffect.h"
|
||||
|
||||
#include "../CSpellHandler.h"
|
||||
|
||||
@@ -17,28 +17,30 @@
|
||||
#include "../../mapObjects/CGHeroInstance.h"
|
||||
#include "../../mapping/CMap.h"
|
||||
#include "../../networkPacks/PacksForClient.h"
|
||||
#include "../../modding/IdentifierStorage.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
ScuttleBoatMechanics::ScuttleBoatMechanics(const CSpell * s)
|
||||
: AdventureSpellMechanics(s)
|
||||
RemoveObjectEffect::RemoveObjectEffect(const CSpell * s, const JsonNode & config)
|
||||
: AdventureSpellRangedEffect(config)
|
||||
, owner(s)
|
||||
, failMessage(MetaString::createFromTextID("core.genrltxt.337")) //%s tried to scuttle the boat, but failed
|
||||
{
|
||||
for(const auto & objectNode : config["objects"].Struct())
|
||||
{
|
||||
if(objectNode.second.Bool())
|
||||
{
|
||||
LIBRARY->identifiers()->requestIdentifier(objectNode.second.getModScope(), "object", objectNode.first, [this](si32 index)
|
||||
{
|
||||
removedObjects.push_back(MapObjectID(index));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ScuttleBoatMechanics::canBeCastAtImpl(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const
|
||||
bool RemoveObjectEffect::canBeCastAtImpl(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const
|
||||
{
|
||||
if(!cb->isInTheMap(pos))
|
||||
return false;
|
||||
|
||||
if(caster->getHeroCaster())
|
||||
{
|
||||
int3 casterPosition = caster->getHeroCaster()->getSightCenter();
|
||||
|
||||
if(!isInScreenRange(casterPosition, pos))
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!cb->isVisibleFor(pos, caster->getCasterOwner()))
|
||||
if (!AdventureSpellRangedEffect::canBeCastAtImpl(problem, cb, caster, pos))
|
||||
return false;
|
||||
|
||||
const TerrainTile * t = cb->getTile(pos);
|
||||
@@ -46,13 +48,11 @@ bool ScuttleBoatMechanics::canBeCastAtImpl(spells::Problem & problem, const IGam
|
||||
return false;
|
||||
|
||||
const CGObjectInstance * topObject = cb->getObj(t->visitableObjects.back());
|
||||
if(topObject->ID != Obj::BOAT)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return vstd::contains(removedObjects, topObject->ID);
|
||||
}
|
||||
|
||||
ESpellCastResult ScuttleBoatMechanics::applyAdventureEffects(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
|
||||
ESpellCastResult RemoveObjectEffect::applyAdventureEffects(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
|
||||
{
|
||||
const auto schoolLevel = parameters.caster->getSpellSchoolLevel(owner);
|
||||
//check if spell works at all
|
||||
@@ -60,7 +60,7 @@ ESpellCastResult ScuttleBoatMechanics::applyAdventureEffects(SpellCastEnvironmen
|
||||
{
|
||||
InfoWindow iw;
|
||||
iw.player = parameters.caster->getCasterOwner();
|
||||
iw.text.appendLocalString(EMetaText::GENERAL_TXT, 337); //%s tried to scuttle the boat, but failed
|
||||
iw.text = failMessage;
|
||||
parameters.caster->getCasterName(iw.text);
|
||||
env->apply(iw);
|
||||
return ESpellCastResult::OK;
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* ScuttleBoatMechanics.h, part of VCMI engine
|
||||
* RemoveObjectEffect.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
@@ -10,18 +10,20 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AdventureSpellMechanics.h"
|
||||
#include "AdventureSpellEffect.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class ScuttleBoatMechanics final : public AdventureSpellMechanics
|
||||
class RemoveObjectEffect final : public AdventureSpellRangedEffect
|
||||
{
|
||||
const CSpell * owner;
|
||||
std::vector<MapObjectID> removedObjects;
|
||||
MetaString failMessage;
|
||||
|
||||
public:
|
||||
ScuttleBoatMechanics(const CSpell * s);
|
||||
RemoveObjectEffect(const CSpell * s, const JsonNode & config);
|
||||
|
||||
protected:
|
||||
bool canBeCastAtImpl(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const override;
|
||||
|
||||
ESpellCastResult applyAdventureEffects(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const override;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SummonBoatMechanics.cpp, part of VCMI engine
|
||||
* SummonBoatEffect.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#include "StdInc.h"
|
||||
|
||||
#include "SummonBoatMechanics.h"
|
||||
#include "SummonBoatEffect.h"
|
||||
|
||||
#include "../CSpellHandler.h"
|
||||
|
||||
@@ -21,12 +21,14 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
SummonBoatMechanics::SummonBoatMechanics(const CSpell * s)
|
||||
: AdventureSpellMechanics(s)
|
||||
SummonBoatEffect::SummonBoatEffect(const CSpell * s, const JsonNode & config)
|
||||
: owner(s)
|
||||
, useExistingBoat(config["useExistingBoat"].Bool())
|
||||
, createNewBoat(config["createNewBoat"].Bool())
|
||||
{
|
||||
}
|
||||
|
||||
bool SummonBoatMechanics::canBeCastImpl(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster) const
|
||||
bool SummonBoatEffect::canBeCastImpl(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster) const
|
||||
{
|
||||
if(!caster->getHeroCaster())
|
||||
return false;
|
||||
@@ -52,7 +54,7 @@ bool SummonBoatMechanics::canBeCastImpl(spells::Problem & problem, const IGameIn
|
||||
return true;
|
||||
}
|
||||
|
||||
ESpellCastResult SummonBoatMechanics::applyAdventureEffects(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
|
||||
ESpellCastResult SummonBoatEffect::applyAdventureEffects(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
|
||||
{
|
||||
const auto schoolLevel = parameters.caster->getSpellSchoolLevel(owner);
|
||||
|
||||
@@ -69,6 +71,9 @@ ESpellCastResult SummonBoatMechanics::applyAdventureEffects(SpellCastEnvironment
|
||||
|
||||
//try to find unoccupied boat to summon
|
||||
const CGBoat * nearest = nullptr;
|
||||
|
||||
if (useExistingBoat)
|
||||
{
|
||||
double dist = 0;
|
||||
for(const auto & b : env->getMap()->getObjects<CGBoat>())
|
||||
{
|
||||
@@ -82,6 +87,7 @@ ESpellCastResult SummonBoatMechanics::applyAdventureEffects(SpellCastEnvironment
|
||||
dist = nDist;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int3 summonPos = parameters.caster->getHeroCaster()->bestLocation();
|
||||
|
||||
@@ -93,7 +99,7 @@ ESpellCastResult SummonBoatMechanics::applyAdventureEffects(SpellCastEnvironment
|
||||
cop.initiator = parameters.caster->getCasterOwner();
|
||||
env->apply(cop);
|
||||
}
|
||||
else if(schoolLevel < 2) //none or basic level -> cannot create boat :(
|
||||
else if(!createNewBoat) //none or basic level -> cannot create boat :(
|
||||
{
|
||||
InfoWindow iw;
|
||||
iw.player = parameters.caster->getCasterOwner();
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SummonBoatMechanics.h, part of VCMI engine
|
||||
* SummonBoatEffect.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
@@ -10,14 +10,18 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AdventureSpellMechanics.h"
|
||||
#include "AdventureSpellEffect.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class SummonBoatMechanics final : public AdventureSpellMechanics
|
||||
class SummonBoatEffect final : public IAdventureSpellEffect
|
||||
{
|
||||
const CSpell * owner;
|
||||
bool useExistingBoat;
|
||||
bool createNewBoat;
|
||||
|
||||
public:
|
||||
SummonBoatMechanics(const CSpell * s);
|
||||
SummonBoatEffect(const CSpell * s, const JsonNode & config);
|
||||
|
||||
protected:
|
||||
bool canBeCastImpl(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster) const override;
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* TownPortalMechanics.cpp, part of VCMI engine
|
||||
* TownPortalEffect.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
@@ -9,7 +9,9 @@
|
||||
*/
|
||||
|
||||
#include "StdInc.h"
|
||||
#include "TownPortalMechanics.h"
|
||||
#include "TownPortalEffect.h"
|
||||
|
||||
#include "AdventureSpellMechanics.h"
|
||||
|
||||
#include "../CSpellHandler.h"
|
||||
|
||||
@@ -23,15 +25,18 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
TownPortalMechanics::TownPortalMechanics(const CSpell * s):
|
||||
AdventureSpellMechanics(s)
|
||||
TownPortalEffect::TownPortalEffect(const CSpell * s, const JsonNode & config)
|
||||
: owner(s)
|
||||
, movementPointsRequired(config["movementPointsRequired"].Integer())
|
||||
, movementPointsTaken(config["movementPointsTaken"].Integer())
|
||||
, allowTownSelection(config["allowTownSelection"].Bool())
|
||||
, skipOccupiedTowns(config["skipOccupiedTowns"].Bool())
|
||||
{
|
||||
}
|
||||
|
||||
ESpellCastResult TownPortalMechanics::applyAdventureEffects(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
|
||||
ESpellCastResult TownPortalEffect::applyAdventureEffects(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
|
||||
{
|
||||
const CGTownInstance * destination = nullptr;
|
||||
const int moveCost = movementCost(env, parameters);
|
||||
|
||||
if(!parameters.caster->getHeroCaster())
|
||||
{
|
||||
@@ -39,7 +44,7 @@ ESpellCastResult TownPortalMechanics::applyAdventureEffects(SpellCastEnvironment
|
||||
return ESpellCastResult::ERROR;
|
||||
}
|
||||
|
||||
if(parameters.caster->getSpellSchoolLevel(owner) < 2)
|
||||
if(!allowTownSelection)
|
||||
{
|
||||
std::vector<const CGTownInstance *> pool = getPossibleTowns(env, parameters);
|
||||
destination = findNearestTown(env, parameters, pool);
|
||||
@@ -47,7 +52,7 @@ ESpellCastResult TownPortalMechanics::applyAdventureEffects(SpellCastEnvironment
|
||||
if(nullptr == destination)
|
||||
return ESpellCastResult::ERROR;
|
||||
|
||||
if(static_cast<int>(parameters.caster->getHeroCaster()->movementPointsRemaining()) < moveCost)
|
||||
if(static_cast<int>(parameters.caster->getHeroCaster()->movementPointsRemaining()) < movementPointsRequired)
|
||||
return ESpellCastResult::ERROR;
|
||||
|
||||
if(destination->getVisitingHero())
|
||||
@@ -98,7 +103,7 @@ ESpellCastResult TownPortalMechanics::applyAdventureEffects(SpellCastEnvironment
|
||||
return ESpellCastResult::ERROR;
|
||||
}
|
||||
|
||||
if(static_cast<int>(parameters.caster->getHeroCaster()->movementPointsRemaining()) < moveCost)
|
||||
if(static_cast<int>(parameters.caster->getHeroCaster()->movementPointsRemaining()) < movementPointsRequired)
|
||||
{
|
||||
env->complain("This hero has not enough movement points!");
|
||||
return ESpellCastResult::ERROR;
|
||||
@@ -131,9 +136,8 @@ ESpellCastResult TownPortalMechanics::applyAdventureEffects(SpellCastEnvironment
|
||||
return ESpellCastResult::OK;
|
||||
}
|
||||
|
||||
void TownPortalMechanics::endCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
|
||||
void TownPortalEffect::endCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
|
||||
{
|
||||
const int moveCost = movementCost(env, parameters);
|
||||
const CGTownInstance * destination = nullptr;
|
||||
|
||||
if(parameters.caster->getSpellSchoolLevel(owner) < 2)
|
||||
@@ -154,12 +158,15 @@ void TownPortalMechanics::endCast(SpellCastEnvironment * env, const AdventureSpe
|
||||
{
|
||||
SetMovePoints smp;
|
||||
smp.hid = ObjectInstanceID(parameters.caster->getCasterUnitId());
|
||||
smp.val = std::max<ui32>(0, parameters.caster->getHeroCaster()->movementPointsRemaining() - moveCost);
|
||||
if(movementPointsTaken < static_cast<int>(parameters.caster->getHeroCaster()->movementPointsRemaining()))
|
||||
smp.val = parameters.caster->getHeroCaster()->movementPointsRemaining() - movementPointsTaken;
|
||||
else
|
||||
smp.val = 0;
|
||||
env->apply(smp);
|
||||
}
|
||||
}
|
||||
|
||||
ESpellCastResult TownPortalMechanics::beginCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
|
||||
ESpellCastResult TownPortalEffect::beginCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters, const AdventureSpellMechanics & mechanics) const
|
||||
{
|
||||
std::vector<const CGTownInstance *> towns = getPossibleTowns(env, parameters);
|
||||
|
||||
@@ -178,9 +185,7 @@ ESpellCastResult TownPortalMechanics::beginCast(SpellCastEnvironment * env, cons
|
||||
return ESpellCastResult::CANCEL;
|
||||
}
|
||||
|
||||
const int moveCost = movementCost(env, parameters);
|
||||
|
||||
if(static_cast<int>(parameters.caster->getHeroCaster()->movementPointsRemaining()) < moveCost)
|
||||
if(static_cast<int>(parameters.caster->getHeroCaster()->movementPointsRemaining()) < movementPointsTaken)
|
||||
{
|
||||
InfoWindow iw;
|
||||
iw.player = parameters.caster->getCasterOwner();
|
||||
@@ -191,7 +196,7 @@ ESpellCastResult TownPortalMechanics::beginCast(SpellCastEnvironment * env, cons
|
||||
|
||||
if(!parameters.pos.isValid() && parameters.caster->getSpellSchoolLevel(owner) >= 2)
|
||||
{
|
||||
auto queryCallback = [this, env, parameters](std::optional<int32_t> reply) -> void
|
||||
auto queryCallback = [&mechanics, env, parameters](std::optional<int32_t> reply) -> void
|
||||
{
|
||||
if(reply.has_value())
|
||||
{
|
||||
@@ -213,7 +218,7 @@ ESpellCastResult TownPortalMechanics::beginCast(SpellCastEnvironment * env, cons
|
||||
AdventureSpellCastParameters p;
|
||||
p.caster = parameters.caster;
|
||||
p.pos = o->visitablePos();
|
||||
performCast(env, p);
|
||||
mechanics.performCast(env, p);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -247,7 +252,7 @@ ESpellCastResult TownPortalMechanics::beginCast(SpellCastEnvironment * env, cons
|
||||
return ESpellCastResult::OK;
|
||||
}
|
||||
|
||||
const CGTownInstance * TownPortalMechanics::findNearestTown(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters, const std::vector <const CGTownInstance *> & pool) const
|
||||
const CGTownInstance * TownPortalEffect::findNearestTown(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters, const std::vector <const CGTownInstance *> & pool) const
|
||||
{
|
||||
if(pool.empty())
|
||||
return nullptr;
|
||||
@@ -271,7 +276,7 @@ const CGTownInstance * TownPortalMechanics::findNearestTown(SpellCastEnvironment
|
||||
return *nearest;
|
||||
}
|
||||
|
||||
std::vector<const CGTownInstance *> TownPortalMechanics::getPossibleTowns(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
|
||||
std::vector<const CGTownInstance *> TownPortalEffect::getPossibleTowns(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
|
||||
{
|
||||
std::vector<const CGTownInstance *> ret;
|
||||
|
||||
@@ -281,19 +286,11 @@ std::vector<const CGTownInstance *> TownPortalMechanics::getPossibleTowns(SpellC
|
||||
{
|
||||
for(auto currTown : env->getCb()->getPlayerState(color)->getTowns())
|
||||
{
|
||||
if (!skipOccupiedTowns || currTown->getVisitingHero() == nullptr)
|
||||
ret.push_back(currTown);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t TownPortalMechanics::movementCost(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
|
||||
{
|
||||
if(parameters.caster != parameters.caster->getHeroCaster()) //if caster is not hero
|
||||
return 0;
|
||||
|
||||
int baseMovementCost = env->getCb()->getSettings().getInteger(EGameSettings::HEROES_MOVEMENT_COST_BASE);
|
||||
return baseMovementCost * ((parameters.caster->getSpellSchoolLevel(owner) >= 3) ? 2 : 3);
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* TownPortalMechanics.h, part of VCMI engine
|
||||
* TownPortalEffect.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
@@ -10,25 +10,30 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AdventureSpellMechanics.h"
|
||||
#include "AdventureSpellEffect.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class CGTownInstance;
|
||||
|
||||
class TownPortalMechanics final : public AdventureSpellMechanics
|
||||
class TownPortalEffect final : public IAdventureSpellEffect
|
||||
{
|
||||
const CSpell * owner;
|
||||
int movementPointsRequired;
|
||||
int movementPointsTaken;
|
||||
bool allowTownSelection;
|
||||
bool skipOccupiedTowns;
|
||||
|
||||
public:
|
||||
TownPortalMechanics(const CSpell * s);
|
||||
TownPortalEffect(const CSpell * s, const JsonNode & config);
|
||||
|
||||
protected:
|
||||
ESpellCastResult applyAdventureEffects(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const override;
|
||||
ESpellCastResult beginCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const override;
|
||||
ESpellCastResult beginCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters, const AdventureSpellMechanics & mechanics) const override;
|
||||
void endCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const override;
|
||||
|
||||
private:
|
||||
const CGTownInstance * findNearestTown(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters, const std::vector<const CGTownInstance *> & pool) const;
|
||||
int32_t movementCost(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const;
|
||||
std::vector<const CGTownInstance *> getPossibleTowns(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const;
|
||||
};
|
||||
|
||||
68
lib/spells/adventure/ViewWorldEffect.cpp
Normal file
68
lib/spells/adventure/ViewWorldEffect.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* ViewWorldEffect.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 "ViewWorldEffect.h"
|
||||
|
||||
#include "../CSpellHandler.h"
|
||||
|
||||
#include "../../CPlayerState.h"
|
||||
#include "../../callback/IGameInfoCallback.h"
|
||||
#include "../../mapObjects/CGHeroInstance.h"
|
||||
#include "../../mapping/CMap.h"
|
||||
#include "../../modding/IdentifierStorage.h"
|
||||
#include "../../networkPacks/PacksForClient.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
ViewWorldEffect::ViewWorldEffect(const CSpell * s, const JsonNode & config)
|
||||
{
|
||||
showTerrain = config["showTerrain"].Bool();
|
||||
|
||||
for(const auto & objectNode : config["objects"].Struct())
|
||||
{
|
||||
if(objectNode.second.Bool())
|
||||
{
|
||||
LIBRARY->identifiers()->requestIdentifier(objectNode.second.getModScope(), "object", objectNode.first, [this](si32 index)
|
||||
{
|
||||
filteredObjects.push_back(MapObjectID(index));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ESpellCastResult ViewWorldEffect::applyAdventureEffects(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
|
||||
{
|
||||
ShowWorldViewEx pack;
|
||||
|
||||
pack.player = parameters.caster->getCasterOwner();
|
||||
pack.showTerrain = showTerrain;
|
||||
|
||||
const auto & fowMap = env->getCb()->getPlayerTeam(parameters.caster->getCasterOwner())->fogOfWarMap;
|
||||
|
||||
for(const auto & obj : env->getMap()->getObjects())
|
||||
{
|
||||
//deleted object remain as empty pointer
|
||||
if(obj && vstd::contains(filteredObjects, obj->ID))
|
||||
{
|
||||
ObjectPosInfo posInfo(obj);
|
||||
|
||||
if(fowMap[posInfo.pos.z][posInfo.pos.x][posInfo.pos.y] == 0)
|
||||
pack.objectPositions.push_back(posInfo);
|
||||
}
|
||||
}
|
||||
|
||||
env->apply(pack);
|
||||
|
||||
return ESpellCastResult::OK;
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
28
lib/spells/adventure/ViewWorldEffect.h
Normal file
28
lib/spells/adventure/ViewWorldEffect.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* ViewWorldEffect.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 "AdventureSpellEffect.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class ViewWorldEffect final : public IAdventureSpellEffect
|
||||
{
|
||||
std::vector<MapObjectID> filteredObjects;
|
||||
bool showTerrain = false;
|
||||
|
||||
public:
|
||||
ViewWorldEffect(const CSpell * s, const JsonNode & config);
|
||||
|
||||
ESpellCastResult applyAdventureEffects(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const override;
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* ViewWorldMechanics.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 "ViewWorldMechanics.h"
|
||||
|
||||
#include "../CSpellHandler.h"
|
||||
|
||||
#include "../../CPlayerState.h"
|
||||
#include "../../callback/IGameInfoCallback.h"
|
||||
#include "../../mapObjects/CGHeroInstance.h"
|
||||
#include "../../mapping/CMap.h"
|
||||
#include "../../networkPacks/PacksForClient.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
ViewMechanics::ViewMechanics(const CSpell * s):
|
||||
AdventureSpellMechanics(s)
|
||||
{
|
||||
}
|
||||
|
||||
ESpellCastResult ViewMechanics::applyAdventureEffects(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
|
||||
{
|
||||
ShowWorldViewEx pack;
|
||||
|
||||
pack.player = parameters.caster->getCasterOwner();
|
||||
|
||||
const auto spellLevel = parameters.caster->getSpellSchoolLevel(owner);
|
||||
|
||||
const auto & fowMap = env->getCb()->getPlayerTeam(parameters.caster->getCasterOwner())->fogOfWarMap;
|
||||
|
||||
for(const auto & obj : env->getMap()->getObjects())
|
||||
{
|
||||
//deleted object remain as empty pointer
|
||||
if(obj && filterObject(obj, spellLevel))
|
||||
{
|
||||
ObjectPosInfo posInfo(obj);
|
||||
|
||||
if(fowMap[posInfo.pos.z][posInfo.pos.x][posInfo.pos.y] == 0)
|
||||
pack.objectPositions.push_back(posInfo);
|
||||
}
|
||||
}
|
||||
pack.showTerrain = showTerrain(spellLevel);
|
||||
|
||||
env->apply(pack);
|
||||
|
||||
return ESpellCastResult::OK;
|
||||
}
|
||||
|
||||
///ViewAirMechanics
|
||||
ViewAirMechanics::ViewAirMechanics(const CSpell * s)
|
||||
: ViewMechanics(s)
|
||||
{
|
||||
}
|
||||
|
||||
bool ViewAirMechanics::filterObject(const CGObjectInstance * obj, const int32_t spellLevel) const
|
||||
{
|
||||
return (obj->ID == Obj::ARTIFACT) || (spellLevel > 1 && obj->ID == Obj::HERO) || (spellLevel > 2 && obj->ID == Obj::TOWN);
|
||||
}
|
||||
|
||||
bool ViewAirMechanics::showTerrain(const int32_t spellLevel) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
///ViewEarthMechanics
|
||||
ViewEarthMechanics::ViewEarthMechanics(const CSpell * s)
|
||||
: ViewMechanics(s)
|
||||
{
|
||||
}
|
||||
|
||||
bool ViewEarthMechanics::filterObject(const CGObjectInstance * obj, const int32_t spellLevel) const
|
||||
{
|
||||
return (obj->ID == Obj::RESOURCE) || (spellLevel > 1 && obj->ID == Obj::MINE);
|
||||
}
|
||||
|
||||
bool ViewEarthMechanics::showTerrain(const int32_t spellLevel) const
|
||||
{
|
||||
return spellLevel > 2;
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* ViewWorldMechanics.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 "AdventureSpellMechanics.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class ViewMechanics : public AdventureSpellMechanics
|
||||
{
|
||||
public:
|
||||
ViewMechanics(const CSpell * s);
|
||||
|
||||
protected:
|
||||
ESpellCastResult applyAdventureEffects(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const override;
|
||||
virtual bool filterObject(const CGObjectInstance * obj, const int32_t spellLevel) const = 0;
|
||||
virtual bool showTerrain(const int32_t spellLevel) const = 0;
|
||||
};
|
||||
|
||||
class ViewAirMechanics final : public ViewMechanics
|
||||
{
|
||||
public:
|
||||
ViewAirMechanics(const CSpell * s);
|
||||
|
||||
protected:
|
||||
bool filterObject(const CGObjectInstance * obj, const int32_t spellLevel) const override;
|
||||
bool showTerrain(const int32_t spellLevel) const override;
|
||||
};
|
||||
|
||||
class ViewEarthMechanics final : public ViewMechanics
|
||||
{
|
||||
public:
|
||||
ViewEarthMechanics(const CSpell * s);
|
||||
|
||||
protected:
|
||||
bool filterObject(const CGObjectInstance * obj, const int32_t spellLevel) const override;
|
||||
bool showTerrain(const int32_t spellLevel) const override;
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
Reference in New Issue
Block a user