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