mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-26 03:52:01 +02:00
Boat summon spell rewritten
This commit is contained in:
parent
69ad62ef58
commit
72b2a09f0b
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -350,7 +350,7 @@ public:
|
||||
class DLL_LINKAGE AdventureSpellCastParameters
|
||||
{
|
||||
public:
|
||||
const CGHeroInstance * caster;
|
||||
const spells::Caster * caster;
|
||||
int3 pos;
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user