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