mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-30 03:15:32 +00:00
Merge branch 'master' into automove
This commit is contained in:
commit
cd97d0c61c
94 changed files with 1034 additions and 759 deletions
|
@ -5,6 +5,7 @@
|
|||
Bug #2311: Targeted scripts are not properly supported on non-unique RefIDs
|
||||
Bug #3676: NiParticleColorModifier isn't applied properly
|
||||
Bug #3714: Savegame fails to load due to conflict between SpellState and MagicEffects
|
||||
Bug #4021: Attributes and skills are not stored as floats
|
||||
Bug #4623: Corprus implementation is incorrect
|
||||
Bug #4774: Guards are ignorant of an invisible player that tries to attack them
|
||||
Bug #5108: Savegame bloating due to inefficient fog textures format
|
||||
|
@ -25,6 +26,7 @@
|
|||
Bug #5427: GetDistance unknown ID error is misleading
|
||||
Bug #5435: Enemies can't hurt the player when collision is off
|
||||
Bug #5441: Enemies can't push a player character when in critical strike stance
|
||||
Bug #5451: Magic projectiles don't disappear with the caster
|
||||
Bug #5452: Autowalk is being included in savegames
|
||||
Feature #5362: Show the soul gems' trapped soul in count dialog
|
||||
Feature #5445: Handle NiLines
|
||||
|
@ -299,7 +301,7 @@
|
|||
Feature #5147: Show spell magicka cost in spell buying window
|
||||
Feature #5170: Editor: Land shape editing, land selection
|
||||
Feature #5172: Editor: Delete instances/references with keypress in scene window
|
||||
Feature #5193: Weapon sheathing
|
||||
Feature #5193: Shields sheathing
|
||||
Feature #5201: Editor: Show tool outline in scene view, when using editmodes
|
||||
Feature #5219: Impelement TestCells console command
|
||||
Feature #5224: Handle NiKeyframeController for NiTriShape
|
||||
|
|
|
@ -13,7 +13,16 @@ MISSINGTOOLS=0
|
|||
|
||||
command -v 7z >/dev/null 2>&1 || { echo "Error: 7z (7zip) is not on the path."; MISSINGTOOLS=1; }
|
||||
command -v cmake >/dev/null 2>&1 || { echo "Error: cmake (CMake) is not on the path."; MISSINGTOOLS=1; }
|
||||
command -v python >/dev/null 2>&1 || { echo "Warning: Python is not on the path, automatic Qt installation impossible."; }
|
||||
|
||||
MISSINGPYTHON=0
|
||||
if ! command -v python >/dev/null 2>&1; then
|
||||
echo "Warning: Python is not on the path, automatic Qt installation impossible."
|
||||
MISSINGPYTHON=1
|
||||
elif ! python --version >/dev/null 2>&1; then
|
||||
echo "Warning: Python is (probably) fake stub Python that comes bundled with newer versions of Windows, automatic Qt installation impossible."
|
||||
echo "If you think you have Python installed, try changing the order of your PATH environment variable in Advanced System Settings."
|
||||
MISSINGPYTHON=1
|
||||
fi
|
||||
|
||||
if [ $MISSINGTOOLS -ne 0 ]; then
|
||||
wrappedExit 1
|
||||
|
@ -745,6 +754,11 @@ fi
|
|||
if [ -d 'Qt/5.15.0' ]; then
|
||||
printf "Exists. "
|
||||
elif [ -z $SKIP_EXTRACT ]; then
|
||||
if [ $MISSINGPYTHON -ne 0 ]; then
|
||||
echo "Can't be automatically installed without Python."
|
||||
wrappedExit 1
|
||||
fi
|
||||
|
||||
pushd "$DEPS" > /dev/null
|
||||
if ! [ -d 'aqt-venv' ]; then
|
||||
echo " Creating Virtualenv for aqt..."
|
||||
|
|
|
@ -15,17 +15,13 @@ set(GAME_HEADER
|
|||
engine.hpp
|
||||
)
|
||||
|
||||
if (BULLET_USE_DOUBLES)
|
||||
add_definitions(-DBT_USE_DOUBLE_PRECISION)
|
||||
endif()
|
||||
|
||||
source_group(game FILES ${GAME} ${GAME_HEADER})
|
||||
|
||||
add_openmw_dir (mwrender
|
||||
actors objects renderingmanager animation rotatecontroller sky npcanimation vismask
|
||||
creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation
|
||||
bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation
|
||||
renderbin actoranimation landmanager navmesh actorspaths recastmesh
|
||||
renderbin actoranimation landmanager navmesh actorspaths recastmesh fogmanager
|
||||
)
|
||||
|
||||
add_openmw_dir (mwinput
|
||||
|
@ -71,7 +67,7 @@ add_openmw_dir (mwworld
|
|||
actionequip timestamp actionalchemy cellstore actionapply actioneat
|
||||
store esmstore recordcmp fallback actionrepair actionsoulgem livecellref actiondoor
|
||||
contentloader esmloader actiontrap cellreflist cellref physicssystem weather projectilemanager
|
||||
cellpreloader
|
||||
cellpreloader datetimemanager
|
||||
)
|
||||
|
||||
add_openmw_dir (mwphysics
|
||||
|
|
|
@ -48,6 +48,7 @@ namespace ESM
|
|||
struct EffectList;
|
||||
struct CreatureLevList;
|
||||
struct ItemLevList;
|
||||
struct TimeStamp;
|
||||
}
|
||||
|
||||
namespace MWRender
|
||||
|
@ -204,24 +205,14 @@ namespace MWBase
|
|||
virtual void advanceTime (double hours, bool incremental = false) = 0;
|
||||
///< Advance in-game time.
|
||||
|
||||
virtual void setHour (double hour) = 0;
|
||||
///< Set in-game time hour.
|
||||
|
||||
virtual void setMonth (int month) = 0;
|
||||
///< Set in-game time month.
|
||||
|
||||
virtual void setDay (int day) = 0;
|
||||
///< Set in-game time day.
|
||||
|
||||
virtual int getDay() const = 0;
|
||||
virtual int getMonth() const = 0;
|
||||
virtual int getYear() const = 0;
|
||||
|
||||
virtual std::string getMonthName (int month = -1) const = 0;
|
||||
///< Return name of month (-1: current month)
|
||||
|
||||
virtual MWWorld::TimeStamp getTimeStamp() const = 0;
|
||||
///< Return current in-game time stamp.
|
||||
///< Return current in-game time and number of day since new game start.
|
||||
|
||||
virtual ESM::EpochTimeStamp getEpochTimeStamp() const = 0;
|
||||
///< Return current in-game date and time.
|
||||
|
||||
virtual bool toggleSky() = 0;
|
||||
///< \return Resulting mode
|
||||
|
|
|
@ -276,7 +276,7 @@ namespace MWClass
|
|||
const MWWorld::LiveCellRef<ESM::Armor> *ref = ptr.get<ESM::Armor>();
|
||||
|
||||
int armorSkillType = getEquipmentSkill(ptr);
|
||||
int armorSkill = actor.getClass().getSkill(actor, armorSkillType);
|
||||
float armorSkill = actor.getClass().getSkill(actor, armorSkillType);
|
||||
|
||||
const MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
int iBaseArmorSkill = world->getStore().get<ESM::GameSetting>().find("iBaseArmorSkill")->mValue.getInteger();
|
||||
|
|
|
@ -605,7 +605,7 @@ namespace MWClass
|
|||
float Creature::getCapacity (const MWWorld::Ptr& ptr) const
|
||||
{
|
||||
const MWMechanics::CreatureStats& stats = getCreatureStats (ptr);
|
||||
return static_cast<float>(stats.getAttribute(ESM::Attribute::Strength).getModified() * 5);
|
||||
return stats.getAttribute(ESM::Attribute::Strength).getModified() * 5;
|
||||
}
|
||||
|
||||
int Creature::getServices(const MWWorld::ConstPtr &actor) const
|
||||
|
@ -745,7 +745,7 @@ namespace MWClass
|
|||
throw std::runtime_error(std::string("Unexpected soundgen type: ")+name);
|
||||
}
|
||||
|
||||
int Creature::getSkill(const MWWorld::Ptr &ptr, int skill) const
|
||||
float Creature::getSkill(const MWWorld::Ptr &ptr, int skill) const
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Creature> *ref =
|
||||
ptr.get<ESM::Creature>();
|
||||
|
|
|
@ -108,7 +108,7 @@ namespace MWClass
|
|||
virtual bool canSwim (const MWWorld::ConstPtr &ptr) const;
|
||||
virtual bool canWalk (const MWWorld::ConstPtr &ptr) const;
|
||||
|
||||
virtual int getSkill(const MWWorld::Ptr &ptr, int skill) const;
|
||||
virtual float getSkill(const MWWorld::Ptr &ptr, int skill) const;
|
||||
|
||||
/// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini)
|
||||
virtual int getBloodTexture (const MWWorld::ConstPtr& ptr) const;
|
||||
|
|
|
@ -125,7 +125,7 @@ namespace MWClass
|
|||
}
|
||||
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
|
||||
int alchemySkill = player.getClass().getSkill(player, ESM::Skill::Alchemy);
|
||||
float alchemySkill = player.getClass().getSkill(player, ESM::Skill::Alchemy);
|
||||
|
||||
static const float fWortChanceValue =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fWortChanceValue")->mValue.getFloat();
|
||||
|
|
|
@ -127,8 +127,8 @@ namespace
|
|||
}
|
||||
|
||||
// initial health
|
||||
int strength = creatureStats.getAttribute(ESM::Attribute::Strength).getBase();
|
||||
int endurance = creatureStats.getAttribute(ESM::Attribute::Endurance).getBase();
|
||||
float strength = creatureStats.getAttribute(ESM::Attribute::Strength).getBase();
|
||||
float endurance = creatureStats.getAttribute(ESM::Attribute::Endurance).getBase();
|
||||
|
||||
int multiplier = 3;
|
||||
|
||||
|
@ -1011,7 +1011,7 @@ namespace MWClass
|
|||
gmst.fJumpEncumbranceMultiplier->mValue.getFloat() *
|
||||
(1.0f - Npc::getNormalizedEncumbrance(ptr));
|
||||
|
||||
float a = static_cast<float>(getSkill(ptr, ESM::Skill::Acrobatics));
|
||||
float a = getSkill(ptr, ESM::Skill::Acrobatics);
|
||||
float b = 0.0f;
|
||||
if(a > 50.0f)
|
||||
{
|
||||
|
@ -1136,7 +1136,7 @@ namespace MWClass
|
|||
|
||||
float fUnarmoredBase1 = store.find("fUnarmoredBase1")->mValue.getFloat();
|
||||
float fUnarmoredBase2 = store.find("fUnarmoredBase2")->mValue.getFloat();
|
||||
int unarmoredSkill = getSkill(ptr, ESM::Skill::Unarmored);
|
||||
float unarmoredSkill = getSkill(ptr, ESM::Skill::Unarmored);
|
||||
|
||||
float ratings[MWWorld::InventoryStore::Slots];
|
||||
for(int i = 0;i < MWWorld::InventoryStore::Slots;i++)
|
||||
|
@ -1283,7 +1283,7 @@ namespace MWClass
|
|||
return MWWorld::Ptr(cell.insert(ref), &cell);
|
||||
}
|
||||
|
||||
int Npc::getSkill(const MWWorld::Ptr& ptr, int skill) const
|
||||
float Npc::getSkill(const MWWorld::Ptr& ptr, int skill) const
|
||||
{
|
||||
return getNpcStats(ptr).getSkill(skill).getModified();
|
||||
}
|
||||
|
|
|
@ -129,7 +129,7 @@ namespace MWClass
|
|||
|
||||
virtual std::string getModel(const MWWorld::ConstPtr &ptr) const;
|
||||
|
||||
virtual int getSkill(const MWWorld::Ptr& ptr, int skill) const;
|
||||
virtual float getSkill(const MWWorld::Ptr& ptr, int skill) const;
|
||||
|
||||
/// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini)
|
||||
virtual int getBloodTexture (const MWWorld::ConstPtr& ptr) const;
|
||||
|
|
|
@ -95,9 +95,9 @@ namespace MWGui
|
|||
|
||||
MWMechanics::SkillValue& value = player.getClass().getNpcStats(player).getSkill(skill);
|
||||
if (skill == ESM::Skill::Security || skill == ESM::Skill::Sneak)
|
||||
value.setBase(std::min(100, value.getBase()+1));
|
||||
value.setBase(std::min(100.f, value.getBase()+1));
|
||||
else
|
||||
value.setBase(std::max(0, value.getBase()-1));
|
||||
value.setBase(std::max(0.f, value.getBase()-1));
|
||||
}
|
||||
|
||||
const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||
|
|
|
@ -157,7 +157,7 @@ namespace MWGui
|
|||
mAttributeValues[i]->setEnabled(true);
|
||||
availableAttributes++;
|
||||
|
||||
int mult = pcStats.getLevelupAttributeMultiplier (i);
|
||||
float mult = pcStats.getLevelupAttributeMultiplier (i);
|
||||
mult = std::min(mult, 100-pcStats.getAttribute(i).getBase());
|
||||
text->setCaption(mult <= 1 ? "" : "x" + MyGUI::utility::toString(mult));
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace MWGui
|
|||
{
|
||||
MWWorld::Ptr player = MWMechanics::getPlayer();
|
||||
mSourceModel = sourceModel;
|
||||
int chance = player.getClass().getSkill(player, ESM::Skill::Sneak);
|
||||
float chance = player.getClass().getSkill(player, ESM::Skill::Sneak);
|
||||
|
||||
mSourceModel->update();
|
||||
|
||||
|
|
|
@ -159,7 +159,7 @@ namespace MWGui
|
|||
for (int i=0; ids[i]; ++i)
|
||||
if (ids[i]==id)
|
||||
{
|
||||
setText (id, std::to_string(value.getModified()));
|
||||
setText (id, std::to_string(static_cast<int>(value.getModified())));
|
||||
|
||||
MyGUI::TextBox* box;
|
||||
getWidget(box, id);
|
||||
|
|
|
@ -74,11 +74,11 @@ namespace MWGui
|
|||
mPlayerGold->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold));
|
||||
|
||||
// NPC can train you in his best 3 skills
|
||||
std::vector< std::pair<int, int> > skills;
|
||||
std::vector< std::pair<int, float> > skills;
|
||||
|
||||
for (int i=0; i<ESM::Skill::Length; ++i)
|
||||
{
|
||||
int value = actor.getClass().getSkill(actor, i);
|
||||
float value = actor.getClass().getSkill(actor, i);
|
||||
|
||||
skills.push_back(std::make_pair(i, value));
|
||||
}
|
||||
|
|
|
@ -150,11 +150,10 @@ namespace MWGui
|
|||
if (hour >= 13) hour -= 12;
|
||||
if (hour == 0) hour = 12;
|
||||
|
||||
std::string dateTimeText =
|
||||
MyGUI::utility::toString(MWBase::Environment::get().getWorld ()->getDay ()) + " "
|
||||
+ month + " (#{sDay} " + MyGUI::utility::toString(MWBase::Environment::get().getWorld ()->getTimeStamp ().getDay())
|
||||
+ ") " + MyGUI::utility::toString(hour) + " " + (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}");
|
||||
|
||||
ESM::EpochTimeStamp currentDate = MWBase::Environment::get().getWorld()->getEpochTimeStamp();
|
||||
int daysPassed = MWBase::Environment::get().getWorld()->getTimeStamp().getDay();
|
||||
std::string formattedHour = pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}";
|
||||
std::string dateTimeText = Misc::StringUtils::format("%i %s (#{sDay} %i) %i %s", currentDate.mDay, month, daysPassed, hour, formattedHour);
|
||||
mDateTimeText->setCaptionWithReplacing (dateTimeText);
|
||||
}
|
||||
|
||||
|
|
|
@ -132,7 +132,7 @@ void getRestorationPerHourOfSleep (const MWWorld::Ptr& ptr, float& health, float
|
|||
MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats (ptr);
|
||||
const MWWorld::Store<ESM::GameSetting>& settings = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||
|
||||
int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified ();
|
||||
float endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified ();
|
||||
health = 0.1f * endurance;
|
||||
|
||||
float fRestMagicMult = settings.find("fRestMagicMult")->mValue.getFloat ();
|
||||
|
@ -765,7 +765,7 @@ namespace MWMechanics
|
|||
{
|
||||
CreatureStats& creatureStats = ptr.getClass().getCreatureStats (ptr);
|
||||
|
||||
int intelligence = creatureStats.getAttribute(ESM::Attribute::Intelligence).getModified();
|
||||
float intelligence = creatureStats.getAttribute(ESM::Attribute::Intelligence).getModified();
|
||||
|
||||
float base = 1.f;
|
||||
if (ptr == getPlayer())
|
||||
|
@ -844,7 +844,7 @@ namespace MWMechanics
|
|||
float fFatigueReturnMult = settings.find("fFatigueReturnMult")->mValue.getFloat ();
|
||||
float fEndFatigueMult = settings.find("fEndFatigueMult")->mValue.getFloat ();
|
||||
|
||||
int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified ();
|
||||
float endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified ();
|
||||
|
||||
float normalizedEncumbrance = ptr.getClass().getNormalizedEncumbrance(ptr);
|
||||
if (normalizedEncumbrance > 1)
|
||||
|
@ -871,7 +871,7 @@ namespace MWMechanics
|
|||
return;
|
||||
|
||||
// Restore fatigue
|
||||
int endurance = stats.getAttribute(ESM::Attribute::Endurance).getModified();
|
||||
float endurance = stats.getAttribute(ESM::Attribute::Endurance).getModified();
|
||||
const MWWorld::Store<ESM::GameSetting>& settings = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||
static const float fFatigueReturnBase = settings.find("fFatigueReturnBase")->mValue.getFloat ();
|
||||
static const float fFatigueReturnMult = settings.find("fFatigueReturnMult")->mValue.getFloat ();
|
||||
|
@ -2051,6 +2051,8 @@ namespace MWMechanics
|
|||
|
||||
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
||||
{
|
||||
iter->first.getClass().getCreatureStats(iter->first).getActiveSpells().update(duration);
|
||||
|
||||
if (iter->first.getClass().getCreatureStats(iter->first).isDead())
|
||||
continue;
|
||||
|
||||
|
|
|
@ -44,11 +44,6 @@ namespace MWMechanics
|
|||
return false;
|
||||
}
|
||||
|
||||
int AiActivate::getTypeId() const
|
||||
{
|
||||
return TypeIdActivate;
|
||||
}
|
||||
|
||||
void AiActivate::writeState(ESM::AiSequence::AiSequence &sequence) const
|
||||
{
|
||||
std::unique_ptr<ESM::AiSequence::AiActivate> activate(new ESM::AiSequence::AiActivate());
|
||||
|
|
|
@ -29,12 +29,13 @@ namespace MWMechanics
|
|||
AiActivate(const ESM::AiSequence::AiActivate* activate);
|
||||
|
||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
int getTypeId() const final;
|
||||
|
||||
static constexpr TypeId getTypeId() { return TypeIdActivate; }
|
||||
|
||||
void writeState(ESM::AiSequence::AiSequence& sequence) const final;
|
||||
|
||||
private:
|
||||
std::string mObjectId;
|
||||
const std::string mObjectId;
|
||||
};
|
||||
}
|
||||
#endif // GAME_MWMECHANICS_AIACTIVATE_H
|
||||
|
|
|
@ -72,16 +72,6 @@ bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, CharacterCont
|
|||
return false;
|
||||
}
|
||||
|
||||
int MWMechanics::AiAvoidDoor::getTypeId() const
|
||||
{
|
||||
return TypeIdAvoidDoor;
|
||||
}
|
||||
|
||||
unsigned int MWMechanics::AiAvoidDoor::getPriority() const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
bool MWMechanics::AiAvoidDoor::isStuck(const osg::Vec3f& actorPos) const
|
||||
{
|
||||
return (actorPos - mLastPos).length2() < 10 * 10;
|
||||
|
|
|
@ -24,16 +24,20 @@ namespace MWMechanics
|
|||
|
||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
|
||||
int getTypeId() const final;
|
||||
static constexpr TypeId getTypeId() { return TypeIdAvoidDoor; }
|
||||
|
||||
unsigned int getPriority() const final;
|
||||
|
||||
bool canCancel() const final { return false; }
|
||||
bool shouldCancelPreviousAi() const final { return false; }
|
||||
static constexpr Options makeDefaultOptions()
|
||||
{
|
||||
AiPackage::Options options;
|
||||
options.mPriority = 2;
|
||||
options.mCanCancel = false;
|
||||
options.mShouldCancelPreviousAi = false;
|
||||
return options;
|
||||
}
|
||||
|
||||
private:
|
||||
float mDuration;
|
||||
MWWorld::ConstPtr mDoorPtr;
|
||||
const MWWorld::ConstPtr mDoorPtr;
|
||||
osg::Vec3f mLastPos;
|
||||
int mDirection;
|
||||
|
||||
|
|
|
@ -31,13 +31,3 @@ bool MWMechanics::AiBreathe::execute (const MWWorld::Ptr& actor, CharacterContro
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
int MWMechanics::AiBreathe::getTypeId() const
|
||||
{
|
||||
return TypeIdBreathe;
|
||||
}
|
||||
|
||||
unsigned int MWMechanics::AiBreathe::getPriority() const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
|
|
@ -12,13 +12,16 @@ namespace MWMechanics
|
|||
public:
|
||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
|
||||
int getTypeId() const final;
|
||||
static constexpr TypeId getTypeId() { return TypeIdBreathe; }
|
||||
|
||||
unsigned int getPriority() const final;
|
||||
|
||||
bool canCancel() const final { return false; }
|
||||
bool shouldCancelPreviousAi() const final { return false; }
|
||||
static constexpr Options makeDefaultOptions()
|
||||
{
|
||||
AiPackage::Options options;
|
||||
options.mPriority = 2;
|
||||
options.mCanCancel = false;
|
||||
options.mShouldCancelPreviousAi = false;
|
||||
return options;
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -10,12 +10,22 @@
|
|||
#include "creaturestats.hpp"
|
||||
#include "steering.hpp"
|
||||
|
||||
MWMechanics::AiCast::AiCast(const std::string& targetId, const std::string& spellId, bool manualSpell)
|
||||
: mTargetId(targetId), mSpellId(spellId), mCasting(false), mManual(manualSpell), mDistance(0)
|
||||
namespace MWMechanics
|
||||
{
|
||||
namespace
|
||||
{
|
||||
float getInitialDistance(const std::string& spellId)
|
||||
{
|
||||
ActionSpell action = ActionSpell(spellId);
|
||||
bool isRanged;
|
||||
return action.getCombatRange(isRanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MWMechanics::AiCast::AiCast(const std::string& targetId, const std::string& spellId, bool manualSpell)
|
||||
: mTargetId(targetId), mSpellId(spellId), mCasting(false), mManual(manualSpell), mDistance(getInitialDistance(spellId))
|
||||
{
|
||||
ActionSpell action = ActionSpell(spellId);
|
||||
bool isRanged;
|
||||
mDistance = action.getCombatRange(isRanged);
|
||||
}
|
||||
|
||||
bool MWMechanics::AiCast::execute(const MWWorld::Ptr& actor, MWMechanics::CharacterController& characterController, MWMechanics::AiState& state, float duration)
|
||||
|
@ -79,13 +89,3 @@ MWWorld::Ptr MWMechanics::AiCast::getTarget() const
|
|||
|
||||
return target;
|
||||
}
|
||||
|
||||
int MWMechanics::AiCast::getTypeId() const
|
||||
{
|
||||
return AiPackage::TypeIdCast;
|
||||
}
|
||||
|
||||
unsigned int MWMechanics::AiCast::getPriority() const
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
|
|
@ -17,21 +17,25 @@ namespace MWMechanics
|
|||
|
||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
|
||||
int getTypeId() const final;
|
||||
static constexpr TypeId getTypeId() { return TypeIdCast; }
|
||||
|
||||
MWWorld::Ptr getTarget() const final;
|
||||
|
||||
unsigned int getPriority() const final;
|
||||
|
||||
bool canCancel() const final { return false; }
|
||||
bool shouldCancelPreviousAi() const final { return false; }
|
||||
static constexpr Options makeDefaultOptions()
|
||||
{
|
||||
AiPackage::Options options;
|
||||
options.mPriority = 3;
|
||||
options.mCanCancel = false;
|
||||
options.mShouldCancelPreviousAi = false;
|
||||
return options;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string mTargetId;
|
||||
std::string mSpellId;
|
||||
const std::string mTargetId;
|
||||
const std::string mSpellId;
|
||||
bool mCasting;
|
||||
bool mManual;
|
||||
float mDistance;
|
||||
const bool mManual;
|
||||
const float mDistance;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -406,16 +406,6 @@ namespace MWMechanics
|
|||
}
|
||||
}
|
||||
|
||||
int AiCombat::getTypeId() const
|
||||
{
|
||||
return TypeIdCombat;
|
||||
}
|
||||
|
||||
unsigned int AiCombat::getPriority() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
MWWorld::Ptr AiCombat::getTarget() const
|
||||
{
|
||||
return MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId);
|
||||
|
|
|
@ -104,18 +104,22 @@ namespace MWMechanics
|
|||
|
||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
|
||||
int getTypeId() const final;
|
||||
static constexpr TypeId getTypeId() { return TypeIdCombat; }
|
||||
|
||||
unsigned int getPriority() const final;
|
||||
static constexpr Options makeDefaultOptions()
|
||||
{
|
||||
AiPackage::Options options;
|
||||
options.mPriority = 1;
|
||||
options.mCanCancel = false;
|
||||
options.mShouldCancelPreviousAi = false;
|
||||
return options;
|
||||
}
|
||||
|
||||
///Returns target ID
|
||||
MWWorld::Ptr getTarget() const final;
|
||||
|
||||
void writeState(ESM::AiSequence::AiSequence &sequence) const final;
|
||||
|
||||
bool canCancel() const final { return false; }
|
||||
bool shouldCancelPreviousAi() const final { return false; }
|
||||
|
||||
private:
|
||||
/// Returns true if combat should end
|
||||
bool attack(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, AiCombatStorage& storage, CharacterController& characterController);
|
||||
|
|
|
@ -26,7 +26,6 @@ namespace MWMechanics
|
|||
, mCellY(std::numeric_limits<int>::max())
|
||||
{
|
||||
mTargetActorRefId = actorId;
|
||||
mMaxDist = 450;
|
||||
}
|
||||
|
||||
AiEscort::AiEscort(const std::string &actorId, const std::string &cellId, int duration, float x, float y, float z)
|
||||
|
@ -35,24 +34,20 @@ namespace MWMechanics
|
|||
, mCellY(std::numeric_limits<int>::max())
|
||||
{
|
||||
mTargetActorRefId = actorId;
|
||||
mMaxDist = 450;
|
||||
}
|
||||
|
||||
AiEscort::AiEscort(const ESM::AiSequence::AiEscort *escort)
|
||||
: mCellId(escort->mCellId), mX(escort->mData.mX), mY(escort->mData.mY), mZ(escort->mData.mZ)
|
||||
, mMaxDist(450)
|
||||
// mDuration isn't saved in the save file, so just giving it "1" for now if the package has a duration.
|
||||
// The exact value of mDuration only matters for repeating packages.
|
||||
// Previously mRemainingDuration could be negative even when mDuration was 0. Checking for > 0 should fix old saves.
|
||||
, mDuration(escort->mRemainingDuration > 0)
|
||||
, mRemainingDuration(escort->mRemainingDuration)
|
||||
, mCellX(std::numeric_limits<int>::max())
|
||||
, mCellY(std::numeric_limits<int>::max())
|
||||
{
|
||||
mTargetActorRefId = escort->mTargetId;
|
||||
mTargetActorId = escort->mTargetActorId;
|
||||
// mDuration isn't saved in the save file, so just giving it "1" for now if the package has a duration.
|
||||
// The exact value of mDuration only matters for repeating packages.
|
||||
if (mRemainingDuration > 0) // Previously mRemainingDuration could be negative even when mDuration was 0. Checking for > 0 should fix old saves.
|
||||
mDuration = 1;
|
||||
else
|
||||
mDuration = 0;
|
||||
}
|
||||
|
||||
bool AiEscort::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
|
||||
|
@ -100,11 +95,6 @@ namespace MWMechanics
|
|||
return false;
|
||||
}
|
||||
|
||||
int AiEscort::getTypeId() const
|
||||
{
|
||||
return TypeIdEscort;
|
||||
}
|
||||
|
||||
void AiEscort::writeState(ESM::AiSequence::AiSequence &sequence) const
|
||||
{
|
||||
std::unique_ptr<ESM::AiSequence::AiEscort> escort(new ESM::AiSequence::AiEscort());
|
||||
|
|
|
@ -32,11 +32,15 @@ namespace MWMechanics
|
|||
|
||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
|
||||
int getTypeId() const final;
|
||||
static constexpr TypeId getTypeId() { return TypeIdEscort; }
|
||||
|
||||
bool useVariableSpeed() const final { return true; }
|
||||
|
||||
bool sideWithTarget() const final { return true; }
|
||||
static constexpr Options makeDefaultOptions()
|
||||
{
|
||||
AiPackage::Options options;
|
||||
options.mUseVariableSpeed = true;
|
||||
options.mSideWithTarget = true;
|
||||
return options;
|
||||
}
|
||||
|
||||
void writeState(ESM::AiSequence::AiSequence &sequence) const final;
|
||||
|
||||
|
@ -45,16 +49,16 @@ namespace MWMechanics
|
|||
osg::Vec3f getDestination() const final { return osg::Vec3f(mX, mY, mZ); }
|
||||
|
||||
private:
|
||||
std::string mCellId;
|
||||
float mX;
|
||||
float mY;
|
||||
float mZ;
|
||||
float mMaxDist;
|
||||
float mDuration; // In hours
|
||||
const std::string mCellId;
|
||||
const float mX;
|
||||
const float mY;
|
||||
const float mZ;
|
||||
float mMaxDist = 450;
|
||||
const float mDuration; // In hours
|
||||
float mRemainingDuration; // In hours
|
||||
|
||||
int mCellX;
|
||||
int mCellY;
|
||||
const int mCellX;
|
||||
const int mCellY;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -14,13 +14,3 @@ bool MWMechanics::AiFace::execute(const MWWorld::Ptr& actor, MWMechanics::Charac
|
|||
osg::Vec3f dir = osg::Vec3f(mTargetX, mTargetY, 0) - actor.getRefData().getPosition().asVec3();
|
||||
return zTurn(actor, std::atan2(dir.x(), dir.y()), osg::DegreesToRadians(3.f));
|
||||
}
|
||||
|
||||
int MWMechanics::AiFace::getTypeId() const
|
||||
{
|
||||
return AiPackage::TypeIdFace;
|
||||
}
|
||||
|
||||
unsigned int MWMechanics::AiFace::getPriority() const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
|
|
@ -12,15 +12,20 @@ namespace MWMechanics
|
|||
|
||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
|
||||
int getTypeId() const final;
|
||||
static constexpr TypeId getTypeId() { return TypeIdFace; }
|
||||
|
||||
unsigned int getPriority() const final;
|
||||
|
||||
bool canCancel() const final { return false; }
|
||||
bool shouldCancelPreviousAi() const final { return false; }
|
||||
static constexpr Options makeDefaultOptions()
|
||||
{
|
||||
AiPackage::Options options;
|
||||
options.mPriority = 2;
|
||||
options.mCanCancel = false;
|
||||
options.mShouldCancelPreviousAi = false;
|
||||
return options;
|
||||
}
|
||||
|
||||
private:
|
||||
float mTargetX, mTargetY;
|
||||
const float mTargetX;
|
||||
const float mTargetY;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -16,25 +16,24 @@
|
|||
|
||||
namespace MWMechanics
|
||||
{
|
||||
|
||||
int AiFollow::mFollowIndexCounter = 0;
|
||||
|
||||
AiFollow::AiFollow(const std::string &actorId, float duration, float x, float y, float z)
|
||||
: mAlwaysFollow(false), mCommanded(false), mDuration(duration), mRemainingDuration(duration), mX(x), mY(y), mZ(z)
|
||||
: mAlwaysFollow(false), mDuration(duration), mRemainingDuration(duration), mX(x), mY(y), mZ(z)
|
||||
, mCellId(""), mActive(false), mFollowIndex(mFollowIndexCounter++)
|
||||
{
|
||||
mTargetActorRefId = actorId;
|
||||
}
|
||||
|
||||
AiFollow::AiFollow(const std::string &actorId, const std::string &cellId, float duration, float x, float y, float z)
|
||||
: mAlwaysFollow(false), mCommanded(false), mDuration(duration), mRemainingDuration(duration), mX(x), mY(y), mZ(z)
|
||||
: mAlwaysFollow(false), mDuration(duration), mRemainingDuration(duration), mX(x), mY(y), mZ(z)
|
||||
, mCellId(cellId), mActive(false), mFollowIndex(mFollowIndexCounter++)
|
||||
{
|
||||
mTargetActorRefId = actorId;
|
||||
}
|
||||
|
||||
AiFollow::AiFollow(const MWWorld::Ptr& actor, float duration, float x, float y, float z)
|
||||
: mAlwaysFollow(false), mCommanded(false), mDuration(duration), mRemainingDuration(duration), mX(x), mY(y), mZ(z)
|
||||
: mAlwaysFollow(false), mDuration(duration), mRemainingDuration(duration), mX(x), mY(y), mZ(z)
|
||||
, mCellId(""), mActive(false), mFollowIndex(mFollowIndexCounter++)
|
||||
{
|
||||
mTargetActorRefId = actor.getCellRef().getRefId();
|
||||
|
@ -42,7 +41,7 @@ AiFollow::AiFollow(const MWWorld::Ptr& actor, float duration, float x, float y,
|
|||
}
|
||||
|
||||
AiFollow::AiFollow(const MWWorld::Ptr& actor, const std::string &cellId, float duration, float x, float y, float z)
|
||||
: mAlwaysFollow(false), mCommanded(false), mDuration(duration), mRemainingDuration(duration), mX(x), mY(y), mZ(z)
|
||||
: mAlwaysFollow(false), mDuration(duration), mRemainingDuration(duration), mX(x), mY(y), mZ(z)
|
||||
, mCellId(cellId), mActive(false), mFollowIndex(mFollowIndexCounter++)
|
||||
{
|
||||
mTargetActorRefId = actor.getCellRef().getRefId();
|
||||
|
@ -50,7 +49,8 @@ AiFollow::AiFollow(const MWWorld::Ptr& actor, const std::string &cellId, float d
|
|||
}
|
||||
|
||||
AiFollow::AiFollow(const MWWorld::Ptr& actor, bool commanded)
|
||||
: mAlwaysFollow(true), mCommanded(commanded), mDuration(0), mRemainingDuration(0), mX(0), mY(0), mZ(0)
|
||||
: TypedAiPackage<AiFollow>(makeDefaultOptions().withShouldCancelPreviousAi(!commanded))
|
||||
, mAlwaysFollow(true), mDuration(0), mRemainingDuration(0), mX(0), mY(0), mZ(0)
|
||||
, mCellId(""), mActive(false), mFollowIndex(mFollowIndexCounter++)
|
||||
{
|
||||
mTargetActorRefId = actor.getCellRef().getRefId();
|
||||
|
@ -58,18 +58,18 @@ AiFollow::AiFollow(const MWWorld::Ptr& actor, bool commanded)
|
|||
}
|
||||
|
||||
AiFollow::AiFollow(const ESM::AiSequence::AiFollow *follow)
|
||||
: mAlwaysFollow(follow->mAlwaysFollow), mCommanded(follow->mCommanded), mRemainingDuration(follow->mRemainingDuration)
|
||||
: TypedAiPackage<AiFollow>(makeDefaultOptions().withShouldCancelPreviousAi(!follow->mCommanded))
|
||||
, mAlwaysFollow(follow->mAlwaysFollow)
|
||||
// mDuration isn't saved in the save file, so just giving it "1" for now if the package had a duration.
|
||||
// The exact value of mDuration only matters for repeating packages.
|
||||
// Previously mRemainingDuration could be negative even when mDuration was 0. Checking for > 0 should fix old saves.
|
||||
, mDuration(follow->mRemainingDuration)
|
||||
, mRemainingDuration(follow->mRemainingDuration)
|
||||
, mX(follow->mData.mX), mY(follow->mData.mY), mZ(follow->mData.mZ)
|
||||
, mCellId(follow->mCellId), mActive(follow->mActive), mFollowIndex(mFollowIndexCounter++)
|
||||
{
|
||||
mTargetActorRefId = follow->mTargetId;
|
||||
mTargetActorId = follow->mTargetActorId;
|
||||
// mDuration isn't saved in the save file, so just giving it "1" for now if the package had a duration.
|
||||
// The exact value of mDuration only matters for repeating packages.
|
||||
if (mRemainingDuration > 0) // Previously mRemainingDuration could be negative even when mDuration was 0. Checking for > 0 should fix old saves.
|
||||
mDuration = 1;
|
||||
else
|
||||
mDuration = 0;
|
||||
}
|
||||
|
||||
bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
|
||||
|
@ -201,14 +201,9 @@ std::string AiFollow::getFollowedActor()
|
|||
return mTargetActorRefId;
|
||||
}
|
||||
|
||||
int AiFollow::getTypeId() const
|
||||
{
|
||||
return TypeIdFollow;
|
||||
}
|
||||
|
||||
bool AiFollow::isCommanded() const
|
||||
{
|
||||
return mCommanded;
|
||||
return !mOptions.mShouldCancelPreviousAi;
|
||||
}
|
||||
|
||||
void AiFollow::writeState(ESM::AiSequence::AiSequence &sequence) const
|
||||
|
@ -222,7 +217,7 @@ void AiFollow::writeState(ESM::AiSequence::AiSequence &sequence) const
|
|||
follow->mRemainingDuration = mRemainingDuration;
|
||||
follow->mCellId = mCellId;
|
||||
follow->mAlwaysFollow = mAlwaysFollow;
|
||||
follow->mCommanded = mCommanded;
|
||||
follow->mCommanded = isCommanded();
|
||||
follow->mActive = mActive;
|
||||
|
||||
ESM::AiSequence::AiPackageContainer package;
|
||||
|
|
|
@ -53,15 +53,18 @@ namespace MWMechanics
|
|||
|
||||
AiFollow(const ESM::AiSequence::AiFollow* follow);
|
||||
|
||||
bool sideWithTarget() const final { return true; }
|
||||
bool followTargetThroughDoors() const final { return true; }
|
||||
bool shouldCancelPreviousAi() const final { return !mCommanded; }
|
||||
|
||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
|
||||
int getTypeId() const final;
|
||||
static constexpr TypeId getTypeId() { return TypeIdFollow; }
|
||||
|
||||
bool useVariableSpeed() const final { return true; }
|
||||
static constexpr Options makeDefaultOptions()
|
||||
{
|
||||
AiPackage::Options options;
|
||||
options.mUseVariableSpeed = true;
|
||||
options.mSideWithTarget = true;
|
||||
options.mFollowTargetThroughDoors = true;
|
||||
return options;
|
||||
}
|
||||
|
||||
/// Returns the actor being followed
|
||||
std::string getFollowedActor();
|
||||
|
@ -86,16 +89,15 @@ namespace MWMechanics
|
|||
private:
|
||||
/// This will make the actor always follow.
|
||||
/** Thus ignoring mDuration and mX,mY,mZ (used for summoned creatures). **/
|
||||
bool mAlwaysFollow;
|
||||
bool mCommanded;
|
||||
float mDuration; // Hours
|
||||
const bool mAlwaysFollow;
|
||||
const float mDuration; // Hours
|
||||
float mRemainingDuration; // Hours
|
||||
float mX;
|
||||
float mY;
|
||||
float mZ;
|
||||
std::string mCellId;
|
||||
const float mX;
|
||||
const float mY;
|
||||
const float mZ;
|
||||
const std::string mCellId;
|
||||
bool mActive; // have we spotted the target?
|
||||
int mFollowIndex;
|
||||
const int mFollowIndex;
|
||||
|
||||
static int mFollowIndexCounter;
|
||||
};
|
||||
|
|
|
@ -24,7 +24,9 @@
|
|||
|
||||
#include <osg/Quat>
|
||||
|
||||
MWMechanics::AiPackage::AiPackage() :
|
||||
MWMechanics::AiPackage::AiPackage(TypeId typeId, const Options& options) :
|
||||
mTypeId(typeId),
|
||||
mOptions(options),
|
||||
mTimer(AI_REACTION_TIME + 1.0f), // to force initial pathbuild
|
||||
mTargetActorRefId(""),
|
||||
mTargetActorId(-1),
|
||||
|
@ -58,31 +60,6 @@ MWWorld::Ptr MWMechanics::AiPackage::getTarget() const
|
|||
return MWWorld::Ptr();
|
||||
}
|
||||
|
||||
bool MWMechanics::AiPackage::sideWithTarget() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MWMechanics::AiPackage::followTargetThroughDoors() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MWMechanics::AiPackage::canCancel() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MWMechanics::AiPackage::shouldCancelPreviousAi() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MWMechanics::AiPackage::getRepeat() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void MWMechanics::AiPackage::reset()
|
||||
{
|
||||
// reset all members
|
||||
|
|
|
@ -55,11 +55,39 @@ namespace MWMechanics
|
|||
TypeIdCast = 11
|
||||
};
|
||||
|
||||
///Default constructor
|
||||
AiPackage();
|
||||
struct Options
|
||||
{
|
||||
unsigned int mPriority = 0;
|
||||
bool mUseVariableSpeed = false;
|
||||
bool mSideWithTarget = false;
|
||||
bool mFollowTargetThroughDoors = false;
|
||||
bool mCanCancel = true;
|
||||
bool mShouldCancelPreviousAi = true;
|
||||
bool mRepeat = false;
|
||||
bool mAlwaysActive = false;
|
||||
|
||||
constexpr Options withRepeat(bool value)
|
||||
{
|
||||
mRepeat = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr Options withShouldCancelPreviousAi(bool value)
|
||||
{
|
||||
mShouldCancelPreviousAi = value;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
AiPackage(TypeId typeId, const Options& options);
|
||||
|
||||
virtual ~AiPackage() = default;
|
||||
|
||||
static constexpr Options makeDefaultOptions()
|
||||
{
|
||||
return Options{};
|
||||
}
|
||||
|
||||
///Clones the package
|
||||
virtual std::unique_ptr<AiPackage> clone() const = 0;
|
||||
|
||||
|
@ -69,13 +97,13 @@ namespace MWMechanics
|
|||
|
||||
/// Returns the TypeID of the AiPackage
|
||||
/// \see enum TypeId
|
||||
virtual int getTypeId() const = 0;
|
||||
TypeId getTypeId() const { return mTypeId; }
|
||||
|
||||
/// Higher number is higher priority (0 being the lowest)
|
||||
virtual unsigned int getPriority() const {return 0;}
|
||||
unsigned int getPriority() const { return mOptions.mPriority; }
|
||||
|
||||
/// Check if package use movement with variable speed
|
||||
virtual bool useVariableSpeed() const { return false;}
|
||||
bool useVariableSpeed() const { return mOptions.mUseVariableSpeed; }
|
||||
|
||||
virtual void writeState (ESM::AiSequence::AiSequence& sequence) const {}
|
||||
|
||||
|
@ -89,24 +117,24 @@ namespace MWMechanics
|
|||
virtual osg::Vec3f getDestination(const MWWorld::Ptr& actor) const { return osg::Vec3f(0, 0, 0); };
|
||||
|
||||
/// Return true if having this AiPackage makes the actor side with the target in fights (default false)
|
||||
virtual bool sideWithTarget() const;
|
||||
bool sideWithTarget() const { return mOptions.mSideWithTarget; }
|
||||
|
||||
/// Return true if the actor should follow the target through teleport doors (default false)
|
||||
virtual bool followTargetThroughDoors() const;
|
||||
bool followTargetThroughDoors() const { return mOptions.mFollowTargetThroughDoors; }
|
||||
|
||||
/// Can this Ai package be canceled? (default true)
|
||||
virtual bool canCancel() const;
|
||||
bool canCancel() const { return mOptions.mCanCancel; }
|
||||
|
||||
/// Upon adding this Ai package, should the Ai Sequence attempt to cancel previous Ai packages (default true)?
|
||||
virtual bool shouldCancelPreviousAi() const;
|
||||
bool shouldCancelPreviousAi() const { return mOptions.mShouldCancelPreviousAi; }
|
||||
|
||||
/// Return true if this package should repeat. Currently only used for Wander packages.
|
||||
virtual bool getRepeat() const;
|
||||
bool getRepeat() const { return mOptions.mRepeat; }
|
||||
|
||||
virtual osg::Vec3f getDestination() const { return osg::Vec3f(0, 0, 0); }
|
||||
|
||||
// Return true if any loaded actor with this AI package must be active.
|
||||
virtual bool alwaysActive() const { return false; }
|
||||
/// Return true if any loaded actor with this AI package must be active.
|
||||
bool alwaysActive() const { return mOptions.mAlwaysActive; }
|
||||
|
||||
/// Reset pathfinding state
|
||||
void reset();
|
||||
|
@ -139,6 +167,9 @@ namespace MWMechanics
|
|||
|
||||
DetourNavigator::Flags getNavigatorFlags(const MWWorld::Ptr& actor) const;
|
||||
|
||||
const TypeId mTypeId;
|
||||
const Options mOptions;
|
||||
|
||||
// TODO: all this does not belong here, move into temporary storage
|
||||
PathFinder mPathFinder;
|
||||
ObstacleCheck mObstacleCheck;
|
||||
|
|
|
@ -66,11 +66,6 @@ bool AiPursue::execute (const MWWorld::Ptr& actor, CharacterController& characte
|
|||
return false;
|
||||
}
|
||||
|
||||
int AiPursue::getTypeId() const
|
||||
{
|
||||
return TypeIdPursue;
|
||||
}
|
||||
|
||||
MWWorld::Ptr AiPursue::getTarget() const
|
||||
{
|
||||
return MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId);
|
||||
|
|
|
@ -27,14 +27,20 @@ namespace MWMechanics
|
|||
AiPursue(const ESM::AiSequence::AiPursue* pursue);
|
||||
|
||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
int getTypeId() const final;
|
||||
|
||||
static constexpr TypeId getTypeId() { return TypeIdPursue; }
|
||||
|
||||
static constexpr Options makeDefaultOptions()
|
||||
{
|
||||
AiPackage::Options options;
|
||||
options.mCanCancel = false;
|
||||
options.mShouldCancelPreviousAi = false;
|
||||
return options;
|
||||
}
|
||||
|
||||
MWWorld::Ptr getTarget() const final;
|
||||
|
||||
void writeState (ESM::AiSequence::AiSequence& sequence) const final;
|
||||
|
||||
bool canCancel() const final { return false; }
|
||||
bool shouldCancelPreviousAi() const final { return false; }
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -338,7 +338,7 @@ void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor, boo
|
|||
dest = actor.getRefData().getPosition().asVec3();
|
||||
}
|
||||
|
||||
MWMechanics::AiTravel travelPackage(dest.x(), dest.y(), dest.z(), true);
|
||||
MWMechanics::AiInternalTravel travelPackage(dest.x(), dest.y(), dest.z());
|
||||
stack(travelPackage, actor, false);
|
||||
}
|
||||
|
||||
|
@ -478,7 +478,11 @@ void AiSequence::readState(const ESM::AiSequence::AiSequence &sequence)
|
|||
}
|
||||
case ESM::AiSequence::Ai_Travel:
|
||||
{
|
||||
package.reset(new AiTravel(static_cast<ESM::AiSequence::AiTravel*>(it->mPackage)));
|
||||
const auto source = static_cast<const ESM::AiSequence::AiTravel*>(it->mPackage);
|
||||
if (source->mHidden)
|
||||
package.reset(new AiInternalTravel(source));
|
||||
else
|
||||
package.reset(new AiTravel(source));
|
||||
break;
|
||||
}
|
||||
case ESM::AiSequence::Ai_Escort:
|
||||
|
|
|
@ -27,14 +27,26 @@ bool isWithinMaxRange(const osg::Vec3f& pos1, const osg::Vec3f& pos2)
|
|||
|
||||
namespace MWMechanics
|
||||
{
|
||||
AiTravel::AiTravel(float x, float y, float z, bool hidden)
|
||||
: mX(x),mY(y),mZ(z),mHidden(hidden)
|
||||
AiTravel::AiTravel(float x, float y, float z, AiTravel*)
|
||||
: mX(x), mY(y), mZ(z), mHidden(false)
|
||||
{
|
||||
}
|
||||
|
||||
AiTravel::AiTravel(float x, float y, float z, AiInternalTravel* derived)
|
||||
: TypedAiPackage<AiTravel>(derived), mX(x), mY(y), mZ(z), mHidden(true)
|
||||
{
|
||||
}
|
||||
|
||||
AiTravel::AiTravel(float x, float y, float z)
|
||||
: AiTravel(x, y, z, this)
|
||||
{
|
||||
}
|
||||
|
||||
AiTravel::AiTravel(const ESM::AiSequence::AiTravel *travel)
|
||||
: mX(travel->mData.mX), mY(travel->mData.mY), mZ(travel->mData.mZ), mHidden(travel->mHidden)
|
||||
: mX(travel->mData.mX), mY(travel->mData.mY), mZ(travel->mData.mZ), mHidden(false)
|
||||
{
|
||||
// Hidden ESM::AiSequence::AiTravel package should be converted into MWMechanics::AiInternalTravel type
|
||||
assert(!travel->mHidden);
|
||||
}
|
||||
|
||||
bool AiTravel::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
|
||||
|
@ -78,11 +90,6 @@ namespace MWMechanics
|
|||
return false;
|
||||
}
|
||||
|
||||
int AiTravel::getTypeId() const
|
||||
{
|
||||
return mHidden ? TypeIdInternalTravel : TypeIdTravel;
|
||||
}
|
||||
|
||||
void AiTravel::fastForward(const MWWorld::Ptr& actor, AiState& state)
|
||||
{
|
||||
if (!isWithinMaxRange(osg::Vec3f(mX, mY, mZ), actor.getRefData().getPosition().asVec3()))
|
||||
|
@ -107,5 +114,20 @@ namespace MWMechanics
|
|||
package.mPackage = travel.release();
|
||||
sequence.mPackages.push_back(package);
|
||||
}
|
||||
|
||||
AiInternalTravel::AiInternalTravel(float x, float y, float z)
|
||||
: AiTravel(x, y, z, this)
|
||||
{
|
||||
}
|
||||
|
||||
AiInternalTravel::AiInternalTravel(const ESM::AiSequence::AiTravel* travel)
|
||||
: AiTravel(travel->mData.mX, travel->mData.mY, travel->mData.mZ, this)
|
||||
{
|
||||
}
|
||||
|
||||
std::unique_ptr<AiPackage> AiInternalTravel::clone() const
|
||||
{
|
||||
return std::make_unique<AiInternalTravel>(*this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,12 +13,18 @@ namespace AiSequence
|
|||
|
||||
namespace MWMechanics
|
||||
{
|
||||
struct AiInternalTravel;
|
||||
|
||||
/// \brief Causes the AI to travel to the specified point
|
||||
class AiTravel final : public TypedAiPackage<AiTravel>
|
||||
class AiTravel : public TypedAiPackage<AiTravel>
|
||||
{
|
||||
public:
|
||||
/// Default constructor
|
||||
AiTravel(float x, float y, float z, bool hidden = false);
|
||||
AiTravel(float x, float y, float z, AiTravel* derived);
|
||||
|
||||
AiTravel(float x, float y, float z, AiInternalTravel* derived);
|
||||
|
||||
AiTravel(float x, float y, float z);
|
||||
|
||||
AiTravel(const ESM::AiSequence::AiTravel* travel);
|
||||
|
||||
/// Simulates the passing of time
|
||||
|
@ -28,20 +34,35 @@ namespace MWMechanics
|
|||
|
||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
|
||||
int getTypeId() const final;
|
||||
static constexpr TypeId getTypeId() { return TypeIdTravel; }
|
||||
|
||||
bool useVariableSpeed() const final { return true; }
|
||||
|
||||
bool alwaysActive() const final { return true; }
|
||||
static constexpr Options makeDefaultOptions()
|
||||
{
|
||||
AiPackage::Options options;
|
||||
options.mUseVariableSpeed = true;
|
||||
options.mAlwaysActive = true;
|
||||
return options;
|
||||
}
|
||||
|
||||
osg::Vec3f getDestination() const final { return osg::Vec3f(mX, mY, mZ); }
|
||||
|
||||
private:
|
||||
float mX;
|
||||
float mY;
|
||||
float mZ;
|
||||
const float mX;
|
||||
const float mY;
|
||||
const float mZ;
|
||||
|
||||
bool mHidden;
|
||||
const bool mHidden;
|
||||
};
|
||||
|
||||
struct AiInternalTravel final : public AiTravel
|
||||
{
|
||||
AiInternalTravel(float x, float y, float z);
|
||||
|
||||
explicit AiInternalTravel(const ESM::AiSequence::AiTravel* travel);
|
||||
|
||||
static constexpr TypeId getTypeId() { return TypeIdInternalTravel; }
|
||||
|
||||
std::unique_ptr<AiPackage> clone() const final;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "aiwander.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
#include <components/esm/aisequence.hpp>
|
||||
|
@ -33,6 +35,8 @@ namespace MWMechanics
|
|||
// distance must be long enough that NPC will need to move to get there.
|
||||
static const int MINIMUM_WANDER_DISTANCE = DESTINATION_TOLERANCE * 2;
|
||||
|
||||
static const std::size_t MAX_IDLE_SIZE = 8;
|
||||
|
||||
const std::string AiWander::sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1] =
|
||||
{
|
||||
std::string("idle2"),
|
||||
|
@ -94,25 +98,29 @@ namespace MWMechanics
|
|||
{
|
||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> getInitialIdle(const std::vector<unsigned char>& idle)
|
||||
{
|
||||
std::vector<unsigned char> result(MAX_IDLE_SIZE, 0);
|
||||
std::copy_n(idle.begin(), std::min(MAX_IDLE_SIZE, idle.size()), result.begin());
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> getInitialIdle(const unsigned char (&idle)[MAX_IDLE_SIZE])
|
||||
{
|
||||
return std::vector<unsigned char>(std::begin(idle), std::end(idle));
|
||||
}
|
||||
}
|
||||
|
||||
AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<unsigned char>& idle, bool repeat):
|
||||
mDistance(distance), mDuration(duration), mRemainingDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle),
|
||||
mRepeat(repeat), mStoredInitialActorPosition(false), mInitialActorPosition(osg::Vec3f(0, 0, 0)),
|
||||
TypedAiPackage<AiWander>(makeDefaultOptions().withRepeat(repeat)),
|
||||
mDistance(std::max(0, distance)),
|
||||
mDuration(std::max(0, duration)),
|
||||
mRemainingDuration(duration), mTimeOfDay(timeOfDay),
|
||||
mIdle(getInitialIdle(idle)),
|
||||
mStoredInitialActorPosition(false), mInitialActorPosition(osg::Vec3f(0, 0, 0)),
|
||||
mHasDestination(false), mDestination(osg::Vec3f(0, 0, 0)), mUsePathgrid(false)
|
||||
{
|
||||
mIdle.resize(8, 0);
|
||||
init();
|
||||
}
|
||||
|
||||
void AiWander::init()
|
||||
{
|
||||
// NOTE: mDistance and mDuration must be set already
|
||||
|
||||
if(mDistance < 0)
|
||||
mDistance = 0;
|
||||
if(mDuration < 0)
|
||||
mDuration = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -235,7 +243,6 @@ namespace MWMechanics
|
|||
stopWalking(actor);
|
||||
// Reset package so it can be used again
|
||||
mRemainingDuration=mDuration;
|
||||
init();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -303,11 +310,6 @@ namespace MWMechanics
|
|||
return false; // AiWander package not yet completed
|
||||
}
|
||||
|
||||
bool AiWander::getRepeat() const
|
||||
{
|
||||
return mRepeat;
|
||||
}
|
||||
|
||||
osg::Vec3f AiWander::getDestination(const MWWorld::Ptr& actor) const
|
||||
{
|
||||
if (mHasDestination)
|
||||
|
@ -593,11 +595,6 @@ namespace MWMechanics
|
|||
}
|
||||
}
|
||||
|
||||
int AiWander::getTypeId() const
|
||||
{
|
||||
return TypeIdWander;
|
||||
}
|
||||
|
||||
void AiWander::stopWalking(const MWWorld::Ptr& actor)
|
||||
{
|
||||
mPathFinder.clearPath();
|
||||
|
@ -867,7 +864,7 @@ namespace MWMechanics
|
|||
assert (mIdle.size() == 8);
|
||||
for (int i=0; i<8; ++i)
|
||||
wander->mData.mIdle[i] = mIdle[i];
|
||||
wander->mData.mShouldRepeat = mRepeat;
|
||||
wander->mData.mShouldRepeat = mOptions.mRepeat;
|
||||
wander->mStoredInitialActorPosition = mStoredInitialActorPosition;
|
||||
if (mStoredInitialActorPosition)
|
||||
wander->mInitialActorPosition = mInitialActorPosition;
|
||||
|
@ -879,11 +876,12 @@ namespace MWMechanics
|
|||
}
|
||||
|
||||
AiWander::AiWander (const ESM::AiSequence::AiWander* wander)
|
||||
: mDistance(wander->mData.mDistance)
|
||||
, mDuration(wander->mData.mDuration)
|
||||
: TypedAiPackage<AiWander>(makeDefaultOptions().withRepeat(wander->mData.mShouldRepeat != 0))
|
||||
, mDistance(std::max(static_cast<short>(0), wander->mData.mDistance))
|
||||
, mDuration(std::max(static_cast<short>(0), wander->mData.mDuration))
|
||||
, mRemainingDuration(wander->mDurationData.mRemainingDuration)
|
||||
, mTimeOfDay(wander->mData.mTimeOfDay)
|
||||
, mRepeat(wander->mData.mShouldRepeat != 0)
|
||||
, mIdle(getInitialIdle(wander->mData.mIdle))
|
||||
, mStoredInitialActorPosition(wander->mStoredInitialActorPosition)
|
||||
, mHasDestination(false)
|
||||
, mDestination(osg::Vec3f(0, 0, 0))
|
||||
|
@ -891,11 +889,7 @@ namespace MWMechanics
|
|||
{
|
||||
if (mStoredInitialActorPosition)
|
||||
mInitialActorPosition = wander->mInitialActorPosition;
|
||||
for (int i=0; i<8; ++i)
|
||||
mIdle.push_back(wander->mData.mIdle[i]);
|
||||
if (mRemainingDuration <= 0 || mRemainingDuration >= 24)
|
||||
mRemainingDuration = mDuration;
|
||||
|
||||
init();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,16 +93,20 @@ namespace MWMechanics
|
|||
|
||||
bool execute(const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||
|
||||
int getTypeId() const final;
|
||||
static constexpr TypeId getTypeId() { return TypeIdWander; }
|
||||
|
||||
bool useVariableSpeed() const final { return true; }
|
||||
static constexpr Options makeDefaultOptions()
|
||||
{
|
||||
AiPackage::Options options;
|
||||
options.mUseVariableSpeed = true;
|
||||
options.mRepeat = false;
|
||||
return options;
|
||||
}
|
||||
|
||||
void writeState(ESM::AiSequence::AiSequence &sequence) const final;
|
||||
|
||||
void fastForward(const MWWorld::Ptr& actor, AiState& state) final;
|
||||
|
||||
bool getRepeat() const final;
|
||||
|
||||
osg::Vec3f getDestination(const MWWorld::Ptr& actor) const final;
|
||||
|
||||
osg::Vec3f getDestination() const final
|
||||
|
@ -114,8 +118,6 @@ namespace MWMechanics
|
|||
}
|
||||
|
||||
private:
|
||||
// NOTE: mDistance and mDuration must be set already
|
||||
void init();
|
||||
void stopWalking(const MWWorld::Ptr& actor);
|
||||
|
||||
/// Have the given actor play an idle animation
|
||||
|
@ -136,12 +138,11 @@ namespace MWMechanics
|
|||
bool destinationIsAtWater(const MWWorld::Ptr &actor, const osg::Vec3f& destination);
|
||||
void completeManualWalking(const MWWorld::Ptr &actor, AiWanderStorage &storage);
|
||||
|
||||
int mDistance; // how far the actor can wander from the spawn point
|
||||
int mDuration;
|
||||
const int mDistance; // how far the actor can wander from the spawn point
|
||||
const int mDuration;
|
||||
float mRemainingDuration;
|
||||
int mTimeOfDay;
|
||||
std::vector<unsigned char> mIdle;
|
||||
bool mRepeat;
|
||||
const int mTimeOfDay;
|
||||
const std::vector<unsigned char> mIdle;
|
||||
|
||||
bool mStoredInitialActorPosition;
|
||||
osg::Vec3f mInitialActorPosition; // Note: an original engine does not reset coordinates even when actor changes a cell
|
||||
|
@ -176,7 +177,7 @@ namespace MWMechanics
|
|||
static const std::string sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1];
|
||||
|
||||
static int OffsetToPreventOvercrowding();
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -468,7 +468,7 @@ MWMechanics::Alchemy::TEffectsIterator MWMechanics::Alchemy::endEffects() const
|
|||
|
||||
bool MWMechanics::Alchemy::knownEffect(unsigned int potionEffectIndex, const MWWorld::Ptr &npc)
|
||||
{
|
||||
int alchemySkill = npc.getClass().getSkill (npc, ESM::Skill::Alchemy);
|
||||
float alchemySkill = npc.getClass().getSkill (npc, ESM::Skill::Alchemy);
|
||||
static const float fWortChanceValue =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fWortChanceValue")->mValue.getFloat();
|
||||
return (potionEffectIndex <= 1 && alchemySkill >= fWortChanceValue)
|
||||
|
|
|
@ -2128,7 +2128,7 @@ void CharacterController::update(float duration, bool animationOnly)
|
|||
cls.onHit(mPtr, realHealthLost, true, MWWorld::Ptr(), MWWorld::Ptr(), osg::Vec3f(), true);
|
||||
}
|
||||
|
||||
const int acrobaticsSkill = cls.getSkill(mPtr, ESM::Skill::Acrobatics);
|
||||
const float acrobaticsSkill = cls.getSkill(mPtr, ESM::Skill::Acrobatics);
|
||||
if (healthLost > (acrobaticsSkill * fatigueTerm))
|
||||
{
|
||||
if (!godmode)
|
||||
|
|
|
@ -101,7 +101,7 @@ namespace MWMechanics
|
|||
blockerTerm *= gmst.find("fBlockStillBonus")->mValue.getFloat();
|
||||
blockerTerm *= blockerStats.getFatigueTerm();
|
||||
|
||||
int attackerSkill = 0;
|
||||
float attackerSkill = 0;
|
||||
if (weapon.isEmpty())
|
||||
attackerSkill = attacker.getClass().getSkill(attacker, ESM::Skill::HandToHand);
|
||||
else
|
||||
|
|
|
@ -126,7 +126,7 @@ namespace MWMechanics
|
|||
return mMagicEffects;
|
||||
}
|
||||
|
||||
void CreatureStats::setAttribute(int index, int base)
|
||||
void CreatureStats::setAttribute(int index, float base)
|
||||
{
|
||||
AttributeValue current = getAttribute(index);
|
||||
current.setBase(base);
|
||||
|
@ -152,10 +152,10 @@ namespace MWMechanics
|
|||
index == ESM::Attribute::Agility ||
|
||||
index == ESM::Attribute::Endurance)
|
||||
{
|
||||
int strength = getAttribute(ESM::Attribute::Strength).getModified();
|
||||
int willpower = getAttribute(ESM::Attribute::Willpower).getModified();
|
||||
int agility = getAttribute(ESM::Attribute::Agility).getModified();
|
||||
int endurance = getAttribute(ESM::Attribute::Endurance).getModified();
|
||||
float strength = getAttribute(ESM::Attribute::Strength).getModified();
|
||||
float willpower = getAttribute(ESM::Attribute::Willpower).getModified();
|
||||
float agility = getAttribute(ESM::Attribute::Agility).getModified();
|
||||
float endurance = getAttribute(ESM::Attribute::Endurance).getModified();
|
||||
DynamicStat<float> fatigue = getFatigue();
|
||||
float diff = (strength+willpower+agility+endurance) - fatigue.getBase();
|
||||
float currentToBaseRatio = fatigue.getBase() > 0 ? (fatigue.getCurrent() / fatigue.getBase()) : 0;
|
||||
|
|
|
@ -138,7 +138,7 @@ namespace MWMechanics
|
|||
|
||||
void setAttribute(int index, const AttributeValue &value);
|
||||
// Shortcut to set only the base
|
||||
void setAttribute(int index, int base);
|
||||
void setAttribute(int index, float base);
|
||||
|
||||
void setHealth(const DynamicStat<float> &value);
|
||||
|
||||
|
|
|
@ -688,10 +688,10 @@ namespace MWMechanics
|
|||
// I suppose the temporary disposition change (second param to getDerivedDisposition()) _has_ to be considered here,
|
||||
// otherwise one would get different prices when exiting and re-entering the dialogue window...
|
||||
int clampedDisposition = getDerivedDisposition(ptr);
|
||||
float a = static_cast<float>(std::min(playerPtr.getClass().getSkill(playerPtr, ESM::Skill::Mercantile), 100));
|
||||
float a = std::min(playerPtr.getClass().getSkill(playerPtr, ESM::Skill::Mercantile), 100.f);
|
||||
float b = std::min(0.1f * playerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f);
|
||||
float c = std::min(0.2f * playerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f);
|
||||
float d = static_cast<float>(std::min(ptr.getClass().getSkill(ptr, ESM::Skill::Mercantile), 100));
|
||||
float d = std::min(ptr.getClass().getSkill(ptr, ESM::Skill::Mercantile), 100.f);
|
||||
float e = std::min(0.1f * sellerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f);
|
||||
float f = std::min(0.2f * sellerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f);
|
||||
float pcTerm = (clampedDisposition - 50 + a + b + c) * playerStats.getFatigueTerm();
|
||||
|
@ -1621,8 +1621,8 @@ namespace MWMechanics
|
|||
static float fSneakSkillMult = store.find("fSneakSkillMult")->mValue.getFloat();
|
||||
static float fSneakBootMult = store.find("fSneakBootMult")->mValue.getFloat();
|
||||
float sneak = static_cast<float>(ptr.getClass().getSkill(ptr, ESM::Skill::Sneak));
|
||||
int agility = stats.getAttribute(ESM::Attribute::Agility).getModified();
|
||||
int luck = stats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||
float agility = stats.getAttribute(ESM::Attribute::Agility).getModified();
|
||||
float luck = stats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||
float bootWeight = 0;
|
||||
if (ptr.getClass().isNpc() && MWBase::Environment::get().getWorld()->isOnGround(ptr))
|
||||
{
|
||||
|
@ -1645,10 +1645,10 @@ namespace MWMechanics
|
|||
float x = sneakTerm * distTerm * stats.getFatigueTerm() + chameleon + invisibility;
|
||||
|
||||
CreatureStats& observerStats = observer.getClass().getCreatureStats(observer);
|
||||
int obsAgility = observerStats.getAttribute(ESM::Attribute::Agility).getModified();
|
||||
int obsLuck = observerStats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||
float obsAgility = observerStats.getAttribute(ESM::Attribute::Agility).getModified();
|
||||
float obsLuck = observerStats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||
float obsBlind = observerStats.getMagicEffects().get(ESM::MagicEffect::Blind).getMagnitude();
|
||||
int obsSneak = observer.getClass().getSkill(observer, ESM::Skill::Sneak);
|
||||
float obsSneak = observer.getClass().getSkill(observer, ESM::Skill::Sneak);
|
||||
|
||||
float obsTerm = obsSneak + 0.2f * obsAgility + 0.1f * obsLuck - obsBlind;
|
||||
|
||||
|
|
|
@ -226,9 +226,9 @@ void MWMechanics::NpcStats::useSkill (int skillIndex, const ESM::Class& class_,
|
|||
|
||||
void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &class_, bool preserveProgress, bool readBook)
|
||||
{
|
||||
int base = getSkill (skillIndex).getBase();
|
||||
float base = getSkill (skillIndex).getBase();
|
||||
|
||||
if (base >= 100)
|
||||
if (base >= 100.f)
|
||||
return;
|
||||
|
||||
base += 1;
|
||||
|
@ -265,7 +265,7 @@ void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &clas
|
|||
MWBase::Environment::get().getWindowManager()->playSound("skillraise");
|
||||
|
||||
std::string message = MWBase::Environment::get().getWindowManager ()->getGameSettingString ("sNotifyMessage39", "");
|
||||
message = Misc::StringUtils::format(message, ("#{" + ESM::Skill::sSkillNameIds[skillIndex] + "}"), base);
|
||||
message = Misc::StringUtils::format(message, ("#{" + ESM::Skill::sSkillNameIds[skillIndex] + "}"), static_cast<int>(base));
|
||||
|
||||
if (readBook)
|
||||
message = "#{sBookSkillMessage}\n" + message;
|
||||
|
@ -299,7 +299,7 @@ void MWMechanics::NpcStats::levelUp()
|
|||
for (int i=0; i<ESM::Attribute::Length; ++i)
|
||||
mSkillIncreases[i] = 0;
|
||||
|
||||
const int endurance = getAttribute(ESM::Attribute::Endurance).getBase();
|
||||
const float endurance = getAttribute(ESM::Attribute::Endurance).getBase();
|
||||
|
||||
// "When you gain a level, in addition to increasing three primary attributes, your Health
|
||||
// will automatically increase by 10% of your Endurance attribute. If you increased Endurance this level,
|
||||
|
@ -316,8 +316,8 @@ void MWMechanics::NpcStats::levelUp()
|
|||
|
||||
void MWMechanics::NpcStats::updateHealth()
|
||||
{
|
||||
const int endurance = getAttribute(ESM::Attribute::Endurance).getBase();
|
||||
const int strength = getAttribute(ESM::Attribute::Strength).getBase();
|
||||
const float endurance = getAttribute(ESM::Attribute::Endurance).getBase();
|
||||
const float strength = getAttribute(ESM::Attribute::Strength).getBase();
|
||||
|
||||
setHealth(floor(0.5f * (strength + endurance)));
|
||||
}
|
||||
|
|
|
@ -22,8 +22,8 @@ namespace MWMechanics
|
|||
float Pickpocket::getChanceModifier(const MWWorld::Ptr &ptr, float add)
|
||||
{
|
||||
NpcStats& stats = ptr.getClass().getNpcStats(ptr);
|
||||
float agility = static_cast<float>(stats.getAttribute(ESM::Attribute::Agility).getModified());
|
||||
float luck = static_cast<float>(stats.getAttribute(ESM::Attribute::Luck).getModified());
|
||||
float agility = stats.getAttribute(ESM::Attribute::Agility).getModified();
|
||||
float luck = stats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||
float sneak = static_cast<float>(ptr.getClass().getSkill(ptr, ESM::Skill::Sneak));
|
||||
return (add + 0.2f * agility + 0.1f * luck + sneak) * stats.getFatigueTerm();
|
||||
}
|
||||
|
|
|
@ -32,9 +32,9 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair)
|
|||
MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player);
|
||||
|
||||
float fatigueTerm = stats.getFatigueTerm();
|
||||
int pcStrength = stats.getAttribute(ESM::Attribute::Strength).getModified();
|
||||
int pcLuck = stats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||
int armorerSkill = player.getClass().getSkill(player, ESM::Skill::Armorer);
|
||||
float pcStrength = stats.getAttribute(ESM::Attribute::Strength).getModified();
|
||||
float pcLuck = stats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||
float armorerSkill = player.getClass().getSkill(player, ESM::Skill::Armorer);
|
||||
|
||||
float fRepairAmountMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||
.find("fRepairAmountMult")->mValue.getFloat();
|
||||
|
|
|
@ -19,8 +19,8 @@ namespace MWMechanics
|
|||
: mActor(actor)
|
||||
{
|
||||
CreatureStats& creatureStats = actor.getClass().getCreatureStats(actor);
|
||||
mAgility = static_cast<float>(creatureStats.getAttribute(ESM::Attribute::Agility).getModified());
|
||||
mLuck = static_cast<float>(creatureStats.getAttribute(ESM::Attribute::Luck).getModified());
|
||||
mAgility = creatureStats.getAttribute(ESM::Attribute::Agility).getModified();
|
||||
mLuck = creatureStats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||
mSecuritySkill = static_cast<float>(actor.getClass().getSkill(actor, ESM::Skill::Security));
|
||||
mFatigueTerm = creatureStats.getFatigueTerm();
|
||||
}
|
||||
|
|
|
@ -40,8 +40,8 @@ namespace MWMechanics
|
|||
|
||||
float resistance = getEffectResistanceAttribute(effectId, magicEffects);
|
||||
|
||||
int willpower = stats.getAttribute(ESM::Attribute::Willpower).getModified();
|
||||
float luck = static_cast<float>(stats.getAttribute(ESM::Attribute::Luck).getModified());
|
||||
float willpower = stats.getAttribute(ESM::Attribute::Willpower).getModified();
|
||||
float luck = stats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||
float x = (willpower + 0.1f * luck) * stats.getFatigueTerm();
|
||||
|
||||
// This makes spells that are easy to cast harder to resist and vice versa
|
||||
|
|
|
@ -94,8 +94,8 @@ namespace MWMechanics
|
|||
|
||||
CreatureStats& stats = actor.getClass().getCreatureStats(actor);
|
||||
|
||||
int actorWillpower = stats.getAttribute(ESM::Attribute::Willpower).getModified();
|
||||
int actorLuck = stats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||
float actorWillpower = stats.getAttribute(ESM::Attribute::Willpower).getModified();
|
||||
float actorLuck = stats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||
|
||||
float castChance = (lowestSkill - spell->mData.mCost + 0.2f * actorWillpower + 0.1f * actorLuck);
|
||||
|
||||
|
|
|
@ -227,29 +227,29 @@ namespace MWMechanics
|
|||
}
|
||||
|
||||
AttributeValue::AttributeValue() :
|
||||
mBase(0), mModifier(0), mDamage(0)
|
||||
mBase(0.f), mModifier(0.f), mDamage(0.f)
|
||||
{
|
||||
}
|
||||
|
||||
int AttributeValue::getModified() const
|
||||
float AttributeValue::getModified() const
|
||||
{
|
||||
return std::max(0, mBase - (int) mDamage + mModifier);
|
||||
return std::max(0.f, mBase - mDamage + mModifier);
|
||||
}
|
||||
int AttributeValue::getBase() const
|
||||
float AttributeValue::getBase() const
|
||||
{
|
||||
return mBase;
|
||||
}
|
||||
int AttributeValue::getModifier() const
|
||||
float AttributeValue::getModifier() const
|
||||
{
|
||||
return mModifier;
|
||||
}
|
||||
|
||||
void AttributeValue::setBase(int base)
|
||||
void AttributeValue::setBase(float base)
|
||||
{
|
||||
mBase = base;
|
||||
}
|
||||
|
||||
void AttributeValue::setModifier(int mod)
|
||||
void AttributeValue::setModifier(float mod)
|
||||
{
|
||||
mModifier = mod;
|
||||
}
|
||||
|
@ -275,14 +275,14 @@ namespace MWMechanics
|
|||
return mDamage;
|
||||
}
|
||||
|
||||
void AttributeValue::writeState (ESM::StatState<int>& state) const
|
||||
void AttributeValue::writeState (ESM::StatState<float>& state) const
|
||||
{
|
||||
state.mBase = mBase;
|
||||
state.mMod = mModifier;
|
||||
state.mDamage = mDamage;
|
||||
}
|
||||
|
||||
void AttributeValue::readState (const ESM::StatState<int>& state)
|
||||
void AttributeValue::readState (const ESM::StatState<float>& state)
|
||||
{
|
||||
mBase = state.mBase;
|
||||
mModifier = state.mMod;
|
||||
|
@ -303,13 +303,13 @@ namespace MWMechanics
|
|||
mProgress = progress;
|
||||
}
|
||||
|
||||
void SkillValue::writeState (ESM::StatState<int>& state) const
|
||||
void SkillValue::writeState (ESM::StatState<float>& state) const
|
||||
{
|
||||
AttributeValue::writeState (state);
|
||||
state.mProgress = mProgress;
|
||||
}
|
||||
|
||||
void SkillValue::readState (const ESM::StatState<int>& state)
|
||||
void SkillValue::readState (const ESM::StatState<float>& state)
|
||||
{
|
||||
AttributeValue::readState (state);
|
||||
mProgress = state.mProgress;
|
||||
|
|
|
@ -122,20 +122,20 @@ namespace MWMechanics
|
|||
|
||||
class AttributeValue
|
||||
{
|
||||
int mBase;
|
||||
int mModifier;
|
||||
float mBase;
|
||||
float mModifier;
|
||||
float mDamage; // needs to be float to allow continuous damage
|
||||
|
||||
public:
|
||||
AttributeValue();
|
||||
|
||||
int getModified() const;
|
||||
int getBase() const;
|
||||
int getModifier() const;
|
||||
float getModified() const;
|
||||
float getBase() const;
|
||||
float getModifier() const;
|
||||
|
||||
void setBase(int base);
|
||||
void setBase(float base);
|
||||
|
||||
void setModifier(int mod);
|
||||
void setModifier(float mod);
|
||||
|
||||
// Maximum attribute damage is limited to the modified value.
|
||||
// Note: I think MW applies damage directly to mModified, since you can also
|
||||
|
@ -145,8 +145,8 @@ namespace MWMechanics
|
|||
|
||||
float getDamage() const;
|
||||
|
||||
void writeState (ESM::StatState<int>& state) const;
|
||||
void readState (const ESM::StatState<int>& state);
|
||||
void writeState (ESM::StatState<float>& state) const;
|
||||
void readState (const ESM::StatState<float>& state);
|
||||
};
|
||||
|
||||
class SkillValue : public AttributeValue
|
||||
|
@ -157,8 +157,8 @@ namespace MWMechanics
|
|||
float getProgress() const;
|
||||
void setProgress(float progress);
|
||||
|
||||
void writeState (ESM::StatState<int>& state) const;
|
||||
void readState (const ESM::StatState<int>& state);
|
||||
void writeState (ESM::StatState<float>& state) const;
|
||||
void readState (const ESM::StatState<float>& state);
|
||||
};
|
||||
|
||||
inline bool operator== (const AttributeValue& left, const AttributeValue& right)
|
||||
|
|
|
@ -8,6 +8,16 @@ namespace MWMechanics
|
|||
template <class T>
|
||||
struct TypedAiPackage : public AiPackage
|
||||
{
|
||||
TypedAiPackage() :
|
||||
AiPackage(T::getTypeId(), T::makeDefaultOptions()) {}
|
||||
|
||||
TypedAiPackage(const Options& options) :
|
||||
AiPackage(T::getTypeId(), options) {}
|
||||
|
||||
template <class Derived>
|
||||
TypedAiPackage(Derived*) :
|
||||
AiPackage(Derived::getTypeId(), Derived::makeDefaultOptions()) {}
|
||||
|
||||
virtual std::unique_ptr<AiPackage> clone() const override
|
||||
{
|
||||
return std::make_unique<T>(*static_cast<const T*>(this));
|
||||
|
|
104
apps/openmw/mwrender/fogmanager.cpp
Normal file
104
apps/openmw/mwrender/fogmanager.cpp
Normal file
|
@ -0,0 +1,104 @@
|
|||
#include "fogmanager.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <components/esm/loadcell.hpp>
|
||||
#include <components/fallback/fallback.hpp>
|
||||
#include <components/sceneutil/util.hpp>
|
||||
#include <components/settings/settings.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
float DLLandFogStart;
|
||||
float DLLandFogEnd;
|
||||
float DLUnderwaterFogStart;
|
||||
float DLUnderwaterFogEnd;
|
||||
float DLInteriorFogStart;
|
||||
float DLInteriorFogEnd;
|
||||
}
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
FogManager::FogManager()
|
||||
: mLandFogStart(0.f)
|
||||
, mLandFogEnd(std::numeric_limits<float>::max())
|
||||
, mUnderwaterFogStart(0.f)
|
||||
, mUnderwaterFogEnd(std::numeric_limits<float>::max())
|
||||
, mFogColor(osg::Vec4f())
|
||||
, mDistantFog(Settings::Manager::getBool("use distant fog", "Fog"))
|
||||
, mUnderwaterColor(Fallback::Map::getColour("Water_UnderwaterColor"))
|
||||
, mUnderwaterWeight(Fallback::Map::getFloat("Water_UnderwaterColorWeight"))
|
||||
, mUnderwaterIndoorFog(Fallback::Map::getFloat("Water_UnderwaterIndoorFog"))
|
||||
{
|
||||
DLLandFogStart = Settings::Manager::getFloat("distant land fog start", "Fog");
|
||||
DLLandFogEnd = Settings::Manager::getFloat("distant land fog end", "Fog");
|
||||
DLUnderwaterFogStart = Settings::Manager::getFloat("distant underwater fog start", "Fog");
|
||||
DLUnderwaterFogEnd = Settings::Manager::getFloat("distant underwater fog end", "Fog");
|
||||
DLInteriorFogStart = Settings::Manager::getFloat("distant interior fog start", "Fog");
|
||||
DLInteriorFogEnd = Settings::Manager::getFloat("distant interior fog end", "Fog");
|
||||
}
|
||||
|
||||
void FogManager::configure(float viewDistance, const ESM::Cell *cell)
|
||||
{
|
||||
osg::Vec4f color = SceneUtil::colourFromRGB(cell->mAmbi.mFog);
|
||||
|
||||
if (mDistantFog)
|
||||
{
|
||||
float density = std::max(0.2f, cell->mAmbi.mFogDensity);
|
||||
mLandFogStart = DLInteriorFogEnd * (1.0f - density) + DLInteriorFogStart*density;
|
||||
mLandFogEnd = DLInteriorFogEnd;
|
||||
mUnderwaterFogStart = DLUnderwaterFogStart;
|
||||
mUnderwaterFogEnd = DLUnderwaterFogEnd;
|
||||
mFogColor = color;
|
||||
}
|
||||
else
|
||||
configure(viewDistance, cell->mAmbi.mFogDensity, mUnderwaterIndoorFog, 1.0f, 0.0f, color);
|
||||
}
|
||||
|
||||
void FogManager::configure(float viewDistance, float fogDepth, float underwaterFog, float dlFactor, float dlOffset, const osg::Vec4f &color)
|
||||
{
|
||||
if (mDistantFog)
|
||||
{
|
||||
mLandFogStart = dlFactor * (DLLandFogStart - dlOffset * DLLandFogEnd);
|
||||
mLandFogEnd = dlFactor * (1.0f - dlOffset) * DLLandFogEnd;
|
||||
mUnderwaterFogStart = DLUnderwaterFogStart;
|
||||
mUnderwaterFogEnd = DLUnderwaterFogEnd;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fogDepth == 0.0)
|
||||
{
|
||||
mLandFogStart = 0.0f;
|
||||
mLandFogEnd = std::numeric_limits<float>::max();
|
||||
}
|
||||
else
|
||||
{
|
||||
mLandFogStart = viewDistance * (1 - fogDepth);
|
||||
mLandFogEnd = viewDistance;
|
||||
}
|
||||
mUnderwaterFogStart = std::min(viewDistance, 6666.f) * (1 - underwaterFog);
|
||||
mUnderwaterFogEnd = std::min(viewDistance, 6666.f);
|
||||
}
|
||||
mFogColor = color;
|
||||
}
|
||||
|
||||
float FogManager::getFogStart(bool isUnderwater) const
|
||||
{
|
||||
return isUnderwater ? mUnderwaterFogStart : mLandFogStart;
|
||||
}
|
||||
|
||||
float FogManager::getFogEnd(bool isUnderwater) const
|
||||
{
|
||||
return isUnderwater ? mUnderwaterFogEnd : mLandFogEnd;
|
||||
}
|
||||
|
||||
osg::Vec4f FogManager::getFogColor(bool isUnderwater) const
|
||||
{
|
||||
if (isUnderwater)
|
||||
{
|
||||
return mUnderwaterColor * mUnderwaterWeight + mFogColor * (1.f-mUnderwaterWeight);
|
||||
}
|
||||
|
||||
return mFogColor;
|
||||
}
|
||||
}
|
39
apps/openmw/mwrender/fogmanager.hpp
Normal file
39
apps/openmw/mwrender/fogmanager.hpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
#ifndef OPENMW_MWRENDER_FOGMANAGER_H
|
||||
#define OPENMW_MWRENDER_FOGMANAGER_H
|
||||
|
||||
#include <osg/Vec4f>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
struct Cell;
|
||||
}
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
class FogManager
|
||||
{
|
||||
public:
|
||||
FogManager();
|
||||
|
||||
void configure(float viewDistance, const ESM::Cell *cell);
|
||||
void configure(float viewDistance, float fogDepth, float underwaterFog, float dlFactor, float dlOffset, const osg::Vec4f &color);
|
||||
|
||||
osg::Vec4f getFogColor(bool isUnderwater) const;
|
||||
float getFogStart(bool isUnderwater) const;
|
||||
float getFogEnd(bool isUnderwater) const;
|
||||
|
||||
private:
|
||||
float mLandFogStart;
|
||||
float mLandFogEnd;
|
||||
float mUnderwaterFogStart;
|
||||
float mUnderwaterFogEnd;
|
||||
osg::Vec4f mFogColor;
|
||||
bool mDistantFog;
|
||||
|
||||
osg::Vec4f mUnderwaterColor;
|
||||
float mUnderwaterWeight;
|
||||
float mUnderwaterIndoorFog;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -69,16 +69,7 @@
|
|||
#include "navmesh.hpp"
|
||||
#include "actorspaths.hpp"
|
||||
#include "recastmesh.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
float DLLandFogStart;
|
||||
float DLLandFogEnd;
|
||||
float DLUnderwaterFogStart;
|
||||
float DLUnderwaterFogEnd;
|
||||
float DLInteriorFogStart;
|
||||
float DLInteriorFogEnd;
|
||||
}
|
||||
#include "fogmanager.hpp"
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
|
@ -204,19 +195,9 @@ namespace MWRender
|
|||
, mWorkQueue(workQueue)
|
||||
, mUnrefQueue(new SceneUtil::UnrefQueue)
|
||||
, mNavigator(navigator)
|
||||
, mLandFogStart(0.f)
|
||||
, mLandFogEnd(std::numeric_limits<float>::max())
|
||||
, mUnderwaterFogStart(0.f)
|
||||
, mUnderwaterFogEnd(std::numeric_limits<float>::max())
|
||||
, mUnderwaterColor(Fallback::Map::getColour("Water_UnderwaterColor"))
|
||||
, mUnderwaterWeight(Fallback::Map::getFloat("Water_UnderwaterColorWeight"))
|
||||
, mUnderwaterIndoorFog(Fallback::Map::getFloat("Water_UnderwaterIndoorFog"))
|
||||
, mNightEyeFactor(0.f)
|
||||
, mDistantFog(false)
|
||||
, mDistantTerrain(false)
|
||||
, mFieldOfViewOverridden(false)
|
||||
, mFieldOfViewOverride(0.f)
|
||||
, mBorders(false)
|
||||
{
|
||||
resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem);
|
||||
resourceSystem->getSceneManager()->setShaderPath(resourcePath + "/shaders");
|
||||
|
@ -284,16 +265,6 @@ namespace MWRender
|
|||
|
||||
mEffectManager.reset(new EffectManager(sceneRoot, mResourceSystem));
|
||||
|
||||
DLLandFogStart = Settings::Manager::getFloat("distant land fog start", "Fog");
|
||||
DLLandFogEnd = Settings::Manager::getFloat("distant land fog end", "Fog");
|
||||
DLUnderwaterFogStart = Settings::Manager::getFloat("distant underwater fog start", "Fog");
|
||||
DLUnderwaterFogEnd = Settings::Manager::getFloat("distant underwater fog end", "Fog");
|
||||
DLInteriorFogStart = Settings::Manager::getFloat("distant interior fog start", "Fog");
|
||||
DLInteriorFogEnd = Settings::Manager::getFloat("distant interior fog end", "Fog");
|
||||
|
||||
mDistantFog = Settings::Manager::getBool("use distant fog", "Fog");
|
||||
mDistantTerrain = Settings::Manager::getBool("distant terrain", "Terrain");
|
||||
|
||||
const std::string normalMapPattern = Settings::Manager::getString("normal map pattern", "Shaders");
|
||||
const std::string heightMapPattern = Settings::Manager::getString("normal height map pattern", "Shaders");
|
||||
const std::string specularMapPattern = Settings::Manager::getString("terrain specular map pattern", "Shaders");
|
||||
|
@ -302,7 +273,7 @@ namespace MWRender
|
|||
|
||||
mTerrainStorage = new TerrainStorage(mResourceSystem, normalMapPattern, heightMapPattern, useTerrainNormalMaps, specularMapPattern, useTerrainSpecularMaps);
|
||||
|
||||
if (mDistantTerrain)
|
||||
if (Settings::Manager::getBool("distant terrain", "Terrain"))
|
||||
{
|
||||
const int compMapResolution = Settings::Manager::getInt("composite map resolution", "Terrain");
|
||||
int compMapPower = Settings::Manager::getInt("composite map level", "Terrain");
|
||||
|
@ -349,8 +320,9 @@ namespace MWRender
|
|||
defaultMat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.f));
|
||||
sceneRoot->getOrCreateStateSet()->setAttribute(defaultMat);
|
||||
|
||||
mSky.reset(new SkyManager(sceneRoot, resourceSystem->getSceneManager()));
|
||||
mFog.reset(new FogManager());
|
||||
|
||||
mSky.reset(new SkyManager(sceneRoot, resourceSystem->getSceneManager()));
|
||||
mSky->setCamera(mViewer->getCamera());
|
||||
mSky->setRainIntensityUniform(mWater->getRainIntensityUniform());
|
||||
|
||||
|
@ -558,9 +530,9 @@ namespace MWRender
|
|||
|
||||
bool RenderingManager::toggleBorders()
|
||||
{
|
||||
mBorders = !mBorders;
|
||||
mTerrain->setBordersVisible(mBorders);
|
||||
return mBorders;
|
||||
bool borders = !mTerrain->getBordersVisible();
|
||||
mTerrain->setBordersVisible(borders);
|
||||
return borders;
|
||||
}
|
||||
|
||||
bool RenderingManager::toggleRenderMode(RenderMode mode)
|
||||
|
@ -606,46 +578,12 @@ namespace MWRender
|
|||
|
||||
void RenderingManager::configureFog(const ESM::Cell *cell)
|
||||
{
|
||||
osg::Vec4f color = SceneUtil::colourFromRGB(cell->mAmbi.mFog);
|
||||
|
||||
if(mDistantFog)
|
||||
{
|
||||
float density = std::max(0.2f, cell->mAmbi.mFogDensity);
|
||||
mLandFogStart = (DLInteriorFogEnd*(1.0f-density) + DLInteriorFogStart*density);
|
||||
mLandFogEnd = DLInteriorFogEnd;
|
||||
mUnderwaterFogStart = DLUnderwaterFogStart;
|
||||
mUnderwaterFogEnd = DLUnderwaterFogEnd;
|
||||
mFogColor = color;
|
||||
}
|
||||
else
|
||||
configureFog(cell->mAmbi.mFogDensity, mUnderwaterIndoorFog, 1.0f, 0.0f, color);
|
||||
mFog->configure(mViewDistance, cell);
|
||||
}
|
||||
|
||||
void RenderingManager::configureFog(float fogDepth, float underwaterFog, float dlFactor, float dlOffset, const osg::Vec4f &color)
|
||||
{
|
||||
if(mDistantFog)
|
||||
{
|
||||
mLandFogStart = dlFactor * (DLLandFogStart - dlOffset*DLLandFogEnd);
|
||||
mLandFogEnd = dlFactor * (1.0f-dlOffset) * DLLandFogEnd;
|
||||
mUnderwaterFogStart = DLUnderwaterFogStart;
|
||||
mUnderwaterFogEnd = DLUnderwaterFogEnd;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(fogDepth == 0.0)
|
||||
{
|
||||
mLandFogStart = 0.0f;
|
||||
mLandFogEnd = std::numeric_limits<float>::max();
|
||||
}
|
||||
else
|
||||
{
|
||||
mLandFogStart = mViewDistance * (1 - fogDepth);
|
||||
mLandFogEnd = mViewDistance;
|
||||
}
|
||||
mUnderwaterFogStart = std::min(mViewDistance, 6666.f) * (1 - underwaterFog);
|
||||
mUnderwaterFogEnd = std::min(mViewDistance, 6666.f);
|
||||
}
|
||||
mFogColor = color;
|
||||
mFog->configure(mViewDistance, fogDepth, underwaterFog, dlFactor, dlOffset, color);
|
||||
}
|
||||
|
||||
SkyManager* RenderingManager::getSkyManager()
|
||||
|
@ -674,19 +612,11 @@ namespace MWRender
|
|||
osg::Vec3f focal, cameraPos;
|
||||
mCamera->getPosition(focal, cameraPos);
|
||||
mCurrentCameraPos = cameraPos;
|
||||
if (mWater->isUnderwater(cameraPos))
|
||||
{
|
||||
setFogColor(mUnderwaterColor * mUnderwaterWeight + mFogColor * (1.f-mUnderwaterWeight));
|
||||
mStateUpdater->setFogStart(mUnderwaterFogStart);
|
||||
mStateUpdater->setFogEnd(mUnderwaterFogEnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
setFogColor(mFogColor);
|
||||
|
||||
mStateUpdater->setFogStart(mLandFogStart);
|
||||
mStateUpdater->setFogEnd(mLandFogEnd);
|
||||
}
|
||||
bool isUnderwater = mWater->isUnderwater(cameraPos);
|
||||
mStateUpdater->setFogStart(mFog->getFogStart(isUnderwater));
|
||||
mStateUpdater->setFogEnd(mFog->getFogEnd(isUnderwater));
|
||||
setFogColor(mFog->getFogColor(isUnderwater));
|
||||
}
|
||||
|
||||
void RenderingManager::updatePlayerPtr(const MWWorld::Ptr &ptr)
|
||||
|
@ -1335,7 +1265,7 @@ namespace MWRender
|
|||
else if (it->first == "Camera" && it->second == "viewing distance")
|
||||
{
|
||||
mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera");
|
||||
if(!mDistantFog)
|
||||
if(!Settings::Manager::getBool("use distant fog", "Fog"))
|
||||
mStateUpdater->setFogEnd(mViewDistance);
|
||||
updateProjectionMatrix();
|
||||
}
|
||||
|
|
|
@ -73,6 +73,7 @@ namespace MWRender
|
|||
class StateUpdater;
|
||||
|
||||
class EffectManager;
|
||||
class FogManager;
|
||||
class SkyManager;
|
||||
class NpcAnimation;
|
||||
class Pathgrid;
|
||||
|
@ -275,6 +276,7 @@ namespace MWRender
|
|||
std::unique_ptr<Terrain::World> mTerrain;
|
||||
TerrainStorage* mTerrainStorage;
|
||||
std::unique_ptr<SkyManager> mSky;
|
||||
std::unique_ptr<FogManager> mFog;
|
||||
std::unique_ptr<EffectManager> mEffectManager;
|
||||
std::unique_ptr<SceneUtil::ShadowManager> mShadowManager;
|
||||
osg::ref_ptr<NpcAnimation> mPlayerAnimation;
|
||||
|
@ -284,27 +286,15 @@ namespace MWRender
|
|||
|
||||
osg::ref_ptr<StateUpdater> mStateUpdater;
|
||||
|
||||
float mLandFogStart;
|
||||
float mLandFogEnd;
|
||||
float mUnderwaterFogStart;
|
||||
float mUnderwaterFogEnd;
|
||||
osg::Vec4f mUnderwaterColor;
|
||||
float mUnderwaterWeight;
|
||||
float mUnderwaterIndoorFog;
|
||||
osg::Vec4f mFogColor;
|
||||
|
||||
osg::Vec4f mAmbientColor;
|
||||
float mNightEyeFactor;
|
||||
|
||||
float mNearClip;
|
||||
float mViewDistance;
|
||||
bool mDistantFog : 1;
|
||||
bool mDistantTerrain : 1;
|
||||
bool mFieldOfViewOverridden : 1;
|
||||
bool mFieldOfViewOverridden;
|
||||
float mFieldOfViewOverride;
|
||||
float mFieldOfView;
|
||||
float mFirstPersonFieldOfView;
|
||||
bool mBorders;
|
||||
|
||||
void operator = (const RenderingManager&);
|
||||
RenderingManager(const RenderingManager&);
|
||||
|
|
|
@ -95,7 +95,7 @@ namespace MWScript
|
|||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
Interpreter::Type_Integer value =
|
||||
Interpreter::Type_Float value =
|
||||
ptr.getClass()
|
||||
.getCreatureStats (ptr)
|
||||
.getAttribute(mIndex)
|
||||
|
@ -118,7 +118,7 @@ namespace MWScript
|
|||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
Interpreter::Type_Integer value = runtime[0].mInteger;
|
||||
Interpreter::Type_Float value = runtime[0].mFloat;
|
||||
runtime.pop();
|
||||
|
||||
MWMechanics::AttributeValue attribute = ptr.getClass().getCreatureStats(ptr).getAttribute(mIndex);
|
||||
|
@ -140,7 +140,7 @@ namespace MWScript
|
|||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
Interpreter::Type_Integer value = runtime[0].mInteger;
|
||||
Interpreter::Type_Float value = runtime[0].mFloat;
|
||||
runtime.pop();
|
||||
|
||||
MWMechanics::AttributeValue attribute = ptr.getClass()
|
||||
|
@ -155,9 +155,9 @@ namespace MWScript
|
|||
return;
|
||||
|
||||
if (value < 0)
|
||||
attribute.setBase(std::max(0, attribute.getBase() + value));
|
||||
attribute.setBase(std::max(0.f, attribute.getBase() + value));
|
||||
else
|
||||
attribute.setBase(std::min(100, attribute.getBase() + value));
|
||||
attribute.setBase(std::min(100.f, attribute.getBase() + value));
|
||||
|
||||
ptr.getClass().getCreatureStats(ptr).setAttribute(mIndex, attribute);
|
||||
}
|
||||
|
@ -345,7 +345,7 @@ namespace MWScript
|
|||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
Interpreter::Type_Integer value = ptr.getClass().getSkill(ptr, mIndex);
|
||||
Interpreter::Type_Float value = ptr.getClass().getSkill(ptr, mIndex);
|
||||
|
||||
runtime.push (value);
|
||||
}
|
||||
|
@ -364,7 +364,7 @@ namespace MWScript
|
|||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
Interpreter::Type_Integer value = runtime[0].mInteger;
|
||||
Interpreter::Type_Float value = runtime[0].mFloat;
|
||||
runtime.pop();
|
||||
|
||||
MWMechanics::NpcStats& stats = ptr.getClass().getNpcStats (ptr);
|
||||
|
@ -386,7 +386,7 @@ namespace MWScript
|
|||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
Interpreter::Type_Integer value = runtime[0].mInteger;
|
||||
Interpreter::Type_Float value = runtime[0].mFloat;
|
||||
runtime.pop();
|
||||
|
||||
MWMechanics::SkillValue &skill = ptr.getClass()
|
||||
|
@ -396,14 +396,14 @@ namespace MWScript
|
|||
if (value == 0)
|
||||
return;
|
||||
|
||||
if (((skill.getBase() <= 0) && (value < 0))
|
||||
|| ((skill.getBase() >= 100) && (value > 0)))
|
||||
if (((skill.getBase() <= 0.f) && (value < 0.f))
|
||||
|| ((skill.getBase() >= 100.f) && (value > 0.f)))
|
||||
return;
|
||||
|
||||
if (value < 0)
|
||||
skill.setBase(std::max(0, skill.getBase() + value));
|
||||
skill.setBase(std::max(0.f, skill.getBase() + value));
|
||||
else
|
||||
skill.setBase(std::min(100, skill.getBase() + value));
|
||||
skill.setBase(std::min(100.f, skill.getBase() + value));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -213,11 +213,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
|
|||
profile.mPlayerClassId = classId;
|
||||
|
||||
profile.mPlayerCell = world.getCellName();
|
||||
|
||||
profile.mInGameTime.mGameHour = world.getTimeStamp().getHour();
|
||||
profile.mInGameTime.mDay = world.getDay();
|
||||
profile.mInGameTime.mMonth = world.getMonth();
|
||||
profile.mInGameTime.mYear = world.getYear();
|
||||
profile.mInGameTime = world.getEpochTimeStamp();
|
||||
profile.mTimePlayed = mTimePlayed;
|
||||
profile.mDescription = description;
|
||||
|
||||
|
|
|
@ -421,7 +421,7 @@ namespace MWWorld
|
|||
return canSwim(ptr) || canWalk(ptr) || canFly(ptr);
|
||||
}
|
||||
|
||||
int Class::getSkill(const MWWorld::Ptr& ptr, int skill) const
|
||||
float Class::getSkill(const MWWorld::Ptr& ptr, int skill) const
|
||||
{
|
||||
throw std::runtime_error("class does not support skills");
|
||||
}
|
||||
|
|
|
@ -321,7 +321,7 @@ namespace MWWorld
|
|||
bool isPureLandCreature(const MWWorld::Ptr& ptr) const;
|
||||
bool isMobile(const MWWorld::Ptr& ptr) const;
|
||||
|
||||
virtual int getSkill(const MWWorld::Ptr& ptr, int skill) const;
|
||||
virtual float getSkill(const MWWorld::Ptr& ptr, int skill) const;
|
||||
|
||||
virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||
const;
|
||||
|
|
227
apps/openmw/mwworld/datetimemanager.cpp
Normal file
227
apps/openmw/mwworld/datetimemanager.cpp
Normal file
|
@ -0,0 +1,227 @@
|
|||
#include "datetimemanager.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
#include "esmstore.hpp"
|
||||
#include "globals.hpp"
|
||||
#include "timestamp.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
static int getDaysPerMonth(int month)
|
||||
{
|
||||
switch (month)
|
||||
{
|
||||
case 0: return 31;
|
||||
case 1: return 28;
|
||||
case 2: return 31;
|
||||
case 3: return 30;
|
||||
case 4: return 31;
|
||||
case 5: return 30;
|
||||
case 6: return 31;
|
||||
case 7: return 31;
|
||||
case 8: return 30;
|
||||
case 9: return 31;
|
||||
case 10: return 30;
|
||||
case 11: return 31;
|
||||
}
|
||||
|
||||
throw std::runtime_error ("month out of range");
|
||||
}
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
void DateTimeManager::setup(Globals& globalVariables)
|
||||
{
|
||||
mGameHour = globalVariables["gamehour"].getFloat();
|
||||
mDaysPassed = globalVariables["dayspassed"].getInteger();
|
||||
mDay = globalVariables["day"].getInteger();
|
||||
mMonth = globalVariables["month"].getInteger();
|
||||
mYear = globalVariables["year"].getInteger();
|
||||
mTimeScale = globalVariables["timescale"].getFloat();
|
||||
}
|
||||
|
||||
void DateTimeManager::setHour(double hour)
|
||||
{
|
||||
if (hour < 0)
|
||||
hour = 0;
|
||||
|
||||
int days = static_cast<int>(hour / 24);
|
||||
hour = std::fmod(hour, 24);
|
||||
mGameHour = static_cast<float>(hour);
|
||||
|
||||
if (days > 0)
|
||||
setDay(days + mDay);
|
||||
}
|
||||
|
||||
void DateTimeManager::setDay(int day)
|
||||
{
|
||||
if (day < 1)
|
||||
day = 1;
|
||||
|
||||
int month = mMonth;
|
||||
while (true)
|
||||
{
|
||||
int days = getDaysPerMonth(month);
|
||||
if (day <= days)
|
||||
break;
|
||||
|
||||
if (month < 11)
|
||||
{
|
||||
++month;
|
||||
}
|
||||
else
|
||||
{
|
||||
month = 0;
|
||||
mYear++;
|
||||
}
|
||||
|
||||
day -= days;
|
||||
}
|
||||
|
||||
mDay = day;
|
||||
mMonth = month;
|
||||
}
|
||||
|
||||
TimeStamp DateTimeManager::getTimeStamp() const
|
||||
{
|
||||
return TimeStamp(mGameHour, mDaysPassed);
|
||||
}
|
||||
|
||||
float DateTimeManager::getTimeScaleFactor() const
|
||||
{
|
||||
return mTimeScale;
|
||||
}
|
||||
|
||||
ESM::EpochTimeStamp DateTimeManager::getEpochTimeStamp() const
|
||||
{
|
||||
ESM::EpochTimeStamp timeStamp;
|
||||
timeStamp.mGameHour = mGameHour;
|
||||
timeStamp.mDay = mDay;
|
||||
timeStamp.mMonth = mMonth;
|
||||
timeStamp.mYear = mYear;
|
||||
return timeStamp;
|
||||
}
|
||||
|
||||
void DateTimeManager::setMonth(int month)
|
||||
{
|
||||
if (month < 0)
|
||||
month = 0;
|
||||
|
||||
int years = month / 12;
|
||||
month = month % 12;
|
||||
|
||||
int days = getDaysPerMonth(month);
|
||||
if (mDay > days)
|
||||
mDay = days;
|
||||
|
||||
mMonth = month;
|
||||
|
||||
if (years > 0)
|
||||
mYear += years;
|
||||
}
|
||||
|
||||
void DateTimeManager::advanceTime(double hours, Globals& globalVariables)
|
||||
{
|
||||
hours += mGameHour;
|
||||
setHour(hours);
|
||||
|
||||
int days = static_cast<int>(hours / 24);
|
||||
if (days > 0)
|
||||
mDaysPassed += days;
|
||||
|
||||
globalVariables["gamehour"].setFloat(mGameHour);
|
||||
globalVariables["dayspassed"].setInteger(mDaysPassed);
|
||||
globalVariables["day"].setInteger(mDay);
|
||||
globalVariables["month"].setInteger(mMonth);
|
||||
globalVariables["year"].setInteger(mYear);
|
||||
}
|
||||
|
||||
std::string DateTimeManager::getMonthName(int month) const
|
||||
{
|
||||
if (month == -1)
|
||||
month = mMonth;
|
||||
|
||||
const int months = 12;
|
||||
if (month < 0 || month >= months)
|
||||
return std::string();
|
||||
|
||||
static const char *monthNames[months] =
|
||||
{
|
||||
"sMonthMorningstar", "sMonthSunsdawn", "sMonthFirstseed", "sMonthRainshand",
|
||||
"sMonthSecondseed", "sMonthMidyear", "sMonthSunsheight", "sMonthLastseed",
|
||||
"sMonthHeartfire", "sMonthFrostfall", "sMonthSunsdusk", "sMonthEveningstar"
|
||||
};
|
||||
|
||||
const ESM::GameSetting *setting = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(monthNames[month]);
|
||||
return setting->mValue.getString();
|
||||
}
|
||||
|
||||
bool DateTimeManager::updateGlobalFloat(const std::string& name, float value)
|
||||
{
|
||||
if (name=="gamehour")
|
||||
{
|
||||
setHour(value);
|
||||
return true;
|
||||
}
|
||||
else if (name=="day")
|
||||
{
|
||||
setDay(static_cast<int>(value));
|
||||
return true;
|
||||
}
|
||||
else if (name=="month")
|
||||
{
|
||||
setMonth(static_cast<int>(value));
|
||||
return true;
|
||||
}
|
||||
else if (name=="year")
|
||||
{
|
||||
mYear = static_cast<int>(value);
|
||||
}
|
||||
else if (name=="timescale")
|
||||
{
|
||||
mTimeScale = value;
|
||||
}
|
||||
else if (name=="dayspassed")
|
||||
{
|
||||
mDaysPassed = static_cast<int>(value);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DateTimeManager::updateGlobalInt(const std::string& name, int value)
|
||||
{
|
||||
if (name=="gamehour")
|
||||
{
|
||||
setHour(static_cast<float>(value));
|
||||
return true;
|
||||
}
|
||||
else if (name=="day")
|
||||
{
|
||||
setDay(value);
|
||||
return true;
|
||||
}
|
||||
else if (name=="month")
|
||||
{
|
||||
setMonth(value);
|
||||
return true;
|
||||
}
|
||||
else if (name=="year")
|
||||
{
|
||||
mYear = value;
|
||||
}
|
||||
else if (name=="timescale")
|
||||
{
|
||||
mTimeScale = static_cast<float>(value);
|
||||
}
|
||||
else if (name=="dayspassed")
|
||||
{
|
||||
mDaysPassed = value;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
43
apps/openmw/mwworld/datetimemanager.hpp
Normal file
43
apps/openmw/mwworld/datetimemanager.hpp
Normal file
|
@ -0,0 +1,43 @@
|
|||
#ifndef GAME_MWWORLD_DATETIMEMANAGER_H
|
||||
#define GAME_MWWORLD_DATETIMEMANAGER_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
struct EpochTimeStamp;
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
class Globals;
|
||||
class TimeStamp;
|
||||
|
||||
class DateTimeManager
|
||||
{
|
||||
int mDaysPassed = 0;
|
||||
int mDay = 0;
|
||||
int mMonth = 0;
|
||||
int mYear = 0;
|
||||
float mGameHour = 0.f;
|
||||
float mTimeScale = 0.f;
|
||||
|
||||
void setHour(double hour);
|
||||
void setDay(int day);
|
||||
void setMonth(int month);
|
||||
|
||||
public:
|
||||
std::string getMonthName(int month) const;
|
||||
TimeStamp getTimeStamp() const;
|
||||
ESM::EpochTimeStamp getEpochTimeStamp() const;
|
||||
float getTimeScaleFactor() const;
|
||||
|
||||
void advanceTime(double hours, Globals& globalVariables);
|
||||
|
||||
void setup(Globals& globalVariables);
|
||||
bool updateGlobalInt(const std::string& name, int value);
|
||||
bool updateGlobalFloat(const std::string& name, float value);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -2,10 +2,9 @@
|
|||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include <components/esm/esmwriter.hpp>
|
||||
#include <components/esm/esmreader.hpp>
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include "esmstore.hpp"
|
||||
|
||||
|
|
|
@ -284,12 +284,12 @@ void MWWorld::InventoryStore::autoEquipWeapon (const MWWorld::Ptr& actor, TSlots
|
|||
// rate weapon
|
||||
for (int i = 0; i < static_cast<int>(weaponSkillsLength); ++i)
|
||||
{
|
||||
int max = 0;
|
||||
float max = 0;
|
||||
int maxWeaponSkill = -1;
|
||||
|
||||
for (int j = 0; j < static_cast<int>(weaponSkillsLength); ++j)
|
||||
{
|
||||
int skillValue = actor.getClass().getSkill(actor, static_cast<int>(weaponSkills[j]));
|
||||
float skillValue = actor.getClass().getSkill(actor, static_cast<int>(weaponSkills[j]));
|
||||
if (skillValue > max && !weaponSkillVisited[j])
|
||||
{
|
||||
max = skillValue;
|
||||
|
@ -399,7 +399,7 @@ void MWWorld::InventoryStore::autoEquipArmor (const MWWorld::Ptr& actor, TSlots&
|
|||
static float fUnarmoredBase1 = store.find("fUnarmoredBase1")->mValue.getFloat();
|
||||
static float fUnarmoredBase2 = store.find("fUnarmoredBase2")->mValue.getFloat();
|
||||
|
||||
int unarmoredSkill = actor.getClass().getSkill(actor, ESM::Skill::Unarmored);
|
||||
float unarmoredSkill = actor.getClass().getSkill(actor, ESM::Skill::Unarmored);
|
||||
float unarmoredRating = (fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill);
|
||||
|
||||
for (ContainerStoreIterator iter (begin(ContainerStore::Type_Clothing | ContainerStore::Type_Armor)); iter!=end(); ++iter)
|
||||
|
|
|
@ -387,6 +387,18 @@ namespace MWWorld
|
|||
{
|
||||
for (std::vector<MagicBoltState>::iterator it = mMagicBolts.begin(); it != mMagicBolts.end();)
|
||||
{
|
||||
// If the actor caster is gone, the magic bolt needs to be removed from the scene during the next frame.
|
||||
MWWorld::Ptr caster = it->getCaster();
|
||||
if (!caster.isEmpty() && caster.getClass().isActor())
|
||||
{
|
||||
if (caster.getRefData().getCount() <= 0 || caster.getClass().getCreatureStats(caster).isDead())
|
||||
{
|
||||
cleanupMagicBolt(*it);
|
||||
it = mMagicBolts.erase(it);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
osg::Quat orient = it->mNode->getAttitude();
|
||||
static float fTargetSpellMaxSpeed = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||
.find("fTargetSpellMaxSpeed")->mValue.getFloat();
|
||||
|
@ -405,8 +417,6 @@ namespace MWWorld
|
|||
|
||||
update(*it, duration);
|
||||
|
||||
MWWorld::Ptr caster = it->getCaster();
|
||||
|
||||
// For AI actors, get combat targets to use in the ray cast. Only those targets will return a positive hit result.
|
||||
std::vector<MWWorld::Ptr> targetActors;
|
||||
if (!caster.isEmpty() && caster.getClass().isActor() && caster != MWMechanics::getPlayer())
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
#include "../mwphysics/object.hpp"
|
||||
#include "../mwphysics/constants.hpp"
|
||||
|
||||
#include "datetimemanager.hpp"
|
||||
#include "player.hpp"
|
||||
#include "manualref.hpp"
|
||||
#include "cellstore.hpp"
|
||||
|
@ -121,33 +122,11 @@ namespace MWWorld
|
|||
LoadersContainer mLoaders;
|
||||
};
|
||||
|
||||
int World::getDaysPerMonth (int month) const
|
||||
{
|
||||
switch (month)
|
||||
{
|
||||
case 0: return 31;
|
||||
case 1: return 28;
|
||||
case 2: return 31;
|
||||
case 3: return 30;
|
||||
case 4: return 31;
|
||||
case 5: return 30;
|
||||
case 6: return 31;
|
||||
case 7: return 31;
|
||||
case 8: return 30;
|
||||
case 9: return 31;
|
||||
case 10: return 30;
|
||||
case 11: return 31;
|
||||
}
|
||||
|
||||
throw std::runtime_error ("month out of range");
|
||||
}
|
||||
|
||||
void World::adjustSky()
|
||||
{
|
||||
if (mSky && (isCellExterior() || isCellQuasiExterior()))
|
||||
{
|
||||
mRendering->skySetDate (mDay->getInteger(), mMonth->getInteger());
|
||||
|
||||
updateSkyDate();
|
||||
mRendering->setSkyEnabled(true);
|
||||
}
|
||||
else
|
||||
|
@ -193,6 +172,8 @@ namespace MWWorld
|
|||
if (mEsm[0].getFormat() == 0)
|
||||
ensureNeededRecords();
|
||||
|
||||
mCurrentDate.reset(new DateTimeManager());
|
||||
|
||||
fillGlobalVariables();
|
||||
|
||||
mStore.setUp(true);
|
||||
|
@ -227,13 +208,7 @@ namespace MWWorld
|
|||
void World::fillGlobalVariables()
|
||||
{
|
||||
mGlobalVariables.fill (mStore);
|
||||
|
||||
mGameHour = &mGlobalVariables["gamehour"];
|
||||
mDaysPassed = &mGlobalVariables["dayspassed"];
|
||||
mDay = &mGlobalVariables["day"];
|
||||
mMonth = &mGlobalVariables["month"];
|
||||
mYear = &mGlobalVariables["year"];
|
||||
mTimeScale = &mGlobalVariables["timescale"];
|
||||
mCurrentDate->setup(mGlobalVariables);
|
||||
}
|
||||
|
||||
void World::startNewGame (bool bypass)
|
||||
|
@ -310,6 +285,7 @@ namespace MWWorld
|
|||
mPhysics->toggleCollisionMode();
|
||||
|
||||
MWBase::Environment::get().getWindowManager()->updatePlayer();
|
||||
mCurrentDate->setup(mGlobalVariables);
|
||||
}
|
||||
|
||||
void World::clear()
|
||||
|
@ -639,26 +615,20 @@ namespace MWWorld
|
|||
|
||||
void World::setGlobalInt (const std::string& name, int value)
|
||||
{
|
||||
if (name=="gamehour")
|
||||
setHour (value);
|
||||
else if (name=="day")
|
||||
setDay (value);
|
||||
else if (name=="month")
|
||||
setMonth (value);
|
||||
else
|
||||
mGlobalVariables[name].setInteger (value);
|
||||
bool dateUpdated = mCurrentDate->updateGlobalInt(name, value);
|
||||
if (dateUpdated)
|
||||
updateSkyDate();
|
||||
|
||||
mGlobalVariables[name].setInteger (value);
|
||||
}
|
||||
|
||||
void World::setGlobalFloat (const std::string& name, float value)
|
||||
{
|
||||
if (name=="gamehour")
|
||||
setHour (value);
|
||||
else if (name=="day")
|
||||
setDay(static_cast<int>(value));
|
||||
else if (name=="month")
|
||||
setMonth(static_cast<int>(value));
|
||||
else
|
||||
mGlobalVariables[name].setFloat (value);
|
||||
bool dateUpdated = mCurrentDate->updateGlobalFloat(name, value);
|
||||
if (dateUpdated)
|
||||
updateSkyDate();
|
||||
|
||||
mGlobalVariables[name].setFloat(value);
|
||||
}
|
||||
|
||||
int World::getGlobalInt (const std::string& name) const
|
||||
|
@ -676,6 +646,11 @@ namespace MWWorld
|
|||
return mGlobalVariables.getType (name);
|
||||
}
|
||||
|
||||
std::string World::getMonthName (int month) const
|
||||
{
|
||||
return mCurrentDate->getMonthName(month);
|
||||
}
|
||||
|
||||
std::string World::getCellName (const MWWorld::CellStore *cell) const
|
||||
{
|
||||
if (!cell)
|
||||
|
@ -894,130 +869,29 @@ namespace MWWorld
|
|||
}
|
||||
|
||||
mWeatherManager->advanceTime (hours, incremental);
|
||||
mCurrentDate->advanceTime(hours, mGlobalVariables);
|
||||
updateSkyDate();
|
||||
|
||||
if (!incremental)
|
||||
{
|
||||
mRendering->notifyWorldSpaceChanged();
|
||||
mProjectileManager->clear();
|
||||
}
|
||||
|
||||
hours += mGameHour->getFloat();
|
||||
|
||||
setHour (hours);
|
||||
|
||||
int days = static_cast<int>(hours / 24);
|
||||
|
||||
if (days>0)
|
||||
mDaysPassed->setInteger (
|
||||
days + mDaysPassed->getInteger());
|
||||
}
|
||||
|
||||
void World::setHour (double hour)
|
||||
float World::getTimeScaleFactor() const
|
||||
{
|
||||
if (hour<0)
|
||||
hour = 0;
|
||||
|
||||
int days = static_cast<int>(hour / 24);
|
||||
|
||||
hour = std::fmod (hour, 24);
|
||||
|
||||
mGameHour->setFloat(static_cast<float>(hour));
|
||||
|
||||
if (days>0)
|
||||
setDay (days + mDay->getInteger());
|
||||
}
|
||||
|
||||
void World::setDay (int day)
|
||||
{
|
||||
if (day<1)
|
||||
day = 1;
|
||||
|
||||
int month = mMonth->getInteger();
|
||||
|
||||
while (true)
|
||||
{
|
||||
int days = getDaysPerMonth (month);
|
||||
if (day<=days)
|
||||
break;
|
||||
|
||||
if (month<11)
|
||||
{
|
||||
++month;
|
||||
}
|
||||
else
|
||||
{
|
||||
month = 0;
|
||||
mYear->setInteger(mYear->getInteger()+1);
|
||||
}
|
||||
|
||||
day -= days;
|
||||
}
|
||||
|
||||
mDay->setInteger(day);
|
||||
mMonth->setInteger(month);
|
||||
|
||||
mRendering->skySetDate(day, month);
|
||||
}
|
||||
|
||||
void World::setMonth (int month)
|
||||
{
|
||||
if (month<0)
|
||||
month = 0;
|
||||
|
||||
int years = month / 12;
|
||||
month = month % 12;
|
||||
|
||||
int days = getDaysPerMonth (month);
|
||||
|
||||
if (mDay->getInteger()>days)
|
||||
mDay->setInteger (days);
|
||||
|
||||
mMonth->setInteger (month);
|
||||
|
||||
if (years>0)
|
||||
mYear->setInteger (years+mYear->getInteger());
|
||||
|
||||
mRendering->skySetDate (mDay->getInteger(), month);
|
||||
}
|
||||
|
||||
int World::getDay() const
|
||||
{
|
||||
return mDay->getInteger();
|
||||
}
|
||||
|
||||
int World::getMonth() const
|
||||
{
|
||||
return mMonth->getInteger();
|
||||
}
|
||||
|
||||
int World::getYear() const
|
||||
{
|
||||
return mYear->getInteger();
|
||||
}
|
||||
|
||||
std::string World::getMonthName (int month) const
|
||||
{
|
||||
if (month==-1)
|
||||
month = getMonth();
|
||||
|
||||
const int months = 12;
|
||||
|
||||
if (month<0 || month>=months)
|
||||
return "";
|
||||
|
||||
static const char *monthNames[months] =
|
||||
{
|
||||
"sMonthMorningstar", "sMonthSunsdawn", "sMonthFirstseed", "sMonthRainshand",
|
||||
"sMonthSecondseed", "sMonthMidyear", "sMonthSunsheight", "sMonthLastseed",
|
||||
"sMonthHeartfire", "sMonthFrostfall", "sMonthSunsdusk", "sMonthEveningstar"
|
||||
};
|
||||
|
||||
return mStore.get<ESM::GameSetting>().find (monthNames[month])->mValue.getString();
|
||||
return mCurrentDate->getTimeScaleFactor();
|
||||
}
|
||||
|
||||
TimeStamp World::getTimeStamp() const
|
||||
{
|
||||
return TimeStamp (mGameHour->getFloat(), mDaysPassed->getInteger());
|
||||
return mCurrentDate->getTimeStamp();
|
||||
}
|
||||
|
||||
ESM::EpochTimeStamp World::getEpochTimeStamp() const
|
||||
{
|
||||
return mCurrentDate->getEpochTimeStamp();
|
||||
}
|
||||
|
||||
bool World::toggleSky()
|
||||
|
@ -1042,11 +916,6 @@ namespace MWWorld
|
|||
mRendering->skySetMoonColour (red);
|
||||
}
|
||||
|
||||
float World::getTimeScaleFactor() const
|
||||
{
|
||||
return mTimeScale->getFloat();
|
||||
}
|
||||
|
||||
void World::changeToInteriorCell (const std::string& cellName, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent)
|
||||
{
|
||||
mPhysics->clearQueuedMovement();
|
||||
|
@ -1089,6 +958,8 @@ namespace MWWorld
|
|||
changeToExteriorCell (position, adjustPlayerPos, changeEvent);
|
||||
else
|
||||
changeToInteriorCell (cellId.mWorldspace, position, adjustPlayerPos, changeEvent);
|
||||
|
||||
mCurrentDate->setup(mGlobalVariables);
|
||||
}
|
||||
|
||||
void World::markCellAsUnchanged()
|
||||
|
@ -3968,4 +3839,10 @@ namespace MWWorld
|
|||
mNavigator->reportStats(frameNumber, stats);
|
||||
mPhysics->reportStats(frameNumber, stats);
|
||||
}
|
||||
|
||||
void World::updateSkyDate()
|
||||
{
|
||||
ESM::EpochTimeStamp currentDate = mCurrentDate->getEpochTimeStamp();
|
||||
mRendering->skySetDate(currentDate.mDay, currentDate.mMonth);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,6 +69,7 @@ namespace MWPhysics
|
|||
|
||||
namespace MWWorld
|
||||
{
|
||||
class DateTimeManager;
|
||||
class WeatherManager;
|
||||
class Player;
|
||||
class ProjectileManager;
|
||||
|
@ -85,13 +86,6 @@ namespace MWWorld
|
|||
LocalScripts mLocalScripts;
|
||||
MWWorld::Globals mGlobalVariables;
|
||||
|
||||
ESM::Variant* mGameHour;
|
||||
ESM::Variant* mDaysPassed;
|
||||
ESM::Variant* mDay;
|
||||
ESM::Variant* mMonth;
|
||||
ESM::Variant* mYear;
|
||||
ESM::Variant* mTimeScale;
|
||||
|
||||
Cells mCells;
|
||||
|
||||
std::string mCurrentWorldSpace;
|
||||
|
@ -102,6 +96,7 @@ namespace MWWorld
|
|||
std::unique_ptr<MWRender::RenderingManager> mRendering;
|
||||
std::unique_ptr<MWWorld::Scene> mWorldScene;
|
||||
std::unique_ptr<MWWorld::WeatherManager> mWeatherManager;
|
||||
std::unique_ptr<MWWorld::DateTimeManager> mCurrentDate;
|
||||
std::shared_ptr<ProjectileManager> mProjectileManager;
|
||||
|
||||
bool mSky;
|
||||
|
@ -139,7 +134,6 @@ namespace MWWorld
|
|||
World& operator= (const World&);
|
||||
|
||||
void updateWeather(float duration, bool paused = false);
|
||||
int getDaysPerMonth (int month) const;
|
||||
|
||||
void rotateObjectImp (const Ptr& ptr, const osg::Vec3f& rot, MWBase::RotationFlags flags);
|
||||
|
||||
|
@ -173,6 +167,8 @@ namespace MWWorld
|
|||
|
||||
void fillGlobalVariables();
|
||||
|
||||
void updateSkyDate();
|
||||
|
||||
/**
|
||||
* @brief loadContentFiles - Loads content files (esm,esp,omwgame,omwaddon)
|
||||
* @param fileCollections- Container which holds content file names and their paths
|
||||
|
@ -318,24 +314,14 @@ namespace MWWorld
|
|||
void advanceTime (double hours, bool incremental = false) override;
|
||||
///< Advance in-game time.
|
||||
|
||||
void setHour (double hour) override;
|
||||
///< Set in-game time hour.
|
||||
|
||||
void setMonth (int month) override;
|
||||
///< Set in-game time month.
|
||||
|
||||
void setDay (int day) override;
|
||||
///< Set in-game time day.
|
||||
|
||||
int getDay() const override;
|
||||
int getMonth() const override;
|
||||
int getYear() const override;
|
||||
|
||||
std::string getMonthName (int month = -1) const override;
|
||||
///< Return name of month (-1: current month)
|
||||
|
||||
TimeStamp getTimeStamp() const override;
|
||||
///< Return current in-game time stamp.
|
||||
///< Return current in-game time and number of day since new game start.
|
||||
|
||||
ESM::EpochTimeStamp getEpochTimeStamp() const override;
|
||||
///< Return current in-game date and time.
|
||||
|
||||
bool toggleSky() override;
|
||||
///< \return Resulting mode
|
||||
|
|
|
@ -287,5 +287,5 @@ endif()
|
|||
set(COMPONENT_FILES ${COMPONENT_FILES} PARENT_SCOPE)
|
||||
|
||||
if (BULLET_USE_DOUBLES)
|
||||
add_definitions(-DBT_USE_DOUBLE_PRECISION)
|
||||
target_compile_definitions(components PUBLIC BT_USE_DOUBLE_PRECISION)
|
||||
endif()
|
||||
|
|
|
@ -247,8 +247,8 @@ namespace Compiler
|
|||
extensions.registerInstruction ("startscript", "c", opcodeStartScript, opcodeStartScriptExplicit);
|
||||
extensions.registerInstruction ("stopscript", "c", opcodeStopScript);
|
||||
extensions.registerFunction ("getsecondspassed", 'f', "", opcodeGetSecondsPassed);
|
||||
extensions.registerInstruction ("enable", "", opcodeEnable, opcodeEnableExplicit);
|
||||
extensions.registerInstruction ("disable", "", opcodeDisable, opcodeDisableExplicit);
|
||||
extensions.registerInstruction ("enable", "x", opcodeEnable, opcodeEnableExplicit);
|
||||
extensions.registerInstruction ("disable", "x", opcodeDisable, opcodeDisableExplicit);
|
||||
extensions.registerFunction ("getdisabled", 'l', "x", opcodeGetDisabled, opcodeGetDisabledExplicit);
|
||||
extensions.registerFunction ("xbox", 'l', "", opcodeXBox);
|
||||
extensions.registerFunction ("onactivate", 'l', "", opcodeOnActivate, opcodeOnActivateExplicit);
|
||||
|
@ -423,13 +423,13 @@ namespace Compiler
|
|||
|
||||
for (int i=0; i<numberOfAttributes; ++i)
|
||||
{
|
||||
extensions.registerFunction (get + attributes[i], 'l', "",
|
||||
extensions.registerFunction (get + attributes[i], 'f', "",
|
||||
opcodeGetAttribute+i, opcodeGetAttributeExplicit+i);
|
||||
|
||||
extensions.registerInstruction (set + attributes[i], "l",
|
||||
extensions.registerInstruction (set + attributes[i], "f",
|
||||
opcodeSetAttribute+i, opcodeSetAttributeExplicit+i);
|
||||
|
||||
extensions.registerInstruction (mod + attributes[i], "l",
|
||||
extensions.registerInstruction (mod + attributes[i], "f",
|
||||
opcodeModAttribute+i, opcodeModAttributeExplicit+i);
|
||||
}
|
||||
|
||||
|
@ -453,13 +453,13 @@ namespace Compiler
|
|||
|
||||
for (int i=0; i<numberOfSkills; ++i)
|
||||
{
|
||||
extensions.registerFunction (get + skills[i], 'l', "",
|
||||
extensions.registerFunction (get + skills[i], 'f', "",
|
||||
opcodeGetSkill+i, opcodeGetSkillExplicit+i);
|
||||
|
||||
extensions.registerInstruction (set + skills[i], "l",
|
||||
extensions.registerInstruction (set + skills[i], "f",
|
||||
opcodeSetSkill+i, opcodeSetSkillExplicit+i);
|
||||
|
||||
extensions.registerInstruction (mod + skills[i], "l",
|
||||
extensions.registerInstruction (mod + skills[i], "f",
|
||||
opcodeModSkill+i, opcodeModSkillExplicit+i);
|
||||
}
|
||||
|
||||
|
|
|
@ -86,13 +86,6 @@ namespace Compiler
|
|||
bool LineParser::parseName (const std::string& name, const TokenLoc& loc,
|
||||
Scanner& scanner)
|
||||
{
|
||||
if (mState==PotentialEndState)
|
||||
{
|
||||
getErrorHandler().warning ("Stray string argument", loc);
|
||||
mState = EndState;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mState==SetState)
|
||||
{
|
||||
std::string name2 = Misc::StringUtils::lowerCase (name);
|
||||
|
@ -445,8 +438,7 @@ namespace Compiler
|
|||
return true;
|
||||
}
|
||||
|
||||
if (code==Scanner::S_newline &&
|
||||
(mState==EndState || mState==BeginState || mState==PotentialEndState))
|
||||
if (code==Scanner::S_newline && (mState==EndState || mState==BeginState))
|
||||
return false;
|
||||
|
||||
if (code==Scanner::S_comma && mState==MessageState)
|
||||
|
|
|
@ -25,8 +25,7 @@ namespace Compiler
|
|||
SetState, SetLocalVarState, SetGlobalVarState, SetPotentialMemberVarState,
|
||||
SetMemberVarState, SetMemberVarState2,
|
||||
MessageState, MessageCommaState, MessageButtonState, MessageButtonCommaState,
|
||||
EndState, PotentialEndState /* may have a stray string argument */,
|
||||
PotentialExplicitState, ExplicitState, MemberState
|
||||
EndState, PotentialExplicitState, ExplicitState, MemberState
|
||||
};
|
||||
|
||||
Locals& mLocals;
|
||||
|
|
|
@ -8,18 +8,18 @@ namespace ESM
|
|||
{
|
||||
// format 0, saved games only
|
||||
|
||||
struct ContainerState : public ObjectState
|
||||
struct ContainerState final : public ObjectState
|
||||
{
|
||||
InventoryState mInventory;
|
||||
|
||||
virtual void load (ESMReader &esm);
|
||||
virtual void save (ESMWriter &esm, bool inInventory = false) const;
|
||||
void load (ESMReader &esm) final;
|
||||
void save (ESMWriter &esm, bool inInventory = false) const final;
|
||||
|
||||
virtual ContainerState& asContainerState()
|
||||
ContainerState& asContainerState() final
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
virtual const ContainerState& asContainerState() const
|
||||
const ContainerState& asContainerState() const final
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
|
|
@ -7,19 +7,19 @@ namespace ESM
|
|||
{
|
||||
// format 0, saved games only
|
||||
|
||||
struct CreatureLevListState : public ObjectState
|
||||
struct CreatureLevListState final : public ObjectState
|
||||
{
|
||||
int mSpawnActorId;
|
||||
bool mSpawn;
|
||||
|
||||
virtual void load (ESMReader &esm);
|
||||
virtual void save (ESMWriter &esm, bool inInventory = false) const;
|
||||
void load (ESMReader &esm) final;
|
||||
void save (ESMWriter &esm, bool inInventory = false) const final;
|
||||
|
||||
virtual CreatureLevListState& asCreatureLevListState()
|
||||
CreatureLevListState& asCreatureLevListState() final
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
virtual const CreatureLevListState& asCreatureLevListState() const
|
||||
const CreatureLevListState& asCreatureLevListState() const final
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace ESM
|
|||
{
|
||||
// format 0, saved games only
|
||||
|
||||
struct CreatureState : public ObjectState
|
||||
struct CreatureState final : public ObjectState
|
||||
{
|
||||
InventoryState mInventory;
|
||||
CreatureStats mCreatureStats;
|
||||
|
@ -17,14 +17,14 @@ namespace ESM
|
|||
/// Initialize to default state
|
||||
void blank();
|
||||
|
||||
virtual void load (ESMReader &esm);
|
||||
virtual void save (ESMWriter &esm, bool inInventory = false) const;
|
||||
void load (ESMReader &esm) final;
|
||||
void save (ESMWriter &esm, bool inInventory = false) const final;
|
||||
|
||||
virtual CreatureState& asCreatureState()
|
||||
CreatureState& asCreatureState() final
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
virtual const CreatureState& asCreatureState() const
|
||||
const CreatureState& asCreatureState() const final
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
|
|
@ -4,8 +4,9 @@
|
|||
|
||||
void ESM::CreatureStats::load (ESMReader &esm)
|
||||
{
|
||||
bool intFallback = esm.getFormat() < 11;
|
||||
for (int i=0; i<8; ++i)
|
||||
mAttributes[i].load (esm);
|
||||
mAttributes[i].load (esm, intFallback);
|
||||
|
||||
for (int i=0; i<3; ++i)
|
||||
mDynamic[i].load (esm);
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace ESM
|
|||
TimeStamp mNextWorsening;
|
||||
};
|
||||
|
||||
StatState<int> mAttributes[Attribute::Length];
|
||||
StatState<float> mAttributes[Attribute::Length];
|
||||
StatState<float> mDynamic[3];
|
||||
|
||||
MagicEffects mMagicEffects;
|
||||
|
|
|
@ -14,6 +14,14 @@ struct TimeStamp
|
|||
int mDay;
|
||||
};
|
||||
|
||||
struct EpochTimeStamp
|
||||
{
|
||||
float mGameHour;
|
||||
int mDay;
|
||||
int mMonth;
|
||||
int mYear;
|
||||
};
|
||||
|
||||
// Pixel color value. Standard four-byte rr,gg,bb,aa format.
|
||||
typedef uint32_t Color;
|
||||
|
||||
|
@ -49,6 +57,26 @@ struct Position
|
|||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
bool inline operator== (const Position& left, const Position& right) noexcept
|
||||
{
|
||||
return left.pos[0] == right.pos[0] &&
|
||||
left.pos[1] == right.pos[1] &&
|
||||
left.pos[2] == right.pos[2] &&
|
||||
left.rot[0] == right.rot[0] &&
|
||||
left.rot[1] == right.rot[1] &&
|
||||
left.rot[2] == right.rot[2];
|
||||
}
|
||||
|
||||
bool inline operator!= (const Position& left, const Position& right) noexcept
|
||||
{
|
||||
return left.pos[0] != right.pos[0] ||
|
||||
left.pos[1] != right.pos[1] ||
|
||||
left.pos[2] != right.pos[2] ||
|
||||
left.rot[0] != right.rot[0] ||
|
||||
left.rot[1] != right.rot[1] ||
|
||||
left.rot[2] != right.rot[2];
|
||||
}
|
||||
|
||||
template <int a, int b, int c, int d>
|
||||
struct FourCC
|
||||
{
|
||||
|
|
|
@ -7,18 +7,18 @@ namespace ESM
|
|||
{
|
||||
// format 0, saved games only
|
||||
|
||||
struct DoorState : public ObjectState
|
||||
struct DoorState final : public ObjectState
|
||||
{
|
||||
int mDoorState = 0;
|
||||
|
||||
virtual void load (ESMReader &esm);
|
||||
virtual void save (ESMWriter &esm, bool inInventory = false) const;
|
||||
void load (ESMReader &esm) final;
|
||||
void save (ESMWriter &esm, bool inInventory = false) const final;
|
||||
|
||||
virtual DoorState& asDoorState()
|
||||
DoorState& asDoorState() final
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
virtual const DoorState& asDoorState() const
|
||||
const DoorState& asDoorState() const final
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace ESM
|
|||
{
|
||||
// format 0, saved games only
|
||||
|
||||
struct NpcState : public ObjectState
|
||||
struct NpcState final : public ObjectState
|
||||
{
|
||||
InventoryState mInventory;
|
||||
NpcStats mNpcStats;
|
||||
|
@ -19,14 +19,14 @@ namespace ESM
|
|||
/// Initialize to default state
|
||||
void blank();
|
||||
|
||||
virtual void load (ESMReader &esm);
|
||||
virtual void save (ESMWriter &esm, bool inInventory = false) const;
|
||||
void load (ESMReader &esm) final;
|
||||
void save (ESMWriter &esm, bool inInventory = false) const final;
|
||||
|
||||
virtual NpcState& asNpcState()
|
||||
NpcState& asNpcState() final
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
virtual const NpcState& asNpcState() const
|
||||
const NpcState& asNpcState() const final
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
|
|
@ -31,8 +31,9 @@ void ESM::NpcStats::load (ESMReader &esm)
|
|||
mDisposition = 0;
|
||||
esm.getHNOT (mDisposition, "DISP");
|
||||
|
||||
bool intFallback = esm.getFormat() < 11;
|
||||
for (int i=0; i<27; ++i)
|
||||
mSkills[i].load (esm);
|
||||
mSkills[i].load (esm, intFallback);
|
||||
|
||||
mWerewolfDeprecatedData = false;
|
||||
if (esm.getFormat() < 8 && esm.peekNextSub("STBA"))
|
||||
|
@ -40,17 +41,17 @@ void ESM::NpcStats::load (ESMReader &esm)
|
|||
// we have deprecated werewolf skills, stored interleaved
|
||||
// Load into one big vector, then remove every 2nd value
|
||||
mWerewolfDeprecatedData = true;
|
||||
std::vector<ESM::StatState<int> > skills(mSkills, mSkills + sizeof(mSkills)/sizeof(mSkills[0]));
|
||||
std::vector<ESM::StatState<float> > skills(mSkills, mSkills + sizeof(mSkills)/sizeof(mSkills[0]));
|
||||
|
||||
for (int i=0; i<27; ++i)
|
||||
{
|
||||
ESM::StatState<int> skill;
|
||||
skill.load(esm);
|
||||
ESM::StatState<float> skill;
|
||||
skill.load(esm, intFallback);
|
||||
skills.push_back(skill);
|
||||
}
|
||||
|
||||
int i=0;
|
||||
for (std::vector<ESM::StatState<int> >::iterator it = skills.begin(); it != skills.end(); ++i)
|
||||
for (std::vector<ESM::StatState<float> >::iterator it = skills.begin(); it != skills.end(); ++i)
|
||||
{
|
||||
if (i%2 == 1)
|
||||
it = skills.erase(it);
|
||||
|
@ -68,7 +69,7 @@ void ESM::NpcStats::load (ESMReader &esm)
|
|||
{
|
||||
ESM::StatState<int> dummy;
|
||||
for (int i=0; i<8; ++i)
|
||||
dummy.load(esm);
|
||||
dummy.load(esm, intFallback);
|
||||
mWerewolfDeprecatedData = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ namespace ESM
|
|||
|
||||
std::map<std::string, Faction> mFactions; // lower case IDs
|
||||
int mDisposition;
|
||||
StatState<int> mSkills[27];
|
||||
StatState<float> mSkills[27];
|
||||
int mBounty;
|
||||
int mReputation;
|
||||
int mWerewolfKills;
|
||||
|
|
|
@ -26,6 +26,7 @@ void ESM::ObjectState::load (ESMReader &esm)
|
|||
mCount = 1;
|
||||
esm.getHNOT (mCount, "COUN");
|
||||
|
||||
mPosition = mRef.mPos;
|
||||
esm.getHNOT (mPosition, "POS_", 24);
|
||||
|
||||
if (esm.isNextSub("LROT"))
|
||||
|
@ -61,7 +62,7 @@ void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const
|
|||
if (mCount!=1)
|
||||
esm.writeHNT ("COUN", mCount);
|
||||
|
||||
if (!inInventory)
|
||||
if (!inInventory && mPosition != mRef.mPos)
|
||||
esm.writeHNT ("POS_", mPosition, 24);
|
||||
|
||||
if (mFlags != 0)
|
||||
|
|
|
@ -44,12 +44,13 @@ void ESM::Player::load (ESMReader &esm)
|
|||
checkPrevItems = false;
|
||||
}
|
||||
|
||||
bool intFallback = esm.getFormat() < 11;
|
||||
if (esm.hasMoreSubs())
|
||||
{
|
||||
for (int i=0; i<ESM::Attribute::Length; ++i)
|
||||
mSaveAttributes[i].load(esm);
|
||||
mSaveAttributes[i].load(esm, intFallback);
|
||||
for (int i=0; i<ESM::Skill::Length; ++i)
|
||||
mSaveSkills[i].load(esm);
|
||||
mSaveSkills[i].load(esm, intFallback);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,8 +30,8 @@ namespace ESM
|
|||
int mCurrentCrimeId;
|
||||
int mPaidCrimeId;
|
||||
|
||||
StatState<int> mSaveAttributes[ESM::Attribute::Length];
|
||||
StatState<int> mSaveSkills[ESM::Skill::Length];
|
||||
StatState<float> mSaveAttributes[ESM::Attribute::Length];
|
||||
StatState<float> mSaveSkills[ESM::Skill::Length];
|
||||
|
||||
typedef std::map<std::string, std::string> PreviousItems; // previous equipped items, needed for bound spells
|
||||
PreviousItems mPreviousItems;
|
||||
|
|
|
@ -2,10 +2,9 @@
|
|||
|
||||
#include "esmreader.hpp"
|
||||
#include "esmwriter.hpp"
|
||||
#include "defs.hpp"
|
||||
|
||||
unsigned int ESM::SavedGame::sRecordId = ESM::REC_SAVE;
|
||||
int ESM::SavedGame::sCurrentFormat = 10;
|
||||
int ESM::SavedGame::sCurrentFormat = 12;
|
||||
|
||||
void ESM::SavedGame::load (ESMReader &esm)
|
||||
{
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "defs.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
|
@ -17,14 +19,6 @@ namespace ESM
|
|||
|
||||
static int sCurrentFormat;
|
||||
|
||||
struct TimeStamp
|
||||
{
|
||||
float mGameHour;
|
||||
int mDay;
|
||||
int mMonth;
|
||||
int mYear;
|
||||
};
|
||||
|
||||
std::vector<std::string> mContentFiles;
|
||||
std::string mPlayerName;
|
||||
int mPlayerLevel;
|
||||
|
@ -36,7 +30,7 @@ namespace ESM
|
|||
std::string mPlayerClassName;
|
||||
|
||||
std::string mPlayerCell;
|
||||
TimeStamp mInGameTime;
|
||||
EpochTimeStamp mInGameTime;
|
||||
double mTimePlayed;
|
||||
std::string mDescription;
|
||||
std::vector<char> mScreenshot; // raw jpg-encoded data
|
||||
|
|
|
@ -9,19 +9,44 @@ namespace ESM
|
|||
StatState<T>::StatState() : mBase(0), mMod(0), mCurrent(0), mDamage(0), mProgress(0) {}
|
||||
|
||||
template<typename T>
|
||||
void StatState<T>::load(ESMReader &esm)
|
||||
void StatState<T>::load(ESMReader &esm, bool intFallback)
|
||||
{
|
||||
esm.getHNT(mBase, "STBA");
|
||||
// We changed stats values from integers to floats; ensure backwards compatibility
|
||||
if (intFallback)
|
||||
{
|
||||
int base = 0;
|
||||
esm.getHNT(base, "STBA");
|
||||
mBase = static_cast<float>(base);
|
||||
|
||||
mMod = 0;
|
||||
esm.getHNOT(mMod, "STMO");
|
||||
mCurrent = 0;
|
||||
esm.getHNOT(mCurrent, "STCU");
|
||||
int mod = 0;
|
||||
esm.getHNOT(mod, "STMO");
|
||||
mMod = static_cast<float>(mod);
|
||||
|
||||
// mDamage was changed to a float; ensure backwards compatibility
|
||||
T oldDamage = 0;
|
||||
esm.getHNOT(oldDamage, "STDA");
|
||||
mDamage = static_cast<float>(oldDamage);
|
||||
int current = 0;
|
||||
esm.getHNOT(current, "STCU");
|
||||
mCurrent = static_cast<float>(current);
|
||||
|
||||
// mDamage was changed to a float; ensure backwards compatibility
|
||||
int oldDamage = 0;
|
||||
esm.getHNOT(oldDamage, "STDA");
|
||||
mDamage = static_cast<float>(oldDamage);
|
||||
}
|
||||
else
|
||||
{
|
||||
mBase = 0;
|
||||
esm.getHNT(mBase, "STBA");
|
||||
|
||||
mMod = 0;
|
||||
esm.getHNOT(mMod, "STMO");
|
||||
|
||||
mCurrent = 0;
|
||||
esm.getHNOT(mCurrent, "STCU");
|
||||
|
||||
mDamage = 0;
|
||||
esm.getHNOT(mDamage, "STDF");
|
||||
|
||||
mProgress = 0;
|
||||
}
|
||||
|
||||
esm.getHNOT(mDamage, "STDF");
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace ESM
|
|||
|
||||
StatState();
|
||||
|
||||
void load (ESMReader &esm);
|
||||
void load (ESMReader &esm, bool intFallback = false);
|
||||
void save (ESMWriter &esm) const;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -139,6 +139,7 @@ namespace Terrain
|
|||
virtual void enable(bool enabled) {}
|
||||
|
||||
virtual void setBordersVisible(bool visible);
|
||||
virtual bool getBordersVisible() { return mBorderVisible; }
|
||||
|
||||
/// Create a View to use with preload feature. The caller is responsible for deleting the view.
|
||||
/// @note Thread safe.
|
||||
|
|
Loading…
Reference in a new issue