forked from teamnwah/openmw-tes3coop
Bug #1055: Check power use and mana before starting cast animation
This commit is contained in:
parent
71d9755ef1
commit
5054d8e6c1
5 changed files with 71 additions and 33 deletions
|
@ -414,6 +414,13 @@ namespace MWBase
|
||||||
|
|
||||||
virtual bool toggleGodMode() = 0;
|
virtual bool toggleGodMode() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief startSpellCast attempt to start casting a spell. Might fail immediately if conditions are not met.
|
||||||
|
* @param actor
|
||||||
|
* @return true if the spell can be casted (i.e. the animation should start)
|
||||||
|
*/
|
||||||
|
virtual bool startSpellCast (const MWWorld::Ptr& actor) = 0;
|
||||||
|
|
||||||
virtual void castSpell (const MWWorld::Ptr& actor) = 0;
|
virtual void castSpell (const MWWorld::Ptr& actor) = 0;
|
||||||
|
|
||||||
virtual void launchProjectile (const std::string& id, bool stack, const ESM::EffectList& effects,
|
virtual void launchProjectile (const std::string& id, bool stack, const ESM::EffectList& effects,
|
||||||
|
|
|
@ -505,10 +505,14 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun
|
||||||
mAttackType.clear();
|
mAttackType.clear();
|
||||||
if(mWeaponType == WeapType_Spell)
|
if(mWeaponType == WeapType_Spell)
|
||||||
{
|
{
|
||||||
|
// Unset casting flag, otherwise pressing the mouse button down would
|
||||||
|
// continue casting every frame if there is no animation
|
||||||
|
mPtr.getClass().getCreatureStats(mPtr).setAttackingOrSpell(false);
|
||||||
|
|
||||||
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||||
|
|
||||||
const std::string spellid = stats.getSpells().getSelectedSpell();
|
const std::string spellid = stats.getSpells().getSelectedSpell();
|
||||||
if(!spellid.empty())
|
if(!spellid.empty() && MWBase::Environment::get().getWorld()->startSpellCast(mPtr))
|
||||||
{
|
{
|
||||||
static const std::string schools[] = {
|
static const std::string schools[] = {
|
||||||
"alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration"
|
"alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration"
|
||||||
|
|
|
@ -300,10 +300,11 @@ namespace MWMechanics
|
||||||
if (item.getCellRef().mEnchantmentCharge == -1)
|
if (item.getCellRef().mEnchantmentCharge == -1)
|
||||||
item.getCellRef().mEnchantmentCharge = enchantment->mData.mCharge;
|
item.getCellRef().mEnchantmentCharge = enchantment->mData.mCharge;
|
||||||
|
|
||||||
if (mCaster.getRefData().getHandle() == "player" && item.getCellRef().mEnchantmentCharge < castCost)
|
if (item.getCellRef().mEnchantmentCharge < castCost)
|
||||||
{
|
{
|
||||||
// TODO: Should there be a sound here?
|
// TODO: Should there be a sound here?
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicInsufficientCharge}");
|
if (mCaster.getRefData().getHandle() == "player")
|
||||||
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicInsufficientCharge}");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370,33 +371,7 @@ namespace MWMechanics
|
||||||
fatigue.setCurrent(std::max(0.f, fatigue.getCurrent() - fatigueLoss));
|
fatigue.setCurrent(std::max(0.f, fatigue.getCurrent() - fatigueLoss));
|
||||||
stats.setFatigue(fatigue);
|
stats.setFatigue(fatigue);
|
||||||
|
|
||||||
// Check mana
|
|
||||||
bool fail = false;
|
bool fail = false;
|
||||||
DynamicStat<float> magicka = stats.getMagicka();
|
|
||||||
if (magicka.getCurrent() < spell->mData.mCost)
|
|
||||||
{
|
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicInsufficientSP}");
|
|
||||||
fail = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reduce mana
|
|
||||||
if (!fail)
|
|
||||||
{
|
|
||||||
magicka.setCurrent(magicka.getCurrent() - spell->mData.mCost);
|
|
||||||
stats.setMagicka(magicka);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this is a power, check if it was already used in last 24h
|
|
||||||
if (!fail && spell->mData.mType & ESM::Spell::ST_Power)
|
|
||||||
{
|
|
||||||
if (stats.canUsePower(spell->mId))
|
|
||||||
stats.usePower(spell->mId);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sPowerAlreadyUsed}");
|
|
||||||
fail = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check success
|
// Check success
|
||||||
int successChance = getSpellSuccessChance(spell, mCaster);
|
int successChance = getSpellSuccessChance(spell, mCaster);
|
||||||
|
|
|
@ -2049,15 +2049,56 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool World::startSpellCast(const Ptr &actor)
|
||||||
|
{
|
||||||
|
MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor);
|
||||||
|
|
||||||
|
std::string message;
|
||||||
|
bool fail = false;
|
||||||
|
bool isPlayer = (actor == getPlayer().getPlayer());
|
||||||
|
|
||||||
|
std::string selectedSpell = stats.getSpells().getSelectedSpell();
|
||||||
|
|
||||||
|
if (!selectedSpell.empty())
|
||||||
|
{
|
||||||
|
const ESM::Spell* spell = getStore().get<ESM::Spell>().search(selectedSpell);
|
||||||
|
|
||||||
|
// Check mana
|
||||||
|
MWMechanics::DynamicStat<float> magicka = stats.getMagicka();
|
||||||
|
if (magicka.getCurrent() < spell->mData.mCost)
|
||||||
|
{
|
||||||
|
message = "#{sMagicInsufficientSP}";
|
||||||
|
fail = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is a power, check if it was already used in the last 24h
|
||||||
|
if (!fail && spell->mData.mType & ESM::Spell::ST_Power)
|
||||||
|
{
|
||||||
|
if (stats.canUsePower(spell->mId))
|
||||||
|
stats.usePower(spell->mId);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
message = "#{sPowerAlreadyUsed}";
|
||||||
|
fail = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduce mana
|
||||||
|
magicka.setCurrent(magicka.getCurrent() - spell->mData.mCost);
|
||||||
|
stats.setMagicka(magicka);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPlayer && fail)
|
||||||
|
MWBase::Environment::get().getWindowManager()->messageBox(message);
|
||||||
|
|
||||||
|
return !fail;
|
||||||
|
}
|
||||||
|
|
||||||
void World::castSpell(const Ptr &actor)
|
void World::castSpell(const Ptr &actor)
|
||||||
{
|
{
|
||||||
MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor);
|
MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor);
|
||||||
InventoryStore& inv = actor.getClass().getInventoryStore(actor);
|
InventoryStore& inv = actor.getClass().getInventoryStore(actor);
|
||||||
|
|
||||||
// Unset casting flag, otherwise pressing the mouse button down would continue casting every frame if using an enchantment
|
|
||||||
// (which casts instantly without an animation)
|
|
||||||
stats.setAttackingOrSpell(false);
|
|
||||||
|
|
||||||
MWWorld::Ptr target = getFacedObject();
|
MWWorld::Ptr target = getFacedObject();
|
||||||
|
|
||||||
std::string selectedSpell = stats.getSpells().getSelectedSpell();
|
std::string selectedSpell = stats.getSpells().getSelectedSpell();
|
||||||
|
|
|
@ -499,6 +499,17 @@ namespace MWWorld
|
||||||
|
|
||||||
virtual bool toggleGodMode();
|
virtual bool toggleGodMode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief startSpellCast attempt to start casting a spell. Might fail immediately if conditions are not met.
|
||||||
|
* @param actor
|
||||||
|
* @return true if the spell can be casted (i.e. the animation should start)
|
||||||
|
*/
|
||||||
|
virtual bool startSpellCast (const MWWorld::Ptr& actor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Cast the actual spell, should be called mid-animation
|
||||||
|
* @param actor
|
||||||
|
*/
|
||||||
virtual void castSpell (const MWWorld::Ptr& actor);
|
virtual void castSpell (const MWWorld::Ptr& actor);
|
||||||
|
|
||||||
virtual void launchProjectile (const std::string& id, bool stack, const ESM::EffectList& effects,
|
virtual void launchProjectile (const std::string& id, bool stack, const ESM::EffectList& effects,
|
||||||
|
|
Loading…
Reference in a new issue