浏览代码

Boat summon spell rewritten

nordsoft 2 年之前
父节点
当前提交
72b2a09f0b
共有 3 个文件被更改,包括 59 次插入47 次删除
  1. 1 1
      lib/mapObjects/CGHeroInstance.cpp
  2. 57 45
      lib/spells/AdventureSpellMechanics.cpp
  3. 1 1
      lib/spells/ISpellMechanics.h

+ 1 - 1
lib/mapObjects/CGHeroInstance.cpp

@@ -570,7 +570,7 @@ TExpType CGHeroInstance::calculateXp(TExpType exp) const
 
 int32_t CGHeroInstance::getCasterUnitId() const
 {
-	return -1; //TODO: special value for attacker/defender hero
+	return id.getNum();
 }
 
 int32_t CGHeroInstance::getSpellSchoolLevel(const spells::Spell * spell, int32_t * outSelectedSchool) const

+ 57 - 45
lib/spells/AdventureSpellMechanics.cpp

@@ -37,27 +37,28 @@ bool AdventureSpellMechanics::adventureCast(SpellCastEnvironment * env, const Ad
 		return false;
 	}
 
-	const CGHeroInstance * caster = parameters.caster;
-
-	if(caster->inTownGarrison)
+	if(const CGHeroInstance * heroCaster = dynamic_cast<const CGHeroInstance *>(parameters.caster))
 	{
-		env->complain("Attempt to cast an adventure spell in town garrison");
-		return false;
-	}
+		if(heroCaster->inTownGarrison)
+		{
+			env->complain("Attempt to cast an adventure spell in town garrison");
+			return false;
+		}
 
-	const auto level = caster->getSpellSchoolLevel(owner);
-	const auto cost = owner->getCost(level);
+		const auto level = heroCaster->getSpellSchoolLevel(owner);
+		const auto cost = owner->getCost(level);
 
-	if(!caster->canCastThisSpell(owner))
-	{
-		env->complain("Hero cannot cast this spell!");
-		return false;
-	}
+		if(!heroCaster->canCastThisSpell(owner))
+		{
+			env->complain("Hero cannot cast this spell!");
+			return false;
+		}
 
-	if(caster->mana < cost)
-	{
-		env->complain("Hero doesn't have enough spell points to cast this spell!");
-		return false;
+		if(heroCaster->mana < cost)
+		{
+			env->complain("Hero doesn't have enough spell points to cast this spell!");
+			return false;
+		}
 	}
 
 	ESpellCastResult result = beginCast(env, parameters);
