1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-10-20 14:16:46 +00:00

Differentiate between invalid and unapplied effects and stop marking unapplied revertable effects as applied in godmode

This commit is contained in:
Evil Eye 2025-10-14 21:26:06 +02:00
parent 34ff702212
commit 5242610366
2 changed files with 95 additions and 108 deletions

View file

@ -44,18 +44,16 @@ namespace
return effect.mMinMagnitude + Misc::Rng::rollDice(effect.mMaxMagnitude - effect.mMinMagnitude + 1, prng);
}
void modifyAiSetting(const MWWorld::Ptr& target, const ESM::ActiveEffect& effect,
ESM::MagicEffect::Effects creatureEffect, MWMechanics::AiSetting setting, float magnitude, bool& invalid)
ESM::ActiveEffect::Flags modifyAiSetting(const MWWorld::Ptr& target, const ESM::ActiveEffect& effect,
ESM::MagicEffect::Effects creatureEffect, MWMechanics::AiSetting setting, float magnitude)
{
if (target == MWMechanics::getPlayer() || (effect.mEffectId == creatureEffect) == target.getClass().isNpc())
invalid = true;
else
{
auto& creatureStats = target.getClass().getCreatureStats(target);
auto stat = creatureStats.getAiSetting(setting);
stat.setModifier(static_cast<int>(stat.getModifier() + magnitude));
creatureStats.setAiSetting(setting, stat);
}
return ESM::ActiveEffect::Flag_Invalid;
auto& creatureStats = target.getClass().getCreatureStats(target);
auto stat = creatureStats.getAiSetting(setting);
stat.setModifier(static_cast<int>(stat.getModifier() + magnitude));
creatureStats.setAiSetting(setting, stat);
return ESM::ActiveEffect::Flag_Applied;
}
void adjustDynamicStat(const MWWorld::Ptr& target, int index, float magnitude, bool allowDecreaseBelowZero = false,
@ -420,12 +418,12 @@ namespace
namespace MWMechanics
{
void applyMagicEffect(const MWWorld::Ptr& target, const MWWorld::Ptr& caster,
const ActiveSpells::ActiveSpellParams& spellParams, ESM::ActiveEffect& effect, bool& invalid,
bool& receivedMagicDamage, bool& affectedHealth, bool& recalculateMagicka)
ESM::ActiveEffect::Flags applyMagicEffect(const MWWorld::Ptr& target, const MWWorld::Ptr& caster,
const ActiveSpells::ActiveSpellParams& spellParams, ESM::ActiveEffect& effect, bool& receivedMagicDamage,
bool& affectedHealth, bool& recalculateMagicka)
{
const auto world = MWBase::Environment::get().getWorld();
bool godmode = target == getPlayer() && world->getGodModeState();
const bool godmode = target == getPlayer() && world->getGodModeState();
switch (effect.mEffectId)
{
case ESM::MagicEffect::CureCommonDisease:
@ -469,7 +467,7 @@ namespace MWMechanics
case ESM::MagicEffect::AlmsiviIntervention:
case ESM::MagicEffect::DivineIntervention:
if (target != getPlayer())
invalid = true;
return ESM::ActiveEffect::Flag_Invalid;
else if (world->isTeleportingEnabled())
{
std::string_view marker
@ -494,7 +492,7 @@ namespace MWMechanics
break;
case ESM::MagicEffect::Mark:
if (target != getPlayer())
invalid = true;
return ESM::ActiveEffect::Flag_Invalid;
else if (world->isTeleportingEnabled())
world->getPlayer().markPosition(target.getCell(), target.getRefData().getPosition());
else if (caster == getPlayer())
@ -502,7 +500,7 @@ namespace MWMechanics
break;
case ESM::MagicEffect::Recall:
if (target != getPlayer())
invalid = true;
return ESM::ActiveEffect::Flag_Invalid;
else if (world->isTeleportingEnabled())
{
MWWorld::CellStore* markedCell = nullptr;
@ -528,7 +526,7 @@ namespace MWMechanics
case ESM::MagicEffect::CommandHumanoid:
if (caster.isEmpty() || !caster.getClass().isActor() || target == getPlayer()
|| (effect.mEffectId == ESM::MagicEffect::CommandCreature) == target.getClass().isNpc())
invalid = true;
return ESM::ActiveEffect::Flag_Invalid;
else if (effect.mMagnitude >= target.getClass().getCreatureStats(target).getLevel())
{
MWMechanics::AiFollow package(caster, true);
@ -536,41 +534,37 @@ namespace MWMechanics
}
break;
case ESM::MagicEffect::ExtraSpell:
if (target.getClass().hasInventoryStore(target))
if (!target.getClass().hasInventoryStore(target))
return ESM::ActiveEffect::Flag_Invalid;
if (target != getPlayer())
{
if (target != getPlayer())
auto& store = target.getClass().getInventoryStore(target);
for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot)
{
auto& store = target.getClass().getInventoryStore(target);
for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot)
// Unequip everything except weapons, torches, and pants
switch (slot)
{
// Unequip everything except weapons, torches, and pants
switch (slot)
case MWWorld::InventoryStore::Slot_Ammunition:
case MWWorld::InventoryStore::Slot_CarriedRight:
case MWWorld::InventoryStore::Slot_Pants:
continue;
case MWWorld::InventoryStore::Slot_CarriedLeft:
{
case MWWorld::InventoryStore::Slot_Ammunition:
case MWWorld::InventoryStore::Slot_CarriedRight:
case MWWorld::InventoryStore::Slot_Pants:
auto carried = store.getSlot(slot);
if (carried == store.end() || carried.getType() != MWWorld::ContainerStore::Type_Armor)
continue;
case MWWorld::InventoryStore::Slot_CarriedLeft:
{
auto carried = store.getSlot(slot);
if (carried == store.end()
|| carried.getType() != MWWorld::ContainerStore::Type_Armor)
continue;
[[fallthrough]];
}
default:
store.unequipSlot(slot);
[[fallthrough]];
}
default:
store.unequipSlot(slot);
}
}
}
else
invalid = true;
break;
case ESM::MagicEffect::TurnUndead:
if (target.getClass().isNpc()
|| target.get<ESM::Creature>()->mBase->mData.mType != ESM::Creature::Undead)
invalid = true;
return ESM::ActiveEffect::Flag_Invalid;
else
{
auto& creatureStats = target.getClass().getCreatureStats(target);
@ -581,32 +575,33 @@ namespace MWMechanics
break;
case ESM::MagicEffect::FrenzyCreature:
case ESM::MagicEffect::FrenzyHumanoid:
modifyAiSetting(
target, effect, ESM::MagicEffect::FrenzyCreature, AiSetting::Fight, effect.mMagnitude, invalid);
break;
return modifyAiSetting(
target, effect, ESM::MagicEffect::FrenzyCreature, AiSetting::Fight, effect.mMagnitude);
case ESM::MagicEffect::CalmCreature:
case ESM::MagicEffect::CalmHumanoid:
modifyAiSetting(
target, effect, ESM::MagicEffect::CalmCreature, AiSetting::Fight, -effect.mMagnitude, invalid);
if (!invalid && effect.mMagnitude > 0)
{
ESM::ActiveEffect::Flags applied = modifyAiSetting(
target, effect, ESM::MagicEffect::CalmCreature, AiSetting::Fight, -effect.mMagnitude);
if (applied != ESM::ActiveEffect::Flag_Applied)
return applied;
if (effect.mMagnitude > 0)
{
auto& creatureStats = target.getClass().getCreatureStats(target);
creatureStats.getAiSequence().stopCombat();
}
break;
}
case ESM::MagicEffect::DemoralizeCreature:
case ESM::MagicEffect::DemoralizeHumanoid:
modifyAiSetting(
target, effect, ESM::MagicEffect::DemoralizeCreature, AiSetting::Flee, effect.mMagnitude, invalid);
break;
return modifyAiSetting(
target, effect, ESM::MagicEffect::DemoralizeCreature, AiSetting::Flee, effect.mMagnitude);
case ESM::MagicEffect::RallyCreature:
case ESM::MagicEffect::RallyHumanoid:
modifyAiSetting(
target, effect, ESM::MagicEffect::RallyCreature, AiSetting::Flee, -effect.mMagnitude, invalid);
break;
return modifyAiSetting(
target, effect, ESM::MagicEffect::RallyCreature, AiSetting::Flee, -effect.mMagnitude);
case ESM::MagicEffect::Charm:
if (!target.getClass().isNpc())
invalid = true;
return ESM::ActiveEffect::Flag_Invalid;
break;
case ESM::MagicEffect::Sound:
if (target == getPlayer())
@ -643,16 +638,12 @@ namespace MWMechanics
case ESM::MagicEffect::SummonCreature04:
case ESM::MagicEffect::SummonCreature05:
if (!target.isInCell())
invalid = true;
else
effect.mArg = summonCreature(effect.mEffectId, target);
return ESM::ActiveEffect::Flag_Invalid;
effect.mArg = summonCreature(effect.mEffectId, target);
break;
case ESM::MagicEffect::BoundGloves:
if (!target.getClass().hasInventoryStore(target))
{
invalid = true;
break;
}
return ESM::ActiveEffect::Flag_Invalid;
addBoundItem(ESM::RefId::stringRefId(world->getStore()
.get<ESM::GameSetting>()
.find("sMagicBoundRightGauntletID")
@ -672,10 +663,7 @@ namespace MWMechanics
case ESM::MagicEffect::BoundShield:
{
if (!target.getClass().hasInventoryStore(target))
{
invalid = true;
break;
}
return ESM::ActiveEffect::Flag_Invalid;
const std::string& item = sBoundItemsMap.at(effect.mEffectId);
const MWWorld::Store<ESM::GameSetting>& gmst = world->getStore().get<ESM::GameSetting>();
const ESM::RefId itemId = ESM::RefId::stringRefId(gmst.find(item)->mValue.getString());
@ -762,7 +750,9 @@ namespace MWMechanics
case ESM::MagicEffect::DrainHealth:
case ESM::MagicEffect::DrainMagicka:
case ESM::MagicEffect::DrainFatigue:
if (!godmode)
if (godmode)
return ESM::ActiveEffect::Flag_Remove;
else
{
int index = effect.mEffectId - ESM::MagicEffect::DrainHealth;
// Unlike Absorb and Damage effects Drain effects can bring stats below zero
@ -781,8 +771,9 @@ namespace MWMechanics
target, effect.mEffectId - ESM::MagicEffect::FortifyHealth, effect.mMagnitude, false, true);
break;
case ESM::MagicEffect::DrainAttribute:
if (!godmode)
damageAttribute(target, effect, effect.mMagnitude);
if (godmode)
return ESM::ActiveEffect::Flag_Remove;
damageAttribute(target, effect, effect.mMagnitude);
break;
case ESM::MagicEffect::FortifyAttribute:
// Abilities affect base stats, but not for drain
@ -798,8 +789,9 @@ namespace MWMechanics
fortifyAttribute(target, effect, effect.mMagnitude);
break;
case ESM::MagicEffect::DrainSkill:
if (!godmode && target.getClass().isNpc())
damageSkill(target, effect, effect.mMagnitude);
if (godmode || !target.getClass().isNpc())
return ESM::ActiveEffect::Flag_Remove;
damageSkill(target, effect, effect.mMagnitude);
break;
case ESM::MagicEffect::FortifySkill:
if (target.getClass().isNpc())
@ -821,7 +813,9 @@ namespace MWMechanics
case ESM::MagicEffect::AbsorbHealth:
case ESM::MagicEffect::AbsorbMagicka:
case ESM::MagicEffect::AbsorbFatigue:
if (!godmode)
if (godmode)
return ESM::ActiveEffect::Flag_Remove;
else
{
int index = effect.mEffectId - ESM::MagicEffect::AbsorbHealth;
adjustDynamicStat(target, index, -effect.mMagnitude);
@ -832,7 +826,9 @@ namespace MWMechanics
}
break;
case ESM::MagicEffect::AbsorbAttribute:
if (!godmode)
if (godmode)
return ESM::ActiveEffect::Flag_Remove;
else
{
damageAttribute(target, effect, effect.mMagnitude);
if (!caster.isEmpty())
@ -840,7 +836,9 @@ namespace MWMechanics
}
break;
case ESM::MagicEffect::AbsorbSkill:
if (!godmode)
if (godmode)
return ESM::ActiveEffect::Flag_Remove;
else
{
if (target.getClass().isNpc())
damageSkill(target, effect, effect.mMagnitude);
@ -851,10 +849,7 @@ namespace MWMechanics
case ESM::MagicEffect::DisintegrateArmor:
{
if (!target.getClass().hasInventoryStore(target))
{
invalid = true;
break;
}
return ESM::ActiveEffect::Flag_Invalid;
if (godmode)
break;
static const std::array<int, 9> priorities{
@ -877,24 +872,18 @@ namespace MWMechanics
}
case ESM::MagicEffect::DisintegrateWeapon:
if (!target.getClass().hasInventoryStore(target))
{
invalid = true;
break;
}
return ESM::ActiveEffect::Flag_Invalid;
if (!godmode)
disintegrateSlot(target, MWWorld::InventoryStore::Slot_CarriedRight, effect.mMagnitude);
break;
}
return ESM::ActiveEffect::Flag_Applied;
}
bool shouldRemoveEffect(const MWWorld::Ptr& target, const ESM::ActiveEffect& effect)
{
if ((effect.mFlags & (ESM::ActiveEffect::Flag_Remove | ESM::ActiveEffect::Flag_Applied))
== ESM::ActiveEffect::Flag_Remove)
{
// Previously marked invalid
if (effect.mFlags & ESM::ActiveEffect::Flag_Invalid)
return true;
}
const auto world = MWBase::Environment::get().getWorld();
switch (effect.mEffectId)
{
@ -936,7 +925,7 @@ namespace MWMechanics
ActiveSpells::ActiveSpellParams& spellParams, ESM::ActiveEffect& effect, float dt, bool playNonLooping)
{
const auto world = MWBase::Environment::get().getWorld();
bool invalid = false;
int32_t applied = ESM::ActiveEffect::Flag_Remove;
bool receivedMagicDamage = false;
bool recalculateMagicka = false;
bool affectedHealth = false;
@ -946,8 +935,8 @@ namespace MWMechanics
for (auto& otherEffect : spellParams.getEffects())
{
if (isCorprusEffect(otherEffect))
applyMagicEffect(target, caster, spellParams, otherEffect, invalid, receivedMagicDamage,
affectedHealth, recalculateMagicka);
applyMagicEffect(target, caster, spellParams, otherEffect, receivedMagicDamage, affectedHealth,
recalculateMagicka);
}
if (target == getPlayer())
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicCorprusWorsens}");
@ -989,7 +978,7 @@ namespace MWMechanics
}
}
else
invalid = true;
applied |= ESM::ActiveEffect::Flag_Invalid;
}
else if (effect.mEffectId == ESM::MagicEffect::Open)
{
@ -1021,11 +1010,11 @@ namespace MWMechanics
}
}
else
invalid = true;
applied |= ESM::ActiveEffect::Flag_Invalid;
}
else if (!target.getClass().isActor())
{
invalid = true;
applied |= ESM::ActiveEffect::Flag_Invalid;
}
else
{
@ -1041,7 +1030,7 @@ namespace MWMechanics
auto& stats = target.getClass().getCreatureStats(target);
auto& magnitudes = stats.getMagicEffects();
if (!spellParams.hasFlag(ESM::ActiveSpells::Flag_AffectsBaseValues)
&& !(effect.mFlags & ESM::ActiveEffect::Flag_Applied))
&& !(effect.mFlags & ESM::ActiveEffect::Flag_Remove))
{
MagicApplicationResult::Type result
= applyProtections(target, caster, spellParams, effect, magicEffect);
@ -1051,7 +1040,7 @@ namespace MWMechanics
float oldMagnitude = 0.f;
if (effect.mFlags & ESM::ActiveEffect::Flag_Applied)
oldMagnitude = effect.mMagnitude;
else
else if (!(effect.mFlags & ESM::ActiveEffect::Flag_Remove))
{
bool isTemporary = spellParams.hasFlag(ESM::ActiveSpells::Flag_Temporary);
bool isEquipment = spellParams.hasFlag(ESM::ActiveSpells::Flag_Equipment);
@ -1086,26 +1075,27 @@ namespace MWMechanics
}
}
if (effect.mEffectId == ESM::MagicEffect::Corprus)
{
spellParams.worsen();
applied |= ESM::ActiveEffect::Flag_Applied;
}
else
applyMagicEffect(target, caster, spellParams, effect, invalid, receivedMagicDamage, affectedHealth,
recalculateMagicka);
applied |= applyMagicEffect(
target, caster, spellParams, effect, receivedMagicDamage, affectedHealth, recalculateMagicka);
effect.mMagnitude = magnitude;
magnitudes.add(EffectKey(effect.mEffectId, effect.getSkillOrAttribute()),
EffectParam(effect.mMagnitude - oldMagnitude));
}
effect.mTimeLeft -= dt;
if (invalid)
if (applied & ESM::ActiveEffect::Flag_Invalid)
{
effect.mTimeLeft = 0;
effect.mFlags |= ESM::ActiveEffect::Flag_Remove;
auto anim = world->getAnimation(target);
if (anim)
anim->removeEffect(ESM::MagicEffect::indexToName(effect.mEffectId));
// Note that we can't return REMOVED here because the effect still needs to be detectable
}
else
effect.mFlags |= ESM::ActiveEffect::Flag_Applied | ESM::ActiveEffect::Flag_Remove;
effect.mFlags |= applied;
if (recalculateMagicka)
target.getClass().getCreatureStats(target).recalculateMagicka();
return { MagicApplicationResult::Type::APPLIED, receivedMagicDamage, affectedHealth };
@ -1116,7 +1106,6 @@ namespace MWMechanics
{
const auto world = MWBase::Environment::get().getWorld();
auto& magnitudes = target.getClass().getCreatureStats(target).getMagicEffects();
bool invalid;
switch (effect.mEffectId)
{
case ESM::MagicEffect::CommandCreature:
@ -1144,18 +1133,16 @@ namespace MWMechanics
break;
case ESM::MagicEffect::FrenzyCreature:
case ESM::MagicEffect::FrenzyHumanoid:
modifyAiSetting(
target, effect, ESM::MagicEffect::FrenzyCreature, AiSetting::Fight, -effect.mMagnitude, invalid);
modifyAiSetting(target, effect, ESM::MagicEffect::FrenzyCreature, AiSetting::Fight, -effect.mMagnitude);
break;
case ESM::MagicEffect::CalmCreature:
case ESM::MagicEffect::CalmHumanoid:
modifyAiSetting(
target, effect, ESM::MagicEffect::CalmCreature, AiSetting::Fight, effect.mMagnitude, invalid);
modifyAiSetting(target, effect, ESM::MagicEffect::CalmCreature, AiSetting::Fight, effect.mMagnitude);
break;
case ESM::MagicEffect::DemoralizeCreature:
case ESM::MagicEffect::DemoralizeHumanoid:
modifyAiSetting(
target, effect, ESM::MagicEffect::DemoralizeCreature, AiSetting::Flee, -effect.mMagnitude, invalid);
target, effect, ESM::MagicEffect::DemoralizeCreature, AiSetting::Flee, -effect.mMagnitude);
break;
case ESM::MagicEffect::NightEye:
{
@ -1174,8 +1161,7 @@ namespace MWMechanics
break;
case ESM::MagicEffect::RallyCreature:
case ESM::MagicEffect::RallyHumanoid:
modifyAiSetting(
target, effect, ESM::MagicEffect::RallyCreature, AiSetting::Flee, effect.mMagnitude, invalid);
modifyAiSetting(target, effect, ESM::MagicEffect::RallyCreature, AiSetting::Flee, effect.mMagnitude);
break;
case ESM::MagicEffect::Sound:
if (magnitudes.getOrDefault(effect.mEffectId).getModifier() <= 0.f && target == getPlayer())

View file

@ -26,7 +26,8 @@ namespace ESM
Flag_Remove = 1 << 1,
Flag_Ignore_Resistances = 1 << 2,
Flag_Ignore_Reflect = 1 << 3,
Flag_Ignore_SpellAbsorption = 1 << 4
Flag_Ignore_SpellAbsorption = 1 << 4,
Flag_Invalid = 1 << 5
};
int32_t mEffectId;