From 14b59e0e4be30b54e2a84493a34c07140ddf92fc Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 25 Mar 2017 22:40:11 +0400 Subject: [PATCH 01/11] Vanilla-like tgm (fixes #3798) --- apps/openmw/mwclass/creature.cpp | 10 +- apps/openmw/mwclass/npc.cpp | 10 +- apps/openmw/mwmechanics/actors.cpp | 5 +- apps/openmw/mwmechanics/character.cpp | 34 ++++-- apps/openmw/mwmechanics/combat.cpp | 30 +++-- apps/openmw/mwmechanics/spellcasting.cpp | 137 +++++++++++++++-------- apps/openmw/mwworld/worldimp.cpp | 16 ++- 7 files changed, 170 insertions(+), 72 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 51e0bdcce..7c2e05c77 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -323,6 +323,9 @@ namespace MWClass if (MWMechanics::blockMeleeAttack(ptr, victim, weapon, damage, attackStrength)) damage = 0; + if (victim == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState()) + damage = 0; + MWMechanics::diseaseContact(victim, ptr); victim.getClass().onHit(victim, damage, healthdmg, weapon, ptr, hitPosition, true); @@ -371,6 +374,11 @@ namespace MWClass ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1); } + bool godmode = object == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState(); + + if (godmode) + damage = 0; + if (!successful) { // Missed @@ -405,7 +413,7 @@ namespace MWClass if(ishealth) { - if (!attacker.isEmpty()) + if (!attacker.isEmpty() && !godmode) { damage = scaleDamage(damage, attacker, ptr); MWBase::Environment::get().getWorld()->spawnBloodEffect(ptr, hitPosition); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 3b7b24981..855850dfd 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -651,6 +651,9 @@ namespace MWClass if (MWMechanics::blockMeleeAttack(ptr, victim, weapon, damage, attackStrength)) damage = 0; + if (victim == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState()) + damage = 0; + MWMechanics::diseaseContact(victim, ptr); othercls.onHit(victim, damage, healthdmg, weapon, ptr, hitPosition, true); @@ -717,6 +720,11 @@ namespace MWClass if (damage < 0.001f) damage = 0; + bool godmode = ptr == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState(); + + if (godmode) + damage = 0; + if (damage > 0.0f && !attacker.isEmpty()) { // 'ptr' is losing health. Play a 'hit' voiced dialog entry if not already saying @@ -802,7 +810,7 @@ namespace MWClass if (ishealth) { - if (!attacker.isEmpty()) + if (!attacker.isEmpty() && !godmode) damage = scaleDamage(damage, attacker, ptr); if (damage > 0.0f) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 0b398a046..9c7d28fc9 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -815,7 +815,10 @@ namespace MWMechanics timeLeft = 0.0f; stats.setTimeToStartDrowning(timeLeft); } - if(timeLeft == 0.0f) + + bool godmode = ptr == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState(); + + if(timeLeft == 0.0f && !godmode) { // If drowning, apply 3 points of damage per second static const float fSuffocationDamage = world->getStore().get().find("fSuffocationDamage")->getFloat(); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index a11aa586f..e8ad0dc1f 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1574,6 +1574,8 @@ void CharacterController::update(float duration) updateMagicEffects(); + bool godmode = mPtr == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState(); + if(!cls.isActor()) updateAnimQueue(); else if(!cls.getCreatureStats(mPtr).isDead()) @@ -1691,8 +1693,12 @@ void CharacterController::update(float duration) } fatigueLoss *= duration; DynamicStat fatigue = cls.getCreatureStats(mPtr).getFatigue(); - fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss, fatigue.getCurrent() < 0); - cls.getCreatureStats(mPtr).setFatigue(fatigue); + + if (!godmode) + { + fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss, fatigue.getCurrent() < 0); + cls.getCreatureStats(mPtr).setFatigue(fatigue); + } if(sneak || inwater || flying) vec.z() = 0.0f; @@ -1748,8 +1754,12 @@ void CharacterController::update(float duration) if (normalizedEncumbrance > 1) normalizedEncumbrance = 1; const float fatigueDecrease = fatigueJumpBase + (1 - normalizedEncumbrance) * fatigueJumpMult; - fatigue.setCurrent(fatigue.getCurrent() - fatigueDecrease); - cls.getCreatureStats(mPtr).setFatigue(fatigue); + + if (!godmode) + { + fatigue.setCurrent(fatigue.getCurrent() - fatigueDecrease); + cls.getCreatureStats(mPtr).setFatigue(fatigue); + } } } else if(mJumpState == JumpState_InAir) @@ -1760,16 +1770,22 @@ void CharacterController::update(float duration) float height = cls.getCreatureStats(mPtr).land(); float healthLost = getFallDamage(mPtr, height); + + bool godmode = mPtr == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState(); + if (healthLost > 0.0f) { const float fatigueTerm = cls.getCreatureStats(mPtr).getFatigueTerm(); // inflict fall damages - DynamicStat health = cls.getCreatureStats(mPtr).getHealth(); - float realHealthLost = static_cast(healthLost * (1.0f - 0.25f * fatigueTerm)); - health.setCurrent(health.getCurrent() - realHealthLost); - cls.getCreatureStats(mPtr).setHealth(health); - cls.onHit(mPtr, realHealthLost, true, MWWorld::Ptr(), MWWorld::Ptr(), osg::Vec3f(), true); + if (!godmode) + { + DynamicStat health = cls.getCreatureStats(mPtr).getHealth(); + float realHealthLost = static_cast(healthLost * (1.0f - 0.25f * fatigueTerm)); + health.setCurrent(health.getCurrent() - realHealthLost); + cls.getCreatureStats(mPtr).setHealth(health); + cls.onHit(mPtr, realHealthLost, true, MWWorld::Ptr(), MWWorld::Ptr(), osg::Vec3f(), true); + } const int acrobaticsSkill = cls.getSkill(mPtr, ESM::Skill::Acrobatics); if (healthLost > (acrobaticsSkill * fatigueTerm)) diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index 29d1f9c7c..54ad75135 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -327,11 +327,17 @@ namespace MWMechanics { int weaphealth = weapon.getClass().getItemHealth(weapon); - const float fWeaponDamageMult = MWBase::Environment::get().getWorld()->getStore().get().find("fWeaponDamageMult")->getFloat(); - float x = std::max(1.f, fWeaponDamageMult * damage); + bool godmode = attacker == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState(); - weaphealth -= std::min(int(x), weaphealth); - weapon.getCellRef().setCharge(weaphealth); + // weapon condition does not degrade when godmode is on + if (!godmode) + { + const float fWeaponDamageMult = MWBase::Environment::get().getWorld()->getStore().get().find("fWeaponDamageMult")->getFloat(); + float x = std::max(1.f, fWeaponDamageMult * damage); + + weaphealth -= std::min(int(x), weaphealth); + weapon.getCellRef().setCharge(weaphealth); + } // Weapon broken? unequip it if (weaphealth == 0) @@ -405,11 +411,17 @@ namespace MWMechanics CreatureStats& stats = attacker.getClass().getCreatureStats(attacker); MWMechanics::DynamicStat fatigue = stats.getFatigue(); const float normalizedEncumbrance = attacker.getClass().getNormalizedEncumbrance(attacker); - float fatigueLoss = fFatigueAttackBase + normalizedEncumbrance * fFatigueAttackMult; - if (!weapon.isEmpty()) - fatigueLoss += weapon.getClass().getWeight(weapon) * attackStrength * fWeaponFatigueMult; - fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss); - stats.setFatigue(fatigue); + + bool godmode = attacker == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState(); + + if (!godmode) + { + float fatigueLoss = fFatigueAttackBase + normalizedEncumbrance * fFatigueAttackMult; + if (!weapon.isEmpty()) + fatigueLoss += weapon.getClass().getWeight(weapon) * attackStrength * fWeaponFatigueMult; + fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss); + stats.setFatigue(fatigue); + } } bool isEnvironmentCompatible(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 3d8e25ce5..5cfaccb84 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -46,11 +46,6 @@ namespace MWMechanics float getSpellSuccessChance (const ESM::Spell* spell, const MWWorld::Ptr& actor, int* effectiveSchool, bool cap) { - CreatureStats& stats = actor.getClass().getCreatureStats(actor); - - if (stats.getMagicEffects().get(ESM::MagicEffect::Silence).getMagnitude()) - return 0; - float y = std::numeric_limits::max(); float lowestSkill = 0; @@ -80,6 +75,13 @@ namespace MWMechanics } } + bool godmode = actor == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState(); + + CreatureStats& stats = actor.getClass().getCreatureStats(actor); + + if (stats.getMagicEffects().get(ESM::MagicEffect::Silence).getMagnitude()&& !godmode) + return 0; + if (spell->mData.mType == ESM::Spell::ST_Power) return stats.getSpells().canUsePower(spell) ? 100 : 0; @@ -89,6 +91,11 @@ namespace MWMechanics if (spell->mData.mFlags & ESM::Spell::F_Always) return 100; + if (godmode) + { + return 100; + } + float castBonus = -stats.getMagicEffects().get(ESM::MagicEffect::Sound).getMagnitude(); int actorWillpower = stats.getAttribute(ESM::Attribute::Willpower).getModified(); @@ -709,14 +716,19 @@ namespace MWMechanics mStack = false; + bool godmode = mCaster == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState(); + // Check if there's enough charge left if (enchantment->mData.mType == ESM::Enchantment::WhenUsed || enchantment->mData.mType == ESM::Enchantment::WhenStrikes) { - const int castCost = getEffectiveEnchantmentCastCost(static_cast(enchantment->mData.mCost), mCaster); + int castCost = getEffectiveEnchantmentCastCost(static_cast(enchantment->mData.mCost), mCaster); if (item.getCellRef().getEnchantmentCharge() == -1) item.getCellRef().setEnchantmentCharge(static_cast(enchantment->mData.mCharge)); + if (godmode) + castCost = 0; + if (item.getCellRef().getEnchantmentCharge() < castCost) { if (mCaster == getPlayer()) @@ -746,8 +758,10 @@ namespace MWMechanics if (mCaster == getPlayer()) mCaster.getClass().skillUsageSucceeded (mCaster, ESM::Skill::Enchant, 1); } - if (enchantment->mData.mType == ESM::Enchantment::CastOnce) + if (enchantment->mData.mType == ESM::Enchantment::CastOnce && !godmode) + { item.getContainerStore()->remove(item, 1, mCaster); + } else if (enchantment->mData.mType != ESM::Enchantment::WhenStrikes) { if (mCaster == getPlayer()) @@ -797,44 +811,50 @@ namespace MWMechanics int school = 0; + bool godmode = mCaster == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState(); + if (mCaster.getClass().isActor() && !mAlwaysSucceed) { school = getSpellSchool(spell, mCaster); CreatureStats& stats = mCaster.getClass().getCreatureStats(mCaster); - // Reduce fatigue (note that in the vanilla game, both GMSTs are 0, and there's no fatigue loss) - static const float fFatigueSpellBase = store.get().find("fFatigueSpellBase")->getFloat(); - static const float fFatigueSpellMult = store.get().find("fFatigueSpellMult")->getFloat(); - DynamicStat fatigue = stats.getFatigue(); - const float normalizedEncumbrance = mCaster.getClass().getNormalizedEncumbrance(mCaster); - float fatigueLoss = spell->mData.mCost * (fFatigueSpellBase + normalizedEncumbrance * fFatigueSpellMult); - fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss); stats.setFatigue(fatigue); + if (!godmode) + { + // Reduce fatigue (note that in the vanilla game, both GMSTs are 0, and there's no fatigue loss) + static const float fFatigueSpellBase = store.get().find("fFatigueSpellBase")->getFloat(); + static const float fFatigueSpellMult = store.get().find("fFatigueSpellMult")->getFloat(); + DynamicStat fatigue = stats.getFatigue(); + const float normalizedEncumbrance = mCaster.getClass().getNormalizedEncumbrance(mCaster); - bool fail = false; + float fatigueLoss = spell->mData.mCost * (fFatigueSpellBase + normalizedEncumbrance * fFatigueSpellMult); + fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss); stats.setFatigue(fatigue); - // Check success - if (!(mCaster == getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState())) - { - float successChance = getSpellSuccessChance(spell, mCaster); - if (Misc::Rng::roll0to99() >= successChance) + bool fail = false; + + // Check success + if (!(mCaster == getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState())) { - if (mCaster == getPlayer()) - MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicSkillFail}"); - fail = true; + float successChance = getSpellSuccessChance(spell, mCaster); + if (Misc::Rng::roll0to99() >= successChance) + { + if (mCaster == getPlayer()) + MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicSkillFail}"); + fail = true; + } } - } - if (fail) - { - // Failure sound - static const std::string schools[] = { - "alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration" - }; + if (fail) + { + // Failure sound + static const std::string schools[] = { + "alteration", "conjuration", "destruction", "illusion", "mysticism", "restoration" + }; - MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - sndMgr->playSound3D(mCaster, "Spell Failure " + schools[school], 1.0f, 1.0f); - return false; + MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); + sndMgr->playSound3D(mCaster, "Spell Failure " + schools[school], 1.0f, 1.0f); + return false; + } } // A power can be used once per 24h @@ -1042,6 +1062,8 @@ namespace MWMechanics bool receivedMagicDamage = false; + bool godmode = actor == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState(); + switch (effectKey.mId) { case ESM::MagicEffect::DamageAttribute: @@ -1064,21 +1086,34 @@ namespace MWMechanics adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::RestoreHealth, magnitude); break; case ESM::MagicEffect::DamageHealth: - receivedMagicDamage = true; - adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::DamageHealth, -magnitude); - break; + if (!godmode) + { + receivedMagicDamage = true; + adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::DamageHealth, -magnitude); + } case ESM::MagicEffect::DamageMagicka: case ESM::MagicEffect::DamageFatigue: - adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::DamageHealth, -magnitude); + if (!godmode) + { + adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::DamageHealth, -magnitude); + } + break; + case ESM::MagicEffect::AbsorbHealth: - if (magnitude > 0.f) - receivedMagicDamage = true; - adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::AbsorbHealth, -magnitude); - break; + if (!godmode) + { + if (magnitude > 0.f) + receivedMagicDamage = true; + adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::AbsorbHealth, -magnitude); + } case ESM::MagicEffect::AbsorbMagicka: case ESM::MagicEffect::AbsorbFatigue: - adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::AbsorbHealth, -magnitude); + if (!godmode) + { + adjustDynamicStat(creatureStats, effectKey.mId-ESM::MagicEffect::AbsorbHealth, -magnitude); + } + break; case ESM::MagicEffect::DisintegrateArmor: @@ -1123,9 +1158,13 @@ namespace MWMechanics if (weather > 1) damageScale *= fMagicSunBlockedMult; - adjustDynamicStat(creatureStats, 0, -magnitude * damageScale); - if (magnitude * damageScale > 0.f) - receivedMagicDamage = true; + if (!godmode) + { + adjustDynamicStat(creatureStats, 0, -magnitude * damageScale); + if (magnitude * damageScale > 0.f) + receivedMagicDamage = true; + } + break; } @@ -1134,8 +1173,12 @@ namespace MWMechanics case ESM::MagicEffect::FrostDamage: case ESM::MagicEffect::Poison: { - adjustDynamicStat(creatureStats, 0, -magnitude); - receivedMagicDamage = true; + if (!godmode) + { + adjustDynamicStat(creatureStats, 0, -magnitude); + receivedMagicDamage = true; + } + break; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 4270a112c..024f2b173 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2340,12 +2340,16 @@ namespace MWWorld MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor); if (stats.isDead()) continue; + + mPhysics->markAsNonSolid (object); + + if (actor == getPlayerPtr() && MWBase::Environment::get().getWorld()->getGodModeState()) + return; + MWMechanics::DynamicStat health = stats.getHealth(); health.setCurrent(health.getCurrent()-healthPerSecond*MWBase::Environment::get().getFrameDuration()); stats.setHealth(health); - mPhysics->markAsNonSolid (object); - if (healthPerSecond > 0.0f) { if (actor == getPlayerPtr()) @@ -2370,12 +2374,16 @@ namespace MWWorld MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor); if (stats.isDead()) continue; + + mPhysics->markAsNonSolid (object); + + if (actor == getPlayerPtr() && MWBase::Environment::get().getWorld()->getGodModeState()) + return; + MWMechanics::DynamicStat health = stats.getHealth(); health.setCurrent(health.getCurrent()-healthPerSecond*MWBase::Environment::get().getFrameDuration()); stats.setHealth(health); - mPhysics->markAsNonSolid (object); - if (healthPerSecond > 0.0f) { if (actor == getPlayerPtr()) From 8d4441bb5ef95bba7ed2cc7d12a7411e490107a5 Mon Sep 17 00:00:00 2001 From: Rob Cutmore Date: Sun, 26 Mar 2017 09:05:05 -0400 Subject: [PATCH 02/11] Editor: document subclasses without ID checks - Removes ID validation for PathgridCreator. - Adds comments explaining why ID validation isn't used in some cases. --- apps/opencs/view/world/infocreator.cpp | 2 ++ apps/opencs/view/world/pathgridcreator.cpp | 10 +++------- apps/opencs/view/world/pathgridcreator.hpp | 3 +-- apps/opencs/view/world/referencecreator.cpp | 2 ++ apps/opencs/view/world/startscriptcreator.cpp | 3 ++- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/opencs/view/world/infocreator.cpp b/apps/opencs/view/world/infocreator.cpp index 243b7d879..d3bc29ab7 100644 --- a/apps/opencs/view/world/infocreator.cpp +++ b/apps/opencs/view/world/infocreator.cpp @@ -48,6 +48,8 @@ CSVWorld::InfoCreator::InfoCreator (CSMWorld::Data& data, QUndoStack& undoStack, QLabel *label = new QLabel ("Topic", this); insertBeforeButtons (label, false); + // Add topic/journal ID input with auto-completion. + // Only existing topic/journal IDs are accepted so no ID validation is performed. CSMWorld::ColumnBase::Display displayType = CSMWorld::ColumnBase::Display_Topic; if (getCollectionId().getType() == CSMWorld::UniversalId::Type_JournalInfos) { diff --git a/apps/opencs/view/world/pathgridcreator.cpp b/apps/opencs/view/world/pathgridcreator.cpp index 7d2f46b91..26523f0c3 100644 --- a/apps/opencs/view/world/pathgridcreator.cpp +++ b/apps/opencs/view/world/pathgridcreator.cpp @@ -10,7 +10,6 @@ #include "../../model/world/idtable.hpp" #include "../widget/droplineedit.hpp" -#include "idvalidator.hpp" std::string CSVWorld::PathgridCreator::getId() const { @@ -28,9 +27,8 @@ CSVWorld::PathgridCreator::PathgridCreator( CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id, - CSMWorld::IdCompletionManager& completionManager, - bool relaxedIdRules -) : GenericCreator(data, undoStack, id, relaxedIdRules) + CSMWorld::IdCompletionManager& completionManager +) : GenericCreator(data, undoStack, id) { setManualEditing(false); @@ -38,10 +36,10 @@ CSVWorld::PathgridCreator::PathgridCreator( insertBeforeButtons(label, false); // Add cell ID input with auto-completion. + // Only existing cell IDs are accepted so no ID validation is performed. CSMWorld::ColumnBase::Display displayType = CSMWorld::ColumnBase::Display_Cell; mCell = new CSVWidget::DropLineEdit(displayType, this); mCell->setCompleter(completionManager.getCompleter(displayType).get()); - mCell->setValidator(new IdValidator(relaxedIdRules, this)); insertBeforeButtons(mCell, true); connect(mCell, SIGNAL (textChanged(const QString&)), this, SLOT (cellChanged())); @@ -65,8 +63,6 @@ std::string CSVWorld::PathgridCreator::getErrors() const std::string cellId = getId(); // Check user input for any errors. - // The last two checks, cell with existing pathgrid and non-existent cell, - // shouldn't be needed but we absolutely want to make sure they never happen. std::string errors; if (cellId.empty()) { diff --git a/apps/opencs/view/world/pathgridcreator.hpp b/apps/opencs/view/world/pathgridcreator.hpp index c2ae20fc0..7e82155f6 100644 --- a/apps/opencs/view/world/pathgridcreator.hpp +++ b/apps/opencs/view/world/pathgridcreator.hpp @@ -44,8 +44,7 @@ namespace CSVWorld CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id, - CSMWorld::IdCompletionManager& completionManager, - bool relaxedIdRules = false); + CSMWorld::IdCompletionManager& completionManager); /// \brief Set cell ID input widget to ID of record to be cloned. /// \param originId Cell ID to be cloned. diff --git a/apps/opencs/view/world/referencecreator.cpp b/apps/opencs/view/world/referencecreator.cpp index cc7ae545a..1363f489a 100644 --- a/apps/opencs/view/world/referencecreator.cpp +++ b/apps/opencs/view/world/referencecreator.cpp @@ -35,6 +35,8 @@ CSVWorld::ReferenceCreator::ReferenceCreator (CSMWorld::Data& data, QUndoStack& QLabel *label = new QLabel ("Cell", this); insertBeforeButtons (label, false); + // Add cell ID input with auto-completion. + // Only existing cell IDs are accepted so no ID validation is performed. mCell = new CSVWidget::DropLineEdit(CSMWorld::ColumnBase::Display_Cell, this); mCell->setCompleter(completionManager.getCompleter(CSMWorld::ColumnBase::Display_Cell).get()); insertBeforeButtons (mCell, true); diff --git a/apps/opencs/view/world/startscriptcreator.cpp b/apps/opencs/view/world/startscriptcreator.cpp index 891199027..00c485224 100644 --- a/apps/opencs/view/world/startscriptcreator.cpp +++ b/apps/opencs/view/world/startscriptcreator.cpp @@ -29,7 +29,7 @@ CSVWorld::StartScriptCreator::StartScriptCreator( QUndoStack &undoStack, const CSMWorld::UniversalId &id, CSMWorld::IdCompletionManager& completionManager -) : GenericCreator(data, undoStack, id, true) +) : GenericCreator(data, undoStack, id) { setManualEditing(false); @@ -38,6 +38,7 @@ CSVWorld::StartScriptCreator::StartScriptCreator( insertBeforeButtons(label, false); // Add script ID input with auto-completion. + // Only existing script IDs are accepted so no ID validation is performed. CSMWorld::ColumnBase::Display displayType = CSMWorld::ColumnBase::Display_Script; mScript = new CSVWidget::DropLineEdit(displayType, this); mScript->setCompleter(completionManager.getCompleter(displayType).get()); From 77bf1efc1ad9293d1dd2ce6a0dc1c453fb3eaa98 Mon Sep 17 00:00:00 2001 From: Rob Cutmore Date: Sun, 26 Mar 2017 09:14:32 -0400 Subject: [PATCH 03/11] Editor: Fix labels for creator user inputs --- apps/opencs/view/world/infocreator.cpp | 14 +++++++++----- apps/opencs/view/world/pathgridcreator.cpp | 2 +- apps/opencs/view/world/startscriptcreator.cpp | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/apps/opencs/view/world/infocreator.cpp b/apps/opencs/view/world/infocreator.cpp index d3bc29ab7..f68c69094 100644 --- a/apps/opencs/view/world/infocreator.cpp +++ b/apps/opencs/view/world/infocreator.cpp @@ -45,16 +45,20 @@ CSVWorld::InfoCreator::InfoCreator (CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id, CSMWorld::IdCompletionManager& completionManager) : GenericCreator (data, undoStack, id) { - QLabel *label = new QLabel ("Topic", this); - insertBeforeButtons (label, false); - - // Add topic/journal ID input with auto-completion. - // Only existing topic/journal IDs are accepted so no ID validation is performed. + // Determine if we're dealing with topics or journals. CSMWorld::ColumnBase::Display displayType = CSMWorld::ColumnBase::Display_Topic; + QString labelText = "Topic"; if (getCollectionId().getType() == CSMWorld::UniversalId::Type_JournalInfos) { displayType = CSMWorld::ColumnBase::Display_Journal; + labelText = "Journal"; } + + QLabel *label = new QLabel (labelText, this); + insertBeforeButtons (label, false); + + // Add topic/journal ID input with auto-completion. + // Only existing topic/journal IDs are accepted so no ID validation is performed. mTopic = new CSVWidget::DropLineEdit(displayType, this); mTopic->setCompleter(completionManager.getCompleter(displayType).get()); insertBeforeButtons (mTopic, true); diff --git a/apps/opencs/view/world/pathgridcreator.cpp b/apps/opencs/view/world/pathgridcreator.cpp index 26523f0c3..95628a5d9 100644 --- a/apps/opencs/view/world/pathgridcreator.cpp +++ b/apps/opencs/view/world/pathgridcreator.cpp @@ -32,7 +32,7 @@ CSVWorld::PathgridCreator::PathgridCreator( { setManualEditing(false); - QLabel *label = new QLabel("Cell ID", this); + QLabel *label = new QLabel("Cell", this); insertBeforeButtons(label, false); // Add cell ID input with auto-completion. diff --git a/apps/opencs/view/world/startscriptcreator.cpp b/apps/opencs/view/world/startscriptcreator.cpp index 00c485224..0eb6bae40 100644 --- a/apps/opencs/view/world/startscriptcreator.cpp +++ b/apps/opencs/view/world/startscriptcreator.cpp @@ -34,7 +34,7 @@ CSVWorld::StartScriptCreator::StartScriptCreator( setManualEditing(false); // Add script ID input label. - QLabel *label = new QLabel("Script ID", this); + QLabel *label = new QLabel("Script", this); insertBeforeButtons(label, false); // Add script ID input with auto-completion. From 343f2cb81db77de82f27ee1ac93923d1d58c7066 Mon Sep 17 00:00:00 2001 From: Rob Cutmore Date: Thu, 30 Mar 2017 08:20:43 -0400 Subject: [PATCH 04/11] Editor: add creator for body parts Added creator subclass for body parts to allow adding first person parts. IDs for first person body parts are expected to end with ".1st". --- apps/opencs/CMakeLists.txt | 1 + apps/opencs/view/world/bodypartcreator.cpp | 54 ++++++++++++++++++++++ apps/opencs/view/world/bodypartcreator.hpp | 47 +++++++++++++++++++ apps/opencs/view/world/subviews.cpp | 9 +++- 4 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 apps/opencs/view/world/bodypartcreator.cpp create mode 100644 apps/opencs/view/world/bodypartcreator.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index e7e19be94..8a3d3c1c8 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -70,6 +70,7 @@ opencs_units (view/world cellcreator pathgridcreator referenceablecreator startscriptcreator referencecreator scenesubview infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable dialoguespinbox recordbuttonbar tableeditidaction scripterrortable extendedcommandconfigurator + bodypartcreator ) opencs_units_noqt (view/world diff --git a/apps/opencs/view/world/bodypartcreator.cpp b/apps/opencs/view/world/bodypartcreator.cpp new file mode 100644 index 000000000..a9fc3e063 --- /dev/null +++ b/apps/opencs/view/world/bodypartcreator.cpp @@ -0,0 +1,54 @@ +#include "bodypartcreator.hpp" + +#include + +#include "../../model/world/data.hpp" +#include "../../model/world/universalid.hpp" + +std::string CSVWorld::BodyPartCreator::getId() const +{ + std::string id = CSVWorld::GenericCreator::getId(); + + if (mFirstPerson->isChecked()) + { + id += ".1st"; + } + + return id; +} + +CSVWorld::BodyPartCreator::BodyPartCreator( + CSMWorld::Data& data, + QUndoStack& undoStack, + const CSMWorld::UniversalId& id +) : GenericCreator(data, undoStack, id) +{ + mFirstPerson = new QCheckBox("First Person", this); + insertBeforeButtons(mFirstPerson, false); + + connect(mFirstPerson, SIGNAL(clicked(bool)), this, SLOT(checkboxClicked())); +} + +std::string CSVWorld::BodyPartCreator::getErrors() const +{ + std::string errors; + + std::string id = getId(); + if (getData().hasId(id)) + { + errors = "ID is already in use"; + } + + return errors; +} + +void CSVWorld::BodyPartCreator::reset() +{ + CSVWorld::GenericCreator::reset(); + mFirstPerson->setChecked(false); +} + +void CSVWorld::BodyPartCreator::checkboxClicked() +{ + update(); +} diff --git a/apps/opencs/view/world/bodypartcreator.hpp b/apps/opencs/view/world/bodypartcreator.hpp new file mode 100644 index 000000000..3c27136dd --- /dev/null +++ b/apps/opencs/view/world/bodypartcreator.hpp @@ -0,0 +1,47 @@ +#ifndef BODYPARTCREATOR_HPP +#define BODYPARTCREATOR_HPP + +class QCheckBox; + +#include "genericcreator.hpp" + +namespace CSMWorld +{ + class Data; + class UniversalId; +} + +namespace CSVWorld +{ + /// \brief Record creator for body parts. + class BodyPartCreator : public GenericCreator + { + Q_OBJECT + + QCheckBox *mFirstPerson; + + private: + + /// \return ID entered by user. + virtual std::string getId() const; + + public: + + BodyPartCreator( + CSMWorld::Data& data, + QUndoStack& undoStack, + const CSMWorld::UniversalId& id); + + /// \return Error description for current user input. + virtual std::string getErrors() const; + + /// \brief Clear ID and checkbox input widgets. + virtual void reset(); + + private slots: + + void checkboxClicked(); + }; +} + +#endif // BODYPARTCREATOR_HPP diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 93e105106..7c27bdf7a 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -17,6 +17,7 @@ #include "infocreator.hpp" #include "pathgridcreator.hpp" #include "previewsubview.hpp" +#include "bodypartcreator.hpp" void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) { @@ -41,7 +42,6 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Birthsigns, CSMWorld::UniversalId::Type_Spells, CSMWorld::UniversalId::Type_Enchantments, - CSMWorld::UniversalId::Type_BodyParts, CSMWorld::UniversalId::Type_SoundGens, CSMWorld::UniversalId::Type_None // end marker @@ -51,6 +51,9 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) manager.add (sTableTypes[i], new CSVDoc::SubViewFactoryWithCreator >); + manager.add (CSMWorld::UniversalId::Type_BodyParts, + new CSVDoc::SubViewFactoryWithCreator >); + manager.add (CSMWorld::UniversalId::Type_StartScripts, new CSVDoc::SubViewFactoryWithCreator); @@ -129,7 +132,6 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Sound, CSMWorld::UniversalId::Type_Faction, CSMWorld::UniversalId::Type_Enchantment, - CSMWorld::UniversalId::Type_BodyPart, CSMWorld::UniversalId::Type_SoundGen, CSMWorld::UniversalId::Type_None // end marker @@ -140,6 +142,9 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) new CSVDoc::SubViewFactoryWithCreator > (false)); + manager.add (CSMWorld::UniversalId::Type_BodyPart, + new CSVDoc::SubViewFactoryWithCreator > (false)); + manager.add (CSMWorld::UniversalId::Type_StartScript, new CSVDoc::SubViewFactoryWithCreator(false)); From 31bd70f3345e533ae4e0c7da9b5f685427f638bd Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sun, 2 Apr 2017 23:19:43 +0400 Subject: [PATCH 05/11] Added missed recharge and repair sounds --- apps/openmw/mwgui/recharge.cpp | 7 +++++++ apps/openmw/mwgui/repair.cpp | 3 +++ apps/openmw/mwmechanics/repair.cpp | 3 +++ 3 files changed, 13 insertions(+) diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 990e4468b..afca12ad9 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -12,6 +12,7 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/soundmanager.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" @@ -137,10 +138,16 @@ void Recharge::onItemClicked(MyGUI::Widget *sender, const MWWorld::Ptr& item) item.getCellRef().setEnchantmentCharge( std::min(item.getCellRef().getEnchantmentCharge() + restored, static_cast(enchantment->mData.mCharge))); + MWBase::Environment::get().getSoundManager()->playSound("Enchant Success",1,1); + player.getClass().getContainerStore(player).restack(item); player.getClass().skillUsageSucceeded (player, ESM::Skill::Enchant, 0); } + else + { + MWBase::Environment::get().getSoundManager()->playSound("Enchant Fail",1,1); + } gem.getContainerStore()->remove(gem, 1, player); diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index 15a4a64d7..3acea985b 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -11,6 +11,7 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/soundmanager.hpp" #include "../mwmechanics/actorutil.hpp" @@ -62,6 +63,8 @@ void Repair::exit() void Repair::startRepairItem(const MWWorld::Ptr &item) { + MWBase::Environment::get().getSoundManager()->playSound("Item Repair Up",1,1); + mRepair.setTool(item); mToolIcon->setItem(item); diff --git a/apps/openmw/mwmechanics/repair.cpp b/apps/openmw/mwmechanics/repair.cpp index 9b48f5fcb..a1c79ea23 100644 --- a/apps/openmw/mwmechanics/repair.cpp +++ b/apps/openmw/mwmechanics/repair.cpp @@ -99,6 +99,9 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair) if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), mTool.getCellRef().getRefId())) { mTool = *iter; + + MWBase::Environment::get().getSoundManager()->playSound("Item Repair Up",1,1); + break; } } From 395e97cf408d67d2fda5b3bd278ac25b6a1cd60e Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Mon, 3 Apr 2017 01:44:26 +0200 Subject: [PATCH 06/11] Remove evil "implicit GetJournalIndex" hack from expression parser --- components/compiler/exprparser.cpp | 16 ---------------- files/openmw.cfg | 3 +++ files/openmw.cfg.local | 3 +++ 3 files changed, 6 insertions(+), 16 deletions(-) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 0c8220e97..7cb0abfd1 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -311,22 +311,6 @@ namespace Compiler return true; } - // die in a fire, Morrowind script compiler! - if (const Extensions *extensions = getContext().getExtensions()) - { - if (getContext().isJournalId (name2)) - { - // JournalID used as an argument. Use the index of that JournalID - Generator::pushString (mCode, mLiterals, name2); - int keyword = extensions->searchKeyword ("getjournalindex"); - extensions->generateFunctionCode (keyword, mCode, mLiterals, mExplicit, 0); - mNextOperand = false; - mOperands.push_back ('l'); - - return true; - } - } - if (mExplicit.empty() && getContext().isId (name2)) { mExplicit = name2; diff --git a/files/openmw.cfg b/files/openmw.cfg index 199e09403..7a87bdc11 100644 --- a/files/openmw.cfg +++ b/files/openmw.cfg @@ -8,3 +8,6 @@ resources=${OPENMW_RESOURCE_FILES} script-blacklist=Museum script-blacklist=MockChangeScript script-blacklist=doortestwarp +script-blacklist=WereChange2Script +script-blacklist=wereDreamScript2 +script-blacklist=wereDreamScript3 diff --git a/files/openmw.cfg.local b/files/openmw.cfg.local index 0640ec843..e7de92e84 100644 --- a/files/openmw.cfg.local +++ b/files/openmw.cfg.local @@ -9,3 +9,6 @@ resources=./resources script-blacklist=Museum script-blacklist=MockChangeScript script-blacklist=doortestwarp +script-blacklist=WereChange2Script +script-blacklist=wereDreamScript2 +script-blacklist=wereDreamScript3 From 785b3c3d01b0d18e8fa348a08a5819ce0fb452e9 Mon Sep 17 00:00:00 2001 From: def Date: Mon, 3 Apr 2017 09:02:05 +0300 Subject: [PATCH 07/11] Hide WorldButton when in game mode --- apps/openmw/mwgui/mapwindow.cpp | 6 ++++++ apps/openmw/mwgui/mapwindow.hpp | 1 + 2 files changed, 7 insertions(+) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 8002dc48a..5c7e73862 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -774,6 +774,12 @@ namespace MWGui mLastScrollWindowCoordinates = currentCoordinates; } + void MapWindow::setVisible(bool visible) + { + WindowBase::setVisible(visible); + mButton->setVisible(visible && MWBase::Environment::get().getWindowManager()->isGuiMode()); + } + void MapWindow::renderGlobalMap() { mGlobalMapRender->render(); diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index a0136b1c7..4e648c4b7 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -204,6 +204,7 @@ namespace MWGui void setCellName(const std::string& cellName); virtual void setAlpha(float alpha); + void setVisible(bool visible); void renderGlobalMap(); From f7664d4bb95c287399cf62cdfc66eaecb997ef1e Mon Sep 17 00:00:00 2001 From: Rob Cutmore Date: Tue, 4 Apr 2017 18:54:58 -0400 Subject: [PATCH 08/11] Editor: reset camera after cell drag and drop When replacing a viewed cell via drag and drop the camera position is not updated to better view the new cell. This flags the camera position as not being set so a better default is set. --- apps/opencs/view/render/unpagedworldspacewidget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index de999db0f..28e269ded 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -92,6 +92,7 @@ bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vectorgetId(); mCell.reset (new Cell (getDocument().getData(), mRootNode, mCellId)); + mCamPositionSet = false; update(); emit cellChanged(*universalIdData.begin()); From 84bad9316d9b49c8f29dcc9c1d655c3fe6ac19a2 Mon Sep 17 00:00:00 2001 From: Rob Cutmore Date: Thu, 6 Apr 2017 19:40:26 -0400 Subject: [PATCH 09/11] Editor: flag orbit camera for re-initialization After swapping cells the orbit cam controller needs to be re-initialized to properly center on the new cell. --- apps/opencs/view/render/cameracontroller.cpp | 5 +++++ apps/opencs/view/render/cameracontroller.hpp | 3 +++ apps/opencs/view/render/unpagedworldspacewidget.cpp | 2 ++ 3 files changed, 10 insertions(+) diff --git a/apps/opencs/view/render/cameracontroller.cpp b/apps/opencs/view/render/cameracontroller.cpp index 7e3570657..288e2da07 100644 --- a/apps/opencs/view/render/cameracontroller.cpp +++ b/apps/opencs/view/render/cameracontroller.cpp @@ -632,6 +632,11 @@ namespace CSVRender getCamera()->getViewMatrix().orthoNormal(getCamera()->getViewMatrix()); } + void OrbitCameraController::reset() + { + mInitialized = false; + } + void OrbitCameraController::onActivate() { mInitialized = false; diff --git a/apps/opencs/view/render/cameracontroller.hpp b/apps/opencs/view/render/cameracontroller.hpp index 97af85790..f15cec231 100644 --- a/apps/opencs/view/render/cameracontroller.hpp +++ b/apps/opencs/view/render/cameracontroller.hpp @@ -159,6 +159,9 @@ namespace CSVRender void update(double dt); + /// \brief Flag controller to be re-initialized. + void reset(); + private: void onActivate(); diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 28e269ded..b82aa45b2 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -15,6 +15,7 @@ #include "../widget/scenetooltoggle.hpp" #include "../widget/scenetooltoggle2.hpp" +#include "cameracontroller.hpp" #include "mask.hpp" #include "tagbase.hpp" @@ -93,6 +94,7 @@ bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vectorreset(); update(); emit cellChanged(*universalIdData.begin()); From 0ff56677f6f93898569f2657291e61efb0fa3525 Mon Sep 17 00:00:00 2001 From: Rob Cutmore Date: Thu, 6 Apr 2017 19:56:18 -0400 Subject: [PATCH 10/11] Remove unused code --- apps/opencs/view/render/cameracontroller.cpp | 5 ----- apps/opencs/view/render/cameracontroller.hpp | 4 ---- 2 files changed, 9 deletions(-) diff --git a/apps/opencs/view/render/cameracontroller.cpp b/apps/opencs/view/render/cameracontroller.cpp index 288e2da07..7b802b0ef 100644 --- a/apps/opencs/view/render/cameracontroller.cpp +++ b/apps/opencs/view/render/cameracontroller.cpp @@ -637,11 +637,6 @@ namespace CSVRender mInitialized = false; } - void OrbitCameraController::onActivate() - { - mInitialized = false; - } - void OrbitCameraController::initialize() { static const int DefaultStartDistance = 10000.f; diff --git a/apps/opencs/view/render/cameracontroller.hpp b/apps/opencs/view/render/cameracontroller.hpp index f15cec231..a2ebba51a 100644 --- a/apps/opencs/view/render/cameracontroller.hpp +++ b/apps/opencs/view/render/cameracontroller.hpp @@ -63,8 +63,6 @@ namespace CSVRender protected: - virtual void onActivate(){} - void addShortcut(CSMPrefs::Shortcut* shortcut); private: @@ -164,8 +162,6 @@ namespace CSVRender private: - void onActivate(); - void initialize(); void rotateHorizontal(double value); From c962b6dd6d2f8a136096109378ea49045c50a866 Mon Sep 17 00:00:00 2001 From: MiroslavR Date: Sun, 9 Apr 2017 18:31:46 +0200 Subject: [PATCH 11/11] Fix correctActorModelPath to work properly when both backward and forward slashes are used in the path (Fixes #3822) --- components/misc/resourcehelpers.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/components/misc/resourcehelpers.cpp b/components/misc/resourcehelpers.cpp index 6fe13abf3..5cf4378b8 100644 --- a/components/misc/resourcehelpers.cpp +++ b/components/misc/resourcehelpers.cpp @@ -127,9 +127,7 @@ std::string Misc::ResourceHelpers::correctBookartPath(const std::string &resPath std::string Misc::ResourceHelpers::correctActorModelPath(const std::string &resPath, const VFS::Manager* vfs) { std::string mdlname = resPath; - std::string::size_type p = mdlname.rfind('\\'); - if(p == std::string::npos) - p = mdlname.rfind('/'); + std::string::size_type p = mdlname.find_last_of("/\\"); if(p != std::string::npos) mdlname.insert(mdlname.begin()+p+1, 'x'); else