1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-29 09:45:34 +00:00

Merge branch 'ondeath' into 'master'

Handle running stats extensions on non-actors gracefully (#7770)

Closes #7770

See merge request OpenMW/openmw!3760
This commit is contained in:
psi29a 2024-01-12 07:55:49 +00:00
commit 53e3dd0a70
2 changed files with 120 additions and 24 deletions

View file

@ -128,6 +128,7 @@
Bug #7742: Governing attribute training limit should use the modified attribute Bug #7742: Governing attribute training limit should use the modified attribute
Bug #7758: Water walking is not taken into account to compute path cost on the water Bug #7758: Water walking is not taken into account to compute path cost on the water
Bug #7761: Rain and ambient loop sounds are mutually exclusive Bug #7761: Rain and ambient loop sounds are mutually exclusive
Bug #7770: Sword of the Perithia: Script execution failure
Feature #2566: Handle NAM9 records for manual cell references Feature #2566: Handle NAM9 records for manual cell references
Feature #3537: Shader-based water ripples Feature #3537: Shader-based water ripples
Feature #5173: Support for NiFogProperty Feature #5173: Support for NiFogProperty

View file

@ -85,7 +85,9 @@ namespace MWScript
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Integer value = ptr.getClass().getCreatureStats(ptr).getLevel(); Interpreter::Type_Integer value = -1;
if (ptr.getClass().isActor())
value = ptr.getClass().getCreatureStats(ptr).getLevel();
runtime.push(value); runtime.push(value);
} }
@ -102,6 +104,7 @@ namespace MWScript
Interpreter::Type_Integer value = runtime[0].mInteger; Interpreter::Type_Integer value = runtime[0].mInteger;
runtime.pop(); runtime.pop();
if (ptr.getClass().isActor())
ptr.getClass().getCreatureStats(ptr).setLevel(value); ptr.getClass().getCreatureStats(ptr).setLevel(value);
} }
}; };
@ -121,7 +124,9 @@ namespace MWScript
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Float value = ptr.getClass().getCreatureStats(ptr).getAttribute(mIndex).getModified(); Interpreter::Type_Float value = 0.f;
if (ptr.getClass().isActor())
value = ptr.getClass().getCreatureStats(ptr).getAttribute(mIndex).getModified();
runtime.push(value); runtime.push(value);
} }
@ -145,6 +150,9 @@ namespace MWScript
Interpreter::Type_Float value = runtime[0].mFloat; Interpreter::Type_Float value = runtime[0].mFloat;
runtime.pop(); runtime.pop();
if (!ptr.getClass().isActor())
return;
MWMechanics::AttributeValue attribute = ptr.getClass().getCreatureStats(ptr).getAttribute(mIndex); MWMechanics::AttributeValue attribute = ptr.getClass().getCreatureStats(ptr).getAttribute(mIndex);
attribute.setBase(value, true); attribute.setBase(value, true);
ptr.getClass().getCreatureStats(ptr).setAttribute(mIndex, attribute); ptr.getClass().getCreatureStats(ptr).setAttribute(mIndex, attribute);
@ -169,6 +177,9 @@ namespace MWScript
Interpreter::Type_Float value = runtime[0].mFloat; Interpreter::Type_Float value = runtime[0].mFloat;
runtime.pop(); runtime.pop();
if (!ptr.getClass().isActor())
return;
MWMechanics::AttributeValue attribute = ptr.getClass().getCreatureStats(ptr).getAttribute(mIndex); MWMechanics::AttributeValue attribute = ptr.getClass().getCreatureStats(ptr).getAttribute(mIndex);
modStat(attribute, value); modStat(attribute, value);
ptr.getClass().getCreatureStats(ptr).setAttribute(mIndex, attribute); ptr.getClass().getCreatureStats(ptr).setAttribute(mIndex, attribute);
@ -189,14 +200,14 @@ namespace MWScript
void execute(Interpreter::Runtime& runtime) override void execute(Interpreter::Runtime& runtime) override
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Float value; Interpreter::Type_Float value = 0.f;
if (mIndex == 0 && ptr.getClass().hasItemHealth(ptr)) if (mIndex == 0 && ptr.getClass().hasItemHealth(ptr))
{ {
// health is a special case // health is a special case
value = static_cast<Interpreter::Type_Float>(ptr.getClass().getItemMaxHealth(ptr)); value = static_cast<Interpreter::Type_Float>(ptr.getClass().getItemMaxHealth(ptr));
} }
else else if (ptr.getClass().isActor())
{ {
value = ptr.getClass().getCreatureStats(ptr).getDynamic(mIndex).getCurrent(); value = ptr.getClass().getCreatureStats(ptr).getDynamic(mIndex).getCurrent();
// GetMagicka shouldn't return negative values // GetMagicka shouldn't return negative values
@ -225,6 +236,9 @@ namespace MWScript
Interpreter::Type_Float value = runtime[0].mFloat; Interpreter::Type_Float value = runtime[0].mFloat;
runtime.pop(); runtime.pop();
if (!ptr.getClass().isActor())
return;
MWMechanics::DynamicStat<float> stat(ptr.getClass().getCreatureStats(ptr).getDynamic(mIndex)); MWMechanics::DynamicStat<float> stat(ptr.getClass().getCreatureStats(ptr).getDynamic(mIndex));
stat.setBase(value); stat.setBase(value);
@ -254,6 +268,9 @@ namespace MWScript
Interpreter::Type_Float diff = runtime[0].mFloat; Interpreter::Type_Float diff = runtime[0].mFloat;
runtime.pop(); runtime.pop();
if (!ptr.getClass().isActor())
return;
// workaround broken endgame scripts that kill dagoth ur // workaround broken endgame scripts that kill dagoth ur
if (!R::implicit && ptr.getCellRef().getRefId() == "dagoth_ur_1") if (!R::implicit && ptr.getCellRef().getRefId() == "dagoth_ur_1")
{ {
@ -301,6 +318,9 @@ namespace MWScript
Interpreter::Type_Float diff = runtime[0].mFloat; Interpreter::Type_Float diff = runtime[0].mFloat;
runtime.pop(); runtime.pop();
if (!ptr.getClass().isActor())
return;
MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr); MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
Interpreter::Type_Float current = stats.getDynamic(mIndex).getCurrent(); Interpreter::Type_Float current = stats.getDynamic(mIndex).getCurrent();
@ -336,6 +356,13 @@ namespace MWScript
void execute(Interpreter::Runtime& runtime) override void execute(Interpreter::Runtime& runtime) override
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
if (!ptr.getClass().isActor())
{
runtime.push(0.f);
return;
}
const MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr); const MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
runtime.push(stats.getDynamic(mIndex).getRatio()); runtime.push(stats.getDynamic(mIndex).getRatio());
@ -357,6 +384,12 @@ namespace MWScript
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
if (!ptr.getClass().isActor())
{
runtime.push(0.f);
return;
}
Interpreter::Type_Float value = ptr.getClass().getSkill(ptr, mId); Interpreter::Type_Float value = ptr.getClass().getSkill(ptr, mId);
runtime.push(value); runtime.push(value);
@ -381,6 +414,9 @@ namespace MWScript
Interpreter::Type_Float value = runtime[0].mFloat; Interpreter::Type_Float value = runtime[0].mFloat;
runtime.pop(); runtime.pop();
if (!ptr.getClass().isNpc())
return;
MWMechanics::NpcStats& stats = ptr.getClass().getNpcStats(ptr); MWMechanics::NpcStats& stats = ptr.getClass().getNpcStats(ptr);
stats.getSkill(mId).setBase(value, true); stats.getSkill(mId).setBase(value, true);
@ -405,6 +441,9 @@ namespace MWScript
Interpreter::Type_Float value = runtime[0].mFloat; Interpreter::Type_Float value = runtime[0].mFloat;
runtime.pop(); runtime.pop();
if (!ptr.getClass().isNpc())
return;
MWMechanics::SkillValue& skill = ptr.getClass().getNpcStats(ptr).getSkill(mId); MWMechanics::SkillValue& skill = ptr.getClass().getNpcStats(ptr).getSkill(mId);
modStat(skill, value); modStat(skill, value);
} }
@ -465,6 +504,9 @@ namespace MWScript
ESM::RefId id = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger)); ESM::RefId id = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger));
runtime.pop(); runtime.pop();
if (!ptr.getClass().isActor())
return;
const ESM::Spell* spell = MWBase::Environment::get().getESMStore()->get<ESM::Spell>().find(id); const ESM::Spell* spell = MWBase::Environment::get().getESMStore()->get<ESM::Spell>().find(id);
MWMechanics::CreatureStats& creatureStats = ptr.getClass().getCreatureStats(ptr); MWMechanics::CreatureStats& creatureStats = ptr.getClass().getCreatureStats(ptr);
@ -491,6 +533,9 @@ namespace MWScript
ESM::RefId id = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger)); ESM::RefId id = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger));
runtime.pop(); runtime.pop();
if (!ptr.getClass().isActor())
return;
MWMechanics::CreatureStats& creatureStats = ptr.getClass().getCreatureStats(ptr); MWMechanics::CreatureStats& creatureStats = ptr.getClass().getCreatureStats(ptr);
creatureStats.getSpells().remove(id); creatureStats.getSpells().remove(id);
@ -514,6 +559,7 @@ namespace MWScript
ESM::RefId spellid = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger)); ESM::RefId spellid = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger));
runtime.pop(); runtime.pop();
if (ptr.getClass().isActor())
ptr.getClass().getCreatureStats(ptr).getActiveSpells().removeEffects(ptr, spellid); ptr.getClass().getCreatureStats(ptr).getActiveSpells().removeEffects(ptr, spellid);
} }
}; };
@ -529,6 +575,7 @@ namespace MWScript
Interpreter::Type_Integer effectId = runtime[0].mInteger; Interpreter::Type_Integer effectId = runtime[0].mInteger;
runtime.pop(); runtime.pop();
if (ptr.getClass().isActor())
ptr.getClass().getCreatureStats(ptr).getActiveSpells().purgeEffect(ptr, effectId); ptr.getClass().getCreatureStats(ptr).getActiveSpells().purgeEffect(ptr, effectId);
} }
}; };
@ -845,7 +892,10 @@ namespace MWScript
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
if (ptr.getClass().isActor())
runtime.push(ptr.getClass().getCreatureStats(ptr).hasCommonDisease()); runtime.push(ptr.getClass().getCreatureStats(ptr).hasCommonDisease());
else
runtime.push(0);
} }
}; };
@ -857,7 +907,10 @@ namespace MWScript
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
if (ptr.getClass().isActor())
runtime.push(ptr.getClass().getCreatureStats(ptr).hasBlightDisease()); runtime.push(ptr.getClass().getCreatureStats(ptr).hasBlightDisease());
else
runtime.push(0);
} }
}; };
@ -872,10 +925,17 @@ namespace MWScript
ESM::RefId race = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger)); ESM::RefId race = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger));
runtime.pop(); runtime.pop();
if (ptr.getClass().isNpc())
{
const ESM::RefId& npcRace = ptr.get<ESM::NPC>()->mBase->mRace; const ESM::RefId& npcRace = ptr.get<ESM::NPC>()->mBase->mRace;
runtime.push(race == npcRace); runtime.push(race == npcRace);
} }
else
{
runtime.push(0);
}
}
}; };
class OpGetWerewolfKills : public Interpreter::Opcode0 class OpGetWerewolfKills : public Interpreter::Opcode0
@ -1043,10 +1103,15 @@ namespace MWScript
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Integer value = ptr.getClass().getCreatureStats(ptr).hasDied(); Interpreter::Type_Integer value = 0;
if (ptr.getClass().isActor())
{
auto& stats = ptr.getClass().getCreatureStats(ptr);
value = stats.hasDied();
if (value) if (value)
ptr.getClass().getCreatureStats(ptr).clearHasDied(); stats.clearHasDied();
}
runtime.push(value); runtime.push(value);
} }
@ -1060,10 +1125,15 @@ namespace MWScript
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Integer value = ptr.getClass().getCreatureStats(ptr).hasBeenMurdered(); Interpreter::Type_Integer value = 0;
if (ptr.getClass().isActor())
{
auto& stats = ptr.getClass().getCreatureStats(ptr);
value = stats.hasBeenMurdered();
if (value) if (value)
ptr.getClass().getCreatureStats(ptr).clearHasBeenMurdered(); stats.clearHasBeenMurdered();
}
runtime.push(value); runtime.push(value);
} }
@ -1077,7 +1147,9 @@ namespace MWScript
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Integer value = ptr.getClass().getCreatureStats(ptr).getKnockedDownOneFrame(); Interpreter::Type_Integer value = 0;
if (ptr.getClass().isActor())
value = ptr.getClass().getCreatureStats(ptr).getKnockedDownOneFrame();
runtime.push(value); runtime.push(value);
} }
@ -1090,7 +1162,10 @@ namespace MWScript
void execute(Interpreter::Runtime& runtime) override void execute(Interpreter::Runtime& runtime) override
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
if (ptr.getClass().isNpc())
runtime.push(ptr.getClass().getNpcStats(ptr).isWerewolf()); runtime.push(ptr.getClass().getNpcStats(ptr).isWerewolf());
else
runtime.push(0);
} }
}; };
@ -1101,6 +1176,7 @@ namespace MWScript
void execute(Interpreter::Runtime& runtime) override void execute(Interpreter::Runtime& runtime) override
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
if (ptr.getClass().isNpc())
MWBase::Environment::get().getMechanicsManager()->setWerewolf(ptr, set); MWBase::Environment::get().getMechanicsManager()->setWerewolf(ptr, set);
} }
}; };
@ -1112,6 +1188,7 @@ namespace MWScript
void execute(Interpreter::Runtime& runtime) override void execute(Interpreter::Runtime& runtime) override
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
if (ptr.getClass().isNpc())
MWBase::Environment::get().getMechanicsManager()->applyWerewolfAcrobatics(ptr); MWBase::Environment::get().getMechanicsManager()->applyWerewolfAcrobatics(ptr);
} }
}; };
@ -1124,6 +1201,9 @@ namespace MWScript
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
if (!ptr.getClass().isActor())
return;
if (ptr == MWMechanics::getPlayer()) if (ptr == MWMechanics::getPlayer())
{ {
MWBase::Environment::get().getMechanicsManager()->resurrect(ptr); MWBase::Environment::get().getMechanicsManager()->resurrect(ptr);
@ -1192,6 +1272,12 @@ namespace MWScript
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
if (!ptr.getClass().isActor())
{
runtime.push(0);
return;
}
const MWMechanics::MagicEffects& effects = ptr.getClass().getCreatureStats(ptr).getMagicEffects(); const MWMechanics::MagicEffects& effects = ptr.getClass().getCreatureStats(ptr).getMagicEffects();
float currentValue = effects.getOrDefault(mPositiveEffect).getMagnitude(); float currentValue = effects.getOrDefault(mPositiveEffect).getMagnitude();
if (mNegativeEffect != -1) if (mNegativeEffect != -1)
@ -1226,6 +1312,13 @@ namespace MWScript
void execute(Interpreter::Runtime& runtime) override void execute(Interpreter::Runtime& runtime) override
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
int arg = runtime[0].mInteger;
runtime.pop();
if (!ptr.getClass().isActor())
return;
MWMechanics::MagicEffects& effects = ptr.getClass().getCreatureStats(ptr).getMagicEffects(); MWMechanics::MagicEffects& effects = ptr.getClass().getCreatureStats(ptr).getMagicEffects();
float currentValue = effects.getOrDefault(mPositiveEffect).getMagnitude(); float currentValue = effects.getOrDefault(mPositiveEffect).getMagnitude();
if (mNegativeEffect != -1) if (mNegativeEffect != -1)
@ -1239,8 +1332,6 @@ namespace MWScript
if (mPositiveEffect == ESM::MagicEffect::ResistFrost) if (mPositiveEffect == ESM::MagicEffect::ResistFrost)
currentValue += effects.getOrDefault(ESM::MagicEffect::FrostShield).getMagnitude(); currentValue += effects.getOrDefault(ESM::MagicEffect::FrostShield).getMagnitude();
int arg = runtime[0].mInteger;
runtime.pop();
effects.modifyBase(mPositiveEffect, (arg - static_cast<int>(currentValue))); effects.modifyBase(mPositiveEffect, (arg - static_cast<int>(currentValue)));
} }
}; };
@ -1261,10 +1352,14 @@ namespace MWScript
void execute(Interpreter::Runtime& runtime) override void execute(Interpreter::Runtime& runtime) override
{ {
MWWorld::Ptr ptr = R()(runtime); MWWorld::Ptr ptr = R()(runtime);
MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
int arg = runtime[0].mInteger; int arg = runtime[0].mInteger;
runtime.pop(); runtime.pop();
if (!ptr.getClass().isActor())
return;
MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
stats.getMagicEffects().modifyBase(mPositiveEffect, arg); stats.getMagicEffects().modifyBase(mPositiveEffect, arg);
} }
}; };