mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-16 20:19:57 +00:00
Merge branch 'master' into coverity_scan
This commit is contained in:
commit
1900cf822b
227 changed files with 4955 additions and 1980 deletions
|
@ -24,8 +24,6 @@ addons:
|
||||||
packages: [
|
packages: [
|
||||||
# Dev
|
# Dev
|
||||||
cmake, clang-3.6, libunshield-dev, libtinyxml-dev,
|
cmake, clang-3.6, libunshield-dev, libtinyxml-dev,
|
||||||
# Tests
|
|
||||||
libgtest-dev, google-mock,
|
|
||||||
# Boost
|
# Boost
|
||||||
libboost-filesystem-dev, libboost-program-options-dev, libboost-system-dev,
|
libboost-filesystem-dev, libboost-program-options-dev, libboost-system-dev,
|
||||||
# FFmpeg
|
# FFmpeg
|
||||||
|
|
|
@ -153,6 +153,7 @@ Programmers
|
||||||
Siimacore
|
Siimacore
|
||||||
sir_herrbatka
|
sir_herrbatka
|
||||||
smbas
|
smbas
|
||||||
|
Sophie Kirschner (pineapplemachine)
|
||||||
spycrab
|
spycrab
|
||||||
Stefan Galowicz (bogglez)
|
Stefan Galowicz (bogglez)
|
||||||
Stanislav Bobrov (Jiub)
|
Stanislav Bobrov (Jiub)
|
||||||
|
@ -171,7 +172,9 @@ Programmers
|
||||||
viadanna
|
viadanna
|
||||||
Vincent Heuken
|
Vincent Heuken
|
||||||
vocollapse
|
vocollapse
|
||||||
|
Yohaulticetl
|
||||||
zelurker
|
zelurker
|
||||||
|
James Carty (MrTopCat)
|
||||||
|
|
||||||
Documentation
|
Documentation
|
||||||
-------------
|
-------------
|
||||||
|
@ -180,9 +183,11 @@ Documentation
|
||||||
Alejandro Sanchez (HiPhish)
|
Alejandro Sanchez (HiPhish)
|
||||||
Bodillium
|
Bodillium
|
||||||
Bret Curtis (psi29a)
|
Bret Curtis (psi29a)
|
||||||
|
David Walley (Loriel)
|
||||||
Cramal
|
Cramal
|
||||||
Ryan Tucker (Ravenwing)
|
Ryan Tucker (Ravenwing)
|
||||||
sir_herrbatka
|
sir_herrbatka
|
||||||
|
Diego Crespo
|
||||||
|
|
||||||
Packagers
|
Packagers
|
||||||
---------
|
---------
|
||||||
|
|
63
CHANGELOG.md
63
CHANGELOG.md
|
@ -4,6 +4,8 @@
|
||||||
Bug #1990: Sunrise/sunset not set correct
|
Bug #1990: Sunrise/sunset not set correct
|
||||||
Bug #2131: Lustidrike's spell misses the player every time
|
Bug #2131: Lustidrike's spell misses the player every time
|
||||||
Bug #2222: Fatigue's effect on selling price is backwards
|
Bug #2222: Fatigue's effect on selling price is backwards
|
||||||
|
Bug #2256: Landing sound not playing when jumping immediately after landing
|
||||||
|
Bug #2274: Thin platform clips through player character instead of lifting
|
||||||
Bug #2326: After a bound item expires the last equipped item of that type is not automatically re-equipped
|
Bug #2326: After a bound item expires the last equipped item of that type is not automatically re-equipped
|
||||||
Bug #2455: Creatures attacks degrade armor
|
Bug #2455: Creatures attacks degrade armor
|
||||||
Bug #2562: Forcing AI to activate a teleport door sometimes causes a crash
|
Bug #2562: Forcing AI to activate a teleport door sometimes causes a crash
|
||||||
|
@ -12,15 +14,25 @@
|
||||||
Bug #2835: Player able to slowly move when overencumbered
|
Bug #2835: Player able to slowly move when overencumbered
|
||||||
Bug #2852: No murder bounty when a player follower commits murder
|
Bug #2852: No murder bounty when a player follower commits murder
|
||||||
Bug #2862: [macOS] Can't quit launcher using Command-Q or OpenMW->Quit
|
Bug #2862: [macOS] Can't quit launcher using Command-Q or OpenMW->Quit
|
||||||
|
Bug #2872: Tab completion in console doesn't work with explicit reference
|
||||||
Bug #2971: Compiler did not reject lines with naked expressions beginning with x.y
|
Bug #2971: Compiler did not reject lines with naked expressions beginning with x.y
|
||||||
|
Bug #3049: Drain and Fortify effects are not properly applied on health, magicka and fatigue
|
||||||
|
Bug #3059: Unable to hit with marksman weapons when too close to an enemy
|
||||||
|
Bug #3072: Fatal error on AddItem <item> that has a script containing Equip <item>
|
||||||
Bug #3249: Fixed revert function not updating views properly
|
Bug #3249: Fixed revert function not updating views properly
|
||||||
Bug #3374: Touch spells not hitting kwama foragers
|
Bug #3374: Touch spells not hitting kwama foragers
|
||||||
Bug #3486: [Mod] NPC Commands does not work
|
Bug #3486: [Mod] NPC Commands does not work
|
||||||
|
Bug #3533: GetSpellEffects should detect effects with zero duration
|
||||||
Bug #3591: Angled hit distance too low
|
Bug #3591: Angled hit distance too low
|
||||||
Bug #3629: DB assassin attack never triggers creature spawning
|
Bug #3629: DB assassin attack never triggers creature spawning
|
||||||
|
Bug #3681: OpenMW-CS: Clicking Scripts in Preferences spawns many color pickers
|
||||||
|
Bug #3788: GetPCInJail and GetPCTraveling do not work as in vanilla
|
||||||
|
Bug #3836: Script fails to compile when command argument contains "\n"
|
||||||
Bug #3876: Landscape texture painting is misaligned
|
Bug #3876: Landscape texture painting is misaligned
|
||||||
Bug #3897: Have Goodbye give all choices the effects of Goodbye
|
Bug #3897: Have Goodbye give all choices the effects of Goodbye
|
||||||
Bug #3911: [macOS] Typing in the "Content List name" dialog box produces double characters
|
Bug #3911: [macOS] Typing in the "Content List name" dialog box produces double characters
|
||||||
|
Bug #3920: RemoveSpellEffects doesn't remove constant effects
|
||||||
|
Bug #3948: AiCombat moving target aiming uses incorrect speed for magic projectiles
|
||||||
Bug #3950: FLATTEN_STATIC_TRANSFORMS optimization breaks animated collision shapes
|
Bug #3950: FLATTEN_STATIC_TRANSFORMS optimization breaks animated collision shapes
|
||||||
Bug #3993: Terrain texture blending map is not upscaled
|
Bug #3993: Terrain texture blending map is not upscaled
|
||||||
Bug #3997: Almalexia doesn't pace
|
Bug #3997: Almalexia doesn't pace
|
||||||
|
@ -31,15 +43,20 @@
|
||||||
Bug #4215: OpenMW shows book text after last EOL tag
|
Bug #4215: OpenMW shows book text after last EOL tag
|
||||||
Bug #4221: Characters get stuck in V-shaped terrain
|
Bug #4221: Characters get stuck in V-shaped terrain
|
||||||
Bug #4230: AiTravel package issues break some Tribunal quests
|
Bug #4230: AiTravel package issues break some Tribunal quests
|
||||||
|
Bug #4231: Infected rats from the "Crimson Plague" quest rendered unconscious by change in Drain Fatigue functionality
|
||||||
Bug #4251: Stationary NPCs do not return to their position after combat
|
Bug #4251: Stationary NPCs do not return to their position after combat
|
||||||
|
Bug #4271: Scamp flickers when attacking
|
||||||
Bug #4274: Pre-0.43 death animations are not forward-compatible with 0.43+
|
Bug #4274: Pre-0.43 death animations are not forward-compatible with 0.43+
|
||||||
Bug #4286: Scripted animations can be interrupted
|
Bug #4286: Scripted animations can be interrupted
|
||||||
Bug #4291: Non-persistent actors that started the game as dead do not play death animations
|
Bug #4291: Non-persistent actors that started the game as dead do not play death animations
|
||||||
Bug #4293: Faction members are not aware of faction ownerships in barter
|
Bug #4293: Faction members are not aware of faction ownerships in barter
|
||||||
|
Bug #4304: "Follow" not working as a second AI package
|
||||||
Bug #4307: World cleanup should remove dead bodies only if death animation is finished
|
Bug #4307: World cleanup should remove dead bodies only if death animation is finished
|
||||||
|
Bug #4311: OpenMW does not handle RootCollisionNode correctly
|
||||||
Bug #4327: Missing animations during spell/weapon stance switching
|
Bug #4327: Missing animations during spell/weapon stance switching
|
||||||
Bug #4358: Running animation is interrupted when magic mode is toggled
|
Bug #4358: Running animation is interrupted when magic mode is toggled
|
||||||
Bug #4368: Settings window ok button doesn't have key focus by default
|
Bug #4368: Settings window ok button doesn't have key focus by default
|
||||||
|
Bug #4378: On-self absorb spells restore stats
|
||||||
Bug #4393: NPCs walk back to where they were after using ResetActors
|
Bug #4393: NPCs walk back to where they were after using ResetActors
|
||||||
Bug #4416: Handle exception if we try to play non-music file
|
Bug #4416: Handle exception if we try to play non-music file
|
||||||
Bug #4419: MRK NiStringExtraData is handled incorrectly
|
Bug #4419: MRK NiStringExtraData is handled incorrectly
|
||||||
|
@ -59,6 +76,7 @@
|
||||||
Bug #4461: "Open" spell from non-player caster isn't a crime
|
Bug #4461: "Open" spell from non-player caster isn't a crime
|
||||||
Bug #4464: OpenMW keeps AiState cached storages even after we cancel AI packages
|
Bug #4464: OpenMW keeps AiState cached storages even after we cancel AI packages
|
||||||
Bug #4469: Abot Silt Striders – Model turn 90 degrees on horizontal
|
Bug #4469: Abot Silt Striders – Model turn 90 degrees on horizontal
|
||||||
|
Bug #4470: Non-bipedal creatures with Weapon & Shield flag have inconsistent behaviour
|
||||||
Bug #4474: No fallback when getVampireHead fails
|
Bug #4474: No fallback when getVampireHead fails
|
||||||
Bug #4475: Scripted animations should not cause movement
|
Bug #4475: Scripted animations should not cause movement
|
||||||
Bug #4479: "Game" category on Advanced page is getting too long
|
Bug #4479: "Game" category on Advanced page is getting too long
|
||||||
|
@ -72,10 +90,39 @@
|
||||||
Bug #4503: Cast and ExplodeSpell commands increase alteration skill
|
Bug #4503: Cast and ExplodeSpell commands increase alteration skill
|
||||||
Bug #4510: Division by zero in MWMechanics::CreatureStats::setAttribute
|
Bug #4510: Division by zero in MWMechanics::CreatureStats::setAttribute
|
||||||
Bug #4519: Knockdown does not discard movement in the 1st-person mode
|
Bug #4519: Knockdown does not discard movement in the 1st-person mode
|
||||||
|
Bug #4531: Movement does not reset idle animations
|
||||||
|
Bug #4539: Paper Doll is affected by GUI scaling
|
||||||
|
Bug #4545: Creatures flee from werewolves
|
||||||
|
Bug #4551: Replace 0 sound range with default range separately
|
||||||
|
Bug #4553: Forcegreeting on non-actor opens a dialogue window which cannot be closed
|
||||||
|
Bug #4557: Topics with reserved names are handled differently from vanilla
|
||||||
|
Bug #4558: Mesh optimizer: check for reserved node name is case-sensitive
|
||||||
|
Bug #4560: OpenMW does not update pinned windows properly
|
||||||
|
Bug #4563: Fast travel price logic checks destination cell instead of service actor cell
|
||||||
|
Bug #4565: Underwater view distance should be limited
|
||||||
|
Bug #4573: Player uses headtracking in the 1st-person mode
|
||||||
|
Bug #4574: Player turning animations are twitchy
|
||||||
|
Bug #4575: Weird result of attack animation blending with movement animations
|
||||||
|
Bug #4576: Reset of idle animations when attack can not be started
|
||||||
|
Bug #4591: Attack strength should be 0 if player did not hold the attack button
|
||||||
|
Bug #4597: <> operator causes a compile error
|
||||||
|
Bug #4604: Picking up gold from the ground only makes 1 grabbed
|
||||||
|
Bug #4607: Scaling for animated collision shapes is applied twice
|
||||||
|
Bug #4608: Falling damage is applied twice
|
||||||
|
Bug #4614: Crash due to division by zero when FlipController has no textures
|
||||||
|
Bug #4615: Flicker effects for light sources are handled incorrectly
|
||||||
|
Bug #4617: First person sneaking offset is not applied while the character is in air
|
||||||
|
Bug #4618: Sneaking is possible while the character is flying
|
||||||
|
Bug #4622: Recharging enchanted items with Soul Gems does not award experience if it fails
|
||||||
|
Bug #4628: NPC record reputation, disposition and faction rank should have unsigned char type
|
||||||
|
Feature #1645: Casting effects from objects
|
||||||
Feature #2606: Editor: Implemented (optional) case sensitive global search
|
Feature #2606: Editor: Implemented (optional) case sensitive global search
|
||||||
Feature #3083: Play animation when NPC is casting spell via script
|
Feature #3083: Play animation when NPC is casting spell via script
|
||||||
Feature #3276: Editor: Search- Show number of (remaining) search results and indicate a search without any results
|
Feature #3103: Provide option for disposition to get increased by successful trade
|
||||||
|
Feature #3276: Editor: Search - Show number of (remaining) search results and indicate a search without any results
|
||||||
Feature #3641: Editor: Limit FPS in 3d preview window
|
Feature #3641: Editor: Limit FPS in 3d preview window
|
||||||
|
Feature #3703: Ranged sneak attack criticals
|
||||||
|
Feature #4012: Editor: Write a log file if OpenCS crashes
|
||||||
Feature #4222: 360° screenshots
|
Feature #4222: 360° screenshots
|
||||||
Feature #4256: Implement ToggleBorders (TB) console command
|
Feature #4256: Implement ToggleBorders (TB) console command
|
||||||
Feature #4324: Add CFBundleIdentifier in Info.plist to allow for macOS function key shortcuts
|
Feature #4324: Add CFBundleIdentifier in Info.plist to allow for macOS function key shortcuts
|
||||||
|
@ -84,11 +131,23 @@
|
||||||
Feature #4444: Per-group KF-animation files support
|
Feature #4444: Per-group KF-animation files support
|
||||||
Feature #4466: Editor: Add option to ignore "Base" records when running verifier
|
Feature #4466: Editor: Add option to ignore "Base" records when running verifier
|
||||||
Feature #4488: Make water shader rougher during rain
|
Feature #4488: Make water shader rougher during rain
|
||||||
Feature #4012: Editor: Write a log file if OpenCS crashes
|
|
||||||
Feature #4509: Show count of enchanted items in stack in the spells list
|
Feature #4509: Show count of enchanted items in stack in the spells list
|
||||||
Feature #4512: Editor: Use markers for lights and creatures levelled lists
|
Feature #4512: Editor: Use markers for lights and creatures levelled lists
|
||||||
|
Feature #4548: Weapon priority: use the actual chance to hit the target instead of weapon skill
|
||||||
|
Feature #4549: Weapon priority: use the actual damage in weapon rating calculations
|
||||||
|
Feature #4550: Weapon priority: make ranged weapon bonus more sensible
|
||||||
|
Feature #4579: Add option for applying Strength into hand to hand damage
|
||||||
|
Feature #4581: Use proper logging system
|
||||||
|
Feature #4624: Spell priority: don't cast hit chance-affecting spells if the enemy is not in respective stance at the moment
|
||||||
|
Feature #4625: Weapon priority: use weighted mean for melee damage rating
|
||||||
|
Feature #4626: Weapon priority: account for weapon speed
|
||||||
|
Feature #4632: AI priority: utilize vanilla AI GMSTs for priority rating
|
||||||
Task #2490: Don't open command prompt window on Release-mode builds automatically
|
Task #2490: Don't open command prompt window on Release-mode builds automatically
|
||||||
Task #4545: Enable is_pod string test
|
Task #4545: Enable is_pod string test
|
||||||
|
Task #4605: Optimize skinning
|
||||||
|
Task #4606: Support Rapture3D's OpenAL driver
|
||||||
|
Task #4613: Incomplete type errors when compiling with g++ on OSX 10.9
|
||||||
|
Task #4621: Optimize combat AI
|
||||||
|
|
||||||
0.44.0
|
0.44.0
|
||||||
------
|
------
|
||||||
|
|
|
@ -1,11 +1,3 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
sudo ln -s /usr/bin/clang-3.6 /usr/local/bin/clang
|
sudo ln -s /usr/bin/clang-3.6 /usr/local/bin/clang
|
||||||
sudo ln -s /usr/bin/clang++-3.6 /usr/local/bin/clang++
|
sudo ln -s /usr/bin/clang++-3.6 /usr/local/bin/clang++
|
||||||
|
|
||||||
# build libgtest & libgtest_main
|
|
||||||
sudo mkdir /usr/src/gtest/build
|
|
||||||
cd /usr/src/gtest/build
|
|
||||||
sudo cmake .. -DBUILD_SHARED_LIBS=1
|
|
||||||
sudo make -j4
|
|
||||||
sudo ln -s /usr/src/gtest/build/libgtest.so /usr/lib/libgtest.so
|
|
||||||
sudo ln -s /usr/src/gtest/build/libgtest_main.so /usr/lib/libgtest_main.so
|
|
||||||
|
|
|
@ -1,8 +1,21 @@
|
||||||
#!/bin/sh
|
#!/bin/sh -e
|
||||||
|
|
||||||
free -m
|
free -m
|
||||||
|
|
||||||
|
env GENERATOR='Unix Makefiles' CONFIGURATION=Release CI/build_googletest.sh
|
||||||
|
GOOGLETEST_DIR="$(pwd)/googletest/build"
|
||||||
|
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
export CODE_COVERAGE=1
|
export CODE_COVERAGE=1
|
||||||
if [ "${CC}" = "clang" ]; then export CODE_COVERAGE=0; fi
|
if [ "${CC}" = "clang" ]; then export CODE_COVERAGE=0; fi
|
||||||
${ANALYZE}cmake .. -DBUILD_WITH_CODE_COVERAGE=${CODE_COVERAGE} -DBUILD_UNITTESTS=1 -DCMAKE_INSTALL_PREFIX=/usr -DBINDIR=/usr/games -DCMAKE_BUILD_TYPE="None" -DUSE_SYSTEM_TINYXML=TRUE
|
${ANALYZE}cmake \
|
||||||
|
-DBUILD_WITH_CODE_COVERAGE=${CODE_COVERAGE} \
|
||||||
|
-DBUILD_UNITTESTS=1 \
|
||||||
|
-DCMAKE_INSTALL_PREFIX=/usr \
|
||||||
|
-DBINDIR=/usr/games \
|
||||||
|
-DCMAKE_BUILD_TYPE="None" \
|
||||||
|
-DUSE_SYSTEM_TINYXML=TRUE \
|
||||||
|
-DGTEST_ROOT="${GOOGLETEST_DIR}" \
|
||||||
|
-DGMOCK_ROOT="${GOOGLETEST_DIR}" \
|
||||||
|
..
|
||||||
|
|
13
CI/build_googletest.sh
Executable file
13
CI/build_googletest.sh
Executable file
|
@ -0,0 +1,13 @@
|
||||||
|
#!/bin/sh -e
|
||||||
|
|
||||||
|
git clone https://github.com/google/googletest.git
|
||||||
|
cd googletest
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake \
|
||||||
|
-D CMAKE_BUILD_TYPE="${CONFIGURATION}" \
|
||||||
|
-D CMAKE_INSTALL_PREFIX=. \
|
||||||
|
-G "${GENERATOR}" \
|
||||||
|
..
|
||||||
|
cmake --build . --config "${CONFIGURATION}"
|
||||||
|
cmake --build . --target install --config "${CONFIGURATION}"
|
|
@ -624,7 +624,7 @@ if (WIN32)
|
||||||
# Warnings that aren't enabled normally and don't need to be enabled
|
# Warnings that aren't enabled normally and don't need to be enabled
|
||||||
# They're unneeded and sometimes completely retarded warnings that /Wall enables
|
# They're unneeded and sometimes completely retarded warnings that /Wall enables
|
||||||
# Not going to bother commenting them as they tend to warn on every standard library file
|
# Not going to bother commenting them as they tend to warn on every standard library file
|
||||||
4061 4263 4264 4266 4350 4371 4435 4514 4548 4571 4610 4619 4623 4625
|
4061 4263 4264 4266 4350 4371 4435 4514 4548 4571 4610 4619 4623 4625
|
||||||
4626 4628 4640 4668 4710 4711 4768 4820 4826 4917 4946 5032 5039 5045
|
4626 4628 4640 4668 4710 4711 4768 4820 4826 4917 4946 5032 5039 5045
|
||||||
|
|
||||||
# Warnings that are thrown on standard libraries and not OpenMW
|
# Warnings that are thrown on standard libraries and not OpenMW
|
||||||
|
@ -643,6 +643,7 @@ if (WIN32)
|
||||||
|
|
||||||
# caused by boost
|
# caused by boost
|
||||||
4191 # 'type cast' : unsafe conversion (1.56, thread_primitives.hpp, normally off)
|
4191 # 'type cast' : unsafe conversion (1.56, thread_primitives.hpp, normally off)
|
||||||
|
4643 # Forward declaring 'X' in namespace std is not permitted by the C++ Standard. (in *_std_fwd.h files)
|
||||||
|
|
||||||
# caused by MyGUI
|
# caused by MyGUI
|
||||||
4275 # non dll-interface class 'std::exception' used as base for dll-interface class 'MyGUI::Exception'
|
4275 # non dll-interface class 'std::exception' used as base for dll-interface class 'MyGUI::Exception'
|
||||||
|
|
|
@ -20,6 +20,7 @@ namespace ESSImport
|
||||||
item.mId = contItem.mItem.toString();
|
item.mId = contItem.mItem.toString();
|
||||||
item.mCount = contItem.mCount;
|
item.mCount = contItem.mCount;
|
||||||
item.mRelativeEquipmentSlot = -1;
|
item.mRelativeEquipmentSlot = -1;
|
||||||
|
item.mLockLevel = 0;
|
||||||
|
|
||||||
unsigned int itemCount = std::abs(item.mCount);
|
unsigned int itemCount = std::abs(item.mCount);
|
||||||
bool separateStacks = false;
|
bool separateStacks = false;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
set(LAUNCHER
|
set(LAUNCHER
|
||||||
datafilespage.cpp
|
datafilespage.cpp
|
||||||
graphicspage.cpp
|
graphicspage.cpp
|
||||||
|
sdlinit.cpp
|
||||||
main.cpp
|
main.cpp
|
||||||
maindialog.cpp
|
maindialog.cpp
|
||||||
playpage.cpp
|
playpage.cpp
|
||||||
|
@ -19,6 +20,7 @@ set(LAUNCHER
|
||||||
set(LAUNCHER_HEADER
|
set(LAUNCHER_HEADER
|
||||||
datafilespage.hpp
|
datafilespage.hpp
|
||||||
graphicspage.hpp
|
graphicspage.hpp
|
||||||
|
sdlinit.hpp
|
||||||
maindialog.hpp
|
maindialog.hpp
|
||||||
playpage.hpp
|
playpage.hpp
|
||||||
textslotmsgbox.hpp
|
textslotmsgbox.hpp
|
||||||
|
|
|
@ -73,6 +73,12 @@ bool Launcher::AdvancedPage::loadSettings()
|
||||||
loadSettingBool(followersAttackOnSightCheckBox, "followers attack on sight", "Game");
|
loadSettingBool(followersAttackOnSightCheckBox, "followers attack on sight", "Game");
|
||||||
loadSettingBool(preventMerchantEquippingCheckBox, "prevent merchant equipping", "Game");
|
loadSettingBool(preventMerchantEquippingCheckBox, "prevent merchant equipping", "Game");
|
||||||
loadSettingBool(rebalanceSoulGemValuesCheckBox, "rebalance soul gem values", "Game");
|
loadSettingBool(rebalanceSoulGemValuesCheckBox, "rebalance soul gem values", "Game");
|
||||||
|
loadSettingBool(chargeForEveryFollowerCheckBox, "charge for every follower travelling", "Game");
|
||||||
|
loadSettingBool(enchantedWeaponsMagicalCheckBox, "enchanted weapons are magical", "Game");
|
||||||
|
loadSettingBool(permanentBarterDispositionChangeCheckBox, "barter disposition change is permanent", "Game");
|
||||||
|
int unarmedFactorsStrengthIndex = mEngineSettings.getInt("strength influences hand to hand", "Game");
|
||||||
|
if (unarmedFactorsStrengthIndex >= 0 && unarmedFactorsStrengthIndex <= 2)
|
||||||
|
unarmedFactorsStrengthComboBox->setCurrentIndex(unarmedFactorsStrengthIndex);
|
||||||
|
|
||||||
// Input Settings
|
// Input Settings
|
||||||
loadSettingBool(allowThirdPersonZoomCheckBox, "allow third person zoom", "Input");
|
loadSettingBool(allowThirdPersonZoomCheckBox, "allow third person zoom", "Input");
|
||||||
|
@ -125,6 +131,12 @@ void Launcher::AdvancedPage::saveSettings()
|
||||||
saveSettingBool(followersAttackOnSightCheckBox, "followers attack on sight", "Game");
|
saveSettingBool(followersAttackOnSightCheckBox, "followers attack on sight", "Game");
|
||||||
saveSettingBool(preventMerchantEquippingCheckBox, "prevent merchant equipping", "Game");
|
saveSettingBool(preventMerchantEquippingCheckBox, "prevent merchant equipping", "Game");
|
||||||
saveSettingBool(rebalanceSoulGemValuesCheckBox, "rebalance soul gem values", "Game");
|
saveSettingBool(rebalanceSoulGemValuesCheckBox, "rebalance soul gem values", "Game");
|
||||||
|
saveSettingBool(chargeForEveryFollowerCheckBox, "charge for every follower travelling", "Game");
|
||||||
|
saveSettingBool(enchantedWeaponsMagicalCheckBox, "enchanted weapons are magical", "Game");
|
||||||
|
saveSettingBool(permanentBarterDispositionChangeCheckBox, "barter disposition change is permanent", "Game");
|
||||||
|
int unarmedFactorsStrengthIndex = unarmedFactorsStrengthComboBox->currentIndex();
|
||||||
|
if (unarmedFactorsStrengthIndex != mEngineSettings.getInt("strength influences hand to hand", "Game"))
|
||||||
|
mEngineSettings.setInt("strength influences hand to hand", "Game", unarmedFactorsStrengthIndex);
|
||||||
|
|
||||||
// Input Settings
|
// Input Settings
|
||||||
saveSettingBool(allowThirdPersonZoomCheckBox, "allow third person zoom", "Input");
|
saveSettingBool(allowThirdPersonZoomCheckBox, "allow third person zoom", "Input");
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
#define MAC_OS_X_VERSION_MIN_REQUIRED __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
|
#define MAC_OS_X_VERSION_MIN_REQUIRED __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
|
||||||
#endif // MAC_OS_X_VERSION_MIN_REQUIRED
|
#endif // MAC_OS_X_VERSION_MIN_REQUIRED
|
||||||
|
|
||||||
#include <SDL.h>
|
|
||||||
#include <SDL_video.h>
|
#include <SDL_video.h>
|
||||||
|
|
||||||
#include <components/files/configurationmanager.hpp>
|
#include <components/files/configurationmanager.hpp>
|
||||||
|
@ -48,27 +47,15 @@ Launcher::GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, Settings:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Launcher::GraphicsPage::connectToSdl() {
|
|
||||||
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
|
|
||||||
SDL_SetMainReady();
|
|
||||||
// Required for determining screen resolution and such on the Graphics tab
|
|
||||||
if (SDL_Init(SDL_INIT_VIDEO) != 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
signal(SIGINT, SIG_DFL); // We don't want to use the SDL event loop in the launcher,
|
|
||||||
// so reset SIGINT which SDL wants to redirect to an SDL_Quit event.
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Launcher::GraphicsPage::setupSDL()
|
bool Launcher::GraphicsPage::setupSDL()
|
||||||
{
|
{
|
||||||
bool sdlConnectSuccessful = connectToSdl();
|
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||||
|
bool sdlConnectSuccessful = initSDL();
|
||||||
if (!sdlConnectSuccessful)
|
if (!sdlConnectSuccessful)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int displays = SDL_GetNumVideoDisplays();
|
int displays = SDL_GetNumVideoDisplays();
|
||||||
|
|
||||||
|
@ -89,8 +76,10 @@ bool Launcher::GraphicsPage::setupSDL()
|
||||||
screenComboBox->addItem(QString(tr("Screen ")) + QString::number(i + 1));
|
screenComboBox->addItem(QString(tr("Screen ")) + QString::number(i + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||||
// Disconnect from SDL processes
|
// Disconnect from SDL processes
|
||||||
SDL_Quit();
|
quitSDL();
|
||||||
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
|
#include "sdlinit.hpp"
|
||||||
|
|
||||||
namespace Files { struct ConfigurationManager; }
|
namespace Files { struct ConfigurationManager; }
|
||||||
|
|
||||||
namespace Launcher
|
namespace Launcher
|
||||||
|
@ -37,11 +39,6 @@ namespace Launcher
|
||||||
QStringList getAvailableResolutions(int screen);
|
QStringList getAvailableResolutions(int screen);
|
||||||
QRect getMaximumResolution();
|
QRect getMaximumResolution();
|
||||||
|
|
||||||
/**
|
|
||||||
* Connect to the SDL so that we can use it to determine graphics
|
|
||||||
* @return whether or not connecting to SDL is successful
|
|
||||||
*/
|
|
||||||
bool connectToSdl();
|
|
||||||
bool setupSDL();
|
bool setupSDL();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,11 +12,18 @@
|
||||||
#endif // MAC_OS_X_VERSION_MIN_REQUIRED
|
#endif // MAC_OS_X_VERSION_MIN_REQUIRED
|
||||||
|
|
||||||
#include "maindialog.hpp"
|
#include "maindialog.hpp"
|
||||||
|
#include "sdlinit.hpp"
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
// Note: we should init SDL2 before Qt4 to avoid crashes on Linux,
|
||||||
|
// but we should init SDL2 after Qt5 to avoid input issues on MacOS X.
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
|
||||||
|
initSDL();
|
||||||
|
#endif
|
||||||
|
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
// Now we make sure the current dir is set to application path
|
// Now we make sure the current dir is set to application path
|
||||||
|
@ -33,11 +40,18 @@ int main(int argc, char *argv[])
|
||||||
if (result == Launcher::FirstRunDialogResultContinue)
|
if (result == Launcher::FirstRunDialogResultContinue)
|
||||||
mainWin.show();
|
mainWin.show();
|
||||||
|
|
||||||
return app.exec();
|
int exitCode = app.exec();
|
||||||
|
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
|
||||||
|
// Disconnect from SDL processes
|
||||||
|
quitSDL();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return exitCode;
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
std::cerr << "ERROR: " << e.what() << std::endl;
|
std::cerr << "ERROR: " << e.what() << std::endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
25
apps/launcher/sdlinit.cpp
Normal file
25
apps/launcher/sdlinit.cpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
#include <SDL.h>
|
||||||
|
#include <SDL_video.h>
|
||||||
|
|
||||||
|
bool initSDL()
|
||||||
|
{
|
||||||
|
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
|
||||||
|
SDL_SetMainReady();
|
||||||
|
// Required for determining screen resolution and such on the Graphics tab
|
||||||
|
if (SDL_Init(SDL_INIT_VIDEO) != 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
signal(SIGINT, SIG_DFL); // We don't want to use the SDL event loop in the launcher,
|
||||||
|
// so reset SIGINT which SDL wants to redirect to an SDL_Quit event.
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void quitSDL()
|
||||||
|
{
|
||||||
|
// Disconnect from SDL processes
|
||||||
|
SDL_Quit();
|
||||||
|
}
|
8
apps/launcher/sdlinit.hpp
Normal file
8
apps/launcher/sdlinit.hpp
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef SDLINIT_H
|
||||||
|
#define SDLINIT_H
|
||||||
|
|
||||||
|
bool initSDL();
|
||||||
|
|
||||||
|
void quitSDL();
|
||||||
|
|
||||||
|
#endif
|
|
@ -5,11 +5,8 @@
|
||||||
#include <QLocalSocket>
|
#include <QLocalSocket>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
#include <components/crashcatcher/crashcatcher.hpp>
|
|
||||||
|
|
||||||
#include <components/fallback/validate.hpp>
|
#include <components/fallback/validate.hpp>
|
||||||
|
|
||||||
#include <components/nifosg/nifloader.hpp>
|
#include <components/nifosg/nifloader.hpp>
|
||||||
|
|
||||||
#include "model/doc/document.hpp"
|
#include "model/doc/document.hpp"
|
||||||
|
@ -27,10 +24,6 @@ CS::Editor::Editor (int argc, char **argv)
|
||||||
mLock(), mMerge (mDocumentManager),
|
mLock(), mMerge (mDocumentManager),
|
||||||
mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL)
|
mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL)
|
||||||
{
|
{
|
||||||
// install the crash handler as soon as possible. note that the log path
|
|
||||||
// does not depend on config being read.
|
|
||||||
crashCatcherInstall(argc, argv, (mCfgMgr.getLogPath() / "openmw-cs-crash.log").string());
|
|
||||||
|
|
||||||
std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig();
|
std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig();
|
||||||
|
|
||||||
setupDataFiles (config.first);
|
setupDataFiles (config.first);
|
||||||
|
@ -301,7 +294,7 @@ bool CS::Editor::makeIPCServer()
|
||||||
mLock = boost::interprocess::file_lock(mPid.string().c_str());
|
mLock = boost::interprocess::file_lock(mPid.string().c_str());
|
||||||
if(!mLock.try_lock())
|
if(!mLock.try_lock())
|
||||||
{
|
{
|
||||||
std::cerr << "OpenCS already running." << std::endl;
|
Log(Debug::Error) << "Error: OpenMW-CS is already running.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,17 +317,17 @@ bool CS::Editor::makeIPCServer()
|
||||||
if(boost::filesystem::exists(fullPath.toUtf8().constData()))
|
if(boost::filesystem::exists(fullPath.toUtf8().constData()))
|
||||||
{
|
{
|
||||||
// TODO: compare pid of the current process with that in the file
|
// TODO: compare pid of the current process with that in the file
|
||||||
std::cout << "Detected unclean shutdown." << std::endl;
|
Log(Debug::Info) << "Detected unclean shutdown.";
|
||||||
// delete the stale file
|
// delete the stale file
|
||||||
if(remove(fullPath.toUtf8().constData()))
|
if(remove(fullPath.toUtf8().constData()))
|
||||||
std::cerr << "ERROR removing stale connection file" << std::endl;
|
Log(Debug::Error) << "Error: can not remove stale connection file.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
catch(const std::exception& e)
|
catch(const std::exception& e)
|
||||||
{
|
{
|
||||||
std::cerr << "ERROR " << e.what() << std::endl;
|
Log(Debug::Error) << "Error: " << e.what();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
#include "editor.hpp"
|
#include "editor.hpp"
|
||||||
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <iostream>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
#include <QMetaType>
|
#include <QMetaType>
|
||||||
|
|
||||||
#include "model/doc/messages.hpp"
|
#include <components/debug/debugging.hpp>
|
||||||
|
|
||||||
|
#include "model/doc/messages.hpp"
|
||||||
#include "model/world/universalid.hpp"
|
#include "model/world/universalid.hpp"
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
|
@ -30,7 +30,7 @@ class Application : public QApplication
|
||||||
}
|
}
|
||||||
catch (const std::exception& exception)
|
catch (const std::exception& exception)
|
||||||
{
|
{
|
||||||
std::cerr << "An exception has been caught: " << exception.what() << std::endl;
|
Log(Debug::Error) << "An exception has been caught: " << exception.what();
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -41,45 +41,43 @@ class Application : public QApplication
|
||||||
Application (int& argc, char *argv[]) : QApplication (argc, argv) {}
|
Application (int& argc, char *argv[]) : QApplication (argc, argv) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int runApplication(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
setenv("OSG_GL_TEXTURE_STORAGE", "OFF", 0);
|
setenv("OSG_GL_TEXTURE_STORAGE", "OFF", 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
try
|
// To allow background thread drawing in OSG
|
||||||
{
|
QApplication::setAttribute(Qt::AA_X11InitThreads, true);
|
||||||
// To allow background thread drawing in OSG
|
|
||||||
QApplication::setAttribute(Qt::AA_X11InitThreads, true);
|
|
||||||
|
|
||||||
Q_INIT_RESOURCE (resources);
|
Q_INIT_RESOURCE (resources);
|
||||||
|
|
||||||
qRegisterMetaType<std::string> ("std::string");
|
qRegisterMetaType<std::string> ("std::string");
|
||||||
qRegisterMetaType<CSMWorld::UniversalId> ("CSMWorld::UniversalId");
|
qRegisterMetaType<CSMWorld::UniversalId> ("CSMWorld::UniversalId");
|
||||||
qRegisterMetaType<CSMDoc::Message> ("CSMDoc::Message");
|
qRegisterMetaType<CSMDoc::Message> ("CSMDoc::Message");
|
||||||
|
|
||||||
Application application (argc, argv);
|
Application application (argc, argv);
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
QDir dir(QCoreApplication::applicationDirPath());
|
QDir dir(QCoreApplication::applicationDirPath());
|
||||||
QDir::setCurrent(dir.absolutePath());
|
QDir::setCurrent(dir.absolutePath());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
application.setWindowIcon (QIcon (":./openmw-cs.png"));
|
application.setWindowIcon (QIcon (":./openmw-cs.png"));
|
||||||
|
|
||||||
CS::Editor editor(argc, argv);
|
CS::Editor editor(argc, argv);
|
||||||
|
|
||||||
if(!editor.makeIPCServer())
|
if(!editor.makeIPCServer())
|
||||||
{
|
|
||||||
editor.connectToIPCServer();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return editor.run();
|
|
||||||
}
|
|
||||||
catch (std::exception& e)
|
|
||||||
{
|
{
|
||||||
std::cerr << "ERROR: " << e.what() << std::endl;
|
editor.connectToIPCServer();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return editor.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
return wrapApplication(&runApplication, argc, argv, "OpenMW-CS");
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
#include <boost/filesystem/fstream.hpp>
|
#include <boost/filesystem/fstream.hpp>
|
||||||
|
@ -13,6 +12,8 @@
|
||||||
#include <components/files/configurationmanager.hpp>
|
#include <components/files/configurationmanager.hpp>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
|
|
||||||
void CSMDoc::Document::addGmsts()
|
void CSMDoc::Document::addGmsts()
|
||||||
{
|
{
|
||||||
for (size_t i=0; i < CSMWorld::DefaultGmsts::FloatCount; ++i)
|
for (size_t i=0; i < CSMWorld::DefaultGmsts::FloatCount; ++i)
|
||||||
|
@ -435,7 +436,7 @@ void CSMDoc::Document::modificationStateChanged (bool clean)
|
||||||
void CSMDoc::Document::reportMessage (const CSMDoc::Message& message, int type)
|
void CSMDoc::Document::reportMessage (const CSMDoc::Message& message, int type)
|
||||||
{
|
{
|
||||||
/// \todo find a better way to get these messages to the user.
|
/// \todo find a better way to get these messages to the user.
|
||||||
std::cout << message.mMessage << std::endl;
|
Log(Debug::Info) << message.mMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMDoc::Document::operationDone2 (int type, bool failed)
|
void CSMDoc::Document::operationDone2 (int type, bool failed)
|
||||||
|
|
|
@ -109,7 +109,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
|
||||||
pathgrid.mPoints[i].mY == pathgrid.mPoints[j].mY &&
|
pathgrid.mPoints[i].mY == pathgrid.mPoints[j].mY &&
|
||||||
pathgrid.mPoints[i].mZ == pathgrid.mPoints[j].mZ)
|
pathgrid.mPoints[i].mZ == pathgrid.mPoints[j].mZ)
|
||||||
{
|
{
|
||||||
std::vector<int>::const_iterator it = find(duplList.begin(), duplList.end(), i);
|
std::vector<int>::const_iterator it = find(duplList.begin(), duplList.end(), static_cast<int>(i));
|
||||||
if (it == duplList.end())
|
if (it == duplList.end())
|
||||||
{
|
{
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#include "refcollection.hpp"
|
#include "refcollection.hpp"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
#include <components/misc/stringops.hpp>
|
#include <components/misc/stringops.hpp>
|
||||||
#include <components/esm/loadcell.hpp>
|
#include <components/esm/loadcell.hpp>
|
||||||
|
|
||||||
|
@ -58,10 +58,10 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool
|
||||||
// message
|
// message
|
||||||
if (index.first != mref.mTarget[0] || index.second != mref.mTarget[1])
|
if (index.first != mref.mTarget[0] || index.second != mref.mTarget[1])
|
||||||
{
|
{
|
||||||
std::cerr << "The Position of moved ref "
|
Log(Debug::Warning) << "Warning: the Position of moved ref "
|
||||||
<< ref.mRefID << " does not match the target cell" << std::endl;
|
<< ref.mRefID << " does not match the target cell";
|
||||||
std::cerr << "Position: #" << index.first << " " << index.second
|
Log(Debug::Warning) << "Position: #" << index.first << " " << index.second
|
||||||
<<", Target #"<< mref.mTarget[0] << " " << mref.mTarget[1] << std::endl;
|
<<", Target #"<< mref.mTarget[0] << " " << mref.mTarget[1];
|
||||||
|
|
||||||
stream.clear();
|
stream.clear();
|
||||||
stream << "#" << mref.mTarget[0] << " " << mref.mTarget[1];
|
stream << "#" << mref.mTarget[0] << " " << mref.mTarget[1];
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#include "object.hpp"
|
#include "object.hpp"
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include <osg/Depth>
|
#include <osg/Depth>
|
||||||
#include <osg/Group>
|
#include <osg/Group>
|
||||||
|
@ -24,6 +23,7 @@
|
||||||
#include "../../model/world/cellcoordinates.hpp"
|
#include "../../model/world/cellcoordinates.hpp"
|
||||||
#include "../../model/prefs/state.hpp"
|
#include "../../model/prefs/state.hpp"
|
||||||
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
#include <components/resource/scenemanager.hpp>
|
#include <components/resource/scenemanager.hpp>
|
||||||
#include <components/sceneutil/lightutil.hpp>
|
#include <components/sceneutil/lightutil.hpp>
|
||||||
#include <components/sceneutil/lightmanager.hpp>
|
#include <components/sceneutil/lightmanager.hpp>
|
||||||
|
@ -133,7 +133,7 @@ void CSVRender::Object::update()
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
// TODO: use error marker mesh
|
// TODO: use error marker mesh
|
||||||
std::cerr << e.what() << std::endl;
|
Log(Debug::Error) << e.what();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
#include "coloreditor.hpp"
|
#include "coloreditor.hpp"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QColor>
|
|
||||||
#include <QColorDialog>
|
#include <QColorDialog>
|
||||||
#include <QDesktopWidget>
|
#include <QDesktopWidget>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QRect>
|
|
||||||
#include <QShowEvent>
|
#include <QShowEvent>
|
||||||
|
|
||||||
#include "colorpickerpopup.hpp"
|
#include "colorpickerpopup.hpp"
|
||||||
|
@ -27,9 +25,7 @@ CSVWidget::ColorEditor::ColorEditor(QWidget *parent, const bool popupOnStart)
|
||||||
mColorPicker(new ColorPickerPopup(this)),
|
mColorPicker(new ColorPickerPopup(this)),
|
||||||
mPopupOnStart(popupOnStart)
|
mPopupOnStart(popupOnStart)
|
||||||
{
|
{
|
||||||
setCheckable(true);
|
|
||||||
connect(this, SIGNAL(clicked()), this, SLOT(showPicker()));
|
connect(this, SIGNAL(clicked()), this, SLOT(showPicker()));
|
||||||
connect(mColorPicker, SIGNAL(hid()), this, SLOT(pickerHid()));
|
|
||||||
connect(mColorPicker, SIGNAL(colorChanged(const QColor &)), this, SLOT(pickerColorChanged(const QColor &)));
|
connect(mColorPicker, SIGNAL(colorChanged(const QColor &)), this, SLOT(pickerColorChanged(const QColor &)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,20 +81,7 @@ void CSVWidget::ColorEditor::setColor(const int colorInt)
|
||||||
|
|
||||||
void CSVWidget::ColorEditor::showPicker()
|
void CSVWidget::ColorEditor::showPicker()
|
||||||
{
|
{
|
||||||
if (isChecked())
|
mColorPicker->showPicker(calculatePopupPosition(), mColor);
|
||||||
{
|
|
||||||
mColorPicker->showPicker(calculatePopupPosition(), mColor);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mColorPicker->hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CSVWidget::ColorEditor::pickerHid()
|
|
||||||
{
|
|
||||||
setChecked(false);
|
|
||||||
emit pickingFinished();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVWidget::ColorEditor::pickerColorChanged(const QColor &color)
|
void CSVWidget::ColorEditor::pickerColorChanged(const QColor &color)
|
||||||
|
|
|
@ -45,7 +45,6 @@ namespace CSVWidget
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void showPicker();
|
void showPicker();
|
||||||
void pickerHid();
|
|
||||||
void pickerColorChanged(const QColor &color);
|
void pickerColorChanged(const QColor &color);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QEvent>
|
#include <QEvent>
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
#include <QMouseEvent>
|
|
||||||
#include <QLayout>
|
#include <QLayout>
|
||||||
#include <QStyleOption>
|
#include <QStyleOption>
|
||||||
|
|
||||||
|
@ -19,7 +18,6 @@ CSVWidget::ColorPickerPopup::ColorPickerPopup(QWidget *parent)
|
||||||
mColorPicker->setWindowFlags(Qt::Widget);
|
mColorPicker->setWindowFlags(Qt::Widget);
|
||||||
mColorPicker->setOptions(QColorDialog::NoButtons | QColorDialog::DontUseNativeDialog);
|
mColorPicker->setOptions(QColorDialog::NoButtons | QColorDialog::DontUseNativeDialog);
|
||||||
mColorPicker->installEventFilter(this);
|
mColorPicker->installEventFilter(this);
|
||||||
mColorPicker->open();
|
|
||||||
connect(mColorPicker,
|
connect(mColorPicker,
|
||||||
SIGNAL(currentColorChanged(const QColor &)),
|
SIGNAL(currentColorChanged(const QColor &)),
|
||||||
this,
|
this,
|
||||||
|
@ -39,8 +37,9 @@ void CSVWidget::ColorPickerPopup::showPicker(const QPoint &position, const QColo
|
||||||
geometry.moveTo(position);
|
geometry.moveTo(position);
|
||||||
setGeometry(geometry);
|
setGeometry(geometry);
|
||||||
|
|
||||||
mColorPicker->setCurrentColor(initialColor);
|
// Calling getColor() creates a blocking dialog that will continue execution once the user chooses OK or Cancel
|
||||||
show();
|
QColor color = mColorPicker->getColor(initialColor);
|
||||||
|
mColorPicker->setCurrentColor(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVWidget::ColorPickerPopup::mousePressEvent(QMouseEvent *event)
|
void CSVWidget::ColorPickerPopup::mousePressEvent(QMouseEvent *event)
|
||||||
|
@ -63,12 +62,6 @@ void CSVWidget::ColorPickerPopup::mousePressEvent(QMouseEvent *event)
|
||||||
QFrame::mousePressEvent(event);
|
QFrame::mousePressEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVWidget::ColorPickerPopup::hideEvent(QHideEvent *event)
|
|
||||||
{
|
|
||||||
QFrame::hideEvent(event);
|
|
||||||
emit hid();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CSVWidget::ColorPickerPopup::eventFilter(QObject *object, QEvent *event)
|
bool CSVWidget::ColorPickerPopup::eventFilter(QObject *object, QEvent *event)
|
||||||
{
|
{
|
||||||
if (object == mColorPicker && event->type() == QEvent::KeyPress)
|
if (object == mColorPicker && event->type() == QEvent::KeyPress)
|
||||||
|
|
|
@ -20,11 +20,9 @@ namespace CSVWidget
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void mousePressEvent(QMouseEvent *event);
|
virtual void mousePressEvent(QMouseEvent *event);
|
||||||
virtual void hideEvent(QHideEvent *event);
|
|
||||||
virtual bool eventFilter(QObject *object, QEvent *event);
|
virtual bool eventFilter(QObject *object, QEvent *event);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void hid();
|
|
||||||
void colorChanged(const QColor &color);
|
void colorChanged(const QColor &color);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
|
|
||||||
#include <components/misc/rng.hpp>
|
#include <components/misc/rng.hpp>
|
||||||
|
|
||||||
#include <components/vfs/manager.hpp>
|
#include <components/vfs/manager.hpp>
|
||||||
|
@ -61,7 +63,7 @@ namespace
|
||||||
void checkSDLError(int ret)
|
void checkSDLError(int ret)
|
||||||
{
|
{
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
std::cerr << "SDL error: " << SDL_GetError() << std::endl;
|
Log(Debug::Error) << "SDL error: " << SDL_GetError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,7 +191,7 @@ bool OMW::Engine::frame(float frametime)
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
std::cerr << "Error in frame: " << e.what() << std::endl;
|
Log(Debug::Error) << "Error in frame: " << e.what();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -198,6 +200,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
|
||||||
: mWindow(NULL)
|
: mWindow(NULL)
|
||||||
, mEncoding(ToUTF8::WINDOWS_1252)
|
, mEncoding(ToUTF8::WINDOWS_1252)
|
||||||
, mEncoder(NULL)
|
, mEncoder(NULL)
|
||||||
|
, mScreenCaptureOperation(nullptr)
|
||||||
, mSkipMenu (false)
|
, mSkipMenu (false)
|
||||||
, mUseSound (true)
|
, mUseSound (true)
|
||||||
, mCompileAll (false)
|
, mCompileAll (false)
|
||||||
|
@ -363,7 +366,7 @@ void OMW::Engine::createWindow(Settings::Manager& settings)
|
||||||
// Try with a lower AA
|
// Try with a lower AA
|
||||||
if (antialiasing > 0)
|
if (antialiasing > 0)
|
||||||
{
|
{
|
||||||
std::cout << "Note: " << antialiasing << "x antialiasing not supported, trying " << antialiasing/2 << std::endl;
|
Log(Debug::Warning) << "Warning: " << antialiasing << "x antialiasing not supported, trying " << antialiasing/2;
|
||||||
antialiasing /= 2;
|
antialiasing /= 2;
|
||||||
Settings::Manager::setInt("antialiasing", "Video", antialiasing);
|
Settings::Manager::setInt("antialiasing", "Video", antialiasing);
|
||||||
checkSDLError(SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, antialiasing));
|
checkSDLError(SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, antialiasing));
|
||||||
|
@ -372,7 +375,7 @@ void OMW::Engine::createWindow(Settings::Manager& settings)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::stringstream error;
|
std::stringstream error;
|
||||||
error << "Failed to create SDL window: " << SDL_GetError() << std::endl;
|
error << "Failed to create SDL window: " << SDL_GetError();
|
||||||
throw std::runtime_error(error.str());
|
throw std::runtime_error(error.str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -419,16 +422,16 @@ void OMW::Engine::setWindowIcon()
|
||||||
std::string windowIcon = (mResDir / "mygui" / "openmw.png").string();
|
std::string windowIcon = (mResDir / "mygui" / "openmw.png").string();
|
||||||
windowIconStream.open(windowIcon, std::ios_base::in | std::ios_base::binary);
|
windowIconStream.open(windowIcon, std::ios_base::in | std::ios_base::binary);
|
||||||
if (windowIconStream.fail())
|
if (windowIconStream.fail())
|
||||||
std::cerr << "Error: Failed to open " << windowIcon << std::endl;
|
Log(Debug::Error) << "Error: Failed to open " << windowIcon;
|
||||||
osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("png");
|
osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("png");
|
||||||
if (!reader)
|
if (!reader)
|
||||||
{
|
{
|
||||||
std::cerr << "Error: Failed to read window icon, no png readerwriter found" << std::endl;
|
Log(Debug::Error) << "Error: Failed to read window icon, no png readerwriter found";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
osgDB::ReaderWriter::ReadResult result = reader->readImage(windowIconStream);
|
osgDB::ReaderWriter::ReadResult result = reader->readImage(windowIconStream);
|
||||||
if (!result.success())
|
if (!result.success())
|
||||||
std::cerr << "Error: Failed to read " << windowIcon << ": " << result.message() << " code " << result.status() << std::endl;
|
Log(Debug::Error) << "Error: Failed to read " << windowIcon << ": " << result.message() << " code " << result.status();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
osg::ref_ptr<osg::Image> image = result.getImage();
|
osg::ref_ptr<osg::Image> image = result.getImage();
|
||||||
|
@ -563,21 +566,19 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||||
{
|
{
|
||||||
std::pair<int, int> result = mEnvironment.getScriptManager()->compileAll();
|
std::pair<int, int> result = mEnvironment.getScriptManager()->compileAll();
|
||||||
if (result.first)
|
if (result.first)
|
||||||
std::cout
|
Log(Debug::Info)
|
||||||
<< "compiled " << result.second << " of " << result.first << " scripts ("
|
<< "compiled " << result.second << " of " << result.first << " scripts ("
|
||||||
<< 100*static_cast<double> (result.second)/result.first
|
<< 100*static_cast<double> (result.second)/result.first
|
||||||
<< "%)"
|
<< "%)";
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
if (mCompileAllDialogue)
|
if (mCompileAllDialogue)
|
||||||
{
|
{
|
||||||
std::pair<int, int> result = MWDialogue::ScriptTest::compileAll(&mExtensions, mWarningsMode);
|
std::pair<int, int> result = MWDialogue::ScriptTest::compileAll(&mExtensions, mWarningsMode);
|
||||||
if (result.first)
|
if (result.first)
|
||||||
std::cout
|
Log(Debug::Info)
|
||||||
<< "compiled " << result.second << " of " << result.first << " dialogue script/actor combinations a("
|
<< "compiled " << result.second << " of " << result.first << " dialogue script/actor combinations a("
|
||||||
<< 100*static_cast<double> (result.second)/result.first
|
<< 100*static_cast<double> (result.second)/result.first
|
||||||
<< "%)"
|
<< "%)";
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -613,14 +614,14 @@ public:
|
||||||
osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension(mScreenshotFormat);
|
osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension(mScreenshotFormat);
|
||||||
if (!readerwriter)
|
if (!readerwriter)
|
||||||
{
|
{
|
||||||
std::cerr << "Error: Can't write screenshot, no '" << mScreenshotFormat << "' readerwriter found" << std::endl;
|
Log(Debug::Error) << "Error: Can't write screenshot, no '" << mScreenshotFormat << "' readerwriter found";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(image, outStream);
|
osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(image, outStream);
|
||||||
if (!result.success())
|
if (!result.success())
|
||||||
{
|
{
|
||||||
std::cerr << "Error: Can't write screenshot: " << result.message() << " code " << result.status() << std::endl;
|
Log(Debug::Error) << "Error: Can't write screenshot: " << result.message() << " code " << result.status();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -635,7 +636,7 @@ void OMW::Engine::go()
|
||||||
{
|
{
|
||||||
assert (!mContentFiles.empty());
|
assert (!mContentFiles.empty());
|
||||||
|
|
||||||
std::cout << "OSG version: " << osgGetVersion() << std::endl;
|
Log(Debug::Info) << "OSG version: " << osgGetVersion();
|
||||||
|
|
||||||
// Load settings
|
// Load settings
|
||||||
Settings::Manager settings;
|
Settings::Manager settings;
|
||||||
|
@ -737,7 +738,7 @@ void OMW::Engine::go()
|
||||||
// Save user settings
|
// Save user settings
|
||||||
settings.saveUser(settingspath);
|
settings.saveUser(settingspath);
|
||||||
|
|
||||||
std::cout << "Quitting peacefully." << std::endl;
|
Log(Debug::Info) << "Quitting peacefully.";
|
||||||
}
|
}
|
||||||
|
|
||||||
void OMW::Engine::setCompileAll (bool all)
|
void OMW::Engine::setCompileAll (bool all)
|
||||||
|
|
|
@ -1,16 +1,11 @@
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include <components/version/version.hpp>
|
#include <components/version/version.hpp>
|
||||||
#include <components/crashcatcher/crashcatcher.hpp>
|
|
||||||
#include <components/files/configurationmanager.hpp>
|
#include <components/files/configurationmanager.hpp>
|
||||||
#include <components/files/escape.hpp>
|
#include <components/files/escape.hpp>
|
||||||
#include <components/fallback/validate.hpp>
|
#include <components/fallback/validate.hpp>
|
||||||
|
#include <components/debug/debugging.hpp>
|
||||||
|
|
||||||
#include <SDL_messagebox.h>
|
|
||||||
#include "engine.hpp"
|
#include "engine.hpp"
|
||||||
|
|
||||||
#include <boost/filesystem/fstream.hpp>
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
// For OutputDebugString
|
// For OutputDebugString
|
||||||
#ifndef WIN32_LEAN_AND_MEAN
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
@ -205,8 +200,8 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
||||||
StringsVector content = variables["content"].as<Files::EscapeStringVector>().toStdStringVector();
|
StringsVector content = variables["content"].as<Files::EscapeStringVector>().toStdStringVector();
|
||||||
if (content.empty())
|
if (content.empty())
|
||||||
{
|
{
|
||||||
std::cout << "No content file given (esm/esp, nor omwgame/omwaddon). Aborting..." << std::endl;
|
Log(Debug::Error) << "No content file given (esm/esp, nor omwgame/omwaddon). Aborting...";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringsVector::const_iterator it(content.begin());
|
StringsVector::const_iterator it(content.begin());
|
||||||
|
@ -220,7 +215,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
||||||
engine.setCell(variables["start"].as<Files::EscapeHashString>().toStdString());
|
engine.setCell(variables["start"].as<Files::EscapeHashString>().toStdString());
|
||||||
engine.setSkipMenu (variables["skip-menu"].as<bool>(), variables["new-game"].as<bool>());
|
engine.setSkipMenu (variables["skip-menu"].as<bool>(), variables["new-game"].as<bool>());
|
||||||
if (!variables["skip-menu"].as<bool>() && variables["new-game"].as<bool>())
|
if (!variables["skip-menu"].as<bool>() && variables["new-game"].as<bool>())
|
||||||
std::cerr << "Warning: new-game used without skip-menu -> ignoring it" << std::endl;
|
Log(Debug::Warning) << "Warning: new-game used without skip-menu -> ignoring it";
|
||||||
|
|
||||||
// scripts
|
// scripts
|
||||||
engine.setCompileAll(variables["script-all"].as<bool>());
|
engine.setCompileAll(variables["script-all"].as<bool>());
|
||||||
|
@ -241,124 +236,33 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(_WIN32) && defined(_DEBUG)
|
int runApplication(int argc, char *argv[])
|
||||||
|
|
||||||
class DebugOutput : public boost::iostreams::sink
|
|
||||||
{
|
{
|
||||||
public:
|
#ifdef __APPLE__
|
||||||
std::streamsize write(const char *str, std::streamsize size)
|
boost::filesystem::path binary_path = boost::filesystem::system_complete(boost::filesystem::path(argv[0]));
|
||||||
{
|
boost::filesystem::current_path(binary_path.parent_path());
|
||||||
// Make a copy for null termination
|
setenv("OSG_GL_TEXTURE_STORAGE", "OFF", 0);
|
||||||
std::string tmp (str, static_cast<unsigned int>(size));
|
|
||||||
// Write string to Visual Studio Debug output
|
|
||||||
OutputDebugString (tmp.c_str ());
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
#else
|
|
||||||
class Tee : public boost::iostreams::sink
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Tee(std::ostream &stream, std::ostream &stream2)
|
|
||||||
: out(stream), out2(stream2)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::streamsize write(const char *str, std::streamsize size)
|
|
||||||
{
|
|
||||||
out.write (str, size);
|
|
||||||
out.flush();
|
|
||||||
out2.write (str, size);
|
|
||||||
out2.flush();
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::ostream &out;
|
|
||||||
std::ostream &out2;
|
|
||||||
};
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Files::ConfigurationManager cfgMgr;
|
||||||
|
std::unique_ptr<OMW::Engine> engine;
|
||||||
|
engine.reset(new OMW::Engine(cfgMgr));
|
||||||
|
|
||||||
|
if (parseOptions(argc, argv, *engine, cfgMgr))
|
||||||
|
{
|
||||||
|
engine->go();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef ANDROID
|
#ifdef ANDROID
|
||||||
extern "C" int SDL_main(int argc, char**argv)
|
extern "C" int SDL_main(int argc, char**argv)
|
||||||
#else
|
#else
|
||||||
int main(int argc, char**argv)
|
int main(int argc, char**argv)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
#if defined(__APPLE__)
|
return wrapApplication(&runApplication, argc, argv, "OpenMW");
|
||||||
setenv("OSG_GL_TEXTURE_STORAGE", "OFF", 0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Some objects used to redirect cout and cerr
|
|
||||||
// Scope must be here, so this still works inside the catch block for logging exceptions
|
|
||||||
std::streambuf* cout_rdbuf = std::cout.rdbuf ();
|
|
||||||
std::streambuf* cerr_rdbuf = std::cerr.rdbuf ();
|
|
||||||
|
|
||||||
#if !(defined(_WIN32) && defined(_DEBUG))
|
|
||||||
boost::iostreams::stream_buffer<Tee> coutsb;
|
|
||||||
boost::iostreams::stream_buffer<Tee> cerrsb;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::ostream oldcout(cout_rdbuf);
|
|
||||||
std::ostream oldcerr(cerr_rdbuf);
|
|
||||||
|
|
||||||
boost::filesystem::ofstream logfile;
|
|
||||||
|
|
||||||
std::unique_ptr<OMW::Engine> engine;
|
|
||||||
|
|
||||||
int ret = 0;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Files::ConfigurationManager cfgMgr;
|
|
||||||
|
|
||||||
#if defined(_WIN32) && defined(_DEBUG)
|
|
||||||
// Redirect cout and cerr to VS debug output when running in debug mode
|
|
||||||
boost::iostreams::stream_buffer<DebugOutput> sb;
|
|
||||||
sb.open(DebugOutput());
|
|
||||||
std::cout.rdbuf (&sb);
|
|
||||||
std::cerr.rdbuf (&sb);
|
|
||||||
#else
|
|
||||||
// Redirect cout and cerr to openmw.log
|
|
||||||
logfile.open (boost::filesystem::path(cfgMgr.getLogPath() / "/openmw.log"));
|
|
||||||
|
|
||||||
coutsb.open (Tee(logfile, oldcout));
|
|
||||||
cerrsb.open (Tee(logfile, oldcerr));
|
|
||||||
|
|
||||||
std::cout.rdbuf (&coutsb);
|
|
||||||
std::cerr.rdbuf (&cerrsb);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
crashCatcherInstall(argc, argv, (cfgMgr.getLogPath() / "crash.log").string());
|
|
||||||
|
|
||||||
#ifdef __APPLE__
|
|
||||||
boost::filesystem::path binary_path = boost::filesystem::system_complete(boost::filesystem::path(argv[0]));
|
|
||||||
boost::filesystem::current_path(binary_path.parent_path());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
engine.reset(new OMW::Engine(cfgMgr));
|
|
||||||
|
|
||||||
if (parseOptions(argc, argv, *engine, cfgMgr))
|
|
||||||
{
|
|
||||||
engine->go();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (std::exception &e)
|
|
||||||
{
|
|
||||||
#if (defined(__APPLE__) || defined(__linux) || defined(__unix) || defined(__posix))
|
|
||||||
if (!isatty(fileno(stdin)))
|
|
||||||
#endif
|
|
||||||
SDL_ShowSimpleMessageBox(0, "OpenMW: Fatal error", e.what(), NULL);
|
|
||||||
|
|
||||||
std::cerr << "\nERROR: " << e.what() << std::endl;
|
|
||||||
|
|
||||||
ret = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore cout and cerr
|
|
||||||
std::cout.rdbuf(cout_rdbuf);
|
|
||||||
std::cerr.rdbuf(cerr_rdbuf);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Platform specific for Windows when there is no console built into the executable.
|
// Platform specific for Windows when there is no console built into the executable.
|
||||||
|
|
|
@ -75,8 +75,8 @@ namespace MWBase
|
||||||
virtual void persuade (int type, ResponseCallback* callback) = 0;
|
virtual void persuade (int type, ResponseCallback* callback) = 0;
|
||||||
virtual int getTemporaryDispositionChange () const = 0;
|
virtual int getTemporaryDispositionChange () const = 0;
|
||||||
|
|
||||||
/// @note This change is temporary and gets discarded when dialogue ends.
|
/// @note Controlled by an option, gets discarded when dialogue ends by default
|
||||||
virtual void applyDispositionChange (int delta) = 0;
|
virtual void applyBarterDispositionChange (int delta) = 0;
|
||||||
|
|
||||||
virtual int countSavedGameRecords() const = 0;
|
virtual int countSavedGameRecords() const = 0;
|
||||||
|
|
||||||
|
|
|
@ -257,7 +257,7 @@ namespace MWBase
|
||||||
virtual void cleanupSummonedCreature(const MWWorld::Ptr& caster, int creatureActorId) = 0;
|
virtual void cleanupSummonedCreature(const MWWorld::Ptr& caster, int creatureActorId) = 0;
|
||||||
|
|
||||||
virtual void confiscateStolenItemToOwner(const MWWorld::Ptr &player, const MWWorld::Ptr &item, const MWWorld::Ptr& victim, int count) = 0;
|
virtual void confiscateStolenItemToOwner(const MWWorld::Ptr &player, const MWWorld::Ptr &item, const MWWorld::Ptr& victim, int count) = 0;
|
||||||
virtual bool isAttackPrepairing(const MWWorld::Ptr& ptr) = 0;
|
virtual bool isAttackPreparing(const MWWorld::Ptr& ptr) = 0;
|
||||||
virtual bool isRunning(const MWWorld::Ptr& ptr) = 0;
|
virtual bool isRunning(const MWWorld::Ptr& ptr) = 0;
|
||||||
virtual bool isSneaking(const MWWorld::Ptr& ptr) = 0;
|
virtual bool isSneaking(const MWWorld::Ptr& ptr) = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -412,6 +412,7 @@ namespace MWBase
|
||||||
/// @note throws an exception when invoked on a teleport door
|
/// @note throws an exception when invoked on a teleport door
|
||||||
virtual void activateDoor(const MWWorld::Ptr& door, int state) = 0;
|
virtual void activateDoor(const MWWorld::Ptr& door, int state) = 0;
|
||||||
|
|
||||||
|
virtual void getActorsStandingOn (const MWWorld::ConstPtr& object, std::vector<MWWorld::Ptr> &actors) = 0; ///< get a list of actors standing on \a object
|
||||||
virtual bool getPlayerStandingOn (const MWWorld::ConstPtr& object) = 0; ///< @return true if the player is standing on \a object
|
virtual bool getPlayerStandingOn (const MWWorld::ConstPtr& object) = 0; ///< @return true if the player is standing on \a object
|
||||||
virtual bool getActorStandingOn (const MWWorld::ConstPtr& object) = 0; ///< @return true if any actor is standing on \a object
|
virtual bool getActorStandingOn (const MWWorld::ConstPtr& object) = 0; ///< @return true if any actor is standing on \a object
|
||||||
virtual bool getPlayerCollidingWith(const MWWorld::ConstPtr& object) = 0; ///< @return true if the player is colliding with \a object
|
virtual bool getPlayerCollidingWith(const MWWorld::ConstPtr& object) = 0; ///< @return true if the player is colliding with \a object
|
||||||
|
@ -490,8 +491,8 @@ namespace MWBase
|
||||||
virtual void castSpell (const MWWorld::Ptr& actor, bool manualSpell=false) = 0;
|
virtual void castSpell (const MWWorld::Ptr& actor, bool manualSpell=false) = 0;
|
||||||
|
|
||||||
virtual void launchMagicBolt (const std::string& spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection) = 0;
|
virtual void launchMagicBolt (const std::string& spellId, const MWWorld::Ptr& caster, const osg::Vec3f& fallbackDirection) = 0;
|
||||||
virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::ConstPtr projectile,
|
virtual void launchProjectile (MWWorld::Ptr& actor, MWWorld::Ptr& projectile,
|
||||||
const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr bow, float speed, float attackStrength) = 0;
|
const osg::Vec3f& worldPos, const osg::Quat& orient, MWWorld::Ptr& bow, float speed, float attackStrength) = 0;
|
||||||
|
|
||||||
virtual void applyLoopingParticles(const MWWorld::Ptr& ptr) = 0;
|
virtual void applyLoopingParticles(const MWWorld::Ptr& ptr) = 0;
|
||||||
|
|
||||||
|
@ -536,7 +537,7 @@ namespace MWBase
|
||||||
/// Spawn a blood effect for \a ptr at \a worldPosition
|
/// Spawn a blood effect for \a ptr at \a worldPosition
|
||||||
virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const osg::Vec3f& worldPosition) = 0;
|
virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const osg::Vec3f& worldPosition) = 0;
|
||||||
|
|
||||||
virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos) = 0;
|
virtual void spawnEffect (const std::string& model, const std::string& textureOverride, const osg::Vec3f& worldPos, float scale = 1.f, bool isMagicVFX = true) = 0;
|
||||||
|
|
||||||
virtual void explodeSpell(const osg::Vec3f& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster,
|
virtual void explodeSpell(const osg::Vec3f& origin, const ESM::EffectList& effects, const MWWorld::Ptr& caster,
|
||||||
const MWWorld::Ptr& ignore, ESM::RangeType rangeType, const std::string& id,
|
const MWWorld::Ptr& ignore, ESM::RangeType rangeType, const std::string& id,
|
||||||
|
@ -566,6 +567,9 @@ namespace MWBase
|
||||||
|
|
||||||
virtual bool isPlayerInJail() const = 0;
|
virtual bool isPlayerInJail() const = 0;
|
||||||
|
|
||||||
|
virtual void setPlayerTraveling(bool traveling) = 0;
|
||||||
|
virtual bool isPlayerTraveling() const = 0;
|
||||||
|
|
||||||
virtual void rotateWorldObject (const MWWorld::Ptr& ptr, osg::Quat rotate) = 0;
|
virtual void rotateWorldObject (const MWWorld::Ptr& ptr, osg::Quat rotate) = 0;
|
||||||
|
|
||||||
/// Return terrain height at \a worldPos position.
|
/// Return terrain height at \a worldPos position.
|
||||||
|
|
|
@ -142,14 +142,14 @@ namespace MWClass
|
||||||
const MWWorld::Store<ESM::GameSetting> &gmst =
|
const MWWorld::Store<ESM::GameSetting> &gmst =
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||||
|
|
||||||
float iWeight = floor(gmst.find(typeGmst)->getFloat());
|
float iWeight = floor(gmst.find(typeGmst)->mValue.getFloat());
|
||||||
|
|
||||||
float epsilon = 0.0005f;
|
float epsilon = 0.0005f;
|
||||||
|
|
||||||
if (ref->mBase->mData.mWeight <= iWeight * gmst.find ("fLightMaxMod")->getFloat() + epsilon)
|
if (ref->mBase->mData.mWeight <= iWeight * gmst.find ("fLightMaxMod")->mValue.getFloat() + epsilon)
|
||||||
return ESM::Skill::LightArmor;
|
return ESM::Skill::LightArmor;
|
||||||
|
|
||||||
if (ref->mBase->mData.mWeight <= iWeight * gmst.find ("fMedMaxMod")->getFloat() + epsilon)
|
if (ref->mBase->mData.mWeight <= iWeight * gmst.find ("fMedMaxMod")->mValue.getFloat() + epsilon)
|
||||||
return ESM::Skill::MediumArmor;
|
return ESM::Skill::MediumArmor;
|
||||||
|
|
||||||
else
|
else
|
||||||
|
@ -285,7 +285,7 @@ namespace MWClass
|
||||||
int armorSkill = actor.getClass().getSkill(actor, armorSkillType);
|
int 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")->getInt();
|
int iBaseArmorSkill = world->getStore().get<ESM::GameSetting>().find("iBaseArmorSkill")->mValue.getInteger();
|
||||||
|
|
||||||
if(ref->mBase->mData.mWeight == 0)
|
if(ref->mBase->mData.mWeight == 0)
|
||||||
return ref->mBase->mData.mArmor;
|
return ref->mBase->mData.mArmor;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include "creature.hpp"
|
#include "creature.hpp"
|
||||||
|
|
||||||
#include <components/misc/rng.hpp>
|
#include <components/misc/rng.hpp>
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
#include <components/esm/loadcrea.hpp>
|
#include <components/esm/loadcrea.hpp>
|
||||||
#include <components/esm/creaturestate.hpp>
|
#include <components/esm/creaturestate.hpp>
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
|
@ -146,7 +146,7 @@ namespace MWClass
|
||||||
if (const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().search(*iter))
|
if (const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().search(*iter))
|
||||||
data->mCreatureStats.getSpells().add (spell);
|
data->mCreatureStats.getSpells().add (spell);
|
||||||
else /// \todo add option to make this a fatal error message pop-up, but default to warning for vanilla compatibility
|
else /// \todo add option to make this a fatal error message pop-up, but default to warning for vanilla compatibility
|
||||||
std::cerr << "Warning: ignoring nonexistent spell '" << *iter << "' on creature '" << ref->mBase->mId << "'" << std::endl;
|
Log(Debug::Warning) << "Warning: ignoring nonexistent spell '" << *iter << "' on creature '" << ref->mBase->mId << "'";
|
||||||
}
|
}
|
||||||
|
|
||||||
// inventory
|
// inventory
|
||||||
|
@ -247,13 +247,13 @@ namespace MWClass
|
||||||
|
|
||||||
MWMechanics::applyFatigueLoss(ptr, weapon, attackStrength);
|
MWMechanics::applyFatigueLoss(ptr, weapon, attackStrength);
|
||||||
|
|
||||||
float dist = gmst.find("fCombatDistance")->getFloat();
|
float dist = gmst.find("fCombatDistance")->mValue.getFloat();
|
||||||
if (!weapon.isEmpty())
|
if (!weapon.isEmpty())
|
||||||
dist *= weapon.get<ESM::Weapon>()->mBase->mData.mReach;
|
dist *= weapon.get<ESM::Weapon>()->mBase->mData.mReach;
|
||||||
|
|
||||||
// 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 (!ptr.isEmpty() && ptr.getClass().isActor() && ptr != MWMechanics::getPlayer())
|
if (!ptr.isEmpty() && ptr.getClass().isActor())
|
||||||
ptr.getClass().getCreatureStats(ptr).getAiSequence().getCombatTargets(targetActors);
|
ptr.getClass().getCreatureStats(ptr).getAiSequence().getCombatTargets(targetActors);
|
||||||
|
|
||||||
std::pair<MWWorld::Ptr, osg::Vec3f> result = MWBase::Environment::get().getWorld()->getHitContact(ptr, dist, targetActors);
|
std::pair<MWWorld::Ptr, osg::Vec3f> result = MWBase::Environment::get().getWorld()->getHitContact(ptr, dist, targetActors);
|
||||||
|
@ -325,9 +325,6 @@ namespace MWClass
|
||||||
if (MWMechanics::blockMeleeAttack(ptr, victim, weapon, damage, attackStrength))
|
if (MWMechanics::blockMeleeAttack(ptr, victim, weapon, damage, attackStrength))
|
||||||
damage = 0;
|
damage = 0;
|
||||||
|
|
||||||
if (victim == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState())
|
|
||||||
damage = 0;
|
|
||||||
|
|
||||||
MWMechanics::diseaseContact(victim, ptr);
|
MWMechanics::diseaseContact(victim, ptr);
|
||||||
|
|
||||||
victim.getClass().onHit(victim, damage, healthdmg, weapon, ptr, hitPosition, true);
|
victim.getClass().onHit(victim, damage, healthdmg, weapon, ptr, hitPosition, true);
|
||||||
|
@ -376,11 +373,6 @@ namespace MWClass
|
||||||
ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1);
|
ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool godmode = object == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState();
|
|
||||||
|
|
||||||
if (godmode)
|
|
||||||
damage = 0;
|
|
||||||
|
|
||||||
if (!successful)
|
if (!successful)
|
||||||
{
|
{
|
||||||
// Missed
|
// Missed
|
||||||
|
@ -402,9 +394,9 @@ namespace MWClass
|
||||||
if (!attacker.isEmpty())
|
if (!attacker.isEmpty())
|
||||||
{
|
{
|
||||||
// Check for knockdown
|
// Check for knockdown
|
||||||
float agilityTerm = stats.getAttribute(ESM::Attribute::Agility).getModified() * getGmst().fKnockDownMult->getFloat();
|
float agilityTerm = stats.getAttribute(ESM::Attribute::Agility).getModified() * getGmst().fKnockDownMult->mValue.getFloat();
|
||||||
float knockdownTerm = stats.getAttribute(ESM::Attribute::Agility).getModified()
|
float knockdownTerm = stats.getAttribute(ESM::Attribute::Agility).getModified()
|
||||||
* getGmst().iKnockDownOddsMult->getInt() * 0.01f + getGmst().iKnockDownOddsBase->getInt();
|
* getGmst().iKnockDownOddsMult->mValue.getInteger() * 0.01f + getGmst().iKnockDownOddsBase->mValue.getInteger();
|
||||||
if (ishealth && agilityTerm <= damage && knockdownTerm <= Misc::Rng::roll0to99())
|
if (ishealth && agilityTerm <= damage && knockdownTerm <= Misc::Rng::roll0to99())
|
||||||
stats.setKnockedDown(true);
|
stats.setKnockedDown(true);
|
||||||
else
|
else
|
||||||
|
@ -415,7 +407,7 @@ namespace MWClass
|
||||||
|
|
||||||
if(ishealth)
|
if(ishealth)
|
||||||
{
|
{
|
||||||
if (!attacker.isEmpty() && !godmode)
|
if (!attacker.isEmpty())
|
||||||
{
|
{
|
||||||
damage = scaleDamage(damage, attacker, ptr);
|
damage = scaleDamage(damage, attacker, ptr);
|
||||||
MWBase::Environment::get().getWorld()->spawnBloodEffect(ptr, hitPosition);
|
MWBase::Environment::get().getWorld()->spawnBloodEffect(ptr, hitPosition);
|
||||||
|
@ -524,8 +516,8 @@ namespace MWClass
|
||||||
|
|
||||||
const GMST& gmst = getGmst();
|
const GMST& gmst = getGmst();
|
||||||
|
|
||||||
float walkSpeed = gmst.fMinWalkSpeedCreature->getFloat() + 0.01f * stats.getAttribute(ESM::Attribute::Speed).getModified()
|
float walkSpeed = gmst.fMinWalkSpeedCreature->mValue.getFloat() + 0.01f * stats.getAttribute(ESM::Attribute::Speed).getModified()
|
||||||
* (gmst.fMaxWalkSpeedCreature->getFloat() - gmst.fMinWalkSpeedCreature->getFloat());
|
* (gmst.fMaxWalkSpeedCreature->mValue.getFloat() - gmst.fMinWalkSpeedCreature->mValue.getFloat());
|
||||||
|
|
||||||
const MWBase::World *world = MWBase::Environment::get().getWorld();
|
const MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||||
const MWMechanics::MagicEffects &mageffects = stats.getMagicEffects();
|
const MWMechanics::MagicEffects &mageffects = stats.getMagicEffects();
|
||||||
|
@ -544,9 +536,9 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
float flySpeed = 0.01f*(stats.getAttribute(ESM::Attribute::Speed).getModified() +
|
float flySpeed = 0.01f*(stats.getAttribute(ESM::Attribute::Speed).getModified() +
|
||||||
mageffects.get(ESM::MagicEffect::Levitate).getMagnitude());
|
mageffects.get(ESM::MagicEffect::Levitate).getMagnitude());
|
||||||
flySpeed = gmst.fMinFlySpeed->getFloat() + flySpeed*(gmst.fMaxFlySpeed->getFloat() - gmst.fMinFlySpeed->getFloat());
|
flySpeed = gmst.fMinFlySpeed->mValue.getFloat() + flySpeed*(gmst.fMaxFlySpeed->mValue.getFloat() - gmst.fMinFlySpeed->mValue.getFloat());
|
||||||
const float normalizedEncumbrance = getNormalizedEncumbrance(ptr);
|
const float normalizedEncumbrance = getNormalizedEncumbrance(ptr);
|
||||||
flySpeed *= 1.0f - gmst.fEncumberedMoveEffect->getFloat() * normalizedEncumbrance;
|
flySpeed *= 1.0f - gmst.fEncumberedMoveEffect->mValue.getFloat() * normalizedEncumbrance;
|
||||||
flySpeed = std::max(0.0f, flySpeed);
|
flySpeed = std::max(0.0f, flySpeed);
|
||||||
moveSpeed = flySpeed;
|
moveSpeed = flySpeed;
|
||||||
}
|
}
|
||||||
|
@ -556,8 +548,8 @@ namespace MWClass
|
||||||
if(running)
|
if(running)
|
||||||
swimSpeed = runSpeed;
|
swimSpeed = runSpeed;
|
||||||
swimSpeed *= 1.0f + 0.01f * mageffects.get(ESM::MagicEffect::SwiftSwim).getMagnitude();
|
swimSpeed *= 1.0f + 0.01f * mageffects.get(ESM::MagicEffect::SwiftSwim).getMagnitude();
|
||||||
swimSpeed *= gmst.fSwimRunBase->getFloat() + 0.01f*getSkill(ptr, ESM::Skill::Athletics) *
|
swimSpeed *= gmst.fSwimRunBase->mValue.getFloat() + 0.01f*getSkill(ptr, ESM::Skill::Athletics) *
|
||||||
gmst.fSwimRunAthleticsMult->getFloat();
|
gmst.fSwimRunAthleticsMult->mValue.getFloat();
|
||||||
moveSpeed = swimSpeed;
|
moveSpeed = swimSpeed;
|
||||||
}
|
}
|
||||||
else if(running)
|
else if(running)
|
||||||
|
@ -822,8 +814,8 @@ namespace MWClass
|
||||||
return;
|
return;
|
||||||
|
|
||||||
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>();
|
||||||
static const float fCorpseRespawnDelay = gmst.find("fCorpseRespawnDelay")->getFloat();
|
static const float fCorpseRespawnDelay = gmst.find("fCorpseRespawnDelay")->mValue.getFloat();
|
||||||
static const float fCorpseClearDelay = gmst.find("fCorpseClearDelay")->getFloat();
|
static const float fCorpseClearDelay = gmst.find("fCorpseClearDelay")->mValue.getFloat();
|
||||||
|
|
||||||
float delay = ptr.getRefData().getCount() == 0 ? fCorpseClearDelay : std::min(fCorpseRespawnDelay, fCorpseClearDelay);
|
float delay = ptr.getRefData().getCount() == 0 ? fCorpseClearDelay : std::min(fCorpseRespawnDelay, fCorpseClearDelay);
|
||||||
|
|
||||||
|
|
|
@ -56,8 +56,8 @@ namespace MWClass
|
||||||
else if (creatureStats.isDead())
|
else if (creatureStats.isDead())
|
||||||
{
|
{
|
||||||
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>();
|
||||||
static const float fCorpseRespawnDelay = gmst.find("fCorpseRespawnDelay")->getFloat();
|
static const float fCorpseRespawnDelay = gmst.find("fCorpseRespawnDelay")->mValue.getFloat();
|
||||||
static const float fCorpseClearDelay = gmst.find("fCorpseClearDelay")->getFloat();
|
static const float fCorpseClearDelay = gmst.find("fCorpseClearDelay")->mValue.getFloat();
|
||||||
|
|
||||||
float delay = std::min(fCorpseRespawnDelay, fCorpseClearDelay);
|
float delay = std::min(fCorpseRespawnDelay, fCorpseClearDelay);
|
||||||
if (creatureStats.getTimeOfDeath() + delay <= MWBase::Environment::get().getWorld()->getTimeStamp())
|
if (creatureStats.getTimeOfDeath() + delay <= MWBase::Environment::get().getWorld()->getTimeStamp())
|
||||||
|
|
|
@ -138,7 +138,7 @@ namespace MWClass
|
||||||
int alchemySkill = npcStats.getSkill (ESM::Skill::Alchemy).getBase();
|
int alchemySkill = npcStats.getSkill (ESM::Skill::Alchemy).getBase();
|
||||||
|
|
||||||
static const float fWortChanceValue =
|
static const float fWortChanceValue =
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fWortChanceValue")->getFloat();
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fWortChanceValue")->mValue.getFloat();
|
||||||
|
|
||||||
MWGui::Widgets::SpellEffectList list;
|
MWGui::Widgets::SpellEffectList list;
|
||||||
for (int i=0; i<4; ++i)
|
for (int i=0; i<4; ++i)
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include <components/misc/rng.hpp>
|
#include <components/misc/rng.hpp>
|
||||||
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
#include <components/esm/loadmgef.hpp>
|
#include <components/esm/loadmgef.hpp>
|
||||||
#include <components/esm/loadnpc.hpp>
|
#include <components/esm/loadnpc.hpp>
|
||||||
#include <components/esm/npcstate.hpp>
|
#include <components/esm/npcstate.hpp>
|
||||||
|
@ -365,15 +366,15 @@ namespace MWClass
|
||||||
if (const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().search(*iter))
|
if (const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().search(*iter))
|
||||||
data->mNpcStats.getSpells().add (spell);
|
data->mNpcStats.getSpells().add (spell);
|
||||||
else
|
else
|
||||||
std::cerr << "Warning: ignoring nonexistent race power '" << *iter << "' on NPC '" << ref->mBase->mId << "'" << std::endl;
|
Log(Debug::Warning) << "Warning: ignoring nonexistent race power '" << *iter << "' on NPC '" << ref->mBase->mId << "'";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ref->mBase->mFaction.empty())
|
if (!ref->mBase->mFaction.empty())
|
||||||
{
|
{
|
||||||
static const int iAutoRepFacMod = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
static const int iAutoRepFacMod = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||||
.find("iAutoRepFacMod")->getInt();
|
.find("iAutoRepFacMod")->mValue.getInteger();
|
||||||
static const int iAutoRepLevMod = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
static const int iAutoRepLevMod = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||||
.find("iAutoRepLevMod")->getInt();
|
.find("iAutoRepLevMod")->mValue.getInteger();
|
||||||
int rank = ref->mBase->getFactionRank();
|
int rank = ref->mBase->getFactionRank();
|
||||||
|
|
||||||
data->mNpcStats.setReputation(iAutoRepFacMod * (rank+1) + iAutoRepLevMod * (data->mNpcStats.getLevel()-1));
|
data->mNpcStats.setReputation(iAutoRepFacMod * (rank+1) + iAutoRepLevMod * (data->mNpcStats.getLevel()-1));
|
||||||
|
@ -395,7 +396,7 @@ namespace MWClass
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/// \todo add option to make this a fatal error message pop-up, but default to warning for vanilla compatibility
|
/// \todo add option to make this a fatal error message pop-up, but default to warning for vanilla compatibility
|
||||||
std::cerr << "Warning: ignoring nonexistent spell '" << *iter << "' on NPC '" << ref->mBase->mId << "'" << std::endl;
|
Log(Debug::Warning) << "Warning: ignoring nonexistent spell '" << *iter << "' on NPC '" << ref->mBase->mId << "'";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -527,7 +528,7 @@ namespace MWClass
|
||||||
const MWBase::World *world = MWBase::Environment::get().getWorld();
|
const MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||||
const MWWorld::Store<ESM::GameSetting> &store = world->getStore().get<ESM::GameSetting>();
|
const MWWorld::Store<ESM::GameSetting> &store = world->getStore().get<ESM::GameSetting>();
|
||||||
|
|
||||||
return store.find("sWerewolfPopup")->getString();
|
return store.find("sWerewolfPopup")->mValue.getString();
|
||||||
}
|
}
|
||||||
|
|
||||||
const MWWorld::LiveCellRef<ESM::NPC> *ref = ptr.get<ESM::NPC>();
|
const MWWorld::LiveCellRef<ESM::NPC> *ref = ptr.get<ESM::NPC>();
|
||||||
|
@ -564,10 +565,10 @@ namespace MWClass
|
||||||
|
|
||||||
MWMechanics::applyFatigueLoss(ptr, weapon, attackStrength);
|
MWMechanics::applyFatigueLoss(ptr, weapon, attackStrength);
|
||||||
|
|
||||||
const float fCombatDistance = store.find("fCombatDistance")->getFloat();
|
const float fCombatDistance = store.find("fCombatDistance")->mValue.getFloat();
|
||||||
float dist = fCombatDistance * (!weapon.isEmpty() ?
|
float dist = fCombatDistance * (!weapon.isEmpty() ?
|
||||||
weapon.get<ESM::Weapon>()->mBase->mData.mReach :
|
weapon.get<ESM::Weapon>()->mBase->mData.mReach :
|
||||||
store.find("fHandToHandReach")->getFloat());
|
store.find("fHandToHandReach")->mValue.getFloat());
|
||||||
|
|
||||||
// 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;
|
||||||
|
@ -637,14 +638,14 @@ namespace MWClass
|
||||||
&& !MWBase::Environment::get().getMechanicsManager()->awarenessCheck(ptr, victim);
|
&& !MWBase::Environment::get().getMechanicsManager()->awarenessCheck(ptr, victim);
|
||||||
if(unaware)
|
if(unaware)
|
||||||
{
|
{
|
||||||
damage *= store.find("fCombatCriticalStrikeMult")->getFloat();
|
damage *= store.find("fCombatCriticalStrikeMult")->mValue.getFloat();
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sTargetCriticalStrike}");
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sTargetCriticalStrike}");
|
||||||
MWBase::Environment::get().getSoundManager()->playSound3D(victim, "critical damage", 1.0f, 1.0f);
|
MWBase::Environment::get().getSoundManager()->playSound3D(victim, "critical damage", 1.0f, 1.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (othercls.getCreatureStats(victim).getKnockedDown())
|
if (othercls.getCreatureStats(victim).getKnockedDown())
|
||||||
damage *= store.find("fCombatKODamageMult")->getFloat();
|
damage *= store.find("fCombatKODamageMult")->mValue.getFloat();
|
||||||
|
|
||||||
// Apply "On hit" enchanted weapons
|
// Apply "On hit" enchanted weapons
|
||||||
MWMechanics::applyOnStrikeEnchantment(ptr, victim, weapon, hitPosition);
|
MWMechanics::applyOnStrikeEnchantment(ptr, victim, weapon, hitPosition);
|
||||||
|
@ -736,14 +737,14 @@ namespace MWClass
|
||||||
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||||
const GMST& gmst = getGmst();
|
const GMST& gmst = getGmst();
|
||||||
|
|
||||||
int chance = store.get<ESM::GameSetting>().find("iVoiceHitOdds")->getInt();
|
int chance = store.get<ESM::GameSetting>().find("iVoiceHitOdds")->mValue.getInteger();
|
||||||
if (Misc::Rng::roll0to99() < chance)
|
if (Misc::Rng::roll0to99() < chance)
|
||||||
MWBase::Environment::get().getDialogueManager()->say(ptr, "hit");
|
MWBase::Environment::get().getDialogueManager()->say(ptr, "hit");
|
||||||
|
|
||||||
// Check for knockdown
|
// Check for knockdown
|
||||||
float agilityTerm = stats.getAttribute(ESM::Attribute::Agility).getModified() * gmst.fKnockDownMult->getFloat();
|
float agilityTerm = stats.getAttribute(ESM::Attribute::Agility).getModified() * gmst.fKnockDownMult->mValue.getFloat();
|
||||||
float knockdownTerm = stats.getAttribute(ESM::Attribute::Agility).getModified()
|
float knockdownTerm = stats.getAttribute(ESM::Attribute::Agility).getModified()
|
||||||
* gmst.iKnockDownOddsMult->getInt() * 0.01f + gmst.iKnockDownOddsBase->getInt();
|
* gmst.iKnockDownOddsMult->mValue.getInteger() * 0.01f + gmst.iKnockDownOddsBase->mValue.getInteger();
|
||||||
if (ishealth && agilityTerm <= damage && knockdownTerm <= Misc::Rng::roll0to99())
|
if (ishealth && agilityTerm <= damage && knockdownTerm <= Misc::Rng::roll0to99())
|
||||||
stats.setKnockedDown(true);
|
stats.setKnockedDown(true);
|
||||||
else
|
else
|
||||||
|
@ -771,7 +772,7 @@ namespace MWClass
|
||||||
|
|
||||||
float unmitigatedDamage = damage;
|
float unmitigatedDamage = damage;
|
||||||
float x = damage / (damage + getArmorRating(ptr));
|
float x = damage / (damage + getArmorRating(ptr));
|
||||||
damage *= std::max(gmst.fCombatArmorMinMult->getFloat(), x);
|
damage *= std::max(gmst.fCombatArmorMinMult->mValue.getFloat(), x);
|
||||||
int damageDiff = static_cast<int>(unmitigatedDamage - damage);
|
int damageDiff = static_cast<int>(unmitigatedDamage - damage);
|
||||||
damage = std::max(1.f, damage);
|
damage = std::max(1.f, damage);
|
||||||
damageDiff = std::max(1, damageDiff);
|
damageDiff = std::max(1, damageDiff);
|
||||||
|
@ -940,15 +941,15 @@ namespace MWClass
|
||||||
bool sneaking = stats.getStance(MWMechanics::CreatureStats::Stance_Sneak);
|
bool sneaking = stats.getStance(MWMechanics::CreatureStats::Stance_Sneak);
|
||||||
bool running = stats.getStance(MWMechanics::CreatureStats::Stance_Run);
|
bool running = stats.getStance(MWMechanics::CreatureStats::Stance_Run);
|
||||||
|
|
||||||
float walkSpeed = gmst.fMinWalkSpeed->getFloat() + 0.01f*npcdata->mNpcStats.getAttribute(ESM::Attribute::Speed).getModified()*
|
float walkSpeed = gmst.fMinWalkSpeed->mValue.getFloat() + 0.01f*npcdata->mNpcStats.getAttribute(ESM::Attribute::Speed).getModified()*
|
||||||
(gmst.fMaxWalkSpeed->getFloat() - gmst.fMinWalkSpeed->getFloat());
|
(gmst.fMaxWalkSpeed->mValue.getFloat() - gmst.fMinWalkSpeed->mValue.getFloat());
|
||||||
walkSpeed *= 1.0f - gmst.fEncumberedMoveEffect->getFloat()*normalizedEncumbrance;
|
walkSpeed *= 1.0f - gmst.fEncumberedMoveEffect->mValue.getFloat()*normalizedEncumbrance;
|
||||||
walkSpeed = std::max(0.0f, walkSpeed);
|
walkSpeed = std::max(0.0f, walkSpeed);
|
||||||
if(sneaking)
|
if(sneaking)
|
||||||
walkSpeed *= gmst.fSneakSpeedMultiplier->getFloat();
|
walkSpeed *= gmst.fSneakSpeedMultiplier->mValue.getFloat();
|
||||||
|
|
||||||
float runSpeed = walkSpeed*(0.01f * npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified() *
|
float runSpeed = walkSpeed*(0.01f * npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified() *
|
||||||
gmst.fAthleticsRunBonus->getFloat() + gmst.fBaseRunMultiplier->getFloat());
|
gmst.fAthleticsRunBonus->mValue.getFloat() + gmst.fBaseRunMultiplier->mValue.getFloat());
|
||||||
|
|
||||||
float moveSpeed;
|
float moveSpeed;
|
||||||
if(getEncumbrance(ptr) > getCapacity(ptr))
|
if(getEncumbrance(ptr) > getCapacity(ptr))
|
||||||
|
@ -958,8 +959,8 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
float flySpeed = 0.01f*(npcdata->mNpcStats.getAttribute(ESM::Attribute::Speed).getModified() +
|
float flySpeed = 0.01f*(npcdata->mNpcStats.getAttribute(ESM::Attribute::Speed).getModified() +
|
||||||
mageffects.get(ESM::MagicEffect::Levitate).getMagnitude());
|
mageffects.get(ESM::MagicEffect::Levitate).getMagnitude());
|
||||||
flySpeed = gmst.fMinFlySpeed->getFloat() + flySpeed*(gmst.fMaxFlySpeed->getFloat() - gmst.fMinFlySpeed->getFloat());
|
flySpeed = gmst.fMinFlySpeed->mValue.getFloat() + flySpeed*(gmst.fMaxFlySpeed->mValue.getFloat() - gmst.fMinFlySpeed->mValue.getFloat());
|
||||||
flySpeed *= 1.0f - gmst.fEncumberedMoveEffect->getFloat() * normalizedEncumbrance;
|
flySpeed *= 1.0f - gmst.fEncumberedMoveEffect->mValue.getFloat() * normalizedEncumbrance;
|
||||||
flySpeed = std::max(0.0f, flySpeed);
|
flySpeed = std::max(0.0f, flySpeed);
|
||||||
moveSpeed = flySpeed;
|
moveSpeed = flySpeed;
|
||||||
}
|
}
|
||||||
|
@ -969,8 +970,8 @@ namespace MWClass
|
||||||
if(running)
|
if(running)
|
||||||
swimSpeed = runSpeed;
|
swimSpeed = runSpeed;
|
||||||
swimSpeed *= 1.0f + 0.01f * mageffects.get(ESM::MagicEffect::SwiftSwim).getMagnitude();
|
swimSpeed *= 1.0f + 0.01f * mageffects.get(ESM::MagicEffect::SwiftSwim).getMagnitude();
|
||||||
swimSpeed *= gmst.fSwimRunBase->getFloat() + 0.01f*npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified()*
|
swimSpeed *= gmst.fSwimRunBase->mValue.getFloat() + 0.01f*npcdata->mNpcStats.getSkill(ESM::Skill::Athletics).getModified()*
|
||||||
gmst.fSwimRunAthleticsMult->getFloat();
|
gmst.fSwimRunAthleticsMult->mValue.getFloat();
|
||||||
moveSpeed = swimSpeed;
|
moveSpeed = swimSpeed;
|
||||||
}
|
}
|
||||||
else if(running && !sneaking)
|
else if(running && !sneaking)
|
||||||
|
@ -981,7 +982,7 @@ namespace MWClass
|
||||||
moveSpeed *= 0.75f;
|
moveSpeed *= 0.75f;
|
||||||
|
|
||||||
if(npcdata->mNpcStats.isWerewolf() && running && npcdata->mNpcStats.getDrawState() == MWMechanics::DrawState_Nothing)
|
if(npcdata->mNpcStats.isWerewolf() && running && npcdata->mNpcStats.getDrawState() == MWMechanics::DrawState_Nothing)
|
||||||
moveSpeed *= gmst.fWereWolfRunMult->getFloat();
|
moveSpeed *= gmst.fWereWolfRunMult->mValue.getFloat();
|
||||||
|
|
||||||
return moveSpeed;
|
return moveSpeed;
|
||||||
}
|
}
|
||||||
|
@ -991,11 +992,15 @@ namespace MWClass
|
||||||
if(getEncumbrance(ptr) > getCapacity(ptr))
|
if(getEncumbrance(ptr) > getCapacity(ptr))
|
||||||
return 0.f;
|
return 0.f;
|
||||||
|
|
||||||
|
const MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
|
||||||
|
if (stats.isParalyzed() || stats.getKnockedDown() || stats.isDead())
|
||||||
|
return 0.f;
|
||||||
|
|
||||||
const NpcCustomData *npcdata = static_cast<const NpcCustomData*>(ptr.getRefData().getCustomData());
|
const NpcCustomData *npcdata = static_cast<const NpcCustomData*>(ptr.getRefData().getCustomData());
|
||||||
const GMST& gmst = getGmst();
|
const GMST& gmst = getGmst();
|
||||||
const MWMechanics::MagicEffects &mageffects = npcdata->mNpcStats.getMagicEffects();
|
const MWMechanics::MagicEffects &mageffects = npcdata->mNpcStats.getMagicEffects();
|
||||||
const float encumbranceTerm = gmst.fJumpEncumbranceBase->getFloat() +
|
const float encumbranceTerm = gmst.fJumpEncumbranceBase->mValue.getFloat() +
|
||||||
gmst.fJumpEncumbranceMultiplier->getFloat() *
|
gmst.fJumpEncumbranceMultiplier->mValue.getFloat() *
|
||||||
(1.0f - Npc::getNormalizedEncumbrance(ptr));
|
(1.0f - Npc::getNormalizedEncumbrance(ptr));
|
||||||
|
|
||||||
float a = static_cast<float>(npcdata->mNpcStats.getSkill(ESM::Skill::Acrobatics).getModified());
|
float a = static_cast<float>(npcdata->mNpcStats.getSkill(ESM::Skill::Acrobatics).getModified());
|
||||||
|
@ -1006,14 +1011,14 @@ namespace MWClass
|
||||||
a = 50.0f;
|
a = 50.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
float x = gmst.fJumpAcrobaticsBase->getFloat() +
|
float x = gmst.fJumpAcrobaticsBase->mValue.getFloat() +
|
||||||
std::pow(a / 15.0f, gmst.fJumpAcroMultiplier->getFloat());
|
std::pow(a / 15.0f, gmst.fJumpAcroMultiplier->mValue.getFloat());
|
||||||
x += 3.0f * b * gmst.fJumpAcroMultiplier->getFloat();
|
x += 3.0f * b * gmst.fJumpAcroMultiplier->mValue.getFloat();
|
||||||
x += mageffects.get(ESM::MagicEffect::Jump).getMagnitude() * 64;
|
x += mageffects.get(ESM::MagicEffect::Jump).getMagnitude() * 64;
|
||||||
x *= encumbranceTerm;
|
x *= encumbranceTerm;
|
||||||
|
|
||||||
if(ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run))
|
if(stats.getStance(MWMechanics::CreatureStats::Stance_Run))
|
||||||
x *= gmst.fJumpRunMultiplier->getFloat();
|
x *= gmst.fJumpRunMultiplier->mValue.getFloat();
|
||||||
x *= npcdata->mNpcStats.getFatigueTerm();
|
x *= npcdata->mNpcStats.getFatigueTerm();
|
||||||
x -= -627.2f;/*gravity constant*/
|
x -= -627.2f;/*gravity constant*/
|
||||||
x /= 3.0f;
|
x /= 3.0f;
|
||||||
|
@ -1078,7 +1083,7 @@ namespace MWClass
|
||||||
float Npc::getCapacity (const MWWorld::Ptr& ptr) const
|
float Npc::getCapacity (const MWWorld::Ptr& ptr) const
|
||||||
{
|
{
|
||||||
const MWMechanics::CreatureStats& stats = getCreatureStats (ptr);
|
const MWMechanics::CreatureStats& stats = getCreatureStats (ptr);
|
||||||
static const float fEncumbranceStrMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fEncumbranceStrMult")->getFloat();
|
static const float fEncumbranceStrMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fEncumbranceStrMult")->mValue.getFloat();
|
||||||
return stats.getAttribute(ESM::Attribute::Strength).getModified()*fEncumbranceStrMult;
|
return stats.getAttribute(ESM::Attribute::Strength).getModified()*fEncumbranceStrMult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1121,8 +1126,8 @@ namespace MWClass
|
||||||
MWMechanics::NpcStats &stats = getNpcStats(ptr);
|
MWMechanics::NpcStats &stats = getNpcStats(ptr);
|
||||||
const MWWorld::InventoryStore &invStore = getInventoryStore(ptr);
|
const MWWorld::InventoryStore &invStore = getInventoryStore(ptr);
|
||||||
|
|
||||||
float fUnarmoredBase1 = store.find("fUnarmoredBase1")->getFloat();
|
float fUnarmoredBase1 = store.find("fUnarmoredBase1")->mValue.getFloat();
|
||||||
float fUnarmoredBase2 = store.find("fUnarmoredBase2")->getFloat();
|
float fUnarmoredBase2 = store.find("fUnarmoredBase2")->mValue.getFloat();
|
||||||
int unarmoredSkill = stats.getSkill(ESM::Skill::Unarmored).getModified();
|
int unarmoredSkill = stats.getSkill(ESM::Skill::Unarmored).getModified();
|
||||||
|
|
||||||
float ratings[MWWorld::InventoryStore::Slots];
|
float ratings[MWWorld::InventoryStore::Slots];
|
||||||
|
@ -1240,11 +1245,10 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||||
osg::Vec3f pos(ptr.getRefData().getPosition().asVec3());
|
osg::Vec3f pos(ptr.getRefData().getPosition().asVec3());
|
||||||
if(world->isUnderwater(ptr.getCell(), pos) || world->isWalkingOnWater(ptr))
|
if (world->isUnderwater(ptr.getCell(), pos) || world->isWalkingOnWater(ptr))
|
||||||
return "DefaultLandWater";
|
return "DefaultLandWater";
|
||||||
if(world->isOnGround(ptr))
|
|
||||||
return "DefaultLand";
|
return "DefaultLand";
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
if(name == "swimleft")
|
if(name == "swimleft")
|
||||||
return "Swim Left";
|
return "Swim Left";
|
||||||
|
@ -1363,8 +1367,8 @@ namespace MWClass
|
||||||
return;
|
return;
|
||||||
|
|
||||||
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>();
|
||||||
static const float fCorpseRespawnDelay = gmst.find("fCorpseRespawnDelay")->getFloat();
|
static const float fCorpseRespawnDelay = gmst.find("fCorpseRespawnDelay")->mValue.getFloat();
|
||||||
static const float fCorpseClearDelay = gmst.find("fCorpseClearDelay")->getFloat();
|
static const float fCorpseClearDelay = gmst.find("fCorpseClearDelay")->mValue.getFloat();
|
||||||
|
|
||||||
float delay = ptr.getRefData().getCount() == 0 ? fCorpseClearDelay : std::min(fCorpseRespawnDelay, fCorpseClearDelay);
|
float delay = ptr.getRefData().getCount() == 0 ? fCorpseClearDelay : std::min(fCorpseRespawnDelay, fCorpseClearDelay);
|
||||||
|
|
||||||
|
|
|
@ -268,27 +268,30 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
text += "\n#{sType} ";
|
text += "\n#{sType} ";
|
||||||
|
|
||||||
std::map <int, std::pair <std::string, std::string> > mapping;
|
static std::map <int, std::pair <std::string, std::string> > mapping;
|
||||||
mapping[ESM::Weapon::ShortBladeOneHand] = std::make_pair("sSkillShortblade", "sOneHanded");
|
if (mapping.empty())
|
||||||
mapping[ESM::Weapon::LongBladeOneHand] = std::make_pair("sSkillLongblade", "sOneHanded");
|
{
|
||||||
mapping[ESM::Weapon::LongBladeTwoHand] = std::make_pair("sSkillLongblade", "sTwoHanded");
|
mapping[ESM::Weapon::ShortBladeOneHand] = std::make_pair("sSkillShortblade", "sOneHanded");
|
||||||
mapping[ESM::Weapon::BluntOneHand] = std::make_pair("sSkillBluntweapon", "sOneHanded");
|
mapping[ESM::Weapon::LongBladeOneHand] = std::make_pair("sSkillLongblade", "sOneHanded");
|
||||||
mapping[ESM::Weapon::BluntTwoClose] = std::make_pair("sSkillBluntweapon", "sTwoHanded");
|
mapping[ESM::Weapon::LongBladeTwoHand] = std::make_pair("sSkillLongblade", "sTwoHanded");
|
||||||
mapping[ESM::Weapon::BluntTwoWide] = std::make_pair("sSkillBluntweapon", "sTwoHanded");
|
mapping[ESM::Weapon::BluntOneHand] = std::make_pair("sSkillBluntweapon", "sOneHanded");
|
||||||
mapping[ESM::Weapon::SpearTwoWide] = std::make_pair("sSkillSpear", "sTwoHanded");
|
mapping[ESM::Weapon::BluntTwoClose] = std::make_pair("sSkillBluntweapon", "sTwoHanded");
|
||||||
mapping[ESM::Weapon::AxeOneHand] = std::make_pair("sSkillAxe", "sOneHanded");
|
mapping[ESM::Weapon::BluntTwoWide] = std::make_pair("sSkillBluntweapon", "sTwoHanded");
|
||||||
mapping[ESM::Weapon::AxeTwoHand] = std::make_pair("sSkillAxe", "sTwoHanded");
|
mapping[ESM::Weapon::SpearTwoWide] = std::make_pair("sSkillSpear", "sTwoHanded");
|
||||||
mapping[ESM::Weapon::MarksmanBow] = std::make_pair("sSkillMarksman", "");
|
mapping[ESM::Weapon::AxeOneHand] = std::make_pair("sSkillAxe", "sOneHanded");
|
||||||
mapping[ESM::Weapon::MarksmanCrossbow] = std::make_pair("sSkillMarksman", "");
|
mapping[ESM::Weapon::AxeTwoHand] = std::make_pair("sSkillAxe", "sTwoHanded");
|
||||||
mapping[ESM::Weapon::MarksmanThrown] = std::make_pair("sSkillMarksman", "");
|
mapping[ESM::Weapon::MarksmanBow] = std::make_pair("sSkillMarksman", "");
|
||||||
mapping[ESM::Weapon::Arrow] = std::make_pair("sSkillMarksman", "");
|
mapping[ESM::Weapon::MarksmanCrossbow] = std::make_pair("sSkillMarksman", "");
|
||||||
mapping[ESM::Weapon::Bolt] = std::make_pair("sSkillMarksman", "");
|
mapping[ESM::Weapon::MarksmanThrown] = std::make_pair("sSkillMarksman", "");
|
||||||
|
mapping[ESM::Weapon::Arrow] = std::make_pair("sSkillMarksman", "");
|
||||||
|
mapping[ESM::Weapon::Bolt] = std::make_pair("sSkillMarksman", "");
|
||||||
|
}
|
||||||
|
|
||||||
std::string type = mapping[ref->mBase->mData.mType].first;
|
const std::string type = mapping[ref->mBase->mData.mType].first;
|
||||||
std::string oneOrTwoHanded = mapping[ref->mBase->mData.mType].second;
|
const std::string oneOrTwoHanded = mapping[ref->mBase->mData.mType].second;
|
||||||
|
|
||||||
text += store.get<ESM::GameSetting>().find(type)->getString() +
|
text += store.get<ESM::GameSetting>().find(type)->mValue.getString() +
|
||||||
((oneOrTwoHanded != "") ? ", " + store.get<ESM::GameSetting>().find(oneOrTwoHanded)->getString() : "");
|
((oneOrTwoHanded != "") ? ", " + store.get<ESM::GameSetting>().find(oneOrTwoHanded)->mValue.getString() : "");
|
||||||
|
|
||||||
// weapon damage
|
// weapon damage
|
||||||
if (ref->mBase->mData.mType >= 9)
|
if (ref->mBase->mData.mType >= 9)
|
||||||
|
@ -326,7 +329,7 @@ namespace MWClass
|
||||||
if (ref->mBase->mData.mType < 9 && Settings::Manager::getBool("show melee info", "Game"))
|
if (ref->mBase->mData.mType < 9 && Settings::Manager::getBool("show melee info", "Game"))
|
||||||
{
|
{
|
||||||
// 64 game units = 1 yard = 3 ft, display value in feet
|
// 64 game units = 1 yard = 3 ft, display value in feet
|
||||||
const float combatDistance = store.get<ESM::GameSetting>().find("fCombatDistance")->getFloat() * ref->mBase->mData.mReach;
|
const float combatDistance = store.get<ESM::GameSetting>().find("fCombatDistance")->mValue.getFloat() * ref->mBase->mData.mReach;
|
||||||
text += MWGui::ToolTips::getWeightString(combatDistance*3/64, "#{sRange}");
|
text += MWGui::ToolTips::getWeightString(combatDistance*3/64, "#{sRange}");
|
||||||
text += " #{sFeet}";
|
text += " #{sFeet}";
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <iostream>
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
|
|
||||||
#include <components/esm/loaddial.hpp>
|
#include <components/esm/loaddial.hpp>
|
||||||
#include <components/esm/loadinfo.hpp>
|
#include <components/esm/loadinfo.hpp>
|
||||||
|
@ -22,6 +23,8 @@
|
||||||
#include <components/interpreter/interpreter.hpp>
|
#include <components/interpreter/interpreter.hpp>
|
||||||
#include <components/interpreter/defines.hpp>
|
#include <components/interpreter/defines.hpp>
|
||||||
|
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwbase/journal.hpp"
|
#include "../mwbase/journal.hpp"
|
||||||
|
@ -201,16 +204,14 @@ namespace MWDialogue
|
||||||
}
|
}
|
||||||
catch (const std::exception& error)
|
catch (const std::exception& error)
|
||||||
{
|
{
|
||||||
std::cerr << std::string ("Dialogue error: An exception has been thrown: ") + error.what() << std::endl;
|
Log(Debug::Error) << std::string ("Dialogue error: An exception has been thrown: ") + error.what();
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!success)
|
if (!success)
|
||||||
{
|
{
|
||||||
std::cerr
|
Log(Debug::Warning)
|
||||||
<< "Warning: compiling failed (dialogue script)" << std::endl
|
<< "Warning: compiling failed (dialogue script)\n" << cmd << "\n\n";
|
||||||
<< cmd
|
|
||||||
<< std::endl << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
|
@ -230,7 +231,7 @@ namespace MWDialogue
|
||||||
}
|
}
|
||||||
catch (const std::exception& error)
|
catch (const std::exception& error)
|
||||||
{
|
{
|
||||||
std::cerr << std::string ("Dialogue error: An exception has been thrown: ") + error.what() << std::endl;
|
Log(Debug::Error) << std::string ("Dialogue error: An exception has been thrown: ") + error.what();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -260,7 +261,7 @@ namespace MWDialogue
|
||||||
const MWWorld::Store<ESM::GameSetting>& gmsts =
|
const MWWorld::Store<ESM::GameSetting>& gmsts =
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||||
|
|
||||||
title = gmsts.find (modifiedTopic)->getString();
|
title = gmsts.find (modifiedTopic)->mValue.getString();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
title = topic;
|
title = topic;
|
||||||
|
@ -508,9 +509,11 @@ namespace MWDialogue
|
||||||
return static_cast<int>(mTemporaryDispositionChange);
|
return static_cast<int>(mTemporaryDispositionChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DialogueManager::applyDispositionChange(int delta)
|
void DialogueManager::applyBarterDispositionChange(int delta)
|
||||||
{
|
{
|
||||||
mTemporaryDispositionChange += delta;
|
mTemporaryDispositionChange += delta;
|
||||||
|
if (Settings::Manager::getBool("barter disposition change is permanent", "Game"))
|
||||||
|
mPermanentDispositionChange += delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DialogueManager::checkServiceRefused(ResponseCallback* callback)
|
bool DialogueManager::checkServiceRefused(ResponseCallback* callback)
|
||||||
|
@ -534,7 +537,7 @@ namespace MWDialogue
|
||||||
|
|
||||||
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
|
MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor);
|
||||||
|
|
||||||
callback->addResponse(gmsts.find ("sServiceRefusal")->getString(), Interpreter::fixDefinesDialog(info->mResponse, interpreterContext));
|
callback->addResponse(gmsts.find ("sServiceRefusal")->mValue.getString(), Interpreter::fixDefinesDialog(info->mResponse, interpreterContext));
|
||||||
|
|
||||||
executeScript (info->mResultScript, mActor);
|
executeScript (info->mResultScript, mActor);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -94,8 +94,8 @@ namespace MWDialogue
|
||||||
virtual void persuade (int type, ResponseCallback* callback);
|
virtual void persuade (int type, ResponseCallback* callback);
|
||||||
virtual int getTemporaryDispositionChange () const;
|
virtual int getTemporaryDispositionChange () const;
|
||||||
|
|
||||||
/// @note This change is temporary and gets discarded when dialogue ends.
|
/// @note Controlled by an option, gets discarded when dialogue ends by default
|
||||||
virtual void applyDispositionChange (int delta);
|
virtual void applyBarterDispositionChange (int delta);
|
||||||
|
|
||||||
virtual int countSavedGameRecords() const;
|
virtual int countSavedGameRecords() const;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
#include "scripttest.hpp"
|
#include "scripttest.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include "../mwworld/manualref.hpp"
|
#include "../mwworld/manualref.hpp"
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
@ -12,6 +10,7 @@
|
||||||
|
|
||||||
#include "../mwscript/compilercontext.hpp"
|
#include "../mwscript/compilercontext.hpp"
|
||||||
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
#include <components/compiler/exception.hpp>
|
#include <components/compiler/exception.hpp>
|
||||||
#include <components/compiler/streamerrorhandler.hpp>
|
#include <components/compiler/streamerrorhandler.hpp>
|
||||||
#include <components/compiler/scanner.hpp>
|
#include <components/compiler/scanner.hpp>
|
||||||
|
@ -80,16 +79,14 @@ void test(const MWWorld::Ptr& actor, int &compiled, int &total, const Compiler::
|
||||||
}
|
}
|
||||||
catch (const std::exception& error)
|
catch (const std::exception& error)
|
||||||
{
|
{
|
||||||
std::cerr << std::string ("Dialogue error: An exception has been thrown: ") + error.what() << std::endl;
|
Log(Debug::Error) << std::string ("Dialogue error: An exception has been thrown: ") + error.what();
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!success)
|
if (!success)
|
||||||
{
|
{
|
||||||
std::cerr
|
Log(Debug::Warning)
|
||||||
<< "compiling failed (dialogue script)" << std::endl
|
<< "compiling failed (dialogue script)\n" << info->mResultScript << "\n\n";
|
||||||
<< info->mResultScript
|
|
||||||
<< std::endl << std::endl;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "charactercreation.hpp"
|
#include "charactercreation.hpp"
|
||||||
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
#include <components/fallback/fallback.hpp>
|
#include <components/fallback/fallback.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
@ -284,7 +285,7 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
std::cerr << "Error: Failed to create chargen window: " << e.what() << std::endl;
|
Log(Debug::Error) << "Error: Failed to create chargen window: " << e.what();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -602,7 +603,7 @@ namespace MWGui
|
||||||
mGenerateClass = "Mage";
|
mGenerateClass = "Mage";
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::cout << "Failed to deduce class from chosen answers in generate class dialog" << std::endl;
|
Log(Debug::Warning) << "Failed to deduce class from chosen answers in generate class dialog.";
|
||||||
mGenerateClass = "Thief";
|
mGenerateClass = "Thief";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
|
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
|
|
||||||
#include "tooltips.hpp"
|
#include "tooltips.hpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
|
@ -924,7 +926,7 @@ namespace MWGui
|
||||||
std::string classImage = std::string("textures\\levelup\\") + classId + ".dds";
|
std::string classImage = std::string("textures\\levelup\\") + classId + ".dds";
|
||||||
if (!MWBase::Environment::get().getWindowManager()->textureExists(classImage))
|
if (!MWBase::Environment::get().getWindowManager()->textureExists(classImage))
|
||||||
{
|
{
|
||||||
std::cout << "No class image for " << classId << ", falling back to default" << std::endl;
|
Log(Debug::Warning) << "No class image for " << classId << ", falling back to default";
|
||||||
classImage = "textures\\levelup\\warrior.dds";
|
classImage = "textures\\levelup\\warrior.dds";
|
||||||
}
|
}
|
||||||
imageBox->setImageTexture(classImage);
|
imageBox->setImageTexture(classImage);
|
||||||
|
|
|
@ -303,6 +303,14 @@ namespace MWGui
|
||||||
bool has_front_quote = false;
|
bool has_front_quote = false;
|
||||||
|
|
||||||
/* Does the input string contain things that don't have to be completed? If yes erase them. */
|
/* Does the input string contain things that don't have to be completed? If yes erase them. */
|
||||||
|
|
||||||
|
/* Erase a possible call to an explicit reference. */
|
||||||
|
size_t explicitPos = tmp.find("->");
|
||||||
|
if (explicitPos != std::string::npos)
|
||||||
|
{
|
||||||
|
tmp.erase(0, explicitPos+2);
|
||||||
|
}
|
||||||
|
|
||||||
/* Are there quotation marks? */
|
/* Are there quotation marks? */
|
||||||
if( tmp.find('"') != std::string::npos ) {
|
if( tmp.find('"') != std::string::npos ) {
|
||||||
int numquotes=0;
|
int numquotes=0;
|
||||||
|
@ -339,6 +347,7 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Erase the input from the output string so we can easily append the completed form later. */
|
/* Erase the input from the output string so we can easily append the completed form later. */
|
||||||
output.erase(output.end()-tmp.length(), output.end());
|
output.erase(output.end()-tmp.length(), output.end());
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ namespace MWGui
|
||||||
|
|
||||||
void ContainerWindow::onItemSelected(int index)
|
void ContainerWindow::onItemSelected(int index)
|
||||||
{
|
{
|
||||||
if (mDragAndDrop->mIsOnDragAndDrop && mModel)
|
if (mDragAndDrop->mIsOnDragAndDrop)
|
||||||
{
|
{
|
||||||
dropItem();
|
dropItem();
|
||||||
return;
|
return;
|
||||||
|
@ -88,6 +88,9 @@ namespace MWGui
|
||||||
|
|
||||||
void ContainerWindow::dragItem(MyGUI::Widget* sender, int count)
|
void ContainerWindow::dragItem(MyGUI::Widget* sender, int count)
|
||||||
{
|
{
|
||||||
|
if (!mModel)
|
||||||
|
return;
|
||||||
|
|
||||||
if (!onTakeItem(mModel->getItem(mSelectedItem), count))
|
if (!onTakeItem(mModel->getItem(mSelectedItem), count))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -96,6 +99,9 @@ namespace MWGui
|
||||||
|
|
||||||
void ContainerWindow::dropItem()
|
void ContainerWindow::dropItem()
|
||||||
{
|
{
|
||||||
|
if (!mModel)
|
||||||
|
return;
|
||||||
|
|
||||||
bool success = mModel->onDropItem(mDragAndDrop->mItem.mBase, mDragAndDrop->mDraggedCount);
|
bool success = mModel->onDropItem(mDragAndDrop->mItem.mBase, mDragAndDrop->mDraggedCount);
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
|
@ -104,7 +110,7 @@ namespace MWGui
|
||||||
|
|
||||||
void ContainerWindow::onBackgroundSelected()
|
void ContainerWindow::onBackgroundSelected()
|
||||||
{
|
{
|
||||||
if (mDragAndDrop->mIsOnDragAndDrop && mModel)
|
if (mDragAndDrop->mIsOnDragAndDrop)
|
||||||
dropItem();
|
dropItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <MyGUI_ScrollBar.h>
|
#include <MyGUI_ScrollBar.h>
|
||||||
#include <MyGUI_Button.h>
|
#include <MyGUI_Button.h>
|
||||||
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
#include <components/widgets/list.hpp>
|
#include <components/widgets/list.hpp>
|
||||||
#include <components/translation/translation.hpp>
|
#include <components/translation/translation.hpp>
|
||||||
|
|
||||||
|
@ -362,52 +363,59 @@ namespace MWGui
|
||||||
if (mGoodbye || MWBase::Environment::get().getDialogueManager()->isInChoice())
|
if (mGoodbye || MWBase::Environment::get().getDialogueManager()->isInChoice())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int separatorPos = 0;
|
const MWWorld::Store<ESM::GameSetting> &gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||||
for (unsigned int i=0; i<mTopicsList->getItemCount(); ++i)
|
|
||||||
{
|
|
||||||
if (mTopicsList->getItemNameAt(i) == "")
|
|
||||||
separatorPos = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (id >= separatorPos)
|
const std::string sPersuasion = gmst.find("sPersuasion")->mValue.getString();
|
||||||
|
const std::string sCompanionShare = gmst.find("sCompanionShare")->mValue.getString();
|
||||||
|
const std::string sBarter = gmst.find("sBarter")->mValue.getString();
|
||||||
|
const std::string sSpells = gmst.find("sSpells")->mValue.getString();
|
||||||
|
const std::string sTravel = gmst.find("sTravel")->mValue.getString();
|
||||||
|
const std::string sSpellMakingMenuTitle = gmst.find("sSpellMakingMenuTitle")->mValue.getString();
|
||||||
|
const std::string sEnchanting = gmst.find("sEnchanting")->mValue.getString();
|
||||||
|
const std::string sServiceTrainingTitle = gmst.find("sServiceTrainingTitle")->mValue.getString();
|
||||||
|
const std::string sRepair = gmst.find("sRepair")->mValue.getString();
|
||||||
|
|
||||||
|
if (topic != sPersuasion && topic != sCompanionShare && topic != sBarter
|
||||||
|
&& topic != sSpells && topic != sTravel && topic != sSpellMakingMenuTitle
|
||||||
|
&& topic != sEnchanting && topic != sServiceTrainingTitle && topic != sRepair)
|
||||||
{
|
{
|
||||||
onTopicActivated(topic);
|
onTopicActivated(topic);
|
||||||
if (mGoodbyeButton->getEnabled())
|
if (mGoodbyeButton->getEnabled())
|
||||||
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mGoodbyeButton);
|
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mGoodbyeButton);
|
||||||
}
|
}
|
||||||
else
|
else if (topic == sPersuasion)
|
||||||
|
mPersuasionDialog.setVisible(true);
|
||||||
|
else if (topic == sCompanionShare)
|
||||||
|
MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Companion, mPtr);
|
||||||
|
else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused(mCallback.get()))
|
||||||
{
|
{
|
||||||
const MWWorld::Store<ESM::GameSetting> &gmst =
|
if (topic == sBarter)
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Barter, mPtr);
|
||||||
|
else if (topic == sSpells)
|
||||||
if (topic == gmst.find("sPersuasion")->getString())
|
MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellBuying, mPtr);
|
||||||
mPersuasionDialog.setVisible(true);
|
else if (topic == sTravel)
|
||||||
else if (topic == gmst.find("sCompanionShare")->getString())
|
MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Travel, mPtr);
|
||||||
MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Companion, mPtr);
|
else if (topic == sSpellMakingMenuTitle)
|
||||||
else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused(mCallback.get()))
|
MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellCreation, mPtr);
|
||||||
{
|
else if (topic == sEnchanting)
|
||||||
if (topic == gmst.find("sBarter")->getString())
|
MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Enchanting, mPtr);
|
||||||
MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Barter, mPtr);
|
else if (topic == sServiceTrainingTitle)
|
||||||
else if (topic == gmst.find("sSpells")->getString())
|
MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Training, mPtr);
|
||||||
MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellBuying, mPtr);
|
else if (topic == sRepair)
|
||||||
else if (topic == gmst.find("sTravel")->getString())
|
MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_MerchantRepair, mPtr);
|
||||||
MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Travel, mPtr);
|
|
||||||
else if (topic == gmst.find("sSpellMakingMenuTitle")->getString())
|
|
||||||
MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellCreation, mPtr);
|
|
||||||
else if (topic == gmst.find("sEnchanting")->getString())
|
|
||||||
MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Enchanting, mPtr);
|
|
||||||
else if (topic == gmst.find("sServiceTrainingTitle")->getString())
|
|
||||||
MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Training, mPtr);
|
|
||||||
else if (topic == gmst.find("sRepair")->getString())
|
|
||||||
MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_MerchantRepair, mPtr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
updateTopics();
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
updateTopics();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DialogueWindow::setPtr(const MWWorld::Ptr& actor)
|
void DialogueWindow::setPtr(const MWWorld::Ptr& actor)
|
||||||
{
|
{
|
||||||
|
if (!actor.getClass().isActor())
|
||||||
|
{
|
||||||
|
Log(Debug::Warning) << "Warning: can not talk with non-actor object.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
bool sameActor = (mPtr == actor);
|
bool sameActor = (mPtr == actor);
|
||||||
if (!sameActor)
|
if (!sameActor)
|
||||||
{
|
{
|
||||||
|
@ -450,7 +458,7 @@ namespace MWGui
|
||||||
void DialogueWindow::restock()
|
void DialogueWindow::restock()
|
||||||
{
|
{
|
||||||
MWMechanics::CreatureStats &sellerStats = mPtr.getClass().getCreatureStats(mPtr);
|
MWMechanics::CreatureStats &sellerStats = mPtr.getClass().getCreatureStats(mPtr);
|
||||||
float delay = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fBarterGoldResetDelay")->getFloat();
|
float delay = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fBarterGoldResetDelay")->mValue.getFloat();
|
||||||
|
|
||||||
// Gold is restocked every 24h
|
// Gold is restocked every 24h
|
||||||
if (MWBase::Environment::get().getWorld()->getTimeStamp() >= sellerStats.getLastRestockTime() + delay)
|
if (MWBase::Environment::get().getWorld()->getTimeStamp() >= sellerStats.getLastRestockTime() + delay)
|
||||||
|
@ -495,31 +503,31 @@ namespace MWGui
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||||
|
|
||||||
if (mPtr.getTypeName() == typeid(ESM::NPC).name())
|
if (mPtr.getTypeName() == typeid(ESM::NPC).name())
|
||||||
mTopicsList->addItem(gmst.find("sPersuasion")->getString());
|
mTopicsList->addItem(gmst.find("sPersuasion")->mValue.getString());
|
||||||
|
|
||||||
if (services & ESM::NPC::AllItems)
|
if (services & ESM::NPC::AllItems)
|
||||||
mTopicsList->addItem(gmst.find("sBarter")->getString());
|
mTopicsList->addItem(gmst.find("sBarter")->mValue.getString());
|
||||||
|
|
||||||
if (services & ESM::NPC::Spells)
|
if (services & ESM::NPC::Spells)
|
||||||
mTopicsList->addItem(gmst.find("sSpells")->getString());
|
mTopicsList->addItem(gmst.find("sSpells")->mValue.getString());
|
||||||
|
|
||||||
if (travel)
|
if (travel)
|
||||||
mTopicsList->addItem(gmst.find("sTravel")->getString());
|
mTopicsList->addItem(gmst.find("sTravel")->mValue.getString());
|
||||||
|
|
||||||
if (services & ESM::NPC::Spellmaking)
|
if (services & ESM::NPC::Spellmaking)
|
||||||
mTopicsList->addItem(gmst.find("sSpellmakingMenuTitle")->getString());
|
mTopicsList->addItem(gmst.find("sSpellmakingMenuTitle")->mValue.getString());
|
||||||
|
|
||||||
if (services & ESM::NPC::Enchanting)
|
if (services & ESM::NPC::Enchanting)
|
||||||
mTopicsList->addItem(gmst.find("sEnchanting")->getString());
|
mTopicsList->addItem(gmst.find("sEnchanting")->mValue.getString());
|
||||||
|
|
||||||
if (services & ESM::NPC::Training)
|
if (services & ESM::NPC::Training)
|
||||||
mTopicsList->addItem(gmst.find("sServiceTrainingTitle")->getString());
|
mTopicsList->addItem(gmst.find("sServiceTrainingTitle")->mValue.getString());
|
||||||
|
|
||||||
if (services & ESM::NPC::Repair)
|
if (services & ESM::NPC::Repair)
|
||||||
mTopicsList->addItem(gmst.find("sRepair")->getString());
|
mTopicsList->addItem(gmst.find("sRepair")->mValue.getString());
|
||||||
|
|
||||||
if (isCompanion())
|
if (isCompanion())
|
||||||
mTopicsList->addItem(gmst.find("sCompanionShare")->getString());
|
mTopicsList->addItem(gmst.find("sCompanionShare")->mValue.getString());
|
||||||
|
|
||||||
if (mTopicsList->getItemCount() > 0)
|
if (mTopicsList->getItemCount() > 0)
|
||||||
mTopicsList->addSeparator();
|
mTopicsList->addSeparator();
|
||||||
|
@ -584,7 +592,7 @@ namespace MWGui
|
||||||
Goodbye* link = new Goodbye();
|
Goodbye* link = new Goodbye();
|
||||||
link->eventActivated += MyGUI::newDelegate(this, &DialogueWindow::onGoodbyeActivated);
|
link->eventActivated += MyGUI::newDelegate(this, &DialogueWindow::onGoodbyeActivated);
|
||||||
mLinks.push_back(link);
|
mLinks.push_back(link);
|
||||||
std::string goodbye = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sGoodbye")->getString();
|
std::string goodbye = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sGoodbye")->mValue.getString();
|
||||||
BookTypesetter::Style* questionStyle = typesetter->createHotStyle(body, textColours.answer, textColours.answerOver,
|
BookTypesetter::Style* questionStyle = typesetter->createHotStyle(body, textColours.answer, textColours.answerOver,
|
||||||
textColours.answerPressed,
|
textColours.answerPressed,
|
||||||
TypesetBook::InteractiveId(link));
|
TypesetBook::InteractiveId(link));
|
||||||
|
|
|
@ -341,7 +341,7 @@ namespace MWGui
|
||||||
MWWorld::Ptr item = (i == 0) ? mEnchanting.getOldItem() : mEnchanting.getGem();
|
MWWorld::Ptr item = (i == 0) ? mEnchanting.getOldItem() : mEnchanting.getGem();
|
||||||
if (MWBase::Environment::get().getMechanicsManager()->isItemStolenFrom(item.getCellRef().getRefId(), mPtr))
|
if (MWBase::Environment::get().getMechanicsManager()->isItemStolenFrom(item.getCellRef().getRefId(), mPtr))
|
||||||
{
|
{
|
||||||
std::string msg = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sNotifyMessage49")->getString();
|
std::string msg = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sNotifyMessage49")->mValue.getString();
|
||||||
if (msg.find("%s") != std::string::npos)
|
if (msg.find("%s") != std::string::npos)
|
||||||
msg.replace(msg.find("%s"), 2, item.getClass().getName(item));
|
msg.replace(msg.find("%s"), 2, item.getClass().getName(item));
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox(msg);
|
MWBase::Environment::get().getWindowManager()->messageBox(msg);
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <boost/algorithm/string/replace.hpp>
|
#include <boost/algorithm/string/replace.hpp>
|
||||||
#include <boost/algorithm/string/predicate.hpp>
|
#include <boost/algorithm/string/predicate.hpp>
|
||||||
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
#include <components/interpreter/defines.hpp>
|
#include <components/interpreter/defines.hpp>
|
||||||
#include <components/misc/stringops.hpp>
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
|
@ -300,7 +301,7 @@ namespace MWGui
|
||||||
|
|
||||||
if (!exists)
|
if (!exists)
|
||||||
{
|
{
|
||||||
std::cerr << "Warning: Could not find \"" << src << "\" referenced by an <img> tag." << std::endl;
|
Log(Debug::Warning) << "Warning: Could not find \"" << src << "\" referenced by an <img> tag.";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -611,7 +611,7 @@ namespace MWGui
|
||||||
// Therefore any value < 1 should show as an empty health bar. We do the same in statswindow :)
|
// Therefore any value < 1 should show as an empty health bar. We do the same in statswindow :)
|
||||||
mEnemyHealth->setProgressPosition(static_cast<size_t>(stats.getHealth().getCurrent() / stats.getHealth().getModified() * 100));
|
mEnemyHealth->setProgressPosition(static_cast<size_t>(stats.getHealth().getCurrent() / stats.getHealth().getModified() * 100));
|
||||||
|
|
||||||
static const float fNPCHealthBarFade = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fNPCHealthBarFade")->getFloat();
|
static const float fNPCHealthBarFade = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fNPCHealthBarFade")->mValue.getFloat();
|
||||||
if (fNPCHealthBarFade > 0.f)
|
if (fNPCHealthBarFade > 0.f)
|
||||||
mEnemyHealth->setAlpha(std::max(0.f, std::min(1.f, mEnemyHealthTimer/fNPCHealthBarFade)));
|
mEnemyHealth->setAlpha(std::max(0.f, std::min(1.f, mEnemyHealthTimer/fNPCHealthBarFade)));
|
||||||
|
|
||||||
|
@ -620,7 +620,7 @@ namespace MWGui
|
||||||
void HUD::setEnemy(const MWWorld::Ptr &enemy)
|
void HUD::setEnemy(const MWWorld::Ptr &enemy)
|
||||||
{
|
{
|
||||||
mEnemyActorId = enemy.getClass().getCreatureStats(enemy).getActorId();
|
mEnemyActorId = enemy.getClass().getCreatureStats(enemy).getActorId();
|
||||||
mEnemyHealthTimer = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fNPCHealthBarTime")->getFloat();
|
mEnemyHealthTimer = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fNPCHealthBarTime")->mValue.getFloat();
|
||||||
if (!mEnemyHealth->getVisible())
|
if (!mEnemyHealth->getVisible())
|
||||||
mWeaponSpellBox->setPosition(mWeaponSpellBox->getPosition() - MyGUI::IntPoint(0,20));
|
mWeaponSpellBox->setPosition(mWeaponSpellBox->getPosition() - MyGUI::IntPoint(0,20));
|
||||||
mEnemyHealth->setVisible(true);
|
mEnemyHealth->setVisible(true);
|
||||||
|
|
|
@ -67,7 +67,13 @@ namespace MWGui
|
||||||
, mLastYSize(0)
|
, mLastYSize(0)
|
||||||
, mPreview(new MWRender::InventoryPreview(parent, resourceSystem, MWMechanics::getPlayer()))
|
, mPreview(new MWRender::InventoryPreview(parent, resourceSystem, MWMechanics::getPlayer()))
|
||||||
, mTrading(false)
|
, mTrading(false)
|
||||||
|
, mScaleFactor(1.0f)
|
||||||
|
, mUpdateTimer(0.f)
|
||||||
{
|
{
|
||||||
|
float uiScale = Settings::Manager::getFloat("scaling factor", "GUI");
|
||||||
|
if (uiScale > 1.0)
|
||||||
|
mScaleFactor = uiScale;
|
||||||
|
|
||||||
mPreviewTexture.reset(new osgMyGUI::OSGTexture(mPreview->getTexture()));
|
mPreviewTexture.reset(new osgMyGUI::OSGTexture(mPreview->getTexture()));
|
||||||
mPreview->rebuild();
|
mPreview->rebuild();
|
||||||
|
|
||||||
|
@ -431,10 +437,10 @@ namespace MWGui
|
||||||
MyGUI::IntSize size = mAvatarImage->getSize();
|
MyGUI::IntSize size = mAvatarImage->getSize();
|
||||||
int width = std::min(mPreview->getTextureWidth(), size.width);
|
int width = std::min(mPreview->getTextureWidth(), size.width);
|
||||||
int height = std::min(mPreview->getTextureHeight(), size.height);
|
int height = std::min(mPreview->getTextureHeight(), size.height);
|
||||||
mPreview->setViewport(width, height);
|
mPreview->setViewport(int(width*mScaleFactor), int(height*mScaleFactor));
|
||||||
|
|
||||||
mAvatarImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f,
|
mAvatarImage->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f,
|
||||||
width/float(mPreview->getTextureWidth()), height/float(mPreview->getTextureHeight())));
|
width*mScaleFactor/float(mPreview->getTextureWidth()), height*mScaleFactor/float(mPreview->getTextureHeight())));
|
||||||
}
|
}
|
||||||
|
|
||||||
void InventoryWindow::onFilterChanged(MyGUI::Widget* _sender)
|
void InventoryWindow::onFilterChanged(MyGUI::Widget* _sender)
|
||||||
|
@ -512,7 +518,7 @@ namespace MWGui
|
||||||
|
|
||||||
// Give the script a chance to run once before we do anything else
|
// Give the script a chance to run once before we do anything else
|
||||||
// this is important when setting pcskipequip as a reaction to onpcequip being set (bk_treasuryreport does this)
|
// this is important when setting pcskipequip as a reaction to onpcequip being set (bk_treasuryreport does this)
|
||||||
if (!script.empty() && MWBase::Environment::get().getWorld()->getScriptsEnabled())
|
if (!force && !script.empty() && MWBase::Environment::get().getWorld()->getScriptsEnabled())
|
||||||
{
|
{
|
||||||
MWScript::InterpreterContext interpreterContext (&ptr.getRefData().getLocals(), ptr);
|
MWScript::InterpreterContext interpreterContext (&ptr.getRefData().getLocals(), ptr);
|
||||||
MWBase::Environment::get().getScriptManager()->run (script, interpreterContext);
|
MWBase::Environment::get().getScriptManager()->run (script, interpreterContext);
|
||||||
|
@ -591,6 +597,11 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
// convert to OpenGL lower-left origin
|
// convert to OpenGL lower-left origin
|
||||||
y = (mAvatarImage->getHeight()-1) - y;
|
y = (mAvatarImage->getHeight()-1) - y;
|
||||||
|
|
||||||
|
// Scale coordinates
|
||||||
|
x = int(x*mScaleFactor);
|
||||||
|
y = int(y*mScaleFactor);
|
||||||
|
|
||||||
int slot = mPreview->getSlotSelected (x, y);
|
int slot = mPreview->getSlotSelected (x, y);
|
||||||
|
|
||||||
if (slot == -1)
|
if (slot == -1)
|
||||||
|
@ -621,6 +632,22 @@ namespace MWGui
|
||||||
void InventoryWindow::onFrame(float dt)
|
void InventoryWindow::onFrame(float dt)
|
||||||
{
|
{
|
||||||
updateEncumbranceBar();
|
updateEncumbranceBar();
|
||||||
|
|
||||||
|
if (mPinned)
|
||||||
|
{
|
||||||
|
mUpdateTimer += dt;
|
||||||
|
if (0.1f < mUpdateTimer)
|
||||||
|
{
|
||||||
|
mUpdateTimer = 0;
|
||||||
|
|
||||||
|
// Update pinned inventory in-game
|
||||||
|
if (!MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||||
|
{
|
||||||
|
mItemView->update();
|
||||||
|
notifyContentChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InventoryWindow::setTrading(bool trading)
|
void InventoryWindow::setTrading(bool trading)
|
||||||
|
@ -671,6 +698,8 @@ namespace MWGui
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int count = object.getRefData().getCount();
|
int count = object.getRefData().getCount();
|
||||||
|
if (object.getClass().isGold(object))
|
||||||
|
count *= object.getClass().getValue(object);
|
||||||
|
|
||||||
MWWorld::Ptr player = MWMechanics::getPlayer();
|
MWWorld::Ptr player = MWMechanics::getPlayer();
|
||||||
MWBase::Environment::get().getWorld()->breakInvisibility(player);
|
MWBase::Environment::get().getWorld()->breakInvisibility(player);
|
||||||
|
|
|
@ -101,6 +101,8 @@ namespace MWGui
|
||||||
std::unique_ptr<MWRender::InventoryPreview> mPreview;
|
std::unique_ptr<MWRender::InventoryPreview> mPreview;
|
||||||
|
|
||||||
bool mTrading;
|
bool mTrading;
|
||||||
|
float mScaleFactor;
|
||||||
|
float mUpdateTimer;
|
||||||
|
|
||||||
void onItemSelected(int index);
|
void onItemSelected(int index);
|
||||||
void onItemSelectedFromSourceModel(int index);
|
void onItemSelectedFromSourceModel(int index);
|
||||||
|
|
|
@ -99,9 +99,9 @@ namespace MWGui
|
||||||
|
|
||||||
std::string message;
|
std::string message;
|
||||||
if (mDays == 1)
|
if (mDays == 1)
|
||||||
message = gmst.find("sNotifyMessage42")->getString();
|
message = gmst.find("sNotifyMessage42")->mValue.getString();
|
||||||
else
|
else
|
||||||
message = gmst.find("sNotifyMessage43")->getString();
|
message = gmst.find("sNotifyMessage43")->mValue.getString();
|
||||||
|
|
||||||
std::stringstream dayStr;
|
std::stringstream dayStr;
|
||||||
dayStr << mDays;
|
dayStr << mDays;
|
||||||
|
@ -110,12 +110,12 @@ namespace MWGui
|
||||||
|
|
||||||
for (std::set<int>::iterator it = skills.begin(); it != skills.end(); ++it)
|
for (std::set<int>::iterator it = skills.begin(); it != skills.end(); ++it)
|
||||||
{
|
{
|
||||||
std::string skillName = gmst.find(ESM::Skill::sSkillNameIds[*it])->getString();
|
std::string skillName = gmst.find(ESM::Skill::sSkillNameIds[*it])->mValue.getString();
|
||||||
std::stringstream skillValue;
|
std::stringstream skillValue;
|
||||||
skillValue << player.getClass().getNpcStats(player).getSkill(*it).getBase();
|
skillValue << player.getClass().getNpcStats(player).getSkill(*it).getBase();
|
||||||
std::string skillMsg = gmst.find("sNotifyMessage44")->getString();
|
std::string skillMsg = gmst.find("sNotifyMessage44")->mValue.getString();
|
||||||
if (*it == ESM::Skill::Sneak || *it == ESM::Skill::Security)
|
if (*it == ESM::Skill::Sneak || *it == ESM::Skill::Security)
|
||||||
skillMsg = gmst.find("sNotifyMessage39")->getString();
|
skillMsg = gmst.find("sNotifyMessage39")->mValue.getString();
|
||||||
|
|
||||||
if (skillMsg.find("%s") != std::string::npos)
|
if (skillMsg.find("%s") != std::string::npos)
|
||||||
skillMsg.replace(skillMsg.find("%s"), 2, skillName);
|
skillMsg.replace(skillMsg.find("%s"), 2, skillName);
|
||||||
|
|
|
@ -10,9 +10,8 @@
|
||||||
#include <MyGUI_TextBox.h>
|
#include <MyGUI_TextBox.h>
|
||||||
|
|
||||||
#include <components/misc/rng.hpp>
|
#include <components/misc/rng.hpp>
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
#include <components/myguiplatform/myguitexture.hpp>
|
#include <components/myguiplatform/myguitexture.hpp>
|
||||||
|
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
#include <components/vfs/manager.hpp>
|
#include <components/vfs/manager.hpp>
|
||||||
|
|
||||||
|
@ -37,6 +36,7 @@ namespace MWGui
|
||||||
, mLastRenderTime(0.0)
|
, mLastRenderTime(0.0)
|
||||||
, mLoadingOnTime(0.0)
|
, mLoadingOnTime(0.0)
|
||||||
, mImportantLabel(false)
|
, mImportantLabel(false)
|
||||||
|
, mVisible(false)
|
||||||
, mProgress(0)
|
, mProgress(0)
|
||||||
, mShowWallpaper(true)
|
, mShowWallpaper(true)
|
||||||
{
|
{
|
||||||
|
@ -93,7 +93,7 @@ namespace MWGui
|
||||||
++found;
|
++found;
|
||||||
}
|
}
|
||||||
if (mSplashScreens.empty())
|
if (mSplashScreens.empty())
|
||||||
std::cerr << "No splash screens found!" << std::endl;
|
Log(Debug::Warning) << "Warning: no splash screens found!";
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadingScreen::setLabel(const std::string &label, bool important)
|
void LoadingScreen::setLabel(const std::string &label, bool important)
|
||||||
|
@ -169,12 +169,18 @@ namespace MWGui
|
||||||
// We are already using node masks to avoid the scene from being updated/rendered, but node masks don't work for computeBound()
|
// We are already using node masks to avoid the scene from being updated/rendered, but node masks don't work for computeBound()
|
||||||
mViewer->getSceneData()->setComputeBoundingSphereCallback(new DontComputeBoundCallback);
|
mViewer->getSceneData()->setComputeBoundingSphereCallback(new DontComputeBoundCallback);
|
||||||
|
|
||||||
|
mShowWallpaper = visible && (MWBase::Environment::get().getStateManager()->getState()
|
||||||
|
== MWBase::StateManager::State_NoGame);
|
||||||
|
|
||||||
|
if (!visible)
|
||||||
|
{
|
||||||
|
draw();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mVisible = visible;
|
mVisible = visible;
|
||||||
mLoadingBox->setVisible(mVisible);
|
mLoadingBox->setVisible(mVisible);
|
||||||
|
|
||||||
mShowWallpaper = mVisible && (MWBase::Environment::get().getStateManager()->getState()
|
|
||||||
== MWBase::StateManager::State_NoGame);
|
|
||||||
|
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
|
|
||||||
if (mShowWallpaper)
|
if (mShowWallpaper)
|
||||||
|
@ -183,9 +189,6 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
|
|
||||||
MWBase::Environment::get().getWindowManager()->pushGuiMode(mShowWallpaper ? GM_LoadingWallpaper : GM_Loading);
|
MWBase::Environment::get().getWindowManager()->pushGuiMode(mShowWallpaper ? GM_LoadingWallpaper : GM_Loading);
|
||||||
|
|
||||||
if (!mVisible)
|
|
||||||
draw();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadingScreen::loadingOff()
|
void LoadingScreen::loadingOff()
|
||||||
|
|
|
@ -57,7 +57,7 @@ void MerchantRepair::setPtr(const MWWorld::Ptr &actor)
|
||||||
|
|
||||||
int basePrice = iter->getClass().getValue(*iter);
|
int basePrice = iter->getClass().getValue(*iter);
|
||||||
float fRepairMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
float fRepairMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||||
.find("fRepairMult")->getFloat();
|
.find("fRepairMult")->mValue.getFloat();
|
||||||
|
|
||||||
float p = static_cast<float>(std::max(1, basePrice));
|
float p = static_cast<float>(std::max(1, basePrice));
|
||||||
float r = static_cast<float>(std::max(1, static_cast<int>(maxDurability / p)));
|
float r = static_cast<float>(std::max(1, static_cast<int>(maxDurability / p)));
|
||||||
|
@ -71,7 +71,7 @@ void MerchantRepair::setPtr(const MWWorld::Ptr &actor)
|
||||||
std::string name = iter->getClass().getName(*iter)
|
std::string name = iter->getClass().getName(*iter)
|
||||||
+ " - " + MyGUI::utility::toString(price)
|
+ " - " + MyGUI::utility::toString(price)
|
||||||
+ MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
+ MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||||
.find("sgp")->getString();
|
.find("sgp")->mValue.getString();
|
||||||
|
|
||||||
|
|
||||||
MyGUI::Button* button =
|
MyGUI::Button* button =
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <MyGUI_RenderManager.h>
|
#include <MyGUI_RenderManager.h>
|
||||||
#include <MyGUI_Button.h>
|
#include <MyGUI_Button.h>
|
||||||
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
#include <components/misc/stringops.hpp>
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
@ -125,7 +126,7 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
if (mInterMessageBoxe != NULL)
|
if (mInterMessageBoxe != NULL)
|
||||||
{
|
{
|
||||||
std::cerr << "Warning: replacing an interactive message box that was not answered yet" << std::endl;
|
Log(Debug::Warning) << "Warning: replacing an interactive message box that was not answered yet";
|
||||||
mInterMessageBoxe->setVisible(false);
|
mInterMessageBoxe->setVisible(false);
|
||||||
delete mInterMessageBoxe;
|
delete mInterMessageBoxe;
|
||||||
mInterMessageBoxe = NULL;
|
mInterMessageBoxe = NULL;
|
||||||
|
|
|
@ -161,6 +161,12 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(index != -1);
|
assert(index != -1);
|
||||||
|
if (index < 0)
|
||||||
|
{
|
||||||
|
mSelected = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mSelected = &mKey[index];
|
mSelected = &mKey[index];
|
||||||
|
|
||||||
// prevent reallocation of zero key from Type_HandToHand
|
// prevent reallocation of zero key from Type_HandToHand
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <osg/Texture2D>
|
#include <osg/Texture2D>
|
||||||
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
#include <components/myguiplatform/myguitexture.hpp>
|
#include <components/myguiplatform/myguitexture.hpp>
|
||||||
|
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
@ -340,7 +341,7 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
std::cerr << "Error creating preview: " << e.what() << std::endl;
|
Log(Debug::Error) << "Error creating preview: " << e.what();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -169,19 +169,18 @@ void Recharge::onItemClicked(MyGUI::Widget *sender, const MWWorld::Ptr& item)
|
||||||
MWBase::Environment::get().getWindowManager()->playSound("Enchant Success");
|
MWBase::Environment::get().getWindowManager()->playSound("Enchant Success");
|
||||||
|
|
||||||
player.getClass().getContainerStore(player).restack(item);
|
player.getClass().getContainerStore(player).restack(item);
|
||||||
|
|
||||||
player.getClass().skillUsageSucceeded (player, ESM::Skill::Enchant, 0);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getWindowManager()->playSound("Enchant Fail");
|
MWBase::Environment::get().getWindowManager()->playSound("Enchant Fail");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
player.getClass().skillUsageSucceeded (player, ESM::Skill::Enchant, 0);
|
||||||
gem.getContainerStore()->remove(gem, 1, player);
|
gem.getContainerStore()->remove(gem, 1, player);
|
||||||
|
|
||||||
if (gem.getRefData().getCount() == 0)
|
if (gem.getRefData().getCount() == 0)
|
||||||
{
|
{
|
||||||
std::string message = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sNotifyMessage51")->getString();
|
std::string message = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sNotifyMessage51")->mValue.getString();
|
||||||
message = boost::str(boost::format(message) % gem.getClass().getName(gem));
|
message = boost::str(boost::format(message) % gem.getClass().getName(gem));
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox(message);
|
MWBase::Environment::get().getWindowManager()->messageBox(message);
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
#include <osgDB/ReadFile>
|
#include <osgDB/ReadFile>
|
||||||
#include <osg/Texture2D>
|
#include <osg/Texture2D>
|
||||||
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
|
|
||||||
#include <components/myguiplatform/myguitexture.hpp>
|
#include <components/myguiplatform/myguitexture.hpp>
|
||||||
|
|
||||||
#include <components/misc/stringops.hpp>
|
#include <components/misc/stringops.hpp>
|
||||||
|
@ -438,14 +440,14 @@ namespace MWGui
|
||||||
osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("jpg");
|
osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("jpg");
|
||||||
if (!readerwriter)
|
if (!readerwriter)
|
||||||
{
|
{
|
||||||
std::cerr << "Error: Can't open savegame screenshot, no jpg readerwriter found" << std::endl;
|
Log(Debug::Error) << "Error: Can't open savegame screenshot, no jpg readerwriter found";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
osgDB::ReaderWriter::ReadResult result = readerwriter->readImage(instream);
|
osgDB::ReaderWriter::ReadResult result = readerwriter->readImage(instream);
|
||||||
if (!result.success())
|
if (!result.success())
|
||||||
{
|
{
|
||||||
std::cerr << "Error: Failed to read savegame screenshot: " << result.message() << " code " << result.status() << std::endl;
|
Log(Debug::Error) << "Error: Failed to read savegame screenshot: " << result.message() << " code " << result.status();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include <SDL_video.h>
|
#include <SDL_video.h>
|
||||||
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
#include <components/widgets/sharedstatebutton.hpp>
|
#include <components/widgets/sharedstatebutton.hpp>
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
|
@ -31,7 +32,8 @@ namespace
|
||||||
if (val == "linear") return "Trilinear";
|
if (val == "linear") return "Trilinear";
|
||||||
if (val == "nearest") return "Bilinear";
|
if (val == "nearest") return "Bilinear";
|
||||||
if (val != "none")
|
if (val != "none")
|
||||||
std::cerr<< "Warning: Invalid texture mipmap option: "<<val <<std::endl;
|
Log(Debug::Warning) << "Warning: Invalid texture mipmap option: "<< val;
|
||||||
|
|
||||||
return "Other";
|
return "Other";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -398,7 +400,7 @@ namespace MWGui
|
||||||
else if(pos == 1)
|
else if(pos == 1)
|
||||||
Settings::Manager::setString("texture mipmap", "General", "linear");
|
Settings::Manager::setString("texture mipmap", "General", "linear");
|
||||||
else
|
else
|
||||||
std::cerr<< "Unexpected option pos "<<pos <<std::endl;
|
Log(Debug::Warning) << "Unexpected option pos " << pos;
|
||||||
apply();
|
apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
#include "sortfilteritemmodel.hpp"
|
#include "sortfilteritemmodel.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include <components/misc/stringops.hpp>
|
#include <components/misc/stringops.hpp>
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
#include <components/esm/loadalch.hpp>
|
#include <components/esm/loadalch.hpp>
|
||||||
#include <components/esm/loadappa.hpp>
|
#include <components/esm/loadappa.hpp>
|
||||||
#include <components/esm/loadarmo.hpp>
|
#include <components/esm/loadarmo.hpp>
|
||||||
|
@ -245,7 +243,7 @@ namespace MWGui
|
||||||
const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().search(enchId);
|
const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().search(enchId);
|
||||||
if (!ench)
|
if (!ench)
|
||||||
{
|
{
|
||||||
std::cerr << "Warning: Can't find enchantment '" << enchId << "' on item " << base.getCellRef().getRefId() << std::endl;
|
Log(Debug::Warning) << "Warning: Can't find enchantment '" << enchId << "' on item " << base.getCellRef().getRefId();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ namespace MWGui
|
||||||
const MWWorld::ESMStore &store =
|
const MWWorld::ESMStore &store =
|
||||||
MWBase::Environment::get().getWorld()->getStore();
|
MWBase::Environment::get().getWorld()->getStore();
|
||||||
|
|
||||||
int price = static_cast<int>(spell.mData.mCost*store.get<ESM::GameSetting>().find("fSpellValueMult")->getFloat());
|
int price = static_cast<int>(spell.mData.mCost*store.get<ESM::GameSetting>().find("fSpellValueMult")->mValue.getFloat());
|
||||||
price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true);
|
price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true);
|
||||||
|
|
||||||
MWWorld::Ptr player = MWMechanics::getPlayer();
|
MWWorld::Ptr player = MWMechanics::getPlayer();
|
||||||
|
|
|
@ -32,8 +32,8 @@ namespace
|
||||||
const MWWorld::Store<ESM::GameSetting> &gmst =
|
const MWWorld::Store<ESM::GameSetting> &gmst =
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||||
|
|
||||||
return gmst.find(ESM::MagicEffect::effectIdToString (id1))->getString()
|
return gmst.find(ESM::MagicEffect::effectIdToString (id1))->mValue.getString()
|
||||||
< gmst.find(ESM::MagicEffect::effectIdToString (id2))->getString();
|
< gmst.find(ESM::MagicEffect::effectIdToString (id2))->mValue.getString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void init(ESM::ENAMstruct& effect)
|
void init(ESM::ENAMstruct& effect)
|
||||||
|
@ -469,7 +469,7 @@ namespace MWGui
|
||||||
mMagickaCost->setCaption(MyGUI::utility::toString(int(y)));
|
mMagickaCost->setCaption(MyGUI::utility::toString(int(y)));
|
||||||
|
|
||||||
float fSpellMakingValueMult =
|
float fSpellMakingValueMult =
|
||||||
store.get<ESM::GameSetting>().find("fSpellMakingValueMult")->getFloat();
|
store.get<ESM::GameSetting>().find("fSpellMakingValueMult")->mValue.getFloat();
|
||||||
|
|
||||||
int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, static_cast<int>(y * fSpellMakingValueMult),true);
|
int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, static_cast<int>(y * fSpellMakingValueMult),true);
|
||||||
|
|
||||||
|
@ -547,7 +547,7 @@ namespace MWGui
|
||||||
for (std::vector<short>::const_iterator it = knownEffects.begin(); it != knownEffects.end(); ++it)
|
for (std::vector<short>::const_iterator it = knownEffects.begin(); it != knownEffects.end(); ++it)
|
||||||
{
|
{
|
||||||
mAvailableEffectsList->addItem(MWBase::Environment::get().getWorld ()->getStore ().get<ESM::GameSetting>().find(
|
mAvailableEffectsList->addItem(MWBase::Environment::get().getWorld ()->getStore ().get<ESM::GameSetting>().find(
|
||||||
ESM::MagicEffect::effectIdToString (*it))->getString());
|
ESM::MagicEffect::effectIdToString (*it))->mValue.getString());
|
||||||
mButtonMapping[i] = *it;
|
mButtonMapping[i] = *it;
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
@ -557,7 +557,7 @@ namespace MWGui
|
||||||
for (std::vector<short>::const_iterator it = knownEffects.begin(); it != knownEffects.end(); ++it)
|
for (std::vector<short>::const_iterator it = knownEffects.begin(); it != knownEffects.end(); ++it)
|
||||||
{
|
{
|
||||||
std::string name = MWBase::Environment::get().getWorld ()->getStore ().get<ESM::GameSetting>().find(
|
std::string name = MWBase::Environment::get().getWorld ()->getStore ().get<ESM::GameSetting>().find(
|
||||||
ESM::MagicEffect::effectIdToString (*it))->getString();
|
ESM::MagicEffect::effectIdToString (*it))->mValue.getString();
|
||||||
MyGUI::Widget* w = mAvailableEffectsList->getItemWidget(name);
|
MyGUI::Widget* w = mAvailableEffectsList->getItemWidget(name);
|
||||||
|
|
||||||
ToolTips::createMagicEffectToolTip (w, *it);
|
ToolTips::createMagicEffectToolTip (w, *it);
|
||||||
|
|
|
@ -75,7 +75,7 @@ namespace MWGui
|
||||||
|
|
||||||
std::string sourcesDescription;
|
std::string sourcesDescription;
|
||||||
|
|
||||||
static const float fadeTime = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fMagicStartIconBlink")->getFloat();
|
static const float fadeTime = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fMagicStartIconBlink")->mValue.getFloat();
|
||||||
|
|
||||||
for (std::vector<MagicEffectInfo>::const_iterator effectIt = it->second.begin();
|
for (std::vector<MagicEffectInfo>::const_iterator effectIt = it->second.begin();
|
||||||
effectIt != it->second.end(); ++effectIt)
|
effectIt != it->second.end(); ++effectIt)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "spellmodel.hpp"
|
#include "spellmodel.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <components/debug/debuglog.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
@ -94,7 +94,7 @@ namespace MWGui
|
||||||
const ESM::Enchantment* enchant = esmStore.get<ESM::Enchantment>().search(enchantId);
|
const ESM::Enchantment* enchant = esmStore.get<ESM::Enchantment>().search(enchantId);
|
||||||
if (!enchant)
|
if (!enchant)
|
||||||
{
|
{
|
||||||
std::cerr << "Warning: Can't find enchantment '" << enchantId << "' on item " << item.getCellRef().getRefId() << std::endl;
|
Log(Debug::Warning) << "Warning: Can't find enchantment '" << enchantId << "' on item " << item.getCellRef().getRefId();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ namespace MWGui
|
||||||
|
|
||||||
Spell()
|
Spell()
|
||||||
: mType(Type_Spell)
|
: mType(Type_Spell)
|
||||||
|
, mCount(0)
|
||||||
, mSelected(false)
|
, mSelected(false)
|
||||||
, mActive(false)
|
, mActive(false)
|
||||||
{
|
{
|
||||||
|
|
|
@ -86,6 +86,10 @@ namespace MWGui
|
||||||
mUpdateTimer = 0;
|
mUpdateTimer = 0;
|
||||||
mSpellView->incrementalUpdate();
|
mSpellView->incrementalUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update effects in-game too if the window is pinned
|
||||||
|
if (mPinned && !MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||||
|
mSpellIcons->updateWidgets(mEffectBox, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpellWindow::updateSpells()
|
void SpellWindow::updateSpells()
|
||||||
|
|
|
@ -61,7 +61,7 @@ namespace MWGui
|
||||||
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||||
for (int i=0; names[i][0]; ++i)
|
for (int i=0; names[i][0]; ++i)
|
||||||
{
|
{
|
||||||
setText (names[i][0], store.get<ESM::GameSetting>().find (names[i][1])->getString());
|
setText (names[i][0], store.get<ESM::GameSetting>().find (names[i][1])->mValue.getString());
|
||||||
}
|
}
|
||||||
|
|
||||||
getWidget(mSkillView, "SkillView");
|
getWidget(mSkillView, "SkillView");
|
||||||
|
@ -306,7 +306,7 @@ namespace MWGui
|
||||||
MyGUI::Widget* levelWidget;
|
MyGUI::Widget* levelWidget;
|
||||||
for (int i=0; i<2; ++i)
|
for (int i=0; i<2; ++i)
|
||||||
{
|
{
|
||||||
int max = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("iLevelUpTotal")->getInt();
|
int max = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("iLevelUpTotal")->mValue.getInteger();
|
||||||
getWidget(levelWidget, i==0 ? "Level_str" : "LevelText");
|
getWidget(levelWidget, i==0 ? "Level_str" : "LevelText");
|
||||||
levelWidget->setUserString("RangePosition_LevelProgress", MyGUI::utility::toString(PCstats.getLevelProgress()));
|
levelWidget->setUserString("RangePosition_LevelProgress", MyGUI::utility::toString(PCstats.getLevelProgress()));
|
||||||
levelWidget->setUserString("Range_LevelProgress", MyGUI::utility::toString(max));
|
levelWidget->setUserString("Range_LevelProgress", MyGUI::utility::toString(max));
|
||||||
|
|
|
@ -313,7 +313,7 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
if (MWBase::Environment::get().getMechanicsManager()->isItemStolenFrom(it->mBase.getCellRef().getRefId(), mPtr))
|
if (MWBase::Environment::get().getMechanicsManager()->isItemStolenFrom(it->mBase.getCellRef().getRefId(), mPtr))
|
||||||
{
|
{
|
||||||
std::string msg = gmst.find("sNotifyMessage49")->getString();
|
std::string msg = gmst.find("sNotifyMessage49")->mValue.getString();
|
||||||
if (msg.find("%s") != std::string::npos)
|
if (msg.find("%s") != std::string::npos)
|
||||||
msg.replace(msg.find("%s"), 2, it->mBase.getClass().getName(it->mBase));
|
msg.replace(msg.find("%s"), 2, it->mBase.getClass().getName(it->mBase));
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox(msg);
|
MWBase::Environment::get().getWindowManager()->messageBox(msg);
|
||||||
|
@ -331,10 +331,10 @@ namespace MWGui
|
||||||
// apply disposition change if merchant is NPC
|
// apply disposition change if merchant is NPC
|
||||||
if ( mPtr.getClass().isNpc() ) {
|
if ( mPtr.getClass().isNpc() ) {
|
||||||
int dispositionDelta = offerAccepted
|
int dispositionDelta = offerAccepted
|
||||||
? gmst.find("iBarterSuccessDisposition")->getInt()
|
? gmst.find("iBarterSuccessDisposition")->mValue.getInteger()
|
||||||
: gmst.find("iBarterFailDisposition")->getInt();
|
: gmst.find("iBarterFailDisposition")->mValue.getInteger();
|
||||||
|
|
||||||
MWBase::Environment::get().getDialogueManager()->applyDispositionChange(dispositionDelta);
|
MWBase::Environment::get().getDialogueManager()->applyBarterDispositionChange(dispositionDelta);
|
||||||
}
|
}
|
||||||
|
|
||||||
// display message on haggle failure
|
// display message on haggle failure
|
||||||
|
|
|
@ -98,7 +98,7 @@ namespace MWGui
|
||||||
for (int i=0; i<3; ++i)
|
for (int i=0; i<3; ++i)
|
||||||
{
|
{
|
||||||
int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer
|
int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer
|
||||||
(mPtr,pcStats.getSkill (skills[i].first).getBase() * gmst.find("iTrainingMod")->getInt (),true);
|
(mPtr,pcStats.getSkill (skills[i].first).getBase() * gmst.find("iTrainingMod")->mValue.getInteger(),true);
|
||||||
|
|
||||||
MyGUI::Button* button = mTrainingOptions->createWidget<MyGUI::Button>(price <= playerGold ? "SandTextButton" : "SandTextButtonDisabled", // can't use setEnabled since that removes tooltip
|
MyGUI::Button* button = mTrainingOptions->createWidget<MyGUI::Button>(price <= playerGold ? "SandTextButton" : "SandTextButtonDisabled", // can't use setEnabled since that removes tooltip
|
||||||
MyGUI::IntCoord(5, 5+i*18, mTrainingOptions->getWidth()-10, 18), MyGUI::Align::Default);
|
MyGUI::IntCoord(5, 5+i*18, mTrainingOptions->getWidth()-10, 18), MyGUI::Align::Default);
|
||||||
|
@ -136,7 +136,7 @@ namespace MWGui
|
||||||
const MWWorld::ESMStore &store =
|
const MWWorld::ESMStore &store =
|
||||||
MWBase::Environment::get().getWorld()->getStore();
|
MWBase::Environment::get().getWorld()->getStore();
|
||||||
|
|
||||||
int price = pcStats.getSkill (skillId).getBase() * store.get<ESM::GameSetting>().find("iTrainingMod")->getInt ();
|
int price = pcStats.getSkill (skillId).getBase() * store.get<ESM::GameSetting>().find("iTrainingMod")->mValue.getInteger();
|
||||||
price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true);
|
price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true);
|
||||||
|
|
||||||
if (price > player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId))
|
if (price > player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId))
|
||||||
|
|
|
@ -46,7 +46,7 @@ namespace MWGui
|
||||||
mSelect->getHeight());
|
mSelect->getHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
void TravelWindow::addDestination(const std::string& name,ESM::Position pos,bool interior)
|
void TravelWindow::addDestination(const std::string& name, ESM::Position pos, bool interior)
|
||||||
{
|
{
|
||||||
int price;
|
int price;
|
||||||
|
|
||||||
|
@ -56,15 +56,15 @@ namespace MWGui
|
||||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
|
||||||
int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId);
|
int playerGold = player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId);
|
||||||
|
|
||||||
if(interior)
|
if (!mPtr.getCell()->isExterior())
|
||||||
{
|
{
|
||||||
price = gmst.find("fMagesGuildTravel")->getInt();
|
price = gmst.find("fMagesGuildTravel")->mValue.getInteger();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ESM::Position PlayerPos = player.getRefData().getPosition();
|
ESM::Position PlayerPos = player.getRefData().getPosition();
|
||||||
float d = sqrt(pow(pos.pos[0] - PlayerPos.pos[0], 2) + pow(pos.pos[1] - PlayerPos.pos[1], 2) + pow(pos.pos[2] - PlayerPos.pos[2], 2));
|
float d = sqrt(pow(pos.pos[0] - PlayerPos.pos[0], 2) + pow(pos.pos[1] - PlayerPos.pos[1], 2) + pow(pos.pos[2] - PlayerPos.pos[2], 2));
|
||||||
price = static_cast<int>(d / gmst.find("fTravelMult")->getFloat());
|
price = static_cast<int>(d / gmst.find("fTravelMult")->mValue.getFloat());
|
||||||
}
|
}
|
||||||
|
|
||||||
price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, price, true);
|
price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, price, true);
|
||||||
|
@ -154,6 +154,10 @@ namespace MWGui
|
||||||
if (playerGold<price)
|
if (playerGold<price)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Set "traveling" flag, so GetPCTraveling can detect teleportation.
|
||||||
|
// We will reset this flag during next world update.
|
||||||
|
MWBase::Environment::get().getWorld()->setPlayerTraveling(true);
|
||||||
|
|
||||||
if (!mPtr.getCell()->isExterior())
|
if (!mPtr.getCell()->isExterior())
|
||||||
// Interior cell -> mages guild transport
|
// Interior cell -> mages guild transport
|
||||||
MWBase::Environment::get().getWindowManager()->playSound("mysticism cast");
|
MWBase::Environment::get().getWindowManager()->playSound("mysticism cast");
|
||||||
|
@ -168,11 +172,11 @@ namespace MWGui
|
||||||
ESM::Position pos = *_sender->getUserData<ESM::Position>();
|
ESM::Position pos = *_sender->getUserData<ESM::Position>();
|
||||||
std::string cellname = _sender->getUserString("Destination");
|
std::string cellname = _sender->getUserString("Destination");
|
||||||
bool interior = _sender->getUserString("interior") == "y";
|
bool interior = _sender->getUserString("interior") == "y";
|
||||||
if (!interior)
|
if (mPtr.getCell()->isExterior())
|
||||||
{
|
{
|
||||||
ESM::Position playerPos = player.getRefData().getPosition();
|
ESM::Position playerPos = player.getRefData().getPosition();
|
||||||
float d = (osg::Vec3f(pos.pos[0], pos.pos[1], 0) - osg::Vec3f(playerPos.pos[0], playerPos.pos[1], 0)).length();
|
float d = (osg::Vec3f(pos.pos[0], pos.pos[1], 0) - osg::Vec3f(playerPos.pos[0], playerPos.pos[1], 0)).length();
|
||||||
int hours = static_cast<int>(d /MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fTravelTimeMult")->getFloat());
|
int hours = static_cast<int>(d /MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fTravelTimeMult")->mValue.getFloat());
|
||||||
for(int i = 0;i < hours;i++)
|
for(int i = 0;i < hours;i++)
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getMechanicsManager ()->rest (true);
|
MWBase::Environment::get().getMechanicsManager ()->rest (true);
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <osg/Texture2D>
|
#include <osg/Texture2D>
|
||||||
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
#include <components/vfs/manager.hpp>
|
#include <components/vfs/manager.hpp>
|
||||||
#include <components/myguiplatform/myguitexture.hpp>
|
#include <components/myguiplatform/myguitexture.hpp>
|
||||||
|
|
||||||
|
@ -21,6 +22,8 @@ VideoWidget::VideoWidget()
|
||||||
setNeedKeyFocus(true);
|
setNeedKeyFocus(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VideoWidget::~VideoWidget() = default;
|
||||||
|
|
||||||
void VideoWidget::setVFS(const VFS::Manager *vfs)
|
void VideoWidget::setVFS(const VFS::Manager *vfs)
|
||||||
{
|
{
|
||||||
mVFS = vfs;
|
mVFS = vfs;
|
||||||
|
@ -37,7 +40,7 @@ void VideoWidget::playVideo(const std::string &video)
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
std::cerr << "Failed to open video: " << e.what() << std::endl;
|
Log(Debug::Error) << "Failed to open video: " << e.what();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,8 @@ namespace MWGui
|
||||||
MYGUI_RTTI_DERIVED(VideoWidget)
|
MYGUI_RTTI_DERIVED(VideoWidget)
|
||||||
|
|
||||||
VideoWidget();
|
VideoWidget();
|
||||||
|
|
||||||
|
~VideoWidget();
|
||||||
|
|
||||||
/// Set the VFS (virtual file system) to find the videos on.
|
/// Set the VFS (virtual file system) to find the videos on.
|
||||||
void setVFS(const VFS::Manager* vfs);
|
void setVFS(const VFS::Manager* vfs);
|
||||||
|
|
|
@ -183,10 +183,10 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
// figure out if player will be woken while sleeping
|
// figure out if player will be woken while sleeping
|
||||||
int x = Misc::Rng::rollDice(hoursToWait);
|
int x = Misc::Rng::rollDice(hoursToWait);
|
||||||
float fSleepRandMod = world->getStore().get<ESM::GameSetting>().find("fSleepRandMod")->getFloat();
|
float fSleepRandMod = world->getStore().get<ESM::GameSetting>().find("fSleepRandMod")->mValue.getFloat();
|
||||||
if (x < fSleepRandMod * hoursToWait)
|
if (x < fSleepRandMod * hoursToWait)
|
||||||
{
|
{
|
||||||
float fSleepRestMod = world->getStore().get<ESM::GameSetting>().find("fSleepRestMod")->getFloat();
|
float fSleepRestMod = world->getStore().get<ESM::GameSetting>().find("fSleepRestMod")->mValue.getFloat();
|
||||||
int interruptAtHoursRemaining = int(fSleepRestMod * hoursToWait);
|
int interruptAtHoursRemaining = int(fSleepRestMod * hoursToWait);
|
||||||
if (interruptAtHoursRemaining != 0)
|
if (interruptAtHoursRemaining != 0)
|
||||||
{
|
{
|
||||||
|
@ -252,7 +252,7 @@ namespace MWGui
|
||||||
// trigger levelup if possible
|
// trigger levelup if possible
|
||||||
const MWWorld::Store<ESM::GameSetting> &gmst =
|
const MWWorld::Store<ESM::GameSetting> &gmst =
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||||
if (mSleeping && pcstats.getLevelProgress () >= gmst.find("iLevelUpTotal")->getInt())
|
if (mSleeping && pcstats.getLevelProgress () >= gmst.find("iLevelUpTotal")->mValue.getInteger())
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getWindowManager()->pushGuiMode (GM_Levelup);
|
MWBase::Environment::get().getWindowManager()->pushGuiMode (GM_Levelup);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
#include <SDL_keyboard.h>
|
#include <SDL_keyboard.h>
|
||||||
#include <SDL_clipboard.h>
|
#include <SDL_clipboard.h>
|
||||||
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
|
|
||||||
#include <components/sdlutil/sdlcursormanager.hpp>
|
#include <components/sdlutil/sdlcursormanager.hpp>
|
||||||
|
|
||||||
#include <components/esm/esmreader.hpp>
|
#include <components/esm/esmreader.hpp>
|
||||||
|
@ -356,7 +358,7 @@ namespace MWGui
|
||||||
mGuiModeStates[GM_Journal].mCloseSound = "book close";
|
mGuiModeStates[GM_Journal].mCloseSound = "book close";
|
||||||
mGuiModeStates[GM_Journal].mOpenSound = "book open";
|
mGuiModeStates[GM_Journal].mOpenSound = "book open";
|
||||||
|
|
||||||
mMessageBoxManager = new MessageBoxManager(mStore->get<ESM::GameSetting>().find("fMessageTimePerChar")->getFloat());
|
mMessageBoxManager = new MessageBoxManager(mStore->get<ESM::GameSetting>().find("fMessageTimePerChar")->mValue.getFloat());
|
||||||
|
|
||||||
SpellBuyingWindow* spellBuyingWindow = new SpellBuyingWindow();
|
SpellBuyingWindow* spellBuyingWindow = new SpellBuyingWindow();
|
||||||
mWindows.push_back(spellBuyingWindow);
|
mWindows.push_back(spellBuyingWindow);
|
||||||
|
@ -898,7 +900,8 @@ namespace MWGui
|
||||||
|
|
||||||
mKeyboardNavigation->onFrame();
|
mKeyboardNavigation->onFrame();
|
||||||
|
|
||||||
mMessageBoxManager->onFrame(frameDuration);
|
if (mMessageBoxManager)
|
||||||
|
mMessageBoxManager->onFrame(frameDuration);
|
||||||
|
|
||||||
mToolTips->onFrame(frameDuration);
|
mToolTips->onFrame(frameDuration);
|
||||||
|
|
||||||
|
@ -1081,7 +1084,7 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
if (!mStore)
|
if (!mStore)
|
||||||
{
|
{
|
||||||
std::cerr << "Error: WindowManager::onRetrieveTag: no Store set up yet, can not replace '" << tag << "'" << std::endl;
|
Log(Debug::Error) << "Error: WindowManager::onRetrieveTag: no Store set up yet, can not replace '" << tag << "'";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const ESM::GameSetting *setting = mStore->get<ESM::GameSetting>().find(tag);
|
const ESM::GameSetting *setting = mStore->get<ESM::GameSetting>().find(tag);
|
||||||
|
@ -1787,7 +1790,7 @@ namespace MWGui
|
||||||
if (found != mCurrentModals.end())
|
if (found != mCurrentModals.end())
|
||||||
mCurrentModals.erase(found);
|
mCurrentModals.erase(found);
|
||||||
else
|
else
|
||||||
std::cerr << " warning: can't find modal window " << input << std::endl;
|
Log(Debug::Warning) << "Warning: can't find modal window " << input;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mCurrentModals.empty())
|
if (mCurrentModals.empty())
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
#include <SDL_version.h>
|
#include <SDL_version.h>
|
||||||
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
#include <components/sdlutil/sdlinputwrapper.hpp>
|
#include <components/sdlutil/sdlinputwrapper.hpp>
|
||||||
#include <components/sdlutil/sdlvideowrapper.hpp>
|
#include <components/sdlutil/sdlvideowrapper.hpp>
|
||||||
#include <components/esm/esmwriter.hpp>
|
#include <components/esm/esmwriter.hpp>
|
||||||
|
@ -120,11 +121,11 @@ namespace MWInput
|
||||||
SDL_ControllerDeviceEvent evt;
|
SDL_ControllerDeviceEvent evt;
|
||||||
evt.which = i;
|
evt.which = i;
|
||||||
controllerAdded(mFakeDeviceID, evt);
|
controllerAdded(mFakeDeviceID, evt);
|
||||||
std::cout << "Detected game controller: " << SDL_GameControllerNameForIndex(i) << std::endl;
|
Log(Debug::Info) << "Detected game controller: " << SDL_GameControllerNameForIndex(i);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::cout << "Detected unusable controller: " << SDL_JoystickNameForIndex(i) << std::endl;
|
Log(Debug::Info) << "Detected unusable controller: " << SDL_JoystickNameForIndex(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1003,9 +1004,9 @@ namespace MWInput
|
||||||
if (!mControlSwitch["playerfighting"] || !mControlSwitch["playercontrols"])
|
if (!mControlSwitch["playerfighting"] || !mControlSwitch["playercontrols"])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// We want to interrupt animation only if attack is prepairing, but still is not triggered
|
// We want to interrupt animation only if attack is preparing, but still is not triggered
|
||||||
// Otherwise we will get a "speedshooting" exploit, when player can skip reload animation by hitting "Toggle Weapon" key twice
|
// Otherwise we will get a "speedshooting" exploit, when player can skip reload animation by hitting "Toggle Weapon" key twice
|
||||||
if (MWBase::Environment::get().getMechanicsManager()->isAttackPrepairing(mPlayer->getPlayer()))
|
if (MWBase::Environment::get().getMechanicsManager()->isAttackPreparing(mPlayer->getPlayer()))
|
||||||
mPlayer->setAttackingOrSpell(false);
|
mPlayer->setAttackingOrSpell(false);
|
||||||
else if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(mPlayer->getPlayer()))
|
else if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(mPlayer->getPlayer()))
|
||||||
return;
|
return;
|
||||||
|
@ -1191,7 +1192,7 @@ namespace MWInput
|
||||||
void InputManager::updateIdleTime(float dt)
|
void InputManager::updateIdleTime(float dt)
|
||||||
{
|
{
|
||||||
static const float vanityDelay = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
static const float vanityDelay = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||||
.find("fVanityDelay")->getFloat();
|
.find("fVanityDelay")->mValue.getFloat();
|
||||||
if (mTimeIdle >= 0.f)
|
if (mTimeIdle >= 0.f)
|
||||||
mTimeIdle += dt;
|
mTimeIdle += dt;
|
||||||
if (mTimeIdle > vanityDelay) {
|
if (mTimeIdle > vanityDelay) {
|
||||||
|
|
|
@ -197,8 +197,14 @@ namespace MWMechanics
|
||||||
|
|
||||||
void ActiveSpells::removeEffects(const std::string &id)
|
void ActiveSpells::removeEffects(const std::string &id)
|
||||||
{
|
{
|
||||||
mSpells.erase(Misc::StringUtils::lowerCase(id));
|
for (TContainer::iterator spell = mSpells.begin(); spell != mSpells.end(); ++spell)
|
||||||
mSpellsChanged = true;
|
{
|
||||||
|
if (spell->first == id)
|
||||||
|
{
|
||||||
|
spell->second.mEffects.clear();
|
||||||
|
mSpellsChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActiveSpells::visitEffectSources(EffectSourceVisitor &visitor) const
|
void ActiveSpells::visitEffectSources(EffectSourceVisitor &visitor) const
|
||||||
|
|
|
@ -2,13 +2,12 @@
|
||||||
|
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include <components/esm/esmreader.hpp>
|
#include <components/esm/esmreader.hpp>
|
||||||
#include <components/esm/esmwriter.hpp>
|
#include <components/esm/esmwriter.hpp>
|
||||||
#include <components/esm/loadnpc.hpp>
|
#include <components/esm/loadnpc.hpp>
|
||||||
|
|
||||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
@ -55,22 +54,22 @@ int getBoundItemSlot (const std::string& itemId)
|
||||||
static std::map<std::string, int> boundItemsMap;
|
static std::map<std::string, int> boundItemsMap;
|
||||||
if (boundItemsMap.empty())
|
if (boundItemsMap.empty())
|
||||||
{
|
{
|
||||||
std::string boundId = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sMagicBoundBootsID")->getString();
|
std::string boundId = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sMagicBoundBootsID")->mValue.getString();
|
||||||
boundItemsMap[boundId] = MWWorld::InventoryStore::Slot_Boots;
|
boundItemsMap[boundId] = MWWorld::InventoryStore::Slot_Boots;
|
||||||
|
|
||||||
boundId = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sMagicBoundCuirassID")->getString();
|
boundId = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sMagicBoundCuirassID")->mValue.getString();
|
||||||
boundItemsMap[boundId] = MWWorld::InventoryStore::Slot_Cuirass;
|
boundItemsMap[boundId] = MWWorld::InventoryStore::Slot_Cuirass;
|
||||||
|
|
||||||
boundId = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sMagicBoundLeftGauntletID")->getString();
|
boundId = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sMagicBoundLeftGauntletID")->mValue.getString();
|
||||||
boundItemsMap[boundId] = MWWorld::InventoryStore::Slot_LeftGauntlet;
|
boundItemsMap[boundId] = MWWorld::InventoryStore::Slot_LeftGauntlet;
|
||||||
|
|
||||||
boundId = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sMagicBoundRightGauntletID")->getString();
|
boundId = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sMagicBoundRightGauntletID")->mValue.getString();
|
||||||
boundItemsMap[boundId] = MWWorld::InventoryStore::Slot_RightGauntlet;
|
boundItemsMap[boundId] = MWWorld::InventoryStore::Slot_RightGauntlet;
|
||||||
|
|
||||||
boundId = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sMagicBoundHelmID")->getString();
|
boundId = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sMagicBoundHelmID")->mValue.getString();
|
||||||
boundItemsMap[boundId] = MWWorld::InventoryStore::Slot_Helmet;
|
boundItemsMap[boundId] = MWWorld::InventoryStore::Slot_Helmet;
|
||||||
|
|
||||||
boundId = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sMagicBoundShieldID")->getString();
|
boundId = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("sMagicBoundShieldID")->mValue.getString();
|
||||||
boundItemsMap[boundId] = MWWorld::InventoryStore::Slot_CarriedLeft;
|
boundItemsMap[boundId] = MWWorld::InventoryStore::Slot_CarriedLeft;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +138,7 @@ void getRestorationPerHourOfSleep (const MWWorld::Ptr& ptr, float& health, float
|
||||||
magicka = 0;
|
magicka = 0;
|
||||||
if (!stunted)
|
if (!stunted)
|
||||||
{
|
{
|
||||||
float fRestMagicMult = settings.find("fRestMagicMult")->getFloat ();
|
float fRestMagicMult = settings.find("fRestMagicMult")->mValue.getFloat ();
|
||||||
magicka = fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified();
|
magicka = fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,7 +179,7 @@ namespace MWMechanics
|
||||||
if (caster.isEmpty() || !caster.getClass().isActor())
|
if (caster.isEmpty() || !caster.getClass().isActor())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
static const float fSoulgemMult = world->getStore().get<ESM::GameSetting>().find("fSoulgemMult")->getFloat();
|
static const float fSoulgemMult = world->getStore().get<ESM::GameSetting>().find("fSoulgemMult")->mValue.getFloat();
|
||||||
|
|
||||||
int creatureSoulValue = mCreature.get<ESM::Creature>()->mBase->mData.mSoul;
|
int creatureSoulValue = mCreature.get<ESM::Creature>()->mBase->mData.mSoul;
|
||||||
if (creatureSoulValue == 0)
|
if (creatureSoulValue == 0)
|
||||||
|
@ -314,9 +313,9 @@ namespace MWMechanics
|
||||||
MWWorld::Ptr& headTrackTarget, float& sqrHeadTrackDistance)
|
MWWorld::Ptr& headTrackTarget, float& sqrHeadTrackDistance)
|
||||||
{
|
{
|
||||||
static const float fMaxHeadTrackDistance = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
static const float fMaxHeadTrackDistance = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||||
.find("fMaxHeadTrackDistance")->getFloat();
|
.find("fMaxHeadTrackDistance")->mValue.getFloat();
|
||||||
static const float fInteriorHeadTrackMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
static const float fInteriorHeadTrackMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||||
.find("fInteriorHeadTrackMult")->getFloat();
|
.find("fInteriorHeadTrackMult")->mValue.getFloat();
|
||||||
float maxDistance = fMaxHeadTrackDistance;
|
float maxDistance = fMaxHeadTrackDistance;
|
||||||
const ESM::Cell* currentCell = actor.getCell()->getCell();
|
const ESM::Cell* currentCell = actor.getCell()->getCell();
|
||||||
if (!currentCell->isExterior() && !(currentCell->mData.mFlags & ESM::Cell::QuasiEx))
|
if (!currentCell->isExterior() && !(currentCell->mData.mFlags & ESM::Cell::QuasiEx))
|
||||||
|
@ -404,7 +403,7 @@ namespace MWMechanics
|
||||||
std::set<MWWorld::Ptr> playerAllies;
|
std::set<MWWorld::Ptr> playerAllies;
|
||||||
getActorsSidingWith(MWMechanics::getPlayer(), playerAllies, cachedAllies);
|
getActorsSidingWith(MWMechanics::getPlayer(), playerAllies, cachedAllies);
|
||||||
|
|
||||||
bool isPlayerFollowerOrEscorter = std::find(playerAllies.begin(), playerAllies.end(), actor1) != playerAllies.end();
|
bool isPlayerFollowerOrEscorter = playerAllies.find(actor1) != playerAllies.end();
|
||||||
|
|
||||||
// If actor2 and at least one actor2 are in combat with actor1, actor1 and its allies start combat with them
|
// If actor2 and at least one actor2 are in combat with actor1, actor1 and its allies start combat with them
|
||||||
// Doesn't apply for player followers/escorters
|
// Doesn't apply for player followers/escorters
|
||||||
|
@ -458,7 +457,7 @@ namespace MWMechanics
|
||||||
// Do aggression check if actor2 is the player or a player follower or escorter
|
// Do aggression check if actor2 is the player or a player follower or escorter
|
||||||
if (!aggressive)
|
if (!aggressive)
|
||||||
{
|
{
|
||||||
if (againstPlayer || std::find(playerAllies.begin(), playerAllies.end(), actor2) != playerAllies.end())
|
if (againstPlayer || playerAllies.find(actor2) != playerAllies.end())
|
||||||
{
|
{
|
||||||
// Player followers and escorters with high fight should not initiate combat with the player or with
|
// Player followers and escorters with high fight should not initiate combat with the player or with
|
||||||
// other player followers or escorters
|
// other player followers or escorters
|
||||||
|
@ -471,7 +470,7 @@ namespace MWMechanics
|
||||||
if (actor1.getClass().isClass(actor1, "Guard") && !actor2.getClass().isNpc())
|
if (actor1.getClass().isClass(actor1, "Guard") && !actor2.getClass().isNpc())
|
||||||
{
|
{
|
||||||
// Check if the creature is too far
|
// Check if the creature is too far
|
||||||
static const float fAlarmRadius = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fAlarmRadius")->getFloat();
|
static const float fAlarmRadius = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fAlarmRadius")->mValue.getFloat();
|
||||||
if (sqrDist > fAlarmRadius * fAlarmRadius)
|
if (sqrDist > fAlarmRadius * fAlarmRadius)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -535,9 +534,9 @@ namespace MWMechanics
|
||||||
|
|
||||||
float base = 1.f;
|
float base = 1.f;
|
||||||
if (ptr == getPlayer())
|
if (ptr == getPlayer())
|
||||||
base = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fPCbaseMagickaMult")->getFloat();
|
base = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fPCbaseMagickaMult")->mValue.getFloat();
|
||||||
else
|
else
|
||||||
base = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fNPCbaseMagickaMult")->getFloat();
|
base = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fNPCbaseMagickaMult")->mValue.getFloat();
|
||||||
|
|
||||||
double magickaFactor = base +
|
double magickaFactor = base +
|
||||||
creatureStats.getMagicEffects().get (EffectKey (ESM::MagicEffect::FortifyMaximumMagicka)).getMagnitude() * 0.1;
|
creatureStats.getMagicEffects().get (EffectKey (ESM::MagicEffect::FortifyMaximumMagicka)).getMagnitude() * 0.1;
|
||||||
|
@ -546,7 +545,7 @@ namespace MWMechanics
|
||||||
float diff = (static_cast<int>(magickaFactor*intelligence)) - magicka.getBase();
|
float diff = (static_cast<int>(magickaFactor*intelligence)) - magicka.getBase();
|
||||||
float currentToBaseRatio = (magicka.getCurrent() / magicka.getBase());
|
float currentToBaseRatio = (magicka.getCurrent() / magicka.getBase());
|
||||||
magicka.setModified(magicka.getModified() + diff, 0);
|
magicka.setModified(magicka.getModified() + diff, 0);
|
||||||
magicka.setCurrent(magicka.getBase() * currentToBaseRatio);
|
magicka.setCurrent(magicka.getBase() * currentToBaseRatio, false, true);
|
||||||
creatureStats.setMagicka(magicka);
|
creatureStats.setMagicka(magicka);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -577,16 +576,21 @@ namespace MWMechanics
|
||||||
float normalizedEncumbrance = ptr.getClass().getNormalizedEncumbrance(ptr);
|
float normalizedEncumbrance = ptr.getClass().getNormalizedEncumbrance(ptr);
|
||||||
if (normalizedEncumbrance > 1)
|
if (normalizedEncumbrance > 1)
|
||||||
normalizedEncumbrance = 1;
|
normalizedEncumbrance = 1;
|
||||||
|
|
||||||
|
// Current fatigue can be above base value due to a fortify effect.
|
||||||
|
// In that case stop here and don't try to restore.
|
||||||
|
DynamicStat<float> fatigue = stats.getFatigue();
|
||||||
|
if (fatigue.getCurrent() >= fatigue.getBase())
|
||||||
|
return;
|
||||||
|
|
||||||
// restore fatigue
|
// Restore fatigue
|
||||||
float fFatigueReturnBase = settings.find("fFatigueReturnBase")->getFloat ();
|
float fFatigueReturnBase = settings.find("fFatigueReturnBase")->mValue.getFloat ();
|
||||||
float fFatigueReturnMult = settings.find("fFatigueReturnMult")->getFloat ();
|
float fFatigueReturnMult = settings.find("fFatigueReturnMult")->mValue.getFloat ();
|
||||||
float fEndFatigueMult = settings.find("fEndFatigueMult")->getFloat ();
|
float fEndFatigueMult = settings.find("fEndFatigueMult")->mValue.getFloat ();
|
||||||
|
|
||||||
float x = fFatigueReturnBase + fFatigueReturnMult * (1 - normalizedEncumbrance);
|
float x = fFatigueReturnBase + fFatigueReturnMult * (1 - normalizedEncumbrance);
|
||||||
x *= fEndFatigueMult * endurance;
|
x *= fEndFatigueMult * endurance;
|
||||||
|
|
||||||
DynamicStat<float> fatigue = stats.getFatigue();
|
|
||||||
fatigue.setCurrent (fatigue.getCurrent() + 3600 * x);
|
fatigue.setCurrent (fatigue.getCurrent() + 3600 * x);
|
||||||
stats.setFatigue (fatigue);
|
stats.setFatigue (fatigue);
|
||||||
}
|
}
|
||||||
|
@ -598,16 +602,20 @@ namespace MWMechanics
|
||||||
|
|
||||||
MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats (ptr);
|
MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats (ptr);
|
||||||
|
|
||||||
int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified ();
|
// Current fatigue can be above base value due to a fortify effect.
|
||||||
|
// In that case stop here and don't try to restore.
|
||||||
|
DynamicStat<float> fatigue = stats.getFatigue();
|
||||||
|
if (fatigue.getCurrent() >= fatigue.getBase())
|
||||||
|
return;
|
||||||
|
|
||||||
// restore fatigue
|
// Restore fatigue
|
||||||
|
int 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")->getFloat ();
|
static const float fFatigueReturnBase = settings.find("fFatigueReturnBase")->mValue.getFloat ();
|
||||||
static const float fFatigueReturnMult = settings.find("fFatigueReturnMult")->getFloat ();
|
static const float fFatigueReturnMult = settings.find("fFatigueReturnMult")->mValue.getFloat ();
|
||||||
|
|
||||||
float x = fFatigueReturnBase + fFatigueReturnMult * endurance;
|
float x = fFatigueReturnBase + fFatigueReturnMult * endurance;
|
||||||
|
|
||||||
DynamicStat<float> fatigue = stats.getFatigue();
|
|
||||||
fatigue.setCurrent (fatigue.getCurrent() + duration * x);
|
fatigue.setCurrent (fatigue.getCurrent() + duration * x);
|
||||||
stats.setFatigue (fatigue);
|
stats.setFatigue (fatigue);
|
||||||
}
|
}
|
||||||
|
@ -688,6 +696,19 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dynamic stats
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
{
|
||||||
|
DynamicStat<float> stat = creatureStats.getDynamic(i);
|
||||||
|
stat.setCurrentModifier(effects.get(ESM::MagicEffect::FortifyHealth + i).getMagnitude() -
|
||||||
|
effects.get(ESM::MagicEffect::DrainHealth + i).getMagnitude(),
|
||||||
|
// Magicka can be decreased below zero due to a fortify effect wearing off
|
||||||
|
// Fatigue can be decreased below zero meaning the actor will be knocked out
|
||||||
|
i == 1 || i == 2);
|
||||||
|
|
||||||
|
creatureStats.setDynamic(i, stat);
|
||||||
|
}
|
||||||
|
|
||||||
// attributes
|
// attributes
|
||||||
for(int i = 0;i < ESM::Attribute::Length;++i)
|
for(int i = 0;i < ESM::Attribute::Length;++i)
|
||||||
{
|
{
|
||||||
|
@ -719,19 +740,6 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// dynamic stats
|
|
||||||
for(int i = 0;i < 3;++i)
|
|
||||||
{
|
|
||||||
DynamicStat<float> stat = creatureStats.getDynamic(i);
|
|
||||||
stat.setModifier(effects.get(ESM::MagicEffect::FortifyHealth+i).getMagnitude() -
|
|
||||||
effects.get(ESM::MagicEffect::DrainHealth+i).getMagnitude(),
|
|
||||||
// Magicka can be decreased below zero due to a fortify effect wearing off
|
|
||||||
// Fatigue can be decreased below zero meaning the actor will be knocked out
|
|
||||||
i == 1 || i == 2);
|
|
||||||
|
|
||||||
creatureStats.setDynamic(i, stat);
|
|
||||||
}
|
|
||||||
|
|
||||||
// AI setting modifiers
|
// AI setting modifiers
|
||||||
int creature = !ptr.getClass().isNpc();
|
int creature = !ptr.getClass().isNpc();
|
||||||
if (creature && ptr.get<ESM::Creature>()->mBase->mData.mType == ESM::Creature::Humanoid)
|
if (creature && ptr.get<ESM::Creature>()->mBase->mData.mType == ESM::Creature::Humanoid)
|
||||||
|
@ -845,14 +853,14 @@ namespace MWMechanics
|
||||||
|
|
||||||
std::string itemGmst = it->second;
|
std::string itemGmst = it->second;
|
||||||
std::string item = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
|
std::string item = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
|
||||||
itemGmst)->getString();
|
itemGmst)->mValue.getString();
|
||||||
|
|
||||||
magnitude > 0 ? addBoundItem(item, ptr) : removeBoundItem(item, ptr);
|
magnitude > 0 ? addBoundItem(item, ptr) : removeBoundItem(item, ptr);
|
||||||
|
|
||||||
if (it->first == ESM::MagicEffect::BoundGloves)
|
if (it->first == ESM::MagicEffect::BoundGloves)
|
||||||
{
|
{
|
||||||
item = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
|
item = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
|
||||||
"sMagicBoundRightGauntletID")->getString();
|
"sMagicBoundRightGauntletID")->mValue.getString();
|
||||||
magnitude > 0 ? addBoundItem(item, ptr) : removeBoundItem(item, ptr);
|
magnitude > 0 ? addBoundItem(item, ptr) : removeBoundItem(item, ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -888,14 +896,14 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Actors::isAttackPrepairing(const MWWorld::Ptr& ptr)
|
bool Actors::isAttackPreparing(const MWWorld::Ptr& ptr)
|
||||||
{
|
{
|
||||||
PtrActorMap::iterator it = mActors.find(ptr);
|
PtrActorMap::iterator it = mActors.find(ptr);
|
||||||
if (it == mActors.end())
|
if (it == mActors.end())
|
||||||
return false;
|
return false;
|
||||||
CharacterController* ctrl = it->second->getCharacterController();
|
CharacterController* ctrl = it->second->getCharacterController();
|
||||||
|
|
||||||
return ctrl->isAttackPrepairing();
|
return ctrl->isAttackPreparing();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Actors::isRunning(const MWWorld::Ptr& ptr)
|
bool Actors::isRunning(const MWWorld::Ptr& ptr)
|
||||||
|
@ -928,7 +936,7 @@ namespace MWMechanics
|
||||||
NpcStats &stats = ptr.getClass().getNpcStats(ptr);
|
NpcStats &stats = ptr.getClass().getNpcStats(ptr);
|
||||||
|
|
||||||
// When npc stats are just initialized, mTimeToStartDrowning == -1 and we should get value from GMST
|
// When npc stats are just initialized, mTimeToStartDrowning == -1 and we should get value from GMST
|
||||||
static const float fHoldBreathTime = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fHoldBreathTime")->getFloat();
|
static const float fHoldBreathTime = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fHoldBreathTime")->mValue.getFloat();
|
||||||
if (stats.getTimeToStartDrowning() == -1.f)
|
if (stats.getTimeToStartDrowning() == -1.f)
|
||||||
stats.setTimeToStartDrowning(fHoldBreathTime);
|
stats.setTimeToStartDrowning(fHoldBreathTime);
|
||||||
|
|
||||||
|
@ -962,7 +970,7 @@ namespace MWMechanics
|
||||||
if(timeLeft == 0.0f && !godmode)
|
if(timeLeft == 0.0f && !godmode)
|
||||||
{
|
{
|
||||||
// If drowning, apply 3 points of damage per second
|
// If drowning, apply 3 points of damage per second
|
||||||
static const float fSuffocationDamage = world->getStore().get<ESM::GameSetting>().find("fSuffocationDamage")->getFloat();
|
static const float fSuffocationDamage = world->getStore().get<ESM::GameSetting>().find("fSuffocationDamage")->mValue.getFloat();
|
||||||
DynamicStat<float> health = stats.getHealth();
|
DynamicStat<float> health = stats.getHealth();
|
||||||
health.setCurrent(health.getCurrent() - fSuffocationDamage*duration);
|
health.setCurrent(health.getCurrent() - fSuffocationDamage*duration);
|
||||||
stats.setHealth(health);
|
stats.setHealth(health);
|
||||||
|
@ -1088,7 +1096,7 @@ namespace MWMechanics
|
||||||
&& creatureStats.getMagicEffects().get(ESM::MagicEffect::CalmHumanoid).getMagnitude() == 0)
|
&& creatureStats.getMagicEffects().get(ESM::MagicEffect::CalmHumanoid).getMagnitude() == 0)
|
||||||
{
|
{
|
||||||
const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore();
|
const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore();
|
||||||
static const int cutoff = esmStore.get<ESM::GameSetting>().find("iCrimeThreshold")->getInt();
|
static const int cutoff = esmStore.get<ESM::GameSetting>().find("iCrimeThreshold")->mValue.getInteger();
|
||||||
// Force dialogue on sight if bounty is greater than the cutoff
|
// Force dialogue on sight if bounty is greater than the cutoff
|
||||||
// In vanilla morrowind, the greeting dialogue is scripted to either arrest the player (< 5000 bounty) or attack (>= 5000 bounty)
|
// In vanilla morrowind, the greeting dialogue is scripted to either arrest the player (< 5000 bounty) or attack (>= 5000 bounty)
|
||||||
if ( player.getClass().getNpcStats(player).getBounty() >= cutoff
|
if ( player.getClass().getNpcStats(player).getBounty() >= cutoff
|
||||||
|
@ -1096,7 +1104,7 @@ namespace MWMechanics
|
||||||
&& MWBase::Environment::get().getWorld()->getLOS(ptr, player)
|
&& MWBase::Environment::get().getWorld()->getLOS(ptr, player)
|
||||||
&& MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, ptr))
|
&& MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, ptr))
|
||||||
{
|
{
|
||||||
static const int iCrimeThresholdMultiplier = esmStore.get<ESM::GameSetting>().find("iCrimeThresholdMultiplier")->getInt();
|
static const int iCrimeThresholdMultiplier = esmStore.get<ESM::GameSetting>().find("iCrimeThresholdMultiplier")->mValue.getInteger();
|
||||||
if (player.getClass().getNpcStats(player).getBounty() >= cutoff * iCrimeThresholdMultiplier)
|
if (player.getClass().getNpcStats(player).getBounty() >= cutoff * iCrimeThresholdMultiplier)
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getMechanicsManager()->startCombat(ptr, player);
|
MWBase::Environment::get().getMechanicsManager()->startCombat(ptr, player);
|
||||||
|
@ -1298,6 +1306,8 @@ namespace MWMechanics
|
||||||
// AI and magic effects update
|
// AI and magic effects update
|
||||||
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
||||||
{
|
{
|
||||||
|
bool isPlayer = iter->first == player;
|
||||||
|
|
||||||
float distSqr = (player.getRefData().getPosition().asVec3() - iter->first.getRefData().getPosition().asVec3()).length2();
|
float distSqr = (player.getRefData().getPosition().asVec3() - iter->first.getRefData().getPosition().asVec3()).length2();
|
||||||
// AI processing is only done within distance of 7168 units to the player. Note the "AI distance" slider doesn't affect this
|
// AI processing is only done within distance of 7168 units to the player. Note the "AI distance" slider doesn't affect this
|
||||||
// (it only does some throttling for targets beyond the "AI distance", so doesn't give any guarantees as to whether AI will be enabled or not)
|
// (it only does some throttling for targets beyond the "AI distance", so doesn't give any guarantees as to whether AI will be enabled or not)
|
||||||
|
@ -1305,7 +1315,7 @@ namespace MWMechanics
|
||||||
// using higher values will make a quest in Bloodmoon harder or impossible to complete (bug #1876)
|
// using higher values will make a quest in Bloodmoon harder or impossible to complete (bug #1876)
|
||||||
bool inProcessingRange = distSqr <= sqrAiProcessingDistance;
|
bool inProcessingRange = distSqr <= sqrAiProcessingDistance;
|
||||||
|
|
||||||
if (iter->first == player)
|
if (isPlayer)
|
||||||
iter->second->getCharacterController()->setAttackingOrSpell(MWBase::Environment::get().getWorld()->getPlayer().getAttackingOrSpell());
|
iter->second->getCharacterController()->setAttackingOrSpell(MWBase::Environment::get().getWorld()->getPlayer().getAttackingOrSpell());
|
||||||
|
|
||||||
// If dead or no longer in combat, no longer store any actors who attempted to hit us. Also remove for the player.
|
// If dead or no longer in combat, no longer store any actors who attempted to hit us. Also remove for the player.
|
||||||
|
@ -1337,12 +1347,12 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
if (timerUpdateAITargets == 0)
|
if (timerUpdateAITargets == 0)
|
||||||
{
|
{
|
||||||
if (iter->first != player)
|
if (!isPlayer)
|
||||||
adjustCommandedActor(iter->first);
|
adjustCommandedActor(iter->first);
|
||||||
|
|
||||||
for(PtrActorMap::iterator it(mActors.begin()); it != mActors.end(); ++it)
|
for(PtrActorMap::iterator it(mActors.begin()); it != mActors.end(); ++it)
|
||||||
{
|
{
|
||||||
if (it->first == iter->first || iter->first == player) // player is not AI-controlled
|
if (it->first == iter->first || isPlayer) // player is not AI-controlled
|
||||||
continue;
|
continue;
|
||||||
engageCombat(iter->first, it->first, cachedAllies, it->first == player);
|
engageCombat(iter->first, it->first, cachedAllies, it->first == player);
|
||||||
}
|
}
|
||||||
|
@ -1353,12 +1363,15 @@ namespace MWMechanics
|
||||||
MWWorld::Ptr headTrackTarget;
|
MWWorld::Ptr headTrackTarget;
|
||||||
|
|
||||||
MWMechanics::CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first);
|
MWMechanics::CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first);
|
||||||
|
bool firstPersonPlayer = isPlayer && MWBase::Environment::get().getWorld()->isFirstPerson();
|
||||||
|
|
||||||
// Unconsious actor can not track target
|
// 1. Unconsious actor can not track target
|
||||||
// Also actors in combat and pursue mode do not bother to headtrack
|
// 2. Actors in combat and pursue mode do not bother to headtrack
|
||||||
|
// 3. Player character does not use headtracking in the 1st-person view
|
||||||
if (!stats.getKnockedDown() &&
|
if (!stats.getKnockedDown() &&
|
||||||
!stats.getAiSequence().isInCombat() &&
|
!stats.getAiSequence().isInCombat() &&
|
||||||
!stats.getAiSequence().hasPackage(AiPackage::TypeIdPursue))
|
!stats.getAiSequence().hasPackage(AiPackage::TypeIdPursue) &&
|
||||||
|
!firstPersonPlayer)
|
||||||
{
|
{
|
||||||
for(PtrActorMap::iterator it(mActors.begin()); it != mActors.end(); ++it)
|
for(PtrActorMap::iterator it(mActors.begin()); it != mActors.end(); ++it)
|
||||||
{
|
{
|
||||||
|
@ -1474,9 +1487,9 @@ namespace MWMechanics
|
||||||
static float sneakSkillTimer = 0.f; // times sneak skill progress from "avoid notice"
|
static float sneakSkillTimer = 0.f; // times sneak skill progress from "avoid notice"
|
||||||
|
|
||||||
const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore();
|
const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore();
|
||||||
const int radius = esmStore.get<ESM::GameSetting>().find("fSneakUseDist")->getInt();
|
const int radius = esmStore.get<ESM::GameSetting>().find("fSneakUseDist")->mValue.getInteger();
|
||||||
|
|
||||||
static float fSneakUseDelay = esmStore.get<ESM::GameSetting>().find("fSneakUseDelay")->getFloat();
|
static float fSneakUseDelay = esmStore.get<ESM::GameSetting>().find("fSneakUseDelay")->mValue.getFloat();
|
||||||
|
|
||||||
if (sneakTimer >= fSneakUseDelay)
|
if (sneakTimer >= fSneakUseDelay)
|
||||||
sneakTimer = 0.f;
|
sneakTimer = 0.f;
|
||||||
|
@ -1666,7 +1679,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(iter->first);
|
MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(iter->first);
|
||||||
if (animation)
|
if (animation)
|
||||||
animation->updateEffects(duration);
|
animation->updateEffects();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1715,7 +1728,7 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::cerr<< "Warning: Actors::playAnimationGroup: Unable to find " << ptr.getCellRef().getRefId() << std::endl;
|
Log(Debug::Warning) << "Warning: Actors::playAnimationGroup: Unable to find " << ptr.getCellRef().getRefId();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1763,38 +1776,36 @@ namespace MWMechanics
|
||||||
std::list<MWWorld::Ptr> Actors::getActorsSidingWith(const MWWorld::Ptr& actor)
|
std::list<MWWorld::Ptr> Actors::getActorsSidingWith(const MWWorld::Ptr& actor)
|
||||||
{
|
{
|
||||||
std::list<MWWorld::Ptr> list;
|
std::list<MWWorld::Ptr> list;
|
||||||
for(PtrActorMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
for(PtrActorMap::iterator iter = mActors.begin(); iter != mActors.end(); ++iter)
|
||||||
{
|
{
|
||||||
const MWWorld::Class &cls = iter->first.getClass();
|
const MWWorld::Ptr &iteratedActor = iter->first;
|
||||||
const CreatureStats &stats = cls.getCreatureStats(iter->first);
|
if (iteratedActor == getPlayer())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const bool sameActor = (iteratedActor == actor);
|
||||||
|
|
||||||
|
const CreatureStats &stats = iteratedActor.getClass().getCreatureStats(iteratedActor);
|
||||||
if (stats.isDead())
|
if (stats.isDead())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// An actor counts as siding with this actor if Follow or Escort is the current AI package, or there are only Combat packages before the Follow/Escort package
|
// An actor counts as siding with this actor if Follow or Escort is the current AI package, or there are only Combat and Wander packages before the Follow/Escort package
|
||||||
for (std::list<MWMechanics::AiPackage*>::const_iterator it = stats.getAiSequence().begin(); it != stats.getAiSequence().end(); ++it)
|
|
||||||
{
|
|
||||||
if ((*it)->sideWithTarget() && (*it)->getTarget() == actor)
|
|
||||||
{
|
|
||||||
list.push_back(iter->first);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if ((*it)->getTypeId() != MWMechanics::AiPackage::TypeIdCombat)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Actors that are targeted by this actor's Follow or Escort packages also side with them
|
// Actors that are targeted by this actor's Follow or Escort packages also side with them
|
||||||
if (actor != getPlayer())
|
for (auto package = stats.getAiSequence().begin(); package != stats.getAiSequence().end(); ++package)
|
||||||
{
|
{
|
||||||
const CreatureStats &stats2 = actor.getClass().getCreatureStats(actor);
|
if ((*package)->sideWithTarget() && !(*package)->getTarget().isEmpty())
|
||||||
for (std::list<MWMechanics::AiPackage*>::const_iterator it2 = stats2.getAiSequence().begin(); it2 != stats2.getAiSequence().end(); ++it2)
|
|
||||||
{
|
{
|
||||||
if ((*it2)->sideWithTarget() && !(*it2)->getTarget().isEmpty())
|
if (sameActor)
|
||||||
{
|
{
|
||||||
list.push_back((*it2)->getTarget());
|
list.push_back((*package)->getTarget());
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
else if ((*it2)->getTypeId() != MWMechanics::AiPackage::TypeIdCombat)
|
else if ((*package)->getTarget() == actor)
|
||||||
break;
|
{
|
||||||
|
list.push_back(iteratedActor);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
else if ((*package)->getTypeId() != AiPackage::TypeIdCombat && (*package)->getTypeId() != AiPackage::TypeIdWander)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
|
@ -1805,17 +1816,21 @@ namespace MWMechanics
|
||||||
std::list<MWWorld::Ptr> list;
|
std::list<MWWorld::Ptr> list;
|
||||||
for(PtrActorMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
for(PtrActorMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
||||||
{
|
{
|
||||||
const MWWorld::Class &cls = iter->first.getClass();
|
const MWWorld::Ptr &iteratedActor = iter->first;
|
||||||
CreatureStats &stats = cls.getCreatureStats(iter->first);
|
if (iteratedActor == getPlayer() || iteratedActor == actor)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const CreatureStats &stats = iteratedActor.getClass().getCreatureStats(iteratedActor);
|
||||||
if (stats.isDead())
|
if (stats.isDead())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// An actor counts as following if AiFollow is the current AiPackage, or there are only Combat packages before the AiFollow package
|
// An actor counts as following if AiFollow is the current AiPackage,
|
||||||
for (std::list<MWMechanics::AiPackage*>::const_iterator it = stats.getAiSequence().begin(); it != stats.getAiSequence().end(); ++it)
|
// or there are only Combat and Wander packages before the AiFollow package
|
||||||
|
for (auto package = stats.getAiSequence().begin(); package != stats.getAiSequence().end(); ++package)
|
||||||
{
|
{
|
||||||
if ((*it)->followTargetThroughDoors() && (*it)->getTarget() == actor)
|
if ((*package)->followTargetThroughDoors() && (*package)->getTarget() == actor)
|
||||||
list.push_back(iter->first);
|
list.push_back(iteratedActor);
|
||||||
else if ((*it)->getTypeId() != MWMechanics::AiPackage::TypeIdCombat)
|
else if ((*package)->getTypeId() != AiPackage::TypeIdCombat && (*package)->getTypeId() != AiPackage::TypeIdWander)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1864,24 +1879,24 @@ namespace MWMechanics
|
||||||
std::list<int> list;
|
std::list<int> list;
|
||||||
for(PtrActorMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
for(PtrActorMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
|
||||||
{
|
{
|
||||||
const MWWorld::Class &cls = iter->first.getClass();
|
const MWWorld::Ptr &iteratedActor = iter->first;
|
||||||
CreatureStats &stats = cls.getCreatureStats(iter->first);
|
if (iteratedActor == getPlayer() || iteratedActor == actor)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const CreatureStats &stats = iteratedActor.getClass().getCreatureStats(iteratedActor);
|
||||||
if (stats.isDead())
|
if (stats.isDead())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// An actor counts as following if AiFollow is the current AiPackage, or there are only Combat packages before the AiFollow package
|
// An actor counts as following if AiFollow is the current AiPackage,
|
||||||
for (std::list<MWMechanics::AiPackage*>::const_iterator it = stats.getAiSequence().begin(); it != stats.getAiSequence().end(); ++it)
|
// or there are only Combat and Wander packages before the AiFollow package
|
||||||
|
for (auto package = stats.getAiSequence().begin(); package != stats.getAiSequence().end(); ++package)
|
||||||
{
|
{
|
||||||
if ((*it)->getTypeId() == MWMechanics::AiPackage::TypeIdFollow)
|
if ((*package)->followTargetThroughDoors() && (*package)->getTarget() == actor)
|
||||||
{
|
{
|
||||||
MWWorld::Ptr followTarget = (*it)->getTarget();
|
list.push_back(static_cast<AiFollow*>(*package)->getFollowIndex());
|
||||||
if (followTarget.isEmpty())
|
|
||||||
continue;
|
|
||||||
if (followTarget == actor)
|
|
||||||
list.push_back(static_cast<MWMechanics::AiFollow*>(*it)->getFollowIndex());
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if ((*it)->getTypeId() != MWMechanics::AiPackage::TypeIdCombat)
|
else if ((*package)->getTypeId() != AiPackage::TypeIdCombat && (*package)->getTypeId() != AiPackage::TypeIdWander)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1893,14 +1908,17 @@ namespace MWMechanics
|
||||||
std::vector<MWWorld::Ptr> neighbors;
|
std::vector<MWWorld::Ptr> neighbors;
|
||||||
osg::Vec3f position (actor.getRefData().getPosition().asVec3());
|
osg::Vec3f position (actor.getRefData().getPosition().asVec3());
|
||||||
getObjectsInRange(position, aiProcessingDistance, neighbors);
|
getObjectsInRange(position, aiProcessingDistance, neighbors);
|
||||||
for(std::vector<MWWorld::Ptr>::const_iterator iter(neighbors.begin());iter != neighbors.end();++iter)
|
for(auto neighbor = neighbors.begin(); neighbor != neighbors.end(); ++neighbor)
|
||||||
{
|
{
|
||||||
const MWWorld::Class &cls = iter->getClass();
|
if (*neighbor == actor)
|
||||||
const CreatureStats &stats = cls.getCreatureStats(*iter);
|
|
||||||
if (stats.isDead() || *iter == actor)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
const CreatureStats &stats = neighbor->getClass().getCreatureStats(*neighbor);
|
||||||
|
if (stats.isDead())
|
||||||
|
continue;
|
||||||
|
|
||||||
if (stats.getAiSequence().isInCombat(actor))
|
if (stats.getAiSequence().isInCombat(actor))
|
||||||
list.push_front(*iter);
|
list.push_front(*neighbor);
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
@ -1912,15 +1930,18 @@ namespace MWMechanics
|
||||||
osg::Vec3f position (actor.getRefData().getPosition().asVec3());
|
osg::Vec3f position (actor.getRefData().getPosition().asVec3());
|
||||||
getObjectsInRange(position, aiProcessingDistance, neighbors);
|
getObjectsInRange(position, aiProcessingDistance, neighbors);
|
||||||
|
|
||||||
std::list<MWWorld::Ptr> followers = getActorsFollowing(actor);
|
std::set<MWWorld::Ptr> followers;
|
||||||
for(std::vector<MWWorld::Ptr>::const_iterator iter(neighbors.begin());iter != neighbors.end();++iter)
|
getActorsFollowing(actor, followers);
|
||||||
|
for (auto neighbor = neighbors.begin(); neighbor != neighbors.end(); ++neighbor)
|
||||||
{
|
{
|
||||||
const CreatureStats &stats = iter->getClass().getCreatureStats(*iter);
|
const CreatureStats &stats = neighbor->getClass().getCreatureStats(*neighbor);
|
||||||
if (stats.isDead() || *iter == actor || iter->getClass().isPureWaterCreature(*iter))
|
if (stats.isDead() || *neighbor == actor || neighbor->getClass().isPureWaterCreature(*neighbor))
|
||||||
continue;
|
continue;
|
||||||
const bool isFollower = std::find(followers.begin(), followers.end(), *iter) != followers.end();
|
|
||||||
if (stats.getAiSequence().isInCombat(actor) || (MWBase::Environment::get().getMechanicsManager()->isAggressive(*iter, actor) && !isFollower))
|
const bool isFollower = followers.find(*neighbor) != followers.end();
|
||||||
list.push_back(*iter);
|
|
||||||
|
if (stats.getAiSequence().isInCombat(actor) || (MWBase::Environment::get().getMechanicsManager()->isAggressive(*neighbor, actor) && !isFollower))
|
||||||
|
list.push_back(*neighbor);
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,7 +118,7 @@ namespace MWMechanics
|
||||||
int countDeaths (const std::string& id) const;
|
int countDeaths (const std::string& id) const;
|
||||||
///< Return the number of deaths for actors with the given ID.
|
///< Return the number of deaths for actors with the given ID.
|
||||||
|
|
||||||
bool isAttackPrepairing(const MWWorld::Ptr& ptr);
|
bool isAttackPreparing(const MWWorld::Ptr& ptr);
|
||||||
bool isRunning(const MWWorld::Ptr& ptr);
|
bool isRunning(const MWWorld::Ptr& ptr);
|
||||||
bool isSneaking(const MWWorld::Ptr& ptr);
|
bool isSneaking(const MWWorld::Ptr& ptr);
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ MWMechanics::AiBreathe::AiBreathe()
|
||||||
|
|
||||||
bool MWMechanics::AiBreathe::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
|
bool MWMechanics::AiBreathe::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
|
||||||
{
|
{
|
||||||
static const float fHoldBreathTime = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fHoldBreathTime")->getFloat();
|
static const float fHoldBreathTime = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fHoldBreathTime")->mValue.getFloat();
|
||||||
|
|
||||||
const MWWorld::Class& actorClass = actor.getClass();
|
const MWWorld::Class& actorClass = actor.getClass();
|
||||||
if (actorClass.isNpc())
|
if (actorClass.isNpc())
|
||||||
|
|
|
@ -42,7 +42,19 @@ bool MWMechanics::AiCast::execute(const MWWorld::Ptr& actor, MWMechanics::Charac
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::Vec3f dir = target.getRefData().getPosition().asVec3() - actor.getRefData().getPosition().asVec3();
|
osg::Vec3f targetPos = target.getRefData().getPosition().asVec3();
|
||||||
|
if (target.getClass().isActor())
|
||||||
|
{
|
||||||
|
osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getHalfExtents(target);
|
||||||
|
targetPos.z() += halfExtents.z() * 2 * 0.75f;
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::Vec3f actorPos = actor.getRefData().getPosition().asVec3();
|
||||||
|
osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getHalfExtents(actor);
|
||||||
|
actorPos.z() += halfExtents.z() * 2 * 0.75f;
|
||||||
|
|
||||||
|
osg::Vec3f dir = targetPos - actorPos;
|
||||||
|
|
||||||
bool turned = smoothTurn(actor, getZAngleToDir(dir), 2, osg::DegreesToRadians(3.f));
|
bool turned = smoothTurn(actor, getZAngleToDir(dir), 2, osg::DegreesToRadians(3.f));
|
||||||
turned &= smoothTurn(actor, getXAngleToDir(dir), 0, osg::DegreesToRadians(3.f));
|
turned &= smoothTurn(actor, getXAngleToDir(dir), 0, osg::DegreesToRadians(3.f));
|
||||||
|
|
||||||
|
|
|
@ -351,7 +351,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
case AiCombatStorage::FleeState_RunToDestination:
|
case AiCombatStorage::FleeState_RunToDestination:
|
||||||
{
|
{
|
||||||
static const float fFleeDistance = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fFleeDistance")->getFloat();
|
static const float fFleeDistance = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fFleeDistance")->mValue.getFloat();
|
||||||
|
|
||||||
float dist = (actor.getRefData().getPosition().asVec3() - target.getRefData().getPosition().asVec3()).length();
|
float dist = (actor.getRefData().getPosition().asVec3() - target.getRefData().getPosition().asVec3()).length();
|
||||||
if ((dist > fFleeDistance && !storage.mLOS)
|
if ((dist > fFleeDistance && !storage.mLOS)
|
||||||
|
@ -372,21 +372,32 @@ namespace MWMechanics
|
||||||
actorMovementSettings.mPosition[1] = storage.mMovement.mPosition[1];
|
actorMovementSettings.mPosition[1] = storage.mMovement.mPosition[1];
|
||||||
actorMovementSettings.mPosition[2] = storage.mMovement.mPosition[2];
|
actorMovementSettings.mPosition[2] = storage.mMovement.mPosition[2];
|
||||||
|
|
||||||
rotateActorOnAxis(actor, 2, actorMovementSettings, storage.mMovement);
|
rotateActorOnAxis(actor, 2, actorMovementSettings, storage);
|
||||||
rotateActorOnAxis(actor, 0, actorMovementSettings, storage.mMovement);
|
rotateActorOnAxis(actor, 0, actorMovementSettings, storage);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiCombat::rotateActorOnAxis(const MWWorld::Ptr& actor, int axis,
|
void AiCombat::rotateActorOnAxis(const MWWorld::Ptr& actor, int axis,
|
||||||
MWMechanics::Movement& actorMovementSettings, MWMechanics::Movement& desiredMovement)
|
MWMechanics::Movement& actorMovementSettings, AiCombatStorage& storage)
|
||||||
{
|
{
|
||||||
actorMovementSettings.mRotation[axis] = 0;
|
actorMovementSettings.mRotation[axis] = 0;
|
||||||
float& targetAngleRadians = desiredMovement.mRotation[axis];
|
float& targetAngleRadians = storage.mMovement.mRotation[axis];
|
||||||
if (targetAngleRadians != 0)
|
if (targetAngleRadians != 0)
|
||||||
{
|
{
|
||||||
if (smoothTurn(actor, targetAngleRadians, axis))
|
// Some attack animations contain small amount of movement.
|
||||||
|
// Since we use cone shapes for melee, we can use a threshold to avoid jittering
|
||||||
|
std::shared_ptr<Action>& currentAction = storage.mCurrentAction;
|
||||||
|
bool isRangedCombat = false;
|
||||||
|
currentAction->getCombatRange(isRangedCombat);
|
||||||
|
// Check if the actor now facing desired direction, no need to turn any more
|
||||||
|
if (isRangedCombat)
|
||||||
{
|
{
|
||||||
// actor now facing desired direction, no need to turn any more
|
if (smoothTurn(actor, targetAngleRadians, axis))
|
||||||
targetAngleRadians = 0;
|
targetAngleRadians = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (smoothTurn(actor, targetAngleRadians, axis, osg::DegreesToRadians(3.f)))
|
||||||
|
targetAngleRadians = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -453,7 +464,7 @@ namespace MWMechanics
|
||||||
if (distToTarget <= rangeAttackOfTarget && Misc::Rng::rollClosedProbability() < 0.25)
|
if (distToTarget <= rangeAttackOfTarget && Misc::Rng::rollClosedProbability() < 0.25)
|
||||||
{
|
{
|
||||||
mMovement.mPosition[0] = Misc::Rng::rollProbability() < 0.5 ? 1.0f : -1.0f; // to the left/right
|
mMovement.mPosition[0] = Misc::Rng::rollProbability() < 0.5 ? 1.0f : -1.0f; // to the left/right
|
||||||
mTimerCombatMove = 0.05f + 0.15f * Misc::Rng::rollClosedProbability();
|
mTimerCombatMove = 0.1f + 0.1f * Misc::Rng::rollClosedProbability();
|
||||||
mCombatMove = true;
|
mCombatMove = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -509,13 +520,13 @@ namespace MWMechanics
|
||||||
|
|
||||||
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||||
|
|
||||||
float baseDelay = store.get<ESM::GameSetting>().find("fCombatDelayCreature")->getFloat();
|
float baseDelay = store.get<ESM::GameSetting>().find("fCombatDelayCreature")->mValue.getFloat();
|
||||||
if (actor.getClass().isNpc())
|
if (actor.getClass().isNpc())
|
||||||
{
|
{
|
||||||
baseDelay = store.get<ESM::GameSetting>().find("fCombatDelayNPC")->getFloat();
|
baseDelay = store.get<ESM::GameSetting>().find("fCombatDelayNPC")->mValue.getFloat();
|
||||||
|
|
||||||
//say a provoking combat phrase
|
//say a provoking combat phrase
|
||||||
int chance = store.get<ESM::GameSetting>().find("iVoiceAttackOdds")->getInt();
|
int chance = store.get<ESM::GameSetting>().find("iVoiceAttackOdds")->mValue.getInteger();
|
||||||
if (Misc::Rng::roll0to99() < chance)
|
if (Misc::Rng::roll0to99() < chance)
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getDialogueManager()->say(actor, "attack");
|
MWBase::Environment::get().getDialogueManager()->say(actor, "attack");
|
||||||
|
@ -600,27 +611,26 @@ osg::Vec3f AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& t
|
||||||
float duration, int weapType, float strength)
|
float duration, int weapType, float strength)
|
||||||
{
|
{
|
||||||
float projSpeed;
|
float projSpeed;
|
||||||
|
const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||||
|
|
||||||
// get projectile speed (depending on weapon type)
|
// get projectile speed (depending on weapon type)
|
||||||
if (weapType == ESM::Weapon::MarksmanThrown)
|
if (weapType == ESM::Weapon::MarksmanThrown)
|
||||||
{
|
{
|
||||||
static float fThrownWeaponMinSpeed =
|
static float fThrownWeaponMinSpeed = gmst.find("fThrownWeaponMinSpeed")->mValue.getFloat();
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fThrownWeaponMinSpeed")->getFloat();
|
static float fThrownWeaponMaxSpeed = gmst.find("fThrownWeaponMaxSpeed")->mValue.getFloat();
|
||||||
static float fThrownWeaponMaxSpeed =
|
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fThrownWeaponMaxSpeed")->getFloat();
|
|
||||||
|
|
||||||
projSpeed =
|
projSpeed = fThrownWeaponMinSpeed + (fThrownWeaponMaxSpeed - fThrownWeaponMinSpeed) * strength;
|
||||||
fThrownWeaponMinSpeed + (fThrownWeaponMaxSpeed - fThrownWeaponMinSpeed) * strength;
|
|
||||||
}
|
}
|
||||||
else
|
else if (weapType != 0)
|
||||||
{
|
{
|
||||||
static float fProjectileMinSpeed =
|
static float fProjectileMinSpeed = gmst.find("fProjectileMinSpeed")->mValue.getFloat();
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fProjectileMinSpeed")->getFloat();
|
static float fProjectileMaxSpeed = gmst.find("fProjectileMaxSpeed")->mValue.getFloat();
|
||||||
static float fProjectileMaxSpeed =
|
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fProjectileMaxSpeed")->getFloat();
|
|
||||||
|
|
||||||
projSpeed =
|
projSpeed = fProjectileMinSpeed + (fProjectileMaxSpeed - fProjectileMinSpeed) * strength;
|
||||||
fProjectileMinSpeed + (fProjectileMaxSpeed - fProjectileMinSpeed) * strength;
|
}
|
||||||
|
else // weapType is 0 ==> it's a target spell projectile
|
||||||
|
{
|
||||||
|
projSpeed = gmst.find("fTargetSpellMaxSpeed")->mValue.getFloat();
|
||||||
}
|
}
|
||||||
|
|
||||||
// idea: perpendicular to dir to target speed components of target move vector and projectile vector should be the same
|
// idea: perpendicular to dir to target speed components of target move vector and projectile vector should be the same
|
||||||
|
|
|
@ -129,7 +129,7 @@ namespace MWMechanics
|
||||||
/// Transfer desired movement (from AiCombatStorage) to Actor
|
/// Transfer desired movement (from AiCombatStorage) to Actor
|
||||||
void updateActorsMovement(const MWWorld::Ptr& actor, float duration, AiCombatStorage& storage);
|
void updateActorsMovement(const MWWorld::Ptr& actor, float duration, AiCombatStorage& storage);
|
||||||
void rotateActorOnAxis(const MWWorld::Ptr& actor, int axis,
|
void rotateActorOnAxis(const MWWorld::Ptr& actor, int axis,
|
||||||
MWMechanics::Movement& actorMovementSettings, MWMechanics::Movement& desiredMovement);
|
MWMechanics::Movement& actorMovementSettings, AiCombatStorage& storage);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -23,8 +23,8 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
float suggestCombatRange(int rangeTypes)
|
float suggestCombatRange(int rangeTypes)
|
||||||
{
|
{
|
||||||
static const float fCombatDistance = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fCombatDistance")->getFloat();
|
static const float fCombatDistance = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fCombatDistance")->mValue.getFloat();
|
||||||
static float fHandToHandReach = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fHandToHandReach")->getFloat();
|
static float fHandToHandReach = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fHandToHandReach")->mValue.getFloat();
|
||||||
|
|
||||||
// This distance is a possible distance of melee attack
|
// This distance is a possible distance of melee attack
|
||||||
static float distance = fCombatDistance * std::max(2.f, fHandToHandReach);
|
static float distance = fCombatDistance * std::max(2.f, fHandToHandReach);
|
||||||
|
@ -114,13 +114,13 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
isRanged = false;
|
isRanged = false;
|
||||||
|
|
||||||
static const float fCombatDistance = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fCombatDistance")->getFloat();
|
static const float fCombatDistance = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fCombatDistance")->mValue.getFloat();
|
||||||
static const float fProjectileMaxSpeed = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fProjectileMaxSpeed")->getFloat();
|
static const float fProjectileMaxSpeed = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fProjectileMaxSpeed")->mValue.getFloat();
|
||||||
|
|
||||||
if (mWeapon.isEmpty())
|
if (mWeapon.isEmpty())
|
||||||
{
|
{
|
||||||
static float fHandToHandReach =
|
static float fHandToHandReach =
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fHandToHandReach")->getFloat();
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fHandToHandReach")->mValue.getFloat();
|
||||||
return fHandToHandReach * fCombatDistance;
|
return fHandToHandReach * fCombatDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,11 +190,6 @@ namespace MWMechanics
|
||||||
|
|
||||||
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
|
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
|
||||||
{
|
{
|
||||||
std::vector<int> equipmentSlots = it->getClass().getEquipmentSlots(*it).first;
|
|
||||||
if (std::find(equipmentSlots.begin(), equipmentSlots.end(), (int)MWWorld::InventoryStore::Slot_CarriedRight)
|
|
||||||
== equipmentSlots.end())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
float rating = rateWeapon(*it, actor, enemy, -1, bestArrowRating, bestBoltRating);
|
float rating = rateWeapon(*it, actor, enemy, -1, bestArrowRating, bestBoltRating);
|
||||||
if (rating > bestActionRating)
|
if (rating > bestActionRating)
|
||||||
{
|
{
|
||||||
|
@ -215,14 +210,12 @@ namespace MWMechanics
|
||||||
|
|
||||||
for (Spells::TIterator it = spells.begin(); it != spells.end(); ++it)
|
for (Spells::TIterator it = spells.begin(); it != spells.end(); ++it)
|
||||||
{
|
{
|
||||||
const ESM::Spell* spell = it->first;
|
float rating = rateSpell(it->first, actor, enemy);
|
||||||
|
|
||||||
float rating = rateSpell(spell, actor, enemy);
|
|
||||||
if (rating > bestActionRating)
|
if (rating > bestActionRating)
|
||||||
{
|
{
|
||||||
bestActionRating = rating;
|
bestActionRating = rating;
|
||||||
bestAction.reset(new ActionSpell(spell->mId));
|
bestAction.reset(new ActionSpell(it->first->mId));
|
||||||
antiFleeRating = vanillaRateSpell(spell, actor, enemy);
|
antiFleeRating = vanillaRateSpell(it->first, actor, enemy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,11 +258,6 @@ namespace MWMechanics
|
||||||
|
|
||||||
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
|
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
|
||||||
{
|
{
|
||||||
std::vector<int> equipmentSlots = it->getClass().getEquipmentSlots(*it).first;
|
|
||||||
if (std::find(equipmentSlots.begin(), equipmentSlots.end(), (int)MWWorld::InventoryStore::Slot_CarriedRight)
|
|
||||||
== equipmentSlots.end())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
float rating = rateWeapon(*it, actor, enemy, -1, bestArrowRating, bestBoltRating);
|
float rating = rateWeapon(*it, actor, enemy, -1, bestArrowRating, bestBoltRating);
|
||||||
if (rating > bestActionRating)
|
if (rating > bestActionRating)
|
||||||
{
|
{
|
||||||
|
@ -280,9 +268,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
for (Spells::TIterator it = spells.begin(); it != spells.end(); ++it)
|
for (Spells::TIterator it = spells.begin(); it != spells.end(); ++it)
|
||||||
{
|
{
|
||||||
const ESM::Spell* spell = it->first;
|
float rating = rateSpell(it->first, actor, enemy);
|
||||||
|
|
||||||
float rating = rateSpell(spell, actor, enemy);
|
|
||||||
if (rating > bestActionRating)
|
if (rating > bestActionRating)
|
||||||
{
|
{
|
||||||
bestActionRating = rating;
|
bestActionRating = rating;
|
||||||
|
@ -336,7 +322,7 @@ namespace MWMechanics
|
||||||
float dist = 1.0f;
|
float dist = 1.0f;
|
||||||
if (activeWeapon.isEmpty() && !selectedSpellId.empty() && !selectedEnchItem.isEmpty())
|
if (activeWeapon.isEmpty() && !selectedSpellId.empty() && !selectedEnchItem.isEmpty())
|
||||||
{
|
{
|
||||||
static const float fHandToHandReach = gmst.find("fHandToHandReach")->getFloat();
|
static const float fHandToHandReach = gmst.find("fHandToHandReach")->mValue.getFloat();
|
||||||
dist = fHandToHandReach;
|
dist = fHandToHandReach;
|
||||||
}
|
}
|
||||||
else if (stats.getDrawState() == MWMechanics::DrawState_Spell)
|
else if (stats.getDrawState() == MWMechanics::DrawState_Spell)
|
||||||
|
@ -375,7 +361,7 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const float fTargetSpellMaxSpeed = gmst.find("fTargetSpellMaxSpeed")->getFloat();
|
static const float fTargetSpellMaxSpeed = gmst.find("fTargetSpellMaxSpeed")->mValue.getFloat();
|
||||||
dist *= std::max(1000.0f, fTargetSpellMaxSpeed);
|
dist *= std::max(1000.0f, fTargetSpellMaxSpeed);
|
||||||
}
|
}
|
||||||
else if (!activeWeapon.isEmpty())
|
else if (!activeWeapon.isEmpty())
|
||||||
|
@ -383,7 +369,7 @@ namespace MWMechanics
|
||||||
const ESM::Weapon* esmWeap = activeWeapon.get<ESM::Weapon>()->mBase;
|
const ESM::Weapon* esmWeap = activeWeapon.get<ESM::Weapon>()->mBase;
|
||||||
if (esmWeap->mData.mType >= ESM::Weapon::MarksmanBow)
|
if (esmWeap->mData.mType >= ESM::Weapon::MarksmanBow)
|
||||||
{
|
{
|
||||||
static const float fTargetSpellMaxSpeed = gmst.find("fProjectileMaxSpeed")->getFloat();
|
static const float fTargetSpellMaxSpeed = gmst.find("fProjectileMaxSpeed")->mValue.getFloat();
|
||||||
dist = fTargetSpellMaxSpeed;
|
dist = fTargetSpellMaxSpeed;
|
||||||
if (!activeAmmo.isEmpty())
|
if (!activeAmmo.isEmpty())
|
||||||
{
|
{
|
||||||
|
@ -399,8 +385,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
dist = (dist > 0.f) ? dist : 1.0f;
|
dist = (dist > 0.f) ? dist : 1.0f;
|
||||||
|
|
||||||
static const float fCombatDistance = gmst.find("fCombatDistance")->getFloat();
|
static const float fCombatDistance = gmst.find("fCombatDistance")->mValue.getFloat();
|
||||||
static const float fCombatDistanceWerewolfMod = gmst.find("fCombatDistanceWerewolfMod")->getFloat();
|
static const float fCombatDistanceWerewolfMod = gmst.find("fCombatDistanceWerewolfMod")->mValue.getFloat();
|
||||||
|
|
||||||
float combatDistance = fCombatDistance;
|
float combatDistance = fCombatDistance;
|
||||||
if (actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf())
|
if (actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf())
|
||||||
|
@ -485,19 +471,22 @@ namespace MWMechanics
|
||||||
if (flee >= 100)
|
if (flee >= 100)
|
||||||
return flee;
|
return flee;
|
||||||
|
|
||||||
static const float fAIFleeHealthMult = gmst.find("fAIFleeHealthMult")->getFloat();
|
static const float fAIFleeHealthMult = gmst.find("fAIFleeHealthMult")->mValue.getFloat();
|
||||||
static const float fAIFleeFleeMult = gmst.find("fAIFleeFleeMult")->getFloat();
|
static const float fAIFleeFleeMult = gmst.find("fAIFleeFleeMult")->mValue.getFloat();
|
||||||
|
|
||||||
float healthPercentage = (stats.getHealth().getModified() == 0.0f)
|
float healthPercentage = (stats.getHealth().getModified() == 0.0f)
|
||||||
? 1.0f : stats.getHealth().getCurrent() / stats.getHealth().getModified();
|
? 1.0f : stats.getHealth().getCurrent() / stats.getHealth().getModified();
|
||||||
float rating = (1.0f - healthPercentage) * fAIFleeHealthMult + flee * fAIFleeFleeMult;
|
float rating = (1.0f - healthPercentage) * fAIFleeHealthMult + flee * fAIFleeFleeMult;
|
||||||
|
|
||||||
static const int iWereWolfLevelToAttack = gmst.find("iWereWolfLevelToAttack")->getInt();
|
static const int iWereWolfLevelToAttack = gmst.find("iWereWolfLevelToAttack")->mValue.getInteger();
|
||||||
|
|
||||||
if (enemy.getClass().isNpc() && enemy.getClass().getNpcStats(enemy).isWerewolf() && stats.getLevel() < iWereWolfLevelToAttack)
|
if (actor.getClass().isNpc() && enemy.getClass().isNpc())
|
||||||
{
|
{
|
||||||
static const int iWereWolfFleeMod = gmst.find("iWereWolfFleeMod")->getInt();
|
if (enemy.getClass().getNpcStats(enemy).isWerewolf() && stats.getLevel() < iWereWolfLevelToAttack)
|
||||||
rating = iWereWolfFleeMod;
|
{
|
||||||
|
static const int iWereWolfFleeMod = gmst.find("iWereWolfFleeMod")->mValue.getInteger();
|
||||||
|
rating = iWereWolfFleeMod;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rating != 0.0f)
|
if (rating != 0.0f)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#include "aisequence.hpp"
|
#include "aisequence.hpp"
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
#include <components/esm/aisequence.hpp>
|
#include <components/esm/aisequence.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
@ -19,6 +19,7 @@
|
||||||
#include "aicombataction.hpp"
|
#include "aicombataction.hpp"
|
||||||
#include "aipursue.hpp"
|
#include "aipursue.hpp"
|
||||||
#include "actorutil.hpp"
|
#include "actorutil.hpp"
|
||||||
|
#include "../mwworld/class.hpp"
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
@ -122,6 +123,20 @@ bool AiSequence::isInCombat() const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AiSequence::isEngagedWithActor() const
|
||||||
|
{
|
||||||
|
for (std::list<AiPackage *>::const_iterator it = mPackages.begin(); it != mPackages.end(); ++it)
|
||||||
|
{
|
||||||
|
if ((*it)->getTypeId() == AiPackage::TypeIdCombat)
|
||||||
|
{
|
||||||
|
MWWorld::Ptr target2 = (*it)->getTarget();
|
||||||
|
if (!target2.isEmpty() && target2.getClass().isNpc())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool AiSequence::hasPackage(int typeId) const
|
bool AiSequence::hasPackage(int typeId) const
|
||||||
{
|
{
|
||||||
for (std::list<AiPackage*>::const_iterator it = mPackages.begin(); it != mPackages.end(); ++it)
|
for (std::list<AiPackage*>::const_iterator it = mPackages.begin(); it != mPackages.end(); ++it)
|
||||||
|
@ -213,7 +228,7 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac
|
||||||
{
|
{
|
||||||
if ((*it)->getTypeId() != AiPackage::TypeIdCombat) break;
|
if ((*it)->getTypeId() != AiPackage::TypeIdCombat) break;
|
||||||
|
|
||||||
MWWorld::Ptr target = static_cast<const AiCombat *>(*it)->getTarget();
|
MWWorld::Ptr target = (*it)->getTarget();
|
||||||
|
|
||||||
// target disappeared (e.g. summoned creatures)
|
// target disappeared (e.g. summoned creatures)
|
||||||
if (target.isEmpty())
|
if (target.isEmpty())
|
||||||
|
@ -227,11 +242,11 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac
|
||||||
|
|
||||||
const ESM::Position &targetPos = target.getRefData().getPosition();
|
const ESM::Position &targetPos = target.getRefData().getPosition();
|
||||||
|
|
||||||
float distTo = (targetPos.asVec3() - vActorPos).length();
|
float distTo = (targetPos.asVec3() - vActorPos).length2();
|
||||||
|
|
||||||
// Small threshold for changing target
|
// Small threshold for changing target
|
||||||
if (it == mPackages.begin())
|
if (it == mPackages.begin())
|
||||||
distTo = std::max(0.f, distTo - 50.f);
|
distTo = std::max(0.f, distTo - 2500.f);
|
||||||
|
|
||||||
// if a target has higher priority than current target or has same priority but closer
|
// if a target has higher priority than current target or has same priority but closer
|
||||||
if (rating > bestRating || ((distTo < nearestDist) && rating == bestRating))
|
if (rating > bestRating || ((distTo < nearestDist) && rating == bestRating))
|
||||||
|
@ -282,7 +297,7 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
std::cerr << "Error during AiSequence::execute: " << e.what() << std::endl;
|
Log(Debug::Error) << "Error during AiSequence::execute: " << e.what();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,6 +88,9 @@ namespace MWMechanics
|
||||||
/// Is there any combat package?
|
/// Is there any combat package?
|
||||||
bool isInCombat () const;
|
bool isInCombat () const;
|
||||||
|
|
||||||
|
/// Are we in combat with any other actor, who's also engaging us?
|
||||||
|
bool isEngagedWithActor () const;
|
||||||
|
|
||||||
/// Does this AI sequence have the given package type?
|
/// Does this AI sequence have the given package type?
|
||||||
bool hasPackage(int typeId) const;
|
bool hasPackage(int typeId) const;
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
#include "aiwander.hpp"
|
#include "aiwander.hpp"
|
||||||
|
|
||||||
#include <cfloat>
|
#include <cfloat>
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
|
#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>
|
||||||
|
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
@ -24,8 +23,6 @@
|
||||||
#include "coordinateconverter.hpp"
|
#include "coordinateconverter.hpp"
|
||||||
#include "actorutil.hpp"
|
#include "actorutil.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
static const int COUNT_BEFORE_RESET = 10;
|
static const int COUNT_BEFORE_RESET = 10;
|
||||||
|
@ -498,7 +495,7 @@ namespace MWMechanics
|
||||||
MWWorld::Ptr player = getPlayer();
|
MWWorld::Ptr player = getPlayer();
|
||||||
|
|
||||||
static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore()
|
static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore()
|
||||||
.get<ESM::GameSetting>().find("fVoiceIdleOdds")->getFloat();
|
.get<ESM::GameSetting>().find("fVoiceIdleOdds")->mValue.getFloat();
|
||||||
|
|
||||||
float roll = Misc::Rng::rollProbability() * 10000.0f;
|
float roll = Misc::Rng::rollProbability() * 10000.0f;
|
||||||
|
|
||||||
|
@ -525,7 +522,7 @@ namespace MWMechanics
|
||||||
int hello = actor.getClass().getCreatureStats(actor).getAiSetting(CreatureStats::AI_Hello).getModified();
|
int hello = actor.getClass().getCreatureStats(actor).getAiSetting(CreatureStats::AI_Hello).getModified();
|
||||||
float helloDistance = static_cast<float>(hello);
|
float helloDistance = static_cast<float>(hello);
|
||||||
static int iGreetDistanceMultiplier = MWBase::Environment::get().getWorld()->getStore()
|
static int iGreetDistanceMultiplier = MWBase::Environment::get().getWorld()->getStore()
|
||||||
.get<ESM::GameSetting>().find("iGreetDistanceMultiplier")->getInt();
|
.get<ESM::GameSetting>().find("iGreetDistanceMultiplier")->mValue.getInteger();
|
||||||
|
|
||||||
helloDistance *= iGreetDistanceMultiplier;
|
helloDistance *= iGreetDistanceMultiplier;
|
||||||
|
|
||||||
|
@ -677,7 +674,7 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::cerr<< "Error: Attempted to play out of range idle animation \""<<idleSelect<<"\" for " << actor.getCellRef().getRefId() << std::endl;
|
Log(Debug::Verbose) << "Attempted to play out of range idle animation \"" << idleSelect << "\" for " << actor.getCellRef().getRefId();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -703,7 +700,7 @@ namespace MWMechanics
|
||||||
for(unsigned int counter = 0; counter < mIdle.size(); counter++)
|
for(unsigned int counter = 0; counter < mIdle.size(); counter++)
|
||||||
{
|
{
|
||||||
static float fIdleChanceMultiplier = MWBase::Environment::get().getWorld()->getStore()
|
static float fIdleChanceMultiplier = MWBase::Environment::get().getWorld()->getStore()
|
||||||
.get<ESM::GameSetting>().find("fIdleChanceMultiplier")->getFloat();
|
.get<ESM::GameSetting>().find("fIdleChanceMultiplier")->mValue.getFloat();
|
||||||
|
|
||||||
unsigned short idleChance = static_cast<unsigned short>(fIdleChanceMultiplier * mIdle[counter]);
|
unsigned short idleChance = static_cast<unsigned short>(fIdleChanceMultiplier * mIdle[counter]);
|
||||||
unsigned short randSelect = (int)(Misc::Rng::rollProbability() * int(100 / fIdleChanceMultiplier));
|
unsigned short randSelect = (int)(Misc::Rng::rollProbability() * int(100 / fIdleChanceMultiplier));
|
||||||
|
|
|
@ -140,11 +140,11 @@ void MWMechanics::Alchemy::updateEffects()
|
||||||
float x = getAlchemyFactor();
|
float x = getAlchemyFactor();
|
||||||
|
|
||||||
x *= mTools[ESM::Apparatus::MortarPestle].get<ESM::Apparatus>()->mBase->mData.mQuality;
|
x *= mTools[ESM::Apparatus::MortarPestle].get<ESM::Apparatus>()->mBase->mData.mQuality;
|
||||||
x *= MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find ("fPotionStrengthMult")->getFloat();
|
x *= MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find ("fPotionStrengthMult")->mValue.getFloat();
|
||||||
|
|
||||||
// value
|
// value
|
||||||
mValue = static_cast<int> (
|
mValue = static_cast<int> (
|
||||||
x * MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find ("iAlchemyMod")->getFloat());
|
x * MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find ("iAlchemyMod")->mValue.getFloat());
|
||||||
|
|
||||||
// build quantified effect list
|
// build quantified effect list
|
||||||
for (std::set<EffectKey>::const_iterator iter (effects.begin()); iter!=effects.end(); ++iter)
|
for (std::set<EffectKey>::const_iterator iter (effects.begin()); iter!=effects.end(); ++iter)
|
||||||
|
@ -160,13 +160,13 @@ void MWMechanics::Alchemy::updateEffects()
|
||||||
}
|
}
|
||||||
|
|
||||||
float fPotionT1MagMul =
|
float fPotionT1MagMul =
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find ("fPotionT1MagMult")->getFloat();
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find ("fPotionT1MagMult")->mValue.getFloat();
|
||||||
|
|
||||||
if (fPotionT1MagMul<=0)
|
if (fPotionT1MagMul<=0)
|
||||||
throw std::runtime_error ("invalid gmst: fPotionT1MagMul");
|
throw std::runtime_error ("invalid gmst: fPotionT1MagMul");
|
||||||
|
|
||||||
float fPotionT1DurMult =
|
float fPotionT1DurMult =
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find ("fPotionT1DurMult")->getFloat();
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find ("fPotionT1DurMult")->mValue.getFloat();
|
||||||
|
|
||||||
if (fPotionT1DurMult<=0)
|
if (fPotionT1DurMult<=0)
|
||||||
throw std::runtime_error ("invalid gmst: fPotionT1DurMult");
|
throw std::runtime_error ("invalid gmst: fPotionT1DurMult");
|
||||||
|
@ -449,7 +449,7 @@ bool MWMechanics::Alchemy::knownEffect(unsigned int potionEffectIndex, const MWW
|
||||||
MWMechanics::NpcStats& npcStats = npc.getClass().getNpcStats(npc);
|
MWMechanics::NpcStats& npcStats = npc.getClass().getNpcStats(npc);
|
||||||
int alchemySkill = npcStats.getSkill (ESM::Skill::Alchemy).getBase();
|
int alchemySkill = npcStats.getSkill (ESM::Skill::Alchemy).getBase();
|
||||||
static const float fWortChanceValue =
|
static const float fWortChanceValue =
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fWortChanceValue")->getFloat();
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fWortChanceValue")->mValue.getFloat();
|
||||||
return (potionEffectIndex <= 1 && alchemySkill >= fWortChanceValue)
|
return (potionEffectIndex <= 1 && alchemySkill >= fWortChanceValue)
|
||||||
|| (potionEffectIndex <= 3 && alchemySkill >= fWortChanceValue*2)
|
|| (potionEffectIndex <= 3 && alchemySkill >= fWortChanceValue*2)
|
||||||
|| (potionEffectIndex <= 5 && alchemySkill >= fWortChanceValue*3)
|
|| (potionEffectIndex <= 5 && alchemySkill >= fWortChanceValue*3)
|
||||||
|
@ -503,5 +503,5 @@ std::string MWMechanics::Alchemy::suggestPotionName()
|
||||||
|
|
||||||
int effectId = effects.begin()->mId;
|
int effectId = effects.begin()->mId;
|
||||||
return MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
|
return MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
|
||||||
ESM::MagicEffect::effectIdToString(effectId))->getString();
|
ESM::MagicEffect::effectIdToString(effectId))->mValue.getString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ namespace MWMechanics
|
||||||
std::vector<std::string> autoCalcNpcSpells(const int *actorSkills, const int *actorAttributes, const ESM::Race* race)
|
std::vector<std::string> autoCalcNpcSpells(const int *actorSkills, const int *actorAttributes, const ESM::Race* race)
|
||||||
{
|
{
|
||||||
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>();
|
||||||
static const float fNPCbaseMagickaMult = gmst.find("fNPCbaseMagickaMult")->getFloat();
|
static const float fNPCbaseMagickaMult = gmst.find("fNPCbaseMagickaMult")->mValue.getFloat();
|
||||||
float baseMagicka = fNPCbaseMagickaMult * actorAttributes[ESM::Attribute::Intelligence];
|
float baseMagicka = fNPCbaseMagickaMult * actorAttributes[ESM::Attribute::Intelligence];
|
||||||
|
|
||||||
static const std::string schools[] = {
|
static const std::string schools[] = {
|
||||||
|
@ -38,7 +38,7 @@ namespace MWMechanics
|
||||||
for (int i=0; i<6; ++i)
|
for (int i=0; i<6; ++i)
|
||||||
{
|
{
|
||||||
const std::string& gmstName = "iAutoSpell" + schools[i] + "Max";
|
const std::string& gmstName = "iAutoSpell" + schools[i] + "Max";
|
||||||
iAutoSpellSchoolMax[i] = gmst.find(gmstName)->getInt();
|
iAutoSpellSchoolMax[i] = gmst.find(gmstName)->mValue.getInteger();
|
||||||
}
|
}
|
||||||
init = true;
|
init = true;
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ namespace MWMechanics
|
||||||
continue;
|
continue;
|
||||||
if (!(spell->mData.mFlags & ESM::Spell::F_Autocalc))
|
if (!(spell->mData.mFlags & ESM::Spell::F_Autocalc))
|
||||||
continue;
|
continue;
|
||||||
static const int iAutoSpellTimesCanCast = gmst.find("iAutoSpellTimesCanCast")->getInt();
|
static const int iAutoSpellTimesCanCast = gmst.find("iAutoSpellTimesCanCast")->mValue.getInteger();
|
||||||
if (baseMagicka < iAutoSpellTimesCanCast * spell->mData.mCost)
|
if (baseMagicka < iAutoSpellTimesCanCast * spell->mData.mCost)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ namespace MWMechanics
|
||||||
if (cap.mReachedLimit && spell->mData.mCost <= cap.mMinCost)
|
if (cap.mReachedLimit && spell->mData.mCost <= cap.mMinCost)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
static const float fAutoSpellChance = gmst.find("fAutoSpellChance")->getFloat();
|
static const float fAutoSpellChance = gmst.find("fAutoSpellChance")->mValue.getFloat();
|
||||||
if (calcAutoCastChance(spell, actorSkills, actorAttributes, school) < fAutoSpellChance)
|
if (calcAutoCastChance(spell, actorSkills, actorAttributes, school) < fAutoSpellChance)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -146,7 +146,7 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore();
|
const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore();
|
||||||
|
|
||||||
static const float fPCbaseMagickaMult = esmStore.get<ESM::GameSetting>().find("fPCbaseMagickaMult")->getFloat();
|
static const float fPCbaseMagickaMult = esmStore.get<ESM::GameSetting>().find("fPCbaseMagickaMult")->mValue.getFloat();
|
||||||
|
|
||||||
float baseMagicka = fPCbaseMagickaMult * actorAttributes[ESM::Attribute::Intelligence];
|
float baseMagicka = fPCbaseMagickaMult * actorAttributes[ESM::Attribute::Intelligence];
|
||||||
bool reachedLimit = false;
|
bool reachedLimit = false;
|
||||||
|
@ -173,7 +173,7 @@ namespace MWMechanics
|
||||||
if (baseMagicka < spell->mData.mCost)
|
if (baseMagicka < spell->mData.mCost)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
static const float fAutoPCSpellChance = esmStore.get<ESM::GameSetting>().find("fAutoPCSpellChance")->getFloat();
|
static const float fAutoPCSpellChance = esmStore.get<ESM::GameSetting>().find("fAutoPCSpellChance")->mValue.getFloat();
|
||||||
if (calcAutoCastChance(spell, actorSkills, actorAttributes, -1) < fAutoPCSpellChance)
|
if (calcAutoCastChance(spell, actorSkills, actorAttributes, -1) < fAutoPCSpellChance)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -206,7 +206,7 @@ namespace MWMechanics
|
||||||
weakestSpell = spell;
|
weakestSpell = spell;
|
||||||
minCost = weakestSpell->mData.mCost;
|
minCost = weakestSpell->mData.mCost;
|
||||||
}
|
}
|
||||||
static const unsigned int iAutoPCSpellMax = esmStore.get<ESM::GameSetting>().find("iAutoPCSpellMax")->getInt();
|
static const unsigned int iAutoPCSpellMax = esmStore.get<ESM::GameSetting>().find("iAutoPCSpellMax")->mValue.getInteger();
|
||||||
if (selectedSpells.size() == iAutoPCSpellMax)
|
if (selectedSpells.size() == iAutoPCSpellMax)
|
||||||
reachedLimit = true;
|
reachedLimit = true;
|
||||||
}
|
}
|
||||||
|
@ -221,7 +221,7 @@ namespace MWMechanics
|
||||||
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt = effects.begin(); effectIt != effects.end(); ++effectIt)
|
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt = effects.begin(); effectIt != effects.end(); ++effectIt)
|
||||||
{
|
{
|
||||||
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effectIt->mEffectID);
|
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effectIt->mEffectID);
|
||||||
static const int iAutoSpellAttSkillMin = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("iAutoSpellAttSkillMin")->getInt();
|
static const int iAutoSpellAttSkillMin = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("iAutoSpellAttSkillMin")->mValue.getInteger();
|
||||||
|
|
||||||
if ((magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill))
|
if ((magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill))
|
||||||
{
|
{
|
||||||
|
@ -278,7 +278,7 @@ namespace MWMechanics
|
||||||
duration = effect.mDuration;
|
duration = effect.mDuration;
|
||||||
|
|
||||||
static const float fEffectCostMult = MWBase::Environment::get().getWorld()->getStore()
|
static const float fEffectCostMult = MWBase::Environment::get().getWorld()->getStore()
|
||||||
.get<ESM::GameSetting>().find("fEffectCostMult")->getFloat();
|
.get<ESM::GameSetting>().find("fEffectCostMult")->mValue.getFloat();
|
||||||
|
|
||||||
float x = 0.5 * (std::max(1, minMagn) + std::max(1, maxMagn));
|
float x = 0.5 * (std::max(1, minMagn) + std::max(1, maxMagn));
|
||||||
x *= 0.1 * magicEffect->mData.mBaseCost;
|
x *= 0.1 * magicEffect->mData.mBaseCost;
|
||||||
|
|
|
@ -123,16 +123,16 @@ float getFallDamage(const MWWorld::Ptr& ptr, float fallHeight)
|
||||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||||
const MWWorld::Store<ESM::GameSetting> &store = world->getStore().get<ESM::GameSetting>();
|
const MWWorld::Store<ESM::GameSetting> &store = world->getStore().get<ESM::GameSetting>();
|
||||||
|
|
||||||
const float fallDistanceMin = store.find("fFallDamageDistanceMin")->getFloat();
|
const float fallDistanceMin = store.find("fFallDamageDistanceMin")->mValue.getFloat();
|
||||||
|
|
||||||
if (fallHeight >= fallDistanceMin)
|
if (fallHeight >= fallDistanceMin)
|
||||||
{
|
{
|
||||||
const float acrobaticsSkill = static_cast<float>(ptr.getClass().getSkill(ptr, ESM::Skill::Acrobatics));
|
const float acrobaticsSkill = static_cast<float>(ptr.getClass().getSkill(ptr, ESM::Skill::Acrobatics));
|
||||||
const float jumpSpellBonus = ptr.getClass().getCreatureStats(ptr).getMagicEffects().get(ESM::MagicEffect::Jump).getMagnitude();
|
const float jumpSpellBonus = ptr.getClass().getCreatureStats(ptr).getMagicEffects().get(ESM::MagicEffect::Jump).getMagnitude();
|
||||||
const float fallAcroBase = store.find("fFallAcroBase")->getFloat();
|
const float fallAcroBase = store.find("fFallAcroBase")->mValue.getFloat();
|
||||||
const float fallAcroMult = store.find("fFallAcroMult")->getFloat();
|
const float fallAcroMult = store.find("fFallAcroMult")->mValue.getFloat();
|
||||||
const float fallDistanceBase = store.find("fFallDistanceBase")->getFloat();
|
const float fallDistanceBase = store.find("fFallDistanceBase")->mValue.getFloat();
|
||||||
const float fallDistanceMult = store.find("fFallDistanceMult")->getFloat();
|
const float fallDistanceMult = store.find("fFallDistanceMult")->mValue.getFloat();
|
||||||
|
|
||||||
float x = fallHeight - fallDistanceMin;
|
float x = fallHeight - fallDistanceMin;
|
||||||
x -= (1.5f * acrobaticsSkill) + jumpSpellBonus;
|
x -= (1.5f * acrobaticsSkill) + jumpSpellBonus;
|
||||||
|
@ -411,10 +411,6 @@ void CharacterController::refreshMovementAnims(const WeaponInfo* weap, Character
|
||||||
if(force || movement != mMovementState)
|
if(force || movement != mMovementState)
|
||||||
{
|
{
|
||||||
mMovementState = movement;
|
mMovementState = movement;
|
||||||
|
|
||||||
if (movement != CharState_None)
|
|
||||||
mIdleState = CharState_None;
|
|
||||||
|
|
||||||
std::string movementAnimName;
|
std::string movementAnimName;
|
||||||
MWRender::Animation::BlendMask movemask = MWRender::Animation::BlendMask_All;
|
MWRender::Animation::BlendMask movemask = MWRender::Animation::BlendMask_All;
|
||||||
const StateInfo *movestate = std::find_if(sMovementList, sMovementListEnd, FindCharState(mMovementState));
|
const StateInfo *movestate = std::find_if(sMovementList, sMovementListEnd, FindCharState(mMovementState));
|
||||||
|
@ -531,7 +527,7 @@ void CharacterController::refreshMovementAnims(const WeaponInfo* weap, Character
|
||||||
|
|
||||||
void CharacterController::refreshIdleAnims(const WeaponInfo* weap, CharacterState idle, bool force)
|
void CharacterController::refreshIdleAnims(const WeaponInfo* weap, CharacterState idle, bool force)
|
||||||
{
|
{
|
||||||
if(force || idle != mIdleState || (!mAnimation->isPlaying(mCurrentIdle) && mAnimQueue.empty()))
|
if(force || idle != mIdleState || mIdleState == CharState_None || (!mAnimation->isPlaying(mCurrentIdle) && mAnimQueue.empty()))
|
||||||
{
|
{
|
||||||
mIdleState = idle;
|
mIdleState = idle;
|
||||||
size_t numLoops = ~0ul;
|
size_t numLoops = ~0ul;
|
||||||
|
@ -562,14 +558,24 @@ void CharacterController::refreshIdleAnims(const WeaponInfo* weap, CharacterStat
|
||||||
// play until the Loop Stop key 2 to 5 times, then play until the Stop key
|
// play until the Loop Stop key 2 to 5 times, then play until the Stop key
|
||||||
// this replicates original engine behavior for the "Idle1h" 1st-person animation
|
// this replicates original engine behavior for the "Idle1h" 1st-person animation
|
||||||
numLoops = 1 + Misc::Rng::rollDice(4);
|
numLoops = 1 + Misc::Rng::rollDice(4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mAnimation->disable(mCurrentIdle);
|
// There is no need to restart anim if the new and old anims are the same.
|
||||||
|
// Just update a number of loops.
|
||||||
|
float startPoint = 0;
|
||||||
|
if (!mCurrentIdle.empty() && mCurrentIdle == idleGroup)
|
||||||
|
{
|
||||||
|
mAnimation->getInfo(mCurrentIdle, &startPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!mCurrentIdle.empty())
|
||||||
|
mAnimation->disable(mCurrentIdle);
|
||||||
|
|
||||||
mCurrentIdle = idleGroup;
|
mCurrentIdle = idleGroup;
|
||||||
if(!mCurrentIdle.empty())
|
if(!mCurrentIdle.empty())
|
||||||
mAnimation->play(mCurrentIdle, idlePriority, MWRender::Animation::BlendMask_All, false,
|
mAnimation->play(mCurrentIdle, idlePriority, MWRender::Animation::BlendMask_All, false,
|
||||||
1.0f, "start", "stop", 0.0f, numLoops, true);
|
1.0f, "start", "stop", startPoint, numLoops, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -583,7 +589,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
|
||||||
refreshHitRecoilAnims();
|
refreshHitRecoilAnims();
|
||||||
|
|
||||||
const WeaponInfo *weap = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(mWeaponType));
|
const WeaponInfo *weap = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(mWeaponType));
|
||||||
if (!mPtr.getClass().isBipedal(mPtr))
|
if (!mPtr.getClass().hasInventoryStore(mPtr))
|
||||||
weap = sWeaponTypeListEnd;
|
weap = sWeaponTypeListEnd;
|
||||||
|
|
||||||
refreshJumpAnims(weap, jump, force);
|
refreshJumpAnims(weap, jump, force);
|
||||||
|
@ -592,7 +598,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
|
||||||
// idle handled last as it can depend on the other states
|
// idle handled last as it can depend on the other states
|
||||||
// FIXME: if one of the below states is close to their last animation frame (i.e. will be disabled in the coming update),
|
// FIXME: if one of the below states is close to their last animation frame (i.e. will be disabled in the coming update),
|
||||||
// the idle animation should be displayed
|
// the idle animation should be displayed
|
||||||
if ((mUpperBodyState != UpperCharState_Nothing
|
if (((mUpperBodyState != UpperCharState_Nothing && mUpperBodyState != UpperCharState_WeapEquiped)
|
||||||
|| (mMovementState != CharState_None && !isTurning())
|
|| (mMovementState != CharState_None && !isTurning())
|
||||||
|| mHitState != CharState_None)
|
|| mHitState != CharState_None)
|
||||||
&& !mPtr.getClass().isBipedal(mPtr))
|
&& !mPtr.getClass().isBipedal(mPtr))
|
||||||
|
@ -773,6 +779,20 @@ void CharacterController::playRandomDeath(float startpoint)
|
||||||
playDeath(startpoint, mDeathState);
|
playDeath(startpoint, mDeathState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string CharacterController::chooseRandomAttackAnimation() const
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
bool isSwimming = MWBase::Environment::get().getWorld()->isSwimming(mPtr);
|
||||||
|
|
||||||
|
if (isSwimming)
|
||||||
|
result = chooseRandomGroup("swimattack");
|
||||||
|
|
||||||
|
if (!isSwimming || !mAnimation->hasAnimation(result))
|
||||||
|
result = chooseRandomGroup("attack");
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim)
|
CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim)
|
||||||
: mPtr(ptr)
|
: mPtr(ptr)
|
||||||
, mWeapon(MWWorld::Ptr())
|
, mWeapon(MWWorld::Ptr())
|
||||||
|
@ -918,11 +938,14 @@ void CharacterController::handleTextKey(const std::string &groupname, const std:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (soundgen == "land") // Morrowind ignores land soundgen for some reason
|
||||||
|
return;
|
||||||
|
|
||||||
std::string sound = mPtr.getClass().getSoundIdFromSndGen(mPtr, soundgen);
|
std::string sound = mPtr.getClass().getSoundIdFromSndGen(mPtr, soundgen);
|
||||||
if(!sound.empty())
|
if(!sound.empty())
|
||||||
{
|
{
|
||||||
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||||
if(evt.compare(10, evt.size()-10, "left") == 0 || evt.compare(10, evt.size()-10, "right") == 0 || evt.compare(10, evt.size()-10, "land") == 0)
|
if(soundgen == "left" || soundgen == "right")
|
||||||
{
|
{
|
||||||
// Don't make foot sounds local for the player, it makes sense to keep them
|
// Don't make foot sounds local for the player, it makes sense to keep them
|
||||||
// positioned on the ground.
|
// positioned on the ground.
|
||||||
|
@ -1123,16 +1146,10 @@ bool CharacterController::updateCreatureState()
|
||||||
else
|
else
|
||||||
mCurrentWeapon = "";
|
mCurrentWeapon = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (weapType != WeapType_Spell || !mAnimation->hasAnimation("spellcast")) // Not all creatures have a dedicated spellcast animation
|
if (weapType != WeapType_Spell || !mAnimation->hasAnimation("spellcast")) // Not all creatures have a dedicated spellcast animation
|
||||||
{
|
{
|
||||||
bool isSwimming = MWBase::Environment::get().getWorld()->isSwimming(mPtr);
|
mCurrentWeapon = chooseRandomAttackAnimation();
|
||||||
int roll = Misc::Rng::rollDice(3); // [0, 2]
|
|
||||||
if (roll == 0)
|
|
||||||
mCurrentWeapon = isSwimming && mAnimation->hasAnimation("swimattack1") ? "swimattack1" : "attack1";
|
|
||||||
else if (roll == 1)
|
|
||||||
mCurrentWeapon = isSwimming && mAnimation->hasAnimation("swimattack2") ? "swimattack2" : "attack2";
|
|
||||||
else
|
|
||||||
mCurrentWeapon = isSwimming && mAnimation->hasAnimation("swimattack3") ? "swimattack3" : "attack3";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mCurrentWeapon.empty())
|
if (!mCurrentWeapon.empty())
|
||||||
|
@ -1212,8 +1229,11 @@ bool CharacterController::updateWeaponState()
|
||||||
mWeapon = weapon != inv.end() ? *weapon : MWWorld::Ptr();
|
mWeapon = weapon != inv.end() ? *weapon : MWWorld::Ptr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use blending only with 3d-person movement animations for bipedal actors
|
||||||
|
bool firstPersonPlayer = (mPtr == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->isFirstPerson());
|
||||||
MWRender::Animation::AnimPriority priorityWeapon(Priority_Weapon);
|
MWRender::Animation::AnimPriority priorityWeapon(Priority_Weapon);
|
||||||
priorityWeapon[MWRender::Animation::BoneGroup_LowerBody] = Priority_WeaponLowerBody;
|
if (!firstPersonPlayer && mPtr.getClass().isBipedal(mPtr))
|
||||||
|
priorityWeapon[MWRender::Animation::BoneGroup_LowerBody] = Priority_WeaponLowerBody;
|
||||||
|
|
||||||
bool forcestateupdate = false;
|
bool forcestateupdate = false;
|
||||||
|
|
||||||
|
@ -1221,11 +1241,11 @@ bool CharacterController::updateWeaponState()
|
||||||
bool isStillWeapon = weaptype > WeapType_HandToHand && weaptype < WeapType_Spell &&
|
bool isStillWeapon = weaptype > WeapType_HandToHand && weaptype < WeapType_Spell &&
|
||||||
mWeaponType > WeapType_HandToHand && mWeaponType < WeapType_Spell;
|
mWeaponType > WeapType_HandToHand && mWeaponType < WeapType_Spell;
|
||||||
|
|
||||||
if(weaptype != mWeaponType && !isKnockedOut() &&
|
if(!isKnockedOut() && !isKnockedDown() && !isRecovery())
|
||||||
!isKnockedDown() && !isRecovery())
|
|
||||||
{
|
{
|
||||||
std::string weapgroup;
|
std::string weapgroup;
|
||||||
if ((!isWerewolf || mWeaponType != WeapType_Spell)
|
if ((!isWerewolf || mWeaponType != WeapType_Spell)
|
||||||
|
&& weaptype != mWeaponType
|
||||||
&& mUpperBodyState != UpperCharState_UnEquipingWeap
|
&& mUpperBodyState != UpperCharState_UnEquipingWeap
|
||||||
&& !isStillWeapon)
|
&& !isStillWeapon)
|
||||||
{
|
{
|
||||||
|
@ -1239,6 +1259,10 @@ bool CharacterController::updateWeaponState()
|
||||||
MWRender::Animation::BlendMask_All, false,
|
MWRender::Animation::BlendMask_All, false,
|
||||||
1.0f, "unequip start", "unequip stop", 0.0f, 0);
|
1.0f, "unequip start", "unequip stop", 0.0f, 0);
|
||||||
mUpperBodyState = UpperCharState_UnEquipingWeap;
|
mUpperBodyState = UpperCharState_UnEquipingWeap;
|
||||||
|
|
||||||
|
// If we do not have the "unequip detach" key, hide weapon manually.
|
||||||
|
if (mAnimation->getTextKeyTime(weapgroup+": unequip detach") < 0)
|
||||||
|
mAnimation->showWeapons(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!downSoundId.empty())
|
if(!downSoundId.empty())
|
||||||
|
@ -1252,47 +1276,64 @@ bool CharacterController::updateWeaponState()
|
||||||
bool animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete);
|
bool animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete);
|
||||||
if (!animPlaying || complete >= 1.0f)
|
if (!animPlaying || complete >= 1.0f)
|
||||||
{
|
{
|
||||||
forcestateupdate = true;
|
// Weapon is changed, no current animation (e.g. unequipping or attack).
|
||||||
mAnimation->showCarriedLeft(updateCarriedLeftVisible(weaptype));
|
// Start equipping animation now.
|
||||||
|
if (weaptype != mWeaponType)
|
||||||
getWeaponGroup(weaptype, weapgroup);
|
|
||||||
mAnimation->setWeaponGroup(weapgroup);
|
|
||||||
|
|
||||||
if (!isStillWeapon)
|
|
||||||
{
|
{
|
||||||
if (weaptype == WeapType_None)
|
forcestateupdate = true;
|
||||||
|
mAnimation->showCarriedLeft(updateCarriedLeftVisible(weaptype));
|
||||||
|
|
||||||
|
getWeaponGroup(weaptype, weapgroup);
|
||||||
|
mAnimation->setWeaponGroup(weapgroup);
|
||||||
|
|
||||||
|
if (!isStillWeapon)
|
||||||
{
|
{
|
||||||
// Disable current weapon animation manually
|
|
||||||
mAnimation->disable(mCurrentWeapon);
|
mAnimation->disable(mCurrentWeapon);
|
||||||
}
|
if (weaptype != WeapType_None)
|
||||||
else
|
{
|
||||||
{
|
mAnimation->showWeapons(false);
|
||||||
mAnimation->showWeapons(false);
|
mAnimation->play(weapgroup, priorityWeapon,
|
||||||
mAnimation->play(weapgroup, priorityWeapon,
|
MWRender::Animation::BlendMask_All, true,
|
||||||
MWRender::Animation::BlendMask_All, true,
|
1.0f, "equip start", "equip stop", 0.0f, 0);
|
||||||
1.0f, "equip start", "equip stop", 0.0f, 0);
|
mUpperBodyState = UpperCharState_EquipingWeap;
|
||||||
mUpperBodyState = UpperCharState_EquipingWeap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isWerewolf)
|
// If we do not have the "equip attach" key, show weapon manually.
|
||||||
{
|
if (weaptype != WeapType_Spell)
|
||||||
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
{
|
||||||
const ESM::Sound *sound = store.get<ESM::Sound>().searchRandom("WolfEquip");
|
if (mAnimation->getTextKeyTime(weapgroup+": equip attach") < 0)
|
||||||
if(sound)
|
mAnimation->showWeapons(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isWerewolf)
|
||||||
|
{
|
||||||
|
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||||
|
const ESM::Sound *sound = store.get<ESM::Sound>().searchRandom("WolfEquip");
|
||||||
|
if(sound)
|
||||||
|
{
|
||||||
|
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||||
|
sndMgr->playSound3D(mPtr, sound->mId, 1.0f, 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mWeaponType = weaptype;
|
||||||
|
getWeaponGroup(mWeaponType, mCurrentWeapon);
|
||||||
|
|
||||||
|
if(!upSoundId.empty() && !isStillWeapon)
|
||||||
{
|
{
|
||||||
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||||
sndMgr->playSound3D(mPtr, sound->mId, 1.0f, 1.0f);
|
sndMgr->playSound3D(mPtr, upSoundId, 1.0f, 1.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mWeaponType = weaptype;
|
// Make sure that we disabled unequipping animation
|
||||||
getWeaponGroup(mWeaponType, mCurrentWeapon);
|
if (mUpperBodyState == UpperCharState_UnEquipingWeap)
|
||||||
|
|
||||||
if(!upSoundId.empty() && !isStillWeapon)
|
|
||||||
{
|
{
|
||||||
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
mUpperBodyState = UpperCharState_Nothing;
|
||||||
sndMgr->playSound3D(mPtr, upSoundId, 1.0f, 1.0f);
|
mAnimation->disable(mCurrentWeapon);
|
||||||
|
mWeaponType = WeapType_None;
|
||||||
|
getWeaponGroup(mWeaponType, mCurrentWeapon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1347,18 +1388,12 @@ bool CharacterController::updateWeaponState()
|
||||||
{
|
{
|
||||||
MWWorld::Ptr player = getPlayer();
|
MWWorld::Ptr player = getPlayer();
|
||||||
|
|
||||||
// We should reset player's idle animation in the first-person mode.
|
bool resetIdle = ammunition;
|
||||||
if (mPtr == player && MWBase::Environment::get().getWorld()->isFirstPerson())
|
|
||||||
mIdleState = CharState_None;
|
|
||||||
|
|
||||||
// In other cases we should not break swim and sneak animations
|
|
||||||
if (mIdleState != CharState_IdleSneak && mIdleState != CharState_IdleSwim)
|
|
||||||
mIdleState = CharState_None;
|
|
||||||
|
|
||||||
if(mUpperBodyState == UpperCharState_WeapEquiped && (mHitState == CharState_None || mHitState == CharState_Block))
|
if(mUpperBodyState == UpperCharState_WeapEquiped && (mHitState == CharState_None || mHitState == CharState_Block))
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getWorld()->breakInvisibility(mPtr);
|
MWBase::Environment::get().getWorld()->breakInvisibility(mPtr);
|
||||||
mAttackStrength = 0;
|
mAttackStrength = 0;
|
||||||
|
|
||||||
if(mWeaponType == WeapType_Spell)
|
if(mWeaponType == WeapType_Spell)
|
||||||
{
|
{
|
||||||
// Unset casting flag, otherwise pressing the mouse button down would
|
// Unset casting flag, otherwise pressing the mouse button down would
|
||||||
|
@ -1367,15 +1402,10 @@ bool CharacterController::updateWeaponState()
|
||||||
if (mPtr == player)
|
if (mPtr == player)
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getWorld()->getPlayer().setAttackingOrSpell(false);
|
MWBase::Environment::get().getWorld()->getPlayer().setAttackingOrSpell(false);
|
||||||
}
|
|
||||||
|
|
||||||
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
// For the player, set the spell we want to cast
|
||||||
|
// This has to be done at the start of the casting animation,
|
||||||
// For the player, set the spell we want to cast
|
// *not* when selecting a spell in the GUI (otherwise you could change the spell mid-animation)
|
||||||
// This has to be done at the start of the casting animation,
|
|
||||||
// *not* when selecting a spell in the GUI (otherwise you could change the spell mid-animation)
|
|
||||||
if (mPtr == player)
|
|
||||||
{
|
|
||||||
std::string selectedSpell = MWBase::Environment::get().getWindowManager()->getSelectedSpell();
|
std::string selectedSpell = MWBase::Environment::get().getWindowManager()->getSelectedSpell();
|
||||||
stats.getSpells().setSelectedSpell(selectedSpell);
|
stats.getSpells().setSelectedSpell(selectedSpell);
|
||||||
}
|
}
|
||||||
|
@ -1387,6 +1417,7 @@ bool CharacterController::updateWeaponState()
|
||||||
MWMechanics::CastSpell cast(mPtr, NULL, false, mCastingManualSpell);
|
MWMechanics::CastSpell cast(mPtr, NULL, false, mCastingManualSpell);
|
||||||
cast.playSpellCastingEffects(spellid);
|
cast.playSpellCastingEffects(spellid);
|
||||||
|
|
||||||
|
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||||
const ESM::Spell *spell = store.get<ESM::Spell>().find(spellid);
|
const ESM::Spell *spell = store.get<ESM::Spell>().find(spellid);
|
||||||
const ESM::ENAMstruct &lastEffect = spell->mEffects.mList.back();
|
const ESM::ENAMstruct &lastEffect = spell->mEffects.mList.back();
|
||||||
const ESM::MagicEffect *effect;
|
const ESM::MagicEffect *effect;
|
||||||
|
@ -1406,19 +1437,39 @@ bool CharacterController::updateWeaponState()
|
||||||
|
|
||||||
const ESM::ENAMstruct &firstEffect = spell->mEffects.mList.at(0); // first effect used for casting animation
|
const ESM::ENAMstruct &firstEffect = spell->mEffects.mList.at(0); // first effect used for casting animation
|
||||||
|
|
||||||
switch(firstEffect.mRange)
|
std::string startKey;
|
||||||
|
std::string stopKey;
|
||||||
|
if (isRandomAttackAnimation(mCurrentWeapon))
|
||||||
{
|
{
|
||||||
case 0: mAttackType = "self"; break;
|
startKey = "start";
|
||||||
case 1: mAttackType = "touch"; break;
|
stopKey = "stop";
|
||||||
case 2: mAttackType = "target"; break;
|
MWBase::Environment::get().getWorld()->castSpell(mPtr, mCastingManualSpell); // No "release" text key to use, so cast immediately
|
||||||
|
mCastingManualSpell = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch(firstEffect.mRange)
|
||||||
|
{
|
||||||
|
case 0: mAttackType = "self"; break;
|
||||||
|
case 1: mAttackType = "touch"; break;
|
||||||
|
case 2: mAttackType = "target"; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
startKey = mAttackType+" start";
|
||||||
|
stopKey = mAttackType+" stop";
|
||||||
}
|
}
|
||||||
|
|
||||||
mAnimation->play(mCurrentWeapon, priorityWeapon,
|
mAnimation->play(mCurrentWeapon, priorityWeapon,
|
||||||
MWRender::Animation::BlendMask_All, true,
|
MWRender::Animation::BlendMask_All, true,
|
||||||
weapSpeed, mAttackType+" start", mAttackType+" stop",
|
1, startKey, stopKey,
|
||||||
0.0f, 0);
|
0.0f, 0);
|
||||||
mUpperBodyState = UpperCharState_CastingSpell;
|
mUpperBodyState = UpperCharState_CastingSpell;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resetIdle = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (mPtr.getClass().hasInventoryStore(mPtr))
|
if (mPtr.getClass().hasInventoryStore(mPtr))
|
||||||
{
|
{
|
||||||
MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
|
MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
|
||||||
|
@ -1458,16 +1509,26 @@ bool CharacterController::updateWeaponState()
|
||||||
}
|
}
|
||||||
else if (ammunition)
|
else if (ammunition)
|
||||||
{
|
{
|
||||||
if(mWeaponType == WeapType_Crossbow || mWeaponType == WeapType_BowAndArrow ||
|
std::string startKey;
|
||||||
mWeaponType == WeapType_Thrown)
|
std::string stopKey;
|
||||||
|
if(mWeaponType == WeapType_Crossbow || mWeaponType == WeapType_BowAndArrow || mWeaponType == WeapType_Thrown)
|
||||||
|
{
|
||||||
mAttackType = "shoot";
|
mAttackType = "shoot";
|
||||||
|
startKey = mAttackType+" start";
|
||||||
|
stopKey = mAttackType+" min attack";
|
||||||
|
}
|
||||||
|
else if (isRandomAttackAnimation(mCurrentWeapon))
|
||||||
|
{
|
||||||
|
startKey = "start";
|
||||||
|
stopKey = "stop";
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(mPtr == getPlayer())
|
if(mPtr == getPlayer())
|
||||||
{
|
{
|
||||||
if (isWeapon)
|
if (isWeapon)
|
||||||
{
|
{
|
||||||
if (Settings::Manager::getBool("best attack", "Game"))
|
if (Settings::Manager::getBool("best attack", "Game"))
|
||||||
{
|
{
|
||||||
MWWorld::ConstContainerStoreIterator weapon = mPtr.getClass().getInventoryStore(mPtr).getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
MWWorld::ConstContainerStoreIterator weapon = mPtr.getClass().getInventoryStore(mPtr).getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||||
mAttackType = getBestAttack(weapon->get<ESM::Weapon>()->mBase);
|
mAttackType = getBestAttack(weapon->get<ESM::Weapon>()->mBase);
|
||||||
|
@ -1476,19 +1537,32 @@ bool CharacterController::updateWeaponState()
|
||||||
setAttackTypeBasedOnMovement();
|
setAttackTypeBasedOnMovement();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
setAttackTypeRandomly(mAttackType);
|
{
|
||||||
|
// There is no "best attack" for Hand-to-Hand
|
||||||
|
setAttackTypeRandomly(mAttackType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// else if (mPtr != getPlayer()) use mAttackType set by AiCombat
|
// else if (mPtr != getPlayer()) use mAttackType set by AiCombat
|
||||||
|
startKey = mAttackType+" start";
|
||||||
|
stopKey = mAttackType+" min attack";
|
||||||
}
|
}
|
||||||
|
|
||||||
mAnimation->play(mCurrentWeapon, priorityWeapon,
|
mAnimation->play(mCurrentWeapon, priorityWeapon,
|
||||||
MWRender::Animation::BlendMask_All, false,
|
MWRender::Animation::BlendMask_All, false,
|
||||||
weapSpeed, mAttackType+" start", mAttackType+" min attack",
|
weapSpeed, startKey, stopKey,
|
||||||
0.0f, 0);
|
0.0f, 0);
|
||||||
mUpperBodyState = UpperCharState_StartToMinAttack;
|
mUpperBodyState = UpperCharState_StartToMinAttack;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We should reset player's idle animation in the first-person mode.
|
||||||
|
if (resetIdle && mPtr == player && MWBase::Environment::get().getWorld()->isFirstPerson())
|
||||||
|
mIdleState = CharState_None;
|
||||||
|
|
||||||
|
// In other cases we should not break swim and sneak animations
|
||||||
|
if (resetIdle && mIdleState != CharState_IdleSneak && mIdleState != CharState_IdleSwim)
|
||||||
|
mIdleState = CharState_None;
|
||||||
|
|
||||||
animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete);
|
animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete);
|
||||||
if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack && !isKnockedDown())
|
if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack && !isKnockedDown())
|
||||||
mAttackStrength = complete;
|
mAttackStrength = complete;
|
||||||
|
@ -1600,16 +1674,11 @@ bool CharacterController::updateWeaponState()
|
||||||
else if(mUpperBodyState == UpperCharState_UnEquipingWeap)
|
else if(mUpperBodyState == UpperCharState_UnEquipingWeap)
|
||||||
mUpperBodyState = UpperCharState_Nothing;
|
mUpperBodyState = UpperCharState_Nothing;
|
||||||
}
|
}
|
||||||
else if(complete >= 1.0f)
|
else if(complete >= 1.0f && !isRandomAttackAnimation(mCurrentWeapon))
|
||||||
{
|
{
|
||||||
std::string start, stop;
|
std::string start, stop;
|
||||||
switch(mUpperBodyState)
|
switch(mUpperBodyState)
|
||||||
{
|
{
|
||||||
case UpperCharState_StartToMinAttack:
|
|
||||||
start = mAttackType+" min attack";
|
|
||||||
stop = mAttackType+" max attack";
|
|
||||||
mUpperBodyState = UpperCharState_MinAttackToMaxAttack;
|
|
||||||
break;
|
|
||||||
case UpperCharState_MinAttackToMaxAttack:
|
case UpperCharState_MinAttackToMaxAttack:
|
||||||
//hack to avoid body pos desync when jumping/sneaking in 'max attack' state
|
//hack to avoid body pos desync when jumping/sneaking in 'max attack' state
|
||||||
if(!mAnimation->isPlaying(mCurrentWeapon))
|
if(!mAnimation->isPlaying(mCurrentWeapon))
|
||||||
|
@ -1617,6 +1686,23 @@ bool CharacterController::updateWeaponState()
|
||||||
MWRender::Animation::BlendMask_All, false,
|
MWRender::Animation::BlendMask_All, false,
|
||||||
0, mAttackType+" min attack", mAttackType+" max attack", 0.999f, 0);
|
0, mAttackType+" min attack", mAttackType+" max attack", 0.999f, 0);
|
||||||
break;
|
break;
|
||||||
|
case UpperCharState_StartToMinAttack:
|
||||||
|
{
|
||||||
|
// If actor is already stopped preparing attack, do not play the "min attack -> max attack" part.
|
||||||
|
// Happens if the player did not hold the attack button.
|
||||||
|
// Note: if the "min attack"->"max attack" is a stub, "play" it anyway. Attack strength will be 1.
|
||||||
|
float minAttackTime = mAnimation->getTextKeyTime(mCurrentWeapon+": "+mAttackType+" "+"min attack");
|
||||||
|
float maxAttackTime = mAnimation->getTextKeyTime(mCurrentWeapon+": "+mAttackType+" "+"max attack");
|
||||||
|
if (mAttackingOrSpell || minAttackTime == maxAttackTime)
|
||||||
|
{
|
||||||
|
start = mAttackType+" min attack";
|
||||||
|
stop = mAttackType+" max attack";
|
||||||
|
mUpperBodyState = UpperCharState_MinAttackToMaxAttack;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
playSwishSound(0.0f);
|
||||||
|
}
|
||||||
|
// Fall-through
|
||||||
case UpperCharState_MaxAttackToMinHit:
|
case UpperCharState_MaxAttackToMinHit:
|
||||||
if(mAttackType == "shoot")
|
if(mAttackType == "shoot")
|
||||||
{
|
{
|
||||||
|
@ -1652,21 +1738,30 @@ bool CharacterController::updateWeaponState()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: apply reload animations only for upper body since blending with movement animations can give weird result.
|
// Note: apply crossbow reload animation only for upper body
|
||||||
// Especially noticable with crossbow reload animation.
|
// since blending with movement animations can give weird result.
|
||||||
if(!start.empty())
|
if(!start.empty())
|
||||||
{
|
{
|
||||||
|
int mask = MWRender::Animation::BlendMask_All;
|
||||||
|
if (mWeaponType == WeapType_Crossbow)
|
||||||
|
mask = MWRender::Animation::BlendMask_UpperBody;
|
||||||
|
|
||||||
mAnimation->disable(mCurrentWeapon);
|
mAnimation->disable(mCurrentWeapon);
|
||||||
if (mUpperBodyState == UpperCharState_FollowStartToFollowStop)
|
if (mUpperBodyState == UpperCharState_FollowStartToFollowStop)
|
||||||
mAnimation->play(mCurrentWeapon, priorityWeapon,
|
mAnimation->play(mCurrentWeapon, priorityWeapon,
|
||||||
MWRender::Animation::BlendMask_UpperBody, true,
|
mask, true,
|
||||||
weapSpeed, start, stop, 0.0f, 0);
|
weapSpeed, start, stop, 0.0f, 0);
|
||||||
else
|
else
|
||||||
mAnimation->play(mCurrentWeapon, priorityWeapon,
|
mAnimation->play(mCurrentWeapon, priorityWeapon,
|
||||||
MWRender::Animation::BlendMask_UpperBody, false,
|
mask, false,
|
||||||
weapSpeed, start, stop, 0.0f, 0);
|
weapSpeed, start, stop, 0.0f, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if(complete >= 1.0f && isRandomAttackAnimation(mCurrentWeapon))
|
||||||
|
{
|
||||||
|
mAnimation->disable(mCurrentWeapon);
|
||||||
|
mUpperBodyState = UpperCharState_WeapEquiped;
|
||||||
|
}
|
||||||
|
|
||||||
if (mPtr.getClass().hasInventoryStore(mPtr))
|
if (mPtr.getClass().hasInventoryStore(mPtr))
|
||||||
{
|
{
|
||||||
|
@ -1729,10 +1824,11 @@ void CharacterController::update(float duration)
|
||||||
else if(!cls.getCreatureStats(mPtr).isDead())
|
else if(!cls.getCreatureStats(mPtr).isDead())
|
||||||
{
|
{
|
||||||
bool onground = world->isOnGround(mPtr);
|
bool onground = world->isOnGround(mPtr);
|
||||||
|
bool incapacitated = (cls.getCreatureStats(mPtr).isParalyzed() || cls.getCreatureStats(mPtr).getKnockedDown());
|
||||||
bool inwater = world->isSwimming(mPtr);
|
bool inwater = world->isSwimming(mPtr);
|
||||||
bool sneak = cls.getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Sneak);
|
|
||||||
bool flying = world->isFlying(mPtr);
|
bool flying = world->isFlying(mPtr);
|
||||||
// Can't run while flying (see speed formula in Npc/Creature::getSpeed)
|
// Can't run and sneak while flying (see speed formula in Npc/Creature::getSpeed)
|
||||||
|
bool sneak = cls.getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Sneak) && !flying;
|
||||||
bool isrunning = cls.getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Run) && !flying;
|
bool isrunning = cls.getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Run) && !flying;
|
||||||
CreatureStats &stats = cls.getCreatureStats(mPtr);
|
CreatureStats &stats = cls.getCreatureStats(mPtr);
|
||||||
|
|
||||||
|
@ -1811,14 +1907,14 @@ void CharacterController::update(float duration)
|
||||||
// reduce fatigue
|
// reduce fatigue
|
||||||
const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
|
const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
|
||||||
float fatigueLoss = 0;
|
float fatigueLoss = 0;
|
||||||
static const float fFatigueRunBase = gmst.find("fFatigueRunBase")->getFloat();
|
static const float fFatigueRunBase = gmst.find("fFatigueRunBase")->mValue.getFloat();
|
||||||
static const float fFatigueRunMult = gmst.find("fFatigueRunMult")->getFloat();
|
static const float fFatigueRunMult = gmst.find("fFatigueRunMult")->mValue.getFloat();
|
||||||
static const float fFatigueSwimWalkBase = gmst.find("fFatigueSwimWalkBase")->getFloat();
|
static const float fFatigueSwimWalkBase = gmst.find("fFatigueSwimWalkBase")->mValue.getFloat();
|
||||||
static const float fFatigueSwimRunBase = gmst.find("fFatigueSwimRunBase")->getFloat();
|
static const float fFatigueSwimRunBase = gmst.find("fFatigueSwimRunBase")->mValue.getFloat();
|
||||||
static const float fFatigueSwimWalkMult = gmst.find("fFatigueSwimWalkMult")->getFloat();
|
static const float fFatigueSwimWalkMult = gmst.find("fFatigueSwimWalkMult")->mValue.getFloat();
|
||||||
static const float fFatigueSwimRunMult = gmst.find("fFatigueSwimRunMult")->getFloat();
|
static const float fFatigueSwimRunMult = gmst.find("fFatigueSwimRunMult")->mValue.getFloat();
|
||||||
static const float fFatigueSneakBase = gmst.find("fFatigueSneakBase")->getFloat();
|
static const float fFatigueSneakBase = gmst.find("fFatigueSneakBase")->mValue.getFloat();
|
||||||
static const float fFatigueSneakMult = gmst.find("fFatigueSneakMult")->getFloat();
|
static const float fFatigueSneakMult = gmst.find("fFatigueSneakMult")->mValue.getFloat();
|
||||||
|
|
||||||
if (cls.getEncumbrance(mPtr) <= cls.getCapacity(mPtr))
|
if (cls.getEncumbrance(mPtr) <= cls.getCapacity(mPtr))
|
||||||
{
|
{
|
||||||
|
@ -1847,7 +1943,7 @@ void CharacterController::update(float duration)
|
||||||
cls.getCreatureStats(mPtr).setFatigue(fatigue);
|
cls.getCreatureStats(mPtr).setFatigue(fatigue);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(sneak || inwater || flying)
|
if(sneak || inwater || flying || incapacitated)
|
||||||
vec.z() = 0.0f;
|
vec.z() = 0.0f;
|
||||||
|
|
||||||
bool inJump = true;
|
bool inJump = true;
|
||||||
|
@ -1858,8 +1954,8 @@ void CharacterController::update(float duration)
|
||||||
forcestateupdate = (mJumpState != JumpState_InAir);
|
forcestateupdate = (mJumpState != JumpState_InAir);
|
||||||
jumpstate = JumpState_InAir;
|
jumpstate = JumpState_InAir;
|
||||||
|
|
||||||
static const float fJumpMoveBase = gmst.find("fJumpMoveBase")->getFloat();
|
static const float fJumpMoveBase = gmst.find("fJumpMoveBase")->mValue.getFloat();
|
||||||
static const float fJumpMoveMult = gmst.find("fJumpMoveMult")->getFloat();
|
static const float fJumpMoveMult = gmst.find("fJumpMoveMult")->mValue.getFloat();
|
||||||
float factor = fJumpMoveBase + fJumpMoveMult * mPtr.getClass().getSkill(mPtr, ESM::Skill::Acrobatics)/100.f;
|
float factor = fJumpMoveBase + fJumpMoveMult * mPtr.getClass().getSkill(mPtr, ESM::Skill::Acrobatics)/100.f;
|
||||||
factor = std::min(1.f, factor);
|
factor = std::min(1.f, factor);
|
||||||
vec.x() *= factor;
|
vec.x() *= factor;
|
||||||
|
@ -1886,8 +1982,8 @@ void CharacterController::update(float duration)
|
||||||
cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 0);
|
cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 0);
|
||||||
|
|
||||||
// decrease fatigue
|
// decrease fatigue
|
||||||
const float fatigueJumpBase = gmst.find("fFatigueJumpBase")->getFloat();
|
const float fatigueJumpBase = gmst.find("fFatigueJumpBase")->mValue.getFloat();
|
||||||
const float fatigueJumpMult = gmst.find("fFatigueJumpMult")->getFloat();
|
const float fatigueJumpMult = gmst.find("fFatigueJumpMult")->mValue.getFloat();
|
||||||
float normalizedEncumbrance = mPtr.getClass().getNormalizedEncumbrance(mPtr);
|
float normalizedEncumbrance = mPtr.getClass().getNormalizedEncumbrance(mPtr);
|
||||||
if (normalizedEncumbrance > 1)
|
if (normalizedEncumbrance > 1)
|
||||||
normalizedEncumbrance = 1;
|
normalizedEncumbrance = 1;
|
||||||
|
@ -1916,17 +2012,15 @@ void CharacterController::update(float duration)
|
||||||
// inflict fall damages
|
// inflict fall damages
|
||||||
if (!godmode)
|
if (!godmode)
|
||||||
{
|
{
|
||||||
DynamicStat<float> health = cls.getCreatureStats(mPtr).getHealth();
|
|
||||||
float realHealthLost = static_cast<float>(healthLost * (1.0f - 0.25f * fatigueTerm));
|
float realHealthLost = static_cast<float>(healthLost * (1.0f - 0.25f * fatigueTerm));
|
||||||
health.setCurrent(health.getCurrent() - realHealthLost);
|
|
||||||
cls.getCreatureStats(mPtr).setHealth(health);
|
|
||||||
cls.onHit(mPtr, realHealthLost, true, MWWorld::Ptr(), MWWorld::Ptr(), osg::Vec3f(), true);
|
cls.onHit(mPtr, realHealthLost, true, MWWorld::Ptr(), MWWorld::Ptr(), osg::Vec3f(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
const int acrobaticsSkill = cls.getSkill(mPtr, ESM::Skill::Acrobatics);
|
const int acrobaticsSkill = cls.getSkill(mPtr, ESM::Skill::Acrobatics);
|
||||||
if (healthLost > (acrobaticsSkill * fatigueTerm))
|
if (healthLost > (acrobaticsSkill * fatigueTerm))
|
||||||
{
|
{
|
||||||
cls.getCreatureStats(mPtr).setKnockedDown(true);
|
if (!godmode)
|
||||||
|
cls.getCreatureStats(mPtr).setKnockedDown(true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1935,6 +2029,12 @@ void CharacterController::update(float duration)
|
||||||
cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 1);
|
cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Play landing sound
|
||||||
|
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||||
|
std::string sound = cls.getSoundIdFromSndGen(mPtr, "land");
|
||||||
|
if (!sound.empty())
|
||||||
|
sndMgr->playSound3D(mPtr, sound, 1.f, 1.f, MWSound::Type::Foot, MWSound::PlayMode::NoPlayerLocal);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1944,6 +2044,12 @@ void CharacterController::update(float duration)
|
||||||
|
|
||||||
inJump = false;
|
inJump = false;
|
||||||
|
|
||||||
|
// Do not play turning animation for player if rotation speed is very slow.
|
||||||
|
// Actual threshold should take framerate in account.
|
||||||
|
float rotationThreshold = 0;
|
||||||
|
if (mPtr == getPlayer())
|
||||||
|
rotationThreshold = 0.015 * 60 * duration;
|
||||||
|
|
||||||
if(std::abs(vec.x()/2.0f) > std::abs(vec.y()))
|
if(std::abs(vec.x()/2.0f) > std::abs(vec.y()))
|
||||||
{
|
{
|
||||||
if(vec.x() > 0.0f)
|
if(vec.x() > 0.0f)
|
||||||
|
@ -1968,26 +2074,38 @@ void CharacterController::update(float duration)
|
||||||
}
|
}
|
||||||
else if(rot.z() != 0.0f && !sneak && !(mPtr == getPlayer() && MWBase::Environment::get().getWorld()->isFirstPerson()))
|
else if(rot.z() != 0.0f && !sneak && !(mPtr == getPlayer() && MWBase::Environment::get().getWorld()->isFirstPerson()))
|
||||||
{
|
{
|
||||||
if(rot.z() > 0.0f)
|
if(rot.z() > rotationThreshold)
|
||||||
{
|
|
||||||
movestate = inwater ? CharState_SwimTurnRight : CharState_TurnRight;
|
movestate = inwater ? CharState_SwimTurnRight : CharState_TurnRight;
|
||||||
mAnimation->disable(mCurrentJump);
|
else if(rot.z() < -rotationThreshold)
|
||||||
}
|
|
||||||
else if(rot.z() < 0.0f)
|
|
||||||
{
|
|
||||||
movestate = inwater ? CharState_SwimTurnLeft : CharState_TurnLeft;
|
movestate = inwater ? CharState_SwimTurnLeft : CharState_TurnLeft;
|
||||||
mAnimation->disable(mCurrentJump);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mTurnAnimationThreshold -= duration;
|
// Player can not use smooth turning as NPCs, so we play turning animation a bit to avoid jittering
|
||||||
if (isTurning())
|
if (mPtr == getPlayer())
|
||||||
mTurnAnimationThreshold = 0.05f;
|
|
||||||
else if (movestate == CharState_None && isTurning()
|
|
||||||
&& mTurnAnimationThreshold > 0)
|
|
||||||
{
|
{
|
||||||
movestate = mMovementState;
|
float threshold = mCurrentMovement.find("swim") == std::string::npos ? 0.4f : 0.8f;
|
||||||
|
float complete;
|
||||||
|
bool animPlaying = mAnimation->getInfo(mCurrentMovement, &complete);
|
||||||
|
if (movestate == CharState_None && isTurning())
|
||||||
|
{
|
||||||
|
if (animPlaying && complete < threshold)
|
||||||
|
movestate = mMovementState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mTurnAnimationThreshold -= duration;
|
||||||
|
if (movestate == CharState_TurnRight || movestate == CharState_TurnLeft ||
|
||||||
|
movestate == CharState_SwimTurnRight || movestate == CharState_SwimTurnLeft)
|
||||||
|
{
|
||||||
|
mTurnAnimationThreshold = 0.05f;
|
||||||
|
}
|
||||||
|
else if (movestate == CharState_None && isTurning()
|
||||||
|
&& mTurnAnimationThreshold > 0)
|
||||||
|
{
|
||||||
|
movestate = mMovementState;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(movestate != CharState_None && !isTurning())
|
if(movestate != CharState_None && !isTurning())
|
||||||
|
@ -1995,7 +2113,16 @@ void CharacterController::update(float duration)
|
||||||
|
|
||||||
if(mAnimQueue.empty() || inwater || sneak)
|
if(mAnimQueue.empty() || inwater || sneak)
|
||||||
{
|
{
|
||||||
idlestate = (inwater ? CharState_IdleSwim : (sneak && !inJump ? CharState_IdleSneak : CharState_Idle));
|
// Note: turning animations should not interrupt idle ones.
|
||||||
|
// Also movement should not stop idle animation for spellcasting stance.
|
||||||
|
if (inwater)
|
||||||
|
idlestate = CharState_IdleSwim;
|
||||||
|
else if (sneak && !inJump)
|
||||||
|
idlestate = CharState_IdleSneak;
|
||||||
|
else if (movestate != CharState_None && !isTurning() && mWeaponType != WeapType_Spell)
|
||||||
|
idlestate = CharState_None;
|
||||||
|
else
|
||||||
|
idlestate = CharState_Idle;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
updateAnimQueue();
|
updateAnimQueue();
|
||||||
|
@ -2017,8 +2144,10 @@ void CharacterController::update(float duration)
|
||||||
|
|
||||||
if (isTurning())
|
if (isTurning())
|
||||||
{
|
{
|
||||||
|
// Adjust animation speed from 1.0 to 1.5 multiplier
|
||||||
|
float turnSpeed = std::min(1.5f, std::abs(rot.z()) / duration / static_cast<float>(osg::PI));
|
||||||
if (duration > 0)
|
if (duration > 0)
|
||||||
mAnimation->adjustSpeedMult(mCurrentMovement, std::min(1.5f, std::abs(rot.z()) / duration / static_cast<float>(osg::PI)));
|
mAnimation->adjustSpeedMult(mCurrentMovement, std::max(turnSpeed, 1.0f));
|
||||||
}
|
}
|
||||||
else if (mMovementState != CharState_None && mAdjustMovementAnimSpeed)
|
else if (mMovementState != CharState_None && mAdjustMovementAnimSpeed)
|
||||||
{
|
{
|
||||||
|
@ -2095,9 +2224,6 @@ void CharacterController::update(float duration)
|
||||||
moved *= (l / newLength);
|
moved *= (l / newLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mSkipAnim)
|
|
||||||
mAnimation->updateEffects(duration);
|
|
||||||
|
|
||||||
if (mFloatToSurface && cls.isActor() && cls.getCreatureStats(mPtr).isDead() && cls.canSwim(mPtr))
|
if (mFloatToSurface && cls.isActor() && cls.getCreatureStats(mPtr).isDead() && cls.canSwim(mPtr))
|
||||||
moved.z() = 1.0;
|
moved.z() = 1.0;
|
||||||
|
|
||||||
|
@ -2385,7 +2511,14 @@ void CharacterController::setAttackTypeBasedOnMovement()
|
||||||
mAttackType = "chop";
|
mAttackType = "chop";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CharacterController::isAttackPrepairing() const
|
bool CharacterController::isRandomAttackAnimation(const std::string& group) const
|
||||||
|
{
|
||||||
|
return (group == "attack1" || group == "swimattack1" ||
|
||||||
|
group == "attack2" || group == "swimattack2" ||
|
||||||
|
group == "attack3" || group == "swimattack3");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CharacterController::isAttackPreparing() const
|
||||||
{
|
{
|
||||||
return mUpperBodyState == UpperCharState_StartToMinAttack ||
|
return mUpperBodyState == UpperCharState_StartToMinAttack ||
|
||||||
mUpperBodyState == UpperCharState_MinAttackToMaxAttack;
|
mUpperBodyState == UpperCharState_MinAttackToMaxAttack;
|
||||||
|
@ -2486,7 +2619,7 @@ void CharacterController::setAttackTypeRandomly(std::string& attackType)
|
||||||
bool CharacterController::readyToPrepareAttack() const
|
bool CharacterController::readyToPrepareAttack() const
|
||||||
{
|
{
|
||||||
return (mHitState == CharState_None || mHitState == CharState_Block)
|
return (mHitState == CharState_None || mHitState == CharState_Block)
|
||||||
&& mUpperBodyState <= UpperCharState_WeapEquiped;
|
&& mUpperBodyState <= UpperCharState_WeapEquiped;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CharacterController::readyToStartAttack() const
|
bool CharacterController::readyToStartAttack() const
|
||||||
|
|
|
@ -31,8 +31,10 @@ enum Priority {
|
||||||
Priority_WeaponLowerBody,
|
Priority_WeaponLowerBody,
|
||||||
Priority_SneakIdleLowerBody,
|
Priority_SneakIdleLowerBody,
|
||||||
Priority_SwimIdle,
|
Priority_SwimIdle,
|
||||||
Priority_Jump,
|
|
||||||
Priority_Movement,
|
Priority_Movement,
|
||||||
|
// Note: in vanilla movement anims have higher priority than jump ones.
|
||||||
|
// It causes issues with landing animations during movement.
|
||||||
|
Priority_Jump,
|
||||||
Priority_Hit,
|
Priority_Hit,
|
||||||
Priority_Weapon,
|
Priority_Weapon,
|
||||||
Priority_Block,
|
Priority_Block,
|
||||||
|
@ -222,6 +224,9 @@ class CharacterController : public MWRender::Animation::TextKeyListener
|
||||||
bool updateCreatureState();
|
bool updateCreatureState();
|
||||||
void updateIdleStormState(bool inwater);
|
void updateIdleStormState(bool inwater);
|
||||||
|
|
||||||
|
std::string chooseRandomAttackAnimation() const;
|
||||||
|
bool isRandomAttackAnimation(const std::string& group) const;
|
||||||
|
|
||||||
bool isPersistentAnimPlaying();
|
bool isPersistentAnimPlaying();
|
||||||
|
|
||||||
void updateAnimQueue();
|
void updateAnimQueue();
|
||||||
|
@ -276,7 +281,7 @@ public:
|
||||||
|
|
||||||
void forceStateUpdate();
|
void forceStateUpdate();
|
||||||
|
|
||||||
bool isAttackPrepairing() const;
|
bool isAttackPreparing() const;
|
||||||
bool isCastingSpell() const;
|
bool isCastingSpell() const;
|
||||||
bool isReadyToBlock() const;
|
bool isReadyToBlock() const;
|
||||||
bool isKnockedDown() const;
|
bool isKnockedDown() const;
|
||||||
|
|
|
@ -82,9 +82,9 @@ namespace MWMechanics
|
||||||
osg::Vec3f(0,0,1)));
|
osg::Vec3f(0,0,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>();
|
||||||
if (angleDegrees < gmst.find("fCombatBlockLeftAngle")->getFloat())
|
if (angleDegrees < gmst.find("fCombatBlockLeftAngle")->mValue.getFloat())
|
||||||
return false;
|
return false;
|
||||||
if (angleDegrees > gmst.find("fCombatBlockRightAngle")->getFloat())
|
if (angleDegrees > gmst.find("fCombatBlockRightAngle")->mValue.getFloat())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
MWMechanics::CreatureStats& attackerStats = attacker.getClass().getCreatureStats(attacker);
|
MWMechanics::CreatureStats& attackerStats = attacker.getClass().getCreatureStats(attacker);
|
||||||
|
@ -92,11 +92,11 @@ namespace MWMechanics
|
||||||
float blockTerm = blocker.getClass().getSkill(blocker, ESM::Skill::Block) + 0.2f * blockerStats.getAttribute(ESM::Attribute::Agility).getModified()
|
float blockTerm = blocker.getClass().getSkill(blocker, ESM::Skill::Block) + 0.2f * blockerStats.getAttribute(ESM::Attribute::Agility).getModified()
|
||||||
+ 0.1f * blockerStats.getAttribute(ESM::Attribute::Luck).getModified();
|
+ 0.1f * blockerStats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||||
float enemySwing = attackStrength;
|
float enemySwing = attackStrength;
|
||||||
float swingTerm = enemySwing * gmst.find("fSwingBlockMult")->getFloat() + gmst.find("fSwingBlockBase")->getFloat();
|
float swingTerm = enemySwing * gmst.find("fSwingBlockMult")->mValue.getFloat() + gmst.find("fSwingBlockBase")->mValue.getFloat();
|
||||||
|
|
||||||
float blockerTerm = blockTerm * swingTerm;
|
float blockerTerm = blockTerm * swingTerm;
|
||||||
if (blocker.getClass().getMovementSettings(blocker).mPosition[1] <= 0)
|
if (blocker.getClass().getMovementSettings(blocker).mPosition[1] <= 0)
|
||||||
blockerTerm *= gmst.find("fBlockStillBonus")->getFloat();
|
blockerTerm *= gmst.find("fBlockStillBonus")->mValue.getFloat();
|
||||||
blockerTerm *= blockerStats.getFatigueTerm();
|
blockerTerm *= blockerStats.getFatigueTerm();
|
||||||
|
|
||||||
int attackerSkill = 0;
|
int attackerSkill = 0;
|
||||||
|
@ -109,8 +109,8 @@ namespace MWMechanics
|
||||||
attackerTerm *= attackerStats.getFatigueTerm();
|
attackerTerm *= attackerStats.getFatigueTerm();
|
||||||
|
|
||||||
int x = int(blockerTerm - attackerTerm);
|
int x = int(blockerTerm - attackerTerm);
|
||||||
int iBlockMaxChance = gmst.find("iBlockMaxChance")->getInt();
|
int iBlockMaxChance = gmst.find("iBlockMaxChance")->mValue.getInteger();
|
||||||
int iBlockMinChance = gmst.find("iBlockMinChance")->getInt();
|
int iBlockMinChance = gmst.find("iBlockMinChance")->mValue.getInteger();
|
||||||
x = std::min(iBlockMaxChance, std::max(iBlockMinChance, x));
|
x = std::min(iBlockMaxChance, std::max(iBlockMinChance, x));
|
||||||
|
|
||||||
if (Misc::Rng::roll0to99() < x)
|
if (Misc::Rng::roll0to99() < x)
|
||||||
|
@ -126,9 +126,9 @@ namespace MWMechanics
|
||||||
inv.unequipItem(*shield, blocker);
|
inv.unequipItem(*shield, blocker);
|
||||||
}
|
}
|
||||||
// Reduce blocker fatigue
|
// Reduce blocker fatigue
|
||||||
const float fFatigueBlockBase = gmst.find("fFatigueBlockBase")->getFloat();
|
const float fFatigueBlockBase = gmst.find("fFatigueBlockBase")->mValue.getFloat();
|
||||||
const float fFatigueBlockMult = gmst.find("fFatigueBlockMult")->getFloat();
|
const float fFatigueBlockMult = gmst.find("fFatigueBlockMult")->mValue.getFloat();
|
||||||
const float fWeaponFatigueBlockMult = gmst.find("fWeaponFatigueBlockMult")->getFloat();
|
const float fWeaponFatigueBlockMult = gmst.find("fWeaponFatigueBlockMult")->mValue.getFloat();
|
||||||
MWMechanics::DynamicStat<float> fatigue = blockerStats.getFatigue();
|
MWMechanics::DynamicStat<float> fatigue = blockerStats.getFatigue();
|
||||||
float normalizedEncumbrance = blocker.getClass().getNormalizedEncumbrance(blocker);
|
float normalizedEncumbrance = blocker.getClass().getNormalizedEncumbrance(blocker);
|
||||||
normalizedEncumbrance = std::min(1.f, normalizedEncumbrance);
|
normalizedEncumbrance = std::min(1.f, normalizedEncumbrance);
|
||||||
|
@ -166,7 +166,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
if ((weapon.get<ESM::Weapon>()->mBase->mData.mFlags & ESM::Weapon::Silver)
|
if ((weapon.get<ESM::Weapon>()->mBase->mData.mFlags & ESM::Weapon::Silver)
|
||||||
&& actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf())
|
&& actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf())
|
||||||
damage *= MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fWereWolfSilverWeaponDamageMult")->getFloat();
|
damage *= MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fWereWolfSilverWeaponDamageMult")->mValue.getFloat();
|
||||||
|
|
||||||
if (damage == 0 && attacker == getPlayer())
|
if (damage == 0 && attacker == getPlayer())
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResistsWeapons}");
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResistsWeapons}");
|
||||||
|
@ -209,11 +209,24 @@ namespace MWMechanics
|
||||||
|
|
||||||
adjustWeaponDamage(damage, weapon, attacker);
|
adjustWeaponDamage(damage, weapon, attacker);
|
||||||
|
|
||||||
if(attacker == getPlayer())
|
if (attacker == getPlayer())
|
||||||
|
{
|
||||||
attacker.getClass().skillUsageSucceeded(attacker, weaponSkill, 0);
|
attacker.getClass().skillUsageSucceeded(attacker, weaponSkill, 0);
|
||||||
|
const MWMechanics::AiSequence& sequence = victim.getClass().getCreatureStats(victim).getAiSequence();
|
||||||
|
|
||||||
|
bool unaware = !sequence.isInCombat()
|
||||||
|
&& !MWBase::Environment::get().getMechanicsManager()->awarenessCheck(attacker, victim);
|
||||||
|
|
||||||
|
if (unaware)
|
||||||
|
{
|
||||||
|
damage *= gmst.find("fCombatCriticalStrikeMult")->mValue.getFloat();
|
||||||
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sTargetCriticalStrike}");
|
||||||
|
MWBase::Environment::get().getSoundManager()->playSound3D(victim, "critical damage", 1.0f, 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (victim.getClass().getCreatureStats(victim).getKnockedDown())
|
if (victim.getClass().getCreatureStats(victim).getKnockedDown())
|
||||||
damage *= gmst.find("fCombatKODamageMult")->getFloat();
|
damage *= gmst.find("fCombatKODamageMult")->mValue.getFloat();
|
||||||
}
|
}
|
||||||
|
|
||||||
reduceWeaponCondition(damage, validVictim, weapon, attacker);
|
reduceWeaponCondition(damage, validVictim, weapon, attacker);
|
||||||
|
@ -228,7 +241,7 @@ namespace MWMechanics
|
||||||
// Non-enchanted arrows shot at enemies have a chance to turn up in their inventory
|
// Non-enchanted arrows shot at enemies have a chance to turn up in their inventory
|
||||||
if (victim != getPlayer() && !appliedEnchantment)
|
if (victim != getPlayer() && !appliedEnchantment)
|
||||||
{
|
{
|
||||||
float fProjectileThrownStoreChance = gmst.find("fProjectileThrownStoreChance")->getFloat();
|
float fProjectileThrownStoreChance = gmst.find("fProjectileThrownStoreChance")->mValue.getFloat();
|
||||||
if (Misc::Rng::rollProbability() < fProjectileThrownStoreChance / 100.f)
|
if (Misc::Rng::rollProbability() < fProjectileThrownStoreChance / 100.f)
|
||||||
victim.getClass().getContainerStore(victim).add(projectile, 1, victim);
|
victim.getClass().getContainerStore(victim).add(projectile, 1, victim);
|
||||||
}
|
}
|
||||||
|
@ -260,10 +273,10 @@ namespace MWMechanics
|
||||||
defenseTerm = victimStats.getEvasion();
|
defenseTerm = victimStats.getEvasion();
|
||||||
}
|
}
|
||||||
defenseTerm += std::min(100.f,
|
defenseTerm += std::min(100.f,
|
||||||
gmst.find("fCombatInvisoMult")->getFloat() *
|
gmst.find("fCombatInvisoMult")->mValue.getFloat() *
|
||||||
victimStats.getMagicEffects().get(ESM::MagicEffect::Chameleon).getMagnitude());
|
victimStats.getMagicEffects().get(ESM::MagicEffect::Chameleon).getMagnitude());
|
||||||
defenseTerm += std::min(100.f,
|
defenseTerm += std::min(100.f,
|
||||||
gmst.find("fCombatInvisoMult")->getFloat() *
|
gmst.find("fCombatInvisoMult")->mValue.getFloat() *
|
||||||
victimStats.getMagicEffects().get(ESM::MagicEffect::Invisibility).getMagnitude());
|
victimStats.getMagicEffects().get(ESM::MagicEffect::Invisibility).getMagnitude());
|
||||||
}
|
}
|
||||||
float attackTerm = skillValue +
|
float attackTerm = skillValue +
|
||||||
|
@ -309,7 +322,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
x = std::min(100.f, x + elementResistance);
|
x = std::min(100.f, x + elementResistance);
|
||||||
|
|
||||||
static const float fElementalShieldMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fElementalShieldMult")->getFloat();
|
static const float fElementalShieldMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fElementalShieldMult")->mValue.getFloat();
|
||||||
x = fElementalShieldMult * magnitude * (1.f - 0.01f * x);
|
x = fElementalShieldMult * magnitude * (1.f - 0.01f * x);
|
||||||
|
|
||||||
// Note swapped victim and attacker, since the attacker takes the damage here.
|
// Note swapped victim and attacker, since the attacker takes the damage here.
|
||||||
|
@ -339,7 +352,7 @@ namespace MWMechanics
|
||||||
// weapon condition does not degrade when godmode is on
|
// weapon condition does not degrade when godmode is on
|
||||||
if (!godmode)
|
if (!godmode)
|
||||||
{
|
{
|
||||||
const float fWeaponDamageMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fWeaponDamageMult")->getFloat();
|
const float fWeaponDamageMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fWeaponDamageMult")->mValue.getFloat();
|
||||||
float x = std::max(1.f, fWeaponDamageMult * damage);
|
float x = std::max(1.f, fWeaponDamageMult * damage);
|
||||||
|
|
||||||
weaphealth -= std::min(int(x), weaphealth);
|
weaphealth -= std::min(int(x), weaphealth);
|
||||||
|
@ -366,21 +379,18 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
static const float fDamageStrengthBase = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
static const float fDamageStrengthBase = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||||
.find("fDamageStrengthBase")->getFloat();
|
.find("fDamageStrengthBase")->mValue.getFloat();
|
||||||
static const float fDamageStrengthMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
static const float fDamageStrengthMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||||
.find("fDamageStrengthMult")->getFloat();
|
.find("fDamageStrengthMult")->mValue.getFloat();
|
||||||
damage *= fDamageStrengthBase +
|
damage *= fDamageStrengthBase +
|
||||||
(attacker.getClass().getCreatureStats(attacker).getAttribute(ESM::Attribute::Strength).getModified() * fDamageStrengthMult * 0.1f);
|
(attacker.getClass().getCreatureStats(attacker).getAttribute(ESM::Attribute::Strength).getModified() * fDamageStrengthMult * 0.1f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void getHandToHandDamage(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim, float &damage, bool &healthdmg, float attackStrength)
|
void getHandToHandDamage(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim, float &damage, bool &healthdmg, float attackStrength)
|
||||||
{
|
{
|
||||||
// Note: MCP contains an option to include Strength in hand-to-hand damage
|
|
||||||
// calculations. Some mods recommend using it, so we may want to include an
|
|
||||||
// option for it.
|
|
||||||
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
|
||||||
float minstrike = store.get<ESM::GameSetting>().find("fMinHandToHandMult")->getFloat();
|
float minstrike = store.get<ESM::GameSetting>().find("fMinHandToHandMult")->mValue.getFloat();
|
||||||
float maxstrike = store.get<ESM::GameSetting>().find("fMaxHandToHandMult")->getFloat();
|
float maxstrike = store.get<ESM::GameSetting>().find("fMaxHandToHandMult")->mValue.getFloat();
|
||||||
damage = static_cast<float>(attacker.getClass().getSkill(attacker, ESM::Skill::HandToHand));
|
damage = static_cast<float>(attacker.getClass().getSkill(attacker, ESM::Skill::HandToHand));
|
||||||
damage *= minstrike + ((maxstrike-minstrike)*attackStrength);
|
damage *= minstrike + ((maxstrike-minstrike)*attackStrength);
|
||||||
|
|
||||||
|
@ -388,6 +398,16 @@ namespace MWMechanics
|
||||||
healthdmg = otherstats.isParalyzed()
|
healthdmg = otherstats.isParalyzed()
|
||||||
|| otherstats.getKnockedDown();
|
|| otherstats.getKnockedDown();
|
||||||
bool isWerewolf = (attacker.getClass().isNpc() && attacker.getClass().getNpcStats(attacker).isWerewolf());
|
bool isWerewolf = (attacker.getClass().isNpc() && attacker.getClass().getNpcStats(attacker).isWerewolf());
|
||||||
|
|
||||||
|
// Options in the launcher's combo box: unarmedFactorsStrengthComboBox
|
||||||
|
// 0 = Do not factor strength into hand-to-hand combat.
|
||||||
|
// 1 = Factor into werewolf hand-to-hand combat.
|
||||||
|
// 2 = Ignore werewolves.
|
||||||
|
int factorStrength = Settings::Manager::getInt("strength influences hand to hand", "Game");
|
||||||
|
if (factorStrength == 1 || (factorStrength == 2 && !isWerewolf)) {
|
||||||
|
damage *= attacker.getClass().getCreatureStats(attacker).getAttribute(ESM::Attribute::Strength).getModified() / 40.0f;
|
||||||
|
}
|
||||||
|
|
||||||
if(isWerewolf)
|
if(isWerewolf)
|
||||||
{
|
{
|
||||||
healthdmg = true;
|
healthdmg = true;
|
||||||
|
@ -395,7 +415,7 @@ namespace MWMechanics
|
||||||
damage *= MWBase::Environment::get().getWorld()->getGlobalFloat("werewolfclawmult");
|
damage *= MWBase::Environment::get().getWorld()->getGlobalFloat("werewolfclawmult");
|
||||||
}
|
}
|
||||||
if(healthdmg)
|
if(healthdmg)
|
||||||
damage *= store.get<ESM::GameSetting>().find("fHandtoHandHealthPer")->getFloat();
|
damage *= store.get<ESM::GameSetting>().find("fHandtoHandHealthPer")->mValue.getFloat();
|
||||||
|
|
||||||
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||||
if(isWerewolf)
|
if(isWerewolf)
|
||||||
|
@ -412,9 +432,9 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
// somewhat of a guess, but using the weapon weight makes sense
|
// somewhat of a guess, but using the weapon weight makes sense
|
||||||
const MWWorld::Store<ESM::GameSetting>& store = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
const MWWorld::Store<ESM::GameSetting>& store = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||||
const float fFatigueAttackBase = store.find("fFatigueAttackBase")->getFloat();
|
const float fFatigueAttackBase = store.find("fFatigueAttackBase")->mValue.getFloat();
|
||||||
const float fFatigueAttackMult = store.find("fFatigueAttackMult")->getFloat();
|
const float fFatigueAttackMult = store.find("fFatigueAttackMult")->mValue.getFloat();
|
||||||
const float fWeaponFatigueMult = store.find("fWeaponFatigueMult")->getFloat();
|
const float fWeaponFatigueMult = store.find("fWeaponFatigueMult")->mValue.getFloat();
|
||||||
CreatureStats& stats = attacker.getClass().getCreatureStats(attacker);
|
CreatureStats& stats = attacker.getClass().getCreatureStats(attacker);
|
||||||
MWMechanics::DynamicStat<float> fatigue = stats.getFatigue();
|
MWMechanics::DynamicStat<float> fatigue = stats.getFatigue();
|
||||||
const float normalizedEncumbrance = attacker.getClass().getNormalizedEncumbrance(attacker);
|
const float normalizedEncumbrance = attacker.getClass().getNormalizedEncumbrance(attacker);
|
||||||
|
@ -439,9 +459,9 @@ namespace MWMechanics
|
||||||
float d = (pos1 - pos2).length();
|
float d = (pos1 - pos2).length();
|
||||||
|
|
||||||
static const int iFightDistanceBase = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
|
static const int iFightDistanceBase = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
|
||||||
"iFightDistanceBase")->getInt();
|
"iFightDistanceBase")->mValue.getInteger();
|
||||||
static const float fFightDistanceMultiplier = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
|
static const float fFightDistanceMultiplier = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
|
||||||
"fFightDistanceMultiplier")->getFloat();
|
"fFightDistanceMultiplier")->mValue.getFloat();
|
||||||
|
|
||||||
return (iFightDistanceBase - fFightDistanceMultiplier * d);
|
return (iFightDistanceBase - fFightDistanceMultiplier * d);
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,8 +48,8 @@ namespace MWMechanics
|
||||||
const MWWorld::Store<ESM::GameSetting> &gmst =
|
const MWWorld::Store<ESM::GameSetting> &gmst =
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||||
|
|
||||||
static const float fFatigueBase = gmst.find("fFatigueBase")->getFloat();
|
static const float fFatigueBase = gmst.find("fFatigueBase")->mValue.getFloat();
|
||||||
static const float fFatigueMult = gmst.find("fFatigueMult")->getFloat();
|
static const float fFatigueMult = gmst.find("fFatigueMult")->mValue.getFloat();
|
||||||
|
|
||||||
return fFatigueBase - fFatigueMult * (1-normalised);
|
return fFatigueBase - fFatigueMult * (1-normalised);
|
||||||
}
|
}
|
||||||
|
@ -195,6 +195,7 @@ namespace MWMechanics
|
||||||
mDead = true;
|
mDead = true;
|
||||||
|
|
||||||
mDynamic[index].setModifier(0);
|
mDynamic[index].setModifier(0);
|
||||||
|
mDynamic[index].setCurrentModifier(0);
|
||||||
mDynamic[index].setCurrent(0);
|
mDynamic[index].setCurrent(0);
|
||||||
|
|
||||||
if (MWBase::Environment::get().getWorld()->getGodModeState())
|
if (MWBase::Environment::get().getWorld()->getGodModeState())
|
||||||
|
|
|
@ -12,10 +12,12 @@ float scaleDamage(float damage, const MWWorld::Ptr& attacker, const MWWorld::Ptr
|
||||||
{
|
{
|
||||||
const MWWorld::Ptr& player = MWMechanics::getPlayer();
|
const MWWorld::Ptr& player = MWMechanics::getPlayer();
|
||||||
|
|
||||||
// [-100, 100]
|
// [-500, 500]
|
||||||
int difficultySetting = Settings::Manager::getInt("difficulty", "Game");
|
int difficultySetting = Settings::Manager::getInt("difficulty", "Game");
|
||||||
|
difficultySetting = std::min(difficultySetting, 500);
|
||||||
|
difficultySetting = std::max(difficultySetting, -500);
|
||||||
|
|
||||||
static const float fDifficultyMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fDifficultyMult")->getFloat();
|
static const float fDifficultyMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fDifficultyMult")->mValue.getFloat();
|
||||||
|
|
||||||
float difficultyTerm = 0.01f * difficultySetting;
|
float difficultyTerm = 0.01f * difficultySetting;
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
float fDiseaseXferChance =
|
float fDiseaseXferChance =
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
|
||||||
"fDiseaseXferChance")->getFloat();
|
"fDiseaseXferChance")->mValue.getFloat();
|
||||||
|
|
||||||
MagicEffects& actorEffects = actor.getClass().getCreatureStats(actor).getMagicEffects();
|
MagicEffects& actorEffects = actor.getClass().getCreatureStats(actor).getMagicEffects();
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ namespace MWMechanics
|
||||||
actor.getClass().getCreatureStats(actor).getSpells().add(it->first);
|
actor.getClass().getCreatureStats(actor).getSpells().add(it->first);
|
||||||
|
|
||||||
std::string msg = "sMagicContractDisease";
|
std::string msg = "sMagicContractDisease";
|
||||||
msg = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(msg)->getString();
|
msg = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(msg)->mValue.getString();
|
||||||
if (msg.find("%s") != std::string::npos)
|
if (msg.find("%s") != std::string::npos)
|
||||||
msg.replace(msg.find("%s"), 2, spell->mName);
|
msg.replace(msg.find("%s"), 2, spell->mName);
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox(msg);
|
MWBase::Environment::get().getWindowManager()->messageBox(msg);
|
||||||
|
|
|
@ -107,7 +107,7 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool powerfulSoul = getGemCharge() >= \
|
const bool powerfulSoul = getGemCharge() >= \
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find ("iSoulAmountForConstantEffect")->getInt();
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find ("iSoulAmountForConstantEffect")->mValue.getInteger();
|
||||||
if ((mObjectType == typeid(ESM::Armor).name()) || (mObjectType == typeid(ESM::Clothing).name()))
|
if ((mObjectType == typeid(ESM::Armor).name()) || (mObjectType == typeid(ESM::Clothing).name()))
|
||||||
{ // Armor or Clothing
|
{ // Armor or Clothing
|
||||||
switch(mCastStyle)
|
switch(mCastStyle)
|
||||||
|
@ -184,7 +184,7 @@ namespace MWMechanics
|
||||||
float magnitudeCost = (magMin + magMax) * baseCost * 0.05f;
|
float magnitudeCost = (magMin + magMax) * baseCost * 0.05f;
|
||||||
if (mCastStyle == ESM::Enchantment::ConstantEffect)
|
if (mCastStyle == ESM::Enchantment::ConstantEffect)
|
||||||
{
|
{
|
||||||
magnitudeCost *= store.get<ESM::GameSetting>().find("fEnchantmentConstantDurationMult")->getFloat();
|
magnitudeCost *= store.get<ESM::GameSetting>().find("fEnchantmentConstantDurationMult")->mValue.getFloat();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -193,7 +193,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
float areaCost = area * 0.05f * baseCost;
|
float areaCost = area * 0.05f * baseCost;
|
||||||
|
|
||||||
const float fEffectCostMult = store.get<ESM::GameSetting>().find("fEffectCostMult")->getFloat();
|
const float fEffectCostMult = store.get<ESM::GameSetting>().find("fEffectCostMult")->mValue.getFloat();
|
||||||
|
|
||||||
cost += (magnitudeCost + areaCost) * fEffectCostMult;
|
cost += (magnitudeCost + areaCost) * fEffectCostMult;
|
||||||
|
|
||||||
|
@ -230,7 +230,7 @@ namespace MWMechanics
|
||||||
if(mEnchanter.isEmpty())
|
if(mEnchanter.isEmpty())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
float priceMultipler = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find ("fEnchantmentValueMult")->getFloat();
|
float priceMultipler = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find ("fEnchantmentValueMult")->mValue.getFloat();
|
||||||
int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mEnchanter, static_cast<int>(getEnchantPoints() * priceMultipler), true);
|
int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mEnchanter, static_cast<int>(getEnchantPoints() * priceMultipler), true);
|
||||||
return price;
|
return price;
|
||||||
}
|
}
|
||||||
|
@ -256,7 +256,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
||||||
|
|
||||||
return static_cast<int>(mOldItemPtr.getClass().getEnchantmentPoints(mOldItemPtr) * store.get<ESM::GameSetting>().find("fEnchantmentMult")->getFloat());
|
return static_cast<int>(mOldItemPtr.getClass().getEnchantmentPoints(mOldItemPtr) * store.get<ESM::GameSetting>().find("fEnchantmentMult")->mValue.getFloat());
|
||||||
}
|
}
|
||||||
bool Enchanting::soulEmpty() const
|
bool Enchanting::soulEmpty() const
|
||||||
{
|
{
|
||||||
|
@ -288,8 +288,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
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>();
|
||||||
|
|
||||||
float chance2 = 7.5f / (gmst.find("fEnchantmentChanceMult")->getFloat() * ((mCastStyle == ESM::Enchantment::ConstantEffect) ?
|
float chance2 = 7.5f / (gmst.find("fEnchantmentChanceMult")->mValue.getFloat() * ((mCastStyle == ESM::Enchantment::ConstantEffect) ?
|
||||||
gmst.find("fEnchantmentConstantChanceMult")->getFloat() : 1.0f ))
|
gmst.find("fEnchantmentConstantChanceMult")->mValue.getFloat() : 1.0f ))
|
||||||
* getEnchantPoints();
|
* getEnchantPoints();
|
||||||
|
|
||||||
return (chance1-chance2);
|
return (chance1-chance2);
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
#ifndef OPENMW_MECHANICS_LEVELLEDLIST_H
|
#ifndef OPENMW_MECHANICS_LEVELLEDLIST_H
|
||||||
#define OPENMW_MECHANICS_LEVELLEDLIST_H
|
#define OPENMW_MECHANICS_LEVELLEDLIST_H
|
||||||
|
|
||||||
#include <iostream>
|
#include <components/debug/debuglog.hpp>
|
||||||
|
|
||||||
#include <components/misc/rng.hpp>
|
#include <components/misc/rng.hpp>
|
||||||
|
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
|
@ -63,7 +62,7 @@ namespace MWMechanics
|
||||||
// Vanilla doesn't fail on nonexistent items in levelled lists
|
// Vanilla doesn't fail on nonexistent items in levelled lists
|
||||||
if (!MWBase::Environment::get().getWorld()->getStore().find(Misc::StringUtils::lowerCase(item)))
|
if (!MWBase::Environment::get().getWorld()->getStore().find(Misc::StringUtils::lowerCase(item)))
|
||||||
{
|
{
|
||||||
std::cerr << "Warning: ignoring nonexistent item '" << item << "' in levelled list '" << levItem->mId << "'" << std::endl;
|
Log(Debug::Warning) << "Warning: ignoring nonexistent item '" << item << "' in levelled list '" << levItem->mId << "'";
|
||||||
return std::string();
|
return std::string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "mechanicsmanagerimp.hpp"
|
#include "mechanicsmanagerimp.hpp"
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
#include <components/misc/rng.hpp>
|
#include <components/misc/rng.hpp>
|
||||||
|
|
||||||
|
@ -35,7 +36,7 @@ namespace
|
||||||
float getFightDispositionBias(float disposition)
|
float getFightDispositionBias(float disposition)
|
||||||
{
|
{
|
||||||
static const float fFightDispMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
|
static const float fFightDispMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(
|
||||||
"fFightDispMult")->getFloat();
|
"fFightDispMult")->mValue.getFloat();
|
||||||
return ((50.f - disposition) * fFightDispMult);
|
return ((50.f - disposition) * fFightDispMult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,11 +45,11 @@ namespace
|
||||||
const MWWorld::Store<ESM::GameSetting> &gmst =
|
const MWWorld::Store<ESM::GameSetting> &gmst =
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||||
|
|
||||||
float persTerm = stats.getAttribute(ESM::Attribute::Personality).getModified() / gmst.find("fPersonalityMod")->getFloat();
|
float persTerm = stats.getAttribute(ESM::Attribute::Personality).getModified() / gmst.find("fPersonalityMod")->mValue.getFloat();
|
||||||
float luckTerm = stats.getAttribute(ESM::Attribute::Luck).getModified() / gmst.find("fLuckMod")->getFloat();
|
float luckTerm = stats.getAttribute(ESM::Attribute::Luck).getModified() / gmst.find("fLuckMod")->mValue.getFloat();
|
||||||
float repTerm = stats.getReputation() * gmst.find("fReputationMod")->getFloat();
|
float repTerm = stats.getReputation() * gmst.find("fReputationMod")->mValue.getFloat();
|
||||||
float fatigueTerm = stats.getFatigueTerm();
|
float fatigueTerm = stats.getFatigueTerm();
|
||||||
float levelTerm = stats.getLevel() * gmst.find("fLevelMod")->getFloat();
|
float levelTerm = stats.getLevel() * gmst.find("fLevelMod")->mValue.getFloat();
|
||||||
|
|
||||||
rating1 = (repTerm + luckTerm + persTerm + stats.getSkill(ESM::Skill::Speechcraft).getModified()) * fatigueTerm;
|
rating1 = (repTerm + luckTerm + persTerm + stats.getSkill(ESM::Skill::Speechcraft).getModified()) * fatigueTerm;
|
||||||
|
|
||||||
|
@ -341,7 +342,7 @@ namespace MWMechanics
|
||||||
if(timeToDrown != mWatchedTimeToStartDrowning)
|
if(timeToDrown != mWatchedTimeToStartDrowning)
|
||||||
{
|
{
|
||||||
static const float fHoldBreathTime = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
static const float fHoldBreathTime = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||||
.find("fHoldBreathTime")->getFloat();
|
.find("fHoldBreathTime")->mValue.getFloat();
|
||||||
|
|
||||||
mWatchedTimeToStartDrowning = timeToDrown;
|
mWatchedTimeToStartDrowning = timeToDrown;
|
||||||
|
|
||||||
|
@ -435,9 +436,9 @@ namespace MWMechanics
|
||||||
return mActors.isActorDetected(actor, observer);
|
return mActors.isActorDetected(actor, observer);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MechanicsManager::isAttackPrepairing(const MWWorld::Ptr& ptr)
|
bool MechanicsManager::isAttackPreparing(const MWWorld::Ptr& ptr)
|
||||||
{
|
{
|
||||||
return mActors.isAttackPrepairing(ptr);
|
return mActors.isAttackPreparing(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MechanicsManager::isRunning(const MWWorld::Ptr& ptr)
|
bool MechanicsManager::isRunning(const MWWorld::Ptr& ptr)
|
||||||
|
@ -542,12 +543,12 @@ namespace MWMechanics
|
||||||
const MWMechanics::NpcStats &playerStats = playerPtr.getClass().getNpcStats(playerPtr);
|
const MWMechanics::NpcStats &playerStats = playerPtr.getClass().getNpcStats(playerPtr);
|
||||||
|
|
||||||
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>();
|
||||||
static const float fDispRaceMod = gmst.find("fDispRaceMod")->getFloat();
|
static const float fDispRaceMod = gmst.find("fDispRaceMod")->mValue.getFloat();
|
||||||
if (Misc::StringUtils::ciEqual(npc->mBase->mRace, player->mBase->mRace))
|
if (Misc::StringUtils::ciEqual(npc->mBase->mRace, player->mBase->mRace))
|
||||||
x += fDispRaceMod;
|
x += fDispRaceMod;
|
||||||
|
|
||||||
static const float fDispPersonalityMult = gmst.find("fDispPersonalityMult")->getFloat();
|
static const float fDispPersonalityMult = gmst.find("fDispPersonalityMult")->mValue.getFloat();
|
||||||
static const float fDispPersonalityBase = gmst.find("fDispPersonalityBase")->getFloat();
|
static const float fDispPersonalityBase = gmst.find("fDispPersonalityBase")->mValue.getFloat();
|
||||||
x += fDispPersonalityMult * (playerStats.getAttribute(ESM::Attribute::Personality).getModified() - fDispPersonalityBase);
|
x += fDispPersonalityMult * (playerStats.getAttribute(ESM::Attribute::Personality).getModified() - fDispPersonalityBase);
|
||||||
|
|
||||||
float reaction = 0;
|
float reaction = 0;
|
||||||
|
@ -591,20 +592,20 @@ namespace MWMechanics
|
||||||
rank = 0;
|
rank = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const float fDispFactionRankMult = gmst.find("fDispFactionRankMult")->getFloat();
|
static const float fDispFactionRankMult = gmst.find("fDispFactionRankMult")->mValue.getFloat();
|
||||||
static const float fDispFactionRankBase = gmst.find("fDispFactionRankBase")->getFloat();
|
static const float fDispFactionRankBase = gmst.find("fDispFactionRankBase")->mValue.getFloat();
|
||||||
static const float fDispFactionMod = gmst.find("fDispFactionMod")->getFloat();
|
static const float fDispFactionMod = gmst.find("fDispFactionMod")->mValue.getFloat();
|
||||||
x += (fDispFactionRankMult * rank
|
x += (fDispFactionRankMult * rank
|
||||||
+ fDispFactionRankBase)
|
+ fDispFactionRankBase)
|
||||||
* fDispFactionMod * reaction;
|
* fDispFactionMod * reaction;
|
||||||
|
|
||||||
static const float fDispCrimeMod = gmst.find("fDispCrimeMod")->getFloat();
|
static const float fDispCrimeMod = gmst.find("fDispCrimeMod")->mValue.getFloat();
|
||||||
static const float fDispDiseaseMod = gmst.find("fDispDiseaseMod")->getFloat();
|
static const float fDispDiseaseMod = gmst.find("fDispDiseaseMod")->mValue.getFloat();
|
||||||
x -= fDispCrimeMod * playerStats.getBounty();
|
x -= fDispCrimeMod * playerStats.getBounty();
|
||||||
if (playerStats.hasCommonDisease() || playerStats.hasBlightDisease())
|
if (playerStats.hasCommonDisease() || playerStats.hasBlightDisease())
|
||||||
x += fDispDiseaseMod;
|
x += fDispDiseaseMod;
|
||||||
|
|
||||||
static const float fDispWeaponDrawn = gmst.find("fDispWeaponDrawn")->getFloat();
|
static const float fDispWeaponDrawn = gmst.find("fDispWeaponDrawn")->mValue.getFloat();
|
||||||
if (playerStats.getDrawState() == MWMechanics::DrawState_Weapon)
|
if (playerStats.getDrawState() == MWMechanics::DrawState_Weapon)
|
||||||
x += fDispWeaponDrawn;
|
x += fDispWeaponDrawn;
|
||||||
|
|
||||||
|
@ -672,16 +673,16 @@ namespace MWMechanics
|
||||||
float target2 = d * (playerRating2 - npcRating2 + 50);
|
float target2 = d * (playerRating2 - npcRating2 + 50);
|
||||||
|
|
||||||
float bribeMod;
|
float bribeMod;
|
||||||
if (type == PT_Bribe10) bribeMod = gmst.find("fBribe10Mod")->getFloat();
|
if (type == PT_Bribe10) bribeMod = gmst.find("fBribe10Mod")->mValue.getFloat();
|
||||||
else if (type == PT_Bribe100) bribeMod = gmst.find("fBribe100Mod")->getFloat();
|
else if (type == PT_Bribe100) bribeMod = gmst.find("fBribe100Mod")->mValue.getFloat();
|
||||||
else bribeMod = gmst.find("fBribe1000Mod")->getFloat();
|
else bribeMod = gmst.find("fBribe1000Mod")->mValue.getFloat();
|
||||||
|
|
||||||
float target3 = d * (playerRating3 - npcRating3 + 50) + bribeMod;
|
float target3 = d * (playerRating3 - npcRating3 + 50) + bribeMod;
|
||||||
|
|
||||||
float iPerMinChance = floor(gmst.find("iPerMinChance")->getFloat());
|
float iPerMinChance = floor(gmst.find("iPerMinChance")->mValue.getFloat());
|
||||||
float iPerMinChange = floor(gmst.find("iPerMinChange")->getFloat());
|
float iPerMinChange = floor(gmst.find("iPerMinChange")->mValue.getFloat());
|
||||||
float fPerDieRollMult = gmst.find("fPerDieRollMult")->getFloat();
|
float fPerDieRollMult = gmst.find("fPerDieRollMult")->mValue.getFloat();
|
||||||
float fPerTempMult = gmst.find("fPerTempMult")->getFloat();
|
float fPerTempMult = gmst.find("fPerTempMult")->mValue.getFloat();
|
||||||
|
|
||||||
float x = 0;
|
float x = 0;
|
||||||
float y = 0;
|
float y = 0;
|
||||||
|
@ -866,7 +867,7 @@ namespace MWMechanics
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// All sMagicBound* GMST's should be of type string
|
// All sMagicBound* GMST's should be of type string
|
||||||
std::string currentGMSTValue = currentSetting.getString();
|
std::string currentGMSTValue = currentSetting.mValue.getString();
|
||||||
Misc::StringUtils::lowerCaseInPlace(currentGMSTValue);
|
Misc::StringUtils::lowerCaseInPlace(currentGMSTValue);
|
||||||
|
|
||||||
boundItemIDCache.insert(currentGMSTValue);
|
boundItemIDCache.insert(currentGMSTValue);
|
||||||
|
@ -1162,7 +1163,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
osg::Vec3f from (player.getRefData().getPosition().asVec3());
|
osg::Vec3f from (player.getRefData().getPosition().asVec3());
|
||||||
const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore();
|
const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore();
|
||||||
float radius = esmStore.get<ESM::GameSetting>().find("fAlarmRadius")->getFloat();
|
float radius = esmStore.get<ESM::GameSetting>().find("fAlarmRadius")->mValue.getFloat();
|
||||||
|
|
||||||
mActors.getObjectsInRange(from, radius, neighbors);
|
mActors.getObjectsInRange(from, radius, neighbors);
|
||||||
|
|
||||||
|
@ -1260,29 +1261,29 @@ namespace MWMechanics
|
||||||
float disp = 0.f, dispVictim = 0.f;
|
float disp = 0.f, dispVictim = 0.f;
|
||||||
if (type == OT_Trespassing || type == OT_SleepingInOwnedBed)
|
if (type == OT_Trespassing || type == OT_SleepingInOwnedBed)
|
||||||
{
|
{
|
||||||
arg = store.find("iCrimeTresspass")->getInt();
|
arg = store.find("iCrimeTresspass")->mValue.getInteger();
|
||||||
disp = dispVictim = store.find("iDispTresspass")->getFloat();
|
disp = dispVictim = store.find("iDispTresspass")->mValue.getFloat();
|
||||||
}
|
}
|
||||||
else if (type == OT_Pickpocket)
|
else if (type == OT_Pickpocket)
|
||||||
{
|
{
|
||||||
arg = store.find("iCrimePickPocket")->getInt();
|
arg = store.find("iCrimePickPocket")->mValue.getInteger();
|
||||||
disp = dispVictim = store.find("fDispPickPocketMod")->getFloat();
|
disp = dispVictim = store.find("fDispPickPocketMod")->mValue.getFloat();
|
||||||
}
|
}
|
||||||
else if (type == OT_Assault)
|
else if (type == OT_Assault)
|
||||||
{
|
{
|
||||||
arg = store.find("iCrimeAttack")->getInt();
|
arg = store.find("iCrimeAttack")->mValue.getInteger();
|
||||||
disp = store.find("iDispAttackMod")->getFloat();
|
disp = store.find("iDispAttackMod")->mValue.getFloat();
|
||||||
dispVictim = store.find("fDispAttacking")->getFloat();
|
dispVictim = store.find("fDispAttacking")->mValue.getFloat();
|
||||||
}
|
}
|
||||||
else if (type == OT_Murder)
|
else if (type == OT_Murder)
|
||||||
{
|
{
|
||||||
arg = store.find("iCrimeKilling")->getInt();
|
arg = store.find("iCrimeKilling")->mValue.getInteger();
|
||||||
disp = dispVictim = store.find("iDispKilling")->getFloat();
|
disp = dispVictim = store.find("iDispKilling")->mValue.getFloat();
|
||||||
}
|
}
|
||||||
else if (type == OT_Theft)
|
else if (type == OT_Theft)
|
||||||
{
|
{
|
||||||
disp = dispVictim = store.find("fDispStealing")->getFloat() * arg;
|
disp = dispVictim = store.find("fDispStealing")->mValue.getFloat() * arg;
|
||||||
arg = static_cast<int>(arg * store.find("fCrimeStealing")->getFloat());
|
arg = static_cast<int>(arg * store.find("fCrimeStealing")->mValue.getFloat());
|
||||||
arg = std::max(1, arg); // Minimum bounty of 1, in case items with zero value are stolen
|
arg = std::max(1, arg); // Minimum bounty of 1, in case items with zero value are stolen
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1292,7 +1293,7 @@ namespace MWMechanics
|
||||||
const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore();
|
const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore();
|
||||||
|
|
||||||
osg::Vec3f from (player.getRefData().getPosition().asVec3());
|
osg::Vec3f from (player.getRefData().getPosition().asVec3());
|
||||||
float radius = esmStore.get<ESM::GameSetting>().find("fAlarmRadius")->getFloat();
|
float radius = esmStore.get<ESM::GameSetting>().find("fAlarmRadius")->mValue.getFloat();
|
||||||
|
|
||||||
mActors.getObjectsInRange(from, radius, neighbors);
|
mActors.getObjectsInRange(from, radius, neighbors);
|
||||||
|
|
||||||
|
@ -1306,21 +1307,21 @@ namespace MWMechanics
|
||||||
// Controls whether witnesses will engage combat with the criminal.
|
// Controls whether witnesses will engage combat with the criminal.
|
||||||
int fight = 0, fightVictim = 0;
|
int fight = 0, fightVictim = 0;
|
||||||
if (type == OT_Trespassing || type == OT_SleepingInOwnedBed)
|
if (type == OT_Trespassing || type == OT_SleepingInOwnedBed)
|
||||||
fight = fightVictim = esmStore.get<ESM::GameSetting>().find("iFightTrespass")->getInt();
|
fight = fightVictim = esmStore.get<ESM::GameSetting>().find("iFightTrespass")->mValue.getInteger();
|
||||||
else if (type == OT_Pickpocket)
|
else if (type == OT_Pickpocket)
|
||||||
{
|
{
|
||||||
fight = esmStore.get<ESM::GameSetting>().find("iFightPickpocket")->getInt();
|
fight = esmStore.get<ESM::GameSetting>().find("iFightPickpocket")->mValue.getInteger();
|
||||||
fightVictim = esmStore.get<ESM::GameSetting>().find("iFightPickpocket")->getInt() * 4; // *4 according to research wiki
|
fightVictim = esmStore.get<ESM::GameSetting>().find("iFightPickpocket")->mValue.getInteger() * 4; // *4 according to research wiki
|
||||||
}
|
}
|
||||||
else if (type == OT_Assault)
|
else if (type == OT_Assault)
|
||||||
{
|
{
|
||||||
fight = esmStore.get<ESM::GameSetting>().find("iFightAttacking")->getInt();
|
fight = esmStore.get<ESM::GameSetting>().find("iFightAttacking")->mValue.getInteger();
|
||||||
fightVictim = esmStore.get<ESM::GameSetting>().find("iFightAttack")->getInt();
|
fightVictim = esmStore.get<ESM::GameSetting>().find("iFightAttack")->mValue.getInteger();
|
||||||
}
|
}
|
||||||
else if (type == OT_Murder)
|
else if (type == OT_Murder)
|
||||||
fight = fightVictim = esmStore.get<ESM::GameSetting>().find("iFightKilling")->getInt();
|
fight = fightVictim = esmStore.get<ESM::GameSetting>().find("iFightKilling")->mValue.getInteger();
|
||||||
else if (type == OT_Theft)
|
else if (type == OT_Theft)
|
||||||
fight = fightVictim = esmStore.get<ESM::GameSetting>().find("fFightStealing")->getInt();
|
fight = fightVictim = esmStore.get<ESM::GameSetting>().find("fFightStealing")->mValue.getInteger();
|
||||||
|
|
||||||
bool reported = false;
|
bool reported = false;
|
||||||
|
|
||||||
|
@ -1445,11 +1446,12 @@ namespace MWMechanics
|
||||||
if (target == getPlayer() || !attacker.getClass().isActor())
|
if (target == getPlayer() || !attacker.getClass().isActor())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
std::list<MWWorld::Ptr> followersAttacker = getActorsSidingWith(attacker);
|
std::set<MWWorld::Ptr> followersAttacker;
|
||||||
|
getActorsSidingWith(attacker, followersAttacker);
|
||||||
|
|
||||||
MWMechanics::CreatureStats& statsTarget = target.getClass().getCreatureStats(target);
|
MWMechanics::CreatureStats& statsTarget = target.getClass().getCreatureStats(target);
|
||||||
|
|
||||||
if (std::find(followersAttacker.begin(), followersAttacker.end(), target) != followersAttacker.end())
|
if (followersAttacker.find(target) != followersAttacker.end())
|
||||||
{
|
{
|
||||||
statsTarget.friendlyHit();
|
statsTarget.friendlyHit();
|
||||||
|
|
||||||
|
@ -1460,24 +1462,11 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attacking an NPC that is already in combat with any other NPC is not a crime
|
if (canCommitCrimeAgainst(target, attacker))
|
||||||
AiSequence& seq = statsTarget.getAiSequence();
|
|
||||||
bool isFightingNpc = false;
|
|
||||||
for (std::list<AiPackage*>::const_iterator it = seq.begin(); it != seq.end(); ++it)
|
|
||||||
{
|
|
||||||
if ((*it)->getTypeId() == AiPackage::TypeIdCombat)
|
|
||||||
{
|
|
||||||
MWWorld::Ptr target2 = (*it)->getTarget();
|
|
||||||
if (!target2.isEmpty() && target2.getClass().isNpc())
|
|
||||||
isFightingNpc = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target.getClass().isNpc() && !attacker.isEmpty() && !seq.isInCombat(attacker)
|
|
||||||
&& !isAggressive(target, attacker) && !isFightingNpc
|
|
||||||
&& !target.getClass().getCreatureStats(target).getAiSequence().hasPackage(AiPackage::TypeIdPursue))
|
|
||||||
commitCrime(attacker, target, MWBase::MechanicsManager::OT_Assault);
|
commitCrime(attacker, target, MWBase::MechanicsManager::OT_Assault);
|
||||||
|
|
||||||
|
AiSequence& seq = statsTarget.getAiSequence();
|
||||||
|
|
||||||
if (!attacker.isEmpty() && (attacker.getClass().getCreatureStats(attacker).getAiSequence().isInCombat(target)
|
if (!attacker.isEmpty() && (attacker.getClass().getCreatureStats(attacker).getAiSequence().isInCombat(target)
|
||||||
|| attacker == getPlayer())
|
|| attacker == getPlayer())
|
||||||
&& !seq.isInCombat(attacker))
|
&& !seq.isInCombat(attacker))
|
||||||
|
@ -1504,6 +1493,14 @@ namespace MWMechanics
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MechanicsManager::canCommitCrimeAgainst(const MWWorld::Ptr &target, const MWWorld::Ptr &attacker)
|
||||||
|
{
|
||||||
|
MWMechanics::AiSequence seq = target.getClass().getCreatureStats(target).getAiSequence();
|
||||||
|
return target.getClass().isNpc() && !attacker.isEmpty() && !seq.isInCombat(attacker)
|
||||||
|
&& !isAggressive(target, attacker) && !seq.isEngagedWithActor()
|
||||||
|
&& !target.getClass().getCreatureStats(target).getAiSequence().hasPackage(AiPackage::TypeIdPursue);
|
||||||
|
}
|
||||||
|
|
||||||
void MechanicsManager::actorKilled(const MWWorld::Ptr &victim, const MWWorld::Ptr &attacker)
|
void MechanicsManager::actorKilled(const MWWorld::Ptr &victim, const MWWorld::Ptr &attacker)
|
||||||
{
|
{
|
||||||
if (attacker.isEmpty() || victim.isEmpty())
|
if (attacker.isEmpty() || victim.isEmpty())
|
||||||
|
@ -1516,11 +1513,10 @@ namespace MWMechanics
|
||||||
return; // TODO: implement animal rights
|
return; // TODO: implement animal rights
|
||||||
|
|
||||||
const MWMechanics::NpcStats& victimStats = victim.getClass().getNpcStats(victim);
|
const MWMechanics::NpcStats& victimStats = victim.getClass().getNpcStats(victim);
|
||||||
if (victimStats.getCrimeId() == -1)
|
const MWWorld::Ptr &player = getPlayer();
|
||||||
return;
|
bool canCommit = attacker == player && canCommitCrimeAgainst(victim, attacker);
|
||||||
|
|
||||||
// For now we report only about crimes of player and player's followers
|
// For now we report only about crimes of player and player's followers
|
||||||
const MWWorld::Ptr &player = getPlayer();
|
|
||||||
if (attacker != player)
|
if (attacker != player)
|
||||||
{
|
{
|
||||||
std::set<MWWorld::Ptr> playerFollowers;
|
std::set<MWWorld::Ptr> playerFollowers;
|
||||||
|
@ -1529,6 +1525,9 @@ namespace MWMechanics
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!canCommit && victimStats.getCrimeId() == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
// Simple check for who attacked first: if the player attacked first, a crimeId should be set
|
// Simple check for who attacked first: if the player attacked first, a crimeId should be set
|
||||||
// Doesn't handle possible edge case where no one reported the assault, but in such a case,
|
// Doesn't handle possible edge case where no one reported the assault, but in such a case,
|
||||||
// for bystanders it is not possible to tell who attacked first, anyway.
|
// for bystanders it is not possible to tell who attacked first, anyway.
|
||||||
|
@ -1553,8 +1552,8 @@ namespace MWMechanics
|
||||||
&& !MWBase::Environment::get().getWorld()->isSwimming(ptr)
|
&& !MWBase::Environment::get().getWorld()->isSwimming(ptr)
|
||||||
&& MWBase::Environment::get().getWorld()->isOnGround(ptr))
|
&& MWBase::Environment::get().getWorld()->isOnGround(ptr))
|
||||||
{
|
{
|
||||||
static float fSneakSkillMult = store.find("fSneakSkillMult")->getFloat();
|
static float fSneakSkillMult = store.find("fSneakSkillMult")->mValue.getFloat();
|
||||||
static float fSneakBootMult = store.find("fSneakBootMult")->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();
|
int agility = stats.getAttribute(ESM::Attribute::Agility).getModified();
|
||||||
int luck = stats.getAttribute(ESM::Attribute::Luck).getModified();
|
int luck = stats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||||
|
@ -1569,8 +1568,8 @@ namespace MWMechanics
|
||||||
sneakTerm = fSneakSkillMult * sneak + 0.2f * agility + 0.1f * luck + bootWeight * fSneakBootMult;
|
sneakTerm = fSneakSkillMult * sneak + 0.2f * agility + 0.1f * luck + bootWeight * fSneakBootMult;
|
||||||
}
|
}
|
||||||
|
|
||||||
static float fSneakDistBase = store.find("fSneakDistanceBase")->getFloat();
|
static float fSneakDistBase = store.find("fSneakDistanceBase")->mValue.getFloat();
|
||||||
static float fSneakDistMult = store.find("fSneakDistanceMultiplier")->getFloat();
|
static float fSneakDistMult = store.find("fSneakDistanceMultiplier")->mValue.getFloat();
|
||||||
|
|
||||||
osg::Vec3f pos1 (ptr.getRefData().getPosition().asVec3());
|
osg::Vec3f pos1 (ptr.getRefData().getPosition().asVec3());
|
||||||
osg::Vec3f pos2 (observer.getRefData().getPosition().asVec3());
|
osg::Vec3f pos2 (observer.getRefData().getPosition().asVec3());
|
||||||
|
@ -1588,8 +1587,8 @@ namespace MWMechanics
|
||||||
float obsTerm = obsSneak + 0.2f * obsAgility + 0.1f * obsLuck - obsBlind;
|
float obsTerm = obsSneak + 0.2f * obsAgility + 0.1f * obsLuck - obsBlind;
|
||||||
|
|
||||||
// is ptr behind the observer?
|
// is ptr behind the observer?
|
||||||
static float fSneakNoViewMult = store.find("fSneakNoViewMult")->getFloat();
|
static float fSneakNoViewMult = store.find("fSneakNoViewMult")->mValue.getFloat();
|
||||||
static float fSneakViewMult = store.find("fSneakViewMult")->getFloat();
|
static float fSneakViewMult = store.find("fSneakViewMult")->mValue.getFloat();
|
||||||
float y = 0;
|
float y = 0;
|
||||||
osg::Vec3f vec = pos1 - pos2;
|
osg::Vec3f vec = pos1 - pos2;
|
||||||
if (observer.getRefData().getBaseNode())
|
if (observer.getRefData().getBaseNode())
|
||||||
|
@ -1749,7 +1748,7 @@ namespace MWMechanics
|
||||||
MWBase::Environment::get().getWorld()->getGlobalInt("pcknownwerewolf")))
|
MWBase::Environment::get().getWorld()->getGlobalInt("pcknownwerewolf")))
|
||||||
{
|
{
|
||||||
const ESM::GameSetting * iWerewolfFightMod = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("iWerewolfFightMod");
|
const ESM::GameSetting * iWerewolfFightMod = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("iWerewolfFightMod");
|
||||||
fight += iWerewolfFightMod->getInt();
|
fight += iWerewolfFightMod->mValue.getInteger();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1842,7 +1841,7 @@ namespace MWMechanics
|
||||||
// Witnesses of the player's transformation will make them a globally known werewolf
|
// Witnesses of the player's transformation will make them a globally known werewolf
|
||||||
std::vector<MWWorld::Ptr> closeActors;
|
std::vector<MWWorld::Ptr> closeActors;
|
||||||
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>();
|
||||||
getActorsInRange(actor.getRefData().getPosition().asVec3(), gmst.find("fAlarmRadius")->getFloat(), closeActors);
|
getActorsInRange(actor.getRefData().getPosition().asVec3(), gmst.find("fAlarmRadius")->mValue.getFloat(), closeActors);
|
||||||
|
|
||||||
bool detected = false, reported = false;
|
bool detected = false, reported = false;
|
||||||
for (std::vector<MWWorld::Ptr>::const_iterator it = closeActors.begin(); it != closeActors.end(); ++it)
|
for (std::vector<MWWorld::Ptr>::const_iterator it = closeActors.begin(); it != closeActors.end(); ++it)
|
||||||
|
@ -1867,7 +1866,7 @@ namespace MWMechanics
|
||||||
if (reported)
|
if (reported)
|
||||||
{
|
{
|
||||||
npcStats.setBounty(npcStats.getBounty()+
|
npcStats.setBounty(npcStats.getBounty()+
|
||||||
gmst.find("iWereWolfBounty")->getInt());
|
gmst.find("iWereWolfBounty")->mValue.getInteger());
|
||||||
windowManager->messageBox("#{sCrimeMessage}");
|
windowManager->messageBox("#{sCrimeMessage}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1879,7 +1878,7 @@ namespace MWMechanics
|
||||||
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>();
|
||||||
MWMechanics::NpcStats &stats = actor.getClass().getNpcStats(actor);
|
MWMechanics::NpcStats &stats = actor.getClass().getNpcStats(actor);
|
||||||
|
|
||||||
stats.getSkill(ESM::Skill::Acrobatics).setBase(gmst.find("fWerewolfAcrobatics")->getInt());
|
stats.getSkill(ESM::Skill::Acrobatics).setBase(gmst.find("fWerewolfAcrobatics")->mValue.getInteger());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MechanicsManager::cleanupSummonedCreature(const MWWorld::Ptr &caster, int creatureActorId)
|
void MechanicsManager::cleanupSummonedCreature(const MWWorld::Ptr &caster, int creatureActorId)
|
||||||
|
|
|
@ -132,6 +132,12 @@ namespace MWMechanics
|
||||||
/// @note No-op for non-player attackers
|
/// @note No-op for non-player attackers
|
||||||
virtual void actorKilled (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker);
|
virtual void actorKilled (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker);
|
||||||
|
|
||||||
|
/// Checks if commiting a crime is currently valid
|
||||||
|
/// @param victim The actor being attacked
|
||||||
|
/// @param attacker The actor commiting the crime
|
||||||
|
/// @return true if the victim is a valid target for crime
|
||||||
|
virtual bool canCommitCrimeAgainst(const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker);
|
||||||
|
|
||||||
/// Utility to check if taking this item is illegal and calling commitCrime if so
|
/// Utility to check if taking this item is illegal and calling commitCrime if so
|
||||||
/// @param container The container the item is in; may be empty for an item in the world
|
/// @param container The container the item is in; may be empty for an item in the world
|
||||||
virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container,
|
virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container,
|
||||||
|
@ -223,7 +229,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
virtual void confiscateStolenItemToOwner(const MWWorld::Ptr &player, const MWWorld::Ptr &item, const MWWorld::Ptr& victim, int count);
|
virtual void confiscateStolenItemToOwner(const MWWorld::Ptr &player, const MWWorld::Ptr &item, const MWWorld::Ptr& victim, int count);
|
||||||
|
|
||||||
virtual bool isAttackPrepairing(const MWWorld::Ptr& ptr);
|
virtual bool isAttackPreparing(const MWWorld::Ptr& ptr);
|
||||||
virtual bool isRunning(const MWWorld::Ptr& ptr);
|
virtual bool isRunning(const MWWorld::Ptr& ptr);
|
||||||
virtual bool isSneaking(const MWWorld::Ptr& ptr);
|
virtual bool isSneaking(const MWWorld::Ptr& ptr);
|
||||||
|
|
||||||
|
|
|
@ -149,12 +149,12 @@ float MWMechanics::NpcStats::getSkillProgressRequirement (int skillIndex, const
|
||||||
const MWWorld::Store<ESM::GameSetting> &gmst =
|
const MWWorld::Store<ESM::GameSetting> &gmst =
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||||
|
|
||||||
float typeFactor = gmst.find ("fMiscSkillBonus")->getFloat();
|
float typeFactor = gmst.find ("fMiscSkillBonus")->mValue.getFloat();
|
||||||
|
|
||||||
for (int i=0; i<5; ++i)
|
for (int i=0; i<5; ++i)
|
||||||
if (class_.mData.mSkills[i][0]==skillIndex)
|
if (class_.mData.mSkills[i][0]==skillIndex)
|
||||||
{
|
{
|
||||||
typeFactor = gmst.find ("fMinorSkillBonus")->getFloat();
|
typeFactor = gmst.find ("fMinorSkillBonus")->mValue.getFloat();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -162,7 +162,7 @@ float MWMechanics::NpcStats::getSkillProgressRequirement (int skillIndex, const
|
||||||
for (int i=0; i<5; ++i)
|
for (int i=0; i<5; ++i)
|
||||||
if (class_.mData.mSkills[i][1]==skillIndex)
|
if (class_.mData.mSkills[i][1]==skillIndex)
|
||||||
{
|
{
|
||||||
typeFactor = gmst.find ("fMajorSkillBonus")->getFloat();
|
typeFactor = gmst.find ("fMajorSkillBonus")->mValue.getFloat();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -178,7 +178,7 @@ float MWMechanics::NpcStats::getSkillProgressRequirement (int skillIndex, const
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Skill>().find (skillIndex);
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::Skill>().find (skillIndex);
|
||||||
if (skill->mData.mSpecialization==class_.mData.mSpecialization)
|
if (skill->mData.mSpecialization==class_.mData.mSpecialization)
|
||||||
{
|
{
|
||||||
specialisationFactor = gmst.find ("fSpecialSkillBonus")->getFloat();
|
specialisationFactor = gmst.find ("fSpecialSkillBonus")->mValue.getFloat();
|
||||||
|
|
||||||
if (specialisationFactor<=0)
|
if (specialisationFactor<=0)
|
||||||
throw std::runtime_error ("invalid skill specialisation factor");
|
throw std::runtime_error ("invalid skill specialisation factor");
|
||||||
|
@ -227,21 +227,21 @@ void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &clas
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||||
|
|
||||||
// is this a minor or major skill?
|
// is this a minor or major skill?
|
||||||
int increase = gmst.find("iLevelupMiscMultAttriubte")->getInt(); // Note: GMST has a typo
|
int increase = gmst.find("iLevelupMiscMultAttriubte")->mValue.getInteger(); // Note: GMST has a typo
|
||||||
for (int k=0; k<5; ++k)
|
for (int k=0; k<5; ++k)
|
||||||
{
|
{
|
||||||
if (class_.mData.mSkills[k][0] == skillIndex)
|
if (class_.mData.mSkills[k][0] == skillIndex)
|
||||||
{
|
{
|
||||||
mLevelProgress += gmst.find("iLevelUpMinorMult")->getInt();
|
mLevelProgress += gmst.find("iLevelUpMinorMult")->mValue.getInteger();
|
||||||
increase = gmst.find("iLevelUpMajorMultAttribute")->getInt();
|
increase = gmst.find("iLevelUpMajorMultAttribute")->mValue.getInteger();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int k=0; k<5; ++k)
|
for (int k=0; k<5; ++k)
|
||||||
{
|
{
|
||||||
if (class_.mData.mSkills[k][1] == skillIndex)
|
if (class_.mData.mSkills[k][1] == skillIndex)
|
||||||
{
|
{
|
||||||
mLevelProgress += gmst.find("iLevelUpMajorMult")->getInt();
|
mLevelProgress += gmst.find("iLevelUpMajorMult")->mValue.getInteger();
|
||||||
increase = gmst.find("iLevelUpMinorMultAttribute")->getInt();
|
increase = gmst.find("iLevelUpMinorMultAttribute")->mValue.getInteger();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,7 +249,7 @@ void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &clas
|
||||||
MWBase::Environment::get().getWorld ()->getStore ().get<ESM::Skill>().find(skillIndex);
|
MWBase::Environment::get().getWorld ()->getStore ().get<ESM::Skill>().find(skillIndex);
|
||||||
mSkillIncreases[skill->mData.mAttribute] += increase;
|
mSkillIncreases[skill->mData.mAttribute] += increase;
|
||||||
|
|
||||||
mSpecIncreases[skill->mData.mSpecialization] += gmst.find("iLevelupSpecialization")->getInt();
|
mSpecIncreases[skill->mData.mSpecialization] += gmst.find("iLevelupSpecialization")->mValue.getInteger();
|
||||||
|
|
||||||
// Play sound & skill progress notification
|
// Play sound & skill progress notification
|
||||||
/// \todo check if character is the player, if levelling is ever implemented for NPCs
|
/// \todo check if character is the player, if levelling is ever implemented for NPCs
|
||||||
|
@ -266,7 +266,7 @@ void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &clas
|
||||||
|
|
||||||
MWBase::Environment::get().getWindowManager ()->messageBox(message.str(), MWGui::ShowInDialogueMode_Never);
|
MWBase::Environment::get().getWindowManager ()->messageBox(message.str(), MWGui::ShowInDialogueMode_Never);
|
||||||
|
|
||||||
if (mLevelProgress >= gmst.find("iLevelUpTotal")->getInt())
|
if (mLevelProgress >= gmst.find("iLevelUpTotal")->mValue.getInteger())
|
||||||
{
|
{
|
||||||
// levelup is possible now
|
// levelup is possible now
|
||||||
MWBase::Environment::get().getWindowManager ()->messageBox ("#{sLevelUpMsg}", MWGui::ShowInDialogueMode_Never);
|
MWBase::Environment::get().getWindowManager ()->messageBox ("#{sLevelUpMsg}", MWGui::ShowInDialogueMode_Never);
|
||||||
|
@ -287,7 +287,7 @@ void MWMechanics::NpcStats::levelUp()
|
||||||
const MWWorld::Store<ESM::GameSetting> &gmst =
|
const MWWorld::Store<ESM::GameSetting> &gmst =
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||||
|
|
||||||
mLevelProgress -= gmst.find("iLevelUpTotal")->getInt();
|
mLevelProgress -= gmst.find("iLevelUpTotal")->mValue.getInteger();
|
||||||
mLevelProgress = std::max(0, mLevelProgress); // might be necessary when levelup was invoked via console
|
mLevelProgress = std::max(0, mLevelProgress); // might be necessary when levelup was invoked via console
|
||||||
|
|
||||||
for (int i=0; i<ESM::Attribute::Length; ++i)
|
for (int i=0; i<ESM::Attribute::Length; ++i)
|
||||||
|
@ -298,7 +298,7 @@ void MWMechanics::NpcStats::levelUp()
|
||||||
// "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,
|
||||||
// the Health increase is calculated from the increased Endurance"
|
// the Health increase is calculated from the increased Endurance"
|
||||||
setHealth(getHealth().getBase() + endurance * gmst.find("fLevelUpHealthEndMult")->getFloat());
|
setHealth(getHealth().getBase() + endurance * gmst.find("fLevelUpHealthEndMult")->mValue.getFloat());
|
||||||
|
|
||||||
setLevel(getLevel()+1);
|
setLevel(getLevel()+1);
|
||||||
}
|
}
|
||||||
|
@ -324,7 +324,7 @@ int MWMechanics::NpcStats::getLevelupAttributeMultiplier(int attribute) const
|
||||||
std::stringstream gmst;
|
std::stringstream gmst;
|
||||||
gmst << "iLevelUp" << std::setfill('0') << std::setw(2) << num << "Mult";
|
gmst << "iLevelUp" << std::setfill('0') << std::setw(2) << num << "Mult";
|
||||||
|
|
||||||
return MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(gmst.str())->getInt();
|
return MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(gmst.str())->mValue.getInteger();
|
||||||
}
|
}
|
||||||
|
|
||||||
int MWMechanics::NpcStats::getSkillIncreasesForSpecialization(int spec) const
|
int MWMechanics::NpcStats::getSkillIncreasesForSpecialization(int spec) const
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "objects.hpp"
|
#include "objects.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <components/debug/debuglog.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
@ -88,7 +88,7 @@ bool Objects::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& gro
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::cerr<< "Warning: Objects::playAnimationGroup: Unable to find " << ptr.getCellRef().getRefId() << std::endl;
|
Log(Debug::Warning) << "Warning: Objects::playAnimationGroup: Unable to find " << ptr.getCellRef().getRefId();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,9 +37,9 @@ namespace MWMechanics
|
||||||
|
|
||||||
float pcSneak = static_cast<float>(mThief.getClass().getSkill(mThief, ESM::Skill::Sneak));
|
float pcSneak = static_cast<float>(mThief.getClass().getSkill(mThief, ESM::Skill::Sneak));
|
||||||
int iPickMinChance = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
int iPickMinChance = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||||
.find("iPickMinChance")->getInt();
|
.find("iPickMinChance")->mValue.getInteger();
|
||||||
int iPickMaxChance = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
int iPickMaxChance = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||||
.find("iPickMaxChance")->getInt();
|
.find("iPickMaxChance")->mValue.getInteger();
|
||||||
|
|
||||||
int roll = Misc::Rng::roll0to99();
|
int roll = Misc::Rng::roll0to99();
|
||||||
if (t < pcSneak / iPickMinChance)
|
if (t < pcSneak / iPickMinChance)
|
||||||
|
@ -57,7 +57,7 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
float stackValue = static_cast<float>(item.getClass().getValue(item) * count);
|
float stackValue = static_cast<float>(item.getClass().getValue(item) * count);
|
||||||
float fPickPocketMod = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
float fPickPocketMod = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||||
.find("fPickPocketMod")->getFloat();
|
.find("fPickPocketMod")->mValue.getFloat();
|
||||||
float valueTerm = 10 * fPickPocketMod * stackValue;
|
float valueTerm = 10 * fPickPocketMod * stackValue;
|
||||||
|
|
||||||
return getDetected(valueTerm);
|
return getDetected(valueTerm);
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue