1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-16 18:19:55 +00:00

Implement difficulty scaling (Fixes #1505)

This commit is contained in:
scrawl 2014-07-20 16:22:52 +02:00
parent 5bbf07976f
commit 28a0899d2b
10 changed files with 159 additions and 63 deletions

View file

@ -69,7 +69,7 @@ add_openmw_dir (mwmechanics
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor
aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting
disease pickpocket levelledlist combat steering obstacle autocalcspell
disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling
)
add_openmw_dir (mwstate

View file

@ -9,6 +9,7 @@
#include "../mwmechanics/movement.hpp"
#include "../mwmechanics/disease.hpp"
#include "../mwmechanics/spellcasting.hpp"
#include "../mwmechanics/difficultyscaling.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/mechanicsmanager.hpp"
@ -412,6 +413,9 @@ namespace MWClass
if(ishealth)
{
if (!attacker.isEmpty())
damage = scaleDamage(damage, attacker, ptr);
MWBase::Environment::get().getSoundManager()->playSound3D(ptr, "Health Damage", 1.0f, 1.0f);
float health = getCreatureStats(ptr).getHealth().getCurrent() - damage;
setActorHealth(ptr, health, attacker);

View file

@ -23,6 +23,7 @@
#include "../mwmechanics/disease.hpp"
#include "../mwmechanics/combat.hpp"
#include "../mwmechanics/autocalcspell.hpp"
#include "../mwmechanics/difficultyscaling.hpp"
#include "../mwworld/ptr.hpp"
#include "../mwworld/actiontalk.hpp"
@ -788,6 +789,9 @@ namespace MWClass
if(ishealth)
{
if (!attacker.isEmpty())
damage = scaleDamage(damage, attacker, ptr);
if(damage > 0.0f)
sndMgr->playSound3D(ptr, "Health Damage", 1.0f, 1.0f);
float health = getCreatureStats(ptr).getHealth().getCurrent() - damage;

View file

@ -157,6 +157,8 @@ namespace MWGui
{
configureWidgets(mMainWidget);
setTitle("#{sOptions}");
getWidget(mOkButton, "OkButton");
getWidget(mResolutionList, "ResolutionList");
getWidget(mFullscreenButton, "FullscreenButton");
@ -174,6 +176,7 @@ namespace MWGui
getWidget(mControlsBox, "ControlsBox");
getWidget(mResetControlsButton, "ResetControlsButton");
getWidget(mRefractionButton, "RefractionButton");
getWidget(mDifficultySlider, "DifficultySlider");
mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onOkButtonClicked);
mShaderModeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onShaderModeToggled);
@ -227,6 +230,10 @@ namespace MWGui
MyGUI::TextBox* fovText;
getWidget(fovText, "FovText");
fovText->setCaption("Field of View (" + boost::lexical_cast<std::string>(int(Settings::Manager::getInt("field of view", "General"))) + ")");
MyGUI::TextBox* diffText;
getWidget(diffText, "DifficultyText");
diffText->setCaptionWithReplacing("#{sDifficulty} (" + boost::lexical_cast<std::string>(int(Settings::Manager::getInt("difficulty", "Game"))) + ")");
}
void SettingsWindow::onOkButtonClicked(MyGUI::Widget* _sender)
@ -406,6 +413,12 @@ namespace MWGui
getWidget(fovText, "FovText");
fovText->setCaption("Field of View (" + boost::lexical_cast<std::string>(int(value)) + ")");
}
if (scroller == mDifficultySlider)
{
MyGUI::TextBox* diffText;
getWidget(diffText, "DifficultyText");
diffText->setCaptionWithReplacing("#{sDifficulty} (" + boost::lexical_cast<std::string>(int(value)) + ")");
}
}
else
{

View file

@ -30,6 +30,7 @@ namespace MWGui
MyGUI::Button* mVSyncButton;
MyGUI::Button* mFPSButton;
MyGUI::ScrollBar* mFOVSlider;
MyGUI::ScrollBar* mDifficultySlider;
MyGUI::ScrollBar* mAnisotropySlider;
MyGUI::ComboBox* mTextureFilteringButton;
MyGUI::TextBox* mAnisotropyLabel;

View file

@ -10,6 +10,7 @@
#include "../mwmechanics/npcstats.hpp"
#include "../mwmechanics/movement.hpp"
#include "../mwmechanics/spellcasting.hpp"
#include "../mwmechanics/difficultyscaling.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/inventorystore.hpp"
@ -292,6 +293,10 @@ namespace MWMechanics
static const float fElementalShieldMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fElementalShieldMult")->getFloat();
x = fElementalShieldMult * magnitude * (1.f - 0.01f * x);
// Note swapped victim and attacker, since the attacker takes the damage here.
x = scaleDamage(x, victim, attacker);
MWMechanics::DynamicStat<float> health = attackerStats.getHealth();
health.setCurrent(health.getCurrent() - x);
attackerStats.setHealth(health);

View file

@ -0,0 +1,38 @@
#include "difficultyscaling.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp"
#include "../mwworld/esmstore.hpp"
#include <components/settings/settings.hpp>
float scaleDamage(float damage, const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim)
{
const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayerPtr();
// [-100, 100]
int difficultySetting = Settings::Manager::getInt("difficulty", "Game");
static const float fDifficultyMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fDifficultyMult")->getFloat();
float difficultyTerm = 0.01f * difficultySetting;
float x = 0;
if (victim == player)
{
if (difficultyTerm > 0)
x = fDifficultyMult * difficultyTerm;
else
x = difficultyTerm / fDifficultyMult;
}
else if (attacker == player)
{
if (difficultyTerm > 0)
x = -difficultyTerm / fDifficultyMult;
else
x = fDifficultyMult * (-difficultyTerm);
}
damage *= 1 + x;
return damage;
}

View file

@ -0,0 +1,12 @@
#ifndef OPENMW_MWMECHANICS_DIFFICULTYSCALING_H
#define OPENMW_MWMECHANICS_DIFFICULTYSCALING_H
namespace MWWorld
{
class Ptr;
}
/// Scales damage dealt to an actor based on difficulty setting
float scaleDamage(float damage, const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim);
#endif

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Layout">
<Widget type="Window" skin="MW_Window_NoCaption" layer="Windows" position="0 0 400 426" name="_Main">
<Widget type="Window" skin="MW_Window" layer="Windows" position="0 0 400 426" name="_Main">
<Property key="MinSize" value="400 446"/>
<Property key="MaxSize" value="400 446"/>
@ -12,47 +12,86 @@
<Widget type="TabItem" skin="" position="4 28 360 312">
<Property key="Caption" value=" #{sPrefs} "/>
<Widget type="TextBox" skin="NormalText" position="4 4 352 18" align="Left Top">
<Property key="Caption" value="#{sTransparency_Menu}"/>
</Widget>
<Widget type="MWScrollBar" skin="MW_HScroll" position="4 28 352 18" align="Left Top" name="MenuTransparencySlider">
<Property key="Range" value="10000"/>
<Property key="Page" value="300"/>
<UserString key="SettingType" value="Slider"/>
<UserString key="SettingCategory" value="GUI"/>
<UserString key="SettingName" value="menu transparency"/>
<UserString key="SettingValueType" value="Float"/>
</Widget>
<Widget type="TextBox" skin="SandText" position="4 52 352 18" align="Left Top">
<Property key="Caption" value="#{sFull}"/>
<Property key="TextAlign" value="Left"/>
</Widget>
<Widget type="TextBox" skin="SandText" position="4 52 352 18" align="Left Top">
<Property key="Caption" value="#{sNone}"/>
<Property key="TextAlign" value="Right"/>
<Widget type="Widget" position="4 4 352 54" align="Left Top">
<Widget type="TextBox" skin="NormalText" position="0 0 352 16" align="Left Top">
<Property key="Caption" value="#{sTransparency_Menu}"/>
</Widget>
<Widget type="MWScrollBar" skin="MW_HScroll" position="0 20 352 14" align="Left Top" name="MenuTransparencySlider">
<Property key="Range" value="10000"/>
<Property key="Page" value="300"/>
<UserString key="SettingType" value="Slider"/>
<UserString key="SettingCategory" value="GUI"/>
<UserString key="SettingName" value="menu transparency"/>
<UserString key="SettingValueType" value="Float"/>
</Widget>
<Widget type="TextBox" skin="SandText" position="0 38 352 16" align="Left Top">
<Property key="Caption" value="#{sFull}"/>
<Property key="TextAlign" value="Left"/>
</Widget>
<Widget type="TextBox" skin="SandText" position="0 38 352 16" align="Left Top">
<Property key="Caption" value="#{sNone}"/>
<Property key="TextAlign" value="Right"/>
</Widget>
</Widget>
<Widget type="TextBox" skin="NormalText" position="4 78 352 18" align="Left Top">
<Property key="Caption" value="#{sMenu_Help_Delay}"/>
</Widget>
<Widget type="MWScrollBar" skin="MW_HScroll" position="4 102 352 18" align="Left Top" name="ToolTipDelaySlider">
<Property key="Range" value="10000"/>
<Property key="Page" value="300"/>
<UserString key="SettingType" value="Slider"/>
<UserString key="SettingCategory" value="GUI"/>
<UserString key="SettingName" value="tooltip delay"/>
<UserString key="SettingValueType" value="Float"/>
</Widget>
<Widget type="TextBox" skin="SandText" position="4 126 352 18" align="Left Top">
<Property key="Caption" value="#{sFast}"/>
<Property key="TextAlign" value="Left"/>
</Widget>
<Widget type="TextBox" skin="SandText" position="4 126 352 18" align="Left Top">
<Property key="Caption" value="#{sSlow}"/>
<Property key="TextAlign" value="Right"/>
<Widget type="Widget" position="4 64 352 54" align="Left Top">
<Widget type="TextBox" skin="NormalText" position="0 0 352 16" align="Left Top">
<Property key="Caption" value="#{sMenu_Help_Delay}"/>
</Widget>
<Widget type="MWScrollBar" skin="MW_HScroll" position="0 20 352 14" align="Left Top" name="ToolTipDelaySlider">
<Property key="Range" value="10000"/>
<Property key="Page" value="300"/>
<UserString key="SettingType" value="Slider"/>
<UserString key="SettingCategory" value="GUI"/>
<UserString key="SettingName" value="tooltip delay"/>
<UserString key="SettingValueType" value="Float"/>
</Widget>
<Widget type="TextBox" skin="SandText" position="0 38 352 16" align="Left Top">
<Property key="Caption" value="#{sFast}"/>
<Property key="TextAlign" value="Left"/>
</Widget>
<Widget type="TextBox" skin="SandText" position="0 38 352 16" align="Left Top">
<Property key="Caption" value="#{sSlow}"/>
<Property key="TextAlign" value="Right"/>
</Widget>
</Widget>
<Widget type="HBox" skin="" position="4 170 260 24">
<Widget type="Widget" position="4 124 352 54" align="Left Top">
<Widget type="TextBox" skin="NormalText" position="0 0 352 16" align="Left Top" name="DifficultyText">
<Property key="Caption" value="#{sDifficulty}"/>
</Widget>
<Widget type="MWScrollBar" skin="MW_HScroll" position="0 20 352 14" align="Left Top" name="DifficultySlider">
<Property key="Range" value="10000"/>
<Property key="Page" value="300"/>
<UserString key="SettingType" value="Slider"/>
<UserString key="SettingCategory" value="Game"/>
<UserString key="SettingName" value="difficulty"/>
<UserString key="SettingValueType" value="Float"/>
<UserString key="SettingMin" value="-100"/>
<UserString key="SettingMax" value="100"/>
</Widget>
<Widget type="TextBox" skin="SandText" position="0 38 352 16" align="Left Top">
<Property key="Caption" value="#{sEasy}"/>
<Property key="TextAlign" value="Left"/>
</Widget>
<Widget type="TextBox" skin="SandText" position="0 38 352 16" align="Left Top">
<Property key="Caption" value="#{sHard}"/>
<Property key="TextAlign" value="Right"/>
</Widget>
</Widget>
<Widget type="HBox" skin="" position="4 200 260 24">
<Widget type="AutoSizedButton" skin="MW_Button" align="Left Top" name="AutosaveButton">
<UserString key="SettingCategory" value="Saves"/>
<UserString key="SettingName" value="autosave"/>
<UserString key="SettingType" value="CheckButton"/>
</Widget>
<Widget type="AutoSizedTextBox" skin="SandText" align="Left Top">
<Property key="Caption" value="#{sQuick_Save}"/>
</Widget>
</Widget>
<Widget type="HBox" skin="" position="4 230 260 24">
<Widget type="AutoSizedButton" skin="MW_Button" align="Left Top" name="BestAttackButton">
<UserString key="SettingCategory" value="Game"/>
<UserString key="SettingName" value="best attack"/>
@ -63,7 +102,7 @@
</Widget>
</Widget>
<Widget type="HBox" skin="" position="4 200 260 24">
<Widget type="HBox" skin="" position="4 260 260 24">
<Widget type="AutoSizedButton" skin="MW_Button" align="Left Top" name="SubtitlesButton">
<UserString key="SettingCategory" value="GUI"/>
<UserString key="SettingName" value="subtitles"/>
@ -74,7 +113,7 @@
</Widget>
</Widget>
<Widget type="HBox" skin="" position="4 230 260 24">
<Widget type="HBox" skin="" position="4 290 260 24">
<Widget type="AutoSizedButton" skin="MW_Button" align="Left Top" name="CrosshairButton">
<UserString key="SettingCategory" value="HUD"/>
<UserString key="SettingName" value="crosshair"/>
@ -85,28 +124,6 @@
</Widget>
</Widget>
<Widget type="HBox" skin="" position="4 260 260 24">
<Widget type="AutoSizedButton" skin="MW_Button" align="Left Top" name="GrabCursorButton">
<UserString key="SettingCategory" value="Input"/>
<UserString key="SettingName" value="grab cursor"/>
<UserString key="SettingType" value="CheckButton"/>
</Widget>
<Widget type="AutoSizedTextBox" skin="SandText" align="Left Top">
<Property key="Caption" value="Grab cursor"/>
</Widget>
</Widget>
<Widget type="HBox" skin="" position="4 290 260 24">
<Widget type="AutoSizedButton" skin="MW_Button" align="Left Top" name="AutosaveButton">
<UserString key="SettingCategory" value="Saves"/>
<UserString key="SettingName" value="autosave"/>
<UserString key="SettingType" value="CheckButton"/>
</Widget>
<Widget type="AutoSizedTextBox" skin="SandText" align="Left Top">
<Property key="Caption" value="#{sQuick_Save}"/>
</Widget>
</Widget>
</Widget>
<Widget type="TabItem" skin="" position="4 28 360 312">
<Property key="Caption" value=" #{sAudio} "/>

View file

@ -170,6 +170,8 @@ always run = false
# Always use the most powerful attack when striking with a weapon (chop, slash or thrust)
best attack = false
difficulty = 0
[Saves]
character =
# Save when resting