From 97db21043dd0e0407069012d7b4b1d618b2d5979 Mon Sep 17 00:00:00 2001 From: Arseniy Shestakov Date: Mon, 21 Aug 2017 02:43:04 +0300 Subject: [PATCH 01/68] Documentation: remove README.linux. Information moved to wiki https://wiki.vcmi.eu/index.php?title=How_to_build_VCMI_(Linux) Time is limited and duplication not make it any easier to maintain documentation. Since we have wiki already we must move all important information here and keep it up to date. --- README.linux | 112 --------------------------------------------------- 1 file changed, 112 deletions(-) delete mode 100644 README.linux diff --git a/README.linux b/README.linux deleted file mode 100644 index c6c045a82..000000000 --- a/README.linux +++ /dev/null @@ -1,112 +0,0 @@ -This readme covers VCMI compilation on Unix-like systems. - -To run the game you will need: -1) Heroes 3 data files (SoD or Complete editions); -2) VCMI data pack (http://download.vcmi.eu/core.zip) -All of them can be installed manually or using vcmibuilder script - -For complete installation instructions see VCMI wiki: -http://wiki.vcmi.eu/index.php?title=Installation_on_Linux#Preparing_data - -I. Prerequisites - -To compile, the following packages (and their development counterparts) are needed to build: - * libstdc++ devel - * CMake build system - * SDL and SDL-devel - * SDL_mixer and SDL_mixer-devel - * SDL_image and SDL_image-devel - * SDL_ttf and SDL_ttf-devel - * zlib and zlib-devel - * (optional) Qt 5, widget and network modules - * the ffmpeg libraries (libavformat and libswscale). Their name could be libavformat-devel and libswscale-devel, or ffmpeg-libs-devel or similar names. - * boost c++ libraries v1.50+ (www.boost.org): - - program-options - - filesystem - - system - - thread - - locale - -On Debian-based systems (e.g. Ubuntu) run: - sudo apt-get install cmake g++ libsdl2-dev libsdl2-image-dev libsdl2-ttf-dev libsdl2-mixer-dev zlib1g-dev libavformat-dev libswscale-dev libboost-dev libboost-filesystem-dev libboost-system-dev libboost-thread-dev libboost-program-options-dev libboost-locale-dev qtbase5-dev - -On RPM-based distributions (e.g. Fedora) run: - sudo yum install cmake gcc-c++ SDL2-devel SDL2_image-devel SDL2_ttf-devel SDL2_mixer-devel boost boost-devel boost-filesystem boost-system boost-thread boost-program-options boost-locale zlib-devel ffmpeg-devel ffmpeg-libs qt5-qtbase-devel - -On Arch-based distributions, there is a development package available for VCMI on the AUR. It can be found at: - https://aur.archlinux.org/packages/vcmi-git/ - - Information about building packages from the Arch User Repository (AUR) can be - found at the Arch wiki. - -II. Getting the sources - -VCMI is still in development. We recommend the following initial directory structure: -. -├── vcmi -> contains sources and is under git control -└── build -> contains build output, makefiles, object files,... - -You can get latest sources with: - git clone https://github.com/vcmi/vcmi.git - -III. Compilation - -Run configure: - mkdir build && cd build - cmake ../vcmi - -Additional options that you may want to use: -To enable debugging: -DCMAKE_BUILD_TYPE=Debug -To change installation directory: -DCMAKE_INSTALL_PREFIX=$absolute_path_to_directory - -Notice: -The ../vcmi/ is not a typo, it will place makefile scripts into the build dir -as the build dir is your working dir when calling CMake. - -Then build vcmi: - make -j2 (j2 = compile with 2 threads, you can specify any value) - -That will generate vcmiclient, vcmiserver, vcmilauncher as well as 3 .so libraries. - -III. Installing binaries - -To install VCMI you can use "make install" command however generation of distribution-specific packages is usually a better idea. In most cases this can be achieved using tool called "checkinstall" - -If you're compiling vcmi for development puposes, the easiest is to use cmake prefix and then make install: - -# mkdir .../trunk/install -# cmake -DCMAKE_INSTALL_PREFIX=.../trunk/install ../vcmi -# make && make install -# .../trunk/install/bin/vcmiclient - - -it's better to use links instead. -Go to /BIN_PATH/, and type: - - ln -s .../trunk/build/client/vcmiclient - ln -s .../trunk/build/server/vcmiserver - ln -s .../trunk/build/launcher/vcmilauncher - -Go to /LIB_PATH/vcmi, and type: - - ln -s .../trunk/build/lib/libvcmi.so libvcmi.so - -Go to /LIB_PATH/vcmi/AI, and type: - ln -s .../trunk/build/AI/VCAI/libVCAI.so - ln -s .../trunk/build/AI/StupidAI/libStupidAI.so - ln -s .../trunk/build/AI/BattleAI/libBattleAI.so - -Go to /DATA_PATH/vcmi, and type: - ln -s .../trunk/source/config - ln -s .../trunk/source/Mods - -IV. Compiling documentation - -To compile using Doxygen, the UseDoxygen CMake module must be installed. It can -be fetched from: http://tobias.rautenkranz.ch/cmake/doxygen/ - -Once UseDoxygen is installed, run: - cmake . - make doc - -The built documentation will be available from ./doc From dfe781945b845b4d991f2b2bbf39a17ca7969b78 Mon Sep 17 00:00:00 2001 From: Arseniy Shestakov Date: Mon, 21 Aug 2017 15:45:33 +0300 Subject: [PATCH 02/68] CMake: try to enable automated DS_Store generation for Mac We should see in AppleScript from CMake would work on Travis CI. Also use VCMI as volume name of DMG for now and update pre-generated DS_Store for it. --- CMakeLists.txt | 10 +++++- osx/DS_Store_Setup.scpt | 75 ++++++++++++++++++++++++++++++++++++++++ osx/dmg_DS_Store | Bin 15364 -> 10244 bytes 3 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 osx/DS_Store_Setup.scpt diff --git a/CMakeLists.txt b/CMakeLists.txt index 95d4fecbe..2d12c323f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -414,7 +414,15 @@ elseif(APPLE AND NOT ENABLE_MONOLITHIC_INSTALL) set(CPACK_MONOLITHIC_INSTALL 1) set(CPACK_GENERATOR "DragNDrop") set(CPACK_DMG_BACKGROUND_IMAGE "${CMAKE_SOURCE_DIR}/osx/dmg_background.png") - set(CPACK_DMG_DS_STORE "${CMAKE_SOURCE_DIR}/osx/dmg_DS_Store") + # CMake code for CPACK_DMG_DS_STORE executed before DS_STORE_SETUP_SCRIPT + # So we can keep both enabled and this shouldn't hurt + # set(CPACK_DMG_DS_STORE "${CMAKE_SOURCE_DIR}/osx/dmg_DS_Store") + set(CPACK_DMG_DS_STORE_SETUP_SCRIPT "${CMAKE_SOURCE_DIR}/osx/DS_Store_Setup.scpt") + + # Always use "VCMI" as volume name so full path will be /Volumes/VCMI/ + # Otherwise DMG background image wouldn't work + # Pre-generated DS_Store use absolute path to background image + set(CPACK_DMG_VOLUME_NAME "${CMAKE_PROJECT_NAME}") set(MACOSX_BUNDLE_NAME "${CMAKE_PROJECT_NAME}") set(MACOSX_BUNDLE_BUNDLE_NAME "${CMAKE_PROJECT_NAME}") diff --git a/osx/DS_Store_Setup.scpt b/osx/DS_Store_Setup.scpt new file mode 100644 index 000000000..6d32c67d4 --- /dev/null +++ b/osx/DS_Store_Setup.scpt @@ -0,0 +1,75 @@ +-- Shamelessly taken from CMake source: Packaging/CMakeDMGSetup.scpt +-- For licensing check cmake_modules/kitware license.txt +-- +-- You can as well use this script to manually generate DS_Store +-- First make DMG writable: +-- hdiutil convert VCMI.dmg -format UDRW -o VCMI_writable.dmg +-- Check current size of the image +-- hdiutil resize -limits VCMI_writable.dmg +-- Increase it size slightly so you can update .DS_Store +-- Using 999999 will result in 512mb file though +-- hdiutil resize -sectors 999999 VCMI_writable.dmg +-- Attach it to /Volumes/VCMI/ +-- hdiutil attach VCMI_writable.dmg +-- After run this script directly and it's will do the job +-- osascript /path/to/vcmi/source/osx/DS_Store_Setup.scpt VCMI +-- You should see icons moving and background appear +-- Now /Volumes/VCMI/.DS_Store can be copied over to /path/to/vcmi/source/osx/dmg_DS_Stor + +on run argv + set image_name to item 1 of argv + + tell application "Finder" + tell disk image_name + + -- wait for the image to finish mounting + set open_attempts to 0 + repeat while open_attempts < 4 + try + open + delay 1 + set open_attempts to 5 + close + on error errStr number errorNumber + set open_attempts to open_attempts + 1 + delay 10 + end try + end repeat + delay 5 + + -- open the image the first time and save a DS_Store with just + -- background and icon setup + open + set current view of container window to icon view + set theViewOptions to the icon view options of container window + set background picture of theViewOptions to file ".background:background.png" + set arrangement of theViewOptions to not arranged + set icon size of theViewOptions to 128 + delay 5 + close + + -- next setup the position of the app and Applications symlink + -- plus hide all the window decoration + open + update without registering applications + tell container window + set sidebar width to 0 + set statusbar visible to false + set toolbar visible to false + set the bounds to { 400, 100, 900, 423 } + set position of item "VCMI.app" to { 133, 140 } + set position of item "Applications" to { 378, 140 } + end tell + update without registering applications + delay 5 + close + + -- one last open and close so you can see everything looks correct + open + delay 5 + close + + end tell + delay 1 +end tell +end run diff --git a/osx/dmg_DS_Store b/osx/dmg_DS_Store index 945e8efcd38affb3de4af142e3e21c8c139f6d9e..f871faa2b9e0d4543fcd0cac871c913bb385be68 100644 GIT binary patch literal 10244 zcmeHMU2Ggz6+Yvv{}S67|529~G?G)PfOmKHf7b@GyZ)gTsa$n~apV+dc4yWZWp-w@ zySAI80i%i+@I%D|0z{>Pc;Eq1UO+}wg?S57AKEGrMMCfzp2!20@&tTm=FaYVx2nnm z6;kIUch7f!&bjA)bLZSU2@y%fJv~OG5YY$I_PLlZeki^WA_(GA~ z+2LPthm(}|bnqK65HQfsfcNblDIYZJWvl!9T~+@i4V(!L4h@g6jE}rfy6zm5T3Tzb zS=1WaZq3wSuYTRMb?2by?AdzL_4Az8x(-`+ zq8)ke_U)vqE-0By=FWn0JHX%wwJW6P{KcFDYDT+td0&E7SNH@8~Gi!E;2k*9hro;UPwbeb;TtYgefr@{65 zm4;#1+q(@@->6obMr*4JU%A=@wr*D)_}>So8}*jy*v(C&(S&}%(#nRlVHcfN z%c-4mzh2XJje=!r%^mr?>j<$w*D%rT{`@CR z|Ar8ai!-2Ye=gFQhtDCL3HMLF`!4z?1%3zEJ91_azrx`!b{Q>F$AKH@1bvn!s7xAF z=mzalgB;o;n{eW9`+9X4K={3_9Ox_!Q{TS_n$?yFgm=A44LqnHdMf3~Z!7qNTi7mQFu7^eHk9UGD zz?aY44jq77lUiW9Ocoj7SEriG@26=Dh@Zd)l}JG`(ci!y4Savboha(g<5Jo~%QQ(* zqFKZ@#(Rd#=zRW)Sm6kLjxN$O^gM0jd47w2KtH2j(HrzO{gvLAhNWrgN$Dx+^HM@e zNne&ON(HGH8VU`2)&u^2d{TH5D#UjXWS)AlsCr3N%GSe8&DP7#i;;$*>0y3!#**qu zY)Or|DCM{K9jT@0zSu4Mm74jXTZ`x|O#3f9N)GGixEFC49Lp9o%OLQtJxDU}djjWy z?+OflN#%DIGN2G0iTl+cFxKRX42-|7OakOZ`xLMu@HDV0umWreoCiJc`FA<-of1A09sZ+J`&{-x|VH)h-?5Rz44{b5QT@;sk8gHd?L*p$x<@fy0bx^=u# z{3Xn|>lMc9@3r;5$}+dZH){oD0VR)uq(dRh_0vn}?5g|8%I}|XdpqN2McwyXNBt1x z6_nRd*p7oO{Qj$xoW|x*_!cb4>^uH=xC9p2uQW1JlY&x9Ct|h|RLLwW^rQ^w!wRmB5HIedT(nMVUnC`>}H!j!w z9A3j&&6BZT_x%O->muhMIe7j3sRMbE`#|pxVgC!1V-%m)S9^Fjj!!>_m$%cf?)Z2B z+ed7Vn7h_K#R<;$iEdYThjRSyi}|{Fbz?$%cNX;RN%_MOsOb2A^ZV&z)O~JO&-8W1SWhgcCu5at zEUCv*ni|jMvgMenSM)?Bkx+A)crH=Nrjkarop<_ymx|)*QpKr7w0a%K4SqjLHjB5N zscIsfDrXZ*(LFvDM6%|L)|0H?L)@Ifcz>|)9^edij~55w3^s>#vGiuJ1<^jB5Iqoh z5O~WU4}4wVN#LId%vtLtfjMg(39JC$6<7s+M4m_|L|+u`lfb;qPCbr;Ra}k9jGam-yWp!wWfwazSXuzvDiv z1zReS)vKv$vYOITIThO~mev#HYEI9Tb4FFiUdyDaT6+idgAd$S?4Ba~rG{-e?lqAE z;+AI1YT*KHR_uMWjN*2%f_uOYN((o#1{v#?QxP99*dufmbQ-VxO-@@F)^1-%^tg3usiCSYovXviNFdTPLHSW^o&O} zkbr@Yp8+Hq7KLv;t4OGPf&~&V5HRq`Vn7P5lvavZv$)Cht)6c$3d%JU79Mx#Y1afl z?ga;$ZxUSLoA1+%(WbIy0nQ73=xMY-KKB0%2)_S&Z_jt#2Z0|Y`2PPyeEU& literal 15364 zcmeHMO>7&-6@E*tVk*|p>c_R!x(Q+BprR(Z{1GWi1td{aY6C%RRH`G#O4TKIB@v=_ z+2x9K;;4}m12qaCisq6-iWcY(d??@`E!qHW00Fres1G?5MGgrH1V(#kk_u>o`r@?T z+nuE-Dlmc|ZH;0_c=O)Oy!U42o0&JW6cI`JO+7&rA)+vdxzdg76B4&G9Y`Tj!*&wv z$tps+QLI+VHRphKP!S*yAP^uBAP^uBAaFk*fIFL0_^`)=JU}2oAV8pr0LO<2i21bO z+a7mA2Qv2)09;13n;|XhD)ZQ*h5z5}z27XO8-a(3=)~+vA=&N#f%} z5X17hI21Q*CfZJK)R!u*=mm@n%_QL~?NWk+*1YkAFfTh40E8d_X=!LlllmxT5cW!+g@R*qe| zluRT~Mlz|)*2&1FbS`%?l1e7Gwzx0lZ{Z^+VqZJ8pgp_w-RHKwF-zjyQ%~C*o<~`t zSh-Xe6X@*met=NbKP!Fy6uKTf+}+dLr}PgD4juWz(PP73{L=B`4=pQ$MXj{HYV)jS zt%_ymE1Sl$GPGBFdP7?^W-4W^wpcD%=6v}XW6?1#IxH+J1AB_D`8N#xTYFUtPgnOl zb9KIM8-{sd)h_F2R#s|;v)Ce^U#bDw(~hxm+FY^Vzg{*PXR1!wGHd4yy9Rz zHS$kCRndw@<&2rP9LL&NR{C694DzgPu$}97zN(eV=IY4Qu7}&1{*D4m$Pq!6dTFB^ zRb#nyw4m9Ivgs+g`K^z?{MxCnQYQ+b-n~i1s^)5o)~6Pa!r!la?SCN=^@tem*M7oq z6uuU2-TlW^==2Nu1<1S`LiBL^@F&{G*-H;mFBM6n60OrJ*<{fsnWR&Us^F{CM<;OQ z)X}~{Wr~uDmK^dZ6<}pk1GOd%P+z>=_aF_&&smkt4Wkxs9|+Nq^cK$xIcC{0KkuT> zHSOuvokPC`&P2l(J_uvwt1*4!Ga<~5hu2>R&cD`;x~=QAbr0vR2sgE)u7a(tK3=e` zD&N+O@IT-A9@>3`uRxY)lt%=5AM_p#k6xq0Z%k46-B+nI_atbJ!h+KfnoU zLeh&>2$MqwR;r3s(!qKC!qh?Y_$#1&!5u@qIfOWmAnp#pT_Z1Zdyltu9{2i=H@l8E zdmbbyPILtGRCwPqjZ80ifR0R$3c){ON~n3-M!Y7d`$AZe7EH@Dy1GWD&x^`1eTAmz z94*rtZP7LQDczvo(M@`X{z@N7honL2xU9aZt1|T^-lPvn#o*n$WUpE~)Cp z?24g{CsHLnrLJUCV@5iwPpTp{1+Sb`Crj2wOsiHa2ItY5X6i-jV$3!)J=(C#j^SG* zCe?&%l<{kX%S3iEUO#ZIbvHh?2Z0@ooAKniT}Pr|0pc+b?=}ID zyK1b`nk1}(@0)h7JkD*cey*bY2#DwVXl5oqmr1M9^msZGO{sIKXg)bR9!<@TWoKu` zXC5u&=lni3x8E@ReTw^cJ+kZODftPu5N`nX>jpE(U839!YeJuOIKcV(Zk%grW8D2V zH|C*@cPQJnML#zZaJ~Ny@cV3rL)h_XS;r5Iygq!IA4A;|s0w-(bWPAp;MYMrpf^Fc zLF|Lq^R~GC{c__julip5T#iS+SAMds{OY?NcE0`88{W@Ye)-zy@IL$ZF6=MA-&X#h zt^E4Br|-{k6zet)It5w;t${9ru7X|yT?f4ex(RYeCidHvmN_t{oOq@jDL(=pU@oTo zLh#2<+kXi+P`~Hrd7ba)M}+QJVNT6t3h8KeESrj^a@cvfY$_j}8_ObO=F_RMWYXVn zm)QoM+V>l}cKeNk`{Tg{hf4?b;A5%Wn2}0oW4VNyR1HH*m$Dg6OP0oq87*TN*>p0I z%Vo!#!LuoR_DGy;@sY@7ibZ`gzR8b@PkEu2@Yr2n=8RtxaS^h0yd_K>kDa{>9do<| z;>gYCjgtc6$o(M$gT#^hE#SbZJ#u&Rq9KJMpU=&y!Viy!leB|dQTXqN%;$>Jzz*V} zsBe$rH$^?~SU#Wkc$U%vJA)d<>hrc)vE0|ZyBSbZb1Du#TFND}4xKJMvI=-uErT39 zoNY2rSFDowPGrEAK#%bwlb=LL55i)FYIvg6K_;wfr0=(pIQX~PgkiG)-x_q+U{!0= z-(h`Fr|6@bX7K#0QUwq56096>3w^cQZNTP-xH&eVW9siE!YY!!GZ>PsbSyD?lJX;6I0eBp2ojdH5Gs z&4Hfy8jOIx4dTRl+a7mKkhwP{I6o!0z)zP^mQklN=LC6L@NJKy2I;^4&j9}QA^85s zTJh&!DDwHdVw$hW-If<6{QLF1*8FG)zW;Fy0L1_L`yWdYqyT{cfdGL3fdGL3fdGL3 dfdGL3fdGL3fdGL3fdGL3fdGL3f&WVc{tYWiai;(P From 525ee8771a619178fe775a4dffb8dbab063ce2aa Mon Sep 17 00:00:00 2001 From: Arseniy Shestakov Date: Thu, 24 Aug 2017 02:40:36 +0300 Subject: [PATCH 03/68] Launcher: avoid menu items not overlap so it's look slightly better It's still very ugly, but less ugly than it's was. --- launcher/mainwindow_moc.ui | 99 ++++++++++++++++++++------------------ 1 file changed, 51 insertions(+), 48 deletions(-) diff --git a/launcher/mainwindow_moc.ui b/launcher/mainwindow_moc.ui index f5a9584ee..9e099e547 100644 --- a/launcher/mainwindow_moc.ui +++ b/launcher/mainwindow_moc.ui @@ -34,15 +34,15 @@ - - 0 + + 89 0 - + - 65 - 16777215 + 89 + 89 @@ -61,27 +61,24 @@ QAbstractItemView::NoDragDrop - QAbstractItemView::SelectRows + QAbstractItemView::SelectItems - 48 - 64 + 89 + 89 - - QListView::Static + + QListView::TopToBottom - QListView::Fixed - - - 0 + QListView::Adjust - 64 - 64 + 100 + 100 @@ -93,12 +90,6 @@ true - - false - - - 0 - Mods @@ -119,32 +110,6 @@ - - - - Play - - - - icons:menu-game.pngicons:menu-game.png - - - - 60 - 60 - - - - false - - - false - - - Qt::ToolButtonIconOnly - - - @@ -179,6 +144,44 @@ + + + + + 89 + 0 + + + + + 89 + 89 + + + + Play + + + + icons:menu-game.pngicons:menu-game.png + + + + 60 + 60 + + + + false + + + false + + + Qt::ToolButtonIconOnly + + + From c6ff28936d4c596ca914476b911a26095e266bbf Mon Sep 17 00:00:00 2001 From: Arseniy Shestakov Date: Thu, 24 Aug 2017 03:22:24 +0300 Subject: [PATCH 04/68] Client: change intro video position --- client/CMT.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/CMT.cpp b/client/CMT.cpp index debae5f2e..1283a9f31 100644 --- a/client/CMT.cpp +++ b/client/CMT.cpp @@ -938,9 +938,9 @@ void processCommand(const std::string &message) //plays intro, ends when intro is over or button has been pressed (handles events) void playIntro() { - if(CCS->videoh->openAndPlayVideo("3DOLOGO.SMK", 60, 40, screen, true, true)) + if(CCS->videoh->openAndPlayVideo("3DOLOGO.SMK", 0, 1, screen, true, true)) { - CCS->videoh->openAndPlayVideo("AZVS.SMK", 60, 80, screen, true, true); + CCS->videoh->openAndPlayVideo("AZVS.SMK", 0, 1, screen, true, true); } } From 1110dd27d1e2be63a9edb3b90a6f90c228913ca8 Mon Sep 17 00:00:00 2001 From: Arseniy Shestakov Date: Thu, 24 Aug 2017 04:52:02 +0300 Subject: [PATCH 05/68] Launcher: use QDesktopWidget to get display list instead of SDL2 First of all SDL2 trying to use dbus and this conflict with Qt. Check mantis#2704. And there no reason to use SDL2 in launcher when Qt can do the same thing as well. --- launcher/CMakeLists.txt | 5 +-- launcher/main.cpp | 4 +- launcher/mainwindow_moc.cpp | 4 +- launcher/mainwindow_moc.h | 2 +- launcher/sdldisplayquery.cpp | 42 --------------------- launcher/sdldisplayquery.h | 14 ------- launcher/settingsView/csettingsview_moc.cpp | 33 ++++++++++------ launcher/settingsView/csettingsview_moc.h | 2 +- 8 files changed, 28 insertions(+), 78 deletions(-) delete mode 100644 launcher/sdldisplayquery.cpp delete mode 100644 launcher/sdldisplayquery.h diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 9365d5faa..6acee13dd 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -2,7 +2,6 @@ # https://doc.qt.io/qt-5/cmake-manual.html include_directories(${CMAKE_HOME_DIRECTORY} ${CMAKE_HOME_DIRECTORY}/include ${CMAKE_CURRENT_SOURCE_DIR}) include_directories(${ZLIB_INCLUDE_DIR} ${Boost_INCLUDE_DIRS} ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Network_INCLUDE_DIRS}) -include_directories(${SDL2_INCLUDE_DIR}) set(launcher_modmanager_SRCS modManager/cdownloadmanager_moc.cpp @@ -38,7 +37,6 @@ set(launcher_SRCS mainwindow_moc.cpp launcherdirs.cpp jsonutils.cpp - sdldisplayquery.cpp ) set(launcher_HEADERS @@ -48,7 +46,6 @@ set(launcher_HEADERS mainwindow_moc.h launcherdirs.h jsonutils.h - sdldisplayquery.h ) set(launcher_FORMS @@ -102,7 +99,7 @@ if(APPLE) set_property(GLOBAL PROPERTY AUTOGEN_TARGETS_FOLDER vcmilauncher) endif() -target_link_libraries(vcmilauncher vcmi Qt5::Widgets Qt5::Network ${SDL2_LIBRARY}) +target_link_libraries(vcmilauncher vcmi Qt5::Widgets Qt5::Network) vcmi_set_output_dir(vcmilauncher "") diff --git a/launcher/main.cpp b/launcher/main.cpp index 49f0d80ff..5bfa2467b 100644 --- a/launcher/main.cpp +++ b/launcher/main.cpp @@ -10,13 +10,11 @@ #include #include "StdInc.h" #include "mainwindow_moc.h" -#include "sdldisplayquery.h" int main(int argc, char * argv[]) { QApplication vcmilauncher(argc, argv); - auto displayList = getDisplays(); - MainWindow mainWindow(displayList); + MainWindow mainWindow; mainWindow.show(); return vcmilauncher.exec(); } diff --git a/launcher/mainwindow_moc.cpp b/launcher/mainwindow_moc.cpp index 43412592e..bac1225a7 100644 --- a/launcher/mainwindow_moc.cpp +++ b/launcher/mainwindow_moc.cpp @@ -39,7 +39,7 @@ void MainWindow::load() settings.init(); } -MainWindow::MainWindow(const QStringList& displayList, QWidget *parent) : +MainWindow::MainWindow(QWidget * parent) : QMainWindow(parent), ui(new Ui::MainWindow) { @@ -62,7 +62,7 @@ MainWindow::MainWindow(const QStringList& displayList, QWidget *parent) : ui->tabSelectList->setMaximumWidth(width + 4); } ui->tabListWidget->setCurrentIndex(0); - ui->settingsView->setDisplayList(displayList); + ui->settingsView->setDisplayList(); connect(ui->tabSelectList, SIGNAL(currentRowChanged(int)), ui->tabListWidget, SLOT(setCurrentIndex(int))); diff --git a/launcher/mainwindow_moc.h b/launcher/mainwindow_moc.h index 7a7220fff..d1b65c67e 100644 --- a/launcher/mainwindow_moc.h +++ b/launcher/mainwindow_moc.h @@ -25,7 +25,7 @@ private: void load(); void startExecutable(QString name); public: - explicit MainWindow(const QStringList& displayList, QWidget *parent = 0); + explicit MainWindow(QWidget * parent = 0); ~MainWindow(); private slots: diff --git a/launcher/sdldisplayquery.cpp b/launcher/sdldisplayquery.cpp deleted file mode 100644 index d0ac8734a..000000000 --- a/launcher/sdldisplayquery.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * sdldisplayquery.cpp, part of VCMI engine - * - * Authors: listed in file AUTHORS in main folder - * - * License: GNU General Public License v2.0 or later - * Full text of license available in license.txt file, in main folder - * - */ -#include "StdInc.h" -#include "sdldisplayquery.h" - -#include -#include - -#include -#include - -QStringList getDisplays() -{ - if(SDL_Init(SDL_INIT_VIDEO)) - return QStringList("default display"); - - const int displays = SDL_GetNumVideoDisplays(); - QStringList list; - - for (int display = 0; display < displays; ++display) - { - SDL_Rect rect; - - if (SDL_GetDisplayBounds (display, &rect)) - continue; - - QString string; - QTextStream(&string) << display << " - " << rect.w << "x" << rect.h << " (at " << rect.x << ", " << rect.y << ")"; - - list << string; - } - - SDL_Quit(); - return list; -} diff --git a/launcher/sdldisplayquery.h b/launcher/sdldisplayquery.h deleted file mode 100644 index b8ab2bca7..000000000 --- a/launcher/sdldisplayquery.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * sdldisplayquery.h, part of VCMI engine - * - * Authors: listed in file AUTHORS in main folder - * - * License: GNU General Public License v2.0 or later - * Full text of license available in license.txt file, in main folder - * - */ -#pragma once - -#include - -QStringList getDisplays(); diff --git a/launcher/settingsView/csettingsview_moc.cpp b/launcher/settingsView/csettingsview_moc.cpp index 2bf8ae288..a5be7626b 100644 --- a/launcher/settingsView/csettingsview_moc.cpp +++ b/launcher/settingsView/csettingsview_moc.cpp @@ -29,19 +29,30 @@ static const std::string knownEncodingsList[] = //TODO: remove hardcode "GB2312" // basic set for Simplified Chinese. Separate from GBK to allow proper detection of H3 fonts }; -void CSettingsView::setDisplayList(const QStringList& displayList) +void CSettingsView::setDisplayList() { - if (displayList.count() < 2) - { - ui->comboBoxDisplayIndex->hide (); - ui->labelDisplayIndex->hide (); - } + QStringList list; + QDesktopWidget * widget = QApplication::desktop(); + for(int display = 0; display < widget->screenCount(); display++) + { + QString string; + auto rect = widget->screenGeometry(display); + QTextStream(&string) << display << " - " << rect.width() << "x" << rect.height(); + list << string; + } + + if(list.count() < 2) + { + ui->comboBoxDisplayIndex->hide(); + ui->labelDisplayIndex->hide(); + } else - { - ui->comboBoxDisplayIndex->clear(); - ui->comboBoxDisplayIndex->addItems(displayList); - ui->comboBoxDisplayIndex->setCurrentIndex(settings["video"]["displayIndex"].Float()); - } + { + int displayIndex = settings["video"]["displayIndex"].Integer(); + ui->comboBoxDisplayIndex->clear(); + ui->comboBoxDisplayIndex->addItems(list); + ui->comboBoxDisplayIndex->setCurrentIndex(displayIndex); + } } void CSettingsView::loadSettings() diff --git a/launcher/settingsView/csettingsview_moc.h b/launcher/settingsView/csettingsview_moc.h index e9e1539a8..fdebb2b98 100644 --- a/launcher/settingsView/csettingsview_moc.h +++ b/launcher/settingsView/csettingsview_moc.h @@ -22,7 +22,7 @@ public: ~CSettingsView(); void loadSettings(); - void setDisplayList(const QStringList& displayList); + void setDisplayList(); private slots: void on_checkBoxFullScreen_stateChanged(int state); From 8180e4d5c5ba9ecd6ba36d8f15af10736b2fa8a3 Mon Sep 17 00:00:00 2001 From: Arseniy Shestakov Date: Fri, 25 Aug 2017 08:32:14 +0300 Subject: [PATCH 06/68] VCMIDirs: improvements for development on Mac and Linux Also added /usr/share/games in VCMIDirsXDG::dataPaths for mantis#2189. --- CMakeLists.txt | 10 +++--- lib/VCMIDirs.cpp | 73 ++++++++++++++++++++++++++++-------------- server/CVCMIServer.cpp | 6 ++-- 3 files changed, 56 insertions(+), 33 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d12c323f..2914f6ea2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -262,16 +262,16 @@ else() set(DATA_DIR "share/vcmi" CACHE STRING "Where to install data files") endif() endif() + + # following constants only used for platforms using XDG (Linux, BSD, etc) + add_definitions(-DM_DATA_DIR="${CMAKE_INSTALL_PREFIX}/${DATA_DIR}") + add_definitions(-DM_BIN_DIR="${CMAKE_INSTALL_PREFIX}/${BIN_DIR}") + add_definitions(-DM_LIB_DIR="${CMAKE_INSTALL_PREFIX}/${LIB_DIR}") endif() set(AI_LIB_DIR "${LIB_DIR}/AI") set(SCRIPTING_LIB_DIR "${LIB_DIR}/scripting") -#define required constants -add_definitions(-DM_DATA_DIR="${CMAKE_INSTALL_PREFIX}/${DATA_DIR}") -add_definitions(-DM_BIN_DIR="${CMAKE_INSTALL_PREFIX}/${BIN_DIR}") -add_definitions(-DM_LIB_DIR="${CMAKE_INSTALL_PREFIX}/${LIB_DIR}") - ####################################### # Add subdirectories # ####################################### diff --git a/lib/VCMIDirs.cpp b/lib/VCMIDirs.cpp index 3fde5079a..e311ca9f7 100644 --- a/lib/VCMIDirs.cpp +++ b/lib/VCMIDirs.cpp @@ -271,7 +271,7 @@ bfs::path VCMIDirsWIN32::userDataPath() const wchar_t profileDir[MAX_PATH]; if (SHGetSpecialFolderPathW(nullptr, profileDir, CSIDL_MYDOCUMENTS, FALSE) != FALSE) - return bfs::path(profileDir) / "My Games\\vcmi"; + return bfs::path(profileDir) / "My Games" / "vcmi"; return "."; } @@ -350,8 +350,16 @@ class IVCMIDirsUNIX : public IVCMIDirs boost::filesystem::path serverPath() const override; std::string genHelpString() const override; + + bool developmentMode() const; }; +bool IVCMIDirsUNIX::developmentMode() const +{ + // We want to be able to run VCMI from single directory. E.g to run from build output directory + return bfs::exists("AI") && bfs::exists("config") && bfs::exists("Mods") && bfs::exists("vcmiserver") && bfs::exists("vcmiclient"); +} + bfs::path IVCMIDirsUNIX::clientPath() const { return binaryPath() / "vcmiclient"; } bfs::path IVCMIDirsUNIX::serverPath() const { return binaryPath() / "vcmiserver"; } @@ -454,7 +462,7 @@ std::vector VCMIDirsOSX::dataPaths() const { std::vector ret; //FIXME: need some proper codepath for detecting running from build output directory - if(bfs::exists("config") && bfs::exists("Mods") && bfs::exists("vcmiserver")) + if(developmentMode()) { ret.push_back("."); } @@ -489,9 +497,9 @@ bfs::path VCMIDirsXDG::userDataPath() const { // $XDG_DATA_HOME, default: $HOME/.local/share const char* homeDir; - if ((homeDir = getenv("XDG_DATA_HOME"))) - return homeDir; - else if ((homeDir = getenv("HOME"))) + if((homeDir = getenv("XDG_DATA_HOME"))) + return bfs::path(homeDir) / "vcmi"; + else if((homeDir = getenv("HOME"))) return bfs::path(homeDir) / ".local" / "share" / "vcmi"; else return "."; @@ -499,7 +507,7 @@ bfs::path VCMIDirsXDG::userDataPath() const bfs::path VCMIDirsXDG::userCachePath() const { // $XDG_CACHE_HOME, default: $HOME/.cache - const char* tempResult; + const char * tempResult; if ((tempResult = getenv("XDG_CACHE_HOME"))) return bfs::path(tempResult) / "vcmi"; else if ((tempResult = getenv("HOME"))) @@ -510,7 +518,7 @@ bfs::path VCMIDirsXDG::userCachePath() const bfs::path VCMIDirsXDG::userConfigPath() const { // $XDG_CONFIG_HOME, default: $HOME/.config - const char* tempResult; + const char * tempResult; if ((tempResult = getenv("XDG_CONFIG_HOME"))) return bfs::path(tempResult) / "vcmi"; else if ((tempResult = getenv("HOME"))) @@ -528,34 +536,51 @@ std::vector VCMIDirsXDG::dataPaths() const // in vcmi fs last directory has highest priority std::vector ret; - const char* tempResult; - ret.push_back(M_DATA_DIR); - - //FIXME: need some proper codepath for detecting running from build output directory - if(bfs::exists("config") && bfs::exists("Mods") && bfs::exists("vcmiserver")) + if(developmentMode()) { //For now we'll disable usage of system directories when VCMI running from bin directory ret.push_back("."); } - else if((tempResult = getenv("XDG_DATA_DIRS")) != nullptr) - { - std::string dataDirsEnv = tempResult; - std::vector dataDirs; - boost::split(dataDirs, dataDirsEnv, boost::is_any_of(":")); - for (auto & entry : boost::adaptors::reverse(dataDirs)) - ret.push_back(entry + "/vcmi"); - } else { - ret.push_back("/usr/share/"); - ret.push_back("/usr/local/share/"); + ret.push_back(M_DATA_DIR); + const char * tempResult; + if((tempResult = getenv("XDG_DATA_DIRS")) != nullptr) + { + std::string dataDirsEnv = tempResult; + std::vector dataDirs; + boost::split(dataDirs, dataDirsEnv, boost::is_any_of(":")); + for (auto & entry : boost::adaptors::reverse(dataDirs)) + ret.push_back(bfs::path(entry) / "vcmi"); + } + else + { + ret.push_back(bfs::path("/usr/share") / "vcmi"); + ret.push_back(bfs::path("/usr/local/share") / "vcmi"); + } + + // Debian and other distributions might want to use it while it's not part of XDG + ret.push_back(bfs::path("/usr/share/games") / "vcmi"); } return ret; } -bfs::path VCMIDirsXDG::libraryPath() const { return M_LIB_DIR; } -bfs::path VCMIDirsXDG::binaryPath() const { return M_BIN_DIR; } +bfs::path VCMIDirsXDG::libraryPath() const +{ + if(developmentMode()) + return "."; + else + return M_LIB_DIR; +} + +bfs::path VCMIDirsXDG::binaryPath() const +{ + if(developmentMode()) + return "."; + else + return M_BIN_DIR; +} std::string VCMIDirsXDG::libraryName(const std::string& basename) const { return "lib" + basename + ".so"; } diff --git a/server/CVCMIServer.cpp b/server/CVCMIServer.cpp index 5515de66e..64145c025 100644 --- a/server/CVCMIServer.cpp +++ b/server/CVCMIServer.cpp @@ -609,11 +609,9 @@ void handleLinuxSignal(int sig) int main(int argc, char * argv[]) { -#ifndef VCMI_WINDOWS +#ifndef VCMI_ANDROID // Correct working dir executable folder (not bundle folder) so we can use executable relative paths - std::string executablePath = argv[0]; - std::string workDir = executablePath.substr(0, executablePath.rfind('/')); - chdir(workDir.c_str()); + boost::filesystem::current_path(boost::filesystem::system_complete(argv[0]).parent_path()); #endif // Installs a sig sev segmentation violation handler // to log stacktrace From fbab52eb1863263c7360519c6bc88c85c8fee782 Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Sun, 20 Aug 2017 19:18:07 +1200 Subject: [PATCH 07/68] added basic handler for loading secondary skill bonuses --- lib/CMakeLists.txt | 1 + lib/CSkillHandler.cpp | 117 ++++++++++++++++++++++++++++++++++++++++++ lib/CSkillHandler.h | 66 ++++++++++++++++++++++++ lib/GameConstants.cpp | 6 +++ lib/GameConstants.h | 3 ++ lib/IGameCallback.cpp | 1 + lib/VCMI_Lib.cpp | 5 ++ lib/VCMI_Lib.h | 3 ++ 8 files changed, 202 insertions(+) create mode 100644 lib/CSkillHandler.cpp create mode 100644 lib/CSkillHandler.h diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 14ad6253d..c1f2dc53a 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -115,6 +115,7 @@ set(lib_SRCS CModHandler.cpp CPathfinder.cpp CRandomGenerator.cpp + CSkillHandler.cpp CStack.cpp CThreadHelper.cpp CTownHandler.cpp diff --git a/lib/CSkillHandler.cpp b/lib/CSkillHandler.cpp new file mode 100644 index 000000000..8a1a3796a --- /dev/null +++ b/lib/CSkillHandler.cpp @@ -0,0 +1,117 @@ +/* + * CSkillHandler.cpp, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ + +#include "StdInc.h" + +#include + +#include "CSkillHandler.h" + +#include "CGeneralTextHandler.h" +#include "filesystem/Filesystem.h" + +#include "JsonNode.h" + +#include "CModHandler.h" +#include "StringConstants.h" + +#include "CStack.h" +#include "battle/BattleInfo.h" +#include "battle/CBattleInfoCallback.h" + +///CSkill +CSkill::CSkill() +{ + for(auto level : NSecondarySkill::levels) + bonusByLevel.push_back(new CBonusSystemNode()); +} + +CSkill::~CSkill() +{ + for(auto bonus : bonusByLevel) + delete bonus; +} + +void CSkill::addNewBonus(const std::shared_ptr& b, int level) +{ + b->source = Bonus::SECONDARY_SKILL; + b->duration = Bonus::PERMANENT; + b->description = identifier; + bonusByLevel[level]->addNewBonus(b); +} + +CBonusSystemNode * CSkill::getBonus(int level) +{ + return bonusByLevel[level]; +} + +///CSkillHandler +CSkillHandler::CSkillHandler() +{ +} + +std::vector CSkillHandler::loadLegacyData(size_t dataSize) +{ + // not supported - no legacy data to load + std::vector legacyData; + return legacyData; +} + +const std::string CSkillHandler::getTypeName() const +{ + return "secondarySkill"; +} + +CSkill * CSkillHandler::loadFromJson(const JsonNode & json, const std::string & identifier) +{ + CSkill * skill = new CSkill(); + skill->identifier = identifier; + + skill->id = SecondarySkill::DEFAULT; + for(int id = 0; id < GameConstants::SKILL_QUANTITY; id++) + { + if(NSecondarySkill::names[id].compare(identifier) == 0) + { + skill->id = SecondarySkill(id); + break; + } + } + + for(int level = 1; level < NSecondarySkill::levels.size(); level++) + { + const std::string & levelName = NSecondarySkill::levels[level]; // basic, advanced, expert + for(auto b : json[levelName].Vector()) + { + auto bonus = JsonUtils::parseBonus(b); + bonus->sid = skill->id; + skill->addNewBonus(bonus, level); + } + } + + return skill; +} + +void CSkillHandler::afterLoadFinalization() +{ +} + +void CSkillHandler::beforeValidate(JsonNode & object) +{ +} + +CSkillHandler::~CSkillHandler() +{ +} + +std::vector CSkillHandler::getDefaultAllowed() const +{ + std::vector allowedSkills(objects.size(), true); + return allowedSkills; +} diff --git a/lib/CSkillHandler.h b/lib/CSkillHandler.h new file mode 100644 index 000000000..38aca6829 --- /dev/null +++ b/lib/CSkillHandler.h @@ -0,0 +1,66 @@ +/* + * CSkillHandler.h, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ +#pragma once + +#include "../lib/HeroBonus.h" +#include "GameConstants.h" +#include "IHandlerBase.h" + +class CSkillHandler; +class CGHeroInstance; +class CMap; +class JsonSerializeFormat; + +class DLL_LINKAGE CSkill // secondary skill +{ +protected: + std::vector bonusByLevel; // bonuses provided by none, basic, advanced and expert level + +public: + CSkill(); + ~CSkill(); + + void addNewBonus(const std::shared_ptr& b, int level); + CBonusSystemNode * getBonus(int level); + + SecondarySkill id; + std::string identifier; + + template void serialize(Handler &h, const int version) + { + h & id & identifier; + h & bonusByLevel; + } + + friend class CSkillHandler; +}; + +class DLL_LINKAGE CSkillHandler: public CHandlerBase +{ +public: + CSkillHandler(); + virtual ~CSkillHandler(); + + ///IHandler base + std::vector loadLegacyData(size_t dataSize) override; + void afterLoadFinalization() override; + void beforeValidate(JsonNode & object) override; + + std::vector getDefaultAllowed() const override; + const std::string getTypeName() const override; + + template void serialize(Handler &h, const int version) + { + h & objects ; + } + +protected: + CSkill * loadFromJson(const JsonNode & json, const std::string & identifier) override; +}; diff --git a/lib/GameConstants.cpp b/lib/GameConstants.cpp index b039ef29c..7da3b4906 100644 --- a/lib/GameConstants.cpp +++ b/lib/GameConstants.cpp @@ -21,6 +21,7 @@ #include "CArtHandler.h" #include "CCreatureHandler.h" #include "spells/CSpellHandler.h" +#include "CSkillHandler.h" #include "StringConstants.h" #include "CGeneralTextHandler.h" @@ -65,6 +66,11 @@ const CSpell * SpellID::toSpell() const return VLC->spellh->objects[*this]; } +const CSkill * SecondarySkill::toSkill() const +{ + return VLC->skillh->objects.at(*this); +} + //template std::ostream & operator << (std::ostream & os, BaseForID id); //template std::ostream & operator << (std::ostream & os, BaseForID id); diff --git a/lib/GameConstants.h b/lib/GameConstants.h index 9218f7f67..4cce159ea 100644 --- a/lib/GameConstants.h +++ b/lib/GameConstants.h @@ -62,6 +62,7 @@ class CArtifactInstance; class CCreature; class CHero; class CSpell; +class CSkill; class CGameInfoCallback; class CNonConstInfoCallback; @@ -320,6 +321,8 @@ public: SecondarySkill(ESecondarySkill _num = WRONG) : num(_num) {} + DLL_LINKAGE const CSkill * toSkill() const; + ID_LIKE_CLASS_COMMON(SecondarySkill, ESecondarySkill) ESecondarySkill num; diff --git a/lib/IGameCallback.cpp b/lib/IGameCallback.cpp index 27c968c28..584ade005 100644 --- a/lib/IGameCallback.cpp +++ b/lib/IGameCallback.cpp @@ -12,6 +12,7 @@ #include "CHeroHandler.h" // for CHeroHandler #include "spells/CSpellHandler.h"// for CSpell +#include "CSkillHandler.h"// for CSkill #include "NetPacks.h" #include "CBonusTypeHandler.h" #include "CModHandler.h" diff --git a/lib/VCMI_Lib.cpp b/lib/VCMI_Lib.cpp index 4b158afef..67fd7141c 100644 --- a/lib/VCMI_Lib.cpp +++ b/lib/VCMI_Lib.cpp @@ -20,6 +20,7 @@ #include "CTownHandler.h" #include "CBuildingHandler.h" #include "spells/CSpellHandler.h" +#include "CSkillHandler.h" #include "CGeneralTextHandler.h" #include "CModHandler.h" #include "IGameEventsReceiver.h" @@ -113,6 +114,8 @@ void LibClasses::init() createHandler(spellh, "Spell", pomtime); + createHandler(skillh, "Skill", pomtime); + createHandler(terviewh, "Terrain view pattern", pomtime); createHandler(tplh, "Template", pomtime); //templates need already resolved identifiers (refactor?) @@ -137,6 +140,7 @@ void LibClasses::clear() delete objh; delete objtypeh; delete spellh; + delete skillh; delete modh; delete bth; delete tplh; @@ -154,6 +158,7 @@ void LibClasses::makeNull() objh = nullptr; objtypeh = nullptr; spellh = nullptr; + skillh = nullptr; modh = nullptr; bth = nullptr; tplh = nullptr; diff --git a/lib/VCMI_Lib.h b/lib/VCMI_Lib.h index 26bfa2a24..a31e73727 100644 --- a/lib/VCMI_Lib.h +++ b/lib/VCMI_Lib.h @@ -14,6 +14,7 @@ class CArtHandler; class CHeroHandler; class CCreatureHandler; class CSpellHandler; +class CSkillHandler; class CBuildingHandler; class CObjectHandler; class CObjectClassesHandler; @@ -41,6 +42,7 @@ public: CHeroHandler * heroh; CCreatureHandler * creh; CSpellHandler * spellh; + CSkillHandler * skillh; CObjectHandler * objh; CObjectClassesHandler * objtypeh; CTownHandler * townh; @@ -67,6 +69,7 @@ public: h & objh; h & objtypeh; h & spellh; + h & skillh; h & modh; h & IS_AI_ENABLED; h & bth; From 159e27a0ab094b18d04a6692123de3b8a1b31f2f Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Mon, 21 Aug 2017 20:49:51 +1200 Subject: [PATCH 08/68] changed CBonusSystemNode* to BonusList in CSkill --- lib/CSkillHandler.cpp | 9 ++++----- lib/CSkillHandler.h | 4 ++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/CSkillHandler.cpp b/lib/CSkillHandler.cpp index 8a1a3796a..7f7f7fa5a 100644 --- a/lib/CSkillHandler.cpp +++ b/lib/CSkillHandler.cpp @@ -29,14 +29,13 @@ ///CSkill CSkill::CSkill() { + BonusList emptyList; for(auto level : NSecondarySkill::levels) - bonusByLevel.push_back(new CBonusSystemNode()); + bonusByLevel.push_back(emptyList); } CSkill::~CSkill() { - for(auto bonus : bonusByLevel) - delete bonus; } void CSkill::addNewBonus(const std::shared_ptr& b, int level) @@ -44,10 +43,10 @@ void CSkill::addNewBonus(const std::shared_ptr& b, int level) b->source = Bonus::SECONDARY_SKILL; b->duration = Bonus::PERMANENT; b->description = identifier; - bonusByLevel[level]->addNewBonus(b); + bonusByLevel[level].push_back(b); } -CBonusSystemNode * CSkill::getBonus(int level) +BonusList CSkill::getBonus(int level) { return bonusByLevel[level]; } diff --git a/lib/CSkillHandler.h b/lib/CSkillHandler.h index 38aca6829..e29c06fba 100644 --- a/lib/CSkillHandler.h +++ b/lib/CSkillHandler.h @@ -21,14 +21,14 @@ class JsonSerializeFormat; class DLL_LINKAGE CSkill // secondary skill { protected: - std::vector bonusByLevel; // bonuses provided by none, basic, advanced and expert level + std::vector bonusByLevel; // bonuses provided by none, basic, advanced and expert level public: CSkill(); ~CSkill(); void addNewBonus(const std::shared_ptr& b, int level); - CBonusSystemNode * getBonus(int level); + BonusList getBonus(int level); SecondarySkill id; std::string identifier; From a6c3352d7c9a6f504274c82efebb9ac94ec0894c Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Tue, 22 Aug 2017 00:35:46 +1200 Subject: [PATCH 09/68] moved secondary skill default bonus initialization into CSkillHandler --- lib/CSkillHandler.cpp | 56 +++++++++++++++++++++++++++++++ lib/CSkillHandler.h | 1 + lib/mapObjects/CGHeroInstance.cpp | 7 ++++ 3 files changed, 64 insertions(+) diff --git a/lib/CSkillHandler.cpp b/lib/CSkillHandler.cpp index 7f7f7fa5a..267b9f388 100644 --- a/lib/CSkillHandler.cpp +++ b/lib/CSkillHandler.cpp @@ -54,6 +54,10 @@ BonusList CSkill::getBonus(int level) ///CSkillHandler CSkillHandler::CSkillHandler() { + for(int id = 0; id < GameConstants::SKILL_QUANTITY; id++) + { + //TODO + } } std::vector CSkillHandler::loadLegacyData(size_t dataSize) @@ -114,3 +118,55 @@ std::vector CSkillHandler::getDefaultAllowed() const std::vector allowedSkills(objects.size(), true); return allowedSkills; } + +// HMM3 default bonus provided by secondary skill +const std::shared_ptr CSkillHandler::defaultBonus(SecondarySkill skill, int level) const +{ + Bonus::BonusType bonusType = Bonus::SECONDARY_SKILL_PREMY; + Bonus::ValueType valueType = Bonus::BASE_NUMBER; + int bonusVal = level; + + static const int archery_bonus[] = { 10, 25, 50 }; + switch (skill) + { + case SecondarySkill::LEADERSHIP: + bonusType = Bonus::MORALE; break; + case SecondarySkill::LUCK: + bonusType = Bonus::LUCK; break; + case SecondarySkill::DIPLOMACY: + bonusType = Bonus::SURRENDER_DISCOUNT; + bonusVal = 20 * level; break; + case SecondarySkill::ARCHERY: + bonusVal = archery_bonus[level-1]; break; + case SecondarySkill::LOGISTICS: + bonusVal = 10 * level; break; + case SecondarySkill::NAVIGATION: + bonusVal = 50 * level; break; + case SecondarySkill::MYSTICISM: + bonusVal = level; break; + case SecondarySkill::EAGLE_EYE: + bonusVal = 30 + 10 * level; break; + case SecondarySkill::NECROMANCY: + bonusVal = 10 * level; break; + case SecondarySkill::LEARNING: + bonusVal = 5 * level; break; + case SecondarySkill::OFFENCE: + bonusVal = 10 * level; break; + case SecondarySkill::ARMORER: + bonusVal = 5 * level; break; + case SecondarySkill::INTELLIGENCE: + bonusVal = 25 << (level-1); break; + case SecondarySkill::SORCERY: + bonusVal = 5 * level; break; + case SecondarySkill::RESISTANCE: + bonusVal = 5 << (level-1); break; + case SecondarySkill::FIRST_AID: + bonusVal = 25 + 25 * level; break; + case SecondarySkill::ESTATES: + bonusVal = 125 << (level-1); break; + default: + valueType = Bonus::INDEPENDENT_MIN; break; + } + + return std::make_shared(Bonus::PERMANENT, bonusType, Bonus::SECONDARY_SKILL, bonusVal, skill, skill, valueType); +} diff --git a/lib/CSkillHandler.h b/lib/CSkillHandler.h index e29c06fba..26227f154 100644 --- a/lib/CSkillHandler.h +++ b/lib/CSkillHandler.h @@ -63,4 +63,5 @@ public: protected: CSkill * loadFromJson(const JsonNode & json, const std::string & identifier) override; + const std::shared_ptr defaultBonus(SecondarySkill skill, int level) const; }; diff --git a/lib/mapObjects/CGHeroInstance.cpp b/lib/mapObjects/CGHeroInstance.cpp index 2884e6e91..fee3134d4 100644 --- a/lib/mapObjects/CGHeroInstance.cpp +++ b/lib/mapObjects/CGHeroInstance.cpp @@ -17,6 +17,7 @@ #include "../CModHandler.h" #include "../CSoundBase.h" #include "../spells/CSpellHandler.h" +#include "../CSkillHandler.h" #include "CObjectClassesHandler.h" #include "../IGameCallback.h" #include "../CGameState.h" @@ -765,6 +766,11 @@ void CGHeroInstance::recreateSecondarySkillsBonuses() void CGHeroInstance::updateSkill(SecondarySkill which, int val) { + BonusList skillBonus = (*VLC->skillh)[which]->getBonus(val); + for (auto b : skillBonus) + addNewBonus(std::make_shared(*b)); + + /* if(which == SecondarySkill::LEADERSHIP || which == SecondarySkill::LUCK) { //luck-> VLC->generaltexth->arraytxt[73+luckSkill]; VLC->generaltexth->arraytxt[104+moraleSkill] bool luck = which == SecondarySkill::LUCK; @@ -844,6 +850,7 @@ void CGHeroInstance::updateSkill(SecondarySkill which, int val) bonus->source = Bonus::SECONDARY_SKILL; addNewBonus(bonus); } + */ CBonusSystemNode::treeHasChanged(); } From 9811fbe02c49d367348c18c2fcad6da7ea34ceb2 Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Tue, 22 Aug 2017 17:27:13 +1200 Subject: [PATCH 10/68] updateSkill attempts to update existing bonus instead of adding new --- lib/mapObjects/CGHeroInstance.cpp | 89 ++++--------------------------- 1 file changed, 9 insertions(+), 80 deletions(-) diff --git a/lib/mapObjects/CGHeroInstance.cpp b/lib/mapObjects/CGHeroInstance.cpp index fee3134d4..720ddf02f 100644 --- a/lib/mapObjects/CGHeroInstance.cpp +++ b/lib/mapObjects/CGHeroInstance.cpp @@ -768,90 +768,19 @@ void CGHeroInstance::updateSkill(SecondarySkill which, int val) { BonusList skillBonus = (*VLC->skillh)[which]->getBonus(val); for (auto b : skillBonus) - addNewBonus(std::make_shared(*b)); - - /* - if(which == SecondarySkill::LEADERSHIP || which == SecondarySkill::LUCK) - { //luck-> VLC->generaltexth->arraytxt[73+luckSkill]; VLC->generaltexth->arraytxt[104+moraleSkill] - bool luck = which == SecondarySkill::LUCK; - Bonus::BonusType type[] = {Bonus::MORALE, Bonus::LUCK}; - - auto b = getBonusLocalFirst(Selector::type(type[luck]).And(Selector::sourceType(Bonus::SECONDARY_SKILL))); - if(!b) + { + // TODO: add standard method for joining bonuses, should match on valType as well + std::shared_ptr existing = getBonusLocalFirst(Selector::typeSubtype(b->type,b->subtype).And(Selector::source(Bonus::SECONDARY_SKILL, b->sid))); + if(existing) { - b = std::make_shared(Bonus::PERMANENT, type[luck], Bonus::SECONDARY_SKILL, +val, which, which, Bonus::BASE_NUMBER); - addNewBonus(b); + if(b->valType == Bonus::INDEPENDENT_MIN || b->valType == Bonus::BASE_NUMBER) + existing->val = b->val; + else + existing->val += b->val; } else - b->val = +val; + addNewBonus(std::make_shared(*b)); } - else if(which == SecondarySkill::DIPLOMACY) //surrender discount: 20% per level - { - - if(auto b = getBonusLocalFirst(Selector::type(Bonus::SURRENDER_DISCOUNT).And(Selector::sourceType(Bonus::SECONDARY_SKILL)))) - b->val = +val; - else - addNewBonus(std::make_shared(Bonus::PERMANENT, Bonus::SURRENDER_DISCOUNT, Bonus::SECONDARY_SKILL, val * 20, which)); - } - - int skillVal = 0; - switch (which) - { - case SecondarySkill::ARCHERY: - switch (val) - { - case 1: - skillVal = 10; break; - case 2: - skillVal = 25; break; - case 3: - skillVal = 50; break; - } - break; - case SecondarySkill::LOGISTICS: - skillVal = 10 * val; break; - case SecondarySkill::NAVIGATION: - skillVal = 50 * val; break; - case SecondarySkill::MYSTICISM: - skillVal = val; break; - case SecondarySkill::EAGLE_EYE: - skillVal = 30 + 10 * val; break; - case SecondarySkill::NECROMANCY: - skillVal = 10 * val; break; - case SecondarySkill::LEARNING: - skillVal = 5 * val; break; - case SecondarySkill::OFFENCE: - skillVal = 10 * val; break; - case SecondarySkill::ARMORER: - skillVal = 5 * val; break; - case SecondarySkill::INTELLIGENCE: - skillVal = 25 << (val-1); break; - case SecondarySkill::SORCERY: - skillVal = 5 * val; break; - case SecondarySkill::RESISTANCE: - skillVal = 5 << (val-1); break; - case SecondarySkill::FIRST_AID: - skillVal = 25 + 25*val; break; - case SecondarySkill::ESTATES: - skillVal = 125 << (val-1); break; - } - - - Bonus::ValueType skillValType = skillVal ? Bonus::BASE_NUMBER : Bonus::INDEPENDENT_MIN; - if(auto b = getExportedBonusList().getFirst(Selector::typeSubtype(Bonus::SECONDARY_SKILL_PREMY, which) - .And(Selector::sourceType(Bonus::SECONDARY_SKILL)))) //only local hero bonus - { - b->val = skillVal; - b->valType = skillValType; - } - else - { - auto bonus = std::make_shared(Bonus::PERMANENT, Bonus::SECONDARY_SKILL_PREMY, Bonus::SECONDARY_SKILL, skillVal, id.getNum(), which, skillValType); - bonus->source = Bonus::SECONDARY_SKILL; - addNewBonus(bonus); - } - */ - CBonusSystemNode::treeHasChanged(); } void CGHeroInstance::setPropertyDer( ui8 what, ui32 val ) From 05cf95400c54f24961f50cd58f70e39869589b24 Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Tue, 22 Aug 2017 21:40:10 +1200 Subject: [PATCH 11/68] loading secondary skill bonuses from config/skills.json works (kind of) --- config/gameConfig.json | 4 ++++ config/schemas/skill.json | 33 +++++++++++++++++++++++++++++++++ config/skills.json | 29 +++++++++++++++++++++++++++++ lib/CModHandler.cpp | 2 ++ 4 files changed, 68 insertions(+) create mode 100644 config/schemas/skill.json create mode 100644 config/skills.json diff --git a/config/gameConfig.json b/config/gameConfig.json index 801287573..ec5ee608f 100644 --- a/config/gameConfig.json +++ b/config/gameConfig.json @@ -76,5 +76,9 @@ "config/spells/other.json", "config/spells/timed.json", "config/spells/ability.json" + ], + "skills" : + [ + "config/skills.json" ] } diff --git a/config/schemas/skill.json b/config/schemas/skill.json new file mode 100644 index 000000000..7b49bbbbb --- /dev/null +++ b/config/schemas/skill.json @@ -0,0 +1,33 @@ +{ + + "type":"object", + "$schema": "http://json-schema.org/draft-04/schema", + + "title" : "VCMI skill format", + "description" : "Format used to replace bonuses provided by secondary skills in VCMI", + + "definitions" : { + + "skillBonus":{ + "description": "Set of bonuses provided by skill at given level", + "type": "array", + "items":{ + "$ref" : "vcmi:bonus" + } + }, + + "required" : ["basic", "advanced", "expert"], + + "properties": { + "basic":{ + "$ref" : "#/definitions/skillBonus" + }, + "advanced":{ + "$ref" : "#/definitions/skillBonus" + }, + "expert":{ + "$ref" : "#/definitions/skillBonus" + }, + } + } +} diff --git a/config/skills.json b/config/skills.json new file mode 100644 index 000000000..9b07e97d0 --- /dev/null +++ b/config/skills.json @@ -0,0 +1,29 @@ +{ + "estates" : { + "index" : 13, + "basic" : [ + { + "subtype" : 13, + "type" : "SECONDARY_SKILL_PREMY", + "val" : 250, + "valueType" : "BASE_NUMBER" + } + ], + "advanced" : [ + { + "subtype" : 13, + "type" : "SECONDARY_SKILL_PREMY", + "val" : 500, + "valueType" : "BASE_NUMBER" + } + ], + "expert" : [ + { + "subtype" : 13, + "type" : "SECONDARY_SKILL_PREMY", + "val" : 1000, + "valueType" : "BASE_NUMBER" + } + ] + } +} diff --git a/lib/CModHandler.cpp b/lib/CModHandler.cpp index 0c3231813..056ebb360 100644 --- a/lib/CModHandler.cpp +++ b/lib/CModHandler.cpp @@ -23,6 +23,7 @@ #include "CStopWatch.h" #include "IHandlerBase.h" #include "spells/CSpellHandler.h" +#include "CSkillHandler.h" CIdentifierStorage::CIdentifierStorage(): state(LOADING) @@ -420,6 +421,7 @@ CContentHandler::CContentHandler() handlers.insert(std::make_pair("objects", ContentTypeHandler(VLC->objtypeh, "object"))); handlers.insert(std::make_pair("heroes", ContentTypeHandler(VLC->heroh, "hero"))); handlers.insert(std::make_pair("spells", ContentTypeHandler(VLC->spellh, "spell"))); + handlers.insert(std::make_pair("skills", ContentTypeHandler(VLC->skillh, "skill"))); handlers.insert(std::make_pair("templates", ContentTypeHandler((IHandlerBase *)VLC->tplh, "template"))); //TODO: any other types of moddables? From 993b7bf614ab034a2e9941cdaeb664fdabc265b4 Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Wed, 23 Aug 2017 00:40:15 +1200 Subject: [PATCH 12/68] skills are initialized properly (and file loading isn't actually working yet) --- lib/CSkillHandler.cpp | 26 +++++++++++++++++++------- lib/CSkillHandler.h | 2 +- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/lib/CSkillHandler.cpp b/lib/CSkillHandler.cpp index 267b9f388..3129ba570 100644 --- a/lib/CSkillHandler.cpp +++ b/lib/CSkillHandler.cpp @@ -27,8 +27,13 @@ #include "battle/CBattleInfoCallback.h" ///CSkill -CSkill::CSkill() +CSkill::CSkill(SecondarySkill id) : id(id) { + if(id == SecondarySkill::DEFAULT) + identifier = "default"; + else + identifier = NSecondarySkill::names[id]; + // init bonus levels BonusList emptyList; for(auto level : NSecondarySkill::levels) bonusByLevel.push_back(emptyList); @@ -56,7 +61,10 @@ CSkillHandler::CSkillHandler() { for(int id = 0; id < GameConstants::SKILL_QUANTITY; id++) { - //TODO + CSkill * skill = new CSkill(SecondarySkill(id)); + for(int level = 1; level < NSecondarySkill::levels.size(); level++) + skill->addNewBonus(defaultBonus(SecondarySkill(id), level), level); + objects.push_back(skill); } } @@ -69,24 +77,28 @@ std::vector CSkillHandler::loadLegacyData(size_t dataSize) const std::string CSkillHandler::getTypeName() const { - return "secondarySkill"; + return "secondarySkill"; } CSkill * CSkillHandler::loadFromJson(const JsonNode & json, const std::string & identifier) { - CSkill * skill = new CSkill(); - skill->identifier = identifier; + CSkill * skill = NULL; - skill->id = SecondarySkill::DEFAULT; for(int id = 0; id < GameConstants::SKILL_QUANTITY; id++) { if(NSecondarySkill::names[id].compare(identifier) == 0) { - skill->id = SecondarySkill(id); + skill = new CSkill(SecondarySkill(id)); break; } } + if(!skill) + { + logGlobal->errorStream() << "unknown secondary skill " << identifier; + throw std::runtime_error("invalid skill"); + } + for(int level = 1; level < NSecondarySkill::levels.size(); level++) { const std::string & levelName = NSecondarySkill::levels[level]; // basic, advanced, expert diff --git a/lib/CSkillHandler.h b/lib/CSkillHandler.h index 26227f154..003fb9f91 100644 --- a/lib/CSkillHandler.h +++ b/lib/CSkillHandler.h @@ -24,7 +24,7 @@ protected: std::vector bonusByLevel; // bonuses provided by none, basic, advanced and expert level public: - CSkill(); + CSkill(SecondarySkill id = SecondarySkill::DEFAULT); ~CSkill(); void addNewBonus(const std::shared_ptr& b, int level); From d8648288f014065ae09518cd8a44ff5a3913cfd7 Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Wed, 23 Aug 2017 10:19:30 +1200 Subject: [PATCH 13/68] added debug info to skill loading --- lib/CSkillHandler.cpp | 9 +++++++++ lib/CSkillHandler.h | 1 + 2 files changed, 10 insertions(+) diff --git a/lib/CSkillHandler.cpp b/lib/CSkillHandler.cpp index 3129ba570..6b23fc54c 100644 --- a/lib/CSkillHandler.cpp +++ b/lib/CSkillHandler.cpp @@ -56,6 +56,12 @@ BonusList CSkill::getBonus(int level) return bonusByLevel[level]; } +DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const CSkill &skill) +{ + out << "Skill(" << (int)skill.id << "," << skill.identifier << "): " << skill.bonusByLevel; + return out; +} + ///CSkillHandler CSkillHandler::CSkillHandler() { @@ -109,6 +115,9 @@ CSkill * CSkillHandler::loadFromJson(const JsonNode & json, const std::string & skill->addNewBonus(bonus, level); } } + CLogger * logger = CLogger::getLogger(CLoggerDomain("skills")); + logger->debugStream() << "loaded secondary skill " << identifier << "(" << (int)skill->id << ")"; + logger->traceStream() << *skill; return skill; } diff --git a/lib/CSkillHandler.h b/lib/CSkillHandler.h index 003fb9f91..45bfda500 100644 --- a/lib/CSkillHandler.h +++ b/lib/CSkillHandler.h @@ -40,6 +40,7 @@ public: } friend class CSkillHandler; + friend std::ostream & operator<<(std::ostream &out, const CSkill &skill); }; class DLL_LINKAGE CSkillHandler: public CHandlerBase From 64e2db6a0f8514d1f63918d6edc7593b4090c697 Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Thu, 24 Aug 2017 00:15:33 +1200 Subject: [PATCH 14/68] added sufficient debug to diagnose - problem is with lack of original data --- config/schemas/skill.json | 6 +++++- lib/CModHandler.cpp | 10 ++++++++-- lib/CModHandler.h | 21 ++++++++++++++++++++- lib/CSkillHandler.cpp | 8 ++++++-- lib/IHandlerBase.h | 2 -- 5 files changed, 39 insertions(+), 8 deletions(-) diff --git a/config/schemas/skill.json b/config/schemas/skill.json index 7b49bbbbb..5c80700ee 100644 --- a/config/schemas/skill.json +++ b/config/schemas/skill.json @@ -19,6 +19,10 @@ "required" : ["basic", "advanced", "expert"], "properties": { + "index":{ + "type": "number", + "description": "numeric id of skill required only for original skills, prohibited for new skills" + }, "basic":{ "$ref" : "#/definitions/skillBonus" }, @@ -27,7 +31,7 @@ }, "expert":{ "$ref" : "#/definitions/skillBonus" - }, + } } } } diff --git a/lib/CModHandler.cpp b/lib/CModHandler.cpp index 056ebb360..f59cee3db 100644 --- a/lib/CModHandler.cpp +++ b/lib/CModHandler.cpp @@ -204,7 +204,12 @@ void CIdentifierStorage::registerObject(std::string scope, std::string type, std std::string fullID = type + '.' + name; checkIdentifier(fullID); - registeredObjects.insert(std::make_pair(fullID, data)); + auto mapping = std::make_pair(fullID, data); + if(!registeredObjects.contains(mapping)) + { + CLogger::getLogger(CLoggerDomain("identifier"))->traceStream() << "registered " << fullID << " as " << scope << ":" << identifier; + registeredObjects.insert(mapping); + } } std::vector CIdentifierStorage::getPossibleIdentifiers(const ObjectCallback & request) @@ -393,8 +398,9 @@ bool CContentHandler::ContentTypeHandler::loadMod(std::string modName, bool vali continue; } + logGlobal->debugStream() << "no original data in loadMod(" << name << "): " << data; } - // normal new object or one with index bigger that data size + // normal new object or one with index bigger than data size performValidate(data,name); handler->loadObject(modName, name, data); } diff --git a/lib/CModHandler.h b/lib/CModHandler.h index 0693ba287..2655909cc 100644 --- a/lib/CModHandler.h +++ b/lib/CModHandler.h @@ -51,6 +51,10 @@ class CIdentifierStorage si32 id; std::string scope; /// scope in which this ID located + bool operator==(const ObjectData & other) const + { + return id == other.id && scope == other.scope; + } template void serialize(Handler &h, const int version) { @@ -59,7 +63,22 @@ class CIdentifierStorage } }; - std::multimap registeredObjects; + class ObjectMap: public std::multimap + { + public: + bool contains(const value_type & value) const + { + auto range = equal_range(value.first); + for(auto contained = range.first; contained != range.second; contained++) + { + if(value.second == contained->second) + return true; + } + return false; + } + }; + + ObjectMap registeredObjects; std::vector scheduledRequests; ELoadingState state; diff --git a/lib/CSkillHandler.cpp b/lib/CSkillHandler.cpp index 6b23fc54c..8072fde40 100644 --- a/lib/CSkillHandler.cpp +++ b/lib/CSkillHandler.cpp @@ -83,7 +83,7 @@ std::vector CSkillHandler::loadLegacyData(size_t dataSize) const std::string CSkillHandler::getTypeName() const { - return "secondarySkill"; + return "skill"; } CSkill * CSkillHandler::loadFromJson(const JsonNode & json, const std::string & identifier) @@ -115,7 +115,7 @@ CSkill * CSkillHandler::loadFromJson(const JsonNode & json, const std::string & skill->addNewBonus(bonus, level); } } - CLogger * logger = CLogger::getLogger(CLoggerDomain("skills")); + CLogger * logger = CLogger::getLogger(CLoggerDomain(getTypeName())); logger->debugStream() << "loaded secondary skill " << identifier << "(" << (int)skill->id << ")"; logger->traceStream() << *skill; @@ -124,6 +124,10 @@ CSkill * CSkillHandler::loadFromJson(const JsonNode & json, const std::string & void CSkillHandler::afterLoadFinalization() { + CLogger * logger = CLogger::getLogger(CLoggerDomain(getTypeName())); + logger->traceStream() << "skill handler after load: "; + for(auto skill : objects) + logger->traceStream() << *skill; } void CSkillHandler::beforeValidate(JsonNode & object) diff --git a/lib/IHandlerBase.h b/lib/IHandlerBase.h index 072ceef44..5e6125e69 100644 --- a/lib/IHandlerBase.h +++ b/lib/IHandlerBase.h @@ -82,12 +82,10 @@ public: auto object = loadFromJson(data, normalizeIdentifier(scope, "core", name)); object->id = _ObjectID(index); - assert(objects[index] == nullptr); // ensure that this id was not loaded before objects[index] = object; registerObject(scope,type_name, name, object->id); - } ConstTransitivePtr<_Object> operator[] (const _ObjectID id) const From 8c7895239e405b4ebf5ff1cb9476dae05ad22d5b Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Thu, 24 Aug 2017 18:01:02 +1200 Subject: [PATCH 15/68] always load objects with index at specified position --- lib/CModHandler.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/CModHandler.cpp b/lib/CModHandler.cpp index f59cee3db..90b97dd47 100644 --- a/lib/CModHandler.cpp +++ b/lib/CModHandler.cpp @@ -390,17 +390,20 @@ bool CContentHandler::ContentTypeHandler::loadMod(std::string modName, bool vali if (originalData.size() > index) { JsonUtils::merge(originalData[index], data); - performValidate(originalData[index],name); handler->loadObject(modName, name, originalData[index], index); - originalData[index].clear(); // do not use same data twice (same ID) - - continue; } - logGlobal->debugStream() << "no original data in loadMod(" << name << "): " << data; + else + { + logGlobal->debugStream() << "no original data in loadMod(" << name << ")"; + logGlobal->traceStream() << data; + performValidate(data, name); + handler->loadObject(modName, name, data, index); + } + continue; } - // normal new object or one with index bigger than data size + // normal new object performValidate(data,name); handler->loadObject(modName, name, data); } From 0357a4fe3bf1df3bba7a28b9a0f81eb02379eb64 Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Fri, 25 Aug 2017 13:35:02 +1200 Subject: [PATCH 16/68] enabled config of skill descriptions --- client/CGameInfo.cpp | 11 ++++++ client/CGameInfo.h | 3 ++ client/widgets/CComponent.cpp | 2 +- client/windows/CHeroWindow.cpp | 2 +- client/windows/CKingdomInterface.cpp | 2 +- client/windows/GUIClasses.cpp | 4 +- config/schemas/skill.json | 16 ++++++-- config/skills.json | 57 ++++++++++++++++------------ lib/CModHandler.cpp | 6 ++- lib/CSkillHandler.cpp | 48 ++++++++++++++++++----- lib/CSkillHandler.h | 23 +++++++++-- lib/mapObjects/CGHeroInstance.cpp | 2 +- 12 files changed, 128 insertions(+), 48 deletions(-) diff --git a/client/CGameInfo.cpp b/client/CGameInfo.cpp index 361367204..f184ac143 100644 --- a/client/CGameInfo.cpp +++ b/client/CGameInfo.cpp @@ -9,6 +9,8 @@ */ #include "StdInc.h" #include "CGameInfo.h" +#include "CSkillHandler.h" +#include "CGeneralTextHandler.h" #include "../lib/VCMI_Lib.h" @@ -32,5 +34,14 @@ void CGameInfo::setFromLib() heroh = VLC->heroh; objh = VLC->objh; spellh = VLC->spellh; + skillh = VLC->skillh; objtypeh = VLC->objtypeh; } + +const std::string & CGameInfo::skillInfo(int skill, int level) const +{ + const std::string & desc = (*skillh)[SecondarySkill(skill)]->getDescription(level); + if(desc.size() > 0) + return desc; + return generaltexth->skillInfoTexts[skill][level-1]; +} diff --git a/client/CGameInfo.h b/client/CGameInfo.h index bd13716e4..fafcbff57 100644 --- a/client/CGameInfo.h +++ b/client/CGameInfo.h @@ -18,6 +18,7 @@ class CArtHandler; class CHeroHandler; class CCreatureHandler; class CSpellHandler; +class CSkillHandler; class CBuildingHandler; class CObjectHandler; class CSoundHandler; @@ -55,6 +56,7 @@ public: ConstTransitivePtr heroh; ConstTransitivePtr creh; ConstTransitivePtr spellh; + ConstTransitivePtr skillh; ConstTransitivePtr objh; ConstTransitivePtr objtypeh; CGeneralTextHandler * generaltexth; @@ -66,5 +68,6 @@ public: friend class CClient; CGameInfo(); + const std::string & skillInfo(int skill, int level) const; }; extern const CGameInfo* CGI; diff --git a/client/widgets/CComponent.cpp b/client/widgets/CComponent.cpp index 00cac6477..f85c0087e 100644 --- a/client/widgets/CComponent.cpp +++ b/client/widgets/CComponent.cpp @@ -148,7 +148,7 @@ std::string CComponent::getDescription() { case primskill: return (subtype < 4)? CGI->generaltexth->arraytxt[2+subtype] //Primary skill : CGI->generaltexth->allTexts[149]; //mana - case secskill: return CGI->generaltexth->skillInfoTexts[subtype][val-1]; + case secskill: return CGI->skillInfo(subtype,val); case resource: return CGI->generaltexth->allTexts[242]; case creature: return ""; case artifact: diff --git a/client/windows/CHeroWindow.cpp b/client/windows/CHeroWindow.cpp index 9eff0fb53..9f3425a7e 100644 --- a/client/windows/CHeroWindow.cpp +++ b/client/windows/CHeroWindow.cpp @@ -240,7 +240,7 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded) level = curHero->getSecSkillLevel(SecondarySkill(curHero->secSkills[g].first)); secSkillAreas[g]->type = skill; secSkillAreas[g]->bonusValue = level; - secSkillAreas[g]->text = CGI->generaltexth->skillInfoTexts[skill][level-1]; + secSkillAreas[g]->text = CGI->skillInfo(skill,level); secSkillAreas[g]->hoverText = boost::str(boost::format(heroscrn[21]) % CGI->generaltexth->levels[level-1] % CGI->generaltexth->skillName[skill]); secSkillImages[g]->setFrame(skill*3 + level + 2); } diff --git a/client/windows/CKingdomInterface.cpp b/client/windows/CKingdomInterface.cpp index 067226a2c..b753b8f76 100644 --- a/client/windows/CKingdomInterface.cpp +++ b/client/windows/CKingdomInterface.cpp @@ -281,7 +281,7 @@ bool InfoBoxAbstractHeroData::prepareMessage(std::string &text, CComponent **com if (!value) return false; - text = CGI->generaltexth->skillInfoTexts[subID][value-1]; + text = CGI->skillInfo(subID,value); *comp = new CComponent(CComponent::secskill, subID, value); return true; } diff --git a/client/windows/GUIClasses.cpp b/client/windows/GUIClasses.cpp index 4237ec3bb..b23929628 100644 --- a/client/windows/GUIClasses.cpp +++ b/client/windows/GUIClasses.cpp @@ -944,7 +944,7 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2, secSkillAreas[b][g]->type = skill; secSkillAreas[b][g]->bonusValue = level; - secSkillAreas[b][g]->text = CGI->generaltexth->skillInfoTexts[skill][level-1]; + secSkillAreas[b][g]->text = CGI->skillInfo(skill,level); secSkillAreas[b][g]->hoverText = CGI->generaltexth->heroscrn[21]; boost::algorithm::replace_first(secSkillAreas[b][g]->hoverText, "%s", CGI->generaltexth->levels[level - 1]); @@ -1222,7 +1222,7 @@ void CUniversityWindow::CItem::clickRight(tribool down, bool previousState) { if(down) { - CRClickPopup::createAndPush(CGI->generaltexth->skillInfoTexts[ID][0], + CRClickPopup::createAndPush(CGI->skillInfo(ID, 1), new CComponent(CComponent::secskill, ID, 1)); } } diff --git a/config/schemas/skill.json b/config/schemas/skill.json index 5c80700ee..266af6abb 100644 --- a/config/schemas/skill.json +++ b/config/schemas/skill.json @@ -9,10 +9,20 @@ "definitions" : { "skillBonus":{ + "type": "object", "description": "Set of bonuses provided by skill at given level", - "type": "array", - "items":{ - "$ref" : "vcmi:bonus" + "required" : ["effects"], + "properties": { + "description": { + "type": "string", + "description": "localizable description" + }, + "effects": { + "type": "array", + "items": { + "$ref" : "vcmi:bonus" + } + } } }, diff --git a/config/skills.json b/config/skills.json index 9b07e97d0..9d8d876da 100644 --- a/config/skills.json +++ b/config/skills.json @@ -1,29 +1,38 @@ { "estates" : { "index" : 13, - "basic" : [ - { - "subtype" : 13, - "type" : "SECONDARY_SKILL_PREMY", - "val" : 250, - "valueType" : "BASE_NUMBER" - } - ], - "advanced" : [ - { - "subtype" : 13, - "type" : "SECONDARY_SKILL_PREMY", - "val" : 500, - "valueType" : "BASE_NUMBER" - } - ], - "expert" : [ - { - "subtype" : 13, - "type" : "SECONDARY_SKILL_PREMY", - "val" : 1000, - "valueType" : "BASE_NUMBER" - } - ] + "basic" : { + "description" : "Hero generates 250 gold each day.", + "effects" : [ + { + "subtype" : 13, + "type" : "SECONDARY_SKILL_PREMY", + "val" : 250, + "valueType" : "BASE_NUMBER" + } + ] + }, + "advanced" : { + "description" : "Hero generates 500 gold each day.", + "effects" : [ + { + "subtype" : 13, + "type" : "SECONDARY_SKILL_PREMY", + "val" : 500, + "valueType" : "BASE_NUMBER" + } + ] + }, + "expert" : { + "description" : "Hero generates 1000 gold each day.", + "effects" : [ + { + "subtype" : 13, + "type" : "SECONDARY_SKILL_PREMY", + "val" : 1000, + "valueType" : "BASE_NUMBER" + } + ] + } } } diff --git a/lib/CModHandler.cpp b/lib/CModHandler.cpp index 90b97dd47..e21824e77 100644 --- a/lib/CModHandler.cpp +++ b/lib/CModHandler.cpp @@ -377,6 +377,7 @@ bool CContentHandler::ContentTypeHandler::loadMod(std::string modName, bool vali if (!modInfo.patches.isNull()) JsonUtils::merge(modInfo.modData, modInfo.patches); + CLogger * logger = CLogger::getLogger(CLoggerDomain("mod")); for(auto & entry : modInfo.modData.Struct()) { const std::string & name = entry.first; @@ -389,6 +390,7 @@ bool CContentHandler::ContentTypeHandler::loadMod(std::string modName, bool vali if (originalData.size() > index) { + logger->traceStream() << "found original data in loadMod(" << name << ") at index " << index; JsonUtils::merge(originalData[index], data); performValidate(originalData[index],name); handler->loadObject(modName, name, originalData[index], index); @@ -396,8 +398,8 @@ bool CContentHandler::ContentTypeHandler::loadMod(std::string modName, bool vali } else { - logGlobal->debugStream() << "no original data in loadMod(" << name << ")"; - logGlobal->traceStream() << data; + logger->debugStream() << "no original data in loadMod(" << name << ") at index " << index; + logger->traceStream() << data; performValidate(data, name); handler->loadObject(modName, name, data, index); } diff --git a/lib/CSkillHandler.cpp b/lib/CSkillHandler.cpp index 8072fde40..78bf19ac2 100644 --- a/lib/CSkillHandler.cpp +++ b/lib/CSkillHandler.cpp @@ -27,16 +27,24 @@ #include "battle/CBattleInfoCallback.h" ///CSkill +CSkill::LevelInfo::LevelInfo() : description("") +{ +} + +CSkill::LevelInfo::~LevelInfo() +{ +} + CSkill::CSkill(SecondarySkill id) : id(id) { if(id == SecondarySkill::DEFAULT) identifier = "default"; else identifier = NSecondarySkill::names[id]; - // init bonus levels - BonusList emptyList; - for(auto level : NSecondarySkill::levels) - bonusByLevel.push_back(emptyList); + // init levels + LevelInfo emptyLevel; + for(int level = 1; level < NSecondarySkill::levels.size(); level++) + levels.push_back(emptyLevel); } CSkill::~CSkill() @@ -48,18 +56,32 @@ void CSkill::addNewBonus(const std::shared_ptr& b, int level) b->source = Bonus::SECONDARY_SKILL; b->duration = Bonus::PERMANENT; b->description = identifier; - bonusByLevel[level].push_back(b); + levels[level-1].effects.push_back(b); } -BonusList CSkill::getBonus(int level) +void CSkill::setDescription(const std::string & desc, int level) { - return bonusByLevel[level]; + levels[level-1].description = desc; +} + +const std::vector> & CSkill::getBonus(int level) const +{ + return levels[level-1].effects; +} + +const std::string & CSkill::getDescription(int level) const +{ + return levels[level-1].description; +} + +DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const CSkill::LevelInfo &info) +{ + return out << "(\"" << info.description << "\"," << info.effects << ")"; } DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const CSkill &skill) { - out << "Skill(" << (int)skill.id << "," << skill.identifier << "): " << skill.bonusByLevel; - return out; + return out << "Skill(" << (int)skill.id << "," << skill.identifier << "): " << skill.levels; } ///CSkillHandler @@ -108,12 +130,18 @@ CSkill * CSkillHandler::loadFromJson(const JsonNode & json, const std::string & for(int level = 1; level < NSecondarySkill::levels.size(); level++) { const std::string & levelName = NSecondarySkill::levels[level]; // basic, advanced, expert - for(auto b : json[levelName].Vector()) + const JsonNode & levelNode = json[levelName]; + // parse bonus effects + for(auto b : levelNode["effects"].Vector()) { auto bonus = JsonUtils::parseBonus(b); bonus->sid = skill->id; skill->addNewBonus(bonus, level); } + // parse skill description - tracked separately + if(vstd::contains(levelNode.Struct(), "description") && !levelNode["description"].isNull()) + //CGI->generaltexth->skillInfoTexts[skill->id][level-1] = levelNode["description"].String(); + skill->setDescription(levelNode["description"].String(), level); } CLogger * logger = CLogger::getLogger(CLoggerDomain(getTypeName())); logger->debugStream() << "loaded secondary skill " << identifier << "(" << (int)skill->id << ")"; diff --git a/lib/CSkillHandler.h b/lib/CSkillHandler.h index 45bfda500..5e2bd68a1 100644 --- a/lib/CSkillHandler.h +++ b/lib/CSkillHandler.h @@ -21,14 +21,30 @@ class JsonSerializeFormat; class DLL_LINKAGE CSkill // secondary skill { protected: - std::vector bonusByLevel; // bonuses provided by none, basic, advanced and expert level + struct LevelInfo + { + std::string description; //descriptions of spell for skill level + std::vector> effects; + + LevelInfo(); + ~LevelInfo(); + + template void serialize(Handler &h, const int version) + { + h & description & effects; + } + }; + + std::vector levels; // bonuses provided by basic, advanced and expert level public: CSkill(SecondarySkill id = SecondarySkill::DEFAULT); ~CSkill(); void addNewBonus(const std::shared_ptr& b, int level); - BonusList getBonus(int level); + void setDescription(const std::string & desc, int level); + const std::vector> & getBonus(int level) const; + const std::string & getDescription(int level) const; SecondarySkill id; std::string identifier; @@ -36,11 +52,12 @@ public: template void serialize(Handler &h, const int version) { h & id & identifier; - h & bonusByLevel; + h & levels; } friend class CSkillHandler; friend std::ostream & operator<<(std::ostream &out, const CSkill &skill); + friend std::ostream & operator<<(std::ostream &out, const CSkill::LevelInfo &info); }; class DLL_LINKAGE CSkillHandler: public CHandlerBase diff --git a/lib/mapObjects/CGHeroInstance.cpp b/lib/mapObjects/CGHeroInstance.cpp index 720ddf02f..ac1532225 100644 --- a/lib/mapObjects/CGHeroInstance.cpp +++ b/lib/mapObjects/CGHeroInstance.cpp @@ -766,7 +766,7 @@ void CGHeroInstance::recreateSecondarySkillsBonuses() void CGHeroInstance::updateSkill(SecondarySkill which, int val) { - BonusList skillBonus = (*VLC->skillh)[which]->getBonus(val); + auto skillBonus = (*VLC->skillh)[which]->getBonus(val); for (auto b : skillBonus) { // TODO: add standard method for joining bonuses, should match on valType as well From c0740e362389fae645b3c758161808d26edb69f2 Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Fri, 25 Aug 2017 17:17:14 +1200 Subject: [PATCH 17/68] fixed crash when loading neutral faction; skills.json no longer requires index values --- config/schemas/skill.json | 4 ---- config/skills.json | 1 - lib/CModHandler.cpp | 8 +++++++- lib/CSkillHandler.cpp | 28 ++++++++++++++++++++++++++++ lib/CSkillHandler.h | 2 ++ lib/CTownHandler.cpp | 5 ++++- 6 files changed, 41 insertions(+), 7 deletions(-) diff --git a/config/schemas/skill.json b/config/schemas/skill.json index 266af6abb..c4f1a3192 100644 --- a/config/schemas/skill.json +++ b/config/schemas/skill.json @@ -29,10 +29,6 @@ "required" : ["basic", "advanced", "expert"], "properties": { - "index":{ - "type": "number", - "description": "numeric id of skill required only for original skills, prohibited for new skills" - }, "basic":{ "$ref" : "#/definitions/skillBonus" }, diff --git a/config/skills.json b/config/skills.json index 9d8d876da..d62bb0a0f 100644 --- a/config/skills.json +++ b/config/skills.json @@ -1,6 +1,5 @@ { "estates" : { - "index" : 13, "basic" : { "description" : "Hero generates 250 gold each day.", "effects" : [ diff --git a/lib/CModHandler.cpp b/lib/CModHandler.cpp index e21824e77..3020235e1 100644 --- a/lib/CModHandler.cpp +++ b/lib/CModHandler.cpp @@ -398,8 +398,14 @@ bool CContentHandler::ContentTypeHandler::loadMod(std::string modName, bool vali } else { + // trace only name field of original data - I miss list comprehension + std::vector originalNames; + for (const JsonNode & orgElem : originalData) + originalNames.push_back(orgElem["name"].String()); logger->debugStream() << "no original data in loadMod(" << name << ") at index " << index; - logger->traceStream() << data; + logger->traceStream() << "originalData: " << originalNames; + logger->traceStream() << "new data: " << data; + performValidate(data, name); handler->loadObject(modName, name, data, index); } diff --git a/lib/CSkillHandler.cpp b/lib/CSkillHandler.cpp index 78bf19ac2..8de6f5c9d 100644 --- a/lib/CSkillHandler.cpp +++ b/lib/CSkillHandler.cpp @@ -150,6 +150,34 @@ CSkill * CSkillHandler::loadFromJson(const JsonNode & json, const std::string & return skill; } +void CSkillHandler::loadObject(std::string scope, std::string name, const JsonNode & data) +{ + auto type_name = getTypeName(); + auto object = loadFromJson(data, normalizeIdentifier(scope, "core", name)); + + if(object->id == SecondarySkill::DEFAULT) // new skill - no index identified + { + object->id = SecondarySkill(objects.size()); + objects.push_back(object); + } + else + objects[object->id] = object; + + registerObject(scope, type_name, name, object->id); +} + +void CSkillHandler::loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) +{ + auto type_name = getTypeName(); + auto object = loadFromJson(data, normalizeIdentifier(scope, "core", name)); + + assert(object->id == index); + objects[index] = object; + + registerObject(scope,type_name, name, object->id); +} + + void CSkillHandler::afterLoadFinalization() { CLogger * logger = CLogger::getLogger(CLoggerDomain(getTypeName())); diff --git a/lib/CSkillHandler.h b/lib/CSkillHandler.h index 5e2bd68a1..628841ecf 100644 --- a/lib/CSkillHandler.h +++ b/lib/CSkillHandler.h @@ -73,6 +73,8 @@ public: std::vector getDefaultAllowed() const override; const std::string getTypeName() const override; + void loadObject(std::string scope, std::string name, const JsonNode & data) override; + void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override; template void serialize(Handler &h, const int version) { diff --git a/lib/CTownHandler.cpp b/lib/CTownHandler.cpp index 8219805f9..d71d3bb3a 100644 --- a/lib/CTownHandler.cpp +++ b/lib/CTownHandler.cpp @@ -763,7 +763,10 @@ void CTownHandler::loadObject(std::string scope, std::string name, const JsonNod { auto object = loadFromJson(data, normalizeIdentifier(scope, "core", name)); object->index = index; - assert(factions[index] == nullptr); // ensure that this id was not loaded before + if (factions.size() > index) + assert(factions[index] == nullptr); // ensure that this id was not loaded before + else + factions.resize(index + 1); factions[index] = object; if (object->town) From 3cc84e59751ba0171bb6023e96a91c5bc1748673 Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Fri, 25 Aug 2017 18:29:34 +1200 Subject: [PATCH 18/68] moved contains functions for multimap to Globals.h --- Global.h | 12 ++++++++++++ config/skills.json | 6 +++--- lib/CModHandler.cpp | 4 ++-- lib/CModHandler.h | 17 +---------------- 4 files changed, 18 insertions(+), 21 deletions(-) diff --git a/Global.h b/Global.h index f9e25f3ff..3d777350e 100644 --- a/Global.h +++ b/Global.h @@ -676,6 +676,18 @@ namespace vstd return v3; } + template + bool containsMapping(const std::multimap & map, const std::pair & mapping) + { + auto range = map.equal_range(mapping.first); + for(auto contained = range.first; contained != range.second; contained++) + { + if(mapping.second == contained->second) + return true; + } + return false; + } + using boost::math::round; } using vstd::operator-=; diff --git a/config/skills.json b/config/skills.json index d62bb0a0f..8107c6537 100644 --- a/config/skills.json +++ b/config/skills.json @@ -4,7 +4,7 @@ "description" : "Hero generates 250 gold each day.", "effects" : [ { - "subtype" : 13, + "subtype" : "skill.estates", "type" : "SECONDARY_SKILL_PREMY", "val" : 250, "valueType" : "BASE_NUMBER" @@ -15,7 +15,7 @@ "description" : "Hero generates 500 gold each day.", "effects" : [ { - "subtype" : 13, + "subtype" : "skill.estates", "type" : "SECONDARY_SKILL_PREMY", "val" : 500, "valueType" : "BASE_NUMBER" @@ -26,7 +26,7 @@ "description" : "Hero generates 1000 gold each day.", "effects" : [ { - "subtype" : 13, + "subtype" : "skill.estates", "type" : "SECONDARY_SKILL_PREMY", "val" : 1000, "valueType" : "BASE_NUMBER" diff --git a/lib/CModHandler.cpp b/lib/CModHandler.cpp index 3020235e1..bddf5ee23 100644 --- a/lib/CModHandler.cpp +++ b/lib/CModHandler.cpp @@ -204,8 +204,8 @@ void CIdentifierStorage::registerObject(std::string scope, std::string type, std std::string fullID = type + '.' + name; checkIdentifier(fullID); - auto mapping = std::make_pair(fullID, data); - if(!registeredObjects.contains(mapping)) + std::pair mapping = std::make_pair(fullID, data); + if(!vstd::containsMapping(registeredObjects, mapping)) { CLogger::getLogger(CLoggerDomain("identifier"))->traceStream() << "registered " << fullID << " as " << scope << ":" << identifier; registeredObjects.insert(mapping); diff --git a/lib/CModHandler.h b/lib/CModHandler.h index 2655909cc..a3ed87b50 100644 --- a/lib/CModHandler.h +++ b/lib/CModHandler.h @@ -63,22 +63,7 @@ class CIdentifierStorage } }; - class ObjectMap: public std::multimap - { - public: - bool contains(const value_type & value) const - { - auto range = equal_range(value.first); - for(auto contained = range.first; contained != range.second; contained++) - { - if(value.second == contained->second) - return true; - } - return false; - } - }; - - ObjectMap registeredObjects; + std::multimap registeredObjects; std::vector scheduledRequests; ELoadingState state; From 91fac7755ab9d665f0f5b960a29d210690feb379 Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Sat, 26 Aug 2017 01:43:20 +1200 Subject: [PATCH 19/68] made tactics skill configurable --- lib/CSkillHandler.cpp | 27 +++++++++++++-------------- lib/battle/BattleInfo.cpp | 4 ++-- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/lib/CSkillHandler.cpp b/lib/CSkillHandler.cpp index 8de6f5c9d..713c5bb90 100644 --- a/lib/CSkillHandler.cpp +++ b/lib/CSkillHandler.cpp @@ -207,28 +207,29 @@ const std::shared_ptr CSkillHandler::defaultBonus(SecondarySkill skill, i Bonus::ValueType valueType = Bonus::BASE_NUMBER; int bonusVal = level; - static const int archery_bonus[] = { 10, 25, 50 }; switch (skill) { + case SecondarySkill::ARCHERY: + bonusVal = 5 + 5 * level * level; break; + case SecondarySkill::LOGISTICS: + bonusVal = 10 * level; break; + case SecondarySkill::DIPLOMACY: + bonusType = Bonus::SURRENDER_DISCOUNT; + bonusVal = 20 * level; break; + case SecondarySkill::NAVIGATION: + bonusVal = 50 * level; break; case SecondarySkill::LEADERSHIP: bonusType = Bonus::MORALE; break; case SecondarySkill::LUCK: bonusType = Bonus::LUCK; break; - case SecondarySkill::DIPLOMACY: - bonusType = Bonus::SURRENDER_DISCOUNT; - bonusVal = 20 * level; break; - case SecondarySkill::ARCHERY: - bonusVal = archery_bonus[level-1]; break; - case SecondarySkill::LOGISTICS: - bonusVal = 10 * level; break; - case SecondarySkill::NAVIGATION: - bonusVal = 50 * level; break; - case SecondarySkill::MYSTICISM: - bonusVal = level; break; case SecondarySkill::EAGLE_EYE: bonusVal = 30 + 10 * level; break; case SecondarySkill::NECROMANCY: bonusVal = 10 * level; break; + case SecondarySkill::ESTATES: + bonusVal = 125 << (level-1); break; + case SecondarySkill::TACTICS: + bonusVal = 1 + 2 * level; break; case SecondarySkill::LEARNING: bonusVal = 5 * level; break; case SecondarySkill::OFFENCE: @@ -243,8 +244,6 @@ const std::shared_ptr CSkillHandler::defaultBonus(SecondarySkill skill, i bonusVal = 5 << (level-1); break; case SecondarySkill::FIRST_AID: bonusVal = 25 + 25 * level; break; - case SecondarySkill::ESTATES: - bonusVal = 125 << (level-1); break; default: valueType = Bonus::INDEPENDENT_MIN; break; } diff --git a/lib/battle/BattleInfo.cpp b/lib/battle/BattleInfo.cpp index 90026af69..6f6079e8a 100644 --- a/lib/battle/BattleInfo.cpp +++ b/lib/battle/BattleInfo.cpp @@ -601,14 +601,14 @@ BattleInfo * BattleInfo::setupBattle(int3 tile, ETerrainType terrain, BFieldType for(int i = 0; i < ARRAY_COUNT(tacticLvls); i++) { if(heroes[i]) - tacticLvls[i] += heroes[i]->getSecSkillLevel(SecondarySkill::TACTICS); + tacticLvls[i] += heroes[i]->valOfBonuses(Selector::typeSubtype(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::TACTICS)); } int tacticsSkillDiff = tacticLvls[0] - tacticLvls[1]; if(tacticsSkillDiff && isTacticsAllowed) { curB->tacticsSide = tacticsSkillDiff < 0; - curB->tacticDistance = std::abs(tacticsSkillDiff)*2 + 1; + curB->tacticDistance = std::abs(tacticsSkillDiff); } else curB->tacticDistance = 0; From c9ef773da00b6278ee2caf0d047642f523e9bfa1 Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Sat, 26 Aug 2017 14:06:47 +1200 Subject: [PATCH 20/68] fixed logging after rebase --- include/vstd/CLoggerBase.h | 1 + lib/CModHandler.cpp | 14 +++----------- lib/CSkillHandler.cpp | 28 ++++++++++++++++++---------- lib/CSkillHandler.h | 1 + lib/logging/CLogger.cpp | 1 + 5 files changed, 24 insertions(+), 21 deletions(-) diff --git a/include/vstd/CLoggerBase.h b/include/vstd/CLoggerBase.h index e548d0407..0c5ad7f10 100644 --- a/include/vstd/CLoggerBase.h +++ b/include/vstd/CLoggerBase.h @@ -190,3 +190,4 @@ extern DLL_LINKAGE vstd::CLoggerBase * logBonus; extern DLL_LINKAGE vstd::CLoggerBase * logNetwork; extern DLL_LINKAGE vstd::CLoggerBase * logAi; extern DLL_LINKAGE vstd::CLoggerBase * logAnim; +extern DLL_LINKAGE vstd::CLoggerBase * logMod; diff --git a/lib/CModHandler.cpp b/lib/CModHandler.cpp index bddf5ee23..c3e0018ff 100644 --- a/lib/CModHandler.cpp +++ b/lib/CModHandler.cpp @@ -207,7 +207,7 @@ void CIdentifierStorage::registerObject(std::string scope, std::string type, std std::pair mapping = std::make_pair(fullID, data); if(!vstd::containsMapping(registeredObjects, mapping)) { - CLogger::getLogger(CLoggerDomain("identifier"))->traceStream() << "registered " << fullID << " as " << scope << ":" << identifier; + logMod->trace("registered %s as %s:%s", fullID, scope, identifier); registeredObjects.insert(mapping); } } @@ -377,7 +377,6 @@ bool CContentHandler::ContentTypeHandler::loadMod(std::string modName, bool vali if (!modInfo.patches.isNull()) JsonUtils::merge(modInfo.modData, modInfo.patches); - CLogger * logger = CLogger::getLogger(CLoggerDomain("mod")); for(auto & entry : modInfo.modData.Struct()) { const std::string & name = entry.first; @@ -390,7 +389,7 @@ bool CContentHandler::ContentTypeHandler::loadMod(std::string modName, bool vali if (originalData.size() > index) { - logger->traceStream() << "found original data in loadMod(" << name << ") at index " << index; + logMod->trace("found original data in loadMod(%s) at index %d", name, index); JsonUtils::merge(originalData[index], data); performValidate(originalData[index],name); handler->loadObject(modName, name, originalData[index], index); @@ -398,14 +397,7 @@ bool CContentHandler::ContentTypeHandler::loadMod(std::string modName, bool vali } else { - // trace only name field of original data - I miss list comprehension - std::vector originalNames; - for (const JsonNode & orgElem : originalData) - originalNames.push_back(orgElem["name"].String()); - logger->debugStream() << "no original data in loadMod(" << name << ") at index " << index; - logger->traceStream() << "originalData: " << originalNames; - logger->traceStream() << "new data: " << data; - + logMod->debug("no original data in loadMod(%s) at index %d", name, index); performValidate(data, name); handler->loadObject(modName, name, data, index); } diff --git a/lib/CSkillHandler.cpp b/lib/CSkillHandler.cpp index 713c5bb90..4423973d0 100644 --- a/lib/CSkillHandler.cpp +++ b/lib/CSkillHandler.cpp @@ -76,12 +76,25 @@ const std::string & CSkill::getDescription(int level) const DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const CSkill::LevelInfo &info) { - return out << "(\"" << info.description << "\"," << info.effects << ")"; + out << "(\"" << info.description << "\", ["; + for(int i=0; i < info.effects.size(); i++) + out << (i ? "," : "") << info.effects[i]->Description(); + return out << "])"; } DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const CSkill &skill) { - return out << "Skill(" << (int)skill.id << "," << skill.identifier << "): " << skill.levels; + out << "Skill(" << (int)skill.id << "," << skill.identifier << "): ["; + for(int i=0; i < skill.levels.size(); i++) + out << (i ? "," : "") << skill.levels[i]; + return out << "]"; +} + +std::string CSkill::toString() const +{ + std::ostringstream ss; + ss << *this; + return ss.str(); } ///CSkillHandler @@ -123,7 +136,7 @@ CSkill * CSkillHandler::loadFromJson(const JsonNode & json, const std::string & if(!skill) { - logGlobal->errorStream() << "unknown secondary skill " << identifier; + logGlobal->error("unknown secondary skill %s", identifier); throw std::runtime_error("invalid skill"); } @@ -143,9 +156,8 @@ CSkill * CSkillHandler::loadFromJson(const JsonNode & json, const std::string & //CGI->generaltexth->skillInfoTexts[skill->id][level-1] = levelNode["description"].String(); skill->setDescription(levelNode["description"].String(), level); } - CLogger * logger = CLogger::getLogger(CLoggerDomain(getTypeName())); - logger->debugStream() << "loaded secondary skill " << identifier << "(" << (int)skill->id << ")"; - logger->traceStream() << *skill; + logMod->debug("loaded secondary skill %s(%d)", identifier, (int)skill->id); + logMod->trace("%s", skill->toString()); return skill; } @@ -180,10 +192,6 @@ void CSkillHandler::loadObject(std::string scope, std::string name, const JsonNo void CSkillHandler::afterLoadFinalization() { - CLogger * logger = CLogger::getLogger(CLoggerDomain(getTypeName())); - logger->traceStream() << "skill handler after load: "; - for(auto skill : objects) - logger->traceStream() << *skill; } void CSkillHandler::beforeValidate(JsonNode & object) diff --git a/lib/CSkillHandler.h b/lib/CSkillHandler.h index 628841ecf..ff4f9bcfd 100644 --- a/lib/CSkillHandler.h +++ b/lib/CSkillHandler.h @@ -45,6 +45,7 @@ public: void setDescription(const std::string & desc, int level); const std::vector> & getBonus(int level) const; const std::string & getDescription(int level) const; + std::string toString() const; SecondarySkill id; std::string identifier; diff --git a/lib/logging/CLogger.cpp b/lib/logging/CLogger.cpp index 2d32d191c..c10b2a277 100644 --- a/lib/logging/CLogger.cpp +++ b/lib/logging/CLogger.cpp @@ -83,6 +83,7 @@ DLL_LINKAGE vstd::CLoggerBase * logBonus = CLogger::getLogger(CLoggerDomain("bon DLL_LINKAGE vstd::CLoggerBase * logNetwork = CLogger::getLogger(CLoggerDomain("network")); DLL_LINKAGE vstd::CLoggerBase * logAi = CLogger::getLogger(CLoggerDomain("ai")); DLL_LINKAGE vstd::CLoggerBase * logAnim = CLogger::getLogger(CLoggerDomain("animation")); +DLL_LINKAGE vstd::CLoggerBase * logMod = CLogger::getLogger(CLoggerDomain("mod")); CLogger * CLogger::getLogger(const CLoggerDomain & domain) { From e8c32e05d88cd35758c4ad0c86858a9231ab83c4 Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Sat, 26 Aug 2017 14:59:24 +1200 Subject: [PATCH 21/68] turned pathfinding effect into a bonus --- config/skills.json | 63 ++++++++++++++++++++++++------- lib/CSkillHandler.cpp | 2 + lib/mapObjects/CGHeroInstance.cpp | 2 +- 3 files changed, 52 insertions(+), 15 deletions(-) diff --git a/config/skills.json b/config/skills.json index 8107c6537..baccfd0cf 100644 --- a/config/skills.json +++ b/config/skills.json @@ -1,7 +1,53 @@ { + "pathfinding" : { + "basic" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.pathfinding", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 25, + "valueType" : "BASE_NUMBER" + } + ] + }, + "advanced" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.pathfinding", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 50, + "valueType" : "BASE_NUMBER" + } + ] + }, + "expert" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.pathfinding", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 75, + "valueType" : "BASE_NUMBER" + } + ] + } + }, "estates" : { "basic" : { - "description" : "Hero generates 250 gold each day.", + "description" : "", + "effects" : [ + { + "subtype" : "skill.estates", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 125, + "valueType" : "BASE_NUMBER" + } + ] + }, + "advanced" : { + "description" : "", "effects" : [ { "subtype" : "skill.estates", @@ -11,8 +57,8 @@ } ] }, - "advanced" : { - "description" : "Hero generates 500 gold each day.", + "expert" : { + "description" : "", "effects" : [ { "subtype" : "skill.estates", @@ -21,17 +67,6 @@ "valueType" : "BASE_NUMBER" } ] - }, - "expert" : { - "description" : "Hero generates 1000 gold each day.", - "effects" : [ - { - "subtype" : "skill.estates", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 1000, - "valueType" : "BASE_NUMBER" - } - ] } } } diff --git a/lib/CSkillHandler.cpp b/lib/CSkillHandler.cpp index 4423973d0..6a02ecdd7 100644 --- a/lib/CSkillHandler.cpp +++ b/lib/CSkillHandler.cpp @@ -217,6 +217,8 @@ const std::shared_ptr CSkillHandler::defaultBonus(SecondarySkill skill, i switch (skill) { + case SecondarySkill::PATHFINDING: + bonusVal = 25 * level; break; case SecondarySkill::ARCHERY: bonusVal = 5 + 5 * level * level; break; case SecondarySkill::LOGISTICS: diff --git a/lib/mapObjects/CGHeroInstance.cpp b/lib/mapObjects/CGHeroInstance.cpp index ac1532225..d8416638b 100644 --- a/lib/mapObjects/CGHeroInstance.cpp +++ b/lib/mapObjects/CGHeroInstance.cpp @@ -87,7 +87,7 @@ ui32 CGHeroInstance::getTileCost(const TerrainTile &dest, const TerrainTile &fro else if(ti->nativeTerrain != from.terType && !ti->hasBonusOfType(Bonus::NO_TERRAIN_PENALTY, from.terType)) { ret = VLC->heroh->terrCosts[from.terType]; - ret -= getSecSkillLevel(SecondarySkill::PATHFINDING) * 25; + ret -= valOfBonuses(Selector::typeSubtype(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::PATHFINDING)); if(ret < GameConstants::BASE_MOVEMENT_COST) ret = GameConstants::BASE_MOVEMENT_COST; } From 1fa6cbe5146a77dc1e692faf72a23bec21d7448c Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Sat, 26 Aug 2017 17:33:00 +1200 Subject: [PATCH 22/68] scouting uses SIGHT_RADIUS bonus --- config/skills.json | 102 ++++++++++++++++++++++++++++++ lib/CSkillHandler.cpp | 2 + lib/mapObjects/CGHeroInstance.cpp | 2 +- 3 files changed, 105 insertions(+), 1 deletion(-) diff --git a/config/skills.json b/config/skills.json index baccfd0cf..9d8445ba8 100644 --- a/config/skills.json +++ b/config/skills.json @@ -34,6 +34,108 @@ ] } }, + "archery" : { + "basic" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.archery", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 10, + "valueType" : "BASE_NUMBER" + } + ] + }, + "advanced" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.archery", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 25, + "valueType" : "BASE_NUMBER" + } + ] + }, + "expert" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.archery", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 50, + "valueType" : "BASE_NUMBER" + } + ] + } + }, + "logistics" : { + "basic" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.logistics", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 10, + "valueType" : "BASE_NUMBER" + } + ] + }, + "advanced" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.logistics", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 20, + "valueType" : "BASE_NUMBER" + } + ] + }, + "expert" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.logistics", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 30, + "valueType" : "BASE_NUMBER" + } + ] + } + }, + "scouting" : { + "basic" : { + "description" : "", + "effects" : [ + { + "type" : "SIGHT_RADIOUS", + "val" : 1, + "valueType" : "BASE_NUMBER" + } + ] + }, + "advanced" : { + "description" : "", + "effects" : [ + { + "type" : "SIGHT_RADIOUS", + "val" : 2, + "valueType" : "BASE_NUMBER" + } + ] + }, + "expert" : { + "description" : "", + "effects" : [ + { + "type" : "SIGHT_RADIOUS", + "val" : 3, + "valueType" : "BASE_NUMBER" + } + ] + } + }, "estates" : { "basic" : { "description" : "", diff --git a/lib/CSkillHandler.cpp b/lib/CSkillHandler.cpp index 6a02ecdd7..8d5504b61 100644 --- a/lib/CSkillHandler.cpp +++ b/lib/CSkillHandler.cpp @@ -223,6 +223,8 @@ const std::shared_ptr CSkillHandler::defaultBonus(SecondarySkill skill, i bonusVal = 5 + 5 * level * level; break; case SecondarySkill::LOGISTICS: bonusVal = 10 * level; break; + case SecondarySkill::SCOUTING: + bonusType = Bonus::SIGHT_RADIOUS; break; case SecondarySkill::DIPLOMACY: bonusType = Bonus::SURRENDER_DISCOUNT; bonusVal = 20 * level; break; diff --git a/lib/mapObjects/CGHeroInstance.cpp b/lib/mapObjects/CGHeroInstance.cpp index d8416638b..e8dea7953 100644 --- a/lib/mapObjects/CGHeroInstance.cpp +++ b/lib/mapObjects/CGHeroInstance.cpp @@ -1071,7 +1071,7 @@ int3 CGHeroInstance::getSightCenter() const int CGHeroInstance::getSightRadius() const { - return 5 + getSecSkillLevel(SecondarySkill::SCOUTING) + valOfBonuses(Bonus::SIGHT_RADIOUS); //default + scouting + return 5 + valOfBonuses(Bonus::SIGHT_RADIOUS); // scouting gives SIGHT_RADIUS bonus } si32 CGHeroInstance::manaRegain() const From 19e619f61e2623e1970da5de54608bd11436e243 Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Sat, 26 Aug 2017 20:49:29 +1200 Subject: [PATCH 23/68] wisdom is now bonus-based --- config/skills.json | 134 ++++++++++++++++++++++++++++++ lib/mapObjects/CBank.cpp | 2 +- lib/mapObjects/CGHeroInstance.cpp | 7 +- lib/mapObjects/CGHeroInstance.h | 1 + lib/mapObjects/MiscObjects.cpp | 2 +- server/CGameHandler.cpp | 8 +- 6 files changed, 147 insertions(+), 7 deletions(-) diff --git a/config/skills.json b/config/skills.json index 9d8445ba8..9b8257e3e 100644 --- a/config/skills.json +++ b/config/skills.json @@ -136,6 +136,140 @@ ] } }, + "diplomacy" : { + "basic" : { + "description" : "", + "effects" : [ + { + "type" : "SURRENDER_DISCOUNT", + "val" : 20, + "valueType" : "BASE_NUMBER" + } + ] + }, + "advanced" : { + "description" : "", + "effects" : [ + { + "type" : "SURRENDER_DISCOUNT", + "val" : 40, + "valueType" : "BASE_NUMBER" + } + ] + }, + "expert" : { + "description" : "", + "effects" : [ + { + "type" : "SURRENDER_DISCOUNT", + "val" : 60, + "valueType" : "BASE_NUMBER" + } + ] + } + }, + "navigation" : { + "basic" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.navigation", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 50, + "valueType" : "BASE_NUMBER" + } + ] + }, + "advanced" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.navigation", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 100, + "valueType" : "BASE_NUMBER" + } + ] + }, + "expert" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.navigation", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 150, + "valueType" : "BASE_NUMBER" + } + ] + } + }, + "leadership" : { + "basic" : { + "description" : "", + "effects" : [ + { + "type" : "MORALE", + "val" : 1, + "valueType" : "BASE_NUMBER" + } + ] + }, + "advanced" : { + "description" : "", + "effects" : [ + { + "type" : "MORALE", + "val" : 2, + "valueType" : "BASE_NUMBER" + } + ] + }, + "expert" : { + "description" : "", + "effects" : [ + { + "type" : "MORALE", + "val" : 3, + "valueType" : "BASE_NUMBER" + } + ] + } + }, + "wisdom" : { + "basic" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.wisdom", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 1, + "valueType" : "BASE_NUMBER" + } + ] + }, + "advanced" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.wisdom", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 2, + "valueType" : "BASE_NUMBER" + } + ] + }, + "expert" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.wisdom", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 3, + "valueType" : "BASE_NUMBER" + } + ] + } + }, "estates" : { "basic" : { "description" : "", diff --git a/lib/mapObjects/CBank.cpp b/lib/mapObjects/CBank.cpp index 12848d258..44227ef7d 100644 --- a/lib/mapObjects/CBank.cpp +++ b/lib/mapObjects/CBank.cpp @@ -266,7 +266,7 @@ void CBank::doVisit(const CGHeroInstance * hero) const { const CSpell * spell = spellId.toSpell(); iw.text.addTxt (MetaString::SPELL_NAME, spellId); - if(spell->level <= hero->getSecSkillLevel(SecondarySkill::WISDOM) + 2) + if(spell->level <= hero->maxSpellLevel()) { if(hero->canLearnSpell(spell)) { diff --git a/lib/mapObjects/CGHeroInstance.cpp b/lib/mapObjects/CGHeroInstance.cpp index e8dea7953..d69e867fa 100644 --- a/lib/mapObjects/CGHeroInstance.cpp +++ b/lib/mapObjects/CGHeroInstance.cpp @@ -957,7 +957,7 @@ bool CGHeroInstance::canLearnSpell(const CSpell * spell) const if(!hasSpellbook()) return false; - if(spell->level > getSecSkillLevel(SecondarySkill::WISDOM) + 2) //not enough wisdom + if(spell->level > maxSpellLevel()) //not enough wisdom return false; if(vstd::contains(spells, spell->id))//already known @@ -1175,6 +1175,11 @@ bool CGHeroInstance::hasSpellbook() const return getArt(ArtifactPosition::SPELLBOOK); } +int CGHeroInstance::maxSpellLevel() const +{ + return std::min(GameConstants::SPELL_LEVELS, 2 + valOfBonuses(Selector::typeSubtype(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::WISDOM))); +} + void CGHeroInstance::deserializationFix() { artDeserializationFix(this); diff --git a/lib/mapObjects/CGHeroInstance.h b/lib/mapObjects/CGHeroInstance.h index b7752e684..73f93901f 100644 --- a/lib/mapObjects/CGHeroInstance.h +++ b/lib/mapObjects/CGHeroInstance.h @@ -146,6 +146,7 @@ public: ////////////////////////////////////////////////////////////////////////// bool hasSpellbook() const; + int maxSpellLevel() const; EAlignment::EAlignment getAlignment() const; const std::string &getBiography() const; bool needsLastStack()const override; diff --git a/lib/mapObjects/MiscObjects.cpp b/lib/mapObjects/MiscObjects.cpp index 2d66a9c02..e8000ec6f 100644 --- a/lib/mapObjects/MiscObjects.cpp +++ b/lib/mapObjects/MiscObjects.cpp @@ -1601,7 +1601,7 @@ void CGShrine::onHeroVisit( const CGHeroInstance * h ) const { iw.text.addTxt(MetaString::ADVOB_TXT,174); } - else if(ID == Obj::SHRINE_OF_MAGIC_THOUGHT && !h->getSecSkillLevel(SecondarySkill::WISDOM)) //it's third level spell and hero doesn't have wisdom + else if(ID == Obj::SHRINE_OF_MAGIC_THOUGHT && h->maxSpellLevel() < 3) //it's third level spell and hero doesn't have wisdom { iw.text.addTxt(MetaString::ADVOB_TXT,130); } diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 9aeadd2fb..329e5b5a0 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -1974,7 +1974,7 @@ void CGameHandler::giveSpells(const CGTownInstance *t, const CGHeroInstance *h) if (t->hasBuilt(BuildingID::GRAIL, ETownType::CONFLUX) && t->hasBuilt(BuildingID::MAGES_GUILD_1)) { // Aurora Borealis give spells of all levels even if only level 1 mages guild built - for (int i = 0; i < h->getSecSkillLevel(SecondarySkill::WISDOM)+2; i++) + for (int i = 0; i < h->maxSpellLevel(); i++) { std::vector spells; getAllowedSpells(spells, i+1); @@ -1984,7 +1984,7 @@ void CGameHandler::giveSpells(const CGTownInstance *t, const CGHeroInstance *h) } else { - for (int i = 0; i < std::min(t->mageGuildLevel(), h->getSecSkillLevel(SecondarySkill::WISDOM)+2); i++) + for (int i = 0; i < std::min(t->mageGuildLevel(), h->maxSpellLevel()); i++) { for (int j = 0; j < t->spellsAtLevel(i+1, true) && j < t->spells.at(i).size(); j++) { @@ -2501,8 +2501,8 @@ void CGameHandler::useScholarSkill(ObjectInstanceID fromHero, ObjectInstanceID t if (!ScholarLevel || !h1->hasSpellbook() || !h2->hasSpellbook()) return;//no scholar skill or no spellbook - int h1Lvl = std::min(ScholarLevel+1, h1->getSecSkillLevel(SecondarySkill::WISDOM)+2), - h2Lvl = std::min(ScholarLevel+1, h2->getSecSkillLevel(SecondarySkill::WISDOM)+2);//heroes can receive this levels + int h1Lvl = std::min(ScholarLevel+1, h1->maxSpellLevel()), + h2Lvl = std::min(ScholarLevel+1, h2->maxSpellLevel());//heroes can receive this levels ChangeSpells cs1; cs1.learn = true; From fc77c40a823089f26db61d676f520d10b1f82d00 Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Sat, 26 Aug 2017 21:16:05 +1200 Subject: [PATCH 24/68] made ballistics bonus-based --- config/skills.json | 99 +++++++++++++++++++++++++++++++ lib/mapObjects/CGHeroInstance.cpp | 2 +- server/CGameHandler.cpp | 2 +- 3 files changed, 101 insertions(+), 2 deletions(-) diff --git a/config/skills.json b/config/skills.json index 9b8257e3e..10ebbcce7 100644 --- a/config/skills.json +++ b/config/skills.json @@ -270,6 +270,105 @@ ] } }, + "mysticism" : { + "basic" : { + "description" : "", + "effects" : [ + { + "type" : "MANA_REGENERATION", + "val" : 1, + "valueType" : "BASE_NUMBER" + } + ] + }, + "advanced" : { + "description" : "", + "effects" : [ + { + "type" : "MANA_REGENERATION", + "val" : 2, + "valueType" : "BASE_NUMBER" + } + ] + }, + "expert" : { + "description" : "", + "effects" : [ + { + "type" : "MANA_REGENERATION", + "val" : 3, + "valueType" : "BASE_NUMBER" + } + ] + } + }, + "luck" : { + "basic" : { + "description" : "", + "effects" : [ + { + "type" : "LUCK", + "val" : 1, + "valueType" : "BASE_NUMBER" + } + ] + }, + "advanced" : { + "description" : "", + "effects" : [ + { + "type" : "LUCK", + "val" : 2, + "valueType" : "BASE_NUMBER" + } + ] + }, + "expert" : { + "description" : "", + "effects" : [ + { + "type" : "LUCK", + "val" : 3, + "valueType" : "BASE_NUMBER" + } + ] + } + }, + "ballistics" : { + "basic" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.ballistics", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 1, + "valueType" : "BASE_NUMBER" + } + ] + }, + "advanced" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.ballistics", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 2, + "valueType" : "BASE_NUMBER" + } + ] + }, + "expert" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.ballistics", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 3, + "valueType" : "BASE_NUMBER" + } + ] + } + }, "estates" : { "basic" : { "description" : "", diff --git a/lib/mapObjects/CGHeroInstance.cpp b/lib/mapObjects/CGHeroInstance.cpp index d69e867fa..6840e2fc2 100644 --- a/lib/mapObjects/CGHeroInstance.cpp +++ b/lib/mapObjects/CGHeroInstance.cpp @@ -1079,7 +1079,7 @@ si32 CGHeroInstance::manaRegain() const if (hasBonusOfType(Bonus::FULL_MANA_REGENERATION)) return manaLimit(); - return 1 + valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, 8) + valOfBonuses(Bonus::MANA_REGENERATION); //1 + Mysticism level + return 1 + valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::MYSTICISM) + valOfBonuses(Bonus::MANA_REGENERATION); //1 + Mysticism level } si32 CGHeroInstance::getManaNewTurn() const diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 329e5b5a0..21d1992e5 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -4070,7 +4070,7 @@ bool CGameHandler::makeBattleAction(BattleAction &ba) CHeroHandler::SBallisticsLevelInfo sbi; if(stack->getCreature()->idNumber == CreatureID::CATAPULT) - sbi = VLC->heroh->ballistics.at(attackingHero->getSecSkillLevel(SecondarySkill::BALLISTICS)); + sbi = VLC->heroh->ballistics.at(attackingHero->valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::BALLISTICS)); else //may need to use higher ballistics level for creatures in future for some cases to match original H3 (upgraded cyclops etc) { sbi = VLC->heroh->ballistics.at(1); From 06d250737174dc26ca1f80c1a214ddfa95666582 Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Sun, 27 Aug 2017 12:59:09 +1200 Subject: [PATCH 25/68] log file loading --- config/skills.json | 6 +++--- lib/filesystem/CFilesystemLoader.cpp | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/config/skills.json b/config/skills.json index 10ebbcce7..bffb5e4a1 100644 --- a/config/skills.json +++ b/config/skills.json @@ -371,7 +371,7 @@ }, "estates" : { "basic" : { - "description" : "", + "description" : "With Basic Estates, a hero contributes 125 gold per day to your cause.", "effects" : [ { "subtype" : "skill.estates", @@ -382,7 +382,7 @@ ] }, "advanced" : { - "description" : "", + "description" : "With Advanced Estates, a hero contributes 250 gold per day to your cause.", "effects" : [ { "subtype" : "skill.estates", @@ -393,7 +393,7 @@ ] }, "expert" : { - "description" : "", + "description" : "With Expert Estates, a hero contributes 500 gold per day to your cause.", "effects" : [ { "subtype" : "skill.estates", diff --git a/lib/filesystem/CFilesystemLoader.cpp b/lib/filesystem/CFilesystemLoader.cpp index 77d63cc59..78b82b38c 100644 --- a/lib/filesystem/CFilesystemLoader.cpp +++ b/lib/filesystem/CFilesystemLoader.cpp @@ -26,8 +26,9 @@ CFilesystemLoader::CFilesystemLoader(std::string _mountPoint, bfs::path baseDire std::unique_ptr CFilesystemLoader::load(const ResourceID & resourceName) const { assert(fileList.count(resourceName)); - - return make_unique(baseDirectory / fileList.at(resourceName)); + boost::filesystem::path file = baseDirectory / fileList.at(resourceName); + logGlobal->trace("loading %s", file.string()); + return make_unique(file); } bool CFilesystemLoader::existsResource(const ResourceID & resourceName) const From 9bbfb57b930de394d9d5a2580dc2f6d4446e222f Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Sun, 27 Aug 2017 15:35:04 +1200 Subject: [PATCH 26/68] cleaned up secondary skill bonus merging --- lib/CSkillHandler.cpp | 2 +- lib/HeroBonus.cpp | 5 +++++ lib/HeroBonus.h | 1 + lib/mapObjects/CGHeroInstance.cpp | 15 +++++++-------- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/lib/CSkillHandler.cpp b/lib/CSkillHandler.cpp index 8d5504b61..a1f288cce 100644 --- a/lib/CSkillHandler.cpp +++ b/lib/CSkillHandler.cpp @@ -257,7 +257,7 @@ const std::shared_ptr CSkillHandler::defaultBonus(SecondarySkill skill, i case SecondarySkill::FIRST_AID: bonusVal = 25 + 25 * level; break; default: - valueType = Bonus::INDEPENDENT_MIN; break; + break; } return std::make_shared(Bonus::PERMANENT, bonusType, Bonus::SECONDARY_SKILL, bonusVal, skill, skill, valueType); diff --git a/lib/HeroBonus.cpp b/lib/HeroBonus.cpp index 12af178eb..25d246669 100644 --- a/lib/HeroBonus.cpp +++ b/lib/HeroBonus.cpp @@ -1166,6 +1166,11 @@ namespace Selector return CSelectFieldEqual(&Bonus::source)(source); } + CSelector DLL_LINKAGE valueType(Bonus::ValueType valType) + { + return CSelectFieldEqual(&Bonus::valType)(valType); + } + DLL_LINKAGE CSelector all([](const Bonus * b){return true;}); DLL_LINKAGE CSelector none([](const Bonus * b){return false;}); diff --git a/lib/HeroBonus.h b/lib/HeroBonus.h index 7ba710a42..a3160af69 100644 --- a/lib/HeroBonus.h +++ b/lib/HeroBonus.h @@ -950,6 +950,7 @@ namespace Selector CSelector DLL_LINKAGE typeSubtypeInfo(Bonus::BonusType type, TBonusSubtype subtype, si32 info); CSelector DLL_LINKAGE source(Bonus::BonusSource source, ui32 sourceID); CSelector DLL_LINKAGE sourceTypeSel(Bonus::BonusSource source); + CSelector DLL_LINKAGE valueType(Bonus::ValueType valType); /** * Selects all bonuses diff --git a/lib/mapObjects/CGHeroInstance.cpp b/lib/mapObjects/CGHeroInstance.cpp index 6840e2fc2..a49dead50 100644 --- a/lib/mapObjects/CGHeroInstance.cpp +++ b/lib/mapObjects/CGHeroInstance.cpp @@ -769,15 +769,14 @@ void CGHeroInstance::updateSkill(SecondarySkill which, int val) auto skillBonus = (*VLC->skillh)[which]->getBonus(val); for (auto b : skillBonus) { - // TODO: add standard method for joining bonuses, should match on valType as well - std::shared_ptr existing = getBonusLocalFirst(Selector::typeSubtype(b->type,b->subtype).And(Selector::source(Bonus::SECONDARY_SKILL, b->sid))); + // bonuses provided by different levels of a secondary skill are aggregated via max (not + as usual) + // different secondary skills providing the same bonus (e.g. ballistics might improve archery as well) are kept separate + std::shared_ptr existing = getBonusLocalFirst( + Selector::typeSubtype(b->type, b->subtype).And( + Selector::source(Bonus::SECONDARY_SKILL, b->sid).And( + Selector::valueType(b->valType)))); if(existing) - { - if(b->valType == Bonus::INDEPENDENT_MIN || b->valType == Bonus::BASE_NUMBER) - existing->val = b->val; - else - existing->val += b->val; - } + vstd::amax(existing->val, b->val); else addNewBonus(std::make_shared(*b)); } From 25e6b5cc07e6385799ed10ba102ffc69ed62cae8 Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Sun, 27 Aug 2017 17:40:52 +1200 Subject: [PATCH 27/68] added bonus type SECONDARY_SKILL_VAL2; refactored CSkillHandler::defaultBonus; made eagleEye level bonus-based --- config/skills.json | 53 ++++++++++++++++++++++++++ lib/CSkillHandler.cpp | 83 ++++++++++++++++++++++------------------- lib/CSkillHandler.h | 2 +- lib/HeroBonus.h | 1 + server/CGameHandler.cpp | 5 +-- 5 files changed, 102 insertions(+), 42 deletions(-) diff --git a/config/skills.json b/config/skills.json index bffb5e4a1..3ef2d2f24 100644 --- a/config/skills.json +++ b/config/skills.json @@ -369,6 +369,59 @@ ] } }, + "eagleEye" : { + "basic" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.eagleEye", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 40, + "valueType" : "BASE_NUMBER" + }, + { + "subtype" : "skill.eagleEye", + "type" : "SECONDARY_SKILL_VAL2", + "val" : 2, + "valueType" : "BASE_NUMBER" + } + ] + }, + "advanced" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.eagleEye", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 50, + "valueType" : "BASE_NUMBER" + }, + { + "subtype" : "skill.eagleEye", + "type" : "SECONDARY_SKILL_VAL2", + "val" : 3, + "valueType" : "BASE_NUMBER" + } + ] + }, + "expert" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.eagleEye", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 60, + "valueType" : "BASE_NUMBER" + }, + { + "subtype" : "skill.eagleEye", + "type" : "SECONDARY_SKILL_VAL2", + "val" : 4, + "valueType" : "BASE_NUMBER" + } + ] + } + }, "estates" : { "basic" : { "description" : "With Basic Estates, a hero contributes 125 gold per day to your cause.", diff --git a/lib/CSkillHandler.cpp b/lib/CSkillHandler.cpp index a1f288cce..bfc06e175 100644 --- a/lib/CSkillHandler.cpp +++ b/lib/CSkillHandler.cpp @@ -54,6 +54,7 @@ CSkill::~CSkill() void CSkill::addNewBonus(const std::shared_ptr& b, int level) { b->source = Bonus::SECONDARY_SKILL; + b->sid = id; b->duration = Bonus::PERMANENT; b->description = identifier; levels[level-1].effects.push_back(b); @@ -104,7 +105,8 @@ CSkillHandler::CSkillHandler() { CSkill * skill = new CSkill(SecondarySkill(id)); for(int level = 1; level < NSecondarySkill::levels.size(); level++) - skill->addNewBonus(defaultBonus(SecondarySkill(id), level), level); + for (auto bonus : defaultBonus(SecondarySkill(id), level)) + skill->addNewBonus(bonus, level); objects.push_back(skill); } } @@ -209,56 +211,61 @@ std::vector CSkillHandler::getDefaultAllowed() const } // HMM3 default bonus provided by secondary skill -const std::shared_ptr CSkillHandler::defaultBonus(SecondarySkill skill, int level) const +std::vector> CSkillHandler::defaultBonus(SecondarySkill skill, int level) const { - Bonus::BonusType bonusType = Bonus::SECONDARY_SKILL_PREMY; - Bonus::ValueType valueType = Bonus::BASE_NUMBER; - int bonusVal = level; + std::vector> result; - switch (skill) + // add bonus based on current values - useful for adding multiple bonuses easily + auto addBonus = [=,&result](int bonusVal, Bonus::BonusType bonusType = Bonus::SECONDARY_SKILL_PREMY) { + int subtype = (bonusType == Bonus::SECONDARY_SKILL_PREMY || bonusType == Bonus::SECONDARY_SKILL_VAL2) ? skill : 0; + result.push_back(std::make_shared(Bonus::PERMANENT, bonusType, Bonus::SECONDARY_SKILL, bonusVal, skill, subtype, Bonus::BASE_NUMBER)); + }; + + switch(skill) { case SecondarySkill::PATHFINDING: - bonusVal = 25 * level; break; + addBonus(25 * level); break; case SecondarySkill::ARCHERY: - bonusVal = 5 + 5 * level * level; break; + addBonus(5 + 5 * level * level); break; case SecondarySkill::LOGISTICS: - bonusVal = 10 * level; break; + addBonus(10 * level); break; case SecondarySkill::SCOUTING: - bonusType = Bonus::SIGHT_RADIOUS; break; + addBonus(level, Bonus::SIGHT_RADIOUS); break; case SecondarySkill::DIPLOMACY: - bonusType = Bonus::SURRENDER_DISCOUNT; - bonusVal = 20 * level; break; + addBonus(20 * level, Bonus::SURRENDER_DISCOUNT); break; case SecondarySkill::NAVIGATION: - bonusVal = 50 * level; break; + addBonus(50 * level); break; case SecondarySkill::LEADERSHIP: - bonusType = Bonus::MORALE; break; + addBonus(level, Bonus::MORALE); break; case SecondarySkill::LUCK: - bonusType = Bonus::LUCK; break; + addBonus(level, Bonus::LUCK); break; case SecondarySkill::EAGLE_EYE: - bonusVal = 30 + 10 * level; break; - case SecondarySkill::NECROMANCY: - bonusVal = 10 * level; break; - case SecondarySkill::ESTATES: - bonusVal = 125 << (level-1); break; - case SecondarySkill::TACTICS: - bonusVal = 1 + 2 * level; break; - case SecondarySkill::LEARNING: - bonusVal = 5 * level; break; - case SecondarySkill::OFFENCE: - bonusVal = 10 * level; break; - case SecondarySkill::ARMORER: - bonusVal = 5 * level; break; - case SecondarySkill::INTELLIGENCE: - bonusVal = 25 << (level-1); break; - case SecondarySkill::SORCERY: - bonusVal = 5 * level; break; - case SecondarySkill::RESISTANCE: - bonusVal = 5 << (level-1); break; - case SecondarySkill::FIRST_AID: - bonusVal = 25 + 25 * level; break; - default: + addBonus(30 + 10 * level); + addBonus(1 + level, Bonus::SECONDARY_SKILL_VAL2); break; + case SecondarySkill::NECROMANCY: + addBonus(10 * level); break; + case SecondarySkill::ESTATES: + addBonus(125 << (level-1)); break; + case SecondarySkill::TACTICS: + addBonus(1 + 2 * level); break; + case SecondarySkill::LEARNING: + addBonus(5 * level); break; + case SecondarySkill::OFFENCE: + addBonus(10 * level); break; + case SecondarySkill::ARMORER: + addBonus(5 * level); break; + case SecondarySkill::INTELLIGENCE: + addBonus(25 << (level-1)); break; + case SecondarySkill::SORCERY: + addBonus(5 * level); break; + case SecondarySkill::RESISTANCE: + addBonus(5 << (level-1)); break; + case SecondarySkill::FIRST_AID: + addBonus(25 + 25 * level); break; + default: + addBonus(level); break; } - return std::make_shared(Bonus::PERMANENT, bonusType, Bonus::SECONDARY_SKILL, bonusVal, skill, skill, valueType); + return result; } diff --git a/lib/CSkillHandler.h b/lib/CSkillHandler.h index ff4f9bcfd..108e356e2 100644 --- a/lib/CSkillHandler.h +++ b/lib/CSkillHandler.h @@ -84,5 +84,5 @@ public: protected: CSkill * loadFromJson(const JsonNode & json, const std::string & identifier) override; - const std::shared_ptr defaultBonus(SecondarySkill skill, int level) const; + std::vector> defaultBonus(SecondarySkill skill, int level) const; }; diff --git a/lib/HeroBonus.h b/lib/HeroBonus.h index a3160af69..1fdf98488 100644 --- a/lib/HeroBonus.h +++ b/lib/HeroBonus.h @@ -95,6 +95,7 @@ private: BONUS_NAME(FULL_MANA_REGENERATION) /*all mana points are replenished every day*/ \ BONUS_NAME(NONEVIL_ALIGNMENT_MIX) /*good and neutral creatures can be mixed without morale penalty*/ \ BONUS_NAME(SECONDARY_SKILL_PREMY) /*%*/ \ + BONUS_NAME(SECONDARY_SKILL_VAL2) /*for secondary skills that have multiple effects, like eagle eye (max level and chance)*/ \ BONUS_NAME(SURRENDER_DISCOUNT) /*%*/ \ BONUS_NAME(STACKS_SPEED) /*additional info - percent of speed bonus applied after direct bonuses; >0 - added, <0 - subtracted to this part*/ \ BONUS_NAME(FLYING_MOVEMENT) /*value - penalty percentage*/ \ diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 21d1992e5..e809c2115 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -592,12 +592,11 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance *hero1, const CGHer if (finishingBattle->winnerHero) { - if (int eagleEyeLevel = finishingBattle->winnerHero->getSecSkillLevel(SecondarySkill::EAGLE_EYE)) + if (int eagleEyeLevel = finishingBattle->winnerHero->valOfBonuses(Bonus::SECONDARY_SKILL_VAL2, SecondarySkill::EAGLE_EYE)) { - int maxLevel = eagleEyeLevel + 1; double eagleEyeChance = finishingBattle->winnerHero->valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::EAGLE_EYE); for (const CSpell *sp : gs->curB->sides.at(!battleResult.data->winner).usedSpellsHistory) - if (sp->level <= maxLevel && !vstd::contains(finishingBattle->winnerHero->spells, sp->id) && getRandomGenerator().nextInt(99) < eagleEyeChance) + if (sp->level <= eagleEyeLevel && !vstd::contains(finishingBattle->winnerHero->spells, sp->id) && getRandomGenerator().nextInt(99) < eagleEyeChance) cs.spells.insert(sp->id); } } From 0153d0fc788880ad4f2f57716e4df3d6be013d9f Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Sun, 27 Aug 2017 19:37:54 +1200 Subject: [PATCH 28/68] made fire/air/water/earth magic skills bonus-based --- config/skills.json | 175 ++++++++++++++++++++++++++++++ lib/CSkillHandler.cpp | 5 + lib/mapObjects/CGHeroInstance.cpp | 4 +- 3 files changed, 183 insertions(+), 1 deletion(-) diff --git a/config/skills.json b/config/skills.json index 3ef2d2f24..99595797e 100644 --- a/config/skills.json +++ b/config/skills.json @@ -422,6 +422,41 @@ ] } }, + "necromancy" : { + "basic" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.necromancy", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 10, + "valueType" : "BASE_NUMBER" + } + ] + }, + "advanced" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.necromancy", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 20, + "valueType" : "BASE_NUMBER" + } + ] + }, + "expert" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.necromancy", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 30, + "valueType" : "BASE_NUMBER" + } + ] + } + }, "estates" : { "basic" : { "description" : "With Basic Estates, a hero contributes 125 gold per day to your cause.", @@ -456,5 +491,145 @@ } ] } + }, + "fireMagic" : { + "basic" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.fireMagic", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 1, + "valueType" : "BASE_NUMBER" + } + ] + }, + "advanced" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.fireMagic", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 2, + "valueType" : "BASE_NUMBER" + } + ] + }, + "expert" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.fireMagic", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 3, + "valueType" : "BASE_NUMBER" + } + ] + } + }, + "airMagic" : { + "basic" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.airMagic", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 1, + "valueType" : "BASE_NUMBER" + } + ] + }, + "advanced" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.airMagic", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 2, + "valueType" : "BASE_NUMBER" + } + ] + }, + "expert" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.airMagic", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 3, + "valueType" : "BASE_NUMBER" + } + ] + } + }, + "waterMagic" : { + "basic" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.waterMagic", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 1, + "valueType" : "BASE_NUMBER" + } + ] + }, + "advanced" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.waterMagic", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 2, + "valueType" : "BASE_NUMBER" + } + ] + }, + "expert" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.waterMagic", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 3, + "valueType" : "BASE_NUMBER" + } + ] + } + }, + "earthMagic" : { + "basic" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.earthMagic", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 1, + "valueType" : "BASE_NUMBER" + } + ] + }, + "advanced" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.earthMagic", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 2, + "valueType" : "BASE_NUMBER" + } + ] + }, + "expert" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.earthMagic", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 3, + "valueType" : "BASE_NUMBER" + } + ] + } } } diff --git a/lib/CSkillHandler.cpp b/lib/CSkillHandler.cpp index bfc06e175..05ba079c3 100644 --- a/lib/CSkillHandler.cpp +++ b/lib/CSkillHandler.cpp @@ -247,6 +247,11 @@ std::vector> CSkillHandler::defaultBonus(SecondarySkill s addBonus(10 * level); break; case SecondarySkill::ESTATES: addBonus(125 << (level-1)); break; + case SecondarySkill::FIRE_MAGIC: + case SecondarySkill::AIR_MAGIC: + case SecondarySkill::WATER_MAGIC: + case SecondarySkill::EARTH_MAGIC: + addBonus(level); break; case SecondarySkill::TACTICS: addBonus(1 + 2 * level); break; case SecondarySkill::LEARNING: diff --git a/lib/mapObjects/CGHeroInstance.cpp b/lib/mapObjects/CGHeroInstance.cpp index a49dead50..09445f793 100644 --- a/lib/mapObjects/CGHeroInstance.cpp +++ b/lib/mapObjects/CGHeroInstance.cpp @@ -825,7 +825,9 @@ ui8 CGHeroInstance::getSpellSchoolLevel(const CSpell * spell, int *outSelectedSc spell->forEachSchool([&, this](const SpellSchoolInfo & cnf, bool & stop) { - int thisSchool = std::max(getSecSkillLevel(cnf.skill), valOfBonuses(Bonus::MAGIC_SCHOOL_SKILL, 1 << ((ui8)cnf.id))); //FIXME: Bonus shouldn't be additive (Witchking Artifacts : Crown of Skies) + int thisSchool = std::max( + valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, cnf.skill), + valOfBonuses(Bonus::MAGIC_SCHOOL_SKILL, 1 << ((ui8)cnf.id))); //FIXME: Bonus shouldn't be additive (Witchking Artifacts : Crown of Skies) if(thisSchool > skill) { skill = thisSchool; From 8bdb8f01ca3f776784526a12e222eac4fd03f277 Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Sun, 27 Aug 2017 20:10:25 +1200 Subject: [PATCH 29/68] made scholar skill bonus-based --- config/skills.json | 35 +++++++++++++++++++++++++++++++++++ lib/CSkillHandler.cpp | 2 ++ server/CGameHandler.cpp | 10 ++++++---- 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/config/skills.json b/config/skills.json index 99595797e..57e208159 100644 --- a/config/skills.json +++ b/config/skills.json @@ -631,5 +631,40 @@ } ] } + }, + "scholar" : { + "basic" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.scholar", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 2, + "valueType" : "BASE_NUMBER" + } + ] + }, + "advanced" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.scholar", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 3, + "valueType" : "BASE_NUMBER" + } + ] + }, + "expert" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.scholar", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 4, + "valueType" : "BASE_NUMBER" + } + ] + } } } diff --git a/lib/CSkillHandler.cpp b/lib/CSkillHandler.cpp index 05ba079c3..236a033a9 100644 --- a/lib/CSkillHandler.cpp +++ b/lib/CSkillHandler.cpp @@ -252,6 +252,8 @@ std::vector> CSkillHandler::defaultBonus(SecondarySkill s case SecondarySkill::WATER_MAGIC: case SecondarySkill::EARTH_MAGIC: addBonus(level); break; + case SecondarySkill::SCHOLAR: + addBonus(1 + level); break; case SecondarySkill::TACTICS: addBonus(1 + 2 * level); break; case SecondarySkill::LEARNING: diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index e809c2115..760990510 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -2489,19 +2489,21 @@ void CGameHandler::useScholarSkill(ObjectInstanceID fromHero, ObjectInstanceID t { const CGHeroInstance * h1 = getHero(fromHero); const CGHeroInstance * h2 = getHero(toHero); + int h1_scholarLevel = h1->valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::SCHOLAR); + int h2_scholarLevel = h1->valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::SCHOLAR); - if (h1->getSecSkillLevel(SecondarySkill::SCHOLAR) < h2->getSecSkillLevel(SecondarySkill::SCHOLAR)) + if (h1_scholarLevel < h2_scholarLevel) { std::swap (h1,h2);//1st hero need to have higher scholar level for correct message std::swap(fromHero, toHero); } - int ScholarLevel = h1->getSecSkillLevel(SecondarySkill::SCHOLAR);//heroes can trade up to this level + int ScholarLevel = std::max(h1_scholarLevel, h2_scholarLevel);//heroes can trade up to this level if (!ScholarLevel || !h1->hasSpellbook() || !h2->hasSpellbook()) return;//no scholar skill or no spellbook - int h1Lvl = std::min(ScholarLevel+1, h1->maxSpellLevel()), - h2Lvl = std::min(ScholarLevel+1, h2->maxSpellLevel());//heroes can receive this levels + int h1Lvl = std::min(ScholarLevel, h1->maxSpellLevel()), + h2Lvl = std::min(ScholarLevel, h2->maxSpellLevel());//heroes can receive this levels ChangeSpells cs1; cs1.learn = true; From 7e5c1ec7f8088a5b0526b70eef776713ecc6ae37 Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Sun, 27 Aug 2017 21:05:17 +1200 Subject: [PATCH 30/68] made artillery bonus-based; supports multiple bonus shots --- config/skills.json | 76 +++++++++++++++++++++++++++++++++++++++++ lib/CSkillHandler.cpp | 4 +++ server/CGameHandler.cpp | 26 +++++++------- 3 files changed, 92 insertions(+), 14 deletions(-) diff --git a/config/skills.json b/config/skills.json index 57e208159..46c867ffb 100644 --- a/config/skills.json +++ b/config/skills.json @@ -666,5 +666,81 @@ } ] } + }, + "tactics" : { + "basic" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.tactics", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 3, + "valueType" : "BASE_NUMBER" + } + ] + }, + "advanced" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.tactics", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 5, + "valueType" : "BASE_NUMBER" + } + ] + }, + "expert" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.tactics", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 7, + "valueType" : "BASE_NUMBER" + } + ] + } + }, + "artillery" : { + "basic" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.artillery", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 50, + "valueType" : "BASE_NUMBER" + } + ] + }, + "advanced" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.artillery", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 75, + "valueType" : "BASE_NUMBER" + }, + { + "subtype" : "skill.artillery", + "type" : "SECONDARY_SKILL_VAL2", + "val" : 1, + "valueType" : "BASE_NUMBER" + } + ] + }, + "expert" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.artillery", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 100, + "valueType" : "BASE_NUMBER" + } + ] + } } } diff --git a/lib/CSkillHandler.cpp b/lib/CSkillHandler.cpp index 236a033a9..412aa2cc1 100644 --- a/lib/CSkillHandler.cpp +++ b/lib/CSkillHandler.cpp @@ -256,6 +256,10 @@ std::vector> CSkillHandler::defaultBonus(SecondarySkill s addBonus(1 + level); break; case SecondarySkill::TACTICS: addBonus(1 + 2 * level); break; + case SecondarySkill::ARTILLERY: + addBonus(25 + 25 * level); break; + if(level > 1) // extra attack + addBonus(1, Bonus::SECONDARY_SKILL_VAL2); case SecondarySkill::LEARNING: addBonus(5 * level); break; case SecondarySkill::OFFENCE: diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 760990510..6071bc092 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -880,9 +880,8 @@ void CGameHandler::prepareAttack(BattleAttack &bat, const CStack *att, const CSt if (att->getCreature()->idNumber == CreatureID::BALLISTA) { - static const int artilleryLvlToChance[] = {0, 50, 75, 100}; const CGHeroInstance * owner = gs->curB->getHero(att->owner); - int chance = artilleryLvlToChance[owner->getSecSkillLevel(SecondarySkill::ARTILLERY)]; + int chance = owner->valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::ARTILLERY); if (chance > getRandomGenerator().nextInt(99)) { bat.flags |= BattleAttack::BALLISTA_DOUBLE_DMG; @@ -4007,19 +4006,18 @@ bool CGameHandler::makeBattleAction(BattleAction &ba) handleAfterAttackCasting(bat); } - //second shot for ballista, only if hero has advanced artillery - - const CGHeroInstance * attackingHero = gs->curB->battleGetFightingHero(ba.side); - - if(destinationStack->alive() - && (stack->getCreature()->idNumber == CreatureID::BALLISTA) - && (attackingHero->getSecSkillLevel(SecondarySkill::ARTILLERY) >= SecSkillLevel::ADVANCED) - ) + //extra shot(s) for ballista, based on artillery skill + if(stack->getCreature()->idNumber == CreatureID::BALLISTA) { - BattleAttack bat2; - bat2.flags |= BattleAttack::SHOT; - prepareAttack(bat2, stack, destinationStack, 0, ba.destinationTile); - sendAndApply(&bat2); + const CGHeroInstance * attackingHero = gs->curB->battleGetFightingHero(ba.side); + int ballistaBonusAttacks = attackingHero->valOfBonuses(Bonus::SECONDARY_SKILL_VAL2, SecondarySkill::ARTILLERY); + while(destinationStack->alive() && ballistaBonusAttacks-- > 0) + { + BattleAttack bat2; + bat2.flags |= BattleAttack::SHOT; + prepareAttack(bat2, stack, destinationStack, 0, ba.destinationTile); + sendAndApply(&bat2); + } } //allow more than one additional attack From aa15feba62d280ce51bdf955e3d265ca353845d2 Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Mon, 28 Aug 2017 00:17:59 +1200 Subject: [PATCH 31/68] moved SECONDARY_SKILL_VAL2 to end of list --- lib/HeroBonus.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/HeroBonus.h b/lib/HeroBonus.h index 1fdf98488..b901ad92a 100644 --- a/lib/HeroBonus.h +++ b/lib/HeroBonus.h @@ -95,7 +95,6 @@ private: BONUS_NAME(FULL_MANA_REGENERATION) /*all mana points are replenished every day*/ \ BONUS_NAME(NONEVIL_ALIGNMENT_MIX) /*good and neutral creatures can be mixed without morale penalty*/ \ BONUS_NAME(SECONDARY_SKILL_PREMY) /*%*/ \ - BONUS_NAME(SECONDARY_SKILL_VAL2) /*for secondary skills that have multiple effects, like eagle eye (max level and chance)*/ \ BONUS_NAME(SURRENDER_DISCOUNT) /*%*/ \ BONUS_NAME(STACKS_SPEED) /*additional info - percent of speed bonus applied after direct bonuses; >0 - added, <0 - subtracted to this part*/ \ BONUS_NAME(FLYING_MOVEMENT) /*value - penalty percentage*/ \ @@ -236,6 +235,7 @@ private: BONUS_NAME(CATAPULT_EXTRA_SHOTS) /*val - number of additional shots, requires CATAPULT bonus to work*/\ BONUS_NAME(RANGED_RETALIATION) /*allows shooters to perform ranged retaliation*/\ BONUS_NAME(BLOCKS_RANGED_RETALIATION) /*disallows ranged retaliation for shooter unit, BLOCKS_RETALIATION bonus is for melee retaliation only*/\ + BONUS_NAME(SECONDARY_SKILL_VAL2) /*for secondary skills that have multiple effects, like eagle eye (max level and chance)*/ \ /* end of list */ From 03c18ff691b25b6adce9744c9b46fc17f734c115 Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Mon, 28 Aug 2017 10:41:32 +1200 Subject: [PATCH 32/68] added remaining skills to skills.json --- config/skills.json | 245 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 245 insertions(+) diff --git a/config/skills.json b/config/skills.json index 46c867ffb..828c35f40 100644 --- a/config/skills.json +++ b/config/skills.json @@ -742,5 +742,250 @@ } ] } + }, + "learning" : { + "basic" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.learning", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 5, + "valueType" : "BASE_NUMBER" + } + ] + }, + "advanced" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.learning", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 10, + "valueType" : "BASE_NUMBER" + } + ] + }, + "expert" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.learning", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 15, + "valueType" : "BASE_NUMBER" + } + ] + } + }, + "offence" : { + "basic" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.offence", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 10, + "valueType" : "BASE_NUMBER" + } + ] + }, + "advanced" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.offence", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 20, + "valueType" : "BASE_NUMBER" + } + ] + }, + "expert" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.offence", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 30, + "valueType" : "BASE_NUMBER" + } + ] + } + }, + "armorer" : { + "basic" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.armorer", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 5, + "valueType" : "BASE_NUMBER" + } + ] + }, + "advanced" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.armorer", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 10, + "valueType" : "BASE_NUMBER" + } + ] + }, + "expert" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.armorer", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 15, + "valueType" : "BASE_NUMBER" + } + ] + } + }, + "intelligence" : { + "basic" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.intelligence", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 25, + "valueType" : "BASE_NUMBER" + } + ] + }, + "advanced" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.intelligence", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 50, + "valueType" : "BASE_NUMBER" + } + ] + }, + "expert" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.intelligence", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 100, + "valueType" : "BASE_NUMBER" + } + ] + } + }, + "sorcery" : { + "basic" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.sorcery", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 5, + "valueType" : "BASE_NUMBER" + } + ] + }, + "advanced" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.sorcery", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 10, + "valueType" : "BASE_NUMBER" + } + ] + }, + "expert" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.sorcery", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 15, + "valueType" : "BASE_NUMBER" + } + ] + } + }, + "resistance" : { + "basic" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.resistance", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 5, + "valueType" : "BASE_NUMBER" + } + ] + }, + "advanced" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.resistance", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 10, + "valueType" : "BASE_NUMBER" + } + ] + }, + "expert" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.resistance", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 20, + "valueType" : "BASE_NUMBER" + } + ] + } + }, + "firstAid" : { + "basic" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.firstAid", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 50, + "valueType" : "BASE_NUMBER" + } + ] + }, + "advanced" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.firstAid", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 75, + "valueType" : "BASE_NUMBER" + } + ] + }, + "expert" : { + "description" : "", + "effects" : [ + { + "subtype" : "skill.firstAid", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 100, + "valueType" : "BASE_NUMBER" + } + ] + } } } From 5091b117e2ed2ce7c266eccfcd6d86936bbf716c Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Mon, 28 Aug 2017 13:56:00 +1200 Subject: [PATCH 33/68] fixed serialization for older savegames --- lib/VCMI_Lib.h | 5 ++++- lib/mapObjects/CGHeroInstance.h | 2 ++ lib/serializer/CSerializer.h | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/VCMI_Lib.h b/lib/VCMI_Lib.h index a31e73727..f2fb8c73c 100644 --- a/lib/VCMI_Lib.h +++ b/lib/VCMI_Lib.h @@ -69,7 +69,10 @@ public: h & objh; h & objtypeh; h & spellh; - h & skillh; + if(version >= 777) + { + h & skillh; + } h & modh; h & IS_AI_ENABLED; h & bth; diff --git a/lib/mapObjects/CGHeroInstance.h b/lib/mapObjects/CGHeroInstance.h index 73f93901f..c99234583 100644 --- a/lib/mapObjects/CGHeroInstance.h +++ b/lib/mapObjects/CGHeroInstance.h @@ -303,5 +303,7 @@ public: h & visitedObjects; BONUS_TREE_DESERIALIZATION_FIX //visitied town pointer will be restored by map serialization method + if(version < 777 && !h.saving) + recreateSecondarySkillsBonuses(); } }; diff --git a/lib/serializer/CSerializer.h b/lib/serializer/CSerializer.h index a7137fdc0..85c7695e1 100644 --- a/lib/serializer/CSerializer.h +++ b/lib/serializer/CSerializer.h @@ -12,7 +12,7 @@ #include "../ConstTransitivePtr.h" #include "../GameConstants.h" -const ui32 SERIALIZATION_VERSION = 776; +const ui32 SERIALIZATION_VERSION = 777; const ui32 MINIMAL_SERIALIZATION_VERSION = 753; const std::string SAVEGAME_MAGIC = "VCMISVG"; From 69a538a600e09fdbecb97eadc44345168d35a4ad Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Mon, 28 Aug 2017 20:09:27 +1200 Subject: [PATCH 34/68] added bonus type MANUAL_CONTROL --- config/skills.json | 18 ++++++++++++++++++ lib/CSkillHandler.cpp | 15 ++++++++++++--- lib/HeroBonus.h | 1 + server/CGameHandler.cpp | 6 +++--- 4 files changed, 34 insertions(+), 6 deletions(-) diff --git a/config/skills.json b/config/skills.json index 828c35f40..7ae2a7501 100644 --- a/config/skills.json +++ b/config/skills.json @@ -343,6 +343,12 @@ "type" : "SECONDARY_SKILL_PREMY", "val" : 1, "valueType" : "BASE_NUMBER" + }, + { + "subtype" : "creature.catapult", + "type" : "MANUAL_CONTROL", + "val" : 100, + "valueType" : "BASE_NUMBER" } ] }, @@ -711,6 +717,12 @@ "type" : "SECONDARY_SKILL_PREMY", "val" : 50, "valueType" : "BASE_NUMBER" + }, + { + "subtype" : "creature.ballista", + "type" : "MANUAL_CONTROL", + "val" : 100, + "valueType" : "BASE_NUMBER" } ] }, @@ -962,6 +974,12 @@ "type" : "SECONDARY_SKILL_PREMY", "val" : 50, "valueType" : "BASE_NUMBER" + }, + { + "subtype" : "creature.firstAidTent", + "type" : "MANUAL_CONTROL", + "val" : 100, + "valueType" : "BASE_NUMBER" } ] }, diff --git a/lib/CSkillHandler.cpp b/lib/CSkillHandler.cpp index 412aa2cc1..98b414d9c 100644 --- a/lib/CSkillHandler.cpp +++ b/lib/CSkillHandler.cpp @@ -216,8 +216,10 @@ std::vector> CSkillHandler::defaultBonus(SecondarySkill s std::vector> result; // add bonus based on current values - useful for adding multiple bonuses easily - auto addBonus = [=,&result](int bonusVal, Bonus::BonusType bonusType = Bonus::SECONDARY_SKILL_PREMY) { - int subtype = (bonusType == Bonus::SECONDARY_SKILL_PREMY || bonusType == Bonus::SECONDARY_SKILL_VAL2) ? skill : 0; + auto addBonus = [=,&result](int bonusVal, Bonus::BonusType bonusType = Bonus::SECONDARY_SKILL_PREMY, int subtype = 0) + { + if(bonusType == Bonus::SECONDARY_SKILL_PREMY || bonusType == Bonus::SECONDARY_SKILL_VAL2) + subtype = skill; result.push_back(std::make_shared(Bonus::PERMANENT, bonusType, Bonus::SECONDARY_SKILL, bonusVal, skill, subtype, Bonus::BASE_NUMBER)); }; @@ -239,6 +241,10 @@ std::vector> CSkillHandler::defaultBonus(SecondarySkill s addBonus(level, Bonus::MORALE); break; case SecondarySkill::LUCK: addBonus(level, Bonus::LUCK); break; + case SecondarySkill::BALLISTICS: + addBonus(100, Bonus::MANUAL_CONTROL, CreatureID::CATAPULT); + addBonus(level); + break; case SecondarySkill::EAGLE_EYE: addBonus(30 + 10 * level); addBonus(1 + level, Bonus::SECONDARY_SKILL_VAL2); @@ -257,9 +263,11 @@ std::vector> CSkillHandler::defaultBonus(SecondarySkill s case SecondarySkill::TACTICS: addBonus(1 + 2 * level); break; case SecondarySkill::ARTILLERY: - addBonus(25 + 25 * level); break; + addBonus(100, Bonus::MANUAL_CONTROL, CreatureID::BALLISTA); + addBonus(25 + 25 * level); if(level > 1) // extra attack addBonus(1, Bonus::SECONDARY_SKILL_VAL2); + break; case SecondarySkill::LEARNING: addBonus(5 * level); break; case SecondarySkill::OFFENCE: @@ -273,6 +281,7 @@ std::vector> CSkillHandler::defaultBonus(SecondarySkill s case SecondarySkill::RESISTANCE: addBonus(5 << (level-1)); break; case SecondarySkill::FIRST_AID: + addBonus(100, Bonus::MANUAL_CONTROL, CreatureID::FIRST_AID_TENT); addBonus(25 + 25 * level); break; default: addBonus(level); break; diff --git a/lib/HeroBonus.h b/lib/HeroBonus.h index b901ad92a..23b2bec5b 100644 --- a/lib/HeroBonus.h +++ b/lib/HeroBonus.h @@ -236,6 +236,7 @@ private: BONUS_NAME(RANGED_RETALIATION) /*allows shooters to perform ranged retaliation*/\ BONUS_NAME(BLOCKS_RANGED_RETALIATION) /*disallows ranged retaliation for shooter unit, BLOCKS_RETALIATION bonus is for melee retaliation only*/\ BONUS_NAME(SECONDARY_SKILL_VAL2) /*for secondary skills that have multiple effects, like eagle eye (max level and chance)*/ \ + BONUS_NAME(MANUAL_CONTROL) /* manually control warmachine with id = subtype, chance = val */ \ /* end of list */ diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 6071bc092..71882b5b7 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -5799,7 +5799,7 @@ void CGameHandler::runBattle() const CGHeroInstance * curOwner = battleGetOwnerHero(next); if ((next->position < 0 || next->getCreature()->idNumber == CreatureID::BALLISTA) //arrow turret or ballista - && (!curOwner || curOwner->getSecSkillLevel(SecondarySkill::ARTILLERY) == 0)) //hero has no artillery + && (!curOwner || getRandomGenerator().nextInt(99) >= curOwner->valOfBonuses(Bonus::MANUAL_CONTROL, CreatureID::BALLISTA))) { BattleAction attack; attack.actionType = Battle::SHOOT; @@ -5829,7 +5829,7 @@ void CGameHandler::runBattle() continue; } - if (!curOwner || curOwner->getSecSkillLevel(SecondarySkill::BALLISTICS) == 0) + if (!curOwner || getRandomGenerator().nextInt(99) >= curOwner->valOfBonuses(Bonus::MANUAL_CONTROL, CreatureID::CATAPULT)) { BattleAction attack; attack.destinationTile = *RandomGeneratorUtil::nextItem(attackableBattleHexes, @@ -5857,7 +5857,7 @@ void CGameHandler::runBattle() continue; } - if (!curOwner || curOwner->getSecSkillLevel(SecondarySkill::FIRST_AID) == 0) //no hero or hero has no first aid + if (!curOwner || getRandomGenerator().nextInt(99) >= curOwner->valOfBonuses(Bonus::MANUAL_CONTROL, CreatureID::FIRST_AID_TENT)) { RandomGeneratorUtil::randomShuffle(possibleStacks, getRandomGenerator()); const CStack * toBeHealed = possibleStacks.front(); From 9b3c61616fd8998d22c87bdd9c3c9b85b86c23ef Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Mon, 28 Aug 2017 23:33:19 +1200 Subject: [PATCH 35/68] made diplomacy join chance bonus-based --- config/skills.json | 18 ++++++++++++++++++ lib/CSkillHandler.cpp | 1 + lib/mapObjects/MiscObjects.cpp | 7 ++++--- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/config/skills.json b/config/skills.json index 7ae2a7501..784614c38 100644 --- a/config/skills.json +++ b/config/skills.json @@ -140,6 +140,12 @@ "basic" : { "description" : "", "effects" : [ + { + "subtype" : "skill.diplomacy", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 1, + "valueType" : "BASE_NUMBER" + }, { "type" : "SURRENDER_DISCOUNT", "val" : 20, @@ -150,6 +156,12 @@ "advanced" : { "description" : "", "effects" : [ + { + "subtype" : "skill.diplomacy", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 2, + "valueType" : "BASE_NUMBER" + }, { "type" : "SURRENDER_DISCOUNT", "val" : 40, @@ -160,6 +172,12 @@ "expert" : { "description" : "", "effects" : [ + { + "subtype" : "skill.diplomacy", + "type" : "SECONDARY_SKILL_PREMY", + "val" : 3, + "valueType" : "BASE_NUMBER" + }, { "type" : "SURRENDER_DISCOUNT", "val" : 60, diff --git a/lib/CSkillHandler.cpp b/lib/CSkillHandler.cpp index 98b414d9c..2825c95b7 100644 --- a/lib/CSkillHandler.cpp +++ b/lib/CSkillHandler.cpp @@ -234,6 +234,7 @@ std::vector> CSkillHandler::defaultBonus(SecondarySkill s case SecondarySkill::SCOUTING: addBonus(level, Bonus::SIGHT_RADIOUS); break; case SecondarySkill::DIPLOMACY: + addBonus(level); addBonus(20 * level, Bonus::SURRENDER_DISCOUNT); break; case SecondarySkill::NAVIGATION: addBonus(50 * level); break; diff --git a/lib/mapObjects/MiscObjects.cpp b/lib/mapObjects/MiscObjects.cpp index e8000ec6f..71588de38 100644 --- a/lib/mapObjects/MiscObjects.cpp +++ b/lib/mapObjects/MiscObjects.cpp @@ -323,17 +323,18 @@ int CGCreature::takenAction(const CGHeroInstance *h, bool allowJoin) const if(count*2 > totalCount) sympathy++; // 2 - hero have similar creatures more that 50% - int charisma = powerFactor + h->getSecSkillLevel(SecondarySkill::DIPLOMACY) + sympathy; + int diplomacy = h->valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::DIPLOMACY); + int charisma = powerFactor + diplomacy + sympathy; if(charisma < character) return FIGHT; if (allowJoin) { - if(h->getSecSkillLevel(SecondarySkill::DIPLOMACY) + sympathy + 1 >= character) + if(diplomacy + sympathy + 1 >= character) return JOIN_FOR_FREE; - else if(h->getSecSkillLevel(SecondarySkill::DIPLOMACY) * 2 + sympathy + 1 >= character) + else if(diplomacy * 2 + sympathy + 1 >= character) return VLC->creh->creatures[subID]->cost[6] * getStackCount(SlotID(0)); //join for gold } From 3fe9bc34b8d55b33bd0c439244656aacfe2d7625 Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Mon, 28 Aug 2017 23:59:01 +1200 Subject: [PATCH 36/68] CGHeroInstance::recreateSecondarySkillsBonuses() restores bonuses for all levels --- lib/mapObjects/CGHeroInstance.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/mapObjects/CGHeroInstance.cpp b/lib/mapObjects/CGHeroInstance.cpp index 09445f793..c78dba632 100644 --- a/lib/mapObjects/CGHeroInstance.cpp +++ b/lib/mapObjects/CGHeroInstance.cpp @@ -761,7 +761,8 @@ void CGHeroInstance::recreateSecondarySkillsBonuses() removeBonus(bonus); for(auto skill_info : secSkills) - updateSkill(SecondarySkill(skill_info.first), skill_info.second); + for(int level = 1; level <= skill_info.second; level++) + updateSkill(SecondarySkill(skill_info.first), level); } void CGHeroInstance::updateSkill(SecondarySkill which, int val) From 899e8403f7d890328e19b331d1b8cea38bfdc145 Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Wed, 30 Aug 2017 10:25:36 +1200 Subject: [PATCH 37/68] skills.json uses base and struct for effects --- config/schemas/skill.json | 9 +- config/skills.json | 1109 +++++++++++++++---------------------- lib/CSkillHandler.cpp | 14 +- 3 files changed, 458 insertions(+), 674 deletions(-) diff --git a/config/schemas/skill.json b/config/schemas/skill.json index c4f1a3192..87506d46b 100644 --- a/config/schemas/skill.json +++ b/config/schemas/skill.json @@ -18,17 +18,20 @@ "description": "localizable description" }, "effects": { - "type": "array", - "items": { + "type": "object", + "additionalProperties" : { "$ref" : "vcmi:bonus" } } } }, - "required" : ["basic", "advanced", "expert"], + "required" : ["base", "basic", "advanced", "expert"], "properties": { + "base":{ + "$ref" : "#/definitions/skillBonus" + }, "basic":{ "$ref" : "#/definitions/skillBonus" }, diff --git a/config/skills.json b/config/skills.json index 784614c38..adfe23ec2 100644 --- a/config/skills.json +++ b/config/skills.json @@ -1,1027 +1,798 @@ { "pathfinding" : { - "basic" : { + "base" : { "description" : "", - "effects" : [ - { + "effects" : { + "main" : { "subtype" : "skill.pathfinding", "type" : "SECONDARY_SKILL_PREMY", - "val" : 25, "valueType" : "BASE_NUMBER" } - ] + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 25 } + } }, "advanced" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.pathfinding", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 50, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 50 } + } }, "expert" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.pathfinding", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 75, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 75 } + } } }, "archery" : { - "basic" : { + "base" : { "description" : "", - "effects" : [ - { + "effects" : { + "main" : { "subtype" : "skill.archery", "type" : "SECONDARY_SKILL_PREMY", - "val" : 10, "valueType" : "BASE_NUMBER" } - ] + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 10 } + } }, "advanced" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.archery", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 25, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 25 } + } }, "expert" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.archery", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 50, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 50 } + } } }, "logistics" : { - "basic" : { + "base" : { "description" : "", - "effects" : [ - { + "effects" : { + "main" : { "subtype" : "skill.logistics", "type" : "SECONDARY_SKILL_PREMY", - "val" : 10, "valueType" : "BASE_NUMBER" } - ] + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 10 } + } }, "advanced" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.logistics", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 20, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 20 } + } }, "expert" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.logistics", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 30, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 30 } + } } }, "scouting" : { - "basic" : { + "base" : { "description" : "", - "effects" : [ - { + "effects" : { + "main" : { "type" : "SIGHT_RADIOUS", - "val" : 1, "valueType" : "BASE_NUMBER" } - ] + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 1 } + } }, "advanced" : { - "description" : "", - "effects" : [ - { - "type" : "SIGHT_RADIOUS", - "val" : 2, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 2 } + } }, "expert" : { - "description" : "", - "effects" : [ - { - "type" : "SIGHT_RADIOUS", - "val" : 3, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 3 } + } } }, "diplomacy" : { - "basic" : { + "base" : { "description" : "", - "effects" : [ - { + "effects" : { + "main" : { "subtype" : "skill.diplomacy", "type" : "SECONDARY_SKILL_PREMY", - "val" : 1, "valueType" : "BASE_NUMBER" }, - { + "surr" : { "type" : "SURRENDER_DISCOUNT", "val" : 20, "valueType" : "BASE_NUMBER" } - ] + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 1 }, + "surr" : { "val" : 20 } + } }, "advanced" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.diplomacy", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 2, - "valueType" : "BASE_NUMBER" - }, - { - "type" : "SURRENDER_DISCOUNT", - "val" : 40, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val": 2 }, + "surr" : { "val" : 40 } + } }, "expert" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.diplomacy", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 3, - "valueType" : "BASE_NUMBER" - }, - { - "type" : "SURRENDER_DISCOUNT", - "val" : 60, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val": 3 }, + "surr" : { "val" : 60 } + } } }, "navigation" : { - "basic" : { + "base" : { "description" : "", - "effects" : [ - { + "effects" : { + "main" : { "subtype" : "skill.navigation", "type" : "SECONDARY_SKILL_PREMY", - "val" : 50, "valueType" : "BASE_NUMBER" } - ] + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 50 } + } }, "advanced" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.navigation", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 100, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 100 } + } }, "expert" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.navigation", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 150, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 150 } + } } }, "leadership" : { - "basic" : { + "base" : { "description" : "", - "effects" : [ - { + "effects" : { + "main" : { "type" : "MORALE", - "val" : 1, "valueType" : "BASE_NUMBER" } - ] + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 1 } + } }, "advanced" : { - "description" : "", - "effects" : [ - { - "type" : "MORALE", - "val" : 2, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 2 } + } }, "expert" : { - "description" : "", - "effects" : [ - { - "type" : "MORALE", - "val" : 3, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 3 } + } } }, "wisdom" : { - "basic" : { + "base" : { "description" : "", - "effects" : [ - { + "effects" : { + "main" : { "subtype" : "skill.wisdom", "type" : "SECONDARY_SKILL_PREMY", - "val" : 1, "valueType" : "BASE_NUMBER" } - ] + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 1 } + } }, "advanced" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.wisdom", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 2, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 2 } + } }, "expert" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.wisdom", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 3, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 3 } + } } }, "mysticism" : { - "basic" : { + "base" : { "description" : "", - "effects" : [ - { + "effects" : { + "main" : { "type" : "MANA_REGENERATION", - "val" : 1, "valueType" : "BASE_NUMBER" } - ] + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 1 } + } }, "advanced" : { - "description" : "", - "effects" : [ - { - "type" : "MANA_REGENERATION", - "val" : 2, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 2 } + } }, "expert" : { - "description" : "", - "effects" : [ - { - "type" : "MANA_REGENERATION", - "val" : 3, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 3 } + } } }, "luck" : { - "basic" : { + "base" : { "description" : "", - "effects" : [ - { + "effects" : { + "main" : { "type" : "LUCK", - "val" : 1, "valueType" : "BASE_NUMBER" } - ] + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 1 } + } }, "advanced" : { - "description" : "", - "effects" : [ - { - "type" : "LUCK", - "val" : 2, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 2 } + } }, "expert" : { - "description" : "", - "effects" : [ - { - "type" : "LUCK", - "val" : 3, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 3 } + } } }, "ballistics" : { - "basic" : { + "base" : { "description" : "", - "effects" : [ - { + "effects" : { + "main" : { "subtype" : "skill.ballistics", "type" : "SECONDARY_SKILL_PREMY", - "val" : 1, "valueType" : "BASE_NUMBER" }, - { + "ctrl" : { "subtype" : "creature.catapult", "type" : "MANUAL_CONTROL", "val" : 100, "valueType" : "BASE_NUMBER" } - ] + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 1 } + } }, "advanced" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.ballistics", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 2, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 2 } + } }, "expert" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.ballistics", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 3, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 3 } + } } }, "eagleEye" : { - "basic" : { + "base" : { "description" : "", - "effects" : [ - { + "effects" : { + "main" : { "subtype" : "skill.eagleEye", "type" : "SECONDARY_SKILL_PREMY", - "val" : 40, "valueType" : "BASE_NUMBER" }, - { + "val2" : { "subtype" : "skill.eagleEye", "type" : "SECONDARY_SKILL_VAL2", - "val" : 2, "valueType" : "BASE_NUMBER" } - ] + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 40 }, + "val2" : { "val" : 2 } + } }, "advanced" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.eagleEye", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 50, - "valueType" : "BASE_NUMBER" - }, - { - "subtype" : "skill.eagleEye", - "type" : "SECONDARY_SKILL_VAL2", - "val" : 3, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 50 }, + "val2" : { "val" : 3 } + } }, "expert" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.eagleEye", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 60, - "valueType" : "BASE_NUMBER" - }, - { - "subtype" : "skill.eagleEye", - "type" : "SECONDARY_SKILL_VAL2", - "val" : 4, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 60 }, + "val2" : { "val" : 4 } + } } }, "necromancy" : { - "basic" : { + "base" : { "description" : "", - "effects" : [ - { + "effects" : { + "main" : { "subtype" : "skill.necromancy", "type" : "SECONDARY_SKILL_PREMY", - "val" : 10, "valueType" : "BASE_NUMBER" } - ] + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 10 } + } }, "advanced" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.necromancy", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 20, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 20 } + } }, "expert" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.necromancy", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 30, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 30 } + } } }, "estates" : { - "basic" : { - "description" : "With Basic Estates, a hero contributes 125 gold per day to your cause.", - "effects" : [ - { + "base" : { + "effects" : { + "main" : { "subtype" : "skill.estates", "type" : "SECONDARY_SKILL_PREMY", - "val" : 125, "valueType" : "BASE_NUMBER" } - ] + } + }, + "basic" : { + "description" : "With Basic Estates, a hero contributes 125 gold per day to your cause.", + "effects" : { + "main" : { "val" : 125 } + } }, "advanced" : { "description" : "With Advanced Estates, a hero contributes 250 gold per day to your cause.", - "effects" : [ - { - "subtype" : "skill.estates", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 250, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 250 } + } }, "expert" : { "description" : "With Expert Estates, a hero contributes 500 gold per day to your cause.", - "effects" : [ - { - "subtype" : "skill.estates", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 500, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 500 } + } } }, "fireMagic" : { - "basic" : { + "base" : { "description" : "", - "effects" : [ - { + "effects" : { + "main" : { "subtype" : "skill.fireMagic", "type" : "SECONDARY_SKILL_PREMY", - "val" : 1, "valueType" : "BASE_NUMBER" } - ] + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 1 } + } }, "advanced" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.fireMagic", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 2, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 2 } + } }, "expert" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.fireMagic", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 3, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 3 } + } } }, "airMagic" : { - "basic" : { + "base" : { "description" : "", - "effects" : [ - { + "effects" : { + "main" : { "subtype" : "skill.airMagic", "type" : "SECONDARY_SKILL_PREMY", - "val" : 1, "valueType" : "BASE_NUMBER" } - ] + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 1 } + } }, "advanced" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.airMagic", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 2, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 2 } + } }, "expert" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.airMagic", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 3, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 3 } + } } }, "waterMagic" : { - "basic" : { + "base" : { "description" : "", - "effects" : [ - { + "effects" : { + "main" : { "subtype" : "skill.waterMagic", "type" : "SECONDARY_SKILL_PREMY", - "val" : 1, "valueType" : "BASE_NUMBER" } - ] + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 1 } + } }, "advanced" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.waterMagic", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 2, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 2 } + } }, "expert" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.waterMagic", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 3, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 3 } + } } }, "earthMagic" : { - "basic" : { + "base" : { "description" : "", - "effects" : [ - { + "effects" : { + "main" : { "subtype" : "skill.earthMagic", "type" : "SECONDARY_SKILL_PREMY", - "val" : 1, "valueType" : "BASE_NUMBER" } - ] + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 1 } + } }, "advanced" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.earthMagic", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 2, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 2 } + } }, "expert" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.earthMagic", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 3, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 3 } + } } }, "scholar" : { - "basic" : { + "base" : { "description" : "", - "effects" : [ - { + "effects" : { + "main" : { "subtype" : "skill.scholar", "type" : "SECONDARY_SKILL_PREMY", - "val" : 2, "valueType" : "BASE_NUMBER" } - ] + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 2 } + } }, "advanced" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.scholar", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 3, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 3 } + } }, "expert" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.scholar", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 4, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 4 } + } } }, "tactics" : { - "basic" : { + "base" : { "description" : "", - "effects" : [ - { + "effects" : { + "main" : { "subtype" : "skill.tactics", "type" : "SECONDARY_SKILL_PREMY", - "val" : 3, "valueType" : "BASE_NUMBER" } - ] + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 3 } + } }, "advanced" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.tactics", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 5, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 5 } + } }, "expert" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.tactics", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 7, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 7 } + } } }, "artillery" : { - "basic" : { + "base" : { "description" : "", - "effects" : [ - { + "effects" : { + "main" : { "subtype" : "skill.artillery", "type" : "SECONDARY_SKILL_PREMY", - "val" : 50, "valueType" : "BASE_NUMBER" }, - { + "val2" : { + "subtype" : "skill.artillery", + "type" : "SECONDARY_SKILL_VAL2", + "valueType" : "BASE_NUMBER" + }, + "ctrl" : { "subtype" : "creature.ballista", "type" : "MANUAL_CONTROL", "val" : 100, "valueType" : "BASE_NUMBER" } - ] + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 50 }, + "val2" : { "val" : 0 } + } }, "advanced" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.artillery", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 75, - "valueType" : "BASE_NUMBER" - }, - { - "subtype" : "skill.artillery", - "type" : "SECONDARY_SKILL_VAL2", - "val" : 1, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 75 }, + "val2" : { "val" : 1 } + } }, "expert" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.artillery", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 100, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 100 }, + "val2" : { "val" : 1 } + } } }, "learning" : { - "basic" : { + "base" : { "description" : "", - "effects" : [ - { + "effects" : { + "main" : { "subtype" : "skill.learning", "type" : "SECONDARY_SKILL_PREMY", - "val" : 5, "valueType" : "BASE_NUMBER" } - ] + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 5 } + } }, "advanced" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.learning", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 10, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 10 } + } }, "expert" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.learning", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 15, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 15 } + } } }, "offence" : { - "basic" : { + "base" : { "description" : "", - "effects" : [ - { + "effects" : { + "main" : { "subtype" : "skill.offence", "type" : "SECONDARY_SKILL_PREMY", - "val" : 10, "valueType" : "BASE_NUMBER" } - ] + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 10 } + } }, "advanced" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.offence", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 20, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 20 } + } }, "expert" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.offence", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 30, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 30 } + } } }, "armorer" : { - "basic" : { + "base" : { "description" : "", - "effects" : [ - { + "effects" : { + "main" : { "subtype" : "skill.armorer", "type" : "SECONDARY_SKILL_PREMY", - "val" : 5, "valueType" : "BASE_NUMBER" } - ] + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 5 } + } }, "advanced" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.armorer", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 10, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 10 } + } }, "expert" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.armorer", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 15, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 15 } + } } }, "intelligence" : { - "basic" : { + "base" : { "description" : "", - "effects" : [ - { + "effects" : { + "main" : { "subtype" : "skill.intelligence", "type" : "SECONDARY_SKILL_PREMY", - "val" : 25, "valueType" : "BASE_NUMBER" } - ] + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 25 } + } }, "advanced" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.intelligence", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 50, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 50 } + } }, "expert" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.intelligence", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 100, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 100 } + } } }, "sorcery" : { - "basic" : { + "base" : { "description" : "", - "effects" : [ - { + "effects" : { + "main" : { "subtype" : "skill.sorcery", "type" : "SECONDARY_SKILL_PREMY", - "val" : 5, "valueType" : "BASE_NUMBER" } - ] + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 5 } + } }, "advanced" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.sorcery", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 10, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 10 } + } }, "expert" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.sorcery", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 15, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 15 } + } } }, "resistance" : { - "basic" : { + "base" : { "description" : "", - "effects" : [ - { + "effects" : { + "main" : { "subtype" : "skill.resistance", "type" : "SECONDARY_SKILL_PREMY", - "val" : 5, "valueType" : "BASE_NUMBER" } - ] + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 5 } + } }, "advanced" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.resistance", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 10, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 10 } + } }, "expert" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.resistance", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 20, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 20 } + } } }, "firstAid" : { - "basic" : { + "base" : { "description" : "", - "effects" : [ - { + "effects" : { + "main" : { "subtype" : "skill.firstAid", "type" : "SECONDARY_SKILL_PREMY", - "val" : 50, "valueType" : "BASE_NUMBER" }, - { + "ctrl" : { "subtype" : "creature.firstAidTent", "type" : "MANUAL_CONTROL", "val" : 100, "valueType" : "BASE_NUMBER" } - ] + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 50 } + } }, "advanced" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.firstAid", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 75, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 75 } + } }, "expert" : { - "description" : "", - "effects" : [ - { - "subtype" : "skill.firstAid", - "type" : "SECONDARY_SKILL_PREMY", - "val" : 100, - "valueType" : "BASE_NUMBER" - } - ] + "effects" : { + "main" : { "val" : 100 } + } } } } diff --git a/lib/CSkillHandler.cpp b/lib/CSkillHandler.cpp index 2825c95b7..1e4190b2e 100644 --- a/lib/CSkillHandler.cpp +++ b/lib/CSkillHandler.cpp @@ -147,9 +147,9 @@ CSkill * CSkillHandler::loadFromJson(const JsonNode & json, const std::string & const std::string & levelName = NSecondarySkill::levels[level]; // basic, advanced, expert const JsonNode & levelNode = json[levelName]; // parse bonus effects - for(auto b : levelNode["effects"].Vector()) + for(auto b : levelNode["effects"].Struct()) { - auto bonus = JsonUtils::parseBonus(b); + auto bonus = JsonUtils::parseBonus(b.second); bonus->sid = skill->id; skill->addNewBonus(bonus, level); } @@ -198,6 +198,16 @@ void CSkillHandler::afterLoadFinalization() void CSkillHandler::beforeValidate(JsonNode & object) { + //handle "base" level info + JsonNode & base = object["base"]; + + auto inheritNode = [&](const std::string & name){ + JsonUtils::inherit(object[name], base); + }; + + inheritNode("basic"); + inheritNode("advanced"); + inheritNode("expert"); } CSkillHandler::~CSkillHandler() From 5e28202f945401dd3a499a89c2242e0690ce45b3 Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Wed, 30 Aug 2017 14:09:02 +1200 Subject: [PATCH 38/68] dropped requirements for base in skill.json --- config/schemas/skill.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/config/schemas/skill.json b/config/schemas/skill.json index 87506d46b..2a41a5136 100644 --- a/config/schemas/skill.json +++ b/config/schemas/skill.json @@ -26,11 +26,13 @@ } }, - "required" : ["base", "basic", "advanced", "expert"], + "required" : ["basic", "advanced", "expert"], "properties": { "base":{ - "$ref" : "#/definitions/skillBonus" + "type": "object", + "description": "will be merged with all levels", + "additionalProperties": true }, "basic":{ "$ref" : "#/definitions/skillBonus" From aadb5d93f7e67405a1c84b790093e70ccce1b0f2 Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Wed, 30 Aug 2017 16:03:24 +1200 Subject: [PATCH 39/68] added comment (and commented-out code) about skill legacy data --- lib/CSkillHandler.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/CSkillHandler.cpp b/lib/CSkillHandler.cpp index 1e4190b2e..a3234a231 100644 --- a/lib/CSkillHandler.cpp +++ b/lib/CSkillHandler.cpp @@ -113,8 +113,24 @@ CSkillHandler::CSkillHandler() std::vector CSkillHandler::loadLegacyData(size_t dataSize) { - // not supported - no legacy data to load std::vector legacyData; + /* problem: CGI is client-side only + for(int id = 0; id < GameConstants::SKILL_QUANTITY; id++) + { + CSkill & skill = *objects[id]; + JsonNode skillNode(JsonNode::DATA_STRUCT); + for(int level = 1; level < NSecondarySkill::levels.size(); level++) + { + //only "real" legacy data is skill description + std::string desc = CGI->generaltexth->skillInfoTexts[skill.id][level-1]; + //update both skill & JSON + skill.setDescription(desc, level); + auto & levelNode = skillNode[NSecondarySkill::levels[level]].Struct(); + levelNode["description"].String() = desc; + } + legacyData.push_back(skillNode); + } + */ return legacyData; } @@ -155,7 +171,6 @@ CSkill * CSkillHandler::loadFromJson(const JsonNode & json, const std::string & } // parse skill description - tracked separately if(vstd::contains(levelNode.Struct(), "description") && !levelNode["description"].isNull()) - //CGI->generaltexth->skillInfoTexts[skill->id][level-1] = levelNode["description"].String(); skill->setDescription(levelNode["description"].String(), level); } logMod->debug("loaded secondary skill %s(%d)", identifier, (int)skill->id); From 36d671b0931ee1c819959a34231bfc832203fce3 Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Wed, 30 Aug 2017 16:23:03 +1200 Subject: [PATCH 40/68] changed indentation from spaces to tabs --- config/schemas/skill.json | 72 +- config/skills.json | 1592 ++++++++++++++++++------------------- lib/CSkillHandler.cpp | 122 +-- lib/CSkillHandler.h | 64 +- 4 files changed, 925 insertions(+), 925 deletions(-) diff --git a/config/schemas/skill.json b/config/schemas/skill.json index 2a41a5136..fdee8aa1e 100644 --- a/config/schemas/skill.json +++ b/config/schemas/skill.json @@ -1,48 +1,48 @@ { - "type":"object", - "$schema": "http://json-schema.org/draft-04/schema", + "type" : "object", + "$schema" : "http://json-schema.org/draft-04/schema", "title" : "VCMI skill format", "description" : "Format used to replace bonuses provided by secondary skills in VCMI", "definitions" : { - "skillBonus":{ - "type": "object", - "description": "Set of bonuses provided by skill at given level", - "required" : ["effects"], - "properties": { - "description": { - "type": "string", - "description": "localizable description" - }, - "effects": { - "type": "object", - "additionalProperties" : { - "$ref" : "vcmi:bonus" - } - } - } - }, + "skillBonus" : { + "type" : "object", + "description" : "Set of bonuses provided by skill at given level", + "required" : ["effects"], + "properties" : { + "description" : { + "type" : "string", + "description" : "localizable description" + }, + "effects" : { + "type" : "object", + "additionalProperties" : { + "$ref" : "vcmi:bonus" + } + } + } + }, - "required" : ["basic", "advanced", "expert"], + "required" : ["basic", "advanced", "expert"], - "properties": { - "base":{ - "type": "object", - "description": "will be merged with all levels", - "additionalProperties": true - }, - "basic":{ - "$ref" : "#/definitions/skillBonus" - }, - "advanced":{ - "$ref" : "#/definitions/skillBonus" - }, - "expert":{ - "$ref" : "#/definitions/skillBonus" - } - } + "properties" : { + "base" : { + "type" : "object", + "description" : "will be merged with all levels", + "additionalProperties" : true + }, + "basic" : { + "$ref" : "#/definitions/skillBonus" + }, + "advanced" : { + "$ref" : "#/definitions/skillBonus" + }, + "expert" : { + "$ref" : "#/definitions/skillBonus" + } + } } } diff --git a/config/skills.json b/config/skills.json index adfe23ec2..cd8c67301 100644 --- a/config/skills.json +++ b/config/skills.json @@ -1,798 +1,798 @@ { - "pathfinding" : { - "base" : { - "description" : "", - "effects" : { - "main" : { - "subtype" : "skill.pathfinding", - "type" : "SECONDARY_SKILL_PREMY", - "valueType" : "BASE_NUMBER" - } - } - }, - "basic" : { - "effects" : { - "main" : { "val" : 25 } - } - }, - "advanced" : { - "effects" : { - "main" : { "val" : 50 } - } - }, - "expert" : { - "effects" : { - "main" : { "val" : 75 } - } - } - }, - "archery" : { - "base" : { - "description" : "", - "effects" : { - "main" : { - "subtype" : "skill.archery", - "type" : "SECONDARY_SKILL_PREMY", - "valueType" : "BASE_NUMBER" - } - } - }, - "basic" : { - "effects" : { - "main" : { "val" : 10 } - } - }, - "advanced" : { - "effects" : { - "main" : { "val" : 25 } - } - }, - "expert" : { - "effects" : { - "main" : { "val" : 50 } - } - } - }, - "logistics" : { - "base" : { - "description" : "", - "effects" : { - "main" : { - "subtype" : "skill.logistics", - "type" : "SECONDARY_SKILL_PREMY", - "valueType" : "BASE_NUMBER" - } - } - }, - "basic" : { - "effects" : { - "main" : { "val" : 10 } - } - }, - "advanced" : { - "effects" : { - "main" : { "val" : 20 } - } - }, - "expert" : { - "effects" : { - "main" : { "val" : 30 } - } - } - }, - "scouting" : { - "base" : { - "description" : "", - "effects" : { - "main" : { - "type" : "SIGHT_RADIOUS", - "valueType" : "BASE_NUMBER" - } - } - }, - "basic" : { - "effects" : { - "main" : { "val" : 1 } - } - }, - "advanced" : { - "effects" : { - "main" : { "val" : 2 } - } - }, - "expert" : { - "effects" : { - "main" : { "val" : 3 } - } - } - }, - "diplomacy" : { - "base" : { - "description" : "", - "effects" : { - "main" : { - "subtype" : "skill.diplomacy", - "type" : "SECONDARY_SKILL_PREMY", - "valueType" : "BASE_NUMBER" - }, - "surr" : { - "type" : "SURRENDER_DISCOUNT", - "val" : 20, - "valueType" : "BASE_NUMBER" - } - } - }, - "basic" : { - "effects" : { - "main" : { "val" : 1 }, - "surr" : { "val" : 20 } - } - }, - "advanced" : { - "effects" : { - "main" : { "val": 2 }, - "surr" : { "val" : 40 } - } - }, - "expert" : { - "effects" : { - "main" : { "val": 3 }, - "surr" : { "val" : 60 } - } - } - }, - "navigation" : { - "base" : { - "description" : "", - "effects" : { - "main" : { - "subtype" : "skill.navigation", - "type" : "SECONDARY_SKILL_PREMY", - "valueType" : "BASE_NUMBER" - } - } - }, - "basic" : { - "effects" : { - "main" : { "val" : 50 } - } - }, - "advanced" : { - "effects" : { - "main" : { "val" : 100 } - } - }, - "expert" : { - "effects" : { - "main" : { "val" : 150 } - } - } - }, - "leadership" : { - "base" : { - "description" : "", - "effects" : { - "main" : { - "type" : "MORALE", - "valueType" : "BASE_NUMBER" - } - } - }, - "basic" : { - "effects" : { - "main" : { "val" : 1 } - } - }, - "advanced" : { - "effects" : { - "main" : { "val" : 2 } - } - }, - "expert" : { - "effects" : { - "main" : { "val" : 3 } - } - } - }, - "wisdom" : { - "base" : { - "description" : "", - "effects" : { - "main" : { - "subtype" : "skill.wisdom", - "type" : "SECONDARY_SKILL_PREMY", - "valueType" : "BASE_NUMBER" - } - } - }, - "basic" : { - "effects" : { - "main" : { "val" : 1 } - } - }, - "advanced" : { - "effects" : { - "main" : { "val" : 2 } - } - }, - "expert" : { - "effects" : { - "main" : { "val" : 3 } - } - } - }, - "mysticism" : { - "base" : { - "description" : "", - "effects" : { - "main" : { - "type" : "MANA_REGENERATION", - "valueType" : "BASE_NUMBER" - } - } - }, - "basic" : { - "effects" : { - "main" : { "val" : 1 } - } - }, - "advanced" : { - "effects" : { - "main" : { "val" : 2 } - } - }, - "expert" : { - "effects" : { - "main" : { "val" : 3 } - } - } - }, - "luck" : { - "base" : { - "description" : "", - "effects" : { - "main" : { - "type" : "LUCK", - "valueType" : "BASE_NUMBER" - } - } - }, - "basic" : { - "effects" : { - "main" : { "val" : 1 } - } - }, - "advanced" : { - "effects" : { - "main" : { "val" : 2 } - } - }, - "expert" : { - "effects" : { - "main" : { "val" : 3 } - } - } - }, - "ballistics" : { - "base" : { - "description" : "", - "effects" : { - "main" : { - "subtype" : "skill.ballistics", - "type" : "SECONDARY_SKILL_PREMY", - "valueType" : "BASE_NUMBER" - }, - "ctrl" : { - "subtype" : "creature.catapult", - "type" : "MANUAL_CONTROL", - "val" : 100, - "valueType" : "BASE_NUMBER" - } - } - }, - "basic" : { - "effects" : { - "main" : { "val" : 1 } - } - }, - "advanced" : { - "effects" : { - "main" : { "val" : 2 } - } - }, - "expert" : { - "effects" : { - "main" : { "val" : 3 } - } - } - }, - "eagleEye" : { - "base" : { - "description" : "", - "effects" : { - "main" : { - "subtype" : "skill.eagleEye", - "type" : "SECONDARY_SKILL_PREMY", - "valueType" : "BASE_NUMBER" - }, - "val2" : { - "subtype" : "skill.eagleEye", - "type" : "SECONDARY_SKILL_VAL2", - "valueType" : "BASE_NUMBER" - } - } - }, - "basic" : { - "effects" : { - "main" : { "val" : 40 }, - "val2" : { "val" : 2 } - } - }, - "advanced" : { - "effects" : { - "main" : { "val" : 50 }, - "val2" : { "val" : 3 } - } - }, - "expert" : { - "effects" : { - "main" : { "val" : 60 }, - "val2" : { "val" : 4 } - } - } - }, - "necromancy" : { - "base" : { - "description" : "", - "effects" : { - "main" : { - "subtype" : "skill.necromancy", - "type" : "SECONDARY_SKILL_PREMY", - "valueType" : "BASE_NUMBER" - } - } - }, - "basic" : { - "effects" : { - "main" : { "val" : 10 } - } - }, - "advanced" : { - "effects" : { - "main" : { "val" : 20 } - } - }, - "expert" : { - "effects" : { - "main" : { "val" : 30 } - } - } - }, - "estates" : { - "base" : { - "effects" : { - "main" : { - "subtype" : "skill.estates", - "type" : "SECONDARY_SKILL_PREMY", - "valueType" : "BASE_NUMBER" - } - } - }, - "basic" : { - "description" : "With Basic Estates, a hero contributes 125 gold per day to your cause.", - "effects" : { - "main" : { "val" : 125 } - } - }, - "advanced" : { - "description" : "With Advanced Estates, a hero contributes 250 gold per day to your cause.", - "effects" : { - "main" : { "val" : 250 } - } - }, - "expert" : { - "description" : "With Expert Estates, a hero contributes 500 gold per day to your cause.", - "effects" : { - "main" : { "val" : 500 } - } - } - }, - "fireMagic" : { - "base" : { - "description" : "", - "effects" : { - "main" : { - "subtype" : "skill.fireMagic", - "type" : "SECONDARY_SKILL_PREMY", - "valueType" : "BASE_NUMBER" - } - } - }, - "basic" : { - "effects" : { - "main" : { "val" : 1 } - } - }, - "advanced" : { - "effects" : { - "main" : { "val" : 2 } - } - }, - "expert" : { - "effects" : { - "main" : { "val" : 3 } - } - } - }, - "airMagic" : { - "base" : { - "description" : "", - "effects" : { - "main" : { - "subtype" : "skill.airMagic", - "type" : "SECONDARY_SKILL_PREMY", - "valueType" : "BASE_NUMBER" - } - } - }, - "basic" : { - "effects" : { - "main" : { "val" : 1 } - } - }, - "advanced" : { - "effects" : { - "main" : { "val" : 2 } - } - }, - "expert" : { - "effects" : { - "main" : { "val" : 3 } - } - } - }, - "waterMagic" : { - "base" : { - "description" : "", - "effects" : { - "main" : { - "subtype" : "skill.waterMagic", - "type" : "SECONDARY_SKILL_PREMY", - "valueType" : "BASE_NUMBER" - } - } - }, - "basic" : { - "effects" : { - "main" : { "val" : 1 } - } - }, - "advanced" : { - "effects" : { - "main" : { "val" : 2 } - } - }, - "expert" : { - "effects" : { - "main" : { "val" : 3 } - } - } - }, - "earthMagic" : { - "base" : { - "description" : "", - "effects" : { - "main" : { - "subtype" : "skill.earthMagic", - "type" : "SECONDARY_SKILL_PREMY", - "valueType" : "BASE_NUMBER" - } - } - }, - "basic" : { - "effects" : { - "main" : { "val" : 1 } - } - }, - "advanced" : { - "effects" : { - "main" : { "val" : 2 } - } - }, - "expert" : { - "effects" : { - "main" : { "val" : 3 } - } - } - }, - "scholar" : { - "base" : { - "description" : "", - "effects" : { - "main" : { - "subtype" : "skill.scholar", - "type" : "SECONDARY_SKILL_PREMY", - "valueType" : "BASE_NUMBER" - } - } - }, - "basic" : { - "effects" : { - "main" : { "val" : 2 } - } - }, - "advanced" : { - "effects" : { - "main" : { "val" : 3 } - } - }, - "expert" : { - "effects" : { - "main" : { "val" : 4 } - } - } - }, - "tactics" : { - "base" : { - "description" : "", - "effects" : { - "main" : { - "subtype" : "skill.tactics", - "type" : "SECONDARY_SKILL_PREMY", - "valueType" : "BASE_NUMBER" - } - } - }, - "basic" : { - "effects" : { - "main" : { "val" : 3 } - } - }, - "advanced" : { - "effects" : { - "main" : { "val" : 5 } - } - }, - "expert" : { - "effects" : { - "main" : { "val" : 7 } - } - } - }, - "artillery" : { - "base" : { - "description" : "", - "effects" : { - "main" : { - "subtype" : "skill.artillery", - "type" : "SECONDARY_SKILL_PREMY", - "valueType" : "BASE_NUMBER" - }, - "val2" : { - "subtype" : "skill.artillery", - "type" : "SECONDARY_SKILL_VAL2", - "valueType" : "BASE_NUMBER" - }, - "ctrl" : { - "subtype" : "creature.ballista", - "type" : "MANUAL_CONTROL", - "val" : 100, - "valueType" : "BASE_NUMBER" - } - } - }, - "basic" : { - "effects" : { - "main" : { "val" : 50 }, - "val2" : { "val" : 0 } - } - }, - "advanced" : { - "effects" : { - "main" : { "val" : 75 }, - "val2" : { "val" : 1 } - } - }, - "expert" : { - "effects" : { - "main" : { "val" : 100 }, - "val2" : { "val" : 1 } - } - } - }, - "learning" : { - "base" : { - "description" : "", - "effects" : { - "main" : { - "subtype" : "skill.learning", - "type" : "SECONDARY_SKILL_PREMY", - "valueType" : "BASE_NUMBER" - } - } - }, - "basic" : { - "effects" : { - "main" : { "val" : 5 } - } - }, - "advanced" : { - "effects" : { - "main" : { "val" : 10 } - } - }, - "expert" : { - "effects" : { - "main" : { "val" : 15 } - } - } - }, - "offence" : { - "base" : { - "description" : "", - "effects" : { - "main" : { - "subtype" : "skill.offence", - "type" : "SECONDARY_SKILL_PREMY", - "valueType" : "BASE_NUMBER" - } - } - }, - "basic" : { - "effects" : { - "main" : { "val" : 10 } - } - }, - "advanced" : { - "effects" : { - "main" : { "val" : 20 } - } - }, - "expert" : { - "effects" : { - "main" : { "val" : 30 } - } - } - }, - "armorer" : { - "base" : { - "description" : "", - "effects" : { - "main" : { - "subtype" : "skill.armorer", - "type" : "SECONDARY_SKILL_PREMY", - "valueType" : "BASE_NUMBER" - } - } - }, - "basic" : { - "effects" : { - "main" : { "val" : 5 } - } - }, - "advanced" : { - "effects" : { - "main" : { "val" : 10 } - } - }, - "expert" : { - "effects" : { - "main" : { "val" : 15 } - } - } - }, - "intelligence" : { - "base" : { - "description" : "", - "effects" : { - "main" : { - "subtype" : "skill.intelligence", - "type" : "SECONDARY_SKILL_PREMY", - "valueType" : "BASE_NUMBER" - } - } - }, - "basic" : { - "effects" : { - "main" : { "val" : 25 } - } - }, - "advanced" : { - "effects" : { - "main" : { "val" : 50 } - } - }, - "expert" : { - "effects" : { - "main" : { "val" : 100 } - } - } - }, - "sorcery" : { - "base" : { - "description" : "", - "effects" : { - "main" : { - "subtype" : "skill.sorcery", - "type" : "SECONDARY_SKILL_PREMY", - "valueType" : "BASE_NUMBER" - } - } - }, - "basic" : { - "effects" : { - "main" : { "val" : 5 } - } - }, - "advanced" : { - "effects" : { - "main" : { "val" : 10 } - } - }, - "expert" : { - "effects" : { - "main" : { "val" : 15 } - } - } - }, - "resistance" : { - "base" : { - "description" : "", - "effects" : { - "main" : { - "subtype" : "skill.resistance", - "type" : "SECONDARY_SKILL_PREMY", - "valueType" : "BASE_NUMBER" - } - } - }, - "basic" : { - "effects" : { - "main" : { "val" : 5 } - } - }, - "advanced" : { - "effects" : { - "main" : { "val" : 10 } - } - }, - "expert" : { - "effects" : { - "main" : { "val" : 20 } - } - } - }, - "firstAid" : { - "base" : { - "description" : "", - "effects" : { - "main" : { - "subtype" : "skill.firstAid", - "type" : "SECONDARY_SKILL_PREMY", - "valueType" : "BASE_NUMBER" - }, - "ctrl" : { - "subtype" : "creature.firstAidTent", - "type" : "MANUAL_CONTROL", - "val" : 100, - "valueType" : "BASE_NUMBER" - } - } - }, - "basic" : { - "effects" : { - "main" : { "val" : 50 } - } - }, - "advanced" : { - "effects" : { - "main" : { "val" : 75 } - } - }, - "expert" : { - "effects" : { - "main" : { "val" : 100 } - } - } - } + "pathfinding" : { + "base" : { + "description" : "", + "effects" : { + "main" : { + "subtype" : "skill.pathfinding", + "type" : "SECONDARY_SKILL_PREMY", + "valueType" : "BASE_NUMBER" + } + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 25 } + } + }, + "advanced" : { + "effects" : { + "main" : { "val" : 50 } + } + }, + "expert" : { + "effects" : { + "main" : { "val" : 75 } + } + } + }, + "archery" : { + "base" : { + "description" : "", + "effects" : { + "main" : { + "subtype" : "skill.archery", + "type" : "SECONDARY_SKILL_PREMY", + "valueType" : "BASE_NUMBER" + } + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 10 } + } + }, + "advanced" : { + "effects" : { + "main" : { "val" : 25 } + } + }, + "expert" : { + "effects" : { + "main" : { "val" : 50 } + } + } + }, + "logistics" : { + "base" : { + "description" : "", + "effects" : { + "main" : { + "subtype" : "skill.logistics", + "type" : "SECONDARY_SKILL_PREMY", + "valueType" : "BASE_NUMBER" + } + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 10 } + } + }, + "advanced" : { + "effects" : { + "main" : { "val" : 20 } + } + }, + "expert" : { + "effects" : { + "main" : { "val" : 30 } + } + } + }, + "scouting" : { + "base" : { + "description" : "", + "effects" : { + "main" : { + "type" : "SIGHT_RADIOUS", + "valueType" : "BASE_NUMBER" + } + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 1 } + } + }, + "advanced" : { + "effects" : { + "main" : { "val" : 2 } + } + }, + "expert" : { + "effects" : { + "main" : { "val" : 3 } + } + } + }, + "diplomacy" : { + "base" : { + "description" : "", + "effects" : { + "main" : { + "subtype" : "skill.diplomacy", + "type" : "SECONDARY_SKILL_PREMY", + "valueType" : "BASE_NUMBER" + }, + "surr" : { + "type" : "SURRENDER_DISCOUNT", + "val" : 20, + "valueType" : "BASE_NUMBER" + } + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 1 }, + "surr" : { "val" : 20 } + } + }, + "advanced" : { + "effects" : { + "main" : { "val": 2 }, + "surr" : { "val" : 40 } + } + }, + "expert" : { + "effects" : { + "main" : { "val": 3 }, + "surr" : { "val" : 60 } + } + } + }, + "navigation" : { + "base" : { + "description" : "", + "effects" : { + "main" : { + "subtype" : "skill.navigation", + "type" : "SECONDARY_SKILL_PREMY", + "valueType" : "BASE_NUMBER" + } + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 50 } + } + }, + "advanced" : { + "effects" : { + "main" : { "val" : 100 } + } + }, + "expert" : { + "effects" : { + "main" : { "val" : 150 } + } + } + }, + "leadership" : { + "base" : { + "description" : "", + "effects" : { + "main" : { + "type" : "MORALE", + "valueType" : "BASE_NUMBER" + } + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 1 } + } + }, + "advanced" : { + "effects" : { + "main" : { "val" : 2 } + } + }, + "expert" : { + "effects" : { + "main" : { "val" : 3 } + } + } + }, + "wisdom" : { + "base" : { + "description" : "", + "effects" : { + "main" : { + "subtype" : "skill.wisdom", + "type" : "SECONDARY_SKILL_PREMY", + "valueType" : "BASE_NUMBER" + } + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 1 } + } + }, + "advanced" : { + "effects" : { + "main" : { "val" : 2 } + } + }, + "expert" : { + "effects" : { + "main" : { "val" : 3 } + } + } + }, + "mysticism" : { + "base" : { + "description" : "", + "effects" : { + "main" : { + "type" : "MANA_REGENERATION", + "valueType" : "BASE_NUMBER" + } + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 1 } + } + }, + "advanced" : { + "effects" : { + "main" : { "val" : 2 } + } + }, + "expert" : { + "effects" : { + "main" : { "val" : 3 } + } + } + }, + "luck" : { + "base" : { + "description" : "", + "effects" : { + "main" : { + "type" : "LUCK", + "valueType" : "BASE_NUMBER" + } + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 1 } + } + }, + "advanced" : { + "effects" : { + "main" : { "val" : 2 } + } + }, + "expert" : { + "effects" : { + "main" : { "val" : 3 } + } + } + }, + "ballistics" : { + "base" : { + "description" : "", + "effects" : { + "main" : { + "subtype" : "skill.ballistics", + "type" : "SECONDARY_SKILL_PREMY", + "valueType" : "BASE_NUMBER" + }, + "ctrl" : { + "subtype" : "creature.catapult", + "type" : "MANUAL_CONTROL", + "val" : 100, + "valueType" : "BASE_NUMBER" + } + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 1 } + } + }, + "advanced" : { + "effects" : { + "main" : { "val" : 2 } + } + }, + "expert" : { + "effects" : { + "main" : { "val" : 3 } + } + } + }, + "eagleEye" : { + "base" : { + "description" : "", + "effects" : { + "main" : { + "subtype" : "skill.eagleEye", + "type" : "SECONDARY_SKILL_PREMY", + "valueType" : "BASE_NUMBER" + }, + "val2" : { + "subtype" : "skill.eagleEye", + "type" : "SECONDARY_SKILL_VAL2", + "valueType" : "BASE_NUMBER" + } + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 40 }, + "val2" : { "val" : 2 } + } + }, + "advanced" : { + "effects" : { + "main" : { "val" : 50 }, + "val2" : { "val" : 3 } + } + }, + "expert" : { + "effects" : { + "main" : { "val" : 60 }, + "val2" : { "val" : 4 } + } + } + }, + "necromancy" : { + "base" : { + "description" : "", + "effects" : { + "main" : { + "subtype" : "skill.necromancy", + "type" : "SECONDARY_SKILL_PREMY", + "valueType" : "BASE_NUMBER" + } + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 10 } + } + }, + "advanced" : { + "effects" : { + "main" : { "val" : 20 } + } + }, + "expert" : { + "effects" : { + "main" : { "val" : 30 } + } + } + }, + "estates" : { + "base" : { + "effects" : { + "main" : { + "subtype" : "skill.estates", + "type" : "SECONDARY_SKILL_PREMY", + "valueType" : "BASE_NUMBER" + } + } + }, + "basic" : { + "description" : "With Basic Estates, a hero contributes 125 gold per day to your cause.", + "effects" : { + "main" : { "val" : 125 } + } + }, + "advanced" : { + "description" : "With Advanced Estates, a hero contributes 250 gold per day to your cause.", + "effects" : { + "main" : { "val" : 250 } + } + }, + "expert" : { + "description" : "With Expert Estates, a hero contributes 500 gold per day to your cause.", + "effects" : { + "main" : { "val" : 500 } + } + } + }, + "fireMagic" : { + "base" : { + "description" : "", + "effects" : { + "main" : { + "subtype" : "skill.fireMagic", + "type" : "SECONDARY_SKILL_PREMY", + "valueType" : "BASE_NUMBER" + } + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 1 } + } + }, + "advanced" : { + "effects" : { + "main" : { "val" : 2 } + } + }, + "expert" : { + "effects" : { + "main" : { "val" : 3 } + } + } + }, + "airMagic" : { + "base" : { + "description" : "", + "effects" : { + "main" : { + "subtype" : "skill.airMagic", + "type" : "SECONDARY_SKILL_PREMY", + "valueType" : "BASE_NUMBER" + } + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 1 } + } + }, + "advanced" : { + "effects" : { + "main" : { "val" : 2 } + } + }, + "expert" : { + "effects" : { + "main" : { "val" : 3 } + } + } + }, + "waterMagic" : { + "base" : { + "description" : "", + "effects" : { + "main" : { + "subtype" : "skill.waterMagic", + "type" : "SECONDARY_SKILL_PREMY", + "valueType" : "BASE_NUMBER" + } + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 1 } + } + }, + "advanced" : { + "effects" : { + "main" : { "val" : 2 } + } + }, + "expert" : { + "effects" : { + "main" : { "val" : 3 } + } + } + }, + "earthMagic" : { + "base" : { + "description" : "", + "effects" : { + "main" : { + "subtype" : "skill.earthMagic", + "type" : "SECONDARY_SKILL_PREMY", + "valueType" : "BASE_NUMBER" + } + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 1 } + } + }, + "advanced" : { + "effects" : { + "main" : { "val" : 2 } + } + }, + "expert" : { + "effects" : { + "main" : { "val" : 3 } + } + } + }, + "scholar" : { + "base" : { + "description" : "", + "effects" : { + "main" : { + "subtype" : "skill.scholar", + "type" : "SECONDARY_SKILL_PREMY", + "valueType" : "BASE_NUMBER" + } + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 2 } + } + }, + "advanced" : { + "effects" : { + "main" : { "val" : 3 } + } + }, + "expert" : { + "effects" : { + "main" : { "val" : 4 } + } + } + }, + "tactics" : { + "base" : { + "description" : "", + "effects" : { + "main" : { + "subtype" : "skill.tactics", + "type" : "SECONDARY_SKILL_PREMY", + "valueType" : "BASE_NUMBER" + } + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 3 } + } + }, + "advanced" : { + "effects" : { + "main" : { "val" : 5 } + } + }, + "expert" : { + "effects" : { + "main" : { "val" : 7 } + } + } + }, + "artillery" : { + "base" : { + "description" : "", + "effects" : { + "main" : { + "subtype" : "skill.artillery", + "type" : "SECONDARY_SKILL_PREMY", + "valueType" : "BASE_NUMBER" + }, + "val2" : { + "subtype" : "skill.artillery", + "type" : "SECONDARY_SKILL_VAL2", + "valueType" : "BASE_NUMBER" + }, + "ctrl" : { + "subtype" : "creature.ballista", + "type" : "MANUAL_CONTROL", + "val" : 100, + "valueType" : "BASE_NUMBER" + } + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 50 }, + "val2" : { "val" : 0 } + } + }, + "advanced" : { + "effects" : { + "main" : { "val" : 75 }, + "val2" : { "val" : 1 } + } + }, + "expert" : { + "effects" : { + "main" : { "val" : 100 }, + "val2" : { "val" : 1 } + } + } + }, + "learning" : { + "base" : { + "description" : "", + "effects" : { + "main" : { + "subtype" : "skill.learning", + "type" : "SECONDARY_SKILL_PREMY", + "valueType" : "BASE_NUMBER" + } + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 5 } + } + }, + "advanced" : { + "effects" : { + "main" : { "val" : 10 } + } + }, + "expert" : { + "effects" : { + "main" : { "val" : 15 } + } + } + }, + "offence" : { + "base" : { + "description" : "", + "effects" : { + "main" : { + "subtype" : "skill.offence", + "type" : "SECONDARY_SKILL_PREMY", + "valueType" : "BASE_NUMBER" + } + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 10 } + } + }, + "advanced" : { + "effects" : { + "main" : { "val" : 20 } + } + }, + "expert" : { + "effects" : { + "main" : { "val" : 30 } + } + } + }, + "armorer" : { + "base" : { + "description" : "", + "effects" : { + "main" : { + "subtype" : "skill.armorer", + "type" : "SECONDARY_SKILL_PREMY", + "valueType" : "BASE_NUMBER" + } + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 5 } + } + }, + "advanced" : { + "effects" : { + "main" : { "val" : 10 } + } + }, + "expert" : { + "effects" : { + "main" : { "val" : 15 } + } + } + }, + "intelligence" : { + "base" : { + "description" : "", + "effects" : { + "main" : { + "subtype" : "skill.intelligence", + "type" : "SECONDARY_SKILL_PREMY", + "valueType" : "BASE_NUMBER" + } + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 25 } + } + }, + "advanced" : { + "effects" : { + "main" : { "val" : 50 } + } + }, + "expert" : { + "effects" : { + "main" : { "val" : 100 } + } + } + }, + "sorcery" : { + "base" : { + "description" : "", + "effects" : { + "main" : { + "subtype" : "skill.sorcery", + "type" : "SECONDARY_SKILL_PREMY", + "valueType" : "BASE_NUMBER" + } + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 5 } + } + }, + "advanced" : { + "effects" : { + "main" : { "val" : 10 } + } + }, + "expert" : { + "effects" : { + "main" : { "val" : 15 } + } + } + }, + "resistance" : { + "base" : { + "description" : "", + "effects" : { + "main" : { + "subtype" : "skill.resistance", + "type" : "SECONDARY_SKILL_PREMY", + "valueType" : "BASE_NUMBER" + } + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 5 } + } + }, + "advanced" : { + "effects" : { + "main" : { "val" : 10 } + } + }, + "expert" : { + "effects" : { + "main" : { "val" : 20 } + } + } + }, + "firstAid" : { + "base" : { + "description" : "", + "effects" : { + "main" : { + "subtype" : "skill.firstAid", + "type" : "SECONDARY_SKILL_PREMY", + "valueType" : "BASE_NUMBER" + }, + "ctrl" : { + "subtype" : "creature.firstAidTent", + "type" : "MANUAL_CONTROL", + "val" : 100, + "valueType" : "BASE_NUMBER" + } + } + }, + "basic" : { + "effects" : { + "main" : { "val" : 50 } + } + }, + "advanced" : { + "effects" : { + "main" : { "val" : 75 } + } + }, + "expert" : { + "effects" : { + "main" : { "val" : 100 } + } + } + } } diff --git a/lib/CSkillHandler.cpp b/lib/CSkillHandler.cpp index a3234a231..cf86970a9 100644 --- a/lib/CSkillHandler.cpp +++ b/lib/CSkillHandler.cpp @@ -37,14 +37,14 @@ CSkill::LevelInfo::~LevelInfo() CSkill::CSkill(SecondarySkill id) : id(id) { - if(id == SecondarySkill::DEFAULT) - identifier = "default"; - else - identifier = NSecondarySkill::names[id]; - // init levels - LevelInfo emptyLevel; - for(int level = 1; level < NSecondarySkill::levels.size(); level++) - levels.push_back(emptyLevel); + if(id == SecondarySkill::DEFAULT) + identifier = "default"; + else + identifier = NSecondarySkill::names[id]; + // init levels + LevelInfo emptyLevel; + for(int level = 1; level < NSecondarySkill::levels.size(); level++) + levels.push_back(emptyLevel); } CSkill::~CSkill() @@ -53,42 +53,42 @@ CSkill::~CSkill() void CSkill::addNewBonus(const std::shared_ptr& b, int level) { - b->source = Bonus::SECONDARY_SKILL; + b->source = Bonus::SECONDARY_SKILL; b->sid = id; - b->duration = Bonus::PERMANENT; - b->description = identifier; - levels[level-1].effects.push_back(b); + b->duration = Bonus::PERMANENT; + b->description = identifier; + levels[level-1].effects.push_back(b); } void CSkill::setDescription(const std::string & desc, int level) { - levels[level-1].description = desc; + levels[level-1].description = desc; } const std::vector> & CSkill::getBonus(int level) const { - return levels[level-1].effects; + return levels[level-1].effects; } const std::string & CSkill::getDescription(int level) const { - return levels[level-1].description; + return levels[level-1].description; } DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const CSkill::LevelInfo &info) { - out << "(\"" << info.description << "\", ["; - for(int i=0; i < info.effects.size(); i++) - out << (i ? "," : "") << info.effects[i]->Description(); - return out << "])"; + out << "(\"" << info.description << "\", ["; + for(int i=0; i < info.effects.size(); i++) + out << (i ? "," : "") << info.effects[i]->Description(); + return out << "])"; } DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const CSkill &skill) { - out << "Skill(" << (int)skill.id << "," << skill.identifier << "): ["; - for(int i=0; i < skill.levels.size(); i++) - out << (i ? "," : "") << skill.levels[i]; - return out << "]"; + out << "Skill(" << (int)skill.id << "," << skill.identifier << "): ["; + for(int i=0; i < skill.levels.size(); i++) + out << (i ? "," : "") << skill.levels[i]; + return out << "]"; } std::string CSkill::toString() const @@ -101,14 +101,14 @@ std::string CSkill::toString() const ///CSkillHandler CSkillHandler::CSkillHandler() { - for(int id = 0; id < GameConstants::SKILL_QUANTITY; id++) - { - CSkill * skill = new CSkill(SecondarySkill(id)); - for(int level = 1; level < NSecondarySkill::levels.size(); level++) + for(int id = 0; id < GameConstants::SKILL_QUANTITY; id++) + { + CSkill * skill = new CSkill(SecondarySkill(id)); + for(int level = 1; level < NSecondarySkill::levels.size(); level++) for (auto bonus : defaultBonus(SecondarySkill(id), level)) skill->addNewBonus(bonus, level); - objects.push_back(skill); - } + objects.push_back(skill); + } } std::vector CSkillHandler::loadLegacyData(size_t dataSize) @@ -141,42 +141,42 @@ const std::string CSkillHandler::getTypeName() const CSkill * CSkillHandler::loadFromJson(const JsonNode & json, const std::string & identifier) { - CSkill * skill = NULL; + CSkill * skill = NULL; - for(int id = 0; id < GameConstants::SKILL_QUANTITY; id++) - { - if(NSecondarySkill::names[id].compare(identifier) == 0) - { - skill = new CSkill(SecondarySkill(id)); - break; - } - } + for(int id = 0; id < GameConstants::SKILL_QUANTITY; id++) + { + if(NSecondarySkill::names[id].compare(identifier) == 0) + { + skill = new CSkill(SecondarySkill(id)); + break; + } + } - if(!skill) - { - logGlobal->error("unknown secondary skill %s", identifier); - throw std::runtime_error("invalid skill"); - } + if(!skill) + { + logGlobal->error("unknown secondary skill %s", identifier); + throw std::runtime_error("invalid skill"); + } - for(int level = 1; level < NSecondarySkill::levels.size(); level++) - { - const std::string & levelName = NSecondarySkill::levels[level]; // basic, advanced, expert - const JsonNode & levelNode = json[levelName]; - // parse bonus effects + for(int level = 1; level < NSecondarySkill::levels.size(); level++) + { + const std::string & levelName = NSecondarySkill::levels[level]; // basic, advanced, expert + const JsonNode & levelNode = json[levelName]; + // parse bonus effects for(auto b : levelNode["effects"].Struct()) - { + { auto bonus = JsonUtils::parseBonus(b.second); - bonus->sid = skill->id; - skill->addNewBonus(bonus, level); - } - // parse skill description - tracked separately - if(vstd::contains(levelNode.Struct(), "description") && !levelNode["description"].isNull()) - skill->setDescription(levelNode["description"].String(), level); - } - logMod->debug("loaded secondary skill %s(%d)", identifier, (int)skill->id); - logMod->trace("%s", skill->toString()); + bonus->sid = skill->id; + skill->addNewBonus(bonus, level); + } + // parse skill description - tracked separately + if(vstd::contains(levelNode.Struct(), "description") && !levelNode["description"].isNull()) + skill->setDescription(levelNode["description"].String(), level); + } + logMod->debug("loaded secondary skill %s(%d)", identifier, (int)skill->id); + logMod->trace("%s", skill->toString()); - return skill; + return skill; } void CSkillHandler::loadObject(std::string scope, std::string name, const JsonNode & data) @@ -231,8 +231,8 @@ CSkillHandler::~CSkillHandler() std::vector CSkillHandler::getDefaultAllowed() const { - std::vector allowedSkills(objects.size(), true); - return allowedSkills; + std::vector allowedSkills(objects.size(), true); + return allowedSkills; } // HMM3 default bonus provided by secondary skill diff --git a/lib/CSkillHandler.h b/lib/CSkillHandler.h index 108e356e2..56f448bb7 100644 --- a/lib/CSkillHandler.h +++ b/lib/CSkillHandler.h @@ -38,51 +38,51 @@ protected: std::vector levels; // bonuses provided by basic, advanced and expert level public: - CSkill(SecondarySkill id = SecondarySkill::DEFAULT); - ~CSkill(); + CSkill(SecondarySkill id = SecondarySkill::DEFAULT); + ~CSkill(); - void addNewBonus(const std::shared_ptr& b, int level); - void setDescription(const std::string & desc, int level); - const std::vector> & getBonus(int level) const; - const std::string & getDescription(int level) const; - std::string toString() const; + void addNewBonus(const std::shared_ptr& b, int level); + void setDescription(const std::string & desc, int level); + const std::vector> & getBonus(int level) const; + const std::string & getDescription(int level) const; + std::string toString() const; - SecondarySkill id; - std::string identifier; + SecondarySkill id; + std::string identifier; - template void serialize(Handler &h, const int version) - { - h & id & identifier; - h & levels; - } + template void serialize(Handler &h, const int version) + { + h & id & identifier; + h & levels; + } - friend class CSkillHandler; - friend std::ostream & operator<<(std::ostream &out, const CSkill &skill); - friend std::ostream & operator<<(std::ostream &out, const CSkill::LevelInfo &info); + friend class CSkillHandler; + friend std::ostream & operator<<(std::ostream &out, const CSkill &skill); + friend std::ostream & operator<<(std::ostream &out, const CSkill::LevelInfo &info); }; class DLL_LINKAGE CSkillHandler: public CHandlerBase { public: - CSkillHandler(); - virtual ~CSkillHandler(); + CSkillHandler(); + virtual ~CSkillHandler(); - ///IHandler base - std::vector loadLegacyData(size_t dataSize) override; - void afterLoadFinalization() override; - void beforeValidate(JsonNode & object) override; + ///IHandler base + std::vector loadLegacyData(size_t dataSize) override; + void afterLoadFinalization() override; + void beforeValidate(JsonNode & object) override; - std::vector getDefaultAllowed() const override; - const std::string getTypeName() const override; - void loadObject(std::string scope, std::string name, const JsonNode & data) override; - void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override; + std::vector getDefaultAllowed() const override; + const std::string getTypeName() const override; + void loadObject(std::string scope, std::string name, const JsonNode & data) override; + void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override; - template void serialize(Handler &h, const int version) - { - h & objects ; - } + template void serialize(Handler &h, const int version) + { + h & objects ; + } protected: - CSkill * loadFromJson(const JsonNode & json, const std::string & identifier) override; + CSkill * loadFromJson(const JsonNode & json, const std::string & identifier) override; std::vector> defaultBonus(SecondarySkill skill, int level) const; }; From 654ca96e9d3ad31f769492351cb7a8f2cb5476cd Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Wed, 30 Aug 2017 19:19:54 +1200 Subject: [PATCH 41/68] fixed code format and other minor issues --- lib/CMakeLists.txt | 3 +- lib/CSkillHandler.cpp | 73 ++++++++++++++++++---------- lib/CSkillHandler.h | 25 +++++----- lib/filesystem/CFilesystemLoader.cpp | 2 +- server/CGameHandler.cpp | 2 +- 5 files changed, 62 insertions(+), 43 deletions(-) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index c1f2dc53a..382f081bb 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -115,7 +115,7 @@ set(lib_SRCS CModHandler.cpp CPathfinder.cpp CRandomGenerator.cpp - CSkillHandler.cpp + CSkillHandler.cpp CStack.cpp CThreadHelper.cpp CTownHandler.cpp @@ -257,6 +257,7 @@ set(lib_HEADERS CPlayerState.h CRandomGenerator.h CScriptingModule.h + CSkillHandler.h CSoundBase.h CStack.h CStopWatch.h diff --git a/lib/CSkillHandler.cpp b/lib/CSkillHandler.cpp index cf86970a9..858f18c20 100644 --- a/lib/CSkillHandler.cpp +++ b/lib/CSkillHandler.cpp @@ -51,7 +51,7 @@ CSkill::~CSkill() { } -void CSkill::addNewBonus(const std::shared_ptr& b, int level) +void CSkill::addNewBonus(const std::shared_ptr & b, int level) { b->source = Bonus::SECONDARY_SKILL; b->sid = id; @@ -75,7 +75,7 @@ const std::string & CSkill::getDescription(int level) const return levels[level-1].description; } -DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const CSkill::LevelInfo &info) +DLL_LINKAGE std::ostream & operator<<(std::ostream & out, const CSkill::LevelInfo & info) { out << "(\"" << info.description << "\", ["; for(int i=0; i < info.effects.size(); i++) @@ -83,7 +83,7 @@ DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const CSkill::LevelInfo return out << "])"; } -DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const CSkill &skill) +DLL_LINKAGE std::ostream & operator<<(std::ostream & out, const CSkill & skill) { out << "Skill(" << (int)skill.id << "," << skill.identifier << "): ["; for(int i=0; i < skill.levels.size(); i++) @@ -141,7 +141,7 @@ const std::string CSkillHandler::getTypeName() const CSkill * CSkillHandler::loadFromJson(const JsonNode & json, const std::string & identifier) { - CSkill * skill = NULL; + CSkill * skill = nullptr; for(int id = 0; id < GameConstants::SKILL_QUANTITY; id++) { @@ -203,7 +203,7 @@ void CSkillHandler::loadObject(std::string scope, std::string name, const JsonNo assert(object->id == index); objects[index] = object; - registerObject(scope,type_name, name, object->id); + registerObject(scope, type_name, name, object->id); } @@ -251,22 +251,30 @@ std::vector> CSkillHandler::defaultBonus(SecondarySkill s switch(skill) { case SecondarySkill::PATHFINDING: - addBonus(25 * level); break; + addBonus(25 * level); + break; case SecondarySkill::ARCHERY: - addBonus(5 + 5 * level * level); break; + addBonus(5 + 5 * level * level); + break; case SecondarySkill::LOGISTICS: - addBonus(10 * level); break; + addBonus(10 * level); + break; case SecondarySkill::SCOUTING: - addBonus(level, Bonus::SIGHT_RADIOUS); break; + addBonus(level, Bonus::SIGHT_RADIOUS); + break; case SecondarySkill::DIPLOMACY: addBonus(level); - addBonus(20 * level, Bonus::SURRENDER_DISCOUNT); break; + addBonus(20 * level, Bonus::SURRENDER_DISCOUNT); + break; case SecondarySkill::NAVIGATION: - addBonus(50 * level); break; + addBonus(50 * level); + break; case SecondarySkill::LEADERSHIP: - addBonus(level, Bonus::MORALE); break; + addBonus(level, Bonus::MORALE); + break; case SecondarySkill::LUCK: - addBonus(level, Bonus::LUCK); break; + addBonus(level, Bonus::LUCK); + break; case SecondarySkill::BALLISTICS: addBonus(100, Bonus::MANUAL_CONTROL, CreatureID::CATAPULT); addBonus(level); @@ -276,18 +284,23 @@ std::vector> CSkillHandler::defaultBonus(SecondarySkill s addBonus(1 + level, Bonus::SECONDARY_SKILL_VAL2); break; case SecondarySkill::NECROMANCY: - addBonus(10 * level); break; + addBonus(10 * level); + break; case SecondarySkill::ESTATES: - addBonus(125 << (level-1)); break; + addBonus(125 << (level-1)); + break; case SecondarySkill::FIRE_MAGIC: case SecondarySkill::AIR_MAGIC: case SecondarySkill::WATER_MAGIC: case SecondarySkill::EARTH_MAGIC: - addBonus(level); break; + addBonus(level); + break; case SecondarySkill::SCHOLAR: - addBonus(1 + level); break; + addBonus(1 + level); + break; case SecondarySkill::TACTICS: - addBonus(1 + 2 * level); break; + addBonus(1 + 2 * level); + break; case SecondarySkill::ARTILLERY: addBonus(100, Bonus::MANUAL_CONTROL, CreatureID::BALLISTA); addBonus(25 + 25 * level); @@ -295,22 +308,30 @@ std::vector> CSkillHandler::defaultBonus(SecondarySkill s addBonus(1, Bonus::SECONDARY_SKILL_VAL2); break; case SecondarySkill::LEARNING: - addBonus(5 * level); break; + addBonus(5 * level); + break; case SecondarySkill::OFFENCE: - addBonus(10 * level); break; + addBonus(10 * level); + break; case SecondarySkill::ARMORER: - addBonus(5 * level); break; + addBonus(5 * level); + break; case SecondarySkill::INTELLIGENCE: - addBonus(25 << (level-1)); break; + addBonus(25 << (level-1)); + break; case SecondarySkill::SORCERY: - addBonus(5 * level); break; + addBonus(5 * level); + break; case SecondarySkill::RESISTANCE: - addBonus(5 << (level-1)); break; + addBonus(5 << (level-1)); + break; case SecondarySkill::FIRST_AID: addBonus(100, Bonus::MANUAL_CONTROL, CreatureID::FIRST_AID_TENT); - addBonus(25 + 25 * level); break; + addBonus(25 + 25 * level); + break; default: - addBonus(level); break; + addBonus(level); + break; } return result; diff --git a/lib/CSkillHandler.h b/lib/CSkillHandler.h index 56f448bb7..92b7b5c82 100644 --- a/lib/CSkillHandler.h +++ b/lib/CSkillHandler.h @@ -13,11 +13,6 @@ #include "GameConstants.h" #include "IHandlerBase.h" -class CSkillHandler; -class CGHeroInstance; -class CMap; -class JsonSerializeFormat; - class DLL_LINKAGE CSkill // secondary skill { protected: @@ -29,9 +24,10 @@ protected: LevelInfo(); ~LevelInfo(); - template void serialize(Handler &h, const int version) + template void serialize(Handler & h, const int version) { - h & description & effects; + h & description; + h & effects; } }; @@ -41,7 +37,7 @@ public: CSkill(SecondarySkill id = SecondarySkill::DEFAULT); ~CSkill(); - void addNewBonus(const std::shared_ptr& b, int level); + void addNewBonus(const std::shared_ptr & b, int level); void setDescription(const std::string & desc, int level); const std::vector> & getBonus(int level) const; const std::string & getDescription(int level) const; @@ -50,15 +46,16 @@ public: SecondarySkill id; std::string identifier; - template void serialize(Handler &h, const int version) + template void serialize(Handler & h, const int version) { - h & id & identifier; + h & id; + h & identifier; h & levels; } friend class CSkillHandler; - friend std::ostream & operator<<(std::ostream &out, const CSkill &skill); - friend std::ostream & operator<<(std::ostream &out, const CSkill::LevelInfo &info); + friend std::ostream & operator<<(std::ostream & out, const CSkill & skill); + friend std::ostream & operator<<(std::ostream & out, const CSkill::LevelInfo & info); }; class DLL_LINKAGE CSkillHandler: public CHandlerBase @@ -77,9 +74,9 @@ public: void loadObject(std::string scope, std::string name, const JsonNode & data) override; void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override; - template void serialize(Handler &h, const int version) + template void serialize(Handler & h, const int version) { - h & objects ; + h & objects; } protected: diff --git a/lib/filesystem/CFilesystemLoader.cpp b/lib/filesystem/CFilesystemLoader.cpp index 78b82b38c..0585c761b 100644 --- a/lib/filesystem/CFilesystemLoader.cpp +++ b/lib/filesystem/CFilesystemLoader.cpp @@ -26,7 +26,7 @@ CFilesystemLoader::CFilesystemLoader(std::string _mountPoint, bfs::path baseDire std::unique_ptr CFilesystemLoader::load(const ResourceID & resourceName) const { assert(fileList.count(resourceName)); - boost::filesystem::path file = baseDirectory / fileList.at(resourceName); + bfs::path file = baseDirectory / fileList.at(resourceName); logGlobal->trace("loading %s", file.string()); return make_unique(file); } diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 71882b5b7..2dfaacd75 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -2489,7 +2489,7 @@ void CGameHandler::useScholarSkill(ObjectInstanceID fromHero, ObjectInstanceID t const CGHeroInstance * h1 = getHero(fromHero); const CGHeroInstance * h2 = getHero(toHero); int h1_scholarLevel = h1->valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::SCHOLAR); - int h2_scholarLevel = h1->valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::SCHOLAR); + int h2_scholarLevel = h2->valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::SCHOLAR); if (h1_scholarLevel < h2_scholarLevel) { From 3764ec8be171d451d49dfa8658b046cc156536d3 Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Wed, 30 Aug 2017 19:47:06 +1200 Subject: [PATCH 42/68] more code format issues --- lib/CSkillHandler.cpp | 2 +- lib/GameConstants.cpp | 2 +- lib/GameConstants.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/CSkillHandler.cpp b/lib/CSkillHandler.cpp index 858f18c20..5e936379a 100644 --- a/lib/CSkillHandler.cpp +++ b/lib/CSkillHandler.cpp @@ -241,7 +241,7 @@ std::vector> CSkillHandler::defaultBonus(SecondarySkill s std::vector> result; // add bonus based on current values - useful for adding multiple bonuses easily - auto addBonus = [=,&result](int bonusVal, Bonus::BonusType bonusType = Bonus::SECONDARY_SKILL_PREMY, int subtype = 0) + auto addBonus = [=, &result](int bonusVal, Bonus::BonusType bonusType = Bonus::SECONDARY_SKILL_PREMY, int subtype = 0) { if(bonusType == Bonus::SECONDARY_SKILL_PREMY || bonusType == Bonus::SECONDARY_SKILL_VAL2) subtype = skill; diff --git a/lib/GameConstants.cpp b/lib/GameConstants.cpp index 7da3b4906..5fa5b70ce 100644 --- a/lib/GameConstants.cpp +++ b/lib/GameConstants.cpp @@ -68,7 +68,7 @@ const CSpell * SpellID::toSpell() const const CSkill * SecondarySkill::toSkill() const { - return VLC->skillh->objects.at(*this); + return VLC->skillh->objects.at(*this); } //template std::ostream & operator << (std::ostream & os, BaseForID id); diff --git a/lib/GameConstants.h b/lib/GameConstants.h index 4cce159ea..8d76f3724 100644 --- a/lib/GameConstants.h +++ b/lib/GameConstants.h @@ -321,7 +321,7 @@ public: SecondarySkill(ESecondarySkill _num = WRONG) : num(_num) {} - DLL_LINKAGE const CSkill * toSkill() const; + DLL_LINKAGE const CSkill * toSkill() const; ID_LIKE_CLASS_COMMON(SecondarySkill, ESecondarySkill) From dba5186a6fc8fee4e5d3a5c29d6cca9cbf94e034 Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Wed, 30 Aug 2017 20:01:09 +1200 Subject: [PATCH 43/68] fixed skill schema definition --- config/schemas/skill.json | 37 +++++++++++++++++++------------------ lib/CSkillHandler.cpp | 1 - 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/config/schemas/skill.json b/config/schemas/skill.json index fdee8aa1e..1997fb11b 100644 --- a/config/schemas/skill.json +++ b/config/schemas/skill.json @@ -24,25 +24,26 @@ } } } + } + + }, + + "required" : ["basic", "advanced", "expert"], + + "properties" : { + "base" : { + "type" : "object", + "description" : "will be merged with all levels", + "additionalProperties" : true }, - - "required" : ["basic", "advanced", "expert"], - - "properties" : { - "base" : { - "type" : "object", - "description" : "will be merged with all levels", - "additionalProperties" : true - }, - "basic" : { - "$ref" : "#/definitions/skillBonus" - }, - "advanced" : { - "$ref" : "#/definitions/skillBonus" - }, - "expert" : { - "$ref" : "#/definitions/skillBonus" - } + "basic" : { + "$ref" : "#/definitions/skillBonus" + }, + "advanced" : { + "$ref" : "#/definitions/skillBonus" + }, + "expert" : { + "$ref" : "#/definitions/skillBonus" } } } diff --git a/lib/CSkillHandler.cpp b/lib/CSkillHandler.cpp index 5e936379a..bb09350b7 100644 --- a/lib/CSkillHandler.cpp +++ b/lib/CSkillHandler.cpp @@ -206,7 +206,6 @@ void CSkillHandler::loadObject(std::string scope, std::string name, const JsonNo registerObject(scope, type_name, name, object->id); } - void CSkillHandler::afterLoadFinalization() { } From abdca71828caf57c78faec283b79be28eeda28fd Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Wed, 30 Aug 2017 22:35:23 +1200 Subject: [PATCH 44/68] skill names and descriptions are fully managed by CSkillHandler --- client/CGameInfo.cpp | 8 ------ client/CGameInfo.h | 1 - client/CPreGame.cpp | 3 +- client/widgets/CComponent.cpp | 5 ++-- client/windows/CHeroWindow.cpp | 7 +++-- client/windows/CKingdomInterface.cpp | 7 +++-- client/windows/GUIClasses.cpp | 19 ++++++------ config/skills.json | 27 ----------------- lib/CGameState.cpp | 8 ++++-- lib/CGeneralTextHandler.cpp | 17 ----------- lib/CGeneralTextHandler.h | 2 -- lib/CSkillHandler.cpp | 43 ++++++++++++++++++++++++---- lib/CSkillHandler.h | 5 ++++ lib/HeroBonus.cpp | 3 +- lib/mapObjects/MiscObjects.cpp | 3 +- 15 files changed, 74 insertions(+), 84 deletions(-) diff --git a/client/CGameInfo.cpp b/client/CGameInfo.cpp index f184ac143..ea58466fd 100644 --- a/client/CGameInfo.cpp +++ b/client/CGameInfo.cpp @@ -37,11 +37,3 @@ void CGameInfo::setFromLib() skillh = VLC->skillh; objtypeh = VLC->objtypeh; } - -const std::string & CGameInfo::skillInfo(int skill, int level) const -{ - const std::string & desc = (*skillh)[SecondarySkill(skill)]->getDescription(level); - if(desc.size() > 0) - return desc; - return generaltexth->skillInfoTexts[skill][level-1]; -} diff --git a/client/CGameInfo.h b/client/CGameInfo.h index fafcbff57..c1c37b500 100644 --- a/client/CGameInfo.h +++ b/client/CGameInfo.h @@ -68,6 +68,5 @@ public: friend class CClient; CGameInfo(); - const std::string & skillInfo(int skill, int level) const; }; extern const CGameInfo* CGI; diff --git a/client/CPreGame.cpp b/client/CPreGame.cpp index 96f67de71..66887893a 100644 --- a/client/CPreGame.cpp +++ b/client/CPreGame.cpp @@ -18,6 +18,7 @@ #include "CGameInfo.h" #include "gui/CCursorHandler.h" #include "../lib/CGeneralTextHandler.h" +#include "../lib/CSkillHandler.h" #include "../lib/CTownHandler.h" #include "../lib/CHeroHandler.h" #include "../lib/mapping/CCampaignHandler.h" @@ -3624,7 +3625,7 @@ void CBonusSelection::updateBonusSelection() desc = CGI->generaltexth->allTexts[718]; boost::algorithm::replace_first(desc, "%s", CGI->generaltexth->levels[bonDescs[i].info3 - 1]); //skill level - boost::algorithm::replace_first(desc, "%s", CGI->generaltexth->skillName[bonDescs[i].info2]); //skill name + boost::algorithm::replace_first(desc, "%s", CGI->skillh->skillName(bonDescs[i].info2)); //skill name picNumber = bonDescs[i].info2 * 3 + bonDescs[i].info3 - 1; break; diff --git a/client/widgets/CComponent.cpp b/client/widgets/CComponent.cpp index f85c0087e..9e0d04ad0 100644 --- a/client/widgets/CComponent.cpp +++ b/client/widgets/CComponent.cpp @@ -22,6 +22,7 @@ #include "../../lib/CArtHandler.h" #include "../../lib/CTownHandler.h" #include "../../lib/CCreatureHandler.h" +#include "../../lib/CSkillHandler.h" #include "../../lib/spells/CSpellHandler.h" #include "../../lib/CGeneralTextHandler.h" #include "../../lib/NetPacksBase.h" @@ -148,7 +149,7 @@ std::string CComponent::getDescription() { case primskill: return (subtype < 4)? CGI->generaltexth->arraytxt[2+subtype] //Primary skill : CGI->generaltexth->allTexts[149]; //mana - case secskill: return CGI->skillInfo(subtype,val); + case secskill: return CGI->skillh->skillInfo(subtype, val); case resource: return CGI->generaltexth->allTexts[242]; case creature: return ""; case artifact: @@ -192,7 +193,7 @@ std::string CComponent::getSubtitleInternal() switch(compType) { case primskill: return boost::str(boost::format("%+d %s") % val % (subtype < 4 ? CGI->generaltexth->primarySkillNames[subtype] : CGI->generaltexth->allTexts[387])); - case secskill: return CGI->generaltexth->levels[val-1] + "\n" + CGI->generaltexth->skillName[subtype]; + case secskill: return CGI->generaltexth->levels[val-1] + "\n" + CGI->skillh->skillName(subtype); case resource: return boost::lexical_cast(val); case creature: return (val? boost::lexical_cast(val) + " " : "") + CGI->creh->creatures[subtype]->*(val != 1 ? &CCreature::namePl : &CCreature::nameSing); case artifact: return CGI->arth->artifacts[subtype]->Name(); diff --git a/client/windows/CHeroWindow.cpp b/client/windows/CHeroWindow.cpp index 9f3425a7e..a7f69fdc6 100644 --- a/client/windows/CHeroWindow.cpp +++ b/client/windows/CHeroWindow.cpp @@ -33,6 +33,7 @@ #include "../lib/CConfigHandler.h" #include "../lib/CGeneralTextHandler.h" #include "../lib/CHeroHandler.h" +#include "../lib/CSkillHandler.h" #include "../lib/mapObjects/CGHeroInstance.h" #include "../lib/NetPacksBase.h" #include "../mapHandler.h" @@ -240,8 +241,8 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded) level = curHero->getSecSkillLevel(SecondarySkill(curHero->secSkills[g].first)); secSkillAreas[g]->type = skill; secSkillAreas[g]->bonusValue = level; - secSkillAreas[g]->text = CGI->skillInfo(skill,level); - secSkillAreas[g]->hoverText = boost::str(boost::format(heroscrn[21]) % CGI->generaltexth->levels[level-1] % CGI->generaltexth->skillName[skill]); + secSkillAreas[g]->text = CGI->skillh->skillInfo(skill, level); + secSkillAreas[g]->hoverText = boost::str(boost::format(heroscrn[21]) % CGI->generaltexth->levels[level-1] % CGI->skillh->skillName(skill)); secSkillImages[g]->setFrame(skill*3 + level + 2); } @@ -372,7 +373,7 @@ void CHeroWindow::showAll(SDL_Surface * to) for(size_t v=0; vsecSkills.size()); ++v) { printAtLoc(CGI->generaltexth->levels[curHero->secSkills[v].second-1], (v%2) ? 212 : 68, 280 + 48 * (v/2), FONT_SMALL, Colors::WHITE, to); - printAtLoc(CGI->generaltexth->skillName[curHero->secSkills[v].first], (v%2) ? 212 : 68, 300 + 48 * (v/2), FONT_SMALL, Colors::WHITE, to); + printAtLoc(CGI->skillh->skillName(curHero->secSkills[v].first), (v%2) ? 212 : 68, 300 + 48 * (v/2), FONT_SMALL, Colors::WHITE, to); } //printing special ability diff --git a/client/windows/CKingdomInterface.cpp b/client/windows/CKingdomInterface.cpp index b753b8f76..cf13b17a0 100644 --- a/client/windows/CKingdomInterface.cpp +++ b/client/windows/CKingdomInterface.cpp @@ -28,6 +28,7 @@ #include "../../lib/CGeneralTextHandler.h" #include "../../lib/CHeroHandler.h" #include "../../lib/CModHandler.h" +#include "../../lib/CSkillHandler.h" #include "../../lib/CTownHandler.h" #include "../../lib/mapObjects/CGHeroInstance.h" #include "../../lib/mapObjects/CGTownInstance.h" @@ -170,7 +171,7 @@ std::string InfoBoxAbstractHeroData::getNameText() return CGI->heroh->heroes[getSubID()]->specName; case HERO_SECONDARY_SKILL: if (getValue()) - return CGI->generaltexth->skillName[getSubID()]; + return CGI->skillh->skillName(getSubID()); else return ""; default: @@ -281,7 +282,7 @@ bool InfoBoxAbstractHeroData::prepareMessage(std::string &text, CComponent **com if (!value) return false; - text = CGI->skillInfo(subID,value); + text = CGI->skillh->skillInfo(subID, value); *comp = new CComponent(CComponent::secskill, subID, value); return true; } @@ -356,7 +357,7 @@ std::string InfoBoxHeroData::getHoverText() if (hero->secSkills.size() > index) { std::string level = CGI->generaltexth->levels[hero->secSkills[index].second-1]; - std::string skill = CGI->generaltexth->skillName[hero->secSkills[index].first]; + std::string skill = CGI->skillh->skillName(hero->secSkills[index].first); return boost::str(boost::format(CGI->generaltexth->heroscrn[21]) % level % skill); } else diff --git a/client/windows/GUIClasses.cpp b/client/windows/GUIClasses.cpp index b23929628..727e21c17 100644 --- a/client/windows/GUIClasses.cpp +++ b/client/windows/GUIClasses.cpp @@ -49,6 +49,7 @@ #include "../lib/CHeroHandler.h" #include "../lib/CModHandler.h" #include "../lib/CondSh.h" +#include "../lib/CSkillHandler.h" #include "../lib/spells/CSpellHandler.h" #include "../lib/CStopWatch.h" #include "../lib/CTownHandler.h" @@ -944,11 +945,11 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2, secSkillAreas[b][g]->type = skill; secSkillAreas[b][g]->bonusValue = level; - secSkillAreas[b][g]->text = CGI->skillInfo(skill,level); + secSkillAreas[b][g]->text = CGI->skillh->skillInfo(skill, level); secSkillAreas[b][g]->hoverText = CGI->generaltexth->heroscrn[21]; boost::algorithm::replace_first(secSkillAreas[b][g]->hoverText, "%s", CGI->generaltexth->levels[level - 1]); - boost::algorithm::replace_first(secSkillAreas[b][g]->hoverText, "%s", CGI->generaltexth->skillName[skill]); + boost::algorithm::replace_first(secSkillAreas[b][g]->hoverText, "%s", CGI->skillh->skillName(skill)); } portrait[b] = new CHeroArea(257 + 228*b, 13, heroInst[b]); @@ -1222,7 +1223,7 @@ void CUniversityWindow::CItem::clickRight(tribool down, bool previousState) { if(down) { - CRClickPopup::createAndPush(CGI->skillInfo(ID, 1), + CRClickPopup::createAndPush(CGI->skillh->skillInfo(ID, 1), new CComponent(CComponent::secskill, ID, 1)); } } @@ -1230,7 +1231,7 @@ void CUniversityWindow::CItem::clickRight(tribool down, bool previousState) void CUniversityWindow::CItem::hover(bool on) { if (on) - GH.statusbar->setText(CGI->generaltexth->skillName[ID]); + GH.statusbar->setText(CGI->skillh->skillName(ID)); else GH.statusbar->clear(); } @@ -1264,7 +1265,7 @@ void CUniversityWindow::CItem::showAll(SDL_Surface * to) blitAtLoc(bar->bg, -28, -22, to); blitAtLoc(bar->bg, -28, 48, to); - printAtMiddleLoc (CGI->generaltexth->skillName[ID], 22, -13, FONT_SMALL, Colors::WHITE,to);//Name + printAtMiddleLoc (CGI->skillh->skillName(ID), 22, -13, FONT_SMALL, Colors::WHITE,to);//Name printAtMiddleLoc (CGI->generaltexth->levels[0], 22, 57, FONT_SMALL, Colors::WHITE,to);//Level(always basic) CAnimImage::showAll(to); @@ -1328,12 +1329,12 @@ CUnivConfirmWindow::CUnivConfirmWindow(CUniversityWindow * PARENT, int SKILL, bo std::string text = CGI->generaltexth->allTexts[608]; boost::replace_first(text, "%s", CGI->generaltexth->levels[0]); - boost::replace_first(text, "%s", CGI->generaltexth->skillName[SKILL]); + boost::replace_first(text, "%s", CGI->skillh->skillName(SKILL)); boost::replace_first(text, "%d", "2000"); new CTextBox(text, Rect(24, 129, 413, 70), 0, FONT_SMALL, CENTER, Colors::WHITE);//Clerk speech - new CLabel(230, 37, FONT_SMALL, CENTER, Colors::WHITE, CGI->generaltexth-> skillName[SKILL]);//Skill name + new CLabel(230, 37, FONT_SMALL, CENTER, Colors::WHITE, CGI->skillh->skillName(SKILL));//Skill name new CAnimImage("SECSKILL", SKILL*3+3, 0, 211, 51);//skill new CLabel(230, 107, FONT_SMALL, CENTER, Colors::WHITE, CGI->generaltexth->levels[1]);//Skill level @@ -1341,11 +1342,11 @@ CUnivConfirmWindow::CUnivConfirmWindow(CUniversityWindow * PARENT, int SKILL, bo new CLabel(230, 267, FONT_SMALL, CENTER, Colors::WHITE, "2000");//Cost std::string hoverText = CGI->generaltexth->allTexts[609]; - boost::replace_first(hoverText, "%s", CGI->generaltexth->levels[0]+ " " + CGI->generaltexth->skillName[SKILL]); + boost::replace_first(hoverText, "%s", CGI->generaltexth->levels[0]+ " " + CGI->skillh->skillName(SKILL)); text = CGI->generaltexth->zelp[633].second; boost::replace_first(text, "%s", CGI->generaltexth->levels[0]); - boost::replace_first(text, "%s", CGI->generaltexth->skillName[SKILL]); + boost::replace_first(text, "%s", CGI->skillh->skillName(SKILL)); boost::replace_first(text, "%d", "2000"); confirm= new CButton(Point(148, 299), "IBY6432.DEF", CButton::tooltip(hoverText, text), [=](){makeDeal(SKILL);}, SDLK_RETURN); diff --git a/config/skills.json b/config/skills.json index cd8c67301..bb5a84b2d 100644 --- a/config/skills.json +++ b/config/skills.json @@ -1,7 +1,6 @@ { "pathfinding" : { "base" : { - "description" : "", "effects" : { "main" : { "subtype" : "skill.pathfinding", @@ -28,7 +27,6 @@ }, "archery" : { "base" : { - "description" : "", "effects" : { "main" : { "subtype" : "skill.archery", @@ -55,7 +53,6 @@ }, "logistics" : { "base" : { - "description" : "", "effects" : { "main" : { "subtype" : "skill.logistics", @@ -82,7 +79,6 @@ }, "scouting" : { "base" : { - "description" : "", "effects" : { "main" : { "type" : "SIGHT_RADIOUS", @@ -108,7 +104,6 @@ }, "diplomacy" : { "base" : { - "description" : "", "effects" : { "main" : { "subtype" : "skill.diplomacy", @@ -143,7 +138,6 @@ }, "navigation" : { "base" : { - "description" : "", "effects" : { "main" : { "subtype" : "skill.navigation", @@ -170,7 +164,6 @@ }, "leadership" : { "base" : { - "description" : "", "effects" : { "main" : { "type" : "MORALE", @@ -196,7 +189,6 @@ }, "wisdom" : { "base" : { - "description" : "", "effects" : { "main" : { "subtype" : "skill.wisdom", @@ -223,7 +215,6 @@ }, "mysticism" : { "base" : { - "description" : "", "effects" : { "main" : { "type" : "MANA_REGENERATION", @@ -249,7 +240,6 @@ }, "luck" : { "base" : { - "description" : "", "effects" : { "main" : { "type" : "LUCK", @@ -275,7 +265,6 @@ }, "ballistics" : { "base" : { - "description" : "", "effects" : { "main" : { "subtype" : "skill.ballistics", @@ -308,7 +297,6 @@ }, "eagleEye" : { "base" : { - "description" : "", "effects" : { "main" : { "subtype" : "skill.eagleEye", @@ -343,7 +331,6 @@ }, "necromancy" : { "base" : { - "description" : "", "effects" : { "main" : { "subtype" : "skill.necromancy", @@ -399,7 +386,6 @@ }, "fireMagic" : { "base" : { - "description" : "", "effects" : { "main" : { "subtype" : "skill.fireMagic", @@ -426,7 +412,6 @@ }, "airMagic" : { "base" : { - "description" : "", "effects" : { "main" : { "subtype" : "skill.airMagic", @@ -453,7 +438,6 @@ }, "waterMagic" : { "base" : { - "description" : "", "effects" : { "main" : { "subtype" : "skill.waterMagic", @@ -480,7 +464,6 @@ }, "earthMagic" : { "base" : { - "description" : "", "effects" : { "main" : { "subtype" : "skill.earthMagic", @@ -507,7 +490,6 @@ }, "scholar" : { "base" : { - "description" : "", "effects" : { "main" : { "subtype" : "skill.scholar", @@ -534,7 +516,6 @@ }, "tactics" : { "base" : { - "description" : "", "effects" : { "main" : { "subtype" : "skill.tactics", @@ -561,7 +542,6 @@ }, "artillery" : { "base" : { - "description" : "", "effects" : { "main" : { "subtype" : "skill.artillery", @@ -602,7 +582,6 @@ }, "learning" : { "base" : { - "description" : "", "effects" : { "main" : { "subtype" : "skill.learning", @@ -629,7 +608,6 @@ }, "offence" : { "base" : { - "description" : "", "effects" : { "main" : { "subtype" : "skill.offence", @@ -656,7 +634,6 @@ }, "armorer" : { "base" : { - "description" : "", "effects" : { "main" : { "subtype" : "skill.armorer", @@ -683,7 +660,6 @@ }, "intelligence" : { "base" : { - "description" : "", "effects" : { "main" : { "subtype" : "skill.intelligence", @@ -710,7 +686,6 @@ }, "sorcery" : { "base" : { - "description" : "", "effects" : { "main" : { "subtype" : "skill.sorcery", @@ -737,7 +712,6 @@ }, "resistance" : { "base" : { - "description" : "", "effects" : { "main" : { "subtype" : "skill.resistance", @@ -764,7 +738,6 @@ }, "firstAid" : { "base" : { - "description" : "", "effects" : { "main" : { "subtype" : "skill.firstAid", diff --git a/lib/CGameState.cpp b/lib/CGameState.cpp index 994adfec9..ef732ccbe 100644 --- a/lib/CGameState.cpp +++ b/lib/CGameState.cpp @@ -20,6 +20,7 @@ #include "CHeroHandler.h" #include "mapObjects/CObjectHandler.h" #include "CModHandler.h" +#include "CSkillHandler.h" #include "mapping/CMap.h" #include "mapping/CMapService.h" #include "StartInfo.h" @@ -113,6 +114,10 @@ void MetaString::getLocalString(const std::pair &txt, std::string &dst { dst = VLC->objtypeh->getObjectName(ser); } + else if(type == SEC_SKILL_NAME) + { + dst = VLC->skillh->skillName(ser); + } else { std::vector *vec; @@ -139,9 +144,6 @@ void MetaString::getLocalString(const std::pair &txt, std::string &dst case ADVOB_TXT: vec = &VLC->generaltexth->advobtxt; break; - case SEC_SKILL_NAME: - vec = &VLC->generaltexth->skillName; - break; case COLOR: vec = &VLC->generaltexth->capColors; break; diff --git a/lib/CGeneralTextHandler.cpp b/lib/CGeneralTextHandler.cpp index f9148edf2..8450eba6e 100644 --- a/lib/CGeneralTextHandler.cpp +++ b/lib/CGeneralTextHandler.cpp @@ -377,23 +377,6 @@ CGeneralTextHandler::CGeneralTextHandler() } while (parser.endLine()); } - { - CLegacyConfigParser parser("DATA/SSTRAITS.TXT"); - - //skip header - parser.endLine(); - parser.endLine(); - - do - { - skillName.push_back(parser.readString()); - - skillInfoTexts.push_back(std::vector()); - for(int j = 0; j < 3; j++) - skillInfoTexts.back().push_back(parser.readString()); - } - while (parser.endLine()); - } { CLegacyConfigParser parser("DATA/SEERHUT.TXT"); diff --git a/lib/CGeneralTextHandler.h b/lib/CGeneralTextHandler.h index 68eecc441..f69d90dd8 100644 --- a/lib/CGeneralTextHandler.h +++ b/lib/CGeneralTextHandler.h @@ -130,8 +130,6 @@ public: std::vector tentColors; //sec skills - std::vector skillName; - std::vector> skillInfoTexts; //[id][level] : level 0 - basic; 2 - advanced std::vector levels; std::vector zcrexp; //more or less useful content of that file //commanders diff --git a/lib/CSkillHandler.cpp b/lib/CSkillHandler.cpp index bb09350b7..4e73967cb 100644 --- a/lib/CSkillHandler.cpp +++ b/lib/CSkillHandler.cpp @@ -35,7 +35,7 @@ CSkill::LevelInfo::~LevelInfo() { } -CSkill::CSkill(SecondarySkill id) : id(id) +CSkill::CSkill(SecondarySkill id) : id(id), name("") { if(id == SecondarySkill::DEFAULT) identifier = "default"; @@ -113,24 +113,41 @@ CSkillHandler::CSkillHandler() std::vector CSkillHandler::loadLegacyData(size_t dataSize) { + CLegacyConfigParser parser("DATA/SSTRAITS.TXT"); + + //skip header + parser.endLine(); + parser.endLine(); + + std::vector skillNames; + std::vector> skillInfoTexts; + do + { + skillNames.push_back(parser.readString()); + skillInfoTexts.push_back(std::vector()); + for(int i = 0; i < 3; i++) + skillInfoTexts.back().push_back(parser.readString()); + } + while (parser.endLine()); + + assert(skillNames.size() == GameConstants::SKILL_QUANTITY); + + //store & construct JSON std::vector legacyData; - /* problem: CGI is client-side only for(int id = 0; id < GameConstants::SKILL_QUANTITY; id++) { CSkill & skill = *objects[id]; JsonNode skillNode(JsonNode::DATA_STRUCT); for(int level = 1; level < NSecondarySkill::levels.size(); level++) { - //only "real" legacy data is skill description - std::string desc = CGI->generaltexth->skillInfoTexts[skill.id][level-1]; - //update both skill & JSON + skill.name = skillNames[id]; + std::string & desc = skillInfoTexts[id][level-1]; skill.setDescription(desc, level); auto & levelNode = skillNode[NSecondarySkill::levels[level]].Struct(); levelNode["description"].String() = desc; } legacyData.push_back(skillNode); } - */ return legacyData; } @@ -139,6 +156,16 @@ const std::string CSkillHandler::getTypeName() const return "skill"; } +const std::string & CSkillHandler::skillInfo(int skill, int level) const +{ + return objects[skill]->getDescription(level); +} + +const std::string & CSkillHandler::skillName(int skill) const +{ + return objects[skill]->name; +} + CSkill * CSkillHandler::loadFromJson(const JsonNode & json, const std::string & identifier) { CSkill * skill = nullptr; @@ -148,6 +175,8 @@ CSkill * CSkillHandler::loadFromJson(const JsonNode & json, const std::string & if(NSecondarySkill::names[id].compare(identifier) == 0) { skill = new CSkill(SecondarySkill(id)); + //skill name isn't stored in JSON + skill->name = objects[id]->name; break; } } @@ -172,6 +201,8 @@ CSkill * CSkillHandler::loadFromJson(const JsonNode & json, const std::string & // parse skill description - tracked separately if(vstd::contains(levelNode.Struct(), "description") && !levelNode["description"].isNull()) skill->setDescription(levelNode["description"].String(), level); + else + skill->setDescription(skillInfo(skill->id, level), level); } logMod->debug("loaded secondary skill %s(%d)", identifier, (int)skill->id); logMod->trace("%s", skill->toString()); diff --git a/lib/CSkillHandler.h b/lib/CSkillHandler.h index 92b7b5c82..b5f64b0e9 100644 --- a/lib/CSkillHandler.h +++ b/lib/CSkillHandler.h @@ -45,11 +45,13 @@ public: SecondarySkill id; std::string identifier; + std::string name; //as displayed in GUI template void serialize(Handler & h, const int version) { h & id; h & identifier; + h & name; h & levels; } @@ -74,6 +76,9 @@ public: void loadObject(std::string scope, std::string name, const JsonNode & data) override; void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override; + const std::string & skillInfo(int skill, int level) const; + const std::string & skillName(int skill) const; + template void serialize(Handler & h, const int version) { h & objects; diff --git a/lib/HeroBonus.cpp b/lib/HeroBonus.cpp index 25d246669..db2671c2d 100644 --- a/lib/HeroBonus.cpp +++ b/lib/HeroBonus.cpp @@ -17,6 +17,7 @@ #include "CCreatureSet.h" #include "CHeroHandler.h" #include "CGeneralTextHandler.h" +#include "CSkillHandler.h" #include "CStack.h" #include "CArtHandler.h" @@ -1078,7 +1079,7 @@ std::string Bonus::Description() const str << VLC->creh->creatures[sid]->namePl; break; case SECONDARY_SKILL: - str << VLC->generaltexth->skillName[sid]/* << " secondary skill"*/; + str << VLC->skillh->skillName(sid); break; default: //todo: handle all possible sources diff --git a/lib/mapObjects/MiscObjects.cpp b/lib/mapObjects/MiscObjects.cpp index 71588de38..26c28bd95 100644 --- a/lib/mapObjects/MiscObjects.cpp +++ b/lib/mapObjects/MiscObjects.cpp @@ -17,6 +17,7 @@ #include "../CSoundBase.h" #include "../CModHandler.h" #include "../CHeroHandler.h" +#include "../CSkillHandler.h" #include "CObjectClassesHandler.h" #include "../spells/CSpellHandler.h" #include "../IGameCallback.h" @@ -1476,7 +1477,7 @@ std::string CGWitchHut::getHoverText(PlayerColor player) const if(wasVisited(player)) { hoverName += "\n" + VLC->generaltexth->allTexts[356]; // + (learn %s) - boost::algorithm::replace_first(hoverName,"%s",VLC->generaltexth->skillName[ability]); + boost::algorithm::replace_first(hoverName, "%s", VLC->skillh->skillName(ability)); } return hoverName; } From 03b7da93e260865b98e5346cbb7bd340832945f6 Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Thu, 31 Aug 2017 09:23:19 +1200 Subject: [PATCH 45/68] use logMod for all mod-related logging --- lib/CArtHandler.cpp | 14 +++--- lib/CHeroHandler.cpp | 2 +- lib/CModHandler.cpp | 90 ++++++++++++++++++------------------ lib/CSkillHandler.cpp | 2 +- lib/CTownHandler.cpp | 8 ++-- lib/IHandlerBase.h | 2 +- lib/JsonDetail.cpp | 4 +- lib/JsonNode.cpp | 24 +++++----- lib/spells/CSpellHandler.cpp | 8 ++-- 9 files changed, 77 insertions(+), 77 deletions(-) diff --git a/lib/CArtHandler.cpp b/lib/CArtHandler.cpp index af146dd6a..6aade4fd9 100644 --- a/lib/CArtHandler.cpp +++ b/lib/CArtHandler.cpp @@ -360,7 +360,7 @@ ArtifactPosition CArtHandler::stringToSlot(std::string slotName) if (it != artifactPositionMap.end()) return it->second; - logGlobal->warn("Warning! Artifact slot %s not recognized!", slotName); + logMod->warn("Warning! Artifact slot %s not recognized!", slotName); return ArtifactPosition::PRE_FIRST; } @@ -421,7 +421,7 @@ CArtifact::EartClass CArtHandler::stringToClass(std::string className) if (it != artifactClassMap.end()) return it->second; - logGlobal->warn("Warning! Artifact rarity %s not recognized!", className); + logMod->warn("Warning! Artifact rarity %s not recognized!", className); return CArtifact::ART_SPECIAL; } @@ -455,7 +455,7 @@ void CArtHandler::loadType(CArtifact * art, const JsonNode & node) } } else - logGlobal->warn("Warning! Artifact type %s not recognized!", b.String()); + logMod->warn("Warning! Artifact type %s not recognized!", b.String()); } } @@ -679,11 +679,11 @@ void CArtHandler::erasePickedArt(ArtifactID id) artifactList->erase(itr); } else - logGlobal->warn("Problem: cannot erase artifact %s from list, it was not present", art->Name()); + logMod->warn("Problem: cannot erase artifact %s from list, it was not present", art->Name()); } else - logGlobal->warn("Problem: cannot find list for artifact %s, strange class. (special?)", art->Name()); + logMod->warn("Problem: cannot find list for artifact %s, strange class. (special?)", art->Name()); } boost::optional&> CArtHandler::listFromClass( CArtifact::EartClass artifactClass ) @@ -869,7 +869,7 @@ bool CArtifactInstance::canBePutAt(const CArtifactSet *artSet, ArtifactPosition auto possibleSlots = artType->possibleSlots.find(artSet->bearerType()); if(possibleSlots == artType->possibleSlots.end()) { - logGlobal->warn("Warning: artifact %s doesn't have defined allowed slots for bearer of type %s", artType->Name(), artSet->bearerType()); + logMod->warn("Warning: artifact %s doesn't have defined allowed slots for bearer of type %s", artType->Name(), artSet->bearerType()); return false; } @@ -1007,7 +1007,7 @@ SpellID CArtifactInstance::getGivenSpellID() const const auto b = getBonusLocalFirst(Selector::type(Bonus::SPELL)); if(!b) { - logGlobal->warn("Warning: %s doesn't bear any spell!", nodeName()); + logMod->warn("Warning: %s doesn't bear any spell!", nodeName()); return SpellID::NONE; } return SpellID(b->subtype); diff --git a/lib/CHeroHandler.cpp b/lib/CHeroHandler.cpp index cdaf9ab44..301f31d7d 100644 --- a/lib/CHeroHandler.cpp +++ b/lib/CHeroHandler.cpp @@ -362,7 +362,7 @@ void CHeroHandler::loadHeroSkills(CHero * hero, const JsonNode & node) } else { - logGlobal->error("Unknown skill level: %s", set["level"].String()); + logMod->error("Unknown skill level: %s", set["level"].String()); } } diff --git a/lib/CModHandler.cpp b/lib/CModHandler.cpp index c3e0018ff..c83e1c72b 100644 --- a/lib/CModHandler.cpp +++ b/lib/CModHandler.cpp @@ -37,7 +37,7 @@ CIdentifierStorage::~CIdentifierStorage() void CIdentifierStorage::checkIdentifier(std::string & ID) { if (boost::algorithm::ends_with(ID, ".")) - logGlobal->warn("BIG WARNING: identifier %s seems to be broken!", ID); + logMod->warn("BIG WARNING: identifier %s seems to be broken!", ID); else { size_t pos = 0; @@ -45,7 +45,7 @@ void CIdentifierStorage::checkIdentifier(std::string & ID) { if (std::tolower(ID[pos]) != ID[pos] ) //Not in camelCase { - logGlobal->warn("Warning: identifier %s is not in camelCase!", ID); + logMod->warn("Warning: identifier %s is not in camelCase!", ID); ID[pos] = std::tolower(ID[pos]);// Try to fix the ID } pos = ID.find('.', pos); @@ -149,7 +149,7 @@ boost::optional CIdentifierStorage::getIdentifier(std::string scope, std:: if (idList.size() == 1) return idList.front().id; if (!silent) - logGlobal->error("Failed to resolve identifier %s of type %s from mod %s", name , type ,scope); + logMod->error("Failed to resolve identifier %s of type %s from mod %s", name , type ,scope); return boost::optional(); } @@ -162,7 +162,7 @@ boost::optional CIdentifierStorage::getIdentifier(std::string type, const if (idList.size() == 1) return idList.front().id; if (!silent) - logGlobal->error("Failed to resolve identifier %s of type %s from mod %s", name.String(), type, name.meta); + logMod->error("Failed to resolve identifier %s of type %s from mod %s", name.String(), type, name.meta); return boost::optional(); } @@ -176,7 +176,7 @@ boost::optional CIdentifierStorage::getIdentifier(const JsonNode & name, b if (idList.size() == 1) return idList.front().id; if (!silent) - logGlobal->error("Failed to resolve identifier %s of type %s from mod %s", name.String(), pair2.first, name.meta); + logMod->error("Failed to resolve identifier %s of type %s from mod %s", name.String(), pair2.first, name.meta); return boost::optional(); } @@ -190,7 +190,7 @@ boost::optional CIdentifierStorage::getIdentifier(std::string scope, std:: if (idList.size() == 1) return idList.front().id; if (!silent) - logGlobal->error("Failed to resolve identifier %s of type %s from mod %s", fullName, pair2.first, scope); + logMod->error("Failed to resolve identifier %s of type %s from mod %s", fullName, pair2.first, scope); return boost::optional(); } @@ -280,15 +280,15 @@ bool CIdentifierStorage::resolveIdentifier(const ObjectCallback & request) // error found. Try to generate some debug info if (identifiers.size() == 0) - logGlobal->error("Unknown identifier!"); + logMod->error("Unknown identifier!"); else - logGlobal->error("Ambiguous identifier request!"); + logMod->error("Ambiguous identifier request!"); - logGlobal->error("Request for %s.%s from mod %s", request.type, request.name, request.localScope); + logMod->error("Request for %s.%s from mod %s", request.type, request.name, request.localScope); for (auto id : identifiers) { - logGlobal->error("\tID is available in mod %s", id.scope); + logMod->error("\tID is available in mod %s", id.scope); } return false; } @@ -308,9 +308,9 @@ void CIdentifierStorage::finalize() { for(auto object : registeredObjects) { - logGlobal->trace("%s : %s -> %d", object.second.scope, object.first, object.second.id); + logMod->trace("%s : %s -> %d", object.second.scope, object.first, object.second.id); } - logGlobal->error("All known identifiers were dumped into log file"); + logMod->error("All known identifiers were dumped into log file"); } assert(errorsFound == false); state = FINISHED; @@ -351,9 +351,9 @@ bool CContentHandler::ContentTypeHandler::preloadModData(std::string modName, st // patching this mod? Send warning and continue - this situation can be handled normally if (remoteName == modName) - logGlobal->warn("Redundant namespace definition for %s", objectName); + logMod->warn("Redundant namespace definition for %s", objectName); - logGlobal->trace("Patching object %s (%s) from %s", objectName, remoteName, modName); + logMod->trace("Patching object %s (%s) from %s", objectName, remoteName, modName); JsonNode & remoteConf = modData[remoteName].patches[objectName]; JsonUtils::merge(remoteConf, entry.second); @@ -477,7 +477,7 @@ void CContentHandler::preloadData(CModInfo & mod) bool validate = (mod.validation != CModInfo::PASSED); // print message in format [<8-symbols checksum>] - logGlobal->info("\t\t[%08x]%s", mod.checksum, mod.name); + logMod->info("\t\t[%08x]%s", mod.checksum, mod.name); if (validate && mod.identifier != "core") { @@ -498,12 +498,12 @@ void CContentHandler::load(CModInfo & mod) if (validate) { if (mod.validation != CModInfo::FAILED) - logGlobal->info("\t\t[DONE] %s", mod.name); + logMod->info("\t\t[DONE] %s", mod.name); else - logGlobal->error("\t\t[FAIL] %s", mod.name); + logMod->error("\t\t[FAIL] %s", mod.name); } else - logGlobal->info("\t\t[SKIP] %s", mod.name); + logMod->info("\t\t[SKIP] %s", mod.name); } static JsonNode loadModSettings(std::string path) @@ -629,39 +629,39 @@ void CModHandler::loadConfigFromFile (std::string name) paths += p.string() + ", "; } paths = paths.substr(0, paths.size() - 2); - logGlobal->debug("Loading hardcoded features settings from [%s], result:", paths); + logMod->debug("Loading hardcoded features settings from [%s], result:", paths); settings.data = JsonUtils::assembleFromFiles("config/" + name); const JsonNode & hardcodedFeatures = settings.data["hardcodedFeatures"]; settings.MAX_HEROES_AVAILABLE_PER_PLAYER = hardcodedFeatures["MAX_HEROES_AVAILABLE_PER_PLAYER"].Integer(); - logGlobal->debug("\tMAX_HEROES_AVAILABLE_PER_PLAYER\t%d", settings.MAX_HEROES_AVAILABLE_PER_PLAYER); + logMod->debug("\tMAX_HEROES_AVAILABLE_PER_PLAYER\t%d", settings.MAX_HEROES_AVAILABLE_PER_PLAYER); settings.MAX_HEROES_ON_MAP_PER_PLAYER = hardcodedFeatures["MAX_HEROES_ON_MAP_PER_PLAYER"].Integer(); - logGlobal->debug("\tMAX_HEROES_ON_MAP_PER_PLAYER\t%d", settings.MAX_HEROES_ON_MAP_PER_PLAYER); + logMod->debug("\tMAX_HEROES_ON_MAP_PER_PLAYER\t%d", settings.MAX_HEROES_ON_MAP_PER_PLAYER); settings.CREEP_SIZE = hardcodedFeatures["CREEP_SIZE"].Integer(); - logGlobal->debug("\tCREEP_SIZE\t%d", settings.CREEP_SIZE); + logMod->debug("\tCREEP_SIZE\t%d", settings.CREEP_SIZE); settings.WEEKLY_GROWTH = hardcodedFeatures["WEEKLY_GROWTH_PERCENT"].Integer(); - logGlobal->debug("\tWEEKLY_GROWTH\t%d", settings.WEEKLY_GROWTH); + logMod->debug("\tWEEKLY_GROWTH\t%d", settings.WEEKLY_GROWTH); settings.NEUTRAL_STACK_EXP = hardcodedFeatures["NEUTRAL_STACK_EXP_DAILY"].Integer(); - logGlobal->debug("\tNEUTRAL_STACK_EXP\t%d", settings.NEUTRAL_STACK_EXP); + logMod->debug("\tNEUTRAL_STACK_EXP\t%d", settings.NEUTRAL_STACK_EXP); settings.MAX_BUILDING_PER_TURN = hardcodedFeatures["MAX_BUILDING_PER_TURN"].Integer(); - logGlobal->debug("\tMAX_BUILDING_PER_TURN\t%d", settings.MAX_BUILDING_PER_TURN); + logMod->debug("\tMAX_BUILDING_PER_TURN\t%d", settings.MAX_BUILDING_PER_TURN); settings.DWELLINGS_ACCUMULATE_CREATURES = hardcodedFeatures["DWELLINGS_ACCUMULATE_CREATURES"].Bool(); - logGlobal->debug("\tDWELLINGS_ACCUMULATE_CREATURES\t%d", static_cast(settings.DWELLINGS_ACCUMULATE_CREATURES)); + logMod->debug("\tDWELLINGS_ACCUMULATE_CREATURES\t%d", static_cast(settings.DWELLINGS_ACCUMULATE_CREATURES)); settings.ALL_CREATURES_GET_DOUBLE_MONTHS = hardcodedFeatures["ALL_CREATURES_GET_DOUBLE_MONTHS"].Bool(); - logGlobal->debug("\tALL_CREATURES_GET_DOUBLE_MONTHS\t%d", static_cast(settings.ALL_CREATURES_GET_DOUBLE_MONTHS)); + logMod->debug("\tALL_CREATURES_GET_DOUBLE_MONTHS\t%d", static_cast(settings.ALL_CREATURES_GET_DOUBLE_MONTHS)); settings.WINNING_HERO_WITH_NO_TROOPS_RETREATS = hardcodedFeatures["WINNING_HERO_WITH_NO_TROOPS_RETREATS"].Bool(); - logGlobal->debug("\tWINNING_HERO_WITH_NO_TROOPS_RETREATS\t%d", static_cast(settings.WINNING_HERO_WITH_NO_TROOPS_RETREATS)); + logMod->debug("\tWINNING_HERO_WITH_NO_TROOPS_RETREATS\t%d", static_cast(settings.WINNING_HERO_WITH_NO_TROOPS_RETREATS)); settings.BLACK_MARKET_MONTHLY_ARTIFACTS_CHANGE = hardcodedFeatures["BLACK_MARKET_MONTHLY_ARTIFACTS_CHANGE"].Bool(); - logGlobal->debug("\tBLACK_MARKET_MONTHLY_ARTIFACTS_CHANGE\t%d", static_cast(settings.BLACK_MARKET_MONTHLY_ARTIFACTS_CHANGE)); + logMod->debug("\tBLACK_MARKET_MONTHLY_ARTIFACTS_CHANGE\t%d", static_cast(settings.BLACK_MARKET_MONTHLY_ARTIFACTS_CHANGE)); const JsonNode & gameModules = settings.data["modules"]; modules.STACK_EXP = gameModules["STACK_EXPERIENCE"].Bool(); - logGlobal->debug("\tSTACK_EXP\t%d", static_cast(modules.STACK_EXP)); + logMod->debug("\tSTACK_EXP\t%d", static_cast(modules.STACK_EXP)); modules.STACK_ARTIFACT = gameModules["STACK_ARTIFACTS"].Bool(); - logGlobal->debug("\tSTACK_ARTIFACT\t%d", static_cast(modules.STACK_ARTIFACT)); + logMod->debug("\tSTACK_ARTIFACT\t%d", static_cast(modules.STACK_ARTIFACT)); modules.COMMANDERS = gameModules["COMMANDERS"].Bool(); - logGlobal->debug("\tCOMMANDERS\t%d", static_cast(modules.COMMANDERS)); + logMod->debug("\tCOMMANDERS\t%d", static_cast(modules.COMMANDERS)); modules.MITHRIL = gameModules["MITHRIL"].Bool(); - logGlobal->debug("\tMITHRIL\t%d", static_cast(modules.MITHRIL)); + logMod->debug("\tMITHRIL\t%d", static_cast(modules.MITHRIL)); } // currentList is passed by value to get current list of depending mods @@ -672,8 +672,8 @@ bool CModHandler::hasCircularDependency(TModID modID, std::set currentL // Mod already present? We found a loop if (vstd::contains(currentList, modID)) { - logGlobal->error("Error: Circular dependency detected! Printing dependency list:"); - logGlobal->error("\t%s -> ", mod.name); + logMod->error("Error: Circular dependency detected! Printing dependency list:"); + logMod->error("\t%s -> ", mod.name); return true; } @@ -684,7 +684,7 @@ bool CModHandler::hasCircularDependency(TModID modID, std::set currentL { if (hasCircularDependency(dependency, currentList)) { - logGlobal->error("\t%s ->\n", mod.name); // conflict detected, print dependency list + logMod->error("\t%s ->\n", mod.name); // conflict detected, print dependency list return true; } } @@ -701,7 +701,7 @@ bool CModHandler::checkDependencies(const std::vector & input) const { if (!vstd::contains(input, dep)) { - logGlobal->error("Error: Mod %s requires missing %s!", mod.name, dep); + logMod->error("Error: Mod %s requires missing %s!", mod.name, dep); return false; } } @@ -710,7 +710,7 @@ bool CModHandler::checkDependencies(const std::vector & input) const { if (vstd::contains(input, conflicting)) { - logGlobal->error("Error: Mod %s conflicts with %s!", mod.name, allMods.at(conflicting).name); + logMod->error("Error: Mod %s conflicts with %s!", mod.name, allMods.at(conflicting).name); return false; } } @@ -941,11 +941,11 @@ void CModHandler::load() CStopWatch totalTime, timer; CContentHandler content; - logGlobal->info("\tInitializing content handler: %d ms", timer.getDiff()); + logMod->info("\tInitializing content handler: %d ms", timer.getDiff()); for(const TModID & modName : activeMods) { - logGlobal->trace("Generating checksum for %s", modName); + logMod->trace("Generating checksum for %s", modName); allMods[modName].updateChecksum(calculateModChecksum(modName, CResourceHandler::get(modName))); } @@ -954,7 +954,7 @@ void CModHandler::load() content.preloadData(coreMod); for(const TModID & modName : activeMods) content.preloadData(allMods[modName]); - logGlobal->info("\tParsing mod data: %d ms", timer.getDiff()); + logMod->info("\tParsing mod data: %d ms", timer.getDiff()); content.load(coreMod); for(const TModID & modName : activeMods) @@ -962,17 +962,17 @@ void CModHandler::load() content.loadCustom(); - logGlobal->info("\tLoading mod data: %d ms", timer.getDiff()); + logMod->info("\tLoading mod data: %d ms", timer.getDiff()); VLC->creh->loadCrExpBon(); VLC->creh->buildBonusTreeForTiers(); //do that after all new creatures are loaded identifiers.finalize(); - logGlobal->info("\tResolving identifiers: %d ms", timer.getDiff()); + logMod->info("\tResolving identifiers: %d ms", timer.getDiff()); content.afterLoadFinalization(); - logGlobal->info("\tHandlers post-load finalization: %d ms ", timer.getDiff()); - logGlobal->info("\tAll game content loaded in %d ms", totalTime.getDiff()); + logMod->info("\tHandlers post-load finalization: %d ms ", timer.getDiff()); + logMod->info("\tAll game content loaded in %d ms", totalTime.getDiff()); } void CModHandler::afterLoad() diff --git a/lib/CSkillHandler.cpp b/lib/CSkillHandler.cpp index 4e73967cb..1fe1e1adf 100644 --- a/lib/CSkillHandler.cpp +++ b/lib/CSkillHandler.cpp @@ -183,7 +183,7 @@ CSkill * CSkillHandler::loadFromJson(const JsonNode & json, const std::string & if(!skill) { - logGlobal->error("unknown secondary skill %s", identifier); + logMod->error("unknown secondary skill %s", identifier); throw std::runtime_error("invalid skill"); } diff --git a/lib/CTownHandler.cpp b/lib/CTownHandler.cpp index d71d3bb3a..40e389435 100644 --- a/lib/CTownHandler.cpp +++ b/lib/CTownHandler.cpp @@ -748,7 +748,7 @@ void CTownHandler::loadObject(std::string scope, std::string name, const JsonNod auto & advMap = data["town"]["adventureMap"]; if (!advMap.isNull()) { - logGlobal->warn("Outdated town mod. Will try to generate valid templates out of fort"); + logMod->warn("Outdated town mod. Will try to generate valid templates out of fort"); JsonNode config; config["animation"] = advMap["castle"]; VLC->objtypeh->getHandlerFor(index, object->index)->addTemplate(config); @@ -818,9 +818,9 @@ void CTownHandler::initializeRequirements() { if (node.Vector().size() > 1) { - logGlobal->warn("Unexpected length of town buildings requirements: %d", node.Vector().size()); - logGlobal->warn("Entry contains: "); - logGlobal->warn(node.toJson()); + logMod->warn("Unexpected length of town buildings requirements: %d", node.Vector().size()); + logMod->warn("Entry contains: "); + logMod->warn(node.toJson()); } return BuildingID(VLC->modh->identifiers.getIdentifier(requirement.town->getBuildingScope(), node.Vector()[0]).get()); }); diff --git a/lib/IHandlerBase.h b/lib/IHandlerBase.h index 5e6125e69..024e7968f 100644 --- a/lib/IHandlerBase.h +++ b/lib/IHandlerBase.h @@ -94,7 +94,7 @@ public: if (raw_id < 0 || raw_id >= objects.size()) { - logGlobal->error("%s id %d is invalid", getTypeName(), static_cast(raw_id)); + logMod->error("%s id %d is invalid", getTypeName(), static_cast(raw_id)); throw std::runtime_error("internal error"); } diff --git a/lib/JsonDetail.cpp b/lib/JsonDetail.cpp index bd7de69f4..b56b8d4b9 100644 --- a/lib/JsonDetail.cpp +++ b/lib/JsonDetail.cpp @@ -163,8 +163,8 @@ JsonNode JsonParser::parse(std::string fileName) if (!errors.empty()) { - logGlobal->warn("File %s is not a valid JSON file!", fileName); - logGlobal->warn(errors); + logMod->warn("File %s is not a valid JSON file!", fileName); + logMod->warn(errors); } return root; } diff --git a/lib/JsonNode.cpp b/lib/JsonNode.cpp index b16d7d385..e00453ed4 100644 --- a/lib/JsonNode.cpp +++ b/lib/JsonNode.cpp @@ -395,7 +395,7 @@ std::shared_ptr JsonUtils::parseBonus (const JsonVector &ability_vec) //T auto it = bonusNameMap.find(type); if (it == bonusNameMap.end()) { - logGlobal->error("Error: invalid ability type %s", type); + logMod->error("Error: invalid ability type %s", type); return b; } b->type = it->second; @@ -413,7 +413,7 @@ const T & parseByMap(const std::map & map, const JsonNode * val, auto it = map.find(type); if (it == map.end()) { - logGlobal->error("Error: invalid %s%s", err, type); + logMod->error("Error: invalid %s%s", err, type); return defaultValue; } else @@ -445,7 +445,7 @@ void JsonUtils::resolveIdentifier(si32 &var, const JsonNode &node, std::string n }); break; default: - logGlobal->error("Error! Wrong identifier used for value of %s", name); + logMod->error("Error! Wrong identifier used for value of %s", name); } } } @@ -467,7 +467,7 @@ void JsonUtils::resolveIdentifier(const JsonNode &node, si32 &var) }); break; default: - logGlobal->error("Error! Wrong identifier used for identifier!"); + logMod->error("Error! Wrong identifier used for identifier!"); } } @@ -489,7 +489,7 @@ bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b) auto it = bonusNameMap.find(type); if (it == bonusNameMap.end()) { - logGlobal->error("Error: invalid ability type %s", type); + logMod->error("Error: invalid ability type %s", type); return false; } b->type = it->second; @@ -533,7 +533,7 @@ bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b) } break; default: - logGlobal->error("Error! Wrong bonus duration format."); + logMod->error("Error! Wrong bonus duration format."); } } @@ -580,7 +580,7 @@ bool JsonUtils::parseBonus(const JsonNode &ability, Bonus *b) auto it = bonusNameMap.find(anotherBonusType); if (it == bonusNameMap.end()) { - logGlobal->error("Error: invalid ability type %s", anotherBonusType); + logMod->error("Error: invalid ability type %s", anotherBonusType); continue; } l2->type = it->second; @@ -723,8 +723,8 @@ bool JsonUtils::validate(const JsonNode &node, std::string schemaName, std::stri std::string log = Validation::check(schemaName, node); if (!log.empty()) { - logGlobal->warn("Data in %s is invalid!", dataName); - logGlobal->warn(log); + logMod->warn("Data in %s is invalid!", dataName); + logMod->warn(log); } return log.empty(); } @@ -745,7 +745,7 @@ const JsonNode & getSchemaByName(std::string name) return loadedSchemas[name]; } - logGlobal->error("Error: missing schema with name %s!", name); + logMod->error("Error: missing schema with name %s!", name); assert(0); return nullNode; } @@ -756,7 +756,7 @@ const JsonNode & JsonUtils::getSchema(std::string URI) size_t posHash = URI.find('#'); if(posColon == std::string::npos) { - logGlobal->error("Invalid schema URI:%s", URI); + logMod->error("Invalid schema URI:%s", URI); return nullNode; } @@ -765,7 +765,7 @@ const JsonNode & JsonUtils::getSchema(std::string URI) if(protocolName != "vcmi") { - logGlobal->error("Error: unsupported URI protocol for schema: %s", URI); + logMod->error("Error: unsupported URI protocol for schema: %s", URI); return nullNode; } diff --git a/lib/spells/CSpellHandler.cpp b/lib/spells/CSpellHandler.cpp index db85e254e..bd0b72ed4 100644 --- a/lib/spells/CSpellHandler.cpp +++ b/lib/spells/CSpellHandler.cpp @@ -819,7 +819,7 @@ CSpell * CSpellHandler::loadFromJson(const JsonNode & json, const std::string & spell->name = json["name"].String(); - logGlobal->trace("%s: loading spell %s", __FUNCTION__, spell->name); + logMod->trace("%s: loading spell %s", __FUNCTION__, spell->name); const auto schoolNames = json["school"]; @@ -854,7 +854,7 @@ CSpell * CSpellHandler::loadFromJson(const JsonNode & json, const std::string & else if(targetType == "LOCATION") spell->targetType = CSpell::LOCATION; else - logGlobal->warn("Spell %s: target type %s - assumed NO_TARGET.", spell->name, (targetType.empty() ? "empty" : "unknown ("+targetType+")")); + logMod->warn("Spell %s: target type %s - assumed NO_TARGET.", spell->name, (targetType.empty() ? "empty" : "unknown ("+targetType+")")); for(const auto & counteredSpell: json["counters"].Struct()) if (counteredSpell.second.Bool()) @@ -899,7 +899,7 @@ CSpell * CSpellHandler::loadFromJson(const JsonNode & json, const std::string & else if(!implicitPositiveness) { spell->positiveness = CSpell::NEUTRAL; //duplicates constructor but, just in case - logGlobal->error("Spell %s: no positiveness specified, assumed NEUTRAL.", spell->name); + logMod->error("Spell %s: no positiveness specified, assumed NEUTRAL.", spell->name); } spell->isSpecial = flags["special"].Bool(); @@ -909,7 +909,7 @@ CSpell * CSpellHandler::loadFromJson(const JsonNode & json, const std::string & auto it = bonusNameMap.find(name); if(it == bonusNameMap.end()) { - logGlobal->error("Spell %s: invalid bonus name %s", spell->name, name); + logMod->error("Spell %s: invalid bonus name %s", spell->name, name); } else { From 233ead56716d1acaa357365f33db4c841ea15a6d Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Thu, 31 Aug 2017 09:44:01 +1200 Subject: [PATCH 46/68] fixed Estates description to match original format --- config/skills.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/skills.json b/config/skills.json index bb5a84b2d..704c9272a 100644 --- a/config/skills.json +++ b/config/skills.json @@ -366,19 +366,19 @@ } }, "basic" : { - "description" : "With Basic Estates, a hero contributes 125 gold per day to your cause.", + "description" : "{Basic Estates}\n\nYour hero contributes 125 gold per day to your cause.", "effects" : { "main" : { "val" : 125 } } }, "advanced" : { - "description" : "With Advanced Estates, a hero contributes 250 gold per day to your cause.", + "description" : "{Advanced Estates}\n\nYour hero contributes 250 gold per day to your cause.", "effects" : { "main" : { "val" : 250 } } }, "expert" : { - "description" : "With Expert Estates, a hero contributes 500 gold per day to your cause.", + "description" : "{Expert Estates}\n\nYour hero contributes 500 gold per day to your cause.", "effects" : { "main" : { "val" : 500 } } From cd35ece10c26573256260033ee87638c444795d6 Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Thu, 31 Aug 2017 10:29:25 +1200 Subject: [PATCH 47/68] fixed DLL_LINKAGE for << operators --- lib/CSkillHandler.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/CSkillHandler.h b/lib/CSkillHandler.h index b5f64b0e9..635145075 100644 --- a/lib/CSkillHandler.h +++ b/lib/CSkillHandler.h @@ -56,8 +56,8 @@ public: } friend class CSkillHandler; - friend std::ostream & operator<<(std::ostream & out, const CSkill & skill); - friend std::ostream & operator<<(std::ostream & out, const CSkill::LevelInfo & info); + friend DLL_LINKAGE std::ostream & operator<<(std::ostream & out, const CSkill & skill); + friend DLL_LINKAGE std::ostream & operator<<(std::ostream & out, const CSkill::LevelInfo & info); }; class DLL_LINKAGE CSkillHandler: public CHandlerBase From d7f76fc43375bb4b5a375c90b6bd18ab1a9b7c7d Mon Sep 17 00:00:00 2001 From: Arseniy Shestakov Date: Sat, 2 Sep 2017 16:09:55 +0300 Subject: [PATCH 48/68] README: add more text and provide links to instructions on wiki --- README.md | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index a5e50ef4c..eaff1181f 100644 --- a/README.md +++ b/README.md @@ -2,20 +2,33 @@ [![AppVeyor Build status](https://ci.appveyor.com/api/projects/status/github/vcmi/vcmi?branch=develop&svg=true)](https://ci.appveyor.com/project/vcmi/vcmi) [![Coverity Scan Build Status](https://scan.coverity.com/projects/vcmi/badge.svg)](https://scan.coverity.com/projects/vcmi) # VCMI Project -VCMI is work-in-progress attempt to recreate engine for Heroes III, giving it new and extended possibilities. To use VCMI you need to own original data files. +VCMI is work-in-progress attempt to recreate engine for Heroes III, giving it new and extended possibilities. ## Links - * Homepage: http://vcmi.eu/ - * Wiki: http://wiki.vcmi.eu/ - * Forums: http://forum.vcmi.eu/ - * Bugtracker: http://bugs.vcmi.eu/ + * Homepage: https://vcmi.eu/ + * Wiki: https://wiki.vcmi.eu/ + * Forums: https://forum.vcmi.eu/ + * Bugtracker: https://bugs.vcmi.eu/ * Slack: https://slack.vcmi.eu/ -## Installation -For installation of latest release see release announcement on http://vcmi.eu/ +## Installation guides -For building from source see project wiki at http://wiki.vcmi.eu/ +To use VCMI you need to own original data files. + + * [Android](https://wiki.vcmi.eu/Installation_on_Android) + * [Linux](https://wiki.vcmi.eu/Installation_on_Linux) + * [macOS](https://wiki.vcmi.eu/Installation_on_macOS) + * [Windows](https://wiki.vcmi.eu/Installation_on_Windows) + +## Building from source + +Platform support is constantly tested by continuous integration and CMake configuration adjusted to generate nice looking projects for all major IDE. Following guides will help you to setup build environment with no effort: + + * [On Linux](https://wiki.vcmi.eu/How_to_build_VCMI_(Linux)) + * [On Linux for Windows with MXE](https://wiki.vcmi.eu/How_to_build_VCMI_(Linux/Cmake/MXE)) + * [On macOS](https://wiki.vcmi.eu/How_to_build_VCMI_(macOS)) + * [On Windows using MSVC and Vcpkg](https://wiki.vcmi.eu/How_to_build_VCMI_(Windows/Vcpkg)) ## Copyright and license From 37df5c9d88a27b57cb4c306207726635f3492644 Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Sun, 3 Sep 2017 23:49:36 +1200 Subject: [PATCH 49/68] reworked mod loading to follow standard approach --- config/schemas/mod.json | 5 ++ config/schemas/skill.json | 12 ++- config/skills.json | 28 +++++++ lib/CModHandler.cpp | 1 + lib/CSkillHandler.cpp | 156 ++------------------------------------ lib/CSkillHandler.h | 3 - 6 files changed, 51 insertions(+), 154 deletions(-) diff --git a/config/schemas/mod.json b/config/schemas/mod.json index be73fe829..63db3e252 100644 --- a/config/schemas/mod.json +++ b/config/schemas/mod.json @@ -97,6 +97,11 @@ "description": "List of configuration files for spells", "items": { "type":"string", "format" : "textFile" } }, + "skills": { + "type":"array", + "description": "List of configuration files for skills", + "items": { "type":"string", "format" : "textFile" } + }, "templates":{ "type":"array", "description": "List of configuration files for RMG templates", diff --git a/config/schemas/skill.json b/config/schemas/skill.json index 1997fb11b..0fe64298b 100644 --- a/config/schemas/skill.json +++ b/config/schemas/skill.json @@ -11,7 +11,7 @@ "skillBonus" : { "type" : "object", "description" : "Set of bonuses provided by skill at given level", - "required" : ["effects"], + "required" : ["description", "effects"], "properties" : { "description" : { "type" : "string", @@ -28,9 +28,17 @@ }, - "required" : ["basic", "advanced", "expert"], + "required" : ["name", "basic", "advanced", "expert"], "properties" : { + "index" : { + "type": "number", + "description": "numeric id of skill, required for existing skills" + }, + "name" : { + "type": "string", + "description": "localizable skill name" + }, "base" : { "type" : "object", "description" : "will be merged with all levels", diff --git a/config/skills.json b/config/skills.json index 704c9272a..6519fae12 100644 --- a/config/skills.json +++ b/config/skills.json @@ -1,5 +1,6 @@ { "pathfinding" : { + "index" : 0, "base" : { "effects" : { "main" : { @@ -26,6 +27,7 @@ } }, "archery" : { + "index" : 1, "base" : { "effects" : { "main" : { @@ -52,6 +54,7 @@ } }, "logistics" : { + "index" : 2, "base" : { "effects" : { "main" : { @@ -78,6 +81,7 @@ } }, "scouting" : { + "index" : 3, "base" : { "effects" : { "main" : { @@ -103,6 +107,7 @@ } }, "diplomacy" : { + "index" : 4, "base" : { "effects" : { "main" : { @@ -137,6 +142,7 @@ } }, "navigation" : { + "index" : 5, "base" : { "effects" : { "main" : { @@ -163,6 +169,7 @@ } }, "leadership" : { + "index" : 6, "base" : { "effects" : { "main" : { @@ -188,6 +195,7 @@ } }, "wisdom" : { + "index" : 7, "base" : { "effects" : { "main" : { @@ -214,6 +222,7 @@ } }, "mysticism" : { + "index" : 8, "base" : { "effects" : { "main" : { @@ -239,6 +248,7 @@ } }, "luck" : { + "index" : 9, "base" : { "effects" : { "main" : { @@ -264,6 +274,7 @@ } }, "ballistics" : { + "index" : 10, "base" : { "effects" : { "main" : { @@ -296,6 +307,7 @@ } }, "eagleEye" : { + "index" : 11, "base" : { "effects" : { "main" : { @@ -330,6 +342,7 @@ } }, "necromancy" : { + "index" : 12, "base" : { "effects" : { "main" : { @@ -356,6 +369,7 @@ } }, "estates" : { + "index" : 13, "base" : { "effects" : { "main" : { @@ -385,6 +399,7 @@ } }, "fireMagic" : { + "index" : 14, "base" : { "effects" : { "main" : { @@ -411,6 +426,7 @@ } }, "airMagic" : { + "index" : 15, "base" : { "effects" : { "main" : { @@ -437,6 +453,7 @@ } }, "waterMagic" : { + "index" : 16, "base" : { "effects" : { "main" : { @@ -463,6 +480,7 @@ } }, "earthMagic" : { + "index" : 17, "base" : { "effects" : { "main" : { @@ -489,6 +507,7 @@ } }, "scholar" : { + "index" : 18, "base" : { "effects" : { "main" : { @@ -515,6 +534,7 @@ } }, "tactics" : { + "index" : 19, "base" : { "effects" : { "main" : { @@ -541,6 +561,7 @@ } }, "artillery" : { + "index" : 20, "base" : { "effects" : { "main" : { @@ -581,6 +602,7 @@ } }, "learning" : { + "index" : 21, "base" : { "effects" : { "main" : { @@ -607,6 +629,7 @@ } }, "offence" : { + "index" : 22, "base" : { "effects" : { "main" : { @@ -633,6 +656,7 @@ } }, "armorer" : { + "index" : 23, "base" : { "effects" : { "main" : { @@ -659,6 +683,7 @@ } }, "intelligence" : { + "index" : 24, "base" : { "effects" : { "main" : { @@ -685,6 +710,7 @@ } }, "sorcery" : { + "index" : 25, "base" : { "effects" : { "main" : { @@ -711,6 +737,7 @@ } }, "resistance" : { + "index" : 26, "base" : { "effects" : { "main" : { @@ -737,6 +764,7 @@ } }, "firstAid" : { + "index" : 27, "base" : { "effects" : { "main" : { diff --git a/lib/CModHandler.cpp b/lib/CModHandler.cpp index c83e1c72b..bf1c36ba8 100644 --- a/lib/CModHandler.cpp +++ b/lib/CModHandler.cpp @@ -404,6 +404,7 @@ bool CContentHandler::ContentTypeHandler::loadMod(std::string modName, bool vali continue; } // normal new object + logMod->trace("no index in loadMod(%s)", name); performValidate(data,name); handler->loadObject(modName, name, data); } diff --git a/lib/CSkillHandler.cpp b/lib/CSkillHandler.cpp index 1fe1e1adf..46e37306e 100644 --- a/lib/CSkillHandler.cpp +++ b/lib/CSkillHandler.cpp @@ -27,7 +27,7 @@ #include "battle/CBattleInfoCallback.h" ///CSkill -CSkill::LevelInfo::LevelInfo() : description("") +CSkill::LevelInfo::LevelInfo() { } @@ -35,7 +35,7 @@ CSkill::LevelInfo::~LevelInfo() { } -CSkill::CSkill(SecondarySkill id) : id(id), name("") +CSkill::CSkill(SecondarySkill id) : id(id) { if(id == SecondarySkill::DEFAULT) identifier = "default"; @@ -101,14 +101,6 @@ std::string CSkill::toString() const ///CSkillHandler CSkillHandler::CSkillHandler() { - for(int id = 0; id < GameConstants::SKILL_QUANTITY; id++) - { - CSkill * skill = new CSkill(SecondarySkill(id)); - for(int level = 1; level < NSecondarySkill::levels.size(); level++) - for (auto bonus : defaultBonus(SecondarySkill(id), level)) - skill->addNewBonus(bonus, level); - objects.push_back(skill); - } } std::vector CSkillHandler::loadLegacyData(size_t dataSize) @@ -136,18 +128,18 @@ std::vector CSkillHandler::loadLegacyData(size_t dataSize) std::vector legacyData; for(int id = 0; id < GameConstants::SKILL_QUANTITY; id++) { - CSkill & skill = *objects[id]; JsonNode skillNode(JsonNode::DATA_STRUCT); + skillNode["name"].String() = skillNames[id]; for(int level = 1; level < NSecondarySkill::levels.size(); level++) { - skill.name = skillNames[id]; std::string & desc = skillInfoTexts[id][level-1]; - skill.setDescription(desc, level); auto & levelNode = skillNode[NSecondarySkill::levels[level]].Struct(); levelNode["description"].String() = desc; + levelNode["effects"].Struct(); // create empty effects objects } legacyData.push_back(skillNode); } + objects.resize(legacyData.size()); return legacyData; } @@ -175,8 +167,6 @@ CSkill * CSkillHandler::loadFromJson(const JsonNode & json, const std::string & if(NSecondarySkill::names[id].compare(identifier) == 0) { skill = new CSkill(SecondarySkill(id)); - //skill name isn't stored in JSON - skill->name = objects[id]->name; break; } } @@ -187,6 +177,7 @@ CSkill * CSkillHandler::loadFromJson(const JsonNode & json, const std::string & throw std::runtime_error("invalid skill"); } + skill->name = json["name"].String(); for(int level = 1; level < NSecondarySkill::levels.size(); level++) { const std::string & levelName = NSecondarySkill::levels[level]; // basic, advanced, expert @@ -198,11 +189,7 @@ CSkill * CSkillHandler::loadFromJson(const JsonNode & json, const std::string & bonus->sid = skill->id; skill->addNewBonus(bonus, level); } - // parse skill description - tracked separately - if(vstd::contains(levelNode.Struct(), "description") && !levelNode["description"].isNull()) - skill->setDescription(levelNode["description"].String(), level); - else - skill->setDescription(skillInfo(skill->id, level), level); + skill->setDescription(levelNode["description"].String(), level); } logMod->debug("loaded secondary skill %s(%d)", identifier, (int)skill->id); logMod->trace("%s", skill->toString()); @@ -210,33 +197,6 @@ CSkill * CSkillHandler::loadFromJson(const JsonNode & json, const std::string & return skill; } -void CSkillHandler::loadObject(std::string scope, std::string name, const JsonNode & data) -{ - auto type_name = getTypeName(); - auto object = loadFromJson(data, normalizeIdentifier(scope, "core", name)); - - if(object->id == SecondarySkill::DEFAULT) // new skill - no index identified - { - object->id = SecondarySkill(objects.size()); - objects.push_back(object); - } - else - objects[object->id] = object; - - registerObject(scope, type_name, name, object->id); -} - -void CSkillHandler::loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) -{ - auto type_name = getTypeName(); - auto object = loadFromJson(data, normalizeIdentifier(scope, "core", name)); - - assert(object->id == index); - objects[index] = object; - - registerObject(scope, type_name, name, object->id); -} - void CSkillHandler::afterLoadFinalization() { } @@ -264,105 +224,3 @@ std::vector CSkillHandler::getDefaultAllowed() const std::vector allowedSkills(objects.size(), true); return allowedSkills; } - -// HMM3 default bonus provided by secondary skill -std::vector> CSkillHandler::defaultBonus(SecondarySkill skill, int level) const -{ - std::vector> result; - - // add bonus based on current values - useful for adding multiple bonuses easily - auto addBonus = [=, &result](int bonusVal, Bonus::BonusType bonusType = Bonus::SECONDARY_SKILL_PREMY, int subtype = 0) - { - if(bonusType == Bonus::SECONDARY_SKILL_PREMY || bonusType == Bonus::SECONDARY_SKILL_VAL2) - subtype = skill; - result.push_back(std::make_shared(Bonus::PERMANENT, bonusType, Bonus::SECONDARY_SKILL, bonusVal, skill, subtype, Bonus::BASE_NUMBER)); - }; - - switch(skill) - { - case SecondarySkill::PATHFINDING: - addBonus(25 * level); - break; - case SecondarySkill::ARCHERY: - addBonus(5 + 5 * level * level); - break; - case SecondarySkill::LOGISTICS: - addBonus(10 * level); - break; - case SecondarySkill::SCOUTING: - addBonus(level, Bonus::SIGHT_RADIOUS); - break; - case SecondarySkill::DIPLOMACY: - addBonus(level); - addBonus(20 * level, Bonus::SURRENDER_DISCOUNT); - break; - case SecondarySkill::NAVIGATION: - addBonus(50 * level); - break; - case SecondarySkill::LEADERSHIP: - addBonus(level, Bonus::MORALE); - break; - case SecondarySkill::LUCK: - addBonus(level, Bonus::LUCK); - break; - case SecondarySkill::BALLISTICS: - addBonus(100, Bonus::MANUAL_CONTROL, CreatureID::CATAPULT); - addBonus(level); - break; - case SecondarySkill::EAGLE_EYE: - addBonus(30 + 10 * level); - addBonus(1 + level, Bonus::SECONDARY_SKILL_VAL2); - break; - case SecondarySkill::NECROMANCY: - addBonus(10 * level); - break; - case SecondarySkill::ESTATES: - addBonus(125 << (level-1)); - break; - case SecondarySkill::FIRE_MAGIC: - case SecondarySkill::AIR_MAGIC: - case SecondarySkill::WATER_MAGIC: - case SecondarySkill::EARTH_MAGIC: - addBonus(level); - break; - case SecondarySkill::SCHOLAR: - addBonus(1 + level); - break; - case SecondarySkill::TACTICS: - addBonus(1 + 2 * level); - break; - case SecondarySkill::ARTILLERY: - addBonus(100, Bonus::MANUAL_CONTROL, CreatureID::BALLISTA); - addBonus(25 + 25 * level); - if(level > 1) // extra attack - addBonus(1, Bonus::SECONDARY_SKILL_VAL2); - break; - case SecondarySkill::LEARNING: - addBonus(5 * level); - break; - case SecondarySkill::OFFENCE: - addBonus(10 * level); - break; - case SecondarySkill::ARMORER: - addBonus(5 * level); - break; - case SecondarySkill::INTELLIGENCE: - addBonus(25 << (level-1)); - break; - case SecondarySkill::SORCERY: - addBonus(5 * level); - break; - case SecondarySkill::RESISTANCE: - addBonus(5 << (level-1)); - break; - case SecondarySkill::FIRST_AID: - addBonus(100, Bonus::MANUAL_CONTROL, CreatureID::FIRST_AID_TENT); - addBonus(25 + 25 * level); - break; - default: - addBonus(level); - break; - } - - return result; -} diff --git a/lib/CSkillHandler.h b/lib/CSkillHandler.h index 635145075..9248ba9d8 100644 --- a/lib/CSkillHandler.h +++ b/lib/CSkillHandler.h @@ -73,8 +73,6 @@ public: std::vector getDefaultAllowed() const override; const std::string getTypeName() const override; - void loadObject(std::string scope, std::string name, const JsonNode & data) override; - void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override; const std::string & skillInfo(int skill, int level) const; const std::string & skillName(int skill) const; @@ -86,5 +84,4 @@ public: protected: CSkill * loadFromJson(const JsonNode & json, const std::string & identifier) override; - std::vector> defaultBonus(SecondarySkill skill, int level) const; }; From bbc087b72377f7f3d9b0260010c28bcebface303 Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Mon, 4 Sep 2017 00:25:37 +1200 Subject: [PATCH 50/68] updated authors and changelog --- AUTHORS | 3 +++ ChangeLog | 3 +++ 2 files changed, 6 insertions(+) diff --git a/AUTHORS b/AUTHORS index dd45a8d5b..ec6df8cab 100644 --- a/AUTHORS +++ b/AUTHORS @@ -66,3 +66,6 @@ Dydzio, Piotr Wójcik aka Chocimier, * Various bug fixes + +Henning Koehler, + * skill modding diff --git a/ChangeLog b/ChangeLog index 35695226f..57add05bf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -11,12 +11,15 @@ GENERAL: - CATAPULT_EXTRA_SHOTS - defines number of extra wall attacks for units that can do so - RANGED_RETALIATION - allows ranged counterattack - BLOCKS_RANGED_RETALIATION - disallow enemy ranged counterattack +- SECONDARY_SKILL_VAL2 - set additional parameter for certain secondary skills +- MANUAL_CONTROL - grant manual control over war machine SPELLS: * Implemented cumulative effects for spells MODS: * Improve support for WoG commander artifacts and skill descriptions +* Added basic support for secondary skill modding 0.98 -> 0.99 From df34a2cc969bc9afe3ecde88d97223b52519ddb1 Mon Sep 17 00:00:00 2001 From: AlexVinS Date: Sun, 3 Sep 2017 23:38:15 +0300 Subject: [PATCH 51/68] Dirty hackfix for https://bugs.vcmi.eu/view.php?id=2780 --- client/gui/CAnimation.cpp | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/client/gui/CAnimation.cpp b/client/gui/CAnimation.cpp index 37563b7ac..301978061 100644 --- a/client/gui/CAnimation.cpp +++ b/client/gui/CAnimation.cpp @@ -253,10 +253,26 @@ static CFileCache animationCache; * DefFile, class used for def loading * *************************************************************************/ +bool operator== (const SDL_Color & lhs, const SDL_Color & rhs) +{ + return (lhs.a == rhs.a) && (lhs.b == rhs.b) &&(lhs.g == rhs.g) &&(lhs.r == rhs.r); +} + CDefFile::CDefFile(std::string Name): data(nullptr), palette(nullptr) { + static SDL_Color H3_ORIG_PALETTE[8] = + { + { 0, 255, 255, SDL_ALPHA_OPAQUE}, + {255, 150, 255, SDL_ALPHA_OPAQUE}, + {255, 100, 255, SDL_ALPHA_OPAQUE}, + {255, 50, 255, SDL_ALPHA_OPAQUE}, + {255, 0, 255, SDL_ALPHA_OPAQUE}, + {255, 255, 0, SDL_ALPHA_OPAQUE}, + {180, 0, 255, SDL_ALPHA_OPAQUE}, + { 0, 255, 0, SDL_ALPHA_OPAQUE} + }; //First 8 colors in def palette used for transparency static SDL_Color H3Palette[8] = { @@ -292,7 +308,17 @@ CDefFile::CDefFile(std::string Name): if (type == 71 || type == 64)//Buttons/buildings don't have shadows\semi-transparency memset(palette.get(), 0, sizeof(SDL_Color)*2); else - memcpy(palette.get(), H3Palette, sizeof(SDL_Color)*8);//initialize shadow\selection colors + { + //TODO: more accurate conversion + memcpy(palette.get(), H3Palette, sizeof(SDL_Color)*2); + + for(int i = 2; i < 8; i++) + { + if(palette[i] == H3_ORIG_PALETTE[i]) + palette[i] = H3Palette[i]; + } + } + for (ui32 i=0; i Date: Tue, 5 Sep 2017 00:30:43 +1200 Subject: [PATCH 52/68] fixed manual control for arrow towers --- config/skills.json | 6 ++++++ server/CGameHandler.cpp | 5 +++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/config/skills.json b/config/skills.json index 6519fae12..fff3480d3 100644 --- a/config/skills.json +++ b/config/skills.json @@ -579,6 +579,12 @@ "type" : "MANUAL_CONTROL", "val" : 100, "valueType" : "BASE_NUMBER" + }, + "ctrl2" : { + "subtype" : "creature.arrowTower", + "type" : "MANUAL_CONTROL", + "val" : 100, + "valueType" : "BASE_NUMBER" } } }, diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 2dfaacd75..d34639483 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -5797,9 +5797,10 @@ void CGameHandler::runBattle() } const CGHeroInstance * curOwner = battleGetOwnerHero(next); + const int stackCreatureId = next->getCreature()->idNumber; - if ((next->position < 0 || next->getCreature()->idNumber == CreatureID::BALLISTA) //arrow turret or ballista - && (!curOwner || getRandomGenerator().nextInt(99) >= curOwner->valOfBonuses(Bonus::MANUAL_CONTROL, CreatureID::BALLISTA))) + if ((stackCreatureId == CreatureID::ARROW_TOWERS || stackCreatureId == CreatureID::BALLISTA) + && (!curOwner || getRandomGenerator().nextInt(99) >= curOwner->valOfBonuses(Bonus::MANUAL_CONTROL, stackCreatureId))) { BattleAction attack; attack.actionType = Battle::SHOOT; From b964a53abef4342d056a259a15008da737743dca Mon Sep 17 00:00:00 2001 From: AlexVinS Date: Mon, 4 Sep 2017 17:52:36 +0300 Subject: [PATCH 53/68] Fixed battle animation --- client/battle/CCreatureAnimation.cpp | 6 +-- client/gui/CAnimation.cpp | 76 ++++++++++++++++++++++++---- 2 files changed, 68 insertions(+), 14 deletions(-) diff --git a/client/battle/CCreatureAnimation.cpp b/client/battle/CCreatureAnimation.cpp index bbd94eb50..d5262aa8d 100644 --- a/client/battle/CCreatureAnimation.cpp +++ b/client/battle/CCreatureAnimation.cpp @@ -291,8 +291,8 @@ std::array CCreatureAnimation::genSpecialPalette() ret[0] = genShadow(0); ret[1] = genShadow(64); - ret[2] = genShadow(128); - ret[3] = genShadow(128); + ret[2] = genShadow(128);//unused + ret[3] = genShadow(128);//unused ret[4] = genShadow(128); ret[5] = genBorderColor(getBorderStrength(elapsedTime), border); ret[6] = addColors(genShadow(128), genBorderColor(getBorderStrength(elapsedTime), border)); @@ -412,7 +412,7 @@ inline void CCreatureAnimation::putPixelAt(SDL_Surface * dest, int X, int Y, siz template inline void CCreatureAnimation::putPixel(ui8 * dest, const SDL_Color & color, size_t index, const std::array & special) const { - if (index < 8) + if((index <= 1) || (index >=4 && index < 8)) { const SDL_Color & pal = special[index]; ColorPutter::PutColor(dest, pal.r, pal.g, pal.b, pal.a); diff --git a/client/gui/CAnimation.cpp b/client/gui/CAnimation.cpp index 301978061..6a7ab5cfb 100644 --- a/client/gui/CAnimation.cpp +++ b/client/gui/CAnimation.cpp @@ -247,6 +247,20 @@ public: } }; +enum class DefType : uint32_t +{ + SPELL = 0x40, + UNUSED_1 = 0x41, + CREATURE = 0x42, + MAP = 0x43, + MAP_HERO = 0x44, + TERRAIN = 0x45, + CURSOR = 0x46, + INTERFACE = 0x47, + UNUSED_2 = 0x48, + BATTLE_HERO = 0x49 +}; + static CFileCache animationCache; /************************************************************************* @@ -262,6 +276,8 @@ CDefFile::CDefFile(std::string Name): data(nullptr), palette(nullptr) { + + #if 0 static SDL_Color H3_ORIG_PALETTE[8] = { { 0, 255, 255, SDL_ALPHA_OPAQUE}, @@ -273,6 +289,8 @@ CDefFile::CDefFile(std::string Name): {180, 0, 255, SDL_ALPHA_OPAQUE}, { 0, 255, 0, SDL_ALPHA_OPAQUE} }; + #endif // 0 + //First 8 colors in def palette used for transparency static SDL_Color H3Palette[8] = { @@ -305,18 +323,54 @@ CDefFile::CDefFile(std::string Name): palette[i].b = data[it++]; palette[i].a = SDL_ALPHA_OPAQUE; } - if (type == 71 || type == 64)//Buttons/buildings don't have shadows\semi-transparency - memset(palette.get(), 0, sizeof(SDL_Color)*2); - else - { - //TODO: more accurate conversion - memcpy(palette.get(), H3Palette, sizeof(SDL_Color)*2); - for(int i = 2; i < 8; i++) - { - if(palette[i] == H3_ORIG_PALETTE[i]) - palette[i] = H3Palette[i]; - } + switch(static_cast(type)) + { + case DefType::SPELL: + palette[0] = H3Palette[0]; + break; + case DefType::CREATURE: + palette[0] = H3Palette[0]; + palette[1] = H3Palette[1]; + palette[4] = H3Palette[4]; + palette[5] = H3Palette[5]; + palette[6] = H3Palette[6]; + palette[7] = H3Palette[7]; + break; + case DefType::MAP: + palette[0] = H3Palette[0]; + palette[1] = H3Palette[1]; + palette[4] = H3Palette[4]; + //5 = owner flag, handled separately + break; + case DefType::MAP_HERO: + palette[0] = H3Palette[0]; + palette[1] = H3Palette[1]; + palette[4] = H3Palette[4]; + //5 = owner flag, handled separately + break; + case DefType::TERRAIN: + palette[0] = H3Palette[0]; + palette[1] = H3Palette[1]; + palette[2] = H3Palette[2]; + palette[3] = H3Palette[3]; + palette[4] = H3Palette[4]; + break; + case DefType::CURSOR: + palette[0] = H3Palette[0]; + break; + case DefType::INTERFACE: + palette[0] = H3Palette[0]; + palette[1] = H3Palette[1]; + palette[4] = H3Palette[4]; + break; + case DefType::BATTLE_HERO: + //TODO: + logAnim->error("Unimplemented def type %d in %s", type, Name); + break; + default: + logAnim->error("Unknown def type %d in %s", type, Name); + break; } From 2f7968b803753a42fb5ef1e8ad3426b51776ab1f Mon Sep 17 00:00:00 2001 From: AlexVinS Date: Mon, 4 Sep 2017 18:41:22 +0300 Subject: [PATCH 54/68] Fixed wrong animation paths --- client/gui/CAnimation.cpp | 3 +++ lib/mapObjects/ObjectTemplate.cpp | 2 ++ 2 files changed, 5 insertions(+) diff --git a/client/gui/CAnimation.cpp b/client/gui/CAnimation.cpp index 6a7ab5cfb..20e921207 100644 --- a/client/gui/CAnimation.cpp +++ b/client/gui/CAnimation.cpp @@ -1468,6 +1468,9 @@ CAnimation::CAnimation(std::string Name, bool Compressed): CDefFile * file = getFile(); init(file); delete file; + + if(source.empty()) + logAnim->error("Animation %s failed to load", Name); } CAnimation::CAnimation(): diff --git a/lib/mapObjects/ObjectTemplate.cpp b/lib/mapObjects/ObjectTemplate.cpp index 114d338f9..7a554db67 100644 --- a/lib/mapObjects/ObjectTemplate.cpp +++ b/lib/mapObjects/ObjectTemplate.cpp @@ -101,6 +101,8 @@ void ObjectTemplate::afterLoadFixup() usedTiles[0][0] = VISITABLE; visitDir = 0xFF; } + boost::algorithm::replace_all(animationFile, "\\", "/"); + boost::algorithm::replace_all(editorAnimationFile, "\\", "/"); } void ObjectTemplate::readTxt(CLegacyConfigParser & parser) From 3a9d73da23127afcb4e33ce1d4d1a93def0fe31f Mon Sep 17 00:00:00 2001 From: AlexVinS Date: Tue, 5 Sep 2017 14:31:34 +0300 Subject: [PATCH 55/68] [c::b] Update project, fixed build --- client/CGameInfo.cpp | 4 ++-- lib/VCMI_lib.cbp | 54 +++++++++++++++++++++++--------------------- 2 files changed, 30 insertions(+), 28 deletions(-) diff --git a/client/CGameInfo.cpp b/client/CGameInfo.cpp index ea58466fd..128169d09 100644 --- a/client/CGameInfo.cpp +++ b/client/CGameInfo.cpp @@ -9,8 +9,8 @@ */ #include "StdInc.h" #include "CGameInfo.h" -#include "CSkillHandler.h" -#include "CGeneralTextHandler.h" +#include "../lib/CSkillHandler.h" +#include "../lib/CGeneralTextHandler.h" #include "../lib/VCMI_Lib.h" diff --git a/lib/VCMI_lib.cbp b/lib/VCMI_lib.cbp index 989d3b8ea..a6441d147 100644 --- a/lib/VCMI_lib.cbp +++ b/lib/VCMI_lib.cbp @@ -125,30 +125,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - @@ -177,14 +153,14 @@ - - + + @@ -230,6 +206,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + From ce4b206472a1f856ade1ef278ff13281b2312180 Mon Sep 17 00:00:00 2001 From: AlexVinS Date: Tue, 5 Sep 2017 14:32:52 +0300 Subject: [PATCH 56/68] More complete support of .def format --- client/gui/CAnimation.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/client/gui/CAnimation.cpp b/client/gui/CAnimation.cpp index 20e921207..48768709a 100644 --- a/client/gui/CAnimation.cpp +++ b/client/gui/CAnimation.cpp @@ -250,14 +250,14 @@ public: enum class DefType : uint32_t { SPELL = 0x40, - UNUSED_1 = 0x41, + SPRITE = 0x41, CREATURE = 0x42, MAP = 0x43, MAP_HERO = 0x44, TERRAIN = 0x45, CURSOR = 0x46, INTERFACE = 0x47, - UNUSED_2 = 0x48, + SPRITE_FRAME = 0x48, BATTLE_HERO = 0x49 }; @@ -329,6 +329,11 @@ CDefFile::CDefFile(std::string Name): case DefType::SPELL: palette[0] = H3Palette[0]; break; + case DefType::SPRITE: + case DefType::SPRITE_FRAME: + for(ui32 i= 0; i<8; i++) + palette[i] = H3Palette[i]; + break; case DefType::CREATURE: palette[0] = H3Palette[0]; palette[1] = H3Palette[1]; @@ -338,11 +343,6 @@ CDefFile::CDefFile(std::string Name): palette[7] = H3Palette[7]; break; case DefType::MAP: - palette[0] = H3Palette[0]; - palette[1] = H3Palette[1]; - palette[4] = H3Palette[4]; - //5 = owner flag, handled separately - break; case DefType::MAP_HERO: palette[0] = H3Palette[0]; palette[1] = H3Palette[1]; @@ -363,10 +363,13 @@ CDefFile::CDefFile(std::string Name): palette[0] = H3Palette[0]; palette[1] = H3Palette[1]; palette[4] = H3Palette[4]; + //player colors handled separately + //TODO: disallow colorizing other def types break; case DefType::BATTLE_HERO: - //TODO: - logAnim->error("Unimplemented def type %d in %s", type, Name); + palette[0] = H3Palette[0]; + palette[1] = H3Palette[1]; + palette[4] = H3Palette[4]; break; default: logAnim->error("Unknown def type %d in %s", type, Name); From a8d25ea7b2b149dbf0967130f3ee1aa697a62ff9 Mon Sep 17 00:00:00 2001 From: AlexVinS Date: Fri, 28 Oct 2016 13:27:45 +0300 Subject: [PATCH 57/68] CHeroWindow tweaks # Conflicts: # AI/FuzzyLite # client/windows/CHeroWindow.cpp --- client/windows/CHeroWindow.cpp | 25 ++++++++++++------------- client/windows/CHeroWindow.h | 1 - 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/client/windows/CHeroWindow.cpp b/client/windows/CHeroWindow.cpp index a7f69fdc6..8a6dce30b 100644 --- a/client/windows/CHeroWindow.cpp +++ b/client/windows/CHeroWindow.cpp @@ -24,6 +24,7 @@ #include "../gui/SDL_Extensions.h" #include "../gui/CGuiHandler.h" +#include "../gui/CAnimation.h" #include "../widgets/MiscWidgets.h" #include "../widgets/CComponent.h" @@ -107,7 +108,7 @@ CHeroWindow::CHeroWindow(const CGHeroInstance *hero): quitButton = new CButton(Point(609, 516), "hsbtns.def", CButton::tooltip(heroscrn[17]), [&](){ close(); }, SDLK_RETURN); quitButton->assignedKeys.insert(SDLK_ESCAPE); dismissButton = new CButton(Point(454, 429), "hsbtns2.def", CButton::tooltip(heroscrn[28]), [&](){ dismissCurrent(); }, SDLK_d); - questlogButton = new CButton(Point(314, 429), "hsbtns4.def", CButton::tooltip(heroscrn[0]), [&](){ questlog(); }, SDLK_q); + questlogButton = new CButton(Point(314, 429), "hsbtns4.def", CButton::tooltip(heroscrn[0]), [=](){ LOCPLINT->showQuestLog(); }, SDLK_q); formations = new CToggleGroup(0); formations->addToggle(0, new CToggleButton(Point(481, 483), "hsbtns6.def", std::make_pair(heroscrn[23], heroscrn[29]), 0, SDLK_t)); @@ -144,11 +145,12 @@ CHeroWindow::CHeroWindow(const CGHeroInstance *hero): luck = new MoraleLuckBox(false, Rect(233,179,53,45)); spellPointsArea = new LRClickableAreaWText(Rect(162,228, 136, 42), CGI->generaltexth->heroscrn[22]); + auto secSkills = std::make_shared("SECSKILL"); for(int i = 0; i < std::min(hero->secSkills.size(), 8u); ++i) { Rect r = Rect(i%2 == 0 ? 18 : 162, 276 + 48 * (i/2), 136, 42); secSkillAreas.push_back(new LRClickableAreaWTextComp(r, CComponent::secskill)); - secSkillImages.push_back(new CAnimImage("SECSKILL", 0, 0, r.x, r.y)); + secSkillImages.push_back(new CAnimImage(secSkills, 0, 0, r.x, r.y)); } //dismiss / quest log @@ -158,12 +160,14 @@ CHeroWindow::CHeroWindow(const CGHeroInstance *hero): //////////////////////////////////////////////////////////////////////////??????????????? //primary skills & exp and mana - new CAnimImage("PSKIL42", 0, 0, 32, 111, false); - new CAnimImage("PSKIL42", 1, 0, 102, 111, false); - new CAnimImage("PSKIL42", 2, 0, 172, 111, false); - new CAnimImage("PSKIL42", 3, 0, 162, 230, false); - new CAnimImage("PSKIL42", 4, 0, 20, 230, false); - new CAnimImage("PSKIL42", 5, 0, 242, 111, false); + auto primSkills = std::make_shared("PSKIL42"); + primSkills->preload(); + new CAnimImage(primSkills, 0, 0, 32, 111); + new CAnimImage(primSkills, 1, 0, 102, 111); + new CAnimImage(primSkills, 2, 0, 172, 111); + new CAnimImage(primSkills, 3, 0, 162, 230); + new CAnimImage(primSkills, 4, 0, 20, 230); + new CAnimImage(primSkills, 5, 0, 242, 111); // various texts new CLabel( 52, 99, FONT_SMALL, CENTER, Colors::YELLOW, CGI->generaltexth->jktexts[1]); @@ -306,11 +310,6 @@ void CHeroWindow::dismissCurrent() LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[22], ony, 0, false); } -void CHeroWindow::questlog() -{ - LOCPLINT->showQuestLog(); -} - void CHeroWindow::commanderWindow() { //TODO: allow equipping commander artifacts by drag / drop diff --git a/client/windows/CHeroWindow.h b/client/windows/CHeroWindow.h index efb0b0a6f..40c9788fa 100644 --- a/client/windows/CHeroWindow.h +++ b/client/windows/CHeroWindow.h @@ -86,7 +86,6 @@ public: void showAll(SDL_Surface * to) override; void dismissCurrent(); //dissmissed currently displayed hero (curHero) - void questlog(); //show quest log in hero window void commanderWindow(); void switchHero(); //changes displayed hero virtual void updateGarrisons() override; //updates the morale widget and calls the parent From 9423555015d1f7e3e085a516624fb2d3c2e17fce Mon Sep 17 00:00:00 2001 From: AlexVinS Date: Fri, 28 Oct 2016 13:39:16 +0300 Subject: [PATCH 58/68] Declare ownership of CCursorHandler::dndObject # Conflicts: # AI/FuzzyLite # client/gui/CGuiHandler.cpp --- client/gui/CCursorHandler.cpp | 11 +++-------- client/gui/CCursorHandler.h | 13 +++++++------ client/gui/CGuiHandler.cpp | 3 +-- client/widgets/CArtifactHolder.cpp | 4 ++-- client/windows/CTradeWindow.cpp | 2 +- 5 files changed, 14 insertions(+), 19 deletions(-) diff --git a/client/gui/CCursorHandler.cpp b/client/gui/CCursorHandler.cpp index 71b68c230..8321e3fde 100644 --- a/client/gui/CCursorHandler.cpp +++ b/client/gui/CCursorHandler.cpp @@ -27,7 +27,7 @@ void CCursorHandler::initCursor() help = CSDL_Ext::newSurface(40,40); //No blending. Ensure, that we are copying pixels during "screen restore draw" - SDL_SetSurfaceBlendMode(help,SDL_BLENDMODE_NONE); + SDL_SetSurfaceBlendMode(help,SDL_BLENDMODE_NONE); SDL_ShowCursor(SDL_DISABLE); changeGraphic(ECursor::ADVENTURE, 0); @@ -55,12 +55,9 @@ void CCursorHandler::changeGraphic(ECursor::ECursorTypes type, int index) } } -void CCursorHandler::dragAndDropCursor(CAnimImage * object) +void CCursorHandler::dragAndDropCursor(std::unique_ptr object) { - if (dndObject) - delete dndObject; - - dndObject = object; + dndObject = std::move(object); } void CCursorHandler::cursorMove(const int & x, const int & y) @@ -233,12 +230,10 @@ void CCursorHandler::render() drawRestored(); } - CCursorHandler::~CCursorHandler() { if(help) SDL_FreeSurface(help); delete currentCursor; - delete dndObject; } diff --git a/client/gui/CCursorHandler.h b/client/gui/CCursorHandler.h index b61889fab..0120eda51 100644 --- a/client/gui/CCursorHandler.h +++ b/client/gui/CCursorHandler.h @@ -17,18 +17,19 @@ namespace ECursor enum ECursorTypes { ADVENTURE, COMBAT, DEFAULT, SPELLBOOK }; enum EBattleCursors { COMBAT_BLOCKED, COMBAT_MOVE, COMBAT_FLY, COMBAT_SHOOT, - COMBAT_HERO, COMBAT_QUERY, COMBAT_POINTER, + COMBAT_HERO, COMBAT_QUERY, COMBAT_POINTER, //various attack frames COMBAT_SHOOT_PENALTY = 15, COMBAT_SHOOT_CATAPULT, COMBAT_HEAL, COMBAT_SACRIFICE, COMBAT_TELEPORT}; } /// handles mouse cursor -class CCursorHandler +class CCursorHandler { SDL_Surface * help; CAnimImage * currentCursor; - CAnimImage * dndObject; //if set, overrides currentCursor + + std::unique_ptr dndObject; //if set, overrides currentCursor bool showing; /// Draw cursor preserving original image below cursor @@ -37,7 +38,7 @@ class CCursorHandler void drawRestored(); /// Simple draw cursor void draw(SDL_Surface *to); - + public: /// position of cursor int xpos, ypos; @@ -58,8 +59,8 @@ public: * @param image Image to replace cursor with or nullptr to use the normal * cursor. CursorHandler takes ownership of object */ - void dragAndDropCursor (CAnimImage * image); - + void dragAndDropCursor (std::unique_ptr image); + void render(); void shiftPos( int &x, int &y ); diff --git a/client/gui/CGuiHandler.cpp b/client/gui/CGuiHandler.cpp index 4b5ce492e..8c52fa944 100644 --- a/client/gui/CGuiHandler.cpp +++ b/client/gui/CGuiHandler.cpp @@ -459,8 +459,7 @@ void CGuiHandler::renderFrame() // draw the mouse cursor and update the screen CCS->curh->render(); - if(0 != SDL_RenderCopy(mainRenderer, screenTexture, nullptr, nullptr)) - logGlobal->error("%s SDL_RenderCopy %s", __FUNCTION__, SDL_GetError()); + SDL_RenderCopy(mainRenderer, screenTexture, nullptr, nullptr); SDL_RenderPresent(mainRenderer); } diff --git a/client/widgets/CArtifactHolder.cpp b/client/widgets/CArtifactHolder.cpp index df7267236..9b12c925f 100644 --- a/client/widgets/CArtifactHolder.cpp +++ b/client/widgets/CArtifactHolder.cpp @@ -290,7 +290,7 @@ void CHeroArtPlace::select () } } - CCS->curh->dragAndDropCursor(new CAnimImage("artifact", ourArt->artType->iconIndex)); + CCS->curh->dragAndDropCursor(make_unique("artifact", ourArt->artType->iconIndex)); ourOwner->commonInfo->src.setTo(this, false); ourOwner->markPossibleSlots(ourArt); @@ -766,7 +766,7 @@ void CArtifactsOfHero::artifactMoved(const ArtifactLocation &src, const Artifact commonInfo->src.art = dst.getArt(); commonInfo->src.slotID = dst.slot; assert(commonInfo->src.AOH); - CCS->curh->dragAndDropCursor(new CAnimImage("artifact", dst.getArt()->artType->iconIndex)); + CCS->curh->dragAndDropCursor(make_unique("artifact", dst.getArt()->artType->iconIndex)); markPossibleSlots(dst.getArt()); } } diff --git a/client/windows/CTradeWindow.cpp b/client/windows/CTradeWindow.cpp index 42d248595..d27193d7a 100644 --- a/client/windows/CTradeWindow.cpp +++ b/client/windows/CTradeWindow.cpp @@ -187,7 +187,7 @@ void CTradeWindow::CTradeableItem::clickLeft(tribool down, bool previousState) aw->arts->markPossibleSlots(art); //aw->arts->commonInfo->dst.AOH = aw->arts; - CCS->curh->dragAndDropCursor(new CAnimImage("artifact", art->artType->iconIndex)); + CCS->curh->dragAndDropCursor(make_unique("artifact", art->artType->iconIndex)); aw->arts->artifactsOnAltar.erase(art); setID(-1); From 69c664389375dc7859cdfa3a933beb7ff9ca5ea1 Mon Sep 17 00:00:00 2001 From: AlexVinS Date: Fri, 28 Oct 2016 14:03:26 +0300 Subject: [PATCH 59/68] More CCursorHandler style tweaks # Conflicts: # AI/FuzzyLite --- client/gui/CCursorHandler.cpp | 38 ++++++++++++++++------------------- client/gui/CCursorHandler.h | 9 +++++---- 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/client/gui/CCursorHandler.cpp b/client/gui/CCursorHandler.cpp index 8321e3fde..9bcfe3a62 100644 --- a/client/gui/CCursorHandler.cpp +++ b/client/gui/CCursorHandler.cpp @@ -23,7 +23,16 @@ void CCursorHandler::initCursor() xpos = ypos = 0; type = ECursor::DEFAULT; dndObject = nullptr; - currentCursor = nullptr; + + cursors = + { + make_unique("CRADVNTR", 0), + make_unique("CRCOMBAT", 0), + make_unique("CRDEFLT", 0), + make_unique("CRSPELL", 0) + }; + + currentCursor = cursors.at(int(ECursor::DEFAULT)).get(); help = CSDL_Ext::newSurface(40,40); //No blending. Ensure, that we are copying pixels during "screen restore draw" @@ -35,22 +44,16 @@ void CCursorHandler::initCursor() void CCursorHandler::changeGraphic(ECursor::ECursorTypes type, int index) { - std::string cursorDefs[4] = { "CRADVNTR.DEF", "CRCOMBAT.DEF", "CRDEFLT.DEF", "CRSPELL.DEF" }; - - if (type != this->type) + if(type != this->type) { - BLOCK_CAPTURING; // not used here - this->type = type; this->frame = index; - - delete currentCursor; - currentCursor = new CAnimImage(cursorDefs[int(type)], index); + currentCursor = cursors.at(int(type)).get(); + currentCursor->setFrame(index); } - - if (frame != index) + else if(index != this->frame) { - frame = index; + this->frame = index; currentCursor->setFrame(index); } } @@ -98,13 +101,6 @@ void CCursorHandler::drawRestored() SDL_Rect temp_rect = genRect(40, 40, x, y); SDL_BlitSurface(help, nullptr, screen, &temp_rect); - //blitAt(help,x,y); -} - -void CCursorHandler::draw(SDL_Surface *to) -{ - currentCursor->moveTo(Point(xpos, ypos)); - currentCursor->showAll(screen); } void CCursorHandler::shiftPos( int &x, int &y ) @@ -230,10 +226,10 @@ void CCursorHandler::render() drawRestored(); } +CCursorHandler::CCursorHandler() = default; + CCursorHandler::~CCursorHandler() { if(help) SDL_FreeSurface(help); - - delete currentCursor; } diff --git a/client/gui/CCursorHandler.h b/client/gui/CCursorHandler.h index 0120eda51..ae9d727b1 100644 --- a/client/gui/CCursorHandler.h +++ b/client/gui/CCursorHandler.h @@ -24,21 +24,21 @@ namespace ECursor } /// handles mouse cursor -class CCursorHandler +class CCursorHandler final { SDL_Surface * help; CAnimImage * currentCursor; std::unique_ptr dndObject; //if set, overrides currentCursor + + std::array, 4> cursors; + bool showing; /// Draw cursor preserving original image below cursor void drawWithScreenRestore(); /// Restore original image below cursor void drawRestored(); - /// Simple draw cursor - void draw(SDL_Surface *to); - public: /// position of cursor int xpos, ypos; @@ -72,5 +72,6 @@ public: /// Move cursor to screen center void centerCursor(); + CCursorHandler(); ~CCursorHandler(); }; From 882e279818591c5980d030830b4240247aa59fbd Mon Sep 17 00:00:00 2001 From: AlexVinS Date: Tue, 5 Sep 2017 16:44:27 +0300 Subject: [PATCH 60/68] Use CAnimation in CBattleInterfaceClasses --- client/battle/CBattleInterface.cpp | 11 ++- client/battle/CBattleInterfaceClasses.cpp | 93 +++++++++++------------ client/battle/CBattleInterfaceClasses.h | 12 ++- client/gui/CAnimation.cpp | 23 +++++- client/gui/CAnimation.h | 4 + 5 files changed, 88 insertions(+), 55 deletions(-) diff --git a/client/battle/CBattleInterface.cpp b/client/battle/CBattleInterface.cpp index add4babdc..794807bcf 100644 --- a/client/battle/CBattleInterface.cpp +++ b/client/battle/CBattleInterface.cpp @@ -23,6 +23,7 @@ #include "../CPlayerInterface.h" #include "../CVideoHandler.h" #include "../Graphics.h" +#include "../gui/CAnimation.h" #include "../gui/CCursorHandler.h" #include "../gui/CGuiHandler.h" #include "../gui/SDL_Extensions.h" @@ -263,7 +264,10 @@ CBattleInterface::CBattleInterface(const CCreatureSet *army1, const CCreatureSet battleImage = hero1->type->heroClass->imageBattleMale; attackingHero = new CBattleHero(battleImage, false, hero1->tempOwner, hero1->tempOwner == curInt->playerID ? hero1 : nullptr, this); - attackingHero->pos = genRect(attackingHero->dh->ourImages[0].bitmap->h, attackingHero->dh->ourImages[0].bitmap->w, pos.x - 43, pos.y - 19); + + IImage * img = attackingHero->animation->getImage(0, 0, true); + if(img) + attackingHero->pos = genRect(img->height(), img->width(), pos.x - 43, pos.y - 19); } else { @@ -278,7 +282,10 @@ CBattleInterface::CBattleInterface(const CCreatureSet *army1, const CCreatureSet battleImage = hero2->type->heroClass->imageBattleMale; defendingHero = new CBattleHero(battleImage, true, hero2->tempOwner, hero2->tempOwner == curInt->playerID ? hero2 : nullptr, this); - defendingHero->pos = genRect(defendingHero->dh->ourImages[0].bitmap->h, defendingHero->dh->ourImages[0].bitmap->w, pos.x + 693, pos.y - 19); + + IImage * img = defendingHero->animation->getImage(0, 0, true); + if(img) + defendingHero->pos = genRect(img->height(), img->width(), pos.x + 693, pos.y - 19); } else { diff --git a/client/battle/CBattleInterfaceClasses.cpp b/client/battle/CBattleInterfaceClasses.cpp index 688991469..2853482c0 100644 --- a/client/battle/CBattleInterfaceClasses.cpp +++ b/client/battle/CBattleInterfaceClasses.cpp @@ -13,13 +13,13 @@ #include "CBattleInterface.h" #include "../CBitmapHandler.h" -#include "../CDefHandler.h" #include "../CGameInfo.h" #include "../CMessage.h" #include "../CMusicHandler.h" #include "../CPlayerInterface.h" #include "../CVideoHandler.h" #include "../Graphics.h" +#include "../gui/CAnimation.h" #include "../gui/CCursorHandler.h" #include "../gui/CGuiHandler.h" #include "../gui/SDL_Extensions.h" @@ -129,13 +129,18 @@ CBattleConsole::CBattleConsole() : lastShown(-1), alterTxt(""), whoSetAlter(0) void CBattleHero::show(SDL_Surface * to) { + IImage * flagFrame = flagAnimation->getImage(flagAnim, 0, true); + + if(!flagFrame) + return; + //animation of flag SDL_Rect temp_rect; if(flip) { temp_rect = genRect( - flag->ourImages[flagAnim].bitmap->h, - flag->ourImages[flagAnim].bitmap->w, + flagFrame->height(), + flagFrame->width(), pos.x + 61, pos.y + 39); @@ -143,28 +148,30 @@ void CBattleHero::show(SDL_Surface * to) else { temp_rect = genRect( - flag->ourImages[flagAnim].bitmap->h, - flag->ourImages[flagAnim].bitmap->w, + flagFrame->height(), + flagFrame->width(), pos.x + 72, pos.y + 39); } - CSDL_Ext::blit8bppAlphaTo24bpp( - flag->ourImages[flagAnim].bitmap, - nullptr, - screen, - &temp_rect); + + flagFrame->draw(screen, &temp_rect, nullptr); //FIXME: why screen? //animation of hero SDL_Rect rect = pos; - CSDL_Ext::blit8bppAlphaTo24bpp(dh->ourImages[currentFrame].bitmap, nullptr, to, &rect); - if ( ++animCount == 4 ) + IImage * heroFrame = animation->getImage(currentFrame, phase, true); + if(!heroFrame) + return; + + heroFrame->draw(to, &rect, nullptr); + + if(++animCount >= 4) { animCount = 0; - if ( ++flagAnim >= flag->ourImages.size()) + if(++flagAnim >= flagAnimation->size(0)) flagAnim = 0; - if ( ++currentFrame >= lastFrame) + if(++currentFrame >= lastFrame) switchToNextPhase(); } } @@ -190,7 +197,13 @@ void CBattleHero::clickLeft(tribool down, bool previousState) if(myOwner->spellDestSelectMode) //we are casting a spell return; - if(myHero != nullptr && !down && myOwner->myTurn && myOwner->getCurrentPlayerInterface()->cb->battleCanCastSpell(myHero, ECastingMode::HERO_CASTING) == ESpellCastProblem::OK) //check conditions + if(boost::logic::indeterminate(down)) + return; + + if(!myHero || down || !myOwner->myTurn) + return; + + if(myOwner->getCurrentPlayerInterface()->cb->battleCanCastSpell(myHero, ECastingMode::HERO_CASTING) == ESpellCastProblem::OK) //check conditions { for(int it=0; itpos.topLeft().x + 1 : myOwner->pos.topRight().x - 79; windowPosition.y = myOwner->pos.y + 135; @@ -220,24 +236,19 @@ void CBattleHero::clickRight(tribool down, bool previousState) void CBattleHero::switchToNextPhase() { - if (phase != nextPhase) + if(phase != nextPhase) { phase = nextPhase; - //find first and last frames of our animation - for (firstFrame = 0; - firstFrame < dh->ourImages.size() && dh->ourImages[firstFrame].groupNumber != phase; - firstFrame++); + firstFrame = 0; - for (lastFrame = firstFrame; - lastFrame < dh->ourImages.size() && dh->ourImages[lastFrame].groupNumber == phase; - lastFrame++); + lastFrame = animation->size(phase); } currentFrame = firstFrame; } -CBattleHero::CBattleHero(const std::string & defName, bool flipG, PlayerColor player, const CGHeroInstance * hero, const CBattleInterface * owner): +CBattleHero::CBattleHero(const std::string & animationPath, bool flipG, PlayerColor player, const CGHeroInstance * hero, const CBattleInterface * owner): flip(flipG), myHero(hero), myOwner(owner), @@ -246,39 +257,25 @@ CBattleHero::CBattleHero(const std::string & defName, bool flipG, PlayerColor pl flagAnim(0), animCount(0) { - dh = CDefHandler::giveDef( defName ); - for(auto & elem : dh->ourImages) //transforming images - { - if(flip) - { - SDL_Surface * hlp = CSDL_Ext::verticalFlip(elem.bitmap); - SDL_FreeSurface(elem.bitmap); - elem.bitmap = hlp; - } - CSDL_Ext::alphaTransform(elem.bitmap); - } + animation = std::make_shared(animationPath); + animation->preload(); + if(flipG) + animation->verticalFlip(); if(flip) - flag = CDefHandler::giveDef("CMFLAGR.DEF"); + flagAnimation = std::make_shared("CMFLAGR"); else - flag = CDefHandler::giveDef("CMFLAGL.DEF"); + flagAnimation = std::make_shared("CMFLAGL"); + + flagAnimation->preload(); + flagAnimation->playerColored(player); - //coloring flag and adding transparency - for(auto & elem : flag->ourImages) - { - CSDL_Ext::alphaTransform(elem.bitmap); - graphics->blueToPlayersAdv(elem.bitmap, player); - } addUsedEvents(LCLICK | RCLICK | HOVER); switchToNextPhase(); } -CBattleHero::~CBattleHero() -{ - delete dh; - delete flag; -} +CBattleHero::~CBattleHero() = default; CBattleOptionsWindow::CBattleOptionsWindow(const SDL_Rect & position, CBattleInterface *owner) { diff --git a/client/battle/CBattleInterfaceClasses.h b/client/battle/CBattleInterfaceClasses.h index 589dafc43..38af30b9a 100644 --- a/client/battle/CBattleInterfaceClasses.h +++ b/client/battle/CBattleInterfaceClasses.h @@ -14,7 +14,6 @@ #include "../windows/CWindowObject.h" struct SDL_Surface; -class CDefHandler; class CGHeroInstance; class CBattleInterface; class CPicture; @@ -53,19 +52,24 @@ class CBattleHero : public CIntObject void switchToNextPhase(); public: bool flip; //false if it's attacking hero, true otherwise - CDefHandler *dh, *flag; //animation and flag + + std::shared_ptr animation; + std::shared_ptr flagAnimation; + const CGHeroInstance * myHero; //this animation's hero instance const CBattleInterface * myOwner; //battle interface to which this animation is assigned int phase; //stage of animation int nextPhase; //stage of animation to be set after current phase is fully displayed int currentFrame, firstFrame, lastFrame; //frame of animation - ui8 flagAnim, animCount; //for flag animation + + size_t flagAnim; + ui8 animCount; //for flag animation void show(SDL_Surface * to) override; //prints next frame of animation to to void setPhase(int newPhase); //sets phase of hero animation void hover(bool on) override; void clickLeft(tribool down, bool previousState) override; //call-in void clickRight(tribool down, bool previousState) override; //call-in - CBattleHero(const std::string &defName, bool filpG, PlayerColor player, const CGHeroInstance *hero, const CBattleInterface *owner); + CBattleHero(const std::string & animationPath, bool filpG, PlayerColor player, const CGHeroInstance * hero, const CBattleInterface * owner); ~CBattleHero(); }; diff --git a/client/gui/CAnimation.cpp b/client/gui/CAnimation.cpp index 48768709a..ce4b56d28 100644 --- a/client/gui/CAnimation.cpp +++ b/client/gui/CAnimation.cpp @@ -29,7 +29,7 @@ typedef std::map > source_map; typedef std::map image_map; typedef std::map group_map; - /// Class for def loading, methods are based on CDefHandler +/// Class for def loading /// After loading will store general info (palette and frame offsets) and pointer to file itself class CDefFile { @@ -1605,6 +1605,27 @@ size_t CAnimation::size(size_t group) const return 0; } +void CAnimation::horizontalFlip() +{ + for(auto & group : images) + for(auto & image : group.second) + image.second->horizontalFlip(); +} + +void CAnimation::verticalFlip() +{ + for(auto & group : images) + for(auto & image : group.second) + image.second->verticalFlip(); +} + +void CAnimation::playerColored(PlayerColor player) +{ + for(auto & group : images) + for(auto & image : group.second) + image.second->playerColored(player); +} + float CFadeAnimation::initialCounter() const { if (fadingMode == EMode::OUT) diff --git a/client/gui/CAnimation.h b/client/gui/CAnimation.h index 319094be5..3b52ed2f0 100644 --- a/client/gui/CAnimation.h +++ b/client/gui/CAnimation.h @@ -127,6 +127,10 @@ public: //total count of frames in group (including not loaded) size_t size(size_t group=0) const; + + void horizontalFlip(); + void verticalFlip(); + void playerColored(PlayerColor player); }; const float DEFAULT_DELTA = 0.05f; From 78b86224a0740667c7cc94d268ce440cbe507d24 Mon Sep 17 00:00:00 2001 From: AlexVinS Date: Tue, 5 Sep 2017 17:21:44 +0300 Subject: [PATCH 61/68] Use CAnimation fro custom battle effects --- client/battle/CBattleAnimations.cpp | 115 +++++++++++++--------------- client/battle/CBattleInterface.cpp | 10 ++- client/battle/CBattleInterface.h | 4 +- 3 files changed, 61 insertions(+), 68 deletions(-) diff --git a/client/battle/CBattleAnimations.cpp b/client/battle/CBattleAnimations.cpp index f6d4eb2a4..6266db763 100644 --- a/client/battle/CBattleAnimations.cpp +++ b/client/battle/CBattleAnimations.cpp @@ -21,6 +21,7 @@ #include "../CMusicHandler.h" #include "../CPlayerInterface.h" #include "../Graphics.h" +#include "../gui/CAnimation.h" #include "../gui/CCursorHandler.h" #include "../gui/CGuiHandler.h" #include "../gui/SDL_Extensions.h" @@ -909,91 +910,82 @@ bool CSpellEffectAnimation::init() const bool areaEffect = (!destTile.isValid() && x == -1 && y == -1); + std::shared_ptr animation = std::make_shared(customAnim); + + animation->preload(); + if(Vflip) + animation->verticalFlip(); + + IImage * first = animation->getImage(0, 0, true); + if(!first) + { + endAnim(); + return false; + } + if(areaEffect) //f.e. armageddon { - CDefHandler * anim = CDefHandler::giveDef(customAnim); - - for(int i=0; i * anim->width < owner->pos.w ; ++i) + for(int i=0; i * first->width() < owner->pos.w ; ++i) { - for(int j=0; j * anim->height < owner->pos.h ; ++j) + for(int j=0; j * first->height() < owner->pos.h ; ++j) { BattleEffect be; be.effectID = ID; - be.anim = CDefHandler::giveDef(customAnim); - if (Vflip) - { - for (auto & elem : be.anim->ourImages) - { - CSDL_Ext::VflipSurf(elem.bitmap); - } - } + be.animation = animation; be.currentFrame = 0; - be.maxFrame = be.anim->ourImages.size(); - be.x = i * anim->width + owner->pos.x; - be.y = j * anim->height + owner->pos.y; + + be.x = i * first->width() + owner->pos.x; + be.y = j * first->height() + owner->pos.y; be.position = BattleHex::INVALID; owner->battleEffects.push_back(be); } } - - delete anim; } else // Effects targeted at a specific creature/hex. { + const CStack * destStack = owner->getCurrentPlayerInterface()->cb->battleGetStackByPos(destTile, false); + Rect & tilePos = owner->bfield[destTile]->pos; + BattleEffect be; + be.effectID = ID; + be.animation = animation; + be.currentFrame = 0; - const CStack* destStack = owner->getCurrentPlayerInterface()->cb->battleGetStackByPos(destTile, false); - Rect & tilePos = owner->bfield[destTile]->pos; - BattleEffect be; - be.effectID = ID; - be.anim = CDefHandler::giveDef(customAnim); - if (Vflip) - { - for (auto & elem : be.anim->ourImages) - { - CSDL_Ext::VflipSurf(elem.bitmap); - } - } - - be.currentFrame = 0; - be.maxFrame = be.anim->ourImages.size(); - - //todo: lightning anim frame count override + //todo: lightning anim frame count override // if(effect == 1) // be.maxFrame = 3; - if(x == -1) - { - be.x = tilePos.x + tilePos.w/2 - be.anim->width/2; - } + if(x == -1) + { + be.x = tilePos.x + tilePos.w/2 - first->width()/2; + } + else + { + be.x = x; + } + + if(y == -1) + { + if(alignToBottom) + be.y = tilePos.y + tilePos.h - first->height(); else - { - be.x = x; - } + be.y = tilePos.y - first->height()/2; + } + else + { + be.y = y; + } - if(y == -1) - { - if(alignToBottom) - be.y = tilePos.y + tilePos.h - be.anim->height; - else - be.y = tilePos.y - be.anim->height/2; - } - else - { - be.y = y; - } + // Correction for 2-hex creatures. + if(destStack != nullptr && destStack->doubleWide()) + be.x += (destStack->side == BattleSide::ATTACKER ? -1 : 1)*tilePos.w/2; - // Correction for 2-hex creatures. - if (destStack != nullptr && destStack->doubleWide()) - be.x += (destStack->side == BattleSide::ATTACKER ? -1 : 1)*tilePos.w/2; - - //Indicate if effect should be drawn on top of everything or just on top of the hex - be.position = destTile; - - owner->battleEffects.push_back(be); + //Indicate if effect should be drawn on top of everything or just on top of the hex + be.position = destTile; + owner->battleEffects.push_back(be); } //battleEffects return true; @@ -1008,7 +1000,7 @@ void CSpellEffectAnimation::nextFrame() { elem.currentFrame += AnimationControls::getSpellEffectSpeed() * GH.mainFPSmng->getElapsedMilliseconds() / 1000; - if(elem.currentFrame >= elem.maxFrame) + if(elem.currentFrame >= elem.animation->size()) { endAnim(); break; @@ -1038,7 +1030,6 @@ void CSpellEffectAnimation::endAnim() for(auto & elem : toDel) { - delete elem->anim; owner->battleEffects.erase(elem); } diff --git a/client/battle/CBattleInterface.cpp b/client/battle/CBattleInterface.cpp index 794807bcf..3ae3a629e 100644 --- a/client/battle/CBattleInterface.cpp +++ b/client/battle/CBattleInterface.cpp @@ -3375,11 +3375,13 @@ void CBattleInterface::showBattleEffects(SDL_Surface *to, const std::vectorcurrentFrame); - currentFrame %= elem->anim->ourImages.size(); + currentFrame %= elem->animation->size(); - SDL_Surface *bitmapToBlit = elem->anim->ourImages[currentFrame].bitmap; - SDL_Rect temp_rect = genRect(bitmapToBlit->h, bitmapToBlit->w, elem->x, elem->y); - SDL_BlitSurface(bitmapToBlit, nullptr, to, &temp_rect); + IImage * img = elem->animation->getImage(currentFrame); + + SDL_Rect temp_rect = genRect(img->height(), img->width(), elem->x, elem->y); + + img->draw(to, &temp_rect, nullptr); } } diff --git a/client/battle/CBattleInterface.h b/client/battle/CBattleInterface.h index ec0aa27a5..638c03d97 100644 --- a/client/battle/CBattleInterface.h +++ b/client/battle/CBattleInterface.h @@ -48,6 +48,7 @@ struct BattleHex; struct InfoAboutHero; struct BattleAction; class CBattleGameInterface; +class CAnimation; /// Small struct which contains information about the id of the attacked stack, the damage dealt,... struct StackAttackedInfo @@ -67,8 +68,7 @@ struct BattleEffect { int x, y; //position on the screen float currentFrame; - int maxFrame; - CDefHandler *anim; //animation to display + std::shared_ptr animation; int effectID; //uniqueID equal ot ID of appropriate CSpellEffectAnim BattleHex position; //Indicates if effect which hex the effect is drawn on }; From 05bb8b13e9e722acd65025fc9111a25c87d6e82b Mon Sep 17 00:00:00 2001 From: AlexVinS Date: Tue, 5 Sep 2017 18:59:26 +0300 Subject: [PATCH 62/68] Use CAnimation for battle creature animation --- client/battle/CCreatureAnimation.cpp | 225 ++++++--------------------- client/battle/CCreatureAnimation.h | 37 +---- client/gui/CAnimation.cpp | 27 +++- client/gui/CAnimation.h | 4 + 4 files changed, 83 insertions(+), 210 deletions(-) diff --git a/client/battle/CCreatureAnimation.cpp b/client/battle/CCreatureAnimation.cpp index d5262aa8d..4903ee76e 100644 --- a/client/battle/CCreatureAnimation.cpp +++ b/client/battle/CCreatureAnimation.cpp @@ -10,14 +10,10 @@ #include "StdInc.h" #include "CCreatureAnimation.h" -#include "../../lib/vcmi_endian.h" #include "../../lib/CConfigHandler.h" #include "../../lib/CCreatureHandler.h" -#include "../../lib/filesystem/Filesystem.h" -#include "../../lib/filesystem/CBinaryReader.h" -#include "../../lib/filesystem/CMemoryStream.h" -#include "../gui/SDL_Pixels.h" +#include "../gui/SDL_Extensions.h" static const SDL_Color creatureBlueBorder = { 0, 255, 255, 255 }; static const SDL_Color creatureGoldBorder = { 255, 255, 0, 255 }; @@ -143,59 +139,40 @@ void CCreatureAnimation::setType(CCreatureAnim::EAnimType type) } CCreatureAnimation::CCreatureAnimation(std::string name, TSpeedController controller) - : defName(name), - speed(0.1), - currentFrame(0), - elapsedTime(0), + : speed(0.1), + currentFrame(0), + elapsedTime(0), type(CCreatureAnim::HOLDING), border(CSDL_Ext::makeColor(0, 0, 0, 0)), - speedController(controller), - once(false) + speedController(controller), + once(false) { - // separate block to avoid accidental use of "data" after it was moved into "pixelData" + forward = std::make_shared(name); + reverse = std::make_shared(name); + + //todo: optimize + forward->preload(); + reverse->preload(); + reverse->verticalFlip(); + + //TODO: get dimensions form CAnimation + IImage * first = forward->getImage(0, type, true); + + if(!first) { - ResourceID resID(std::string("SPRITES/") + name, EResType::ANIMATION); - - auto data = CResourceHandler::get()->load(resID)->readAll(); - - pixelData = std::move(data.first); - pixelDataSize = data.second; - } - - CMemoryStream stm(pixelData.get(), pixelDataSize); - - CBinaryReader reader(&stm); - - reader.readInt32(); // def type, unused - - fullWidth = reader.readInt32(); - fullHeight = reader.readInt32(); - - int totalBlocks = reader.readInt32(); - - for (auto & elem : palette) - { - elem.r = reader.readUInt8(); - elem.g = reader.readUInt8(); - elem.b = reader.readUInt8(); - elem.a = SDL_ALPHA_OPAQUE; - } - - for (int i=0; iwidth(); + fullHeight = first->height(); // if necessary, add one frame into vcmi-only group DEAD - if (dataOffsets.count(CCreatureAnim::DEAD) == 0) - dataOffsets[CCreatureAnim::DEAD].push_back(dataOffsets[CCreatureAnim::DEATH].back()); + if(forward->size(CCreatureAnim::DEAD) == 0) + { + forward->duplicateImage(CCreatureAnim::DEATH, forward->size(CCreatureAnim::DEATH)-1, CCreatureAnim::DEAD); + reverse->duplicateImage(CCreatureAnim::DEATH, reverse->size(CCreatureAnim::DEATH)-1, CCreatureAnim::DEAD); + } play(); } @@ -285,142 +262,38 @@ static SDL_Color addColors(const SDL_Color & base, const SDL_Color & over) ); } -std::array CCreatureAnimation::genSpecialPalette() +void CCreatureAnimation::genBorderPalette(IImage::BorderPallete & target) { - std::array ret; - - ret[0] = genShadow(0); - ret[1] = genShadow(64); - ret[2] = genShadow(128);//unused - ret[3] = genShadow(128);//unused - ret[4] = genShadow(128); - ret[5] = genBorderColor(getBorderStrength(elapsedTime), border); - ret[6] = addColors(genShadow(128), genBorderColor(getBorderStrength(elapsedTime), border)); - ret[7] = addColors(genShadow(64), genBorderColor(getBorderStrength(elapsedTime), border)); - - return ret; + target[0] = genBorderColor(getBorderStrength(elapsedTime), border); + target[1] = addColors(genShadow(128), genBorderColor(getBorderStrength(elapsedTime), border)); + target[2] = addColors(genShadow(64), genBorderColor(getBorderStrength(elapsedTime), border)); } -template -void CCreatureAnimation::nextFrameT(SDL_Surface * dest, bool rotate) -{ - assert(dataOffsets.count(type) && dataOffsets.at(type).size() > size_t(currentFrame)); - ui32 offset = dataOffsets.at(type).at(floor(currentFrame)); - - CMemoryStream stm(pixelData.get(), pixelDataSize); - - CBinaryReader reader(&stm); - - reader.getStream()->seek(offset); - - reader.readUInt32(); // unused, size of pixel data for this frame - const ui32 defType2 = reader.readUInt32(); - const ui32 fullWidth = reader.readUInt32(); - /*const ui32 fullHeight =*/ reader.readUInt32(); - const ui32 spriteWidth = reader.readUInt32(); - const ui32 spriteHeight = reader.readUInt32(); - const int leftMargin = reader.readInt32(); - const int topMargin = reader.readInt32(); - - const int rightMargin = fullWidth - spriteWidth - leftMargin; - //const int bottomMargin = fullHeight - spriteHeight - topMargin; - - const size_t baseOffset = reader.getStream()->tell(); - - assert(defType2 == 1); - UNUSED(defType2); - - auto specialPalette = genSpecialPalette(); - - for (ui32 i=0; i(dest, destX + (rotate?(-j):(j)), destY, lineData[currentOffset + j], specialPalette); - - currentOffset += length; - } - else// RLE - { - if (type != 0) // transparency row, handle it here for speed - { - for (size_t j=0; j(dest, destX + (rotate?(-j):(j)), destY, type, specialPalette); - } - } - - destX += rotate ? (-length) : (length); - totalRowLength += length; - } - } -} void CCreatureAnimation::nextFrame(SDL_Surface *dest, bool attacker) { - // Note: please notice that attacker value is inversed when passed further. - // This is intended behavior because "attacker" actually does not needs rotation - switch(dest->format->BytesPerPixel) - { - case 2: return nextFrameT<2>(dest, !attacker); - case 3: return nextFrameT<3>(dest, !attacker); - case 4: return nextFrameT<4>(dest, !attacker); - default: - logGlobal->error("%d bpp is not supported!", (int)dest->format->BitsPerPixel); - } + size_t frame = floor(currentFrame); + + IImage * image = nullptr; + + if(attacker) + image = forward->getImage(frame, type); + else + image = reverse->getImage(frame, type); + + IImage::BorderPallete borderPallete; + genBorderPalette(borderPallete); + + image->setBorderPallete(borderPallete); + + image->draw(dest, pos.x, pos.y); + } int CCreatureAnimation::framesInGroup(CCreatureAnim::EAnimType group) const { - if(dataOffsets.count(group) == 0) - return 0; - - return dataOffsets.at(group).size(); -} - -ui8 * CCreatureAnimation::getPixelAddr(SDL_Surface * dest, int X, int Y) const -{ - return (ui8*)dest->pixels + X * dest->format->BytesPerPixel + Y * dest->pitch; -} - -template -inline void CCreatureAnimation::putPixelAt(SDL_Surface * dest, int X, int Y, size_t index, const std::array & special) const -{ - if ( X < pos.x + pos.w && Y < pos.y + pos.h && X >= 0 && Y >= 0) - putPixel(getPixelAddr(dest, X, Y), palette[index], index, special); -} - -template -inline void CCreatureAnimation::putPixel(ui8 * dest, const SDL_Color & color, size_t index, const std::array & special) const -{ - if((index <= 1) || (index >=4 && index < 8)) - { - const SDL_Color & pal = special[index]; - ColorPutter::PutColor(dest, pal.r, pal.g, pal.b, pal.a); - } - else - { - ColorPutter::PutColor(dest, color.r, color.g, color.b); - } + return forward->size(group); } bool CCreatureAnimation::isDead() const diff --git a/client/battle/CCreatureAnimation.h b/client/battle/CCreatureAnimation.h index 53386b55e..a9e03f510 100644 --- a/client/battle/CCreatureAnimation.h +++ b/client/battle/CCreatureAnimation.h @@ -10,8 +10,8 @@ #pragma once #include "../../lib/FunctionList.h" -#include "../gui/SDL_Extensions.h" #include "../widgets/Images.h" +#include "../gui/CAnimation.h" class CIntObject; class CCreatureAnimation; @@ -52,21 +52,11 @@ public: typedef std::function TSpeedController; private: - std::string defName; + std::shared_ptr forward; + std::shared_ptr reverse; - int fullWidth, fullHeight; - - // palette, as read from def file - std::array palette; - - //key = id of group (note that some groups may be missing) - //value = offset of pixel data for each frame, vector size = number of frames in group - std::map> dataOffsets; - - //animation raw data - //TODO: use vector instead? - std::unique_ptr pixelData; - size_t pixelDataSize; + int fullWidth; + int fullHeight; // speed of animation, measure in frames per second float speed; @@ -85,21 +75,10 @@ private: bool once; // animation will be played once and the reset to idling - ui8 * getPixelAddr(SDL_Surface * dest, int ftcpX, int ftcpY) const; - - template - void putPixelAt(SDL_Surface * dest, int X, int Y, size_t index, const std::array & special) const; - - template - void putPixel( ui8 * dest, const SDL_Color & color, size_t index, const std::array & special) const; - - template - void nextFrameT(SDL_Surface * dest, bool rotate); - void endAnimation(); - /// creates 8 special colors for current frame - std::array genSpecialPalette(); + + void genBorderPalette(IImage::BorderPallete & target); public: // function(s) that will be called when animation ends, after reset to 1st frame @@ -118,7 +97,7 @@ public: void setType(CCreatureAnim::EAnimType type); //sets type of animation and cleares framecount CCreatureAnim::EAnimType getType() const; //returns type of animation - void nextFrame(SDL_Surface * dest, bool rotate); + void nextFrame(SDL_Surface * dest, bool attacker); // should be called every frame, return true when animation was reset to beginning bool incrementFrame(float timePassed); diff --git a/client/gui/CAnimation.cpp b/client/gui/CAnimation.cpp index ce4b56d28..84fccf1a4 100644 --- a/client/gui/CAnimation.cpp +++ b/client/gui/CAnimation.cpp @@ -100,6 +100,8 @@ public: void shiftPalette(int from, int howMany) override; + void setBorderPallete(const BorderPallete & borderPallete) override; + friend class SDLImageLoader; }; @@ -157,6 +159,7 @@ public: void verticalFlip() override; void shiftPalette(int from, int howMany) override; + void setBorderPallete(const BorderPallete & borderPallete) override; friend class CompImageLoader; }; @@ -985,6 +988,15 @@ void SDLImage::shiftPalette(int from, int howMany) } } +void SDLImage::setBorderPallete(const IImage::BorderPallete & borderPallete) +{ + if(surf->format->palette) + { + SDL_SetColors(surf, const_cast(borderPallete.data()), 5, 3); + } +} + + SDLImage::~SDLImage() { SDL_FreeSurface(surf); @@ -1238,22 +1250,27 @@ CompImage::~CompImage() void CompImage::horizontalFlip() { - logAnim->error("CompImage::horizontalFlip is not implemented"); + logAnim->error("%s is not implemented", BOOST_CURRENT_FUNCTION); } void CompImage::verticalFlip() { - logAnim->error("CompImage::verticalFlip is not implemented"); + logAnim->error("%s is not implemented", BOOST_CURRENT_FUNCTION); } void CompImage::shiftPalette(int from, int howMany) { - logAnim->error("CompImage::shiftPalette is not implemented"); + logAnim->error("%s is not implemented", BOOST_CURRENT_FUNCTION); } -void CompImage::exportBitmap(const boost::filesystem::path& path) const +void CompImage::setBorderPallete(const IImage::BorderPallete & borderPallete) { - logAnim->error("CompImage::exportBitmap is not implemented"); + logAnim->error("%s is not implemented", BOOST_CURRENT_FUNCTION); +} + +void CompImage::exportBitmap(const boost::filesystem::path & path) const +{ + logAnim->error("%s is not implemented", BOOST_CURRENT_FUNCTION); } diff --git a/client/gui/CAnimation.h b/client/gui/CAnimation.h index 3b52ed2f0..3eeaeec2c 100644 --- a/client/gui/CAnimation.h +++ b/client/gui/CAnimation.h @@ -24,6 +24,7 @@ class IImage { int refCount; public: + using BorderPallete = std::array; //draws image on surface "where" at position virtual void draw(SDL_Surface * where, int posX = 0, int posY = 0, Rect * src = nullptr, ui8 alpha = 255) const=0; @@ -49,6 +50,9 @@ public: //only indexed bitmaps, 16 colors maximum virtual void shiftPalette(int from, int howMany) = 0; + //only indexed bitmaps, colors 5,6,7 must be special + virtual void setBorderPallete(const BorderPallete & borderPallete) = 0; + virtual void horizontalFlip() = 0; virtual void verticalFlip() = 0; From 6cd0dd98432dd58c8b63c0926d0474c9b06ef0fb Mon Sep 17 00:00:00 2001 From: AlexVinS Date: Tue, 5 Sep 2017 20:04:17 +0300 Subject: [PATCH 63/68] Use CAnimation for creature projectiles --- client/Graphics.cpp | 23 ++++---------- client/battle/CBattleAnimations.cpp | 9 +++--- client/battle/CBattleInterface.cpp | 49 +++++++++++++---------------- client/battle/CBattleInterface.h | 4 ++- client/gui/CAnimation.cpp | 11 +++++++ client/gui/CAnimation.h | 2 ++ 6 files changed, 47 insertions(+), 51 deletions(-) diff --git a/client/Graphics.cpp b/client/Graphics.cpp index d13f10ae3..f29da89e7 100644 --- a/client/Graphics.cpp +++ b/client/Graphics.cpp @@ -232,16 +232,10 @@ std::shared_ptr Graphics::loadHeroFlagAnimation(const std::string & for(const auto & rotation : rotations) { - const int sourceGroup = rotation.first; - const int targetGroup = rotation.second; + const int sourceGroup = rotation.first; + const int targetGroup = rotation.second; - for(size_t frame = 0; frame < anim->size(sourceGroup); ++frame) - { - anim->duplicateImage(sourceGroup, frame, targetGroup); - - IImage * image = anim->getImage(frame, targetGroup); - image->verticalFlip(); - } + anim->createFlippedGroup(sourceGroup, targetGroup); } return anim; @@ -262,15 +256,10 @@ std::shared_ptr Graphics::loadHeroAnimation(const std::string &name) for(const auto & rotation : rotations) { - const int sourceGroup = rotation.first; - const int targetGroup = rotation.second; + const int sourceGroup = rotation.first; + const int targetGroup = rotation.second; - for(size_t frame = 0; frame < anim->size(sourceGroup); ++frame) - { - anim->duplicateImage(sourceGroup, frame, targetGroup); - IImage * image = anim->getImage(frame, targetGroup); - image->verticalFlip(); - } + anim->createFlippedGroup(sourceGroup, targetGroup); } return anim; diff --git a/client/battle/CBattleAnimations.cpp b/client/battle/CBattleAnimations.cpp index 6266db763..e3492d7ad 100644 --- a/client/battle/CBattleAnimations.cpp +++ b/client/battle/CBattleAnimations.cpp @@ -16,7 +16,6 @@ #include "CBattleInterface.h" #include "CCreatureAnimation.h" -#include "../CDefHandler.h" #include "../CGameInfo.h" #include "../CMusicHandler.h" #include "../CPlayerInterface.h" @@ -786,11 +785,11 @@ bool CShootingAnimation::init() spi.dx = animSpeed; spi.dy = 0; - SDL_Surface * img = owner->idToProjectile[spi.creID]->ourImages[0].bitmap; + IImage * img = owner->idToProjectile[spi.creID]->getImage(0); // Add explosion anim - Point animPos(destPos.x - 126 + img->w / 2, - destPos.y - 105 + img->h / 2); + Point animPos(destPos.x - 126 + img->width() / 2, + destPos.y - 105 + img->height() / 2); owner->addNewAnim( new CSpellEffectAnimation(owner, catapultDamage ? "SGEXPL.DEF" : "CSGRCK.DEF", animPos.x, animPos.y)); } @@ -802,7 +801,7 @@ bool CShootingAnimation::init() owner->initStackProjectile(shooter); // only frames below maxFrame are usable: anything higher is either no present or we don't know when it should be used - size_t maxFrame = std::min(angles.size(), owner->idToProjectile.at(spi.creID)->ourImages.size()); + size_t maxFrame = std::min(angles.size(), owner->idToProjectile.at(spi.creID)->size(0)); assert(maxFrame > 0); diff --git a/client/battle/CBattleInterface.cpp b/client/battle/CBattleInterface.cpp index 3ae3a629e..d05a2e0e3 100644 --- a/client/battle/CBattleInterface.cpp +++ b/client/battle/CBattleInterface.cpp @@ -432,9 +432,6 @@ CBattleInterface::~CBattleInterface() for (auto & elem : creAnims) delete elem.second; - for (auto & elem : idToProjectile) - delete elem.second; - for (auto & elem : idToObstacle) delete elem.second; @@ -1006,20 +1003,21 @@ void CBattleInterface::newStack(const CStack *stack) void CBattleInterface::initStackProjectile(const CStack * stack) { - CDefHandler *&projectile = idToProjectile[stack->getCreature()->idNumber]; - - const CCreature *creature;//creature whose shots should be loaded - if (stack->getCreature()->idNumber == CreatureID::ARROW_TOWERS) + const CCreature * creature;//creature whose shots should be loaded + if(stack->getCreature()->idNumber == CreatureID::ARROW_TOWERS) creature = CGI->creh->creatures[siegeH->town->town->clientInfo.siegeShooter]; else creature = stack->getCreature(); - projectile = CDefHandler::giveDef(creature->animation.projectileImageName); + std::shared_ptr projectile = std::make_shared(creature->animation.projectileImageName); + projectile->preload(); - for (auto & elem : projectile->ourImages) //alpha transforming - { - CSDL_Ext::alphaTransform(elem.bitmap); - } + if(projectile->size(1) != 0) + logAnim->error("Expected empty group 1 in stack projectile"); + else + projectile->createFlippedGroup(0, 1); + + idToProjectile[stack->getCreature()->idNumber] = projectile; } void CBattleInterface::stackRemoved(int stackID) @@ -3173,23 +3171,18 @@ void CBattleInterface::showProjectiles(SDL_Surface *to) continue; // wait... } - SDL_Surface *image = idToProjectile[it->creID]->ourImages[it->frameNum].bitmap; + size_t group = it->reverse ? 1 : 0; + IImage * image = idToProjectile[it->creID]->getImage(it->frameNum, group, true); - SDL_Rect dst; - dst.h = image->h; - dst.w = image->w; - dst.x = it->x - dst.w / 2; - dst.y = it->y - dst.h / 2; + if(image) + { + SDL_Rect dst; + dst.h = image->height(); + dst.w = image->width(); + dst.x = it->x - dst.w / 2; + dst.y = it->y - dst.h / 2; - if (it->reverse) - { - SDL_Surface *rev = CSDL_Ext::verticalFlip(image); - CSDL_Ext::blit8bppAlphaTo24bpp(rev, nullptr, to, &dst); - SDL_FreeSurface(rev); - } - else - { - CSDL_Ext::blit8bppAlphaTo24bpp(image, nullptr, to, &dst); + image->draw(to, &dst, nullptr); } // Update projectile @@ -3207,7 +3200,7 @@ void CBattleInterface::showProjectiles(SDL_Surface *to) it->y = it->catapultInfo->calculateY(it->x); ++(it->frameNum); - it->frameNum %= idToProjectile[it->creID]->ourImages.size(); + it->frameNum %= idToProjectile[it->creID]->size(0); } else { diff --git a/client/battle/CBattleInterface.h b/client/battle/CBattleInterface.h index 638c03d97..f61bbe5b8 100644 --- a/client/battle/CBattleInterface.h +++ b/client/battle/CBattleInterface.h @@ -128,7 +128,9 @@ private: const CCreatureSet *army1, *army2; //copy of initial armies (for result window) const CGHeroInstance *attackingHeroInstance, *defendingHeroInstance; std::map creAnims; //animations of creatures from fighting armies (order by BattleInfo's stacks' ID) - std::map idToProjectile; //projectiles of creatures (creatureID, defhandler) + + std::map> idToProjectile; + std::map idToObstacle; //obstacles located on the battlefield std::map idToAbsoluteObstacle; //obstacles located on the battlefield diff --git a/client/gui/CAnimation.cpp b/client/gui/CAnimation.cpp index 84fccf1a4..66c81ad99 100644 --- a/client/gui/CAnimation.cpp +++ b/client/gui/CAnimation.cpp @@ -1643,6 +1643,17 @@ void CAnimation::playerColored(PlayerColor player) image.second->playerColored(player); } +void CAnimation::createFlippedGroup(const size_t sourceGroup, const size_t targetGroup) +{ + for(size_t frame = 0; frame < size(sourceGroup); ++frame) + { + duplicateImage(sourceGroup, frame, targetGroup); + + IImage * image = getImage(frame, targetGroup); + image->verticalFlip(); + } +} + float CFadeAnimation::initialCounter() const { if (fadingMode == EMode::OUT) diff --git a/client/gui/CAnimation.h b/client/gui/CAnimation.h index 3eeaeec2c..58356e2ef 100644 --- a/client/gui/CAnimation.h +++ b/client/gui/CAnimation.h @@ -135,6 +135,8 @@ public: void horizontalFlip(); void verticalFlip(); void playerColored(PlayerColor player); + + void createFlippedGroup(const size_t sourceGroup, const size_t targetGroup); }; const float DEFAULT_DELTA = 0.05f; From 610740011c6d3a7dc81b9a9aa4c38d21afb214be Mon Sep 17 00:00:00 2001 From: Arseniy Shestakov Date: Wed, 6 Sep 2017 12:24:39 +0300 Subject: [PATCH 64/68] CMake: print useful debug information on every build That way we don't need to ask more questions regarding system where build failed. --- CMakeLists.txt | 2 ++ cmake_modules/VCMIUtils.cmake | 56 +++++++++++++++++++++++++++++++++-- 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2914f6ea2..41d1f7231 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,6 +68,7 @@ set(PACKAGE_FILE_NAME "" CACHE STRING "Override for CPack package filename") set(CMAKE_MODULE_PATH ${CMAKE_HOME_DIRECTORY}/cmake_modules) # Contains custom functions and macros, but don't altering any options include(VCMIUtils) +vcmi_print_important_variables() # Options to enable folders in CMake generated projects for Visual Studio, Xcode, etc # Very useful to put 3rd-party libraries such as Minizip, GoogleTest and FuzzyLite in their own folders @@ -90,6 +91,7 @@ if(ENABLE_GITVERSION) include(GetGitRevisionDescription) get_git_head_revision(GIT_REFSPEC GIT_SHA1) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/Version.cpp.in" "${CMAKE_BINARY_DIR}/Version.cpp" @ONLY) + vcmi_print_git_commit_hash() else() add_definitions(-DVCMI_NO_EXTRA_VERSION) endif(ENABLE_GITVERSION) diff --git a/cmake_modules/VCMIUtils.cmake b/cmake_modules/VCMIUtils.cmake index a69bfd83d..4a7cdf1e4 100644 --- a/cmake_modules/VCMIUtils.cmake +++ b/cmake_modules/VCMIUtils.cmake @@ -63,14 +63,64 @@ endif(${CMAKE_GENERATOR} MATCHES "Xcode") # Can be called to see check cmake variables and environment variables # For "install" debugging just copy it here. There no easy way to include modules from source. -function(vcmi_get_cmake_debug_info) +function(vcmi_print_all_variables) - message(STATUS "Debug - Internal variables:") + message(STATUS "-- -- Start of all internal variables") get_cmake_property(_variableNames VARIABLES) foreach(_variableName ${_variableNames}) message(STATUS "${_variableName}=${${_variableName}}") endforeach() - message(STATUS "Debug - Environment variables:") + message(STATUS "-- -- End of all internal variables") + message(STATUS "--") + message(STATUS "-- -- Start of all environment variables") execute_process(COMMAND "${CMAKE_COMMAND}" "-E" "environment") + message(STATUS "-- -- End of all environment variables") + +endfunction() + +# Print CMake variables most important for debugging +function(vcmi_print_important_variables) + + message(STATUS "-- -- Start of VCMI build debug information") + + message(STATUS "CMAKE_VERSION: " ${CMAKE_VERSION}) + message(STATUS "CMAKE_BUILD_TYPE: " ${CMAKE_BUILD_TYPE}) + message(STATUS "CMAKE_BINARY_DIR: " ${CMAKE_BINARY_DIR}) + message(STATUS "CMAKE_SOURCE_DIR: " ${CMAKE_SOURCE_DIR}) +# message(STATUS "PROJECT_BINARY_DIR: " ${PROJECT_BINARY_DIR}) +# message(STATUS "PROJECT_SOURCE_DIR: " ${PROJECT_SOURCE_DIR}) + message(STATUS "CMAKE_MODULE_PATH: " ${CMAKE_MODULE_PATH}) + message(STATUS "CMAKE_COMMAND: " ${CMAKE_COMMAND}) + message(STATUS "CMAKE_ROOT: " ${CMAKE_ROOT}) +# message(STATUS "CMAKE_CURRENT_LIST_FILE and LINE: ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE}") +# message(STATUS "CMAKE_INCLUDE_PATH: " ${CMAKE_INCLUDE_PATH}) +# message(STATUS "CMAKE_LIBRARY_PATH: " ${CMAKE_LIBRARY_PATH}) + + message(STATUS "UNIX: ${UNIX} - WIN32: ${WIN32} - APPLE: ${APPLE}") + message(STATUS "MINGW: ${MINGW} - CYGWIN: ${CYGWIN} - MSVC: ${MSVC}") + message(STATUS "CMAKE_CXX_COMPILER_ID: " ${CMAKE_CXX_COMPILER_ID}) + message(STATUS "CMAKE_CXX_COMPILER_VERSION: " ${CMAKE_CXX_COMPILER_VERSION}) + message(STATUS "CMAKE_C_COMPILER: " ${CMAKE_C_COMPILER}) + message(STATUS "CMAKE_CXX_COMPILER: " ${CMAKE_CXX_COMPILER}) +# message(STATUS "CMAKE_COMPILER_IS_GNUCC: " ${CMAKE_COMPILER_IS_GNUCC}) +# message(STATUS "CMAKE_COMPILER_IS_GNUCXX: " ${CMAKE_COMPILER_IS_GNUCXX}) +# message(STATUS "CMAKE_C_FLAGS: " ${CMAKE_C_FLAGS}) +# message(STATUS "CMAKE_CXX_FLAGS: " ${CMAKE_CXX_FLAGS}) + + message(STATUS "CMAKE_SYSTEM: " ${CMAKE_SYSTEM}) + message(STATUS "CMAKE_SYSTEM_NAME: " ${CMAKE_SYSTEM_NAME}) + message(STATUS "CMAKE_SYSTEM_VERSION: " ${CMAKE_SYSTEM_VERSION}) + message(STATUS "CMAKE_SYSTEM_PROCESSOR: " ${CMAKE_SYSTEM_PROCESSOR}) + + message(STATUS "-- -- End of VCMI build debug information") + +endfunction() + +# Print Git commit hash +function(vcmi_print_git_commit_hash) + + message(STATUS "-- -- Start of Git information") + message(STATUS "GIT_SHA1: " ${GIT_SHA1}) + message(STATUS "-- -- End of Git information") endfunction() From 3bbff27127699f10295698faf3d058e6ead07c9c Mon Sep 17 00:00:00 2001 From: AlexVinS Date: Tue, 5 Sep 2017 20:45:29 +0300 Subject: [PATCH 65/68] Wiped CDefEssential --- client/CDefHandler.cpp | 24 ----------- client/CDefHandler.h | 15 ++----- client/battle/CBattleAnimations.cpp | 62 ++++++++++++++++------------ client/battle/CBattleAnimations.h | 16 ++++--- client/battle/CBattleInterface.cpp | 31 ++++++++------ client/battle/CBattleInterface.h | 5 ++- client/battle/CCreatureAnimation.cpp | 13 +++--- client/battle/CCreatureAnimation.h | 3 +- client/gui/CAnimation.h | 2 +- lib/CGameState.h | 1 - 10 files changed, 76 insertions(+), 96 deletions(-) diff --git a/client/CDefHandler.cpp b/client/CDefHandler.cpp index c04ec4218..4069c58ca 100644 --- a/client/CDefHandler.cpp +++ b/client/CDefHandler.cpp @@ -29,12 +29,9 @@ static long long pow(long long a, int b) CDefHandler::CDefHandler() { - notFreeImgs = false; } CDefHandler::~CDefHandler() { - if (notFreeImgs) - return; for (auto & elem : ourImages) { if (elem.bitmap) @@ -44,11 +41,6 @@ CDefHandler::~CDefHandler() } } } -CDefEssential::~CDefEssential() -{ - for(auto & elem : ourImages) - SDL_FreeSurface(elem.bitmap); -} void CDefHandler::openFromMemory(ui8 *table, const std::string & name) { @@ -350,14 +342,6 @@ SDL_Surface * CDefHandler::getSprite (int SIndex, const ui8 * FDef, const SDL_Co return ret; } -CDefEssential * CDefHandler::essentialize() -{ - auto ret = new CDefEssential(); - ret->ourImages = ourImages; - notFreeImgs = true; - return ret; -} - CDefHandler * CDefHandler::giveDef(const std::string & defName) { ResourceID resID(std::string("SPRITES/") + defName, EResType::ANIMATION); @@ -369,12 +353,4 @@ CDefHandler * CDefHandler::giveDef(const std::string & defName) nh->openFromMemory(data.get(), defName); return nh; } -CDefEssential * CDefHandler::giveDefEss(const std::string & defName) -{ - CDefEssential * ret; - CDefHandler * temp = giveDef(defName); - ret = temp->essentialize(); - delete temp; - return ret; -} diff --git a/client/CDefHandler.h b/client/CDefHandler.h index 31bdf5f59..0ea257e2a 100644 --- a/client/CDefHandler.h +++ b/client/CDefHandler.h @@ -66,12 +66,6 @@ struct SSpriteDef ui32 TopMargin; } PACKED_STRUCT; -class CDefEssential //DefHandler with images only -{ -public: - std::vector ourImages; - ~CDefEssential(); -}; class CDefHandler { @@ -84,20 +78,17 @@ private: int group; } ; std::vector SEntries ; - - void openFromMemory(ui8 * table, const std::string & name); + + void openFromMemory(ui8 * table, const std::string & name); SDL_Surface * getSprite (int SIndex, const ui8 * FDef, const SDL_Color * palette) const; public: int width, height; //width and height std::string defName; std::vector ourImages; - bool notFreeImgs; CDefHandler(); ~CDefHandler(); - - CDefEssential * essentialize(); + static CDefHandler * giveDef(const std::string & defName); - static CDefEssential * giveDefEss(const std::string & defName); }; diff --git a/client/battle/CBattleAnimations.cpp b/client/battle/CBattleAnimations.cpp index e3492d7ad..6aec07ab5 100644 --- a/client/battle/CBattleAnimations.cpp +++ b/client/battle/CBattleAnimations.cpp @@ -58,13 +58,13 @@ bool CBattleAnimation::isEarliest(bool perStackConcurrency) { int lowestMoveID = owner->animIDhelper + 5; CBattleStackAnimation * thAnim = dynamic_cast(this); - CSpellEffectAnimation * thSen = dynamic_cast(this); + CEffectAnimation * thSen = dynamic_cast(this); for(auto & elem : owner->pendingAnims) { CBattleStackAnimation * stAnim = dynamic_cast(elem.first); - CSpellEffectAnimation * sen = dynamic_cast(elem.first); + CEffectAnimation * sen = dynamic_cast(elem.first); if(perStackConcurrency && stAnim && thAnim && stAnim->stack->ID != thAnim->stack->ID) continue; @@ -171,7 +171,7 @@ bool CDefenceAnimation::init() if(attAnim && attAnim->stack->ID != stack->ID) continue; - CSpellEffectAnimation * sen = dynamic_cast(elem.first); + CEffectAnimation * sen = dynamic_cast(elem.first); if (sen) continue; @@ -243,7 +243,7 @@ CCreatureAnim::EAnimType CDefenceAnimation::getMyAnimType() if(killed) return CCreatureAnim::DEATH; - if (vstd::contains(stack->state, EBattleStackState::DEFENDING_ANIM)) + if(vstd::contains(stack->state, EBattleStackState::DEFENDING_ANIM)) return CCreatureAnim::DEFENCE; return CCreatureAnim::HITTED; @@ -270,10 +270,15 @@ void CDefenceAnimation::nextFrame() void CDefenceAnimation::endAnim() { - if (killed) + if(killed) + { myAnim->setType(CCreatureAnim::DEAD); + } else + { myAnim->setType(CCreatureAnim::HOLDING); + } + CBattleAnimation::endAnim(); @@ -791,7 +796,7 @@ bool CShootingAnimation::init() Point animPos(destPos.x - 126 + img->width() / 2, destPos.y - 105 + img->height() / 2); - owner->addNewAnim( new CSpellEffectAnimation(owner, catapultDamage ? "SGEXPL.DEF" : "CSGRCK.DEF", animPos.x, animPos.y)); + owner->addNewAnim( new CEffectAnimation(owner, catapultDamage ? "SGEXPL.DEF" : "CSGRCK.DEF", animPos.x, animPos.y)); } auto & angles = shooterInfo->animation.missleFrameAngles; @@ -872,35 +877,40 @@ void CShootingAnimation::endAnim() delete this; } -CSpellEffectAnimation::CSpellEffectAnimation(CBattleInterface * _owner, ui32 _effect, BattleHex _destTile, int _dx, int _dy, bool _Vflip, bool _alignToBottom) - :CBattleAnimation(_owner), effect(_effect), destTile(_destTile), customAnim(""), x(-1), y(-1), dx(_dx), dy(_dy), Vflip(_Vflip), alignToBottom(_alignToBottom) +CEffectAnimation::CEffectAnimation(CBattleInterface * _owner, std::string _customAnim, int _x, int _y, int _dx, int _dy, bool _Vflip, bool _alignToBottom) + : CBattleAnimation(_owner), + destTile(BattleHex::INVALID), + customAnim(_customAnim), + x(_x), + y(_y), + dx(_dx), + dy(_dy), + Vflip(_Vflip), + alignToBottom(_alignToBottom) { - logAnim->debug("Created spell anim for effect #%d", effect); + logAnim->debug("Created effect animation %s", customAnim); } -CSpellEffectAnimation::CSpellEffectAnimation(CBattleInterface * _owner, std::string _customAnim, int _x, int _y, int _dx, int _dy, bool _Vflip, bool _alignToBottom) - :CBattleAnimation(_owner), effect(-1), destTile(BattleHex::INVALID), customAnim(_customAnim), x(_x), y(_y), dx(_dx), dy(_dy), Vflip(_Vflip), alignToBottom(_alignToBottom) +CEffectAnimation::CEffectAnimation(CBattleInterface * _owner, std::string _customAnim, BattleHex _destTile, bool _Vflip, bool _alignToBottom) + : CBattleAnimation(_owner), + destTile(_destTile), + customAnim(_customAnim), + x(-1), + y(-1), + dx(0), + dy(0), + Vflip(_Vflip), + alignToBottom(_alignToBottom) { - logAnim->debug("Created spell anim for %s", customAnim); -} - -CSpellEffectAnimation::CSpellEffectAnimation(CBattleInterface * _owner, std::string _customAnim, BattleHex _destTile, bool _Vflip, bool _alignToBottom) - :CBattleAnimation(_owner), effect(-1), destTile(_destTile), customAnim(_customAnim), x(-1), y(-1), dx(0), dy(0), Vflip(_Vflip), alignToBottom(_alignToBottom) -{ - logAnim->debug("Created spell anim for %s", customAnim); + logAnim->debug("Created effect animation %s", customAnim); } -bool CSpellEffectAnimation::init() +bool CEffectAnimation::init() { if(!isEarliest(true)) return false; - if(customAnim.empty() && effect != ui32(-1) && !graphics->battleACToDef[effect].empty()) - { - customAnim = graphics->battleACToDef[effect][0]; - } - if(customAnim.empty()) { endAnim(); @@ -990,7 +1000,7 @@ bool CSpellEffectAnimation::init() return true; } -void CSpellEffectAnimation::nextFrame() +void CEffectAnimation::nextFrame() { //notice: there may be more than one effect in owner->battleEffects correcponding to this animation (ie. armageddon) for(auto & elem : owner->battleEffects) @@ -1013,7 +1023,7 @@ void CSpellEffectAnimation::nextFrame() } } -void CSpellEffectAnimation::endAnim() +void CEffectAnimation::endAnim() { CBattleAnimation::endAnim(); diff --git a/client/battle/CBattleAnimations.h b/client/battle/CBattleAnimations.h index 98232d84f..18104d558 100644 --- a/client/battle/CBattleAnimations.h +++ b/client/battle/CBattleAnimations.h @@ -208,16 +208,15 @@ public: void endAnim() override; //last two params only for catapult attacks - CShootingAnimation(CBattleInterface * _owner, const CStack * attacker, BattleHex _dest, - const CStack * _attacked, bool _catapult = false, int _catapultDmg = 0); + CShootingAnimation(CBattleInterface * _owner, const CStack * attacker, BattleHex _dest, + const CStack * _attacked, bool _catapult = false, int _catapultDmg = 0); virtual ~CShootingAnimation(){}; }; -/// This class manages a spell effect animation -class CSpellEffectAnimation : public CBattleAnimation +/// This class manages effect animation +class CEffectAnimation : public CBattleAnimation { private: - ui32 effect; BattleHex destTile; std::string customAnim; int x, y, dx, dy; @@ -228,8 +227,7 @@ public: void nextFrame() override; void endAnim() override; - CSpellEffectAnimation(CBattleInterface * _owner, ui32 _effect, BattleHex _destTile, int _dx = 0, int _dy = 0, bool _Vflip = false, bool _alignToBottom = false); - CSpellEffectAnimation(CBattleInterface * _owner, std::string _customAnim, int _x, int _y, int _dx = 0, int _dy = 0, bool _Vflip = false, bool _alignToBottom = false); - CSpellEffectAnimation(CBattleInterface * _owner, std::string _customAnim, BattleHex _destTile, bool _Vflip = false, bool _alignToBottom = false); - virtual ~CSpellEffectAnimation(){}; + CEffectAnimation(CBattleInterface * _owner, std::string _customAnim, int _x, int _y, int _dx = 0, int _dy = 0, bool _Vflip = false, bool _alignToBottom = false); + CEffectAnimation(CBattleInterface * _owner, std::string _customAnim, BattleHex _destTile, bool _Vflip = false, bool _alignToBottom = false); + virtual ~CEffectAnimation(){}; }; diff --git a/client/battle/CBattleInterface.cpp b/client/battle/CBattleInterface.cpp index d05a2e0e3..7248f457a 100644 --- a/client/battle/CBattleInterface.cpp +++ b/client/battle/CBattleInterface.cpp @@ -1221,7 +1221,7 @@ void CBattleInterface::stackIsCatapulting(const CatapultAttack & ca) { Point destPos = CClickableHex::getXYUnitAnim(attackInfo.destinationTile, nullptr, this) + Point(99, 120); - addNewAnim(new CSpellEffectAnimation(this, "SGEXPL.DEF", destPos.x, destPos.y)); + addNewAnim(new CEffectAnimation(this, "SGEXPL.DEF", destPos.x, destPos.y)); } } @@ -1309,20 +1309,23 @@ void CBattleInterface::spellCast(const BattleSpellCast *sc) std::string animToDisplay = spell.animationInfo.selectProjectile(angle); - if (!animToDisplay.empty()) + if(!animToDisplay.empty()) { + //TODO: calculate inside CEffectAnimation + std::shared_ptr tmp = std::make_shared(animToDisplay); + tmp->load(0, 0); + IImage * first = tmp->getImage(0, 0); + //displaying animation - CDefEssential *animDef = CDefHandler::giveDefEss(animToDisplay); double diffX = (destcoord.x - srccoord.x)*(destcoord.x - srccoord.x); double diffY = (destcoord.y - srccoord.y)*(destcoord.y - srccoord.y); double distance = sqrt(diffX + diffY); int steps = distance / AnimationControls::getSpellEffectSpeed() + 1; - int dx = (destcoord.x - srccoord.x - animDef->ourImages[0].bitmap->w)/steps; - int dy = (destcoord.y - srccoord.y - animDef->ourImages[0].bitmap->h)/steps; + int dx = (destcoord.x - srccoord.x - first->width())/steps; + int dy = (destcoord.y - srccoord.y - first->height())/steps; - delete animDef; - addNewAnim(new CSpellEffectAnimation(this, animToDisplay, srccoord.x, srccoord.y, dx, dy, Vflip)); + addNewAnim(new CEffectAnimation(this, animToDisplay, srccoord.x, srccoord.y, dx, dy, Vflip)); } } waitForAnims(); @@ -1354,8 +1357,8 @@ void CBattleInterface::spellCast(const BattleSpellCast *sc) { Point leftHero = Point(15, 30) + pos; Point rightHero = Point(755, 30) + pos; - addNewAnim(new CSpellEffectAnimation(this, sc->side ? "SP07_A.DEF" : "SP07_B.DEF", leftHero.x, leftHero.y, 0, 0, false)); - addNewAnim(new CSpellEffectAnimation(this, sc->side ? "SP07_B.DEF" : "SP07_A.DEF", rightHero.x, rightHero.y, 0, 0, false)); + addNewAnim(new CEffectAnimation(this, sc->side ? "SP07_A.DEF" : "SP07_B.DEF", leftHero.x, leftHero.y, 0, 0, false)); + addNewAnim(new CEffectAnimation(this, sc->side ? "SP07_B.DEF" : "SP07_A.DEF", rightHero.x, rightHero.y, 0, 0, false)); } } @@ -1418,9 +1421,11 @@ void CBattleInterface::castThisSpell(SpellID spellID) } } -void CBattleInterface::displayEffect(ui32 effect, int destTile) +void CBattleInterface::displayEffect(ui32 effect, BattleHex destTile) { - addNewAnim(new CSpellEffectAnimation(this, effect, destTile, 0, 0, false)); + std::string customAnim = graphics->battleACToDef[effect][0]; + + addNewAnim(new CEffectAnimation(this, customAnim, destTile)); } void CBattleInterface::displaySpellAnimation(const CSpell::TAnimation & animation, BattleHex destinationTile) @@ -1431,7 +1436,7 @@ void CBattleInterface::displaySpellAnimation(const CSpell::TAnimation & animatio } else { - addNewAnim(new CSpellEffectAnimation(this, animation.resourceName, destinationTile, false, animation.verticalPosition == VerticalPosition::BOTTOM)); + addNewAnim(new CEffectAnimation(this, animation.resourceName, destinationTile, false, animation.verticalPosition == VerticalPosition::BOTTOM)); } } @@ -2737,7 +2742,7 @@ void CBattleInterface::obstaclePlaced(const CObstacleInstance & oi) //we assume here that effect graphics have the same size as the usual obstacle image // -> if we know how to blit obstacle, let's blit the effect in the same place Point whereTo = getObstaclePosition(getObstacleImage(oi), oi); - addNewAnim(new CSpellEffectAnimation(this, defname, whereTo.x, whereTo.y)); + addNewAnim(new CEffectAnimation(this, defname, whereTo.x, whereTo.y)); //TODO we need to wait after playing sound till it's finished, otherwise it overlaps and sounds really bad //CCS->soundh->playSound(sound); diff --git a/client/battle/CBattleInterface.h b/client/battle/CBattleInterface.h index f61bbe5b8..5c0913208 100644 --- a/client/battle/CBattleInterface.h +++ b/client/battle/CBattleInterface.h @@ -120,6 +120,7 @@ class CBattleInterface : public CIntObject }; private: SDL_Surface *background, *menu, *amountNormal, *amountNegative, *amountPositive, *amountEffNeutral, *cellBorders, *backgroundWithHexes; + CButton *bOptions, *bSurrender, *bFlee, *bAutofight, *bSpell, * bWait, *bDefence, *bConsoleUp, *bConsoleDown, *btactNext, *btactEnd; CBattleConsole *console; @@ -342,7 +343,7 @@ public: void spellCast(const BattleSpellCast *sc); //called when a hero casts a spell void battleStacksEffectsSet(const SetStackEffect & sse); //called when a specific effect is set to stacks void castThisSpell(SpellID spellID); //called when player has chosen a spell from spellbook - void displayEffect(ui32 effect, int destTile); //displays custom effect on the battlefield + void displayEffect(ui32 effect, BattleHex destTile); //displays custom effect on the battlefield void displaySpellCast(SpellID spellID, BattleHex destinationTile); //displays spell`s cast animation void displaySpellEffect(SpellID spellID, BattleHex destinationTile); //displays spell`s affected animation @@ -378,7 +379,7 @@ public: friend class CBattleResultWindow; friend class CBattleHero; - friend class CSpellEffectAnimation; + friend class CEffectAnimation; friend class CBattleStackAnimation; friend class CReverseAnimation; friend class CDefenceAnimation; diff --git a/client/battle/CCreatureAnimation.cpp b/client/battle/CCreatureAnimation.cpp index 4903ee76e..715ad1c15 100644 --- a/client/battle/CCreatureAnimation.cpp +++ b/client/battle/CCreatureAnimation.cpp @@ -138,8 +138,9 @@ void CCreatureAnimation::setType(CCreatureAnim::EAnimType type) play(); } -CCreatureAnimation::CCreatureAnimation(std::string name, TSpeedController controller) - : speed(0.1), +CCreatureAnimation::CCreatureAnimation(const std::string & name_, TSpeedController controller) + : name(name_), + speed(0.1), currentFrame(0), elapsedTime(0), type(CCreatureAnim::HOLDING), @@ -147,8 +148,8 @@ CCreatureAnimation::CCreatureAnimation(std::string name, TSpeedController contro speedController(controller), once(false) { - forward = std::make_shared(name); - reverse = std::make_shared(name); + forward = std::make_shared(name_); + reverse = std::make_shared(name_); //todo: optimize forward->preload(); @@ -269,8 +270,6 @@ void CCreatureAnimation::genBorderPalette(IImage::BorderPallete & target) target[2] = addColors(genShadow(64), genBorderColor(getBorderStrength(elapsedTime), border)); } - - void CCreatureAnimation::nextFrame(SDL_Surface *dest, bool attacker) { size_t frame = floor(currentFrame); @@ -288,7 +287,6 @@ void CCreatureAnimation::nextFrame(SDL_Surface *dest, bool attacker) image->setBorderPallete(borderPallete); image->draw(dest, pos.x, pos.y); - } int CCreatureAnimation::framesInGroup(CCreatureAnim::EAnimType group) const @@ -329,6 +327,7 @@ void CCreatureAnimation::pause() void CCreatureAnimation::play() { + logAnim->trace("Play %s group %d at %d:%d", name, static_cast(getType()), pos.x, pos.y); speed = 0; if (speedController(this, type) != 0) speed = 1 / speedController(this, type); diff --git a/client/battle/CCreatureAnimation.h b/client/battle/CCreatureAnimation.h index a9e03f510..1065930ed 100644 --- a/client/battle/CCreatureAnimation.h +++ b/client/battle/CCreatureAnimation.h @@ -52,6 +52,7 @@ public: typedef std::function TSpeedController; private: + std::string name; std::shared_ptr forward; std::shared_ptr reverse; @@ -92,7 +93,7 @@ public: /// name - path to .def file, relative to SPRITES/ directory /// controller - function that will return for how long *each* frame /// in specified group of animation should be played, measured in seconds - CCreatureAnimation(std::string name, TSpeedController speedController); + CCreatureAnimation(const std::string & name_, TSpeedController speedController); void setType(CCreatureAnim::EAnimType type); //sets type of animation and cleares framecount CCreatureAnim::EAnimType getType() const; //returns type of animation diff --git a/client/gui/CAnimation.h b/client/gui/CAnimation.h index 58356e2ef..bf9e04ceb 100644 --- a/client/gui/CAnimation.h +++ b/client/gui/CAnimation.h @@ -136,7 +136,7 @@ public: void verticalFlip(); void playerColored(PlayerColor player); - void createFlippedGroup(const size_t sourceGroup, const size_t targetGroup); + void createFlippedGroup(const size_t sourceGroup, const size_t targetGroup); }; const float DEFAULT_DELTA = 0.05f; diff --git a/lib/CGameState.h b/lib/CGameState.h index 9c1400253..cc75984ce 100644 --- a/lib/CGameState.h +++ b/lib/CGameState.h @@ -37,7 +37,6 @@ class CGObjectInstance; class CCreature; class CMap; struct StartInfo; -struct SDL_Surface; class CMapHandler; struct SetObjectProperty; struct MetaString; From a7104377d6a57afcbdf4fb8ba319c06deda16c7f Mon Sep 17 00:00:00 2001 From: Henning Koehler Date: Thu, 7 Sep 2017 00:27:26 +1200 Subject: [PATCH 66/68] fixed CREATURE_TYPE_LIMITER for creatures without a stack instance (#374) --- lib/HeroBonus.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/HeroBonus.cpp b/lib/HeroBonus.cpp index db2671c2d..df749ad8c 100644 --- a/lib/HeroBonus.cpp +++ b/lib/HeroBonus.cpp @@ -1221,6 +1221,8 @@ const CCreature * retrieveCreature(const CBonusSystemNode *node) { case CBonusSystemNode::CREATURE: return (static_cast(node)); + case CBonusSystemNode::STACK_BATTLE: + return (static_cast(node))->type; default: const CStackInstance *csi = retreiveStackInstance(node); if(csi) From c30d9f2fd6e22c8c1e05ebecc183b827383dbf53 Mon Sep 17 00:00:00 2001 From: AlexVinS Date: Wed, 6 Sep 2017 15:50:59 +0300 Subject: [PATCH 67/68] Fix --- client/battle/CCreatureAnimation.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/client/battle/CCreatureAnimation.cpp b/client/battle/CCreatureAnimation.cpp index 715ad1c15..835e733a1 100644 --- a/client/battle/CCreatureAnimation.cpp +++ b/client/battle/CCreatureAnimation.cpp @@ -154,7 +154,13 @@ CCreatureAnimation::CCreatureAnimation(const std::string & name_, TSpeedControll //todo: optimize forward->preload(); reverse->preload(); - reverse->verticalFlip(); + + // if necessary, add one frame into vcmi-only group DEAD + if(forward->size(CCreatureAnim::DEAD) == 0) + { + forward->duplicateImage(CCreatureAnim::DEATH, forward->size(CCreatureAnim::DEATH)-1, CCreatureAnim::DEAD); + reverse->duplicateImage(CCreatureAnim::DEATH, reverse->size(CCreatureAnim::DEATH)-1, CCreatureAnim::DEAD); + } //TODO: get dimensions form CAnimation IImage * first = forward->getImage(0, type, true); @@ -168,12 +174,7 @@ CCreatureAnimation::CCreatureAnimation(const std::string & name_, TSpeedControll fullWidth = first->width(); fullHeight = first->height(); - // if necessary, add one frame into vcmi-only group DEAD - if(forward->size(CCreatureAnim::DEAD) == 0) - { - forward->duplicateImage(CCreatureAnim::DEATH, forward->size(CCreatureAnim::DEATH)-1, CCreatureAnim::DEAD); - reverse->duplicateImage(CCreatureAnim::DEATH, reverse->size(CCreatureAnim::DEATH)-1, CCreatureAnim::DEAD); - } + reverse->verticalFlip(); play(); } @@ -327,8 +328,8 @@ void CCreatureAnimation::pause() void CCreatureAnimation::play() { - logAnim->trace("Play %s group %d at %d:%d", name, static_cast(getType()), pos.x, pos.y); + //logAnim->trace("Play %s group %d at %d:%d", name, static_cast(getType()), pos.x, pos.y); speed = 0; - if (speedController(this, type) != 0) + if(speedController(this, type) != 0) speed = 1 / speedController(this, type); } From 940c8a0b82cb07a0d35e93e1de624976e18e0565 Mon Sep 17 00:00:00 2001 From: Arseniy Shestakov Date: Fri, 8 Sep 2017 03:40:00 +0300 Subject: [PATCH 68/68] CMake: add $ORIGIN into RPATH for single-directory installation End up that single-directory installation is useful for Snap package. --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 41d1f7231..d9140306c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,7 +54,7 @@ option(ENABLE_PCH "Enable compilation using precompiled headers" ON) option(ENABLE_GITVERSION "Enable Version.cpp with Git commit hash" ON) option(ENABLE_DEBUG_CONSOLE "Enable debug console for Windows builds" ON) -# Useful for debugging +# Used for Snap packages and also useful for debugging option(ENABLE_MONOLITHIC_INSTALL "Install everything in single directory on Linux and Mac" OFF) # Allow to pass package name from Travis CI @@ -250,6 +250,7 @@ else() include(GNUInstallDirs) if(ENABLE_MONOLITHIC_INSTALL) + set(CMAKE_INSTALL_RPATH "$ORIGIN/") set(BIN_DIR "." CACHE STRING "Where to install binaries") set(LIB_DIR "." CACHE STRING "Where to install main library") set(DATA_DIR "." CACHE STRING "Where to install data files")