forked from mirror/openmw-tes3mp
commit
1d84cbe963
1130 changed files with 78734 additions and 10779 deletions
31
.gitignore
vendored
31
.gitignore
vendored
|
@ -10,7 +10,6 @@ prebuilt
|
|||
|
||||
## doxygen
|
||||
Doxygen
|
||||
!docs/cs-manual/Makefile
|
||||
|
||||
## ides/editors
|
||||
*~
|
||||
|
@ -22,6 +21,8 @@ Doxygen
|
|||
.project
|
||||
.settings
|
||||
.directory
|
||||
.idea
|
||||
cmake-build-*
|
||||
## qt-creator
|
||||
CMakeLists.txt.user*
|
||||
|
||||
|
@ -34,15 +35,36 @@ resources
|
|||
|
||||
## binaries
|
||||
/esmtool
|
||||
/mwiniimport
|
||||
/omwlauncher
|
||||
/openmw
|
||||
/opencs
|
||||
/niftest
|
||||
/bsatool
|
||||
/openmw-cs
|
||||
/openmw-essimporter
|
||||
/openmw-iniimporter
|
||||
/openmw-launcher
|
||||
/openmw-wizard
|
||||
|
||||
## generated objects
|
||||
apps/openmw/config.hpp
|
||||
apps/launcher/ui_contentselector.h
|
||||
apps/launcher/ui_settingspage.h
|
||||
apps/opencs/ui_contentselector.h
|
||||
apps/opencs/ui_filedialog.h
|
||||
apps/wizard/qrc_wizard.cxx
|
||||
apps/wizard/ui_componentselectionpage.h
|
||||
apps/wizard/ui_conclusionpage.h
|
||||
apps/wizard/ui_existinginstallationpage.h
|
||||
apps/wizard/ui_importpage.h
|
||||
apps/wizard/ui_installationpage.h
|
||||
apps/wizard/ui_installationtargetpage.h
|
||||
apps/wizard/ui_intropage.h
|
||||
apps/wizard/ui_languageselectionpage.h
|
||||
apps/wizard/ui_methodselectionpage.h
|
||||
components/ui_contentselector.h
|
||||
docs/mainpage.hpp
|
||||
docs/Doxyfile
|
||||
docs/DoxyfilePages
|
||||
moc_*.cxx
|
||||
*.cxx_parameters
|
||||
*qrc_launcher.cxx
|
||||
|
@ -54,3 +76,6 @@ moc_*.cxx
|
|||
*ui_playpage.h
|
||||
*.[ao]
|
||||
*.so
|
||||
gamecontrollerdb.txt
|
||||
openmw.appdata.xml
|
||||
venv/
|
||||
|
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
[submodule "extern/breakpad"]
|
||||
path = extern/breakpad
|
||||
url = https://chromium.googlesource.com/breakpad/breakpad
|
66
.travis.yml
66
.travis.yml
|
@ -1,6 +1,7 @@
|
|||
os:
|
||||
- linux
|
||||
# - osx
|
||||
osx_image: xcode8.2
|
||||
language: cpp
|
||||
sudo: required
|
||||
dist: trusty
|
||||
|
@ -11,17 +12,37 @@ branches:
|
|||
- /openmw-.*$/
|
||||
env:
|
||||
global:
|
||||
# The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
|
||||
# via the "travis encrypt" command using the project repo's public key
|
||||
- secure: "jybGzAdUbqt9vWR/GEnRd96BgAi/7Zd1+2HK68j/i/8+/1YH2XxLOy4Jv/DUBhBlJIkxs/Xv8dRcUlFOclZDHX1d/9Qnsqd3oUVkD7k1y7cTOWy9TBQaE/v/kZo3LpzA3xPwwthrb0BvqIbOfIELi5fS5s8ba85WFRg3AX70wWE="
|
||||
- macos_qt_formula=qt@5.5
|
||||
- secure: NZmvVuA0O9NJXVQ12tXQZHDJC2mbFgYNFcsicw0DgW1It2Nk5hxIkF0pfu4/Z59mhQuOPgRVjl5b0FKy2Axh0gkWc1DJEXGwNaiW5lpTMNWR1LJG5rxa8LrDUpFkycpbzfAFuTUZu5z3iYVv64XzELvBuqNGhPMu1LeBnrlech0jFNjkR9p5qtJGWb8zYcPMCC57rig8a9g1ABoVYS6UXjrKpx0946ZLRsE5ukc9pXsypGwPmOMyfzZkxxzIqFaxoE5JIEdaJTWba/6Za315ozYYIi/N35ROI1YAv5GHRe/Iw9XAa4vQpbDzjM7ZSsZdTvvQsSU598gD2xC6jFUKSrpW6GZKwM2x236fZLGnOk5Uw7DUbG+AwpcEmxBwoy9PjBl9ZF3tJykI0gROewCy8MODhdsVMKr1HGIMVBIJySm/RnNqtoDbYV8mYnSl5b8rwJiCajoiR8Zuv4CIfGneeH1a3DOQDPH/qkDsU6ilzF4ANsBlMUUpgY653KBMBmTlNuVZSH527tnD7Fg6JgHVuSQkTbRa1vSkR7Zcre604RZcAoaEdbX3bhVDasPPghU/I742L0RH3oQNlR09pPBDZ8kG7ydl4aPHwpCWnvXNM1vgxtGvnYLztwrse7IoaRXRYiMFmrso78WhMWUDKgvY4wV9aeUu0DtnMezZVIQwCKg=
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:openmw/openmw'
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-precise-3.6
|
||||
packages: [
|
||||
# Dev
|
||||
clang-3.6, libunshield-dev, libtinyxml-dev,
|
||||
g++-6,
|
||||
# Tests
|
||||
libgtest-dev, google-mock,
|
||||
# Boost
|
||||
libboost-filesystem-dev, libboost-program-options-dev, libboost-system-dev, libboost-thread-dev,
|
||||
# FFmpeg
|
||||
libavcodec-dev, libavformat-dev, libavutil-dev, libswscale-dev,
|
||||
# Audio & Video
|
||||
libsdl2-dev, qtbase5-dev, libopenal-dev,
|
||||
# The other ones from OpenMW ppa
|
||||
libbullet-dev, libswresample-dev, libopenscenegraph-3.4-dev, libmygui-dev
|
||||
]
|
||||
|
||||
coverity_scan:
|
||||
project:
|
||||
name: "OpenMW/openmw"
|
||||
name: "TES3MP/openmw-tes3mp"
|
||||
description: "<Your project description here>"
|
||||
notification_email: scrawl@baseoftrash.de
|
||||
notification_email: stas5978@gmail.com
|
||||
build_command_prepend: "cmake . -DBUILD_UNITTESTS=FALSE"
|
||||
build_command: "make -j2"
|
||||
build_command: "make -j3"
|
||||
branch_pattern: coverity_scan
|
||||
matrix:
|
||||
include:
|
||||
|
@ -32,27 +53,24 @@ matrix:
|
|||
allow_failures:
|
||||
- env: ANALYZE="scan-build-3.6 --use-cc clang-3.6 --use-c++ clang++-3.6 "
|
||||
|
||||
before_install:
|
||||
- if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./CI/before_install.linux.sh; fi
|
||||
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then ./CI/before_install.osx.sh; fi
|
||||
before_script:
|
||||
- if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./CI/before_script.linux.sh; fi
|
||||
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then ./CI/before_script.osx.sh; fi
|
||||
before_install:
|
||||
- ./CI/before_install.${TRAVIS_OS_NAME}.sh
|
||||
before_script: ./CI/before_script.${TRAVIS_OS_NAME}.sh
|
||||
script:
|
||||
- cd ./build
|
||||
- if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then ${ANALYZE}make -j3; fi
|
||||
- if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then make package; fi
|
||||
- if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi
|
||||
- if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "linux" ]; then cd .. && ./CI/check_tabs.sh; fi
|
||||
notifications:
|
||||
recipients:
|
||||
- corrmage+travis-ci@gmail.com
|
||||
email:
|
||||
on_success: change
|
||||
on_failure: always
|
||||
irc:
|
||||
channels:
|
||||
- "chat.freenode.net#openmw"
|
||||
on_success: change
|
||||
on_failure: always
|
||||
use_notice: true
|
||||
#notifications:
|
||||
# email:
|
||||
# recipients:
|
||||
# - corrmage+travis-ci@gmail.com
|
||||
# on_success: change
|
||||
# on_failure: always
|
||||
# irc:
|
||||
# channels:
|
||||
# - "chat.freenode.net#openmw"
|
||||
# on_success: change
|
||||
# on_failure: always
|
||||
# use_notice: true
|
||||
|
|
47
AUTHORS.md
47
AUTHORS.md
|
@ -14,15 +14,23 @@ Programmers
|
|||
|
||||
Adam Hogan (aurix)
|
||||
Aesylwinn
|
||||
aegis
|
||||
Aleksandar Jovanov
|
||||
Alex Haddad (rainChu)
|
||||
Alex McKibben (WeirdSexy)
|
||||
Alex McKibben
|
||||
alexanderkjall
|
||||
Alexander Nadeau (wareya)
|
||||
Alexander Olofsson (Ace)
|
||||
Allofich
|
||||
AnyOldName3
|
||||
Aussiemon
|
||||
Austin Salgat (Salgat)
|
||||
Artem Kotsynyak (greye)
|
||||
artemutin
|
||||
Arthur Moore (EmperorArthur)
|
||||
Assumeru
|
||||
athile
|
||||
Ben Shealy (bentsherman)
|
||||
Bret Curtis (psi29a)
|
||||
Britt Mathis (galdor557)
|
||||
cc9cii
|
||||
|
@ -31,6 +39,7 @@ Programmers
|
|||
Cory F. Cohen (cfcohen)
|
||||
Cris Mihalache (Mirceam)
|
||||
darkf
|
||||
devnexen
|
||||
Dieho
|
||||
Dmitry Shkurskiy (endorph)
|
||||
Douglas Diniz (Dgdiniz)
|
||||
|
@ -44,6 +53,7 @@ Programmers
|
|||
eroen
|
||||
escondida
|
||||
Evgeniy Mineev (sandstranger)
|
||||
Federico Guerra (FedeWar)
|
||||
Fil Krynicki (filkry)
|
||||
Gašper Sedej
|
||||
gugus/gus
|
||||
|
@ -62,13 +72,18 @@ Programmers
|
|||
John Blomberg (fstp)
|
||||
Jordan Ayers
|
||||
Jordan Milne
|
||||
Jules Blok (Armada651)
|
||||
Julien Voisin (jvoisin/ap0)
|
||||
Karl-Felix Glatzer (k1ll)
|
||||
Kevin Poitra (PuppyKevin)
|
||||
Koncord
|
||||
Kurnevsky Evgeny (kurnevsky)
|
||||
Lars Söderberg (Lazaroth)
|
||||
lazydev
|
||||
Leon Krieg (lkrieg)
|
||||
Leon Saunders (emoose)
|
||||
logzero
|
||||
lohikaarme
|
||||
Lukasz Gromanowski (lgro)
|
||||
Manuel Edelmann (vorenon)
|
||||
Marc Bouvier (CramitDeFrog)
|
||||
|
@ -76,6 +91,7 @@ Programmers
|
|||
Mark Siewert (mark76)
|
||||
Marco Melletti (mellotanica)
|
||||
Marco Schulze
|
||||
Martin Otto (MAtahualpa)
|
||||
Mateusz Kołaczek (PL_kolek)
|
||||
Mateusz Malisz (malice)
|
||||
megaton
|
||||
|
@ -83,6 +99,7 @@ Programmers
|
|||
Michael Mc Donnell
|
||||
Michael Papageorgiou (werdanith)
|
||||
Michał Bień (Glorf)
|
||||
Michał Moroz (dragonee)
|
||||
Miroslav Puda (pakanek)
|
||||
MiroslavR
|
||||
naclander
|
||||
|
@ -92,26 +109,31 @@ Programmers
|
|||
Nikolay Kasyanov (corristo)
|
||||
nobrakal
|
||||
Nolan Poe (nopoe)
|
||||
Oleg Chkan (mrcheko)
|
||||
Paul Cercueil (pcercuei)
|
||||
Paul McElroy (Greendogo)
|
||||
Pi03k
|
||||
Pieter van der Kloet (pvdk)
|
||||
pkubik
|
||||
Radu-Marius Popovici (rpopovici)
|
||||
rcutmore
|
||||
rdimesio
|
||||
riothamus
|
||||
Rob Cutmore (rcutmore)
|
||||
Robert MacGregor (Ragora)
|
||||
Rohit Nirmal
|
||||
Roman Melnik (Kromgart)
|
||||
Roman Proskuryakov (humbug)
|
||||
Roman Proskuryakov (kpp)
|
||||
Sandy Carter (bwrsandman)
|
||||
Scott Howard
|
||||
Sebastian Wick (swick)
|
||||
Sergey Shambir
|
||||
ShadowRadiance
|
||||
sir_herrbatka
|
||||
smbas
|
||||
Stefan Galowicz (bogglez)
|
||||
Stanislav Bobrov (Jiub)
|
||||
stil-t
|
||||
svaante
|
||||
Sylvain Thesnieres (Garvek)
|
||||
t6
|
||||
terrorfisch
|
||||
|
@ -123,19 +145,21 @@ Programmers
|
|||
vocollapse
|
||||
zelurker
|
||||
|
||||
Manual
|
||||
------
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
Bodillium
|
||||
Cramal
|
||||
Alejandro Sanchez (HiPhish)
|
||||
Bodillium
|
||||
Bret Curtis (psi29a)
|
||||
Cramal
|
||||
Ryan Tucker (Ravenwing)
|
||||
sir_herrbatka
|
||||
|
||||
Packagers
|
||||
---------
|
||||
|
||||
Alexander Olofsson (Ace) - Windows
|
||||
Bret Curtis (psi29a) - Ubuntu Linux
|
||||
Bret Curtis (psi29a) - Debian and Ubuntu Linux
|
||||
Edmondo Tommasina (edmondo) - Gentoo Linux
|
||||
Julian Ospald (hasufell) - Gentoo Linux
|
||||
Karl-Felix Glatzer (k1ll) - Linux Binaries
|
||||
|
@ -146,16 +170,16 @@ Packagers
|
|||
Public Relations and Translations
|
||||
---------------------------------
|
||||
|
||||
Alex McKibben (WeirdSexy) - Podcaster
|
||||
Artem Kotsynyak (greye) - Russian News Writer
|
||||
Dawid Lakomy (Vedyimyn) - Polish News Writer
|
||||
Jim Clauwaert (Zedd) - Public Outreach
|
||||
Julien Voisin (jvoisin/ap0) - French News Writer
|
||||
Tom Koenderink (Okulo) - English News Writer
|
||||
Lukasz Gromanowski (lgro) - English News Writer
|
||||
Martin Otto (Atahualpa) - Podcaster, Public Outreach, German Translator
|
||||
Mickey Lyle (raevol) - Release Manager
|
||||
Pithorn - Chinese News Writer
|
||||
sir_herrbatka - Polish News Writer
|
||||
Dawid Lakomy (Vedyimyn) - Polish News Writer
|
||||
Tom Koenderink (Okulo) - English News Writer
|
||||
|
||||
Website
|
||||
-------
|
||||
|
@ -206,7 +230,6 @@ Inactive Contributors
|
|||
Nekochan
|
||||
pchan3
|
||||
penguinroad
|
||||
psi29a
|
||||
sergoz
|
||||
spyboot
|
||||
Star-Demon
|
||||
|
|
225
CHANGELOG.md
225
CHANGELOG.md
|
@ -1,3 +1,228 @@
|
|||
0.41.0
|
||||
------
|
||||
|
||||
Bug #1138: Casting water walking doesn't move the player out of the water
|
||||
Bug #1931: Rocks from blocked passage in Bamz-Amschend, Radacs Forge can reset and cant be removed again.
|
||||
Bug #2048: Almvisi and Divine Intervention display wrong spell effect
|
||||
Bug #2054: Show effect-indicator for "instant effect" spells and potions
|
||||
Bug #2150: Clockwork City door animation problem
|
||||
Bug #2288: Playback of weapon idle animation not correct
|
||||
Bug #2410: Stat-review window doesn't display starting spells, powers, or abilities
|
||||
Bug #2493: Repairing occasionally very slow
|
||||
Bug #2716: [OSG] Water surface is too transparent from some angles
|
||||
Bug #2859: [MAC OS X] Cannot exit fullscreen once enabled
|
||||
Bug #3091: Editor: will not save addon if global variable value type is null
|
||||
Bug #3277: Editor: Non-functional nested tables in subviews need to be hidden instead of being disabled
|
||||
Bug #3348: Disabled map markers show on minimap
|
||||
Bug #3350: Extending selection to instances with same object results in duplicates.
|
||||
Bug #3353: [Mod] Romance version 3.7 script failed
|
||||
Bug #3376: [Mod] Vampire Embrace script fails to execute
|
||||
Bug #3385: Banners don't animate in stormy weather as they do in the original game
|
||||
Bug #3393: Akulakhan re-enabled after main quest
|
||||
Bug #3427: Editor: OpenMW-CS instances won´t get deleted
|
||||
Bug #3451: Feril Salmyn corpse isn't where it is supposed to be
|
||||
Bug #3497: Zero-weight armor is displayed as "heavy" in inventory tooltip
|
||||
Bug #3499: Idle animations don't always loop
|
||||
Bug #3500: Spark showers at Sotha Sil do not appear until you look at the ceiling
|
||||
Bug #3515: Editor: Moved objects in interior cells are teleported to exterior cells.
|
||||
Bug #3520: Editor: OpenMW-CS cannot find project file when launching the game
|
||||
Bug #3521: Armed NPCs don't use correct melee attacks
|
||||
Bug #3535: Changing cell immediately after dying causes character to freeze.
|
||||
Bug #3542: Unable to rest if unalerted slaughterfish are in the cell with you
|
||||
Bug #3549: Blood effects occur even when a hit is resisted
|
||||
Bug #3551: NPC Todwendy in german version can't interact
|
||||
Bug #3552: Opening the journal when fonts are missing results in a crash
|
||||
Bug #3555: SetInvisible command should not apply graphic effect
|
||||
Bug #3561: Editor: changes from omwaddon are not loaded in [New Addon] mode
|
||||
Bug #3562: Non-hostile NPCs can be disarmed by stealing their weapons via sneaking
|
||||
Bug #3564: Editor: openmw-cs verification results
|
||||
Bug #3568: Items that should be invisible are shown in the inventory
|
||||
Bug #3574: Alchemy: Alembics and retorts are used in reverse
|
||||
Bug #3575: Diaglog choices don't work in mw 0.40
|
||||
Bug #3576: Minor differences in AI reaction to hostile spell effects
|
||||
Bug #3577: not local nolore dialog test
|
||||
Bug #3578: Animation Replacer hangs after one cicle/step
|
||||
Bug #3579: Bound Armor skillups and sounds
|
||||
Bug #3583: Targetted GetCurrentAiPackage returns 0
|
||||
Bug #3584: Persuasion bug
|
||||
Bug #3590: Vendor, Ilen Faveran, auto equips items from stock
|
||||
Bug #3594: Weather doesn't seem to update correctly in Mournhold
|
||||
Bug #3598: Saving doesn't save status of objects
|
||||
Bug #3600: Screen goes black when trying to travel to Sadrith Mora
|
||||
Bug #3608: Water ripples aren't created when walking on water
|
||||
Bug #3626: Argonian NPCs swim like khajiits
|
||||
Bug #3627: Cannot delete "Blessed touch" spell from spellbook
|
||||
Bug #3634: An enchanted throwing weapon consumes charges from the stack in your inventory. (0.40.0)
|
||||
Bug #3635: Levelled items in merchants are "re-rolled" (not bug 2952, see inside)
|
||||
Feature #1118: AI combat: flee
|
||||
Feature #1596: Editor: Render water
|
||||
Feature #2042: Adding a non-portable Light to the inventory should cause the player to glow
|
||||
Feature #3166: Editor: Instance editing mode - rotate sub mode
|
||||
Feature #3167: Editor: Instance editing mode - scale sub mode
|
||||
Feature #3420: ess-Importer: player control flags
|
||||
Feature #3489: You shouldn't be be able to re-cast a bound equipment spell
|
||||
Feature #3496: Zero-weight boots should play light boot footsteps
|
||||
Feature #3516: Water Walking should give a "can't cast" message and fail when you are too deep
|
||||
Feature #3519: Play audio and visual effects for all effects in a spell
|
||||
Feature #3527: Double spell explosion scaling
|
||||
Feature #3534: Play particle textures for spell effects
|
||||
Feature #3539: Make NPCs use opponent's weapon range to decide whether to dodge
|
||||
Feature #3540: Allow dodging for creatures with "biped" flag
|
||||
Feature #3545: Drop shadow for items in menu
|
||||
Feature #3558: Implement same spell range for "on touch" spells as original engine
|
||||
Feature #3560: Allow using telekinesis with touch spells on objects
|
||||
Task #3585: Some objects added by Morrowind Rebirth do not display properly their texture
|
||||
|
||||
0.40.0
|
||||
------
|
||||
|
||||
Bug #1320: AiWander - Creatures in cells without pathgrids do not wander
|
||||
Bug #1873: Death events are triggered at the beginning of the death animation
|
||||
Bug #1996: Resting interrupts magic effects
|
||||
Bug #2399: Vampires can rest in broad daylight and survive the experience
|
||||
Bug #2604: Incorrect magicka recalculation
|
||||
Bug #2721: Telekinesis extends interaction range where it shouldn't
|
||||
Bug #2981: When waiting, NPCs can go where they wouldn't go normally.
|
||||
Bug #3045: Esp files containing the letter '#' in the file name cannot be loaded on startup
|
||||
Bug #3071: Slowfall does not stop momentum when jumping
|
||||
Bug #3085: Plugins can not replace parent cell references with a cell reference of different type
|
||||
Bug #3145: Bug with AI Cliff Racer. He will not attack you, unless you put in front of him.
|
||||
Bug #3149: Editor: Weather tables were missing from regions
|
||||
Bug #3201: Netch shoots over your head
|
||||
Bug #3269: If you deselect a mod and try to load a save made inside a cell added by it, you end bellow the terrain in the grid 0/0
|
||||
Bug #3286: Editor: Script editor tab width
|
||||
Bug #3329: Teleportation spells cause crash to desktop after build update from 0.37 to 0.38.0
|
||||
Bug #3331: Editor: Start Scripts table: Adding a script doesn't refresh the list of Start Scripts and allows to add a single script multiple times
|
||||
Bug #3332: Editor: Scene view: Tool tips only occur when holding the left mouse button
|
||||
Bug #3340: ESS-Importer does not separate item stacks
|
||||
Bug #3342: Editor: Creation of pathgrids did not check if the pathgrid already existed
|
||||
Bug #3346: "Talked to PC" is always 0 for "Hello" dialogue
|
||||
Bug #3349: AITravel doesn't repeat
|
||||
Bug #3370: NPCs wandering to invalid locations after training
|
||||
Bug #3378: "StopCombat" command does not function in vanilla quest
|
||||
Bug #3384: Battle at Nchurdamz - Larienna Macrina does not stop combat after killing Hrelvesuu
|
||||
Bug #3388: Monster Respawn tied to Quicksave
|
||||
Bug #3390: Strange visual effect in Dagoth Ur's chamber
|
||||
Bug #3391: Inappropriate Blight weather behavior at end of main quest
|
||||
Bug #3394: Replaced dialogue inherits some of its old data
|
||||
Bug #3397: Actors that start the game dead always have the same death pose
|
||||
Bug #3401: Sirollus Saccus sells not glass arrows
|
||||
Bug #3402: Editor: Weapon data not being properly set
|
||||
Bug #3405: Mulvisic Othril will not use her chitin throwing stars
|
||||
Bug #3407: Tanisie Verethi will immediately detect the player
|
||||
Bug #3408: Improper behavior of ashmire particles
|
||||
Bug #3412: Ai Wander start time resets when saving/loading the game
|
||||
Bug #3416: 1st person and 3rd person camera isn't converted from .ess correctly
|
||||
Bug #3421: Idling long enough while paralyzed sometimes causes character to get stuck
|
||||
Bug #3423: Sleep interruption inside dungeons too agressive
|
||||
Bug #3424: Pickpocketing sometimes won't work
|
||||
Bug #3432: AiFollow / AiEscort durations handled incorrectly
|
||||
Bug #3434: Dead NPC's and Creatures still contribute to sneak skill increases
|
||||
Bug #3437: Weather-conditioned dialogue should not play in interiors
|
||||
Bug #3439: Effects cast by summon stick around after their death
|
||||
Bug #3440: Parallax maps looks weird
|
||||
Bug #3443: Class graphic for custom class should be Acrobat
|
||||
Bug #3446: OpenMW segfaults when using Atrayonis's "Anthology Solstheim: Tomb of the Snow Prince" mod
|
||||
Bug #3448: After dispelled, invisibility icon is still displayed
|
||||
Bug #3453: First couple of seconds of NPC speech is muted
|
||||
Bug #3455: Portable house mods lock player and npc movement up exiting house.
|
||||
Bug #3456: Equipping an item will undo dispel of constant effect invisibility
|
||||
Bug #3458: Constant effect restore health doesn't work during Wait
|
||||
Bug #3466: It is possible to stack multiple scroll effects of the same type
|
||||
Bug #3471: When two mods delete the same references, many references are not disabled by the engine.
|
||||
Bug #3473: 3rd person camera can be glitched
|
||||
Feature #1424: NPC "Face" function
|
||||
Feature #2974: Editor: Multiple Deletion of Subrecords
|
||||
Feature #3044: Editor: Render path grid v2
|
||||
Feature #3362: Editor: Configurable key bindings
|
||||
Feature #3375: Make sun / moon reflections weather dependent
|
||||
Feature #3386: Editor: Edit pathgrid
|
||||
|
||||
0.39.0
|
||||
------
|
||||
|
||||
Bug #1384: Dark Brotherhood Assassin (and other scripted NPCs?) spawns beneath/inside solid objects
|
||||
Bug #1544: "Drop" drops equipped item in a separate stack
|
||||
Bug #1587: Collision detection glitches
|
||||
Bug #1629: Container UI locks up in Vivec at Jeanne's
|
||||
Bug #1771: Dark Brotherhood Assassin oddity in Eight Plates
|
||||
Bug #1827: Unhandled NiTextureEffect in ex_dwrv_ruin30.nif
|
||||
Bug #2089: When saving while swimming in water in an interior cell, you will be spawned under water on loading
|
||||
Bug #2295: Internal texture not showing, nipixeldata
|
||||
Bug #2363: Corpses don't disappear
|
||||
Bug #2369: Respawns should be timed individually
|
||||
Bug #2393: Сharacter is stuck in the tree
|
||||
Bug #2444: [Mod] NPCs from Animated Morrowind appears not using proper animations
|
||||
Bug #2467: Creatures do not respawn
|
||||
Bug #2515: Ghosts in Ibar-Dad spawn stuck in walls
|
||||
Bug #2610: FixMe script still needs to be implemented
|
||||
Bug #2689: Riekling raider pig constantly screams while running
|
||||
Bug #2719: Vivec don't put their hands on the knees with this replacer (Psymoniser Vivec God Replacement NPC Edition v1.0
|
||||
Bug #2737: Camera shaking when side stepping around object
|
||||
Bug #2760: AI Combat Priority Problem - Use of restoration spell instead of attacking
|
||||
Bug #2806: Stack overflow in LocalScripts::getNext
|
||||
Bug #2807: Collision detection allows player to become stuck inside objects
|
||||
Bug #2814: Stairs to Marandus have improper collision
|
||||
Bug #2925: Ranes Ienith will not appear, breaking the Morag Tong and Thieves Guid questlines
|
||||
Bug #3024: Editor: Creator bar in startscript subview does not accept script ID drops
|
||||
Bug #3046: Sleep creature: Velk is spawned half-underground in the Thirr River Valley
|
||||
Bug #3080: Calling aifollow without operant in local script every frame causes mechanics to overheat + log
|
||||
Bug #3101: Regression: White guar does not move
|
||||
Bug #3108: Game Freeze after Killing Diseased Rat in Foreign Quarter Tomb
|
||||
Bug #3124: Bloodmoon Quest - Rite of the Wolf Giver (BM_WolfGiver) – Innocent victim won't turn werewolf
|
||||
Bug #3125: Improper dialogue window behavior when talking to creatures
|
||||
Bug #3130: Some wandering NPCs disappearing, cannot finish quests
|
||||
Bug #3132: Editor: GMST ID named sMake Enchantment is instead named sMake when making new game from scratch
|
||||
Bug #3133: OpenMW and the OpenCS are writting warnings about scripts that use the function GetDisabled.
|
||||
Bug #3135: Journal entry for The Pigrim's Path missing name
|
||||
Bug #3136: Dropped bow is displaced
|
||||
Bug #3140: Editor: OpenMW-CS fails to open newly converted and saved omwaddon file.
|
||||
Bug #3142: Duplicate Resist Magic message
|
||||
Bug #3143: Azura missing her head
|
||||
Bug #3146: Potion effect showing when ingredient effects are not known
|
||||
Bug #3155: When executing chop attack with a spear, hands turn partly invisible
|
||||
Bug #3161: Fast travel from Silt Strider or Boat Ride will break save files made afterwards
|
||||
Bug #3163: Editor: Objects dropped to scene do not always save
|
||||
Bug #3173: Game Crashes After Casting Recall Spell
|
||||
Bug #3174: Constant effect enchantments play spell animation on dead bodies
|
||||
Bug #3175: Spell effects do not wear down when caster dies
|
||||
Bug #3176: NPCs appearing randomly far away from towns
|
||||
Bug #3177: Submerged corpse floats ontop of water when it shouldn't (Widow Vabdas' Deed quest)
|
||||
Bug #3184: Bacola Closcius in Balmora, South Wall Cornerclub spams magic effects if attacked
|
||||
Bug #3207: Editor: New objects do not render
|
||||
Bug #3212: Arrow of Ranged Silence
|
||||
Bug #3213: Looking at Floor After Magical Transport
|
||||
Bug #3220: The number of remaining ingredients in the alchemy window doesn't go down when failing to brew a potion
|
||||
Bug #3222: Falling through the water in Vivec
|
||||
Bug #3223: Crash at the beginning with MOD (The Symphony)
|
||||
Bug #3228: Purple screen when leveling up.
|
||||
Bug #3233: Infinite disposition via MWDialogue::Filter::testDisposition() glitch
|
||||
Bug #3234: Armor mesh stuck on body in inventory menu
|
||||
Bug #3235: Unlike vanilla, OpenMW don't allow statics and activators cast effects on the player.
|
||||
Bug #3238: Not loading cells when using Poorly Placed Object Fix.esm
|
||||
Bug #3248: Editor: Using the "Next Script" and "Previous Script" buttons changes the record status to "Modified"
|
||||
Bug #3258: Woman biped skeleton
|
||||
Bug #3259: No alternating punches
|
||||
Bug #3262: Crash in class selection menu
|
||||
Bug #3279: Load menu: Deleting a savegame makes scroll bar jump to the top
|
||||
Bug #3326: Starting a new game, getting to class selection, then starting another new game temporarily assigns Acrobat class
|
||||
Bug #3327: Stuck in table after loading when character was sneaking when quicksave
|
||||
Feature #652: Editor: GMST verifier
|
||||
Feature #929: Editor: Info record verifier
|
||||
Feature #1279: Editor: Render cell border markers
|
||||
Feature #2482: Background cell loading and caching of loaded cells
|
||||
Feature #2484: Editor: point lighting
|
||||
Feature #2801: Support NIF bump map textures in osg
|
||||
Feature #2926: Editor: Optional line wrap in script editor wrap lines
|
||||
Feature #3000: Editor: Reimplement 3D scene camera system
|
||||
Feature #3035: Editor: Make scenes a drop target for referenceables
|
||||
Feature #3043: Editor: Render cell markers v2
|
||||
Feature #3164: Editor: Instance Selection Menu
|
||||
Feature #3165: Editor: Instance editing mode - move sub mode
|
||||
Feature #3244: Allow changing water Level of Interiors behaving like exteriors
|
||||
Feature #3250: Editor: Use "Enter" key instead of clicking "Create" button to confirm ID input in Creator Bar
|
||||
Support #3179: Fatal error on startup
|
||||
|
||||
0.38.0
|
||||
------
|
||||
|
||||
|
|
|
@ -1,21 +1,24 @@
|
|||
#!/bin/sh
|
||||
echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca-
|
||||
sudo ln -s /usr/bin/clang-3.6 /usr/local/bin/clang
|
||||
sudo ln -s /usr/bin/clang++-3.6 /usr/local/bin/clang++
|
||||
|
||||
if [ "${ANALYZE}" ]; then
|
||||
echo "yes" | sudo add-apt-repository "deb http://llvm.org/apt/`lsb_release -sc`/ llvm-toolchain-`lsb_release -sc`-3.6 main"
|
||||
wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key|sudo apt-key add -
|
||||
fi
|
||||
|
||||
echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse"
|
||||
echo "yes" | sudo apt-add-repository ppa:openmw/openmw
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -qq libgtest-dev google-mock
|
||||
sudo apt-get install -qq libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev
|
||||
sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev
|
||||
sudo apt-get install -qq libbullet-dev libopenscenegraph-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev
|
||||
if [ "${ANALYZE}" ]; then sudo apt-get install -qq clang-3.6; fi
|
||||
# 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
|
||||
|
||||
cd ~/
|
||||
git clone https://github.com/TES3MP/RakNet
|
||||
cd RakNet
|
||||
cmake . -DRAKNET_ENABLE_DLL=OFF -DRAKNET_ENABLE_SAMPLES=OFF -DCMAKE_BUILD_TYPE=Release
|
||||
mkdir ./lib
|
||||
make -j3 install
|
||||
cp ./Lib/RakNetLibStatic/libRakNetLibStatic.a ./lib
|
||||
cd ..
|
||||
|
||||
wget https://github.com/zdevito/terra/releases/download/release-2016-03-25/terra-Linux-x86_64-332a506.zip
|
||||
unzip terra-Linux-x86_64-332a506.zip
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
#!/bin/sh
|
||||
|
||||
export CXX=clang++
|
||||
export CC=clang
|
||||
|
||||
brew tap openmw/openmw
|
||||
brew update
|
||||
brew unlink boost
|
||||
brew install openmw-mygui openmw-bullet openmw-sdl2 openmw-ffmpeg openmw/openmw/qt unshield
|
||||
|
||||
brew rm cmake || true
|
||||
brew rm pkgconfig || true
|
||||
brew rm qt5 || true
|
||||
brew install cmake pkgconfig $macos_qt_formula
|
||||
|
||||
curl https://downloads.openmw.org/osx/dependencies/openmw-deps-0ecece4.zip -o ~/openmw-deps.zip
|
||||
unzip ~/openmw-deps.zip -d /private/tmp/openmw-deps > /dev/null
|
||||
|
|
|
@ -4,5 +4,14 @@ free -m
|
|||
mkdir build
|
||||
cd build
|
||||
export CODE_COVERAGE=1
|
||||
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="RelWithDebInfo" -DUSE_SYSTEM_TINYXML=TRUE
|
||||
export RAKNET_ROOT=~/RakNet
|
||||
export Terra_ROOT=~/terra-Linux-x86_64-332a506
|
||||
export BUILD_SERVER=OFF
|
||||
if [ "${CC}" = "clang" ]; then export CODE_COVERAGE=0;
|
||||
else
|
||||
export COMPILER_NAME=gcc
|
||||
export CXX=g++-6
|
||||
export CC=gcc-6
|
||||
export BUILD_SERVER=ON
|
||||
fi
|
||||
${ANALYZE}cmake .. -DBUILD_OPENMW_MP=${BUILD_SERVER} -DBUILD_WITH_CODE_COVERAGE=${CODE_COVERAGE} -DBUILD_BSATOOL=OFF -DBUILD_ESMTOOL=OFF -DBUILD_ESSIMPORTER=OFF -DBUILD_LAUNCHER=OFF -DBUILD_MWINIIMPORTER=OFF -DBUILD_MYGUI_PLUGIN=OFF -DBUILD_OPENCS=OFF -DBUILD_WIZARD=OFF -DBUILD_BROWSER=OFF -DBUILD_UNITTESTS=1 -DCMAKE_INSTALL_PREFIX=/usr -DBINDIR=/usr/games -DCMAKE_BUILD_TYPE="None" -DUSE_SYSTEM_TINYXML=TRUE -DRakNet_LIBRARY_RELEASE=~/RakNet/lib/libRakNetLibStatic.a -DRakNet_LIBRARY_DEBUG=~/RakNet/lib/libRakNetLibStatic.a
|
||||
|
|
468
CI/before_script.msvc.sh
Executable file → Normal file
468
CI/before_script.msvc.sh
Executable file → Normal file
|
@ -1,5 +1,21 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
APPVEYOR=${APPVEYOR:-}
|
||||
CI=${CI:-}
|
||||
STEP=${STEP:-}
|
||||
|
||||
VERBOSE=""
|
||||
STRIP=""
|
||||
SKIP_DOWNLOAD=""
|
||||
SKIP_EXTRACT=""
|
||||
KEEP=""
|
||||
UNITY_BUILD=""
|
||||
VS_VERSION=""
|
||||
PLATFORM=""
|
||||
CONFIGURATION=""
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
ARGSTR=$1
|
||||
shift
|
||||
|
@ -16,10 +32,6 @@ while [ $# -gt 0 ]; do
|
|||
V )
|
||||
VERBOSE=true ;;
|
||||
|
||||
v )
|
||||
VS_VERSION=$1
|
||||
shift ;;
|
||||
|
||||
d )
|
||||
SKIP_DOWNLOAD=true ;;
|
||||
|
||||
|
@ -32,6 +44,10 @@ while [ $# -gt 0 ]; do
|
|||
u )
|
||||
UNITY_BUILD=true ;;
|
||||
|
||||
v )
|
||||
VS_VERSION=$1
|
||||
shift ;;
|
||||
|
||||
p )
|
||||
PLATFORM=$1
|
||||
shift ;;
|
||||
|
@ -78,9 +94,6 @@ done
|
|||
if [ -z $VERBOSE ]; then
|
||||
STRIP="> /dev/null 2>&1"
|
||||
fi
|
||||
if [ -z $VS_VERSION ]; then
|
||||
VS_VERSION="2013"
|
||||
fi
|
||||
|
||||
if [ -z $APPVEYOR ]; then
|
||||
echo "Running prebuild outside of Appveyor."
|
||||
|
@ -90,9 +103,7 @@ if [ -z $APPVEYOR ]; then
|
|||
else
|
||||
echo "Running prebuild in Appveyor."
|
||||
|
||||
cd $APPVEYOR_BUILD_FOLDER
|
||||
VERSION="$(cat README.md | grep Version: | awk '{ print $3; }')-$(git rev-parse --short HEAD)"
|
||||
appveyor UpdateBuild -Version "$VERSION" > /dev/null &
|
||||
cd "$APPVEYOR_BUILD_FOLDER"
|
||||
fi
|
||||
|
||||
run_cmd() {
|
||||
|
@ -105,7 +116,7 @@ run_cmd() {
|
|||
|
||||
if [ $RET -ne 0 ]; then
|
||||
if [ -z $APPVEYOR ]; then
|
||||
echo "Command $CMD failed, output can be found in `real_pwd`/output.log"
|
||||
echo "Command $CMD failed, output can be found in $(real_pwd)/output.log"
|
||||
else
|
||||
echo
|
||||
echo "Command $CMD failed;"
|
||||
|
@ -184,44 +195,58 @@ add_osg_dlls() {
|
|||
OSG_PLUGINS="$OSG_PLUGINS $@"
|
||||
}
|
||||
|
||||
QT_PLATFORMS=""
|
||||
add_qt_platform_dlls() {
|
||||
QT_PLATFORMS="$QT_PLATFORMS $@"
|
||||
}
|
||||
|
||||
if [ -z $PLATFORM ]; then
|
||||
PLATFORM=`uname -m`
|
||||
PLATFORM="$(uname -m)"
|
||||
fi
|
||||
|
||||
if [ -z $CONFIGURATION ]; then
|
||||
CONFIGURATION="Debug"
|
||||
fi
|
||||
|
||||
if [ -z $VS_VERSION ]; then
|
||||
VS_VERSION="2013"
|
||||
fi
|
||||
|
||||
case $VS_VERSION in
|
||||
14|2015 )
|
||||
14|14.0|2015 )
|
||||
GENERATOR="Visual Studio 14 2015"
|
||||
XP_TOOLSET="v140_xp"
|
||||
TOOLSET="v140"
|
||||
MSVC_VER="14"
|
||||
MSVC_YEAR="2015"
|
||||
;;
|
||||
|
||||
# 12|2013|
|
||||
* )
|
||||
12|12.0|2013 )
|
||||
GENERATOR="Visual Studio 12 2013"
|
||||
XP_TOOLSET="v120_xp"
|
||||
TOOLSET="v120"
|
||||
MSVC_VER="12"
|
||||
MSVC_YEAR="2013"
|
||||
;;
|
||||
esac
|
||||
|
||||
case $PLATFORM in
|
||||
x64|x86_64|x86-64|win64|Win64 )
|
||||
ARCHNAME=x86-64
|
||||
ARCHSUFFIX=64
|
||||
BITS=64
|
||||
ARCHNAME="x86-64"
|
||||
ARCHSUFFIX="64"
|
||||
BITS="64"
|
||||
|
||||
BASE_OPTS="-G\"$GENERATOR Win64\""
|
||||
add_cmake_opts "-G\"$GENERATOR Win64\""
|
||||
;;
|
||||
|
||||
x32|x86|i686|i386|win32|Win32 )
|
||||
ARCHNAME=x86
|
||||
ARCHSUFFIX=86
|
||||
BITS=32
|
||||
ARCHNAME="x86"
|
||||
ARCHSUFFIX="86"
|
||||
BITS="32"
|
||||
|
||||
BASE_OPTS="-G\"$GENERATOR\" -T$XP_TOOLSET"
|
||||
add_cmake_opts "-G\"$GENERATOR\"" -T$XP_TOOLSET
|
||||
BASE_OPTS="-G\"$GENERATOR\""
|
||||
add_cmake_opts "-G\"$GENERATOR\""
|
||||
;;
|
||||
|
||||
* )
|
||||
|
@ -230,35 +255,38 @@ case $PLATFORM in
|
|||
;;
|
||||
esac
|
||||
|
||||
if ! [ -z $UNITY_BUILD ]; then
|
||||
add_cmake_opts "-DOPENMW_UNITY_BUILD=True"
|
||||
fi
|
||||
|
||||
case $CONFIGURATION in
|
||||
debug|Debug|DEBUG )
|
||||
CONFIGURATION=Debug
|
||||
BUILD_CONFIG=Debug
|
||||
;;
|
||||
|
||||
release|Release|RELEASE )
|
||||
CONFIGURATION=Release
|
||||
BUILD_CONFIG=Release
|
||||
;;
|
||||
|
||||
relwithdebinfo|RelWithDebInfo|RELWITHDEBINFO )
|
||||
CONFIGURATION=RelWithDebInfo
|
||||
CONFIGURATION=Release
|
||||
BUILD_CONFIG=RelWithDebInfo
|
||||
;;
|
||||
esac
|
||||
|
||||
if ! [ -z $UNITY_BUILD ]; then
|
||||
add_cmake_opts "-DOPENMW_UNITY_BUILD=True"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "=========================="
|
||||
echo "Starting prebuild on win$BITS"
|
||||
echo "=========================="
|
||||
echo "==================================="
|
||||
echo "Starting prebuild on MSVC${MSVC_YEAR} WIN${BITS}"
|
||||
echo "==================================="
|
||||
echo
|
||||
|
||||
# cd OpenMW/AppVeyor-test
|
||||
mkdir -p deps
|
||||
cd deps
|
||||
|
||||
DEPS="`pwd`"
|
||||
DEPS="$(pwd)"
|
||||
|
||||
if [ -z $SKIP_DOWNLOAD ]; then
|
||||
echo "Downloading dependency packages."
|
||||
|
@ -266,162 +294,165 @@ if [ -z $SKIP_DOWNLOAD ]; then
|
|||
|
||||
# Boost
|
||||
if [ -z $APPVEYOR ]; then
|
||||
download "Boost 1.58.0" \
|
||||
http://sourceforge.net/projects/boost/files/boost-binaries/1.58.0/boost_1_58_0-msvc-12.0-$BITS.exe \
|
||||
boost-1.58.0-win$BITS.exe
|
||||
download "Boost 1.61.0" \
|
||||
"http://sourceforge.net/projects/boost/files/boost-binaries/1.61.0/boost_1_61_0-msvc-${MSVC_VER}.0-${BITS}.exe" \
|
||||
"boost-1.61.0-msvc${MSVC_YEAR}-win${BITS}.exe"
|
||||
fi
|
||||
|
||||
# Bullet
|
||||
download "Bullet 2.83.5" \
|
||||
http://www.lysator.liu.se/~ace/OpenMW/deps/Bullet-2.83.5-win$BITS.7z \
|
||||
Bullet-2.83.5-win$BITS.7z
|
||||
download "Bullet 2.86" \
|
||||
"http://www.lysator.liu.se/~ace/OpenMW/deps/Bullet-2.86-msvc${MSVC_YEAR}-win${BITS}.7z" \
|
||||
"Bullet-2.86-msvc${MSVC_YEAR}-win${BITS}.7z"
|
||||
|
||||
# FFmpeg
|
||||
download "FFmpeg 2.5.2" \
|
||||
http://ffmpeg.zeranoe.com/builds/win$BITS/shared/ffmpeg-2.5.2-win$BITS-shared.7z \
|
||||
ffmpeg$BITS-2.5.2.7z \
|
||||
http://ffmpeg.zeranoe.com/builds/win$BITS/dev/ffmpeg-2.5.2-win$BITS-dev.7z \
|
||||
ffmpeg$BITS-2.5.2-dev.7z
|
||||
download "FFmpeg 3.0.1" \
|
||||
"http://ffmpeg.zeranoe.com/builds/win${BITS}/shared/ffmpeg-3.0.1-win${BITS}-shared.7z" \
|
||||
"ffmpeg-3.0.1-win${BITS}.7z" \
|
||||
"http://ffmpeg.zeranoe.com/builds/win${BITS}/dev/ffmpeg-3.0.1-win${BITS}-dev.7z" \
|
||||
"ffmpeg-3.0.1-dev-win${BITS}.7z"
|
||||
|
||||
# MyGUI
|
||||
download "MyGUI 3.2.2" \
|
||||
http://www.lysator.liu.se/~ace/OpenMW/deps/MyGUI-3.2.2-win$BITS.7z \
|
||||
MyGUI-3.2.2-win$BITS.7z
|
||||
download "MyGUI 3.2.3-git" \
|
||||
"http://www.lysator.liu.se/~ace/OpenMW/deps/MyGUI-3.2.3-git-msvc${MSVC_YEAR}-win${BITS}.7z" \
|
||||
"MyGUI-3.2.3-git-msvc${MSVC_YEAR}-win${BITS}.7z"
|
||||
|
||||
# OpenAL
|
||||
download "OpenAL-Soft 1.16.0" \
|
||||
http://kcat.strangesoft.net/openal-binaries/openal-soft-1.16.0-bin.zip \
|
||||
OpenAL-Soft-1.16.0.zip
|
||||
download "OpenAL-Soft 1.17.2" \
|
||||
"http://kcat.strangesoft.net/openal-binaries/openal-soft-1.17.2-bin.zip" \
|
||||
"OpenAL-Soft-1.17.2.zip"
|
||||
|
||||
# OSG
|
||||
download "OpenSceneGraph 3.3.8" \
|
||||
http://www.lysator.liu.se/~ace/OpenMW/deps/OSG-3.3.8-win$BITS.7z \
|
||||
OSG-3.3.8-win$BITS.7z
|
||||
download "OpenSceneGraph 3.4.0-scrawl" \
|
||||
"http://www.lysator.liu.se/~ace/OpenMW/deps/OSG-3.4.0-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z" \
|
||||
"OSG-3.4.0-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z"
|
||||
|
||||
# Qt
|
||||
if [ -z $APPVEYOR ]; then
|
||||
download "Qt 4.8.6" \
|
||||
http://sourceforge.net/projects/qt64ng/files/qt/$ARCHNAME/4.8.6/msvc2013/qt-4.8.6-x$ARCHSUFFIX-msvc2013.7z \
|
||||
qt$BITS-4.8.6.7z
|
||||
if [ $BITS == "64" ]; then
|
||||
QT_SUFFIX="_64"
|
||||
else
|
||||
QT_SUFFIX=""
|
||||
fi
|
||||
|
||||
download "Qt 5.7.2" \
|
||||
"http://download.qt.io/official_releases/qt/5.7/5.7.0/qt-opensource-windows-x86-msvc${MSVC_YEAR}${QT_SUFFIX}-5.7.0.exe" \
|
||||
"qt-5.7.0-msvc${MSVC_YEAR}-win${BITS}.exe" \
|
||||
"http://www.lysator.liu.se/~ace/OpenMW/deps/qt-5-install.qs" \
|
||||
"qt-5-install.qs"
|
||||
fi
|
||||
|
||||
# SDL2
|
||||
download "SDL 2.0.3" \
|
||||
https://www.libsdl.org/release/SDL2-devel-2.0.3-VC.zip \
|
||||
SDL2-2.0.3.zip
|
||||
download "SDL 2.0.4" \
|
||||
"https://www.libsdl.org/release/SDL2-devel-2.0.4-VC.zip" \
|
||||
"SDL2-2.0.4.zip"
|
||||
fi
|
||||
|
||||
cd .. #/..
|
||||
|
||||
# Set up dependencies
|
||||
BUILD_DIR="MSVC${MSVC_YEAR}_${BITS}"
|
||||
if [ -z $KEEP ]; then
|
||||
echo
|
||||
printf "Preparing build directory... "
|
||||
echo "(Re)Creating build directory."
|
||||
|
||||
rm -rf Build_$BITS
|
||||
mkdir -p Build_$BITS/deps
|
||||
|
||||
echo Done.
|
||||
rm -rf "$BUILD_DIR"
|
||||
fi
|
||||
mkdir -p Build_$BITS/deps
|
||||
cd Build_$BITS/deps
|
||||
|
||||
DEPS_INSTALL=`pwd`
|
||||
mkdir -p "${BUILD_DIR}/deps"
|
||||
cd "${BUILD_DIR}/deps"
|
||||
|
||||
DEPS_INSTALL="$(pwd)"
|
||||
cd $DEPS
|
||||
|
||||
echo
|
||||
echo "Extracting dependencies..."
|
||||
echo "Extracting dependencies, this might take a while..."
|
||||
echo "---------------------------------------------------"
|
||||
echo
|
||||
|
||||
|
||||
# Boost
|
||||
printf "Boost 1.58.0... "
|
||||
if [ -z $APPVEYOR ]; then
|
||||
printf "Boost 1.61.0... "
|
||||
else
|
||||
if [ $MSVC_VER -eq 12 ]; then
|
||||
printf "Boost 1.58.0 AppVeyor... "
|
||||
else
|
||||
printf "Boost 1.60.0 AppVeyor... "
|
||||
fi
|
||||
fi
|
||||
{
|
||||
if [ -z $APPVEYOR ]; then
|
||||
cd $DEPS_INSTALL
|
||||
|
||||
BOOST_SDK="`real_pwd`/Boost"
|
||||
BOOST_SDK="$(real_pwd)/Boost"
|
||||
|
||||
if [ -d Boost ] && grep "BOOST_VERSION 105800" Boost/boost/version.hpp > /dev/null; then
|
||||
if [ -d Boost ] && grep "BOOST_VERSION 106100" Boost/boost/version.hpp > /dev/null; then
|
||||
printf "Exists. "
|
||||
elif [ -z $SKIP_EXTRACT ]; then
|
||||
rm -rf Boost
|
||||
$DEPS/boost-1.58.0-win$BITS.exe //dir="$(echo $BOOST_SDK | sed s,/,\\\\,g)" //verysilent
|
||||
"${DEPS}/boost-1.61.0-msvc${MSVC_YEAR}-win${BITS}.exe" //dir="$(echo $BOOST_SDK | sed s,/,\\\\,g)" //verysilent
|
||||
fi
|
||||
|
||||
add_cmake_opts -DBOOST_ROOT="$BOOST_SDK" \
|
||||
-DBOOST_LIBRARYDIR="$BOOST_SDK/lib$BITS-msvc-12.0"
|
||||
-DBOOST_LIBRARYDIR="${BOOST_SDK}/lib${BITS}-msvc-${MSVC_VER}.0"
|
||||
|
||||
echo Done.
|
||||
else
|
||||
# Appveyor unstable has all the boost we need already
|
||||
BOOST_SDK="c:/Libraries/boost"
|
||||
if [ $MSVC_VER -eq 12 ]; then
|
||||
BOOST_SDK="c:/Libraries/boost_1_58_0"
|
||||
else
|
||||
BOOST_SDK="c:/Libraries/boost_1_60_0"
|
||||
fi
|
||||
add_cmake_opts -DBOOST_ROOT="$BOOST_SDK" \
|
||||
-DBOOST_LIBRARYDIR="$BOOST_SDK/lib$BITS-msvc-12.0"
|
||||
-DBOOST_LIBRARYDIR="${BOOST_SDK}/lib${BITS}-msvc-${MSVC_VER}.0"
|
||||
|
||||
echo AppVeyor.
|
||||
echo Done.
|
||||
fi
|
||||
}
|
||||
cd $DEPS
|
||||
echo
|
||||
|
||||
# Bullet
|
||||
printf "Bullet 2.83.5... "
|
||||
printf "Bullet 2.86... "
|
||||
{
|
||||
cd $DEPS_INSTALL
|
||||
|
||||
if [ -d Bullet ]; then
|
||||
printf "Exists. (No version checking) "
|
||||
printf -- "Exists. (No version checking) "
|
||||
elif [ -z $SKIP_EXTRACT ]; then
|
||||
rm -rf Bullet
|
||||
eval 7z x -y $DEPS/Bullet-2.83.5-win$BITS.7z $STRIP
|
||||
mv Bullet-2.83.5-win$BITS Bullet
|
||||
eval 7z x -y "${DEPS}/Bullet-2.86-msvc${MSVC_YEAR}-win${BITS}.7z" $STRIP
|
||||
mv "Bullet-2.86-msvc${MSVC_YEAR}-win${BITS}" Bullet
|
||||
fi
|
||||
|
||||
BULLET_SDK="`real_pwd`/Bullet"
|
||||
add_cmake_opts -DBULLET_INCLUDE_DIR="$BULLET_SDK/include/bullet" \
|
||||
-DBULLET_COLLISION_LIBRARY="$BULLET_SDK/lib/BulletCollision.lib" \
|
||||
-DBULLET_COLLISION_LIBRARY_DEBUG="$BULLET_SDK/lib/BulletCollision_Debug.lib" \
|
||||
-DBULLET_MATH_LIBRARY="$BULLET_SDK/lib/LinearMath.lib" \
|
||||
-DBULLET_MATH_LIBRARY_DEBUG="$BULLET_SDK/lib/LinearMath_Debug.lib"
|
||||
export BULLET_ROOT="$(real_pwd)/Bullet"
|
||||
|
||||
echo Done.
|
||||
}
|
||||
cd $DEPS
|
||||
echo
|
||||
|
||||
# FFmpeg
|
||||
printf "FFmpeg 2.5.2... "
|
||||
printf "FFmpeg 3.0.1... "
|
||||
{
|
||||
cd $DEPS_INSTALL
|
||||
|
||||
if [ -d FFmpeg ] && grep "FFmpeg version: 2.5.2" FFmpeg/README.txt > /dev/null; then
|
||||
if [ -d FFmpeg ] && grep "FFmpeg version: 3.0.1" FFmpeg/README.txt > /dev/null; then
|
||||
printf "Exists. "
|
||||
elif [ -z $SKIP_EXTRACT ]; then
|
||||
rm -rf FFmpeg
|
||||
|
||||
eval 7z x -y $DEPS/ffmpeg$BITS-2.5.2.7z $STRIP
|
||||
eval 7z x -y $DEPS/ffmpeg$BITS-2.5.2-dev.7z $STRIP
|
||||
eval 7z x -y "${DEPS}/ffmpeg-3.0.1-win${BITS}.7z" $STRIP
|
||||
eval 7z x -y "${DEPS}/ffmpeg-3.0.1-dev-win${BITS}.7z" $STRIP
|
||||
|
||||
mv ffmpeg-2.5.2-win$BITS-shared FFmpeg
|
||||
cp -r ffmpeg-2.5.2-win$BITS-dev/* FFmpeg/
|
||||
rm -rf ffmpeg-2.5.2-win$BITS-dev
|
||||
mv "ffmpeg-3.0.1-win${BITS}-shared" FFmpeg
|
||||
cp -r "ffmpeg-3.0.1-win${BITS}-dev/"* FFmpeg/
|
||||
rm -rf "ffmpeg-3.0.1-win${BITS}-dev"
|
||||
fi
|
||||
|
||||
FFMPEG_SDK="`real_pwd`/FFmpeg"
|
||||
add_cmake_opts -DAVCODEC_INCLUDE_DIRS="$FFMPEG_SDK/include" \
|
||||
-DAVCODEC_LIBRARIES="$FFMPEG_SDK/lib/avcodec.lib" \
|
||||
-DAVDEVICE_INCLUDE_DIRS="$FFMPEG_SDK/include" \
|
||||
-DAVDEVICE_LIBRARIES="$FFMPEG_SDK/lib/avdevice.lib" \
|
||||
-DAVFORMAT_INCLUDE_DIRS="$FFMPEG_SDK/include" \
|
||||
-DAVFORMAT_LIBRARIES="$FFMPEG_SDK/lib/avformat.lib" \
|
||||
-DAVUTIL_INCLUDE_DIRS="$FFMPEG_SDK/include" \
|
||||
-DAVUTIL_LIBRARIES="$FFMPEG_SDK/lib/avutil.lib" \
|
||||
-DPOSTPROC_INCLUDE_DIRS="$FFMPEG_SDK/include" \
|
||||
-DPOSTPROC_LIBRARIES="$FFMPEG_SDK/lib/postproc.lib" \
|
||||
-DSWRESAMPLE_INCLUDE_DIRS="$FFMPEG_SDK/include" \
|
||||
-DSWRESAMPLE_LIBRARIES="$FFMPEG_SDK/lib/swresample.lib" \
|
||||
-DSWSCALE_INCLUDE_DIRS="$FFMPEG_SDK/include" \
|
||||
-DSWSCALE_LIBRARIES="$FFMPEG_SDK/lib/swscale.lib"
|
||||
|
||||
add_runtime_dlls `pwd`/FFmpeg/bin/{avcodec-56,avformat-56,avutil-54,swresample-1,swscale-3}.dll
|
||||
export FFMPEG_HOME="$(real_pwd)/FFmpeg"
|
||||
add_runtime_dlls "$(pwd)/FFmpeg/bin/"{avcodec-57,avformat-57,avutil-55,swresample-2,swscale-4}.dll
|
||||
|
||||
if [ $BITS -eq 32 ]; then
|
||||
add_cmake_opts "-DCMAKE_EXE_LINKER_FLAGS=\"/machine:X86 /safeseh:no\""
|
||||
|
@ -430,78 +461,79 @@ printf "FFmpeg 2.5.2... "
|
|||
echo Done.
|
||||
}
|
||||
cd $DEPS
|
||||
echo
|
||||
|
||||
# MyGUI
|
||||
printf "MyGUI 3.2.2... "
|
||||
printf "MyGUI 3.2.3-git... "
|
||||
{
|
||||
cd $DEPS_INSTALL
|
||||
|
||||
if [ -d MyGUI ] && \
|
||||
grep "MYGUI_VERSION_MAJOR 3" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null && \
|
||||
grep "MYGUI_VERSION_MINOR 2" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null && \
|
||||
grep "MYGUI_VERSION_PATCH 2" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null
|
||||
grep "MYGUI_VERSION_PATCH 3" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null
|
||||
then
|
||||
printf "Exists. "
|
||||
elif [ -z $SKIP_EXTRACT ]; then
|
||||
rm -rf MyGUI
|
||||
eval 7z x -y $DEPS/MyGUI-3.2.2-win$BITS.7z $STRIP
|
||||
mv MyGUI-3.2.2-win$BITS MyGUI
|
||||
eval 7z x -y "${DEPS}/MyGUI-3.2.3-git-msvc${MSVC_YEAR}-win${BITS}.7z" $STRIP
|
||||
mv "MyGUI-3.2.3-git-msvc${MSVC_YEAR}-win${BITS}" MyGUI
|
||||
fi
|
||||
|
||||
MYGUI_SDK="`real_pwd`/MyGUI"
|
||||
|
||||
add_cmake_opts -DMYGUISDK="$MYGUI_SDK" \
|
||||
-DMYGUI_INCLUDE_DIRS="$MYGUI_SDK/include/MYGUI" \
|
||||
-DMYGUI_PREQUEST_FILE="$MYGUI_SDK/include/MYGUI/MyGUI_Prerequest.h"
|
||||
export MYGUI_HOME="$(real_pwd)/MyGUI"
|
||||
|
||||
if [ $CONFIGURATION == "Debug" ]; then
|
||||
SUFFIX="_d"
|
||||
else
|
||||
SUFFIX=""
|
||||
fi
|
||||
add_runtime_dlls `pwd`/MyGUI/bin/$CONFIGURATION/MyGUIEngine$SUFFIX.dll
|
||||
add_runtime_dlls "$(pwd)/MyGUI/bin/${CONFIGURATION}/MyGUIEngine${SUFFIX}.dll"
|
||||
|
||||
echo Done.
|
||||
}
|
||||
cd $DEPS
|
||||
echo
|
||||
|
||||
# OpenAL
|
||||
printf "OpenAL-Soft 1.16.0... "
|
||||
printf "OpenAL-Soft 1.17.2... "
|
||||
{
|
||||
if [ -d openal-soft-1.16.0-bin ]; then
|
||||
if [ -d openal-soft-1.17.2-bin ]; then
|
||||
printf "Exists. "
|
||||
elif [ -z $SKIP_EXTRACT ]; then
|
||||
rm -rf openal-soft-1.16.0-bin
|
||||
eval 7z x -y OpenAL-Soft-1.16.0.zip $STRIP
|
||||
rm -rf openal-soft-1.17.2-bin
|
||||
eval 7z x -y OpenAL-Soft-1.17.2.zip $STRIP
|
||||
fi
|
||||
|
||||
OPENAL_SDK="`real_pwd`/openal-soft-1.16.0-bin"
|
||||
OPENAL_SDK="$(real_pwd)/openal-soft-1.17.2-bin"
|
||||
|
||||
add_cmake_opts -DOPENAL_INCLUDE_DIR="$OPENAL_SDK/include/AL" \
|
||||
-DOPENAL_LIBRARY="$OPENAL_SDK/libs/Win$BITS/OpenAL32.lib"
|
||||
add_cmake_opts -DOPENAL_INCLUDE_DIR="${OPENAL_SDK}/include/AL" \
|
||||
-DOPENAL_LIBRARY="${OPENAL_SDK}/libs/Win${BITS}/OpenAL32.lib"
|
||||
|
||||
add_runtime_dlls "$(pwd)/openal-soft-1.17.2-bin/bin/WIN${BITS}/soft_oal.dll:OpenAL32.dll"
|
||||
|
||||
echo Done.
|
||||
}
|
||||
cd $DEPS
|
||||
echo
|
||||
|
||||
# OSG
|
||||
printf "OSG 3.3.8... "
|
||||
printf "OSG 3.4.0-scrawl... "
|
||||
{
|
||||
cd $DEPS_INSTALL
|
||||
|
||||
if [ -d OSG ] && \
|
||||
grep "OPENSCENEGRAPH_MAJOR_VERSION 3" OSG/include/osg/Version > /dev/null && \
|
||||
grep "OPENSCENEGRAPH_MINOR_VERSION 3" OSG/include/osg/Version > /dev/null && \
|
||||
grep "OPENSCENEGRAPH_PATCH_VERSION 8" OSG/include/osg/Version > /dev/null
|
||||
grep "OPENSCENEGRAPH_MINOR_VERSION 4" OSG/include/osg/Version > /dev/null && \
|
||||
grep "OPENSCENEGRAPH_PATCH_VERSION 0" OSG/include/osg/Version > /dev/null
|
||||
then
|
||||
printf "Exists. "
|
||||
elif [ -z $SKIP_EXTRACT ]; then
|
||||
rm -rf OSG
|
||||
eval 7z x -y $DEPS/OSG-3.3.8-win$BITS.7z $STRIP
|
||||
mv OSG-3.3.8-win$BITS OSG
|
||||
eval 7z x -y "${DEPS}/OSG-3.4.0-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z" $STRIP
|
||||
mv "OSG-3.4.0-scrawl-msvc${MSVC_YEAR}-win${BITS}" OSG
|
||||
fi
|
||||
|
||||
OSG_SDK="`real_pwd`/OSG"
|
||||
OSG_SDK="$(real_pwd)/OSG"
|
||||
|
||||
add_cmake_opts -DOSG_DIR="$OSG_SDK"
|
||||
|
||||
|
@ -511,85 +543,101 @@ printf "OSG 3.3.8... "
|
|||
SUFFIX=""
|
||||
fi
|
||||
|
||||
add_runtime_dlls `pwd`/OSG/bin/{OpenThreads,zlib}$SUFFIX.dll \
|
||||
`pwd`/OSG/bin/osg{,Animation,DB,FX,GA,Particle,Qt,Text,Util,Viewer}$SUFFIX.dll
|
||||
add_runtime_dlls "$(pwd)/OSG/bin/"{OpenThreads,zlib,libpng*}${SUFFIX}.dll \
|
||||
"$(pwd)/OSG/bin/osg"{,Animation,DB,FX,GA,Particle,Text,Util,Viewer}${SUFFIX}.dll
|
||||
|
||||
add_osg_dlls `pwd`/OSG/bin/osgPlugins-3.3.8/osgdb_{bmp,dds,gif,jpeg,png,tga}$SUFFIX.dll
|
||||
add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.0/osgdb_"{bmp,dds,jpeg,osg,png,tga}${SUFFIX}.dll
|
||||
add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.0/osgdb_serializers_osg"{,animation,fx,ga,particle,text,util,viewer}${SUFFIX}.dll
|
||||
|
||||
echo Done.
|
||||
}
|
||||
cd $DEPS
|
||||
echo
|
||||
|
||||
# Qt
|
||||
if [ -z $APPVEYOR ]; then
|
||||
printf "Qt 4.8.6... "
|
||||
printf "Qt 5.7.0... "
|
||||
else
|
||||
printf "Qt 5.4... "
|
||||
printf "Qt 5.7 AppVeyor... "
|
||||
fi
|
||||
{
|
||||
if [ $BITS -eq 64 ]; then
|
||||
SUFFIX="_64"
|
||||
else
|
||||
SUFFIX=""
|
||||
fi
|
||||
|
||||
if [ -z $APPVEYOR ]; then
|
||||
cd $DEPS_INSTALL
|
||||
QT_SDK="`real_pwd`/Qt"
|
||||
QT_SDK="$(real_pwd)/Qt/5.7/msvc${MSVC_YEAR}${SUFFIX}"
|
||||
|
||||
if [ -d Qt ] && head -n2 Qt/BUILDINFO.txt | grep "4.8.6" > /dev/null; then
|
||||
if [ -d Qt ] && head -n2 Qt/InstallationLog.txt | grep "5.7.0" > /dev/null; then
|
||||
printf "Exists. "
|
||||
elif [ -z $SKIP_EXTRACT ]; then
|
||||
rm -rf Qt
|
||||
eval 7z x -y $DEPS/qt$BITS-4.8.6.7z $STRIP
|
||||
mv qt-4.8.6-* Qt
|
||||
cd Qt
|
||||
eval ./qtbinpatcher.exe $STRIP
|
||||
cp "${DEPS}/qt-5-install.qs" qt-install.qs
|
||||
|
||||
|
||||
sed -i "s|INSTALL_DIR|$(real_pwd)/Qt|" qt-install.qs
|
||||
sed -i "s/qt.VERSION.winBITS_msvcYEAR/qt.57.win${BITS}_msvc${MSVC_YEAR}${SUFFIX}/" qt-install.qs
|
||||
|
||||
printf -- "(Installation might take a while) "
|
||||
"${DEPS}/qt-5.7.0-msvc${MSVC_YEAR}-win${BITS}.exe" --script qt-install.qs --silent
|
||||
|
||||
mv qt-install.qs Qt/
|
||||
|
||||
echo Done.
|
||||
printf " Cleaning up extraneous data... "
|
||||
rm -r "$(real_pwd)/Qt/"{dist,Docs,Examples,Tools,vcredist,components.xml,MaintenanceTool.dat,MaintenanceTool.exe,MaintenanceTool.ini,network.xml,qt-install.qs}
|
||||
fi
|
||||
|
||||
cd $QT_SDK
|
||||
|
||||
add_cmake_opts -DDESIRED_QT_VERSION=4 \
|
||||
-DQT_QMAKE_EXECUTABLE="$QT_SDK/bin/qmake.exe"
|
||||
add_cmake_opts -DDESIRED_QT_VERSION=5 \
|
||||
-DQT_QMAKE_EXECUTABLE="${QT_SDK}/bin/qmake.exe" \
|
||||
-DCMAKE_PREFIX_PATH="$QT_SDK"
|
||||
|
||||
if [ $CONFIGURATION == "Debug" ]; then
|
||||
SUFFIX="d4"
|
||||
SUFFIX="d"
|
||||
else
|
||||
SUFFIX="4"
|
||||
SUFFIX=""
|
||||
fi
|
||||
|
||||
add_runtime_dlls `pwd`/bin/Qt{Core,Gui,Network,OpenGL}$SUFFIX.dll
|
||||
add_runtime_dlls "$(pwd)/bin/lib"{EGL,GLESv2}${SUFFIX}.dll \
|
||||
"$(pwd)/bin/Qt5"{Core,Gui,Network,OpenGL,Widgets}${SUFFIX}.dll
|
||||
add_qt_platform_dlls "$(pwd)/plugins/platforms/qwindows${SUFFIX}.dll"
|
||||
|
||||
echo Done.
|
||||
else
|
||||
if [ $BITS -eq 32 ]; then
|
||||
QT_SDK="C:/Qt/5.4/msvc2013_opengl"
|
||||
else
|
||||
QT_SDK="C:/Qt/5.4/msvc2013_64_opengl"
|
||||
fi
|
||||
QT_SDK="C:/Qt/5.7/msvc${MSVC_YEAR}${SUFFIX}"
|
||||
|
||||
add_cmake_opts -DDESIRED_QT_VERSION=5 \
|
||||
-DQT_QMAKE_EXECUTABLE="$QT_SDK/bin/qmake.exe" \
|
||||
-DQT_QMAKE_EXECUTABLE="${QT_SDK}/bin/qmake.exe" \
|
||||
-DCMAKE_PREFIX_PATH="$QT_SDK"
|
||||
|
||||
echo AppVeyor.
|
||||
echo Done.
|
||||
fi
|
||||
}
|
||||
cd $DEPS
|
||||
echo
|
||||
|
||||
# SDL2
|
||||
printf "SDL 2.0.3... "
|
||||
printf "SDL 2.0.4... "
|
||||
{
|
||||
if [ -d SDL2-2.0.3 ]; then
|
||||
if [ -d SDL2-2.0.4 ]; then
|
||||
printf "Exists. "
|
||||
elif [ -z $SKIP_EXTRACT ]; then
|
||||
rm -rf SDL2-2.0.3
|
||||
eval 7z x -y SDL2-2.0.3.zip $STRIP
|
||||
rm -rf SDL2-2.0.4
|
||||
eval 7z x -y SDL2-2.0.4.zip $STRIP
|
||||
fi
|
||||
|
||||
SDL_SDK="`real_pwd`/SDL2-2.0.3"
|
||||
add_cmake_opts -DSDL2_INCLUDE_DIR="$SDL_SDK/include" \
|
||||
-DSDL2MAIN_LIBRARY="$SDL_SDK/lib/x$ARCHSUFFIX/SDL2main.lib" \
|
||||
-DSDL2_LIBRARY_PATH="$SDL_SDK/lib/x$ARCHSUFFIX/SDL2.lib"
|
||||
export SDL2DIR="$(real_pwd)/SDL2-2.0.4"
|
||||
|
||||
add_runtime_dlls `pwd`/SDL2-2.0.3/lib/x$ARCHSUFFIX/SDL2.dll
|
||||
add_runtime_dlls "$(pwd)/SDL2-2.0.4/lib/x${ARCHSUFFIX}/SDL2.dll"
|
||||
|
||||
echo Done.
|
||||
}
|
||||
echo
|
||||
|
||||
|
||||
cd $DEPS_INSTALL/..
|
||||
|
@ -602,12 +650,10 @@ add_cmake_opts -DBUILD_BSATOOL=no \
|
|||
-DBUILD_MYGUI_PLUGIN=no \
|
||||
-DOPENMW_MP_BUILD=on
|
||||
|
||||
if [ -z $CI ]; then
|
||||
echo " (Outside of CI, doing full build.)"
|
||||
else
|
||||
if [ ! -z $CI ]; then
|
||||
case $STEP in
|
||||
components )
|
||||
echo " Subproject: Components."
|
||||
echo " Building subproject: Components."
|
||||
add_cmake_opts -DBUILD_ESSIMPORTER=no \
|
||||
-DBUILD_LAUNCHER=no \
|
||||
-DBUILD_MWINIIMPORTER=no \
|
||||
|
@ -615,64 +661,98 @@ else
|
|||
-DBUILD_OPENMW=no \
|
||||
-DBUILD_WIZARD=no
|
||||
;;
|
||||
|
||||
openmw )
|
||||
echo " Subproject: OpenMW."
|
||||
echo " Building subproject: OpenMW."
|
||||
add_cmake_opts -DBUILD_ESSIMPORTER=no \
|
||||
-DBUILD_LAUNCHER=no \
|
||||
-DBUILD_MWINIIMPORTER=no \
|
||||
-DBUILD_OPENCS=no \
|
||||
-DBUILD_WIZARD=no
|
||||
;;
|
||||
|
||||
opencs )
|
||||
echo " Subproject: OpenCS."
|
||||
echo " Building subproject: OpenCS."
|
||||
add_cmake_opts -DBUILD_ESSIMPORTER=no \
|
||||
-DBUILD_LAUNCHER=no \
|
||||
-DBUILD_MWINIIMPORTER=no \
|
||||
-DBUILD_OPENMW=no \
|
||||
-DBUILD_WIZARD=no
|
||||
;;
|
||||
|
||||
misc )
|
||||
echo " Subproject: Misc."
|
||||
echo " Building subprojects: Misc."
|
||||
add_cmake_opts -DBUILD_OPENCS=no \
|
||||
-DBUILD_OPENMW=no
|
||||
;;
|
||||
* )
|
||||
echo " Building everything."
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# NOTE: Disable this when/if we want to run test cases
|
||||
if [ -z $CI ]; then
|
||||
echo "- Copying Runtime DLLs..."
|
||||
mkdir -p $BUILD_CONFIG
|
||||
for DLL in $RUNTIME_DLLS; do
|
||||
TARGET="$(basename "$DLL")"
|
||||
if [[ "$DLL" == *":"* ]]; then
|
||||
IFS=':'; SPLIT=( ${DLL} ); unset IFS
|
||||
|
||||
DLL=${SPLIT[0]}
|
||||
TARGET=${SPLIT[1]}
|
||||
fi
|
||||
|
||||
echo " ${TARGET}."
|
||||
cp "$DLL" "$BUILD_CONFIG/$TARGET"
|
||||
done
|
||||
echo
|
||||
|
||||
echo "- OSG Plugin DLLs..."
|
||||
mkdir -p $BUILD_CONFIG/osgPlugins-3.4.0
|
||||
for DLL in $OSG_PLUGINS; do
|
||||
echo " $(basename $DLL)."
|
||||
cp "$DLL" $BUILD_CONFIG/osgPlugins-3.4.0
|
||||
done
|
||||
echo
|
||||
|
||||
echo "- Qt Platform DLLs..."
|
||||
mkdir -p ${BUILD_CONFIG}/platforms
|
||||
for DLL in $QT_PLATFORMS; do
|
||||
echo " $(basename $DLL)"
|
||||
cp "$DLL" "${BUILD_CONFIG}/platforms"
|
||||
done
|
||||
echo
|
||||
fi
|
||||
|
||||
if [ -z $VERBOSE ]; then
|
||||
printf " Configuring... "
|
||||
printf -- "- Configuring... "
|
||||
else
|
||||
echo " cmake .. $CMAKE_OPTS"
|
||||
echo "- cmake .. $CMAKE_OPTS"
|
||||
fi
|
||||
|
||||
run_cmd cmake .. $CMAKE_OPTS
|
||||
RET=$?
|
||||
|
||||
if [ -z $VERBOSE ]; then
|
||||
if [ $RET -eq 0 ]; then echo Done.
|
||||
else echo Failed.; fi
|
||||
if [ $RET -eq 0 ]; then
|
||||
echo Done.
|
||||
else
|
||||
echo Failed.
|
||||
fi
|
||||
fi
|
||||
|
||||
echo
|
||||
|
||||
# NOTE: Disable this when/if we want to run test cases
|
||||
if [ -z $CI ]; then
|
||||
echo "Copying Runtime DLLs..."
|
||||
mkdir -p $CONFIGURATION
|
||||
for DLL in $RUNTIME_DLLS; do
|
||||
echo " `basename $DLL`."
|
||||
cp "$DLL" $CONFIGURATION/
|
||||
done
|
||||
echo "OSG Plugin DLLs..."
|
||||
mkdir -p $CONFIGURATION/osgPlugins-3.3.8
|
||||
for DLL in $OSG_PLUGINS; do
|
||||
echo " `basename $DLL`."
|
||||
cp "$DLL" $CONFIGURATION/osgPlugins-3.3.8
|
||||
done
|
||||
echo "- Copying Runtime Resources/Config Files"
|
||||
echo " gamecontrollerdb.txt"
|
||||
cp gamecontrollerdb.txt $BUILD_CONFIG/gamecontrollerdb.txt
|
||||
echo " openmw.cfg"
|
||||
cp openmw.cfg.install $BUILD_CONFIG/openmw.cfg
|
||||
echo " openmw-cs.cfg"
|
||||
cp openmw-cs.cfg $BUILD_CONFIG/openmw-cs.cfg
|
||||
echo " settings-default.cfg"
|
||||
cp settings-default.cfg $BUILD_CONFIG/settings-default.cfg
|
||||
echo " resources/"
|
||||
cp -r resources $BUILD_CONFIG/resources
|
||||
echo
|
||||
fi
|
||||
|
||||
exit $RET
|
||||
exit $RET
|
|
@ -1,5 +1,22 @@
|
|||
#!/bin/sh
|
||||
|
||||
export CXX=clang++
|
||||
export CC=clang
|
||||
|
||||
DEPENDENCIES_ROOT="/private/tmp/openmw-deps/openmw-deps"
|
||||
QT_PATH=`brew --prefix $macos_qt_formula`
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_FRAMEWORK_PATH="/usr/local/lib/macosx/Release" -DCMAKE_EXE_LINKER_FLAGS="-F/usr/local/lib/macosx/Release" -DCMAKE_CXX_FLAGS="-stdlib=libstdc++" -DCMAKE_BUILD_TYPE=Debug -DBUILD_MYGUI_PLUGIN=OFF -G"Unix Makefiles" ..
|
||||
|
||||
cmake \
|
||||
-D CMAKE_PREFIX_PATH="$DEPENDENCIES_ROOT;$QT_PATH" \
|
||||
-D CMAKE_OSX_DEPLOYMENT_TARGET="10.8" \
|
||||
-D CMAKE_OSX_SYSROOT="macosx10.12" \
|
||||
-D CMAKE_BUILD_TYPE=Debug \
|
||||
-D OPENMW_OSX_DEPLOYMENT=TRUE \
|
||||
-D DESIRED_QT_VERSION=5 \
|
||||
-D BUILD_ESMTOOL=FALSE \
|
||||
-D BUILD_MYGUI_PLUGIN=FALSE \
|
||||
-G"Unix Makefiles" \
|
||||
..
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
#!/bin/bash
|
||||
|
||||
APPVEYOR=""
|
||||
CI=""
|
||||
|
||||
PACKAGE=""
|
||||
PLATFORM=""
|
||||
CONFIGURATION=""
|
||||
VS_VERSION=""
|
||||
|
||||
if [ -z $PLATFORM ]; then
|
||||
PLATFORM=`uname -m`
|
||||
fi
|
||||
|
@ -8,39 +16,63 @@ if [ -z $CONFIGURATION ]; then
|
|||
CONFIGURATION="Debug"
|
||||
fi
|
||||
|
||||
case $PLATFORM in
|
||||
x32|x86|i686|i386|win32|Win32 )
|
||||
BITS=32
|
||||
PLATFORM=Win32
|
||||
case $VS_VERSION in
|
||||
14|14.0|2015 )
|
||||
GENERATOR="Visual Studio 14 2015"
|
||||
MSVC_YEAR="2015"
|
||||
MSVC_VER="14.0"
|
||||
;;
|
||||
|
||||
# 12|2013|
|
||||
* )
|
||||
GENERATOR="Visual Studio 12 2013"
|
||||
MSVC_YEAR="2013"
|
||||
MVSC_VER="12.0"
|
||||
;;
|
||||
esac
|
||||
|
||||
case $PLATFORM in
|
||||
x64|x86_64|x86-64|win64|Win64 )
|
||||
BITS=64
|
||||
PLATFORM=x64
|
||||
;;
|
||||
|
||||
* )
|
||||
echo "Unknown platform $PLATFORM."
|
||||
exit 1 ;;
|
||||
x32|x86|i686|i386|win32|Win32 )
|
||||
BITS=32
|
||||
;;
|
||||
esac
|
||||
|
||||
case $CONFIGURATION in
|
||||
debug|Debug|DEBUG )
|
||||
CONFIGURATION=Debug
|
||||
;;
|
||||
|
||||
release|Release|RELEASE )
|
||||
CONFIGURATION=Release
|
||||
;;
|
||||
|
||||
relwithdebinfo|RelWithDebInfo|RELWITHDEBINFO )
|
||||
CONFIGURATION=RelWithDebInfo
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z $APPVEYOR ]; then
|
||||
echo "Running $BITS-bit $CONFIGURATION build outside of Appveyor."
|
||||
echo "Running ${BITS}-bit MSVC${MSVC_YEAR} ${CONFIGURATION} build outside of Appveyor."
|
||||
|
||||
DIR=$(echo "$0" | sed "s,\\\\,/,g" | sed "s,\(.\):,/\\1,")
|
||||
cd $(dirname "$DIR")/..
|
||||
else
|
||||
echo "Running $BITS-bit $CONFIGURATION build in Appveyor."
|
||||
echo "Running ${BITS}-bit MSVC${MSVC_YEAR} ${CONFIGURATION} build in Appveyor."
|
||||
|
||||
cd $APPVEYOR_BUILD_FOLDER
|
||||
fi
|
||||
|
||||
cd build_$BITS
|
||||
BUILD_DIR="MSVC${MSVC_YEAR}_${BITS}"
|
||||
cd ${BUILD_DIR}
|
||||
|
||||
which msbuild > /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
msbuild() {
|
||||
/c/Program\ Files\ \(x86\)/MSBuild/12.0/Bin/MSBuild.exe "$@"
|
||||
/c/Program\ Files\ \(x86\)/MSBuild/${MSVC_VER}/Bin/MSBuild.exe "$@"
|
||||
}
|
||||
fi
|
||||
|
||||
|
|
394
CMakeLists.txt
394
CMakeLists.txt
|
@ -25,7 +25,7 @@ endif()
|
|||
message(STATUS "Configuring OpenMW...")
|
||||
|
||||
set(OPENMW_VERSION_MAJOR 0)
|
||||
set(OPENMW_VERSION_MINOR 38)
|
||||
set(OPENMW_VERSION_MINOR 41)
|
||||
set(OPENMW_VERSION_RELEASE 0)
|
||||
|
||||
set(OPENMW_VERSION_COMMITHASH "")
|
||||
|
@ -46,7 +46,7 @@ if(EXISTS ${PROJECT_SOURCE_DIR}/.git)
|
|||
else(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow)
|
||||
message(STATUS "Shallow Git clone detected, not attempting to retrieve version info")
|
||||
endif(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow)
|
||||
endif(EXISTS ${PROJECT_SOURCE_DIR}/.git)
|
||||
endif(EXISTS ${PROJECT_SOURCE_DIR}/.git)
|
||||
|
||||
# Macros
|
||||
include(OpenMWMacros)
|
||||
|
@ -65,9 +65,11 @@ option(OPENMW_UNITY_BUILD "Use fewer compilation units to speed up compile time"
|
|||
|
||||
# Apps and tools
|
||||
option(BUILD_OPENMW "build OpenMW" ON)
|
||||
option(BUILD_OPENMW_MP "build OpenMW-MP" ON)
|
||||
option(BUILD_BSATOOL "build BSA extractor" ON)
|
||||
option(BUILD_ESMTOOL "build ESM inspector" ON)
|
||||
option(BUILD_LAUNCHER "build Launcher" ON)
|
||||
option(BUILD_BROWSER "build tes3mp Server Browser" ON)
|
||||
option(BUILD_MWINIIMPORTER "build MWiniImporter" ON)
|
||||
option(BUILD_ESSIMPORTER "build ESS (Morrowind save game) importer" ON)
|
||||
option(BUILD_OPENCS "build OpenMW Construction Set" ON)
|
||||
|
@ -76,6 +78,14 @@ option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF)
|
|||
option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest" OFF)
|
||||
option(BUILD_NIFTEST "build nif file tester" OFF)
|
||||
option(BUILD_MYGUI_PLUGIN "build MyGUI plugin for OpenMW resources, to use with MyGUI tools" ON)
|
||||
option(BUILD_DOCS "build documentation." OFF )
|
||||
|
||||
# what is necessary to build documentation
|
||||
IF( BUILD_DOCS )
|
||||
# Builds the documentation.
|
||||
FIND_PACKAGE( Sphinx REQUIRED )
|
||||
FIND_PACKAGE( Doxygen REQUIRED )
|
||||
ENDIF()
|
||||
|
||||
# OS X deployment
|
||||
option(OPENMW_OSX_DEPLOYMENT OFF)
|
||||
|
@ -88,7 +98,7 @@ endif()
|
|||
# Set up common paths
|
||||
if (APPLE)
|
||||
set(MORROWIND_DATA_FILES "./data" CACHE PATH "location of Morrowind data files")
|
||||
set(OPENMW_RESOURCE_FILES "./resources" CACHE PATH "location of OpenMW resources files")
|
||||
set(OPENMW_RESOURCE_FILES "../Resources/resources" CACHE PATH "location of OpenMW resources files")
|
||||
elseif(UNIX)
|
||||
# Paths
|
||||
SET(BINDIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Where to install binaries")
|
||||
|
@ -116,7 +126,10 @@ if (WIN32)
|
|||
option(USE_DEBUG_CONSOLE "whether a debug console should be enabled for debug builds, if false debug output is redirected to Visual Studio output" ON)
|
||||
endif()
|
||||
|
||||
if (NOT BUILD_LAUNCHER AND NOT BUILD_OPENCS AND NOT BUILD_WIZARD)
|
||||
find_package(RakNet REQUIRED)
|
||||
include_directories(${RakNet_INCLUDES})
|
||||
|
||||
if (NOT BUILD_LAUNCHER AND NOT BUILD_BROWSER AND NOT BUILD_OPENCS AND NOT BUILD_WIZARD)
|
||||
set(USE_QT FALSE)
|
||||
else()
|
||||
set(USE_QT TRUE)
|
||||
|
@ -124,7 +137,7 @@ endif()
|
|||
|
||||
# Dependencies
|
||||
if (USE_QT)
|
||||
set(DESIRED_QT_VERSION 4 CACHE STRING "The QT version OpenMW should use (4 or 5)")
|
||||
set(DESIRED_QT_VERSION 5 CACHE STRING "The QT version OpenMW should use (4 or 5)")
|
||||
set_property(CACHE DESIRED_QT_VERSION PROPERTY STRINGS 4 5)
|
||||
message(STATUS "Using Qt${DESIRED_QT_VERSION}")
|
||||
|
||||
|
@ -140,41 +153,31 @@ if (USE_QT)
|
|||
endif()
|
||||
endif()
|
||||
|
||||
if (USE_QT AND DESIRED_QT_VERSION MATCHES 5)
|
||||
# 2.8.11+ is required to make Qt5 happy and allow linking QtMain on Windows.
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
if (APPLE)
|
||||
# OS X build process relies on this fix: https://github.com/Kitware/CMake/commit/3df5147043d83aa09acd5c9ce31d5c602efb99db
|
||||
cmake_minimum_required(VERSION 3.1.0)
|
||||
elseif (USE_QT AND DESIRED_QT_VERSION MATCHES 5)
|
||||
# 2.8.11+ is required to make Qt5 happy and allow linking QtMain on Windows.
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
else()
|
||||
# We probably support older versions than this.
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
# We probably support older versions than this.
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
endif()
|
||||
|
||||
# Sound setup
|
||||
unset(FFMPEG_LIBRARIES CACHE)
|
||||
|
||||
find_package(FFmpeg REQUIRED)
|
||||
|
||||
set (FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${SWSCALE_LIBRARY} ${SWRESAMPLE_LIBRARIES})
|
||||
|
||||
if ( NOT AVCODEC_FOUND OR NOT AVFORMAT_FOUND OR NOT AVUTIL_FOUND OR NOT SWSCALE_FOUND OR NOT SWRESAMPLE_FOUND)
|
||||
message(FATAL_ERROR "FFmpeg component required, but not found!")
|
||||
endif()
|
||||
# Required for building the FFmpeg headers
|
||||
add_definitions(-D__STDC_CONSTANT_MACROS)
|
||||
IF(BUILD_OPENMW OR BUILD_OPENCS)
|
||||
# Sound setup
|
||||
find_package(FFmpeg REQUIRED COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE SWRESAMPLE)
|
||||
# Required for building the FFmpeg headers
|
||||
add_definitions(-D__STDC_CONSTANT_MACROS)
|
||||
|
||||
# TinyXML
|
||||
option(USE_SYSTEM_TINYXML "Use system TinyXML library instead of internal." OFF)
|
||||
if(USE_SYSTEM_TINYXML)
|
||||
find_library(TINYXML_LIBRARIES tinyxml)
|
||||
find_path(TINYXML_INCLUDE_DIR tinyxml.h)
|
||||
message(STATUS "Found TinyXML: ${TINYXML_LIBRARIES} ${TINYXML_INCLUDE_DIR}")
|
||||
if (USE_SYSTEM_TINYXML)
|
||||
find_package(TinyXML REQUIRED)
|
||||
add_definitions (-DTIXML_USE_STL)
|
||||
if(TINYXML_LIBRARIES AND TINYXML_INCLUDE_DIR)
|
||||
include_directories(${TINYXML_INCLUDE_DIR})
|
||||
message(STATUS "Using system TinyXML library.")
|
||||
else()
|
||||
message(FATAL_ERROR "Detection of system TinyXML incomplete.")
|
||||
endif()
|
||||
include_directories(SYSTEM ${TinyXML_INCLUDE_DIRS})
|
||||
endif()
|
||||
ENDIF(BUILD_OPENMW OR BUILD_OPENCS)
|
||||
|
||||
# Platform specific
|
||||
if (WIN32)
|
||||
|
@ -190,9 +193,10 @@ if (WIN32)
|
|||
add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN)
|
||||
endif()
|
||||
|
||||
if (ANDROID)
|
||||
set(OPENGL_ES TRUE CACHE BOOL "enable opengl es support for android" FORCE)
|
||||
endif (ANDROID)
|
||||
if (NOT WIN32 AND BUILD_WIZARD) # windows users can just run the morrowind installer
|
||||
find_package(LIBUNSHIELD REQUIRED) # required only for non win32 when building openmw-wizard
|
||||
set(OPENMW_USE_UNSHIELD TRUE)
|
||||
endif()
|
||||
|
||||
option(OPENGL_ES "enable opengl es support" FALSE )
|
||||
|
||||
|
@ -213,14 +217,57 @@ if(NOT HAVE_STDINT_H)
|
|||
message(FATAL_ERROR "stdint.h was not found" )
|
||||
endif()
|
||||
|
||||
include (CheckIncludeFileCXX)
|
||||
check_include_file_cxx(unordered_map HAVE_UNORDERED_MAP)
|
||||
if (HAVE_UNORDERED_MAP)
|
||||
add_definitions(-DHAVE_UNORDERED_MAP)
|
||||
endif ()
|
||||
|
||||
IF(BUILD_OPENMW OR BUILD_OPENCS)
|
||||
|
||||
find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle osgUtil osgFX)
|
||||
|
||||
set(USED_OSG_PLUGINS
|
||||
osgdb_bmp
|
||||
osgdb_dds
|
||||
osgdb_jpeg
|
||||
osgdb_osg
|
||||
osgdb_png
|
||||
osgdb_serializers_osg
|
||||
osgdb_tga
|
||||
)
|
||||
|
||||
get_filename_component(OSG_LIB_DIR ${OSGDB_LIBRARY} DIRECTORY)
|
||||
set(OSGPlugins_LIB_DIR "${OSG_LIB_DIR}/osgPlugins-${OPENSCENEGRAPH_VERSION}")
|
||||
|
||||
if(OSG_STATIC)
|
||||
add_definitions(-DOSG_LIBRARY_STATIC)
|
||||
|
||||
find_package(OSGPlugins REQUIRED COMPONENTS ${USED_OSG_PLUGINS})
|
||||
list(APPEND OPENSCENEGRAPH_LIBRARIES ${OSGPlugins_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(QT_STATIC)
|
||||
if(WIN32)
|
||||
if(DESIRED_QT_VERSION MATCHES 4)
|
||||
# QtCore needs WSAAsyncSelect from Ws2_32.lib
|
||||
set(QT_QTCORE_LIBRARY ${QT_QTCORE_LIBRARY} Ws2_32.lib)
|
||||
message("QT_QTCORE_LIBRARY: ${QT_QTCORE_LIBRARY}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(REQUIRED_BULLET_VERSION 286) # Bullet 286 required due to runtime bugfixes for btCapsuleShape
|
||||
if (DEFINED ENV{TRAVIS_BRANCH} OR DEFINED ENV{APPVEYOR})
|
||||
set(REQUIRED_BULLET_VERSION 283) # but for build testing, 283 is fine
|
||||
endif()
|
||||
|
||||
find_package(MyGUI 3.2.1 REQUIRED)
|
||||
find_package(SDL2 REQUIRED)
|
||||
find_package(OpenAL REQUIRED)
|
||||
find_package(Bullet ${REQUIRED_BULLET_VERSION} REQUIRED COMPONENTS BulletCollision LinearMath)
|
||||
|
||||
ENDIF(BUILD_OPENMW OR BUILD_OPENCS)
|
||||
|
||||
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS})
|
||||
|
||||
|
||||
set(BOOST_COMPONENTS system filesystem program_options thread)
|
||||
set(BOOST_COMPONENTS system filesystem program_options)
|
||||
if(WIN32)
|
||||
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} locale)
|
||||
endif(WIN32)
|
||||
|
@ -229,92 +276,18 @@ IF(BOOST_STATIC)
|
|||
set(Boost_USE_STATIC_LIBS ON)
|
||||
endif()
|
||||
|
||||
if (USE_QT)
|
||||
set (OSG_QT osgQt)
|
||||
endif()
|
||||
|
||||
find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgText osgGA osgAnimation osgParticle ${OSG_QT} osgUtil osgFX)
|
||||
|
||||
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS})
|
||||
|
||||
if(OSG_STATIC)
|
||||
macro(use_static_osg_plugin_library PLUGIN_NAME)
|
||||
set(PLUGIN_NAME_DBG ${PLUGIN_NAME}d ${PLUGIN_NAME}D ${PLUGIN_NAME}_d ${PLUGIN_NAME}_D ${PLUGIN_NAME}_debug ${PLUGIN_NAME})
|
||||
|
||||
# For now, users wishing to do a static build will need to pass the path to where the plugins reside
|
||||
# More clever logic would need to deduce the path, probably installed under <OpenSceneGraph>/lib/osgPlugins-<X.X.X>
|
||||
find_library(${PLUGIN_NAME}_LIBRARY_REL NAMES ${PLUGIN_NAME} HINTS ${OSG_PLUGIN_LIB_SEARCH_PATH})
|
||||
find_library(${PLUGIN_NAME}_LIBRARY_DBG NAMES ${PLUGIN_NAME_DBG} HINTS ${OSG_PLUGIN_LIB_SEARCH_PATH})
|
||||
make_library_set(${PLUGIN_NAME}_LIBRARY)
|
||||
|
||||
if("${${PLUGIN_NAME}_LIBRARY}" STREQUAL "")
|
||||
message(FATAL_ERROR "Unable to find static OpenSceneGraph plugin: ${PLUGIN_NAME}")
|
||||
endif()
|
||||
|
||||
set(OPENSCENEGRAPH_LIBRARIES ${OPENSCENEGRAPH_LIBRARIES} ${${PLUGIN_NAME}_LIBRARY})
|
||||
endmacro()
|
||||
|
||||
macro(use_static_osg_plugin_dep DEPENDENCY)
|
||||
find_package(${DEPENDENCY} REQUIRED)
|
||||
|
||||
set(OPENSCENEGRAPH_LIBRARIES ${OPENSCENEGRAPH_LIBRARIES} ${${DEPENDENCY}_LIBRARIES})
|
||||
endmacro()
|
||||
|
||||
add_definitions(-DOSG_LIBRARY_STATIC)
|
||||
|
||||
set(PLUGIN_LIST
|
||||
osgdb_png # depends on libpng, zlib
|
||||
osgdb_tga
|
||||
osgdb_dds
|
||||
osgdb_jpeg # depends on libjpeg
|
||||
)
|
||||
|
||||
foreach(PLUGIN ${PLUGIN_LIST})
|
||||
use_static_osg_plugin_library(${PLUGIN})
|
||||
endforeach()
|
||||
|
||||
# OSG static plugins need to linked against their respective dependencies
|
||||
set(PLUGIN_DEPS_LIST
|
||||
PNG # needed by osgdb_png
|
||||
ZLIB # needed by osgdb_png
|
||||
JPEG # needed by osgdb_jpeg
|
||||
)
|
||||
|
||||
foreach(DEPENDENCY ${PLUGIN_DEPS_LIST})
|
||||
use_static_osg_plugin_dep(${DEPENDENCY})
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(QT_STATIC)
|
||||
if(WIN32)
|
||||
if(DESIRED_QT_VERSION MATCHES 4)
|
||||
# QtCore needs WSAAsyncSelect from Ws2_32.lib
|
||||
set(QT_QTCORE_LIBRARY ${QT_QTCORE_LIBRARY} Ws2_32.lib)
|
||||
message("QT_QTCORE_LIBRARY: ${QT_QTCORE_LIBRARY}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_package(MyGUI REQUIRED)
|
||||
if (${MYGUI_VERSION} VERSION_LESS "3.2.1")
|
||||
message(FATAL_ERROR "OpenMW requires MyGUI 3.2.1 or later, please install the latest version from http://mygui.info")
|
||||
endif()
|
||||
|
||||
find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
|
||||
find_package(SDL2 REQUIRED)
|
||||
find_package(OpenAL REQUIRED)
|
||||
find_package(Bullet REQUIRED)
|
||||
|
||||
include_directories("."
|
||||
SYSTEM
|
||||
${SDL2_INCLUDE_DIR}
|
||||
${Boost_INCLUDE_DIR}
|
||||
${MYGUI_INCLUDE_DIRS}
|
||||
${MyGUI_INCLUDE_DIRS}
|
||||
${OPENAL_INCLUDE_DIR}
|
||||
${BULLET_INCLUDE_DIRS}
|
||||
${Bullet_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${MYGUI_LIB_DIR})
|
||||
link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS})
|
||||
|
||||
if(MYGUI_STATIC)
|
||||
add_definitions(-DMYGUI_STATIC)
|
||||
|
@ -331,6 +304,11 @@ endif (APPLE)
|
|||
# Set up DEBUG define
|
||||
set_directory_properties(PROPERTIES COMPILE_DEFINITIONS_DEBUG DEBUG=1)
|
||||
|
||||
if (NOT APPLE)
|
||||
set(OPENMW_MYGUI_FILES_ROOT ${OpenMW_BINARY_DIR})
|
||||
set(OPENMW_SHADERS_ROOT ${OpenMW_BINARY_DIR})
|
||||
endif ()
|
||||
|
||||
add_subdirectory(files/)
|
||||
|
||||
# Specify build paths
|
||||
|
@ -349,14 +327,24 @@ endif (APPLE)
|
|||
|
||||
# Other files
|
||||
|
||||
configure_file(${OpenMW_SOURCE_DIR}/files/tes3mp/tes3mp-client-default.cfg
|
||||
"${OpenMW_BINARY_DIR}/tes3mp-client-default.cfg")
|
||||
|
||||
configure_file(${OpenMW_SOURCE_DIR}/files/tes3mp/tes3mp-server-default.cfg
|
||||
"${OpenMW_BINARY_DIR}/tes3mp-server-default.cfg")
|
||||
|
||||
configure_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg
|
||||
"${OpenMW_BINARY_DIR}/settings-default.cfg")
|
||||
|
||||
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local
|
||||
"${OpenMW_BINARY_DIR}/openmw.cfg")
|
||||
|
||||
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
|
||||
"${OpenMW_BINARY_DIR}/openmw.cfg.install")
|
||||
if (NOT APPLE)
|
||||
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local
|
||||
"${OpenMW_BINARY_DIR}/openmw.cfg")
|
||||
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
|
||||
"${OpenMW_BINARY_DIR}/openmw.cfg.install")
|
||||
else ()
|
||||
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
|
||||
"${OpenMW_BINARY_DIR}/openmw.cfg")
|
||||
endif ()
|
||||
|
||||
configure_file(${OpenMW_SOURCE_DIR}/files/openmw-cs.cfg
|
||||
"${OpenMW_BINARY_DIR}/openmw-cs.cfg")
|
||||
|
@ -378,21 +366,17 @@ endif()
|
|||
|
||||
# CXX Compiler settings
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unused-parameter -std=c++98 -pedantic -Wno-long-long")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wundef -Wno-unused-parameter -std=c++98 -pedantic -Wno-long-long -Wno-variadic-macros")
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL Clang AND NOT APPLE)
|
||||
execute_process(COMMAND ${CMAKE_C_COMPILER} --version OUTPUT_VARIABLE CLANG_VERSION)
|
||||
string(REGEX REPLACE ".*version ([0-9\\.]*).*" "\\1" CLANG_VERSION ${CLANG_VERSION})
|
||||
if ("${CLANG_VERSION}" VERSION_GREATER 3.6 OR "${CLANG_VERSION}" VERSION_EQUAL 3.6)
|
||||
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 3.6 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 3.6)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-potentially-evaluated-expression")
|
||||
endif ("${CLANG_VERSION}" VERSION_GREATER 3.6 OR "${CLANG_VERSION}" VERSION_EQUAL 3.6)
|
||||
endif(CMAKE_CXX_COMPILER_ID STREQUAL Clang AND NOT APPLE)
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion
|
||||
OUTPUT_VARIABLE GCC_VERSION)
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL GNU AND "${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6)
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL GNU AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.6 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 4.6)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-but-set-parameter")
|
||||
endif(CMAKE_CXX_COMPILER_ID STREQUAL GNU AND "${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6)
|
||||
endif()
|
||||
elseif (MSVC)
|
||||
# Enable link-time code generation globally for all linking
|
||||
if (OPENMW_LTO_BUILD)
|
||||
|
@ -415,6 +399,9 @@ IF(NOT WIN32 AND NOT APPLE)
|
|||
IF(BUILD_LAUNCHER)
|
||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-launcher" DESTINATION "${BINDIR}" )
|
||||
ENDIF(BUILD_LAUNCHER)
|
||||
IF(BUILD_BROWSER)
|
||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-browser" DESTINATION "${BINDIR}" )
|
||||
ENDIF(BUILD_BROWSER)
|
||||
IF(BUILD_BSATOOL)
|
||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/bsatool" DESTINATION "${BINDIR}" )
|
||||
ENDIF(BUILD_BSATOOL)
|
||||
|
@ -458,6 +445,11 @@ IF(NOT WIN32 AND NOT APPLE)
|
|||
INSTALL(FILES "${OpenMW_BINARY_DIR}/resources/version" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
|
||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
|
||||
|
||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/tes3mp-client-default" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
|
||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/tes3mp-client.install" DESTINATION "${SYSCONFDIR}" RENAME "tes3mp-client.cfg" COMPONENT "openmw")
|
||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/tes3mp-server-default" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw-mp")
|
||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/tes3mp-server.install" DESTINATION "${SYSCONFDIR}" RENAME "tes3mp-server.cfg" COMPONENT "openmw-mp")
|
||||
|
||||
IF(BUILD_OPENCS)
|
||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "opencs")
|
||||
ENDIF(BUILD_OPENCS)
|
||||
|
@ -468,8 +460,10 @@ IF(NOT WIN32 AND NOT APPLE)
|
|||
ENDIF(NOT WIN32 AND NOT APPLE)
|
||||
|
||||
if(WIN32)
|
||||
FILE(GLOB dll_files "${OpenMW_BINARY_DIR}/Release/*.dll")
|
||||
INSTALL(FILES ${dll_files} DESTINATION ".")
|
||||
FILE(GLOB dll_files_debug "${OpenMW_BINARY_DIR}/Debug/*.dll")
|
||||
FILE(GLOB dll_files_release "${OpenMW_BINARY_DIR}/Release/*.dll")
|
||||
INSTALL(FILES ${dll_files_debug} DESTINATION "." CONFIGURATIONS Debug)
|
||||
INSTALL(FILES ${dll_files_release} DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel)
|
||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg")
|
||||
INSTALL(FILES "${OpenMW_SOURCE_DIR}/CHANGELOG.md" DESTINATION "." RENAME "CHANGELOG.txt")
|
||||
INSTALL(FILES "${OpenMW_SOURCE_DIR}/README.md" DESTINATION "." RENAME "README.txt")
|
||||
|
@ -477,33 +471,25 @@ if(WIN32)
|
|||
"${OpenMW_SOURCE_DIR}/Docs/license/GPL3.txt"
|
||||
"${OpenMW_SOURCE_DIR}/Docs/license/DejaVu Font License.txt"
|
||||
"${OpenMW_BINARY_DIR}/settings-default.cfg"
|
||||
"${OpenMW_BINARY_DIR}/tes3mp-client-default.cfg"
|
||||
"${OpenMW_BINARY_DIR}/gamecontrollerdb.txt"
|
||||
"${OpenMW_BINARY_DIR}/Release/openmw.exe"
|
||||
DESTINATION ".")
|
||||
|
||||
IF(BUILD_LAUNCHER)
|
||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-launcher.exe" DESTINATION ".")
|
||||
ENDIF(BUILD_LAUNCHER)
|
||||
IF(BUILD_MWINIIMPORTER)
|
||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-iniimporter.exe" DESTINATION ".")
|
||||
ENDIF(BUILD_MWINIIMPORTER)
|
||||
IF(BUILD_ESSIMPORTER)
|
||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-essimporter.exe" DESTINATION ".")
|
||||
ENDIF(BUILD_ESSIMPORTER)
|
||||
IF(BUILD_OPENCS)
|
||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-cs.exe" DESTINATION ".")
|
||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.cfg" DESTINATION ".")
|
||||
ENDIF(BUILD_OPENCS)
|
||||
IF(BUILD_WIZARD)
|
||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-wizard.exe" DESTINATION ".")
|
||||
ENDIF(BUILD_WIZARD)
|
||||
if(BUILD_MYGUI_PLUGIN)
|
||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/Plugin_MyGUI_OpenMW_Resources.dll" DESTINATION ".")
|
||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Debug/Plugin_MyGUI_OpenMW_Resources.dll" DESTINATION "." CONFIGURATIONS Debug)
|
||||
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/Plugin_MyGUI_OpenMW_Resources.dll" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel)
|
||||
ENDIF(BUILD_MYGUI_PLUGIN)
|
||||
|
||||
IF(DESIRED_QT_VERSION MATCHES 5)
|
||||
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/Debug/platforms" DESTINATION "." CONFIGURATIONS Debug)
|
||||
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/Release/platforms" DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel)
|
||||
ENDIF()
|
||||
|
||||
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".")
|
||||
FILE(GLOB plugin_dir "${OpenMW_BINARY_DIR}/Release/osgPlugins-*")
|
||||
INSTALL(DIRECTORY ${plugin_dir} DESTINATION ".")
|
||||
FILE(GLOB plugin_dir_debug "${OpenMW_BINARY_DIR}/Debug/osgPlugins-*")
|
||||
FILE(GLOB plugin_dir_release "${OpenMW_BINARY_DIR}/Release/osgPlugins-*")
|
||||
INSTALL(DIRECTORY ${plugin_dir_debug} DESTINATION "." CONFIGURATIONS Debug)
|
||||
INSTALL(DIRECTORY ${plugin_dir_release} DESTINATION "." CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel)
|
||||
|
||||
SET(CPACK_GENERATOR "NSIS")
|
||||
SET(CPACK_PACKAGE_NAME "OpenMW")
|
||||
|
@ -516,6 +502,9 @@ if(WIN32)
|
|||
IF(BUILD_LAUNCHER)
|
||||
SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};openmw-launcher;OpenMW Launcher")
|
||||
ENDIF(BUILD_LAUNCHER)
|
||||
IF(BUILD_BROWSER)
|
||||
SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};tes3mp-browser;tes3mp Launcher")
|
||||
ENDIF(BUILD_BROWSER)
|
||||
IF(BUILD_OPENCS)
|
||||
SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};openmw-cs;OpenMW Construction Set")
|
||||
ENDIF(BUILD_OPENCS)
|
||||
|
@ -534,8 +523,8 @@ if(WIN32)
|
|||
SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\www.openmw.org")
|
||||
SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\www.openmw.org")
|
||||
SET(CPACK_NSIS_INSTALLED_ICON_NAME "openmw-launcher.exe")
|
||||
SET(CPACK_NSIS_MUI_ICON "${OpenMW_SOURCE_DIR}/files/windows/openmw.ico")
|
||||
SET(CPACK_NSIS_MUI_UNIICON "${OpenMW_SOURCE_DIR}/files/windows/openmw.ico")
|
||||
SET(CPACK_NSIS_MUI_ICON "${OpenMW_SOURCE_DIR}/files/tes3mp/tes3mp.ico")
|
||||
SET(CPACK_NSIS_MUI_UNIICON "${OpenMW_SOURCE_DIR}/files/tes3mp/tes3mp.ico")
|
||||
SET(CPACK_PACKAGE_ICON "${OpenMW_SOURCE_DIR}\\\\files\\\\openmw.bmp")
|
||||
|
||||
SET(VCREDIST32 "${OpenMW_BINARY_DIR}/vcredist_x86.exe")
|
||||
|
@ -565,8 +554,13 @@ if(WIN32)
|
|||
endif(WIN32)
|
||||
|
||||
# Extern
|
||||
IF(BUILD_OPENMW OR BUILD_OPENCS)
|
||||
add_subdirectory (extern/osg-ffmpeg-videoplayer)
|
||||
add_subdirectory (extern/oics)
|
||||
if (BUILD_OPENCS)
|
||||
add_subdirectory (extern/osgQt)
|
||||
endif()
|
||||
ENDIF(BUILD_OPENMW OR BUILD_OPENCS)
|
||||
|
||||
# Components
|
||||
add_subdirectory (components)
|
||||
|
@ -577,6 +571,10 @@ add_subdirectory (components)
|
|||
#endif()
|
||||
|
||||
# Apps and tools
|
||||
if (BUILD_OPENMW_MP)
|
||||
add_subdirectory( apps/openmw-mp )
|
||||
endif()
|
||||
|
||||
if (BUILD_OPENMW)
|
||||
add_subdirectory( apps/openmw )
|
||||
endif()
|
||||
|
@ -593,6 +591,10 @@ if (BUILD_LAUNCHER)
|
|||
add_subdirectory( apps/launcher )
|
||||
endif()
|
||||
|
||||
if (BUILD_BROWSER)
|
||||
add_subdirectory( apps/browser )
|
||||
endif()
|
||||
|
||||
if (BUILD_MWINIIMPORTER)
|
||||
add_subdirectory( apps/mwiniimporter )
|
||||
endif()
|
||||
|
@ -631,20 +633,20 @@ if (WIN32)
|
|||
endforeach( OUTPUTCONFIG )
|
||||
|
||||
if (USE_DEBUG_CONSOLE AND BUILD_OPENMW)
|
||||
set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:CONSOLE")
|
||||
set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/SUBSYSTEM:CONSOLE")
|
||||
set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_DEBUG "_CONSOLE")
|
||||
set_target_properties(tes3mp PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:CONSOLE")
|
||||
set_target_properties(tes3mp PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/SUBSYSTEM:CONSOLE")
|
||||
set_target_properties(tes3mp PROPERTIES COMPILE_DEFINITIONS_DEBUG "_CONSOLE")
|
||||
elseif (BUILD_OPENMW)
|
||||
# Turn off debug console, debug output will be written to visual studio output instead
|
||||
set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:WINDOWS")
|
||||
set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/SUBSYSTEM:WINDOWS")
|
||||
set_target_properties(tes3mp PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:WINDOWS")
|
||||
set_target_properties(tes3mp PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/SUBSYSTEM:WINDOWS")
|
||||
endif()
|
||||
|
||||
if (BUILD_OPENMW)
|
||||
# Release builds use the debug console
|
||||
set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:CONSOLE")
|
||||
set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_RELEASE "_CONSOLE")
|
||||
set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:CONSOLE")
|
||||
set_target_properties(tes3mp PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:CONSOLE")
|
||||
set_target_properties(tes3mp PROPERTIES COMPILE_DEFINITIONS_RELEASE "_CONSOLE")
|
||||
set_target_properties(tes3mp PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:CONSOLE")
|
||||
endif()
|
||||
|
||||
# Play a bit with the warning levels
|
||||
|
@ -667,9 +669,15 @@ if (WIN32)
|
|||
4987 # nonstandard extension used (triggered by setjmp.h)
|
||||
4996 # Function was declared deprecated
|
||||
|
||||
# caused by OSG
|
||||
4589 # Constructor of abstract class 'osg::Operation' ignores initializer for virtual base class 'osg::Referenced' (False warning)
|
||||
|
||||
# caused by boost
|
||||
4191 # 'type cast' : unsafe conversion (1.56, thread_primitives.hpp, normally off)
|
||||
|
||||
# caused by MyGUI
|
||||
4275 # non dll-interface class 'std::exception' used as base for dll-interface class 'MyGUI::Exception'
|
||||
|
||||
# OpenMW specific warnings
|
||||
4099 # Type mismatch, declared class or struct is defined with other type
|
||||
4100 # Unreferenced formal parameter (-Wunused-parameter)
|
||||
|
@ -683,19 +691,25 @@ if (WIN32)
|
|||
4309 # Variable overflow, trying to store 128 in a signed char for example
|
||||
4351 # New behavior: elements of array 'array' will be default initialized (desired behavior)
|
||||
4355 # Using 'this' in member initialization list
|
||||
4464 # relative include path contains '..'
|
||||
4505 # Unreferenced local function has been removed
|
||||
4701 # Potentially uninitialized local variable used
|
||||
4702 # Unreachable code
|
||||
4714 # function 'QString QString::trimmed(void) &&' marked as __forceinline not inlined
|
||||
4800 # Boolean optimization warning, e.g. myBool = (myInt != 0) instead of myBool = myInt
|
||||
)
|
||||
|
||||
if (MSVC_VERSION GREATER 1800)
|
||||
set(WARNINGS_DISABLE ${WARNINGS_DISABLE} 5026 5027
|
||||
5031 # #pragma warning(pop): likely mismatch, popping warning state pushed in different file (config_begin.hpp, config_end.hpp)
|
||||
)
|
||||
endif()
|
||||
|
||||
foreach(d ${WARNINGS_DISABLE})
|
||||
set(WARNINGS "${WARNINGS} /wd${d}")
|
||||
endforeach(d)
|
||||
|
||||
set_target_properties(components PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
|
||||
# oics uses tinyxml, which has an initialized but unused variable
|
||||
set_target_properties(oics PROPERTIES COMPILE_FLAGS "${WARNINGS} /wd4189 ${MT_BUILD}")
|
||||
set_target_properties(osg-ffmpeg-videoplayer PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
|
||||
|
||||
if (BUILD_BSATOOL)
|
||||
|
@ -714,6 +728,10 @@ if (WIN32)
|
|||
set_target_properties(openmw-launcher PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
|
||||
endif()
|
||||
|
||||
if (BUILD_BROWSER)
|
||||
set_target_properties(tes3mp-browser PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
|
||||
endif()
|
||||
|
||||
if (BUILD_MWINIIMPORTER)
|
||||
set_target_properties(openmw-iniimporter PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
|
||||
endif()
|
||||
|
@ -723,7 +741,12 @@ if (WIN32)
|
|||
endif()
|
||||
|
||||
if (BUILD_OPENMW)
|
||||
set_target_properties(openmw PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
|
||||
# Very specific issue this, only needed on 32-bit VS2015 during unity builds.
|
||||
if (MSVC_VERSION GREATER 1800 AND CMAKE_SIZEOF_VOID_P EQUAL 4 AND OPENMW_UNITY_BUILD)
|
||||
set_target_properties(tes3mp PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD} /bigobj")
|
||||
else()
|
||||
set_target_properties(tes3mp PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (BUILD_WIZARD)
|
||||
|
@ -732,8 +755,8 @@ if (WIN32)
|
|||
endif(MSVC)
|
||||
|
||||
# TODO: At some point release builds should not use the console but rather write to a log file
|
||||
#set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS")
|
||||
#set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:WINDOWS")
|
||||
#set_target_properties(tes3mp PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS")
|
||||
#set_target_properties(tes3mp PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:WINDOWS")
|
||||
endif()
|
||||
|
||||
# Apple bundling
|
||||
|
@ -750,14 +773,7 @@ if (APPLE)
|
|||
configure_file("${QT_COCOA_PLUGIN_PATH}" "${OPENCS_BUNDLE_NAME}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}" COPYONLY)
|
||||
endif ()
|
||||
|
||||
set(INSTALL_SUBDIR OpenMW)
|
||||
|
||||
install(DIRECTORY "${APP_BUNDLE_DIR}" USE_SOURCE_PERMISSIONS DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
||||
install(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
||||
install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
||||
install(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
||||
install(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
||||
install(FILES "${OpenMW_BINARY_DIR}/openmw-cs.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
||||
install(DIRECTORY "${APP_BUNDLE_DIR}" USE_SOURCE_PERMISSIONS DESTINATION "." COMPONENT Runtime)
|
||||
|
||||
set(CPACK_GENERATOR "DragNDrop")
|
||||
set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION})
|
||||
|
@ -765,8 +781,8 @@ if (APPLE)
|
|||
set(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINOR})
|
||||
set(CPACK_PACKAGE_VERSION_PATCH ${OPENMW_VERSION_RELEASE})
|
||||
|
||||
set(INSTALLED_OPENMW_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}")
|
||||
set(INSTALLED_OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}")
|
||||
set(INSTALLED_OPENMW_APP "\${CMAKE_INSTALL_PREFIX}/${APP_BUNDLE_NAME}")
|
||||
set(INSTALLED_OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${OPENCS_BUNDLE_NAME}")
|
||||
|
||||
install(CODE "
|
||||
set(BU_CHMOD_BUNDLE_ITEMS ON)
|
||||
|
@ -776,19 +792,16 @@ if (APPLE)
|
|||
" COMPONENT Runtime)
|
||||
|
||||
set(ABSOLUTE_PLUGINS "")
|
||||
set(USED_OSG_PLUGINS
|
||||
osgdb_dds
|
||||
osgdb_jpeg
|
||||
osgdb_png
|
||||
osgdb_tga
|
||||
)
|
||||
|
||||
foreach (PLUGIN_NAME ${USED_OSG_PLUGINS})
|
||||
set(PLUGIN_ABS "${OSG_PLUGIN_LIB_SEARCH_PATH}/${PLUGIN_NAME}.so")
|
||||
set(PLUGIN_ABS "${OSGPlugins_LIB_DIR}/${PLUGIN_NAME}.so")
|
||||
set(ABSOLUTE_PLUGINS ${PLUGIN_ABS} ${ABSOLUTE_PLUGINS})
|
||||
endforeach ()
|
||||
|
||||
get_filename_component(OSG_PLUGIN_PREFIX_DIR "${OSG_PLUGIN_LIB_SEARCH_PATH}" NAME)
|
||||
get_filename_component(OSG_PLUGIN_PREFIX_DIR "${OSGPlugins_LIB_DIR}" NAME)
|
||||
if (NOT OSG_PLUGIN_PREFIX_DIR)
|
||||
message(FATAL_ERROR "Can't get directory name for OSG plugins from '${OSGPlugins_LIB_DIR}'")
|
||||
endif()
|
||||
|
||||
# installs used plugins in bundle at given path (bundle_path must be relative to ${CMAKE_INSTALL_PREFIX})
|
||||
# and returns list of install paths for all installed plugins
|
||||
|
@ -813,8 +826,8 @@ if (APPLE)
|
|||
set(${plugins_var} ${PLUGINS} PARENT_SCOPE)
|
||||
endfunction (install_plugins_for_bundle)
|
||||
|
||||
install_plugins_for_bundle("${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}" PLUGINS)
|
||||
install_plugins_for_bundle("${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}" OPENCS_PLUGINS)
|
||||
install_plugins_for_bundle("${APP_BUNDLE_NAME}" PLUGINS)
|
||||
install_plugins_for_bundle("${OPENCS_BUNDLE_NAME}" OPENCS_PLUGINS)
|
||||
|
||||
set(PLUGINS ${PLUGINS} "${INSTALLED_OPENMW_APP}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}")
|
||||
set(OPENCS_PLUGINS ${OPENCS_PLUGINS} "${INSTALLED_OPENCS_APP}/Contents/MacOS/${QT_COCOA_PLUGIN_GROUP}/${QT_COCOA_PLUGIN_NAME}")
|
||||
|
@ -856,3 +869,4 @@ if (DOXYGEN_FOUND)
|
|||
WORKING_DIRECTORY ${OpenMW_BINARY_DIR}
|
||||
COMMENT "Generating documentation for the github-pages at ${DOXYGEN_PAGES_OUTPUT_DIR}" VERBATIM)
|
||||
endif ()
|
||||
|
||||
|
|
114
README.md
114
README.md
|
@ -1,107 +1,41 @@
|
|||
OpenMW
|
||||
TES3MP
|
||||
======
|
||||
|
||||
[![Build Status](https://api.travis-ci.org/OpenMW/openmw.svg)](https://travis-ci.org/OpenMW/openmw) [![Build status](https://ci.appveyor.com/api/projects/status/e6bqw8oouy8ufd46?svg=true)](https://ci.appveyor.com/project/scrawl/openmw) [![Coverity Scan Build Status](https://scan.coverity.com/projects/3740/badge.svg)](https://scan.coverity.com/projects/3740)
|
||||
[![Build Status](https://travis-ci.org/TES3MP/openmw-tes3mp.svg?branch=master)](https://travis-ci.org/TES3MP/openmw-tes3mp)
|
||||
|
||||
OpenMW is a recreation of the engine for the popular role-playing game Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work.
|
||||
TES3MP is a project aiming to add multiplayer functionality to [OpenMW](https://github.com/OpenMW/openmw), a free and open source recreation of the popular Bethesda Softworks game "The Elder Scrolls III: Morrowind".
|
||||
|
||||
OpenMW also comes with OpenMW-CS, a replacement for Morrowind's TES Construction Set.
|
||||
|
||||
* Version: 0.38.0
|
||||
* License: GPL (see docs/license/GPL3.txt for more information)
|
||||
* Website: http://www.openmw.org
|
||||
* IRC: #openmw on irc.freenode.net
|
||||
* Version: 0.5.1
|
||||
* License: GPLv3 (see docs/license/GPL3.txt for more information)
|
||||
* Website: https://steamcommunity.com/groups/mwmulti
|
||||
|
||||
Font Licenses:
|
||||
* DejaVuLGCSansMono.ttf: custom (see docs/license/DejaVu Font License.txt for more information)
|
||||
|
||||
Current Status
|
||||
Project Status
|
||||
--------------
|
||||
|
||||
The main quests in Morrowind, Tribunal and Bloodmoon are all completable. Some issues with side quests are to be expected (but rare). Check the [bug tracker](https://bugs.openmw.org/versions/21) for a list of issues we need to resolve before the "1.0" release. Even before the "1.0" release however, OpenMW boasts some new [features](https://wiki.openmw.org/index.php?title=Features), such as improved graphics and user interfaces.
|
||||
[Version changelog](https://github.com/TES3MP/openmw-tes3mp/blob/master/tes3mp-changelog.md)
|
||||
|
||||
Pre-existing modifications created for the original Morrowind engine can be hit-and-miss. The OpenMW script compiler performs more thorough error-checking than Morrowind does, meaning that a mod created for Morrowind may not necessarily run in OpenMW. Some mods also rely on quirky behaviour or engine bugs in order to work. We are considering such compatibility issues on a case-by-case basis - in some cases adding a workaround to OpenMW may be feasible, in other cases fixing the mod will be the only option. If you know of any mods that work or don't work, feel free to add them to the [Mod status](https://wiki.openmw.org/index.php?title=Mod_status) wiki page.
|
||||
Our project is not yet in a playable state, though we are getting close. At the moment we have synchronization of character appearance, character skills, stats, attributes and death, movement in interiors and exteriors, melee and ranged combat, spell casting, picking up and dropping items in the world, using doors and levers, and adding and removing items from containers, as well as [serverside Lua scripts](https://github.com/TES3MP/PluginExamples) used to save and load the state of most of the aforementioned.
|
||||
|
||||
Contributing
|
||||
--------------
|
||||
|
||||
Development has been relatively fast, but any contribution regarding [code](https://github.com/TES3MP/openmw-tes3mp/blob/master/CONTRIBUTING.md), documentation, bug hunting or video showcases is greatly appreciated.
|
||||
|
||||
Test sessions are often advertised in [our Steam group](https://steamcommunity.com/groups/mwmulti) or [our Discord server](https://discord.gg/H8zhhuk).
|
||||
|
||||
Feel free to contact the [team members](https://github.com/TES3MP/openmw-tes3mp/blob/master/tes3mp-credits.md) for any questions you might have.
|
||||
|
||||
Getting Started
|
||||
---------------
|
||||
|
||||
* [Official forums](https://forum.openmw.org/)
|
||||
* [Installation instructions](https://wiki.openmw.org/index.php?title=Installation_Instructions)
|
||||
* [Build from source](https://wiki.openmw.org/index.php?title=Development_Environment_Setup)
|
||||
* [Testing the game](https://wiki.openmw.org/index.php?title=Testing)
|
||||
* [How to contribute](https://wiki.openmw.org/index.php?title=Contribution_Wanted)
|
||||
* [Report a bug](http://bugs.openmw.org/projects/openmw) - read the [guidelines](https://wiki.openmw.org/index.php?title=Bug_Reporting_Guidelines) before submitting your first bug!
|
||||
* [Known issues](http://bugs.openmw.org/projects/openmw/issues?utf8=%E2%9C%93&set_filter=1&f%5B%5D=status_id&op%5Bstatus_id%5D=%3D&v%5Bstatus_id%5D%5B%5D=7&f%5B%5D=tracker_id&op%5Btracker_id%5D=%3D&v%5Btracker_id%5D%5B%5D=1&f%5B%5D=&c%5B%5D=project&c%5B%5D=tracker&c%5B%5D=status&c%5B%5D=priority&c%5B%5D=subject&c%5B%5D=assigned_to&c%5B%5D=updated_on&group_by=tracker)
|
||||
* [Community forums](https://steamcommunity.com/groups/mwmulti)
|
||||
* [Installation and build instructions](https://github.com/TES3MP/openmw-tes3mp/wiki/Installation-and-build-instructions)
|
||||
* [Known issues and bug reports](https://github.com/TES3MP/openmw-tes3mp/issues)
|
||||
|
||||
The data path
|
||||
-------------
|
||||
Donations
|
||||
---------------
|
||||
|
||||
The data path tells OpenMW where to find your Morrowind files. If you run the launcher, OpenMW should be able to pick up the location of these files on its own, if both Morrowind and OpenMW are installed properly (installing Morrowind under WINE is considered a proper install).
|
||||
|
||||
Command line options
|
||||
--------------------
|
||||
|
||||
Syntax: openmw <options>
|
||||
Allowed options:
|
||||
--help print help message
|
||||
--version print version information and quit
|
||||
--data arg (=data) set data directories (later directories
|
||||
have higher priority)
|
||||
--data-local arg set local data directory (highest
|
||||
priority)
|
||||
--fallback-archive arg (=fallback-archive)
|
||||
set fallback BSA archives (later
|
||||
archives have higher priority)
|
||||
--resources arg (=resources) set resources directory
|
||||
--start arg set initial cell
|
||||
--content arg content file(s): esm/esp, or
|
||||
omwgame/omwaddon
|
||||
--no-sound [=arg(=1)] (=0) disable all sounds
|
||||
--script-verbose [=arg(=1)] (=0) verbose script output
|
||||
--script-all [=arg(=1)] (=0) compile all scripts (excluding dialogue
|
||||
scripts) at startup
|
||||
--script-all-dialogue [=arg(=1)] (=0) compile all dialogue scripts at startup
|
||||
--script-console [=arg(=1)] (=0) enable console-only script
|
||||
functionality
|
||||
--script-run arg select a file containing a list of
|
||||
console commands that is executed on
|
||||
startup
|
||||
--script-warn [=arg(=1)] (=1) handling of warnings when compiling
|
||||
scripts
|
||||
0 - ignore warning
|
||||
1 - show warning but consider script as
|
||||
correctly compiled anyway
|
||||
2 - treat warnings as errors
|
||||
--script-blacklist arg ignore the specified script (if the use
|
||||
of the blacklist is enabled)
|
||||
--script-blacklist-use [=arg(=1)] (=1)
|
||||
enable script blacklisting
|
||||
--load-savegame arg load a save game file on game startup
|
||||
(specify an absolute filename or a
|
||||
filename relative to the current
|
||||
working directory)
|
||||
--skip-menu [=arg(=1)] (=0) skip main menu on game startup
|
||||
--new-game [=arg(=1)] (=0) run new game sequence (ignored if
|
||||
skip-menu=0)
|
||||
--fs-strict [=arg(=1)] (=0) strict file system handling (no case
|
||||
folding)
|
||||
--encoding arg (=win1252) Character encoding used in OpenMW game
|
||||
messages:
|
||||
|
||||
win1250 - Central and Eastern European
|
||||
such as Polish, Czech, Slovak,
|
||||
Hungarian, Slovene, Bosnian, Croatian,
|
||||
Serbian (Latin script), Romanian and
|
||||
Albanian languages
|
||||
|
||||
win1251 - Cyrillic alphabet such as
|
||||
Russian, Bulgarian, Serbian Cyrillic
|
||||
and other languages
|
||||
|
||||
win1252 - Western European (Latin)
|
||||
alphabet, used by default
|
||||
--fallback arg fallback values
|
||||
--no-grab Don't grab mouse cursor
|
||||
--export-fonts [=arg(=1)] (=0) Export Morrowind .fnt fonts to PNG
|
||||
image and XML file in current directory
|
||||
--activate-dist arg (=-1) activation distance override
|
||||
You can benefit the project by supporting OpenMW and/or by [becoming Koncord's patron](https://www.patreon.com/Koncord).
|
||||
|
|
93
apps/browser/CMakeLists.txt
Normal file
93
apps/browser/CMakeLists.txt
Normal file
|
@ -0,0 +1,93 @@
|
|||
|
||||
set (CMAKE_CXX_STANDARD 11)
|
||||
|
||||
set(BROWSER_UI
|
||||
${CMAKE_SOURCE_DIR}/files/tes3mp/ui/Main.ui
|
||||
${CMAKE_SOURCE_DIR}/files/tes3mp/ui/ServerInfo.ui
|
||||
)
|
||||
set(BROWSER
|
||||
main.cpp
|
||||
MainWindow.cpp
|
||||
ServerModel.cpp
|
||||
NetController.cpp
|
||||
ServerInfoDialog.cpp
|
||||
MySortFilterProxyModel.cpp
|
||||
netutils/HTTPNetwork.cpp
|
||||
netutils/Utils.cpp
|
||||
${CMAKE_SOURCE_DIR}/files/tes3mp/browser.rc
|
||||
)
|
||||
|
||||
set(BROWSER_HEADER_MOC
|
||||
MainWindow.hpp
|
||||
ServerModel.hpp
|
||||
ServerInfoDialog.hpp
|
||||
MySortFilterProxyModel.hpp
|
||||
)
|
||||
|
||||
set(BROWSER_HEADER
|
||||
${BROWSER_HEADER_MOC}
|
||||
NetController.hpp
|
||||
netutils/HTTPNetwork.hpp
|
||||
netutils/Utils.hpp
|
||||
)
|
||||
|
||||
source_group(browser FILES ${BROWSER} ${BROWSER_HEADER})
|
||||
|
||||
set(QT_USE_QTGUI 1)
|
||||
|
||||
# Set some platform specific settings
|
||||
if(WIN32)
|
||||
set(GUI_TYPE WIN32)
|
||||
set(QT_USE_QTMAIN TRUE)
|
||||
endif(WIN32)
|
||||
|
||||
if (DESIRED_QT_VERSION MATCHES 4)
|
||||
message(SEND_ERROR "QT4 is not supported.")
|
||||
#include(${QT_USE_FILE})
|
||||
#QT4_ADD_RESOURCES(RCC_SRCS ${CMAKE_SOURCE_DIR}/files/launcher/launcher.qrc)
|
||||
#QT4_WRAP_CPP(MOC_SRCS ${BROWSER_HEADER_MOC})
|
||||
#QT4_WRAP_UI(UI_HDRS ${BROWSER_UI})
|
||||
else()
|
||||
QT5_ADD_RESOURCES(RCC_SRCS ${CMAKE_SOURCE_DIR}/files/launcher/launcher.qrc)
|
||||
QT5_WRAP_CPP(MOC_SRCS ${BROWSER_HEADER_MOC})
|
||||
QT5_WRAP_UI(UI_HDRS ${BROWSER_UI})
|
||||
endif()
|
||||
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
if(NOT WIN32)
|
||||
include_directories(${LIBUNSHIELD_INCLUDE_DIR})
|
||||
endif(NOT WIN32)
|
||||
|
||||
# Main executable
|
||||
add_executable(tes3mp-browser
|
||||
${GUI_TYPE}
|
||||
${BROWSER}
|
||||
${BROWSER_HEADER}
|
||||
${RCC_SRCS}
|
||||
${MOC_SRCS}
|
||||
${UI_HDRS}
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
INSTALL(TARGETS tes3mp-browser RUNTIME DESTINATION ".")
|
||||
endif (WIN32)
|
||||
|
||||
target_link_libraries(tes3mp-browser
|
||||
${SDL2_LIBRARY_ONLY}
|
||||
${RakNet_LIBRARY}
|
||||
components
|
||||
)
|
||||
|
||||
if (DESIRED_QT_VERSION MATCHES 4)
|
||||
# target_link_libraries(tes3mp-browser ${QT_QTGUI_LIBRARY} ${QT_QTCORE_LIBRARY})
|
||||
# if(WIN32)
|
||||
# target_link_libraries(tes3mp-browser ${QT_QTMAIN_LIBRARY})
|
||||
# endif(WIN32)
|
||||
else()
|
||||
qt5_use_modules(tes3mp-browser Widgets Core)
|
||||
endif()
|
||||
|
||||
if (BUILD_WITH_CODE_COVERAGE)
|
||||
add_definitions (--coverage)
|
||||
target_link_libraries(tes3mp-browser gcov)
|
||||
endif()
|
228
apps/browser/MainWindow.cpp
Normal file
228
apps/browser/MainWindow.cpp
Normal file
|
@ -0,0 +1,228 @@
|
|||
//
|
||||
// Created by koncord on 06.01.17.
|
||||
//
|
||||
|
||||
#include "MainWindow.hpp"
|
||||
#include "NetController.hpp"
|
||||
#include "ServerInfoDialog.hpp"
|
||||
#include "components/files/configurationmanager.hpp"
|
||||
#include <qdebug.h>
|
||||
#include <QInputDialog>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QFile>
|
||||
#include <QJsonDocument>
|
||||
|
||||
using namespace Process;
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent)
|
||||
{
|
||||
setupUi(this);
|
||||
|
||||
mGameInvoker = new ProcessInvoker();
|
||||
|
||||
browser = new ServerModel;
|
||||
favorites = new ServerModel;
|
||||
proxyModel = new MySortFilterProxyModel(this);
|
||||
proxyModel->setSourceModel(browser);
|
||||
tblServerBrowser->setModel(proxyModel);
|
||||
tblFavorites->setModel(proxyModel);
|
||||
|
||||
tblServerBrowser->hideColumn(ServerData::ADDR);
|
||||
tblFavorites->hideColumn(ServerData::ADDR);
|
||||
|
||||
connect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabSwitched(int)));
|
||||
connect(actionAdd, SIGNAL(triggered(bool)), this, SLOT(addServer()));
|
||||
connect(actionAdd_by_IP, SIGNAL(triggered(bool)), this, SLOT(addServerByIP()));
|
||||
connect(actionDelete, SIGNAL(triggered(bool)), this, SLOT(deleteServer()));
|
||||
connect(actionRefresh, SIGNAL(triggered(bool)), this, SLOT(refresh()));
|
||||
connect(actionPlay, SIGNAL(triggered(bool)), this, SLOT(play()));
|
||||
connect(tblServerBrowser, SIGNAL(clicked(QModelIndex)), this, SLOT(serverSelected()));
|
||||
connect(tblFavorites, SIGNAL(clicked(QModelIndex)), this, SLOT(serverSelected()));
|
||||
connect(tblFavorites, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(play()));
|
||||
connect(tblServerBrowser, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(play()));
|
||||
connect(cBoxNotFull, SIGNAL(toggled(bool)), this, SLOT(notFullSwitch(bool)));
|
||||
connect(cBoxWithPlayers, SIGNAL(toggled(bool)), this, SLOT(havePlayersSwitch(bool)));
|
||||
connect(comboLatency, SIGNAL(currentIndexChanged(int)), this, SLOT(maxLatencyChanged(int)));
|
||||
connect(leGamemode, SIGNAL(textChanged(const QString &)), this, SLOT(gamemodeChanged(const QString &)));
|
||||
loadFavorites();
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
delete mGameInvoker;
|
||||
}
|
||||
|
||||
void MainWindow::addServerAndUpdate(QString addr)
|
||||
{
|
||||
favorites->insertRow(0);
|
||||
QModelIndex mi = favorites->index(0, ServerData::ADDR);
|
||||
favorites->setData(mi, addr, Qt::EditRole);
|
||||
NetController::get()->updateInfo(favorites, mi);
|
||||
}
|
||||
|
||||
void MainWindow::addServer()
|
||||
{
|
||||
int id = tblServerBrowser->selectionModel()->currentIndex().row();
|
||||
|
||||
if(id >= 0)
|
||||
{
|
||||
int sourceId = proxyModel->mapToSource(proxyModel->index(id, ServerData::ADDR)).row();
|
||||
favorites->myData.push_back(browser->myData[sourceId]);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::addServerByIP()
|
||||
{
|
||||
bool ok;
|
||||
QString text = QInputDialog::getText(this, tr("Add Server by address"), tr("Address:"), QLineEdit::Normal, "", &ok);
|
||||
if(ok && !text.isEmpty())
|
||||
addServerAndUpdate(text);
|
||||
}
|
||||
|
||||
void MainWindow::deleteServer()
|
||||
{
|
||||
if(tabWidget->currentIndex() != 1)
|
||||
return;
|
||||
int id = tblFavorites->selectionModel()->currentIndex().row();
|
||||
if(id >= 0)
|
||||
{
|
||||
int sourceId = proxyModel->mapToSource(proxyModel->index(id, ServerData::ADDR)).row();
|
||||
favorites->removeRow(sourceId);
|
||||
if(favorites->myData.isEmpty())
|
||||
{
|
||||
actionPlay->setEnabled(false);
|
||||
actionDelete->setEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool MainWindow::refresh()
|
||||
{
|
||||
return NetController::get()->updateInfo(proxyModel->sourceModel());
|
||||
/*tblServerBrowser->resizeColumnToContents(ServerData::HOSTNAME);
|
||||
tblServerBrowser->resizeColumnToContents(ServerData::MODNAME);
|
||||
tblFavorites->resizeColumnToContents(ServerData::HOSTNAME);
|
||||
tblFavorites->resizeColumnToContents(ServerData::MODNAME);*/
|
||||
}
|
||||
|
||||
void MainWindow::play()
|
||||
{
|
||||
QTableView *curTable = tabWidget->currentIndex() ? tblFavorites : tblServerBrowser;
|
||||
int id = curTable->selectionModel()->currentIndex().row();
|
||||
if(id < 0)
|
||||
return;
|
||||
|
||||
ServerInfoDialog infoDialog(this);
|
||||
ServerModel *sm = ((ServerModel*)proxyModel->sourceModel());
|
||||
|
||||
int sourceId = proxyModel->mapToSource(proxyModel->index(id, ServerData::ADDR)).row();
|
||||
NetController::get()->selectServer(&sm->myData[sourceId]);
|
||||
infoDialog.refresh();
|
||||
if(!infoDialog.exec())
|
||||
return;
|
||||
|
||||
QStringList arguments;
|
||||
arguments.append(QLatin1String("--connect=") + sm->myData[sourceId].addr.toLatin1());
|
||||
|
||||
if(sm->myData[sourceId].needPassw)
|
||||
{
|
||||
bool ok;
|
||||
QString passw = QInputDialog::getText(this, "Connecting to: " + sm->myData[sourceId].addr, "Password: ", QLineEdit::Password, "", &ok);
|
||||
if(!ok)
|
||||
return;
|
||||
arguments.append(QLatin1String("--password=") + passw.toLatin1());
|
||||
}
|
||||
|
||||
if (mGameInvoker->startProcess(QLatin1String("tes3mp"), arguments, true))
|
||||
return qApp->quit();
|
||||
}
|
||||
|
||||
void MainWindow::tabSwitched(int index)
|
||||
{
|
||||
if(index == 0)
|
||||
{
|
||||
proxyModel->setSourceModel(browser);
|
||||
actionDelete->setEnabled(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
proxyModel->setSourceModel(favorites);
|
||||
}
|
||||
actionPlay->setEnabled(false);
|
||||
actionAdd->setEnabled(false);
|
||||
}
|
||||
|
||||
void MainWindow::serverSelected()
|
||||
{
|
||||
actionPlay->setEnabled(true);
|
||||
if(tabWidget->currentIndex() == 0)
|
||||
actionAdd->setEnabled(true);
|
||||
if(tabWidget->currentIndex() == 1)
|
||||
actionDelete->setEnabled(true);
|
||||
}
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
Files::ConfigurationManager cfgMgr;
|
||||
QString cfgPath = QString::fromStdString((cfgMgr.getUserConfigPath() / "favorites.dat").string());
|
||||
|
||||
QJsonArray saveData;
|
||||
for(auto server : favorites->myData)
|
||||
saveData.push_back(server.addr);
|
||||
|
||||
QFile file(cfgPath);
|
||||
|
||||
if(!file.open(QIODevice::WriteOnly))
|
||||
{
|
||||
qDebug() << "Cannot save " << cfgPath;
|
||||
return;
|
||||
}
|
||||
|
||||
file.write(QJsonDocument(saveData).toJson());
|
||||
file.close();
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::loadFavorites()
|
||||
{
|
||||
Files::ConfigurationManager cfgMgr;
|
||||
QString cfgPath = QString::fromStdString((cfgMgr.getUserConfigPath() / "favorites.dat").string());
|
||||
|
||||
QFile file(cfgPath);
|
||||
if(!file.open(QIODevice::ReadOnly))
|
||||
{
|
||||
qDebug() << "Cannot open " << cfgPath;
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonDocument jsonDoc(QJsonDocument::fromJson(file.readAll()));
|
||||
|
||||
for(auto server : jsonDoc.array())
|
||||
addServerAndUpdate(server.toString());
|
||||
|
||||
file.close();
|
||||
}
|
||||
|
||||
void MainWindow::notFullSwitch(bool state)
|
||||
{
|
||||
proxyModel->filterFullServer(state);
|
||||
}
|
||||
|
||||
void MainWindow::havePlayersSwitch(bool state)
|
||||
{
|
||||
proxyModel->filterEmptyServers(state);
|
||||
}
|
||||
|
||||
void MainWindow::maxLatencyChanged(int index)
|
||||
{
|
||||
int maxLatency = index * 50;
|
||||
proxyModel->pingLessThan(maxLatency);
|
||||
|
||||
}
|
||||
|
||||
void MainWindow::gamemodeChanged(const QString &text)
|
||||
{
|
||||
proxyModel->setFilterFixedString(text);
|
||||
proxyModel->setFilterKeyColumn(ServerData::MODNAME);
|
||||
}
|
44
apps/browser/MainWindow.hpp
Normal file
44
apps/browser/MainWindow.hpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
//
|
||||
// Created by koncord on 06.01.17.
|
||||
//
|
||||
|
||||
#ifndef NEWLAUNCHER_MAIN_HPP
|
||||
#define NEWLAUNCHER_MAIN_HPP
|
||||
|
||||
|
||||
#include "ui_Main.h"
|
||||
#include "ServerModel.hpp"
|
||||
#include "MySortFilterProxyModel.hpp"
|
||||
#include <components/process/processinvoker.hpp>
|
||||
|
||||
class MainWindow : public QMainWindow, private Ui::MainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MainWindow(QWidget *parent = 0);
|
||||
virtual ~MainWindow();
|
||||
protected:
|
||||
void closeEvent(QCloseEvent * event) Q_DECL_OVERRIDE;
|
||||
void addServerAndUpdate(QString addr);
|
||||
public slots:
|
||||
bool refresh();
|
||||
protected slots:
|
||||
void tabSwitched(int index);
|
||||
void addServer();
|
||||
void addServerByIP();
|
||||
void deleteServer();
|
||||
void play();
|
||||
void serverSelected();
|
||||
void notFullSwitch(bool state);
|
||||
void havePlayersSwitch(bool state);
|
||||
void maxLatencyChanged(int index);
|
||||
void gamemodeChanged(const QString &text);
|
||||
private:
|
||||
Process::ProcessInvoker *mGameInvoker;
|
||||
ServerModel *browser, *favorites;
|
||||
MySortFilterProxyModel *proxyModel;
|
||||
void loadFavorites();
|
||||
};
|
||||
|
||||
|
||||
#endif //NEWLAUNCHER_MAIN_HPP
|
54
apps/browser/MySortFilterProxyModel.cpp
Normal file
54
apps/browser/MySortFilterProxyModel.cpp
Normal file
|
@ -0,0 +1,54 @@
|
|||
//
|
||||
// Created by koncord on 30.01.17.
|
||||
//
|
||||
|
||||
#include "MySortFilterProxyModel.hpp"
|
||||
#include "ServerModel.hpp"
|
||||
|
||||
#include <qdebug.h>
|
||||
|
||||
bool MySortFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
|
||||
{
|
||||
|
||||
QModelIndex pingIndex = sourceModel()->index(sourceRow, ServerData::PING, sourceParent);
|
||||
QModelIndex plIndex = sourceModel()->index(sourceRow, ServerData::PLAYERS, sourceParent);
|
||||
QModelIndex maxPlIndex = sourceModel()->index(sourceRow, ServerData::MAX_PLAYERS, sourceParent);
|
||||
|
||||
int ping = sourceModel()->data(pingIndex).toInt();
|
||||
int players = sourceModel()->data(plIndex).toInt();
|
||||
int maxPlayers = sourceModel()->data(maxPlIndex).toInt();
|
||||
|
||||
if(maxPing > 0 && (ping == -1 || ping > maxPing))
|
||||
return false;
|
||||
if(filterEmpty && players == 0)
|
||||
return false;
|
||||
if(filterFull && players >= maxPlayers)
|
||||
return false;
|
||||
|
||||
return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
|
||||
}
|
||||
|
||||
MySortFilterProxyModel::MySortFilterProxyModel(QObject *parent) : QSortFilterProxyModel(parent)
|
||||
{
|
||||
filterEmpty = false;
|
||||
filterFull = false;
|
||||
maxPing = 0;
|
||||
}
|
||||
|
||||
void MySortFilterProxyModel::filterEmptyServers(bool state)
|
||||
{
|
||||
filterEmpty = state;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void MySortFilterProxyModel::filterFullServer(bool state)
|
||||
{
|
||||
filterFull = state;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void MySortFilterProxyModel::pingLessThan(int maxPing)
|
||||
{
|
||||
this->maxPing = maxPing;
|
||||
invalidateFilter();
|
||||
}
|
27
apps/browser/MySortFilterProxyModel.hpp
Normal file
27
apps/browser/MySortFilterProxyModel.hpp
Normal file
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// Created by koncord on 30.01.17.
|
||||
//
|
||||
|
||||
#ifndef OPENMW_MYSORTFILTERPROXYMODEL_HPP
|
||||
#define OPENMW_MYSORTFILTERPROXYMODEL_HPP
|
||||
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
class MySortFilterProxyModel : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
protected:
|
||||
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const Q_DECL_FINAL;
|
||||
public:
|
||||
MySortFilterProxyModel(QObject *parent);
|
||||
void filterFullServer(bool state);
|
||||
void filterEmptyServers(bool state);
|
||||
void pingLessThan(int maxPing);
|
||||
private:
|
||||
bool filterEmpty, filterFull;
|
||||
int maxPing;
|
||||
};
|
||||
|
||||
|
||||
#endif //OPENMW_MYSORTFILTERPROXYMODEL_HPP
|
266
apps/browser/NetController.cpp
Normal file
266
apps/browser/NetController.cpp
Normal file
|
@ -0,0 +1,266 @@
|
|||
//
|
||||
// Created by koncord on 07.01.17.
|
||||
//
|
||||
|
||||
#include <cassert>
|
||||
#include <QtCore/QTime>
|
||||
#include "NetController.hpp"
|
||||
#include "qdebug.h"
|
||||
|
||||
#include <RakPeer.h>
|
||||
#include <RakSleep.h>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <memory>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
|
||||
using namespace std;
|
||||
|
||||
NetController *NetController::mThis = nullptr;
|
||||
|
||||
NetController *NetController::get()
|
||||
{
|
||||
assert(mThis);
|
||||
return mThis;
|
||||
}
|
||||
|
||||
void NetController::Create(std::string addr, unsigned short port)
|
||||
{
|
||||
assert(!mThis);
|
||||
mThis = new NetController(addr, port);
|
||||
}
|
||||
|
||||
void NetController::Destroy()
|
||||
{
|
||||
assert(mThis);
|
||||
delete mThis;
|
||||
mThis = nullptr;
|
||||
}
|
||||
|
||||
NetController::NetController(std::string addr, unsigned short port) : httpNetwork(addr, port)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
NetController::~NetController()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
struct pattern
|
||||
{
|
||||
pattern(QString value): value(value) {}
|
||||
bool operator()(const ServerData &data)
|
||||
{
|
||||
return value == data.addr;
|
||||
}
|
||||
QString value;
|
||||
};
|
||||
|
||||
void NetController::setData(QString address, QJsonObject server, ServerModel *model)
|
||||
{
|
||||
QModelIndex mi = model->index(0, ServerData::ADDR);
|
||||
model->setData(mi, address);
|
||||
|
||||
mi = model->index(0, ServerData::PLAYERS);
|
||||
model->setData(mi, server["players"].toInt());
|
||||
|
||||
mi = model->index(0, ServerData::MAX_PLAYERS);
|
||||
model->setData(mi, server["max_players"].toInt());
|
||||
|
||||
mi = model->index(0, ServerData::HOSTNAME);
|
||||
model->setData(mi, server["hostname"].toString());
|
||||
|
||||
mi = model->index(0, ServerData::MODNAME);
|
||||
model->setData(mi, server["modname"].toString());
|
||||
|
||||
mi = model->index(0, ServerData::VERSION);
|
||||
model->setData(mi, server["version"].toString());
|
||||
|
||||
mi = model->index(0, ServerData::PASSW);
|
||||
model->setData(mi, server["passw"].toBool());
|
||||
|
||||
mi = model->index(0, ServerData::PING);
|
||||
|
||||
// This *should* fix a crash when a port isn't returned by data.
|
||||
if(!address.contains(":"))
|
||||
address.append(":25565");
|
||||
QStringList addr = address.split(":");
|
||||
model->setData(mi, PingRakNetServer(addr[0].toLatin1().data(), addr[1].toUShort()));
|
||||
}
|
||||
|
||||
bool NetController::downloadInfo(QAbstractItemModel *pModel, QModelIndex index)
|
||||
{
|
||||
ServerModel *model = ((ServerModel *) pModel);
|
||||
|
||||
/*
|
||||
* download stuff
|
||||
*/
|
||||
|
||||
QString data;
|
||||
QJsonParseError err;
|
||||
|
||||
if(index.isValid() && index.row() >= 0)
|
||||
{
|
||||
const ServerData &sd = model->myData[index.row()];
|
||||
while(true)
|
||||
{
|
||||
data = QString::fromStdString(httpNetwork.getData((QString("/api/servers/") + sd.addr).toLatin1()));
|
||||
if (!data.isEmpty() && data != "NO_CONTENT" && data != "LOST_CONNECTION")
|
||||
break;
|
||||
RakSleep(30);
|
||||
}
|
||||
qDebug() << "Content for \"" << sd.addr << "\": " << data;
|
||||
|
||||
if(data == "bad request" || data == "not found") // TODO: if server is not registered we should download info directly from the server
|
||||
{
|
||||
qDebug() << "Server is not registered";
|
||||
return false;
|
||||
}
|
||||
|
||||
QJsonDocument jsonDocument = QJsonDocument::fromJson(data.toLatin1(), &err);
|
||||
QJsonObject server = jsonDocument.object()["server"].toObject();
|
||||
|
||||
setData(sd.addr, server, model);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
data = QString::fromStdString(httpNetwork.getData("/api/servers"));
|
||||
if (!data.isEmpty() && data != "NO_CONTENT" && data != "LOST_CONNECTION")
|
||||
break;
|
||||
RakSleep(30);
|
||||
}
|
||||
|
||||
if(data == "UNKNOWN_ADDRESS")
|
||||
{
|
||||
QMessageBox::critical(0, "Error", "Cannot connect to the master server!");
|
||||
return false;
|
||||
}
|
||||
|
||||
qDebug() << "Content: " << data;
|
||||
|
||||
QJsonDocument jsonDocument = QJsonDocument::fromJson(data.toLatin1(), &err);
|
||||
|
||||
QJsonObject listServers = jsonDocument.object()["list servers"].toObject();
|
||||
|
||||
for(auto iter = listServers.begin(); iter != listServers.end(); iter++)
|
||||
{
|
||||
QJsonObject server = iter->toObject();
|
||||
qDebug() << iter.key();
|
||||
qDebug() << server["hostname"].toString();
|
||||
qDebug() << server["modname"].toString();
|
||||
qDebug() << server["players"].toInt();
|
||||
qDebug() << server["max_players"].toInt();
|
||||
qDebug() << server["version"].toString();
|
||||
qDebug() << server["passw"].toBool();
|
||||
|
||||
QVector<ServerData>::Iterator value = std::find_if(model->myData.begin(), model->myData.end(), pattern(iter.key()));
|
||||
if(value == model->myData.end())
|
||||
model->insertRow(0);
|
||||
|
||||
setData(iter.key(), server, model);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NetController::updateInfo(QAbstractItemModel *pModel, QModelIndex index)
|
||||
{
|
||||
ServerModel *model = ((ServerModel*)pModel);
|
||||
|
||||
bool result;
|
||||
if (index.isValid() && index.row() >= 0)
|
||||
result = downloadInfo(pModel, index);
|
||||
else
|
||||
{
|
||||
for (auto iter = model->myData.begin(); iter != model->myData.end(); iter++)
|
||||
{
|
||||
qDebug() << iter->addr;
|
||||
}
|
||||
model->removeRows(0, model->rowCount(index));
|
||||
result = downloadInfo(pModel, index);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void NetController::updateInfo()
|
||||
{
|
||||
QString data;
|
||||
QString uri = "/api/servers/" + sd->addr;
|
||||
while (true)
|
||||
{
|
||||
data = QString::fromStdString(httpNetwork.getData(uri.toLatin1()));
|
||||
if (!data.isEmpty() && data != "NO_CONTENT" && data != "LOST_CONNECTION")
|
||||
break;
|
||||
RakSleep(30);
|
||||
}
|
||||
|
||||
if(data == "UNKNOWN_ADDRESS")
|
||||
{
|
||||
QMessageBox::critical(0, "Error", "Cannot connect to the master server!");
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "Content: " << data;
|
||||
|
||||
QJsonParseError err;
|
||||
QJsonDocument jsonDocument = QJsonDocument::fromJson(data.toLatin1(), &err);
|
||||
|
||||
QMap<QString, QVariant> map = jsonDocument.toVariant().toMap()["server"].toMap();
|
||||
|
||||
qDebug() << sd->addr;
|
||||
qDebug() << map["hostname"].toString();
|
||||
qDebug() << map["modname"].toString();
|
||||
qDebug() << map["players"].toInt();
|
||||
qDebug() << map["max_players"].toInt();
|
||||
qDebug() << map["version"].toString();
|
||||
qDebug() << map["passw"].toBool();
|
||||
|
||||
sd->hostName = map["hostname"].toString();
|
||||
sd->modName = map["modname"].toString();
|
||||
sd->players = map["players"].toInt();
|
||||
sd->maxPlayers = map["max_players"].toInt();
|
||||
|
||||
if(!sd->addr.contains(":"))
|
||||
sd->addr.append(":25565");
|
||||
QStringList addr = sd->addr.split(":");
|
||||
sd->ping = PingRakNetServer(addr[0].toLatin1(), addr[1].toUShort());
|
||||
if(sd->ping != PING_UNREACHABLE)
|
||||
sed = getExtendedData(addr[0].toLatin1(), addr[1].toUShort());
|
||||
else
|
||||
qDebug() << "Server is unreachable";
|
||||
}
|
||||
|
||||
QStringList NetController::players()
|
||||
{
|
||||
QStringList listPlayers;
|
||||
for(auto player = sed.players.begin(); player != sed.players.end(); player++)
|
||||
listPlayers.push_back(player->c_str());
|
||||
return listPlayers;
|
||||
}
|
||||
|
||||
QStringList NetController::plugins()
|
||||
{
|
||||
QStringList listPlugins;
|
||||
for(auto plugin = sed.plugins.begin(); plugin != sed.plugins.end(); plugin++)
|
||||
listPlugins.push_back(plugin->c_str());
|
||||
return listPlugins;
|
||||
}
|
||||
|
||||
void NetController::selectServer(ServerData *pServerData)
|
||||
{
|
||||
sd = pServerData;
|
||||
}
|
||||
|
||||
ServerData *NetController::selectedServer()
|
||||
{
|
||||
return sd;
|
||||
}
|
||||
|
42
apps/browser/NetController.hpp
Normal file
42
apps/browser/NetController.hpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
//
|
||||
// Created by koncord on 07.01.17.
|
||||
//
|
||||
|
||||
#ifndef NEWLAUNCHER_NETCONTROLLER_HPP
|
||||
#define NEWLAUNCHER_NETCONTROLLER_HPP
|
||||
|
||||
|
||||
#include "ServerModel.hpp"
|
||||
#include "netutils/HTTPNetwork.hpp"
|
||||
#include "netutils/Utils.hpp"
|
||||
|
||||
struct ServerModel;
|
||||
|
||||
class NetController
|
||||
{
|
||||
public:
|
||||
static NetController *get();
|
||||
static void Create(std::string addr, unsigned short port);
|
||||
static void Destroy();
|
||||
bool updateInfo(QAbstractItemModel *pModel, QModelIndex index= QModelIndex());
|
||||
void updateInfo();
|
||||
QStringList players();
|
||||
QStringList plugins();
|
||||
void selectServer(ServerData *pServerData);
|
||||
ServerData *selectedServer();
|
||||
protected:
|
||||
NetController(std::string addr, unsigned short port);
|
||||
~NetController();
|
||||
private:
|
||||
NetController(const NetController &controller);
|
||||
bool downloadInfo(QAbstractItemModel *pModel, QModelIndex index);
|
||||
void setData(QString addr, QJsonObject server, ServerModel *model);
|
||||
|
||||
static NetController *mThis;
|
||||
ServerData *sd;
|
||||
HTTPNetwork httpNetwork;
|
||||
ServerExtendedData sed;
|
||||
};
|
||||
|
||||
|
||||
#endif //NEWLAUNCHER_NETCONTROLLER_HPP
|
39
apps/browser/ServerInfoDialog.cpp
Normal file
39
apps/browser/ServerInfoDialog.cpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
//
|
||||
// Created by koncord on 07.01.17.
|
||||
//
|
||||
|
||||
#include "qdebug.h"
|
||||
#include "NetController.hpp"
|
||||
|
||||
#include "ServerInfoDialog.hpp"
|
||||
|
||||
ServerInfoDialog::ServerInfoDialog(QWidget *parent): QDialog(parent)
|
||||
{
|
||||
setupUi(this);
|
||||
connect(btnRefresh, SIGNAL(clicked()), this, SLOT(refresh()));
|
||||
}
|
||||
|
||||
ServerInfoDialog::~ServerInfoDialog()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ServerInfoDialog::refresh()
|
||||
{
|
||||
NetController::get()->updateInfo();
|
||||
ServerData *sd = NetController::get()->selectedServer();
|
||||
if (sd)
|
||||
{
|
||||
leAddr->setText(sd->addr);
|
||||
lblName->setText(sd->hostName);
|
||||
lblPing->setNum(sd->ping);
|
||||
|
||||
listPlayers->clear();
|
||||
QStringList players = NetController::get()->players();
|
||||
listPlayers->addItems(players);
|
||||
listPlugins->clear();
|
||||
listPlugins->addItems(NetController::get()->plugins());
|
||||
|
||||
lblPlayers->setText(QString::number(players.size()) + " / " + QString::number(sd->maxPlayers));
|
||||
}
|
||||
}
|
21
apps/browser/ServerInfoDialog.hpp
Normal file
21
apps/browser/ServerInfoDialog.hpp
Normal file
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// Created by koncord on 07.01.17.
|
||||
//
|
||||
|
||||
#ifndef NEWLAUNCHER_SERVERINFODIALOG_HPP
|
||||
#define NEWLAUNCHER_SERVERINFODIALOG_HPP
|
||||
|
||||
#include "ui_ServerInfo.h"
|
||||
|
||||
class ServerInfoDialog : public QDialog, public Ui::Dialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ServerInfoDialog(QWidget *parent = 0);
|
||||
virtual ~ServerInfoDialog();
|
||||
public slots:
|
||||
void refresh();
|
||||
};
|
||||
|
||||
|
||||
#endif //NEWLAUNCHER_SERVERINFODIALOG_HPP
|
200
apps/browser/ServerModel.cpp
Normal file
200
apps/browser/ServerModel.cpp
Normal file
|
@ -0,0 +1,200 @@
|
|||
#include <qmessagebox.h>
|
||||
#include "ServerModel.hpp"
|
||||
#include <qdebug.h>
|
||||
|
||||
ServerModel::ServerModel(QObject *parent) : QAbstractTableModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
ServerModel::~ServerModel()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*QHash<int, QByteArray> ServerModel::roleNames() const
|
||||
{
|
||||
return roles;
|
||||
}*/
|
||||
|
||||
QVariant ServerModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
if (index.row() < 0 || index.row() > myData.size())
|
||||
return QVariant();
|
||||
|
||||
const ServerData &sd = myData.at(index.row());
|
||||
|
||||
if(role == Qt::DisplayRole)
|
||||
{
|
||||
QVariant var;
|
||||
switch (index.column())
|
||||
{
|
||||
case ServerData::ADDR:
|
||||
var = sd.addr;
|
||||
break;
|
||||
case ServerData::PASSW:
|
||||
var = sd.needPassw ? "Yes" : "No";
|
||||
break;
|
||||
case ServerData::VERSION:
|
||||
var = sd.version;
|
||||
break;
|
||||
case ServerData::PLAYERS:
|
||||
var = sd.players;
|
||||
break;
|
||||
case ServerData::MAX_PLAYERS:
|
||||
var = sd.maxPlayers;
|
||||
break;
|
||||
case ServerData::HOSTNAME:
|
||||
var = sd.hostName;
|
||||
break;
|
||||
case ServerData::PING:
|
||||
var = sd.ping;
|
||||
break;
|
||||
case ServerData::MODNAME:
|
||||
if(sd.modName.isEmpty())
|
||||
var = "default";
|
||||
else
|
||||
var = sd.modName;
|
||||
break;
|
||||
}
|
||||
return var;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant ServerModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
QVariant var;
|
||||
if (orientation == Qt::Horizontal)
|
||||
{
|
||||
if (role == Qt::SizeHintRole)
|
||||
{
|
||||
/*if(section == ServerData::HOSTNAME)
|
||||
var = QSize(200, 25);*/
|
||||
}
|
||||
else if (role == Qt::DisplayRole)
|
||||
{
|
||||
|
||||
switch (section)
|
||||
{
|
||||
case ServerData::ADDR:
|
||||
var = "Address";
|
||||
break;
|
||||
case ServerData::PASSW:
|
||||
var = "Password";
|
||||
break;
|
||||
case ServerData::VERSION:
|
||||
var = "Version";
|
||||
break;
|
||||
case ServerData::HOSTNAME:
|
||||
var = "Host name";
|
||||
break;
|
||||
case ServerData::PLAYERS:
|
||||
var = "Players";
|
||||
break;
|
||||
case ServerData::MAX_PLAYERS:
|
||||
var = "Max players";
|
||||
break;
|
||||
case ServerData::PING:
|
||||
var = "Ping";
|
||||
break;
|
||||
case ServerData::MODNAME:
|
||||
var = "Game mode";
|
||||
}
|
||||
}
|
||||
}
|
||||
return var;
|
||||
}
|
||||
|
||||
int ServerModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
return myData.size();
|
||||
}
|
||||
|
||||
int ServerModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
return ServerData::LAST;
|
||||
}
|
||||
|
||||
bool ServerModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
if (index.isValid() && role == Qt::EditRole)
|
||||
{
|
||||
int row = index.row();
|
||||
int col = index.column();
|
||||
|
||||
ServerData &sd = myData[row];
|
||||
bool ok = true;
|
||||
switch(col)
|
||||
{
|
||||
case ServerData::ADDR:
|
||||
sd.addr = value.toString();
|
||||
ok = !sd.addr.isEmpty();
|
||||
break;
|
||||
case ServerData::PASSW:
|
||||
sd.needPassw = value.toBool();
|
||||
break;
|
||||
case ServerData::VERSION:
|
||||
sd.version = value.toString();
|
||||
ok = !sd.addr.isEmpty();
|
||||
break;
|
||||
case ServerData::PLAYERS:
|
||||
sd.players = value.toInt(&ok);
|
||||
break;
|
||||
case ServerData::MAX_PLAYERS:
|
||||
sd.maxPlayers = value.toInt(&ok);
|
||||
break;
|
||||
case ServerData::HOSTNAME:
|
||||
sd.hostName = value.toString();
|
||||
ok = !sd.addr.isEmpty();
|
||||
break;
|
||||
case ServerData::PING:
|
||||
sd.ping = value.toInt(&ok);
|
||||
break;
|
||||
case ServerData::MODNAME:
|
||||
sd.modName = value.toString();
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
if(ok)
|
||||
emit(dataChanged(index, index));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ServerModel::insertRows(int position, int count, const QModelIndex &index)
|
||||
{
|
||||
Q_UNUSED(index);
|
||||
beginInsertRows(QModelIndex(), position, position + count - 1);
|
||||
|
||||
for (int row = 0; row < count; ++row) {
|
||||
ServerData sd {"", -1, -1, -1, "", "", false, 0};
|
||||
myData.insert(position, sd);
|
||||
}
|
||||
|
||||
endInsertRows();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ServerModel::removeRows(int position, int count, const QModelIndex &parent)
|
||||
{
|
||||
if (count == 0)
|
||||
return false;
|
||||
|
||||
beginRemoveRows(parent, position, position + count - 1);
|
||||
myData.erase(myData.begin()+position, myData.begin() + position + count);
|
||||
endRemoveRows();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QModelIndex ServerModel::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
|
||||
QModelIndex index = QAbstractTableModel::index(row, column, parent);
|
||||
//qDebug() << "Valid index? " << index.isValid() << " " << row << " " << column;
|
||||
return index;
|
||||
}
|
56
apps/browser/ServerModel.hpp
Normal file
56
apps/browser/ServerModel.hpp
Normal file
|
@ -0,0 +1,56 @@
|
|||
#ifndef SERVERMODEL_FONTMODEL_HPP
|
||||
#define SERVERMODEL_FONTMODEL_HPP
|
||||
|
||||
#include <QObject>
|
||||
#include <vector>
|
||||
#include <QString>
|
||||
#include <QAbstractTableModel>
|
||||
|
||||
struct ServerData
|
||||
{
|
||||
QString addr;
|
||||
int players, maxPlayers;
|
||||
int ping;
|
||||
QString hostName;
|
||||
QString modName;
|
||||
bool needPassw;
|
||||
QString version;
|
||||
enum IDS
|
||||
{
|
||||
ADDR,
|
||||
HOSTNAME,
|
||||
PLAYERS,
|
||||
MAX_PLAYERS,
|
||||
PASSW,
|
||||
MODNAME,
|
||||
PING,
|
||||
VERSION,
|
||||
LAST
|
||||
};
|
||||
};
|
||||
|
||||
class ServerModel: public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ServerModel(QObject *parent = 0);
|
||||
~ServerModel();
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_FINAL;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_FINAL;
|
||||
int columnCount(const QModelIndex &parent) const Q_DECL_FINAL;
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) Q_DECL_FINAL;
|
||||
|
||||
bool insertRows(int row, int count, const QModelIndex &index = QModelIndex()) Q_DECL_FINAL;
|
||||
bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) Q_DECL_FINAL;
|
||||
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_FINAL;
|
||||
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const Q_DECL_FINAL;
|
||||
|
||||
|
||||
public:
|
||||
//QHash<int, QByteArray> roles;
|
||||
QVector<ServerData> myData;
|
||||
};
|
||||
|
||||
|
||||
#endif //SERVERMODEL_FONTMODEL_HPP
|
57
apps/browser/main.cpp
Normal file
57
apps/browser/main.cpp
Normal file
|
@ -0,0 +1,57 @@
|
|||
#include <QApplication>
|
||||
#include <components/settings/settings.hpp>
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
#include "MainWindow.hpp"
|
||||
#include "NetController.hpp"
|
||||
|
||||
std::string loadSettings (Settings::Manager & settings)
|
||||
{
|
||||
Files::ConfigurationManager mCfgMgr;
|
||||
// Create the settings manager and load default settings file
|
||||
const std::string localdefault = (mCfgMgr.getLocalPath() / "tes3mp-client-default.cfg").string();
|
||||
const std::string globaldefault = (mCfgMgr.getGlobalPath() / "tes3mp-client-default.cfg").string();
|
||||
|
||||
// prefer local
|
||||
if (boost::filesystem::exists(localdefault))
|
||||
settings.loadDefault(localdefault);
|
||||
else if (boost::filesystem::exists(globaldefault))
|
||||
settings.loadDefault(globaldefault);
|
||||
else
|
||||
throw std::runtime_error ("No default settings file found! Make sure the file \"tes3mp-client-default.cfg\" was properly installed.");
|
||||
|
||||
// load user settings if they exist
|
||||
const std::string settingspath = (mCfgMgr.getUserConfigPath() / "tes3mp-client.cfg").string();
|
||||
if (boost::filesystem::exists(settingspath))
|
||||
settings.loadUser(settingspath);
|
||||
|
||||
return settingspath;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Settings::Manager mgr;
|
||||
|
||||
loadSettings(mgr);
|
||||
|
||||
std::string addr = mgr.getString("address", "Master");
|
||||
int port = mgr.getInt("port", "Master");
|
||||
|
||||
// initialize resources, if needed
|
||||
// Q_INIT_RESOURCE(resfile);
|
||||
|
||||
NetController::Create(addr, port);
|
||||
atexit(NetController::Destroy);
|
||||
QApplication app(argc, argv);
|
||||
MainWindow d;
|
||||
|
||||
if (d.refresh())
|
||||
{
|
||||
d.show();
|
||||
return app.exec();
|
||||
}
|
||||
else
|
||||
{
|
||||
app.exit();
|
||||
return 0;
|
||||
}
|
||||
}
|
99
apps/browser/netutils/HTTPNetwork.cpp
Normal file
99
apps/browser/netutils/HTTPNetwork.cpp
Normal file
|
@ -0,0 +1,99 @@
|
|||
//
|
||||
// Created by koncord on 07.01.17.
|
||||
//
|
||||
|
||||
#include <RakPeer.h>
|
||||
#include <HTTPConnection2.h>
|
||||
#include <TCPInterface.h>
|
||||
#include <RakSleep.h>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "HTTPNetwork.hpp"
|
||||
|
||||
using namespace RakNet;
|
||||
|
||||
HTTPNetwork::HTTPNetwork(std::string addr, unsigned short port) : address(addr), port(port)
|
||||
{
|
||||
httpConnection = HTTPConnection2::GetInstance();
|
||||
tcpInterface = new TCPInterface;
|
||||
tcpInterface->Start(0, 64);
|
||||
tcpInterface->AttachPlugin(httpConnection);
|
||||
}
|
||||
|
||||
HTTPNetwork::~HTTPNetwork()
|
||||
{
|
||||
delete tcpInterface;
|
||||
}
|
||||
|
||||
std::string HTTPNetwork::answer()
|
||||
{
|
||||
RakNet::SystemAddress sa;
|
||||
RakNet::Packet *packet;
|
||||
RakNet::SystemAddress hostReceived;
|
||||
RakNet::RakString response;
|
||||
RakNet::RakString transmitted, hostTransmitted;
|
||||
int contentOffset = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
// This is kind of crappy, but for TCP plugins, always do HasCompletedConnectionAttempt,
|
||||
// then Receive(), then HasFailedConnectionAttempt(),HasLostConnection()
|
||||
sa = tcpInterface->HasCompletedConnectionAttempt();
|
||||
if (sa != RakNet::UNASSIGNED_SYSTEM_ADDRESS)
|
||||
printf("Connected to master server: %s\n", sa.ToString());
|
||||
|
||||
sa = tcpInterface->HasFailedConnectionAttempt();
|
||||
if (sa != RakNet::UNASSIGNED_SYSTEM_ADDRESS)
|
||||
{
|
||||
printf("Failed to connect to master server: %s\n", sa.ToString());
|
||||
return "FAIL_CONNECT";
|
||||
}
|
||||
sa = tcpInterface->HasLostConnection();
|
||||
if (sa != RakNet::UNASSIGNED_SYSTEM_ADDRESS)
|
||||
{
|
||||
printf("Lost connection to master server: %s\n", sa.ToString());
|
||||
return "LOST_CONNECTION";
|
||||
}
|
||||
|
||||
for (packet = tcpInterface->Receive(); packet; tcpInterface->DeallocatePacket(
|
||||
packet), packet = tcpInterface->Receive());
|
||||
|
||||
if (httpConnection->GetResponse(transmitted, hostTransmitted, response, hostReceived, contentOffset))
|
||||
{
|
||||
if (contentOffset < 0)
|
||||
return "NO_CONTENT"; // no content
|
||||
tcpInterface->CloseConnection(sa);
|
||||
|
||||
return (response.C_String() + contentOffset);
|
||||
}
|
||||
RakSleep(30);
|
||||
}
|
||||
}
|
||||
|
||||
std::string HTTPNetwork::getData(const char *uri)
|
||||
{
|
||||
RakNet::RakString createRequest = RakNet::RakString::FormatForGET(uri);
|
||||
|
||||
if (!httpConnection->TransmitRequest(createRequest, address.c_str(), port))
|
||||
return "UNKNOWN_ADDRESS";
|
||||
return answer();
|
||||
}
|
||||
|
||||
std::string HTTPNetwork::getDataPOST(const char *uri, const char* body, const char* contentType)
|
||||
{
|
||||
RakNet::RakString createRequest = RakNet::RakString::FormatForPOST(uri, contentType, body);
|
||||
|
||||
if (!httpConnection->TransmitRequest(createRequest, address.c_str(), port))
|
||||
return "UNKNOWN_ADDRESS";
|
||||
return answer();
|
||||
}
|
||||
|
||||
std::string HTTPNetwork::getDataPUT(const char *uri, const char* body, const char* contentType)
|
||||
{
|
||||
RakNet::RakString createRequest = RakNet::RakString::FormatForPUT(uri, contentType, body);
|
||||
|
||||
if (!httpConnection->TransmitRequest(createRequest, address.c_str(), port))
|
||||
return "UNKNOWN_ADDRESS";
|
||||
return answer();
|
||||
}
|
35
apps/browser/netutils/HTTPNetwork.hpp
Normal file
35
apps/browser/netutils/HTTPNetwork.hpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
//
|
||||
// Created by koncord on 07.01.17.
|
||||
//
|
||||
|
||||
#ifndef NEWLAUNCHER_HTTPNETWORK_HPP
|
||||
#define NEWLAUNCHER_HTTPNETWORK_HPP
|
||||
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace RakNet
|
||||
{
|
||||
class TCPInterface;
|
||||
class HTTPConnection2;
|
||||
}
|
||||
|
||||
class HTTPNetwork
|
||||
{
|
||||
public:
|
||||
HTTPNetwork(std::string addr, unsigned short port);
|
||||
~HTTPNetwork();
|
||||
std::string getData(const char *uri);
|
||||
std::string getDataPOST(const char *uri, const char* body, const char* contentType = "application/json");
|
||||
std::string getDataPUT(const char *uri, const char* body, const char* contentType = "application/json");
|
||||
|
||||
protected:
|
||||
RakNet::TCPInterface *tcpInterface;
|
||||
RakNet::HTTPConnection2 *httpConnection;
|
||||
std::string address;
|
||||
unsigned short port;
|
||||
std::string answer();
|
||||
};
|
||||
|
||||
|
||||
#endif //NEWLAUNCHER_HTTPNETWORK_HPP
|
156
apps/browser/netutils/Utils.cpp
Normal file
156
apps/browser/netutils/Utils.cpp
Normal file
|
@ -0,0 +1,156 @@
|
|||
//
|
||||
// Created by koncord on 07.01.17.
|
||||
//
|
||||
|
||||
#include <RakPeer.h>
|
||||
#include <MessageIdentifiers.h>
|
||||
#include <RakSleep.h>
|
||||
#include <GetTime.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <components/openmw-mp/Version.hpp>
|
||||
|
||||
#include "Utils.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
unsigned int PingRakNetServer(const char *addr, unsigned short port)
|
||||
{
|
||||
RakNet::Packet *packet;
|
||||
bool done = false;
|
||||
int attempts = 0;
|
||||
RakNet::TimeMS time = PING_UNREACHABLE;
|
||||
|
||||
RakNet::SocketDescriptor socketDescriptor {0, ""};
|
||||
RakNet::RakPeerInterface *peer = RakNet::RakPeerInterface::GetInstance();
|
||||
peer->Startup(1,&socketDescriptor, 1);
|
||||
|
||||
peer->Ping(addr, port, false);
|
||||
while (!done)
|
||||
{
|
||||
for (packet=peer->Receive(); packet; peer->DeallocatePacket(packet), packet=peer->Receive())
|
||||
{
|
||||
if(packet->data[0] == ID_UNCONNECTED_PONG)
|
||||
{
|
||||
RakNet::BitStream bsIn(&packet->data[1], packet->length, false);
|
||||
bsIn.Read(time);
|
||||
time = RakNet::GetTimeMS() - time - 5;
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (attempts >= 60) // wait 300 msec
|
||||
done = true;
|
||||
attempts++;
|
||||
RakSleep(5);
|
||||
}
|
||||
|
||||
peer->Shutdown(0);
|
||||
RakNet::RakPeerInterface::DestroyInstance(peer);
|
||||
return time;
|
||||
}
|
||||
|
||||
ServerExtendedData getExtendedData(const char *addr, unsigned short port)
|
||||
{
|
||||
ServerExtendedData data;
|
||||
RakNet::SocketDescriptor socketDescriptor = {0, ""};
|
||||
RakNet::RakPeerInterface *peer = RakNet::RakPeerInterface::GetInstance();
|
||||
peer->Startup(1, &socketDescriptor, 1);
|
||||
|
||||
stringstream sstr(TES3MP_VERSION);
|
||||
sstr << TES3MP_PROTO_VERSION;
|
||||
|
||||
std::string msg = "";
|
||||
|
||||
if (peer->Connect(addr, port, sstr.str().c_str(), (int)(sstr.str().size()), 0, 0, 3, 500, 0) != RakNet::CONNECTION_ATTEMPT_STARTED)
|
||||
msg = "Connection attempt failed.\n";
|
||||
|
||||
|
||||
int queue = 0;
|
||||
while (queue == 0)
|
||||
{
|
||||
for (RakNet::Packet *packet = peer->Receive(); packet; peer->DeallocatePacket(
|
||||
packet), packet = peer->Receive())
|
||||
{
|
||||
switch (packet->data[0])
|
||||
{
|
||||
case ID_CONNECTION_ATTEMPT_FAILED:
|
||||
{
|
||||
msg = "Connection failed.\n"
|
||||
"Either the IP address is wrong or a firewall on either system is blocking\n"
|
||||
"UDP packets on the port you have chosen.";
|
||||
queue = -1;
|
||||
break;
|
||||
}
|
||||
case ID_INVALID_PASSWORD:
|
||||
{
|
||||
msg = "Connection failed.\n"
|
||||
"The client or server is outdated.\n";
|
||||
queue = -1;
|
||||
break;
|
||||
}
|
||||
case ID_CONNECTION_REQUEST_ACCEPTED:
|
||||
{
|
||||
msg = "Connection accepted.\n";
|
||||
queue = 1;
|
||||
break;
|
||||
}
|
||||
case ID_DISCONNECTION_NOTIFICATION:
|
||||
throw runtime_error("ID_DISCONNECTION_NOTIFICATION.\n");
|
||||
case ID_CONNECTION_BANNED:
|
||||
throw runtime_error("ID_CONNECTION_BANNED.\n");
|
||||
case ID_CONNECTION_LOST:
|
||||
throw runtime_error("ID_CONNECTION_LOST.\n");
|
||||
default:
|
||||
printf("Connection message with identifier %i has arrived in initialization.\n", packet->data[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
puts(msg.c_str());
|
||||
|
||||
if(queue == -1) // connection is failed
|
||||
return data;
|
||||
|
||||
{
|
||||
RakNet::BitStream bs;
|
||||
bs.Write((unsigned char) (ID_USER_PACKET_ENUM + 1));
|
||||
peer->Send(&bs, HIGH_PRIORITY, RELIABLE_ORDERED, 0, RakNet::UNASSIGNED_SYSTEM_ADDRESS, true);
|
||||
}
|
||||
|
||||
RakNet::Packet *packet;
|
||||
bool done = false;
|
||||
while (!done)
|
||||
{
|
||||
for (packet = peer->Receive(); packet; peer->DeallocatePacket(packet), packet = peer->Receive())
|
||||
{
|
||||
if(packet->data[0] == (ID_USER_PACKET_ENUM+1))
|
||||
{
|
||||
RakNet::BitStream bs(packet->data, packet->length, false);
|
||||
bs.IgnoreBytes(1);
|
||||
size_t length = 0;
|
||||
bs.Read(length);
|
||||
for(int i = 0; i < length; i++)
|
||||
{
|
||||
RakNet::RakString str;
|
||||
bs.Read(str);
|
||||
data.players.push_back(str.C_String());
|
||||
}
|
||||
bs.Read(length);
|
||||
for(int i = 0; i < length; i++)
|
||||
{
|
||||
RakNet::RakString str;
|
||||
bs.Read(str);
|
||||
data.plugins.push_back(str.C_String());
|
||||
}
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
peer->Shutdown(0);
|
||||
RakSleep(10);
|
||||
RakNet::RakPeerInterface::DestroyInstance(peer);
|
||||
return data;
|
||||
}
|
24
apps/browser/netutils/Utils.hpp
Normal file
24
apps/browser/netutils/Utils.hpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// Created by koncord on 07.01.17.
|
||||
//
|
||||
|
||||
#ifndef NEWLAUNCHER_PING_HPP
|
||||
#define NEWLAUNCHER_PING_HPP
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
|
||||
#define PING_UNREACHABLE 999
|
||||
|
||||
unsigned int PingRakNetServer(const char *addr, unsigned short port);
|
||||
|
||||
struct ServerExtendedData
|
||||
{
|
||||
std::vector<std::string> players;
|
||||
std::vector<std::string> plugins;
|
||||
};
|
||||
|
||||
ServerExtendedData getExtendedData(const char *addr, unsigned short port);
|
||||
|
||||
#endif //NEWLAUNCHER_PING_HPP
|
|
@ -5,6 +5,7 @@
|
|||
#include <map>
|
||||
#include <set>
|
||||
#include <fstream>
|
||||
#include <cmath>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
|
@ -354,12 +355,12 @@ int load(Arguments& info)
|
|||
esm.getRecHeader(flags);
|
||||
|
||||
EsmTool::RecordBase *record = EsmTool::RecordBase::create(n);
|
||||
if (record == 0)
|
||||
if (record == 0)
|
||||
{
|
||||
if (std::find(skipped.begin(), skipped.end(), n.val) == skipped.end())
|
||||
if (std::find(skipped.begin(), skipped.end(), n.intval) == skipped.end())
|
||||
{
|
||||
std::cout << "Skipping " << n.toString() << " records." << std::endl;
|
||||
skipped.push_back(n.val);
|
||||
skipped.push_back(n.intval);
|
||||
}
|
||||
|
||||
esm.skipRecord();
|
||||
|
@ -391,20 +392,20 @@ int load(Arguments& info)
|
|||
record->print();
|
||||
}
|
||||
|
||||
if (record->getType().val == ESM::REC_CELL && loadCells && interested)
|
||||
if (record->getType().intval == ESM::REC_CELL && loadCells && interested)
|
||||
{
|
||||
loadCell(record->cast<ESM::Cell>()->get(), esm, info);
|
||||
}
|
||||
|
||||
if (save)
|
||||
if (save)
|
||||
{
|
||||
info.data.mRecords.push_back(record);
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
delete record;
|
||||
}
|
||||
++info.data.mRecordStats[n.val];
|
||||
++info.data.mRecordStats[n.intval];
|
||||
}
|
||||
|
||||
} catch(std::exception &e) {
|
||||
|
@ -442,23 +443,18 @@ int clone(Arguments& info)
|
|||
size_t recordCount = info.data.mRecords.size();
|
||||
|
||||
int digitCount = 1; // For a nicer output
|
||||
if (recordCount > 9) ++digitCount;
|
||||
if (recordCount > 99) ++digitCount;
|
||||
if (recordCount > 999) ++digitCount;
|
||||
if (recordCount > 9999) ++digitCount;
|
||||
if (recordCount > 99999) ++digitCount;
|
||||
if (recordCount > 999999) ++digitCount;
|
||||
if (recordCount > 0)
|
||||
digitCount = (int)std::log10(recordCount) + 1;
|
||||
|
||||
std::cout << "Loaded " << recordCount << " records:" << std::endl << std::endl;
|
||||
|
||||
ESM::NAME name;
|
||||
|
||||
int i = 0;
|
||||
typedef std::map<int, int> Stats;
|
||||
Stats &stats = info.data.mRecordStats;
|
||||
for (Stats::iterator it = stats.begin(); it != stats.end(); ++it)
|
||||
{
|
||||
name.val = it->first;
|
||||
ESM::NAME name;
|
||||
name.intval = it->first;
|
||||
int amount = it->second;
|
||||
std::cout << std::setw(digitCount) << amount << " " << name.toString() << " ";
|
||||
|
||||
|
@ -491,12 +487,12 @@ int clone(Arguments& info)
|
|||
for (Records::iterator it = records.begin(); it != records.end() && i > 0; ++it)
|
||||
{
|
||||
EsmTool::RecordBase *record = *it;
|
||||
name.val = record->getType().val;
|
||||
const ESM::NAME& typeName = record->getType();
|
||||
|
||||
esm.startRecord(name.toString(), record->getFlags());
|
||||
esm.startRecord(typeName.toString(), record->getFlags());
|
||||
|
||||
record->save(esm);
|
||||
if (name.val == ESM::REC_CELL) {
|
||||
if (typeName.intval == ESM::REC_CELL) {
|
||||
ESM::Cell *ptr = &record->cast<ESM::Cell>()->get();
|
||||
if (!info.data.mCellRefs[ptr].empty()) {
|
||||
typedef std::deque<std::pair<ESM::CellRef, bool> > RefList;
|
||||
|
@ -508,7 +504,7 @@ int clone(Arguments& info)
|
|||
}
|
||||
}
|
||||
|
||||
esm.endRecord(name.toString());
|
||||
esm.endRecord(typeName.toString());
|
||||
|
||||
saved++;
|
||||
int perc = (int)((saved / (float)recordCount)*100);
|
||||
|
|
|
@ -179,7 +179,7 @@ RecordBase::create(ESM::NAME type)
|
|||
{
|
||||
RecordBase *record = 0;
|
||||
|
||||
switch (type.val) {
|
||||
switch (type.intval) {
|
||||
case ESM::REC_ACTI:
|
||||
{
|
||||
record = new EsmTool::Record<ESM::Activator>;
|
||||
|
@ -494,7 +494,7 @@ void Record<ESM::Book>::print()
|
|||
std::cout << " Weight: " << mData.mData.mWeight << std::endl;
|
||||
std::cout << " Value: " << mData.mData.mValue << std::endl;
|
||||
std::cout << " IsScroll: " << mData.mData.mIsScroll << std::endl;
|
||||
std::cout << " SkillID: " << mData.mData.mSkillID << std::endl;
|
||||
std::cout << " SkillId: " << mData.mData.mSkillId << std::endl;
|
||||
std::cout << " Enchantment Points: " << mData.mData.mEnchant << std::endl;
|
||||
if (mPrintPlain)
|
||||
{
|
||||
|
|
|
@ -42,3 +42,7 @@ if (BUILD_WITH_CODE_COVERAGE)
|
|||
add_definitions (--coverage)
|
||||
target_link_libraries(openmw-essimporter gcov)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
INSTALL(TARGETS openmw-essimporter RUNTIME DESTINATION ".")
|
||||
endif(WIN32)
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
#include <string>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include "convertacdt.hpp"
|
||||
|
||||
namespace ESSImport
|
||||
|
@ -49,4 +55,49 @@ namespace ESSImport
|
|||
npcStats.mTimeToStartDrowning = actorData.mACDT.mBreathMeter;
|
||||
}
|
||||
|
||||
void convertANIS (const ANIS& anis, ESM::AnimationState& state)
|
||||
{
|
||||
static const char* animGroups[] =
|
||||
{
|
||||
"Idle", "Idle2", "Idle3", "Idle4", "Idle5", "Idle6", "Idle7", "Idle8", "Idle9", "Idlehh", "Idle1h", "Idle2c",
|
||||
"Idle2w", "IdleSwim", "IdleSpell", "IdleCrossbow", "IdleSneak", "IdleStorm", "Torch", "Hit1", "Hit2", "Hit3",
|
||||
"Hit4", "Hit5", "SwimHit1", "SwimHit2", "SwimHit3", "Death1", "Death2", "Death3", "Death4", "Death5",
|
||||
"DeathKnockDown", "DeathKnockOut", "KnockDown", "KnockOut", "SwimDeath", "SwimDeath2", "SwimDeath3",
|
||||
"SwimDeathKnockDown", "SwimDeathKnockOut", "SwimKnockOut", "SwimKnockDown", "SwimWalkForward",
|
||||
"SwimWalkBack", "SwimWalkLeft", "SwimWalkRight", "SwimRunForward", "SwimRunBack", "SwimRunLeft",
|
||||
"SwimRunRight", "SwimTurnLeft", "SwimTurnRight", "WalkForward", "WalkBack", "WalkLeft", "WalkRight",
|
||||
"TurnLeft", "TurnRight", "RunForward", "RunBack", "RunLeft", "RunRight", "SneakForward", "SneakBack",
|
||||
"SneakLeft", "SneakRight", "Jump", "WalkForwardhh", "WalkBackhh", "WalkLefthh", "WalkRighthh",
|
||||
"TurnLefthh", "TurnRighthh", "RunForwardhh", "RunBackhh", "RunLefthh", "RunRighthh", "SneakForwardhh",
|
||||
"SneakBackhh", "SneakLefthh", "SneakRighthh", "Jumphh", "WalkForward1h", "WalkBack1h", "WalkLeft1h",
|
||||
"WalkRight1h", "TurnLeft1h", "TurnRight1h", "RunForward1h", "RunBack1h", "RunLeft1h", "RunRight1h",
|
||||
"SneakForward1h", "SneakBack1h", "SneakLeft1h", "SneakRight1h", "Jump1h", "WalkForward2c", "WalkBack2c",
|
||||
"WalkLeft2c", "WalkRight2c", "TurnLeft2c", "TurnRight2c", "RunForward2c", "RunBack2c", "RunLeft2c",
|
||||
"RunRight2c", "SneakForward2c", "SneakBack2c", "SneakLeft2c", "SneakRight2c", "Jump2c", "WalkForward2w",
|
||||
"WalkBack2w", "WalkLeft2w", "WalkRight2w", "TurnLeft2w", "TurnRight2w", "RunForward2w", "RunBack2w",
|
||||
"RunLeft2w", "RunRight2w", "SneakForward2w", "SneakBack2w", "SneakLeft2w", "SneakRight2w", "Jump2w",
|
||||
"SpellCast", "SpellTurnLeft", "SpellTurnRight", "Attack1", "Attack2", "Attack3", "SwimAttack1",
|
||||
"SwimAttack2", "SwimAttack3", "HandToHand", "Crossbow", "BowAndArrow", "ThrowWeapon", "WeaponOneHand",
|
||||
"WeaponTwoHand", "WeaponTwoWide", "Shield", "PickProbe", "InventoryHandToHand", "InventoryWeaponOneHand",
|
||||
"InventoryWeaponTwoHand", "InventoryWeaponTwoWide"
|
||||
};
|
||||
|
||||
if (anis.mGroupIndex < (sizeof(animGroups) / sizeof(*animGroups)))
|
||||
{
|
||||
std::string group(animGroups[anis.mGroupIndex]);
|
||||
Misc::StringUtils::lowerCaseInPlace(group);
|
||||
|
||||
ESM::AnimationState::ScriptedAnimation scriptedAnim;
|
||||
scriptedAnim.mGroup = group;
|
||||
scriptedAnim.mTime = anis.mTime;
|
||||
scriptedAnim.mAbsolute = true;
|
||||
// Neither loop count nor queueing seems to be supported by the ess format.
|
||||
scriptedAnim.mLoopCount = std::numeric_limits<size_t>::max();
|
||||
state.mScriptedAnims.push_back(scriptedAnim);
|
||||
}
|
||||
else
|
||||
// TODO: Handle 0xFF index, which seems to be used for finished animations.
|
||||
std::cerr << "unknown animation group index: " << static_cast<unsigned int>(anis.mGroupIndex) << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <components/esm/creaturestats.hpp>
|
||||
#include <components/esm/npcstats.hpp>
|
||||
#include <components/esm/loadskil.hpp>
|
||||
#include <components/esm/animationstate.hpp>
|
||||
|
||||
#include "importacdt.hpp"
|
||||
|
||||
|
@ -18,6 +19,8 @@ namespace ESSImport
|
|||
void convertACSC (const ACSC& acsc, ESM::CreatureStats& cStats);
|
||||
|
||||
void convertNpcData (const ActorData& actorData, ESM::NpcStats& npcStats);
|
||||
|
||||
void convertANIS (const ANIS& anis, ESM::AnimationState& state);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -34,6 +34,9 @@ namespace
|
|||
objstate.mCount = 0;
|
||||
convertSCRI(cellref.mSCRI, objstate.mLocals);
|
||||
objstate.mHasLocals = !objstate.mLocals.mVariables.empty();
|
||||
|
||||
if (cellref.mHasANIS)
|
||||
convertANIS(cellref.mANIS, objstate.mAnimationState);
|
||||
}
|
||||
|
||||
bool isIndexedRefId(const std::string& indexedRefId)
|
||||
|
|
|
@ -121,7 +121,7 @@ public:
|
|||
{
|
||||
mContext->mPlayer.mObject.mCreatureStats.mLevel = npc.mNpdt52.mLevel;
|
||||
mContext->mPlayerBase = npc;
|
||||
std::map<int, float> empty;
|
||||
ESM::SpellState::SpellParams empty;
|
||||
// FIXME: player start spells and birthsign spells aren't listed here,
|
||||
// need to fix openmw to account for this
|
||||
for (std::vector<std::string>::const_iterator it = npc.mSpells.mList.begin(); it != npc.mSpells.mList.end(); ++it)
|
||||
|
@ -202,7 +202,7 @@ public:
|
|||
bool isDeleted = false;
|
||||
|
||||
book.load(esm, isDeleted);
|
||||
if (book.mData.mSkillID == -1)
|
||||
if (book.mData.mSkillId == -1)
|
||||
mContext->mPlayer.mObject.mNpcStats.mUsedIds.push_back(Misc::StringUtils::lowerCase(book.mId));
|
||||
|
||||
mRecords[book.mId] = book;
|
||||
|
@ -271,23 +271,34 @@ private:
|
|||
class ConvertPCDT : public Converter
|
||||
{
|
||||
public:
|
||||
ConvertPCDT() : mFirstPersonCam(true) {}
|
||||
ConvertPCDT()
|
||||
: mFirstPersonCam(true),
|
||||
mTeleportingEnabled(true),
|
||||
mLevitationEnabled(true)
|
||||
{}
|
||||
|
||||
virtual void read(ESM::ESMReader &esm)
|
||||
{
|
||||
PCDT pcdt;
|
||||
pcdt.load(esm);
|
||||
|
||||
convertPCDT(pcdt, mContext->mPlayer, mContext->mDialogueState.mKnownTopics, mFirstPersonCam);
|
||||
convertPCDT(pcdt, mContext->mPlayer, mContext->mDialogueState.mKnownTopics, mFirstPersonCam, mTeleportingEnabled, mLevitationEnabled, mContext->mControlsState);
|
||||
}
|
||||
virtual void write(ESM::ESMWriter &esm)
|
||||
{
|
||||
esm.startRecord(ESM::REC_ENAB);
|
||||
esm.writeHNT("TELE", mTeleportingEnabled);
|
||||
esm.writeHNT("LEVT", mLevitationEnabled);
|
||||
esm.endRecord(ESM::REC_ENAB);
|
||||
|
||||
esm.startRecord(ESM::REC_CAM_);
|
||||
esm.writeHNT("FIRS", mFirstPersonCam);
|
||||
esm.endRecord(ESM::REC_CAM_);
|
||||
}
|
||||
private:
|
||||
bool mFirstPersonCam;
|
||||
bool mTeleportingEnabled;
|
||||
bool mLevitationEnabled;
|
||||
};
|
||||
|
||||
class ConvertCNTC : public Converter
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
namespace ESSImport
|
||||
{
|
||||
|
||||
void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector<std::string>& outDialogueTopics, bool& firstPersonCam)
|
||||
void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector<std::string>& outDialogueTopics, bool& firstPersonCam, bool& teleportingEnabled, bool& levitationEnabled, ESM::ControlsState& controls)
|
||||
{
|
||||
out.mBirthsign = pcdt.mBirthsign;
|
||||
out.mObject.mNpcStats.mBounty = pcdt.mBounty;
|
||||
|
@ -17,24 +17,72 @@ namespace ESSImport
|
|||
faction.mReputation = it->mReputation;
|
||||
out.mObject.mNpcStats.mFactions[Misc::StringUtils::lowerCase(it->mFactionName.toString())] = faction;
|
||||
}
|
||||
for (int i=0; i<3; ++i)
|
||||
out.mObject.mNpcStats.mSpecIncreases[i] = pcdt.mPNAM.mSpecIncreases[i];
|
||||
for (int i=0; i<8; ++i)
|
||||
out.mObject.mNpcStats.mSkillIncrease[i] = pcdt.mPNAM.mSkillIncreases[i];
|
||||
for (int i=0; i<27; ++i)
|
||||
out.mObject.mNpcStats.mSkills[i].mProgress = pcdt.mPNAM.mSkillProgress[i];
|
||||
out.mObject.mNpcStats.mLevelProgress = pcdt.mPNAM.mLevelProgress;
|
||||
|
||||
if (pcdt.mPNAM.mDrawState & PCDT::DrawState_Weapon)
|
||||
if (pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_WeaponDrawn)
|
||||
out.mObject.mCreatureStats.mDrawState = 1;
|
||||
if (pcdt.mPNAM.mDrawState & PCDT::DrawState_Spell)
|
||||
if (pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_SpellDrawn)
|
||||
out.mObject.mCreatureStats.mDrawState = 2;
|
||||
|
||||
firstPersonCam = (pcdt.mPNAM.mCameraState == PCDT::CameraState_FirstPerson);
|
||||
firstPersonCam = !(pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_ThirdPerson);
|
||||
teleportingEnabled = !(pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_TeleportingDisabled);
|
||||
levitationEnabled = !(pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_LevitationDisabled);
|
||||
|
||||
for (std::vector<std::string>::const_iterator it = pcdt.mKnownDialogueTopics.begin();
|
||||
it != pcdt.mKnownDialogueTopics.end(); ++it)
|
||||
{
|
||||
outDialogueTopics.push_back(Misc::StringUtils::lowerCase(*it));
|
||||
}
|
||||
|
||||
controls.mViewSwitchDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_ViewSwitchDisabled;
|
||||
controls.mControlsDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_ControlsDisabled;
|
||||
controls.mJumpingDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_JumpingDisabled;
|
||||
controls.mLookingDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_LookingDisabled;
|
||||
controls.mVanityModeDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_VanityModeDisabled;
|
||||
controls.mWeaponDrawingDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_WeaponDrawingDisabled;
|
||||
controls.mSpellDrawingDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_SpellDrawingDisabled;
|
||||
|
||||
if (pcdt.mHasMark)
|
||||
{
|
||||
out.mHasMark = 1;
|
||||
|
||||
const PCDT::PNAM::MarkLocation& mark = pcdt.mPNAM.mMarkLocation;
|
||||
|
||||
ESM::CellId cell;
|
||||
cell.mWorldspace = ESM::CellId::sDefaultWorldspace;
|
||||
cell.mPaged = true;
|
||||
|
||||
cell.mIndex.mX = mark.mCellX;
|
||||
cell.mIndex.mY = mark.mCellY;
|
||||
|
||||
// TODO: Figure out a better way to detect interiors. (0, 0) is a valid exterior cell.
|
||||
if (mark.mCellX == 0 && mark.mCellY == 0)
|
||||
{
|
||||
cell.mWorldspace = pcdt.mMNAM;
|
||||
cell.mPaged = false;
|
||||
}
|
||||
|
||||
out.mMarkedCell = cell;
|
||||
out.mMarkedPosition.pos[0] = mark.mX;
|
||||
out.mMarkedPosition.pos[1] = mark.mY;
|
||||
out.mMarkedPosition.pos[2] = mark.mZ;
|
||||
out.mMarkedPosition.rot[0] = out.mMarkedPosition.rot[1] = 0.0f;
|
||||
out.mMarkedPosition.rot[2] = mark.mRotZ;
|
||||
}
|
||||
|
||||
if (pcdt.mHasENAM)
|
||||
{
|
||||
const int cellSize = 8192;
|
||||
out.mLastKnownExteriorPosition[0] = (pcdt.mENAM.mCellX + 0.5f) * cellSize;
|
||||
out.mLastKnownExteriorPosition[1] = (pcdt.mENAM.mCellY + 0.5f) * cellSize;
|
||||
out.mLastKnownExteriorPosition[2] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,11 +4,12 @@
|
|||
#include "importplayer.hpp"
|
||||
|
||||
#include <components/esm/player.hpp>
|
||||
#include <components/esm/controlsstate.hpp>
|
||||
|
||||
namespace ESSImport
|
||||
{
|
||||
|
||||
void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector<std::string>& outDialogueTopics, bool& firstPersonCam);
|
||||
void convertPCDT(const PCDT& pcdt, ESM::Player& out, std::vector<std::string>& outDialogueTopics, bool& firstPersonCam, bool& teleportingEnabled, bool& levitationEnabled, ESM::ControlsState& controls);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ namespace ESSImport
|
|||
// unsure at which point between TGTN and CRED
|
||||
if (esm.isNextSub("AADT"))
|
||||
{
|
||||
// occured when a creature was in the middle of its attack, 44 bytes
|
||||
// occurred when a creature was in the middle of its attack, 44 bytes
|
||||
esm.skipHSub();
|
||||
}
|
||||
|
||||
|
@ -123,8 +123,13 @@ namespace ESSImport
|
|||
|
||||
if (esm.isNextSub("ND3D"))
|
||||
esm.skipHSub();
|
||||
|
||||
mHasANIS = false;
|
||||
if (esm.isNextSub("ANIS"))
|
||||
esm.skipHSub();
|
||||
{
|
||||
mHasANIS = true;
|
||||
esm.getHT(mANIS);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -55,6 +55,12 @@ namespace ESSImport
|
|||
unsigned char mCorpseClearCountdown; // hours?
|
||||
unsigned char mUnknown3[71];
|
||||
};
|
||||
struct ANIS
|
||||
{
|
||||
unsigned char mGroupIndex;
|
||||
unsigned char mUnknown[3];
|
||||
float mTime;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
struct ActorData : public ESM::CellRef
|
||||
|
@ -77,6 +83,9 @@ namespace ESSImport
|
|||
|
||||
SCRI mSCRI;
|
||||
|
||||
bool mHasANIS;
|
||||
ANIS mANIS; // scripted animation state
|
||||
|
||||
void load(ESM::ESMReader& esm);
|
||||
};
|
||||
|
||||
|
|
|
@ -51,6 +51,7 @@ namespace
|
|||
{
|
||||
for (int x=0; x<128; ++x)
|
||||
{
|
||||
assert(image->data(x,y));
|
||||
*(image->data(x,y)+2) = *it++;
|
||||
*(image->data(x,y)+1) = *it++;
|
||||
*image->data(x,y) = *it++;
|
||||
|
@ -322,14 +323,14 @@ namespace ESSImport
|
|||
ESM::NAME n = esm.getRecName();
|
||||
esm.getRecHeader();
|
||||
|
||||
std::map<unsigned int, boost::shared_ptr<Converter> >::iterator it = converters.find(n.val);
|
||||
std::map<unsigned int, boost::shared_ptr<Converter> >::iterator it = converters.find(n.intval);
|
||||
if (it != converters.end())
|
||||
{
|
||||
it->second->read(esm);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (unknownRecords.insert(n.val).second)
|
||||
if (unknownRecords.insert(n.intval).second)
|
||||
{
|
||||
std::ios::fmtflags f(std::cerr.flags());
|
||||
std::cerr << "unknown record " << n.toString() << " (0x" << std::hex << esm.getFileOffset() << ")" << std::endl;
|
||||
|
@ -422,6 +423,10 @@ namespace ESSImport
|
|||
writer.startRecord (ESM::REC_DIAS);
|
||||
context.mDialogueState.save(writer);
|
||||
writer.endRecord(ESM::REC_DIAS);
|
||||
|
||||
writer.startRecord(ESM::REC_INPU);
|
||||
context.mControlsState.save(writer);
|
||||
writer.endRecord(ESM::REC_INPU);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <components/esm/globalmap.hpp>
|
||||
#include <components/esm/loadcrea.hpp>
|
||||
#include <components/esm/loadnpc.hpp>
|
||||
#include <components/esm/controlsstate.hpp>
|
||||
|
||||
#include "importnpcc.hpp"
|
||||
#include "importcrec.hpp"
|
||||
|
@ -32,6 +33,8 @@ namespace ESSImport
|
|||
|
||||
ESM::DialogueState mDialogueState;
|
||||
|
||||
ESM::ControlsState mControlsState;
|
||||
|
||||
// cells which should show an explored overlay on the global map
|
||||
std::set<std::pair<int, int> > mExploredCells;
|
||||
|
||||
|
@ -59,10 +62,14 @@ namespace ESSImport
|
|||
playerCellId.mPaged = true;
|
||||
playerCellId.mIndex.mX = playerCellId.mIndex.mY = 0;
|
||||
mPlayer.mCellId = playerCellId;
|
||||
//mPlayer.mLastKnownExteriorPosition
|
||||
mPlayer.mHasMark = 0; // TODO
|
||||
mPlayer.mLastKnownExteriorPosition[0]
|
||||
= mPlayer.mLastKnownExteriorPosition[1]
|
||||
= mPlayer.mLastKnownExteriorPosition[2]
|
||||
= 0.0f;
|
||||
mPlayer.mHasMark = 0;
|
||||
mPlayer.mCurrentCrimeId = 0; // TODO
|
||||
mPlayer.mObject.blank();
|
||||
mPlayer.mObject.mEnabled = true;
|
||||
mPlayer.mObject.mRef.mRefID = "player"; // REFR.mRefID would be PlayerSaveGame
|
||||
|
||||
mGlobalMapState.mBounds.mMinX = 0;
|
||||
|
|
|
@ -21,13 +21,18 @@ namespace ESSImport
|
|||
item.mCount = contItem.mCount;
|
||||
item.mRelativeEquipmentSlot = -1;
|
||||
|
||||
// seems that a stack of items can have a set of subrecords for each item? rings0000.ess
|
||||
// doesn't make any sense to me, if the values were different then the items shouldn't stack in the first place?
|
||||
// I guess we should double check the stacking logic in OpenMW
|
||||
for (int i=0;i<std::abs(item.mCount);++i)
|
||||
unsigned int itemCount = std::abs(item.mCount);
|
||||
bool separateStacks = false;
|
||||
for (unsigned int i=0;i<itemCount;++i)
|
||||
{
|
||||
if (esm.isNextSub("XIDX")) // index in the stack?
|
||||
esm.skipHSub();
|
||||
bool newStack = esm.isNextSub("XIDX");
|
||||
if (newStack)
|
||||
{
|
||||
unsigned int idx;
|
||||
esm.getHT(idx);
|
||||
separateStacks = true;
|
||||
item.mCount = 1;
|
||||
}
|
||||
|
||||
item.mSCRI.load(esm);
|
||||
|
||||
|
@ -38,9 +43,13 @@ namespace ESSImport
|
|||
int charge=-1;
|
||||
esm.getHNOT(charge, "XHLT");
|
||||
item.mChargeInt = charge;
|
||||
|
||||
if (newStack)
|
||||
mItems.push_back(item);
|
||||
}
|
||||
|
||||
mItems.push_back(item);
|
||||
if (!separateStacks)
|
||||
mItems.push_back(item);
|
||||
}
|
||||
|
||||
// equipped items
|
||||
|
|
|
@ -23,9 +23,12 @@ namespace ESSImport
|
|||
mKnownDialogueTopics.push_back(esm.getHString());
|
||||
}
|
||||
|
||||
mHasMark = false;
|
||||
if (esm.isNextSub("MNAM"))
|
||||
esm.skipHSub(); // If this field is here it seems to specify the interior cell the player is in,
|
||||
// but it's not always here, so it's kinda useless
|
||||
{
|
||||
mHasMark = true;
|
||||
mMNAM = esm.getHString();
|
||||
}
|
||||
|
||||
esm.getHNT(mPNAM, "PNAM");
|
||||
|
||||
|
@ -34,6 +37,14 @@ namespace ESSImport
|
|||
if (esm.isNextSub("NAM9"))
|
||||
esm.skipHSub();
|
||||
|
||||
// Rest state. You shouldn't even be able to save during rest, but skip just in case.
|
||||
if (esm.isNextSub("RNAM"))
|
||||
/*
|
||||
int hoursLeft;
|
||||
float x, y, z; // resting position
|
||||
*/
|
||||
esm.skipHSub(); // 16 bytes
|
||||
|
||||
mBounty = 0;
|
||||
esm.getHNOT(mBounty, "CNAM");
|
||||
|
||||
|
@ -50,8 +61,12 @@ namespace ESSImport
|
|||
if (esm.isNextSub("NAM3"))
|
||||
esm.skipHSub();
|
||||
|
||||
mHasENAM = false;
|
||||
if (esm.isNextSub("ENAM"))
|
||||
esm.skipHSub();
|
||||
{
|
||||
mHasENAM = true;
|
||||
esm.getHT(mENAM);
|
||||
}
|
||||
|
||||
if (esm.isNextSub("LNAM"))
|
||||
esm.skipHSub();
|
||||
|
@ -63,12 +78,19 @@ namespace ESSImport
|
|||
mFactions.push_back(fnam);
|
||||
}
|
||||
|
||||
if (esm.isNextSub("AADT"))
|
||||
esm.skipHSub(); // 44 bytes, no clue
|
||||
mHasAADT = false;
|
||||
if (esm.isNextSub("AADT")) // Attack animation data?
|
||||
{
|
||||
mHasAADT = true;
|
||||
esm.getHT(mAADT);
|
||||
}
|
||||
|
||||
if (esm.isNextSub("KNAM"))
|
||||
esm.skipHSub(); // assigned Quick Keys, I think
|
||||
|
||||
if (esm.isNextSub("ANIS"))
|
||||
esm.skipHSub(); // 16 bytes
|
||||
|
||||
if (esm.isNextSub("WERE"))
|
||||
{
|
||||
// some werewolf data, 152 bytes
|
||||
|
@ -76,10 +98,6 @@ namespace ESSImport
|
|||
esm.getSubHeader();
|
||||
esm.skip(152);
|
||||
}
|
||||
|
||||
// unsure if before or after WERE
|
||||
if (esm.isNextSub("ANIS"))
|
||||
esm.skipHSub();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -38,15 +38,23 @@ struct PCDT
|
|||
|
||||
std::vector<std::string> mKnownDialogueTopics;
|
||||
|
||||
enum DrawState_
|
||||
enum PlayerFlags
|
||||
{
|
||||
DrawState_Weapon = 0x80,
|
||||
DrawState_Spell = 0x100
|
||||
};
|
||||
enum CameraState
|
||||
{
|
||||
CameraState_FirstPerson = 0x8,
|
||||
CameraState_ThirdPerson = 0xa
|
||||
PlayerFlags_ViewSwitchDisabled = 0x1,
|
||||
PlayerFlags_ControlsDisabled = 0x4,
|
||||
PlayerFlags_Sleeping = 0x10,
|
||||
PlayerFlags_Waiting = 0x40,
|
||||
PlayerFlags_WeaponDrawn = 0x80,
|
||||
PlayerFlags_SpellDrawn = 0x100,
|
||||
PlayerFlags_InJail = 0x200,
|
||||
PlayerFlags_JumpingDisabled = 0x1000,
|
||||
PlayerFlags_LookingDisabled = 0x2000,
|
||||
PlayerFlags_VanityModeDisabled = 0x4000,
|
||||
PlayerFlags_WeaponDrawingDisabled = 0x8000,
|
||||
PlayerFlags_SpellDrawingDisabled = 0x10000,
|
||||
PlayerFlags_ThirdPerson = 0x20000,
|
||||
PlayerFlags_TeleportingDisabled = 0x40000,
|
||||
PlayerFlags_LevitationDisabled = 0x80000
|
||||
};
|
||||
|
||||
#pragma pack(push)
|
||||
|
@ -63,18 +71,53 @@ struct PCDT
|
|||
|
||||
struct PNAM
|
||||
{
|
||||
short mDrawState; // DrawState
|
||||
short mCameraState; // CameraState
|
||||
struct MarkLocation
|
||||
{
|
||||
float mX, mY, mZ; // worldspace position
|
||||
float mRotZ; // Z angle in radians
|
||||
int mCellX, mCellY; // grid coordinates; for interior cells this is always (0, 0)
|
||||
};
|
||||
|
||||
int mPlayerFlags; // controls, camera and draw state
|
||||
unsigned int mLevelProgress;
|
||||
float mSkillProgress[27]; // skill progress, non-uniform scaled
|
||||
unsigned char mSkillIncreases[8]; // number of skill increases for each attribute
|
||||
unsigned char mUnknown3[88];
|
||||
int mTelekinesisRangeBonus; // in units; seems redundant
|
||||
float mVisionBonus; // range: <0.0, 1.0>; affected by light spells and Get/Mod/SetPCVisionBonus
|
||||
int mDetectKeyMagnitude; // seems redundant
|
||||
int mDetectEnchantmentMagnitude; // seems redundant
|
||||
int mDetectAnimalMagnitude; // seems redundant
|
||||
MarkLocation mMarkLocation;
|
||||
unsigned char mUnknown3[40];
|
||||
unsigned char mSpecIncreases[3]; // number of skill increases for each specialization
|
||||
unsigned char mUnknown4;
|
||||
};
|
||||
|
||||
struct ENAM
|
||||
{
|
||||
int mCellX;
|
||||
int mCellY;
|
||||
};
|
||||
|
||||
struct AADT // 44 bytes
|
||||
{
|
||||
int animGroupIndex; // See convertANIS() for the mapping.
|
||||
unsigned char mUnknown5[40];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
std::vector<FNAM> mFactions;
|
||||
PNAM mPNAM;
|
||||
|
||||
bool mHasMark;
|
||||
std::string mMNAM; // mark cell name; can also be sDefaultCellname or region name
|
||||
|
||||
bool mHasENAM;
|
||||
ENAM mENAM; // last exterior cell
|
||||
|
||||
bool mHasAADT;
|
||||
AADT mAADT;
|
||||
|
||||
void load(ESM::ESMReader& esm);
|
||||
};
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace ESM
|
|||
namespace ESSImport
|
||||
{
|
||||
|
||||
/// Local variable assigments for a running script
|
||||
/// Local variable assignments for a running script
|
||||
struct SCRI
|
||||
{
|
||||
std::string mScript;
|
||||
|
|
|
@ -87,6 +87,10 @@ add_executable(openmw-launcher
|
|||
${UI_HDRS}
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
INSTALL(TARGETS openmw-launcher RUNTIME DESTINATION ".")
|
||||
endif (WIN32)
|
||||
|
||||
target_link_libraries(openmw-launcher
|
||||
${SDL2_LIBRARY_ONLY}
|
||||
components
|
||||
|
|
|
@ -35,14 +35,6 @@ int main(int argc, char *argv[])
|
|||
// Now we make sure the current dir is set to application path
|
||||
QDir dir(QCoreApplication::applicationDirPath());
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
if (dir.dirName() == "MacOS") {
|
||||
dir.cdUp();
|
||||
dir.cdUp();
|
||||
dir.cdUp();
|
||||
}
|
||||
#endif
|
||||
|
||||
QDir::setCurrent(dir.absolutePath());
|
||||
|
||||
Launcher::MainDialog mainWin;
|
||||
|
|
|
@ -293,6 +293,7 @@ bool Launcher::MainDialog::setupGameSettings()
|
|||
{
|
||||
mGameSettings.clear();
|
||||
|
||||
QString localPath = QString::fromUtf8(mCfgMgr.getLocalPath().string().c_str());
|
||||
QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str());
|
||||
QString globalPath = QString::fromUtf8(mCfgMgr.getGlobalPath().string().c_str());
|
||||
|
||||
|
@ -320,13 +321,13 @@ bool Launcher::MainDialog::setupGameSettings()
|
|||
// Now the rest - priority: user > local > global
|
||||
QStringList paths;
|
||||
paths.append(globalPath + QString("openmw.cfg"));
|
||||
paths.append(QString("openmw.cfg"));
|
||||
paths.append(localPath + QString("openmw.cfg"));
|
||||
paths.append(userPath + QString("openmw.cfg"));
|
||||
|
||||
foreach (const QString &path, paths) {
|
||||
qDebug() << "Loading config file:" << path.toUtf8().constData();
|
||||
foreach (const QString &path2, paths) {
|
||||
qDebug() << "Loading config file:" << path2.toUtf8().constData();
|
||||
|
||||
QFile file(path);
|
||||
file.setFileName(path2);
|
||||
if (file.exists()) {
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
cfgError(tr("Error opening OpenMW configuration file"),
|
||||
|
@ -346,13 +347,13 @@ bool Launcher::MainDialog::setupGameSettings()
|
|||
QStringList dataDirs;
|
||||
|
||||
// Check if the paths actually contain data files
|
||||
foreach (const QString path, mGameSettings.getDataDirs()) {
|
||||
QDir dir(path);
|
||||
foreach (const QString path3, mGameSettings.getDataDirs()) {
|
||||
QDir dir(path3);
|
||||
QStringList filters;
|
||||
filters << "*.esp" << "*.esm" << "*.omwgame" << "*.omwaddon";
|
||||
|
||||
if (!dir.entryList(filters).isEmpty())
|
||||
dataDirs.append(path);
|
||||
dataDirs.append(path3);
|
||||
}
|
||||
|
||||
if (dataDirs.isEmpty())
|
||||
|
@ -579,6 +580,6 @@ void Launcher::MainDialog::play()
|
|||
|
||||
// Launch the game detached
|
||||
|
||||
if (mGameInvoker->startProcess(QLatin1String("openmw"), true))
|
||||
if (mGameInvoker->startProcess(QLatin1String("tes3mp-browser"), true))
|
||||
return qApp->quit();
|
||||
}
|
||||
|
|
|
@ -22,7 +22,8 @@ target_link_libraries(openmw-iniimporter
|
|||
if (WIN32)
|
||||
target_link_libraries(openmw-iniimporter
|
||||
${Boost_LOCALE_LIBRARY})
|
||||
endif()
|
||||
INSTALL(TARGETS openmw-iniimporter RUNTIME DESTINATION ".")
|
||||
endif(WIN32)
|
||||
|
||||
if (MINGW)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -municode")
|
||||
|
|
|
@ -824,8 +824,8 @@ void MwIniImporter::importArchives(multistrmap &cfg, const multistrmap &ini) con
|
|||
// does not appears in the ini file
|
||||
cfg["fallback-archive"].push_back("Morrowind.bsa");
|
||||
|
||||
for(std::vector<std::string>::const_iterator it=archives.begin(); it!=archives.end(); ++it) {
|
||||
cfg["fallback-archive"].push_back(*it);
|
||||
for(std::vector<std::string>::const_iterator iter=archives.begin(); iter!=archives.end(); ++iter) {
|
||||
cfg["fallback-archive"].push_back(*iter);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -865,8 +865,8 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, co
|
|||
|
||||
// this will sort files by time order first, then alphabetical (maybe), I suspect non ASCII filenames will be stuffed.
|
||||
sort(contentFiles.begin(), contentFiles.end());
|
||||
for(std::vector<std::pair<std::time_t, std::string> >::const_iterator it=contentFiles.begin(); it!=contentFiles.end(); ++it) {
|
||||
cfg["content"].push_back(it->second);
|
||||
for(std::vector<std::pair<std::time_t, std::string> >::const_iterator iter=contentFiles.begin(); iter!=contentFiles.end(); ++iter) {
|
||||
cfg["content"].push_back(iter->second);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ opencs_units_noqt (model/world
|
|||
universalid record commands columnbase columnimp scriptcontext cell refidcollection
|
||||
refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope
|
||||
pathgrid landtexture land nestedtablewrapper nestedcollection nestedcoladapterimp nestedinfocollection
|
||||
idcompletionmanager metadata defaultgmsts
|
||||
idcompletionmanager metadata defaultgmsts infoselectwrapper commandmacro
|
||||
)
|
||||
|
||||
opencs_hdrs_noqt (model/world
|
||||
|
@ -35,14 +35,14 @@ opencs_hdrs_noqt (model/world
|
|||
|
||||
|
||||
opencs_units (model/tools
|
||||
tools reportmodel mergeoperation
|
||||
tools reportmodel mergeoperation
|
||||
)
|
||||
|
||||
opencs_units_noqt (model/tools
|
||||
mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck
|
||||
birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck
|
||||
startscriptcheck search searchoperation searchstage pathgridcheck soundgencheck magiceffectcheck
|
||||
mergestages gmstcheck
|
||||
mergestages gmstcheck topicinfocheck journalcheck
|
||||
)
|
||||
|
||||
opencs_hdrs_noqt (model/tools
|
||||
|
@ -66,8 +66,8 @@ opencs_hdrs_noqt (view/doc
|
|||
|
||||
|
||||
opencs_units (view/world
|
||||
table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator
|
||||
cellcreator referenceablecreator startscriptcreator referencecreator scenesubview
|
||||
table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator globalcreator
|
||||
cellcreator pathgridcreator referenceablecreator startscriptcreator referencecreator scenesubview
|
||||
infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable
|
||||
dialoguespinbox recordbuttonbar tableeditidaction scripterrortable extendedcommandconfigurator
|
||||
)
|
||||
|
@ -85,12 +85,14 @@ opencs_units (view/widget
|
|||
|
||||
opencs_units (view/render
|
||||
scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget
|
||||
previewwidget editmode instancemode instanceselectionmode
|
||||
previewwidget editmode instancemode instanceselectionmode instancemovemode
|
||||
orbitcameramode pathgridmode selectionmode pathgridselectionmode cameracontroller
|
||||
cellwater
|
||||
)
|
||||
|
||||
opencs_units_noqt (view/render
|
||||
lighting lightingday lightingnight
|
||||
lightingbright object cell terrainstorage tagbase cellarrow
|
||||
lighting lightingday lightingnight lightingbright object cell terrainstorage tagbase
|
||||
cellarrow cellmarker cellborder pathgrid
|
||||
)
|
||||
|
||||
opencs_hdrs_noqt (view/render
|
||||
|
@ -107,11 +109,12 @@ opencs_units_noqt (view/tools
|
|||
)
|
||||
|
||||
opencs_units (view/prefs
|
||||
dialogue pagebase page
|
||||
dialogue pagebase page keybindingpage
|
||||
)
|
||||
|
||||
opencs_units (model/prefs
|
||||
state setting intsetting doublesetting boolsetting enumsetting coloursetting
|
||||
state setting intsetting doublesetting boolsetting enumsetting coloursetting shortcut
|
||||
shortcuteventhandler shortcutmanager shortcutsetting modifiersetting
|
||||
)
|
||||
|
||||
opencs_units_noqt (model/prefs
|
||||
|
@ -159,9 +162,15 @@ endif()
|
|||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
if(APPLE)
|
||||
set (OPENCS_MAC_ICON ${CMAKE_SOURCE_DIR}/files/mac/openmw-cs.icns)
|
||||
set (OPENCS_MAC_ICON "${CMAKE_SOURCE_DIR}/files/mac/openmw-cs.icns")
|
||||
set (OPENCS_CFG "${OpenMW_BINARY_DIR}/openmw-cs.cfg")
|
||||
set (OPENCS_DEFAULT_FILTERS_FILE "${OpenMW_BINARY_DIR}/resources/defaultfilters")
|
||||
set (OPENCS_OPENMW_CFG "${OpenMW_BINARY_DIR}/openmw.cfg")
|
||||
else()
|
||||
set (OPENCS_MAC_ICON "")
|
||||
set (OPENCS_CFG "")
|
||||
set (OPENCS_DEFAULT_FILTERS_FILE "")
|
||||
set (OPENCS_OPENMW_CFG "")
|
||||
endif(APPLE)
|
||||
|
||||
add_executable(openmw-cs
|
||||
|
@ -171,12 +180,23 @@ add_executable(openmw-cs
|
|||
${OPENCS_MOC_SRC}
|
||||
${OPENCS_RES_SRC}
|
||||
${OPENCS_MAC_ICON}
|
||||
${OPENCS_CFG}
|
||||
${OPENCS_DEFAULT_FILTERS_FILE}
|
||||
${OPENCS_OPENMW_CFG}
|
||||
)
|
||||
|
||||
if(APPLE)
|
||||
set(OPENCS_BUNDLE_NAME "OpenMW-CS")
|
||||
set(OPENCS_BUNDLE_RESOURCES_DIR "${OpenMW_BINARY_DIR}/${OPENCS_BUNDLE_NAME}.app/Contents/Resources")
|
||||
|
||||
set(OPENMW_MYGUI_FILES_ROOT ${OPENCS_BUNDLE_RESOURCES_DIR})
|
||||
set(OPENMW_SHADERS_ROOT ${OPENCS_BUNDLE_RESOURCES_DIR})
|
||||
|
||||
add_subdirectory(../../files/ ${CMAKE_CURRENT_BINARY_DIR}/files)
|
||||
|
||||
set_target_properties(openmw-cs PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}"
|
||||
OUTPUT_NAME "OpenMW-CS"
|
||||
OUTPUT_NAME ${OPENCS_BUNDLE_NAME}
|
||||
MACOSX_BUNDLE_ICON_FILE "openmw-cs.icns"
|
||||
MACOSX_BUNDLE_BUNDLE_NAME "OpenCS"
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER "org.openmw.opencs"
|
||||
|
@ -187,16 +207,27 @@ if(APPLE)
|
|||
|
||||
set_source_files_properties(${OPENCS_MAC_ICON} PROPERTIES
|
||||
MACOSX_PACKAGE_LOCATION Resources)
|
||||
set_source_files_properties(${OPENCS_CFG} PROPERTIES
|
||||
MACOSX_PACKAGE_LOCATION Resources)
|
||||
set_source_files_properties(${OPENCS_DEFAULT_FILTERS_FILE} PROPERTIES
|
||||
MACOSX_PACKAGE_LOCATION Resources/resources)
|
||||
set_source_files_properties(${OPENCS_OPENMW_CFG} PROPERTIES
|
||||
MACOSX_PACKAGE_LOCATION Resources)
|
||||
|
||||
add_custom_command(TARGET openmw-cs
|
||||
POST_BUILD
|
||||
COMMAND cp "${OpenMW_BINARY_DIR}/resources/version" "${OPENCS_BUNDLE_RESOURCES_DIR}/resources")
|
||||
endif(APPLE)
|
||||
|
||||
target_link_libraries(openmw-cs
|
||||
${OSG_LIBRARIES}
|
||||
${OPENTHREADS_LIBRARIES}
|
||||
${OSGTEXT_LIBRARIES}
|
||||
${OSGUTIL_LIBRARIES}
|
||||
${OSGVIEWER_LIBRARIES}
|
||||
${OSGGA_LIBRARIES}
|
||||
${OSGFX_LIBRARIES}
|
||||
${OSGQT_LIBRARIES}
|
||||
${EXTERN_OSGQT_LIBRARY}
|
||||
${Boost_SYSTEM_LIBRARY}
|
||||
${Boost_FILESYSTEM_LIBRARY}
|
||||
${Boost_PROGRAM_OPTIONS_LIBRARY}
|
||||
|
@ -219,9 +250,18 @@ endif()
|
|||
|
||||
if (WIN32)
|
||||
target_link_libraries(openmw-cs ${Boost_LOCALE_LIBRARY})
|
||||
INSTALL(TARGETS openmw-cs RUNTIME DESTINATION ".")
|
||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.cfg" DESTINATION ".")
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
# Debug version needs increased number of sections beyond 2^16
|
||||
if (CMAKE_CL_64)
|
||||
set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj")
|
||||
endif (CMAKE_CL_64)
|
||||
endif (MSVC)
|
||||
|
||||
|
||||
if(APPLE)
|
||||
INSTALL(TARGETS openmw-cs BUNDLE DESTINATION OpenMW COMPONENT BUNDLE)
|
||||
INSTALL(TARGETS openmw-cs BUNDLE DESTINATION "." COMPONENT BUNDLE)
|
||||
endif()
|
||||
|
|
90
apps/opencs/Networking.cpp
Normal file
90
apps/opencs/Networking.cpp
Normal file
|
@ -0,0 +1,90 @@
|
|||
#include "editor.hpp"
|
||||
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QIcon>
|
||||
#include <QMetaType>
|
||||
|
||||
#include "model/doc/messages.hpp"
|
||||
|
||||
#include "model/world/universalid.hpp"
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
#include <QDir>
|
||||
#endif
|
||||
|
||||
Q_DECLARE_METATYPE (std::string)
|
||||
|
||||
class Application : public QApplication
|
||||
{
|
||||
private:
|
||||
|
||||
bool notify (QObject *receiver, QEvent *event)
|
||||
{
|
||||
try
|
||||
{
|
||||
return QApplication::notify (receiver, event);
|
||||
}
|
||||
catch (const std::exception& exception)
|
||||
{
|
||||
std::cerr << "An exception has been caught: " << exception.what() << std::endl;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Application (int& argc, char *argv[]) : QApplication (argc, argv) {}
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#ifdef Q_OS_MAC
|
||||
setenv("OSG_GL_TEXTURE_STORAGE", "OFF", 0);
|
||||
#endif
|
||||
|
||||
try
|
||||
{
|
||||
// To allow background thread drawing in OSG
|
||||
QApplication::setAttribute(Qt::AA_X11InitThreads, true);
|
||||
|
||||
Q_INIT_RESOURCE (resources);
|
||||
|
||||
qRegisterMetaType<std::string> ("std::string");
|
||||
qRegisterMetaType<CSMWorld::UniversalId> ("CSMWorld::UniversalId");
|
||||
qRegisterMetaType<CSMDoc::Message> ("CSMDoc::Message");
|
||||
|
||||
Application application (argc, argv);
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
QDir dir(QCoreApplication::applicationDirPath());
|
||||
if (dir.dirName() == "MacOS") {
|
||||
dir.cdUp();
|
||||
dir.cdUp();
|
||||
dir.cdUp();
|
||||
}
|
||||
QDir::setCurrent(dir.absolutePath());
|
||||
#endif
|
||||
|
||||
application.setWindowIcon (QIcon (":./openmw-cs.png"));
|
||||
|
||||
CS::Editor editor;
|
||||
|
||||
if(!editor.makeIPCServer())
|
||||
{
|
||||
editor.connectToIPCServer();
|
||||
return 0;
|
||||
}
|
||||
return editor.run();
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cerr << "ERROR: " << e.what() << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
|
@ -62,11 +62,6 @@ int main(int argc, char *argv[])
|
|||
|
||||
#ifdef Q_OS_MAC
|
||||
QDir dir(QCoreApplication::applicationDirPath());
|
||||
if (dir.dirName() == "MacOS") {
|
||||
dir.cdUp();
|
||||
dir.cdUp();
|
||||
dir.cdUp();
|
||||
}
|
||||
QDir::setCurrent(dir.absolutePath());
|
||||
#endif
|
||||
|
||||
|
|
|
@ -274,7 +274,7 @@ CSMDoc::Document::Document (const VFS::Manager* vfs, const Files::ConfigurationM
|
|||
const Fallback::Map* fallback,
|
||||
ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager,
|
||||
const std::vector<std::string>& blacklistedScripts)
|
||||
: mVFS(vfs), mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, resourcesManager, fallback),
|
||||
: mVFS(vfs), mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, resourcesManager, fallback, resDir),
|
||||
mTools (*this, encoding),
|
||||
mProjectPath ((configuration.getUserDataPath() / "projects") /
|
||||
(savePath.filename().string() + ".project")),
|
||||
|
|
|
@ -41,6 +41,7 @@ CSMDoc::DocumentManager::DocumentManager (const Files::ConfigurationManager& con
|
|||
CSMDoc::DocumentManager::~DocumentManager()
|
||||
{
|
||||
mLoaderThread.quit();
|
||||
mLoader.stop();
|
||||
mLoader.hasThingsToDo().wakeAll();
|
||||
mLoaderThread.wait();
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "loader.hpp"
|
||||
|
||||
#include <QTimer>
|
||||
#include <iostream>
|
||||
|
||||
#include "../tools/reportmodel.hpp"
|
||||
|
||||
|
@ -11,11 +11,12 @@ CSMDoc::Loader::Stage::Stage() : mFile (0), mRecordsLoaded (0), mRecordsLeft (fa
|
|||
|
||||
|
||||
CSMDoc::Loader::Loader()
|
||||
: mShouldStop(false)
|
||||
{
|
||||
QTimer *timer = new QTimer (this);
|
||||
mTimer = new QTimer (this);
|
||||
|
||||
connect (timer, SIGNAL (timeout()), this, SLOT (load()));
|
||||
timer->start();
|
||||
connect (mTimer, SIGNAL (timeout()), this, SLOT (load()));
|
||||
mTimer->start();
|
||||
}
|
||||
|
||||
QWaitCondition& CSMDoc::Loader::hasThingsToDo()
|
||||
|
@ -23,6 +24,11 @@ QWaitCondition& CSMDoc::Loader::hasThingsToDo()
|
|||
return mThingsToDo;
|
||||
}
|
||||
|
||||
void CSMDoc::Loader::stop()
|
||||
{
|
||||
mShouldStop = true;
|
||||
}
|
||||
|
||||
void CSMDoc::Loader::load()
|
||||
{
|
||||
if (mDocuments.empty())
|
||||
|
@ -30,6 +36,10 @@ void CSMDoc::Loader::load()
|
|||
mMutex.lock();
|
||||
mThingsToDo.wait (&mMutex);
|
||||
mMutex.unlock();
|
||||
|
||||
if (mShouldStop)
|
||||
mTimer->stop();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -63,11 +73,11 @@ void CSMDoc::Loader::load()
|
|||
CSMWorld::UniversalId log (CSMWorld::UniversalId::Type_LoadErrorLog, 0);
|
||||
|
||||
{ // silence a g++ warning
|
||||
for (CSMDoc::Messages::Iterator iter (messages.begin());
|
||||
iter!=messages.end(); ++iter)
|
||||
for (CSMDoc::Messages::Iterator messageIter (messages.begin());
|
||||
messageIter!=messages.end(); ++messageIter)
|
||||
{
|
||||
document->getReport (log)->add (*iter);
|
||||
emit loadMessage (document, iter->mMessage);
|
||||
document->getReport (log)->add (*messageIter);
|
||||
emit loadMessage (document, messageIter->mMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <QObject>
|
||||
#include <QMutex>
|
||||
#include <QTimer>
|
||||
#include <QWaitCondition>
|
||||
|
||||
namespace CSMDoc
|
||||
|
@ -28,12 +29,17 @@ namespace CSMDoc
|
|||
QWaitCondition mThingsToDo;
|
||||
std::vector<std::pair<Document *, Stage> > mDocuments;
|
||||
|
||||
QTimer* mTimer;
|
||||
bool mShouldStop;
|
||||
|
||||
public:
|
||||
|
||||
Loader();
|
||||
|
||||
QWaitCondition& hasThingsToDo();
|
||||
|
||||
void stop();
|
||||
|
||||
private slots:
|
||||
|
||||
void load();
|
||||
|
|
|
@ -81,7 +81,7 @@ void CSMDoc::Runner::start (bool delayed)
|
|||
arguments << ("--script-run="+mStartup->fileName());;
|
||||
|
||||
arguments <<
|
||||
QString::fromUtf8 (("--data="+mProjectPath.parent_path().string()).c_str());
|
||||
QString::fromUtf8 (("--data=\""+mProjectPath.parent_path().string()+"\"").c_str());
|
||||
|
||||
for (std::vector<std::string>::const_iterator iter (mContentFiles.begin());
|
||||
iter!=mContentFiles.end(); ++iter)
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include "../world/infocollection.hpp"
|
||||
#include "../world/cellcoordinates.hpp"
|
||||
|
||||
#include "document.hpp"
|
||||
#include "savingstate.hpp"
|
||||
|
@ -238,7 +239,7 @@ void CSMDoc::CollectionReferencesStage::perform (int stage, Messages& messages)
|
|||
// An empty mOriginalCell is meant to indicate that it is the same as
|
||||
// the current cell. It is possible that a moved ref is moved again.
|
||||
if ((record.get().mOriginalCell.empty() ?
|
||||
record.get().mCell : record.get().mOriginalCell) != stream.str() && !interior)
|
||||
record.get().mCell : record.get().mOriginalCell) != stream.str() && !interior && record.mState!=CSMWorld::RecordBase::State_ModifiedOnly && !record.get().mNew)
|
||||
indices.push_back (i);
|
||||
else
|
||||
indices.push_front (i);
|
||||
|
@ -265,13 +266,32 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages)
|
|||
std::map<std::string, std::deque<int> >::const_iterator references =
|
||||
mState.getSubRecords().find (Misc::StringUtils::lowerCase (cell.get().mId));
|
||||
|
||||
if (cell.isModified() ||
|
||||
if (cell.isModified() ||
|
||||
cell.mState == CSMWorld::RecordBase::State_Deleted ||
|
||||
references!=mState.getSubRecords().end())
|
||||
{
|
||||
CSMWorld::Cell cellRecord = cell.get();
|
||||
bool interior = cellRecord.mId.substr (0, 1)!="#";
|
||||
|
||||
// count new references and adjust RefNumCount accordingsly
|
||||
int newRefNum = cellRecord.mRefNumCounter;
|
||||
|
||||
if (references!=mState.getSubRecords().end())
|
||||
{
|
||||
for (std::deque<int>::const_iterator iter (references->second.begin());
|
||||
iter!=references->second.end(); ++iter)
|
||||
{
|
||||
const CSMWorld::Record<CSMWorld::CellRef>& ref =
|
||||
mDocument.getData().getReferences().getRecord (*iter);
|
||||
|
||||
if (ref.get().mNew ||
|
||||
(!interior && ref.mState==CSMWorld::RecordBase::State_ModifiedOnly &&
|
||||
/// \todo consider worldspace
|
||||
CSMWorld::CellCoordinates (ref.get().getCellIndex()).getId("")!=ref.get().mCell))
|
||||
++cellRecord.mRefNumCounter;
|
||||
}
|
||||
}
|
||||
|
||||
// write cell data
|
||||
writer.startRecord (cellRecord.sRecordId);
|
||||
|
||||
|
@ -301,6 +321,10 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages)
|
|||
{
|
||||
CSMWorld::CellRef refRecord = ref.get();
|
||||
|
||||
// Check for uninitialized content file
|
||||
if (!refRecord.mRefNum.hasContentFile())
|
||||
refRecord.mRefNum.mContentFile = 0;
|
||||
|
||||
// recalculate the ref's cell location
|
||||
std::ostringstream stream;
|
||||
if (!interior)
|
||||
|
@ -309,11 +333,18 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages)
|
|||
stream << "#" << index.first << " " << index.second;
|
||||
}
|
||||
|
||||
// An empty mOriginalCell is meant to indicate that it is the same as
|
||||
// the current cell. It is possible that a moved ref is moved again.
|
||||
if ((refRecord.mOriginalCell.empty() ? refRecord.mCell : refRecord.mOriginalCell)
|
||||
if (refRecord.mNew ||
|
||||
(!interior && ref.mState==CSMWorld::RecordBase::State_ModifiedOnly &&
|
||||
refRecord.mCell!=stream.str()))
|
||||
{
|
||||
refRecord.mRefNum.mIndex = newRefNum++;
|
||||
}
|
||||
else if ((refRecord.mOriginalCell.empty() ? refRecord.mCell : refRecord.mOriginalCell)
|
||||
!= stream.str() && !interior)
|
||||
{
|
||||
// An empty mOriginalCell is meant to indicate that it is the same as
|
||||
// the current cell. It is possible that a moved ref is moved again.
|
||||
|
||||
ESM::MovedCellRef moved;
|
||||
moved.mRefNum = refRecord.mRefNum;
|
||||
|
||||
|
@ -350,7 +381,7 @@ int CSMDoc::WritePathgridCollectionStage::setup()
|
|||
void CSMDoc::WritePathgridCollectionStage::perform (int stage, Messages& messages)
|
||||
{
|
||||
ESM::ESMWriter& writer = mState.getWriter();
|
||||
const CSMWorld::Record<CSMWorld::Pathgrid>& pathgrid =
|
||||
const CSMWorld::Record<CSMWorld::Pathgrid>& pathgrid =
|
||||
mDocument.getData().getPathgrids().getRecord (stage);
|
||||
|
||||
if (pathgrid.isModified() || pathgrid.mState == CSMWorld::RecordBase::State_Deleted)
|
||||
|
@ -386,7 +417,7 @@ int CSMDoc::WriteLandCollectionStage::setup()
|
|||
void CSMDoc::WriteLandCollectionStage::perform (int stage, Messages& messages)
|
||||
{
|
||||
ESM::ESMWriter& writer = mState.getWriter();
|
||||
const CSMWorld::Record<CSMWorld::Land>& land =
|
||||
const CSMWorld::Record<CSMWorld::Land>& land =
|
||||
mDocument.getData().getLand().getRecord (stage);
|
||||
|
||||
if (land.isModified() || land.mState == CSMWorld::RecordBase::State_Deleted)
|
||||
|
@ -412,7 +443,7 @@ int CSMDoc::WriteLandTextureCollectionStage::setup()
|
|||
void CSMDoc::WriteLandTextureCollectionStage::perform (int stage, Messages& messages)
|
||||
{
|
||||
ESM::ESMWriter& writer = mState.getWriter();
|
||||
const CSMWorld::Record<CSMWorld::LandTexture>& landTexture =
|
||||
const CSMWorld::Record<CSMWorld::LandTexture>& landTexture =
|
||||
mDocument.getData().getLandTextures().getRecord (stage);
|
||||
|
||||
if (landTexture.isModified() || landTexture.mState == CSMWorld::RecordBase::State_Deleted)
|
||||
|
|
|
@ -313,7 +313,7 @@ boost::shared_ptr<CSMFilter::Node> CSMFilter::Parser::parseNAry (const Token& ke
|
|||
|
||||
nodes.push_back (node);
|
||||
|
||||
Token token = getNextToken();
|
||||
token = getNextToken();
|
||||
|
||||
if (!token || (token.mType!=Token::Type_Close && token.mType!=Token::Type_Comma))
|
||||
{
|
||||
|
|
|
@ -15,10 +15,16 @@
|
|||
CSMPrefs::DoubleSetting::DoubleSetting (Category *parent, Settings::Manager *values,
|
||||
QMutex *mutex, const std::string& key, const std::string& label, double default_)
|
||||
: Setting (parent, values, mutex, key, label),
|
||||
mMin (0), mMax (std::numeric_limits<double>::max()),
|
||||
mPrecision(2), mMin (0), mMax (std::numeric_limits<double>::max()),
|
||||
mDefault (default_)
|
||||
{}
|
||||
|
||||
CSMPrefs::DoubleSetting& CSMPrefs::DoubleSetting::setPrecision(int precision)
|
||||
{
|
||||
mPrecision = precision;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CSMPrefs::DoubleSetting& CSMPrefs::DoubleSetting::setRange (double min, double max)
|
||||
{
|
||||
mMin = min;
|
||||
|
@ -49,6 +55,7 @@ std::pair<QWidget *, QWidget *> CSMPrefs::DoubleSetting::makeWidgets (QWidget *p
|
|||
QLabel *label = new QLabel (QString::fromUtf8 (getLabel().c_str()), parent);
|
||||
|
||||
QDoubleSpinBox *widget = new QDoubleSpinBox (parent);
|
||||
widget->setDecimals(mPrecision);
|
||||
widget->setRange (mMin, mMax);
|
||||
widget->setValue (mDefault);
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ namespace CSMPrefs
|
|||
{
|
||||
Q_OBJECT
|
||||
|
||||
int mPrecision;
|
||||
double mMin;
|
||||
double mMax;
|
||||
std::string mTooltip;
|
||||
|
@ -20,6 +21,8 @@ namespace CSMPrefs
|
|||
QMutex *mutex, const std::string& key, const std::string& label,
|
||||
double default_);
|
||||
|
||||
DoubleSetting& setPrecision (int precision);
|
||||
|
||||
// defaults to [0, std::numeric_limits<double>::max()]
|
||||
DoubleSetting& setRange (double min, double max);
|
||||
|
||||
|
|
147
apps/opencs/model/prefs/modifiersetting.cpp
Normal file
147
apps/opencs/model/prefs/modifiersetting.cpp
Normal file
|
@ -0,0 +1,147 @@
|
|||
#include "modifiersetting.hpp"
|
||||
|
||||
#include <QEvent>
|
||||
#include <QKeyEvent>
|
||||
#include <QLabel>
|
||||
#include <QMouseEvent>
|
||||
#include <QPushButton>
|
||||
#include <QWidget>
|
||||
|
||||
#include "state.hpp"
|
||||
#include "shortcutmanager.hpp"
|
||||
|
||||
namespace CSMPrefs
|
||||
{
|
||||
ModifierSetting::ModifierSetting(Category* parent, Settings::Manager* values, QMutex* mutex, const std::string& key,
|
||||
const std::string& label)
|
||||
: Setting(parent, values, mutex, key, label)
|
||||
, mButton(0)
|
||||
, mEditorActive(false)
|
||||
{
|
||||
}
|
||||
|
||||
std::pair<QWidget*, QWidget*> ModifierSetting::makeWidgets(QWidget* parent)
|
||||
{
|
||||
int modifier = 0;
|
||||
State::get().getShortcutManager().getModifier(getKey(), modifier);
|
||||
|
||||
QString text = QString::fromUtf8(State::get().getShortcutManager().convertToString(modifier).c_str());
|
||||
|
||||
QLabel* label = new QLabel(QString::fromUtf8(getLabel().c_str()), parent);
|
||||
QPushButton* widget = new QPushButton(text, parent);
|
||||
|
||||
widget->setCheckable(true);
|
||||
widget->installEventFilter(this);
|
||||
mButton = widget;
|
||||
|
||||
connect(widget, SIGNAL(toggled(bool)), this, SLOT(buttonToggled(bool)));
|
||||
|
||||
return std::make_pair(label, widget);
|
||||
}
|
||||
|
||||
bool ModifierSetting::eventFilter(QObject* target, QEvent* event)
|
||||
{
|
||||
if (event->type() == QEvent::KeyPress)
|
||||
{
|
||||
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
|
||||
if (keyEvent->isAutoRepeat())
|
||||
return true;
|
||||
|
||||
int mod = keyEvent->modifiers();
|
||||
int key = keyEvent->key();
|
||||
|
||||
return handleEvent(target, mod, key);
|
||||
}
|
||||
else if (event->type() == QEvent::MouseButtonPress)
|
||||
{
|
||||
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
int mod = mouseEvent->modifiers();
|
||||
int button = mouseEvent->button();
|
||||
|
||||
return handleEvent(target, mod, button);
|
||||
}
|
||||
else if (event->type() == QEvent::FocusOut)
|
||||
{
|
||||
resetState();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ModifierSetting::handleEvent(QObject* target, int mod, int value)
|
||||
{
|
||||
// For potential future exceptions
|
||||
const int Blacklist[] =
|
||||
{
|
||||
0
|
||||
};
|
||||
|
||||
const size_t BlacklistSize = sizeof(Blacklist) / sizeof(int);
|
||||
|
||||
if (!mEditorActive)
|
||||
{
|
||||
if (value == Qt::RightButton)
|
||||
{
|
||||
// Clear modifier
|
||||
int modifier = 0;
|
||||
storeValue(modifier);
|
||||
|
||||
resetState();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle blacklist
|
||||
for (size_t i = 0; i < BlacklistSize; ++i)
|
||||
{
|
||||
if (value == Blacklist[i])
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Update modifier
|
||||
int modifier = value;
|
||||
storeValue(modifier);
|
||||
|
||||
resetState();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ModifierSetting::storeValue(int modifier)
|
||||
{
|
||||
State::get().getShortcutManager().setModifier(getKey(), modifier);
|
||||
|
||||
// Convert to string and assign
|
||||
std::string value = State::get().getShortcutManager().convertToString(modifier);
|
||||
|
||||
{
|
||||
QMutexLocker lock(getMutex());
|
||||
getValues().setString(getKey(), getParent()->getKey(), value);
|
||||
}
|
||||
|
||||
getParent()->getState()->update(*this);
|
||||
}
|
||||
|
||||
void ModifierSetting::resetState()
|
||||
{
|
||||
mButton->setChecked(false);
|
||||
mEditorActive = false;
|
||||
|
||||
// Button text
|
||||
int modifier = 0;
|
||||
State::get().getShortcutManager().getModifier(getKey(), modifier);
|
||||
|
||||
QString text = QString::fromUtf8(State::get().getShortcutManager().convertToString(modifier).c_str());
|
||||
mButton->setText(text);
|
||||
}
|
||||
|
||||
void ModifierSetting::buttonToggled(bool checked)
|
||||
{
|
||||
if (checked)
|
||||
mButton->setText("Press keys or click here...");
|
||||
|
||||
mEditorActive = checked;
|
||||
}
|
||||
}
|
44
apps/opencs/model/prefs/modifiersetting.hpp
Normal file
44
apps/opencs/model/prefs/modifiersetting.hpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
#ifndef CSM_PREFS_MODIFIERSETTING_H
|
||||
#define CSM_PREFS_MODIFIERSETTING_H
|
||||
|
||||
#include <QKeySequence>
|
||||
|
||||
#include "setting.hpp"
|
||||
|
||||
class QEvent;
|
||||
class QPushButton;
|
||||
|
||||
namespace CSMPrefs
|
||||
{
|
||||
class ModifierSetting : public Setting
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
ModifierSetting(Category* parent, Settings::Manager* values, QMutex* mutex, const std::string& key,
|
||||
const std::string& label);
|
||||
|
||||
virtual std::pair<QWidget*, QWidget*> makeWidgets(QWidget* parent);
|
||||
|
||||
protected:
|
||||
|
||||
bool eventFilter(QObject* target, QEvent* event);
|
||||
|
||||
private:
|
||||
|
||||
bool handleEvent(QObject* target, int mod, int value);
|
||||
|
||||
void storeValue(int modifier);
|
||||
void resetState();
|
||||
|
||||
QPushButton* mButton;
|
||||
bool mEditorActive;
|
||||
|
||||
private slots:
|
||||
|
||||
void buttonToggled(bool checked);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
214
apps/opencs/model/prefs/shortcut.cpp
Normal file
214
apps/opencs/model/prefs/shortcut.cpp
Normal file
|
@ -0,0 +1,214 @@
|
|||
#include "shortcut.hpp"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <QAction>
|
||||
#include <QWidget>
|
||||
|
||||
#include "state.hpp"
|
||||
#include "shortcutmanager.hpp"
|
||||
|
||||
namespace CSMPrefs
|
||||
{
|
||||
Shortcut::Shortcut(const std::string& name, QWidget* parent)
|
||||
: QObject(parent)
|
||||
, mEnabled(true)
|
||||
, mName(name)
|
||||
, mModName("")
|
||||
, mSecondaryMode(SM_Ignore)
|
||||
, mModifier(0)
|
||||
, mCurrentPos(0)
|
||||
, mLastPos(0)
|
||||
, mActivationStatus(AS_Inactive)
|
||||
, mModifierStatus(false)
|
||||
, mAction(0)
|
||||
{
|
||||
assert (parent);
|
||||
|
||||
State::get().getShortcutManager().addShortcut(this);
|
||||
State::get().getShortcutManager().getSequence(name, mSequence);
|
||||
}
|
||||
|
||||
Shortcut::Shortcut(const std::string& name, const std::string& modName, QWidget* parent)
|
||||
: QObject(parent)
|
||||
, mEnabled(true)
|
||||
, mName(name)
|
||||
, mModName(modName)
|
||||
, mSecondaryMode(SM_Ignore)
|
||||
, mModifier(0)
|
||||
, mCurrentPos(0)
|
||||
, mLastPos(0)
|
||||
, mActivationStatus(AS_Inactive)
|
||||
, mModifierStatus(false)
|
||||
, mAction(0)
|
||||
{
|
||||
assert (parent);
|
||||
|
||||
State::get().getShortcutManager().addShortcut(this);
|
||||
State::get().getShortcutManager().getSequence(name, mSequence);
|
||||
State::get().getShortcutManager().getModifier(modName, mModifier);
|
||||
}
|
||||
|
||||
Shortcut::Shortcut(const std::string& name, const std::string& modName, SecondaryMode secMode, QWidget* parent)
|
||||
: QObject(parent)
|
||||
, mEnabled(true)
|
||||
, mName(name)
|
||||
, mModName(modName)
|
||||
, mSecondaryMode(secMode)
|
||||
, mModifier(0)
|
||||
, mCurrentPos(0)
|
||||
, mLastPos(0)
|
||||
, mActivationStatus(AS_Inactive)
|
||||
, mModifierStatus(false)
|
||||
, mAction(0)
|
||||
{
|
||||
assert (parent);
|
||||
|
||||
State::get().getShortcutManager().addShortcut(this);
|
||||
State::get().getShortcutManager().getSequence(name, mSequence);
|
||||
State::get().getShortcutManager().getModifier(modName, mModifier);
|
||||
}
|
||||
|
||||
Shortcut::~Shortcut()
|
||||
{
|
||||
State::get().getShortcutManager().removeShortcut(this);
|
||||
}
|
||||
|
||||
bool Shortcut::isEnabled() const
|
||||
{
|
||||
return mEnabled;
|
||||
}
|
||||
|
||||
const std::string& Shortcut::getName() const
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
const std::string& Shortcut::getModifierName() const
|
||||
{
|
||||
return mModName;
|
||||
}
|
||||
|
||||
Shortcut::SecondaryMode Shortcut::getSecondaryMode() const
|
||||
{
|
||||
return mSecondaryMode;
|
||||
}
|
||||
|
||||
const QKeySequence& Shortcut::getSequence() const
|
||||
{
|
||||
return mSequence;
|
||||
}
|
||||
|
||||
int Shortcut::getModifier() const
|
||||
{
|
||||
return mModifier;
|
||||
}
|
||||
|
||||
int Shortcut::getPosition() const
|
||||
{
|
||||
return mCurrentPos;
|
||||
}
|
||||
|
||||
int Shortcut::getLastPosition() const
|
||||
{
|
||||
return mLastPos;
|
||||
}
|
||||
|
||||
Shortcut::ActivationStatus Shortcut::getActivationStatus() const
|
||||
{
|
||||
return mActivationStatus;
|
||||
}
|
||||
|
||||
bool Shortcut::getModifierStatus() const
|
||||
{
|
||||
return mModifierStatus;
|
||||
}
|
||||
|
||||
void Shortcut::enable(bool state)
|
||||
{
|
||||
mEnabled = state;
|
||||
}
|
||||
|
||||
void Shortcut::setSequence(const QKeySequence& sequence)
|
||||
{
|
||||
mSequence = sequence;
|
||||
mCurrentPos = 0;
|
||||
mLastPos = sequence.count() - 1;
|
||||
|
||||
if (mAction)
|
||||
{
|
||||
mAction->setText(mActionText + "\t" + State::get().getShortcutManager().convertToString(mSequence).data());
|
||||
}
|
||||
}
|
||||
|
||||
void Shortcut::setModifier(int modifier)
|
||||
{
|
||||
mModifier = modifier;
|
||||
}
|
||||
|
||||
void Shortcut::setPosition(int pos)
|
||||
{
|
||||
mCurrentPos = pos;
|
||||
}
|
||||
|
||||
void Shortcut::setActivationStatus(ActivationStatus status)
|
||||
{
|
||||
mActivationStatus = status;
|
||||
}
|
||||
|
||||
void Shortcut::setModifierStatus(bool status)
|
||||
{
|
||||
mModifierStatus = status;
|
||||
}
|
||||
|
||||
void Shortcut::associateAction(QAction* action)
|
||||
{
|
||||
if (mAction)
|
||||
{
|
||||
mAction->setText(mActionText);
|
||||
|
||||
disconnect(this, SIGNAL(activated()), mAction, SLOT(trigger()));
|
||||
disconnect(mAction, SIGNAL(destroyed()), this, SLOT(actionDeleted()));
|
||||
}
|
||||
|
||||
mAction = action;
|
||||
|
||||
if (mAction)
|
||||
{
|
||||
mActionText = mAction->text();
|
||||
mAction->setText(mActionText + "\t" + State::get().getShortcutManager().convertToString(mSequence).data());
|
||||
|
||||
connect(this, SIGNAL(activated()), mAction, SLOT(trigger()));
|
||||
connect(mAction, SIGNAL(destroyed()), this, SLOT(actionDeleted()));
|
||||
}
|
||||
}
|
||||
|
||||
void Shortcut::signalActivated(bool state)
|
||||
{
|
||||
emit activated(state);
|
||||
}
|
||||
|
||||
void Shortcut::signalActivated()
|
||||
{
|
||||
emit activated();
|
||||
}
|
||||
|
||||
void Shortcut::signalSecondary(bool state)
|
||||
{
|
||||
emit secondary(state);
|
||||
}
|
||||
void Shortcut::signalSecondary()
|
||||
{
|
||||
emit secondary();
|
||||
}
|
||||
|
||||
QString Shortcut::toString() const
|
||||
{
|
||||
return QString(State::get().getShortcutManager().convertToString(mSequence, mModifier).data());
|
||||
}
|
||||
|
||||
void Shortcut::actionDeleted()
|
||||
{
|
||||
mAction = 0;
|
||||
}
|
||||
}
|
122
apps/opencs/model/prefs/shortcut.hpp
Normal file
122
apps/opencs/model/prefs/shortcut.hpp
Normal file
|
@ -0,0 +1,122 @@
|
|||
#ifndef CSM_PREFS_SHORTCUT_H
|
||||
#define CSM_PREFS_SHORTCUT_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <QKeySequence>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
class QAction;
|
||||
class QWidget;
|
||||
|
||||
namespace CSMPrefs
|
||||
{
|
||||
/// A class similar in purpose to QShortcut, but with the ability to use mouse buttons
|
||||
class Shortcut : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
enum ActivationStatus
|
||||
{
|
||||
AS_Regular,
|
||||
AS_Secondary,
|
||||
AS_Inactive
|
||||
};
|
||||
|
||||
enum SecondaryMode
|
||||
{
|
||||
SM_Replace, ///< The secondary signal replaces the regular signal when the modifier is active
|
||||
SM_Detach, ///< The secondary signal is emitted independent of the regular signal, even if not active
|
||||
SM_Ignore ///< The secondary signal will not ever be emitted
|
||||
};
|
||||
|
||||
Shortcut(const std::string& name, QWidget* parent);
|
||||
Shortcut(const std::string& name, const std::string& modName, QWidget* parent);
|
||||
Shortcut(const std::string& name, const std::string& modName, SecondaryMode secMode, QWidget* parent);
|
||||
|
||||
~Shortcut();
|
||||
|
||||
bool isEnabled() const;
|
||||
|
||||
const std::string& getName() const;
|
||||
const std::string& getModifierName() const;
|
||||
|
||||
SecondaryMode getSecondaryMode() const;
|
||||
|
||||
const QKeySequence& getSequence() const;
|
||||
int getModifier() const;
|
||||
|
||||
/// The position in the sequence
|
||||
int getPosition() const;
|
||||
/// The position in the sequence
|
||||
int getLastPosition() const;
|
||||
|
||||
ActivationStatus getActivationStatus() const;
|
||||
bool getModifierStatus() const;
|
||||
|
||||
void enable(bool state);
|
||||
|
||||
void setSequence(const QKeySequence& sequence);
|
||||
void setModifier(int modifier);
|
||||
|
||||
/// The position in the sequence
|
||||
void setPosition(int pos);
|
||||
|
||||
void setActivationStatus(ActivationStatus status);
|
||||
void setModifierStatus(bool status);
|
||||
|
||||
/// Appends the sequence to the QAction text, also keeps it up to date
|
||||
void associateAction(QAction* action);
|
||||
|
||||
// Workaround for Qt4 signals being "protected"
|
||||
void signalActivated(bool state);
|
||||
void signalActivated();
|
||||
|
||||
void signalSecondary(bool state);
|
||||
void signalSecondary();
|
||||
|
||||
QString toString() const;
|
||||
|
||||
private:
|
||||
|
||||
bool mEnabled;
|
||||
|
||||
std::string mName;
|
||||
std::string mModName;
|
||||
SecondaryMode mSecondaryMode;
|
||||
QKeySequence mSequence;
|
||||
int mModifier;
|
||||
|
||||
int mCurrentPos;
|
||||
int mLastPos;
|
||||
|
||||
ActivationStatus mActivationStatus;
|
||||
bool mModifierStatus;
|
||||
|
||||
QAction* mAction;
|
||||
QString mActionText;
|
||||
|
||||
private slots:
|
||||
|
||||
void actionDeleted();
|
||||
|
||||
signals:
|
||||
|
||||
/// Triggered when the shortcut is activated or deactivated; can be determined from \p state
|
||||
void activated(bool state);
|
||||
|
||||
/// Convenience signal.
|
||||
void activated();
|
||||
|
||||
/// Triggered depending on SecondaryMode
|
||||
void secondary(bool state);
|
||||
|
||||
/// Convenience signal.
|
||||
void secondary();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
338
apps/opencs/model/prefs/shortcuteventhandler.cpp
Normal file
338
apps/opencs/model/prefs/shortcuteventhandler.cpp
Normal file
|
@ -0,0 +1,338 @@
|
|||
#include "shortcuteventhandler.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
#include <QEvent>
|
||||
#include <QKeyEvent>
|
||||
#include <QMouseEvent>
|
||||
#include <QWidget>
|
||||
|
||||
#include "shortcut.hpp"
|
||||
|
||||
namespace CSMPrefs
|
||||
{
|
||||
ShortcutEventHandler::ShortcutEventHandler(QObject* parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void ShortcutEventHandler::addShortcut(Shortcut* shortcut)
|
||||
{
|
||||
// Enforced by shortcut class
|
||||
QWidget* widget = static_cast<QWidget*>(shortcut->parent());
|
||||
|
||||
// Check if widget setup is needed
|
||||
ShortcutMap::iterator shortcutListIt = mWidgetShortcuts.find(widget);
|
||||
if (shortcutListIt == mWidgetShortcuts.end())
|
||||
{
|
||||
// Create list
|
||||
shortcutListIt = mWidgetShortcuts.insert(std::make_pair(widget, ShortcutList())).first;
|
||||
|
||||
// Check if widget has a parent with shortcuts, unfortunately it is not typically set yet
|
||||
updateParent(widget);
|
||||
|
||||
// Intercept widget events
|
||||
widget->installEventFilter(this);
|
||||
connect(widget, SIGNAL(destroyed()), this, SLOT(widgetDestroyed()));
|
||||
}
|
||||
|
||||
// Add to list
|
||||
shortcutListIt->second.push_back(shortcut);
|
||||
}
|
||||
|
||||
void ShortcutEventHandler::removeShortcut(Shortcut* shortcut)
|
||||
{
|
||||
// Enforced by shortcut class
|
||||
QWidget* widget = static_cast<QWidget*>(shortcut->parent());
|
||||
|
||||
ShortcutMap::iterator shortcutListIt = mWidgetShortcuts.find(widget);
|
||||
if (shortcutListIt != mWidgetShortcuts.end())
|
||||
{
|
||||
std::remove(shortcutListIt->second.begin(), shortcutListIt->second.end(), shortcut);
|
||||
}
|
||||
}
|
||||
|
||||
bool ShortcutEventHandler::eventFilter(QObject* watched, QEvent* event)
|
||||
{
|
||||
// Process event
|
||||
if (event->type() == QEvent::KeyPress)
|
||||
{
|
||||
QWidget* widget = static_cast<QWidget*>(watched);
|
||||
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
|
||||
unsigned int mod = (unsigned int) keyEvent->modifiers();
|
||||
unsigned int key = (unsigned int) keyEvent->key();
|
||||
|
||||
if (!keyEvent->isAutoRepeat())
|
||||
return activate(widget, mod, key);
|
||||
}
|
||||
else if (event->type() == QEvent::KeyRelease)
|
||||
{
|
||||
QWidget* widget = static_cast<QWidget*>(watched);
|
||||
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
|
||||
unsigned int mod = (unsigned int) keyEvent->modifiers();
|
||||
unsigned int key = (unsigned int) keyEvent->key();
|
||||
|
||||
if (!keyEvent->isAutoRepeat())
|
||||
return deactivate(widget, mod, key);
|
||||
}
|
||||
else if (event->type() == QEvent::MouseButtonPress)
|
||||
{
|
||||
QWidget* widget = static_cast<QWidget*>(watched);
|
||||
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
unsigned int mod = (unsigned int) mouseEvent->modifiers();
|
||||
unsigned int button = (unsigned int) mouseEvent->button();
|
||||
|
||||
return activate(widget, mod, button);
|
||||
}
|
||||
else if (event->type() == QEvent::MouseButtonRelease)
|
||||
{
|
||||
QWidget* widget = static_cast<QWidget*>(watched);
|
||||
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
unsigned int mod = (unsigned int) mouseEvent->modifiers();
|
||||
unsigned int button = (unsigned int) mouseEvent->button();
|
||||
|
||||
return deactivate(widget, mod, button);
|
||||
}
|
||||
else if (event->type() == QEvent::FocusOut)
|
||||
{
|
||||
QWidget* widget = static_cast<QWidget*>(watched);
|
||||
ShortcutMap::iterator shortcutListIt = mWidgetShortcuts.find(widget);
|
||||
|
||||
// Deactivate in case events are missed
|
||||
for (ShortcutList::iterator it = shortcutListIt->second.begin(); it != shortcutListIt->second.end(); ++it)
|
||||
{
|
||||
Shortcut* shortcut = *it;
|
||||
|
||||
shortcut->setPosition(0);
|
||||
shortcut->setModifierStatus(false);
|
||||
|
||||
if (shortcut->getActivationStatus() == Shortcut::AS_Regular)
|
||||
{
|
||||
shortcut->setActivationStatus(Shortcut::AS_Inactive);
|
||||
shortcut->signalActivated(false);
|
||||
}
|
||||
else if (shortcut->getActivationStatus() == Shortcut::AS_Secondary)
|
||||
{
|
||||
shortcut->setActivationStatus(Shortcut::AS_Inactive);
|
||||
shortcut->signalSecondary(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (event->type() == QEvent::FocusIn)
|
||||
{
|
||||
QWidget* widget = static_cast<QWidget*>(watched);
|
||||
updateParent(widget);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ShortcutEventHandler::updateParent(QWidget* widget)
|
||||
{
|
||||
QWidget* parent = widget->parentWidget();
|
||||
while (parent)
|
||||
{
|
||||
ShortcutMap::iterator parentIt = mWidgetShortcuts.find(parent);
|
||||
if (parentIt != mWidgetShortcuts.end())
|
||||
{
|
||||
mChildParentRelations.insert(std::make_pair(widget, parent));
|
||||
updateParent(parent);
|
||||
break;
|
||||
}
|
||||
|
||||
// Check next
|
||||
parent = parent->parentWidget();
|
||||
}
|
||||
}
|
||||
|
||||
bool ShortcutEventHandler::activate(QWidget* widget, unsigned int mod, unsigned int button)
|
||||
{
|
||||
std::vector<std::pair<MatchResult, Shortcut*> > potentials;
|
||||
bool used = false;
|
||||
|
||||
while (widget)
|
||||
{
|
||||
ShortcutMap::iterator shortcutListIt = mWidgetShortcuts.find(widget);
|
||||
assert(shortcutListIt != mWidgetShortcuts.end());
|
||||
|
||||
// Find potential activations
|
||||
for (ShortcutList::iterator it = shortcutListIt->second.begin(); it != shortcutListIt->second.end(); ++it)
|
||||
{
|
||||
Shortcut* shortcut = *it;
|
||||
|
||||
if (!shortcut->isEnabled())
|
||||
continue;
|
||||
|
||||
if (checkModifier(mod, button, shortcut, true))
|
||||
used = true;
|
||||
|
||||
if (shortcut->getActivationStatus() != Shortcut::AS_Inactive)
|
||||
continue;
|
||||
|
||||
int pos = shortcut->getPosition();
|
||||
int lastPos = shortcut->getLastPosition();
|
||||
MatchResult result = match(mod, button, shortcut->getSequence()[pos]);
|
||||
|
||||
if (result == Matches_WithMod || result == Matches_NoMod)
|
||||
{
|
||||
if (pos < lastPos && (result == Matches_WithMod || pos > 0))
|
||||
{
|
||||
shortcut->setPosition(pos+1);
|
||||
}
|
||||
else if (pos == lastPos)
|
||||
{
|
||||
potentials.push_back(std::make_pair(result, shortcut));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Move on to parent
|
||||
WidgetMap::iterator widgetIt = mChildParentRelations.find(widget);
|
||||
widget = (widgetIt != mChildParentRelations.end()) ? widgetIt->second : 0;
|
||||
}
|
||||
|
||||
// Only activate the best match; in exact conflicts, this will favor the first shortcut added.
|
||||
if (!potentials.empty())
|
||||
{
|
||||
std::sort(potentials.begin(), potentials.end(), ShortcutEventHandler::sort);
|
||||
Shortcut* shortcut = potentials.front().second;
|
||||
|
||||
if (shortcut->getModifierStatus() && shortcut->getSecondaryMode() == Shortcut::SM_Replace)
|
||||
{
|
||||
shortcut->setActivationStatus(Shortcut::AS_Secondary);
|
||||
shortcut->signalSecondary(true);
|
||||
shortcut->signalSecondary();
|
||||
}
|
||||
else
|
||||
{
|
||||
shortcut->setActivationStatus(Shortcut::AS_Regular);
|
||||
shortcut->signalActivated(true);
|
||||
shortcut->signalActivated();
|
||||
}
|
||||
|
||||
used = true;
|
||||
}
|
||||
|
||||
return used;
|
||||
}
|
||||
|
||||
bool ShortcutEventHandler::deactivate(QWidget* widget, unsigned int mod, unsigned int button)
|
||||
{
|
||||
const int KeyMask = 0x01FFFFFF;
|
||||
|
||||
bool used = false;
|
||||
|
||||
while (widget)
|
||||
{
|
||||
ShortcutMap::iterator shortcutListIt = mWidgetShortcuts.find(widget);
|
||||
assert(shortcutListIt != mWidgetShortcuts.end());
|
||||
|
||||
for (ShortcutList::iterator it = shortcutListIt->second.begin(); it != shortcutListIt->second.end(); ++it)
|
||||
{
|
||||
Shortcut* shortcut = *it;
|
||||
|
||||
if (checkModifier(mod, button, shortcut, false))
|
||||
used = true;
|
||||
|
||||
int pos = shortcut->getPosition();
|
||||
MatchResult result = match(0, button, shortcut->getSequence()[pos] & KeyMask);
|
||||
|
||||
if (result != Matches_Not)
|
||||
{
|
||||
shortcut->setPosition(0);
|
||||
|
||||
if (shortcut->getActivationStatus() == Shortcut::AS_Regular)
|
||||
{
|
||||
shortcut->setActivationStatus(Shortcut::AS_Inactive);
|
||||
shortcut->signalActivated(false);
|
||||
used = true;
|
||||
}
|
||||
else if (shortcut->getActivationStatus() == Shortcut::AS_Secondary)
|
||||
{
|
||||
shortcut->setActivationStatus(Shortcut::AS_Inactive);
|
||||
shortcut->signalSecondary(false);
|
||||
used = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Move on to parent
|
||||
WidgetMap::iterator widgetIt = mChildParentRelations.find(widget);
|
||||
widget = (widgetIt != mChildParentRelations.end()) ? widgetIt->second : 0;
|
||||
}
|
||||
|
||||
return used;
|
||||
}
|
||||
|
||||
bool ShortcutEventHandler::checkModifier(unsigned int mod, unsigned int button, Shortcut* shortcut, bool activate)
|
||||
{
|
||||
if (!shortcut->isEnabled() || !shortcut->getModifier() || shortcut->getSecondaryMode() == Shortcut::SM_Ignore ||
|
||||
shortcut->getModifierStatus() == activate)
|
||||
return false;
|
||||
|
||||
MatchResult result = match(mod, button, shortcut->getModifier());
|
||||
bool used = false;
|
||||
|
||||
if (result != Matches_Not)
|
||||
{
|
||||
shortcut->setModifierStatus(activate);
|
||||
|
||||
if (shortcut->getSecondaryMode() == Shortcut::SM_Detach)
|
||||
{
|
||||
if (activate)
|
||||
{
|
||||
shortcut->signalSecondary(true);
|
||||
shortcut->signalSecondary();
|
||||
}
|
||||
else
|
||||
{
|
||||
shortcut->signalSecondary(false);
|
||||
}
|
||||
}
|
||||
else if (!activate && shortcut->getActivationStatus() == Shortcut::AS_Secondary)
|
||||
{
|
||||
shortcut->setActivationStatus(Shortcut::AS_Inactive);
|
||||
shortcut->setPosition(0);
|
||||
shortcut->signalSecondary(false);
|
||||
used = true;
|
||||
}
|
||||
}
|
||||
|
||||
return used;
|
||||
}
|
||||
|
||||
ShortcutEventHandler::MatchResult ShortcutEventHandler::match(unsigned int mod, unsigned int button,
|
||||
unsigned int value)
|
||||
{
|
||||
if ((mod | button) == value)
|
||||
{
|
||||
return Matches_WithMod;
|
||||
}
|
||||
else if (button == value)
|
||||
{
|
||||
return Matches_NoMod;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Matches_Not;
|
||||
}
|
||||
}
|
||||
|
||||
bool ShortcutEventHandler::sort(const std::pair<MatchResult, Shortcut*>& left,
|
||||
const std::pair<MatchResult, Shortcut*>& right)
|
||||
{
|
||||
if (left.first == Matches_WithMod && right.first == Matches_NoMod)
|
||||
return true;
|
||||
else
|
||||
return left.second->getPosition() >= right.second->getPosition();
|
||||
}
|
||||
|
||||
void ShortcutEventHandler::widgetDestroyed()
|
||||
{
|
||||
QWidget* widget = static_cast<QWidget*>(sender());
|
||||
|
||||
mWidgetShortcuts.erase(widget);
|
||||
mChildParentRelations.erase(widget);
|
||||
}
|
||||
}
|
69
apps/opencs/model/prefs/shortcuteventhandler.hpp
Normal file
69
apps/opencs/model/prefs/shortcuteventhandler.hpp
Normal file
|
@ -0,0 +1,69 @@
|
|||
#ifndef CSM_PREFS_SHORTCUT_EVENT_HANDLER_H
|
||||
#define CSM_PREFS_SHORTCUT_EVENT_HANDLER_H
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class QEvent;
|
||||
class QWidget;
|
||||
|
||||
namespace CSMPrefs
|
||||
{
|
||||
class Shortcut;
|
||||
|
||||
/// Users of this class should install it as an event handler
|
||||
class ShortcutEventHandler : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
ShortcutEventHandler(QObject* parent);
|
||||
|
||||
void addShortcut(Shortcut* shortcut);
|
||||
void removeShortcut(Shortcut* shortcut);
|
||||
|
||||
protected:
|
||||
|
||||
bool eventFilter(QObject* watched, QEvent* event);
|
||||
|
||||
private:
|
||||
|
||||
typedef std::vector<Shortcut*> ShortcutList;
|
||||
// Child, Parent
|
||||
typedef std::map<QWidget*, QWidget*> WidgetMap;
|
||||
typedef std::map<QWidget*, ShortcutList> ShortcutMap;
|
||||
|
||||
enum MatchResult
|
||||
{
|
||||
Matches_WithMod,
|
||||
Matches_NoMod,
|
||||
Matches_Not
|
||||
};
|
||||
|
||||
void updateParent(QWidget* widget);
|
||||
|
||||
bool activate(QWidget* widget, unsigned int mod, unsigned int button);
|
||||
|
||||
bool deactivate(QWidget* widget, unsigned int mod, unsigned int button);
|
||||
|
||||
bool checkModifier(unsigned int mod, unsigned int button, Shortcut* shortcut, bool activate);
|
||||
|
||||
MatchResult match(unsigned int mod, unsigned int button, unsigned int value);
|
||||
|
||||
// Prefers Matches_WithMod and a larger number of buttons
|
||||
static bool sort(const std::pair<MatchResult, Shortcut*>& left,
|
||||
const std::pair<MatchResult, Shortcut*>& right);
|
||||
|
||||
WidgetMap mChildParentRelations;
|
||||
ShortcutMap mWidgetShortcuts;
|
||||
|
||||
private slots:
|
||||
|
||||
void widgetDestroyed();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
791
apps/opencs/model/prefs/shortcutmanager.cpp
Normal file
791
apps/opencs/model/prefs/shortcutmanager.cpp
Normal file
|
@ -0,0 +1,791 @@
|
|||
#include "shortcutmanager.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QStringList>
|
||||
|
||||
#include "shortcut.hpp"
|
||||
#include "shortcuteventhandler.hpp"
|
||||
|
||||
namespace CSMPrefs
|
||||
{
|
||||
ShortcutManager::ShortcutManager()
|
||||
{
|
||||
createLookupTables();
|
||||
mEventHandler = new ShortcutEventHandler(this);
|
||||
}
|
||||
|
||||
void ShortcutManager::addShortcut(Shortcut* shortcut)
|
||||
{
|
||||
mShortcuts.insert(std::make_pair(shortcut->getName(), shortcut));
|
||||
mShortcuts.insert(std::make_pair(shortcut->getModifierName(), shortcut));
|
||||
mEventHandler->addShortcut(shortcut);
|
||||
}
|
||||
|
||||
void ShortcutManager::removeShortcut(Shortcut* shortcut)
|
||||
{
|
||||
std::pair<ShortcutMap::iterator, ShortcutMap::iterator> range = mShortcuts.equal_range(shortcut->getName());
|
||||
|
||||
for (ShortcutMap::iterator it = range.first; it != range.second;)
|
||||
{
|
||||
if (it->second == shortcut)
|
||||
{
|
||||
mShortcuts.erase(it++);
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
mEventHandler->removeShortcut(shortcut);
|
||||
}
|
||||
|
||||
bool ShortcutManager::getSequence(const std::string& name, QKeySequence& sequence) const
|
||||
{
|
||||
SequenceMap::const_iterator item = mSequences.find(name);
|
||||
if (item != mSequences.end())
|
||||
{
|
||||
sequence = item->second;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void ShortcutManager::setSequence(const std::string& name, const QKeySequence& sequence)
|
||||
{
|
||||
// Add to map/modify
|
||||
SequenceMap::iterator item = mSequences.find(name);
|
||||
if (item != mSequences.end())
|
||||
{
|
||||
item->second = sequence;
|
||||
}
|
||||
else
|
||||
{
|
||||
mSequences.insert(std::make_pair(name, sequence));
|
||||
}
|
||||
|
||||
// Change active shortcuts
|
||||
std::pair<ShortcutMap::iterator, ShortcutMap::iterator> rangeS = mShortcuts.equal_range(name);
|
||||
|
||||
for (ShortcutMap::iterator it = rangeS.first; it != rangeS.second; ++it)
|
||||
{
|
||||
it->second->setSequence(sequence);
|
||||
}
|
||||
}
|
||||
|
||||
bool ShortcutManager::getModifier(const std::string& name, int& modifier) const
|
||||
{
|
||||
ModifierMap::const_iterator item = mModifiers.find(name);
|
||||
if (item != mModifiers.end())
|
||||
{
|
||||
modifier = item->second;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void ShortcutManager::setModifier(const std::string& name, int modifier)
|
||||
{
|
||||
// Add to map/modify
|
||||
ModifierMap::iterator item = mModifiers.find(name);
|
||||
if (item != mModifiers.end())
|
||||
{
|
||||
item->second = modifier;
|
||||
}
|
||||
else
|
||||
{
|
||||
mModifiers.insert(std::make_pair(name, modifier));
|
||||
}
|
||||
|
||||
// Change active shortcuts
|
||||
std::pair<ShortcutMap::iterator, ShortcutMap::iterator> rangeS = mShortcuts.equal_range(name);
|
||||
|
||||
for (ShortcutMap::iterator it = rangeS.first; it != rangeS.second; ++it)
|
||||
{
|
||||
it->second->setModifier(modifier);
|
||||
}
|
||||
}
|
||||
|
||||
std::string ShortcutManager::convertToString(const QKeySequence& sequence) const
|
||||
{
|
||||
const int MouseKeyMask = 0x01FFFFFF;
|
||||
const int ModMask = 0x7E000000;
|
||||
|
||||
std::string result;
|
||||
|
||||
for (int i = 0; i < (int)sequence.count(); ++i)
|
||||
{
|
||||
int mods = sequence[i] & ModMask;
|
||||
int key = sequence[i] & MouseKeyMask;
|
||||
|
||||
if (key)
|
||||
{
|
||||
NameMap::const_iterator searchResult = mNames.find(key);
|
||||
if (searchResult != mNames.end())
|
||||
{
|
||||
if (mods && i == 0)
|
||||
{
|
||||
if (mods & Qt::ControlModifier)
|
||||
result.append("Ctl+");
|
||||
if (mods & Qt::ShiftModifier)
|
||||
result.append("Shift+");
|
||||
if (mods & Qt::AltModifier)
|
||||
result.append("Alt+");
|
||||
if (mods & Qt::MetaModifier)
|
||||
result.append("Meta+");
|
||||
if (mods & Qt::KeypadModifier)
|
||||
result.append("Keypad+");
|
||||
if (mods & Qt::GroupSwitchModifier)
|
||||
result.append("GroupSwitch+");
|
||||
}
|
||||
else if (i > 0)
|
||||
{
|
||||
result.append("+");
|
||||
}
|
||||
|
||||
result.append(searchResult->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string ShortcutManager::convertToString(int modifier) const
|
||||
{
|
||||
NameMap::const_iterator searchResult = mNames.find(modifier);
|
||||
if (searchResult != mNames.end())
|
||||
{
|
||||
return searchResult->second;
|
||||
}
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string ShortcutManager::convertToString(const QKeySequence& sequence, int modifier) const
|
||||
{
|
||||
std::string concat = convertToString(sequence) + ";" + convertToString(modifier);
|
||||
return concat;
|
||||
}
|
||||
|
||||
void ShortcutManager::convertFromString(const std::string& data, QKeySequence& sequence) const
|
||||
{
|
||||
const int MaxKeys = 4; // A limitation of QKeySequence
|
||||
|
||||
size_t end = data.find(";");
|
||||
size_t size = std::min(end, data.size());
|
||||
|
||||
std::string value = data.substr(0, size);
|
||||
size_t start = 0;
|
||||
|
||||
int keyPos = 0;
|
||||
int mods = 0;
|
||||
|
||||
int keys[MaxKeys] = {};
|
||||
|
||||
while (start < value.size())
|
||||
{
|
||||
end = data.find("+", start);
|
||||
end = std::min(end, value.size());
|
||||
|
||||
std::string name = value.substr(start, end - start);
|
||||
|
||||
if (name == "Ctl")
|
||||
{
|
||||
mods |= Qt::ControlModifier;
|
||||
}
|
||||
else if (name == "Shift")
|
||||
{
|
||||
mods |= Qt::ShiftModifier;
|
||||
}
|
||||
else if (name == "Alt")
|
||||
{
|
||||
mods |= Qt::AltModifier;
|
||||
}
|
||||
else if (name == "Meta")
|
||||
{
|
||||
mods |= Qt::MetaModifier;
|
||||
}
|
||||
else if (name == "Keypad")
|
||||
{
|
||||
mods |= Qt::KeypadModifier;
|
||||
}
|
||||
else if (name == "GroupSwitch")
|
||||
{
|
||||
mods |= Qt::GroupSwitchModifier;
|
||||
}
|
||||
else
|
||||
{
|
||||
KeyMap::const_iterator searchResult = mKeys.find(name);
|
||||
if (searchResult != mKeys.end())
|
||||
{
|
||||
keys[keyPos] = mods | searchResult->second;
|
||||
|
||||
mods = 0;
|
||||
keyPos += 1;
|
||||
|
||||
if (keyPos >= MaxKeys)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
start = end + 1;
|
||||
}
|
||||
|
||||
sequence = QKeySequence(keys[0], keys[1], keys[2], keys[3]);
|
||||
}
|
||||
|
||||
void ShortcutManager::convertFromString(const std::string& data, int& modifier) const
|
||||
{
|
||||
size_t start = data.find(";") + 1;
|
||||
start = std::min(start, data.size());
|
||||
|
||||
std::string name = data.substr(start);
|
||||
KeyMap::const_iterator searchResult = mKeys.find(name);
|
||||
if (searchResult != mKeys.end())
|
||||
{
|
||||
modifier = searchResult->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
modifier = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ShortcutManager::convertFromString(const std::string& data, QKeySequence& sequence, int& modifier) const
|
||||
{
|
||||
convertFromString(data, sequence);
|
||||
convertFromString(data, modifier);
|
||||
}
|
||||
|
||||
void ShortcutManager::createLookupTables()
|
||||
{
|
||||
// Mouse buttons
|
||||
mNames.insert(std::make_pair(Qt::LeftButton, "LMB"));
|
||||
mNames.insert(std::make_pair(Qt::RightButton, "RMB"));
|
||||
mNames.insert(std::make_pair(Qt::MiddleButton, "MMB"));
|
||||
mNames.insert(std::make_pair(Qt::XButton1, "Mouse4"));
|
||||
mNames.insert(std::make_pair(Qt::XButton2, "Mouse5"));
|
||||
|
||||
// Keyboard buttons
|
||||
for (size_t i = 0; QtKeys[i].first != 0; ++i)
|
||||
{
|
||||
mNames.insert(QtKeys[i]);
|
||||
}
|
||||
|
||||
// Generate inverse map
|
||||
for (NameMap::const_iterator it = mNames.begin(); it != mNames.end(); ++it)
|
||||
{
|
||||
mKeys.insert(std::make_pair(it->second, it->first));
|
||||
}
|
||||
}
|
||||
|
||||
QString ShortcutManager::processToolTip(const QString& toolTip) const
|
||||
{
|
||||
const QChar SequenceStart = '{';
|
||||
const QChar SequenceEnd = '}';
|
||||
|
||||
QStringList substrings;
|
||||
|
||||
int prevIndex = 0;
|
||||
int startIndex = toolTip.indexOf(SequenceStart);
|
||||
int endIndex = (startIndex != -1) ? toolTip.indexOf(SequenceEnd, startIndex) : -1;
|
||||
|
||||
// Process every valid shortcut escape sequence
|
||||
while (startIndex != -1 && endIndex != -1)
|
||||
{
|
||||
int count = startIndex - prevIndex;
|
||||
if (count > 0)
|
||||
{
|
||||
substrings.push_back(toolTip.mid(prevIndex, count));
|
||||
}
|
||||
|
||||
// Find sequence name
|
||||
startIndex += 1; // '{' character
|
||||
count = endIndex - startIndex;
|
||||
if (count > 0)
|
||||
{
|
||||
QString settingName = toolTip.mid(startIndex, count);
|
||||
|
||||
QKeySequence sequence;
|
||||
int modifier;
|
||||
|
||||
if (getSequence(settingName.toUtf8().data(), sequence))
|
||||
{
|
||||
QString value = QString::fromUtf8(convertToString(sequence).c_str());
|
||||
substrings.push_back(value);
|
||||
}
|
||||
else if (getModifier(settingName.toUtf8().data(), modifier))
|
||||
{
|
||||
QString value = QString::fromUtf8(convertToString(modifier).c_str());
|
||||
substrings.push_back(value);
|
||||
}
|
||||
|
||||
prevIndex = endIndex + 1; // '}' character
|
||||
}
|
||||
|
||||
startIndex = toolTip.indexOf(SequenceStart, endIndex);
|
||||
endIndex = (startIndex != -1) ? toolTip.indexOf(SequenceEnd, startIndex) : -1;
|
||||
}
|
||||
|
||||
if (prevIndex < toolTip.size())
|
||||
{
|
||||
substrings.push_back(toolTip.mid(prevIndex));
|
||||
}
|
||||
|
||||
return substrings.join("");
|
||||
}
|
||||
|
||||
const std::pair<int, const char*> ShortcutManager::QtKeys[] =
|
||||
{
|
||||
std::make_pair((int)Qt::Key_Space , "Space"),
|
||||
std::make_pair((int)Qt::Key_Exclam , "Exclam"),
|
||||
std::make_pair((int)Qt::Key_QuoteDbl , "QuoteDbl"),
|
||||
std::make_pair((int)Qt::Key_NumberSign , "NumberSign"),
|
||||
std::make_pair((int)Qt::Key_Dollar , "Dollar"),
|
||||
std::make_pair((int)Qt::Key_Percent , "Percent"),
|
||||
std::make_pair((int)Qt::Key_Ampersand , "Ampersand"),
|
||||
std::make_pair((int)Qt::Key_Apostrophe , "Apostrophe"),
|
||||
std::make_pair((int)Qt::Key_ParenLeft , "ParenLeft"),
|
||||
std::make_pair((int)Qt::Key_ParenRight , "ParenRight"),
|
||||
std::make_pair((int)Qt::Key_Asterisk , "Asterisk"),
|
||||
std::make_pair((int)Qt::Key_Plus , "Plus"),
|
||||
std::make_pair((int)Qt::Key_Comma , "Comma"),
|
||||
std::make_pair((int)Qt::Key_Minus , "Minus"),
|
||||
std::make_pair((int)Qt::Key_Period , "Period"),
|
||||
std::make_pair((int)Qt::Key_Slash , "Slash"),
|
||||
std::make_pair((int)Qt::Key_0 , "0"),
|
||||
std::make_pair((int)Qt::Key_1 , "1"),
|
||||
std::make_pair((int)Qt::Key_2 , "2"),
|
||||
std::make_pair((int)Qt::Key_3 , "3"),
|
||||
std::make_pair((int)Qt::Key_4 , "4"),
|
||||
std::make_pair((int)Qt::Key_5 , "5"),
|
||||
std::make_pair((int)Qt::Key_6 , "6"),
|
||||
std::make_pair((int)Qt::Key_7 , "7"),
|
||||
std::make_pair((int)Qt::Key_8 , "8"),
|
||||
std::make_pair((int)Qt::Key_9 , "9"),
|
||||
std::make_pair((int)Qt::Key_Colon , "Colon"),
|
||||
std::make_pair((int)Qt::Key_Semicolon , "Semicolon"),
|
||||
std::make_pair((int)Qt::Key_Less , "Less"),
|
||||
std::make_pair((int)Qt::Key_Equal , "Equal"),
|
||||
std::make_pair((int)Qt::Key_Greater , "Greater"),
|
||||
std::make_pair((int)Qt::Key_Question , "Question"),
|
||||
std::make_pair((int)Qt::Key_At , "At"),
|
||||
std::make_pair((int)Qt::Key_A , "A"),
|
||||
std::make_pair((int)Qt::Key_B , "B"),
|
||||
std::make_pair((int)Qt::Key_C , "C"),
|
||||
std::make_pair((int)Qt::Key_D , "D"),
|
||||
std::make_pair((int)Qt::Key_E , "E"),
|
||||
std::make_pair((int)Qt::Key_F , "F"),
|
||||
std::make_pair((int)Qt::Key_G , "G"),
|
||||
std::make_pair((int)Qt::Key_H , "H"),
|
||||
std::make_pair((int)Qt::Key_I , "I"),
|
||||
std::make_pair((int)Qt::Key_J , "J"),
|
||||
std::make_pair((int)Qt::Key_K , "K"),
|
||||
std::make_pair((int)Qt::Key_L , "L"),
|
||||
std::make_pair((int)Qt::Key_M , "M"),
|
||||
std::make_pair((int)Qt::Key_N , "N"),
|
||||
std::make_pair((int)Qt::Key_O , "O"),
|
||||
std::make_pair((int)Qt::Key_P , "P"),
|
||||
std::make_pair((int)Qt::Key_Q , "Q"),
|
||||
std::make_pair((int)Qt::Key_R , "R"),
|
||||
std::make_pair((int)Qt::Key_S , "S"),
|
||||
std::make_pair((int)Qt::Key_T , "T"),
|
||||
std::make_pair((int)Qt::Key_U , "U"),
|
||||
std::make_pair((int)Qt::Key_V , "V"),
|
||||
std::make_pair((int)Qt::Key_W , "W"),
|
||||
std::make_pair((int)Qt::Key_X , "X"),
|
||||
std::make_pair((int)Qt::Key_Y , "Y"),
|
||||
std::make_pair((int)Qt::Key_Z , "Z"),
|
||||
std::make_pair((int)Qt::Key_BracketLeft , "BracketLeft"),
|
||||
std::make_pair((int)Qt::Key_Backslash , "Backslash"),
|
||||
std::make_pair((int)Qt::Key_BracketRight , "BracketRight"),
|
||||
std::make_pair((int)Qt::Key_AsciiCircum , "AsciiCircum"),
|
||||
std::make_pair((int)Qt::Key_Underscore , "Underscore"),
|
||||
std::make_pair((int)Qt::Key_QuoteLeft , "QuoteLeft"),
|
||||
std::make_pair((int)Qt::Key_BraceLeft , "BraceLeft"),
|
||||
std::make_pair((int)Qt::Key_Bar , "Bar"),
|
||||
std::make_pair((int)Qt::Key_BraceRight , "BraceRight"),
|
||||
std::make_pair((int)Qt::Key_AsciiTilde , "AsciiTilde"),
|
||||
std::make_pair((int)Qt::Key_nobreakspace , "nobreakspace"),
|
||||
std::make_pair((int)Qt::Key_exclamdown , "exclamdown"),
|
||||
std::make_pair((int)Qt::Key_cent , "cent"),
|
||||
std::make_pair((int)Qt::Key_sterling , "sterling"),
|
||||
std::make_pair((int)Qt::Key_currency , "currency"),
|
||||
std::make_pair((int)Qt::Key_yen , "yen"),
|
||||
std::make_pair((int)Qt::Key_brokenbar , "brokenbar"),
|
||||
std::make_pair((int)Qt::Key_section , "section"),
|
||||
std::make_pair((int)Qt::Key_diaeresis , "diaeresis"),
|
||||
std::make_pair((int)Qt::Key_copyright , "copyright"),
|
||||
std::make_pair((int)Qt::Key_ordfeminine , "ordfeminine"),
|
||||
std::make_pair((int)Qt::Key_guillemotleft , "guillemotleft"),
|
||||
std::make_pair((int)Qt::Key_notsign , "notsign"),
|
||||
std::make_pair((int)Qt::Key_hyphen , "hyphen"),
|
||||
std::make_pair((int)Qt::Key_registered , "registered"),
|
||||
std::make_pair((int)Qt::Key_macron , "macron"),
|
||||
std::make_pair((int)Qt::Key_degree , "degree"),
|
||||
std::make_pair((int)Qt::Key_plusminus , "plusminus"),
|
||||
std::make_pair((int)Qt::Key_twosuperior , "twosuperior"),
|
||||
std::make_pair((int)Qt::Key_threesuperior , "threesuperior"),
|
||||
std::make_pair((int)Qt::Key_acute , "acute"),
|
||||
std::make_pair((int)Qt::Key_mu , "mu"),
|
||||
std::make_pair((int)Qt::Key_paragraph , "paragraph"),
|
||||
std::make_pair((int)Qt::Key_periodcentered , "periodcentered"),
|
||||
std::make_pair((int)Qt::Key_cedilla , "cedilla"),
|
||||
std::make_pair((int)Qt::Key_onesuperior , "onesuperior"),
|
||||
std::make_pair((int)Qt::Key_masculine , "masculine"),
|
||||
std::make_pair((int)Qt::Key_guillemotright , "guillemotright"),
|
||||
std::make_pair((int)Qt::Key_onequarter , "onequarter"),
|
||||
std::make_pair((int)Qt::Key_onehalf , "onehalf"),
|
||||
std::make_pair((int)Qt::Key_threequarters , "threequarters"),
|
||||
std::make_pair((int)Qt::Key_questiondown , "questiondown"),
|
||||
std::make_pair((int)Qt::Key_Agrave , "Agrave"),
|
||||
std::make_pair((int)Qt::Key_Aacute , "Aacute"),
|
||||
std::make_pair((int)Qt::Key_Acircumflex , "Acircumflex"),
|
||||
std::make_pair((int)Qt::Key_Atilde , "Atilde"),
|
||||
std::make_pair((int)Qt::Key_Adiaeresis , "Adiaeresis"),
|
||||
std::make_pair((int)Qt::Key_Aring , "Aring"),
|
||||
std::make_pair((int)Qt::Key_AE , "AE"),
|
||||
std::make_pair((int)Qt::Key_Ccedilla , "Ccedilla"),
|
||||
std::make_pair((int)Qt::Key_Egrave , "Egrave"),
|
||||
std::make_pair((int)Qt::Key_Eacute , "Eacute"),
|
||||
std::make_pair((int)Qt::Key_Ecircumflex , "Ecircumflex"),
|
||||
std::make_pair((int)Qt::Key_Ediaeresis , "Ediaeresis"),
|
||||
std::make_pair((int)Qt::Key_Igrave , "Igrave"),
|
||||
std::make_pair((int)Qt::Key_Iacute , "Iacute"),
|
||||
std::make_pair((int)Qt::Key_Icircumflex , "Icircumflex"),
|
||||
std::make_pair((int)Qt::Key_Idiaeresis , "Idiaeresis"),
|
||||
std::make_pair((int)Qt::Key_ETH , "ETH"),
|
||||
std::make_pair((int)Qt::Key_Ntilde , "Ntilde"),
|
||||
std::make_pair((int)Qt::Key_Ograve , "Ograve"),
|
||||
std::make_pair((int)Qt::Key_Oacute , "Oacute"),
|
||||
std::make_pair((int)Qt::Key_Ocircumflex , "Ocircumflex"),
|
||||
std::make_pair((int)Qt::Key_Otilde , "Otilde"),
|
||||
std::make_pair((int)Qt::Key_Odiaeresis , "Odiaeresis"),
|
||||
std::make_pair((int)Qt::Key_multiply , "multiply"),
|
||||
std::make_pair((int)Qt::Key_Ooblique , "Ooblique"),
|
||||
std::make_pair((int)Qt::Key_Ugrave , "Ugrave"),
|
||||
std::make_pair((int)Qt::Key_Uacute , "Uacute"),
|
||||
std::make_pair((int)Qt::Key_Ucircumflex , "Ucircumflex"),
|
||||
std::make_pair((int)Qt::Key_Udiaeresis , "Udiaeresis"),
|
||||
std::make_pair((int)Qt::Key_Yacute , "Yacute"),
|
||||
std::make_pair((int)Qt::Key_THORN , "THORN"),
|
||||
std::make_pair((int)Qt::Key_ssharp , "ssharp"),
|
||||
std::make_pair((int)Qt::Key_division , "division"),
|
||||
std::make_pair((int)Qt::Key_ydiaeresis , "ydiaeresis"),
|
||||
std::make_pair((int)Qt::Key_Escape , "Escape"),
|
||||
std::make_pair((int)Qt::Key_Tab , "Tab"),
|
||||
std::make_pair((int)Qt::Key_Backtab , "Backtab"),
|
||||
std::make_pair((int)Qt::Key_Backspace , "Backspace"),
|
||||
std::make_pair((int)Qt::Key_Return , "Return"),
|
||||
std::make_pair((int)Qt::Key_Enter , "Enter"),
|
||||
std::make_pair((int)Qt::Key_Insert , "Insert"),
|
||||
std::make_pair((int)Qt::Key_Delete , "Delete"),
|
||||
std::make_pair((int)Qt::Key_Pause , "Pause"),
|
||||
std::make_pair((int)Qt::Key_Print , "Print"),
|
||||
std::make_pair((int)Qt::Key_SysReq , "SysReq"),
|
||||
std::make_pair((int)Qt::Key_Clear , "Clear"),
|
||||
std::make_pair((int)Qt::Key_Home , "Home"),
|
||||
std::make_pair((int)Qt::Key_End , "End"),
|
||||
std::make_pair((int)Qt::Key_Left , "Left"),
|
||||
std::make_pair((int)Qt::Key_Up , "Up"),
|
||||
std::make_pair((int)Qt::Key_Right , "Right"),
|
||||
std::make_pair((int)Qt::Key_Down , "Down"),
|
||||
std::make_pair((int)Qt::Key_PageUp , "PageUp"),
|
||||
std::make_pair((int)Qt::Key_PageDown , "PageDown"),
|
||||
std::make_pair((int)Qt::Key_Shift , "Shift"),
|
||||
std::make_pair((int)Qt::Key_Control , "Control"),
|
||||
std::make_pair((int)Qt::Key_Meta , "Meta"),
|
||||
std::make_pair((int)Qt::Key_Alt , "Alt"),
|
||||
std::make_pair((int)Qt::Key_CapsLock , "CapsLock"),
|
||||
std::make_pair((int)Qt::Key_NumLock , "NumLock"),
|
||||
std::make_pair((int)Qt::Key_ScrollLock , "ScrollLock"),
|
||||
std::make_pair((int)Qt::Key_F1 , "F1"),
|
||||
std::make_pair((int)Qt::Key_F2 , "F2"),
|
||||
std::make_pair((int)Qt::Key_F3 , "F3"),
|
||||
std::make_pair((int)Qt::Key_F4 , "F4"),
|
||||
std::make_pair((int)Qt::Key_F5 , "F5"),
|
||||
std::make_pair((int)Qt::Key_F6 , "F6"),
|
||||
std::make_pair((int)Qt::Key_F7 , "F7"),
|
||||
std::make_pair((int)Qt::Key_F8 , "F8"),
|
||||
std::make_pair((int)Qt::Key_F9 , "F9"),
|
||||
std::make_pair((int)Qt::Key_F10 , "F10"),
|
||||
std::make_pair((int)Qt::Key_F11 , "F11"),
|
||||
std::make_pair((int)Qt::Key_F12 , "F12"),
|
||||
std::make_pair((int)Qt::Key_F13 , "F13"),
|
||||
std::make_pair((int)Qt::Key_F14 , "F14"),
|
||||
std::make_pair((int)Qt::Key_F15 , "F15"),
|
||||
std::make_pair((int)Qt::Key_F16 , "F16"),
|
||||
std::make_pair((int)Qt::Key_F17 , "F17"),
|
||||
std::make_pair((int)Qt::Key_F18 , "F18"),
|
||||
std::make_pair((int)Qt::Key_F19 , "F19"),
|
||||
std::make_pair((int)Qt::Key_F20 , "F20"),
|
||||
std::make_pair((int)Qt::Key_F21 , "F21"),
|
||||
std::make_pair((int)Qt::Key_F22 , "F22"),
|
||||
std::make_pair((int)Qt::Key_F23 , "F23"),
|
||||
std::make_pair((int)Qt::Key_F24 , "F24"),
|
||||
std::make_pair((int)Qt::Key_F25 , "F25"),
|
||||
std::make_pair((int)Qt::Key_F26 , "F26"),
|
||||
std::make_pair((int)Qt::Key_F27 , "F27"),
|
||||
std::make_pair((int)Qt::Key_F28 , "F28"),
|
||||
std::make_pair((int)Qt::Key_F29 , "F29"),
|
||||
std::make_pair((int)Qt::Key_F30 , "F30"),
|
||||
std::make_pair((int)Qt::Key_F31 , "F31"),
|
||||
std::make_pair((int)Qt::Key_F32 , "F32"),
|
||||
std::make_pair((int)Qt::Key_F33 , "F33"),
|
||||
std::make_pair((int)Qt::Key_F34 , "F34"),
|
||||
std::make_pair((int)Qt::Key_F35 , "F35"),
|
||||
std::make_pair((int)Qt::Key_Super_L , "Super_L"),
|
||||
std::make_pair((int)Qt::Key_Super_R , "Super_R"),
|
||||
std::make_pair((int)Qt::Key_Menu , "Menu"),
|
||||
std::make_pair((int)Qt::Key_Hyper_L , "Hyper_L"),
|
||||
std::make_pair((int)Qt::Key_Hyper_R , "Hyper_R"),
|
||||
std::make_pair((int)Qt::Key_Help , "Help"),
|
||||
std::make_pair((int)Qt::Key_Direction_L , "Direction_L"),
|
||||
std::make_pair((int)Qt::Key_Direction_R , "Direction_R"),
|
||||
std::make_pair((int)Qt::Key_Back , "Back"),
|
||||
std::make_pair((int)Qt::Key_Forward , "Forward"),
|
||||
std::make_pair((int)Qt::Key_Stop , "Stop"),
|
||||
std::make_pair((int)Qt::Key_Refresh , "Refresh"),
|
||||
std::make_pair((int)Qt::Key_VolumeDown , "VolumeDown"),
|
||||
std::make_pair((int)Qt::Key_VolumeMute , "VolumeMute"),
|
||||
std::make_pair((int)Qt::Key_VolumeUp , "VolumeUp"),
|
||||
std::make_pair((int)Qt::Key_BassBoost , "BassBoost"),
|
||||
std::make_pair((int)Qt::Key_BassUp , "BassUp"),
|
||||
std::make_pair((int)Qt::Key_BassDown , "BassDown"),
|
||||
std::make_pair((int)Qt::Key_TrebleUp , "TrebleUp"),
|
||||
std::make_pair((int)Qt::Key_TrebleDown , "TrebleDown"),
|
||||
std::make_pair((int)Qt::Key_MediaPlay , "MediaPlay"),
|
||||
std::make_pair((int)Qt::Key_MediaStop , "MediaStop"),
|
||||
std::make_pair((int)Qt::Key_MediaPrevious , "MediaPrevious"),
|
||||
std::make_pair((int)Qt::Key_MediaNext , "MediaNext"),
|
||||
std::make_pair((int)Qt::Key_MediaRecord , "MediaRecord"),
|
||||
std::make_pair((int)Qt::Key_MediaPause , "MediaPause"),
|
||||
std::make_pair((int)Qt::Key_MediaTogglePlayPause , "MediaTogglePlayPause"),
|
||||
std::make_pair((int)Qt::Key_HomePage , "HomePage"),
|
||||
std::make_pair((int)Qt::Key_Favorites , "Favorites"),
|
||||
std::make_pair((int)Qt::Key_Search , "Search"),
|
||||
std::make_pair((int)Qt::Key_Standby , "Standby"),
|
||||
std::make_pair((int)Qt::Key_OpenUrl , "OpenUrl"),
|
||||
std::make_pair((int)Qt::Key_LaunchMail , "LaunchMail"),
|
||||
std::make_pair((int)Qt::Key_LaunchMedia , "LaunchMedia"),
|
||||
std::make_pair((int)Qt::Key_Launch0 , "Launch0"),
|
||||
std::make_pair((int)Qt::Key_Launch1 , "Launch1"),
|
||||
std::make_pair((int)Qt::Key_Launch2 , "Launch2"),
|
||||
std::make_pair((int)Qt::Key_Launch3 , "Launch3"),
|
||||
std::make_pair((int)Qt::Key_Launch4 , "Launch4"),
|
||||
std::make_pair((int)Qt::Key_Launch5 , "Launch5"),
|
||||
std::make_pair((int)Qt::Key_Launch6 , "Launch6"),
|
||||
std::make_pair((int)Qt::Key_Launch7 , "Launch7"),
|
||||
std::make_pair((int)Qt::Key_Launch8 , "Launch8"),
|
||||
std::make_pair((int)Qt::Key_Launch9 , "Launch9"),
|
||||
std::make_pair((int)Qt::Key_LaunchA , "LaunchA"),
|
||||
std::make_pair((int)Qt::Key_LaunchB , "LaunchB"),
|
||||
std::make_pair((int)Qt::Key_LaunchC , "LaunchC"),
|
||||
std::make_pair((int)Qt::Key_LaunchD , "LaunchD"),
|
||||
std::make_pair((int)Qt::Key_LaunchE , "LaunchE"),
|
||||
std::make_pair((int)Qt::Key_LaunchF , "LaunchF"),
|
||||
std::make_pair((int)Qt::Key_MonBrightnessUp , "MonBrightnessUp"),
|
||||
std::make_pair((int)Qt::Key_MonBrightnessDown , "MonBrightnessDown"),
|
||||
std::make_pair((int)Qt::Key_KeyboardLightOnOff , "KeyboardLightOnOff"),
|
||||
std::make_pair((int)Qt::Key_KeyboardBrightnessUp , "KeyboardBrightnessUp"),
|
||||
std::make_pair((int)Qt::Key_KeyboardBrightnessDown , "KeyboardBrightnessDown"),
|
||||
std::make_pair((int)Qt::Key_PowerOff , "PowerOff"),
|
||||
std::make_pair((int)Qt::Key_WakeUp , "WakeUp"),
|
||||
std::make_pair((int)Qt::Key_Eject , "Eject"),
|
||||
std::make_pair((int)Qt::Key_ScreenSaver , "ScreenSaver"),
|
||||
std::make_pair((int)Qt::Key_WWW , "WWW"),
|
||||
std::make_pair((int)Qt::Key_Memo , "Memo"),
|
||||
std::make_pair((int)Qt::Key_LightBulb , "LightBulb"),
|
||||
std::make_pair((int)Qt::Key_Shop , "Shop"),
|
||||
std::make_pair((int)Qt::Key_History , "History"),
|
||||
std::make_pair((int)Qt::Key_AddFavorite , "AddFavorite"),
|
||||
std::make_pair((int)Qt::Key_HotLinks , "HotLinks"),
|
||||
std::make_pair((int)Qt::Key_BrightnessAdjust , "BrightnessAdjust"),
|
||||
std::make_pair((int)Qt::Key_Finance , "Finance"),
|
||||
std::make_pair((int)Qt::Key_Community , "Community"),
|
||||
std::make_pair((int)Qt::Key_AudioRewind , "AudioRewind"),
|
||||
std::make_pair((int)Qt::Key_BackForward , "BackForward"),
|
||||
std::make_pair((int)Qt::Key_ApplicationLeft , "ApplicationLeft"),
|
||||
std::make_pair((int)Qt::Key_ApplicationRight , "ApplicationRight"),
|
||||
std::make_pair((int)Qt::Key_Book , "Book"),
|
||||
std::make_pair((int)Qt::Key_CD , "CD"),
|
||||
std::make_pair((int)Qt::Key_Calculator , "Calculator"),
|
||||
std::make_pair((int)Qt::Key_ToDoList , "ToDoList"),
|
||||
std::make_pair((int)Qt::Key_ClearGrab , "ClearGrab"),
|
||||
std::make_pair((int)Qt::Key_Close , "Close"),
|
||||
std::make_pair((int)Qt::Key_Copy , "Copy"),
|
||||
std::make_pair((int)Qt::Key_Cut , "Cut"),
|
||||
std::make_pair((int)Qt::Key_Display , "Display"),
|
||||
std::make_pair((int)Qt::Key_DOS , "DOS"),
|
||||
std::make_pair((int)Qt::Key_Documents , "Documents"),
|
||||
std::make_pair((int)Qt::Key_Excel , "Excel"),
|
||||
std::make_pair((int)Qt::Key_Explorer , "Explorer"),
|
||||
std::make_pair((int)Qt::Key_Game , "Game"),
|
||||
std::make_pair((int)Qt::Key_Go , "Go"),
|
||||
std::make_pair((int)Qt::Key_iTouch , "iTouch"),
|
||||
std::make_pair((int)Qt::Key_LogOff , "LogOff"),
|
||||
std::make_pair((int)Qt::Key_Market , "Market"),
|
||||
std::make_pair((int)Qt::Key_Meeting , "Meeting"),
|
||||
std::make_pair((int)Qt::Key_MenuKB , "MenuKB"),
|
||||
std::make_pair((int)Qt::Key_MenuPB , "MenuPB"),
|
||||
std::make_pair((int)Qt::Key_MySites , "MySites"),
|
||||
std::make_pair((int)Qt::Key_News , "News"),
|
||||
std::make_pair((int)Qt::Key_OfficeHome , "OfficeHome"),
|
||||
std::make_pair((int)Qt::Key_Option , "Option"),
|
||||
std::make_pair((int)Qt::Key_Paste , "Paste"),
|
||||
std::make_pair((int)Qt::Key_Phone , "Phone"),
|
||||
std::make_pair((int)Qt::Key_Calendar , "Calendar"),
|
||||
std::make_pair((int)Qt::Key_Reply , "Reply"),
|
||||
std::make_pair((int)Qt::Key_Reload , "Reload"),
|
||||
std::make_pair((int)Qt::Key_RotateWindows , "RotateWindows"),
|
||||
std::make_pair((int)Qt::Key_RotationPB , "RotationPB"),
|
||||
std::make_pair((int)Qt::Key_RotationKB , "RotationKB"),
|
||||
std::make_pair((int)Qt::Key_Save , "Save"),
|
||||
std::make_pair((int)Qt::Key_Send , "Send"),
|
||||
std::make_pair((int)Qt::Key_Spell , "Spell"),
|
||||
std::make_pair((int)Qt::Key_SplitScreen , "SplitScreen"),
|
||||
std::make_pair((int)Qt::Key_Support , "Support"),
|
||||
std::make_pair((int)Qt::Key_TaskPane , "TaskPane"),
|
||||
std::make_pair((int)Qt::Key_Terminal , "Terminal"),
|
||||
std::make_pair((int)Qt::Key_Tools , "Tools"),
|
||||
std::make_pair((int)Qt::Key_Travel , "Travel"),
|
||||
std::make_pair((int)Qt::Key_Video , "Video"),
|
||||
std::make_pair((int)Qt::Key_Word , "Word"),
|
||||
std::make_pair((int)Qt::Key_Xfer , "Xfer"),
|
||||
std::make_pair((int)Qt::Key_ZoomIn , "ZoomIn"),
|
||||
std::make_pair((int)Qt::Key_ZoomOut , "ZoomOut"),
|
||||
std::make_pair((int)Qt::Key_Away , "Away"),
|
||||
std::make_pair((int)Qt::Key_Messenger , "Messenger"),
|
||||
std::make_pair((int)Qt::Key_WebCam , "WebCam"),
|
||||
std::make_pair((int)Qt::Key_MailForward , "MailForward"),
|
||||
std::make_pair((int)Qt::Key_Pictures , "Pictures"),
|
||||
std::make_pair((int)Qt::Key_Music , "Music"),
|
||||
std::make_pair((int)Qt::Key_Battery , "Battery"),
|
||||
std::make_pair((int)Qt::Key_Bluetooth , "Bluetooth"),
|
||||
std::make_pair((int)Qt::Key_WLAN , "WLAN"),
|
||||
std::make_pair((int)Qt::Key_UWB , "UWB"),
|
||||
std::make_pair((int)Qt::Key_AudioForward , "AudioForward"),
|
||||
std::make_pair((int)Qt::Key_AudioRepeat , "AudioRepeat"),
|
||||
std::make_pair((int)Qt::Key_AudioRandomPlay , "AudioRandomPlay"),
|
||||
std::make_pair((int)Qt::Key_Subtitle , "Subtitle"),
|
||||
std::make_pair((int)Qt::Key_AudioCycleTrack , "AudioCycleTrack"),
|
||||
std::make_pair((int)Qt::Key_Time , "Time"),
|
||||
std::make_pair((int)Qt::Key_Hibernate , "Hibernate"),
|
||||
std::make_pair((int)Qt::Key_View , "View"),
|
||||
std::make_pair((int)Qt::Key_TopMenu , "TopMenu"),
|
||||
std::make_pair((int)Qt::Key_PowerDown , "PowerDown"),
|
||||
std::make_pair((int)Qt::Key_Suspend , "Suspend"),
|
||||
std::make_pair((int)Qt::Key_ContrastAdjust , "ContrastAdjust"),
|
||||
std::make_pair((int)Qt::Key_LaunchG , "LaunchG"),
|
||||
std::make_pair((int)Qt::Key_LaunchH , "LaunchH"),
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,7,0)
|
||||
std::make_pair((int)Qt::Key_TouchpadToggle , "TouchpadToggle"),
|
||||
std::make_pair((int)Qt::Key_TouchpadOn , "TouchpadOn"),
|
||||
std::make_pair((int)Qt::Key_TouchpadOff , "TouchpadOff"),
|
||||
std::make_pair((int)Qt::Key_MicMute , "MicMute"),
|
||||
std::make_pair((int)Qt::Key_Red , "Red"),
|
||||
std::make_pair((int)Qt::Key_Green , "Green"),
|
||||
std::make_pair((int)Qt::Key_Yellow , "Yellow"),
|
||||
std::make_pair((int)Qt::Key_Blue , "Blue"),
|
||||
std::make_pair((int)Qt::Key_ChannelUp , "ChannelUp"),
|
||||
std::make_pair((int)Qt::Key_ChannelDown , "ChannelDown"),
|
||||
std::make_pair((int)Qt::Key_Guide , "Guide"),
|
||||
std::make_pair((int)Qt::Key_Info , "Info"),
|
||||
std::make_pair((int)Qt::Key_Settings , "Settings"),
|
||||
std::make_pair((int)Qt::Key_MicVolumeUp , "MicVolumeUp"),
|
||||
std::make_pair((int)Qt::Key_MicVolumeDown , "MicVolumeDown"),
|
||||
std::make_pair((int)Qt::Key_New , "New"),
|
||||
std::make_pair((int)Qt::Key_Open , "Open"),
|
||||
std::make_pair((int)Qt::Key_Find , "Find"),
|
||||
std::make_pair((int)Qt::Key_Undo , "Undo"),
|
||||
std::make_pair((int)Qt::Key_Redo , "Redo"),
|
||||
#endif
|
||||
std::make_pair((int)Qt::Key_AltGr , "AltGr"),
|
||||
std::make_pair((int)Qt::Key_Multi_key , "Multi_key"),
|
||||
std::make_pair((int)Qt::Key_Kanji , "Kanji"),
|
||||
std::make_pair((int)Qt::Key_Muhenkan , "Muhenkan"),
|
||||
std::make_pair((int)Qt::Key_Henkan , "Henkan"),
|
||||
std::make_pair((int)Qt::Key_Romaji , "Romaji"),
|
||||
std::make_pair((int)Qt::Key_Hiragana , "Hiragana"),
|
||||
std::make_pair((int)Qt::Key_Katakana , "Katakana"),
|
||||
std::make_pair((int)Qt::Key_Hiragana_Katakana , "Hiragana_Katakana"),
|
||||
std::make_pair((int)Qt::Key_Zenkaku , "Zenkaku"),
|
||||
std::make_pair((int)Qt::Key_Hankaku , "Hankaku"),
|
||||
std::make_pair((int)Qt::Key_Zenkaku_Hankaku , "Zenkaku_Hankaku"),
|
||||
std::make_pair((int)Qt::Key_Touroku , "Touroku"),
|
||||
std::make_pair((int)Qt::Key_Massyo , "Massyo"),
|
||||
std::make_pair((int)Qt::Key_Kana_Lock , "Kana_Lock"),
|
||||
std::make_pair((int)Qt::Key_Kana_Shift , "Kana_Shift"),
|
||||
std::make_pair((int)Qt::Key_Eisu_Shift , "Eisu_Shift"),
|
||||
std::make_pair((int)Qt::Key_Eisu_toggle , "Eisu_toggle"),
|
||||
std::make_pair((int)Qt::Key_Hangul , "Hangul"),
|
||||
std::make_pair((int)Qt::Key_Hangul_Start , "Hangul_Start"),
|
||||
std::make_pair((int)Qt::Key_Hangul_End , "Hangul_End"),
|
||||
std::make_pair((int)Qt::Key_Hangul_Hanja , "Hangul_Hanja"),
|
||||
std::make_pair((int)Qt::Key_Hangul_Jamo , "Hangul_Jamo"),
|
||||
std::make_pair((int)Qt::Key_Hangul_Romaja , "Hangul_Romaja"),
|
||||
std::make_pair((int)Qt::Key_Codeinput , "Codeinput"),
|
||||
std::make_pair((int)Qt::Key_Hangul_Jeonja , "Hangul_Jeonja"),
|
||||
std::make_pair((int)Qt::Key_Hangul_Banja , "Hangul_Banja"),
|
||||
std::make_pair((int)Qt::Key_Hangul_PreHanja , "Hangul_PreHanja"),
|
||||
std::make_pair((int)Qt::Key_Hangul_PostHanja , "Hangul_PostHanja"),
|
||||
std::make_pair((int)Qt::Key_SingleCandidate , "SingleCandidate"),
|
||||
std::make_pair((int)Qt::Key_MultipleCandidate , "MultipleCandidate"),
|
||||
std::make_pair((int)Qt::Key_PreviousCandidate , "PreviousCandidate"),
|
||||
std::make_pair((int)Qt::Key_Hangul_Special , "Hangul_Special"),
|
||||
std::make_pair((int)Qt::Key_Mode_switch , "Mode_switch"),
|
||||
std::make_pair((int)Qt::Key_Dead_Grave , "Dead_Grave"),
|
||||
std::make_pair((int)Qt::Key_Dead_Acute , "Dead_Acute"),
|
||||
std::make_pair((int)Qt::Key_Dead_Circumflex , "Dead_Circumflex"),
|
||||
std::make_pair((int)Qt::Key_Dead_Tilde , "Dead_Tilde"),
|
||||
std::make_pair((int)Qt::Key_Dead_Macron , "Dead_Macron"),
|
||||
std::make_pair((int)Qt::Key_Dead_Breve , "Dead_Breve"),
|
||||
std::make_pair((int)Qt::Key_Dead_Abovedot , "Dead_Abovedot"),
|
||||
std::make_pair((int)Qt::Key_Dead_Diaeresis , "Dead_Diaeresis"),
|
||||
std::make_pair((int)Qt::Key_Dead_Abovering , "Dead_Abovering"),
|
||||
std::make_pair((int)Qt::Key_Dead_Doubleacute , "Dead_Doubleacute"),
|
||||
std::make_pair((int)Qt::Key_Dead_Caron , "Dead_Caron"),
|
||||
std::make_pair((int)Qt::Key_Dead_Cedilla , "Dead_Cedilla"),
|
||||
std::make_pair((int)Qt::Key_Dead_Ogonek , "Dead_Ogonek"),
|
||||
std::make_pair((int)Qt::Key_Dead_Iota , "Dead_Iota"),
|
||||
std::make_pair((int)Qt::Key_Dead_Voiced_Sound , "Dead_Voiced_Sound"),
|
||||
std::make_pair((int)Qt::Key_Dead_Semivoiced_Sound , "Dead_Semivoiced_Sound"),
|
||||
std::make_pair((int)Qt::Key_Dead_Belowdot , "Dead_Belowdot"),
|
||||
std::make_pair((int)Qt::Key_Dead_Hook , "Dead_Hook"),
|
||||
std::make_pair((int)Qt::Key_Dead_Horn , "Dead_Horn"),
|
||||
std::make_pair((int)Qt::Key_MediaLast , "MediaLast"),
|
||||
std::make_pair((int)Qt::Key_Select , "Select"),
|
||||
std::make_pair((int)Qt::Key_Yes , "Yes"),
|
||||
std::make_pair((int)Qt::Key_No , "No"),
|
||||
std::make_pair((int)Qt::Key_Cancel , "Cancel"),
|
||||
std::make_pair((int)Qt::Key_Printer , "Printer"),
|
||||
std::make_pair((int)Qt::Key_Execute , "Execute"),
|
||||
std::make_pair((int)Qt::Key_Sleep , "Sleep"),
|
||||
std::make_pair((int)Qt::Key_Play , "Play"),
|
||||
std::make_pair((int)Qt::Key_Zoom , "Zoom"),
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,7,0)
|
||||
std::make_pair((int)Qt::Key_Exit , "Exit"),
|
||||
#endif
|
||||
std::make_pair((int)Qt::Key_Context1 , "Context1"),
|
||||
std::make_pair((int)Qt::Key_Context2 , "Context2"),
|
||||
std::make_pair((int)Qt::Key_Context3 , "Context3"),
|
||||
std::make_pair((int)Qt::Key_Context4 , "Context4"),
|
||||
std::make_pair((int)Qt::Key_Call , "Call"),
|
||||
std::make_pair((int)Qt::Key_Hangup , "Hangup"),
|
||||
std::make_pair((int)Qt::Key_Flip , "Flip"),
|
||||
std::make_pair((int)Qt::Key_ToggleCallHangup , "ToggleCallHangup"),
|
||||
std::make_pair((int)Qt::Key_VoiceDial , "VoiceDial"),
|
||||
std::make_pair((int)Qt::Key_LastNumberRedial , "LastNumberRedial"),
|
||||
std::make_pair((int)Qt::Key_Camera , "Camera"),
|
||||
std::make_pair((int)Qt::Key_CameraFocus , "CameraFocus"),
|
||||
std::make_pair(0 , (const char*) 0)
|
||||
};
|
||||
|
||||
}
|
73
apps/opencs/model/prefs/shortcutmanager.hpp
Normal file
73
apps/opencs/model/prefs/shortcutmanager.hpp
Normal file
|
@ -0,0 +1,73 @@
|
|||
#ifndef CSM_PREFS_SHORTCUTMANAGER_H
|
||||
#define CSM_PREFS_SHORTCUTMANAGER_H
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <QKeySequence>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
namespace CSMPrefs
|
||||
{
|
||||
class Shortcut;
|
||||
class ShortcutEventHandler;
|
||||
|
||||
/// Class used to track and update shortcuts/sequences
|
||||
class ShortcutManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
ShortcutManager();
|
||||
|
||||
/// The shortcut class will do this automatically
|
||||
void addShortcut(Shortcut* shortcut);
|
||||
|
||||
/// The shortcut class will do this automatically
|
||||
void removeShortcut(Shortcut* shortcut);
|
||||
|
||||
bool getSequence(const std::string& name, QKeySequence& sequence) const;
|
||||
void setSequence(const std::string& name, const QKeySequence& sequence);
|
||||
|
||||
bool getModifier(const std::string& name, int& modifier) const;
|
||||
void setModifier(const std::string& name, int modifier);
|
||||
|
||||
std::string convertToString(const QKeySequence& sequence) const;
|
||||
std::string convertToString(int modifier) const;
|
||||
|
||||
std::string convertToString(const QKeySequence& sequence, int modifier) const;
|
||||
|
||||
void convertFromString(const std::string& data, QKeySequence& sequence) const;
|
||||
void convertFromString(const std::string& data, int& modifier) const;
|
||||
|
||||
void convertFromString(const std::string& data, QKeySequence& sequence, int& modifier) const;
|
||||
|
||||
/// Replaces "{sequence-name}" or "{modifier-name}" with the appropriate text
|
||||
QString processToolTip(const QString& toolTip) const;
|
||||
|
||||
private:
|
||||
|
||||
// Need a multimap in case multiple shortcuts share the same name
|
||||
typedef std::multimap<std::string, Shortcut*> ShortcutMap;
|
||||
typedef std::map<std::string, QKeySequence> SequenceMap;
|
||||
typedef std::map<std::string, int> ModifierMap;
|
||||
typedef std::map<int, std::string> NameMap;
|
||||
typedef std::map<std::string, int> KeyMap;
|
||||
|
||||
ShortcutMap mShortcuts;
|
||||
SequenceMap mSequences;
|
||||
ModifierMap mModifiers;
|
||||
|
||||
NameMap mNames;
|
||||
KeyMap mKeys;
|
||||
|
||||
ShortcutEventHandler* mEventHandler;
|
||||
|
||||
void createLookupTables();
|
||||
|
||||
static const std::pair<int, const char*> QtKeys[];
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
197
apps/opencs/model/prefs/shortcutsetting.cpp
Normal file
197
apps/opencs/model/prefs/shortcutsetting.cpp
Normal file
|
@ -0,0 +1,197 @@
|
|||
#include "shortcutsetting.hpp"
|
||||
|
||||
#include <QEvent>
|
||||
#include <QKeyEvent>
|
||||
#include <QLabel>
|
||||
#include <QMouseEvent>
|
||||
#include <QPushButton>
|
||||
#include <QWidget>
|
||||
|
||||
#include "state.hpp"
|
||||
#include "shortcutmanager.hpp"
|
||||
|
||||
namespace CSMPrefs
|
||||
{
|
||||
const int ShortcutSetting::MaxKeys;
|
||||
|
||||
ShortcutSetting::ShortcutSetting(Category* parent, Settings::Manager* values, QMutex* mutex, const std::string& key,
|
||||
const std::string& label)
|
||||
: Setting(parent, values, mutex, key, label)
|
||||
, mButton(0)
|
||||
, mEditorActive(false)
|
||||
, mEditorPos(0)
|
||||
{
|
||||
for (int i = 0; i < MaxKeys; ++i)
|
||||
{
|
||||
mEditorKeys[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<QWidget*, QWidget*> ShortcutSetting::makeWidgets(QWidget* parent)
|
||||
{
|
||||
QKeySequence sequence;
|
||||
State::get().getShortcutManager().getSequence(getKey(), sequence);
|
||||
|
||||
QString text = QString::fromUtf8(State::get().getShortcutManager().convertToString(sequence).c_str());
|
||||
|
||||
QLabel* label = new QLabel(QString::fromUtf8(getLabel().c_str()), parent);
|
||||
QPushButton* widget = new QPushButton(text, parent);
|
||||
|
||||
widget->setCheckable(true);
|
||||
widget->installEventFilter(this);
|
||||
mButton = widget;
|
||||
|
||||
connect(widget, SIGNAL(toggled(bool)), this, SLOT(buttonToggled(bool)));
|
||||
|
||||
return std::make_pair(label, widget);
|
||||
}
|
||||
|
||||
bool ShortcutSetting::eventFilter(QObject* target, QEvent* event)
|
||||
{
|
||||
if (event->type() == QEvent::KeyPress)
|
||||
{
|
||||
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
|
||||
if (keyEvent->isAutoRepeat())
|
||||
return true;
|
||||
|
||||
int mod = keyEvent->modifiers();
|
||||
int key = keyEvent->key();
|
||||
|
||||
return handleEvent(target, mod, key, true);
|
||||
}
|
||||
else if (event->type() == QEvent::KeyRelease)
|
||||
{
|
||||
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
|
||||
if (keyEvent->isAutoRepeat())
|
||||
return true;
|
||||
|
||||
int mod = keyEvent->modifiers();
|
||||
int key = keyEvent->key();
|
||||
|
||||
return handleEvent(target, mod, key, false);
|
||||
}
|
||||
else if (event->type() == QEvent::MouseButtonPress)
|
||||
{
|
||||
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
int mod = mouseEvent->modifiers();
|
||||
int key = mouseEvent->button();
|
||||
|
||||
return handleEvent(target, mod, key, true);
|
||||
}
|
||||
else if (event->type() == QEvent::MouseButtonRelease)
|
||||
{
|
||||
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
int mod = mouseEvent->modifiers();
|
||||
int key = mouseEvent->button();
|
||||
|
||||
return handleEvent(target, mod, key, false);
|
||||
}
|
||||
else if (event->type() == QEvent::FocusOut)
|
||||
{
|
||||
resetState();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ShortcutSetting::handleEvent(QObject* target, int mod, int value, bool active)
|
||||
{
|
||||
// Modifiers are handled differently
|
||||
const int Blacklist[] =
|
||||
{
|
||||
Qt::Key_Shift,
|
||||
Qt::Key_Control,
|
||||
Qt::Key_Meta,
|
||||
Qt::Key_Alt,
|
||||
Qt::Key_AltGr
|
||||
};
|
||||
|
||||
const size_t BlacklistSize = sizeof(Blacklist) / sizeof(int);
|
||||
|
||||
if (!mEditorActive)
|
||||
{
|
||||
if (value == Qt::RightButton && !active)
|
||||
{
|
||||
// Clear sequence
|
||||
QKeySequence sequence = QKeySequence(0, 0, 0, 0);
|
||||
storeValue(sequence);
|
||||
|
||||
resetState();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle blacklist
|
||||
for (size_t i = 0; i < BlacklistSize; ++i)
|
||||
{
|
||||
if (value == Blacklist[i])
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!active || mEditorPos >= MaxKeys)
|
||||
{
|
||||
// Update key
|
||||
QKeySequence sequence = QKeySequence(mEditorKeys[0], mEditorKeys[1], mEditorKeys[2], mEditorKeys[3]);
|
||||
storeValue(sequence);
|
||||
|
||||
resetState();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mEditorPos == 0)
|
||||
{
|
||||
mEditorKeys[0] = mod | value;
|
||||
}
|
||||
else
|
||||
{
|
||||
mEditorKeys[mEditorPos] = value;
|
||||
}
|
||||
|
||||
mEditorPos += 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ShortcutSetting::storeValue(const QKeySequence& sequence)
|
||||
{
|
||||
State::get().getShortcutManager().setSequence(getKey(), sequence);
|
||||
|
||||
// Convert to string and assign
|
||||
std::string value = State::get().getShortcutManager().convertToString(sequence);
|
||||
|
||||
{
|
||||
QMutexLocker lock(getMutex());
|
||||
getValues().setString(getKey(), getParent()->getKey(), value);
|
||||
}
|
||||
|
||||
getParent()->getState()->update(*this);
|
||||
}
|
||||
|
||||
void ShortcutSetting::resetState()
|
||||
{
|
||||
mButton->setChecked(false);
|
||||
mEditorActive = false;
|
||||
mEditorPos = 0;
|
||||
for (int i = 0; i < MaxKeys; ++i)
|
||||
{
|
||||
mEditorKeys[i] = 0;
|
||||
}
|
||||
|
||||
// Button text
|
||||
QKeySequence sequence;
|
||||
State::get().getShortcutManager().getSequence(getKey(), sequence);
|
||||
|
||||
QString text = QString::fromUtf8(State::get().getShortcutManager().convertToString(sequence).c_str());
|
||||
mButton->setText(text);
|
||||
}
|
||||
|
||||
void ShortcutSetting::buttonToggled(bool checked)
|
||||
{
|
||||
if (checked)
|
||||
mButton->setText("Press keys or click here...");
|
||||
|
||||
mEditorActive = checked;
|
||||
}
|
||||
}
|
49
apps/opencs/model/prefs/shortcutsetting.hpp
Normal file
49
apps/opencs/model/prefs/shortcutsetting.hpp
Normal file
|
@ -0,0 +1,49 @@
|
|||
#ifndef CSM_PREFS_SHORTCUTSETTING_H
|
||||
#define CSM_PREFS_SHORTCUTSETTING_H
|
||||
|
||||
#include <QKeySequence>
|
||||
|
||||
#include "setting.hpp"
|
||||
|
||||
class QEvent;
|
||||
class QPushButton;
|
||||
|
||||
namespace CSMPrefs
|
||||
{
|
||||
class ShortcutSetting : public Setting
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
ShortcutSetting(Category* parent, Settings::Manager* values, QMutex* mutex, const std::string& key,
|
||||
const std::string& label);
|
||||
|
||||
virtual std::pair<QWidget*, QWidget*> makeWidgets(QWidget* parent);
|
||||
|
||||
protected:
|
||||
|
||||
bool eventFilter(QObject* target, QEvent* event);
|
||||
|
||||
private:
|
||||
|
||||
bool handleEvent(QObject* target, int mod, int value, bool active);
|
||||
|
||||
void storeValue(const QKeySequence& sequence);
|
||||
void resetState();
|
||||
|
||||
static const int MaxKeys = 4;
|
||||
|
||||
QPushButton* mButton;
|
||||
|
||||
bool mEditorActive;
|
||||
int mEditorPos;
|
||||
int mEditorKeys[MaxKeys];
|
||||
|
||||
private slots:
|
||||
|
||||
void buttonToggled(bool checked);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -9,6 +9,8 @@
|
|||
#include "doublesetting.hpp"
|
||||
#include "boolsetting.hpp"
|
||||
#include "coloursetting.hpp"
|
||||
#include "shortcutsetting.hpp"
|
||||
#include "modifiersetting.hpp"
|
||||
|
||||
CSMPrefs::State *CSMPrefs::State::sThis = 0;
|
||||
|
||||
|
@ -136,6 +138,9 @@ void CSMPrefs::State::declare()
|
|||
declareBool ("wrap-lines", "Wrap Lines", false).
|
||||
setTooltip ("Wrap lines longer than width of script editor.");
|
||||
declareBool ("mono-font", "Use monospace font", true);
|
||||
declareInt ("tab-width", "Tab Width", 4).
|
||||
setTooltip ("Number of characters for tab width").
|
||||
setRange (1, 10);
|
||||
EnumValue warningsNormal ("Normal", "Report warnings as warning");
|
||||
declareEnum ("warnings", "Warning Mode", warningsNormal).
|
||||
addValue ("Ignore", "Do not report warning").
|
||||
|
@ -162,20 +167,17 @@ void CSMPrefs::State::declare()
|
|||
"list go to the first/last item");
|
||||
|
||||
declareCategory ("3D Scene Input");
|
||||
EnumValue left ("Left Mouse-Button");
|
||||
EnumValue cLeft ("Ctrl-Left Mouse-Button");
|
||||
EnumValue right ("Right Mouse-Button");
|
||||
EnumValue cRight ("Ctrl-Right Mouse-Button");
|
||||
EnumValue middle ("Middle Mouse-Button");
|
||||
EnumValue cMiddle ("Ctrl-Middle Mouse-Button");
|
||||
EnumValues inputButtons;
|
||||
inputButtons.add (left).add (cLeft).add (right).add (cRight).add (middle).add (cMiddle);
|
||||
declareEnum ("p-navi", "Primary Camera Navigation Button", left).addValues (inputButtons);
|
||||
declareEnum ("s-navi", "Secondary Camera Navigation Button", cLeft).addValues (inputButtons);
|
||||
declareEnum ("p-edit", "Primary Editing Button", right).addValues (inputButtons);
|
||||
declareEnum ("s-edit", "Secondary Editing Button", cRight).addValues (inputButtons);
|
||||
declareEnum ("p-select", "Primary Selection Button", middle).addValues (inputButtons);
|
||||
declareEnum ("s-select", "Secondary Selection Button", cMiddle).addValues (inputButtons);
|
||||
declareDouble ("p-navi-free-sensitivity", "Free Camera Sensitivity", 1/650.).setPrecision(5).setRange(0.0, 1.0);
|
||||
declareBool ("p-navi-free-invert", "Invert Free Camera Mouse Input", false);
|
||||
declareDouble ("p-navi-orbit-sensitivity", "Orbit Camera Sensitivity", 1/650.).setPrecision(5).setRange(0.0, 1.0);
|
||||
declareBool ("p-navi-orbit-invert", "Invert Orbit Camera Mouse Input", false);
|
||||
declareDouble ("s-navi-sensitivity", "Secondary Camera Movement Sensitivity", 50.0).setRange(-1000.0, 1000.0);
|
||||
declareDouble ("navi-wheel-factor", "Camera Zoom Sensitivity", 8).setRange(-100.0, 100.0);
|
||||
declareDouble ("navi-free-lin-speed", "Free Camera Linear Speed", 1000.0).setRange(1.0, 10000.0);
|
||||
declareDouble ("navi-free-rot-speed", "Free Camera Rotational Speed", 3.14 / 2).setRange(0.001, 6.28);
|
||||
declareDouble ("navi-free-speed-mult", "Free Camera Speed Multiplier (from Modifier)", 8).setRange(0.001, 1000.0);
|
||||
declareDouble ("navi-orbit-rot-speed", "Orbital Camera Rotational Speed", 3.14 / 4).setRange(0.001, 6.28);
|
||||
declareDouble ("navi-orbit-speed-mult", "Orbital Camera Speed Multiplier (from Modifier)", 4).setRange(0.001, 1000.0);
|
||||
declareSeparator();
|
||||
declareBool ("context-select", "Context Sensitive Selection", false);
|
||||
declareDouble ("drag-factor", "Mouse sensitivity during drag operations", 1.0).
|
||||
|
@ -186,6 +188,7 @@ void CSMPrefs::State::declare()
|
|||
"Shift-acceleration factor during drag operations", 4.0).
|
||||
setTooltip ("Acceleration factor during drag operations while holding down shift").
|
||||
setRange (0.001, 100.0);
|
||||
declareDouble ("rotate-factor", "Free rotation factor", 0.007).setPrecision(4).setRange(0.0001, 0.1);
|
||||
|
||||
declareCategory ("Tooltips");
|
||||
declareBool ("scene", "Show Tooltips in 3D scenes", true);
|
||||
|
@ -210,6 +213,119 @@ void CSMPrefs::State::declare()
|
|||
addValues (insertOutsideCell);
|
||||
declareEnum ("outside-visible-drop", "Handling drops outside of visible cells", showAndInsert).
|
||||
addValues (insertOutsideVisibleCell);
|
||||
|
||||
declareCategory ("Key Bindings");
|
||||
|
||||
declareSubcategory ("Document");
|
||||
declareShortcut ("document-file-newgame", "New Game", QKeySequence(Qt::ControlModifier | Qt::Key_N));
|
||||
declareShortcut ("document-file-newaddon", "New Addon", QKeySequence());
|
||||
declareShortcut ("document-file-open", "Open", QKeySequence(Qt::ControlModifier | Qt::Key_O));
|
||||
declareShortcut ("document-file-save", "Save", QKeySequence(Qt::ControlModifier | Qt::Key_S));
|
||||
declareShortcut ("document-file-verify", "Verify", QKeySequence());
|
||||
declareShortcut ("document-file-merge", "Merge", QKeySequence());
|
||||
declareShortcut ("document-file-errorlog", "Open Load Error Log", QKeySequence());
|
||||
declareShortcut ("document-file-metadata", "Meta Data", QKeySequence());
|
||||
declareShortcut ("document-file-close", "Close Document", QKeySequence(Qt::ControlModifier | Qt::Key_W));
|
||||
declareShortcut ("document-file-exit", "Exit Application", QKeySequence(Qt::ControlModifier | Qt::Key_Q));
|
||||
declareShortcut ("document-edit-undo", "Undo", QKeySequence(Qt::ControlModifier | Qt::Key_Z));
|
||||
declareShortcut ("document-edit-redo", "Redo", QKeySequence(Qt::ControlModifier | Qt::ShiftModifier | Qt::Key_Z));
|
||||
declareShortcut ("document-edit-preferences", "Open Preferences", QKeySequence());
|
||||
declareShortcut ("document-edit-search", "Search", QKeySequence(Qt::ControlModifier | Qt::Key_F));
|
||||
declareShortcut ("document-view-newview", "New View", QKeySequence());
|
||||
declareShortcut ("document-view-statusbar", "Toggle Status Bar", QKeySequence());
|
||||
declareShortcut ("document-view-filters", "Open Filter List", QKeySequence());
|
||||
declareShortcut ("document-world-regions", "Open Region List", QKeySequence());
|
||||
declareShortcut ("document-world-cells", "Open Cell List", QKeySequence());
|
||||
declareShortcut ("document-world-referencables", "Open Object List", QKeySequence());
|
||||
declareShortcut ("document-world-references", "Open Instance List", QKeySequence());
|
||||
declareShortcut ("document-world-pathgrid", "Open Pathgrid List", QKeySequence());
|
||||
declareShortcut ("document-world-regionmap", "Open Region Map", QKeySequence());
|
||||
declareShortcut ("document-mechanics-globals", "Open Global List", QKeySequence());
|
||||
declareShortcut ("document-mechanics-gamesettings", "Open Game Settings", QKeySequence());
|
||||
declareShortcut ("document-mechanics-scripts", "Open Script List", QKeySequence());
|
||||
declareShortcut ("document-mechanics-spells", "Open Spell List", QKeySequence());
|
||||
declareShortcut ("document-mechanics-enchantments", "Open Enchantment List", QKeySequence());
|
||||
declareShortcut ("document-mechanics-magiceffects", "Open Magic Effect List", QKeySequence());
|
||||
declareShortcut ("document-mechanics-startscripts", "Open Start Script List", QKeySequence());
|
||||
declareShortcut ("document-character-skills", "Open Skill List", QKeySequence());
|
||||
declareShortcut ("document-character-classes", "Open Class List", QKeySequence());
|
||||
declareShortcut ("document-character-factions", "Open Faction List", QKeySequence());
|
||||
declareShortcut ("document-character-races", "Open Race List", QKeySequence());
|
||||
declareShortcut ("document-character-birthsigns", "Open Birthsign List", QKeySequence());
|
||||
declareShortcut ("document-character-topics", "Open Topic List", QKeySequence());
|
||||
declareShortcut ("document-character-journals", "Open Journal List", QKeySequence());
|
||||
declareShortcut ("document-character-topicinfos", "Open Topic Info List", QKeySequence());
|
||||
declareShortcut ("document-character-journalinfos", "Open Journal Info List", QKeySequence());
|
||||
declareShortcut ("document-character-bodyparts", "Open Body Part List", QKeySequence());
|
||||
declareShortcut ("document-assets-sounds", "Open Sound Asset List", QKeySequence());
|
||||
declareShortcut ("document-assets-soundgens", "Open Sound Generator List", QKeySequence());
|
||||
declareShortcut ("document-assets-meshes", "Open Mesh Asset List", QKeySequence());
|
||||
declareShortcut ("document-assets-icons", "Open Icon Asset List", QKeySequence());
|
||||
declareShortcut ("document-assets-music", "Open Music Asset List", QKeySequence());
|
||||
declareShortcut ("document-assets-soundres", "Open Sound File List", QKeySequence());
|
||||
declareShortcut ("document-assets-textures", "Open Texture Asset List", QKeySequence());
|
||||
declareShortcut ("document-assets-videos", "Open Video Asset List", QKeySequence());
|
||||
declareShortcut ("document-debug-run", "Run Debug", QKeySequence());
|
||||
declareShortcut ("document-debug-shutdown", "Stop Debug", QKeySequence());
|
||||
declareShortcut ("document-debug-runlog", "Open Run Log", QKeySequence());
|
||||
|
||||
declareSubcategory ("Table");
|
||||
declareShortcut ("table-edit", "Edit Record", QKeySequence());
|
||||
declareShortcut ("table-add", "Add Row/Record", QKeySequence(Qt::ShiftModifier | Qt::Key_A));
|
||||
declareShortcut ("table-clone", "Clone Record", QKeySequence(Qt::ShiftModifier | Qt::Key_D));
|
||||
declareShortcut ("table-revert", "Revert Record", QKeySequence());
|
||||
declareShortcut ("table-remove", "Remove Row/Record", QKeySequence(Qt::Key_Delete));
|
||||
declareShortcut ("table-moveup", "Move Record Up", QKeySequence());
|
||||
declareShortcut ("table-movedown", "Move Record Down", QKeySequence());
|
||||
declareShortcut ("table-view", "View Record", QKeySequence());
|
||||
declareShortcut ("table-preview", "Preview Record", QKeySequence());
|
||||
declareShortcut ("table-extendeddelete", "Extended Record Deletion", QKeySequence());
|
||||
declareShortcut ("table-extendedrevert", "Extended Record Revertion", QKeySequence());
|
||||
|
||||
declareSubcategory ("Report Table");
|
||||
declareShortcut ("reporttable-show", "Show Report", QKeySequence());
|
||||
declareShortcut ("reporttable-remove", "Remove Report", QKeySequence(Qt::Key_Delete));
|
||||
declareShortcut ("reporttable-replace", "Replace Report", QKeySequence());
|
||||
declareShortcut ("reporttable-refresh", "Refresh Report", QKeySequence());
|
||||
|
||||
declareSubcategory ("Scene");
|
||||
declareShortcut ("scene-navi-primary", "Camera Rotation From Mouse Movement", QKeySequence(Qt::LeftButton));
|
||||
declareShortcut ("scene-navi-secondary", "Camera Translation From Mouse Movement",
|
||||
QKeySequence(Qt::ControlModifier | (int)Qt::LeftButton));
|
||||
declareShortcut ("scene-edit-primary", "Primary Edit", QKeySequence(Qt::RightButton));
|
||||
declareShortcut ("scene-edit-secondary", "Secondary Edit",
|
||||
QKeySequence(Qt::ControlModifier | (int)Qt::RightButton));
|
||||
declareShortcut ("scene-select-primary", "Primary Select", QKeySequence(Qt::MiddleButton));
|
||||
declareShortcut ("scene-select-secondary", "Secondary Select",
|
||||
QKeySequence(Qt::ControlModifier | (int)Qt::MiddleButton));
|
||||
declareModifier ("scene-speed-modifier", "Speed Modifier", Qt::Key_Shift);
|
||||
declareShortcut ("scene-load-cam-cell", "Load Camera Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_5));
|
||||
declareShortcut ("scene-load-cam-eastcell", "Load East Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_6));
|
||||
declareShortcut ("scene-load-cam-northcell", "Load North Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_8));
|
||||
declareShortcut ("scene-load-cam-westcell", "Load West Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_4));
|
||||
declareShortcut ("scene-load-cam-southcell", "Load South Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_2));
|
||||
declareShortcut ("scene-edit-abort", "Abort", QKeySequence(Qt::Key_Escape));
|
||||
declareShortcut ("scene-focus-toolbar", "Toggle Toolbar Focus", QKeySequence(Qt::Key_T));
|
||||
declareShortcut ("scene-render-stats", "Debug Rendering Stats", QKeySequence(Qt::Key_F3));
|
||||
|
||||
declareSubcategory ("1st/Free Camera");
|
||||
declareShortcut ("free-forward", "Forward", QKeySequence(Qt::Key_W));
|
||||
declareShortcut ("free-backward", "Backward", QKeySequence(Qt::Key_S));
|
||||
declareShortcut ("free-left", "Left", QKeySequence(Qt::Key_A));
|
||||
declareShortcut ("free-right", "Right", QKeySequence(Qt::Key_D));
|
||||
declareShortcut ("free-roll-left", "Roll Left", QKeySequence(Qt::Key_Q));
|
||||
declareShortcut ("free-roll-right", "Roll Right", QKeySequence(Qt::Key_E));
|
||||
declareShortcut ("free-speed-mode", "Toggle Speed Mode", QKeySequence(Qt::Key_F));
|
||||
|
||||
declareSubcategory ("Orbit Camera");
|
||||
declareShortcut ("orbit-up", "Up", QKeySequence(Qt::Key_W));
|
||||
declareShortcut ("orbit-down", "Down", QKeySequence(Qt::Key_S));
|
||||
declareShortcut ("orbit-left", "Left", QKeySequence(Qt::Key_A));
|
||||
declareShortcut ("orbit-right", "Right", QKeySequence(Qt::Key_D));
|
||||
declareShortcut ("orbit-roll-left", "Roll Left", QKeySequence(Qt::Key_Q));
|
||||
declareShortcut ("orbit-roll-right", "Roll Right", QKeySequence(Qt::Key_E));
|
||||
declareShortcut ("orbit-speed-mode", "Toggle Speed Mode", QKeySequence(Qt::Key_F));
|
||||
declareShortcut ("orbit-center-selection", "Center On Selected", QKeySequence(Qt::Key_C));
|
||||
}
|
||||
|
||||
void CSMPrefs::State::declareCategory (const std::string& key)
|
||||
|
@ -326,6 +442,50 @@ CSMPrefs::ColourSetting& CSMPrefs::State::declareColour (const std::string& key,
|
|||
return *setting;
|
||||
}
|
||||
|
||||
CSMPrefs::ShortcutSetting& CSMPrefs::State::declareShortcut (const std::string& key, const std::string& label,
|
||||
const QKeySequence& default_)
|
||||
{
|
||||
if (mCurrentCategory==mCategories.end())
|
||||
throw std::logic_error ("no category for setting");
|
||||
|
||||
std::string seqStr = getShortcutManager().convertToString(default_);
|
||||
setDefault (key, seqStr);
|
||||
|
||||
// Setup with actual data
|
||||
QKeySequence sequence;
|
||||
|
||||
getShortcutManager().convertFromString(mSettings.getString(key, mCurrentCategory->second.getKey()), sequence);
|
||||
getShortcutManager().setSequence(key, sequence);
|
||||
|
||||
CSMPrefs::ShortcutSetting *setting = new CSMPrefs::ShortcutSetting (&mCurrentCategory->second, &mSettings, &mMutex,
|
||||
key, label);
|
||||
mCurrentCategory->second.addSetting (setting);
|
||||
|
||||
return *setting;
|
||||
}
|
||||
|
||||
CSMPrefs::ModifierSetting& CSMPrefs::State::declareModifier(const std::string& key, const std::string& label,
|
||||
int default_)
|
||||
{
|
||||
if (mCurrentCategory==mCategories.end())
|
||||
throw std::logic_error ("no category for setting");
|
||||
|
||||
std::string modStr = getShortcutManager().convertToString(default_);
|
||||
setDefault (key, modStr);
|
||||
|
||||
// Setup with actual data
|
||||
int modifier;
|
||||
|
||||
getShortcutManager().convertFromString(mSettings.getString(key, mCurrentCategory->second.getKey()), modifier);
|
||||
getShortcutManager().setModifier(key, modifier);
|
||||
|
||||
CSMPrefs::ModifierSetting *setting = new CSMPrefs::ModifierSetting (&mCurrentCategory->second, &mSettings, &mMutex,
|
||||
key, label);
|
||||
mCurrentCategory->second.addSetting (setting);
|
||||
|
||||
return *setting;
|
||||
}
|
||||
|
||||
void CSMPrefs::State::declareSeparator()
|
||||
{
|
||||
if (mCurrentCategory==mCategories.end())
|
||||
|
@ -337,6 +497,17 @@ void CSMPrefs::State::declareSeparator()
|
|||
mCurrentCategory->second.addSetting (setting);
|
||||
}
|
||||
|
||||
void CSMPrefs::State::declareSubcategory(const std::string& label)
|
||||
{
|
||||
if (mCurrentCategory==mCategories.end())
|
||||
throw std::logic_error ("no category for setting");
|
||||
|
||||
CSMPrefs::Setting *setting =
|
||||
new CSMPrefs::Setting (&mCurrentCategory->second, &mSettings, &mMutex, "", label);
|
||||
|
||||
mCurrentCategory->second.addSetting (setting);
|
||||
}
|
||||
|
||||
void CSMPrefs::State::setDefault (const std::string& key, const std::string& default_)
|
||||
{
|
||||
Settings::CategorySetting fullKey (mCurrentCategory->second.getKey(), key);
|
||||
|
@ -355,10 +526,10 @@ CSMPrefs::State::State (const Files::ConfigurationManager& configurationManager)
|
|||
if (sThis)
|
||||
throw std::logic_error ("An instance of CSMPRefs::State already exists");
|
||||
|
||||
sThis = this;
|
||||
|
||||
load();
|
||||
declare();
|
||||
|
||||
sThis = this;
|
||||
}
|
||||
|
||||
CSMPrefs::State::~State()
|
||||
|
@ -382,6 +553,11 @@ CSMPrefs::State::Iterator CSMPrefs::State::end()
|
|||
return mCategories.end();
|
||||
}
|
||||
|
||||
CSMPrefs::ShortcutManager& CSMPrefs::State::getShortcutManager()
|
||||
{
|
||||
return mShortcutManager;
|
||||
}
|
||||
|
||||
CSMPrefs::Category& CSMPrefs::State::operator[] (const std::string& key)
|
||||
{
|
||||
Iterator iter = mCategories.find (key);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#ifndef CSV_PREFS_STATE_H
|
||||
#ifndef CSM_PREFS_STATE_H
|
||||
#define CSM_PREFS_STATE_H
|
||||
|
||||
#include <map>
|
||||
|
@ -16,6 +16,7 @@
|
|||
#include "category.hpp"
|
||||
#include "setting.hpp"
|
||||
#include "enumsetting.hpp"
|
||||
#include "shortcutmanager.hpp"
|
||||
|
||||
class QColor;
|
||||
|
||||
|
@ -25,6 +26,8 @@ namespace CSMPrefs
|
|||
class DoubleSetting;
|
||||
class BoolSetting;
|
||||
class ColourSetting;
|
||||
class ShortcutSetting;
|
||||
class ModifierSetting;
|
||||
|
||||
/// \brief User settings state
|
||||
///
|
||||
|
@ -45,6 +48,7 @@ namespace CSMPrefs
|
|||
|
||||
const std::string mConfigFile;
|
||||
const Files::ConfigurationManager& mConfigurationManager;
|
||||
ShortcutManager mShortcutManager;
|
||||
Settings::Manager mSettings;
|
||||
Collection mCategories;
|
||||
Iterator mCurrentCategory;
|
||||
|
@ -71,8 +75,15 @@ namespace CSMPrefs
|
|||
|
||||
ColourSetting& declareColour (const std::string& key, const std::string& label, QColor default_);
|
||||
|
||||
ShortcutSetting& declareShortcut (const std::string& key, const std::string& label,
|
||||
const QKeySequence& default_);
|
||||
|
||||
ModifierSetting& declareModifier(const std::string& key, const std::string& label, int modifier_);
|
||||
|
||||
void declareSeparator();
|
||||
|
||||
void declareSubcategory(const std::string& label);
|
||||
|
||||
void setDefault (const std::string& key, const std::string& default_);
|
||||
|
||||
public:
|
||||
|
@ -87,6 +98,8 @@ namespace CSMPrefs
|
|||
|
||||
Iterator end();
|
||||
|
||||
ShortcutManager& getShortcutManager();
|
||||
|
||||
Category& operator[](const std::string& key);
|
||||
|
||||
void update (const Setting& setting);
|
||||
|
|
79
apps/opencs/model/tools/journalcheck.cpp
Normal file
79
apps/opencs/model/tools/journalcheck.cpp
Normal file
|
@ -0,0 +1,79 @@
|
|||
#include "journalcheck.hpp"
|
||||
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
|
||||
CSMTools::JournalCheckStage::JournalCheckStage(const CSMWorld::IdCollection<ESM::Dialogue> &journals,
|
||||
const CSMWorld::InfoCollection& journalInfos)
|
||||
: mJournals(journals), mJournalInfos(journalInfos)
|
||||
{}
|
||||
|
||||
int CSMTools::JournalCheckStage::setup()
|
||||
{
|
||||
return mJournals.getSize();
|
||||
}
|
||||
|
||||
void CSMTools::JournalCheckStage::perform(int stage, CSMDoc::Messages& messages)
|
||||
{
|
||||
const CSMWorld::Record<ESM::Dialogue> &journalRecord = mJournals.getRecord(stage);
|
||||
|
||||
if (journalRecord.isDeleted())
|
||||
return;
|
||||
|
||||
const ESM::Dialogue &journal = journalRecord.get();
|
||||
int statusNamedCount = 0;
|
||||
int totalInfoCount = 0;
|
||||
std::set<int> questIndices;
|
||||
|
||||
CSMWorld::InfoCollection::Range range = mJournalInfos.getTopicRange(journal.mId);
|
||||
|
||||
for (CSMWorld::InfoCollection::RecordConstIterator it = range.first; it != range.second; ++it)
|
||||
{
|
||||
const CSMWorld::Record<CSMWorld::Info> infoRecord = (*it);
|
||||
|
||||
if (infoRecord.isDeleted())
|
||||
continue;
|
||||
|
||||
const CSMWorld::Info& journalInfo = infoRecord.get();
|
||||
|
||||
totalInfoCount += 1;
|
||||
|
||||
if (journalInfo.mQuestStatus == ESM::DialInfo::QS_Name)
|
||||
{
|
||||
statusNamedCount += 1;
|
||||
}
|
||||
|
||||
if (journalInfo.mResponse.empty())
|
||||
{
|
||||
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_JournalInfo, journalInfo.mId);
|
||||
|
||||
messages.add(id, "Journal Info: missing description", "", CSMDoc::Message::Severity_Warning);
|
||||
}
|
||||
|
||||
std::pair<std::set<int>::iterator, bool> result = questIndices.insert(journalInfo.mData.mJournalIndex);
|
||||
|
||||
// Duplicate index
|
||||
if (result.second == false)
|
||||
{
|
||||
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_JournalInfo, journalInfo.mId);
|
||||
|
||||
std::ostringstream stream;
|
||||
stream << "Journal: duplicated quest index " << journalInfo.mData.mJournalIndex;
|
||||
|
||||
messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error);
|
||||
}
|
||||
}
|
||||
|
||||
if (totalInfoCount == 0)
|
||||
{
|
||||
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Journal, journal.mId);
|
||||
|
||||
messages.add(id, "Journal: no defined Journal Infos", "", CSMDoc::Message::Severity_Warning);
|
||||
}
|
||||
else if (statusNamedCount > 1)
|
||||
{
|
||||
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Journal, journal.mId);
|
||||
|
||||
messages.add(id, "Journal: multiple infos with quest status \"Named\"", "", CSMDoc::Message::Severity_Error);
|
||||
}
|
||||
}
|
35
apps/opencs/model/tools/journalcheck.hpp
Normal file
35
apps/opencs/model/tools/journalcheck.hpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
#ifndef CSM_TOOLS_JOURNALCHECK_H
|
||||
#define CSM_TOOLS_JOURNALCHECK_H
|
||||
|
||||
#include <components/esm/loaddial.hpp>
|
||||
|
||||
#include "../world/idcollection.hpp"
|
||||
#include "../world/infocollection.hpp"
|
||||
|
||||
#include "../doc/stage.hpp"
|
||||
|
||||
namespace CSMTools
|
||||
{
|
||||
/// \brief VerifyStage: make sure that journal infos are good
|
||||
class JournalCheckStage : public CSMDoc::Stage
|
||||
{
|
||||
public:
|
||||
|
||||
JournalCheckStage(const CSMWorld::IdCollection<ESM::Dialogue>& journals,
|
||||
const CSMWorld::InfoCollection& journalInfos);
|
||||
|
||||
virtual int setup();
|
||||
///< \return number of steps
|
||||
|
||||
virtual void perform(int stage, CSMDoc::Messages& messages);
|
||||
///< Messages resulting from this stage will be appended to \a messages
|
||||
|
||||
private:
|
||||
|
||||
const CSMWorld::IdCollection<ESM::Dialogue>& mJournals;
|
||||
const CSMWorld::InfoCollection& mJournalInfos;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -99,6 +99,7 @@ void CSMTools::MergeReferencesStage::perform (int stage, CSMDoc::Messages& messa
|
|||
|
||||
ref.mRefNum.mIndex = mIndex[Misc::StringUtils::lowerCase (ref.mCell)]++;
|
||||
ref.mRefNum.mContentFile = 0;
|
||||
ref.mNew = false;
|
||||
|
||||
CSMWorld::Record<CSMWorld::CellRef> newRecord (
|
||||
CSMWorld::RecordBase::State_ModifiedOnly, 0, &ref);
|
||||
|
@ -128,7 +129,7 @@ void CSMTools::ListLandTexturesMergeStage::perform (int stage, CSMDoc::Messages&
|
|||
|
||||
// make sure record is loaded
|
||||
land.loadData (ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML |
|
||||
ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM);
|
||||
ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX);
|
||||
|
||||
if (const ESM::Land::LandData *data = land.getLandData (ESM::Land::DATA_VTEX))
|
||||
{
|
||||
|
@ -183,7 +184,7 @@ void CSMTools::MergeLandTexturesStage::perform (int stage, CSMDoc::Messages& mes
|
|||
CSMWorld::LandTexture texture =
|
||||
mState.mSource.getData().getLandTextures().getRecord (index).get();
|
||||
|
||||
std::ostringstream stream;
|
||||
stream.clear();
|
||||
stream << mNext->second-1 << "_0";
|
||||
|
||||
texture.mIndex = mNext->second-1;
|
||||
|
@ -220,7 +221,7 @@ void CSMTools::MergeLandStage::perform (int stage, CSMDoc::Messages& messages)
|
|||
const CSMWorld::Land& land = record.get();
|
||||
|
||||
land.loadData (ESM::Land::DATA_VCLR | ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML |
|
||||
ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM);
|
||||
ESM::Land::DATA_VTEX);
|
||||
|
||||
CSMWorld::Land newLand (land);
|
||||
|
||||
|
|
|
@ -70,20 +70,6 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
|
|||
|
||||
for (unsigned int i = 0; i < pathgrid.mPoints.size(); ++i)
|
||||
{
|
||||
// check the connection number for each point matches the edge connections
|
||||
if (pathgrid.mPoints[i].mConnectionNum > pointList[i].mConnectionNum)
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << " has has less edges than expected for point " << i;
|
||||
messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Error);
|
||||
}
|
||||
else if (pathgrid.mPoints[i].mConnectionNum < pointList[i].mConnectionNum)
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << " has has more edges than expected for point " << i;
|
||||
messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Error);
|
||||
}
|
||||
|
||||
// check that edges are bidirectional
|
||||
bool foundReverse = false;
|
||||
for (unsigned int j = 0; j < pointList[i].mOtherIndex.size(); ++j)
|
||||
|
|
|
@ -425,7 +425,7 @@ void CSMTools::ReferenceableCheckStage::creatureCheck (
|
|||
|
||||
//stats checks
|
||||
if (creature.mData.mLevel < 1)
|
||||
messages.push_back (std::make_pair (id, creature.mId + " has non-postive level"));
|
||||
messages.push_back (std::make_pair (id, creature.mId + " has non-positive level"));
|
||||
|
||||
if (creature.mData.mStrength < 0)
|
||||
messages.push_back (std::make_pair (id, creature.mId + " has negative strength"));
|
||||
|
@ -659,7 +659,7 @@ void CSMTools::ReferenceableCheckStage::npcCheck (
|
|||
{
|
||||
if ((npc.mFlags & ESM::NPC::Autocalc) == 0) //0x0010 = autocalculated flag
|
||||
{
|
||||
messages.push_back (std::make_pair (id, npc.mId + " mNpdtType or flags mismatch!")); //should not happend?
|
||||
messages.push_back (std::make_pair (id, npc.mId + " mNpdtType or flags mismatch!")); //should not happen?
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -915,7 +915,7 @@ void CSMTools::ReferenceableCheckStage::inventoryListCheck(
|
|||
id + " contains non-existing item (" + itemName + ")"));
|
||||
else
|
||||
{
|
||||
// Needs to accomodate Containers, Creatures, and NPCs
|
||||
// Needs to accommodate containers, creatures, and NPCs
|
||||
switch (localIndex.second)
|
||||
{
|
||||
case CSMWorld::UniversalId::Type_Potion:
|
||||
|
|
|
@ -29,9 +29,16 @@ void CSMTools::RegionCheckStage::perform (int stage, CSMDoc::Messages& messages)
|
|||
|
||||
// test for empty name
|
||||
if (region.mName.empty())
|
||||
messages.push_back (std::make_pair (id, region.mId + " has an empty name"));
|
||||
messages.add(id, region.mId + " has an empty name", "", CSMDoc::Message::Severity_Error);
|
||||
|
||||
/// \todo test that the ID in mSleeplist exists
|
||||
|
||||
// test that chances add up to 100
|
||||
int chances = region.mData.mClear + region.mData.mCloudy + region.mData.mFoggy + region.mData.mOvercast +
|
||||
region.mData.mRain + region.mData.mThunder + region.mData.mAsh + region.mData.mBlight +
|
||||
region.mData.mA + region.mData.mB;
|
||||
if (chances != 100)
|
||||
messages.add(id, "Weather chances do not add up to 100", "", CSMDoc::Message::Severity_Error);
|
||||
|
||||
/// \todo check data members that can't be edited in the table view
|
||||
}
|
||||
|
|
|
@ -37,14 +37,18 @@ int CSMTools::ReportModel::columnCount (const QModelIndex & parent) const
|
|||
|
||||
QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const
|
||||
{
|
||||
if (role!=Qt::DisplayRole)
|
||||
if (role!=Qt::DisplayRole && role!=Qt::UserRole)
|
||||
return QVariant();
|
||||
|
||||
switch (index.column())
|
||||
{
|
||||
case Column_Type:
|
||||
|
||||
return static_cast<int> (mRows.at (index.row()).mId.getType());
|
||||
if(role == Qt::UserRole)
|
||||
return QString::fromUtf8 (
|
||||
mRows.at (index.row()).mId.getTypeName().c_str());
|
||||
else
|
||||
return static_cast<int> (mRows.at (index.row()).mId.getType());
|
||||
|
||||
case Column_Id:
|
||||
{
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
#include "magiceffectcheck.hpp"
|
||||
#include "mergeoperation.hpp"
|
||||
#include "gmstcheck.hpp"
|
||||
#include "topicinfocheck.hpp"
|
||||
#include "journalcheck.hpp"
|
||||
|
||||
CSMDoc::OperationHolder *CSMTools::Tools::get (int type)
|
||||
{
|
||||
|
@ -111,9 +113,24 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier()
|
|||
mData.getReferenceables(),
|
||||
mData.getResources (CSMWorld::UniversalId::Type_Icons),
|
||||
mData.getResources (CSMWorld::UniversalId::Type_Textures)));
|
||||
|
||||
|
||||
mVerifierOperation->appendStage (new GmstCheckStage (mData.getGmsts()));
|
||||
|
||||
mVerifierOperation->appendStage (new TopicInfoCheckStage (mData.getTopicInfos(),
|
||||
mData.getCells(),
|
||||
mData.getClasses(),
|
||||
mData.getFactions(),
|
||||
mData.getGmsts(),
|
||||
mData.getGlobals(),
|
||||
mData.getJournals(),
|
||||
mData.getRaces(),
|
||||
mData.getRegions(),
|
||||
mData.getTopics(),
|
||||
mData.getReferenceables().getDataSet(),
|
||||
mData.getResources (CSMWorld::UniversalId::Type_SoundsRes)));
|
||||
|
||||
mVerifierOperation->appendStage (new JournalCheckStage(mData.getJournals(), mData.getJournalInfos()));
|
||||
|
||||
mVerifier.setOperation (mVerifierOperation);
|
||||
}
|
||||
|
||||
|
|
441
apps/opencs/model/tools/topicinfocheck.cpp
Normal file
441
apps/opencs/model/tools/topicinfocheck.cpp
Normal file
|
@ -0,0 +1,441 @@
|
|||
#include "topicinfocheck.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "../world/infoselectwrapper.hpp"
|
||||
|
||||
CSMTools::TopicInfoCheckStage::TopicInfoCheckStage(
|
||||
const CSMWorld::InfoCollection& topicInfos,
|
||||
const CSMWorld::IdCollection<CSMWorld::Cell>& cells,
|
||||
const CSMWorld::IdCollection<ESM::Class>& classes,
|
||||
const CSMWorld::IdCollection<ESM::Faction>& factions,
|
||||
const CSMWorld::IdCollection<ESM::GameSetting>& gmsts,
|
||||
const CSMWorld::IdCollection<ESM::Global>& globals,
|
||||
const CSMWorld::IdCollection<ESM::Dialogue>& journals,
|
||||
const CSMWorld::IdCollection<ESM::Race>& races,
|
||||
const CSMWorld::IdCollection<ESM::Region>& regions,
|
||||
const CSMWorld::IdCollection<ESM::Dialogue> &topics,
|
||||
const CSMWorld::RefIdData& referencables,
|
||||
const CSMWorld::Resources& soundFiles)
|
||||
: mTopicInfos(topicInfos),
|
||||
mCells(cells),
|
||||
mClasses(classes),
|
||||
mFactions(factions),
|
||||
mGameSettings(gmsts),
|
||||
mGlobals(globals),
|
||||
mJournals(journals),
|
||||
mRaces(races),
|
||||
mRegions(regions),
|
||||
mTopics(topics),
|
||||
mReferencables(referencables),
|
||||
mSoundFiles(soundFiles)
|
||||
{}
|
||||
|
||||
int CSMTools::TopicInfoCheckStage::setup()
|
||||
{
|
||||
// Generate list of cell names for reference checking
|
||||
|
||||
mCellNames.clear();
|
||||
for (int i = 0; i < mCells.getSize(); ++i)
|
||||
{
|
||||
const CSMWorld::Record<CSMWorld::Cell>& cellRecord = mCells.getRecord(i);
|
||||
|
||||
if (cellRecord.isDeleted())
|
||||
continue;
|
||||
|
||||
mCellNames.insert(cellRecord.get().mName);
|
||||
}
|
||||
// Cell names can also include region names
|
||||
for (int i = 0; i < mRegions.getSize(); ++i)
|
||||
{
|
||||
const CSMWorld::Record<ESM::Region>& regionRecord = mRegions.getRecord(i);
|
||||
|
||||
if (regionRecord.isDeleted())
|
||||
continue;
|
||||
|
||||
mCellNames.insert(regionRecord.get().mName);
|
||||
}
|
||||
// Default cell name
|
||||
int index = mGameSettings.searchId("sDefaultCellname");
|
||||
if (index != -1)
|
||||
{
|
||||
const CSMWorld::Record<ESM::GameSetting>& gmstRecord = mGameSettings.getRecord(index);
|
||||
|
||||
if (!gmstRecord.isDeleted() && gmstRecord.get().mValue.getType() == ESM::VT_String)
|
||||
{
|
||||
mCellNames.insert(gmstRecord.get().mValue.getString());
|
||||
}
|
||||
}
|
||||
|
||||
return mTopicInfos.getSize();
|
||||
}
|
||||
|
||||
void CSMTools::TopicInfoCheckStage::perform(int stage, CSMDoc::Messages& messages)
|
||||
{
|
||||
const CSMWorld::Record<CSMWorld::Info>& infoRecord = mTopicInfos.getRecord(stage);
|
||||
|
||||
if (infoRecord.isDeleted())
|
||||
return;
|
||||
|
||||
const CSMWorld::Info& topicInfo = infoRecord.get();
|
||||
|
||||
// There should always be a topic that matches
|
||||
int topicIndex = mTopics.searchId(topicInfo.mTopicId);
|
||||
|
||||
const CSMWorld::Record<ESM::Dialogue>& topicRecord = mTopics.getRecord(topicIndex);
|
||||
|
||||
if (topicRecord.isDeleted())
|
||||
return;
|
||||
|
||||
const ESM::Dialogue& topic = topicRecord.get();
|
||||
|
||||
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_TopicInfo, topicInfo.mId);
|
||||
|
||||
// Check fields
|
||||
|
||||
if (!topicInfo.mActor.empty())
|
||||
{
|
||||
verifyActor(topicInfo.mActor, id, messages);
|
||||
}
|
||||
|
||||
if (!topicInfo.mClass.empty())
|
||||
{
|
||||
verifyId(topicInfo.mClass, mClasses, id, messages);
|
||||
}
|
||||
|
||||
if (!topicInfo.mCell.empty())
|
||||
{
|
||||
verifyCell(topicInfo.mCell, id, messages);
|
||||
}
|
||||
|
||||
if (!topicInfo.mFaction.empty() && !topicInfo.mFactionLess)
|
||||
{
|
||||
if (verifyId(topicInfo.mFaction, mFactions, id, messages))
|
||||
{
|
||||
verifyFactionRank(topicInfo.mFaction, topicInfo.mData.mRank, id, messages);
|
||||
}
|
||||
}
|
||||
|
||||
if (!topicInfo.mPcFaction.empty())
|
||||
{
|
||||
if (verifyId(topicInfo.mPcFaction, mFactions, id, messages))
|
||||
{
|
||||
verifyFactionRank(topicInfo.mPcFaction, topicInfo.mData.mPCrank, id, messages);
|
||||
}
|
||||
}
|
||||
|
||||
if (topicInfo.mData.mGender < -1 || topicInfo.mData.mGender > 1)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
messages.add(id, "Gender: Value is invalid", "", CSMDoc::Message::Severity_Error);
|
||||
}
|
||||
|
||||
if (!topicInfo.mRace.empty())
|
||||
{
|
||||
verifyId(topicInfo.mRace, mRaces, id, messages);
|
||||
}
|
||||
|
||||
if (!topicInfo.mSound.empty())
|
||||
{
|
||||
verifySound(topicInfo.mSound, id, messages);
|
||||
}
|
||||
|
||||
if (topicInfo.mResponse.empty() && topic.mType != ESM::Dialogue::Voice)
|
||||
{
|
||||
messages.add(id, "Response is empty", "", CSMDoc::Message::Severity_Warning);
|
||||
}
|
||||
|
||||
// Check info conditions
|
||||
|
||||
for (std::vector<ESM::DialInfo::SelectStruct>::const_iterator it = topicInfo.mSelects.begin();
|
||||
it != topicInfo.mSelects.end(); ++it)
|
||||
{
|
||||
verifySelectStruct((*it), id, messages);
|
||||
}
|
||||
}
|
||||
|
||||
// Verification functions
|
||||
|
||||
bool CSMTools::TopicInfoCheckStage::verifyActor(const std::string& actor, const CSMWorld::UniversalId& id,
|
||||
CSMDoc::Messages& messages)
|
||||
{
|
||||
const std::string specifier = "Actor";
|
||||
|
||||
CSMWorld::RefIdData::LocalIndex index = mReferencables.searchId(actor);
|
||||
|
||||
if (index.first == -1)
|
||||
{
|
||||
writeMissingIdError(specifier, actor, id, messages);
|
||||
return false;
|
||||
}
|
||||
else if (mReferencables.getRecord(index).isDeleted())
|
||||
{
|
||||
writeDeletedRecordError(specifier, actor, id, messages);
|
||||
return false;
|
||||
}
|
||||
else if (index.second != CSMWorld::UniversalId::Type_Npc && index.second != CSMWorld::UniversalId::Type_Creature)
|
||||
{
|
||||
writeInvalidTypeError(specifier, actor, index.second, "NPC or Creature", id, messages);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSMTools::TopicInfoCheckStage::verifyCell(const std::string& cell, const CSMWorld::UniversalId& id,
|
||||
CSMDoc::Messages& messages)
|
||||
{
|
||||
const std::string specifier = "Cell";
|
||||
|
||||
if (mCellNames.find(cell) == mCellNames.end())
|
||||
{
|
||||
writeMissingIdError(specifier, cell, id, messages);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSMTools::TopicInfoCheckStage::verifyFactionRank(const std::string& factionName, int rank, const CSMWorld::UniversalId& id,
|
||||
CSMDoc::Messages& messages)
|
||||
{
|
||||
if (rank < -1)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << "Rank or PC Rank is set to " << rank << ", but should be set to -1 if no rank is required";
|
||||
|
||||
messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
int index = mFactions.searchId(factionName);
|
||||
|
||||
const ESM::Faction &faction = mFactions.getRecord(index).get();
|
||||
|
||||
int limit = 0;
|
||||
for (; limit < 10; ++limit)
|
||||
{
|
||||
if (faction.mRanks[limit].empty())
|
||||
break;
|
||||
}
|
||||
|
||||
if (rank >= limit)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << "Rank or PC Rank is set to " << rank << " which is more than the maximum of " << limit - 1
|
||||
<< " for the " << factionName << " faction";
|
||||
|
||||
messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSMTools::TopicInfoCheckStage::verifyItem(const std::string& item, const CSMWorld::UniversalId& id,
|
||||
CSMDoc::Messages& messages)
|
||||
{
|
||||
const std::string specifier = "Item";
|
||||
|
||||
CSMWorld::RefIdData::LocalIndex index = mReferencables.searchId(item);
|
||||
|
||||
if (index.first == -1)
|
||||
{
|
||||
writeMissingIdError(specifier, item, id, messages);
|
||||
return false;
|
||||
}
|
||||
else if (mReferencables.getRecord(index).isDeleted())
|
||||
{
|
||||
writeDeletedRecordError(specifier, item, id, messages);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (index.second)
|
||||
{
|
||||
case CSMWorld::UniversalId::Type_Potion:
|
||||
case CSMWorld::UniversalId::Type_Apparatus:
|
||||
case CSMWorld::UniversalId::Type_Armor:
|
||||
case CSMWorld::UniversalId::Type_Book:
|
||||
case CSMWorld::UniversalId::Type_Clothing:
|
||||
case CSMWorld::UniversalId::Type_Ingredient:
|
||||
case CSMWorld::UniversalId::Type_Light:
|
||||
case CSMWorld::UniversalId::Type_Lockpick:
|
||||
case CSMWorld::UniversalId::Type_Miscellaneous:
|
||||
case CSMWorld::UniversalId::Type_Probe:
|
||||
case CSMWorld::UniversalId::Type_Repair:
|
||||
case CSMWorld::UniversalId::Type_Weapon:
|
||||
case CSMWorld::UniversalId::Type_ItemLevelledList:
|
||||
break;
|
||||
|
||||
default:
|
||||
writeInvalidTypeError(specifier, item, index.second, "Potion, Armor, Book, etc.", id, messages);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSMTools::TopicInfoCheckStage::verifySelectStruct(const ESM::DialInfo::SelectStruct& select,
|
||||
const CSMWorld::UniversalId& id, CSMDoc::Messages& messages)
|
||||
{
|
||||
CSMWorld::ConstInfoSelectWrapper infoCondition(select);
|
||||
|
||||
if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_None)
|
||||
{
|
||||
messages.add(id, "Invalid Info Condition: " + infoCondition.toString(), "", CSMDoc::Message::Severity_Error);
|
||||
return false;
|
||||
}
|
||||
else if (!infoCondition.variantTypeIsValid())
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << "Info Condition: Value for \"" << infoCondition.toString() << "\" has a type of ";
|
||||
|
||||
switch (select.mValue.getType())
|
||||
{
|
||||
case ESM::VT_None: stream << "None"; break;
|
||||
case ESM::VT_Short: stream << "Short"; break;
|
||||
case ESM::VT_Int: stream << "Int"; break;
|
||||
case ESM::VT_Long: stream << "Long"; break;
|
||||
case ESM::VT_Float: stream << "Float"; break;
|
||||
case ESM::VT_String: stream << "String"; break;
|
||||
default: stream << "Unknown"; break;
|
||||
}
|
||||
|
||||
messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error);
|
||||
return false;
|
||||
}
|
||||
else if (infoCondition.conditionIsAlwaysTrue())
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << "Info Condition: " << infoCondition.toString() << " is always true";
|
||||
|
||||
messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Warning);
|
||||
return false;
|
||||
}
|
||||
else if (infoCondition.conditionIsNeverTrue())
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << "Info Condition: " << infoCondition.toString() << " is never true";
|
||||
|
||||
messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Warning);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Id checks
|
||||
if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_Global &&
|
||||
!verifyId(infoCondition.getVariableName(), mGlobals, id, messages))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_Journal &&
|
||||
!verifyId(infoCondition.getVariableName(), mJournals, id, messages))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_Item &&
|
||||
!verifyItem(infoCondition.getVariableName(), id, messages))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_Dead &&
|
||||
!verifyActor(infoCondition.getVariableName(), id, messages))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_NotId &&
|
||||
!verifyActor(infoCondition.getVariableName(), id, messages))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_NotFaction &&
|
||||
!verifyId(infoCondition.getVariableName(), mFactions, id, messages))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_NotClass &&
|
||||
!verifyId(infoCondition.getVariableName(), mClasses, id, messages))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_NotRace &&
|
||||
!verifyId(infoCondition.getVariableName(), mRaces, id, messages))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (infoCondition.getFunctionName() == CSMWorld::ConstInfoSelectWrapper::Function_NotCell &&
|
||||
!verifyCell(infoCondition.getVariableName(), id, messages))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CSMTools::TopicInfoCheckStage::verifySound(const std::string& sound, const CSMWorld::UniversalId& id,
|
||||
CSMDoc::Messages& messages)
|
||||
{
|
||||
const std::string specifier = "Sound File";
|
||||
|
||||
if (mSoundFiles.searchId(sound) == -1)
|
||||
{
|
||||
writeMissingIdError(specifier, sound, id, messages);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool CSMTools::TopicInfoCheckStage::verifyId(const std::string& name, const CSMWorld::IdCollection<T>& collection,
|
||||
const CSMWorld::UniversalId& id, CSMDoc::Messages& messages)
|
||||
{
|
||||
int index = collection.searchId(name);
|
||||
|
||||
if (index == -1)
|
||||
{
|
||||
writeMissingIdError(T::getRecordType(), name, id, messages);
|
||||
return false;
|
||||
}
|
||||
else if (collection.getRecord(index).isDeleted())
|
||||
{
|
||||
writeDeletedRecordError(T::getRecordType(), name, id, messages);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Error functions
|
||||
|
||||
void CSMTools::TopicInfoCheckStage::writeMissingIdError(const std::string& specifier, const std::string& missingId,
|
||||
const CSMWorld::UniversalId& id, CSMDoc::Messages& messages)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << specifier << ": ID or name \"" << missingId << "\" could not be found";
|
||||
|
||||
messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error);
|
||||
}
|
||||
|
||||
void CSMTools::TopicInfoCheckStage::writeDeletedRecordError(const std::string& specifier, const std::string& recordId,
|
||||
const CSMWorld::UniversalId& id, CSMDoc::Messages& messages)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << specifier << ": Deleted record with ID \"" << recordId << "\" is being referenced";
|
||||
|
||||
messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error);
|
||||
}
|
||||
|
||||
void CSMTools::TopicInfoCheckStage::writeInvalidTypeError(const std::string& specifier, const std::string& invalidId,
|
||||
CSMWorld::UniversalId::Type invalidType, const std::string& expectedType, const CSMWorld::UniversalId& id,
|
||||
CSMDoc::Messages& messages)
|
||||
{
|
||||
CSMWorld::UniversalId tempId(invalidType, invalidId);
|
||||
|
||||
std::ostringstream stream;
|
||||
stream << specifier << ": invalid type of " << tempId.getTypeName() << " was found for referencable \""
|
||||
<< invalidId << "\" (can be of type " << expectedType << ")";
|
||||
|
||||
messages.add(id, stream.str(), "", CSMDoc::Message::Severity_Error);
|
||||
}
|
95
apps/opencs/model/tools/topicinfocheck.hpp
Normal file
95
apps/opencs/model/tools/topicinfocheck.hpp
Normal file
|
@ -0,0 +1,95 @@
|
|||
#ifndef CSM_TOOLS_TOPICINFOCHECK_HPP
|
||||
#define CSM_TOOLS_TOPICINFOCHECK_HPP
|
||||
|
||||
#include <set>
|
||||
|
||||
#include <components/esm/loadclas.hpp>
|
||||
#include <components/esm/loaddial.hpp>
|
||||
#include <components/esm/loadfact.hpp>
|
||||
#include <components/esm/loadglob.hpp>
|
||||
#include <components/esm/loadgmst.hpp>
|
||||
#include <components/esm/loadrace.hpp>
|
||||
#include <components/esm/loadregn.hpp>
|
||||
|
||||
#include "../world/cell.hpp"
|
||||
#include "../world/idcollection.hpp"
|
||||
#include "../world/infocollection.hpp"
|
||||
#include "../world/refiddata.hpp"
|
||||
#include "../world/resources.hpp"
|
||||
|
||||
#include "../doc/stage.hpp"
|
||||
|
||||
namespace CSMTools
|
||||
{
|
||||
/// \brief VerifyStage: check topics
|
||||
class TopicInfoCheckStage : public CSMDoc::Stage
|
||||
{
|
||||
public:
|
||||
|
||||
TopicInfoCheckStage(
|
||||
const CSMWorld::InfoCollection& topicInfos,
|
||||
const CSMWorld::IdCollection<CSMWorld::Cell>& cells,
|
||||
const CSMWorld::IdCollection<ESM::Class>& classes,
|
||||
const CSMWorld::IdCollection<ESM::Faction>& factions,
|
||||
const CSMWorld::IdCollection<ESM::GameSetting>& gmsts,
|
||||
const CSMWorld::IdCollection<ESM::Global>& globals,
|
||||
const CSMWorld::IdCollection<ESM::Dialogue>& journals,
|
||||
const CSMWorld::IdCollection<ESM::Race>& races,
|
||||
const CSMWorld::IdCollection<ESM::Region>& regions,
|
||||
const CSMWorld::IdCollection<ESM::Dialogue>& topics,
|
||||
const CSMWorld::RefIdData& referencables,
|
||||
const CSMWorld::Resources& soundFiles);
|
||||
|
||||
virtual int setup();
|
||||
///< \return number of steps
|
||||
|
||||
virtual void perform(int step, CSMDoc::Messages& messages);
|
||||
///< Messages resulting from this stage will be appended to \a messages
|
||||
|
||||
private:
|
||||
|
||||
const CSMWorld::InfoCollection& mTopicInfos;
|
||||
|
||||
const CSMWorld::IdCollection<CSMWorld::Cell>& mCells;
|
||||
const CSMWorld::IdCollection<ESM::Class>& mClasses;
|
||||
const CSMWorld::IdCollection<ESM::Faction>& mFactions;
|
||||
const CSMWorld::IdCollection<ESM::GameSetting>& mGameSettings;
|
||||
const CSMWorld::IdCollection<ESM::Global>& mGlobals;
|
||||
const CSMWorld::IdCollection<ESM::Dialogue>& mJournals;
|
||||
const CSMWorld::IdCollection<ESM::Race>& mRaces;
|
||||
const CSMWorld::IdCollection<ESM::Region>& mRegions;
|
||||
const CSMWorld::IdCollection<ESM::Dialogue>& mTopics;
|
||||
|
||||
const CSMWorld::RefIdData& mReferencables;
|
||||
const CSMWorld::Resources& mSoundFiles;
|
||||
|
||||
std::set<std::string> mCellNames;
|
||||
|
||||
// These return false when not successful and write an error
|
||||
bool verifyActor(const std::string& name, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages);
|
||||
bool verifyCell(const std::string& name, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages);
|
||||
bool verifyFactionRank(const std::string& name, int rank, const CSMWorld::UniversalId& id,
|
||||
CSMDoc::Messages& messages);
|
||||
bool verifyItem(const std::string& name, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages);
|
||||
bool verifySelectStruct(const ESM::DialInfo::SelectStruct& select, const CSMWorld::UniversalId& id,
|
||||
CSMDoc::Messages& messages);
|
||||
bool verifySound(const std::string& name, const CSMWorld::UniversalId& id, CSMDoc::Messages& messages);
|
||||
|
||||
template <typename T>
|
||||
bool verifyId(const std::string& name, const CSMWorld::IdCollection<T>& collection,
|
||||
const CSMWorld::UniversalId& id, CSMDoc::Messages& messages);
|
||||
|
||||
// Common error messages
|
||||
void writeMissingIdError(const std::string& specifier, const std::string& missingId,
|
||||
const CSMWorld::UniversalId& id, CSMDoc::Messages& messages);
|
||||
|
||||
void writeDeletedRecordError(const std::string& specifier, const std::string& recordId,
|
||||
const CSMWorld::UniversalId& id, CSMDoc::Messages& messages);
|
||||
|
||||
void writeInvalidTypeError(const std::string& specifier, const std::string& invalidId,
|
||||
CSMWorld::UniversalId::Type invalidType, const std::string& expectedType,
|
||||
const CSMWorld::UniversalId& id, CSMDoc::Messages& messages);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,5 +1,7 @@
|
|||
#include "cellcoordinates.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
|
||||
|
@ -7,6 +9,9 @@ CSMWorld::CellCoordinates::CellCoordinates() : mX (0), mY (0) {}
|
|||
|
||||
CSMWorld::CellCoordinates::CellCoordinates (int x, int y) : mX (x), mY (y) {}
|
||||
|
||||
CSMWorld::CellCoordinates::CellCoordinates (const std::pair<int, int>& coordinates)
|
||||
: mX (coordinates.first), mY (coordinates.second) {}
|
||||
|
||||
int CSMWorld::CellCoordinates::getX() const
|
||||
{
|
||||
return mX;
|
||||
|
@ -32,11 +37,16 @@ std::string CSMWorld::CellCoordinates::getId (const std::string& worldspace) con
|
|||
return stream.str();
|
||||
}
|
||||
|
||||
bool CSMWorld::CellCoordinates::isExteriorCell (const std::string& id)
|
||||
{
|
||||
return (!id.empty() && id[0]=='#');
|
||||
}
|
||||
|
||||
std::pair<CSMWorld::CellCoordinates, bool> CSMWorld::CellCoordinates::fromId (
|
||||
const std::string& id)
|
||||
{
|
||||
// no worldspace for now, needs to be changed for 1.1
|
||||
if (!id.empty() && id[0]=='#')
|
||||
if (isExteriorCell(id))
|
||||
{
|
||||
int x, y;
|
||||
char ignore;
|
||||
|
@ -49,6 +59,13 @@ std::pair<CSMWorld::CellCoordinates, bool> CSMWorld::CellCoordinates::fromId (
|
|||
return std::make_pair (CellCoordinates(), false);
|
||||
}
|
||||
|
||||
std::pair<int, int> CSMWorld::CellCoordinates::coordinatesToCellIndex (float x, float y)
|
||||
{
|
||||
const int cellSize = 8192;
|
||||
|
||||
return std::make_pair (std::floor (x/cellSize), std::floor (y/cellSize));
|
||||
}
|
||||
|
||||
bool CSMWorld::operator== (const CellCoordinates& left, const CellCoordinates& right)
|
||||
{
|
||||
return left.getX()==right.getX() && left.getY()==right.getY();
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <QMetaType>
|
||||
|
||||
|
@ -19,6 +20,8 @@ namespace CSMWorld
|
|||
|
||||
CellCoordinates (int x, int y);
|
||||
|
||||
CellCoordinates (const std::pair<int, int>& coordinates);
|
||||
|
||||
int getX() const;
|
||||
|
||||
int getY() const;
|
||||
|
@ -29,11 +32,16 @@ namespace CSMWorld
|
|||
std::string getId (const std::string& worldspace) const;
|
||||
///< Return the ID for the cell at these coordinates.
|
||||
|
||||
static bool isExteriorCell (const std::string& id);
|
||||
|
||||
/// \return first: CellCoordinates (or 0, 0 if cell does not have coordinates),
|
||||
/// second: is cell paged?
|
||||
///
|
||||
/// \note The worldspace part of \a id is ignored
|
||||
static std::pair<CellCoordinates, bool> fromId (const std::string& id);
|
||||
|
||||
/// \return cell coordinates such that given world coordinates are in it.
|
||||
static std::pair<int, int> coordinatesToCellIndex (float x, float y);
|
||||
};
|
||||
|
||||
bool operator== (const CellCoordinates& left, const CellCoordinates& right);
|
||||
|
|
|
@ -85,6 +85,7 @@ namespace CSMWorld
|
|||
Display_Enchantment,
|
||||
//CONCRETE TYPES ENDS HERE
|
||||
|
||||
Display_UnsignedInteger8,
|
||||
Display_Integer,
|
||||
Display_Float,
|
||||
Display_Var,
|
||||
|
@ -130,10 +131,14 @@ namespace CSMWorld
|
|||
Display_InfoCondComp,
|
||||
Display_String32,
|
||||
Display_LongString256,
|
||||
Display_BookType,
|
||||
Display_BloodType,
|
||||
Display_EmitterType,
|
||||
|
||||
Display_EffectSkill, // must display at least one, unlike Display_Skill
|
||||
Display_EffectAttribute, // must display at least one, unlike Display_Attribute
|
||||
Display_IngredEffectId, // display none allowed, unlike Display_EffectId
|
||||
Display_GenderNpc, // must display at least one, unlike Display_Gender
|
||||
|
||||
//top level columns that nest other columns
|
||||
Display_NestedHeader
|
||||
|
|
|
@ -1757,6 +1757,41 @@ namespace CSMWorld
|
|||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ESXRecordT>
|
||||
struct GenderNpcColumn : public Column<ESXRecordT>
|
||||
{
|
||||
GenderNpcColumn()
|
||||
: Column<ESXRecordT>(Columns::ColumnId_GenderNpc, ColumnBase::Display_GenderNpc)
|
||||
{}
|
||||
|
||||
virtual QVariant get(const Record<ESXRecordT>& record) const
|
||||
{
|
||||
// Implemented this way to allow additional gender types in the future.
|
||||
if ((record.get().mData.mFlags & ESM::BodyPart::BPF_Female) == ESM::BodyPart::BPF_Female)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual void set(Record<ESXRecordT>& record, const QVariant& data)
|
||||
{
|
||||
ESXRecordT record2 = record.get();
|
||||
|
||||
// Implemented this way to allow additional gender types in the future.
|
||||
if (data.toInt() == 1)
|
||||
record2.mData.mFlags = (record2.mData.mFlags & ~ESM::BodyPart::BPF_Female) | ESM::BodyPart::BPF_Female;
|
||||
else
|
||||
record2.mData.mFlags = record2.mData.mFlags & ~ESM::BodyPart::BPF_Female;
|
||||
|
||||
record.setModified(record2);
|
||||
}
|
||||
|
||||
virtual bool isEditable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ESXRecordT>
|
||||
struct EnchantmentTypeColumn : public Column<ESXRecordT>
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include "universalid.hpp"
|
||||
#include "infoselectwrapper.hpp"
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
|
@ -97,7 +98,7 @@ namespace CSMWorld
|
|||
{ ColumnId_ArmorType, "Armor Type" },
|
||||
{ ColumnId_Health, "Health" },
|
||||
{ ColumnId_ArmorValue, "Armor Value" },
|
||||
{ ColumnId_Scroll, "Scroll" },
|
||||
{ ColumnId_BookType, "Book Type" },
|
||||
{ ColumnId_ClothingType, "Clothing Type" },
|
||||
{ ColumnId_WeightCapacity, "Weight Capacity" },
|
||||
{ ColumnId_OrganicContainer, "Organic Container" },
|
||||
|
@ -111,8 +112,8 @@ namespace CSMWorld
|
|||
{ ColumnId_Flies, "Flies" },
|
||||
{ ColumnId_Walks, "Walks" },
|
||||
{ ColumnId_Essential, "Essential" },
|
||||
{ ColumnId_SkeletonBlood, "Skeleton Blood" },
|
||||
{ ColumnId_MetalBlood, "Metal Blood" },
|
||||
{ ColumnId_BloodType, "Blood Type" },
|
||||
|
||||
{ ColumnId_OpenSound, "Open Sound" },
|
||||
{ ColumnId_CloseSound, "Close Sound" },
|
||||
{ ColumnId_Duration, "Duration" },
|
||||
|
@ -122,10 +123,8 @@ namespace CSMWorld
|
|||
{ ColumnId_Dynamic, "Dynamic" },
|
||||
{ ColumnId_Portable, "Portable" },
|
||||
{ ColumnId_NegativeLight, "Negative Light" },
|
||||
{ ColumnId_Flickering, "Flickering" },
|
||||
{ ColumnId_SlowFlickering, "Slow Flickering" },
|
||||
{ ColumnId_Pulsing, "Pulsing" },
|
||||
{ ColumnId_SlowPulsing, "Slow Pulsing" },
|
||||
{ ColumnId_EmitterType, "Emitter Type" },
|
||||
|
||||
{ ColumnId_Fire, "Fire" },
|
||||
{ ColumnId_OffByDefault, "Off by default" },
|
||||
{ ColumnId_IsKey, "Is Key" },
|
||||
|
@ -273,8 +272,8 @@ namespace CSMWorld
|
|||
{ ColumnId_InfoList, "Info List" },
|
||||
{ ColumnId_InfoCondition, "Info Conditions" },
|
||||
{ ColumnId_InfoCondFunc, "Function" },
|
||||
{ ColumnId_InfoCondVar, "Func/Variable" },
|
||||
{ ColumnId_InfoCondComp, "Comp" },
|
||||
{ ColumnId_InfoCondVar, "Variable/Object" },
|
||||
{ ColumnId_InfoCondComp, "Relation" },
|
||||
{ ColumnId_InfoCondValue, "Values" },
|
||||
{ ColumnId_OriginalCell, "Original Cell" },
|
||||
|
||||
|
@ -284,6 +283,7 @@ namespace CSMWorld
|
|||
{ ColumnId_NpcMisc, "NPC Misc" },
|
||||
{ ColumnId_Level, "Level" },
|
||||
{ ColumnId_NpcFactionID, "Faction ID" },
|
||||
{ ColumnId_GenderNpc, "Gender"},
|
||||
{ ColumnId_Mana, "Mana" },
|
||||
{ ColumnId_Fatigue, "Fatigue" },
|
||||
{ ColumnId_NpcDisposition, "NPC Disposition" },
|
||||
|
@ -325,6 +325,12 @@ namespace CSMWorld
|
|||
{ ColumnId_Idle7, "Idle 7" },
|
||||
{ ColumnId_Idle8, "Idle 8" },
|
||||
|
||||
{ ColumnId_RegionWeather, "Weather" },
|
||||
{ ColumnId_WeatherName, "Type" },
|
||||
{ ColumnId_WeatherChance, "Percent Chance" },
|
||||
|
||||
{ ColumnId_Text, "Text" },
|
||||
|
||||
{ ColumnId_UseValue1, "Use value 1" },
|
||||
{ ColumnId_UseValue2, "Use value 2" },
|
||||
{ ColumnId_UseValue3, "Use value 3" },
|
||||
|
@ -546,16 +552,19 @@ namespace
|
|||
"AI Wander", "AI Travel", "AI Follow", "AI Escort", "AI Activate", 0
|
||||
};
|
||||
|
||||
static const char *sInfoCondFunc[] =
|
||||
static const char *sBookType[] =
|
||||
{
|
||||
" ", "Function", "Global", "Local", "Journal",
|
||||
"Item", "Dead", "Not ID", "Not Faction", "Not Class",
|
||||
"Not Race", "Not Cell", "Not Local", 0
|
||||
"Book", "Scroll", 0
|
||||
};
|
||||
|
||||
static const char *sInfoCondComp[] =
|
||||
static const char *sBloodType[] =
|
||||
{
|
||||
"!=", "<", "<=", "=", ">", ">=", 0
|
||||
"Default (Red)", "Skeleton Blood (White)", "Metal Blood (Golden)", 0
|
||||
};
|
||||
|
||||
static const char *sEmitterType[] =
|
||||
{
|
||||
"<None>", "Flickering", "Flickering (Slow)", "Pulsing", "Pulsing (Slow)", 0
|
||||
};
|
||||
|
||||
const char **getEnumNames (CSMWorld::Columns::ColumnId column)
|
||||
|
@ -585,10 +594,11 @@ namespace
|
|||
case CSMWorld::Columns::ColumnId_EffectId: return sEffectId;
|
||||
case CSMWorld::Columns::ColumnId_PartRefType: return sPartRefType;
|
||||
case CSMWorld::Columns::ColumnId_AiPackageType: return sAiPackageType;
|
||||
case CSMWorld::Columns::ColumnId_InfoCondFunc: return sInfoCondFunc;
|
||||
// FIXME: don't have dynamic value enum delegate, use Display_String for now
|
||||
//case CSMWorld::Columns::ColumnId_InfoCond: return sInfoCond;
|
||||
case CSMWorld::Columns::ColumnId_InfoCondComp: return sInfoCondComp;
|
||||
case CSMWorld::Columns::ColumnId_InfoCondFunc: return CSMWorld::ConstInfoSelectWrapper::FunctionEnumStrings;
|
||||
case CSMWorld::Columns::ColumnId_InfoCondComp: return CSMWorld::ConstInfoSelectWrapper::RelationEnumStrings;
|
||||
case CSMWorld::Columns::ColumnId_BookType: return sBookType;
|
||||
case CSMWorld::Columns::ColumnId_BloodType: return sBloodType;
|
||||
case CSMWorld::Columns::ColumnId_EmitterType: return sEmitterType;
|
||||
|
||||
default: return 0;
|
||||
}
|
||||
|
|
|
@ -92,7 +92,7 @@ namespace CSMWorld
|
|||
ColumnId_ArmorType = 77,
|
||||
ColumnId_Health = 78,
|
||||
ColumnId_ArmorValue = 79,
|
||||
ColumnId_Scroll = 80,
|
||||
ColumnId_BookType = 80,
|
||||
ColumnId_ClothingType = 81,
|
||||
ColumnId_WeightCapacity = 82,
|
||||
ColumnId_OrganicContainer = 83,
|
||||
|
@ -107,8 +107,8 @@ namespace CSMWorld
|
|||
ColumnId_Flies = 92,
|
||||
ColumnId_Walks = 93,
|
||||
ColumnId_Essential = 94,
|
||||
ColumnId_SkeletonBlood = 95,
|
||||
ColumnId_MetalBlood = 96,
|
||||
ColumnId_BloodType = 95,
|
||||
// unused
|
||||
ColumnId_OpenSound = 97,
|
||||
ColumnId_CloseSound = 98,
|
||||
ColumnId_Duration = 99,
|
||||
|
@ -118,10 +118,8 @@ namespace CSMWorld
|
|||
ColumnId_Dynamic = 103,
|
||||
ColumnId_Portable = 104,
|
||||
ColumnId_NegativeLight = 105,
|
||||
ColumnId_Flickering = 106,
|
||||
ColumnId_SlowFlickering = 107,
|
||||
ColumnId_Pulsing = 108,
|
||||
ColumnId_SlowPulsing = 109,
|
||||
ColumnId_EmitterType = 106,
|
||||
// unused (3x)
|
||||
ColumnId_Fire = 110,
|
||||
ColumnId_OffByDefault = 111,
|
||||
ColumnId_IsKey = 112,
|
||||
|
@ -278,7 +276,7 @@ namespace CSMWorld
|
|||
ColumnId_NpcMisc = 251,
|
||||
ColumnId_Level = 252,
|
||||
ColumnId_NpcFactionID = 253,
|
||||
// unused
|
||||
ColumnId_GenderNpc = 254,
|
||||
ColumnId_Mana = 255,
|
||||
ColumnId_Fatigue = 256,
|
||||
ColumnId_NpcDisposition = 257,
|
||||
|
@ -325,6 +323,12 @@ namespace CSMWorld
|
|||
ColumnId_Idle7 = 292,
|
||||
ColumnId_Idle8 = 293,
|
||||
|
||||
ColumnId_RegionWeather = 294,
|
||||
ColumnId_WeatherName = 295,
|
||||
ColumnId_WeatherChance = 296,
|
||||
|
||||
ColumnId_Text = 297,
|
||||
|
||||
// Allocated to a separate value range, so we don't get a collision should we ever need
|
||||
// to extend the number of use values.
|
||||
ColumnId_UseValue1 = 0x10000,
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "record.hpp"
|
||||
#include "commands.hpp"
|
||||
#include "idtableproxymodel.hpp"
|
||||
#include "commandmacro.hpp"
|
||||
|
||||
std::vector<std::string> CSMWorld::CommandDispatcher::getDeletableRecords() const
|
||||
{
|
||||
|
@ -171,10 +172,9 @@ void CSMWorld::CommandDispatcher::executeModify (QAbstractItemModel *model, cons
|
|||
|
||||
if (modifyCell.get())
|
||||
{
|
||||
mDocument.getUndoStack().beginMacro (modifyData->text());
|
||||
mDocument.getUndoStack().push (modifyData.release());
|
||||
mDocument.getUndoStack().push (modifyCell.release());
|
||||
mDocument.getUndoStack().endMacro();
|
||||
CommandMacro macro (mDocument.getUndoStack());
|
||||
macro.push (modifyData.release());
|
||||
macro.push (modifyCell.release());
|
||||
}
|
||||
else
|
||||
mDocument.getUndoStack().push (modifyData.release());
|
||||
|
@ -194,9 +194,7 @@ void CSMWorld::CommandDispatcher::executeDelete()
|
|||
|
||||
int columnIndex = model.findColumnIndex (Columns::ColumnId_Id);
|
||||
|
||||
if (rows.size()>1)
|
||||
mDocument.getUndoStack().beginMacro (tr ("Delete multiple records"));
|
||||
|
||||
CommandMacro macro (mDocument.getUndoStack(), rows.size()>1 ? "Delete multiple records" : "");
|
||||
for (std::vector<std::string>::const_iterator iter (rows.begin()); iter!=rows.end(); ++iter)
|
||||
{
|
||||
std::string id = model.data (model.getModelIndex (*iter, columnIndex)).
|
||||
|
@ -204,7 +202,7 @@ void CSMWorld::CommandDispatcher::executeDelete()
|
|||
|
||||
if (mId.getType() == UniversalId::Type_Referenceables)
|
||||
{
|
||||
mDocument.getUndoStack().push ( new CSMWorld::DeleteCommand (model, id,
|
||||
macro.push (new CSMWorld::DeleteCommand (model, id,
|
||||
static_cast<CSMWorld::UniversalId::Type>(model.data (model.index (
|
||||
model.getModelIndex (id, columnIndex).row(),
|
||||
model.findColumnIndex (CSMWorld::Columns::ColumnId_RecordType))).toInt())));
|
||||
|
@ -212,9 +210,6 @@ void CSMWorld::CommandDispatcher::executeDelete()
|
|||
else
|
||||
mDocument.getUndoStack().push (new CSMWorld::DeleteCommand (model, id));
|
||||
}
|
||||
|
||||
if (rows.size()>1)
|
||||
mDocument.getUndoStack().endMacro();
|
||||
}
|
||||
|
||||
void CSMWorld::CommandDispatcher::executeRevert()
|
||||
|
@ -231,25 +226,19 @@ void CSMWorld::CommandDispatcher::executeRevert()
|
|||
|
||||
int columnIndex = model.findColumnIndex (Columns::ColumnId_Id);
|
||||
|
||||
if (rows.size()>1)
|
||||
mDocument.getUndoStack().beginMacro (tr ("Revert multiple records"));
|
||||
|
||||
CommandMacro macro (mDocument.getUndoStack(), rows.size()>1 ? "Revert multiple records" : "");
|
||||
for (std::vector<std::string>::const_iterator iter (rows.begin()); iter!=rows.end(); ++iter)
|
||||
{
|
||||
std::string id = model.data (model.getModelIndex (*iter, columnIndex)).
|
||||
toString().toUtf8().constData();
|
||||
|
||||
mDocument.getUndoStack().push (new CSMWorld::RevertCommand (model, id));
|
||||
macro.push (new CSMWorld::RevertCommand (model, id));
|
||||
}
|
||||
|
||||
if (rows.size()>1)
|
||||
mDocument.getUndoStack().endMacro();
|
||||
}
|
||||
|
||||
void CSMWorld::CommandDispatcher::executeExtendedDelete()
|
||||
{
|
||||
if (mExtendedTypes.size()>1)
|
||||
mDocument.getUndoStack().beginMacro (tr ("Extended delete of multiple records"));
|
||||
CommandMacro macro (mDocument.getUndoStack(), mExtendedTypes.size()>1 ? tr ("Extended delete of multiple records") : "");
|
||||
|
||||
for (std::vector<UniversalId>::const_iterator iter (mExtendedTypes.begin());
|
||||
iter!=mExtendedTypes.end(); ++iter)
|
||||
|
@ -276,20 +265,15 @@ void CSMWorld::CommandDispatcher::executeExtendedDelete()
|
|||
Misc::StringUtils::lowerCase (record.get().mCell)))
|
||||
continue;
|
||||
|
||||
mDocument.getUndoStack().push (
|
||||
new CSMWorld::DeleteCommand (model, record.get().mId));
|
||||
macro.push (new CSMWorld::DeleteCommand (model, record.get().mId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mExtendedTypes.size()>1)
|
||||
mDocument.getUndoStack().endMacro();
|
||||
}
|
||||
|
||||
void CSMWorld::CommandDispatcher::executeExtendedRevert()
|
||||
{
|
||||
if (mExtendedTypes.size()>1)
|
||||
mDocument.getUndoStack().beginMacro (tr ("Extended revert of multiple records"));
|
||||
CommandMacro macro (mDocument.getUndoStack(), mExtendedTypes.size()>1 ? tr ("Extended revert of multiple records") : "");
|
||||
|
||||
for (std::vector<UniversalId>::const_iterator iter (mExtendedTypes.begin());
|
||||
iter!=mExtendedTypes.end(); ++iter)
|
||||
|
@ -313,12 +297,8 @@ void CSMWorld::CommandDispatcher::executeExtendedRevert()
|
|||
Misc::StringUtils::lowerCase (record.get().mCell)))
|
||||
continue;
|
||||
|
||||
mDocument.getUndoStack().push (
|
||||
new CSMWorld::RevertCommand (model, record.get().mId));
|
||||
macro.push (new CSMWorld::RevertCommand (model, record.get().mId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mExtendedTypes.size()>1)
|
||||
mDocument.getUndoStack().endMacro();
|
||||
}
|
||||
|
|
26
apps/opencs/model/world/commandmacro.cpp
Normal file
26
apps/opencs/model/world/commandmacro.cpp
Normal file
|
@ -0,0 +1,26 @@
|
|||
|
||||
#include "commandmacro.hpp"
|
||||
|
||||
#include <QUndoStack>
|
||||
#include <QUndoCommand>
|
||||
|
||||
CSMWorld::CommandMacro::CommandMacro (QUndoStack& undoStack, const QString& description)
|
||||
: mUndoStack (undoStack), mDescription (description), mStarted (false)
|
||||
{}
|
||||
|
||||
CSMWorld::CommandMacro::~CommandMacro()
|
||||
{
|
||||
if (mStarted)
|
||||
mUndoStack.endMacro();
|
||||
}
|
||||
|
||||
void CSMWorld::CommandMacro::push (QUndoCommand *command)
|
||||
{
|
||||
if (!mStarted)
|
||||
{
|
||||
mUndoStack.beginMacro (mDescription.isEmpty() ? command->text() : mDescription);
|
||||
mStarted = true;
|
||||
}
|
||||
|
||||
mUndoStack.push (command);
|
||||
}
|
34
apps/opencs/model/world/commandmacro.hpp
Normal file
34
apps/opencs/model/world/commandmacro.hpp
Normal file
|
@ -0,0 +1,34 @@
|
|||
#ifndef CSM_WOLRD_COMMANDMACRO_H
|
||||
#define CSM_WOLRD_COMMANDMACRO_H
|
||||
|
||||
class QUndoStack;
|
||||
class QUndoCommand;
|
||||
|
||||
#include <QString>
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class CommandMacro
|
||||
{
|
||||
QUndoStack& mUndoStack;
|
||||
QString mDescription;
|
||||
bool mStarted;
|
||||
|
||||
/// not implemented
|
||||
CommandMacro (const CommandMacro&);
|
||||
|
||||
/// not implemented
|
||||
CommandMacro& operator= (const CommandMacro&);
|
||||
|
||||
public:
|
||||
|
||||
/// If \a description is empty, the description of the first command is used.
|
||||
CommandMacro (QUndoStack& undoStack, const QString& description = "");
|
||||
|
||||
~CommandMacro();
|
||||
|
||||
void push (QUndoCommand *command);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -8,9 +8,12 @@
|
|||
#include <QAbstractItemModel>
|
||||
#include <QAbstractProxyModel>
|
||||
|
||||
#include "cellcoordinates.hpp"
|
||||
#include "idcollection.hpp"
|
||||
#include "idtable.hpp"
|
||||
#include "idtree.hpp"
|
||||
#include "nestedtablewrapper.hpp"
|
||||
#include "pathgrid.hpp"
|
||||
|
||||
CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelIndex& index,
|
||||
const QVariant& new_, QUndoCommand* parent)
|
||||
|
@ -68,9 +71,6 @@ void CSMWorld::ModifyCommand::undo()
|
|||
|
||||
void CSMWorld::CreateCommand::applyModifications()
|
||||
{
|
||||
for (std::map<int, QVariant>::const_iterator iter (mValues.begin()); iter!=mValues.end(); ++iter)
|
||||
mModel.setData (mModel.getModelIndex (mId, iter->first), iter->second);
|
||||
|
||||
if (!mNestedValues.empty())
|
||||
{
|
||||
CSMWorld::IdTree *tree = dynamic_cast<CSMWorld::IdTree *>(&mModel);
|
||||
|
@ -114,7 +114,7 @@ void CSMWorld::CreateCommand::setType (UniversalId::Type type)
|
|||
|
||||
void CSMWorld::CreateCommand::redo()
|
||||
{
|
||||
mModel.addRecord (mId, mType);
|
||||
mModel.addRecordWithData (mId, mValues, mType);
|
||||
applyModifications();
|
||||
}
|
||||
|
||||
|
@ -238,6 +238,29 @@ void CSMWorld::CloneCommand::undo()
|
|||
mModel.removeRow (mModel.getModelIndex (mId, 0).row());
|
||||
}
|
||||
|
||||
CSMWorld::CreatePathgridCommand::CreatePathgridCommand(IdTable& model, const std::string& id, QUndoCommand *parent)
|
||||
: CreateCommand(model, id, parent)
|
||||
{
|
||||
setType(UniversalId::Type_Pathgrid);
|
||||
}
|
||||
|
||||
void CSMWorld::CreatePathgridCommand::redo()
|
||||
{
|
||||
CreateCommand::redo();
|
||||
|
||||
Record<Pathgrid> record = static_cast<const Record<Pathgrid>& >(mModel.getRecord(mId));
|
||||
record.get().blank();
|
||||
record.get().mCell = mId;
|
||||
|
||||
std::pair<CellCoordinates, bool> coords = CellCoordinates::fromId(mId);
|
||||
if (coords.second)
|
||||
{
|
||||
record.get().mData.mX = coords.first.getX();
|
||||
record.get().mData.mY = coords.first.getY();
|
||||
}
|
||||
|
||||
mModel.setRecord(mId, record, mType);
|
||||
}
|
||||
|
||||
CSMWorld::UpdateCellCommand::UpdateCellCommand (IdTable& model, int row, QUndoCommand *parent)
|
||||
: QUndoCommand (parent), mModel (model), mRow (row)
|
||||
|
|
|
@ -153,6 +153,15 @@ namespace CSMWorld
|
|||
virtual void undo();
|
||||
};
|
||||
|
||||
class CreatePathgridCommand : public CreateCommand
|
||||
{
|
||||
public:
|
||||
|
||||
CreatePathgridCommand(IdTable& model, const std::string& id, QUndoCommand *parent = 0);
|
||||
|
||||
virtual void redo();
|
||||
};
|
||||
|
||||
/// \brief Update cell ID according to x/y-coordinates
|
||||
///
|
||||
/// \note The new value will be calculated in the first call to redo instead of the
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include <components/esm/loadglob.hpp>
|
||||
#include <components/esm/cellref.hpp>
|
||||
|
||||
#include <components/resource/scenemanager.hpp>
|
||||
|
||||
#include "idtable.hpp"
|
||||
#include "idtree.hpp"
|
||||
#include "columnimp.hpp"
|
||||
|
@ -59,11 +61,13 @@ int CSMWorld::Data::count (RecordBase::State state, const CollectionBase& collec
|
|||
return number;
|
||||
}
|
||||
|
||||
CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourcesManager, const Fallback::Map* fallback)
|
||||
CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourcesManager, const Fallback::Map* fallback, const boost::filesystem::path& resDir)
|
||||
: mEncoder (encoding), mPathgrids (mCells), mRefs (mCells),
|
||||
mResourcesManager (resourcesManager), mFallbackMap(fallback),
|
||||
mReader (0), mDialogue (0), mReaderIndex(0), mResourceSystem(new Resource::ResourceSystem(resourcesManager.getVFS()))
|
||||
mReader (0), mDialogue (0), mReaderIndex(1), mResourceSystem(new Resource::ResourceSystem(resourcesManager.getVFS()))
|
||||
{
|
||||
mResourceSystem->getSceneManager()->setShaderPath((resDir / "shaders").string());
|
||||
|
||||
int index = 0;
|
||||
|
||||
mGlobals.addColumn (new StringIdColumn<ESM::Global>);
|
||||
|
@ -177,6 +181,14 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
|
|||
mRegions.addColumn (new NameColumn<ESM::Region>);
|
||||
mRegions.addColumn (new MapColourColumn<ESM::Region>);
|
||||
mRegions.addColumn (new SleepListColumn<ESM::Region>);
|
||||
// Region Weather
|
||||
mRegions.addColumn (new NestedParentColumn<ESM::Region> (Columns::ColumnId_RegionWeather));
|
||||
index = mRegions.getColumns()-1;
|
||||
mRegions.addAdapter (std::make_pair(&mRegions.getColumn(index), new RegionWeatherAdapter ()));
|
||||
mRegions.getNestableColumn(index)->addColumn(
|
||||
new NestedChildColumn (Columns::ColumnId_WeatherName, ColumnBase::Display_String, false));
|
||||
mRegions.getNestableColumn(index)->addColumn(
|
||||
new NestedChildColumn (Columns::ColumnId_WeatherChance, ColumnBase::Display_UnsignedInteger8));
|
||||
// Region Sounds
|
||||
mRegions.addColumn (new NestedParentColumn<ESM::Region> (Columns::ColumnId_RegionSounds));
|
||||
index = mRegions.getColumns()-1;
|
||||
|
@ -271,7 +283,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
|
|||
new NestedChildColumn (Columns::ColumnId_InfoCondFunc, ColumnBase::Display_InfoCondFunc));
|
||||
// FIXME: don't have dynamic value enum delegate, use Display_String for now
|
||||
mTopicInfos.getNestableColumn(index)->addColumn(
|
||||
new NestedChildColumn (Columns::ColumnId_InfoCondVar, ColumnBase::Display_String));
|
||||
new NestedChildColumn (Columns::ColumnId_InfoCondVar, ColumnBase::Display_InfoCondVar));
|
||||
mTopicInfos.getNestableColumn(index)->addColumn(
|
||||
new NestedChildColumn (Columns::ColumnId_InfoCondComp, ColumnBase::Display_InfoCondComp));
|
||||
mTopicInfos.getNestableColumn(index)->addColumn(
|
||||
|
@ -351,7 +363,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
|
|||
mBodyParts.addColumn (new FixedRecordTypeColumn<ESM::BodyPart> (UniversalId::Type_BodyPart));
|
||||
mBodyParts.addColumn (new BodyPartTypeColumn<ESM::BodyPart>);
|
||||
mBodyParts.addColumn (new VampireColumn<ESM::BodyPart>);
|
||||
mBodyParts.addColumn (new FlagColumn<ESM::BodyPart> (Columns::ColumnId_Female, ESM::BodyPart::BPF_Female));
|
||||
mBodyParts.addColumn(new GenderNpcColumn<ESM::BodyPart>);
|
||||
mBodyParts.addColumn (new FlagColumn<ESM::BodyPart> (Columns::ColumnId_Playable,
|
||||
ESM::BodyPart::BPF_NotPlayable, ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, true));
|
||||
|
||||
|
@ -887,9 +899,11 @@ int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base
|
|||
|
||||
mReader = new ESM::ESMReader;
|
||||
mReader->setEncoder (&mEncoder);
|
||||
mReader->setIndex(mReaderIndex++);
|
||||
mReader->setIndex((project || !base) ? 0 : mReaderIndex++);
|
||||
mReader->open (path.string());
|
||||
|
||||
mContentFileNames.insert(std::make_pair(path.filename().string(), mReader->getIndex()));
|
||||
|
||||
mBase = base;
|
||||
mProject = project;
|
||||
|
||||
|
@ -902,6 +916,20 @@ int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base
|
|||
mMetaData.setRecord (0, Record<MetaData> (RecordBase::State_ModifiedOnly, 0, &metaData));
|
||||
}
|
||||
|
||||
// Fix uninitialized master data index
|
||||
for (std::vector<ESM::Header::MasterData>::const_iterator masterData = mReader->getGameFiles().begin();
|
||||
masterData != mReader->getGameFiles().end(); ++masterData)
|
||||
{
|
||||
std::map<std::string, int>::iterator nameResult = mContentFileNames.find(masterData->name);
|
||||
if (nameResult != mContentFileNames.end())
|
||||
{
|
||||
ESM::Header::MasterData& hackedMasterData = const_cast<ESM::Header::MasterData&>(*masterData);
|
||||
|
||||
|
||||
hackedMasterData.index = nameResult->second;
|
||||
}
|
||||
}
|
||||
|
||||
return mReader->getRecordCount();
|
||||
}
|
||||
|
||||
|
@ -934,7 +962,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
|
|||
|
||||
bool unhandledRecord = false;
|
||||
|
||||
switch (n.val)
|
||||
switch (n.intval)
|
||||
{
|
||||
case ESM::REC_GLOB: mGlobals.load (*mReader, mBase); break;
|
||||
case ESM::REC_GMST: mGmsts.load (*mReader, mBase); break;
|
||||
|
@ -965,7 +993,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
|
|||
if (index!=-1/* && !mBase*/)
|
||||
mLand.getRecord (index).get().loadData (
|
||||
ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML | ESM::Land::DATA_VCLR |
|
||||
ESM::Land::DATA_VTEX | ESM::Land::DATA_WNAM);
|
||||
ESM::Land::DATA_VTEX);
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -1046,7 +1074,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
|
|||
else
|
||||
{
|
||||
mTopics.load (record, mBase);
|
||||
mDialogue = &mTopics.getRecord (record.mId).get();
|
||||
mDialogue = &mTopics.getRecord (record.mId).get();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -123,6 +123,8 @@ namespace CSMWorld
|
|||
|
||||
std::vector<boost::shared_ptr<ESM::ESMReader> > mReaders;
|
||||
|
||||
std::map<std::string, int> mContentFileNames;
|
||||
|
||||
// not implemented
|
||||
Data (const Data&);
|
||||
Data& operator= (const Data&);
|
||||
|
@ -138,7 +140,7 @@ namespace CSMWorld
|
|||
|
||||
public:
|
||||
|
||||
Data (ToUTF8::FromType encoding, const ResourcesManager& resourcesManager, const Fallback::Map* fallback);
|
||||
Data (ToUTF8::FromType encoding, const ResourcesManager& resourcesManager, const Fallback::Map* fallback, const boost::filesystem::path& resDir);
|
||||
|
||||
virtual ~Data();
|
||||
|
||||
|
|
|
@ -1627,264 +1627,264 @@ const char * CSMWorld::DefaultGmsts::OptionalStrings[CSMWorld::DefaultGmsts::Opt
|
|||
|
||||
const float CSMWorld::DefaultGmsts::FloatsDefaultValues[CSMWorld::DefaultGmsts::FloatCount] =
|
||||
{
|
||||
0.3, // fAIFleeFleeMult
|
||||
7.0, // fAIFleeHealthMult
|
||||
3.0, // fAIMagicSpellMult
|
||||
1.0, // fAIMeleeArmorMult
|
||||
1.0, // fAIMeleeSummWeaponMult
|
||||
2.0, // fAIMeleeWeaponMult
|
||||
5.0, // fAIRangeMagicSpellMult
|
||||
5.0, // fAIRangeMeleeWeaponMult
|
||||
2000.0, // fAlarmRadius
|
||||
1.0, // fAthleticsRunBonus
|
||||
40.0, // fAudioDefaultMaxDistance
|
||||
5.0, // fAudioDefaultMinDistance
|
||||
50.0, // fAudioMaxDistanceMult
|
||||
20.0, // fAudioMinDistanceMult
|
||||
60.0, // fAudioVoiceDefaultMaxDistance
|
||||
10.0, // fAudioVoiceDefaultMinDistance
|
||||
50.0, // fAutoPCSpellChance
|
||||
80.0, // fAutoSpellChance
|
||||
50.0, // fBargainOfferBase
|
||||
-4.0, // fBargainOfferMulti
|
||||
24.0, // fBarterGoldResetDelay
|
||||
1.75, // fBaseRunMultiplier
|
||||
1.25, // fBlockStillBonus
|
||||
150.0, // fBribe1000Mod
|
||||
75.0, // fBribe100Mod
|
||||
35.0, // fBribe10Mod
|
||||
60.0, // fCombatAngleXY
|
||||
60.0, // fCombatAngleZ
|
||||
0.25, // fCombatArmorMinMult
|
||||
-90.0, // fCombatBlockLeftAngle
|
||||
30.0, // fCombatBlockRightAngle
|
||||
4.0, // fCombatCriticalStrikeMult
|
||||
0.1, // fCombatDelayCreature
|
||||
0.1, // fCombatDelayNPC
|
||||
128.0, // fCombatDistance
|
||||
0.3, // fCombatDistanceWerewolfMod
|
||||
30.0, // fCombatForceSideAngle
|
||||
0.2, // fCombatInvisoMult
|
||||
1.5, // fCombatKODamageMult
|
||||
45.0, // fCombatTorsoSideAngle
|
||||
0.3, // fCombatTorsoStartPercent
|
||||
0.8, // fCombatTorsoStopPercent
|
||||
15.0, // fConstantEffectMult
|
||||
72.0, // fCorpseClearDelay
|
||||
72.0, // fCorpseRespawnDelay
|
||||
0.5, // fCrimeGoldDiscountMult
|
||||
0.9, // fCrimeGoldTurnInMult
|
||||
1.0, // fCrimeStealing
|
||||
0.5, // fDamageStrengthBase
|
||||
0.1, // fDamageStrengthMult
|
||||
5.0, // fDifficultyMult
|
||||
2.5, // fDiseaseXferChance
|
||||
-10.0, // fDispAttacking
|
||||
-1.0, // fDispBargainFailMod
|
||||
1.0, // fDispBargainSuccessMod
|
||||
0.0, // fDispCrimeMod
|
||||
-10.0, // fDispDiseaseMod
|
||||
3.0, // fDispFactionMod
|
||||
1.0, // fDispFactionRankBase
|
||||
0.5, // fDispFactionRankMult
|
||||
1.0, // fDispositionMod
|
||||
50.0, // fDispPersonalityBase
|
||||
0.5, // fDispPersonalityMult
|
||||
-25.0, // fDispPickPocketMod
|
||||
5.0, // fDispRaceMod
|
||||
-0.5, // fDispStealing
|
||||
-5.0, // fDispWeaponDrawn
|
||||
0.5, // fEffectCostMult
|
||||
0.1, // fElementalShieldMult
|
||||
3.0, // fEnchantmentChanceMult
|
||||
0.5, // fEnchantmentConstantChanceMult
|
||||
100.0, // fEnchantmentConstantDurationMult
|
||||
0.1, // fEnchantmentMult
|
||||
1000.0, // fEnchantmentValueMult
|
||||
0.3, // fEncumberedMoveEffect
|
||||
5.0, // fEncumbranceStrMult
|
||||
0.04, // fEndFatigueMult
|
||||
0.25, // fFallAcroBase
|
||||
0.01, // fFallAcroMult
|
||||
400.0, // fFallDamageDistanceMin
|
||||
0.0, // fFallDistanceBase
|
||||
0.07, // fFallDistanceMult
|
||||
2.0, // fFatigueAttackBase
|
||||
0.0, // fFatigueAttackMult
|
||||
1.25, // fFatigueBase
|
||||
4.0, // fFatigueBlockBase
|
||||
0.0, // fFatigueBlockMult
|
||||
5.0, // fFatigueJumpBase
|
||||
0.0, // fFatigueJumpMult
|
||||
0.5, // fFatigueMult
|
||||
2.5, // fFatigueReturnBase
|
||||
0.02, // fFatigueReturnMult
|
||||
5.0, // fFatigueRunBase
|
||||
2.0, // fFatigueRunMult
|
||||
1.5, // fFatigueSneakBase
|
||||
1.5, // fFatigueSneakMult
|
||||
0.0, // fFatigueSpellBase
|
||||
0.0, // fFatigueSpellCostMult
|
||||
0.0, // fFatigueSpellMult
|
||||
7.0, // fFatigueSwimRunBase
|
||||
0.0, // fFatigueSwimRunMult
|
||||
2.5, // fFatigueSwimWalkBase
|
||||
0.0, // fFatigueSwimWalkMult
|
||||
0.2, // fFightDispMult
|
||||
0.005, // fFightDistanceMultiplier
|
||||
50.0, // fFightStealing
|
||||
3000.0, // fFleeDistance
|
||||
512.0, // fGreetDistanceReset
|
||||
0.1, // fHandtoHandHealthPer
|
||||
1.0, // fHandToHandReach
|
||||
0.5, // fHoldBreathEndMult
|
||||
20.0, // fHoldBreathTime
|
||||
0.75, // fIdleChanceMultiplier
|
||||
1.0, // fIngredientMult
|
||||
0.5, // fInteriorHeadTrackMult
|
||||
128.0, // fJumpAcrobaticsBase
|
||||
4.0, // fJumpAcroMultiplier
|
||||
0.5, // fJumpEncumbranceBase
|
||||
1.0, // fJumpEncumbranceMultiplier
|
||||
0.5, // fJumpMoveBase
|
||||
0.5, // fJumpMoveMult
|
||||
1.0, // fJumpRunMultiplier
|
||||
0.5, // fKnockDownMult
|
||||
5.0, // fLevelMod
|
||||
0.1, // fLevelUpHealthEndMult
|
||||
0.6, // fLightMaxMod
|
||||
10.0, // fLuckMod
|
||||
10.0, // fMagesGuildTravel
|
||||
1.5, // fMagicCreatureCastDelay
|
||||
0.0167, // fMagicDetectRefreshRate
|
||||
1.0, // fMagicItemConstantMult
|
||||
1.0, // fMagicItemCostMult
|
||||
1.0, // fMagicItemOnceMult
|
||||
1.0, // fMagicItemPriceMult
|
||||
0.05, // fMagicItemRechargePerSecond
|
||||
1.0, // fMagicItemStrikeMult
|
||||
1.0, // fMagicItemUsedMult
|
||||
3.0, // fMagicStartIconBlink
|
||||
0.5, // fMagicSunBlockedMult
|
||||
0.75, // fMajorSkillBonus
|
||||
300.0, // fMaxFlySpeed
|
||||
0.5, // fMaxHandToHandMult
|
||||
400.0, // fMaxHeadTrackDistance
|
||||
200.0, // fMaxWalkSpeed
|
||||
300.0, // fMaxWalkSpeedCreature
|
||||
0.9, // fMedMaxMod
|
||||
0.1, // fMessageTimePerChar
|
||||
5.0, // fMinFlySpeed
|
||||
0.1, // fMinHandToHandMult
|
||||
1.0, // fMinorSkillBonus
|
||||
100.0, // fMinWalkSpeed
|
||||
5.0, // fMinWalkSpeedCreature
|
||||
1.25, // fMiscSkillBonus
|
||||
2.0, // fNPCbaseMagickaMult
|
||||
0.5, // fNPCHealthBarFade
|
||||
3.0, // fNPCHealthBarTime
|
||||
1.0, // fPCbaseMagickaMult
|
||||
0.3, // fPerDieRollMult
|
||||
5.0, // fPersonalityMod
|
||||
1.0, // fPerTempMult
|
||||
-1.0, // fPickLockMult
|
||||
0.3, // fPickPocketMod
|
||||
20.0, // fPotionMinUsefulDuration
|
||||
0.5, // fPotionStrengthMult
|
||||
0.5, // fPotionT1DurMult
|
||||
1.5, // fPotionT1MagMult
|
||||
20.0, // fPotionT4BaseStrengthMult
|
||||
12.0, // fPotionT4EquipStrengthMult
|
||||
3000.0, // fProjectileMaxSpeed
|
||||
400.0, // fProjectileMinSpeed
|
||||
25.0, // fProjectileThrownStoreChance
|
||||
3.0, // fRepairAmountMult
|
||||
1.0, // fRepairMult
|
||||
1.0, // fReputationMod
|
||||
0.15, // fRestMagicMult
|
||||
0.0, // fSeriousWoundMult
|
||||
0.25, // fSleepRandMod
|
||||
0.3, // fSleepRestMod
|
||||
-1.0, // fSneakBootMult
|
||||
0.5, // fSneakDistanceBase
|
||||
0.002, // fSneakDistanceMultiplier
|
||||
0.5, // fSneakNoViewMult
|
||||
1.0, // fSneakSkillMult
|
||||
0.75, // fSneakSpeedMultiplier
|
||||
1.0, // fSneakUseDelay
|
||||
500.0, // fSneakUseDist
|
||||
1.5, // fSneakViewMult
|
||||
3.0, // fSoulGemMult
|
||||
0.8, // fSpecialSkillBonus
|
||||
7.0, // fSpellMakingValueMult
|
||||
2.0, // fSpellPriceMult
|
||||
10.0, // fSpellValueMult
|
||||
0.25, // fStromWalkMult
|
||||
0.7, // fStromWindSpeed
|
||||
3.0, // fSuffocationDamage
|
||||
0.9, // fSwimHeightScale
|
||||
0.1, // fSwimRunAthleticsMult
|
||||
0.5, // fSwimRunBase
|
||||
0.02, // fSwimWalkAthleticsMult
|
||||
0.5, // fSwimWalkBase
|
||||
1.0, // fSwingBlockBase
|
||||
1.0, // fSwingBlockMult
|
||||
1000.0, // fTargetSpellMaxSpeed
|
||||
1000.0, // fThrownWeaponMaxSpeed
|
||||
300.0, // fThrownWeaponMinSpeed
|
||||
0.0, // fTrapCostMult
|
||||
4000.0, // fTravelMult
|
||||
16000.0,// fTravelTimeMult
|
||||
0.1, // fUnarmoredBase1
|
||||
0.065, // fUnarmoredBase2
|
||||
30.0, // fVanityDelay
|
||||
10.0, // fVoiceIdleOdds
|
||||
0.0, // fWaterReflectUpdateAlways
|
||||
10.0, // fWaterReflectUpdateSeldom
|
||||
0.1, // fWeaponDamageMult
|
||||
1.0, // fWeaponFatigueBlockMult
|
||||
0.25, // fWeaponFatigueMult
|
||||
150.0, // fWereWolfAcrobatics
|
||||
150.0, // fWereWolfAgility
|
||||
1.0, // fWereWolfAlchemy
|
||||
1.0, // fWereWolfAlteration
|
||||
1.0, // fWereWolfArmorer
|
||||
150.0, // fWereWolfAthletics
|
||||
1.0, // fWereWolfAxe
|
||||
1.0, // fWereWolfBlock
|
||||
1.0, // fWereWolfBluntWeapon
|
||||
1.0, // fWereWolfConjuration
|
||||
1.0, // fWereWolfDestruction
|
||||
1.0, // fWereWolfEnchant
|
||||
150.0, // fWereWolfEndurance
|
||||
400.0, // fWereWolfFatigue
|
||||
100.0, // fWereWolfHandtoHand
|
||||
2.0, // fWereWolfHealth
|
||||
1.0, // fWereWolfHeavyArmor
|
||||
1.0, // fWereWolfIllusion
|
||||
1.0, // fWereWolfIntellegence
|
||||
1.0, // fWereWolfLightArmor
|
||||
1.0, // fWereWolfLongBlade
|
||||
1.0, // fWereWolfLuck
|
||||
100.0, // fWereWolfMagicka
|
||||
1.0, // fWereWolfMarksman
|
||||
1.0, // fWereWolfMediumArmor
|
||||
1.0, // fWereWolfMerchantile
|
||||
1.0, // fWereWolfMysticism
|
||||
1.0, // fWereWolfPersonality
|
||||
1.0, // fWereWolfRestoration
|
||||
1.5, // fWereWolfRunMult
|
||||
1.0, // fWereWolfSecurity
|
||||
1.0, // fWereWolfShortBlade
|
||||
1.5, // fWereWolfSilverWeaponDamageMult
|
||||
1.0, // fWereWolfSneak
|
||||
1.0, // fWereWolfSpear
|
||||
1.0, // fWereWolfSpeechcraft
|
||||
150.0, // fWereWolfSpeed
|
||||
150.0, // fWereWolfStrength
|
||||
100.0, // fWereWolfUnarmored
|
||||
1.0, // fWereWolfWillPower
|
||||
15.0 // fWortChanceValue
|
||||
0.3f, // fAIFleeFleeMult
|
||||
7.0f, // fAIFleeHealthMult
|
||||
3.0f, // fAIMagicSpellMult
|
||||
1.0f, // fAIMeleeArmorMult
|
||||
1.0f, // fAIMeleeSummWeaponMult
|
||||
2.0f, // fAIMeleeWeaponMult
|
||||
5.0f, // fAIRangeMagicSpellMult
|
||||
5.0f, // fAIRangeMeleeWeaponMult
|
||||
2000.0f, // fAlarmRadius
|
||||
1.0f, // fAthleticsRunBonus
|
||||
40.0f, // fAudioDefaultMaxDistance
|
||||
5.0f, // fAudioDefaultMinDistance
|
||||
50.0f, // fAudioMaxDistanceMult
|
||||
20.0f, // fAudioMinDistanceMult
|
||||
60.0f, // fAudioVoiceDefaultMaxDistance
|
||||
10.0f, // fAudioVoiceDefaultMinDistance
|
||||
50.0f, // fAutoPCSpellChance
|
||||
80.0f, // fAutoSpellChance
|
||||
50.0f, // fBargainOfferBase
|
||||
-4.0f, // fBargainOfferMulti
|
||||
24.0f, // fBarterGoldResetDelay
|
||||
1.75f, // fBaseRunMultiplier
|
||||
1.25f, // fBlockStillBonus
|
||||
150.0f, // fBribe1000Mod
|
||||
75.0f, // fBribe100Mod
|
||||
35.0f, // fBribe10Mod
|
||||
60.0f, // fCombatAngleXY
|
||||
60.0f, // fCombatAngleZ
|
||||
0.25f, // fCombatArmorMinMult
|
||||
-90.0f, // fCombatBlockLeftAngle
|
||||
30.0f, // fCombatBlockRightAngle
|
||||
4.0f, // fCombatCriticalStrikeMult
|
||||
0.1f, // fCombatDelayCreature
|
||||
0.1f, // fCombatDelayNPC
|
||||
128.0f, // fCombatDistance
|
||||
0.3f, // fCombatDistanceWerewolfMod
|
||||
30.0f, // fCombatForceSideAngle
|
||||
0.2f, // fCombatInvisoMult
|
||||
1.5f, // fCombatKODamageMult
|
||||
45.0f, // fCombatTorsoSideAngle
|
||||
0.3f, // fCombatTorsoStartPercent
|
||||
0.8f, // fCombatTorsoStopPercent
|
||||
15.0f, // fConstantEffectMult
|
||||
72.0f, // fCorpseClearDelay
|
||||
72.0f, // fCorpseRespawnDelay
|
||||
0.5f, // fCrimeGoldDiscountMult
|
||||
0.9f, // fCrimeGoldTurnInMult
|
||||
1.0f, // fCrimeStealing
|
||||
0.5f, // fDamageStrengthBase
|
||||
0.1f, // fDamageStrengthMult
|
||||
5.0f, // fDifficultyMult
|
||||
2.5f, // fDiseaseXferChance
|
||||
-10.0f, // fDispAttacking
|
||||
-1.0f, // fDispBargainFailMod
|
||||
1.0f, // fDispBargainSuccessMod
|
||||
0.0f, // fDispCrimeMod
|
||||
-10.0f, // fDispDiseaseMod
|
||||
3.0f, // fDispFactionMod
|
||||
1.0f, // fDispFactionRankBase
|
||||
0.5f, // fDispFactionRankMult
|
||||
1.0f, // fDispositionMod
|
||||
50.0f, // fDispPersonalityBase
|
||||
0.5f, // fDispPersonalityMult
|
||||
-25.0f, // fDispPickPocketMod
|
||||
5.0f, // fDispRaceMod
|
||||
-0.5f, // fDispStealing
|
||||
-5.0f, // fDispWeaponDrawn
|
||||
0.5f, // fEffectCostMult
|
||||
0.1f, // fElementalShieldMult
|
||||
3.0f, // fEnchantmentChanceMult
|
||||
0.5f, // fEnchantmentConstantChanceMult
|
||||
100.0f, // fEnchantmentConstantDurationMult
|
||||
0.1f, // fEnchantmentMult
|
||||
1000.0f, // fEnchantmentValueMult
|
||||
0.3f, // fEncumberedMoveEffect
|
||||
5.0f, // fEncumbranceStrMult
|
||||
0.04f, // fEndFatigueMult
|
||||
0.25f, // fFallAcroBase
|
||||
0.01f, // fFallAcroMult
|
||||
400.0f, // fFallDamageDistanceMin
|
||||
0.0f, // fFallDistanceBase
|
||||
0.07f, // fFallDistanceMult
|
||||
2.0f, // fFatigueAttackBase
|
||||
0.0f, // fFatigueAttackMult
|
||||
1.25f, // fFatigueBase
|
||||
4.0f, // fFatigueBlockBase
|
||||
0.0f, // fFatigueBlockMult
|
||||
5.0f, // fFatigueJumpBase
|
||||
0.0f, // fFatigueJumpMult
|
||||
0.5f, // fFatigueMult
|
||||
2.5f, // fFatigueReturnBase
|
||||
0.02f, // fFatigueReturnMult
|
||||
5.0f, // fFatigueRunBase
|
||||
2.0f, // fFatigueRunMult
|
||||
1.5f, // fFatigueSneakBase
|
||||
1.5f, // fFatigueSneakMult
|
||||
0.0f, // fFatigueSpellBase
|
||||
0.0f, // fFatigueSpellCostMult
|
||||
0.0f, // fFatigueSpellMult
|
||||
7.0f, // fFatigueSwimRunBase
|
||||
0.0f, // fFatigueSwimRunMult
|
||||
2.5f, // fFatigueSwimWalkBase
|
||||
0.0f, // fFatigueSwimWalkMult
|
||||
0.2f, // fFightDispMult
|
||||
0.005f, // fFightDistanceMultiplier
|
||||
50.0f, // fFightStealing
|
||||
3000.0f, // fFleeDistance
|
||||
512.0f, // fGreetDistanceReset
|
||||
0.1f, // fHandtoHandHealthPer
|
||||
1.0f, // fHandToHandReach
|
||||
0.5f, // fHoldBreathEndMult
|
||||
20.0f, // fHoldBreathTime
|
||||
0.75f, // fIdleChanceMultiplier
|
||||
1.0f, // fIngredientMult
|
||||
0.5f, // fInteriorHeadTrackMult
|
||||
128.0f, // fJumpAcrobaticsBase
|
||||
4.0f, // fJumpAcroMultiplier
|
||||
0.5f, // fJumpEncumbranceBase
|
||||
1.0f, // fJumpEncumbranceMultiplier
|
||||
0.5f, // fJumpMoveBase
|
||||
0.5f, // fJumpMoveMult
|
||||
1.0f, // fJumpRunMultiplier
|
||||
0.5f, // fKnockDownMult
|
||||
5.0f, // fLevelMod
|
||||
0.1f, // fLevelUpHealthEndMult
|
||||
0.6f, // fLightMaxMod
|
||||
10.0f, // fLuckMod
|
||||
10.0f, // fMagesGuildTravel
|
||||
1.5f, // fMagicCreatureCastDelay
|
||||
0.0167f, // fMagicDetectRefreshRate
|
||||
1.0f, // fMagicItemConstantMult
|
||||
1.0f, // fMagicItemCostMult
|
||||
1.0f, // fMagicItemOnceMult
|
||||
1.0f, // fMagicItemPriceMult
|
||||
0.05f, // fMagicItemRechargePerSecond
|
||||
1.0f, // fMagicItemStrikeMult
|
||||
1.0f, // fMagicItemUsedMult
|
||||
3.0f, // fMagicStartIconBlink
|
||||
0.5f, // fMagicSunBlockedMult
|
||||
0.75f, // fMajorSkillBonus
|
||||
300.0f, // fMaxFlySpeed
|
||||
0.5f, // fMaxHandToHandMult
|
||||
400.0f, // fMaxHeadTrackDistance
|
||||
200.0f, // fMaxWalkSpeed
|
||||
300.0f, // fMaxWalkSpeedCreature
|
||||
0.9f, // fMedMaxMod
|
||||
0.1f, // fMessageTimePerChar
|
||||
5.0f, // fMinFlySpeed
|
||||
0.1f, // fMinHandToHandMult
|
||||
1.0f, // fMinorSkillBonus
|
||||
100.0f, // fMinWalkSpeed
|
||||
5.0f, // fMinWalkSpeedCreature
|
||||
1.25f, // fMiscSkillBonus
|
||||
2.0f, // fNPCbaseMagickaMult
|
||||
0.5f, // fNPCHealthBarFade
|
||||
3.0f, // fNPCHealthBarTime
|
||||
1.0f, // fPCbaseMagickaMult
|
||||
0.3f, // fPerDieRollMult
|
||||
5.0f, // fPersonalityMod
|
||||
1.0f, // fPerTempMult
|
||||
-1.0f, // fPickLockMult
|
||||
0.3f, // fPickPocketMod
|
||||
20.0f, // fPotionMinUsefulDuration
|
||||
0.5f, // fPotionStrengthMult
|
||||
0.5f, // fPotionT1DurMult
|
||||
1.5f, // fPotionT1MagMult
|
||||
20.0f, // fPotionT4BaseStrengthMult
|
||||
12.0f, // fPotionT4EquipStrengthMult
|
||||
3000.0f, // fProjectileMaxSpeed
|
||||
400.0f, // fProjectileMinSpeed
|
||||
25.0f, // fProjectileThrownStoreChance
|
||||
3.0f, // fRepairAmountMult
|
||||
1.0f, // fRepairMult
|
||||
1.0f, // fReputationMod
|
||||
0.15f, // fRestMagicMult
|
||||
0.0f, // fSeriousWoundMult
|
||||
0.25f, // fSleepRandMod
|
||||
0.3f, // fSleepRestMod
|
||||
-1.0f, // fSneakBootMult
|
||||
0.5f, // fSneakDistanceBase
|
||||
0.002f, // fSneakDistanceMultiplier
|
||||
0.5f, // fSneakNoViewMult
|
||||
1.0f, // fSneakSkillMult
|
||||
0.75f, // fSneakSpeedMultiplier
|
||||
1.0f, // fSneakUseDelay
|
||||
500.0f, // fSneakUseDist
|
||||
1.5f, // fSneakViewMult
|
||||
3.0f, // fSoulGemMult
|
||||
0.8f, // fSpecialSkillBonus
|
||||
7.0f, // fSpellMakingValueMult
|
||||
2.0f, // fSpellPriceMult
|
||||
10.0f, // fSpellValueMult
|
||||
0.25f, // fStromWalkMult
|
||||
0.7f, // fStromWindSpeed
|
||||
3.0f, // fSuffocationDamage
|
||||
0.9f, // fSwimHeightScale
|
||||
0.1f, // fSwimRunAthleticsMult
|
||||
0.5f, // fSwimRunBase
|
||||
0.02f, // fSwimWalkAthleticsMult
|
||||
0.5f, // fSwimWalkBase
|
||||
1.0f, // fSwingBlockBase
|
||||
1.0f, // fSwingBlockMult
|
||||
1000.0f, // fTargetSpellMaxSpeed
|
||||
1000.0f, // fThrownWeaponMaxSpeed
|
||||
300.0f, // fThrownWeaponMinSpeed
|
||||
0.0f, // fTrapCostMult
|
||||
4000.0f, // fTravelMult
|
||||
16000.0f,// fTravelTimeMult
|
||||
0.1f, // fUnarmoredBase1
|
||||
0.065f, // fUnarmoredBase2
|
||||
30.0f, // fVanityDelay
|
||||
10.0f, // fVoiceIdleOdds
|
||||
0.0f, // fWaterReflectUpdateAlways
|
||||
10.0f, // fWaterReflectUpdateSeldom
|
||||
0.1f, // fWeaponDamageMult
|
||||
1.0f, // fWeaponFatigueBlockMult
|
||||
0.25f, // fWeaponFatigueMult
|
||||
150.0f, // fWereWolfAcrobatics
|
||||
150.0f, // fWereWolfAgility
|
||||
1.0f, // fWereWolfAlchemy
|
||||
1.0f, // fWereWolfAlteration
|
||||
1.0f, // fWereWolfArmorer
|
||||
150.0f, // fWereWolfAthletics
|
||||
1.0f, // fWereWolfAxe
|
||||
1.0f, // fWereWolfBlock
|
||||
1.0f, // fWereWolfBluntWeapon
|
||||
1.0f, // fWereWolfConjuration
|
||||
1.0f, // fWereWolfDestruction
|
||||
1.0f, // fWereWolfEnchant
|
||||
150.0f, // fWereWolfEndurance
|
||||
400.0f, // fWereWolfFatigue
|
||||
100.0f, // fWereWolfHandtoHand
|
||||
2.0f, // fWereWolfHealth
|
||||
1.0f, // fWereWolfHeavyArmor
|
||||
1.0f, // fWereWolfIllusion
|
||||
1.0f, // fWereWolfIntellegence
|
||||
1.0f, // fWereWolfLightArmor
|
||||
1.0f, // fWereWolfLongBlade
|
||||
1.0f, // fWereWolfLuck
|
||||
100.0f, // fWereWolfMagicka
|
||||
1.0f, // fWereWolfMarksman
|
||||
1.0f, // fWereWolfMediumArmor
|
||||
1.0f, // fWereWolfMerchantile
|
||||
1.0f, // fWereWolfMysticism
|
||||
1.0f, // fWereWolfPersonality
|
||||
1.0f, // fWereWolfRestoration
|
||||
1.5f, // fWereWolfRunMult
|
||||
1.0f, // fWereWolfSecurity
|
||||
1.0f, // fWereWolfShortBlade
|
||||
1.5f, // fWereWolfSilverWeaponDamageMult
|
||||
1.0f, // fWereWolfSneak
|
||||
1.0f, // fWereWolfSpear
|
||||
1.0f, // fWereWolfSpeechcraft
|
||||
150.0f, // fWereWolfSpeed
|
||||
150.0f, // fWereWolfStrength
|
||||
100.0f, // fWereWolfUnarmored
|
||||
1.0f, // fWereWolfWillPower
|
||||
15.0f // fWortChanceValue
|
||||
};
|
||||
|
||||
const int CSMWorld::DefaultGmsts::IntsDefaultValues[CSMWorld::DefaultGmsts::IntCount] =
|
||||
|
|
|
@ -60,6 +60,10 @@ std::vector<CSMWorld::ColumnBase::Display> CSMWorld::IdCompletionManager::getDis
|
|||
{
|
||||
types.push_back(current->first);
|
||||
}
|
||||
|
||||
// Hack for Display_InfoCondVar
|
||||
types.push_back(CSMWorld::ColumnBase::Display_InfoCondVar);
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
|
@ -104,7 +108,7 @@ void CSMWorld::IdCompletionManager::generateCompleters(CSMWorld::Data &data)
|
|||
QAbstractItemView *popup = new CSVWidget::CompleterPopup();
|
||||
completer->setPopup(popup); // The completer takes ownership of the popup
|
||||
completer->setMaxVisibleItems(10);
|
||||
|
||||
|
||||
mCompleters[current->first] = completer;
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue