Selaa lähdekoodia

Fixes issues related to spell mechanics

nordsoft 2 vuotta sitten
vanhempi
sitoutus
b9cabef179

+ 5 - 1
lib/mapObjects/CRewardableConstructor.cpp

@@ -132,7 +132,11 @@ void CRandomRewardObjectInfo::configureReward(CRewardableObject * object, CRando
 	reward.artifacts = JsonRandom::loadArtifacts(source["artifacts"], rng);
 	reward.spells = JsonRandom::loadSpells(source["spells"], rng, spells);
 	reward.creatures = JsonRandom::loadCreatures(source["creatures"], rng);
-	reward.casts = JsonRandom::loadSpells(source["casts"], rng, spells);
+	if(!source["spellCast"].isNull() && source["spellCast"].isStruct())
+	{
+		reward.spellCast.first = JsonRandom::loadSpell(source["spellCast"]["spell"], rng);
+		reward.spellCast.second = source["spellCast"]["schoolLevel"].Integer();
+	}
 
 	for ( auto node : source["changeCreatures"].Struct() )
 	{

+ 8 - 7
lib/mapObjects/CRewardableObject.cpp

@@ -363,13 +363,14 @@ void CRewardableObject::grantRewardAfterLevelup(const CRewardVisitInfo & info, c
 		cb->giveCreatures(this, hero, creatures, false);
 	}
 	
-	if(!info.reward.casts.empty())
-	{
-		caster = std::make_unique<spells::OuterCaster>(hero, SecSkillLevel::EXPERT);
-		for(const auto & c : info.reward.casts)
-		{
-			cb->castSpell(caster.get(), c, int3{-1, -1, -1});
-		}
+	if(info.reward.spellCast.first != SpellID::NONE)
+	{
+		caster.setActualCaster(hero);
+		caster.setSpellSchoolLevel(info.reward.spellCast.second);
+		cb->castSpell(&caster, info.reward.spellCast.first, int3{-1, -1, -1});
+		
+		if(info.reward.removeObject)
+			logMod->warn("Removal of object with spell casts is not supported!");
 	}
 	else if(info.reward.removeObject) //FIXME: object can't track spell cancel or finish, so removeObject leads to crash
 		cb->removeObject(this);

+ 7 - 5
lib/mapObjects/CRewardableObject.h

@@ -171,8 +171,8 @@ public:
 	std::vector<SpellID> spells;
 	std::vector<CStackBasicDescriptor> creatures;
 	
-	/// actions that hero may execute and object caster
-	std::vector<SpellID> casts;
+	/// actions that hero may execute and object caster. Pair of spellID and school level
+	std::pair<SpellID, int> spellCast;
 
 	/// list of components that will be added to reward description. First entry in list will override displayed component
 	std::vector<Component> extraComponents;
@@ -195,7 +195,8 @@ public:
 		movePoints(0),
 		movePercentage(-1),
 		primary(4, 0),
-		removeObject(false)
+		removeObject(false),
+		spellCast(SpellID::NONE, SecSkillLevel::NONE)
 	{}
 
 	template <typename Handler> void serialize(Handler &h, const int version)
@@ -217,7 +218,8 @@ public:
 		h & spells;
 		h & creatures;
 		h & creaturesChange;
-		h & casts;
+		if(version >= 821)
+			h & spellCast;
 	}
 };
 
@@ -324,7 +326,7 @@ protected:
 	bool onceVisitableObjectCleared;
 	
 	/// caster to cast adveture spells
-	mutable std::unique_ptr<spells::OuterCaster> caster;
+	mutable spells::OuterCaster caster;
 
 public:
 	EVisitMode getVisitMode() const;

+ 3 - 3
lib/mapObjects/JsonRandom.h

@@ -32,7 +32,7 @@ namespace JsonRandom
 	};
 
 	DLL_LINKAGE si32 loadValue(const JsonNode & value, CRandomGenerator & rng, si32 defaultValue = 0);
-	DLL_LINKAGE std::string loadKey(const JsonNode & value, CRandomGenerator & rng, const std::set<std::string> & valuesSet);
+	DLL_LINKAGE std::string loadKey(const JsonNode & value, CRandomGenerator & rng, const std::set<std::string> & valuesSet = {});
 	DLL_LINKAGE TResources loadResources(const JsonNode & value, CRandomGenerator & rng);
 	DLL_LINKAGE TResources loadResource(const JsonNode & value, CRandomGenerator & rng);
 	DLL_LINKAGE std::vector<si32> loadPrimary(const JsonNode & value, CRandomGenerator & rng);
@@ -41,8 +41,8 @@ namespace JsonRandom
 	DLL_LINKAGE ArtifactID loadArtifact(const JsonNode & value, CRandomGenerator & rng);
 	DLL_LINKAGE std::vector<ArtifactID> loadArtifacts(const JsonNode & value, CRandomGenerator & rng);
 
-	DLL_LINKAGE SpellID loadSpell(const JsonNode & value, CRandomGenerator & rng, std::vector<SpellID> spells);
-	DLL_LINKAGE std::vector<SpellID> loadSpells(const JsonNode & value, CRandomGenerator & rng, const std::vector<SpellID> & spells);
+	DLL_LINKAGE SpellID loadSpell(const JsonNode & value, CRandomGenerator & rng, std::vector<SpellID> spells = {});
+	DLL_LINKAGE std::vector<SpellID> loadSpells(const JsonNode & value, CRandomGenerator & rng, const std::vector<SpellID> & spells = {});
 
 	DLL_LINKAGE CStackBasicDescriptor loadCreature(const JsonNode & value, CRandomGenerator & rng);
 	DLL_LINKAGE std::vector<CStackBasicDescriptor> loadCreatures(const JsonNode & value, CRandomGenerator & rng);

+ 4 - 7
lib/spells/AdventureSpellMechanics.cpp

@@ -122,13 +122,7 @@ void AdventureSpellMechanics::endCast(SpellCastEnvironment * env, const Adventur
 	switch(result)
 	{
 	case ESpellCastResult::OK:
-		{
-			SetMana sm;
-			sm.hid = ObjectInstanceID(parameters.caster->getCasterUnitId());
-			sm.absolute = false;
-			sm.val = -cost;
-			env->apply(&sm);
-		}
+		parameters.caster->spendMana(env, cost);
 		break;
 	default:
 		break;
@@ -584,6 +578,9 @@ std::vector <const CGTownInstance*> TownPortalMechanics::getPossibleTowns(SpellC
 
 int32_t TownPortalMechanics::movementCost(const AdventureSpellCastParameters & parameters) const
 {
+	if(parameters.caster != parameters.caster->getHeroCaster()) //if caster is not hero
+		return 0;
+	
 	return GameConstants::BASE_MOVEMENT_COST * ((parameters.caster->getSpellSchoolLevel(owner) >= 3) ? 2 : 3);
 }
 

+ 14 - 0
lib/spells/OuterCaster.cpp

@@ -17,10 +17,24 @@ VCMI_LIB_NAMESPACE_BEGIN
 namespace spells
 {
 
+OuterCaster::OuterCaster()
+	: ProxyCaster(nullptr), schoolLevel(0)
+{
+}
+
 OuterCaster::OuterCaster(const Caster * actualCaster_, int schoolLevel_)
 	: ProxyCaster(actualCaster_), schoolLevel(schoolLevel_)
 {
+}
+
+void OuterCaster::setActualCaster(const Caster * actualCaster_)
+{
+	actualCaster = actualCaster_;
+}
 
+void OuterCaster::setSpellSchoolLevel(int level)
+{
+	schoolLevel = level;
 }
 
 void OuterCaster::spendMana(ServerCallback * server, const int32_t spellCost) const

+ 4 - 0
lib/spells/OuterCaster.h

@@ -21,7 +21,11 @@ class DLL_LINKAGE OuterCaster : public ProxyCaster
 {
 	int schoolLevel;
 public:
+	OuterCaster();
 	OuterCaster(const Caster * actualCaster_, int schoolLevel_);
+	
+	void setActualCaster(const Caster * actualCaster);
+	void setSpellSchoolLevel(int level);
 
 	int32_t getSpellSchoolLevel(const Spell * spell, int32_t * outSelectedSchool = nullptr) const override;
 	void spendMana(ServerCallback * server, const int32_t spellCost) const override;