mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Merge branch 'develop' into handlersAbstraction
# Conflicts: # CI/linux/before_install.sh # CI/mac/before_install.sh # CI/mxe/before_install.sh # lib/CModHandler.cpp # lib/mapObjects/CObjectClassesHandler.cpp # lib/mapObjects/CObjectClassesHandler.h # lib/mapObjects/CommonConstructors.cpp # server/CGameHandler.cpp # test/CMakeLists.txt # test/spells/effects/TeleportTest.cpp
This commit is contained in:
		
							
								
								
									
										118
									
								
								.github/workflows/github.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								.github/workflows/github.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,118 @@ | |||||||
|  | name: CMake | ||||||
|  |  | ||||||
|  | on: [ push ] | ||||||
|  |  | ||||||
|  | env: | ||||||
|  |   # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) | ||||||
|  |   BUILD_TYPE: Release | ||||||
|  |  | ||||||
|  | jobs: | ||||||
|  |   build: | ||||||
|  |     strategy: | ||||||
|  |       matrix: | ||||||
|  |         include: | ||||||
|  |           - platform: linux | ||||||
|  |             os: ubuntu-20.04 | ||||||
|  |             cc: clang-10 | ||||||
|  |             cxx: clang++-10 | ||||||
|  |             test: 0 | ||||||
|  |           - platform: linux | ||||||
|  |             os: ubuntu-20.04 | ||||||
|  |             cc: gcc-9 | ||||||
|  |             cxx: g++-9 | ||||||
|  |             test: 0 | ||||||
|  |           - platform: mac | ||||||
|  |             os: macos-latest | ||||||
|  |             test: 0 | ||||||
|  |             pack: 1 | ||||||
|  |             extension: dmg | ||||||
|  |           - platform: mxe | ||||||
|  |             os: ubuntu-20.04 | ||||||
|  |             mxe: i686-w64-mingw32.shared | ||||||
|  |             test: 0 | ||||||
|  |             pack: 1 | ||||||
|  |             extension: exe | ||||||
|  |              | ||||||
|  |     runs-on: ${{ matrix.os }} | ||||||
|  |  | ||||||
|  |     steps: | ||||||
|  |     - uses: actions/checkout@v2 | ||||||
|  |       with: | ||||||
|  |         submodules: recursive | ||||||
|  |  | ||||||
|  |     - name: Dependencies | ||||||
|  |       run: source ${{github.workspace}}/CI/${{matrix.platform}}/before_install.sh | ||||||
|  |       env: | ||||||
|  |         MXE_TARGET: ${{ matrix.mxe }} | ||||||
|  |          | ||||||
|  |     - name: Git branch name | ||||||
|  |       id: git-branch-name | ||||||
|  |       uses: EthanSK/git-branch-name-action@v1 | ||||||
|  |  | ||||||
|  |     - name: Build Number | ||||||
|  |       run: | | ||||||
|  |         source ${{github.workspace}}/CI/get_package_name.sh | ||||||
|  |         echo VCMI_PACKAGE_FILE_NAME="$VCMI_PACKAGE_FILE_NAME" >> $GITHUB_ENV | ||||||
|  |         echo VCMI_PACKAGE_NAME_SUFFIX="$VCMI_PACKAGE_NAME_SUFFIX" >> $GITHUB_ENV | ||||||
|  |       env: | ||||||
|  |         PULL_REQUEST: ${{ github.event.pull_request.number }} | ||||||
|  |  | ||||||
|  |     - name: Configure CMake | ||||||
|  |       run: | | ||||||
|  |         mkdir ${{github.workspace}}/build | ||||||
|  |         cd ${{github.workspace}}/build | ||||||
|  |         cmake -G Ninja .. -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \ | ||||||
|  |             -DENABLE_TEST=${{matrix.test}} \ | ||||||
|  |             -DPACKAGE_NAME_SUFFIX:STRING="$VCMI_PACKAGE_NAME_SUFFIX" \ | ||||||
|  |             -DPACKAGE_FILE_NAME:STRING="$VCMI_PACKAGE_FILE_NAME" | ||||||
|  |       env: | ||||||
|  |         CC: ${{ matrix.cc }} | ||||||
|  |         CXX: ${{ matrix.cxx }} | ||||||
|  |  | ||||||
|  |     - name: Build | ||||||
|  |       run: | | ||||||
|  |         cd ${{github.workspace}}/build | ||||||
|  |         ninja | ||||||
|  |  | ||||||
|  |     - name: Test | ||||||
|  |       if: ${{ matrix.test == 1 }} | ||||||
|  |       run: | | ||||||
|  |         cd ${{github.workspace}}/build | ||||||
|  |         ctest -C Release -V | ||||||
|  |    | ||||||
|  |     - name: Pack | ||||||
|  |       id: cpack | ||||||
|  |       if: ${{ matrix.pack == 1 }} | ||||||
|  |       run: | | ||||||
|  |         cd ${{github.workspace}}/build | ||||||
|  |         cpack | ||||||
|  |          | ||||||
|  |     - name: Additional logs | ||||||
|  |       if: ${{ failure() && steps.cpack.outcome == 'failure' && matrix.platform == 'mxe' }} | ||||||
|  |       run: | | ||||||
|  |         cat ${{github.workspace}}/build/_CPack_Packages/win32/NSIS/project.nsi | ||||||
|  |         cat ${{github.workspace}}/build/_CPack_Packages/win32/NSIS/NSISOutput.log | ||||||
|  |          | ||||||
|  |     - name: Artifacts | ||||||
|  |       if: ${{ matrix.pack == 1 }} | ||||||
|  |       uses: actions/upload-artifact@v2 | ||||||
|  |       with: | ||||||
|  |         name: ${{ env.VCMI_PACKAGE_FILE_NAME }} - ${{ matrix.platform }} | ||||||
|  |         path: ${{github.workspace}}/build/${{ env.VCMI_PACKAGE_FILE_NAME }}.${{ matrix.extension }} | ||||||
|  |    | ||||||
|  |     - name: Upload build | ||||||
|  |       if: ${{ matrix.pack == 1 && github.ref == 'refs/heads/develop' }} | ||||||
|  |       run: | | ||||||
|  |         cd ${{github.workspace}}/build | ||||||
|  |         source ${{github.workspace}}/CI/upload_package.sh | ||||||
|  |       env: | ||||||
|  |         DEPLOY_RSA: ${{ secrets.DEPLOY_RSA }} | ||||||
|  |         PACKAGE_EXTENSION: ${{ matrix.extension }} | ||||||
|  |          | ||||||
|  |     - uses: act10ns/slack@v1 | ||||||
|  |       with: | ||||||
|  |         status: ${{ job.status }} | ||||||
|  |         channel: '#notifications' | ||||||
|  |       env: | ||||||
|  |         SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} | ||||||
|  |       if: always() | ||||||
| @@ -1166,12 +1166,12 @@ void VCAI::pickBestArtifacts(const CGHeroInstance * h, const CGHeroInstance * ot | |||||||
|  |  | ||||||
| 			for(auto location : allArtifacts) | 			for(auto location : allArtifacts) | ||||||
| 			{ | 			{ | ||||||
|  | 				if(location.slot == ArtifactPosition::MACH4 || location.slot == ArtifactPosition::SPELLBOOK) | ||||||
|  | 					continue; // don't attempt to move catapult and spellbook | ||||||
|  |  | ||||||
| 				if(location.relatedObj() == target && location.slot < ArtifactPosition::AFTER_LAST) | 				if(location.relatedObj() == target && location.slot < ArtifactPosition::AFTER_LAST) | ||||||
| 					continue; //don't reequip artifact we already wear | 					continue; //don't reequip artifact we already wear | ||||||
|  |  | ||||||
| 				if(location.slot == ArtifactPosition::MACH4) // don't attempt to move catapult |  | ||||||
| 					continue; |  | ||||||
|  |  | ||||||
| 				auto s = location.getSlot(); | 				auto s = location.getSlot(); | ||||||
| 				if(!s || s->locked) //we can't move locks | 				if(!s || s->locked) //we can't move locks | ||||||
| 					continue; | 					continue; | ||||||
|   | |||||||
							
								
								
									
										973
									
								
								CI/NSIS.template.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										973
									
								
								CI/NSIS.template.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,973 @@ | |||||||
|  | ; CPack install script designed for a nmake build | ||||||
|  |  | ||||||
|  | ;-------------------------------- | ||||||
|  | ; You must define these values | ||||||
|  |  | ||||||
|  |   !define VERSION "@CPACK_PACKAGE_VERSION@" | ||||||
|  |   !define PATCH  "@CPACK_PACKAGE_VERSION_PATCH@" | ||||||
|  |   !define INST_DIR "@CPACK_TEMPORARY_DIRECTORY@" | ||||||
|  |  | ||||||
|  | ;-------------------------------- | ||||||
|  | ;Variables | ||||||
|  |  | ||||||
|  |   Var MUI_TEMP | ||||||
|  |   Var STARTMENU_FOLDER | ||||||
|  |   Var SV_ALLUSERS | ||||||
|  |   Var START_MENU | ||||||
|  |   Var DO_NOT_ADD_TO_PATH | ||||||
|  |   Var ADD_TO_PATH_ALL_USERS | ||||||
|  |   Var ADD_TO_PATH_CURRENT_USER | ||||||
|  |   Var INSTALL_DESKTOP | ||||||
|  |   Var IS_DEFAULT_INSTALLDIR | ||||||
|  | ;-------------------------------- | ||||||
|  | ;Include Modern UI | ||||||
|  |  | ||||||
|  |   Unicode True | ||||||
|  |   !include "MUI.nsh" | ||||||
|  |  | ||||||
|  |   ;Default installation folder | ||||||
|  |   InstallDir "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" | ||||||
|  |  | ||||||
|  | ;-------------------------------- | ||||||
|  | ;General | ||||||
|  |  | ||||||
|  |   ;Name and file | ||||||
|  |   Name "@CPACK_NSIS_PACKAGE_NAME@" | ||||||
|  |   OutFile "@CPACK_TOPLEVEL_DIRECTORY@/@CPACK_OUTPUT_FILE_NAME@" | ||||||
|  |  | ||||||
|  |   ;Set compression | ||||||
|  |   SetCompressor @CPACK_NSIS_COMPRESSOR@ | ||||||
|  |  | ||||||
|  |   ;Require administrator access | ||||||
|  |   RequestExecutionLevel admin | ||||||
|  |  | ||||||
|  | @CPACK_NSIS_DEFINES@ | ||||||
|  |  | ||||||
|  |   !include Sections.nsh | ||||||
|  |  | ||||||
|  | ;--- Component support macros: --- | ||||||
|  | ; The code for the add/remove functionality is from: | ||||||
|  | ;   http://nsis.sourceforge.net/Add/Remove_Functionality | ||||||
|  | ; It has been modified slightly and extended to provide | ||||||
|  | ; inter-component dependencies. | ||||||
|  | Var AR_SecFlags | ||||||
|  | Var AR_RegFlags | ||||||
|  | @CPACK_NSIS_SECTION_SELECTED_VARS@ | ||||||
|  |  | ||||||
|  | ; Loads the "selected" flag for the section named SecName into the | ||||||
|  | ; variable VarName. | ||||||
|  | !macro LoadSectionSelectedIntoVar SecName VarName | ||||||
|  |  SectionGetFlags ${${SecName}} $${VarName} | ||||||
|  |  IntOp $${VarName} $${VarName} & ${SF_SELECTED}  ;Turn off all other bits | ||||||
|  | !macroend | ||||||
|  |  | ||||||
|  | ; Loads the value of a variable... can we get around this? | ||||||
|  | !macro LoadVar VarName | ||||||
|  |   IntOp $R0 0 + $${VarName} | ||||||
|  | !macroend | ||||||
|  |  | ||||||
|  | ; Sets the value of a variable | ||||||
|  | !macro StoreVar VarName IntValue | ||||||
|  |   IntOp $${VarName} 0 + ${IntValue} | ||||||
|  | !macroend | ||||||
|  |  | ||||||
|  | !macro InitSection SecName | ||||||
|  |   ;  This macro reads component installed flag from the registry and | ||||||
|  |   ;changes checked state of the section on the components page. | ||||||
|  |   ;Input: section index constant name specified in Section command. | ||||||
|  |  | ||||||
|  |   ClearErrors | ||||||
|  |   ;Reading component status from registry | ||||||
|  |   ReadRegDWORD $AR_RegFlags HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" "Installed" | ||||||
|  |   IfErrors "default_${SecName}" | ||||||
|  |     ;Status will stay default if registry value not found | ||||||
|  |     ;(component was never installed) | ||||||
|  |   IntOp $AR_RegFlags $AR_RegFlags & ${SF_SELECTED} ;Turn off all other bits | ||||||
|  |   SectionGetFlags ${${SecName}} $AR_SecFlags  ;Reading default section flags | ||||||
|  |   IntOp $AR_SecFlags $AR_SecFlags & 0xFFFE  ;Turn lowest (enabled) bit off | ||||||
|  |   IntOp $AR_SecFlags $AR_RegFlags | $AR_SecFlags      ;Change lowest bit | ||||||
|  |  | ||||||
|  |   ; Note whether this component was installed before | ||||||
|  |   !insertmacro StoreVar ${SecName}_was_installed $AR_RegFlags | ||||||
|  |   IntOp $R0 $AR_RegFlags & $AR_RegFlags | ||||||
|  |  | ||||||
|  |   ;Writing modified flags | ||||||
|  |   SectionSetFlags ${${SecName}} $AR_SecFlags | ||||||
|  |  | ||||||
|  |  "default_${SecName}:" | ||||||
|  |  !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected | ||||||
|  | !macroend | ||||||
|  |  | ||||||
|  | !macro FinishSection SecName | ||||||
|  |   ;  This macro reads section flag set by user and removes the section | ||||||
|  |   ;if it is not selected. | ||||||
|  |   ;Then it writes component installed flag to registry | ||||||
|  |   ;Input: section index constant name specified in Section command. | ||||||
|  |  | ||||||
|  |   SectionGetFlags ${${SecName}} $AR_SecFlags  ;Reading section flags | ||||||
|  |   ;Checking lowest bit: | ||||||
|  |   IntOp $AR_SecFlags $AR_SecFlags & ${SF_SELECTED} | ||||||
|  |   IntCmp $AR_SecFlags 1 "leave_${SecName}" | ||||||
|  |     ;Section is not selected: | ||||||
|  |     ;Calling Section uninstall macro and writing zero installed flag | ||||||
|  |     !insertmacro "Remove_${${SecName}}" | ||||||
|  |     WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" \ | ||||||
|  |   "Installed" 0 | ||||||
|  |     Goto "exit_${SecName}" | ||||||
|  |  | ||||||
|  |  "leave_${SecName}:" | ||||||
|  |     ;Section is selected: | ||||||
|  |     WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@\Components\${SecName}" \ | ||||||
|  |   "Installed" 1 | ||||||
|  |  | ||||||
|  |  "exit_${SecName}:" | ||||||
|  | !macroend | ||||||
|  |  | ||||||
|  | !macro RemoveSection_CPack SecName | ||||||
|  |   ;  This macro is used to call section's Remove_... macro | ||||||
|  |   ;from the uninstaller. | ||||||
|  |   ;Input: section index constant name specified in Section command. | ||||||
|  |  | ||||||
|  |   !insertmacro "Remove_${${SecName}}" | ||||||
|  | !macroend | ||||||
|  |  | ||||||
|  | ; Determine whether the selection of SecName changed | ||||||
|  | !macro MaybeSelectionChanged SecName | ||||||
|  |   !insertmacro LoadVar ${SecName}_selected | ||||||
|  |   SectionGetFlags ${${SecName}} $R1 | ||||||
|  |   IntOp $R1 $R1 & ${SF_SELECTED} ;Turn off all other bits | ||||||
|  |  | ||||||
|  |   ; See if the status has changed: | ||||||
|  |   IntCmp $R0 $R1 "${SecName}_unchanged" | ||||||
|  |   !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected | ||||||
|  |  | ||||||
|  |   IntCmp $R1 ${SF_SELECTED} "${SecName}_was_selected" | ||||||
|  |   !insertmacro "Deselect_required_by_${SecName}" | ||||||
|  |   goto "${SecName}_unchanged" | ||||||
|  |  | ||||||
|  |   "${SecName}_was_selected:" | ||||||
|  |   !insertmacro "Select_${SecName}_depends" | ||||||
|  |  | ||||||
|  |   "${SecName}_unchanged:" | ||||||
|  | !macroend | ||||||
|  | ;--- End of Add/Remove macros --- | ||||||
|  |  | ||||||
|  | ;-------------------------------- | ||||||
|  | ;Interface Settings | ||||||
|  |  | ||||||
|  |   !define MUI_HEADERIMAGE | ||||||
|  |   !define MUI_ABORTWARNING | ||||||
|  |  | ||||||
|  | ;---------------------------------------- | ||||||
|  | ; based upon a script of "Written by KiCHiK 2003-01-18 05:57:02" | ||||||
|  | ;---------------------------------------- | ||||||
|  | !verbose 3 | ||||||
|  | !include "WinMessages.NSH" | ||||||
|  | !verbose 4 | ||||||
|  | ;==================================================== | ||||||
|  | ; get_NT_environment | ||||||
|  | ;     Returns: the selected environment | ||||||
|  | ;     Output : head of the stack | ||||||
|  | ;==================================================== | ||||||
|  | !macro select_NT_profile UN | ||||||
|  | Function ${UN}select_NT_profile | ||||||
|  |    StrCmp $ADD_TO_PATH_ALL_USERS "1" 0 environment_single | ||||||
|  |       DetailPrint "Selected environment for all users" | ||||||
|  |       Push "all" | ||||||
|  |       Return | ||||||
|  |    environment_single: | ||||||
|  |       DetailPrint "Selected environment for current user only." | ||||||
|  |       Push "current" | ||||||
|  |       Return | ||||||
|  | FunctionEnd | ||||||
|  | !macroend | ||||||
|  | !insertmacro select_NT_profile "" | ||||||
|  | !insertmacro select_NT_profile "un." | ||||||
|  | ;---------------------------------------------------- | ||||||
|  | !define NT_current_env 'HKCU "Environment"' | ||||||
|  | !define NT_all_env     'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' | ||||||
|  |  | ||||||
|  | !ifndef WriteEnvStr_RegKey | ||||||
|  |   !ifdef ALL_USERS | ||||||
|  |     !define WriteEnvStr_RegKey \ | ||||||
|  |        'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' | ||||||
|  |   !else | ||||||
|  |     !define WriteEnvStr_RegKey 'HKCU "Environment"' | ||||||
|  |   !endif | ||||||
|  | !endif | ||||||
|  |  | ||||||
|  | ; AddToPath - Adds the given dir to the search path. | ||||||
|  | ;        Input - head of the stack | ||||||
|  | ;        Note - Win9x systems requires reboot | ||||||
|  |  | ||||||
|  | Function AddToPath | ||||||
|  |   Exch $0 | ||||||
|  |   Push $1 | ||||||
|  |   Push $2 | ||||||
|  |   Push $3 | ||||||
|  |  | ||||||
|  |   # don't add if the path doesn't exist | ||||||
|  |   IfFileExists "$0\*.*" "" AddToPath_done | ||||||
|  |  | ||||||
|  |   ReadEnvStr $1 PATH | ||||||
|  |   ; if the path is too long for a NSIS variable NSIS will return a 0 | ||||||
|  |   ; length string.  If we find that, then warn and skip any path | ||||||
|  |   ; modification as it will trash the existing path. | ||||||
|  |   StrLen $2 $1 | ||||||
|  |   IntCmp $2 0 CheckPathLength_ShowPathWarning CheckPathLength_Done CheckPathLength_Done | ||||||
|  |     CheckPathLength_ShowPathWarning: | ||||||
|  |     Messagebox MB_OK|MB_ICONEXCLAMATION "Warning! PATH too long installer unable to modify PATH!" | ||||||
|  |     Goto AddToPath_done | ||||||
|  |   CheckPathLength_Done: | ||||||
|  |   Push "$1;" | ||||||
|  |   Push "$0;" | ||||||
|  |   Call StrStr | ||||||
|  |   Pop $2 | ||||||
|  |   StrCmp $2 "" "" AddToPath_done | ||||||
|  |   Push "$1;" | ||||||
|  |   Push "$0\;" | ||||||
|  |   Call StrStr | ||||||
|  |   Pop $2 | ||||||
|  |   StrCmp $2 "" "" AddToPath_done | ||||||
|  |   GetFullPathName /SHORT $3 $0 | ||||||
|  |   Push "$1;" | ||||||
|  |   Push "$3;" | ||||||
|  |   Call StrStr | ||||||
|  |   Pop $2 | ||||||
|  |   StrCmp $2 "" "" AddToPath_done | ||||||
|  |   Push "$1;" | ||||||
|  |   Push "$3\;" | ||||||
|  |   Call StrStr | ||||||
|  |   Pop $2 | ||||||
|  |   StrCmp $2 "" "" AddToPath_done | ||||||
|  |  | ||||||
|  |   Call IsNT | ||||||
|  |   Pop $1 | ||||||
|  |   StrCmp $1 1 AddToPath_NT | ||||||
|  |     ; Not on NT | ||||||
|  |     StrCpy $1 $WINDIR 2 | ||||||
|  |     FileOpen $1 "$1\autoexec.bat" a | ||||||
|  |     FileSeek $1 -1 END | ||||||
|  |     FileReadByte $1 $2 | ||||||
|  |     IntCmp $2 26 0 +2 +2 # DOS EOF | ||||||
|  |       FileSeek $1 -1 END # write over EOF | ||||||
|  |     FileWrite $1 "$\r$\nSET PATH=%PATH%;$3$\r$\n" | ||||||
|  |     FileClose $1 | ||||||
|  |     SetRebootFlag true | ||||||
|  |     Goto AddToPath_done | ||||||
|  |  | ||||||
|  |   AddToPath_NT: | ||||||
|  |     StrCmp $ADD_TO_PATH_ALL_USERS "1" ReadAllKey | ||||||
|  |       ReadRegStr $1 ${NT_current_env} "PATH" | ||||||
|  |       Goto DoTrim | ||||||
|  |     ReadAllKey: | ||||||
|  |       ReadRegStr $1 ${NT_all_env} "PATH" | ||||||
|  |     DoTrim: | ||||||
|  |     StrCmp $1 "" AddToPath_NTdoIt | ||||||
|  |       Push $1 | ||||||
|  |       Call Trim | ||||||
|  |       Pop $1 | ||||||
|  |       StrCpy $0 "$1;$0" | ||||||
|  |     AddToPath_NTdoIt: | ||||||
|  |       StrCmp $ADD_TO_PATH_ALL_USERS "1" WriteAllKey | ||||||
|  |         WriteRegExpandStr ${NT_current_env} "PATH" $0 | ||||||
|  |         Goto DoSend | ||||||
|  |       WriteAllKey: | ||||||
|  |         WriteRegExpandStr ${NT_all_env} "PATH" $0 | ||||||
|  |       DoSend: | ||||||
|  |       SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 | ||||||
|  |  | ||||||
|  |   AddToPath_done: | ||||||
|  |     Pop $3 | ||||||
|  |     Pop $2 | ||||||
|  |     Pop $1 | ||||||
|  |     Pop $0 | ||||||
|  | FunctionEnd | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ; RemoveFromPath - Remove a given dir from the path | ||||||
|  | ;     Input: head of the stack | ||||||
|  |  | ||||||
|  | Function un.RemoveFromPath | ||||||
|  |   Exch $0 | ||||||
|  |   Push $1 | ||||||
|  |   Push $2 | ||||||
|  |   Push $3 | ||||||
|  |   Push $4 | ||||||
|  |   Push $5 | ||||||
|  |   Push $6 | ||||||
|  |  | ||||||
|  |   IntFmt $6 "%c" 26 # DOS EOF | ||||||
|  |  | ||||||
|  |   Call un.IsNT | ||||||
|  |   Pop $1 | ||||||
|  |   StrCmp $1 1 unRemoveFromPath_NT | ||||||
|  |     ; Not on NT | ||||||
|  |     StrCpy $1 $WINDIR 2 | ||||||
|  |     FileOpen $1 "$1\autoexec.bat" r | ||||||
|  |     GetTempFileName $4 | ||||||
|  |     FileOpen $2 $4 w | ||||||
|  |     GetFullPathName /SHORT $0 $0 | ||||||
|  |     StrCpy $0 "SET PATH=%PATH%;$0" | ||||||
|  |     Goto unRemoveFromPath_dosLoop | ||||||
|  |  | ||||||
|  |     unRemoveFromPath_dosLoop: | ||||||
|  |       FileRead $1 $3 | ||||||
|  |       StrCpy $5 $3 1 -1 # read last char | ||||||
|  |       StrCmp $5 $6 0 +2 # if DOS EOF | ||||||
|  |         StrCpy $3 $3 -1 # remove DOS EOF so we can compare | ||||||
|  |       StrCmp $3 "$0$\r$\n" unRemoveFromPath_dosLoopRemoveLine | ||||||
|  |       StrCmp $3 "$0$\n" unRemoveFromPath_dosLoopRemoveLine | ||||||
|  |       StrCmp $3 "$0" unRemoveFromPath_dosLoopRemoveLine | ||||||
|  |       StrCmp $3 "" unRemoveFromPath_dosLoopEnd | ||||||
|  |       FileWrite $2 $3 | ||||||
|  |       Goto unRemoveFromPath_dosLoop | ||||||
|  |       unRemoveFromPath_dosLoopRemoveLine: | ||||||
|  |         SetRebootFlag true | ||||||
|  |         Goto unRemoveFromPath_dosLoop | ||||||
|  |  | ||||||
|  |     unRemoveFromPath_dosLoopEnd: | ||||||
|  |       FileClose $2 | ||||||
|  |       FileClose $1 | ||||||
|  |       StrCpy $1 $WINDIR 2 | ||||||
|  |       Delete "$1\autoexec.bat" | ||||||
|  |       CopyFiles /SILENT $4 "$1\autoexec.bat" | ||||||
|  |       Delete $4 | ||||||
|  |       Goto unRemoveFromPath_done | ||||||
|  |  | ||||||
|  |   unRemoveFromPath_NT: | ||||||
|  |     StrCmp $ADD_TO_PATH_ALL_USERS "1" unReadAllKey | ||||||
|  |       ReadRegStr $1 ${NT_current_env} "PATH" | ||||||
|  |       Goto unDoTrim | ||||||
|  |     unReadAllKey: | ||||||
|  |       ReadRegStr $1 ${NT_all_env} "PATH" | ||||||
|  |     unDoTrim: | ||||||
|  |     StrCpy $5 $1 1 -1 # copy last char | ||||||
|  |     StrCmp $5 ";" +2 # if last char != ; | ||||||
|  |       StrCpy $1 "$1;" # append ; | ||||||
|  |     Push $1 | ||||||
|  |     Push "$0;" | ||||||
|  |     Call un.StrStr ; Find `$0;` in $1 | ||||||
|  |     Pop $2 ; pos of our dir | ||||||
|  |     StrCmp $2 "" unRemoveFromPath_done | ||||||
|  |       ; else, it is in path | ||||||
|  |       # $0 - path to add | ||||||
|  |       # $1 - path var | ||||||
|  |       StrLen $3 "$0;" | ||||||
|  |       StrLen $4 $2 | ||||||
|  |       StrCpy $5 $1 -$4 # $5 is now the part before the path to remove | ||||||
|  |       StrCpy $6 $2 "" $3 # $6 is now the part after the path to remove | ||||||
|  |       StrCpy $3 $5$6 | ||||||
|  |  | ||||||
|  |       StrCpy $5 $3 1 -1 # copy last char | ||||||
|  |       StrCmp $5 ";" 0 +2 # if last char == ; | ||||||
|  |         StrCpy $3 $3 -1 # remove last char | ||||||
|  |  | ||||||
|  |       StrCmp $ADD_TO_PATH_ALL_USERS "1" unWriteAllKey | ||||||
|  |         WriteRegExpandStr ${NT_current_env} "PATH" $3 | ||||||
|  |         Goto unDoSend | ||||||
|  |       unWriteAllKey: | ||||||
|  |         WriteRegExpandStr ${NT_all_env} "PATH" $3 | ||||||
|  |       unDoSend: | ||||||
|  |       SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 | ||||||
|  |  | ||||||
|  |   unRemoveFromPath_done: | ||||||
|  |     Pop $6 | ||||||
|  |     Pop $5 | ||||||
|  |     Pop $4 | ||||||
|  |     Pop $3 | ||||||
|  |     Pop $2 | ||||||
|  |     Pop $1 | ||||||
|  |     Pop $0 | ||||||
|  | FunctionEnd | ||||||
|  |  | ||||||
|  | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||||
|  | ; Uninstall sutff | ||||||
|  | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||||
|  |  | ||||||
|  | ########################################### | ||||||
|  | #            Utility Functions            # | ||||||
|  | ########################################### | ||||||
|  |  | ||||||
|  | ;==================================================== | ||||||
|  | ; IsNT - Returns 1 if the current system is NT, 0 | ||||||
|  | ;        otherwise. | ||||||
|  | ;     Output: head of the stack | ||||||
|  | ;==================================================== | ||||||
|  | ; IsNT | ||||||
|  | ; no input | ||||||
|  | ; output, top of the stack = 1 if NT or 0 if not | ||||||
|  | ; | ||||||
|  | ; Usage: | ||||||
|  | ;   Call IsNT | ||||||
|  | ;   Pop $R0 | ||||||
|  | ;  ($R0 at this point is 1 or 0) | ||||||
|  |  | ||||||
|  | !macro IsNT un | ||||||
|  | Function ${un}IsNT | ||||||
|  |   Push $0 | ||||||
|  |   ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion | ||||||
|  |   StrCmp $0 "" 0 IsNT_yes | ||||||
|  |   ; we are not NT. | ||||||
|  |   Pop $0 | ||||||
|  |   Push 0 | ||||||
|  |   Return | ||||||
|  |  | ||||||
|  |   IsNT_yes: | ||||||
|  |     ; NT!!! | ||||||
|  |     Pop $0 | ||||||
|  |     Push 1 | ||||||
|  | FunctionEnd | ||||||
|  | !macroend | ||||||
|  | !insertmacro IsNT "" | ||||||
|  | !insertmacro IsNT "un." | ||||||
|  |  | ||||||
|  | ; StrStr | ||||||
|  | ; input, top of stack = string to search for | ||||||
|  | ;        top of stack-1 = string to search in | ||||||
|  | ; output, top of stack (replaces with the portion of the string remaining) | ||||||
|  | ; modifies no other variables. | ||||||
|  | ; | ||||||
|  | ; Usage: | ||||||
|  | ;   Push "this is a long ass string" | ||||||
|  | ;   Push "ass" | ||||||
|  | ;   Call StrStr | ||||||
|  | ;   Pop $R0 | ||||||
|  | ;  ($R0 at this point is "ass string") | ||||||
|  |  | ||||||
|  | !macro StrStr un | ||||||
|  | Function ${un}StrStr | ||||||
|  | Exch $R1 ; st=haystack,old$R1, $R1=needle | ||||||
|  |   Exch    ; st=old$R1,haystack | ||||||
|  |   Exch $R2 ; st=old$R1,old$R2, $R2=haystack | ||||||
|  |   Push $R3 | ||||||
|  |   Push $R4 | ||||||
|  |   Push $R5 | ||||||
|  |   StrLen $R3 $R1 | ||||||
|  |   StrCpy $R4 0 | ||||||
|  |   ; $R1=needle | ||||||
|  |   ; $R2=haystack | ||||||
|  |   ; $R3=len(needle) | ||||||
|  |   ; $R4=cnt | ||||||
|  |   ; $R5=tmp | ||||||
|  |   loop: | ||||||
|  |     StrCpy $R5 $R2 $R3 $R4 | ||||||
|  |     StrCmp $R5 $R1 done | ||||||
|  |     StrCmp $R5 "" done | ||||||
|  |     IntOp $R4 $R4 + 1 | ||||||
|  |     Goto loop | ||||||
|  | done: | ||||||
|  |   StrCpy $R1 $R2 "" $R4 | ||||||
|  |   Pop $R5 | ||||||
|  |   Pop $R4 | ||||||
|  |   Pop $R3 | ||||||
|  |   Pop $R2 | ||||||
|  |   Exch $R1 | ||||||
|  | FunctionEnd | ||||||
|  | !macroend | ||||||
|  | !insertmacro StrStr "" | ||||||
|  | !insertmacro StrStr "un." | ||||||
|  |  | ||||||
|  | Function Trim ; Added by Pelaca | ||||||
|  | 	Exch $R1 | ||||||
|  | 	Push $R2 | ||||||
|  | Loop: | ||||||
|  | 	StrCpy $R2 "$R1" 1 -1 | ||||||
|  | 	StrCmp "$R2" " " RTrim | ||||||
|  | 	StrCmp "$R2" "$\n" RTrim | ||||||
|  | 	StrCmp "$R2" "$\r" RTrim | ||||||
|  | 	StrCmp "$R2" ";" RTrim | ||||||
|  | 	GoTo Done | ||||||
|  | RTrim: | ||||||
|  | 	StrCpy $R1 "$R1" -1 | ||||||
|  | 	Goto Loop | ||||||
|  | Done: | ||||||
|  | 	Pop $R2 | ||||||
|  | 	Exch $R1 | ||||||
|  | FunctionEnd | ||||||
|  |  | ||||||
|  | Function ConditionalAddToRegisty | ||||||
|  |   Pop $0 | ||||||
|  |   Pop $1 | ||||||
|  |   StrCmp "$0" "" ConditionalAddToRegisty_EmptyString | ||||||
|  |     WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" \ | ||||||
|  |     "$1" "$0" | ||||||
|  |     ;MessageBox MB_OK "Set Registry: '$1' to '$0'" | ||||||
|  |     DetailPrint "Set install registry entry: '$1' to '$0'" | ||||||
|  |   ConditionalAddToRegisty_EmptyString: | ||||||
|  | FunctionEnd | ||||||
|  |  | ||||||
|  | ;-------------------------------- | ||||||
|  |  | ||||||
|  | !ifdef CPACK_USES_DOWNLOAD | ||||||
|  | Function DownloadFile | ||||||
|  |     IfFileExists $INSTDIR\* +2 | ||||||
|  |     CreateDirectory $INSTDIR | ||||||
|  |     Pop $0 | ||||||
|  |  | ||||||
|  |     ; Skip if already downloaded | ||||||
|  |     IfFileExists $INSTDIR\$0 0 +2 | ||||||
|  |     Return | ||||||
|  |  | ||||||
|  |     StrCpy $1 "@CPACK_DOWNLOAD_SITE@" | ||||||
|  |  | ||||||
|  |   try_again: | ||||||
|  |     NSISdl::download "$1/$0" "$INSTDIR\$0" | ||||||
|  |  | ||||||
|  |     Pop $1 | ||||||
|  |     StrCmp $1 "success" success | ||||||
|  |     StrCmp $1 "Cancelled" cancel | ||||||
|  |     MessageBox MB_OK "Download failed: $1" | ||||||
|  |   cancel: | ||||||
|  |     Return | ||||||
|  |   success: | ||||||
|  | FunctionEnd | ||||||
|  | !endif | ||||||
|  |  | ||||||
|  | ;-------------------------------- | ||||||
|  | ; Installation types | ||||||
|  | @CPACK_NSIS_INSTALLATION_TYPES@ | ||||||
|  |  | ||||||
|  | ;-------------------------------- | ||||||
|  | ; Component sections | ||||||
|  | @CPACK_NSIS_COMPONENT_SECTIONS@ | ||||||
|  |  | ||||||
|  | ;-------------------------------- | ||||||
|  | ; Define some macro setting for the gui | ||||||
|  | @CPACK_NSIS_INSTALLER_MUI_ICON_CODE@ | ||||||
|  | @CPACK_NSIS_INSTALLER_ICON_CODE@ | ||||||
|  | @CPACK_NSIS_INSTALLER_MUI_WELCOMEFINISH_CODE@ | ||||||
|  | @CPACK_NSIS_INSTALLER_MUI_UNWELCOMEFINISH_CODE@ | ||||||
|  | @CPACK_NSIS_INSTALLER_MUI_COMPONENTS_DESC@ | ||||||
|  | @CPACK_NSIS_INSTALLER_MUI_FINISHPAGE_RUN_CODE@ | ||||||
|  |  | ||||||
|  | ;-------------------------------- | ||||||
|  | ;Pages | ||||||
|  |   !insertmacro MUI_PAGE_WELCOME | ||||||
|  |  | ||||||
|  |   !insertmacro MUI_PAGE_LICENSE "@CPACK_RESOURCE_FILE_LICENSE@" | ||||||
|  |   Page custom InstallOptionsPage | ||||||
|  |   !insertmacro MUI_PAGE_DIRECTORY | ||||||
|  |  | ||||||
|  |   ;Start Menu Folder Page Configuration | ||||||
|  |   !define MUI_STARTMENUPAGE_REGISTRY_ROOT "SHCTX" | ||||||
|  |   !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" | ||||||
|  |   !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder" | ||||||
|  |   !insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER | ||||||
|  |  | ||||||
|  |   @CPACK_NSIS_PAGE_COMPONENTS@ | ||||||
|  |  | ||||||
|  |   !insertmacro MUI_PAGE_INSTFILES | ||||||
|  |   !insertmacro MUI_PAGE_FINISH | ||||||
|  |  | ||||||
|  |   !insertmacro MUI_UNPAGE_CONFIRM | ||||||
|  |   !insertmacro MUI_UNPAGE_INSTFILES | ||||||
|  |  | ||||||
|  | ;-------------------------------- | ||||||
|  | ;Languages | ||||||
|  |  | ||||||
|  |   !insertmacro MUI_LANGUAGE "English" ;first language is the default language | ||||||
|  |   !insertmacro MUI_LANGUAGE "Albanian" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Arabic" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Basque" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Belarusian" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Bosnian" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Breton" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Bulgarian" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Croatian" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Czech" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Danish" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Dutch" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Estonian" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Farsi" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Finnish" | ||||||
|  |   !insertmacro MUI_LANGUAGE "French" | ||||||
|  |   !insertmacro MUI_LANGUAGE "German" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Greek" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Hebrew" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Hungarian" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Icelandic" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Indonesian" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Irish" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Italian" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Japanese" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Korean" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Kurdish" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Latvian" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Lithuanian" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Luxembourgish" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Macedonian" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Malay" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Mongolian" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Norwegian" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Polish" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Portuguese" | ||||||
|  |   !insertmacro MUI_LANGUAGE "PortugueseBR" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Romanian" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Russian" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Serbian" | ||||||
|  |   !insertmacro MUI_LANGUAGE "SerbianLatin" | ||||||
|  |   !insertmacro MUI_LANGUAGE "SimpChinese" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Slovak" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Slovenian" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Spanish" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Swedish" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Thai" | ||||||
|  |   !insertmacro MUI_LANGUAGE "TradChinese" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Turkish" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Ukrainian" | ||||||
|  |   !insertmacro MUI_LANGUAGE "Welsh" | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ;-------------------------------- | ||||||
|  | ;Reserve Files | ||||||
|  |  | ||||||
|  |   ;These files should be inserted before other files in the data block | ||||||
|  |   ;Keep these lines before any File command | ||||||
|  |   ;Only for solid compression (by default, solid compression is enabled for BZIP2 and LZMA) | ||||||
|  |  | ||||||
|  |   ReserveFile "NSIS.InstallOptions.ini" | ||||||
|  |   !insertmacro MUI_RESERVEFILE_INSTALLOPTIONS | ||||||
|  |  | ||||||
|  | ;-------------------------------- | ||||||
|  | ;Installer Sections | ||||||
|  |  | ||||||
|  | Section "-Core installation" | ||||||
|  |   ;Use the entire tree produced by the INSTALL target.  Keep the | ||||||
|  |   ;list of directories here in sync with the RMDir commands below. | ||||||
|  |   SetOutPath "$INSTDIR" | ||||||
|  |   @CPACK_NSIS_EXTRA_PREINSTALL_COMMANDS@ | ||||||
|  |   @CPACK_NSIS_FULL_INSTALL@ | ||||||
|  |  | ||||||
|  |   ;Store installation folder | ||||||
|  |   WriteRegStr SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "" $INSTDIR | ||||||
|  |  | ||||||
|  |   ;Create uninstaller | ||||||
|  |   WriteUninstaller "$INSTDIR\Uninstall.exe" | ||||||
|  |   Push "DisplayName" | ||||||
|  |   Push "@CPACK_NSIS_DISPLAY_NAME@" | ||||||
|  |   Call ConditionalAddToRegisty | ||||||
|  |   Push "DisplayVersion" | ||||||
|  |   Push "@CPACK_PACKAGE_VERSION@" | ||||||
|  |   Call ConditionalAddToRegisty | ||||||
|  |   Push "Publisher" | ||||||
|  |   Push "@CPACK_PACKAGE_VENDOR@" | ||||||
|  |   Call ConditionalAddToRegisty | ||||||
|  |   Push "UninstallString" | ||||||
|  |   Push "$INSTDIR\Uninstall.exe" | ||||||
|  |   Call ConditionalAddToRegisty | ||||||
|  |   Push "NoRepair" | ||||||
|  |   Push "1" | ||||||
|  |   Call ConditionalAddToRegisty | ||||||
|  |  | ||||||
|  |   !ifdef CPACK_NSIS_ADD_REMOVE | ||||||
|  |   ;Create add/remove functionality | ||||||
|  |   Push "ModifyPath" | ||||||
|  |   Push "$INSTDIR\AddRemove.exe" | ||||||
|  |   Call ConditionalAddToRegisty | ||||||
|  |   !else | ||||||
|  |   Push "NoModify" | ||||||
|  |   Push "1" | ||||||
|  |   Call ConditionalAddToRegisty | ||||||
|  |   !endif | ||||||
|  |  | ||||||
|  |   ; Optional registration | ||||||
|  |   Push "DisplayIcon" | ||||||
|  |   Push "$INSTDIR\@CPACK_NSIS_INSTALLED_ICON_NAME@" | ||||||
|  |   Call ConditionalAddToRegisty | ||||||
|  |   Push "HelpLink" | ||||||
|  |   Push "@CPACK_NSIS_HELP_LINK@" | ||||||
|  |   Call ConditionalAddToRegisty | ||||||
|  |   Push "URLInfoAbout" | ||||||
|  |   Push "@CPACK_NSIS_URL_INFO_ABOUT@" | ||||||
|  |   Call ConditionalAddToRegisty | ||||||
|  |   Push "Contact" | ||||||
|  |   Push "@CPACK_NSIS_CONTACT@" | ||||||
|  |   Call ConditionalAddToRegisty | ||||||
|  |   !insertmacro MUI_INSTALLOPTIONS_READ $INSTALL_DESKTOP "NSIS.InstallOptions.ini" "Field 5" "State" | ||||||
|  |   !insertmacro MUI_STARTMENU_WRITE_BEGIN Application | ||||||
|  |  | ||||||
|  |   ;Create shortcuts | ||||||
|  |   CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER" | ||||||
|  | @CPACK_NSIS_CREATE_ICONS@ | ||||||
|  | @CPACK_NSIS_CREATE_ICONS_EXTRA@ | ||||||
|  |   CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe" | ||||||
|  |  | ||||||
|  |   ;Read a value from an InstallOptions INI file | ||||||
|  |   !insertmacro MUI_INSTALLOPTIONS_READ $DO_NOT_ADD_TO_PATH "NSIS.InstallOptions.ini" "Field 2" "State" | ||||||
|  |   !insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_ALL_USERS "NSIS.InstallOptions.ini" "Field 3" "State" | ||||||
|  |   !insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_CURRENT_USER "NSIS.InstallOptions.ini" "Field 4" "State" | ||||||
|  |  | ||||||
|  |   ; Write special uninstall registry entries | ||||||
|  |   Push "StartMenu" | ||||||
|  |   Push "$STARTMENU_FOLDER" | ||||||
|  |   Call ConditionalAddToRegisty | ||||||
|  |   Push "DoNotAddToPath" | ||||||
|  |   Push "$DO_NOT_ADD_TO_PATH" | ||||||
|  |   Call ConditionalAddToRegisty | ||||||
|  |   Push "AddToPathAllUsers" | ||||||
|  |   Push "$ADD_TO_PATH_ALL_USERS" | ||||||
|  |   Call ConditionalAddToRegisty | ||||||
|  |   Push "AddToPathCurrentUser" | ||||||
|  |   Push "$ADD_TO_PATH_CURRENT_USER" | ||||||
|  |   Call ConditionalAddToRegisty | ||||||
|  |   Push "InstallToDesktop" | ||||||
|  |   Push "$INSTALL_DESKTOP" | ||||||
|  |   Call ConditionalAddToRegisty | ||||||
|  |  | ||||||
|  |   !insertmacro MUI_STARTMENU_WRITE_END | ||||||
|  |  | ||||||
|  | @CPACK_NSIS_EXTRA_INSTALL_COMMANDS@ | ||||||
|  |  | ||||||
|  | SectionEnd | ||||||
|  |  | ||||||
|  | Section "-Add to path" | ||||||
|  |   Push $INSTDIR\bin | ||||||
|  |   StrCmp "@CPACK_NSIS_MODIFY_PATH@" "ON" 0 doNotAddToPath | ||||||
|  |   StrCmp $DO_NOT_ADD_TO_PATH "1" doNotAddToPath 0 | ||||||
|  |     Call AddToPath | ||||||
|  |   doNotAddToPath: | ||||||
|  | SectionEnd | ||||||
|  |  | ||||||
|  | ;-------------------------------- | ||||||
|  | ; Create custom pages | ||||||
|  | Function InstallOptionsPage | ||||||
|  |   !insertmacro MUI_HEADER_TEXT "Install Options" "Choose options for installing @CPACK_NSIS_PACKAGE_NAME@" | ||||||
|  |   !insertmacro MUI_INSTALLOPTIONS_DISPLAY "NSIS.InstallOptions.ini" | ||||||
|  |  | ||||||
|  | FunctionEnd | ||||||
|  |  | ||||||
|  | ;-------------------------------- | ||||||
|  | ; determine admin versus local install | ||||||
|  | Function un.onInit | ||||||
|  |  | ||||||
|  |   ClearErrors | ||||||
|  |   UserInfo::GetName | ||||||
|  |   IfErrors noLM | ||||||
|  |   Pop $0 | ||||||
|  |   UserInfo::GetAccountType | ||||||
|  |   Pop $1 | ||||||
|  |   StrCmp $1 "Admin" 0 +3 | ||||||
|  |     SetShellVarContext all | ||||||
|  |     ;MessageBox MB_OK 'User "$0" is in the Admin group' | ||||||
|  |     Goto done | ||||||
|  |   StrCmp $1 "Power" 0 +3 | ||||||
|  |     SetShellVarContext all | ||||||
|  |     ;MessageBox MB_OK 'User "$0" is in the Power Users group' | ||||||
|  |     Goto done | ||||||
|  |  | ||||||
|  |   noLM: | ||||||
|  |     ;Get installation folder from registry if available | ||||||
|  |  | ||||||
|  |   done: | ||||||
|  |  | ||||||
|  | FunctionEnd | ||||||
|  |  | ||||||
|  | ;--- Add/Remove callback functions: --- | ||||||
|  | !macro SectionList MacroName | ||||||
|  |   ;This macro used to perform operation on multiple sections. | ||||||
|  |   ;List all of your components in following manner here. | ||||||
|  | @CPACK_NSIS_COMPONENT_SECTION_LIST@ | ||||||
|  | !macroend | ||||||
|  |  | ||||||
|  | Section -FinishComponents | ||||||
|  |   ;Removes unselected components and writes component status to registry | ||||||
|  |   !insertmacro SectionList "FinishSection" | ||||||
|  |  | ||||||
|  | !ifdef CPACK_NSIS_ADD_REMOVE | ||||||
|  |   ; Get the name of the installer executable | ||||||
|  |   System::Call 'kernel32::GetModuleFileNameA(i 0, t .R0, i 1024) i r1' | ||||||
|  |   StrCpy $R3 $R0 | ||||||
|  |  | ||||||
|  |   ; Strip off the last 13 characters, to see if we have AddRemove.exe | ||||||
|  |   StrLen $R1 $R0 | ||||||
|  |   IntOp $R1 $R0 - 13 | ||||||
|  |   StrCpy $R2 $R0 13 $R1 | ||||||
|  |   StrCmp $R2 "AddRemove.exe" addremove_installed | ||||||
|  |  | ||||||
|  |   ; We're not running AddRemove.exe, so install it | ||||||
|  |   CopyFiles $R3 $INSTDIR\AddRemove.exe | ||||||
|  |  | ||||||
|  |   addremove_installed: | ||||||
|  | !endif | ||||||
|  | SectionEnd | ||||||
|  | ;--- End of Add/Remove callback functions --- | ||||||
|  |  | ||||||
|  | ;-------------------------------- | ||||||
|  | ; Component dependencies | ||||||
|  | Function .onSelChange | ||||||
|  |   !insertmacro SectionList MaybeSelectionChanged | ||||||
|  | FunctionEnd | ||||||
|  |  | ||||||
|  | ;-------------------------------- | ||||||
|  | ;Uninstaller Section | ||||||
|  |  | ||||||
|  | Section "Uninstall" | ||||||
|  |   ReadRegStr $START_MENU SHCTX \ | ||||||
|  |    "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "StartMenu" | ||||||
|  |   ;MessageBox MB_OK "Start menu is in: $START_MENU" | ||||||
|  |   ReadRegStr $DO_NOT_ADD_TO_PATH SHCTX \ | ||||||
|  |     "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "DoNotAddToPath" | ||||||
|  |   ReadRegStr $ADD_TO_PATH_ALL_USERS SHCTX \ | ||||||
|  |     "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "AddToPathAllUsers" | ||||||
|  |   ReadRegStr $ADD_TO_PATH_CURRENT_USER SHCTX \ | ||||||
|  |     "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "AddToPathCurrentUser" | ||||||
|  |   ;MessageBox MB_OK "Add to path: $DO_NOT_ADD_TO_PATH all users: $ADD_TO_PATH_ALL_USERS" | ||||||
|  |   ReadRegStr $INSTALL_DESKTOP SHCTX \ | ||||||
|  |     "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "InstallToDesktop" | ||||||
|  |   ;MessageBox MB_OK "Install to desktop: $INSTALL_DESKTOP " | ||||||
|  |  | ||||||
|  | @CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS@ | ||||||
|  |  | ||||||
|  |   ;Remove files we installed. | ||||||
|  |   ;Keep the list of directories here in sync with the File commands above. | ||||||
|  | @CPACK_NSIS_DELETE_FILES@ | ||||||
|  | @CPACK_NSIS_DELETE_DIRECTORIES@ | ||||||
|  |  | ||||||
|  | !ifdef CPACK_NSIS_ADD_REMOVE | ||||||
|  |   ;Remove the add/remove program | ||||||
|  |   Delete "$INSTDIR\AddRemove.exe" | ||||||
|  | !endif | ||||||
|  |  | ||||||
|  |   ;Remove the uninstaller itself. | ||||||
|  |   Delete "$INSTDIR\Uninstall.exe" | ||||||
|  |   DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" | ||||||
|  |  | ||||||
|  |   ;Remove the installation directory if it is empty. | ||||||
|  |   RMDir "$INSTDIR" | ||||||
|  |  | ||||||
|  |   ; Remove the registry entries. | ||||||
|  |   DeleteRegKey SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" | ||||||
|  |  | ||||||
|  |   ; Removes all optional components | ||||||
|  |   !insertmacro SectionList "RemoveSection_CPack" | ||||||
|  |  | ||||||
|  |   !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP | ||||||
|  |  | ||||||
|  |   Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk" | ||||||
|  | @CPACK_NSIS_DELETE_ICONS@ | ||||||
|  | @CPACK_NSIS_DELETE_ICONS_EXTRA@ | ||||||
|  |  | ||||||
|  |   ;Delete empty start menu parent diretories | ||||||
|  |   StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP" | ||||||
|  |  | ||||||
|  |   startMenuDeleteLoop: | ||||||
|  |     ClearErrors | ||||||
|  |     RMDir $MUI_TEMP | ||||||
|  |     GetFullPathName $MUI_TEMP "$MUI_TEMP\.." | ||||||
|  |  | ||||||
|  |     IfErrors startMenuDeleteLoopDone | ||||||
|  |  | ||||||
|  |     StrCmp "$MUI_TEMP" "$SMPROGRAMS" startMenuDeleteLoopDone startMenuDeleteLoop | ||||||
|  |   startMenuDeleteLoopDone: | ||||||
|  |  | ||||||
|  |   ; If the user changed the shortcut, then untinstall may not work. This should | ||||||
|  |   ; try to fix it. | ||||||
|  |   StrCpy $MUI_TEMP "$START_MENU" | ||||||
|  |   Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk" | ||||||
|  | @CPACK_NSIS_DELETE_ICONS_EXTRA@ | ||||||
|  |  | ||||||
|  |   ;Delete empty start menu parent diretories | ||||||
|  |   StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP" | ||||||
|  |  | ||||||
|  |   secondStartMenuDeleteLoop: | ||||||
|  |     ClearErrors | ||||||
|  |     RMDir $MUI_TEMP | ||||||
|  |     GetFullPathName $MUI_TEMP "$MUI_TEMP\.." | ||||||
|  |  | ||||||
|  |     IfErrors secondStartMenuDeleteLoopDone | ||||||
|  |  | ||||||
|  |     StrCmp "$MUI_TEMP" "$SMPROGRAMS" secondStartMenuDeleteLoopDone secondStartMenuDeleteLoop | ||||||
|  |   secondStartMenuDeleteLoopDone: | ||||||
|  |  | ||||||
|  |   DeleteRegKey /ifempty SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" | ||||||
|  |  | ||||||
|  |   Push $INSTDIR\bin | ||||||
|  |   StrCmp $DO_NOT_ADD_TO_PATH_ "1" doNotRemoveFromPath 0 | ||||||
|  |     Call un.RemoveFromPath | ||||||
|  |   doNotRemoveFromPath: | ||||||
|  | SectionEnd | ||||||
|  |  | ||||||
|  | ;-------------------------------- | ||||||
|  | ; determine admin versus local install | ||||||
|  | ; Is install for "AllUsers" or "JustMe"? | ||||||
|  | ; Default to "JustMe" - set to "AllUsers" if admin or on Win9x | ||||||
|  | ; This function is used for the very first "custom page" of the installer. | ||||||
|  | ; This custom page does not show up visibly, but it executes prior to the | ||||||
|  | ; first visible page and sets up $INSTDIR properly... | ||||||
|  | ; Choose different default installation folder based on SV_ALLUSERS... | ||||||
|  | ; "Program Files" for AllUsers, "My Documents" for JustMe... | ||||||
|  |  | ||||||
|  | Function .onInit | ||||||
|  |   StrCmp "@CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL@" "ON" 0 inst | ||||||
|  |  | ||||||
|  |   ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "UninstallString" | ||||||
|  |   StrCmp $0 "" inst | ||||||
|  |  | ||||||
|  |   MessageBox MB_YESNOCANCEL|MB_ICONEXCLAMATION \ | ||||||
|  |   "@CPACK_NSIS_PACKAGE_NAME@ is already installed. $\n$\nDo you want to uninstall the old version before installing the new one?" \ | ||||||
|  |   /SD IDYES IDYES uninst IDNO inst | ||||||
|  |   Abort | ||||||
|  |  | ||||||
|  | ;Run the uninstaller | ||||||
|  | uninst: | ||||||
|  |   ClearErrors | ||||||
|  |   StrLen $2 "\Uninstall.exe" | ||||||
|  |   StrCpy $3 $0 -$2 # remove "\Uninstall.exe" from UninstallString to get path | ||||||
|  |   ExecWait '"$0" /S _?=$3' ;Do not copy the uninstaller to a temp file | ||||||
|  |  | ||||||
|  |   IfErrors uninst_failed inst | ||||||
|  | uninst_failed: | ||||||
|  |   MessageBox MB_OK|MB_ICONSTOP "Uninstall failed." | ||||||
|  |   Abort | ||||||
|  |  | ||||||
|  |  | ||||||
|  | inst: | ||||||
|  |   ; Reads components status for registry | ||||||
|  |   !insertmacro SectionList "InitSection" | ||||||
|  |  | ||||||
|  |   ; check to see if /D has been used to change | ||||||
|  |   ; the install directory by comparing it to the | ||||||
|  |   ; install directory that is expected to be the | ||||||
|  |   ; default | ||||||
|  |   StrCpy $IS_DEFAULT_INSTALLDIR 0 | ||||||
|  |   StrCmp "$INSTDIR" "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" 0 +2 | ||||||
|  |     StrCpy $IS_DEFAULT_INSTALLDIR 1 | ||||||
|  |  | ||||||
|  |   StrCpy $SV_ALLUSERS "JustMe" | ||||||
|  |   ; if default install dir then change the default | ||||||
|  |   ; if it is installed for JustMe | ||||||
|  |   StrCmp "$IS_DEFAULT_INSTALLDIR" "1" 0 +2 | ||||||
|  |     StrCpy $INSTDIR "$DOCUMENTS\@CPACK_PACKAGE_INSTALL_DIRECTORY@" | ||||||
|  |  | ||||||
|  |   ClearErrors | ||||||
|  |   UserInfo::GetName | ||||||
|  |   IfErrors noLM | ||||||
|  |   Pop $0 | ||||||
|  |   UserInfo::GetAccountType | ||||||
|  |   Pop $1 | ||||||
|  |   StrCmp $1 "Admin" 0 +4 | ||||||
|  |     SetShellVarContext all | ||||||
|  |     ;MessageBox MB_OK 'User "$0" is in the Admin group' | ||||||
|  |     StrCpy $SV_ALLUSERS "AllUsers" | ||||||
|  |     Goto done | ||||||
|  |   StrCmp $1 "Power" 0 +4 | ||||||
|  |     SetShellVarContext all | ||||||
|  |     ;MessageBox MB_OK 'User "$0" is in the Power Users group' | ||||||
|  |     StrCpy $SV_ALLUSERS "AllUsers" | ||||||
|  |     Goto done | ||||||
|  |  | ||||||
|  |   noLM: | ||||||
|  |     StrCpy $SV_ALLUSERS "AllUsers" | ||||||
|  |     ;Get installation folder from registry if available | ||||||
|  |  | ||||||
|  |   done: | ||||||
|  |   StrCmp $SV_ALLUSERS "AllUsers" 0 +3 | ||||||
|  |     StrCmp "$IS_DEFAULT_INSTALLDIR" "1" 0 +2 | ||||||
|  |       StrCpy $INSTDIR "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" | ||||||
|  |  | ||||||
|  |   StrCmp "@CPACK_NSIS_MODIFY_PATH@" "ON" 0 noOptionsPage | ||||||
|  |     !insertmacro MUI_INSTALLOPTIONS_EXTRACT "NSIS.InstallOptions.ini" | ||||||
|  |  | ||||||
|  |   noOptionsPage: | ||||||
|  | FunctionEnd | ||||||
							
								
								
									
										210
									
								
								CI/appveyor.yml
									
									
									
									
									
								
							
							
						
						
									
										210
									
								
								CI/appveyor.yml
									
									
									
									
									
								
							| @@ -1,105 +1,105 @@ | |||||||
| # Common configuration for all branches | # Common configuration for all branches | ||||||
| version: 1.0.{build} | version: 1.0.{build} | ||||||
| max_jobs: 2 | max_jobs: 2 | ||||||
| clone_depth: 10 | clone_depth: 10 | ||||||
| clone_folder: c:\projects\vcmi\source | clone_folder: c:\projects\vcmi\source | ||||||
| install: | install: | ||||||
| - bash c:\projects\vcmi\source\CI\msvc\install.sh | - bash c:\projects\vcmi\source\CI\msvc\install.sh | ||||||
| build_script: | build_script: | ||||||
| - cmd: c:\projects\vcmi\source\CI\msvc\build_script.bat | - cmd: c:\projects\vcmi\source\CI\msvc\build_script.bat | ||||||
| artifacts: | artifacts: | ||||||
| - path: build_$(VCMI_BUILD_PLATFORM)\*.exe | - path: build_$(VCMI_BUILD_PLATFORM)\*.exe | ||||||
| notifications: | notifications: | ||||||
|   - provider: Slack |   - provider: Slack | ||||||
|     incoming_webhook: |     incoming_webhook: | ||||||
|       secure: zxT3HTnxL744HiSv7ig7sjGL4LmJ8n3MsY8PEA/kinbVMkmcxrSgVBVkHV79RfSWSyq4oLMSRvMMpG8SuDWnf6oK/qvgaiAWfwwlCIiA7uQ= |       secure: zxT3HTnxL744HiSv7ig7sjGL4LmJ8n3MsY8PEA/kinbVMkmcxrSgVBVkHV79RfSWSyq4oLMSRvMMpG8SuDWnf6oK/qvgaiAWfwwlCIiA7uQ= | ||||||
|  |  | ||||||
| # Branch-specific configuration | # Branch-specific configuration | ||||||
| for: | for: | ||||||
| # Extended configuration for toolchain_test branch | # Extended configuration for toolchain_test branch | ||||||
| - | - | ||||||
|   branches: |   branches: | ||||||
|     only: |     only: | ||||||
|       - toolchain_test |       - toolchain_test | ||||||
|   environment: |   environment: | ||||||
|     matrix: |     matrix: | ||||||
|       - NAME: MSVS 2015 x86 - Release |       - NAME: MSVS 2015 x86 - Release | ||||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 |         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 | ||||||
|         VCMI_GENERATOR: Visual Studio 14 2015 |         VCMI_GENERATOR: Visual Studio 14 2015 | ||||||
|         VCMI_BUILD_PLATFORM: x86 |         VCMI_BUILD_PLATFORM: x86 | ||||||
|         VCMI_BUILD_CONFIGURATION: Release |         VCMI_BUILD_CONFIGURATION: Release | ||||||
|       - NAME: MSVS 2015 x86 - Debug |       - NAME: MSVS 2015 x86 - Debug | ||||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 |         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 | ||||||
|         VCMI_GENERATOR: Visual Studio 14 2015 |         VCMI_GENERATOR: Visual Studio 14 2015 | ||||||
|         VCMI_BUILD_PLATFORM: x86 |         VCMI_BUILD_PLATFORM: x86 | ||||||
|         VCMI_BUILD_CONFIGURATION: Debug |         VCMI_BUILD_CONFIGURATION: Debug | ||||||
|  |  | ||||||
|       - NAME: MSVS 2015 x64 - Release |       - NAME: MSVS 2015 x64 - Release | ||||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 |         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 | ||||||
|         VCMI_GENERATOR: Visual Studio 14 2015 Win64 |         VCMI_GENERATOR: Visual Studio 14 2015 Win64 | ||||||
|         VCMI_BUILD_PLATFORM: x64 |         VCMI_BUILD_PLATFORM: x64 | ||||||
|         VCMI_BUILD_CONFIGURATION: Release |         VCMI_BUILD_CONFIGURATION: Release | ||||||
|       - NAME: MSVS 2015 x64 - Debug |       - NAME: MSVS 2015 x64 - Debug | ||||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 |         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 | ||||||
|         VCMI_GENERATOR: Visual Studio 14 2015 Win64 |         VCMI_GENERATOR: Visual Studio 14 2015 Win64 | ||||||
|         VCMI_BUILD_PLATFORM: x64 |         VCMI_BUILD_PLATFORM: x64 | ||||||
|         VCMI_BUILD_CONFIGURATION: Debug |         VCMI_BUILD_CONFIGURATION: Debug | ||||||
|  |  | ||||||
|       - NAME: MSVS 2017 x86 - Release |       - NAME: MSVS 2017 x86 - Release | ||||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 |         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 | ||||||
|         VCMI_GENERATOR: Visual Studio 15 2017 |         VCMI_GENERATOR: Visual Studio 15 2017 | ||||||
|         VCMI_BUILD_PLATFORM: x86 |         VCMI_BUILD_PLATFORM: x86 | ||||||
|         VCMI_BUILD_CONFIGURATION: Release |         VCMI_BUILD_CONFIGURATION: Release | ||||||
|       - NAME: MSVS 2017 x86 - Debug |       - NAME: MSVS 2017 x86 - Debug | ||||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 |         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 | ||||||
|         VCMI_GENERATOR: Visual Studio 15 2017 |         VCMI_GENERATOR: Visual Studio 15 2017 | ||||||
|         VCMI_BUILD_PLATFORM: x86 |         VCMI_BUILD_PLATFORM: x86 | ||||||
|         VCMI_BUILD_CONFIGURATION: Debug |         VCMI_BUILD_CONFIGURATION: Debug | ||||||
|  |  | ||||||
|       - NAME: MSVS 2017 x64 - Release |       - NAME: MSVS 2017 x64 - Release | ||||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 |         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 | ||||||
|         VCMI_GENERATOR: Visual Studio 15 2017 Win64 |         VCMI_GENERATOR: Visual Studio 15 2017 Win64 | ||||||
|         VCMI_BUILD_PLATFORM: x64 |         VCMI_BUILD_PLATFORM: x64 | ||||||
|         VCMI_BUILD_CONFIGURATION: Release |         VCMI_BUILD_CONFIGURATION: Release | ||||||
|       - NAME: MSVS 2017 x64 - Debug |       - NAME: MSVS 2017 x64 - Debug | ||||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 |         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 | ||||||
|         VCMI_GENERATOR: Visual Studio 15 2017 Win64 |         VCMI_GENERATOR: Visual Studio 15 2017 Win64 | ||||||
|         VCMI_BUILD_PLATFORM: x64 |         VCMI_BUILD_PLATFORM: x64 | ||||||
|         VCMI_BUILD_CONFIGURATION: Debug |         VCMI_BUILD_CONFIGURATION: Debug | ||||||
|  |  | ||||||
| # Special configuration for coverity_scan branch | # Special configuration for coverity_scan branch | ||||||
| - | - | ||||||
|   branches: |   branches: | ||||||
|     only: |     only: | ||||||
|       - coverity_scan |       - coverity_scan | ||||||
|   environment: |   environment: | ||||||
|     matrix: |     matrix: | ||||||
|       - NAME: Coverity - MSVS 2017 x86 - Release |       - NAME: Coverity - MSVS 2017 x86 - Release | ||||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 |         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 | ||||||
|         VCMI_GENERATOR: Visual Studio 15 2017 |         VCMI_GENERATOR: Visual Studio 15 2017 | ||||||
|         VCMI_BUILD_PLATFORM: x86 |         VCMI_BUILD_PLATFORM: x86 | ||||||
|         VCMI_BUILD_CONFIGURATION: Release |         VCMI_BUILD_CONFIGURATION: Release | ||||||
|         environment: |         environment: | ||||||
|     coverity_token: |     coverity_token: | ||||||
|       secure: XNnpYevnZxGmXW1zLu+3js2S+pqfWPQmL26hVgOTBTI= |       secure: XNnpYevnZxGmXW1zLu+3js2S+pqfWPQmL26hVgOTBTI= | ||||||
|     coverity_email: |     coverity_email: | ||||||
|       secure: JDd5yXvYaq/yJEVjoadEhA== |       secure: JDd5yXvYaq/yJEVjoadEhA== | ||||||
|   build_script: |   build_script: | ||||||
|     - cmd: c:\projects\vcmi\source\CI\msvc\coverity_build_script.bat |     - cmd: c:\projects\vcmi\source\CI\msvc\coverity_build_script.bat | ||||||
|   after_test: |   after_test: | ||||||
|     - ps: c:\projects\vcmi\source\CI\msvc\coverity_upload_script.ps |     - ps: c:\projects\vcmi\source\CI\msvc\coverity_upload_script.ps | ||||||
|  |  | ||||||
| # Default configuration for all other branches | # Default configuration for all other branches | ||||||
| - | - | ||||||
|   environment: |   environment: | ||||||
|     matrix: |     matrix: | ||||||
|       - NAME: MSVS 2017 x86 - Release |       - NAME: MSVS 2017 x86 - Release | ||||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 |         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 | ||||||
|         VCMI_GENERATOR: Visual Studio 15 2017 |         VCMI_GENERATOR: Visual Studio 15 2017 | ||||||
|         VCMI_BUILD_PLATFORM: x86 |         VCMI_BUILD_PLATFORM: x86 | ||||||
|         VCMI_BUILD_CONFIGURATION: Release |         VCMI_BUILD_CONFIGURATION: Release | ||||||
|       - NAME: MSVS 2017 x64 - Release |       - NAME: MSVS 2017 x64 - Release | ||||||
|         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 |         APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 | ||||||
|         VCMI_GENERATOR: Visual Studio 15 2017 Win64 |         VCMI_GENERATOR: Visual Studio 15 2017 Win64 | ||||||
|         VCMI_BUILD_PLATFORM: x64 |         VCMI_BUILD_PLATFORM: x64 | ||||||
|         VCMI_BUILD_CONFIGURATION: Release |         VCMI_BUILD_CONFIGURATION: Release | ||||||
|   | |||||||
| @@ -13,6 +13,13 @@ then | |||||||
| 	TMP_BRANCH="$APPVEYOR_REPO_BRANCH" | 	TMP_BRANCH="$APPVEYOR_REPO_BRANCH" | ||||||
| 	TMP_PRID="$APPVEYOR_PULL_REQUEST_NUMBER" | 	TMP_PRID="$APPVEYOR_PULL_REQUEST_NUMBER" | ||||||
| 	TMP_COMMIT="$APPVEYOR_REPO_COMMIT" | 	TMP_COMMIT="$APPVEYOR_REPO_COMMIT" | ||||||
|  | elif [ ! -z "${GITHUB_RUN_ID}" ]; | ||||||
|  | then | ||||||
|  | 	echo "Using Github environment variables!" | ||||||
|  | 	TMP_JOBID="$GITHUB_RUN_ID" | ||||||
|  | 	TMP_BRANCH=${GITHUB_REF#refs/heads/} | ||||||
|  | 	TMP_PRID="$PULL_REQUEST" | ||||||
|  | 	TMP_COMMIT=$(git rev-parse --short "$GITHUB_SHA") | ||||||
| else | else | ||||||
| 	echo "No Travir or AppVeyor environment variables found!" | 	echo "No Travir or AppVeyor environment variables found!" | ||||||
| 	exit | 	exit | ||||||
|   | |||||||
| @@ -1,27 +1,16 @@ | |||||||
| #!/bin/sh | #!/bin/sh | ||||||
|  |  | ||||||
| #new Clang | sudo apt-get update | ||||||
| sudo add-apt-repository --yes ppa:h-rayflood/llvm |  | ||||||
|  |  | ||||||
| #new SDL2 | # Boost | ||||||
| sudo add-apt-repository --yes ppa:zoogie/sdl2-snapshots | wget -nv https://boostorg.jfrog.io/artifactory/main/release/1.66.0/source/boost_1_66_0.tar.gz | ||||||
|  | tar xfz boost_1_66_0.tar.gz | ||||||
|  | cd boost_1_66_0 | ||||||
|  | ./bootstrap.sh --with-libraries=program_options,filesystem,system,thread,locale,date_time | ||||||
|  | ./b2 | ||||||
|  | sudo ./b2 install | ||||||
|  |  | ||||||
| #new Qt | # Dependencies | ||||||
| sudo add-apt-repository --yes ppa:beineri/opt-qt571-trusty | sudo apt-get install libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev | ||||||
|  | sudo apt-get install qtbase5-dev | ||||||
| #new CMake | sudo apt-get install ninja-build zlib1g-dev libavformat-dev libswscale-dev libtbb-dev libluajit-5.1-dev | ||||||
| sudo add-apt-repository --yes ppa:george-edison55/cmake-3.x |  | ||||||
|  |  | ||||||
| sudo apt-get update -qq |  | ||||||
|  |  | ||||||
| sudo apt-get install -qq $SUPPORT |  | ||||||
| sudo apt-get install -qq $PACKAGE |  | ||||||
| sudo apt-get install -qq cmake ninja-build libboost1.54-all-dev zlib1g-dev |  | ||||||
| sudo apt-get install -qq libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev |  | ||||||
| sudo apt-get install -qq libavformat-dev libswscale-dev |  | ||||||
| sudo apt-get install -qq qt57declarative |  | ||||||
| sudo apt-get install -qq libluajit-5.1-dev |  | ||||||
|  |  | ||||||
| #setup compiler |  | ||||||
| source /opt/qt57/bin/qt57-env.sh |  | ||||||
| export CC=${REAL_CC} CXX=${REAL_CXX} |  | ||||||
| @@ -1,7 +1,7 @@ | |||||||
| #!/bin/sh | #!/bin/sh | ||||||
|  |  | ||||||
| brew update | brew update | ||||||
| brew install smpeg2 libpng freetype sdl2 sdl2_ttf sdl2_image qt5 ffmpeg ninja luajit | brew install smpeg2 libpng freetype qt5 ffmpeg ninja boost tbb luajit | ||||||
| brew install sdl2_mixer | brew install sdl2 sdl2_ttf sdl2_image sdl2_mixer | ||||||
|  |  | ||||||
| export CMAKE_PREFIX_PATH="/usr/local/opt/qt5:$CMAKE_PREFIX_PATH" | echo CMAKE_PREFIX_PATH="/usr/local/opt/qt5:$CMAKE_PREFIX_PATH" >> $GITHUB_ENV | ||||||
|   | |||||||
| @@ -1,15 +0,0 @@ | |||||||
| #!/bin/sh |  | ||||||
| if [ -z "$encrypted_1d30f79f8582_key" ]; |  | ||||||
| then |  | ||||||
| 	# Due to security measures travis not expose encryption keys for PR from forks |  | ||||||
| 	exit 0 |  | ||||||
| fi |  | ||||||
| cpack |  | ||||||
|  |  | ||||||
| touch /tmp/deploy_rsa |  | ||||||
| chmod 600 /tmp/deploy_rsa |  | ||||||
| openssl aes-256-cbc -K $encrypted_1d30f79f8582_key -iv $encrypted_1d30f79f8582_iv -in $TRAVIS_BUILD_DIR/CI/deploy_rsa.enc -out /tmp/deploy_rsa -d |  | ||||||
| eval "$(ssh-agent -s)" |  | ||||||
| ssh-add /tmp/deploy_rsa |  | ||||||
|  |  | ||||||
| sftp -r -o StrictHostKeyChecking=no travis@beholder.vcmi.eu <<< "put $VCMI_PACKAGE_FILE_NAME.dmg /incoming/$VCMI_PACKAGE_FILE_NAME.dmg" |  | ||||||
| @@ -4,7 +4,7 @@ | |||||||
| sudo apt-get install -qq nsis ninja-build | sudo apt-get install -qq nsis ninja-build | ||||||
|  |  | ||||||
| # MXE repository was too slow for Travis far too often | # MXE repository was too slow for Travis far too often | ||||||
| wget https://github.com/vcmi/vcmi-deps-mxe/releases/download/2019-06-28/mxe-i686-w64-mingw32.shared-2019-06-28.tar | wget -nv https://github.com/vcmi/vcmi-deps-mxe/releases/download/2019-06-28/mxe-i686-w64-mingw32.shared-2019-06-28.tar | ||||||
| tar -xvf mxe-i686-w64-mingw32.shared-2019-06-28.tar | tar -xvf mxe-i686-w64-mingw32.shared-2019-06-28.tar | ||||||
| sudo dpkg -i mxe-*.deb | sudo dpkg -i mxe-*.deb | ||||||
| sudo apt-get install -f --yes | sudo apt-get install -f --yes | ||||||
| @@ -36,5 +36,7 @@ mxe-i686-w64-mingw32.static-luajit | |||||||
| fi # Disable | fi # Disable | ||||||
|  |  | ||||||
| # alias for CMake | # alias for CMake | ||||||
| sudo mv /usr/bin/cmake /usr/bin/cmake.orig |  | ||||||
| sudo ln -s /usr/lib/mxe/usr/bin/$MXE_TARGET-cmake /usr/bin/cmake | CMAKE_LOCATION=$(which cmake) | ||||||
|  | sudo mv $CMAKE_LOCATION $CMAKE_LOCATION.orig | ||||||
|  | sudo ln -s /usr/lib/mxe/usr/bin/$MXE_TARGET-cmake $CMAKE_LOCATION | ||||||
|   | |||||||
| @@ -1,16 +0,0 @@ | |||||||
| #!/bin/sh |  | ||||||
| if [ -z "$encrypted_1d30f79f8582_key" ]; |  | ||||||
| then |  | ||||||
| 	# Due to security measures travis not expose encryption keys for PR from forks |  | ||||||
| 	exit 0 |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| cpack |  | ||||||
|  |  | ||||||
| touch /tmp/deploy_rsa |  | ||||||
| chmod 600 /tmp/deploy_rsa |  | ||||||
| openssl aes-256-cbc -K $encrypted_1d30f79f8582_key -iv $encrypted_1d30f79f8582_iv -in $TRAVIS_BUILD_DIR/CI/deploy_rsa.enc -out /tmp/deploy_rsa -d |  | ||||||
| eval "$(ssh-agent -s)" |  | ||||||
| ssh-add /tmp/deploy_rsa |  | ||||||
|  |  | ||||||
| sftp -r -o StrictHostKeyChecking=no travis@beholder.vcmi.eu <<< "put $VCMI_PACKAGE_FILE_NAME.exe /incoming/$VCMI_PACKAGE_FILE_NAME.exe" |  | ||||||
							
								
								
									
										15
									
								
								CI/upload_package.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								CI/upload_package.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | #!/bin/sh | ||||||
|  | if [ -z "$DEPLOY_RSA" ]; | ||||||
|  | then | ||||||
|  | 	# Due to security measures travis not expose encryption keys for PR from forks | ||||||
|  | 	echo "Build generation is skipped for forks" | ||||||
|  | 	exit 0 | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | echo "$DEPLOY_RSA" > /tmp/deploy_rsa | ||||||
|  | chmod 600 /tmp/deploy_rsa | ||||||
|  |  | ||||||
|  | eval "$(ssh-agent -s)" | ||||||
|  | ssh-add /tmp/deploy_rsa | ||||||
|  |  | ||||||
|  | sftp -r -o StrictHostKeyChecking=no travis@beholder.vcmi.eu <<< "put $VCMI_PACKAGE_FILE_NAME.$PACKAGE_EXTENSION /incoming/$VCMI_PACKAGE_FILE_NAME.$PACKAGE_EXTENSION" | ||||||
| @@ -64,7 +64,7 @@ set(PACKAGE_FILE_NAME "" CACHE STRING "Override for CPack package filename") | |||||||
| #        Miscellaneous options             # | #        Miscellaneous options             # | ||||||
| ############################################ | ############################################ | ||||||
|  |  | ||||||
| set(CMAKE_MODULE_PATH ${CMAKE_HOME_DIRECTORY}/cmake_modules) | set(CMAKE_MODULE_PATH ${CMAKE_HOME_DIRECTORY}/cmake_modules ${PROJECT_SOURCE_DIR}/CI) | ||||||
| # Contains custom functions and macros, but don't altering any options | # Contains custom functions and macros, but don't altering any options | ||||||
| include(VCMIUtils) | include(VCMIUtils) | ||||||
| vcmi_print_important_variables() | vcmi_print_important_variables() | ||||||
| @@ -88,7 +88,7 @@ define_property( | |||||||
| # Generate Version.cpp | # Generate Version.cpp | ||||||
| if(ENABLE_GITVERSION) | if(ENABLE_GITVERSION) | ||||||
| 	add_custom_target(update_version ALL | 	add_custom_target(update_version ALL | ||||||
| 		COMMAND ${CMAKE_COMMAND} -DGIT_SHA1="${GIT_SHA1}" -P "${CMAKE_MODULE_PATH}/Version.cmake" | 		COMMAND ${CMAKE_COMMAND} -DGIT_SHA1="${GIT_SHA1}" -P "${PROJECT_SOURCE_DIR}/cmake_modules/Version.cmake" | ||||||
| 	) | 	) | ||||||
| else() | else() | ||||||
| 	add_definitions(-DVCMI_NO_EXTRA_VERSION) | 	add_definitions(-DVCMI_NO_EXTRA_VERSION) | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								Global.h
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Global.h
									
									
									
									
									
								
							| @@ -191,7 +191,7 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size."); | |||||||
| #include <boost/format.hpp> | #include <boost/format.hpp> | ||||||
| #include <boost/functional/hash.hpp> | #include <boost/functional/hash.hpp> | ||||||
| #include <boost/lexical_cast.hpp> | #include <boost/lexical_cast.hpp> | ||||||
| #ifndef VCMI_ANDROID | #ifdef VCMI_WINDOWS | ||||||
| #include <boost/locale/generator.hpp> | #include <boost/locale/generator.hpp> | ||||||
| #endif | #endif | ||||||
| #include <boost/logic/tribool.hpp> | #include <boost/logic/tribool.hpp> | ||||||
|   | |||||||
| @@ -656,19 +656,20 @@ CFocusable::~CFocusable() | |||||||
|  |  | ||||||
| 	focusables -= this; | 	focusables -= this; | ||||||
| } | } | ||||||
|  |  | ||||||
| void CFocusable::giveFocus() | void CFocusable::giveFocus() | ||||||
| { | { | ||||||
|  | 	focus = true; | ||||||
|  | 	focusGot(); | ||||||
|  | 	redraw(); | ||||||
|  |  | ||||||
| 	if(inputWithFocus) | 	if(inputWithFocus) | ||||||
| 	{ | 	{ | ||||||
| 		inputWithFocus->focus = false; | 		inputWithFocus->focus = false; | ||||||
| 		inputWithFocus->focusLost(); |  | ||||||
| 		inputWithFocus->redraw(); | 		inputWithFocus->redraw(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	focus = true; |  | ||||||
| 	inputWithFocus = this; | 	inputWithFocus = this; | ||||||
| 	focusGot(); |  | ||||||
| 	redraw(); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void CFocusable::moveFocus() | void CFocusable::moveFocus() | ||||||
|   | |||||||
| @@ -1158,7 +1158,7 @@ CGameState::CrossoverHeroesList CGameState::getCrossoverHeroesFromPreviousScenar | |||||||
|  |  | ||||||
| 	auto campaignState = scenarioOps->campState; | 	auto campaignState = scenarioOps->campState; | ||||||
| 	auto bonus = campaignState->getBonusForCurrentMap(); | 	auto bonus = campaignState->getBonusForCurrentMap(); | ||||||
| 	if (bonus && bonus->type == CScenarioTravel::STravelBonus::HEROES_FROM_PREVIOUS_SCENARIO) | 	if(bonus && bonus->type == CScenarioTravel::STravelBonus::HEROES_FROM_PREVIOUS_SCENARIO) | ||||||
| 	{ | 	{ | ||||||
| 		std::vector<CGHeroInstance *> heroes; | 		std::vector<CGHeroInstance *> heroes; | ||||||
| 		for(auto & node : campaignState->camp->scenarios[bonus->info2].crossoverHeroes) | 		for(auto & node : campaignState->camp->scenarios[bonus->info2].crossoverHeroes) | ||||||
| @@ -1172,12 +1172,8 @@ CGameState::CrossoverHeroesList CGameState::getCrossoverHeroesFromPreviousScenar | |||||||
| 	{ | 	{ | ||||||
| 		if(!campaignState->mapsConquered.empty()) | 		if(!campaignState->mapsConquered.empty()) | ||||||
| 		{ | 		{ | ||||||
| 			std::vector<CGHeroInstance *> heroes; | 			std::vector<CGHeroInstance *> heroes = {}; | ||||||
| 			for(auto & node : campaignState->camp->scenarios[campaignState->mapsConquered.back()].crossoverHeroes) |  | ||||||
| 			{ |  | ||||||
| 				auto h = CCampaignState::crossoverDeserialize(node); |  | ||||||
| 				heroes.push_back(h); |  | ||||||
| 			} |  | ||||||
| 			crossoverHeroes.heroesFromAnyPreviousScenarios = crossoverHeroes.heroesFromPreviousScenario = heroes; | 			crossoverHeroes.heroesFromAnyPreviousScenarios = crossoverHeroes.heroesFromPreviousScenario = heroes; | ||||||
| 			crossoverHeroes.heroesFromPreviousScenario = heroes; | 			crossoverHeroes.heroesFromPreviousScenario = heroes; | ||||||
|  |  | ||||||
| @@ -1190,7 +1186,7 @@ CGameState::CrossoverHeroesList CGameState::getCrossoverHeroesFromPreviousScenar | |||||||
| 				// remove heroes which didn't reached the end of the scenario, but were available at the start | 				// remove heroes which didn't reached the end of the scenario, but were available at the start | ||||||
| 				for(auto hero : lostCrossoverHeroes) | 				for(auto hero : lostCrossoverHeroes) | ||||||
| 				{ | 				{ | ||||||
| //					auto hero = CCampaignState::crossoverDeserialize(node); | 					//					auto hero = CCampaignState::crossoverDeserialize(node); | ||||||
| 					vstd::erase_if(crossoverHeroes.heroesFromAnyPreviousScenarios, [hero](CGHeroInstance * h) | 					vstd::erase_if(crossoverHeroes.heroesFromAnyPreviousScenarios, [hero](CGHeroInstance * h) | ||||||
| 					{ | 					{ | ||||||
| 						return hero->subID == h->subID; | 						return hero->subID == h->subID; | ||||||
| @@ -1202,11 +1198,12 @@ CGameState::CrossoverHeroesList CGameState::getCrossoverHeroesFromPreviousScenar | |||||||
| 				{ | 				{ | ||||||
| 					auto hero = CCampaignState::crossoverDeserialize(node); | 					auto hero = CCampaignState::crossoverDeserialize(node); | ||||||
| 					// add new heroes and replace old heroes with newer ones | 					// add new heroes and replace old heroes with newer ones | ||||||
| 					auto it = range::find_if(crossoverHeroes.heroesFromAnyPreviousScenarios,  [hero](CGHeroInstance * h) | 					auto it = range::find_if(crossoverHeroes.heroesFromAnyPreviousScenarios, [hero](CGHeroInstance * h) | ||||||
| 					{ | 					{ | ||||||
| 						return hero->subID == h->subID; | 						return hero->subID == h->subID; | ||||||
| 					}); | 					}); | ||||||
| 					if (it != crossoverHeroes.heroesFromAnyPreviousScenarios.end()) |  | ||||||
|  | 					if(it != crossoverHeroes.heroesFromAnyPreviousScenarios.end()) | ||||||
| 					{ | 					{ | ||||||
| 						// replace old hero with newer one | 						// replace old hero with newer one | ||||||
| 						crossoverHeroes.heroesFromAnyPreviousScenarios[it - crossoverHeroes.heroesFromAnyPreviousScenarios.begin()] = hero; | 						crossoverHeroes.heroesFromAnyPreviousScenarios[it - crossoverHeroes.heroesFromAnyPreviousScenarios.begin()] = hero; | ||||||
| @@ -1216,6 +1213,11 @@ CGameState::CrossoverHeroesList CGameState::getCrossoverHeroesFromPreviousScenar | |||||||
| 						// add new hero | 						// add new hero | ||||||
| 						crossoverHeroes.heroesFromAnyPreviousScenarios.push_back(hero); | 						crossoverHeroes.heroesFromAnyPreviousScenarios.push_back(hero); | ||||||
| 					} | 					} | ||||||
|  |  | ||||||
|  | 					if(mapNr == campaignState->mapsConquered.back()) | ||||||
|  | 					{ | ||||||
|  | 						crossoverHeroes.heroesFromPreviousScenario.push_back(hero); | ||||||
|  | 					} | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|   | |||||||
| @@ -719,46 +719,68 @@ bool CModHandler::checkDependencies(const std::vector <TModID> & input) const | |||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| std::vector <TModID> CModHandler::resolveDependencies(std::vector <TModID> modsToResolve) const | // Returned vector affects the resource loaders call order (see CFilesystemList::load). | ||||||
|  | // The loaders call order matters when dependent mod overrides resources in its dependencies. | ||||||
|  | std::vector <TModID> CModHandler::validateAndSortDependencies(std::vector <TModID> modsToResolve) const | ||||||
| { | { | ||||||
| 	std::vector<TModID> brokenMods; | 	// Topological sort algorithm. | ||||||
|  | 	// TODO: Investigate possible ways to improve performance. | ||||||
|  | 	boost::range::sort(modsToResolve); // Sort mods per name | ||||||
|  | 	std::vector <TModID> sortedValidMods; // Vector keeps order of elements (LIFO)  | ||||||
|  | 	sortedValidMods.reserve(modsToResolve.size()); // push_back calls won't cause memory reallocation | ||||||
|  | 	std::set <TModID> resolvedModIDs; // Use a set for validation for performance reason, but set does not keep order of elements | ||||||
|  |  | ||||||
| 	auto looksValid = [&](const CModInfo & mod) -> bool | 	// Mod is resolved if it has not dependencies or all its dependencies are already resolved | ||||||
|  | 	auto isResolved = [&](const CModInfo & mod) -> CModInfo::EValidationStatus | ||||||
| 	{ | 	{ | ||||||
| 		auto res = true; | 		if(mod.dependencies.size() > resolvedModIDs.size()) | ||||||
|  | 			return CModInfo::PENDING; | ||||||
|  |  | ||||||
| 		for(const TModID & dependency : mod.dependencies) | 		for(const TModID & dependency : mod.dependencies) | ||||||
| 		{ | 		{ | ||||||
| 			if(!vstd::contains(modsToResolve, dependency)) | 			if(!vstd::contains(resolvedModIDs, dependency)) | ||||||
| 			{ | 				return CModInfo::PENDING; | ||||||
| 				logMod->error("Mod '%s' will not work: it depends on mod '%s', which is not installed.", mod.name, dependency); |  | ||||||
| 				res = false; //continue iterations, since we should show all errors for the current mod. |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
| 		return res; | 		return CModInfo::PASSED; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	while(true) | 	while(true) | ||||||
| 	{ | 	{ | ||||||
| 		for(auto mod : modsToResolve) | 		std::set <TModID> resolvedOnCurrentTreeLevel; | ||||||
|  | 		for(auto it = modsToResolve.begin(); it != modsToResolve.end();) // One iteration - one level of mods tree | ||||||
| 		{ | 		{ | ||||||
| 			if(!looksValid(this->allMods.at(mod))) | 			if(isResolved(allMods.at(*it)) == CModInfo::PASSED) | ||||||
| 				brokenMods.push_back(mod); |  | ||||||
| 		} |  | ||||||
| 		if(!brokenMods.empty()) |  | ||||||
| 		{ |  | ||||||
| 			vstd::erase_if(modsToResolve, [&](TModID mid) |  | ||||||
| 			{ | 			{ | ||||||
| 				return brokenMods.end() != std::find(brokenMods.begin(), brokenMods.end(), mid); | 				resolvedOnCurrentTreeLevel.insert(*it); // Not to the resolvedModIDs, so current node childs will be resolved on the next iteration | ||||||
| 			}); | 				sortedValidMods.push_back(*it); | ||||||
| 			brokenMods.clear(); | 				it = modsToResolve.erase(it); | ||||||
| 				continue; | 				continue; | ||||||
|  | 			} | ||||||
|  | 			it++; | ||||||
| 		} | 		} | ||||||
|  | 		if(resolvedOnCurrentTreeLevel.size()) | ||||||
|  | 		{ | ||||||
|  | 			resolvedModIDs.insert(resolvedOnCurrentTreeLevel.begin(), resolvedOnCurrentTreeLevel.end()); | ||||||
|  | 		            continue; | ||||||
|  | 		} | ||||||
|  | 		// If there're no valid mods on the current mods tree level, no more mod can be resolved, should be end. | ||||||
| 		break; | 		break; | ||||||
| 	} | 	} | ||||||
| 	boost::range::sort(modsToResolve); |  | ||||||
| 	return modsToResolve; | 	// Left mods have unresolved dependencies, output all to log. | ||||||
|  | 	for(const auto & brokenModID : modsToResolve) | ||||||
|  | 	{ | ||||||
|  | 		const CModInfo & brokenMod = allMods.at(brokenModID); | ||||||
|  | 		for(const TModID & dependency : brokenMod.dependencies) | ||||||
|  | 		{ | ||||||
|  | 			if(!vstd::contains(resolvedModIDs, dependency)) | ||||||
|  | 				logMod->error("Mod '%s' will not work: it depends on mod '%s', which is not installed.", brokenMod.name, dependency); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return sortedValidMods; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| std::vector<std::string> CModHandler::getModList(std::string path) | std::vector<std::string> CModHandler::getModList(std::string path) | ||||||
| { | { | ||||||
| 	std::string modDir = boost::to_upper_copy(path + "MODS/"); | 	std::string modDir = boost::to_upper_copy(path + "MODS/"); | ||||||
| @@ -898,7 +920,7 @@ static ui32 calculateModChecksum(const std::string modName, ISimpleResourceLoade | |||||||
|  |  | ||||||
| void CModHandler::loadModFilesystems() | void CModHandler::loadModFilesystems() | ||||||
| { | { | ||||||
| 	activeMods = resolveDependencies(activeMods); | 	activeMods = validateAndSortDependencies(activeMods); | ||||||
|  |  | ||||||
| 	coreMod.updateChecksum(calculateModChecksum("core", CResourceHandler::get("core"))); | 	coreMod.updateChecksum(calculateModChecksum("core", CResourceHandler::get("core"))); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -242,9 +242,15 @@ class DLL_LINKAGE CModHandler | |||||||
| 	// - circular dependencies | 	// - circular dependencies | ||||||
| 	bool checkDependencies(const std::vector <TModID> & input) const; | 	bool checkDependencies(const std::vector <TModID> & input) const; | ||||||
|  |  | ||||||
| 	// returns load order in which all dependencies are resolved, e.g. loaded after required mods | 	/** | ||||||
| 	// function assumes that input list is valid (checkDependencies returned true) | 	* 1. Set apart mods with resolved dependencies from mods which have unresolved dependencies | ||||||
| 	std::vector <TModID> resolveDependencies(std::vector<TModID> input) const; | 	* 2. Sort resolved mods using topological algorithm | ||||||
|  | 	* 3. Log all problem mods and their unresolved dependencies | ||||||
|  | 	* | ||||||
|  | 	* @param modsToResolve list of valid mod IDs (checkDependencies returned true - TODO: Clarify it.) | ||||||
|  | 	* @return a vector of the topologically sorted resolved mods: child nodes (dependent mods) have greater index than parents | ||||||
|  | 	*/ | ||||||
|  | 	std::vector <TModID> validateAndSortDependencies(std::vector <TModID> modsToResolve) const; | ||||||
|  |  | ||||||
| 	std::vector<std::string> getModList(std::string path); | 	std::vector<std::string> getModList(std::string path); | ||||||
| 	void loadMods(std::string path, std::string parent, const JsonNode & modSettings, bool enableMods); | 	void loadMods(std::string path, std::string parent, const JsonNode & modSettings, bool enableMods); | ||||||
|   | |||||||
| @@ -261,6 +261,28 @@ bool JsonNode::isCompact() const | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | bool JsonNode::TryBoolFromString(bool & success) const | ||||||
|  | { | ||||||
|  | 	success = true; | ||||||
|  | 	if(type == JsonNode::JsonType::DATA_BOOL) | ||||||
|  | 		return Bool(); | ||||||
|  |  | ||||||
|  | 	success = type == JsonNode::JsonType::DATA_STRING; | ||||||
|  | 	if(success) | ||||||
|  | 	{ | ||||||
|  | 		auto boolParamStr = String(); | ||||||
|  | 		boost::algorithm::trim(boolParamStr); | ||||||
|  | 		boost::algorithm::to_lower(boolParamStr); | ||||||
|  | 		success = boolParamStr == "true"; | ||||||
|  |  | ||||||
|  | 		if(success) | ||||||
|  | 			return true; | ||||||
|  | 		 | ||||||
|  | 		success = boolParamStr == "false"; | ||||||
|  | 	} | ||||||
|  | 	return false; | ||||||
|  | } | ||||||
|  |  | ||||||
| void JsonNode::clear() | void JsonNode::clear() | ||||||
| { | { | ||||||
| 	setType(JsonType::DATA_NULL); | 	setType(JsonType::DATA_NULL); | ||||||
| @@ -632,7 +654,17 @@ std::shared_ptr<ILimiter> JsonUtils::parseLimiter(const JsonNode & limiter) | |||||||
| 				{ | 				{ | ||||||
| 					creatureLimiter->setCreature(CreatureID(creature)); | 					creatureLimiter->setCreature(CreatureID(creature)); | ||||||
| 				}); | 				}); | ||||||
| 				creatureLimiter->includeUpgrades = parameters.size() > 1 ? parameters[1].Bool() : false; | 				auto includeUpgrades = false; | ||||||
|  |  | ||||||
|  | 				if(parameters.size() > 1) | ||||||
|  | 				{ | ||||||
|  | 					bool success = true; | ||||||
|  | 					includeUpgrades = parameters[1].TryBoolFromString(success); | ||||||
|  |  | ||||||
|  | 					if(!success) | ||||||
|  | 						logMod->error("Second parameter of '%s' limiter should be Bool", limiterType); | ||||||
|  | 				} | ||||||
|  | 				creatureLimiter->includeUpgrades = includeUpgrades; | ||||||
| 				return creatureLimiter; | 				return creatureLimiter; | ||||||
| 			} | 			} | ||||||
| 			else if(limiterType == "HAS_ANOTHER_BONUS_LIMITER") | 			else if(limiterType == "HAS_ANOTHER_BONUS_LIMITER") | ||||||
|   | |||||||
| @@ -87,6 +87,9 @@ public: | |||||||
| 	/// removes all data from node and sets type to null | 	/// removes all data from node and sets type to null | ||||||
| 	void clear(); | 	void clear(); | ||||||
|  |  | ||||||
|  | 	/// returns bool or bool equivalent of string value if 'success' is true, or false otherwise | ||||||
|  | 	bool TryBoolFromString(bool & success) const; | ||||||
|  |  | ||||||
| 	/// non-const accessors, node will change type on type mismatch | 	/// non-const accessors, node will change type on type mismatch | ||||||
| 	bool & Bool(); | 	bool & Bool(); | ||||||
| 	double & Float(); | 	double & Float(); | ||||||
|   | |||||||
| @@ -654,7 +654,7 @@ namespace VCMIDirs | |||||||
| 		static bool initialized = false; | 		static bool initialized = false; | ||||||
| 		if (!initialized) | 		if (!initialized) | ||||||
| 		{ | 		{ | ||||||
| 			#ifndef VCMI_ANDROID | 			#ifdef VCMI_WINDOWS | ||||||
| 			std::locale::global(boost::locale::generator().generate("en_US.UTF-8")); | 			std::locale::global(boost::locale::generator().generate("en_US.UTF-8")); | ||||||
| 			#endif | 			#endif | ||||||
| 			boost::filesystem::path::imbue(std::locale()); | 			boost::filesystem::path::imbue(std::locale()); | ||||||
|   | |||||||
| @@ -148,30 +148,43 @@ std::vector<JsonNode> CObjectClassesHandler::loadLegacyData(size_t dataSize) | |||||||
|  |  | ||||||
| /// selects preferred ID (or subID) for new object | /// selects preferred ID (or subID) for new object | ||||||
| template<typename Map> | template<typename Map> | ||||||
| si32 selectNextID(const JsonNode & fixedID, const Map & map, si32 defaultID) | si32 selectNextID(const JsonNode & fixedID, const Map & map, si32 fixedObjectsBound) | ||||||
| { | { | ||||||
| 	if (!fixedID.isNull() && (si32)fixedID.Float() < defaultID) | 	assert(fixedObjectsBound > 0); | ||||||
| 		return static_cast<si32>(fixedID.Float()); // H3M object with fixed ID | 	if(fixedID.isNull()) | ||||||
|  | 	{ | ||||||
|  | 		auto lastID = map.empty() ? 0 : map.rbegin()->first; | ||||||
|  | 		return lastID < fixedObjectsBound ? fixedObjectsBound : lastID + 1; | ||||||
|  | 	} | ||||||
|  | 	auto id = static_cast<si32>(fixedID.Float()); | ||||||
|  | 	if(id >= fixedObjectsBound) | ||||||
|  | 		logGlobal->error("Getting next ID overflowed: %d >= %d", id, fixedObjectsBound); | ||||||
|  |  | ||||||
| 	if (map.empty()) | 	return id; | ||||||
| 		return defaultID; // no objects loaded, keep gap for H3M objects |  | ||||||
| 	if (map.rbegin()->first >= defaultID) |  | ||||||
| 		return map.rbegin()->first + 1; // some modded objects loaded, return next available |  | ||||||
|  |  | ||||||
| 	return defaultID; // some H3M objects loaded, first modded found |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void CObjectClassesHandler::loadObjectEntry(const std::string & identifier, const JsonNode & entry, ObjectContainter * obj) | void CObjectClassesHandler::loadObjectEntry(const std::string & identifier, const JsonNode & entry, ObjectContainter * obj, bool isSubobject) | ||||||
| { | { | ||||||
| 	if (!handlerConstructors.count(obj->handlerName)) | 	static const si32 fixedObjectsBound = 1000; // legacy value for backward compatibilitty | ||||||
|  | 	static const si32 fixedSubobjectsBound = 10000000; // large enough arbitrary value to avoid ID-collisions | ||||||
|  | 	si32 usedBound = fixedObjectsBound; | ||||||
|  |  | ||||||
|  | 	if(!handlerConstructors.count(obj->handlerName)) | ||||||
| 	{ | 	{ | ||||||
| 		logGlobal->error("Handler with name %s was not found!", obj->handlerName); | 		logGlobal->error("Handler with name %s was not found!", obj->handlerName); | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
|  | 	const auto convertedId = VLC->modh->normalizeIdentifier(entry.meta, "core", identifier); | ||||||
|  | 	const auto & entryIndex = entry["index"]; | ||||||
|  | 	bool useSelectNextID = !isSubobject || entryIndex.isNull(); | ||||||
|  |  | ||||||
| 	std::string convertedId = VLC->modh->normalizeIdentifier(entry.meta, "core", identifier); | 	if(useSelectNextID && isSubobject) | ||||||
|  | 	{ | ||||||
| 	si32 id = selectNextID(entry["index"], obj->subObjects, 1000); | 		usedBound = fixedSubobjectsBound; | ||||||
|  | 		logGlobal->error("Subobject index is Null. convertedId = '%s' obj->id = %d", convertedId, obj->id); | ||||||
|  | 	} | ||||||
|  | 	si32 id = useSelectNextID ? selectNextID(entryIndex, obj->subObjects, usedBound)  | ||||||
|  | 		: (si32)entryIndex.Float(); | ||||||
|  |  | ||||||
| 	auto handler = handlerConstructors.at(obj->handlerName)(); | 	auto handler = handlerConstructors.at(obj->handlerName)(); | ||||||
| 	handler->setType(obj->id, id); | 	handler->setType(obj->id, id); | ||||||
| @@ -196,46 +209,54 @@ void CObjectClassesHandler::loadObjectEntry(const std::string & identifier, cons | |||||||
|  |  | ||||||
| 	//some mods redefine content handlers in the decoration.json in such way: | 	//some mods redefine content handlers in the decoration.json in such way: | ||||||
| 	//"core:sign" : { "types" : { "forgeSign" : { ... | 	//"core:sign" : { "types" : { "forgeSign" : { ... | ||||||
| 	static const std::vector<std::string> knownProblemObjects | 	static const std::vector<std::string> breakersRMG | ||||||
| 	{ | 	{ | ||||||
| 		"hota.hota decorations:hotaPandoraBox" | 		"hota.hota decorations:hotaPandoraBox" | ||||||
| 		, "hota.hota decorations:hotaSubterreanGate" | 		, "hota.hota decorations:hotaSubterreanGate" | ||||||
| 	}; | 	}; | ||||||
| 	bool overrideForce = !obj->subObjects.count(id) || | 	const bool isExistingKey = obj->subObjects.count(id) > 0; | ||||||
| 	std::any_of(knownProblemObjects.begin(), knownProblemObjects.end(), [obj, id](const std::string & str) | 	const bool isBreaker = std::any_of(breakersRMG.begin(), breakersRMG.end(), | ||||||
| 	{ | 		[&handler](const std::string & str) | ||||||
| 		return str.compare(obj->subObjects[id]->subTypeName) == 0; | 		{ | ||||||
| 	}); | 			return str.compare(handler->subTypeName) == 0; | ||||||
|  | 		}); | ||||||
|  | 	const bool passedHandler = !isExistingKey && !isBreaker; | ||||||
|  |  | ||||||
| 	if(overrideForce) // DO NOT override mod handlers by default | 	if(passedHandler) | ||||||
| 	{ | 	{ | ||||||
| 		obj->subObjects[id] = handler; | 		obj->subObjects[id] = handler; | ||||||
| 		obj->subIds[convertedId] = id; | 		obj->subIds[convertedId] = id; | ||||||
| 	} | 	} | ||||||
|  | 	else if(isExistingKey) //It's supposed that fan mods handlers are not overridden by default handlers | ||||||
|  | 	{ | ||||||
|  | 		logGlobal->trace("Handler '%s' has not been overridden with handler '%s' in object %s(%d)::%s(%d)", | ||||||
|  | 			obj->subObjects[id]->subTypeName, obj->handlerName, obj->identifier, obj->id, convertedId, id); | ||||||
|  | 	} | ||||||
| 	else | 	else | ||||||
| 	{ | 	{ | ||||||
| 		logGlobal->warn("Don't override handler %s in object %s(%d)::%s(%d) subTypeName : %s" | 		logGlobal->warn("Handler '%s' for object %s(%d)::%s(%d) has not been activated as RMG breaker", | ||||||
| 			, obj->handlerName, obj->identifier, obj->id, convertedId, id, obj->subObjects[id]->subTypeName); | 			obj->handlerName, obj->identifier, obj->id, convertedId, id); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| CObjectClassesHandler::ObjectContainter * CObjectClassesHandler::loadFromJson(const std::string & scope, const JsonNode & json, const std::string & name) | CObjectClassesHandler::ObjectContainter * CObjectClassesHandler::loadFromJson(const std::string & scope, const JsonNode & json, const std::string & name) | ||||||
| { | { | ||||||
| 	auto obj = new ObjectContainter(); | 	auto obj = new ObjectContainter(); | ||||||
|  | 	static const si32 fixedObjectsBound = 256; //Legacy value for backward compatibility | ||||||
|  |  | ||||||
| 	obj->identifier = name; | 	obj->identifier = name; | ||||||
| 	obj->name = json["name"].String(); | 	obj->name = json["name"].String(); | ||||||
| 	obj->handlerName = json["handler"].String(); | 	obj->handlerName = json["handler"].String(); | ||||||
| 	obj->base = json["base"]; | 	obj->base = json["base"]; | ||||||
| 	obj->id = selectNextID(json["index"], objects, 256); | 	obj->id = selectNextID(json["index"], objects, fixedObjectsBound); | ||||||
|  |  | ||||||
| 	if(json["defaultAiValue"].isNull()) | 	if(json["defaultAiValue"].isNull()) | ||||||
| 		obj->groupDefaultAiValue = boost::none; | 		obj->groupDefaultAiValue = boost::none; | ||||||
| 	else | 	else | ||||||
| 		obj->groupDefaultAiValue = static_cast<boost::optional<si32>>(json["defaultAiValue"].Integer()); | 		obj->groupDefaultAiValue = static_cast<boost::optional<si32>>(json["defaultAiValue"].Integer()); | ||||||
|  |  | ||||||
| 	for (auto entry : json["types"].Struct()) | 	for (auto entry : json["types"].Struct()) | ||||||
| 	{ |  | ||||||
| 		loadObjectEntry(entry.first, entry.second, obj); | 		loadObjectEntry(entry.first, entry.second, obj); | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return obj; | 	return obj; | ||||||
| } | } | ||||||
| @@ -257,6 +278,8 @@ void CObjectClassesHandler::loadObject(std::string scope, std::string name, cons | |||||||
|  |  | ||||||
| void CObjectClassesHandler::loadSubObject(const std::string & identifier, JsonNode config, si32 ID, boost::optional<si32> subID) | void CObjectClassesHandler::loadSubObject(const std::string & identifier, JsonNode config, si32 ID, boost::optional<si32> subID) | ||||||
| { | { | ||||||
|  | 	static const bool isSubObject = true; | ||||||
|  |  | ||||||
| 	config.setType(JsonNode::JsonType::DATA_STRUCT); // ensure that input is not NULL | 	config.setType(JsonNode::JsonType::DATA_STRUCT); // ensure that input is not NULL | ||||||
| 	assert(objects.count(ID)); | 	assert(objects.count(ID)); | ||||||
| 	if (subID) | 	if (subID) | ||||||
| @@ -265,10 +288,8 @@ void CObjectClassesHandler::loadSubObject(const std::string & identifier, JsonNo | |||||||
| 		assert(config["index"].isNull()); | 		assert(config["index"].isNull()); | ||||||
| 		config["index"].Float() = subID.get(); | 		config["index"].Float() = subID.get(); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	inheritNodeWithMeta(config, objects.at(ID)->base); | 	inheritNodeWithMeta(config, objects.at(ID)->base); | ||||||
|  | 	loadObjectEntry(identifier, config, objects[ID], isSubObject); | ||||||
| 	loadObjectEntry(identifier, config, objects[ID]); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void CObjectClassesHandler::removeSubObject(si32 ID, si32 subID) | void CObjectClassesHandler::removeSubObject(si32 ID, si32 subID) | ||||||
|   | |||||||
| @@ -283,8 +283,9 @@ class DLL_LINKAGE CObjectClassesHandler : public IHandlerBase | |||||||
| 	/// format: customNames[primaryID][secondaryID] -> name | 	/// format: customNames[primaryID][secondaryID] -> name | ||||||
| 	std::map<si32, std::vector<std::string>> customNames; | 	std::map<si32, std::vector<std::string>> customNames; | ||||||
|  |  | ||||||
| 	void loadObjectEntry(const std::string & identifier, const JsonNode & entry, ObjectContainter * obj); | 	void loadObjectEntry(const std::string & identifier, const JsonNode & entry, ObjectContainter * obj, bool isSubobject = false); | ||||||
| 	ObjectContainter * loadFromJson(const std::string & scope, const JsonNode & json, const std::string & name); | 	ObjectContainter * loadFromJson(const std::string & scope, const JsonNode & json, const std::string & name); | ||||||
|  |  | ||||||
| public: | public: | ||||||
| 	CObjectClassesHandler(); | 	CObjectClassesHandler(); | ||||||
| 	~CObjectClassesHandler(); | 	~CObjectClassesHandler(); | ||||||
|   | |||||||
| @@ -144,21 +144,24 @@ CDwellingInstanceConstructor::CDwellingInstanceConstructor() | |||||||
| void CDwellingInstanceConstructor::initTypeData(const JsonNode & input) | void CDwellingInstanceConstructor::initTypeData(const JsonNode & input) | ||||||
| { | { | ||||||
| 	const JsonVector & levels = input["creatures"].Vector(); | 	const JsonVector & levels = input["creatures"].Vector(); | ||||||
| 	availableCreatures.resize(levels.size()); | 	const auto totalLevels = levels.size(); | ||||||
| 	for (size_t i=0; i<levels.size(); i++) |  | ||||||
|  | 	availableCreatures.resize(totalLevels); | ||||||
|  | 	for(auto currentLevel = 0; currentLevel < totalLevels; currentLevel++) | ||||||
| 	{ | 	{ | ||||||
| 		const JsonVector & creatures = levels[i].Vector(); | 		const JsonVector & creaturesOnLevel = levels[currentLevel].Vector(); | ||||||
| 		availableCreatures[i].resize(creatures.size()); | 		const auto creaturesNumber = creaturesOnLevel.size(); | ||||||
| 		for (size_t j=0; j<creatures.size(); j++) | 		availableCreatures[currentLevel].resize(creaturesNumber); | ||||||
|  |  | ||||||
|  | 		for(auto currentCreature = 0; currentCreature < creaturesNumber; currentCreature++) | ||||||
| 		{ | 		{ | ||||||
| 			VLC->modh->identifiers.requestIdentifier("creature", creatures[j], [=] (si32 index) | 			VLC->modh->identifiers.requestIdentifier("creature", creaturesOnLevel[currentCreature], [=] (si32 index) | ||||||
| 			{ | 			{ | ||||||
| 				availableCreatures[i][j] = VLC->creh->objects[index]; | 				availableCreatures[currentLevel][currentCreature] = VLC->creh->objects[index]; | ||||||
| 			}); | 			}); | ||||||
| 		} | 		} | ||||||
| 		assert(!availableCreatures[i].empty()); | 		assert(!availableCreatures[currentLevel].empty()); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	guards = input["guards"]; | 	guards = input["guards"]; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -30,7 +30,7 @@ SHeroName::SHeroName() : heroId(-1) | |||||||
|  |  | ||||||
| PlayerInfo::PlayerInfo(): canHumanPlay(false), canComputerPlay(false), | PlayerInfo::PlayerInfo(): canHumanPlay(false), canComputerPlay(false), | ||||||
| 	aiTactic(EAiTactic::RANDOM), isFactionRandom(false), hasRandomHero(false), mainCustomHeroPortrait(-1), mainCustomHeroId(-1), hasMainTown(false), | 	aiTactic(EAiTactic::RANDOM), isFactionRandom(false), hasRandomHero(false), mainCustomHeroPortrait(-1), mainCustomHeroId(-1), hasMainTown(false), | ||||||
| 	generateHeroAtMainTown(false), team(TeamID::NO_TEAM), /* following are unused */ generateHero(false), p7(0), powerPlaceholders(-1) | 	generateHeroAtMainTown(false), posOfMainTown(-1), team(TeamID::NO_TEAM), /* following are unused */ generateHero(false), p7(0), powerPlaceholders(-1) | ||||||
| { | { | ||||||
| 	allowedFactions = VLC->townh->getAllowedFactions(); | 	allowedFactions = VLC->townh->getAllowedFactions(); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
|     GNU GENERAL PUBLIC LICENSE |     GNU GENERAL PUBLIC LICENSE | ||||||
| 		       Version 2, June 1991 | 		       Version 2, June 1991 | ||||||
|  |  | ||||||
|  Copyright (C) 1989, 1991 Free Software Foundation, Inc., |  Copyright (C) 1989, 1991 Free Software Foundation, Inc., | ||||||
|   | |||||||
| @@ -11,10 +11,16 @@ if(APPLE) | |||||||
| 		") | 		") | ||||||
| 	endif() | 	endif() | ||||||
|  |  | ||||||
|  | 	# Manually fix VCMI library links in AI libraries with install_name_tool | ||||||
| 	install(CODE " | 	install(CODE " | ||||||
| 		set(BU_CHMOD_BUNDLE_ITEMS ON) | 		set(BU_CHMOD_BUNDLE_ITEMS ON) | ||||||
| 		include(BundleUtilities) | 		include(BundleUtilities) | ||||||
| 		fixup_bundle(\"\${CMAKE_INSTALL_PREFIX}/${APP_BUNDLE_DIR}\" \"\" \"\") | 		fixup_bundle(\"\${CMAKE_INSTALL_PREFIX}/${APP_BUNDLE_DIR}\" \"\" \"\") | ||||||
|  | 		execute_process(COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change \"libvcmi.dylib\" \"@executable_path/../Frameworks/libvcmi.dylib\" \"\${CMAKE_INSTALL_PREFIX}/${APP_BUNDLE_BINARY_DIR}/AI/libBattleAI.dylib\") | ||||||
|  | 		execute_process(COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change \"libvcmi.dylib\" \"@executable_path/../Frameworks/libvcmi.dylib\" \"\${CMAKE_INSTALL_PREFIX}/${APP_BUNDLE_BINARY_DIR}/AI/libEmptyAI.dylib\") | ||||||
|  | 		execute_process(COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change \"libvcmi.dylib\" \"@executable_path/../Frameworks/libvcmi.dylib\" \"\${CMAKE_INSTALL_PREFIX}/${APP_BUNDLE_BINARY_DIR}/AI/libStupidAI.dylib\") | ||||||
|  | 		execute_process(COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change \"libvcmi.dylib\" \"@executable_path/../Frameworks/libvcmi.dylib\" \"\${CMAKE_INSTALL_PREFIX}/${APP_BUNDLE_BINARY_DIR}/AI/libVCAI.dylib\") | ||||||
|  | 		execute_process(COMMAND rm \"\${CMAKE_INSTALL_PREFIX}/${APP_BUNDLE_BINARY_DIR}/libvcmi.dylib\") | ||||||
| 	" COMPONENT Runtime) | 	" COMPONENT Runtime) | ||||||
| endif(APPLE) | endif(APPLE) | ||||||
|  |  | ||||||
| @@ -22,7 +28,7 @@ endif(APPLE) | |||||||
| if(WIN32) | if(WIN32) | ||||||
| 	if(ENABLE_LAUNCHER) | 	if(ENABLE_LAUNCHER) | ||||||
| 		# Temporary ugly fix for Qt deployment since windeployqt broken in Vcpkg | 		# Temporary ugly fix for Qt deployment since windeployqt broken in Vcpkg | ||||||
| 		 |  | ||||||
| 		#there are some weird issues with variables used in path not evaluated properly when trying to remove code duplication from below lines | 		#there are some weird issues with variables used in path not evaluated properly when trying to remove code duplication from below lines | ||||||
| 		if(EXISTS ${CMAKE_BINARY_DIR}/../../vcpkg) #current path to vcpkg main folder on appveyor CI | 		if(EXISTS ${CMAKE_BINARY_DIR}/../../vcpkg) #current path to vcpkg main folder on appveyor CI | ||||||
| 			if(CMAKE_SIZEOF_VOID_P EQUAL 8) #64 bit build | 			if(CMAKE_SIZEOF_VOID_P EQUAL 8) #64 bit build | ||||||
|   | |||||||
| @@ -1306,11 +1306,11 @@ void CGameHandler::handleClientDisconnection(std::shared_ptr<CConnection> c) | |||||||
| { | { | ||||||
| 	for(auto playerConns : connections) | 	for(auto playerConns : connections) | ||||||
| 	{ | 	{ | ||||||
| 		for(auto conn : playerConns.second) | 		for(auto i = playerConns.second.begin(); i != playerConns.second.end(); ) | ||||||
| 		{ | 		{ | ||||||
| 			if(lobby->state != EServerState::SHUTDOWN && conn == c) | 			if(lobby->state != EServerState::SHUTDOWN && *i == c) | ||||||
| 			{ | 			{ | ||||||
| 				vstd::erase_if_present(playerConns.second, conn); | 				i = playerConns.second.erase(i); | ||||||
| 				if(playerConns.second.size()) | 				if(playerConns.second.size()) | ||||||
| 					continue; | 					continue; | ||||||
| 				PlayerCheated pc; | 				PlayerCheated pc; | ||||||
| @@ -1319,6 +1319,8 @@ void CGameHandler::handleClientDisconnection(std::shared_ptr<CConnection> c) | |||||||
| 				sendAndApply(&pc); | 				sendAndApply(&pc); | ||||||
| 				checkVictoryLossConditionsForPlayer(playerConns.first); | 				checkVictoryLossConditionsForPlayer(playerConns.first); | ||||||
| 			} | 			} | ||||||
|  | 			else | ||||||
|  | 				++i; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @@ -5426,7 +5428,8 @@ void CGameHandler::checkVictoryLossConditionsForAll() | |||||||
| void CGameHandler::checkVictoryLossConditionsForPlayer(PlayerColor player) | void CGameHandler::checkVictoryLossConditionsForPlayer(PlayerColor player) | ||||||
| { | { | ||||||
| 	const PlayerState * p = getPlayerState(player); | 	const PlayerState * p = getPlayerState(player); | ||||||
| 	if (p->status != EPlayerStatus::INGAME) return; |  | ||||||
|  | 	if(!p || p->status != EPlayerStatus::INGAME) return; | ||||||
|  |  | ||||||
| 	auto victoryLossCheckResult = gs->checkForVictoryAndLoss(player); | 	auto victoryLossCheckResult = gs->checkForVictoryAndLoss(player); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -90,11 +90,7 @@ set(test_SRCS | |||||||
|  		spells/targetConditions/ReceptiveFeatureConditionTest.cpp |  		spells/targetConditions/ReceptiveFeatureConditionTest.cpp | ||||||
|  		spells/targetConditions/SpellEffectConditionTest.cpp |  		spells/targetConditions/SpellEffectConditionTest.cpp | ||||||
|  		spells/targetConditions/TargetConditionItemFixture.cpp |  		spells/targetConditions/TargetConditionItemFixture.cpp | ||||||
|  | 		 | ||||||
| 		vcai/mock_ResourceManager.cpp |  | ||||||
| 		vcai/mock_VCAI.cpp |  | ||||||
| 		vcai/ResurceManagerTest.cpp |  | ||||||
|  |  | ||||||
| 		mock/BattleFake.cpp | 		mock/BattleFake.cpp | ||||||
|  		mock/mock_IGameCallback.cpp |  		mock/mock_IGameCallback.cpp | ||||||
|  		mock/mock_MapService.cpp |  		mock/mock_MapService.cpp | ||||||
| @@ -147,16 +143,12 @@ set(mock_HEADERS | |||||||
| 		mock/mock_UnitInfo.h | 		mock/mock_UnitInfo.h | ||||||
| 		mock/mock_vstd_RNG.h | 		mock/mock_vstd_RNG.h | ||||||
| 		mock/mock_CPSICallback.h | 		mock/mock_CPSICallback.h | ||||||
|  |  | ||||||
| 		vcai/mock_ResourceManager.h |  | ||||||
| 		vcai/mock_VCAI.h |  | ||||||
| 		vcai/mock_VCAI_CGoal.h |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| add_subdirectory_with_folder("3rdparty" googletest EXCLUDE_FROM_ALL) | add_subdirectory_with_folder("3rdparty" googletest EXCLUDE_FROM_ALL) | ||||||
|  |  | ||||||
| add_executable(vcmitest ${test_SRCS} ${test_HEADERS} ${mock_HEADERS}) | add_executable(vcmitest ${test_SRCS} ${test_HEADERS} ${mock_HEADERS}) | ||||||
| target_link_libraries(vcmitest PRIVATE gtest gmock vcmi ${SYSTEM_LIBS} VCAI) | target_link_libraries(vcmitest PRIVATE gtest gmock vcmi ${SYSTEM_LIBS}) | ||||||
|  |  | ||||||
| target_include_directories(vcmitest | target_include_directories(vcmitest | ||||||
| 		PUBLIC	${CMAKE_CURRENT_SOURCE_DIR} | 		PUBLIC	${CMAKE_CURRENT_SOURCE_DIR} | ||||||
|   | |||||||
| @@ -42,6 +42,12 @@ TEST(MapFormat, Random) | |||||||
| 	SCOPED_TRACE("MapFormat_Random start"); | 	SCOPED_TRACE("MapFormat_Random start"); | ||||||
|  |  | ||||||
| 	CMapGenOptions opt; | 	CMapGenOptions opt; | ||||||
|  | 	CRmgTemplate tmpl; | ||||||
|  |  | ||||||
|  | 	const_cast<CRmgTemplate::CPlayerCountRange &>(tmpl.getCpuPlayers()).addRange(1, 4); | ||||||
|  | 	const_cast<CRmgTemplate::Zones &>(tmpl.getZones())[0] = std::make_shared<rmg::ZoneOptions>(); | ||||||
|  |  | ||||||
|  | 	opt.setMapTemplate(&tmpl); | ||||||
|  |  | ||||||
| 	opt.setHeight(CMapHeader::MAP_SIZE_MIDDLE); | 	opt.setHeight(CMapHeader::MAP_SIZE_MIDDLE); | ||||||
| 	opt.setWidth(CMapHeader::MAP_SIZE_MIDDLE); | 	opt.setWidth(CMapHeader::MAP_SIZE_MIDDLE); | ||||||
| @@ -84,7 +90,7 @@ static JsonNode getFromArchive(CZipLoader & archive, const std::string & archive | |||||||
| 	ResourceID resource(archiveFilename, EResType::TEXT); | 	ResourceID resource(archiveFilename, EResType::TEXT); | ||||||
|  |  | ||||||
| 	if(!archive.existsResource(resource)) | 	if(!archive.existsResource(resource)) | ||||||
| 		throw std::runtime_error(archiveFilename+" not found"); | 		throw std::runtime_error(archiveFilename + " not found"); | ||||||
|  |  | ||||||
| 	auto data = archive.load(resource)->readAll(); | 	auto data = archive.load(resource)->readAll(); | ||||||
|  |  | ||||||
| @@ -144,14 +150,14 @@ TEST(MapFormat, Objects) | |||||||
| { | { | ||||||
| 	static const std::string MAP_DATA_PATH = "test/ObjectPropertyTest/"; | 	static const std::string MAP_DATA_PATH = "test/ObjectPropertyTest/"; | ||||||
|  |  | ||||||
| 	const JsonNode initialHeader(ResourceID(MAP_DATA_PATH+CMapFormatJson::HEADER_FILE_NAME)); | 	const JsonNode initialHeader(ResourceID(MAP_DATA_PATH + CMapFormatJson::HEADER_FILE_NAME)); | ||||||
| 	const JsonNode expectedHeader(ResourceID(MAP_DATA_PATH+CMapFormatJson::HEADER_FILE_NAME));//same as initial for now | 	const JsonNode expectedHeader(ResourceID(MAP_DATA_PATH + CMapFormatJson::HEADER_FILE_NAME));//same as initial for now | ||||||
|  |  | ||||||
| 	const JsonNode initialObjects(ResourceID(MAP_DATA_PATH+CMapFormatJson::OBJECTS_FILE_NAME)); | 	const JsonNode initialObjects(ResourceID(MAP_DATA_PATH + CMapFormatJson::OBJECTS_FILE_NAME)); | ||||||
| 	const JsonNode expectedObjects(ResourceID(MAP_DATA_PATH+"objects.ex.json")); | 	const JsonNode expectedObjects(ResourceID(MAP_DATA_PATH + "objects.ex.json")); | ||||||
|  |  | ||||||
| 	const JsonNode expectedSurface(ResourceID(MAP_DATA_PATH+"surface_terrain.json")); | 	const JsonNode expectedSurface(ResourceID(MAP_DATA_PATH + "surface_terrain.json")); | ||||||
| 	const JsonNode expectedUnderground(ResourceID(MAP_DATA_PATH+"underground_terrain.json")); | 	const JsonNode expectedUnderground(ResourceID(MAP_DATA_PATH + "underground_terrain.json")); | ||||||
|  |  | ||||||
| 	std::unique_ptr<CMap> originalMap = loadOriginal(initialHeader, initialObjects, expectedSurface, expectedUnderground); | 	std::unique_ptr<CMap> originalMap = loadOriginal(initialHeader, initialObjects, expectedSurface, expectedUnderground); | ||||||
|  |  | ||||||
| @@ -183,11 +189,11 @@ TEST(MapFormat, Terrain) | |||||||
| { | { | ||||||
| 	static const std::string MAP_DATA_PATH = "test/TerrainTest/"; | 	static const std::string MAP_DATA_PATH = "test/TerrainTest/"; | ||||||
|  |  | ||||||
| 	const JsonNode expectedHeader(ResourceID(MAP_DATA_PATH+CMapFormatJson::HEADER_FILE_NAME)); | 	const JsonNode expectedHeader(ResourceID(MAP_DATA_PATH + CMapFormatJson::HEADER_FILE_NAME)); | ||||||
| 	const JsonNode expectedObjects(ResourceID(MAP_DATA_PATH+CMapFormatJson::OBJECTS_FILE_NAME)); | 	const JsonNode expectedObjects(ResourceID(MAP_DATA_PATH + CMapFormatJson::OBJECTS_FILE_NAME)); | ||||||
|  |  | ||||||
| 	const JsonNode expectedSurface(ResourceID(MAP_DATA_PATH+"surface_terrain.json")); | 	const JsonNode expectedSurface(ResourceID(MAP_DATA_PATH + "surface_terrain.json")); | ||||||
| 	const JsonNode expectedUnderground(ResourceID(MAP_DATA_PATH+"underground_terrain.json")); | 	const JsonNode expectedUnderground(ResourceID(MAP_DATA_PATH + "underground_terrain.json")); | ||||||
|  |  | ||||||
| 	std::unique_ptr<CMap> originalMap = loadOriginal(expectedHeader, expectedObjects, expectedSurface, expectedUnderground); | 	std::unique_ptr<CMap> originalMap = loadOriginal(expectedHeader, expectedObjects, expectedSurface, expectedUnderground); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -194,6 +194,7 @@ TEST_F(TargetConditionTest, StoresNormalLevelCondition) | |||||||
|  |  | ||||||
| TEST_F(TargetConditionTest, StoresReceptiveFeature) | TEST_F(TargetConditionTest, StoresReceptiveFeature) | ||||||
| { | { | ||||||
|  | 	redirectFactoryToStub(); | ||||||
| 	auto itemStub = std::make_shared<StrictMock<ItemMock>>(); | 	auto itemStub = std::make_shared<StrictMock<ItemMock>>(); | ||||||
| 	EXPECT_CALL(factoryMock, createReceptiveFeature()).WillOnce(Return(itemStub)); | 	EXPECT_CALL(factoryMock, createReceptiveFeature()).WillOnce(Return(itemStub)); | ||||||
| 	setupSubject(JsonNode()); | 	setupSubject(JsonNode()); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user