@@ -82,7 +83,7 @@ ESpellCastResult AdventureSpellMechanics::applyAdventureEffects(SpellCastEnviron
 		for(const Bonus & b : bonuses)
 		{
 			GiveBonus gb;
-			gb.id = parameters.caster->id.getNum();
+			gb.id = parameters.caster->getCasterUnitId();
 			gb.bonus = b;
 			env->apply(&gb);
 		}
@@ -105,7 +106,7 @@ ESpellCastResult AdventureSpellMechanics::beginCast(SpellCastEnvironment * env,
 void AdventureSpellMechanics::performCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
 {
 	AdvmapSpellCast asc;
-	asc.casterID = parameters.caster->id;
+	asc.casterID = ObjectInstanceID(parameters.caster->getCasterUnitId());
 	asc.spellID = owner->id;
 	env->apply(&asc);
 
@@ -123,7 +124,7 @@ void AdventureSpellMechanics::endCast(SpellCastEnvironment * env, const Adventur
 	case ESpellCastResult::OK:
 		{
 			SetMana sm;
-			sm.hid = parameters.caster->id;
+			sm.hid = ObjectInstanceID(parameters.caster->getCasterUnitId());
 			sm.absolute = false;
 			sm.val = -cost;
 			env->apply(&sm);
@@ -142,21 +143,29 @@ SummonBoatMechanics::SummonBoatMechanics(const CSpell * s):
 
 ESpellCastResult SummonBoatMechanics::applyAdventureEffects(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
 {
-	if(parameters.caster->boat)
+	//casts to minimal abstraction level
+	const auto * objectCaster = dynamic_cast<const CGObjectInstance *>(parameters.caster);
+	const auto * heroCaster = dynamic_cast<const CGHeroInstance *>(parameters.caster);
+	const auto * boatGeneratorCaster = dynamic_cast<const IBoatGenerator *>(parameters.caster);
+	
+	if(heroCaster && heroCaster->boat)
 	{
 		InfoWindow iw;
-		iw.player = parameters.caster->tempOwner;
+		iw.player = parameters.caster->getCasterOwner();
 		iw.text.addTxt(MetaString::GENERAL_TXT, 333);//%s is already in boat
-		iw.text.addReplacement(parameters.caster->getNameTranslated());
+		parameters.caster->getCasterName(iw.text);
 		env->apply(&iw);
 		return ESpellCastResult::CANCEL;
 	}
 
-	int3 summonPos = parameters.caster->bestLocation();
+	int3 summonPos(-1, -1, -1);
+	if(boatGeneratorCaster)
+		summonPos = (boatGeneratorCaster)->bestLocation();
+	
 	if(summonPos.x < 0)
 	{
 		InfoWindow iw;
-		iw.player = parameters.caster->tempOwner;
+		iw.player = parameters.caster->getCasterOwner();
 		iw.text.addTxt(MetaString::GENERAL_TXT, 334);//There is no place to put the boat.
 		env->apply(&iw);
 		return ESpellCastResult::CANCEL;
@@ -168,9 +177,9 @@ ESpellCastResult SummonBoatMechanics::applyAdventureEffects(SpellCastEnvironment
 	if(env->getRNG()->getInt64Range(0, 99)() >= owner->getLevelPower(schoolLevel)) //power is % chance of success
 	{
 		InfoWindow iw;
-		iw.player = parameters.caster->tempOwner;
+		iw.player = parameters.caster->getCasterOwner();
 		iw.text.addTxt(MetaString::GENERAL_TXT, 336); //%s tried to summon a boat, but failed.
-		iw.text.addReplacement(parameters.caster->getNameTranslated());
+		parameters.caster->getCasterName(iw.text);
 		env->apply(&iw);
 		return ESpellCastResult::OK;
 	}
@@ -178,19 +187,22 @@ ESpellCastResult SummonBoatMechanics::applyAdventureEffects(SpellCastEnvironment
 	//try to find unoccupied boat to summon
 	const CGBoat * nearest = nullptr;
 	double dist = 0;
-	for(const CGObjectInstance * obj : env->getMap()->objects)
+	if(objectCaster)
 	{
-		if(obj && obj->ID == Obj::BOAT)
+		for(const CGObjectInstance * obj : env->getMap()->objects)
 		{
-			const auto * b = dynamic_cast<const CGBoat *>(obj);
-			if(b->hero)
-				continue; //we're looking for unoccupied boat
-
-			double nDist = b->pos.dist2d(parameters.caster->visitablePos());
-			if(!nearest || nDist < dist) //it's first boat or closer than previous
+			if(obj && obj->ID == Obj::BOAT)
 			{
-				nearest = b;
-				dist = nDist;
+				const auto * b = dynamic_cast<const CGBoat *>(obj);
+				if(b->hero)
+					continue; //we're looking for unoccupied boat
+
+				double nDist = b->pos.dist2d(objectCaster->visitablePos());
+				if(!nearest || nDist < dist) //it's first boat or closer than previous
+				{
+					nearest = b;
+					dist = nDist;
+				}
 			}
 		}
 	}
@@ -205,15 +217,15 @@ ESpellCastResult SummonBoatMechanics::applyAdventureEffects(SpellCastEnvironment
 	else if(schoolLevel < 2) //none or basic level -> cannot create boat :(
 	{
 		InfoWindow iw;
-		iw.player = parameters.caster->tempOwner;
+		iw.player = parameters.caster->getCasterOwner();
 		iw.text.addTxt(MetaString::GENERAL_TXT, 335); //There are no boats to summon.
 		env->apply(&iw);
 	}
-	else //create boat
+	else if(boatGeneratorCaster) //create boat
 	{
 		NewObject no;
 		no.ID = Obj::BOAT;
-		no.subID = parameters.caster->getBoatType();
+		no.subID = boatGeneratorCaster->getBoatType();
 		no.pos = summonPos + int3(1,0,0);
 		env->apply(&no);
 	}
@@ -233,9 +245,9 @@ ESpellCastResult ScuttleBoatMechanics::applyAdventureEffects(SpellCastEnvironmen
 	if(env->getRNG()->getInt64Range(0, 99)() >= owner->getLevelPower(schoolLevel)) //power is % chance of success
 	{
 		InfoWindow iw;
-		iw.player = parameters.caster->tempOwner;
+		iw.player = parameters.caster->getCasterOwner();
 		iw.text.addTxt(MetaString::GENERAL_TXT, 337); //%s tried to scuttle the boat, but failed
-		iw.text.addReplacement(parameters.caster->getNameTranslated());
+		parameters.caster->getCasterName(iw.text);
 		env->apply(&iw);
 		return ESpellCastResult::OK;
 	}
@@ -304,9 +316,9 @@ ESpellCastResult DimensionDoorMechanics::applyAdventureEffects(SpellCastEnvironm
 	if(parameters.caster->getBonuses(Selector::source(Bonus::SPELL_EFFECT, owner->id), Selector::all, cachingStr.str())->size() >= owner->getLevelPower(schoolLevel)) //limit casts per turn
 	{
 		InfoWindow iw;
-		iw.player = parameters.caster->tempOwner;
+		iw.player = parameters.caster->getCasterOwner();
 		iw.text.addTxt(MetaString::GENERAL_TXT, 338); //%s is not skilled enough to cast this spell again today.
-		iw.text.addReplacement(parameters.caster->getNameTranslated());
+		parameters.caster->getCasterName(iw.text);
 		env->apply(&iw);
 		return ESpellCastResult::CANCEL;
 	}
@@ -319,7 +331,7 @@ ESpellCastResult DimensionDoorMechanics::applyAdventureEffects(SpellCastEnvironm
 	if(!dest->isClear(curr)) //wrong dest tile
 	{
 		InfoWindow iw;
-		iw.player = parameters.caster->tempOwner;
+		iw.player = parameters.caster->getCasterOwner();
 		iw.text.addTxt(MetaString::GENERAL_TXT, 70); //Dimension Door failed!
 		env->apply(&iw);
 	}

+ 1 - 1
lib/spells/ISpellMechanics.h

@@ -350,7 +350,7 @@ public:
 class DLL_LINKAGE AdventureSpellCastParameters
 {
 public:
-	const CGHeroInstance * caster;
+	const spells::Caster * caster;
 	int3 pos;
 };