Compare commits
45 Commits
Author | SHA1 | Date |
---|---|---|
|
d23f043f34 | |
|
d8c1e259f4 | |
|
918a2da926 | |
|
ea805bcdf1 | |
|
06508f3c27 | |
|
46bd5e4ecf | |
|
a295c90da3 | |
|
e9823bed28 | |
|
f593da858c | |
|
e5b56bfe88 | |
|
50e092b0cb | |
|
31d7301bfb | |
|
3a4d6de70c | |
|
8635702fbf | |
|
4a78f03051 | |
|
68a6537cdb | |
|
a57e637d5f | |
|
db58ebbefb | |
|
37519a6093 | |
|
306af72daf | |
|
caf77d899b | |
|
fa01a0fb3e | |
|
6e51b30da0 | |
|
06b52867de | |
|
d212aba253 | |
|
753c068fb2 | |
|
6361dc03d1 | |
|
7c93b1b84f | |
|
a5ec6f3db1 | |
|
24d268c53f | |
|
cebddea8fc | |
|
fd42f32c6a | |
|
3567f74bcd | |
|
9ca4e261ab | |
|
23dc6d93c3 | |
|
a84001c8bf | |
|
4ccd8753d1 | |
|
1d21d74bb9 | |
|
3ebaed3777 | |
|
5d24318a39 | |
|
a161750966 | |
|
c3fcfb84f8 | |
|
35e1404f43 | |
|
f004d53072 | |
|
4a1cdbcd20 |
|
@ -1,2 +1,5 @@
|
|||
*.bundle filter=lfs diff=lfs merge=lfs -text
|
||||
*.servph filter=lfs diff=lfs merge=lfs -text
|
||||
hfx[[:space:]]impacts filter=lfs diff=lfs merge=lfs -text
|
||||
hideoutcat filter=lfs diff=lfs merge=lfs -text
|
||||
*.exe filter=lfs diff=lfs merge=lfs -text
|
||||
|
|
|
@ -4,6 +4,12 @@
|
|||
set "mo2_install=%cd%"
|
||||
set "repository=%mo2_install%\Fika-Tarkov"
|
||||
|
||||
:: Specifying links to download for files
|
||||
set "git_repository=https://files.moddinglounge.com/Rage/Fika-Tarkov.git"
|
||||
set "git_file=https://github.com/git-for-windows/git/releases/download/v2.47.1.windows.1/PortableGit-2.47.1-64-bit.7z.exe"
|
||||
set "SevenZ_file=https://www.7-zip.org/a/7zr.exe"
|
||||
set "mo2_file=https://github.com/ModOrganizer2/modorganizer/releases/download/v2.5.2/Mod.Organizer-2.5.2.7z"
|
||||
|
||||
:: Set path to the portable Git executable
|
||||
set "portable_git=%mo2_install%\PortableGit\bin\git.exe"
|
||||
set "portable_7z=%mo2_install%\7zr.exe"
|
||||
|
@ -22,7 +28,7 @@ if not exist "%mo2_install%\PortableGit\bin\git.exe" (
|
|||
echo ----
|
||||
echo Installing Portable Git...
|
||||
:: Download Git Portable
|
||||
curl -L -o PortableGit-2.47.1-64-bit.7z.exe https://github.com/git-for-windows/git/releases/download/v2.47.1.windows.1/PortableGit-2.47.1-64-bit.7z.exe
|
||||
curl -L -o PortableGit-2.47.1-64-bit.7z.exe %git_file%
|
||||
|
||||
if %errorlevel% neq 0 (
|
||||
echo ERROR: Failed to download Git Portable. Check your internet connection and try again.
|
||||
|
@ -41,7 +47,7 @@ if not exist "%mo2_install%\7zr.exe" (
|
|||
echo ----
|
||||
echo Installing 7zip Portable...
|
||||
:: Download 7zip Portable
|
||||
curl -L -o 7zr.exe https://www.7-zip.org/a/7zr.exe
|
||||
curl -L -o 7zr.exe %SevenZ_file%
|
||||
)
|
||||
|
||||
:: Determining if an installation exists already
|
||||
|
@ -64,10 +70,10 @@ IF EXIST "%mo2_install%\ModOrganizer.exe" (
|
|||
timeout 10
|
||||
|
||||
:: Clone or update the Git repository
|
||||
if not exist "Fika-Tarkov\.git" (
|
||||
if not exist "%repository%\.git" (
|
||||
echo ----
|
||||
echo Cloning repository...
|
||||
"%portable_git%" clone https://files.moddinglounge.com/Rage/Fika-Tarkov.git
|
||||
"%portable_git%" clone %git_repository%
|
||||
) else (
|
||||
echo ----
|
||||
echo Repository already exists. Pulling latest changes...
|
||||
|
@ -84,18 +90,11 @@ IF EXIST "%mo2_install%\ModOrganizer.exe" (
|
|||
echo Synchronizing profiles folder...
|
||||
robocopy "%repository%/profiles" "%mo2_install%/profiles" /MIR
|
||||
|
||||
echo ----
|
||||
echo Synchronizing stylesheets folder...
|
||||
robocopy "%repository%/stylesheets" "%mo2_install%/stylesheets" /E
|
||||
|
||||
echo ----
|
||||
echo Synchronizing plugins folder...
|
||||
robocopy "%repository%/plugins" "%mo2_install%/plugins" /E
|
||||
|
||||
pause
|
||||
exit /B 0
|
||||
|
||||
:InstallModpack
|
||||
echo.
|
||||
echo !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
echo WARNING! The script will install the modpack in the folder this script is ran from!
|
||||
echo Be sure that your folder is empty before continuing with the installation!
|
||||
|
@ -108,9 +107,19 @@ IF EXIST "%mo2_install%\ModOrganizer.exe" (
|
|||
timeout 30
|
||||
|
||||
:: Requiring user input for game path
|
||||
echo ----
|
||||
set /p "game_path=Please enter the path to your game installation: "
|
||||
|
||||
if "%game_path%"=="" (
|
||||
echo.
|
||||
echo No path entered. Exiting.
|
||||
echo.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
:: Download MO2
|
||||
curl -L -o MO2.7z https://github.com/ModOrganizer2/modorganizer/releases/download/v2.5.2/Mod.Organizer-2.5.2.7z
|
||||
curl -L -o MO2.7z %mo2_file%
|
||||
if %errorlevel% neq 0 (
|
||||
echo ERROR: Failed to download the archive. Check your internet connection and try again.
|
||||
pause
|
||||
|
@ -136,9 +145,10 @@ IF EXIST "%mo2_install%\ModOrganizer.exe" (
|
|||
:: Deleting the archive
|
||||
del MO2.7z
|
||||
|
||||
:: Syncing all of the necessary folders and files
|
||||
echo ----
|
||||
echo Cloning repository...
|
||||
"%portable_git%" clone https://files.moddinglounge.com/Rage/Fika-Tarkov.git
|
||||
"%portable_git%" clone %git_repository%
|
||||
|
||||
echo ----
|
||||
echo Synchronizing mods folder...
|
||||
|
@ -148,14 +158,60 @@ IF EXIST "%mo2_install%\ModOrganizer.exe" (
|
|||
echo Synchronizing profiles folder...
|
||||
robocopy "%repository%/profiles" "%mo2_install%/profiles" /MIR
|
||||
|
||||
echo ----
|
||||
echo Synchronizing stylesheets folder...
|
||||
robocopy "%repository%/stylesheets" "%mo2_install%/stylesheets" /E
|
||||
|
||||
echo ----
|
||||
echo Synchronizing plugins folder...
|
||||
robocopy "%repository%/plugins" "%mo2_install%/plugins" /E
|
||||
|
||||
echo ----
|
||||
echo Synchronizing stylesheets folder...
|
||||
robocopy "%repository%/stylesheets" "%mo2_install%/stylesheets" /E
|
||||
|
||||
echo ----
|
||||
echo Synchronizing USVFS files...
|
||||
robocopy "usvfs_proxy_x64.exe" "%mo2_install%" /E
|
||||
robocopy "usvfs_proxy_x86.exe" "%mo2_install%" /E
|
||||
robocopy "usvfs_x64.dll" "%mo2_install%" /E
|
||||
robocopy "usvfs_x86.dll" "%mo2_install%" /E
|
||||
|
||||
:: Escape backslashes in the game path
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
set "game_path=!game_path:\=/!"
|
||||
set "escaped_path="
|
||||
|
||||
for /l %%i in (0,1,255) do (
|
||||
for /f "tokens=1,* delims=" %%a in ("!game_path:~%%i,1!") do (
|
||||
if "%%a"=="" goto path_done
|
||||
if %%a==/ (
|
||||
set "escaped_path=!escaped_path!//" :: Double the backslash
|
||||
) else (
|
||||
set "escaped_path=!escaped_path!%%a"
|
||||
)
|
||||
)
|
||||
)
|
||||
:path_done
|
||||
|
||||
echo Original Path: %game_path%
|
||||
echo Escaped Path: %escaped_path%
|
||||
|
||||
:: Replace placeholders in ModOrganizer.ini
|
||||
echo ----
|
||||
echo Updating ModOrganizer.ini...
|
||||
set "ini_file=%repository%\ModOrganizer.ini"
|
||||
set "temp_ini=%ini_file%.tmp"
|
||||
|
||||
(for /f "usebackq delims=" %%A in ("%ini_file%") do (
|
||||
set "line=%%A"
|
||||
set "line=!line:game_path=%escaped_path%!"
|
||||
set "line=!line:replace_me=%game_path%!"
|
||||
echo(!line!
|
||||
)) > "%temp_ini%"
|
||||
|
||||
move /y "%temp_ini%" "%mo2_install%\ModOrganizer.ini"
|
||||
|
||||
echo ----
|
||||
echo ModOrganizer.ini updated successfully!
|
||||
|
||||
echo ----
|
||||
echo Installation complete. Launch ModOrganizer.exe and follow the remaining instructions.
|
||||
|
||||
|
|
140
ModOrganizer.ini
140
ModOrganizer.ini
|
@ -1,22 +1,136 @@
|
|||
[General]
|
||||
gameName=SPT
|
||||
gamePath=@ByteArray(replace_me)
|
||||
gamePath=@ByteArray(game_path)
|
||||
selected_profile=@ByteArray(Multiplayer)
|
||||
version=2.5.2
|
||||
first_start=false
|
||||
previousSeparatorColor=@Variant(\0\0\0\x43\x1\xff\xff\x44\x44\x36\x36))\0\0)
|
||||
backup_install=true
|
||||
|
||||
[Settings]
|
||||
style=Dark Bronze.qss
|
||||
[PluginPersistance]
|
||||
Python%20Proxy\tryInit=false
|
||||
|
||||
[customExecutables]
|
||||
size=1
|
||||
1\arguments=
|
||||
1\binary=replace_me/SPT.Launcher.exe
|
||||
1\hide=false
|
||||
1\ownicon=false
|
||||
1\steamAppID=
|
||||
1\title=Multiplayer
|
||||
1\toolbar=false
|
||||
1\workingDirectory=replace_me
|
||||
[Settings]
|
||||
profile_local_inis=false
|
||||
profile_local_saves=false
|
||||
profile_archive_invalidation=true
|
||||
log_level=1
|
||||
language=en
|
||||
compact_downloads=true
|
||||
meta_downloads=false
|
||||
autohide_downloads=false
|
||||
check_for_updates=true
|
||||
use_prereleases=false
|
||||
center_dialogs=false
|
||||
show_change_game_confirmation=true
|
||||
show_menubar_on_alt=true
|
||||
double_click_previews=true
|
||||
style=Dark Bronze.qss
|
||||
overwrittenLooseFilesColor=@Variant(\0\0\0\x43\x1@@\0\0\xff\xff\0\0\0\0)
|
||||
overwritingLooseFilesColor=@Variant(\0\0\0\x43\x1@@\xff\xff\0\0\0\0\0\0)
|
||||
overwrittenArchiveFilesColor=@Variant(\0\0\0\x43\x1@@\0\0\xff\xff\xff\xff\0\0)
|
||||
overwritingArchiveFilesColor=@Variant(\0\0\0\x43\x1@@\xff\xff\0\0\xff\xff\0\0)
|
||||
containsPluginColor=@Variant(\0\0\0\x43\x1@@\0\0\0\0\xff\xff\0\0)
|
||||
containedColor=@Variant(\0\0\0\x43\x1@@\0\0\0\0\xff\xff\0\0)
|
||||
colorSeparatorScrollbars=true
|
||||
display_foreign=true
|
||||
collapsible_separators_asc=true
|
||||
collapsible_separators_dsc=true
|
||||
collapsible_separators_conflicts_from=true
|
||||
collapsible_separators_conflicts_to=true
|
||||
collapsible_separators_per_profile=false
|
||||
save_filters=false
|
||||
auto_collapse_on_hover=false
|
||||
autocheck_update_install=true
|
||||
collapsible_separators_icons_1=true
|
||||
collapsible_separators_icons_2=true
|
||||
collapsible_separators_icons_3=true
|
||||
collapsible_separators_icons_7=true
|
||||
crash_dumps_type=1
|
||||
crash_dumps_max=5
|
||||
loot_log_level=2
|
||||
endorsement_integration=true
|
||||
tracked_integration=true
|
||||
category_mappings=true
|
||||
hide_api_counter=false
|
||||
force_enable_core_files=true
|
||||
lock_gui=true
|
||||
archive_parsing_experimental=false
|
||||
offline_mode=false
|
||||
use_proxy=false
|
||||
use_custom_browser=false
|
||||
custom_browser=
|
||||
executable_blacklist="Chrome.exe;Firefox.exe;TSVNCache.exe;TGitCache.exe;Steam.exe;GameOverlayUI.exe;Discord.exe;GalaxyClient.exe;Spotify.exe;Brave.exe"
|
||||
skip_file_suffixes=.mohidden
|
||||
skip_directories=.git
|
||||
filter_regex=false
|
||||
regex_case_sensitive=false
|
||||
regex_extended=false
|
||||
filter_scroll_to_selection=false
|
||||
|
||||
[Widgets]
|
||||
SettingsDialog_tabWidget_index=0
|
||||
MainWindow_executablesListBox_index=1
|
||||
MainWindow_tabWidget_index=2
|
||||
MainWindow_dataTabShowOnlyConflicts_checked=false
|
||||
MainWindow_dataTabShowFromArchives_checked=false
|
||||
MainWindow_groupCombo_index=0
|
||||
MainWindow_modList_index=SWAG + DONUTS_backup, Fika, Essentials, Bug Fixes & Optimizations, Interface & HUD, SFX & Music, New Items & Keys, Gameplay Tweaks, New Traders & Tweaks, New Weapons & Gear, AI & Combat Tweaks, VFX & Atmosphere, Modlist Addons, Backburner, Version 1.32.0, Unsorted, Overwrite
|
||||
MainWindow_filters_index=0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
MainWindow_filtersAnd_checked=true
|
||||
MainWindow_filtersOr_checked=false
|
||||
MainWindow_filtersSeparators_index=0
|
||||
ModInfoTabOrder=tabFiles tabText tabIni tabImages tabESPs tabConflicts tabCategories tabNexus tabNotes
|
||||
ModInfoDialog_tabWidget_index=0
|
||||
ModInfoDialog_imagesShowDDS_checked=false
|
||||
ModInfoDialog_tabConflictsTabs_index=0
|
||||
ModInfoDialog_conflictsAdvancedShowNoConflict_checked=true
|
||||
ModInfoDialog_conflictsAdvancedShowAll_checked=true
|
||||
ModInfoDialog_conflictsAdvancedShowNearest_checked=false
|
||||
|
||||
[Geometry]
|
||||
SettingsDialog_geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\x2\xe3\0\0\x1\x30\0\0\x6\x16\0\0\x3\x9d\0\0\x2\xe3\0\0\x1N\0\0\x6\x16\0\0\x3\x9d\0\0\0\0\0\0\0\0\t\xe\0\0\x2\xe3\0\0\x1N\0\0\x6\x16\0\0\x3\x9d)
|
||||
MainWindow_state=@ByteArray(\0\0\0\xff\0\0\0\0\xfd\0\0\0\x1\0\0\0\x3\0\0\t\xe\0\0\0\xd7\xfc\x1\0\0\0\x1\xfb\0\0\0\xe\0l\0o\0g\0\x44\0o\0\x63\0k\0\0\0\0\0\0\0\t\xe\0\0\0R\0\xff\xff\xff\0\0\t\xe\0\0\x4T\0\0\0\x4\0\0\0\x4\0\0\0\b\0\0\0\b\xfc\0\0\0\x1\0\0\0\x2\0\0\0\x1\0\0\0\xe\0t\0o\0o\0l\0\x42\0\x61\0r\x1\0\0\0\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0)
|
||||
MainWindow_geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\0\0\xff\xff\xff\xf9\0\0\t\r\0\0\x4\xe8\0\0\0\v\0\0\0\x1f\0\0\az\0\0\x4w\0\0\0\0\x2\0\0\0\t\xe\0\0\0\0\0\0\0\x17\0\0\t\r\0\0\x4\xe8)
|
||||
MainWindow_docks_logDock_size=215
|
||||
MainWindow_menuBar_visibility=true
|
||||
MainWindow_statusBar_visibility=true
|
||||
MainWindow_toolBar_visibility=true
|
||||
toolbar_size=@Size(42 36)
|
||||
toolbar_button_style=0
|
||||
MainWindow_splitter_state=@ByteArray(\0\0\0\xff\0\0\0\x1\0\0\0\x2\0\0\x3\xf9\0\0\x2\xb0\x1\xff\xff\xff\xff\x1\0\0\0\x1\0)
|
||||
MainWindow_categoriesSplitter_state=@ByteArray(\0\0\0\xff\0\0\0\x1\0\0\0\x2\0\0\x1\b\0\0\x3\x16\0\xff\xff\xff\xff\x1\0\0\0\x1\0)
|
||||
MainWindow_monitor=0
|
||||
MainWindow_categoriesGroup_visibility=false
|
||||
MainWindow_espList_state=@ByteArray(\0\0\0\xff\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\x2\x1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x2n\0\0\0\x4\x1\x1\0\x1\0\0\0\0\0\0\0\0\x1\0\0\0\x64\xff\xff\xff\xff\0\0\0\x81\0\0\0\0\0\0\0\x4\0\0\x1\xce\0\0\0\x1\0\0\0\0\0\0\0%\0\0\0\x1\0\0\0\0\0\0\0\x33\0\0\0\x1\0\0\0\0\0\0\0H\0\0\0\x1\0\0\0\0\0\0\x3\xe8\0\0\0\0\x46\0\0\0\0)
|
||||
MainWindow_downloadView_state=@ByteArray(\0\0\0\xff\0\0\0\0\0\0\0\x1\0\0\0\x1\0\0\0\x3\x1\0\0\0\0\0\0\0\0\0\0\0\b\xf0\0\0\0\x4\0\0\0\x4\0\0\0\x64\0\0\0\a\0\0\0\x64\0\0\0\x6\0\0\0\x64\0\0\0\x5\0\0\0\x64\0\0\x3\x80\0\0\0\b\x1\x1\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\x64\xff\xff\xff\xff\0\0\0\x81\0\0\0\0\0\0\0\b\0\0\x2\x62\0\0\0\x1\0\0\0\0\0\0\0V\0\0\0\x1\0\0\0\0\0\0\0\x64\0\0\0\x1\0\0\0\0\0\0\0\x64\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\x3\xe8\x1\0\0\0\0\0\0\0\0)
|
||||
MainWindow_savegameList_state=@ByteArray(\0\0\0\xff\0\0\0\0\0\0\0\x1\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x2n\0\0\0\x2\x1\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\0\x64\xff\xff\xff\xff\0\0\0\x81\0\0\0\0\0\0\0\x2\0\0\x1\xa1\0\0\0\x1\0\0\0\0\0\0\0\xcd\0\0\0\x1\0\0\0\0\0\0\x3\xe8\0\0\0\0\x64\0\0\0\0)
|
||||
MainWindow_dataTree_state=@ByteArray(\0\0\0\xff\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x3\x80\0\0\0\x5\x1\x1\0\x1\0\0\0\0\0\0\0\0\0\0\0\0\x64\xff\xff\xff\xff\0\0\0\x81\0\0\0\0\0\0\0\x5\0\0\x1s\0\0\0\x1\0\0\0\0\0\0\0\x81\0\0\0\x1\0\0\0\0\0\0\0\xb2\0\0\0\x1\0\0\0\0\0\0\0\x64\0\0\0\x1\0\0\0\0\0\0\0v\0\0\0\x1\0\0\0\0\0\0\x3\xe8\0\0\0\0\x64\0\0\0\0)
|
||||
MainWindow_modList_state=@ByteArray(\0\0\0\xff\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\t\x1\0\0\0\v\0\0\0\0\0\0\0\x2\0\0\0\x3\0\0\0\x6\0\0\0\x5\0\0\0\a\0\0\0\b\0\0\0\t\0\0\0\x4\0\0\0\n\0\0\0\x1\0\0\0\v\0\0\0\0\0\0\0\n\0\0\0\x1\0\0\0\x2\0\0\0\b\0\0\0\x4\0\0\0\x3\0\0\0\x5\0\0\0\x6\0\0\0\a\0\0\0\t\0\0\0\v\xc2\x3\0\0\0\x5\0\0\0\a\0\0\0Y\0\0\0\x3\0\0\0 \0\0\0\x6\0\0\0 \0\0\0\n\0\0\x1\xb3\0\0\0\x5\0\0\0 \0\0\x5\x42\0\0\0\v\x1\x1\0\x1\0\0\0\0\0\0\0\0\x1\0\0\0'\xff\xff\xff\xff\0\0\0\x81\0\0\0\0\0\0\0\v\0\0\x3\n\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\x64\0\0\0\x1\0\0\0\0\0\0\0H\0\0\0\x1\0\0\0\0\0\0\0\xac\0\0\0\x1\0\0\0\0\0\0\0|\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\x64\0\0\0\x1\0\0\0\0\0\0\x3\xe8\x1\0\0\0U\0\0\0\0)
|
||||
EditExecutablesDialog_geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\x2\xa7\0\0\x1\x8d\0\0\a2\0\0\x3\xbb\0\0\x2\xa7\0\0\x1\xab\0\0\a2\0\0\x3\xbb\0\0\0\0\0\0\0\0\t\xe\0\0\x2\xa7\0\0\x1\xab\0\0\a2\0\0\x3\xbb)
|
||||
ModInfoDialog_tabTextSplitter_state=@ByteArray(\0\0\0\xff\0\0\0\x1\0\0\0\x2\0\0\x1\xc8\0\0\x3\x62\0\xff\xff\xff\xff\x1\0\0\0\x1\0)
|
||||
ModInfoDialog_tabIniSplitter_state=@ByteArray(\0\0\0\xff\0\0\0\x1\0\0\0\x2\0\0\0\xc8\0\0\0\xed\x1\xff\xff\xff\xff\x1\0\0\0\x1\0)
|
||||
ModInfoDialog_tabImagesSplitter_state=@ByteArray(\0\0\0\xff\0\0\0\x1\0\0\0\x2\0\0\0\x80\0\0\0\x83\0\xff\xff\xff\xff\x1\0\0\0\x1\0)
|
||||
ModInfoDialog_ESPsSplitter_state=@ByteArray(\0\0\0\xff\0\0\0\x1\0\0\0\x2\0\0\0|\0\0\0\xab\x1\xff\xff\xff\xff\x1\0\0\0\x1\0)
|
||||
ModInfoDialog_overwriteExpander_state=@ByteArray(\x1)
|
||||
ModInfoDialog_overwrittenExpander_state=@ByteArray(\x1)
|
||||
ModInfoDialog_noConflictExpander_state=@ByteArray(\0)
|
||||
ModInfoDialog_overwriteTree_state=@ByteArray(\0\0\0\xff\0\0\0\0\0\0\0\x1\0\0\0\x1\0\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x5(\0\0\0\x2\x1\x1\0\x1\0\0\0\0\0\0\0\0\0\0\0\0\x64\xff\xff\xff\xff\0\0\0\x81\0\0\0\0\0\0\0\x2\0\0\x2\x88\0\0\0\x1\0\0\0\0\0\0\x2\xa0\0\0\0\x1\0\0\0\0\0\0\x3\xe8\0\0\0\0\x64\0\0\0\0)
|
||||
ModInfoDialog_noConflictTree_state=@ByteArray(\0\0\0\xff\0\0\0\0\0\0\0\x1\0\0\0\x1\0\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x64\0\0\0\x1\x1\x1\0\x1\0\0\0\0\0\0\0\0\0\0\0\0\x64\xff\xff\xff\xff\0\0\0\x81\0\0\0\0\0\0\0\x1\0\0\0\x64\0\0\0\x1\0\0\0\0\0\0\x3\xe8\0\0\0\0\x64\0\0\0\0)
|
||||
ModInfoDialog_overwrittenTree_state=@ByteArray(\0\0\0\xff\0\0\0\0\0\0\0\x1\0\0\0\x1\0\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x2\xdd\0\0\0\x2\x1\x1\0\x1\0\0\0\0\0\0\0\0\0\0\0\0\x64\xff\xff\xff\xff\0\0\0\x81\0\0\0\0\0\0\0\x2\0\0\x2y\0\0\0\x1\0\0\0\0\0\0\0\x64\0\0\0\x1\0\0\0\0\0\0\x3\xe8\0\0\0\0\x64\0\0\0\0)
|
||||
ModInfoDialog_conflictsAdvancedList_state="@ByteArray(\0\0\0\xff\0\0\0\0\0\0\0\x1\0\0\0\x1\0\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x1,\0\0\0\x3\x1\x1\0\x1\0\0\0\0\0\0\0\0\0\0\0\0\x64\xff\xff\xff\xff\0\0\0\x81\0\0\0\0\0\0\0\x3\0\0\0\x64\0\0\0\x1\0\0\0\0\0\0\0\x64\0\0\0\x1\0\0\0\0\0\0\0\x64\0\0\0\x1\0\0\0\0\0\0\x3\xe8\0\0\0\0\x64\0\0\0\0)"
|
||||
ModInfoDialog_filetree_state=@ByteArray(\0\0\0\xff\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x5\x30\0\0\0\x4\x1\x1\0\x1\0\0\0\0\0\0\0\0\0\0\0\0\x64\xff\xff\xff\xff\0\0\0\x81\0\0\0\0\0\0\0\x4\0\0\x1\xbf\0\0\0\x1\0\0\0\0\0\0\0\x64\0\0\0\x1\0\0\0\0\0\0\0\x64\0\0\0\x1\0\0\0\0\0\0\x2\xa9\0\0\0\x1\0\0\0\0\0\0\x3\xe8\0\0\0\0\x64\0\0\0\0)
|
||||
ModInfoDialog_geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\x1\xca\0\0\x1\x1b\0\0\a\x17\0\0\x4\x1e\0\0\x1\xca\0\0\x1\x39\0\0\a\x17\0\0\x4\x1e\0\0\0\0\0\0\0\0\t\xe\0\0\x1\xca\0\0\x1\x39\0\0\a\x17\0\0\x4\x1e)
|
||||
PreviewDialog_geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\x3\r\0\0\x1\x35\0\0\x5\xec\0\0\x3\x99\0\0\x3\r\0\0\x1S\0\0\x5\xec\0\0\x3\x99\0\0\0\0\0\0\0\0\t\xe\0\0\x3\r\0\0\x1S\0\0\x5\xec\0\0\x3\x99)
|
||||
ProfilesDialog_geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\x3\x8c\0\0\x1\xb2\0\0\x5m\0\0\x3\x1b\0\0\x3\x8c\0\0\x1\xd0\0\0\x5m\0\0\x3\x1b\0\0\0\0\0\0\0\0\t\xe\0\0\x3\x8c\0\0\x1\xd0\0\0\x5m\0\0\x3\x1b)
|
||||
__overwriteDialog_geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\x2\x82\0\0\x1\x8c\0\0\a\xa9\0\0\x4\xa8\0\0\x2\x82\0\0\x1\xaa\0\0\a\xa9\0\0\x4\xa8\0\0\0\0\0\0\0\0\t\xe\0\0\x2\x82\0\0\x1\xaa\0\0\a\xa9\0\0\x4\xa8)
|
||||
__overwriteDialog_filesView_state=@ByteArray(\0\0\0\xff\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\0\x1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x4\xfe\0\0\0\x4\x1\x1\0\x1\0\0\0\0\0\0\0\0\0\0\0\0\x64\xff\xff\xff\xff\0\0\0\x81\0\0\0\0\0\0\0\x4\0\0\x1\xd7\0\0\0\x1\0\0\0\0\0\0\0\x64\0\0\0\x1\0\0\0\0\0\0\0\x64\0\0\0\x1\0\0\0\0\0\0\x2_\0\0\0\x1\0\0\0\0\0\0\x3\xe8\0\0\0\0\x64\0\0\0\0)
|
||||
ProblemsDialog_geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\x3^\0\0\x1\x9c\0\0\x5\x9b\0\0\x3\x31\0\0\x3^\0\0\x1\xba\0\0\x5\x9b\0\0\x3\x31\0\0\0\0\0\0\0\0\t\xe\0\0\x3^\0\0\x1\xba\0\0\x5\x9b\0\0\x3\x31)
|
||||
CategoriesDialog_geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\x1\xd3\0\0\x1T\0\0\x4\x99\0\0\x3#\0\0\x1\xd3\0\0\x1r\0\0\x4\x99\0\0\x3#\0\0\0\0\0\0\0\0\t\xe\0\0\x1\xd3\0\0\x1r\0\0\x4\x99\0\0\x3#)
|
||||
ListDialog_geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\x3\xfa\0\0\0\xfe\0\0\x4\xff\0\0\x3^\0\0\x3\xfa\0\0\x1\x1c\0\0\x4\xff\0\0\x3^\0\0\0\0\0\0\0\0\t\xe\0\0\x3\xfa\0\0\x1\x1c\0\0\x4\xff\0\0\x3^)
|
||||
|
||||
[Servers]
|
||||
size=0
|
||||
|
||||
[pluginBlacklist]
|
||||
size=0
|
||||
|
|
|
@ -19,7 +19,7 @@ nexusLastModified=2024-09-09T09:16:47Z
|
|||
nexusCategory=0
|
||||
converted=false
|
||||
validated=false
|
||||
color=@Variant(\0\0\0\x43\x1\xff\xff\x44\x44\x36\x36))\0\0)
|
||||
color=@Variant(\0\0\0\x43\x1\xff\xff\xc4\xc4\x9b\x9btt\0\0)
|
||||
tracked=0
|
||||
|
||||
[installedFiles]
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,28 @@
|
|||
[General]
|
||||
gameName=spt
|
||||
modid=0
|
||||
version=d2025.5.14.0
|
||||
newestVersion=
|
||||
category="-1,"
|
||||
nexusFileStatus=1
|
||||
installationFile=AI-Refactored.RC2.zip
|
||||
repository=Nexus
|
||||
ignoredVersion=
|
||||
comments=
|
||||
notes=
|
||||
nexusDescription=
|
||||
url=
|
||||
hasCustomURL=false
|
||||
lastNexusQuery=
|
||||
lastNexusUpdate=
|
||||
nexusLastModified=2025-05-14T12:50:24Z
|
||||
nexusCategory=0
|
||||
converted=false
|
||||
validated=false
|
||||
color=@Variant(\0\0\0\x43\0\xff\xff\0\0\0\0\0\0\0\0)
|
||||
tracked=0
|
||||
|
||||
[installedFiles]
|
||||
1\modid=0
|
||||
1\fileid=0
|
||||
size=1
|
|
@ -1,28 +0,0 @@
|
|||
[General]
|
||||
gameName=spt
|
||||
modid=0
|
||||
version=d2024.12.21.0
|
||||
newestVersion=
|
||||
category="1,2"
|
||||
nexusFileStatus=1
|
||||
installationFile=WTT-Armory-Ak5C-1.0.3.zip
|
||||
repository=Nexus
|
||||
ignoredVersion=
|
||||
comments=
|
||||
notes=
|
||||
nexusDescription=
|
||||
url=
|
||||
hasCustomURL=false
|
||||
lastNexusQuery=
|
||||
lastNexusUpdate=
|
||||
nexusLastModified=2024-12-22T04:12:41Z
|
||||
nexusCategory=0
|
||||
converted=false
|
||||
validated=false
|
||||
color=@Variant(\0\0\0\x43\0\xff\xff\0\0\0\0\0\0\0\0)
|
||||
tracked=0
|
||||
|
||||
[installedFiles]
|
||||
1\modid=0
|
||||
1\fileid=0
|
||||
size=1
|
|
@ -1,95 +0,0 @@
|
|||
{
|
||||
"manifest": [
|
||||
{
|
||||
"key": "WeaponAK5C/ak5c.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/commonassets/physics/physicsmaterials.bundle",
|
||||
"assets/content/audio/blendoptions/assets.bundle",
|
||||
"assets/content/weapons/additional_hands/client_assets.bundle",
|
||||
"assets/content/weapons/weapon_root_anim_fix.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "WeaponAK5C/ak5cbarrel.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/commonassets/physics/physicsmaterials.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "WeaponAK5C/ak5ccover.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/commonassets/physics/physicsmaterials.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "WeaponAK5C/ak5cfs.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/commonassets/physics/physicsmaterials.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "WeaponAK5C/ak5cgrip.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/commonassets/physics/physicsmaterials.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "WeaponAK5C/ak5chandguard.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/commonassets/physics/physicsmaterials.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "WeaponAK5C/ak5cmag.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/commonassets/physics/physicsmaterials.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "WeaponAK5C/ak5cmuzzle.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/commonassets/physics/physicsmaterials.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "WeaponAK5C/ak5crail.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/commonassets/physics/physicsmaterials.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "WeaponAK5C/ak5cstock.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/commonassets/physics/physicsmaterials.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "WeaponAK5C/ak5cstock_1.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/commonassets/physics/physicsmaterials.bundle"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
BIN
mods/AK-5C/user/mods/WTTArmoryAk5C/bundles/WeaponAK5C/ak5c.bundle (Stored with Git LFS)
BIN
mods/AK-5C/user/mods/WTTArmoryAk5C/bundles/WeaponAK5C/ak5c.bundle (Stored with Git LFS)
Binary file not shown.
BIN
mods/AK-5C/user/mods/WTTArmoryAk5C/bundles/WeaponAK5C/ak5cbarrel.bundle (Stored with Git LFS)
BIN
mods/AK-5C/user/mods/WTTArmoryAk5C/bundles/WeaponAK5C/ak5cbarrel.bundle (Stored with Git LFS)
Binary file not shown.
BIN
mods/AK-5C/user/mods/WTTArmoryAk5C/bundles/WeaponAK5C/ak5ccover.bundle (Stored with Git LFS)
BIN
mods/AK-5C/user/mods/WTTArmoryAk5C/bundles/WeaponAK5C/ak5ccover.bundle (Stored with Git LFS)
Binary file not shown.
BIN
mods/AK-5C/user/mods/WTTArmoryAk5C/bundles/WeaponAK5C/ak5cfs.bundle (Stored with Git LFS)
BIN
mods/AK-5C/user/mods/WTTArmoryAk5C/bundles/WeaponAK5C/ak5cfs.bundle (Stored with Git LFS)
Binary file not shown.
BIN
mods/AK-5C/user/mods/WTTArmoryAk5C/bundles/WeaponAK5C/ak5cgrip.bundle (Stored with Git LFS)
BIN
mods/AK-5C/user/mods/WTTArmoryAk5C/bundles/WeaponAK5C/ak5cgrip.bundle (Stored with Git LFS)
Binary file not shown.
BIN
mods/AK-5C/user/mods/WTTArmoryAk5C/bundles/WeaponAK5C/ak5chandguard.bundle (Stored with Git LFS)
BIN
mods/AK-5C/user/mods/WTTArmoryAk5C/bundles/WeaponAK5C/ak5chandguard.bundle (Stored with Git LFS)
Binary file not shown.
BIN
mods/AK-5C/user/mods/WTTArmoryAk5C/bundles/WeaponAK5C/ak5cmag.bundle (Stored with Git LFS)
BIN
mods/AK-5C/user/mods/WTTArmoryAk5C/bundles/WeaponAK5C/ak5cmag.bundle (Stored with Git LFS)
Binary file not shown.
BIN
mods/AK-5C/user/mods/WTTArmoryAk5C/bundles/WeaponAK5C/ak5cmuzzle.bundle (Stored with Git LFS)
BIN
mods/AK-5C/user/mods/WTTArmoryAk5C/bundles/WeaponAK5C/ak5cmuzzle.bundle (Stored with Git LFS)
Binary file not shown.
BIN
mods/AK-5C/user/mods/WTTArmoryAk5C/bundles/WeaponAK5C/ak5crail.bundle (Stored with Git LFS)
BIN
mods/AK-5C/user/mods/WTTArmoryAk5C/bundles/WeaponAK5C/ak5crail.bundle (Stored with Git LFS)
Binary file not shown.
BIN
mods/AK-5C/user/mods/WTTArmoryAk5C/bundles/WeaponAK5C/ak5cstock.bundle (Stored with Git LFS)
BIN
mods/AK-5C/user/mods/WTTArmoryAk5C/bundles/WeaponAK5C/ak5cstock.bundle (Stored with Git LFS)
Binary file not shown.
BIN
mods/AK-5C/user/mods/WTTArmoryAk5C/bundles/WeaponAK5C/ak5cstock_1.bundle (Stored with Git LFS)
BIN
mods/AK-5C/user/mods/WTTArmoryAk5C/bundles/WeaponAK5C/ak5cstock_1.bundle (Stored with Git LFS)
Binary file not shown.
|
@ -1,128 +0,0 @@
|
|||
{
|
||||
"PEACEKEEPER": {
|
||||
"items": [
|
||||
{
|
||||
"_id": "6671efb6acbb23fc7b97d066",
|
||||
"_tpl": "6671ec0028088d829af1a668",
|
||||
"parentId": "hideout",
|
||||
"slotId": "hideout",
|
||||
"upd": {
|
||||
"StackObjectsCount": 1000
|
||||
}
|
||||
},
|
||||
{
|
||||
"_id": "6671efbac1e4261ab018d515",
|
||||
"_tpl": "6671ecd0c978c594704b61f4",
|
||||
"parentId": "hideout",
|
||||
"slotId": "hideout",
|
||||
"upd": {
|
||||
"StackObjectsCount": 1000
|
||||
}
|
||||
},
|
||||
{
|
||||
"_id": "6671f0d35157784af2055255",
|
||||
"_tpl": "6671ebcdd32bd95eb398e920",
|
||||
"parentId": "hideout",
|
||||
"slotId": "hideout",
|
||||
"upd": {
|
||||
"StackObjectsCount": 99805,
|
||||
"Repairable": {
|
||||
"Durability": 100,
|
||||
"MaxDurability": 100
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"_id": "6671f11665b0f49c45f19bf3",
|
||||
"_tpl": "6671ee9490d3a9978a371da7",
|
||||
"parentId": "6671f0d35157784af2055255",
|
||||
"slotId": "mod_mount"
|
||||
},
|
||||
{
|
||||
"_id": "6671f11420335e0bdd93c863",
|
||||
"_tpl": "6671eca71020d64fb2240530",
|
||||
"parentId": "6671f0d35157784af2055255",
|
||||
"slotId": "mod_sight_front"
|
||||
},
|
||||
{
|
||||
"_id": "6671f1115ea70dbd607d2aa7",
|
||||
"_tpl": "6671ecb42225b07c8afc4ce3",
|
||||
"parentId": "6671f0d35157784af2055255",
|
||||
"slotId": "mod_stock"
|
||||
},
|
||||
{
|
||||
"_id": "6671f10e062ffaf93fb65338",
|
||||
"_tpl": "6671ec6e0bebf6ee2d5abf61",
|
||||
"parentId": "6671f0d35157784af2055255",
|
||||
"slotId": "mod_pistol_grip"
|
||||
},
|
||||
{
|
||||
"_id": "6671f10a2e68b8c0ad1ff43d",
|
||||
"_tpl": "6671ec0028088d829af1a668",
|
||||
"parentId": "6671f0d35157784af2055255",
|
||||
"slotId": "mod_magazine"
|
||||
},
|
||||
{
|
||||
"_id": "6671f1307017899a8c8d4320",
|
||||
"_tpl": "6671ece3365d10b3362eb40f",
|
||||
"parentId": "6671f0d35157784af2055255",
|
||||
"slotId": "mod_handguard"
|
||||
},
|
||||
{
|
||||
"_id": "6671f0ffd993ff5c5c65dc59",
|
||||
"_tpl": "6671ed4b45dbd54033e7bbb0",
|
||||
"parentId": "6671f0d35157784af2055255",
|
||||
"slotId": "mod_barrel"
|
||||
},
|
||||
{
|
||||
"_id": "6671f192da41c7ae8fd07708",
|
||||
"_tpl": "6671ed384a25cc51b3e8d8a7",
|
||||
"parentId": "6671f1307017899a8c8d4320",
|
||||
"slotId": "mod_tactical"
|
||||
},
|
||||
{
|
||||
"_id": "6671f18f92e55b4c2e842ac3",
|
||||
"_tpl": "6671ed384a25cc51b3e8d8a7",
|
||||
"parentId": "6671f1307017899a8c8d4320",
|
||||
"slotId": "mod_tactical_2"
|
||||
},
|
||||
{
|
||||
"_id": "6671f106d133165140d4e524",
|
||||
"_tpl": "6671ed5805ef46250c47e46a",
|
||||
"parentId": "6671f0ffd993ff5c5c65dc59",
|
||||
"slotId": "mod_muzzle"
|
||||
}
|
||||
],
|
||||
"barter_scheme": {
|
||||
"6671efb6acbb23fc7b97d066": [
|
||||
[
|
||||
{
|
||||
"count": 25,
|
||||
"_tpl": "5696686a4bdc2da3298b456a"
|
||||
}
|
||||
]
|
||||
],
|
||||
"6671efbac1e4261ab018d515": [
|
||||
[
|
||||
{
|
||||
"count": 58,
|
||||
"_tpl": "5696686a4bdc2da3298b456a"
|
||||
}
|
||||
]
|
||||
],
|
||||
"6671f0d35157784af2055255": [
|
||||
[
|
||||
{
|
||||
"count": 785,
|
||||
"_tpl": "5696686a4bdc2da3298b456a"
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"loyal_level_items": {
|
||||
"6671efb6acbb23fc7b97d066": 2,
|
||||
"6671efbac1e4261ab018d515": 2,
|
||||
"6671f0d35157784af2055255": 2
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,34 +0,0 @@
|
|||
{
|
||||
"name": "WTTArmoryAk5C",
|
||||
"author": "Tron and MoxoPixel",
|
||||
"version": "1.0.3",
|
||||
"license": "NCSA",
|
||||
"main": "src/mod.js",
|
||||
"sptVersion": "~3.10",
|
||||
"loadBefore": [],
|
||||
"loadAfter": [],
|
||||
"isBundleMod": true,
|
||||
"incompatibilities": [],
|
||||
"contributors": [],
|
||||
"scripts": {
|
||||
"setup": "npm i",
|
||||
"build": "node ./build.mjs",
|
||||
"buildinfo": "node ./build.mjs --verbose"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "20.11",
|
||||
"@typescript-eslint/eslint-plugin": "7.2",
|
||||
"@typescript-eslint/parser": "7.2",
|
||||
"archiver": "^6.0",
|
||||
"eslint": "8.57",
|
||||
"fs-extra": "11.2",
|
||||
"ignore": "^5.2",
|
||||
"os": "^0.1",
|
||||
"tsyringe": "4.8.0",
|
||||
"typescript": "5.4",
|
||||
"winston": "3.12"
|
||||
},
|
||||
"dependencies": {
|
||||
"jsonc": "^2.0.0"
|
||||
}
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
import type { WTTInstanceManager } from "./WTTInstanceManager";
|
||||
import customAssortSchemes from "../db/CustomAssortSchemes/CustomAssortSchemes.json";
|
||||
import { traderIDs } from "./references/configConsts";
|
||||
import type { ITraderAssort } from "@spt/models/eft/common/tables/ITrader";
|
||||
export class CustomAssortSchemeService
|
||||
{
|
||||
private instanceManager: WTTInstanceManager;
|
||||
|
||||
public preSptLoad(instanceManager: WTTInstanceManager): void
|
||||
{
|
||||
this.instanceManager = instanceManager;
|
||||
}
|
||||
|
||||
public postDBLoad(): void
|
||||
{
|
||||
const tables = this.instanceManager.database;
|
||||
for (const traderId in customAssortSchemes)
|
||||
{
|
||||
const traderIdFromMap = traderIDs[traderId];
|
||||
const finalTraderId = traderIdFromMap || traderId;
|
||||
const trader = tables.traders[finalTraderId];
|
||||
|
||||
if (!trader)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const newAssort : ITraderAssort = customAssortSchemes[traderId];
|
||||
|
||||
for (const item of newAssort.items)
|
||||
{
|
||||
trader.assort.items.push(item);
|
||||
}
|
||||
for (const [itemName, scheme] of Object.entries(newAssort.barter_scheme))
|
||||
{
|
||||
trader.assort.barter_scheme[itemName] = scheme;
|
||||
}
|
||||
|
||||
for (const [itemName, count] of Object.entries(newAssort.loyal_level_items))
|
||||
{
|
||||
trader.assort.loyal_level_items[itemName] = count;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,856 +0,0 @@
|
|||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
import type { NewItemFromCloneDetails } from "@spt/models/spt/mod/NewItemDetails";
|
||||
import type { ConfigItem } from "./references/configConsts";
|
||||
import { traderIDs } from "./references/configConsts";
|
||||
import { currencyIDs } from "./references/configConsts";
|
||||
import { inventorySlots } from "./references/configConsts";
|
||||
import { ItemMap } from "./references/items";
|
||||
import { ItemBaseClassMap } from "./references/itemBaseClasses";
|
||||
import { ItemHandbookCategoryMap } from "./references/itemHandbookCategories";
|
||||
import { LogTextColor } from "@spt/models/spt/logging/LogTextColor";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import type { WTTInstanceManager } from "./WTTInstanceManager";
|
||||
import type { IDatabaseTables } from "@spt/models/spt/server/IDatabaseTables";
|
||||
import type { ILocation } from "@spt/models/eft/common/ILocation";
|
||||
import type { IPreset } from "@spt/models/eft/common/IGlobals";
|
||||
import type { IItem } from "@spt/models/eft/common/tables/IItem";
|
||||
import type { IInventory } from "@spt/models/eft/common/tables/IBotType";
|
||||
import type { IProps } from "@spt/models/eft/common/tables/ITemplateItem";
|
||||
|
||||
export class CustomItemService {
|
||||
private instanceManager: WTTInstanceManager;
|
||||
|
||||
public preSptLoad(instanceManager: WTTInstanceManager): void {
|
||||
this.instanceManager = instanceManager;
|
||||
}
|
||||
|
||||
public postDBLoad(): void {
|
||||
const configPath = path.join(__dirname, "../db/Items");
|
||||
const configFiles = fs
|
||||
.readdirSync(configPath)
|
||||
.filter((file) => !file.includes("BaseItemReplacement"));
|
||||
|
||||
let numItemsAdded = 0;
|
||||
|
||||
for (const file of configFiles) {
|
||||
const filePath = path.join(configPath, file);
|
||||
|
||||
try {
|
||||
const fileContents = fs.readFileSync(filePath, "utf-8");
|
||||
const config = JSON.parse(fileContents) as ConfigItem;
|
||||
|
||||
for (const itemId in config) {
|
||||
const itemConfig = config[itemId];
|
||||
|
||||
try {
|
||||
const { exampleCloneItem, finalItemTplToClone } =
|
||||
this.createExampleCloneItem(itemConfig, itemId);
|
||||
|
||||
if (this.instanceManager.debug) {
|
||||
console.log(`Processing file: ${file}, Item ID: ${itemId}`);
|
||||
console.log(
|
||||
`Prefab Path: ${exampleCloneItem.overrideProperties?.Prefab.path}`
|
||||
);
|
||||
}
|
||||
|
||||
this.instanceManager.customItem.createItemFromClone(exampleCloneItem);
|
||||
|
||||
this.processStaticLootContainers(itemConfig, itemId);
|
||||
this.processModSlots(itemConfig, [finalItemTplToClone], itemId);
|
||||
this.processInventorySlots(itemConfig, itemId);
|
||||
this.processMasterySections(itemConfig, itemId);
|
||||
this.processWeaponPresets(itemConfig, itemId);
|
||||
this.processTraders(itemConfig, itemId);
|
||||
this.addtoHallofFame(itemConfig, itemId);
|
||||
this.addtoSpecialSlots(itemConfig, itemId);
|
||||
|
||||
numItemsAdded++;
|
||||
} catch (itemError) {
|
||||
console.error(`Error processing item ID: ${itemId} in file: ${file}`);
|
||||
console.error(itemError);
|
||||
}
|
||||
}
|
||||
} catch (fileError) {
|
||||
console.error(`Error processing config file: ${file}`);
|
||||
console.error(fileError);
|
||||
}
|
||||
}
|
||||
|
||||
if (numItemsAdded > 0) {
|
||||
this.instanceManager.logger.log(
|
||||
`[${this.instanceManager.modName}] Database: Loaded ${numItemsAdded} custom items.`,
|
||||
LogTextColor.GREEN
|
||||
);
|
||||
} else {
|
||||
this.instanceManager.logger.log(
|
||||
`[${this.instanceManager.modName}] Database: No custom items loaded.`,
|
||||
LogTextColor.GREEN
|
||||
);
|
||||
}
|
||||
|
||||
// Post-item processing (e.g., bot inventories, quest modifications)
|
||||
for (const file of configFiles) {
|
||||
const filePath = path.join(configPath, file);
|
||||
|
||||
try {
|
||||
const fileContents = fs.readFileSync(filePath, "utf-8");
|
||||
const config = JSON.parse(fileContents) as ConfigItem;
|
||||
|
||||
for (const itemId in config) {
|
||||
const itemConfig = config[itemId];
|
||||
this.processBotInventories(itemConfig, itemConfig.itemTplToClone, itemId);
|
||||
}
|
||||
} catch (fileError) {
|
||||
console.error(`Error processing bot inventories for file: ${file}`);
|
||||
console.error(fileError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an example clone item with the provided item configuration and item ID.
|
||||
*
|
||||
* @param {any} itemConfig - The configuration of the item to clone.
|
||||
* @param {string} itemId - The ID of the item.
|
||||
* @return {{ exampleCloneItem: NewItemFromCloneDetails, finalItemTplToClone: string }} The created example clone item and the final item template to clone.
|
||||
*/
|
||||
private createExampleCloneItem(
|
||||
itemConfig: ConfigItem[string],
|
||||
itemId: string
|
||||
): {
|
||||
exampleCloneItem: NewItemFromCloneDetails;
|
||||
finalItemTplToClone: string;
|
||||
} {
|
||||
const itemTplToCloneFromMap =
|
||||
ItemMap[itemConfig.itemTplToClone] || itemConfig.itemTplToClone;
|
||||
const finalItemTplToClone = itemTplToCloneFromMap;
|
||||
|
||||
const parentIdFromMap =
|
||||
ItemBaseClassMap[itemConfig.parentId] || itemConfig.parentId;
|
||||
const finalParentId = parentIdFromMap;
|
||||
|
||||
const handbookParentIdFromMap =
|
||||
ItemHandbookCategoryMap[itemConfig.handbookParentId] ||
|
||||
itemConfig.handbookParentId;
|
||||
const finalHandbookParentId = handbookParentIdFromMap;
|
||||
|
||||
const itemPrefabPath = `customItems/${itemId}.bundle`;
|
||||
|
||||
const exampleCloneItem: NewItemFromCloneDetails = {
|
||||
itemTplToClone: finalItemTplToClone,
|
||||
overrideProperties: itemConfig.overrideProperties
|
||||
? {
|
||||
...itemConfig.overrideProperties,
|
||||
Prefab: {
|
||||
path:
|
||||
itemConfig.overrideProperties.Prefab?.path || itemPrefabPath,
|
||||
rcid: ""
|
||||
}
|
||||
}
|
||||
: undefined,
|
||||
parentId: finalParentId,
|
||||
newId: itemId,
|
||||
fleaPriceRoubles: itemConfig.fleaPriceRoubles,
|
||||
handbookPriceRoubles: itemConfig.handbookPriceRoubles,
|
||||
handbookParentId: finalHandbookParentId,
|
||||
locales: itemConfig.locales
|
||||
};
|
||||
if (this.instanceManager.debug) {
|
||||
console.log(`Cloning item ${finalItemTplToClone} for itemID: ${itemId}`);
|
||||
}
|
||||
return { exampleCloneItem, finalItemTplToClone };
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an item to a static loot container with a given probability.
|
||||
*
|
||||
* @param {string} containerID - The ID of the loot container.
|
||||
* @param {string} itemToAdd - The item to add to the loot container.
|
||||
* @param {number} probability - The probability of the item being added.
|
||||
* @return {void} This function does not return anything.
|
||||
*/
|
||||
private addToStaticLoot(
|
||||
containerID: string,
|
||||
itemToAdd: string,
|
||||
probability: number
|
||||
): void {
|
||||
const locations = this.instanceManager.database.locations;
|
||||
|
||||
for (const locationID in locations) {
|
||||
if (!Object.prototype.hasOwnProperty.call(locations, locationID)) {
|
||||
continue; // Skip invalid locations
|
||||
}
|
||||
|
||||
const location: ILocation = locations[locationID];
|
||||
if (!location.staticLoot) {
|
||||
if (this.instanceManager.debug) {
|
||||
console.warn(`Warning: No static loot found in location: ${locationID}`);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const staticLoot = location.staticLoot;
|
||||
if (!Object.prototype.hasOwnProperty.call(staticLoot, containerID)) {
|
||||
if (this.instanceManager.debug) {
|
||||
console.log(`Error: Loot container ID ${containerID} not found in location: ${locationID}`);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const lootContainer = staticLoot[containerID];
|
||||
if (!lootContainer) {
|
||||
if (this.instanceManager.debug) {
|
||||
console.log(`Error: Loot container ID ${containerID} is null in location: ${locationID}`);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const templateFromMap = ItemMap[itemToAdd];
|
||||
const finalTemplate = templateFromMap || itemToAdd;
|
||||
|
||||
const newLoot = [
|
||||
{
|
||||
tpl: finalTemplate,
|
||||
relativeProbability: probability,
|
||||
},
|
||||
];
|
||||
|
||||
lootContainer.itemDistribution.push(...newLoot);
|
||||
if (this.instanceManager.debug) {
|
||||
console.log(`Added ${itemToAdd} to loot container: ${containerID} in location: ${locationID}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processes the static loot containers for a given item.
|
||||
*
|
||||
* @param {any} itemConfig - The configuration object for the item.
|
||||
* @param {string} itemId - The ID of the item.
|
||||
* @return {void} This function does not return a value.
|
||||
*/
|
||||
private processStaticLootContainers(itemConfig: ConfigItem[string], itemId: string): void {
|
||||
if (itemConfig.addtoStaticLootContainers) {
|
||||
if (this.instanceManager.debug) {
|
||||
console.log("Processing static loot containers for item:", itemId);
|
||||
}
|
||||
if (Array.isArray(itemConfig.StaticLootContainers)) {
|
||||
if (this.instanceManager.debug) {
|
||||
console.log("Adding item to multiple static loot containers:");
|
||||
}
|
||||
for (const container of itemConfig.StaticLootContainers) {
|
||||
const staticLootContainer =
|
||||
ItemMap[container.ContainerName] || container.ContainerName;
|
||||
|
||||
this.addToStaticLoot(
|
||||
staticLootContainer,
|
||||
itemId,
|
||||
container.Probability
|
||||
);
|
||||
|
||||
if (this.instanceManager.debug) {
|
||||
console.log(
|
||||
` - Added to container '${staticLootContainer}' with probability ${container.Probability}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
const staticLootContainer =
|
||||
ItemMap[itemConfig.StaticLootContainers] ||
|
||||
itemConfig.StaticLootContainers;
|
||||
this.addToStaticLoot(
|
||||
staticLootContainer,
|
||||
itemId,
|
||||
itemConfig.Probability
|
||||
);
|
||||
if (this.instanceManager.debug) {
|
||||
console.log(`Added to container '${staticLootContainer}' with probability ${itemConfig.Probability}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the mod slots of an item.
|
||||
*
|
||||
* @param {any} itemConfig - The configuration of the item.
|
||||
* @param {string[]} finalItemTplToClone - The final item template to clone.
|
||||
* @param {string} itemId - The ID of the item.
|
||||
* @returns {void}
|
||||
*/
|
||||
private processModSlots(
|
||||
itemConfig: ConfigItem[string],
|
||||
finalItemTplToClone: string[],
|
||||
itemId: string
|
||||
): void {
|
||||
const tables = this.instanceManager.database;
|
||||
|
||||
const moddableItemWhitelistIds = Array.isArray(
|
||||
itemConfig.ModdableItemWhitelist
|
||||
)
|
||||
? itemConfig.ModdableItemWhitelist.map((shortname) => ItemMap[shortname])
|
||||
: itemConfig.ModdableItemWhitelist
|
||||
? [ItemMap[itemConfig.ModdableItemWhitelist]]
|
||||
: [];
|
||||
|
||||
const moddableItemBlacklistIds = Array.isArray(
|
||||
itemConfig.ModdableItemBlacklist
|
||||
)
|
||||
? itemConfig.ModdableItemBlacklist.map((shortname) => ItemMap[shortname])
|
||||
: itemConfig.ModdableItemBlacklist
|
||||
? [ItemMap[itemConfig.ModdableItemBlacklist]]
|
||||
: [];
|
||||
|
||||
const modSlots = Array.isArray(itemConfig.modSlot)
|
||||
? itemConfig.modSlot
|
||||
: itemConfig.modSlot
|
||||
? [itemConfig.modSlot]
|
||||
: [];
|
||||
|
||||
const lowercaseModSlots = modSlots.map((modSlotName) =>
|
||||
modSlotName.toLowerCase()
|
||||
);
|
||||
|
||||
if (itemConfig.addtoModSlots) {
|
||||
if (this.instanceManager.debug) {
|
||||
console.log("Processing mod slots for item:", itemId);
|
||||
}
|
||||
for (const parentItemId in tables.templates.items) {
|
||||
const parentItem = tables.templates.items[parentItemId];
|
||||
|
||||
if (!parentItem._props.Slots) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const isBlacklisted = moddableItemBlacklistIds.includes(parentItemId);
|
||||
const isWhitelisted = moddableItemWhitelistIds.includes(parentItemId);
|
||||
|
||||
if (isBlacklisted) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let addToModSlots = false;
|
||||
|
||||
if (isWhitelisted && itemConfig.modSlot) {
|
||||
addToModSlots = true;
|
||||
}
|
||||
else if (!isBlacklisted && itemConfig.modSlot) {
|
||||
for (const modSlot of parentItem._props.Slots) {
|
||||
if (
|
||||
modSlot._props.filters?.[0].Filter.some((filterItem) =>
|
||||
finalItemTplToClone.includes(filterItem)
|
||||
)
|
||||
) {
|
||||
if (lowercaseModSlots.includes(modSlot._name.toLowerCase())) {
|
||||
addToModSlots = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (addToModSlots) {
|
||||
for (const modSlot of parentItem._props.Slots) {
|
||||
if (lowercaseModSlots.includes(modSlot._name.toLowerCase())) {
|
||||
if (!modSlot._props.filters) {
|
||||
modSlot._props.filters = [
|
||||
{
|
||||
AnimationIndex: 0,
|
||||
Filter: []
|
||||
}
|
||||
];
|
||||
}
|
||||
if (!modSlot._props.filters[0].Filter.includes(itemId)) {
|
||||
modSlot._props.filters[0].Filter.push(itemId);
|
||||
if (this.instanceManager.debug) {
|
||||
console.log(`Successfully added item ${itemId} to the filter of mod slot ${modSlot._name} for parent item ${parentItemId}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the inventory slots for a given item.
|
||||
*
|
||||
* @param {any} itemConfig - The configuration object for the item.
|
||||
* @param {string} itemId - The ID of the item.
|
||||
* @param {any} defaultInventorySlots - The default inventory slots.
|
||||
* @return {void} This function does not return a value.
|
||||
*/
|
||||
private processInventorySlots(
|
||||
itemConfig: ConfigItem[string],
|
||||
itemId: string
|
||||
): void {
|
||||
const tables = this.instanceManager.database;
|
||||
|
||||
if (itemConfig.addtoInventorySlots) {
|
||||
if (this.instanceManager.debug) {
|
||||
console.log("Processing inventory slots for item:", itemId);
|
||||
}
|
||||
const defaultInventorySlots =
|
||||
tables.templates.items["55d7217a4bdc2d86028b456d"]._props.Slots;
|
||||
|
||||
const allowedSlots = Array.isArray(itemConfig.addtoInventorySlots)
|
||||
? itemConfig.addtoInventorySlots
|
||||
: [itemConfig.addtoInventorySlots];
|
||||
|
||||
// Iterate over the slots and push the item into the filters per the config
|
||||
for (const slot of defaultInventorySlots) {
|
||||
const slotName = inventorySlots[slot._name];
|
||||
const slotId = Object.keys(inventorySlots).find(
|
||||
(key) => inventorySlots[key] === slot._name
|
||||
);
|
||||
|
||||
if (
|
||||
allowedSlots.includes(slot._name) ||
|
||||
allowedSlots.includes(slotName) ||
|
||||
allowedSlots.includes(slotId)
|
||||
) {
|
||||
if (!slot._props.filters[0].Filter.includes(itemId)) {
|
||||
slot._props.filters[0].Filter.push(itemId);
|
||||
if (this.instanceManager.debug) {
|
||||
console.log(`Successfully added item ${itemId} to the filter of slot ${slot._name}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the mastery sections for an item.
|
||||
*
|
||||
* @param {any} itemConfig - The configuration object for the item.
|
||||
* @param {string} itemId - The ID of the item.
|
||||
* @param {any} tables - The tables object containing global configuration.
|
||||
* @return {void} This function does not return a value.
|
||||
*/
|
||||
private processMasterySections(
|
||||
itemConfig: ConfigItem[string],
|
||||
itemId: string
|
||||
): void {
|
||||
const tables = this.instanceManager.database;
|
||||
if (itemConfig.masteries) {
|
||||
if (this.instanceManager.debug) {
|
||||
console.log("Processing mastery sections for item:", itemId);
|
||||
}
|
||||
const masterySections = Array.isArray(itemConfig.masterySections)
|
||||
? itemConfig.masterySections
|
||||
: [itemConfig.masterySections];
|
||||
|
||||
for (const mastery of masterySections) {
|
||||
const existingMastery = tables.globals.config.Mastering.find(
|
||||
(existing) => existing.Name === mastery.Name
|
||||
);
|
||||
if (existingMastery) {
|
||||
existingMastery.Templates.push(...mastery.Templates);
|
||||
if (this.instanceManager.debug) {
|
||||
console.log(` - Adding to existing mastery section for item: ${itemId}`);
|
||||
}
|
||||
}
|
||||
else {
|
||||
tables.globals.config.Mastering.push(mastery);
|
||||
if (this.instanceManager.debug) {
|
||||
console.log(` - Adding new mastery section for item: ${itemId}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes weapon presets based on the provided item configuration and tables.
|
||||
*
|
||||
* @param {any} itemConfig - The item configuration.
|
||||
* @return {void} This function does not return anything.
|
||||
*/
|
||||
private processWeaponPresets(
|
||||
itemConfig: ConfigItem[string],
|
||||
itemId: string
|
||||
): void {
|
||||
const tables = this.instanceManager.database;
|
||||
const { addweaponpreset, weaponpresets } = itemConfig;
|
||||
const itemPresets = tables.globals.ItemPresets;
|
||||
|
||||
if (addweaponpreset) {
|
||||
if (this.instanceManager.debug) {
|
||||
console.log("Processing weapon presets for item:", itemId);
|
||||
}
|
||||
for (const presetData of weaponpresets) {
|
||||
const preset: IPreset = {
|
||||
_changeWeaponName: presetData._changeWeaponName,
|
||||
_encyclopedia: presetData._encyclopedia || undefined,
|
||||
_id: presetData._id,
|
||||
_items: presetData._items.map((itemData: IItem) => {
|
||||
const item: IItem = {
|
||||
_id: itemData._id,
|
||||
_tpl: itemData._tpl
|
||||
};
|
||||
|
||||
// Add parentId and slotId only if they are present in itemData
|
||||
if (itemData.parentId) {
|
||||
item.parentId = itemData.parentId;
|
||||
}
|
||||
if (itemData.slotId) {
|
||||
item.slotId = itemData.slotId;
|
||||
}
|
||||
|
||||
return item;
|
||||
}),
|
||||
_name: presetData._name,
|
||||
_parent: presetData._parent,
|
||||
_type: "Preset"
|
||||
};
|
||||
|
||||
itemPresets[preset._id] = preset;
|
||||
|
||||
if (this.instanceManager.debug) {
|
||||
console.log(` - Added weapon preset: ${preset._name}`);
|
||||
console.log(` - Preset: ${JSON.stringify(preset)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes traders based on the item configuration.
|
||||
*
|
||||
* @param {any} itemConfig - The configuration of the item.
|
||||
* @param {string} itemId - The ID of the item.
|
||||
* @return {void} This function does not return a value.
|
||||
*/
|
||||
private processTraders(
|
||||
itemConfig: ConfigItem[string],
|
||||
itemId: string
|
||||
): void {
|
||||
const tables = this.instanceManager.database;
|
||||
if (!itemConfig.addtoTraders) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { traderId, traderItems, barterScheme } = itemConfig;
|
||||
|
||||
const traderIdFromMap = traderIDs[traderId];
|
||||
const finalTraderId = traderIdFromMap || traderId;
|
||||
const trader = tables.traders[finalTraderId];
|
||||
|
||||
if (!trader) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const item of traderItems) {
|
||||
if (this.instanceManager.debug) {
|
||||
console.log("Processing traders for item:", itemId);
|
||||
}
|
||||
const newItem = {
|
||||
_id: itemId,
|
||||
_tpl: itemId,
|
||||
parentId: "hideout",
|
||||
slotId: "hideout",
|
||||
upd: {
|
||||
UnlimitedCount: item.unlimitedCount,
|
||||
StackObjectsCount: item.stackObjectsCount
|
||||
}
|
||||
};
|
||||
|
||||
trader.assort.items.push(newItem);
|
||||
if (this.instanceManager.debug) {
|
||||
console.log(`Successfully added item ${itemId} to the trader ${traderId}`);
|
||||
}
|
||||
}
|
||||
|
||||
trader.assort.barter_scheme[itemId] = [];
|
||||
|
||||
for (const scheme of barterScheme) {
|
||||
if (this.instanceManager.debug) {
|
||||
console.log("Processing trader barter scheme for item:", itemId);
|
||||
}
|
||||
const count = scheme.count;
|
||||
const tpl = currencyIDs[scheme._tpl] || ItemMap[scheme._tpl];
|
||||
|
||||
if (!tpl) {
|
||||
throw new Error(
|
||||
`Invalid _tpl value in barterScheme for item: ${itemId}`
|
||||
);
|
||||
}
|
||||
|
||||
trader.assort.barter_scheme[itemId].push([
|
||||
{
|
||||
count: count,
|
||||
_tpl: tpl
|
||||
}
|
||||
]);
|
||||
if (this.instanceManager.debug) {
|
||||
console.log(`Successfully added item ${itemId} to the barter scheme of trader ${traderId}`);
|
||||
}
|
||||
}
|
||||
|
||||
trader.assort.loyal_level_items[itemId] = itemConfig.loyallevelitems;
|
||||
}
|
||||
|
||||
private addtoHallofFame(itemConfig: ConfigItem[string], itemId: string) {
|
||||
const hallofFame1 = this.instanceManager.database.templates.items["63dbd45917fff4dee40fe16e"];
|
||||
const hallofFame2 = this.instanceManager.database.templates.items["65424185a57eea37ed6562e9"];
|
||||
const hallofFame3 = this.instanceManager.database.templates.items["6542435ea57eea37ed6562f0"];
|
||||
|
||||
// Add to Hall of Fame filters
|
||||
if (itemConfig.addtoHallOfFame) {
|
||||
const hallOfFames = [hallofFame1, hallofFame2, hallofFame3];
|
||||
for (const hall of hallOfFames) {
|
||||
for (const slot of hall._props.Slots) {
|
||||
for (const filter of slot._props.filters) {
|
||||
if (!filter.Filter.includes(itemId)) {
|
||||
filter.Filter.push(itemId);
|
||||
|
||||
if (this.instanceManager.debug) {
|
||||
console.log(`Added item ${itemId} to filter Hall of Fame ${hall._name}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private addtoSpecialSlots(itemConfig: ConfigItem[string], itemId: string) {
|
||||
const tables = this.instanceManager.database;
|
||||
if (itemConfig.addtoSpecialSlots) {
|
||||
const pockets = tables.templates.items["627a4e6b255f7527fb05a0f6"];
|
||||
for (const slot of pockets._props.Slots) {
|
||||
if (!slot._props.filters[0].Filter.includes(itemId)) {
|
||||
slot._props.filters[0].Filter.push(itemId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the bot inventories based on the given item configuration.
|
||||
*
|
||||
* @param {ConfigItem[string]} itemConfig - The item configuration.
|
||||
* @param {string} finalItemTplToClone - The final item template to clone.
|
||||
* @param {string} itemId - The item ID.
|
||||
* @return {void} This function does not return anything.
|
||||
*/
|
||||
private processBotInventories(
|
||||
itemConfig: ConfigItem[string],
|
||||
finalItemTplToClone: string,
|
||||
itemId: string
|
||||
): void {
|
||||
const tables = this.instanceManager.database;
|
||||
|
||||
if (!itemConfig.addtoBots) return;
|
||||
|
||||
if (this.instanceManager.debug) {
|
||||
console.log("Processing bot inventories for item:", itemId);
|
||||
}
|
||||
|
||||
// Iterate through bot types
|
||||
for (const botId in tables.bots.types) {
|
||||
const botType = botId;
|
||||
const botInventory = tables.bots.types[botId].inventory;
|
||||
|
||||
botInventory.Ammo = botInventory.Ammo || {};
|
||||
|
||||
// Process items and equipment
|
||||
this.processInventoryType(botInventory.items, finalItemTplToClone, itemId, botType, "items");
|
||||
this.processInventoryType(botInventory.equipment, finalItemTplToClone, itemId, botType, "equipment");
|
||||
|
||||
// Process mods if applicable
|
||||
if (itemConfig.addtoModSlots && itemConfig.modSlot) {
|
||||
this.processBotModSlots(finalItemTplToClone, itemId, botType, itemConfig.modSlot);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes inventory type (items or equipment) and gathers mods based on Slots.
|
||||
*
|
||||
* @param {any} inventoryType - The inventory type to process.
|
||||
* @param {string} finalTplToClone - The final item template to clone.
|
||||
* @param {string} itemId - The item ID.
|
||||
* @param {string} botType - The bot type identifier.
|
||||
* @param {string} typeLabel - Label indicating items or equipment.
|
||||
* @return {void} This function does not return anything.
|
||||
*/
|
||||
private processInventoryType(
|
||||
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
||||
inventoryType: any,
|
||||
finalTplToClone: string,
|
||||
itemId: string,
|
||||
botType: string,
|
||||
typeLabel: string
|
||||
): void {
|
||||
const tables = this.instanceManager.database;
|
||||
if (typeLabel === "equipment" && (
|
||||
(inventoryType.FirstPrimaryWeapon?.[finalTplToClone]) ||
|
||||
(inventoryType.SecondPrimaryWeapon?.[finalTplToClone]) ||
|
||||
(inventoryType.Holster?.[finalTplToClone])
|
||||
)) {
|
||||
if (!this.ensureValidWeaponPreset(itemId)) {
|
||||
return;
|
||||
}
|
||||
this.processAmmoAndChambers(tables.bots.types[botType].inventory, tables.templates.items[itemId]._props, itemId, botType);
|
||||
}
|
||||
|
||||
for (const lootSlot in inventoryType) {
|
||||
const items = inventoryType[lootSlot];
|
||||
if (items && items[finalTplToClone] !== undefined) {
|
||||
const weight = items[finalTplToClone];
|
||||
if (this.instanceManager.debug) {
|
||||
console.log(` - Adding item to bot ${typeLabel} for bot type: ${botType} in loot slot: ${lootSlot} with weight: ${weight}`);
|
||||
}
|
||||
items[itemId] = weight;
|
||||
|
||||
this.addModsToItem(tables, itemId, botType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds mods to an item based on its Slots configuration.
|
||||
*
|
||||
* @param {any} tables - The database tables.
|
||||
* @param {string} itemId - The item ID.
|
||||
* @param {string} botType - The bot type identifier.
|
||||
* @return {void} This function does not return anything.
|
||||
*/
|
||||
private addModsToItem(tables: IDatabaseTables, itemId: string, botType: string): void {
|
||||
const itemProps = tables.templates.items[itemId]._props;
|
||||
if (itemProps?.Slots) {
|
||||
for (const slot of itemProps.Slots) {
|
||||
const slotName = slot._name;
|
||||
const filters = slot._props.filters;
|
||||
if (filters && filters.length > 0) {
|
||||
for (const filter of filters) {
|
||||
for (const modId of filter.Filter) {
|
||||
if (modId && tables.templates.items[modId]) {
|
||||
tables.bots.types[botType].inventory.mods[itemId] = tables.bots.types[botType].inventory.mods[itemId] || {};
|
||||
tables.bots.types[botType].inventory.mods[itemId][slotName] = tables.bots.types[botType].inventory.mods[itemId][slotName] || [];
|
||||
if (!tables.bots.types[botType].inventory.mods[itemId][slotName].includes(modId)) {
|
||||
tables.bots.types[botType].inventory.mods[itemId][slotName].push(modId);
|
||||
if (tables.templates.items[modId]._props) {
|
||||
if (tables.templates.items[modId]._props.Slots.length > 0) {
|
||||
this.addModsToItem(tables, modId, botType);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.instanceManager.debug) {
|
||||
console.log(` - Added mod ${modId} to ${itemId}'s ${slotName} of bot type ${botType}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes mod slots and adds itemId to specified slots if finalItemTplToClone is present.
|
||||
*
|
||||
* @param {any} mods - The mods inventory.
|
||||
* @param {string} finalItemTplToClone - The final item template to clone.
|
||||
* @param {string} itemId - The item ID.
|
||||
* @param {string} botType - The bot type identifier.
|
||||
* @param {string[]} modSlots - The list of mod slots to process.
|
||||
* @return {void} This function does not return anything.
|
||||
*/
|
||||
private processBotModSlots(
|
||||
finalItemTplToClone: string,
|
||||
itemId: string,
|
||||
botType: string,
|
||||
modSlots: string[]
|
||||
): void {
|
||||
const mods = this.instanceManager.database.bots.types[botType].inventory.mods;
|
||||
for (const item in mods) {
|
||||
const itemMods = mods[item];
|
||||
|
||||
for (const modSlot of modSlots) {
|
||||
if (itemMods[modSlot]?.includes(finalItemTplToClone)) {
|
||||
itemMods[modSlot].push(itemId);
|
||||
if (this.instanceManager.debug) {
|
||||
console.log(` - Added item ${itemId} to mod slot ${modSlot} for bot type ${botType} in item ${item}`);
|
||||
}
|
||||
|
||||
// Adding nested mods for the new item
|
||||
this.addModsToItem(this.instanceManager.database, itemId, botType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes ammo and chambers, adding calibers and chamber filters if needed.
|
||||
*
|
||||
* @param {any} botInventory - The bot's inventory.
|
||||
* @param {any} itemProps - The properties of the item.
|
||||
* @param {string} itemId - The item ID.
|
||||
* @param {string} botType - The bot type identifier.
|
||||
* @return {void} This function does not return anything.
|
||||
*/
|
||||
private processAmmoAndChambers(
|
||||
botInventory: IInventory,
|
||||
itemProps: IProps,
|
||||
itemId: string,
|
||||
botType: string
|
||||
): void {
|
||||
const ammoCaliber = itemProps.ammoCaliber;
|
||||
if (!ammoCaliber) return;
|
||||
|
||||
botInventory.Ammo[ammoCaliber] = botInventory.Ammo[ammoCaliber] || {};
|
||||
|
||||
if (this.instanceManager.debug) {
|
||||
console.log(` - Added new caliber ${ammoCaliber} to bot inventory for bot type ${botType}`);
|
||||
}
|
||||
|
||||
if (itemProps.Chambers) {
|
||||
for (const chamber of itemProps.Chambers) {
|
||||
const filters = chamber._props.filters;
|
||||
if (filters && filters.length > 0) {
|
||||
for (const filter of filters) {
|
||||
for (const filterItem of filter.Filter) {
|
||||
botInventory.Ammo[ammoCaliber][filterItem] = botInventory.Ammo[ammoCaliber][filterItem] || 0;
|
||||
if (this.instanceManager.debug) {
|
||||
console.log(` - Added filter item ${filterItem} to caliber ${ammoCaliber} in bot inventory for bot type ${botType}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the weapon has a valid preset in the global ItemPresets.
|
||||
*
|
||||
* @param {string} itemId - The item ID.
|
||||
* @return {boolean} True if the weapon has a valid preset, false otherwise.
|
||||
*/
|
||||
private ensureValidWeaponPreset(itemId: string): boolean {
|
||||
const db = this.instanceManager.database;
|
||||
const presets: Record<string, IPreset> = db.globals.ItemPresets;
|
||||
for (const presetObj of Object.values(presets)) {
|
||||
if (presetObj._items[0]._tpl === itemId) {
|
||||
if (this.instanceManager.debug) {
|
||||
console.log(` - Valid preset found for item ${itemId}`);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (this.instanceManager.debug) {
|
||||
console.warn(`No valid preset found for item ${itemId} in globals.ItemPresets`);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,119 +0,0 @@
|
|||
import path from "node:path";
|
||||
|
||||
import type { ILogger } from "@spt/models/spt/utils/ILogger";
|
||||
import type { ProfileController } from "@spt/controllers/ProfileController";
|
||||
import type { ProfileCallbacks } from "@spt/callbacks/ProfileCallbacks";
|
||||
import type { EventOutputHolder } from "@spt/routers/EventOutputHolder";
|
||||
import type { DatabaseServer } from "@spt/servers/DatabaseServer";
|
||||
import type { IDatabaseTables } from "@spt/models/spt/server/IDatabaseTables";
|
||||
import type { StaticRouterModService } from "@spt/services/mod/staticRouter/StaticRouterModService";
|
||||
import type { DynamicRouterModService } from "@spt/services/mod/dynamicRouter/DynamicRouterModService";
|
||||
import type { TraderAssortService } from "@spt/services/TraderAssortService";
|
||||
import type { DependencyContainer } from "tsyringe";
|
||||
import type { CustomItemService } from "@spt/services/mod/CustomItemService";
|
||||
import type { ImageRouter } from "@spt/routers/ImageRouter";
|
||||
import type { PreSptModLoader } from "@spt/loaders/PreSptModLoader";
|
||||
import type { ConfigServer } from "@spt/servers/ConfigServer";
|
||||
import type { JsonUtil } from "@spt/utils/JsonUtil";
|
||||
import type { ProfileHelper } from "@spt/helpers/ProfileHelper";
|
||||
import type { RagfairPriceService } from "@spt/services/RagfairPriceService";
|
||||
import type { ImporterUtil } from "@spt/utils/ImporterUtil";
|
||||
import type { SaveServer } from "@spt/servers/SaveServer";
|
||||
import type { ItemHelper } from "@spt/helpers/ItemHelper";
|
||||
import type { ApplicationContext } from "@spt/context/ApplicationContext";
|
||||
import type { VFS } from "@spt/utils/VFS";
|
||||
|
||||
export class WTTInstanceManager
|
||||
{
|
||||
//#region Accessible in or after preSptLoad
|
||||
public modName: string;
|
||||
public debug: boolean;
|
||||
// Useful Paths
|
||||
public profilePath: string = path.join(process.cwd(), "\\user\\profiles");
|
||||
|
||||
// Instances
|
||||
public container: DependencyContainer;
|
||||
public PreSptModLoader: PreSptModLoader;
|
||||
public configServer: ConfigServer;
|
||||
public saveServer: SaveServer;
|
||||
public itemHelper: ItemHelper;
|
||||
public logger: ILogger;
|
||||
public staticRouter: StaticRouterModService;
|
||||
public dynamicRouter: DynamicRouterModService;
|
||||
public profileController: ProfileController;
|
||||
public profileCallbacks: ProfileCallbacks;
|
||||
//#endregion
|
||||
|
||||
//#region Acceessible in or after postDBLoad
|
||||
public database: IDatabaseTables;
|
||||
public customItem: CustomItemService;
|
||||
public imageRouter: ImageRouter;
|
||||
public jsonUtil: JsonUtil;
|
||||
public profileHelper: ProfileHelper;
|
||||
public eventOutputHolder: EventOutputHolder;
|
||||
public ragfairPriceService: RagfairPriceService;
|
||||
public importerUtil: ImporterUtil;
|
||||
public traderAssortService: TraderAssortService;
|
||||
public applicationContext: ApplicationContext;
|
||||
public vfs: VFS;
|
||||
//#endregion
|
||||
|
||||
// Call at the start of the mods postDBLoad method
|
||||
public preSptLoad(container: DependencyContainer, mod: string): void
|
||||
{
|
||||
this.modName = mod;
|
||||
|
||||
this.container = container;
|
||||
this.PreSptModLoader = container.resolve<PreSptModLoader>("PreSptModLoader");
|
||||
this.imageRouter = container.resolve<ImageRouter>("ImageRouter");
|
||||
this.configServer = container.resolve<ConfigServer>("ConfigServer");
|
||||
this.saveServer = container.resolve<SaveServer>("SaveServer");
|
||||
this.itemHelper = container.resolve<ItemHelper>("ItemHelper");
|
||||
this.eventOutputHolder = container.resolve<EventOutputHolder>("EventOutputHolder");
|
||||
this.profileController = container.resolve<ProfileController>("ProfileController");
|
||||
this.profileCallbacks = container.resolve<ProfileCallbacks>("ProfileCallbacks");
|
||||
this.logger = container.resolve<ILogger>("WinstonLogger");
|
||||
this.staticRouter = container.resolve<StaticRouterModService>("StaticRouterModService");
|
||||
this.dynamicRouter = container.resolve<DynamicRouterModService>("DynamicRouterModService");
|
||||
this.traderAssortService = container.resolve<TraderAssortService>("TraderAssortService");
|
||||
this.vfs = container.resolve<VFS>("VFS");
|
||||
|
||||
|
||||
}
|
||||
|
||||
public postDBLoad(container: DependencyContainer): void
|
||||
{
|
||||
this.database = container.resolve<DatabaseServer>("DatabaseServer").getTables();
|
||||
this.customItem = container.resolve<CustomItemService>("CustomItemService");
|
||||
this.jsonUtil = container.resolve<JsonUtil>("JsonUtil");
|
||||
this.profileHelper = container.resolve<ProfileHelper>("ProfileHelper");
|
||||
this.ragfairPriceService = container.resolve<RagfairPriceService>("RagfairPriceService");
|
||||
this.importerUtil = container.resolve<ImporterUtil>("ImporterUtil");
|
||||
this.applicationContext = container.resolve<ApplicationContext>("ApplicationContext");
|
||||
|
||||
}
|
||||
|
||||
public colorLog(message: string, color: string) {
|
||||
const colorCodes = {
|
||||
red: "\x1b[31m",
|
||||
green: "\x1b[32m",
|
||||
yellow: "\x1b[33m",
|
||||
blue: "\x1b[34m",
|
||||
magenta: "\x1b[35m",
|
||||
cyan: "\x1b[36m",
|
||||
white: "\x1b[37m",
|
||||
gray: "\x1b[90m",
|
||||
brightRed: "\x1b[91m",
|
||||
brightGreen: "\x1b[92m",
|
||||
brightYellow: "\x1b[93m",
|
||||
brightBlue: "\x1b[94m",
|
||||
brightMagenta: "\x1b[95m",
|
||||
brightCyan: "\x1b[96m",
|
||||
brightWhite: "\x1b[97m"
|
||||
};
|
||||
|
||||
const resetCode = "\x1b[0m";
|
||||
const colorCode = colorCodes[color as keyof typeof colorCodes] || "\x1b[37m"; // Default to white if color is invalid.
|
||||
console.log(`${colorCode}${message}${resetCode}`); // Log the colored message here
|
||||
}
|
||||
}
|
|
@ -1,94 +0,0 @@
|
|||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
import type { DependencyContainer } from "tsyringe";
|
||||
import type { IPostDBLoadMod } from "@spt/models/external/IPostDBLoadMod";
|
||||
import type { IPreSptLoadMod } from "@spt/models/external/IPreSptLoadMod";
|
||||
import { LogTextColor } from "@spt/models/spt/logging/LogTextColor";
|
||||
|
||||
// WTT imports
|
||||
import { WTTInstanceManager } from "./WTTInstanceManager";
|
||||
|
||||
// Boss imports
|
||||
import { CustomItemService } from "./CustomItemService";
|
||||
|
||||
// Custom Trader Assort Items
|
||||
import { CustomAssortSchemeService } from "./CustomAssortSchemeService";
|
||||
|
||||
|
||||
|
||||
class WTTArmoryAk5C
|
||||
implements IPreSptLoadMod, IPostDBLoadMod
|
||||
{
|
||||
private instanceManager: WTTInstanceManager = new WTTInstanceManager();
|
||||
private version: string;
|
||||
private modName = "WTTArmoryAk5C";
|
||||
|
||||
private customItemService: CustomItemService = new CustomItemService();
|
||||
private customAssortSchemeService: CustomAssortSchemeService = new CustomAssortSchemeService();
|
||||
|
||||
debug = false;
|
||||
|
||||
// Anything that needs done on preSptLoad, place here.
|
||||
public preSptLoad(container: DependencyContainer): void
|
||||
{
|
||||
// Initialize the instance manager DO NOTHING ELSE BEFORE THIS
|
||||
this.instanceManager.preSptLoad(container, this.modName);
|
||||
this.instanceManager.debug = this.debug;
|
||||
// EVERYTHING AFTER HERE MUST USE THE INSTANCE
|
||||
|
||||
this.getVersionFromJson();
|
||||
this.displayCreditBanner();
|
||||
|
||||
this.customItemService.preSptLoad(this.instanceManager);
|
||||
|
||||
this.customAssortSchemeService.preSptLoad(this.instanceManager);
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Anything that needs done on postDBLoad, place here.
|
||||
postDBLoad(container: DependencyContainer): void
|
||||
{
|
||||
// Initialize the instance manager DO NOTHING ELSE BEFORE THIS
|
||||
this.instanceManager.postDBLoad(container);
|
||||
// EVERYTHING AFTER HERE MUST USE THE INSTANCE
|
||||
|
||||
this.customItemService.postDBLoad();
|
||||
|
||||
this.customAssortSchemeService.postDBLoad();
|
||||
this.instanceManager.logger.log(
|
||||
`[${this.modName}] Database: Loading complete.`,
|
||||
LogTextColor.GREEN
|
||||
);
|
||||
}
|
||||
|
||||
private getVersionFromJson(): void
|
||||
{
|
||||
const packageJsonPath = path.join(__dirname, "../package.json");
|
||||
|
||||
fs.readFile(packageJsonPath, "utf-8", (err, data) =>
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
console.error("Error reading file:", err);
|
||||
return;
|
||||
}
|
||||
|
||||
const jsonData = JSON.parse(data);
|
||||
this.version = jsonData.version;
|
||||
});
|
||||
}
|
||||
|
||||
private displayCreditBanner(): void
|
||||
{
|
||||
this.instanceManager.colorLog
|
||||
(`[${this.modName}] Developers: Tron, MoxoPixel, and the WTT Team
|
||||
Swede dreams are made of this`, "green");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = { mod: new WTTArmoryAk5C() };
|
|
@ -1,296 +0,0 @@
|
|||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
|
||||
import type { IPreset } from "@spt/models/eft/common/IGlobals";
|
||||
import type { Ixyz } from "@spt/models/eft/common/Ixyz";
|
||||
import type { IPrefab } from "@spt/models/eft/common/tables/ICustomizationItem";
|
||||
|
||||
export interface ConfigItem
|
||||
{
|
||||
[itemId: string]: {
|
||||
itemTplToClone: string;
|
||||
overrideProperties: {
|
||||
Prefab: {
|
||||
path: string;
|
||||
rcid: string;
|
||||
};
|
||||
ReverbVolume: number;
|
||||
};
|
||||
parentId: string;
|
||||
fleaPriceRoubles: number;
|
||||
handbookPriceRoubles: number;
|
||||
handbookParentId: string;
|
||||
locales: {
|
||||
[locale: string]: {
|
||||
name: string;
|
||||
shortName: string;
|
||||
description: string;
|
||||
};
|
||||
};
|
||||
clearClonedProps: boolean;
|
||||
addtoInventorySlots: string[];
|
||||
addtoModSlots: boolean;
|
||||
modSlot: string[];
|
||||
ModdableItemWhitelist: string;
|
||||
ModdableItemBlacklist: string;
|
||||
addtoTraders: boolean;
|
||||
traderId: traderIDs;
|
||||
traderItems: {
|
||||
unlimitedCount: boolean;
|
||||
stackObjectsCount: number;
|
||||
}[];
|
||||
barterScheme: {
|
||||
count: number;
|
||||
_tpl: string;
|
||||
}[];
|
||||
loyallevelitems: number;
|
||||
addtoBots: boolean;
|
||||
addtoStaticLootContainers: boolean;
|
||||
StaticLootContainers: string;
|
||||
Probability: number;
|
||||
masteries: boolean;
|
||||
masterySections: {
|
||||
Name: string;
|
||||
Templates: string[];
|
||||
Level2: number;
|
||||
Level3: number;
|
||||
};
|
||||
addweaponpreset: boolean;
|
||||
weaponpresets: IPreset[];
|
||||
addtoHallOfFame: boolean;
|
||||
addtoSpecialSlots: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
export interface HeadConfig {
|
||||
path: string;
|
||||
addHeadToPlayer: boolean;
|
||||
side: string[];
|
||||
locales: {
|
||||
[key: string]: string; // This allows dynamic locale keys, such as "en", "ru", etc.
|
||||
};
|
||||
}
|
||||
|
||||
export interface VoiceConfig
|
||||
{
|
||||
[voiceId: string]: {
|
||||
locales: {
|
||||
[key: string]: string; // This allows dynamic locale keys, such as "en", "ru", etc.
|
||||
};
|
||||
name: string;
|
||||
addVoiceToPlayer: boolean;
|
||||
sideSpecificVoice: string;
|
||||
addToBotTypes: Record<string, number>;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ClothingConfig {
|
||||
type: string; // The type of clothing item, e.g., "bottom"
|
||||
suiteId: string; // ID of the clothing item's suite
|
||||
outfitId: string; // Unique identifier for the outfit
|
||||
bottomId?: string; // ID of the clothing item's bottom
|
||||
locales: {
|
||||
[key: string]: string; // This allows dynamic locale keys, such as "en", "ru", etc.
|
||||
};
|
||||
topId?: string; // ID of the clothing item's top
|
||||
handsId?: string; // ID of the clothing item's hands
|
||||
side: string[]; // Side of the clothing item, e.g., ["usec", "bear"]
|
||||
bottomBundlePath?: string; // Path to the clothing item's asset bundle
|
||||
topBundlePath?: string; // Path to the clothing item's top asset bundle
|
||||
handsBundlePath?: string; // Path to the clothing item's hands asset bundle
|
||||
watchPrefab?: IPrefab; // Path to the watch prefab asset bundle
|
||||
watchPosition?: Ixyz; // Position of the watch on the clothing item
|
||||
watchRotation?: Ixyz; // Rotation of the watch on the clothing item
|
||||
handsBaseID?: string; // ID of the clothing item's hands base
|
||||
traderId: string; // Trader who sells this item, e.g., "RAGMAN"
|
||||
loyaltyLevel: number; // Loyalty level required to purchase the item
|
||||
profileLevel: number; // Player profile level required to purchase the item
|
||||
standing: number; // Minimum standing required with the trader
|
||||
currencyId: string; // Currency type for the item's price, e.g., "ROUBLES"
|
||||
price: number; // Cost of the clothing item in the specified currency
|
||||
}
|
||||
|
||||
|
||||
export enum traderIDs
|
||||
{
|
||||
MECHANIC = "5a7c2eca46aef81a7ca2145d",
|
||||
SKIER = "58330581ace78e27b8b10cee",
|
||||
PEACEKEEPER = "5935c25fb3acc3127c3d8cd9",
|
||||
THERAPIST = "54cb57776803fa99248b456e",
|
||||
PRAPOR = "54cb50c76803fa8b248b4571",
|
||||
JAEGAR = "5c0647fdd443bc2504c2d371",
|
||||
RAGMAN = "5ac3b934156ae10c4430e83c",
|
||||
FENCE = "579dc571d53a0658a154fbec",
|
||||
BADGER = "bd3a8b28356d9c6509966546"
|
||||
}
|
||||
|
||||
export enum currencyIDs
|
||||
{
|
||||
ROUBLES = "5449016a4bdc2d6f028b456f",
|
||||
EUROS = "569668774bdc2da2298b4568",
|
||||
DOLLARS = "5696686a4bdc2da3298b456a"
|
||||
}
|
||||
|
||||
export enum allBotTypes
|
||||
{
|
||||
|
||||
// Arena Fighters
|
||||
ARENAFIGHTER = "arenafighter",
|
||||
ARENAFIGHTEREVENT = "arenafighterevent",
|
||||
|
||||
// Scavs
|
||||
ASSAULT = "assault",
|
||||
ASSAULTGROUP = "assaultgroup",
|
||||
MARKSMAN = "marksman",
|
||||
CRAZYASSAULTEVENT = "crazyassaultevent",
|
||||
CURSEDASSAULT = "cursedassault",
|
||||
|
||||
// PMC's
|
||||
BEAR = "bear",
|
||||
USEC = "usec",
|
||||
PMCBEAR = "pmcbear",
|
||||
PMCUSEC = "pmcusec",
|
||||
PMC = "pmcbot",
|
||||
|
||||
// ExUsec
|
||||
EXUSEC = "exusec",
|
||||
|
||||
// Cultists
|
||||
CULTISTPRIEST = "sectantpriest",
|
||||
CULTISTWARRIOR = "sectantwarrior",
|
||||
CULTISTONI = "sectantoni",
|
||||
CULTISTPRIESTEVENT = "sectantpriestevent",
|
||||
CULTISTPREDVESTNIK = "sectantpredvestnik",
|
||||
CULTISTPRIZRAK = "sectantprizrak",
|
||||
|
||||
// BTR
|
||||
BTR = "btrshooter",
|
||||
|
||||
// Spirits
|
||||
SPIRITSPRING = "spiritspring",
|
||||
SPIRITWINTER = "spiritwinter",
|
||||
|
||||
// Zombies
|
||||
INFECTEDASSAULT = "infectedassault",
|
||||
INFECTEDCIVIL = "infectedcivil",
|
||||
INFECTEDLABORANT = "infectedlaborant",
|
||||
INFECTEDPMC = "infectedpmc",
|
||||
INFECTEDTAGILLA = "infectedtagilla",
|
||||
|
||||
|
||||
// Santa
|
||||
GIFTER = "gifter",
|
||||
|
||||
// Bosses & Followers
|
||||
|
||||
// Kaban
|
||||
KABAN = "bossboar",
|
||||
KABANSNIPER = "bossboarsniper",
|
||||
FOLLOWERBOAR = "followerboar",
|
||||
FOLLOWERBOARCLOSE1 = "followerboarclose1",
|
||||
FOLLOWERBOARCLOSE2 = "followerboarclose2",
|
||||
|
||||
// Killa
|
||||
KILLA = "bosskilla",
|
||||
|
||||
// Kolontay
|
||||
KOLONTAY = "bosskolontay",
|
||||
FOLLOWERKOLONTAYASSAULT = "followerkolontayassault",
|
||||
FOLLOWERKOLONTAYSECURITY = "followerkolontaysecurity",
|
||||
|
||||
// Partisan
|
||||
PARTISAN = "bosspartisan",
|
||||
|
||||
// Reshala
|
||||
RESHALA = "bossbully",
|
||||
FOLLOWERRESHALA = "followerbully",
|
||||
|
||||
// Gluhar
|
||||
GLUHAR = "bossgluhar",
|
||||
FOLLOWERGLUHARASSAULT = "followergluharassault",
|
||||
FOLLOWERGLUHARSCOUT = "followergluharscout",
|
||||
FOLLOWERGLUHARSECURITY = "followergluharsecurity",
|
||||
FOLLOWERGLUHARSNIPER = "followergluharsnipe",
|
||||
|
||||
// Goons
|
||||
KNIGHT = "bossknight",
|
||||
FOLLOWERBIGPIPE = "followerbigpipe",
|
||||
FOLLOWERBIRDEYE = "followerbirdeye",
|
||||
|
||||
// Shturman
|
||||
SHTURMAN = "bosskojaniy",
|
||||
FOLLOWERSHTURMAN = "followerkojaniy",
|
||||
|
||||
// Sanitar
|
||||
SANITAR = "bosssanitar",
|
||||
FOLLOWERSANITAR = "followersanitar",
|
||||
|
||||
// Tagilla
|
||||
TAGILLA = "bosstagilla",
|
||||
FOLLOWERTAGILLA = "followertagilla",
|
||||
|
||||
// Zryachiy
|
||||
ZRYACHIY = "bosszryachiy",
|
||||
FOLLOWERZRYACHIY = "followerzryachiy",
|
||||
PEACEFULZRYACHIYEVENT = "peacefulzryachiyevent",
|
||||
RAVANGEZRYACHIYEVENT = "ravengezryachiyevent",
|
||||
|
||||
// Traders
|
||||
|
||||
// Peacemaker
|
||||
PEACEMAKER = "peacemaker",
|
||||
|
||||
// Skier
|
||||
SKIER = "skier",
|
||||
|
||||
}
|
||||
|
||||
export enum inventorySlots
|
||||
{
|
||||
FirstPrimaryWeapon = "55d729c64bdc2d89028b4570",
|
||||
SecondPrimaryWeapon = "55d729d14bdc2d86028b456e",
|
||||
Holster = "55d729d84bdc2de3098b456b",
|
||||
Scabbard = "55d729e34bdc2d1b198b456d",
|
||||
FaceCover = "55d729e84bdc2d8a028b4569",
|
||||
Headwear = "55d729ef4bdc2d3a168b456c",
|
||||
TacticalVest = "55d729f74bdc2d87028b456e",
|
||||
SecuredContainer = "55d72a054bdc2d88028b456e",
|
||||
Backpack = "55d72a104bdc2d89028b4571",
|
||||
ArmorVest = "55d72a194bdc2d86028b456f",
|
||||
Pockets = "55d72a274bdc2de3098b456c",
|
||||
Earpiece = "5665b7164bdc2d144c8b4570",
|
||||
Dogtag = "59f0be1e86f77453be490939",
|
||||
Eyewear = "5a0ad9313f1241000e072755",
|
||||
ArmBand = "5b3f583786f77411d552fb2b"
|
||||
}
|
||||
|
||||
export enum Stashes
|
||||
{
|
||||
LEVEL1 = "566abbc34bdc2d92178b4576",
|
||||
LEVEL2 = "5811ce572459770cba1a34ea",
|
||||
LEVEL3 = "5811ce662459770f6f490f32",
|
||||
LEVEL4 = "5811ce772459770e9e5f9532"
|
||||
}
|
||||
|
||||
export interface QuestZone
|
||||
{
|
||||
zoneId: string;
|
||||
zoneName: string;
|
||||
zoneType: string;
|
||||
flareType?: string;
|
||||
zoneLocation: string;
|
||||
position: {
|
||||
x: string;
|
||||
y: string;
|
||||
z: string;
|
||||
};
|
||||
rotation: {
|
||||
x: string;
|
||||
y: string;
|
||||
z: string;
|
||||
};
|
||||
scale: {
|
||||
x: string;
|
||||
y: string;
|
||||
z: string;
|
||||
};
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
export const ItemBaseClassMap: { [itemName: string]: string } = {
|
||||
"AMMO": "5485a8684bdc2da71d8b4567",
|
||||
"AMMO_CONTAINER": "543be5cb4bdc2deb348b4568",
|
||||
"ARMORED_EQUIPMENT": "57bef4c42459772e8d35a53b",
|
||||
"ARMBAND": "5b3f15d486f77432d0509248",
|
||||
"ARMOR": "5448e54d4bdc2dcc718b4568",
|
||||
"ARMORPLATE": "644120aa86ffbe10ee032b6f",
|
||||
"ASSAULT_CARBINE": "5447b5fc4bdc2d87278b4567",
|
||||
"ASSAULT_RIFLE": "5447b5f14bdc2d61278b4567",
|
||||
"ASSAULT_SCOPE": "55818add4bdc2d5b648b456f",
|
||||
"BACKPACK": "5448e53e4bdc2d60728b4567",
|
||||
"BARREL": "555ef6e44bdc2de9068b457e",
|
||||
"BATTERY": "57864ee62459775490116fc1",
|
||||
"BIPOD": "55818afb4bdc2dde698b456d",
|
||||
"BUILDING_MATERIAL": "57864ada245977548638de91",
|
||||
"CHARGING_HANDLE": "55818a6f4bdc2db9688b456b",
|
||||
"CHEST_RIG": "5448e5284bdc2dcb718b4567",
|
||||
"COMMON_CONTAINER": "5795f317245977243854e041",
|
||||
"COMPACT_REFLEX_SIGHT": "55818acf4bdc2dde698b456b",
|
||||
"COMPASS": "5f4fbaaca5573a5ac31db429",
|
||||
"DRINK": "5448e8d64bdc2dce718b4568",
|
||||
"DRUG": "5448f3a14bdc2d27728b4569",
|
||||
"ELECTRONICS": "57864a66245977548f04a81f",
|
||||
"FACECOVER": "5a341c4686f77469e155819e",
|
||||
"FLASHLIGHT": "55818b084bdc2d5b648b4571",
|
||||
"FLASHHIDER": "550aa4bf4bdc2dd6348b456b",
|
||||
"FOOD": "5448e8d04bdc2ddf718b4569",
|
||||
"FOREGRIP": "55818af64bdc2d5b648b4570",
|
||||
"FUEL": "5d650c3e815116009f6201d2",
|
||||
"GAS_BLOCK": "56ea9461d2720b67698b456f",
|
||||
"GRENADE_LAUNCHER": "5447bedf4bdc2d87278b4568",
|
||||
"HANDGUN": "5447b5cf4bdc2d65278b4567",
|
||||
"HANDGUARD": "55818a104bdc2db9688b4569",
|
||||
"HEADPHONES": "5645bcb74bdc2ded0b8b4578",
|
||||
"HEADWEAR": "5a341c4086f77401f2541505",
|
||||
"INFO": "5448ecbe4bdc2d60728b4568",
|
||||
"INVENTORY": "55d720f24bdc2d88028b456d",
|
||||
"IRON_SIGHT": "55818ac54bdc2d5b648b456e",
|
||||
"KEYCARD": "5c164d2286f774194c5e69fa",
|
||||
"KEYMECHANICAL": "5c99f98d86f7745c314214b3",
|
||||
"KEY_CARD": "5c164d2286f774194c5e69fa",
|
||||
"KNIFE": "5447e1d04bdc2dff2f8b4567",
|
||||
"LOCKING_CONTAINER": "5671435f4bdc2d96058b4569",
|
||||
"LOOT_CONTAINER": "566965d44bdc2d814c8b4571",
|
||||
"LUBRICANT": "57864e4c24597754843f8723",
|
||||
"MACHINEGUN": "5447bed64bdc2d97278b4568",
|
||||
"MAGAZINE": "5448bc234bdc2d3c308b4569",
|
||||
"MAP": "567849dd4bdc2d150f8b456e",
|
||||
"MARKSMAN_RIFLE": "5447b6194bdc2d67278b4567",
|
||||
"MEDICAL_ITEM": "5448f3ac4bdc2dce718b4569",
|
||||
"MEDICAL_SUPPLIES": "57864c8c245977548867e7f1",
|
||||
"MEDITKIT": "5448f39d4bdc2d0a728b4568",
|
||||
"MONEY": "543be5dd4bdc2deb348b4569",
|
||||
"MUZZLECOMBO": "550aa4dd4bdc2dc9348b4569",
|
||||
"MOUNT": "55818b224bdc2dde698b456f",
|
||||
"NIGHTVISION": "5a2c3a9486f774688b05e574",
|
||||
"OTHER": "590c745b86f7743cc433c5f2",
|
||||
"PISTOLGRIP": "55818a684bdc2ddd698b456d",
|
||||
"POCKETS": "557596e64bdc2dc2118b4571",
|
||||
"PORTABLE_RANGEFINDER": "61605ddea09d851a0a0c1bbc",
|
||||
"RANDOMLOOTCONTAINER": "62f109593b54472778797866",
|
||||
"RECEIVER": "55818a304bdc2db5418b457d",
|
||||
"REFLEX_SIGHT": "55818ad54bdc2ddc698b4569",
|
||||
"REPAIRKITS": "616eb7aea207f41933308f46",
|
||||
"SCOPE": "55818ae44bdc2dde698b456c",
|
||||
"SHOTGUN": "5447b6094bdc2dc3278b4567",
|
||||
"SILENCER": "550aa4cd4bdc2dd8348b456c",
|
||||
"SNIPER_RIFLE": "5447b6254bdc2dc3278b4568",
|
||||
"SPECIAL_ITEM": "5447e0e74bdc2d3c308b4567",
|
||||
"STASH": "566abbb64bdc2d144c8b457d",
|
||||
"STATIONARY_CONT.": "567583764bdc2d98058b456e",
|
||||
"STIMULANT": "5448f3a64bdc2d60728b456a",
|
||||
"STOCK": "55818a594bdc2db9688b456a",
|
||||
"THROWABLE_WEAPON": "543be6564bdc2df4348b4568",
|
||||
"THERMALVISION": "5d21f59b6dbe99052b54ef83",
|
||||
"TOOL": "57864bb7245977548b3b66c2",
|
||||
"UBGL": "55818b014bdc2ddc698b456b",
|
||||
"VIS_OBSERV_DEVICE": "5448e5724bdc2ddf718b4568",
|
||||
};
|
|
@ -1,81 +0,0 @@
|
|||
export const ItemHandbookCategoryMap: { [itemName: string]: string } = {
|
||||
"AMMO": "5b47574386f77428ca22b346",
|
||||
"AMMO_BOXES": "5b47574386f77428ca22b33c",
|
||||
"AMMO_ROUNDS": "5b47574386f77428ca22b33b",
|
||||
"BARTER": "5b47574386f77428ca22b33e",
|
||||
"BARTER_BUILDING": "5b47574386f77428ca22b2ee",
|
||||
"BARTER_ELECTRONICS": "5b47574386f77428ca22b2ef",
|
||||
"BARTER_ENERGY": "5b47574386f77428ca22b2ed",
|
||||
"BARTER_FLAMMABLE": "5b47574386f77428ca22b2f2",
|
||||
"BARTER_HOUSEHOLD": "5b47574386f77428ca22b2f0",
|
||||
"BARTER_MEDICAL": "5b47574386f77428ca22b2f3",
|
||||
"BARTER_OTHERS": "5b47574386f77428ca22b2f4",
|
||||
"BARTER_TOOLS": "5b47574386f77428ca22b2f6",
|
||||
"BARTER_VALUABLES": "5b47574386f77428ca22b2f1",
|
||||
"GEAR": "5b47574386f77428ca22b33f",
|
||||
"GEAR_ARMOR": "5b5f701386f774093f2ecf0f",
|
||||
"GEAR_BACKPACKS": "5b5f6f6c86f774093f2ecf0b",
|
||||
"GEAR_CASES": "5b5f6fa186f77409407a7eb7",
|
||||
"GEAR_COMPONENTS": "5b5f704686f77447ec5d76d7",
|
||||
"GEAR_FACECOVERS": "5b47574386f77428ca22b32f",
|
||||
"GEAR_HEADSETS": "5b5f6f3c86f774094242ef87",
|
||||
"GEAR_HEADWEAR": "5b47574386f77428ca22b330",
|
||||
"GEAR_RIGS": "5b5f6f8786f77447ed563642",
|
||||
"GEAR_SECURED": "5b5f6fd286f774093f2ecf0d",
|
||||
"GEAR_VISORS": "5b47574386f77428ca22b331",
|
||||
"INFO": "5b47574386f77428ca22b341",
|
||||
"KEYS": "5b47574386f77428ca22b342",
|
||||
"KEYS_ELECTRONIC": "5c518ed586f774119a772aee",
|
||||
"KEYS_MECHANIC": "5c518ec986f7743b68682ce2",
|
||||
"MAPS": "5b47574386f77428ca22b343",
|
||||
"MEDICAL": "5b47574386f77428ca22b344",
|
||||
"MEDICAL_INJECTORS": "5b47574386f77428ca22b33a",
|
||||
"MEDICAL_INJURY": "5b47574386f77428ca22b339",
|
||||
"MEDICAL_MEDKITS": "5b47574386f77428ca22b338",
|
||||
"MEDICAL_PILLS": "5b47574386f77428ca22b337",
|
||||
"MODS": "5b5f71a686f77447ed5636ab",
|
||||
"MODS_FUNCTIONAL": "5b5f71b386f774093f2ecf11",
|
||||
"MODS_GEAR": "5b5f750686f774093e6cb503",
|
||||
"MODS_VITAL": "5b5f75b986f77447ec5d7710",
|
||||
"MOD_ASSAULT_SCOPE": "5b5f740a86f77447ec5d7706",
|
||||
"MOD_AUX": "5b5f74cc86f77447ec5d770a",
|
||||
"MOD_BARREL": "5b5f75c686f774094242f19f",
|
||||
"MOD_BIPOD": "5b5f71c186f77409407a7ec0",
|
||||
"MOD_CHARGE": "5b5f751486f77447ec5d770c",
|
||||
"MOD_FLASHHIDER": "5b5f724c86f774093f2ecf15",
|
||||
"MOD_FOREGRIP": "5b5f71de86f774093f2ecf13",
|
||||
"MOD_GASBLOCK": "5b5f760586f774093e6cb509",
|
||||
"MOD_HANDGUARD": "5b5f75e486f77447ec5d7712",
|
||||
"MOD_IRON_SIGHT": "5b5f746686f77447ec5d7708",
|
||||
"MOD_LAUNCHER": "5b5f752e86f774093e6cb505",
|
||||
"MOD_LIGHTLASER": "5b5f736886f774094242f193",
|
||||
"MOD_MAGAZINE": "5b5f754a86f774094242f19b",
|
||||
"MOD_MOUNT": "5b5f755f86f77447ec5d770e",
|
||||
"MOD_MICRO_DOT": "5b5f744786f774094242f197",
|
||||
"MOD_MUZZLE": "5b5f724186f77447ed5636ad",
|
||||
"MOD_OPTIC": "5b5f748386f774093e6cb501",
|
||||
"MOD_PISTOLGRIP": "5b5f761f86f774094242f1a1",
|
||||
"MOD_RECEIVER": "5b5f764186f77447ec5d7714",
|
||||
"MOD_SIGHT": "5b5f73ec86f774093e6cb4fd",
|
||||
"MOD_STOCK": "5b5f757486f774093e6cb507",
|
||||
"MOD_SUPPRESSOR": "5b5f731a86f774093e6cb4f9",
|
||||
"MONEY": "5b5f78b786f77447ed5636af",
|
||||
"PROVISIONS": "5b47574386f77428ca22b340",
|
||||
"PROVISIONS_DRINKS": "5b47574386f77428ca22b335",
|
||||
"PROVISIONS_FOOD": "5b47574386f77428ca22b336",
|
||||
"QUEST": "5b619f1a86f77450a702a6f3",
|
||||
"SPEC": "5b47574386f77428ca22b345",
|
||||
"WEAPONS": "5b5f78dc86f77409407a7f8e",
|
||||
"WEAPONS_ASSAULTRIFLES": "5b5f78fc86f77409407a7f90",
|
||||
"WEAPONS_BOLTACTION": "5b5f798886f77447ed5636b5",
|
||||
"WEAPONS_CARBINES": "5b5f78e986f77447ed5636b1",
|
||||
"WEAPONS_DMR": "5b5f791486f774093f2ed3be",
|
||||
"WEAPONS_GL": "5b5f79d186f774093f2ed3c2",
|
||||
"WEAPONS_MG": "5b5f79a486f77409407a7f94",
|
||||
"WEAPONS_MELEE": "5b5f7a0886f77409407a7f96",
|
||||
"WEAPONS_PISTOLS": "5b5f792486f77447ed5636b3",
|
||||
"WEAPONS_SHOTGUNS": "5b5f794b86f77409407a7f92",
|
||||
"WEAPONS_SMG": "5b5f796a86f774093f2ed3c0",
|
||||
"WEAPONS_SPECIAL": "5b5f79eb86f77447ed5636b7",
|
||||
"WEAPONS_THROW": "5b5f7a2386f774093f2ed3c4",
|
||||
};
|
File diff suppressed because it is too large
Load Diff
|
@ -1,28 +0,0 @@
|
|||
[General]
|
||||
gameName=spt
|
||||
modid=0
|
||||
version=d2025.1.14.0
|
||||
newestVersion=
|
||||
category="1,"
|
||||
nexusFileStatus=1
|
||||
installationFile=AUG_AttachmentPack.zip
|
||||
repository=
|
||||
ignoredVersion=
|
||||
comments=
|
||||
notes=
|
||||
nexusDescription=
|
||||
url=
|
||||
hasCustomURL=false
|
||||
lastNexusQuery=
|
||||
lastNexusUpdate=
|
||||
nexusLastModified=2025-01-15T01:12:37Z
|
||||
nexusCategory=0
|
||||
converted=false
|
||||
validated=false
|
||||
color=@Variant(\0\0\0\x43\0\xff\xff\0\0\0\0\0\0\0\0)
|
||||
tracked=0
|
||||
|
||||
[installedFiles]
|
||||
1\modid=0
|
||||
1\fileid=0
|
||||
size=1
|
|
@ -1,36 +0,0 @@
|
|||
{
|
||||
"manifest": [
|
||||
{
|
||||
"key": "assets/content/items/mods/handguards/handguard_fb20.bundle",
|
||||
"dependencyKeys": [
|
||||
"assets/commonassets/physics/physicsmaterials.bundle",
|
||||
"cubemaps",
|
||||
"shaders"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "assets/content/items/mods/handguards/handguard_guerilla.bundle",
|
||||
"dependencyKeys": [
|
||||
"assets/commonassets/physics/physicsmaterials.bundle",
|
||||
"cubemaps",
|
||||
"shaders"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "assets/content/items/mods/handguards/handguard_turaco.bundle",
|
||||
"dependencyKeys": [
|
||||
"assets/commonassets/physics/physicsmaterials.bundle",
|
||||
"cubemaps",
|
||||
"shaders"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "assets/content/items/mods/magazines/mag_aug_60.bundle",
|
||||
"dependencyKeys": [
|
||||
"assets/commonassets/physics/physicsmaterials.bundle",
|
||||
"cubemaps",
|
||||
"shaders"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,24 +0,0 @@
|
|||
{
|
||||
"templates": {
|
||||
"6786e03b67ad44fd9b0fabd0": {
|
||||
"Name": "AUG RAS Handguard",
|
||||
"ShortName": "AUG",
|
||||
"Description": "ARMY Metal AUG RAS Handguard For AUG A3 AEG Bullpup Rifle"
|
||||
},
|
||||
"6786e03b67ad44fd9b0fabd1": {
|
||||
"Name": "AUG Cantilever Handguard",
|
||||
"ShortName": "AUG",
|
||||
"Description": "The AUG Cantilever Forend combines a top rail, side rail, and M-LOK forend into a compact, light, and incredibly versatile package."
|
||||
},
|
||||
"6786e03b67ad44fd9b0fabd2": {
|
||||
"Name": "AUG Turaco handguard",
|
||||
"ShortName": "AUG",
|
||||
"Description": "A CNC made handguard with an M-LOK interface."
|
||||
},
|
||||
"6786e03b67ad44fd9b0fabd3": {
|
||||
"Name": "AUG A3 556x45 60-round drum magazine",
|
||||
"ShortName": "AUG",
|
||||
"Description": "A modified PMAG-D60 made to fit Steyr AUG A3"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
{
|
||||
"Items": [
|
||||
{
|
||||
"Id": "6786e03b67ad44fd9b0fabd0",
|
||||
"ParentId": "5b5f75e486f77447ec5d7712",
|
||||
"Price": 20000
|
||||
},
|
||||
{
|
||||
"Id": "6786e03b67ad44fd9b0fabd1",
|
||||
"ParentId": "5b5f75e486f77447ec5d7712",
|
||||
"Price": 18000
|
||||
},
|
||||
{
|
||||
"Id": "6786e03b67ad44fd9b0fabd2",
|
||||
"ParentId": "5b5f75e486f77447ec5d7712",
|
||||
"Price": 17000
|
||||
},
|
||||
{
|
||||
"Id": "6786e03b67ad44fd9b0fabd3",
|
||||
"ParentId": "5b5f754a86f774094242f19b",
|
||||
"Price": 15000
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,771 +0,0 @@
|
|||
{
|
||||
"6786e03b67ad44fd9b0fabd0": {
|
||||
"_id": "6786e03b67ad44fd9b0fabd0",
|
||||
"_name": "handguard_fb20",
|
||||
"_parent": "55818a104bdc2db9688b4569",
|
||||
"_type": "Item",
|
||||
"_props": {
|
||||
"Name": "",
|
||||
"ShortName": "",
|
||||
"Description": "",
|
||||
"Weight": 0.209,
|
||||
"BackgroundColor": "blue",
|
||||
"Width": 2,
|
||||
"Height": 1,
|
||||
"StackMaxSize": 1,
|
||||
"ItemSound": "mod",
|
||||
"Prefab": {
|
||||
"path": "assets/content/items/mods/handguards/handguard_fb20.bundle",
|
||||
"rcid": ""
|
||||
},
|
||||
"UsePrefab": {
|
||||
"path": "",
|
||||
"rcid": ""
|
||||
},
|
||||
"StackObjectsCount": 1,
|
||||
"NotShownInSlot": false,
|
||||
"ExaminedByDefault": true,
|
||||
"ExamineTime": 1,
|
||||
"IsUndiscardable": false,
|
||||
"IsUnsaleable": false,
|
||||
"IsUnbuyable": false,
|
||||
"IsUngivable": false,
|
||||
"IsLockedafterEquip": false,
|
||||
"QuestItem": false,
|
||||
"LootExperience": 10,
|
||||
"ExamineExperience": 3,
|
||||
"HideEntrails": false,
|
||||
"RepairCost": 0,
|
||||
"RepairSpeed": 0,
|
||||
"ExtraSizeLeft": 1,
|
||||
"ExtraSizeRight": 0,
|
||||
"ExtraSizeUp": 0,
|
||||
"ExtraSizeDown": 0,
|
||||
"ExtraSizeForceAdd": false,
|
||||
"MergesWithChildren": true,
|
||||
"CanSellOnRagfair": true,
|
||||
"CanRequireOnRagfair": false,
|
||||
"ConflictingItems": [],
|
||||
"Unlootable": false,
|
||||
"UnlootableFromSlot": "FirstPrimaryWeapon",
|
||||
"UnlootableFromSide": [],
|
||||
"AnimationVariantsNumber": 0,
|
||||
"DiscardingBlock": false,
|
||||
"RagFairCommissionModifier": 1,
|
||||
"IsAlwaysAvailableForInsurance": false,
|
||||
"DiscardLimit": -1,
|
||||
"DropSoundType": "None",
|
||||
"InsuranceDisabled": false,
|
||||
"QuestStashMaxCount": 0,
|
||||
"IsSpecialSlotOnly": false,
|
||||
"IsUnremovable": false,
|
||||
"Grids": [],
|
||||
"Slots": [
|
||||
{
|
||||
"_name": "mod_mount_000",
|
||||
"_id": "5c6d5d8b2e221644fc630b3b",
|
||||
"_parent": "5c6d5d8b2e221644fc630b39",
|
||||
"_props": {
|
||||
"filters": [
|
||||
{
|
||||
"Shift": 0,
|
||||
"Filter": [
|
||||
"5a800961159bd4315e3a1657",
|
||||
"57fd23e32459772d0805bcf1",
|
||||
"544909bb4bdc2d6f028b4577",
|
||||
"5d10b49bd7ad1a1a560708b0",
|
||||
"5c06595c0db834001a66af6c",
|
||||
"5cc9c20cd7f00c001336c65d",
|
||||
"5d2369418abbc306c62e0c80",
|
||||
"5b07dd285acfc4001754240d",
|
||||
"56def37dd2720bec348b456a",
|
||||
"5a7b483fe899ef0016170d15",
|
||||
"61605d88ffa6e502ac5e7eeb",
|
||||
"5a5f1ce64f39f90b401987bc",
|
||||
"560d657b4bdc2da74d8b4572",
|
||||
"5b3a337e5acfc4704b4a19a0",
|
||||
"5c5952732e2216398b5abda2",
|
||||
"57d17e212459775a1179a0f5",
|
||||
"6267c6396b642f77f56f5c1c",
|
||||
"6272370ee4013c5d7e31f418",
|
||||
"6272379924e29f06af4d5ecb",
|
||||
"626becf9582c3e319310b837"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"_required": false,
|
||||
"_mergeSlotWithChildren": false,
|
||||
"_proto": "55d30c4c4bdc2db4468b457e"
|
||||
},
|
||||
{
|
||||
"_name": "mod_mount_001",
|
||||
"_id": "5c6d5d8b2e221644fc630b3c",
|
||||
"_parent": "5c6d5d8b2e221644fc630b39",
|
||||
"_props": {
|
||||
"filters": [
|
||||
{
|
||||
"Shift": 0,
|
||||
"Filter": [
|
||||
"5a800961159bd4315e3a1657",
|
||||
"57fd23e32459772d0805bcf1",
|
||||
"544909bb4bdc2d6f028b4577",
|
||||
"5d10b49bd7ad1a1a560708b0",
|
||||
"5c06595c0db834001a66af6c",
|
||||
"5cc9c20cd7f00c001336c65d",
|
||||
"5d2369418abbc306c62e0c80",
|
||||
"5b07dd285acfc4001754240d",
|
||||
"56def37dd2720bec348b456a",
|
||||
"5a7b483fe899ef0016170d15",
|
||||
"61605d88ffa6e502ac5e7eeb",
|
||||
"5a5f1ce64f39f90b401987bc",
|
||||
"560d657b4bdc2da74d8b4572",
|
||||
"5b3a337e5acfc4704b4a19a0",
|
||||
"5c5952732e2216398b5abda2",
|
||||
"57d17e212459775a1179a0f5",
|
||||
"6267c6396b642f77f56f5c1c",
|
||||
"6272370ee4013c5d7e31f418",
|
||||
"6272379924e29f06af4d5ecb",
|
||||
"626becf9582c3e319310b837"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"_required": false,
|
||||
"_mergeSlotWithChildren": false,
|
||||
"_proto": "55d30c4c4bdc2db4468b457e"
|
||||
},
|
||||
{
|
||||
"_name": "mod_tactical",
|
||||
"_id": "5c6d5d8b2e221644fc630b3e",
|
||||
"_parent": "5c6d5d8b2e221644fc630b39",
|
||||
"_props": {
|
||||
"filters": [
|
||||
{
|
||||
"Shift": 0,
|
||||
"Filter": [
|
||||
"57fd23e32459772d0805bcf1",
|
||||
"544909bb4bdc2d6f028b4577",
|
||||
"5d10b49bd7ad1a1a560708b0",
|
||||
"5c06595c0db834001a66af6c",
|
||||
"5a7b483fe899ef0016170d15",
|
||||
"61605d88ffa6e502ac5e7eeb",
|
||||
"5c5952732e2216398b5abda2"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"_required": false,
|
||||
"_mergeSlotWithChildren": false,
|
||||
"_proto": "55d30c4c4bdc2db4468b457e"
|
||||
},
|
||||
{
|
||||
"_name": "mod_foregrip",
|
||||
"_id": "5c6d5d8b2e221644fc630b40",
|
||||
"_parent": "5c6d5d8b2e221644fc630b39",
|
||||
"_props": {
|
||||
"filters": [
|
||||
{
|
||||
"Shift": 0,
|
||||
"Filter": [
|
||||
"5c7fc87d2e221644f31c0298",
|
||||
"5cda9bcfd7f00c0c0b53e900",
|
||||
"59f8a37386f7747af3328f06",
|
||||
"619386379fb0c665d5490dbe",
|
||||
"5c87ca002e221600114cb150",
|
||||
"588226d124597767ad33f787",
|
||||
"588226dd24597767ad33f789",
|
||||
"588226e62459776e3e094af7",
|
||||
"588226ef24597767af46e39c",
|
||||
"59fc48e086f77463b1118392",
|
||||
"5fce0cf655375d18a253eff0",
|
||||
"5cf4fb76d7f00c065703d3ac",
|
||||
"5b057b4f5acfc4771e1bd3e9",
|
||||
"5c791e872e2216001219c40a",
|
||||
"558032614bdc2de7118b4585",
|
||||
"58c157be86f77403c74b2bb6",
|
||||
"58c157c886f774032749fb06",
|
||||
"5f6340d3ca442212f4047eb2",
|
||||
"591af28e86f77414a27a9e1d",
|
||||
"5c1cd46f2e22164bef5cfedb",
|
||||
"5c1bc4812e22164bef5cfde7",
|
||||
"5c1bc5612e221602b5429350",
|
||||
"5c1bc5af2e221602b412949b",
|
||||
"5c1bc5fb2e221602b1779b32",
|
||||
"5c1bc7432e221602b412949d",
|
||||
"5c1bc7752e221602b1779b34"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"_required": false,
|
||||
"_mergeSlotWithChildren": false,
|
||||
"_proto": "55d30c4c4bdc2db4468b457e"
|
||||
}
|
||||
],
|
||||
"CanPutIntoDuringTheRaid": true,
|
||||
"CantRemoveFromSlotsDuringRaid": [],
|
||||
"Durability": 100,
|
||||
"Accuracy": 0,
|
||||
"Recoil": -1,
|
||||
"Loudness": 0,
|
||||
"EffectiveDistance": 0,
|
||||
"Ergonomics": 8,
|
||||
"Velocity": 0,
|
||||
"RaidModdable": false,
|
||||
"ToolModdable": true,
|
||||
"BlocksFolding": false,
|
||||
"BlocksCollapsible": false,
|
||||
"IsAnimated": false,
|
||||
"HasShoulderContact": false,
|
||||
"SightingRange": 0,
|
||||
"DoubleActionAccuracyPenaltyMult": 1,
|
||||
"HeatFactor": 0.985,
|
||||
"CoolFactor": 1.055
|
||||
},
|
||||
"_proto": "55d459824bdc2d892f8b4573"
|
||||
},
|
||||
"6786e03b67ad44fd9b0fabd1": {
|
||||
"_id": "6786e03b67ad44fd9b0fabd1",
|
||||
"_name": "handguard_guerilla",
|
||||
"_parent": "55818a104bdc2db9688b4569",
|
||||
"_type": "Item",
|
||||
"_props": {
|
||||
"Name": "",
|
||||
"ShortName": "",
|
||||
"Description": "",
|
||||
"Weight": 0.209,
|
||||
"BackgroundColor": "blue",
|
||||
"Width": 2,
|
||||
"Height": 1,
|
||||
"StackMaxSize": 1,
|
||||
"ItemSound": "mod",
|
||||
"Prefab": {
|
||||
"path": "assets/content/items/mods/handguards/handguard_guerilla.bundle",
|
||||
"rcid": ""
|
||||
},
|
||||
"UsePrefab": {
|
||||
"path": "",
|
||||
"rcid": ""
|
||||
},
|
||||
"StackObjectsCount": 1,
|
||||
"NotShownInSlot": false,
|
||||
"ExaminedByDefault": true,
|
||||
"ExamineTime": 1,
|
||||
"IsUndiscardable": false,
|
||||
"IsUnsaleable": false,
|
||||
"IsUnbuyable": false,
|
||||
"IsUngivable": false,
|
||||
"IsLockedafterEquip": false,
|
||||
"QuestItem": false,
|
||||
"LootExperience": 10,
|
||||
"ExamineExperience": 3,
|
||||
"HideEntrails": false,
|
||||
"RepairCost": 0,
|
||||
"RepairSpeed": 0,
|
||||
"ExtraSizeLeft": 1,
|
||||
"ExtraSizeRight": 0,
|
||||
"ExtraSizeUp": 0,
|
||||
"ExtraSizeDown": 0,
|
||||
"ExtraSizeForceAdd": false,
|
||||
"MergesWithChildren": true,
|
||||
"CanSellOnRagfair": true,
|
||||
"CanRequireOnRagfair": false,
|
||||
"ConflictingItems": [],
|
||||
"Unlootable": false,
|
||||
"UnlootableFromSlot": "FirstPrimaryWeapon",
|
||||
"UnlootableFromSide": [],
|
||||
"AnimationVariantsNumber": 0,
|
||||
"DiscardingBlock": false,
|
||||
"RagFairCommissionModifier": 1,
|
||||
"IsAlwaysAvailableForInsurance": false,
|
||||
"DiscardLimit": -1,
|
||||
"DropSoundType": "None",
|
||||
"InsuranceDisabled": false,
|
||||
"QuestStashMaxCount": 0,
|
||||
"IsSpecialSlotOnly": false,
|
||||
"IsUnremovable": false,
|
||||
"Grids": [],
|
||||
"Slots": [
|
||||
{
|
||||
"_name": "mod_mount_001",
|
||||
"_id": "5c6d5d8b2e221644fc630b3c",
|
||||
"_parent": "5c6d5d8b2e221644fc630b39",
|
||||
"_props": {
|
||||
"filters": [
|
||||
{
|
||||
"Shift": 0,
|
||||
"Filter": [
|
||||
"5a800961159bd4315e3a1657",
|
||||
"57fd23e32459772d0805bcf1",
|
||||
"544909bb4bdc2d6f028b4577",
|
||||
"5d10b49bd7ad1a1a560708b0",
|
||||
"5c06595c0db834001a66af6c",
|
||||
"5cc9c20cd7f00c001336c65d",
|
||||
"5d2369418abbc306c62e0c80",
|
||||
"5b07dd285acfc4001754240d",
|
||||
"56def37dd2720bec348b456a",
|
||||
"5a7b483fe899ef0016170d15",
|
||||
"61605d88ffa6e502ac5e7eeb",
|
||||
"5a5f1ce64f39f90b401987bc",
|
||||
"560d657b4bdc2da74d8b4572",
|
||||
"5b3a337e5acfc4704b4a19a0",
|
||||
"5c5952732e2216398b5abda2",
|
||||
"57d17e212459775a1179a0f5",
|
||||
"6267c6396b642f77f56f5c1c",
|
||||
"6272370ee4013c5d7e31f418",
|
||||
"6272379924e29f06af4d5ecb",
|
||||
"626becf9582c3e319310b837"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"_required": false,
|
||||
"_mergeSlotWithChildren": false,
|
||||
"_proto": "55d30c4c4bdc2db4468b457e"
|
||||
},
|
||||
{
|
||||
"_name": "mod_foregrip",
|
||||
"_id": "5c6d5d8b2e221644fc630b40",
|
||||
"_parent": "5c6d5d8b2e221644fc630b39",
|
||||
"_props": {
|
||||
"filters": [
|
||||
{
|
||||
"Shift": 0,
|
||||
"Filter": [
|
||||
"5c7fc87d2e221644f31c0298",
|
||||
"5cda9bcfd7f00c0c0b53e900",
|
||||
"59f8a37386f7747af3328f06",
|
||||
"619386379fb0c665d5490dbe",
|
||||
"5c87ca002e221600114cb150",
|
||||
"588226d124597767ad33f787",
|
||||
"588226dd24597767ad33f789",
|
||||
"588226e62459776e3e094af7",
|
||||
"588226ef24597767af46e39c",
|
||||
"59fc48e086f77463b1118392",
|
||||
"5fce0cf655375d18a253eff0",
|
||||
"5cf4fb76d7f00c065703d3ac",
|
||||
"5b057b4f5acfc4771e1bd3e9",
|
||||
"5c791e872e2216001219c40a",
|
||||
"558032614bdc2de7118b4585",
|
||||
"58c157be86f77403c74b2bb6",
|
||||
"58c157c886f774032749fb06",
|
||||
"5f6340d3ca442212f4047eb2",
|
||||
"591af28e86f77414a27a9e1d",
|
||||
"5c1cd46f2e22164bef5cfedb",
|
||||
"5c1bc4812e22164bef5cfde7",
|
||||
"5c1bc5612e221602b5429350",
|
||||
"5c1bc5af2e221602b412949b",
|
||||
"5c1bc5fb2e221602b1779b32",
|
||||
"5c1bc7432e221602b412949d",
|
||||
"5c1bc7752e221602b1779b34"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"_required": false,
|
||||
"_mergeSlotWithChildren": false,
|
||||
"_proto": "55d30c4c4bdc2db4468b457e"
|
||||
},
|
||||
{
|
||||
"_name": "mod_tactical",
|
||||
"_id": "5c6d5d8b2e221644fc630b3e",
|
||||
"_parent": "5c6d5d8b2e221644fc630b39",
|
||||
"_props": {
|
||||
"filters": [
|
||||
{
|
||||
"Shift": 0,
|
||||
"Filter": [
|
||||
"57fd23e32459772d0805bcf1",
|
||||
"544909bb4bdc2d6f028b4577",
|
||||
"5d10b49bd7ad1a1a560708b0",
|
||||
"5c06595c0db834001a66af6c",
|
||||
"5a7b483fe899ef0016170d15",
|
||||
"61605d88ffa6e502ac5e7eeb",
|
||||
"5c5952732e2216398b5abda2"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"_required": false,
|
||||
"_mergeSlotWithChildren": false,
|
||||
"_proto": "55d30c4c4bdc2db4468b457e"
|
||||
}
|
||||
],
|
||||
"CanPutIntoDuringTheRaid": true,
|
||||
"CantRemoveFromSlotsDuringRaid": [],
|
||||
"Durability": 100,
|
||||
"Accuracy": 0,
|
||||
"Recoil": -1,
|
||||
"Loudness": 0,
|
||||
"EffectiveDistance": 0,
|
||||
"Ergonomics": 8,
|
||||
"Velocity": 0,
|
||||
"RaidModdable": false,
|
||||
"ToolModdable": true,
|
||||
"BlocksFolding": false,
|
||||
"BlocksCollapsible": false,
|
||||
"IsAnimated": false,
|
||||
"HasShoulderContact": false,
|
||||
"SightingRange": 0,
|
||||
"DoubleActionAccuracyPenaltyMult": 1,
|
||||
"HeatFactor": 0.985,
|
||||
"CoolFactor": 1.055
|
||||
},
|
||||
"_proto": "55d459824bdc2d892f8b4573"
|
||||
},
|
||||
"6786e03b67ad44fd9b0fabd2": {
|
||||
"_id": "6786e03b67ad44fd9b0fabd2",
|
||||
"_name": "handguard_turaco",
|
||||
"_parent": "55818a104bdc2db9688b4569",
|
||||
"_type": "Item",
|
||||
"_props": {
|
||||
"Name": "",
|
||||
"ShortName": "",
|
||||
"Description": "",
|
||||
"Weight": 0.209,
|
||||
"BackgroundColor": "blue",
|
||||
"Width": 2,
|
||||
"Height": 1,
|
||||
"StackMaxSize": 1,
|
||||
"ItemSound": "mod",
|
||||
"Prefab": {
|
||||
"path": "assets/content/items/mods/handguards/handguard_turaco.bundle",
|
||||
"rcid": ""
|
||||
},
|
||||
"UsePrefab": {
|
||||
"path": "",
|
||||
"rcid": ""
|
||||
},
|
||||
"StackObjectsCount": 1,
|
||||
"NotShownInSlot": false,
|
||||
"ExaminedByDefault": true,
|
||||
"ExamineTime": 1,
|
||||
"IsUndiscardable": false,
|
||||
"IsUnsaleable": false,
|
||||
"IsUnbuyable": false,
|
||||
"IsUngivable": false,
|
||||
"IsLockedafterEquip": false,
|
||||
"QuestItem": false,
|
||||
"LootExperience": 10,
|
||||
"ExamineExperience": 3,
|
||||
"HideEntrails": false,
|
||||
"RepairCost": 0,
|
||||
"RepairSpeed": 0,
|
||||
"ExtraSizeLeft": 1,
|
||||
"ExtraSizeRight": 0,
|
||||
"ExtraSizeUp": 0,
|
||||
"ExtraSizeDown": 0,
|
||||
"ExtraSizeForceAdd": false,
|
||||
"MergesWithChildren": true,
|
||||
"CanSellOnRagfair": true,
|
||||
"CanRequireOnRagfair": false,
|
||||
"ConflictingItems": [],
|
||||
"Unlootable": false,
|
||||
"UnlootableFromSlot": "FirstPrimaryWeapon",
|
||||
"UnlootableFromSide": [],
|
||||
"AnimationVariantsNumber": 0,
|
||||
"DiscardingBlock": false,
|
||||
"RagFairCommissionModifier": 1,
|
||||
"IsAlwaysAvailableForInsurance": false,
|
||||
"DiscardLimit": -1,
|
||||
"DropSoundType": "None",
|
||||
"InsuranceDisabled": false,
|
||||
"QuestStashMaxCount": 0,
|
||||
"IsSpecialSlotOnly": false,
|
||||
"IsUnremovable": false,
|
||||
"Grids": [],
|
||||
"Slots": [
|
||||
{
|
||||
"_name": "mod_mount_000",
|
||||
"_id": "5c6d5d8b2e221644fc630b3b",
|
||||
"_parent": "5c6d5d8b2e221644fc630b39",
|
||||
"_props": {
|
||||
"filters": [
|
||||
{
|
||||
"Shift": 0,
|
||||
"Filter": [
|
||||
"5a800961159bd4315e3a1657",
|
||||
"57fd23e32459772d0805bcf1",
|
||||
"544909bb4bdc2d6f028b4577",
|
||||
"5d10b49bd7ad1a1a560708b0",
|
||||
"5c06595c0db834001a66af6c",
|
||||
"5cc9c20cd7f00c001336c65d",
|
||||
"5d2369418abbc306c62e0c80",
|
||||
"5b07dd285acfc4001754240d",
|
||||
"56def37dd2720bec348b456a",
|
||||
"5a7b483fe899ef0016170d15",
|
||||
"61605d88ffa6e502ac5e7eeb",
|
||||
"5a5f1ce64f39f90b401987bc",
|
||||
"560d657b4bdc2da74d8b4572",
|
||||
"5b3a337e5acfc4704b4a19a0",
|
||||
"5c5952732e2216398b5abda2",
|
||||
"57d17e212459775a1179a0f5",
|
||||
"6267c6396b642f77f56f5c1c",
|
||||
"6272370ee4013c5d7e31f418",
|
||||
"6272379924e29f06af4d5ecb",
|
||||
"626becf9582c3e319310b837"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"_required": false,
|
||||
"_mergeSlotWithChildren": false,
|
||||
"_proto": "55d30c4c4bdc2db4468b457e"
|
||||
},
|
||||
{
|
||||
"_name": "mod_mount_001",
|
||||
"_id": "5c6d5d8b2e221644fc630b3c",
|
||||
"_parent": "5c6d5d8b2e221644fc630b39",
|
||||
"_props": {
|
||||
"filters": [
|
||||
{
|
||||
"Shift": 0,
|
||||
"Filter": [
|
||||
"5a800961159bd4315e3a1657",
|
||||
"57fd23e32459772d0805bcf1",
|
||||
"544909bb4bdc2d6f028b4577",
|
||||
"5d10b49bd7ad1a1a560708b0",
|
||||
"5c06595c0db834001a66af6c",
|
||||
"5cc9c20cd7f00c001336c65d",
|
||||
"5d2369418abbc306c62e0c80",
|
||||
"5b07dd285acfc4001754240d",
|
||||
"56def37dd2720bec348b456a",
|
||||
"5a7b483fe899ef0016170d15",
|
||||
"61605d88ffa6e502ac5e7eeb",
|
||||
"5a5f1ce64f39f90b401987bc",
|
||||
"560d657b4bdc2da74d8b4572",
|
||||
"5b3a337e5acfc4704b4a19a0",
|
||||
"5c5952732e2216398b5abda2",
|
||||
"57d17e212459775a1179a0f5",
|
||||
"6267c6396b642f77f56f5c1c",
|
||||
"6272370ee4013c5d7e31f418",
|
||||
"6272379924e29f06af4d5ecb",
|
||||
"626becf9582c3e319310b837"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"_required": false,
|
||||
"_mergeSlotWithChildren": false,
|
||||
"_proto": "55d30c4c4bdc2db4468b457e"
|
||||
},
|
||||
{
|
||||
"_name": "mod_tactical",
|
||||
"_id": "5c6d5d8b2e221644fc630b3e",
|
||||
"_parent": "5c6d5d8b2e221644fc630b39",
|
||||
"_props": {
|
||||
"filters": [
|
||||
{
|
||||
"Shift": 0,
|
||||
"Filter": [
|
||||
"57fd23e32459772d0805bcf1",
|
||||
"544909bb4bdc2d6f028b4577",
|
||||
"5d10b49bd7ad1a1a560708b0",
|
||||
"5c06595c0db834001a66af6c",
|
||||
"5a7b483fe899ef0016170d15",
|
||||
"61605d88ffa6e502ac5e7eeb",
|
||||
"5c5952732e2216398b5abda2"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"_required": false,
|
||||
"_mergeSlotWithChildren": false,
|
||||
"_proto": "55d30c4c4bdc2db4468b457e"
|
||||
},
|
||||
{
|
||||
"_name": "mod_foregrip",
|
||||
"_id": "5c6d5d8b2e221644fc630b40",
|
||||
"_parent": "5c6d5d8b2e221644fc630b39",
|
||||
"_props": {
|
||||
"filters": [
|
||||
{
|
||||
"Shift": 0,
|
||||
"Filter": [
|
||||
"5c7fc87d2e221644f31c0298",
|
||||
"5cda9bcfd7f00c0c0b53e900",
|
||||
"59f8a37386f7747af3328f06",
|
||||
"619386379fb0c665d5490dbe",
|
||||
"5c87ca002e221600114cb150",
|
||||
"588226d124597767ad33f787",
|
||||
"588226dd24597767ad33f789",
|
||||
"588226e62459776e3e094af7",
|
||||
"588226ef24597767af46e39c",
|
||||
"59fc48e086f77463b1118392",
|
||||
"5fce0cf655375d18a253eff0",
|
||||
"5cf4fb76d7f00c065703d3ac",
|
||||
"5b057b4f5acfc4771e1bd3e9",
|
||||
"5c791e872e2216001219c40a",
|
||||
"558032614bdc2de7118b4585",
|
||||
"58c157be86f77403c74b2bb6",
|
||||
"58c157c886f774032749fb06",
|
||||
"5f6340d3ca442212f4047eb2",
|
||||
"591af28e86f77414a27a9e1d",
|
||||
"5c1cd46f2e22164bef5cfedb",
|
||||
"5c1bc4812e22164bef5cfde7",
|
||||
"5c1bc5612e221602b5429350",
|
||||
"5c1bc5af2e221602b412949b",
|
||||
"5c1bc5fb2e221602b1779b32",
|
||||
"5c1bc7432e221602b412949d",
|
||||
"5c1bc7752e221602b1779b34",
|
||||
"5a7dbfc1159bd40016548fde"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"_required": false,
|
||||
"_mergeSlotWithChildren": false,
|
||||
"_proto": "55d30c4c4bdc2db4468b457e"
|
||||
}
|
||||
],
|
||||
"CanPutIntoDuringTheRaid": true,
|
||||
"CantRemoveFromSlotsDuringRaid": [],
|
||||
"Durability": 100,
|
||||
"Accuracy": 0,
|
||||
"Recoil": -1,
|
||||
"Loudness": 0,
|
||||
"EffectiveDistance": 0,
|
||||
"Ergonomics": 8,
|
||||
"Velocity": 0,
|
||||
"RaidModdable": false,
|
||||
"ToolModdable": true,
|
||||
"BlocksFolding": false,
|
||||
"BlocksCollapsible": false,
|
||||
"IsAnimated": false,
|
||||
"HasShoulderContact": false,
|
||||
"SightingRange": 0,
|
||||
"DoubleActionAccuracyPenaltyMult": 1,
|
||||
"HeatFactor": 0.985,
|
||||
"CoolFactor": 1.055
|
||||
},
|
||||
"_proto": "55d459824bdc2d892f8b4573"
|
||||
},
|
||||
"6786e03b67ad44fd9b0fabd3": {
|
||||
"_id": "6786e03b67ad44fd9b0fabd3",
|
||||
"_name": "mag_aug_60",
|
||||
"_parent": "5448bc234bdc2d3c308b4569",
|
||||
"_type": "Item",
|
||||
"_props": {
|
||||
"Name": "",
|
||||
"ShortName": "",
|
||||
"Description": "",
|
||||
"Weight": 0.58,
|
||||
"BackgroundColor": "yellow",
|
||||
"Width": 1,
|
||||
"Height": 2,
|
||||
"StackMaxSize": 1,
|
||||
"ItemSound": "mag_plastic",
|
||||
"Prefab": {
|
||||
"path": "assets/content/items/mods/magazines/mag_aug_60.bundle",
|
||||
"rcid": ""
|
||||
},
|
||||
"UsePrefab": {
|
||||
"path": "",
|
||||
"rcid": ""
|
||||
},
|
||||
"StackObjectsCount": 1,
|
||||
"NotShownInSlot": false,
|
||||
"ExaminedByDefault": true,
|
||||
"ExamineTime": 1,
|
||||
"IsUndiscardable": false,
|
||||
"IsUnsaleable": false,
|
||||
"IsUnbuyable": false,
|
||||
"IsUngivable": false,
|
||||
"IsLockedafterEquip": false,
|
||||
"QuestItem": false,
|
||||
"LootExperience": 10,
|
||||
"ExamineExperience": 2,
|
||||
"HideEntrails": false,
|
||||
"RepairCost": 0,
|
||||
"RepairSpeed": 0,
|
||||
"ExtraSizeLeft": 0,
|
||||
"ExtraSizeRight": 0,
|
||||
"ExtraSizeUp": 0,
|
||||
"ExtraSizeDown": 1,
|
||||
"ExtraSizeForceAdd": false,
|
||||
"MergesWithChildren": true,
|
||||
"CanSellOnRagfair": false,
|
||||
"CanRequireOnRagfair": false,
|
||||
"ConflictingItems": [],
|
||||
"Unlootable": false,
|
||||
"UnlootableFromSlot": "FirstPrimaryWeapon",
|
||||
"UnlootableFromSide": [],
|
||||
"AnimationVariantsNumber": 0,
|
||||
"DiscardingBlock": false,
|
||||
"RagFairCommissionModifier": 1,
|
||||
"IsAlwaysAvailableForInsurance": false,
|
||||
"DiscardLimit": -1,
|
||||
"DropSoundType": "None",
|
||||
"InsuranceDisabled": false,
|
||||
"QuestStashMaxCount": 0,
|
||||
"IsSpecialSlotOnly": false,
|
||||
"IsUnremovable": false,
|
||||
"Grids": [],
|
||||
"Slots": [],
|
||||
"CanPutIntoDuringTheRaid": true,
|
||||
"CantRemoveFromSlotsDuringRaid": [],
|
||||
"Durability": 100,
|
||||
"Accuracy": 0,
|
||||
"Recoil": 0,
|
||||
"Loudness": 0,
|
||||
"EffectiveDistance": 0,
|
||||
"Ergonomics": -16,
|
||||
"Velocity": 0,
|
||||
"RaidModdable": true,
|
||||
"ToolModdable": false,
|
||||
"BlocksFolding": false,
|
||||
"BlocksCollapsible": false,
|
||||
"IsAnimated": false,
|
||||
"HasShoulderContact": false,
|
||||
"SightingRange": 0,
|
||||
"DoubleActionAccuracyPenaltyMult": 1,
|
||||
"magAnimationIndex": 5,
|
||||
"Cartridges": [
|
||||
{
|
||||
"_name": "cartridges",
|
||||
"_id": "59c1383d86f774290a37e0cb",
|
||||
"_parent": "59c1383d86f774290a37e0ca",
|
||||
"_max_count": 60,
|
||||
"_props": {
|
||||
"filters": [
|
||||
{
|
||||
"Filter": [
|
||||
"59e6920f86f77411d82aa167",
|
||||
"59e6927d86f77411da468256",
|
||||
"54527a984bdc2d4e668b4567",
|
||||
"54527ac44bdc2d36668b4567",
|
||||
"59e68f6f86f7746c9f75e846",
|
||||
"59e6906286f7746c9f75e847",
|
||||
"59e690b686f7746c9f75e848",
|
||||
"59e6918f86f7746c9f75e849",
|
||||
"60194943740c5d77f6705eea",
|
||||
"601949593ae8f707c4608daa",
|
||||
"5c0d5ae286f7741e46554302",
|
||||
"5fbe3ffdf8b6a877a729ea82",
|
||||
"5fd20ff893a8961fc660a954",
|
||||
"619636be6db0f2477964e710",
|
||||
"6196364158ef8c428c287d9f",
|
||||
"6196365d58ef8c428c287da1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"_proto": "5748538b2459770af276a261"
|
||||
}
|
||||
],
|
||||
"CanFast": true,
|
||||
"CanHit": false,
|
||||
"CanAdmin": false,
|
||||
"LoadUnloadModifier": 60,
|
||||
"CheckTimeModifier": 20,
|
||||
"CheckOverride": 0,
|
||||
"ReloadMagType": "ExternalMagazine",
|
||||
"VisibleAmmoRangesString": "1-3",
|
||||
"MalfunctionChance": 0.3,
|
||||
"TagColor": 0,
|
||||
"TagName": ""
|
||||
},
|
||||
"_proto": "55802d5f4bdc2dac148b458e"
|
||||
}
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
{
|
||||
"traderId":"5935c25fb3acc3127c3d8cd9",
|
||||
"assorts":{
|
||||
"items":[
|
||||
{
|
||||
"_id":"6786e03b67ad44fd9b0fabd0",
|
||||
"_tpl":"6786e03b67ad44fd9b0fabd0",
|
||||
"parentId":"hideout",
|
||||
"slotId":"hideout",
|
||||
"upd":{
|
||||
"UnlimitedCount":true,
|
||||
"StackObjectsCount":999999
|
||||
}
|
||||
},
|
||||
{
|
||||
"_id":"6786e03b67ad44fd9b0fabd1",
|
||||
"_tpl":"6786e03b67ad44fd9b0fabd1",
|
||||
"parentId":"hideout",
|
||||
"slotId":"hideout",
|
||||
"upd":{
|
||||
"UnlimitedCount":true,
|
||||
"StackObjectsCount":999999
|
||||
}
|
||||
},
|
||||
{
|
||||
"_id":"6786e03b67ad44fd9b0fabd2",
|
||||
"_tpl":"6786e03b67ad44fd9b0fabd2",
|
||||
"parentId":"hideout",
|
||||
"slotId":"hideout",
|
||||
"upd":{
|
||||
"UnlimitedCount":true,
|
||||
"StackObjectsCount":999999
|
||||
}
|
||||
},
|
||||
{
|
||||
"_id":"6786e03b67ad44fd9b0fabd3",
|
||||
"_tpl":"6786e03b67ad44fd9b0fabd3",
|
||||
"parentId":"hideout",
|
||||
"slotId":"hideout",
|
||||
"upd":{
|
||||
"UnlimitedCount":true,
|
||||
"StackObjectsCount":999999
|
||||
}
|
||||
}
|
||||
],
|
||||
"barter_scheme":{
|
||||
"6786e03b67ad44fd9b0fabd0":[
|
||||
[
|
||||
{
|
||||
"count":21000,
|
||||
"_tpl":"5449016a4bdc2d6f028b456f"
|
||||
}
|
||||
]
|
||||
],
|
||||
"6786e03b67ad44fd9b0fabd1":[
|
||||
[
|
||||
{
|
||||
"count":21000,
|
||||
"_tpl":"5449016a4bdc2d6f028b456f"
|
||||
}
|
||||
]
|
||||
],
|
||||
"6786e03b67ad44fd9b0fabd2":[
|
||||
[
|
||||
{
|
||||
"count":21000,
|
||||
"_tpl":"5449016a4bdc2d6f028b456f"
|
||||
}
|
||||
]
|
||||
],
|
||||
"6786e03b67ad44fd9b0fabd3":[
|
||||
[
|
||||
{
|
||||
"count":21000,
|
||||
"_tpl":"5449016a4bdc2d6f028b456f"
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"loyal_level_items":{
|
||||
"6786e03b67ad44fd9b0fabd0":3,
|
||||
"6786e03b67ad44fd9b0fabd1":3,
|
||||
"6786e03b67ad44fd9b0fabd2":3,
|
||||
"6786e03b67ad44fd9b0fabd3":3
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,103 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
let mydb;
|
||||
|
||||
class Mod {
|
||||
postDBLoad(container) {
|
||||
// Credit Banner
|
||||
console.log(`
|
||||
=======================================
|
||||
| AUG Attachment Pack |
|
||||
| Created by: KoKaZ93 |
|
||||
| 3.10 Port made by: GMAK3R |
|
||||
=======================================
|
||||
`);
|
||||
|
||||
const modLoader = container.resolve("PreSptModLoader");
|
||||
const importerUtil = container.resolve("ImporterUtil");
|
||||
const db = container.resolve("DatabaseServer").getTables();
|
||||
const locales = db.locales.global;
|
||||
const items = db.templates.items;
|
||||
const handbook = db.templates.handbook.Items;
|
||||
const peacekeeper = db.traders["5935c25fb3acc3127c3d8cd9"];
|
||||
|
||||
mydb = importerUtil.loadRecursive(`${modLoader.getModPath("AUG_AttachmentPack")}database/`);
|
||||
|
||||
for (const item in mydb.templates.items) {
|
||||
items[item] = mydb.templates.items[item];
|
||||
}
|
||||
|
||||
for (const item of mydb.templates.handbook.Items) {
|
||||
handbook.push(item);
|
||||
}
|
||||
|
||||
for (const item of mydb.traders.assort.assorts.items) {
|
||||
peacekeeper.assort.items.push(item);
|
||||
}
|
||||
|
||||
for (const bc in mydb.traders.assort.assorts.barter_scheme) {
|
||||
peacekeeper.assort.barter_scheme[bc] = mydb.traders.assort.assorts.barter_scheme[bc];
|
||||
}
|
||||
|
||||
for (const level in mydb.traders.assort.assorts.loyal_level_items) {
|
||||
peacekeeper.assort.loyal_level_items[level] = mydb.traders.assort.assorts.loyal_level_items[level];
|
||||
}
|
||||
|
||||
for (const localeID in locales) {
|
||||
if (localeID == "en") {
|
||||
for (const [itemId, template] of Object.entries(mydb.locales.en.templates)) {
|
||||
for (const [key, value] of Object.entries(template)) {
|
||||
locales[localeID][`${itemId} ${key}`] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Mod.addHandguardToFilters(db);
|
||||
Mod.addMagazineToFilters(db);
|
||||
}
|
||||
|
||||
static addHandguardToFilters(db) {
|
||||
const isItemSlotsExist = (item) =>
|
||||
item._props && item._props.Slots && item._props.Slots.length > 0;
|
||||
const attachmentToAdd = ["6786e03b67ad44fd9b0fabd0", "6786e03b67ad44fd9b0fabd1", "6786e03b67ad44fd9b0fabd2"];
|
||||
const attachmentItemId = "634e61b0767cb15c4601a877";
|
||||
|
||||
for (const item of Object.values(db.templates.items)) {
|
||||
if (isItemSlotsExist(item)) {
|
||||
for (const slot of item._props.Slots) {
|
||||
if (slot._props.filters.some((filter) => filter.Filter.includes(attachmentItemId))) {
|
||||
slot._props.filters.forEach((filter) => {
|
||||
if (filter.Filter.includes(attachmentItemId)) {
|
||||
filter.Filter.push(...attachmentToAdd);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static addMagazineToFilters(db) {
|
||||
const isItemSlotsExist = (item) =>
|
||||
item._props && item._props.Slots && item._props.Slots.length > 0;
|
||||
const attachmentToAdd = "6786e03b67ad44fd9b0fabd3";
|
||||
const attachmentItemId = "630e1adbbd357927e4007c09";
|
||||
|
||||
for (const item of Object.values(db.templates.items)) {
|
||||
if (isItemSlotsExist(item)) {
|
||||
for (const slot of item._props.Slots) {
|
||||
if (slot._props.filters.some((filter) => filter.Filter.includes(attachmentItemId))) {
|
||||
slot._props.filters.forEach((filter) => {
|
||||
if (filter.Filter.includes(attachmentItemId)) {
|
||||
filter.Filter.push(attachmentToAdd);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { mod: new Mod() };
|
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
"name": "AUG Attachment Pack",
|
||||
"author": "KoKaZ93",
|
||||
"license": "CC BY-NC-SA 3.0",
|
||||
"version": "1.0.4",
|
||||
"sptVersion": "3.10.x",
|
||||
"main": "mod.js",
|
||||
"isBundleMod": true
|
||||
}
|
|
@ -0,0 +1,402 @@
|
|||
Attribution-NonCommercial-NoDerivatives 4.0 International
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons Corporation ("Creative Commons") is not a law firm and
|
||||
does not provide legal services or legal advice. Distribution of
|
||||
Creative Commons public licenses does not create a lawyer-client or
|
||||
other relationship. Creative Commons makes its licenses and related
|
||||
information available on an "as-is" basis. Creative Commons gives no
|
||||
warranties regarding its licenses, any material licensed under their
|
||||
terms and conditions, or any related information. Creative Commons
|
||||
disclaims all liability for damages resulting from their use to the
|
||||
fullest extent possible.
|
||||
|
||||
Using Creative Commons Public Licenses
|
||||
|
||||
Creative Commons public licenses provide a standard set of terms and
|
||||
conditions that creators and other rights holders may use to share
|
||||
original works of authorship and other material subject to copyright
|
||||
and certain other rights specified in the public license below. The
|
||||
following considerations are for informational purposes only, are not
|
||||
exhaustive, and do not form part of our licenses.
|
||||
|
||||
Considerations for licensors: Our public licenses are
|
||||
intended for use by those authorized to give the public
|
||||
permission to use material in ways otherwise restricted by
|
||||
copyright and certain other rights. Our licenses are
|
||||
irrevocable. Licensors should read and understand the terms
|
||||
and conditions of the license they choose before applying it.
|
||||
Licensors should also secure all rights necessary before
|
||||
applying our licenses so that the public can reuse the
|
||||
material as expected. Licensors should clearly mark any
|
||||
material not subject to the license. This includes other CC-
|
||||
licensed material, or material used under an exception or
|
||||
limitation to copyright. More considerations for licensors:
|
||||
wiki.creativecommons.org/Considerations_for_licensors
|
||||
|
||||
Considerations for the public: By using one of our public
|
||||
licenses, a licensor grants the public permission to use the
|
||||
licensed material under specified terms and conditions. If
|
||||
the licensor's permission is not necessary for any reason--for
|
||||
example, because of any applicable exception or limitation to
|
||||
copyright--then that use is not regulated by the license. Our
|
||||
licenses grant only permissions under copyright and certain
|
||||
other rights that a licensor has authority to grant. Use of
|
||||
the licensed material may still be restricted for other
|
||||
reasons, including because others have copyright or other
|
||||
rights in the material. A licensor may make special requests,
|
||||
such as asking that all changes be marked or described.
|
||||
Although not required by our licenses, you are encouraged to
|
||||
respect those requests where reasonable. More considerations
|
||||
for the public:
|
||||
wiki.creativecommons.org/Considerations_for_licensees
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons Attribution-NonCommercial-NoDerivatives 4.0
|
||||
International Public License
|
||||
|
||||
By exercising the Licensed Rights (defined below), You accept and agree
|
||||
to be bound by the terms and conditions of this Creative Commons
|
||||
Attribution-NonCommercial-NoDerivatives 4.0 International Public
|
||||
License ("Public License"). To the extent this Public License may be
|
||||
interpreted as a contract, You are granted the Licensed Rights in
|
||||
consideration of Your acceptance of these terms and conditions, and the
|
||||
Licensor grants You such rights in consideration of benefits the
|
||||
Licensor receives from making the Licensed Material available under
|
||||
these terms and conditions.
|
||||
|
||||
|
||||
Section 1 -- Definitions.
|
||||
|
||||
a. Adapted Material means material subject to Copyright and Similar
|
||||
Rights that is derived from or based upon the Licensed Material
|
||||
and in which the Licensed Material is translated, altered,
|
||||
arranged, transformed, or otherwise modified in a manner requiring
|
||||
permission under the Copyright and Similar Rights held by the
|
||||
Licensor. For purposes of this Public License, where the Licensed
|
||||
Material is a musical work, performance, or sound recording,
|
||||
Adapted Material is always produced where the Licensed Material is
|
||||
synched in timed relation with a moving image.
|
||||
|
||||
b. Copyright and Similar Rights means copyright and/or similar rights
|
||||
closely related to copyright including, without limitation,
|
||||
performance, broadcast, sound recording, and Sui Generis Database
|
||||
Rights, without regard to how the rights are labeled or
|
||||
categorized. For purposes of this Public License, the rights
|
||||
specified in Section 2(b)(1)-(2) are not Copyright and Similar
|
||||
Rights.
|
||||
|
||||
c. Effective Technological Measures means those measures that, in the
|
||||
absence of proper authority, may not be circumvented under laws
|
||||
fulfilling obligations under Article 11 of the WIPO Copyright
|
||||
Treaty adopted on December 20, 1996, and/or similar international
|
||||
agreements.
|
||||
|
||||
d. Exceptions and Limitations means fair use, fair dealing, and/or
|
||||
any other exception or limitation to Copyright and Similar Rights
|
||||
that applies to Your use of the Licensed Material.
|
||||
|
||||
e. Licensed Material means the artistic or literary work, database,
|
||||
or other material to which the Licensor applied this Public
|
||||
License.
|
||||
|
||||
f. Licensed Rights means the rights granted to You subject to the
|
||||
terms and conditions of this Public License, which are limited to
|
||||
all Copyright and Similar Rights that apply to Your use of the
|
||||
Licensed Material and that the Licensor has authority to license.
|
||||
|
||||
g. Licensor means the individual(s) or entity(ies) granting rights
|
||||
under this Public License.
|
||||
|
||||
h. NonCommercial means not primarily intended for or directed towards
|
||||
commercial advantage or monetary compensation. For purposes of
|
||||
this Public License, the exchange of the Licensed Material for
|
||||
other material subject to Copyright and Similar Rights by digital
|
||||
file-sharing or similar means is NonCommercial provided there is
|
||||
no payment of monetary compensation in connection with the
|
||||
exchange.
|
||||
|
||||
i. Share means to provide material to the public by any means or
|
||||
process that requires permission under the Licensed Rights, such
|
||||
as reproduction, public display, public performance, distribution,
|
||||
dissemination, communication, or importation, and to make material
|
||||
available to the public including in ways that members of the
|
||||
public may access the material from a place and at a time
|
||||
individually chosen by them.
|
||||
|
||||
j. Sui Generis Database Rights means rights other than copyright
|
||||
resulting from Directive 96/9/EC of the European Parliament and of
|
||||
the Council of 11 March 1996 on the legal protection of databases,
|
||||
as amended and/or succeeded, as well as other essentially
|
||||
equivalent rights anywhere in the world.
|
||||
|
||||
k. You means the individual or entity exercising the Licensed Rights
|
||||
under this Public License. Your has a corresponding meaning.
|
||||
|
||||
|
||||
Section 2 -- Scope.
|
||||
|
||||
a. License grant.
|
||||
|
||||
1. Subject to the terms and conditions of this Public License,
|
||||
the Licensor hereby grants You a worldwide, royalty-free,
|
||||
non-sublicensable, non-exclusive, irrevocable license to
|
||||
exercise the Licensed Rights in the Licensed Material to:
|
||||
|
||||
a. reproduce and Share the Licensed Material, in whole or
|
||||
in part, for NonCommercial purposes only; and
|
||||
|
||||
b. produce and reproduce, but not Share, Adapted Material
|
||||
for NonCommercial purposes only.
|
||||
|
||||
2. Exceptions and Limitations. For the avoidance of doubt, where
|
||||
Exceptions and Limitations apply to Your use, this Public
|
||||
License does not apply, and You do not need to comply with
|
||||
its terms and conditions.
|
||||
|
||||
3. Term. The term of this Public License is specified in Section
|
||||
6(a).
|
||||
|
||||
4. Media and formats; technical modifications allowed. The
|
||||
Licensor authorizes You to exercise the Licensed Rights in
|
||||
all media and formats whether now known or hereafter created,
|
||||
and to make technical modifications necessary to do so. The
|
||||
Licensor waives and/or agrees not to assert any right or
|
||||
authority to forbid You from making technical modifications
|
||||
necessary to exercise the Licensed Rights, including
|
||||
technical modifications necessary to circumvent Effective
|
||||
Technological Measures. For purposes of this Public License,
|
||||
simply making modifications authorized by this Section 2(a)
|
||||
(4) never produces Adapted Material.
|
||||
|
||||
5. Downstream recipients.
|
||||
|
||||
a. Offer from the Licensor -- Licensed Material. Every
|
||||
recipient of the Licensed Material automatically
|
||||
receives an offer from the Licensor to exercise the
|
||||
Licensed Rights under the terms and conditions of this
|
||||
Public License.
|
||||
|
||||
b. No downstream restrictions. You may not offer or impose
|
||||
any additional or different terms or conditions on, or
|
||||
apply any Effective Technological Measures to, the
|
||||
Licensed Material if doing so restricts exercise of the
|
||||
Licensed Rights by any recipient of the Licensed
|
||||
Material.
|
||||
|
||||
6. No endorsement. Nothing in this Public License constitutes or
|
||||
may be construed as permission to assert or imply that You
|
||||
are, or that Your use of the Licensed Material is, connected
|
||||
with, or sponsored, endorsed, or granted official status by,
|
||||
the Licensor or others designated to receive attribution as
|
||||
provided in Section 3(a)(1)(A)(i).
|
||||
|
||||
b. Other rights.
|
||||
|
||||
1. Moral rights, such as the right of integrity, are not
|
||||
licensed under this Public License, nor are publicity,
|
||||
privacy, and/or other similar personality rights; however, to
|
||||
the extent possible, the Licensor waives and/or agrees not to
|
||||
assert any such rights held by the Licensor to the limited
|
||||
extent necessary to allow You to exercise the Licensed
|
||||
Rights, but not otherwise.
|
||||
|
||||
2. Patent and trademark rights are not licensed under this
|
||||
Public License.
|
||||
|
||||
3. To the extent possible, the Licensor waives any right to
|
||||
collect royalties from You for the exercise of the Licensed
|
||||
Rights, whether directly or through a collecting society
|
||||
under any voluntary or waivable statutory or compulsory
|
||||
licensing scheme. In all other cases the Licensor expressly
|
||||
reserves any right to collect such royalties, including when
|
||||
the Licensed Material is used other than for NonCommercial
|
||||
purposes.
|
||||
|
||||
|
||||
Section 3 -- License Conditions.
|
||||
|
||||
Your exercise of the Licensed Rights is expressly made subject to the
|
||||
following conditions.
|
||||
|
||||
a. Attribution.
|
||||
|
||||
1. If You Share the Licensed Material, You must:
|
||||
|
||||
a. retain the following if it is supplied by the Licensor
|
||||
with the Licensed Material:
|
||||
|
||||
i. identification of the creator(s) of the Licensed
|
||||
Material and any others designated to receive
|
||||
attribution, in any reasonable manner requested by
|
||||
the Licensor (including by pseudonym if
|
||||
designated);
|
||||
|
||||
ii. a copyright notice;
|
||||
|
||||
iii. a notice that refers to this Public License;
|
||||
|
||||
iv. a notice that refers to the disclaimer of
|
||||
warranties;
|
||||
|
||||
v. a URI or hyperlink to the Licensed Material to the
|
||||
extent reasonably practicable;
|
||||
|
||||
b. indicate if You modified the Licensed Material and
|
||||
retain an indication of any previous modifications; and
|
||||
|
||||
c. indicate the Licensed Material is licensed under this
|
||||
Public License, and include the text of, or the URI or
|
||||
hyperlink to, this Public License.
|
||||
|
||||
For the avoidance of doubt, You do not have permission under
|
||||
this Public License to Share Adapted Material.
|
||||
|
||||
2. You may satisfy the conditions in Section 3(a)(1) in any
|
||||
reasonable manner based on the medium, means, and context in
|
||||
which You Share the Licensed Material. For example, it may be
|
||||
reasonable to satisfy the conditions by providing a URI or
|
||||
hyperlink to a resource that includes the required
|
||||
information.
|
||||
|
||||
3. If requested by the Licensor, You must remove any of the
|
||||
information required by Section 3(a)(1)(A) to the extent
|
||||
reasonably practicable.
|
||||
|
||||
|
||||
Section 4 -- Sui Generis Database Rights.
|
||||
|
||||
Where the Licensed Rights include Sui Generis Database Rights that
|
||||
apply to Your use of the Licensed Material:
|
||||
|
||||
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
|
||||
to extract, reuse, reproduce, and Share all or a substantial
|
||||
portion of the contents of the database for NonCommercial purposes
|
||||
only and provided You do not Share Adapted Material;
|
||||
|
||||
b. if You include all or a substantial portion of the database
|
||||
contents in a database in which You have Sui Generis Database
|
||||
Rights, then the database in which You have Sui Generis Database
|
||||
Rights (but not its individual contents) is Adapted Material; and
|
||||
|
||||
c. You must comply with the conditions in Section 3(a) if You Share
|
||||
all or a substantial portion of the contents of the database.
|
||||
|
||||
For the avoidance of doubt, this Section 4 supplements and does not
|
||||
replace Your obligations under this Public License where the Licensed
|
||||
Rights include other Copyright and Similar Rights.
|
||||
|
||||
|
||||
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
|
||||
|
||||
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
|
||||
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
|
||||
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
|
||||
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
|
||||
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
|
||||
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
|
||||
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
|
||||
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
|
||||
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
|
||||
|
||||
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
|
||||
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
|
||||
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
|
||||
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
|
||||
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
|
||||
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
|
||||
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
|
||||
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
|
||||
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
|
||||
|
||||
c. The disclaimer of warranties and limitation of liability provided
|
||||
above shall be interpreted in a manner that, to the extent
|
||||
possible, most closely approximates an absolute disclaimer and
|
||||
waiver of all liability.
|
||||
|
||||
|
||||
Section 6 -- Term and Termination.
|
||||
|
||||
a. This Public License applies for the term of the Copyright and
|
||||
Similar Rights licensed here. However, if You fail to comply with
|
||||
this Public License, then Your rights under this Public License
|
||||
terminate automatically.
|
||||
|
||||
b. Where Your right to use the Licensed Material has terminated under
|
||||
Section 6(a), it reinstates:
|
||||
|
||||
1. automatically as of the date the violation is cured, provided
|
||||
it is cured within 30 days of Your discovery of the
|
||||
violation; or
|
||||
|
||||
2. upon express reinstatement by the Licensor.
|
||||
|
||||
For the avoidance of doubt, this Section 6(b) does not affect any
|
||||
right the Licensor may have to seek remedies for Your violations
|
||||
of this Public License.
|
||||
|
||||
c. For the avoidance of doubt, the Licensor may also offer the
|
||||
Licensed Material under separate terms or conditions or stop
|
||||
distributing the Licensed Material at any time; however, doing so
|
||||
will not terminate this Public License.
|
||||
|
||||
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
|
||||
License.
|
||||
|
||||
|
||||
Section 7 -- Other Terms and Conditions.
|
||||
|
||||
a. The Licensor shall not be bound by any additional or different
|
||||
terms or conditions communicated by You unless expressly agreed.
|
||||
|
||||
b. Any arrangements, understandings, or agreements regarding the
|
||||
Licensed Material not stated herein are separate from and
|
||||
independent of the terms and conditions of this Public License.
|
||||
|
||||
|
||||
Section 8 -- Interpretation.
|
||||
|
||||
a. For the avoidance of doubt, this Public License does not, and
|
||||
shall not be interpreted to, reduce, limit, restrict, or impose
|
||||
conditions on any use of the Licensed Material that could lawfully
|
||||
be made without permission under this Public License.
|
||||
|
||||
b. To the extent possible, if any provision of this Public License is
|
||||
deemed unenforceable, it shall be automatically reformed to the
|
||||
minimum extent necessary to make it enforceable. If the provision
|
||||
cannot be reformed, it shall be severed from this Public License
|
||||
without affecting the enforceability of the remaining terms and
|
||||
conditions.
|
||||
|
||||
c. No term or condition of this Public License will be waived and no
|
||||
failure to comply consented to unless expressly agreed to by the
|
||||
Licensor.
|
||||
|
||||
d. Nothing in this Public License constitutes or may be interpreted
|
||||
as a limitation upon, or waiver of, any privileges and immunities
|
||||
that apply to the Licensor or You, including from the legal
|
||||
processes of any jurisdiction or authority.
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons is not a party to its public
|
||||
licenses. Notwithstanding, Creative Commons may elect to apply one of
|
||||
its public licenses to material it publishes and in those instances
|
||||
will be considered the “Licensor.” The text of the Creative Commons
|
||||
public licenses is dedicated to the public domain under the CC0 Public
|
||||
Domain Dedication. Except for the limited purpose of indicating that
|
||||
material is shared under a Creative Commons public license or as
|
||||
otherwise permitted by the Creative Commons policies published at
|
||||
creativecommons.org/policies, Creative Commons does not authorize the
|
||||
use of the trademark "Creative Commons" or any other trademark or logo
|
||||
of Creative Commons without its prior written consent including,
|
||||
without limitation, in connection with any unauthorized modifications
|
||||
to any of its public licenses or any other arrangements,
|
||||
understandings, or agreements concerning use of licensed material. For
|
||||
the avoidance of doubt, this paragraph does not form part of the
|
||||
public licenses.
|
||||
|
||||
Creative Commons may be contacted at creativecommons.org.
|
Binary file not shown.
|
@ -0,0 +1,28 @@
|
|||
[General]
|
||||
gameName=spt
|
||||
modid=0
|
||||
version=d2025.5.13.0
|
||||
newestVersion=
|
||||
category="-1,"
|
||||
nexusFileStatus=1
|
||||
installationFile=acidphantasm-botplacementsystem.zip
|
||||
repository=
|
||||
ignoredVersion=
|
||||
comments=
|
||||
notes=
|
||||
nexusDescription=
|
||||
url=
|
||||
hasCustomURL=false
|
||||
lastNexusQuery=
|
||||
lastNexusUpdate=
|
||||
nexusLastModified=2025-05-14T12:49:35Z
|
||||
nexusCategory=0
|
||||
converted=false
|
||||
validated=false
|
||||
color=@Variant(\0\0\0\x43\0\xff\xff\0\0\0\0\0\0\0\0)
|
||||
tracked=0
|
||||
|
||||
[installedFiles]
|
||||
1\modid=0
|
||||
1\fileid=0
|
||||
size=1
|
BIN
mods/Acids Bot Placement System/user/mods/acidphantasm-botplacementsystem/ABPSConfig.exe (Stored with Git LFS)
Normal file
BIN
mods/Acids Bot Placement System/user/mods/acidphantasm-botplacementsystem/ABPSConfig.exe (Stored with Git LFS)
Normal file
Binary file not shown.
|
@ -0,0 +1,402 @@
|
|||
Attribution-NonCommercial-NoDerivatives 4.0 International
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons Corporation ("Creative Commons") is not a law firm and
|
||||
does not provide legal services or legal advice. Distribution of
|
||||
Creative Commons public licenses does not create a lawyer-client or
|
||||
other relationship. Creative Commons makes its licenses and related
|
||||
information available on an "as-is" basis. Creative Commons gives no
|
||||
warranties regarding its licenses, any material licensed under their
|
||||
terms and conditions, or any related information. Creative Commons
|
||||
disclaims all liability for damages resulting from their use to the
|
||||
fullest extent possible.
|
||||
|
||||
Using Creative Commons Public Licenses
|
||||
|
||||
Creative Commons public licenses provide a standard set of terms and
|
||||
conditions that creators and other rights holders may use to share
|
||||
original works of authorship and other material subject to copyright
|
||||
and certain other rights specified in the public license below. The
|
||||
following considerations are for informational purposes only, are not
|
||||
exhaustive, and do not form part of our licenses.
|
||||
|
||||
Considerations for licensors: Our public licenses are
|
||||
intended for use by those authorized to give the public
|
||||
permission to use material in ways otherwise restricted by
|
||||
copyright and certain other rights. Our licenses are
|
||||
irrevocable. Licensors should read and understand the terms
|
||||
and conditions of the license they choose before applying it.
|
||||
Licensors should also secure all rights necessary before
|
||||
applying our licenses so that the public can reuse the
|
||||
material as expected. Licensors should clearly mark any
|
||||
material not subject to the license. This includes other CC-
|
||||
licensed material, or material used under an exception or
|
||||
limitation to copyright. More considerations for licensors:
|
||||
wiki.creativecommons.org/Considerations_for_licensors
|
||||
|
||||
Considerations for the public: By using one of our public
|
||||
licenses, a licensor grants the public permission to use the
|
||||
licensed material under specified terms and conditions. If
|
||||
the licensor's permission is not necessary for any reason--for
|
||||
example, because of any applicable exception or limitation to
|
||||
copyright--then that use is not regulated by the license. Our
|
||||
licenses grant only permissions under copyright and certain
|
||||
other rights that a licensor has authority to grant. Use of
|
||||
the licensed material may still be restricted for other
|
||||
reasons, including because others have copyright or other
|
||||
rights in the material. A licensor may make special requests,
|
||||
such as asking that all changes be marked or described.
|
||||
Although not required by our licenses, you are encouraged to
|
||||
respect those requests where reasonable. More considerations
|
||||
for the public:
|
||||
wiki.creativecommons.org/Considerations_for_licensees
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons Attribution-NonCommercial-NoDerivatives 4.0
|
||||
International Public License
|
||||
|
||||
By exercising the Licensed Rights (defined below), You accept and agree
|
||||
to be bound by the terms and conditions of this Creative Commons
|
||||
Attribution-NonCommercial-NoDerivatives 4.0 International Public
|
||||
License ("Public License"). To the extent this Public License may be
|
||||
interpreted as a contract, You are granted the Licensed Rights in
|
||||
consideration of Your acceptance of these terms and conditions, and the
|
||||
Licensor grants You such rights in consideration of benefits the
|
||||
Licensor receives from making the Licensed Material available under
|
||||
these terms and conditions.
|
||||
|
||||
|
||||
Section 1 -- Definitions.
|
||||
|
||||
a. Adapted Material means material subject to Copyright and Similar
|
||||
Rights that is derived from or based upon the Licensed Material
|
||||
and in which the Licensed Material is translated, altered,
|
||||
arranged, transformed, or otherwise modified in a manner requiring
|
||||
permission under the Copyright and Similar Rights held by the
|
||||
Licensor. For purposes of this Public License, where the Licensed
|
||||
Material is a musical work, performance, or sound recording,
|
||||
Adapted Material is always produced where the Licensed Material is
|
||||
synched in timed relation with a moving image.
|
||||
|
||||
b. Copyright and Similar Rights means copyright and/or similar rights
|
||||
closely related to copyright including, without limitation,
|
||||
performance, broadcast, sound recording, and Sui Generis Database
|
||||
Rights, without regard to how the rights are labeled or
|
||||
categorized. For purposes of this Public License, the rights
|
||||
specified in Section 2(b)(1)-(2) are not Copyright and Similar
|
||||
Rights.
|
||||
|
||||
c. Effective Technological Measures means those measures that, in the
|
||||
absence of proper authority, may not be circumvented under laws
|
||||
fulfilling obligations under Article 11 of the WIPO Copyright
|
||||
Treaty adopted on December 20, 1996, and/or similar international
|
||||
agreements.
|
||||
|
||||
d. Exceptions and Limitations means fair use, fair dealing, and/or
|
||||
any other exception or limitation to Copyright and Similar Rights
|
||||
that applies to Your use of the Licensed Material.
|
||||
|
||||
e. Licensed Material means the artistic or literary work, database,
|
||||
or other material to which the Licensor applied this Public
|
||||
License.
|
||||
|
||||
f. Licensed Rights means the rights granted to You subject to the
|
||||
terms and conditions of this Public License, which are limited to
|
||||
all Copyright and Similar Rights that apply to Your use of the
|
||||
Licensed Material and that the Licensor has authority to license.
|
||||
|
||||
g. Licensor means the individual(s) or entity(ies) granting rights
|
||||
under this Public License.
|
||||
|
||||
h. NonCommercial means not primarily intended for or directed towards
|
||||
commercial advantage or monetary compensation. For purposes of
|
||||
this Public License, the exchange of the Licensed Material for
|
||||
other material subject to Copyright and Similar Rights by digital
|
||||
file-sharing or similar means is NonCommercial provided there is
|
||||
no payment of monetary compensation in connection with the
|
||||
exchange.
|
||||
|
||||
i. Share means to provide material to the public by any means or
|
||||
process that requires permission under the Licensed Rights, such
|
||||
as reproduction, public display, public performance, distribution,
|
||||
dissemination, communication, or importation, and to make material
|
||||
available to the public including in ways that members of the
|
||||
public may access the material from a place and at a time
|
||||
individually chosen by them.
|
||||
|
||||
j. Sui Generis Database Rights means rights other than copyright
|
||||
resulting from Directive 96/9/EC of the European Parliament and of
|
||||
the Council of 11 March 1996 on the legal protection of databases,
|
||||
as amended and/or succeeded, as well as other essentially
|
||||
equivalent rights anywhere in the world.
|
||||
|
||||
k. You means the individual or entity exercising the Licensed Rights
|
||||
under this Public License. Your has a corresponding meaning.
|
||||
|
||||
|
||||
Section 2 -- Scope.
|
||||
|
||||
a. License grant.
|
||||
|
||||
1. Subject to the terms and conditions of this Public License,
|
||||
the Licensor hereby grants You a worldwide, royalty-free,
|
||||
non-sublicensable, non-exclusive, irrevocable license to
|
||||
exercise the Licensed Rights in the Licensed Material to:
|
||||
|
||||
a. reproduce and Share the Licensed Material, in whole or
|
||||
in part, for NonCommercial purposes only; and
|
||||
|
||||
b. produce and reproduce, but not Share, Adapted Material
|
||||
for NonCommercial purposes only.
|
||||
|
||||
2. Exceptions and Limitations. For the avoidance of doubt, where
|
||||
Exceptions and Limitations apply to Your use, this Public
|
||||
License does not apply, and You do not need to comply with
|
||||
its terms and conditions.
|
||||
|
||||
3. Term. The term of this Public License is specified in Section
|
||||
6(a).
|
||||
|
||||
4. Media and formats; technical modifications allowed. The
|
||||
Licensor authorizes You to exercise the Licensed Rights in
|
||||
all media and formats whether now known or hereafter created,
|
||||
and to make technical modifications necessary to do so. The
|
||||
Licensor waives and/or agrees not to assert any right or
|
||||
authority to forbid You from making technical modifications
|
||||
necessary to exercise the Licensed Rights, including
|
||||
technical modifications necessary to circumvent Effective
|
||||
Technological Measures. For purposes of this Public License,
|
||||
simply making modifications authorized by this Section 2(a)
|
||||
(4) never produces Adapted Material.
|
||||
|
||||
5. Downstream recipients.
|
||||
|
||||
a. Offer from the Licensor -- Licensed Material. Every
|
||||
recipient of the Licensed Material automatically
|
||||
receives an offer from the Licensor to exercise the
|
||||
Licensed Rights under the terms and conditions of this
|
||||
Public License.
|
||||
|
||||
b. No downstream restrictions. You may not offer or impose
|
||||
any additional or different terms or conditions on, or
|
||||
apply any Effective Technological Measures to, the
|
||||
Licensed Material if doing so restricts exercise of the
|
||||
Licensed Rights by any recipient of the Licensed
|
||||
Material.
|
||||
|
||||
6. No endorsement. Nothing in this Public License constitutes or
|
||||
may be construed as permission to assert or imply that You
|
||||
are, or that Your use of the Licensed Material is, connected
|
||||
with, or sponsored, endorsed, or granted official status by,
|
||||
the Licensor or others designated to receive attribution as
|
||||
provided in Section 3(a)(1)(A)(i).
|
||||
|
||||
b. Other rights.
|
||||
|
||||
1. Moral rights, such as the right of integrity, are not
|
||||
licensed under this Public License, nor are publicity,
|
||||
privacy, and/or other similar personality rights; however, to
|
||||
the extent possible, the Licensor waives and/or agrees not to
|
||||
assert any such rights held by the Licensor to the limited
|
||||
extent necessary to allow You to exercise the Licensed
|
||||
Rights, but not otherwise.
|
||||
|
||||
2. Patent and trademark rights are not licensed under this
|
||||
Public License.
|
||||
|
||||
3. To the extent possible, the Licensor waives any right to
|
||||
collect royalties from You for the exercise of the Licensed
|
||||
Rights, whether directly or through a collecting society
|
||||
under any voluntary or waivable statutory or compulsory
|
||||
licensing scheme. In all other cases the Licensor expressly
|
||||
reserves any right to collect such royalties, including when
|
||||
the Licensed Material is used other than for NonCommercial
|
||||
purposes.
|
||||
|
||||
|
||||
Section 3 -- License Conditions.
|
||||
|
||||
Your exercise of the Licensed Rights is expressly made subject to the
|
||||
following conditions.
|
||||
|
||||
a. Attribution.
|
||||
|
||||
1. If You Share the Licensed Material, You must:
|
||||
|
||||
a. retain the following if it is supplied by the Licensor
|
||||
with the Licensed Material:
|
||||
|
||||
i. identification of the creator(s) of the Licensed
|
||||
Material and any others designated to receive
|
||||
attribution, in any reasonable manner requested by
|
||||
the Licensor (including by pseudonym if
|
||||
designated);
|
||||
|
||||
ii. a copyright notice;
|
||||
|
||||
iii. a notice that refers to this Public License;
|
||||
|
||||
iv. a notice that refers to the disclaimer of
|
||||
warranties;
|
||||
|
||||
v. a URI or hyperlink to the Licensed Material to the
|
||||
extent reasonably practicable;
|
||||
|
||||
b. indicate if You modified the Licensed Material and
|
||||
retain an indication of any previous modifications; and
|
||||
|
||||
c. indicate the Licensed Material is licensed under this
|
||||
Public License, and include the text of, or the URI or
|
||||
hyperlink to, this Public License.
|
||||
|
||||
For the avoidance of doubt, You do not have permission under
|
||||
this Public License to Share Adapted Material.
|
||||
|
||||
2. You may satisfy the conditions in Section 3(a)(1) in any
|
||||
reasonable manner based on the medium, means, and context in
|
||||
which You Share the Licensed Material. For example, it may be
|
||||
reasonable to satisfy the conditions by providing a URI or
|
||||
hyperlink to a resource that includes the required
|
||||
information.
|
||||
|
||||
3. If requested by the Licensor, You must remove any of the
|
||||
information required by Section 3(a)(1)(A) to the extent
|
||||
reasonably practicable.
|
||||
|
||||
|
||||
Section 4 -- Sui Generis Database Rights.
|
||||
|
||||
Where the Licensed Rights include Sui Generis Database Rights that
|
||||
apply to Your use of the Licensed Material:
|
||||
|
||||
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
|
||||
to extract, reuse, reproduce, and Share all or a substantial
|
||||
portion of the contents of the database for NonCommercial purposes
|
||||
only and provided You do not Share Adapted Material;
|
||||
|
||||
b. if You include all or a substantial portion of the database
|
||||
contents in a database in which You have Sui Generis Database
|
||||
Rights, then the database in which You have Sui Generis Database
|
||||
Rights (but not its individual contents) is Adapted Material; and
|
||||
|
||||
c. You must comply with the conditions in Section 3(a) if You Share
|
||||
all or a substantial portion of the contents of the database.
|
||||
|
||||
For the avoidance of doubt, this Section 4 supplements and does not
|
||||
replace Your obligations under this Public License where the Licensed
|
||||
Rights include other Copyright and Similar Rights.
|
||||
|
||||
|
||||
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
|
||||
|
||||
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
|
||||
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
|
||||
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
|
||||
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
|
||||
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
|
||||
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
|
||||
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
|
||||
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
|
||||
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
|
||||
|
||||
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
|
||||
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
|
||||
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
|
||||
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
|
||||
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
|
||||
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
|
||||
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
|
||||
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
|
||||
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
|
||||
|
||||
c. The disclaimer of warranties and limitation of liability provided
|
||||
above shall be interpreted in a manner that, to the extent
|
||||
possible, most closely approximates an absolute disclaimer and
|
||||
waiver of all liability.
|
||||
|
||||
|
||||
Section 6 -- Term and Termination.
|
||||
|
||||
a. This Public License applies for the term of the Copyright and
|
||||
Similar Rights licensed here. However, if You fail to comply with
|
||||
this Public License, then Your rights under this Public License
|
||||
terminate automatically.
|
||||
|
||||
b. Where Your right to use the Licensed Material has terminated under
|
||||
Section 6(a), it reinstates:
|
||||
|
||||
1. automatically as of the date the violation is cured, provided
|
||||
it is cured within 30 days of Your discovery of the
|
||||
violation; or
|
||||
|
||||
2. upon express reinstatement by the Licensor.
|
||||
|
||||
For the avoidance of doubt, this Section 6(b) does not affect any
|
||||
right the Licensor may have to seek remedies for Your violations
|
||||
of this Public License.
|
||||
|
||||
c. For the avoidance of doubt, the Licensor may also offer the
|
||||
Licensed Material under separate terms or conditions or stop
|
||||
distributing the Licensed Material at any time; however, doing so
|
||||
will not terminate this Public License.
|
||||
|
||||
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
|
||||
License.
|
||||
|
||||
|
||||
Section 7 -- Other Terms and Conditions.
|
||||
|
||||
a. The Licensor shall not be bound by any additional or different
|
||||
terms or conditions communicated by You unless expressly agreed.
|
||||
|
||||
b. Any arrangements, understandings, or agreements regarding the
|
||||
Licensed Material not stated herein are separate from and
|
||||
independent of the terms and conditions of this Public License.
|
||||
|
||||
|
||||
Section 8 -- Interpretation.
|
||||
|
||||
a. For the avoidance of doubt, this Public License does not, and
|
||||
shall not be interpreted to, reduce, limit, restrict, or impose
|
||||
conditions on any use of the Licensed Material that could lawfully
|
||||
be made without permission under this Public License.
|
||||
|
||||
b. To the extent possible, if any provision of this Public License is
|
||||
deemed unenforceable, it shall be automatically reformed to the
|
||||
minimum extent necessary to make it enforceable. If the provision
|
||||
cannot be reformed, it shall be severed from this Public License
|
||||
without affecting the enforceability of the remaining terms and
|
||||
conditions.
|
||||
|
||||
c. No term or condition of this Public License will be waived and no
|
||||
failure to comply consented to unless expressly agreed to by the
|
||||
Licensor.
|
||||
|
||||
d. Nothing in this Public License constitutes or may be interpreted
|
||||
as a limitation upon, or waiver of, any privileges and immunities
|
||||
that apply to the Licensor or You, including from the legal
|
||||
processes of any jurisdiction or authority.
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons is not a party to its public
|
||||
licenses. Notwithstanding, Creative Commons may elect to apply one of
|
||||
its public licenses to material it publishes and in those instances
|
||||
will be considered the “Licensor.” The text of the Creative Commons
|
||||
public licenses is dedicated to the public domain under the CC0 Public
|
||||
Domain Dedication. Except for the limited purpose of indicating that
|
||||
material is shared under a Creative Commons public license or as
|
||||
otherwise permitted by the Creative Commons policies published at
|
||||
creativecommons.org/policies, Creative Commons does not authorize the
|
||||
use of the trademark "Creative Commons" or any other trademark or logo
|
||||
of Creative Commons without its prior written consent including,
|
||||
without limitation, in connection with any unauthorized modifications
|
||||
to any of its public licenses or any other arrangements,
|
||||
understandings, or agreements concerning use of licensed material. For
|
||||
the avoidance of doubt, this paragraph does not form part of the
|
||||
public licenses.
|
||||
|
||||
Creative Commons may be contacted at creativecommons.org.
|
|
@ -0,0 +1,640 @@
|
|||
{
|
||||
"pmcDifficulty": {
|
||||
"easy": 10,
|
||||
"normal": 50,
|
||||
"hard": 30,
|
||||
"impossible": 10
|
||||
},
|
||||
"pmcConfig": {
|
||||
"startingPMCs": {
|
||||
"enable": true,
|
||||
"ignoreMaxBotCaps": true,
|
||||
"groupChance": 25,
|
||||
"maxGroupSize": 3,
|
||||
"maxGroupCount": 4,
|
||||
"mapLimits": {
|
||||
"bigmap": {
|
||||
"min": 8,
|
||||
"max": 10
|
||||
},
|
||||
"factory4_day": {
|
||||
"min": 5,
|
||||
"max": 7
|
||||
},
|
||||
"factory4_night": {
|
||||
"min": 5,
|
||||
"max": 7
|
||||
},
|
||||
"interchange": {
|
||||
"min": 9,
|
||||
"max": 13
|
||||
},
|
||||
"laboratory": {
|
||||
"min": 7,
|
||||
"max": 9
|
||||
},
|
||||
"lighthouse": {
|
||||
"min": 7,
|
||||
"max": 10
|
||||
},
|
||||
"rezervbase": {
|
||||
"min": 8,
|
||||
"max": 10
|
||||
},
|
||||
"sandbox": {
|
||||
"min": 8,
|
||||
"max": 11
|
||||
},
|
||||
"sandbox_high": {
|
||||
"min": 8,
|
||||
"max": 11
|
||||
},
|
||||
"shoreline": {
|
||||
"min": 9,
|
||||
"max": 13
|
||||
},
|
||||
"tarkovstreets": {
|
||||
"min": 7,
|
||||
"max": 10
|
||||
},
|
||||
"woods": {
|
||||
"min": 9,
|
||||
"max": 13
|
||||
}
|
||||
}
|
||||
},
|
||||
"waves": {
|
||||
"enable": false,
|
||||
"ignoreMaxBotCaps": false,
|
||||
"groupChance": 10,
|
||||
"maxGroupSize": 2,
|
||||
"maxGroupCount": 3,
|
||||
"maxBotsPerWave": 5,
|
||||
"delayBeforeFirstWave": 500,
|
||||
"secondsBetweenWaves": 360,
|
||||
"stopWavesBeforeEndOfRaidLimit": 300
|
||||
}
|
||||
},
|
||||
"scavConfig": {
|
||||
"startingScavs": {
|
||||
"enable": true,
|
||||
"maxBotSpawns": {
|
||||
"bigmap": 5,
|
||||
"factory4_day": 3,
|
||||
"factory4_night": 3,
|
||||
"interchange": 5,
|
||||
"laboratory": 0,
|
||||
"lighthouse": 5,
|
||||
"rezervbase": 5,
|
||||
"sandbox": 5,
|
||||
"sandbox_high": 5,
|
||||
"shoreline": 5,
|
||||
"tarkovstreets": 5,
|
||||
"woods": 5
|
||||
},
|
||||
"maxBotsPerZone": 1,
|
||||
"startingMarksman": true
|
||||
},
|
||||
"waves": {
|
||||
"enable": true,
|
||||
"enableCustomFactory": true,
|
||||
"startSpawns": 60,
|
||||
"stopSpawns": 600,
|
||||
"activeTimeMin": 180,
|
||||
"activeTimeMax": 240,
|
||||
"quietTimeMin": 120,
|
||||
"quietTimeMax": 180,
|
||||
"checkToSpawnTimer": 15,
|
||||
"pendingBotsToTrigger": 3
|
||||
}
|
||||
},
|
||||
"bossDifficulty": {
|
||||
"easy": 0,
|
||||
"normal": 60,
|
||||
"hard": 30,
|
||||
"impossible": 10
|
||||
},
|
||||
"bossConfig": {
|
||||
"bossKnight": {
|
||||
"enable": true,
|
||||
"time": -1,
|
||||
"spawnChance": {
|
||||
"bigmap": 30,
|
||||
"factory4_day": 0,
|
||||
"factory4_night": 0,
|
||||
"interchange": 0,
|
||||
"laboratory": 0,
|
||||
"lighthouse": 30,
|
||||
"rezervbase": 0,
|
||||
"sandbox": 0,
|
||||
"sandbox_high": 0,
|
||||
"shoreline": 30,
|
||||
"tarkovstreets": 0,
|
||||
"woods": 30
|
||||
},
|
||||
"bossZone": {
|
||||
"bigmap": "ZoneScavBase",
|
||||
"factory4_day": "",
|
||||
"factory4_night": "",
|
||||
"interchange": "",
|
||||
"laboratory": "",
|
||||
"lighthouse": "Zone_TreatmentContainers,Zone_Chalet",
|
||||
"rezervbase": "",
|
||||
"sandbox": "",
|
||||
"sandbox_high": "",
|
||||
"shoreline": "ZoneMeteoStation",
|
||||
"tarkovstreets": "",
|
||||
"woods": "ZoneScavBase2"
|
||||
}
|
||||
},
|
||||
"bossBully": {
|
||||
"enable": true,
|
||||
"time": -1,
|
||||
"spawnChance": {
|
||||
"bigmap": 30,
|
||||
"factory4_day": 0,
|
||||
"factory4_night": 0,
|
||||
"interchange": 0,
|
||||
"laboratory": 0,
|
||||
"lighthouse": 0,
|
||||
"rezervbase": 0,
|
||||
"sandbox": 0,
|
||||
"sandbox_high": 0,
|
||||
"shoreline": 0,
|
||||
"tarkovstreets": 0,
|
||||
"woods": 0
|
||||
},
|
||||
"bossZone": {
|
||||
"bigmap": "ZoneDormitory,ZoneGasStation,ZoneScavBase",
|
||||
"factory4_day": "",
|
||||
"factory4_night": "",
|
||||
"interchange": "",
|
||||
"laboratory": "",
|
||||
"lighthouse": "",
|
||||
"rezervbase": "",
|
||||
"sandbox": "",
|
||||
"sandbox_high": "",
|
||||
"shoreline": "",
|
||||
"tarkovstreets": "",
|
||||
"woods": ""
|
||||
}
|
||||
},
|
||||
"bossTagilla": {
|
||||
"enable": true,
|
||||
"time": -1,
|
||||
"spawnChance": {
|
||||
"bigmap": 0,
|
||||
"factory4_day": 30,
|
||||
"factory4_night": 30,
|
||||
"interchange": 0,
|
||||
"laboratory": 0,
|
||||
"lighthouse": 0,
|
||||
"rezervbase": 0,
|
||||
"sandbox": 0,
|
||||
"sandbox_high": 0,
|
||||
"shoreline": 0,
|
||||
"tarkovstreets": 0,
|
||||
"woods": 0
|
||||
},
|
||||
"bossZone": {
|
||||
"bigmap": "",
|
||||
"factory4_day": "BotZone",
|
||||
"factory4_night": "BotZone",
|
||||
"interchange": "",
|
||||
"laboratory": "",
|
||||
"lighthouse": "",
|
||||
"rezervbase": "",
|
||||
"sandbox": "",
|
||||
"sandbox_high": "",
|
||||
"shoreline": "",
|
||||
"tarkovstreets": "",
|
||||
"woods": ""
|
||||
}
|
||||
},
|
||||
"bossKilla": {
|
||||
"enable": true,
|
||||
"time": -1,
|
||||
"spawnChance": {
|
||||
"bigmap": 0,
|
||||
"factory4_day": 0,
|
||||
"factory4_night": 0,
|
||||
"interchange": 30,
|
||||
"laboratory": 0,
|
||||
"lighthouse": 0,
|
||||
"rezervbase": 0,
|
||||
"sandbox": 0,
|
||||
"sandbox_high": 0,
|
||||
"shoreline": 0,
|
||||
"tarkovstreets": 0,
|
||||
"woods": 0
|
||||
},
|
||||
"bossZone": {
|
||||
"bigmap": "",
|
||||
"factory4_day": "",
|
||||
"factory4_night": "",
|
||||
"interchange": "ZoneCenterBot,ZoneCenter,ZoneOLI,ZoneIDEA,ZoneGoshan",
|
||||
"laboratory": "",
|
||||
"lighthouse": "",
|
||||
"rezervbase": "",
|
||||
"sandbox": "",
|
||||
"sandbox_high": "",
|
||||
"shoreline": "",
|
||||
"tarkovstreets": "",
|
||||
"woods": ""
|
||||
}
|
||||
},
|
||||
"bossZryachiy": {
|
||||
"enable": true,
|
||||
"time": -1,
|
||||
"spawnChance": {
|
||||
"bigmap": 0,
|
||||
"factory4_day": 0,
|
||||
"factory4_night": 0,
|
||||
"interchange": 0,
|
||||
"laboratory": 0,
|
||||
"lighthouse": 100,
|
||||
"rezervbase": 0,
|
||||
"sandbox": 0,
|
||||
"sandbox_high": 0,
|
||||
"shoreline": 0,
|
||||
"tarkovstreets": 0,
|
||||
"woods": 0
|
||||
},
|
||||
"bossZone": {
|
||||
"bigmap": "",
|
||||
"factory4_day": "",
|
||||
"factory4_night": "",
|
||||
"interchange": "",
|
||||
"laboratory": "",
|
||||
"lighthouse": "Zone_Island",
|
||||
"rezervbase": "",
|
||||
"sandbox": "",
|
||||
"sandbox_high": "",
|
||||
"shoreline": "",
|
||||
"tarkovstreets": "",
|
||||
"woods": ""
|
||||
}
|
||||
},
|
||||
"bossGluhar": {
|
||||
"enable": true,
|
||||
"time": -1,
|
||||
"spawnChance": {
|
||||
"bigmap": 0,
|
||||
"factory4_day": 0,
|
||||
"factory4_night": 0,
|
||||
"interchange": 0,
|
||||
"laboratory": 0,
|
||||
"lighthouse": 0,
|
||||
"rezervbase": 30,
|
||||
"sandbox": 0,
|
||||
"sandbox_high": 0,
|
||||
"shoreline": 0,
|
||||
"tarkovstreets": 0,
|
||||
"woods": 0
|
||||
},
|
||||
"bossZone": {
|
||||
"bigmap": "",
|
||||
"factory4_day": "",
|
||||
"factory4_night": "",
|
||||
"interchange": "",
|
||||
"laboratory": "",
|
||||
"lighthouse": "",
|
||||
"rezervbase": "ZoneRailStrorage,ZonePTOR2,ZoneBarrack,ZoneSubStorage",
|
||||
"sandbox": "",
|
||||
"sandbox_high": "",
|
||||
"shoreline": "",
|
||||
"tarkovstreets": "",
|
||||
"woods": ""
|
||||
}
|
||||
},
|
||||
"bossSanitar": {
|
||||
"enable": true,
|
||||
"time": -1,
|
||||
"spawnChance": {
|
||||
"bigmap": 0,
|
||||
"factory4_day": 0,
|
||||
"factory4_night": 0,
|
||||
"interchange": 0,
|
||||
"laboratory": 0,
|
||||
"lighthouse": 0,
|
||||
"rezervbase": 0,
|
||||
"sandbox": 0,
|
||||
"sandbox_high": 0,
|
||||
"shoreline": 30,
|
||||
"tarkovstreets": 0,
|
||||
"woods": 0
|
||||
},
|
||||
"bossZone": {
|
||||
"bigmap": "",
|
||||
"factory4_day": "",
|
||||
"factory4_night": "",
|
||||
"interchange": "",
|
||||
"laboratory": "",
|
||||
"lighthouse": "",
|
||||
"rezervbase": "",
|
||||
"sandbox": "",
|
||||
"sandbox_high": "",
|
||||
"shoreline": "ZoneGreenHouses,ZoneSanatorium1,ZoneSanatorium2,ZonePort",
|
||||
"tarkovstreets": "",
|
||||
"woods": ""
|
||||
}
|
||||
},
|
||||
"bossKolontay": {
|
||||
"enable": true,
|
||||
"time": -1,
|
||||
"spawnChance": {
|
||||
"bigmap": 0,
|
||||
"factory4_day": 0,
|
||||
"factory4_night": 0,
|
||||
"interchange": 0,
|
||||
"laboratory": 0,
|
||||
"lighthouse": 0,
|
||||
"rezervbase": 0,
|
||||
"sandbox": 0,
|
||||
"sandbox_high": 30,
|
||||
"shoreline": 0,
|
||||
"tarkovstreets": 30,
|
||||
"woods": 0
|
||||
},
|
||||
"bossZone": {
|
||||
"bigmap": "",
|
||||
"factory4_day": "",
|
||||
"factory4_night": "",
|
||||
"interchange": "",
|
||||
"laboratory": "",
|
||||
"lighthouse": "",
|
||||
"rezervbase": "",
|
||||
"sandbox": "",
|
||||
"sandbox_high": "ZoneSandbox",
|
||||
"shoreline": "",
|
||||
"tarkovstreets": "ZoneClimova,ZoneMvd",
|
||||
"woods": ""
|
||||
}
|
||||
},
|
||||
"bossBoar": {
|
||||
"enable": true,
|
||||
"time": -1,
|
||||
"spawnChance": {
|
||||
"bigmap": 0,
|
||||
"factory4_day": 0,
|
||||
"factory4_night": 0,
|
||||
"interchange": 0,
|
||||
"laboratory": 0,
|
||||
"lighthouse": 0,
|
||||
"rezervbase": 0,
|
||||
"sandbox": 0,
|
||||
"sandbox_high": 0,
|
||||
"shoreline": 0,
|
||||
"tarkovstreets": 30,
|
||||
"woods": 0
|
||||
},
|
||||
"bossZone": {
|
||||
"bigmap": "",
|
||||
"factory4_day": "",
|
||||
"factory4_night": "",
|
||||
"interchange": "",
|
||||
"laboratory": "",
|
||||
"lighthouse": "",
|
||||
"rezervbase": "",
|
||||
"sandbox": "",
|
||||
"sandbox_high": "",
|
||||
"shoreline": "",
|
||||
"tarkovstreets": "ZoneCarShowroom",
|
||||
"woods": ""
|
||||
}
|
||||
},
|
||||
"bossKojaniy": {
|
||||
"enable": true,
|
||||
"time": -1,
|
||||
"spawnChance": {
|
||||
"bigmap": 0,
|
||||
"factory4_day": 0,
|
||||
"factory4_night": 0,
|
||||
"interchange": 0,
|
||||
"laboratory": 0,
|
||||
"lighthouse": 0,
|
||||
"rezervbase": 0,
|
||||
"sandbox": 0,
|
||||
"sandbox_high": 0,
|
||||
"shoreline": 0,
|
||||
"tarkovstreets": 0,
|
||||
"woods": 30
|
||||
},
|
||||
"bossZone": {
|
||||
"bigmap": "",
|
||||
"factory4_day": "",
|
||||
"factory4_night": "",
|
||||
"interchange": "",
|
||||
"laboratory": "",
|
||||
"lighthouse": "",
|
||||
"rezervbase": "",
|
||||
"sandbox": "",
|
||||
"sandbox_high": "",
|
||||
"shoreline": "",
|
||||
"tarkovstreets": "",
|
||||
"woods": "ZoneWoodCutter"
|
||||
}
|
||||
},
|
||||
"bossPartisan": {
|
||||
"enable": true,
|
||||
"time": -1,
|
||||
"spawnChance": {
|
||||
"bigmap": 30,
|
||||
"factory4_day": 0,
|
||||
"factory4_night": 0,
|
||||
"interchange": 0,
|
||||
"laboratory": 0,
|
||||
"lighthouse": 30,
|
||||
"rezervbase": 0,
|
||||
"sandbox": 0,
|
||||
"sandbox_high": 0,
|
||||
"shoreline": 30,
|
||||
"tarkovstreets": 0,
|
||||
"woods": 30
|
||||
},
|
||||
"bossZone": {
|
||||
"bigmap": "",
|
||||
"factory4_day": "",
|
||||
"factory4_night": "",
|
||||
"interchange": "",
|
||||
"laboratory": "",
|
||||
"lighthouse": "",
|
||||
"rezervbase": "",
|
||||
"sandbox": "",
|
||||
"sandbox_high": "",
|
||||
"shoreline": "",
|
||||
"tarkovstreets": "",
|
||||
"woods": ""
|
||||
}
|
||||
},
|
||||
"sectantPriest": {
|
||||
"enable": true,
|
||||
"time": -1,
|
||||
"spawnChance": {
|
||||
"bigmap": 15,
|
||||
"factory4_day": 0,
|
||||
"factory4_night": 20,
|
||||
"interchange": 0,
|
||||
"laboratory": 0,
|
||||
"lighthouse": 0,
|
||||
"rezervbase": 0,
|
||||
"sandbox": 0,
|
||||
"sandbox_high": 44,
|
||||
"shoreline": 15,
|
||||
"tarkovstreets": 0,
|
||||
"woods": 15
|
||||
},
|
||||
"bossZone": {
|
||||
"bigmap": "ZoneScavBase",
|
||||
"factory4_day": "",
|
||||
"factory4_night": "BotZone",
|
||||
"interchange": "",
|
||||
"laboratory": "",
|
||||
"lighthouse": "",
|
||||
"rezervbase": "",
|
||||
"sandbox": "",
|
||||
"sandbox_high": "ZoneSandbox",
|
||||
"shoreline": "ZoneSanatorium1,ZoneSanatorium2,ZoneForestSpawn",
|
||||
"tarkovstreets": "",
|
||||
"woods": "ZoneMiniHouse,ZoneBrokenVill"
|
||||
}
|
||||
},
|
||||
"arenaFighterEvent": {
|
||||
"enable": true,
|
||||
"time": -1,
|
||||
"spawnChance": {
|
||||
"bigmap": 5,
|
||||
"factory4_day": 0,
|
||||
"factory4_night": 0,
|
||||
"interchange": 0,
|
||||
"laboratory": 0,
|
||||
"lighthouse": 0,
|
||||
"rezervbase": 0,
|
||||
"sandbox": 0,
|
||||
"sandbox_high": 0,
|
||||
"shoreline": 0,
|
||||
"tarkovstreets": 0,
|
||||
"woods": 5
|
||||
},
|
||||
"bossZone": {
|
||||
"bigmap": "ZoneFactoryCenter,ZoneScavBase",
|
||||
"factory4_day": "",
|
||||
"factory4_night": "",
|
||||
"interchange": "",
|
||||
"laboratory": "",
|
||||
"lighthouse": "",
|
||||
"rezervbase": "",
|
||||
"sandbox": "",
|
||||
"sandbox_high": "",
|
||||
"shoreline": "",
|
||||
"tarkovstreets": "",
|
||||
"woods": "ZoneMiniHouse,ZoneClearVill,ZoneRoad,ZoneBrokenVill,ZoneScavBase2"
|
||||
}
|
||||
},
|
||||
"pmcBot": {
|
||||
"enable": true,
|
||||
"addExtraSpawns": true,
|
||||
"disableVanillaSpawns": false,
|
||||
"time": -1,
|
||||
"spawnChance": {
|
||||
"bigmap": 0,
|
||||
"factory4_day": 0,
|
||||
"factory4_night": 0,
|
||||
"interchange": 0,
|
||||
"laboratory": 75,
|
||||
"lighthouse": 0,
|
||||
"rezervbase": 0,
|
||||
"sandbox": 0,
|
||||
"sandbox_high": 0,
|
||||
"shoreline": 0,
|
||||
"tarkovstreets": 0,
|
||||
"woods": 0
|
||||
},
|
||||
"bossZone": {
|
||||
"bigmap": "",
|
||||
"factory4_day": "",
|
||||
"factory4_night": "",
|
||||
"interchange": "",
|
||||
"laboratory": "BotZoneBasement,BotZoneFloor1,BotZoneFloor2",
|
||||
"lighthouse": "",
|
||||
"rezervbase": "",
|
||||
"sandbox": "",
|
||||
"sandbox_high": "",
|
||||
"shoreline": "",
|
||||
"tarkovstreets": "",
|
||||
"woods": ""
|
||||
}
|
||||
},
|
||||
"exUsec": {
|
||||
"enable": true,
|
||||
"addExtraSpawns": false,
|
||||
"disableVanillaSpawns": false,
|
||||
"time": -1,
|
||||
"spawnChance": {
|
||||
"bigmap": 0,
|
||||
"factory4_day": 0,
|
||||
"factory4_night": 0,
|
||||
"interchange": 0,
|
||||
"laboratory": 0,
|
||||
"lighthouse": 0,
|
||||
"rezervbase": 0,
|
||||
"sandbox": 0,
|
||||
"sandbox_high": 0,
|
||||
"shoreline": 0,
|
||||
"tarkovstreets": 0,
|
||||
"woods": 0
|
||||
},
|
||||
"bossZone": {
|
||||
"bigmap": "",
|
||||
"factory4_day": "",
|
||||
"factory4_night": "",
|
||||
"interchange": "",
|
||||
"laboratory": "",
|
||||
"lighthouse": "",
|
||||
"rezervbase": "",
|
||||
"sandbox": "",
|
||||
"sandbox_high": "",
|
||||
"shoreline": "",
|
||||
"tarkovstreets": "",
|
||||
"woods": ""
|
||||
}
|
||||
},
|
||||
"gifter": {
|
||||
"enable": true,
|
||||
"time": -1,
|
||||
"spawnChance": {
|
||||
"bigmap": 0,
|
||||
"factory4_day": 0,
|
||||
"factory4_night": 0,
|
||||
"interchange": 0,
|
||||
"laboratory": 0,
|
||||
"lighthouse": 0,
|
||||
"rezervbase": 0,
|
||||
"sandbox": 0,
|
||||
"sandbox_high": 0,
|
||||
"shoreline": 0,
|
||||
"tarkovstreets": 0,
|
||||
"woods": 0
|
||||
},
|
||||
"bossZone": {
|
||||
"bigmap": "",
|
||||
"factory4_day": "",
|
||||
"factory4_night": "",
|
||||
"interchange": "",
|
||||
"laboratory": "",
|
||||
"lighthouse": "",
|
||||
"rezervbase": "",
|
||||
"sandbox": "",
|
||||
"sandbox_high": "",
|
||||
"shoreline": "",
|
||||
"tarkovstreets": "",
|
||||
"woods": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"configAppSettings": {
|
||||
"showUndo": true,
|
||||
"showDefault": false,
|
||||
"disableAnimations": false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"name": "Acids Bot Placement System",
|
||||
"version": "1.1.1",
|
||||
"sptVersion": "~3.11",
|
||||
"loadBefore": [
|
||||
"RaidOverhaul",
|
||||
"WTT-RogueJustice"
|
||||
],
|
||||
"loadAfter": [],
|
||||
"incompatibilities": [],
|
||||
"isBundleMod": false,
|
||||
"main": "src/mod.js",
|
||||
"scripts": {
|
||||
"setup": "npm i",
|
||||
"build": "node ./build.mjs",
|
||||
"buildinfo": "node ./build.mjs --verbose"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "20.11",
|
||||
"@typescript-eslint/eslint-plugin": "7.2",
|
||||
"@typescript-eslint/parser": "7.2",
|
||||
"archiver": "^6.0",
|
||||
"eslint": "8.57",
|
||||
"fs-extra": "11.2",
|
||||
"ignore": "^5.2",
|
||||
"tsyringe": "4.8.0",
|
||||
"typescript": "5.8",
|
||||
"winston": "3.12"
|
||||
},
|
||||
"author": "acidphantasm",
|
||||
"contributors": [],
|
||||
"license": "BY-NC-ND 4.0"
|
||||
}
|
|
@ -0,0 +1,187 @@
|
|||
import { injectable, inject } from "tsyringe";
|
||||
import { IBossLocationSpawn } from "@spt/models/eft/common/ILocationBase";
|
||||
import type { ILogger } from "@spt/models/spt/utils/ILogger";
|
||||
import type { ICloner } from "@spt/utils/cloners/ICloner";
|
||||
import { WeightedRandomHelper } from "@spt/helpers/WeightedRandomHelper";
|
||||
import { RandomUtil } from "@spt/utils/RandomUtil";
|
||||
import { ModConfig } from "../Globals/ModConfig";
|
||||
|
||||
// Default Boss Data
|
||||
import {
|
||||
arenaFighterEventData,
|
||||
bossBoarData,
|
||||
bossBullyData,
|
||||
bossGluharData,
|
||||
bossKillaData,
|
||||
bossKnightData,
|
||||
bossKojaniyData,
|
||||
bossKolontayData,
|
||||
bossPartisanData,
|
||||
bossSanitarData,
|
||||
bossTagillaData,
|
||||
bossZryachiyData,
|
||||
exUsecData,
|
||||
gifterData,
|
||||
pmcBotData,
|
||||
pmcBotReserveData,
|
||||
pmcBotLaboratoryData,
|
||||
sectantPriestData
|
||||
} from "../Defaults/Bosses"
|
||||
|
||||
@injectable()
|
||||
export class BossSpawnControl
|
||||
{
|
||||
constructor(
|
||||
@inject("WinstonLogger") protected logger: ILogger,
|
||||
@inject("RandomUtil") protected randomUtil: RandomUtil,
|
||||
@inject("PrimaryCloner") protected cloner: ICloner,
|
||||
@inject("WeightedRandomHelper") protected weightedRandomHelper: WeightedRandomHelper
|
||||
)
|
||||
{}
|
||||
|
||||
public getCustomMapData(location: string, escapeTimeLimit: number): IBossLocationSpawn[]
|
||||
{
|
||||
return this.getConfigValueForLocation(location, escapeTimeLimit)
|
||||
}
|
||||
|
||||
private getConfigValueForLocation(location: string, escapeTimeLimit: number): IBossLocationSpawn[]
|
||||
{
|
||||
const bossesForMap: IBossLocationSpawn[] = [];
|
||||
for (const boss in ModConfig.config.bossConfig)
|
||||
{
|
||||
const bossDefaultData = this.cloner.clone(this.getDefaultValuesForBoss(boss, location));
|
||||
const bossConfigData = ModConfig.config.bossConfig[boss];
|
||||
const difficultyWeights = ModConfig.config.bossDifficulty;
|
||||
|
||||
if (!bossConfigData.enable) continue;
|
||||
|
||||
if (boss == "exUsec" && !bossConfigData.disableVanillaSpawns && location == "lighthouse" || boss == "pmcBot" && !bossConfigData.disableVanillaSpawns && (location == "laboratory" || location == "rezervbase"))
|
||||
{
|
||||
for (const bossSpawn in bossDefaultData)
|
||||
{
|
||||
// Create the vanilla spawns
|
||||
//bossDefaultData[bossSpawn].BossChance = bossConfigData.spawnChance[location];
|
||||
bossDefaultData[0].BossDifficult = this.weightedRandomHelper.getWeightedValue(difficultyWeights);
|
||||
bossesForMap.push(bossDefaultData[bossSpawn]);
|
||||
}
|
||||
if (!bossConfigData.addExtraSpawns) continue;
|
||||
}
|
||||
|
||||
if (!bossConfigData.spawnChance[location]) continue;
|
||||
|
||||
if (location.includes("factory")) bossConfigData.bossZone[location] = "BotZone"
|
||||
if ((boss == "pmcBot") && bossConfigData.addExtraSpawns)
|
||||
{
|
||||
bossesForMap.push(...this.generateBossWaves(location, escapeTimeLimit));
|
||||
continue;
|
||||
}
|
||||
|
||||
bossDefaultData[0].BossChance = bossConfigData.spawnChance[location];
|
||||
bossDefaultData[0].BossZone = bossConfigData.bossZone[location];
|
||||
bossDefaultData[0].BossDifficult = this.weightedRandomHelper.getWeightedValue(difficultyWeights);
|
||||
bossDefaultData[0].BossEscortDifficult = this.weightedRandomHelper.getWeightedValue(difficultyWeights);
|
||||
bossDefaultData[0].Time = bossConfigData.time;
|
||||
bossesForMap.push(bossDefaultData[0]);
|
||||
}
|
||||
|
||||
return bossesForMap;
|
||||
}
|
||||
|
||||
private generateBossWaves(location: string, escapeTimeLimit: number): IBossLocationSpawn[]
|
||||
{
|
||||
const pmcWaveSpawnInfo: IBossLocationSpawn[] = [];
|
||||
|
||||
const difficultyWeights = ModConfig.config.bossDifficulty;
|
||||
const waveMaxPMCCount = location != "laboratory" ? 4 : 10;
|
||||
const waveGroupLimit = 4;
|
||||
const waveGroupSize = 2;
|
||||
const waveGroupChance = 100;
|
||||
const waveTimer = 450;
|
||||
const endWavesAtRemainingTime = 300;
|
||||
const waveCount = Math.floor((((escapeTimeLimit * 60) - endWavesAtRemainingTime)) / waveTimer);
|
||||
let currentWaveTime = waveTimer;
|
||||
const bossConfigData = ModConfig.config.bossConfig["pmcBot"];
|
||||
|
||||
//this.logger.warning(`[Boss Waves] Generating ${waveCount} waves for Raiders`)
|
||||
for (let i = 1; i <= waveCount; i++)
|
||||
{
|
||||
if (i == 1) currentWaveTime = -1;
|
||||
|
||||
let currentPMCCount = 0;
|
||||
let groupCount = 0;
|
||||
while (currentPMCCount < waveMaxPMCCount)
|
||||
{
|
||||
if (groupCount >= waveGroupLimit) break;
|
||||
let groupSize = 0;
|
||||
const remainingSpots = waveMaxPMCCount - currentPMCCount;
|
||||
const isAGroup = remainingSpots > 1 ? this.randomUtil.getChance100(waveGroupChance) : false;
|
||||
if (isAGroup)
|
||||
{
|
||||
groupSize = Math.min(remainingSpots - 1, this.randomUtil.getInt(1, waveGroupSize));
|
||||
}
|
||||
const bossDefaultData = this.cloner.clone(this.getDefaultValuesForBoss("pmcBot", ""));
|
||||
|
||||
bossDefaultData[0].BossChance = bossConfigData.spawnChance[location];
|
||||
bossDefaultData[0].BossZone = bossConfigData.bossZone[location];
|
||||
bossDefaultData[0].BossEscortAmount = groupSize.toString();
|
||||
bossDefaultData[0].BossDifficult = this.weightedRandomHelper.getWeightedValue(difficultyWeights);
|
||||
bossDefaultData[0].BossEscortDifficult = this.weightedRandomHelper.getWeightedValue(difficultyWeights);
|
||||
bossDefaultData[0].IgnoreMaxBots = false;
|
||||
bossDefaultData[0].Time = currentWaveTime;
|
||||
currentPMCCount += groupSize + 1;
|
||||
groupCount++
|
||||
pmcWaveSpawnInfo.push(bossDefaultData[0]);
|
||||
|
||||
//this.logger.warning(`[Boss Waves] Adding 1 spawn for Raiders to ${location} | GroupSize: ${groupSize + 1}`);
|
||||
}
|
||||
//this.logger.warning(`[Boss Waves] Wave: ${i} | Time: ${currentWaveTime} | Groups: ${groupCount} | TotalRaiderss: ${currentPMCCount}/${waveMaxPMCCount}`);
|
||||
currentWaveTime += waveTimer;
|
||||
}
|
||||
|
||||
return pmcWaveSpawnInfo;
|
||||
}
|
||||
|
||||
private getDefaultValuesForBoss(boss: string, location: string): IBossLocationSpawn[]
|
||||
{
|
||||
switch (boss)
|
||||
{
|
||||
case "bossKnight":
|
||||
return bossKnightData;
|
||||
case "bossBully":
|
||||
return bossBullyData;
|
||||
case "bossTagilla":
|
||||
return bossTagillaData;
|
||||
case "bossKilla":
|
||||
return bossKillaData;
|
||||
case "bossZryachiy":
|
||||
return bossZryachiyData;
|
||||
case "bossGluhar":
|
||||
return bossGluharData;
|
||||
case "bossSanitar":
|
||||
return bossSanitarData;
|
||||
case "bossKolontay":
|
||||
return bossKolontayData;
|
||||
case "bossBoar":
|
||||
return bossBoarData;
|
||||
case "bossKojaniy":
|
||||
return bossKojaniyData;
|
||||
case "bossPartisan":
|
||||
return bossPartisanData;
|
||||
case "sectantPriest":
|
||||
return sectantPriestData;
|
||||
case "arenaFighterEvent":
|
||||
return arenaFighterEventData;
|
||||
case "pmcBot": // Requires Triggers + Has Multiple Zones
|
||||
if (location == "rezervbase") return pmcBotReserveData;
|
||||
if (location == "laboratory") return pmcBotLaboratoryData;
|
||||
else return pmcBotData;
|
||||
case "exUsec": // Has Multiple Zones
|
||||
return exUsecData;
|
||||
case "gifter":
|
||||
return gifterData;
|
||||
default:
|
||||
this.logger.error(`[ABPS] Boss not found in config ${boss}`)
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,221 @@
|
|||
import { injectable, inject } from "tsyringe";
|
||||
import { ILocationBase, IBossLocationSpawn, IWave } from "@spt/models/eft/common/ILocationBase";
|
||||
import type { ILogger } from "@spt/models/spt/utils/ILogger";
|
||||
|
||||
import { BossSpawnControl } from "./BossSpawnControl";
|
||||
import { DatabaseService } from "@spt/services/DatabaseService";
|
||||
import { ILocations } from "@spt/models/spt/server/ILocations";
|
||||
import { VanillaAdjustmentControl } from "./VanillaAdjustmentControl";
|
||||
import { PMCSpawnControl } from "./PMCSpawnControl";
|
||||
import { ScavSpawnControl } from "./ScavSpawnControl";
|
||||
import { IRaidChanges } from "@spt/models/spt/location/IRaidChanges";
|
||||
import type { ICloner } from "@spt/utils/cloners/ICloner";
|
||||
import { ModConfig } from "../Globals/ModConfig";
|
||||
|
||||
@injectable()
|
||||
export class MapSpawnControl
|
||||
{
|
||||
public validMaps: string[] = [
|
||||
"bigmap",
|
||||
"factory4_day",
|
||||
"factory4_night",
|
||||
"interchange",
|
||||
"laboratory",
|
||||
"lighthouse",
|
||||
"rezervbase",
|
||||
"sandbox",
|
||||
"sandbox_high",
|
||||
"shoreline",
|
||||
"tarkovstreets",
|
||||
"woods"
|
||||
];
|
||||
|
||||
public botMapCache: Record<string, IBossLocationSpawn[]> = {};
|
||||
public scavMapCache: Record<string, IWave[]> = {};
|
||||
public locationData: ILocations = {};
|
||||
|
||||
constructor(
|
||||
@inject("WinstonLogger") protected logger: ILogger,
|
||||
@inject("DatabaseService") protected databaseService: DatabaseService,
|
||||
@inject("BossSpawnControl") protected bossSpawnControl: BossSpawnControl,
|
||||
@inject("ScavSpawnControl") protected scavSpawnControl: ScavSpawnControl,
|
||||
@inject("PMCSpawnControl") protected pmcSpawnControl: PMCSpawnControl,
|
||||
@inject("PrimaryCloner") protected cloner: ICloner,
|
||||
@inject("VanillaAdjustmentControl") protected vanillaAdjustmentControl: VanillaAdjustmentControl
|
||||
)
|
||||
{}
|
||||
|
||||
public configureInitialData(): void
|
||||
{
|
||||
this.locationData = this.databaseService.getTables().locations;
|
||||
for (const map in this.validMaps)
|
||||
{
|
||||
const mapName = this.validMaps[map];
|
||||
this.locationData[mapName].base.BossLocationSpawn = [];
|
||||
this.botMapCache[mapName] = [];
|
||||
this.scavMapCache[mapName] = [];
|
||||
if (ModConfig.config.scavConfig.waves.enable) this.vanillaAdjustmentControl.enableAllSpawnSystem(this.locationData[mapName].base);
|
||||
this.vanillaAdjustmentControl.removeExistingWaves(this.locationData[mapName].base);
|
||||
this.vanillaAdjustmentControl.fixPMCHostility(this.locationData[mapName].base);
|
||||
this.vanillaAdjustmentControl.adjustNewWaveSettings(this.locationData[mapName].base);
|
||||
/*
|
||||
This is how you make a spawn point properly
|
||||
if (this.validMaps[map] == "bigmap") {
|
||||
const test = {
|
||||
"BotZoneName": "",
|
||||
"Categories": [
|
||||
"Player"
|
||||
],
|
||||
"ColliderParams": {
|
||||
"_parent": "SpawnSphereParams",
|
||||
"_props": {
|
||||
"Center": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"Radius": 75
|
||||
}
|
||||
},
|
||||
"CorePointId": 0,
|
||||
"DelayToCanSpawnSec": 4,
|
||||
"Id": crypto.randomUUID(),
|
||||
"Infiltration": "Boiler Tanks",
|
||||
"Position": {
|
||||
"x": 288.068,
|
||||
"y": 1.718,
|
||||
"z": -200.166
|
||||
},
|
||||
"Rotation": 17.73762,
|
||||
"Sides": [
|
||||
"Pmc"
|
||||
]
|
||||
}
|
||||
this.locationData[mapName].base.SpawnPointParams.push(test);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
this.vanillaAdjustmentControl.disableVanillaSettings();
|
||||
this.vanillaAdjustmentControl.removeCustomPMCWaves();
|
||||
this.buildInitialCache();
|
||||
}
|
||||
public buildInitialCache(): void
|
||||
{
|
||||
this.buildBossWaves();
|
||||
this.buildPMCWaves();
|
||||
this.buildStartingScavs();
|
||||
this.replaceOriginalLocations();
|
||||
}
|
||||
|
||||
private buildBossWaves(): void
|
||||
{
|
||||
for (const map in this.validMaps)
|
||||
{
|
||||
const mapName = this.validMaps[map];
|
||||
const mapData = this.bossSpawnControl.getCustomMapData(this.validMaps[map], this.locationData[mapName].base.EscapeTimeLimit);
|
||||
if (mapData.length) mapData.forEach((index) => (this.botMapCache[mapName].push(index)));
|
||||
}
|
||||
}
|
||||
|
||||
private buildPMCWaves(): void
|
||||
{
|
||||
for (const map in this.validMaps)
|
||||
{
|
||||
const mapName = this.validMaps[map];
|
||||
const mapData = this.pmcSpawnControl.getCustomMapData(this.validMaps[map], this.locationData[mapName].base.EscapeTimeLimit);
|
||||
if (mapData.length) mapData.forEach((index) => (this.botMapCache[mapName].push(index)));
|
||||
}
|
||||
}
|
||||
|
||||
private buildStartingScavs(): void
|
||||
{
|
||||
for (const map in this.validMaps)
|
||||
{
|
||||
const mapName = this.validMaps[map];
|
||||
if (mapName == "laboratory") continue;
|
||||
const mapData = this.scavSpawnControl.getCustomMapData(this.validMaps[map]);
|
||||
if (mapData.length) mapData.forEach((index) => (this.scavMapCache[mapName].push(index)));
|
||||
}
|
||||
}
|
||||
|
||||
private replaceOriginalLocations(): void
|
||||
{
|
||||
for (const map in this.validMaps)
|
||||
{
|
||||
const mapName = this.validMaps[map];
|
||||
this.locationData[mapName].base.BossLocationSpawn = this.cloner.clone(this.botMapCache[mapName]);
|
||||
this.locationData[mapName].base.waves = this.cloner.clone(this.scavMapCache[mapName]);
|
||||
}
|
||||
}
|
||||
|
||||
public rebuildCache(location: string): void
|
||||
{
|
||||
location = location.toLowerCase();
|
||||
this.locationData = this.databaseService.getTables().locations;
|
||||
this.botMapCache[location] = [];
|
||||
this.scavMapCache[location] = [];
|
||||
this.rebuildBossWave(location);
|
||||
this.rebuildPMCWave(location);
|
||||
this.rebuildStartingScavs(location)
|
||||
this.rebuildLocation(location);
|
||||
}
|
||||
|
||||
private rebuildBossWave(location: string): void
|
||||
{
|
||||
const mapName = location.toLowerCase();
|
||||
this.logger.warning(`[ABPS] Recreating bosses for ${mapName}`);
|
||||
|
||||
const mapData = this.bossSpawnControl.getCustomMapData(mapName, this.locationData[mapName].base.EscapeTimeLimit);
|
||||
if (mapData.length) mapData.forEach((index) => (this.botMapCache[mapName].push(index)));
|
||||
}
|
||||
|
||||
private rebuildPMCWave(location: string): void
|
||||
{
|
||||
const mapName = location.toLowerCase();
|
||||
this.logger.warning(`[ABPS] Recreating PMCs for ${mapName}`);
|
||||
|
||||
const mapData = this.pmcSpawnControl.getCustomMapData(mapName, this.locationData[mapName].base.EscapeTimeLimit);
|
||||
if (mapData.length) mapData.forEach((index) => (this.botMapCache[mapName].push(index)));
|
||||
}
|
||||
|
||||
private rebuildStartingScavs(location: string): void
|
||||
{
|
||||
const mapName = location.toLowerCase();
|
||||
if (mapName == "laboratory") return;
|
||||
this.logger.warning(`[ABPS] Recreating scavs for ${mapName}`);
|
||||
|
||||
const mapData = this.scavSpawnControl.getCustomMapData(mapName);
|
||||
if (mapData.length) mapData.forEach((index) => (this.scavMapCache[mapName].push(index)));
|
||||
}
|
||||
|
||||
private rebuildLocation(location: string): void
|
||||
{
|
||||
const mapName = location.toLowerCase();
|
||||
this.locationData[mapName].base.BossLocationSpawn = this.cloner.clone(this.botMapCache[mapName]);
|
||||
this.locationData[mapName].base.waves = this.cloner.clone(this.scavMapCache[mapName]);
|
||||
}
|
||||
|
||||
public adjustWaves(mapBase: ILocationBase, raidAdjustments: IRaidChanges): void
|
||||
{
|
||||
const locationName = mapBase.Id.toLowerCase();
|
||||
if (raidAdjustments.simulatedRaidStartSeconds > 60)
|
||||
{
|
||||
const mapBosses = mapBase.BossLocationSpawn.filter((x) => x.Time == -1 && x.BossName != "pmcUSEC" && x.BossName != "pmcBEAR");
|
||||
mapBase.BossLocationSpawn = mapBase.BossLocationSpawn.filter((x) => x.Time > raidAdjustments.simulatedRaidStartSeconds && (x.BossName == "pmcUSEC" || x.BossName == "pmcBEAR"));
|
||||
|
||||
for (const bossWave of mapBase.BossLocationSpawn)
|
||||
{
|
||||
bossWave.Time -= Math.max(raidAdjustments.simulatedRaidStartSeconds, 0);
|
||||
}
|
||||
|
||||
const totalRemainingTime = raidAdjustments.raidTimeMinutes * 60;
|
||||
const newStartingPMCs = this.pmcSpawnControl.generateScavRaidRemainingPMCs(locationName, totalRemainingTime);
|
||||
newStartingPMCs.forEach((index) => (mapBase.BossLocationSpawn.push(index)));
|
||||
mapBosses.forEach((index) => (mapBase.BossLocationSpawn.push(index)));
|
||||
|
||||
const newStartingScavs = this.scavSpawnControl.generateStartingScavs(locationName, "assault", true);
|
||||
newStartingScavs.forEach((index) => (mapBase.waves.push(index)));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,212 @@
|
|||
import { injectable, inject } from "tsyringe";
|
||||
import { IBossLocationSpawn } from "@spt/models/eft/common/ILocationBase";
|
||||
import type { ILogger } from "@spt/models/spt/utils/ILogger";
|
||||
import type { ICloner } from "@spt/utils/cloners/ICloner";
|
||||
import { RandomUtil } from "@spt/utils/RandomUtil";
|
||||
import { WeightedRandomHelper } from "@spt/helpers/WeightedRandomHelper";
|
||||
|
||||
|
||||
// Default PMC Data
|
||||
import {
|
||||
pmcBEARData,
|
||||
pmcUSECData
|
||||
} from "../Defaults/PMCs";
|
||||
|
||||
import { ModConfig } from "../Globals/ModConfig";
|
||||
import { Labs_NonGateSpawnZones } from "../Defaults/MapSpawnZones";
|
||||
|
||||
@injectable()
|
||||
export class PMCSpawnControl
|
||||
{
|
||||
constructor(
|
||||
@inject("WinstonLogger") protected logger: ILogger,
|
||||
@inject("RandomUtil") protected randomUtil: RandomUtil,
|
||||
@inject("PrimaryCloner") protected cloner: ICloner,
|
||||
@inject("WeightedRandomHelper") protected weightedRandomHelper: WeightedRandomHelper
|
||||
)
|
||||
{}
|
||||
|
||||
public getCustomMapData(location: string, escapeTimeLimit: number): IBossLocationSpawn[]
|
||||
{
|
||||
return this.getConfigValueForLocation(location, escapeTimeLimit)
|
||||
}
|
||||
|
||||
private getConfigValueForLocation(location: string, escapeTimeLimit: number): IBossLocationSpawn[]
|
||||
{
|
||||
let pmcSpawnInfo: IBossLocationSpawn[] = [];
|
||||
if (ModConfig.config.pmcConfig.startingPMCs.enable)
|
||||
{
|
||||
pmcSpawnInfo = pmcSpawnInfo.concat(this.generateStartingPMCWaves(location));
|
||||
}
|
||||
if (ModConfig.config.pmcConfig.waves.enable)
|
||||
{
|
||||
pmcSpawnInfo = pmcSpawnInfo.concat(this.generatePMCWaves(location, escapeTimeLimit));
|
||||
}
|
||||
return pmcSpawnInfo;
|
||||
}
|
||||
|
||||
private generateStartingPMCWaves(location: string): IBossLocationSpawn[]
|
||||
{
|
||||
const startingPMCWaveInfo: IBossLocationSpawn[] = [];
|
||||
const ignoreMaxBotCaps = ModConfig.config.pmcConfig.startingPMCs.ignoreMaxBotCaps;
|
||||
const minPMCCount = ModConfig.config.pmcConfig.startingPMCs.mapLimits[location].min;
|
||||
const maxPMCCount = ModConfig.config.pmcConfig.startingPMCs.mapLimits[location].max;
|
||||
const generatedPMCCount = this.randomUtil.getInt(minPMCCount, maxPMCCount);
|
||||
const groupChance = ModConfig.config.pmcConfig.startingPMCs.groupChance;
|
||||
const groupLimit = ModConfig.config.pmcConfig.startingPMCs.maxGroupCount;
|
||||
const groupMaxSize = ModConfig.config.pmcConfig.startingPMCs.maxGroupSize;
|
||||
const difficultyWeights = ModConfig.config.pmcDifficulty;
|
||||
|
||||
let currentPMCCount = 0;
|
||||
let groupCount = 0;
|
||||
|
||||
while (currentPMCCount < generatedPMCCount)
|
||||
{
|
||||
const canBeAGroup = groupCount >= groupLimit ? false : true;
|
||||
let groupSize = 0;
|
||||
const remainingSpots = generatedPMCCount - currentPMCCount;
|
||||
|
||||
const isAGroup = remainingSpots > 1 ? this.randomUtil.getChance100(groupChance) : false;
|
||||
if (isAGroup && canBeAGroup)
|
||||
{
|
||||
groupSize = Math.min(remainingSpots - 1, this.randomUtil.getInt(1, groupMaxSize));
|
||||
groupCount++
|
||||
}
|
||||
|
||||
const pmcType = this.randomUtil.getChance100(50) ? "pmcUSEC" : "pmcBEAR";
|
||||
const bossDefaultData = this.cloner.clone(this.getDefaultValuesForBoss(pmcType));
|
||||
|
||||
bossDefaultData[0].BossEscortAmount = groupSize.toString();
|
||||
bossDefaultData[0].BossDifficult = this.weightedRandomHelper.getWeightedValue(difficultyWeights);
|
||||
bossDefaultData[0].BossEscortDifficult = this.weightedRandomHelper.getWeightedValue(difficultyWeights);
|
||||
bossDefaultData[0].BossZone = "";
|
||||
bossDefaultData[0].IgnoreMaxBots = ignoreMaxBotCaps;
|
||||
currentPMCCount += groupSize + 1;
|
||||
startingPMCWaveInfo.push(bossDefaultData[0]);
|
||||
|
||||
//this.logger.warning(`[Starting PMC] Adding 1 spawn for ${pmcType} to ${location} | GroupSize: ${groupSize + 1}`);
|
||||
}
|
||||
|
||||
//this.logger.warning(`[Starting PMCs] Map: ${location} (Time Limit: ${escapeTimeLimit}m) | Limits: ${minPMCCount}-${maxPMCCount} | Groups: ${groupCount} | TotalPMCs: ${currentPMCCount}/${generatedPMCCount}`);
|
||||
return startingPMCWaveInfo;
|
||||
}
|
||||
|
||||
private generatePMCWaves(location: string, escapeTimeLimit: number): IBossLocationSpawn[]
|
||||
{
|
||||
const pmcWaveSpawnInfo: IBossLocationSpawn[] = [];
|
||||
|
||||
const ignoreMaxBotCaps = ModConfig.config.pmcConfig.waves.ignoreMaxBotCaps;
|
||||
const difficultyWeights = ModConfig.config.pmcDifficulty;
|
||||
const waveMaxPMCCount = location.includes("factory") ? Math.min(2, ModConfig.config.pmcConfig.waves.maxBotsPerWave - 2) : ModConfig.config.pmcConfig.waves.maxBotsPerWave;
|
||||
const waveGroupLimit = ModConfig.config.pmcConfig.waves.maxGroupCount;
|
||||
const waveGroupSize = ModConfig.config.pmcConfig.waves.maxGroupSize;
|
||||
const waveGroupChance = ModConfig.config.pmcConfig.waves.groupChance;
|
||||
const firstWaveTimer = ModConfig.config.pmcConfig.waves.delayBeforeFirstWave;
|
||||
const waveTimer = ModConfig.config.pmcConfig.waves.secondsBetweenWaves;
|
||||
const endWavesAtRemainingTime = ModConfig.config.pmcConfig.waves.stopWavesBeforeEndOfRaidLimit;
|
||||
const waveCount = Math.floor((((escapeTimeLimit * 60) - endWavesAtRemainingTime) - firstWaveTimer) / waveTimer);
|
||||
let currentWaveTime = firstWaveTimer;
|
||||
|
||||
//this.logger.warning(`[PMC Waves] Generating ${waveCount} waves for PMCs`)
|
||||
for (let i = 1; i <= waveCount; i++)
|
||||
{
|
||||
let currentPMCCount = 0;
|
||||
let groupCount = 0;
|
||||
while (currentPMCCount < waveMaxPMCCount)
|
||||
{
|
||||
const canBeAGroup = groupCount >= waveGroupLimit ? false : true;
|
||||
let groupSize = 0;
|
||||
const remainingSpots = waveMaxPMCCount - currentPMCCount;
|
||||
const isAGroup = remainingSpots > 1 ? this.randomUtil.getChance100(waveGroupChance) : false;
|
||||
if (isAGroup && canBeAGroup)
|
||||
{
|
||||
groupSize = Math.min(remainingSpots - 1, this.randomUtil.getInt(1, waveGroupSize));
|
||||
groupCount++
|
||||
}
|
||||
|
||||
const pmcType = this.randomUtil.getChance100(50) ? "pmcUSEC" : "pmcBEAR";
|
||||
const bossDefaultData = this.cloner.clone(this.getDefaultValuesForBoss(pmcType));
|
||||
|
||||
bossDefaultData[0].BossEscortAmount = groupSize.toString();
|
||||
bossDefaultData[0].Time = currentWaveTime;
|
||||
bossDefaultData[0].BossDifficult = this.weightedRandomHelper.getWeightedValue(difficultyWeights);
|
||||
bossDefaultData[0].BossEscortDifficult = this.weightedRandomHelper.getWeightedValue(difficultyWeights);
|
||||
bossDefaultData[0].BossZone = "";
|
||||
bossDefaultData[0].IgnoreMaxBots = ignoreMaxBotCaps;
|
||||
currentPMCCount += groupSize + 1;
|
||||
pmcWaveSpawnInfo.push(bossDefaultData[0]);
|
||||
|
||||
//this.logger.warning(`[PMC Waves] Adding 1 spawn for ${pmcType} to ${location} | GroupSize: ${groupSize + 1}`);
|
||||
}
|
||||
//this.logger.warning(`[PMC Waves] Wave: ${i} | Time: ${currentWaveTime} | Groups: ${groupCount} | TotalPMCs: ${currentPMCCount}/${waveMaxPMCCount}`);
|
||||
currentWaveTime += waveTimer;
|
||||
}
|
||||
|
||||
return pmcWaveSpawnInfo;
|
||||
}
|
||||
|
||||
private getDefaultValuesForBoss(boss: string): IBossLocationSpawn[]
|
||||
{
|
||||
switch (boss)
|
||||
{
|
||||
case "pmcUSEC":
|
||||
return pmcUSECData;
|
||||
case "pmcBEAR":
|
||||
return pmcBEARData;
|
||||
default:
|
||||
this.logger.error(`[ABPS] PMC not found in config ${boss}`)
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
public generateScavRaidRemainingPMCs(location: string, remainingRaidTime: number): IBossLocationSpawn[]
|
||||
{
|
||||
const startingPMCWaveInfo: IBossLocationSpawn[] = [];
|
||||
const ignoreMaxBotCaps = ModConfig.config.pmcConfig.startingPMCs.ignoreMaxBotCaps;
|
||||
const minPMCCount = ModConfig.config.pmcConfig.startingPMCs.mapLimits[location].min;
|
||||
const maxPMCCount = ModConfig.config.pmcConfig.startingPMCs.mapLimits[location].max;
|
||||
let generatedPMCCount = this.randomUtil.getInt(minPMCCount, maxPMCCount);
|
||||
const groupChance = ModConfig.config.pmcConfig.startingPMCs.groupChance;
|
||||
const groupLimit = ModConfig.config.pmcConfig.startingPMCs.maxGroupCount;
|
||||
const groupMaxSize = ModConfig.config.pmcConfig.startingPMCs.maxGroupSize;
|
||||
const difficultyWeights = ModConfig.config.pmcDifficulty;
|
||||
|
||||
let currentPMCCount = 0;
|
||||
let groupCount = 0;
|
||||
|
||||
if (remainingRaidTime < 600) generatedPMCCount = this.randomUtil.getInt(1, 3);
|
||||
if (remainingRaidTime < 1200) generatedPMCCount = this.randomUtil.getInt(1, 6);
|
||||
if (remainingRaidTime < 1800) generatedPMCCount = this.randomUtil.getInt(4, 9);
|
||||
|
||||
if (location.includes("factory") && generatedPMCCount > 5) generatedPMCCount -= 2;
|
||||
|
||||
while (currentPMCCount < generatedPMCCount)
|
||||
{
|
||||
const canBeAGroup = groupCount >= groupLimit ? false : true;
|
||||
let groupSize = 0;
|
||||
const remainingSpots = generatedPMCCount - currentPMCCount;
|
||||
const isAGroup = remainingSpots > 1 ? this.randomUtil.getChance100(groupChance) : false;
|
||||
if (isAGroup && canBeAGroup)
|
||||
{
|
||||
groupSize = Math.min(remainingSpots - 1, this.randomUtil.getInt(1, groupMaxSize));
|
||||
groupCount++
|
||||
}
|
||||
|
||||
const pmcType = this.randomUtil.getChance100(50) ? "pmcUSEC" : "pmcBEAR";
|
||||
const bossDefaultData = this.cloner.clone(this.getDefaultValuesForBoss(pmcType));
|
||||
|
||||
bossDefaultData[0].BossEscortAmount = groupSize.toString();
|
||||
bossDefaultData[0].BossDifficult = this.weightedRandomHelper.getWeightedValue(difficultyWeights);
|
||||
bossDefaultData[0].BossEscortDifficult = this.weightedRandomHelper.getWeightedValue(difficultyWeights);
|
||||
bossDefaultData[0].BossZone = "";
|
||||
bossDefaultData[0].IgnoreMaxBots = ignoreMaxBotCaps;
|
||||
currentPMCCount += groupSize + 1;
|
||||
startingPMCWaveInfo.push(bossDefaultData[0]);
|
||||
|
||||
//this.logger.warning(`[Starting PMC] Adding 1 spawn for ${pmcType} to ${location} | GroupSize: ${groupSize + 1}`);
|
||||
}
|
||||
|
||||
//this.logger.warning(`[Starting PMCs] Map: ${location} (Time Limit: ${escapeTimeLimit}m) | Limits: ${minPMCCount}-${maxPMCCount} | Groups: ${groupCount} | TotalPMCs: ${currentPMCCount}/${generatedPMCCount}`);
|
||||
return startingPMCWaveInfo;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,214 @@
|
|||
import { injectable, inject } from "tsyringe";
|
||||
import { IWave, WildSpawnType } from "@spt/models/eft/common/ILocationBase";
|
||||
import type { ILogger } from "@spt/models/spt/utils/ILogger";
|
||||
import type { ICloner } from "@spt/utils/cloners/ICloner";
|
||||
import { RandomUtil } from "@spt/utils/RandomUtil";
|
||||
import { WeightedRandomHelper } from "@spt/helpers/WeightedRandomHelper";
|
||||
|
||||
|
||||
// Default Scav Data
|
||||
|
||||
|
||||
import { ModConfig } from "../Globals/ModConfig";
|
||||
import { scavData } from "../Defaults/Scavs";
|
||||
import { DatabaseService } from "@spt/services/DatabaseService";
|
||||
import {
|
||||
Customs_SpawnZones,
|
||||
Customs_SnipeSpawnZones,
|
||||
Factory_SpawnZones,
|
||||
GroundZero_SpawnZones,
|
||||
Interchange_SpawnZones,
|
||||
Labs_NonGateSpawnZones,
|
||||
Lighthouse_NonWaterTreatmentSpawnZones,
|
||||
Lighthouse_SnipeSpawnZones,
|
||||
Reserve_SpawnZones,
|
||||
Shoreline_SpawnZones,
|
||||
Shoreline_SnipeSpawnZones,
|
||||
Streets_SpawnZones,
|
||||
Streets_SnipeSpawnZones,
|
||||
Woods_SpawnZones,
|
||||
Woods_SnipeSpawnZones,
|
||||
GroundZero_SnipeSpawnZones
|
||||
} from "../Defaults/MapSpawnZones";
|
||||
import { createExhaustableArray } from "../Utils/GlobalUtils";
|
||||
|
||||
@injectable()
|
||||
export class ScavSpawnControl
|
||||
{
|
||||
constructor(
|
||||
@inject("WinstonLogger") protected logger: ILogger,
|
||||
@inject("DatabaseService") protected databaseService: DatabaseService,
|
||||
@inject("RandomUtil") protected randomUtil: RandomUtil,
|
||||
@inject("PrimaryCloner") protected cloner: ICloner,
|
||||
@inject("WeightedRandomHelper") protected weightedRandomHelper: WeightedRandomHelper
|
||||
)
|
||||
{}
|
||||
|
||||
public getCustomMapData(location: string): IWave[]
|
||||
{
|
||||
return this.getConfigValueForLocation(location)
|
||||
}
|
||||
|
||||
private getConfigValueForLocation(location: string): IWave[]
|
||||
{
|
||||
const scavSpawnInfo: IWave[] = [];
|
||||
if (ModConfig.config.scavConfig.startingScavs.enable) scavSpawnInfo.push(...this.generateStartingScavs(location));
|
||||
if (ModConfig.config.scavConfig.startingScavs.startingMarksman)
|
||||
{
|
||||
const marksmanSpawn = this.generateStartingScavs(location, "marksman");
|
||||
if (marksmanSpawn.length)
|
||||
{
|
||||
scavSpawnInfo.push(...marksmanSpawn);
|
||||
}
|
||||
}
|
||||
return scavSpawnInfo;
|
||||
}
|
||||
|
||||
public generateStartingScavs(location: string, botRole = "assault", lateStart = false): IWave[]
|
||||
{
|
||||
const scavWaveSpawnInfo: IWave[] = [];
|
||||
|
||||
const waveLength = this.databaseService.getTables().locations[location].base.waves.length;
|
||||
|
||||
const maxStartingSpawns: number = ModConfig.config.scavConfig.startingScavs.maxBotSpawns[location];
|
||||
const scavCap = lateStart ? maxStartingSpawns * 0.75 : maxStartingSpawns;
|
||||
const playerScavChance = lateStart ? 60 : 10;
|
||||
|
||||
const maxBotsPerZone = location.includes("factory") || location.includes("sandbox") ? maxStartingSpawns : ModConfig.config.scavConfig.startingScavs.maxBotsPerZone;
|
||||
const availableSpawnZones = botRole == "assault" ? createExhaustableArray(this.getNonMarksmanSpawnZones(location), this.randomUtil, this.cloner) : createExhaustableArray(this.getMarksmanSpawnZones(location), this.randomUtil, this.cloner);
|
||||
let spawnsAdded = botRole == "assault" ? 0 : waveLength;
|
||||
let marksmanCount = 0;
|
||||
|
||||
while (spawnsAdded < scavCap)
|
||||
{
|
||||
if (spawnsAdded >= maxStartingSpawns) break;
|
||||
const scavDefaultData = this.cloner.clone(this.getDefaultValues());
|
||||
let selectedSpawnZone = location.includes("factory") || location.includes("sandbox") || !availableSpawnZones.hasValues() ? "" : availableSpawnZones.getRandomValue();
|
||||
if (botRole != "assault")
|
||||
{
|
||||
if (!availableSpawnZones.hasValues()) break;
|
||||
if (selectedSpawnZone == undefined) break;
|
||||
if (marksmanCount >= 2) break;
|
||||
selectedSpawnZone = availableSpawnZones.getRandomValue();
|
||||
marksmanCount++;
|
||||
}
|
||||
const remainingSpots = maxStartingSpawns - spawnsAdded;
|
||||
const groupSize = botRole == "assault" ? Math.min(remainingSpots - 1, this.randomUtil.getInt(1, maxBotsPerZone)) : 1;
|
||||
|
||||
scavDefaultData.slots_min = groupSize > 1 ? 1 : 0;
|
||||
scavDefaultData.slots_max = groupSize > 1 ? groupSize : 1;
|
||||
scavDefaultData.time_min = 1;
|
||||
scavDefaultData.time_max = 3;
|
||||
scavDefaultData.number = spawnsAdded;
|
||||
scavDefaultData.WildSpawnType = botRole == "assault" ? WildSpawnType.ASSAULT : WildSpawnType.MARKSMAN;
|
||||
scavDefaultData.isPlayers = botRole == "assault" ? this.randomUtil.getChance100(playerScavChance) ? true : false : false;
|
||||
scavDefaultData.SpawnPoints = selectedSpawnZone;
|
||||
|
||||
spawnsAdded++;
|
||||
scavWaveSpawnInfo.push(scavDefaultData);
|
||||
//this.logger.warning(`[Scav Waves] ${scavDefaultData.number} - Adding 1 spawn for ${botRole} to ${location} | Zone: ${selectedSpawnZone} Min: ${scavDefaultData.slots_min} | Max: ${scavDefaultData.slots_max}`);
|
||||
}
|
||||
|
||||
return scavWaveSpawnInfo;
|
||||
}
|
||||
|
||||
private getDefaultValues(): IWave
|
||||
{
|
||||
return scavData;
|
||||
}
|
||||
|
||||
private getNonMarksmanSpawnZones(location: string): string[]
|
||||
{
|
||||
switch (location)
|
||||
{
|
||||
case "bigmap":
|
||||
return Customs_SpawnZones;
|
||||
case "factory4_day":
|
||||
case "factory4_night":
|
||||
return Factory_SpawnZones;
|
||||
case "interchange":
|
||||
return Interchange_SpawnZones;
|
||||
case "laboratory":
|
||||
return Labs_NonGateSpawnZones;
|
||||
case "lighthouse":
|
||||
return Lighthouse_NonWaterTreatmentSpawnZones;
|
||||
case "rezervbase":
|
||||
return Reserve_SpawnZones;
|
||||
case "sandbox":
|
||||
case "sandbox_high":
|
||||
return GroundZero_SpawnZones;
|
||||
case "shoreline":
|
||||
return Shoreline_SpawnZones;
|
||||
case "tarkovstreets":
|
||||
return Streets_SpawnZones;
|
||||
case "woods":
|
||||
return Woods_SpawnZones;
|
||||
}
|
||||
}
|
||||
|
||||
private getMarksmanSpawnZones(location: string): string[]
|
||||
{
|
||||
switch (location)
|
||||
{
|
||||
case "bigmap":
|
||||
return Customs_SnipeSpawnZones;
|
||||
case "factory4_day":
|
||||
case "factory4_night":
|
||||
return undefined;
|
||||
case "interchange":
|
||||
return undefined;
|
||||
case "laboratory":
|
||||
return undefined;
|
||||
case "lighthouse":
|
||||
return Lighthouse_SnipeSpawnZones;
|
||||
case "rezervbase":
|
||||
return undefined;
|
||||
case "sandbox":
|
||||
case "sandbox_high":
|
||||
return GroundZero_SnipeSpawnZones;
|
||||
case "shoreline":
|
||||
return Shoreline_SnipeSpawnZones;
|
||||
case "tarkovstreets":
|
||||
return Streets_SnipeSpawnZones;
|
||||
case "woods":
|
||||
return Woods_SnipeSpawnZones;
|
||||
}
|
||||
}
|
||||
|
||||
public generateInitialScavsForRemainingRaidTime(location: string, botRole: string): IWave[]
|
||||
{
|
||||
const scavWaveSpawnInfo: IWave[] = [];
|
||||
|
||||
const waveLength = this.databaseService.getTables().locations[location].base.waves.length;
|
||||
|
||||
const maxStartingSpawns: number = ModConfig.config.scavConfig.startingScavs.maxBotSpawns[location] * 0.75;
|
||||
const maxBotsPerZone = location.includes("factory") || location.includes("sandbox") ? maxStartingSpawns : ModConfig.config.scavConfig.startingScavs.maxBotsPerZone;
|
||||
const checkMarksman = ModConfig.config.scavConfig.startingScavs.startingMarksman;
|
||||
|
||||
const availableSpawnZones = botRole == "assault" ? createExhaustableArray(this.getNonMarksmanSpawnZones(location), this.randomUtil, this.cloner) : createExhaustableArray(this.getMarksmanSpawnZones(location), this.randomUtil, this.cloner);
|
||||
let spawnsAdded = botRole == "assault" ? 0 : waveLength;
|
||||
|
||||
while (spawnsAdded < maxStartingSpawns)
|
||||
{
|
||||
if (spawnsAdded >= maxStartingSpawns) break;
|
||||
const scavDefaultData = this.cloner.clone(this.getDefaultValues());
|
||||
const selectedSpawnZone = location.includes("factory") || location.includes("sandbox") || !availableSpawnZones.hasValues() ? "" : availableSpawnZones.getRandomValue();
|
||||
const remainingSpots = maxStartingSpawns - spawnsAdded;
|
||||
const groupSize = Math.min(remainingSpots - 1, this.randomUtil.getInt(1, maxBotsPerZone));
|
||||
|
||||
scavDefaultData.slots_min = groupSize > 1 ? 1 : 1;
|
||||
scavDefaultData.slots_max = groupSize > 1 ? groupSize : 1;
|
||||
scavDefaultData.time_min = 1;
|
||||
scavDefaultData.time_max = 3;
|
||||
scavDefaultData.number = spawnsAdded;
|
||||
scavDefaultData.isPlayers = botRole == "assault" ? this.randomUtil.getChance100(60) ? true : false : false;
|
||||
scavDefaultData.SpawnPoints = selectedSpawnZone;
|
||||
|
||||
spawnsAdded++;
|
||||
scavWaveSpawnInfo.push(scavDefaultData);
|
||||
//this.logger.warning(`[Scav Waves] ${scavDefaultData.number} - Adding 1 spawn for assault to ${location} | Zone: ${selectedSpawnZone} Min: ${scavDefaultData.slots_min} | Max: ${scavDefaultData.slots_max}`);
|
||||
}
|
||||
|
||||
return scavWaveSpawnInfo;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
import { injectable, inject } from "tsyringe";
|
||||
import type { ILogger } from "@spt/models/spt/utils/ILogger";
|
||||
import { ConfigServer } from "@spt/servers/ConfigServer";
|
||||
import { DatabaseService } from "@spt/services/DatabaseService";
|
||||
import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
|
||||
import { ILocationConfig } from "@spt/models/spt/config/ILocationConfig";
|
||||
import { ILocationBase } from "@spt/models/eft/common/ILocationBase";
|
||||
import { newPMCHostilitySettings } from "../Defaults/Hostility";
|
||||
import type { ICloner } from "@spt/utils/cloners/ICloner";
|
||||
import { IPmcConfig } from "@spt/models/spt/config/IPmcConfig";
|
||||
import { IBotConfig } from "@spt/models/spt/config/IBotConfig";
|
||||
import { ModConfig } from "../Globals/ModConfig";
|
||||
|
||||
@injectable()
|
||||
export class VanillaAdjustmentControl
|
||||
{
|
||||
public locationConfig: ILocationConfig;
|
||||
public pmcConfig: IPmcConfig;
|
||||
public botConfig: IBotConfig;
|
||||
|
||||
constructor(
|
||||
@inject("WinstonLogger") protected logger: ILogger,
|
||||
@inject("DatabaseService") protected databaseService: DatabaseService,
|
||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||
@inject("PrimaryCloner") protected cloner: ICloner
|
||||
)
|
||||
{
|
||||
this.locationConfig = this.configServer.getConfig<ILocationConfig>(ConfigTypes.LOCATION);
|
||||
this.pmcConfig = this.configServer.getConfig<IPmcConfig>(ConfigTypes.PMC);
|
||||
this.botConfig = this.configServer.getConfig<IBotConfig>(ConfigTypes.BOT);
|
||||
}
|
||||
|
||||
public disableVanillaSettings(): void
|
||||
{
|
||||
this.locationConfig.splitWaveIntoSingleSpawnsSettings.enabled = false;
|
||||
this.locationConfig.rogueLighthouseSpawnTimeSettings.enabled = false;
|
||||
this.locationConfig.addOpenZonesToAllMaps = false;
|
||||
this.locationConfig.addCustomBotWavesToMaps = false;
|
||||
this.locationConfig.enableBotTypeLimits = false;
|
||||
}
|
||||
|
||||
public disableNewSpawnSystem(base: any): void
|
||||
{
|
||||
if (base.Id == "laboratory") return;
|
||||
|
||||
base.NewSpawn = false;
|
||||
base.OfflineNewSpawn = false;
|
||||
base.OldSpawn = true;
|
||||
base.OfflineOldSpawn = true;
|
||||
}
|
||||
|
||||
public enableAllSpawnSystem(base: any): void
|
||||
{
|
||||
if (base.Id == "laboratory") return;
|
||||
|
||||
base.NewSpawn = true;
|
||||
base.OfflineNewSpawn = true;
|
||||
base.OldSpawn = true;
|
||||
base.OfflineOldSpawn = true;
|
||||
}
|
||||
|
||||
public adjustNewWaveSettings(base: any): void
|
||||
{
|
||||
if (base.Id == "laboratory") return;
|
||||
|
||||
if (ModConfig.config.scavConfig.waves.enableCustomFactory && base.Id.includes("factory"))
|
||||
{
|
||||
// Start-Stop Time for spawns
|
||||
base.BotStart = ModConfig.config.scavConfig.waves.startSpawns;
|
||||
base.BotStop = (base.EscapeTimeLimit * 60) - ModConfig.config.scavConfig.waves.stopSpawns;
|
||||
|
||||
// Start-Stop wave times for active spawning
|
||||
base.BotSpawnTimeOnMin = 10;
|
||||
base.BotSpawnTimeOnMax = 30;
|
||||
|
||||
// Start-Stop wave wait times between active spawning
|
||||
base.BotSpawnTimeOffMin = 240;
|
||||
base.BotSpawnTimeOffMax = 300;
|
||||
|
||||
// Probably how often it checks to spawn while active spawning
|
||||
base.BotSpawnPeriodCheck = 15;
|
||||
|
||||
// Bot count required to trigger a spawn
|
||||
base.BotSpawnCountStep = 3;
|
||||
|
||||
base.BotLocationModifier.NonWaveSpawnBotsLimitPerPlayer = 20;
|
||||
base.BotLocationModifier.NonWaveSpawnBotsLimitPerPlayerPvE = 20;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Start-Stop Time for spawns
|
||||
base.BotStart = ModConfig.config.scavConfig.waves.startSpawns;
|
||||
base.BotStop = (base.EscapeTimeLimit * 60) - ModConfig.config.scavConfig.waves.stopSpawns;
|
||||
|
||||
// Start-Stop wave times for active spawning
|
||||
base.BotSpawnTimeOnMin = ModConfig.config.scavConfig.waves.activeTimeMin;
|
||||
base.BotSpawnTimeOnMax = ModConfig.config.scavConfig.waves.activeTimeMax;
|
||||
|
||||
// Start-Stop wave wait times between active spawning
|
||||
base.BotSpawnTimeOffMin = ModConfig.config.scavConfig.waves.quietTimeMin;
|
||||
base.BotSpawnTimeOffMax = ModConfig.config.scavConfig.waves.quietTimeMax;
|
||||
|
||||
// Probably how often it checks to spawn while active spawning
|
||||
base.BotSpawnPeriodCheck = ModConfig.config.scavConfig.waves.checkToSpawnTimer;
|
||||
|
||||
// Bot count required to trigger a spawn
|
||||
base.BotSpawnCountStep = ModConfig.config.scavConfig.waves.pendingBotsToTrigger;
|
||||
|
||||
base.BotLocationModifier.NonWaveSpawnBotsLimitPerPlayer = 20;
|
||||
base.BotLocationModifier.NonWaveSpawnBotsLimitPerPlayerPvE = 20;
|
||||
}
|
||||
}
|
||||
|
||||
public removeExistingWaves(base: any): void
|
||||
{
|
||||
base.waves = [];
|
||||
}
|
||||
|
||||
public fixPMCHostility(base: ILocationBase): void
|
||||
{
|
||||
const hostility = base.BotLocationModifier?.AdditionalHostilitySettings;
|
||||
if (hostility)
|
||||
{
|
||||
for (const bot in hostility)
|
||||
{
|
||||
if (hostility[bot].BotRole == "pmcUSEC" || hostility[bot].BotRole == "pmcBEAR")
|
||||
{
|
||||
const newHostilitySettings = this.cloner.clone(newPMCHostilitySettings);
|
||||
newHostilitySettings.BotRole = hostility[bot].BotRole;
|
||||
hostility[bot] = newHostilitySettings;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public removeCustomPMCWaves(): void
|
||||
{
|
||||
this.pmcConfig.removeExistingPmcWaves = false;
|
||||
this.pmcConfig.customPmcWaves = {};
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,64 @@
|
|||
export const newPMCHostilitySettings =
|
||||
{
|
||||
AlwaysEnemies: [
|
||||
"arenaFighter",
|
||||
"arenaFighterEvent",
|
||||
"assault",
|
||||
"assaultGroup",
|
||||
"bossBoar",
|
||||
"bossBoarSniper",
|
||||
"bossBully",
|
||||
"bossGluhar",
|
||||
"bossKilla",
|
||||
"bossKnight",
|
||||
"bossKojaniy",
|
||||
"bossKolontay",
|
||||
"bossPartisan",
|
||||
"bossSanitar",
|
||||
"bossTagilla",
|
||||
"crazyAssaultEvent",
|
||||
"cursedAssault",
|
||||
"exUsec",
|
||||
"followerBigPipe",
|
||||
"followerBirdEye",
|
||||
"followerBoar",
|
||||
"followerBoarClose1",
|
||||
"followerBoarClose2",
|
||||
"followerGluharAssault",
|
||||
"followerGluharScout",
|
||||
"followerGluharSecurity",
|
||||
"followerGluharSnipe",
|
||||
"followerKojaniy",
|
||||
"followerKolontayAssault",
|
||||
"followerKolontaySecurity",
|
||||
"followerSanitar",
|
||||
"followerTagilla",
|
||||
"marksman",
|
||||
"peacemaker",
|
||||
"pmcBEAR",
|
||||
"pmcBot",
|
||||
"pmcUSEC",
|
||||
"sectactPriestEvent",
|
||||
"sectantPriest",
|
||||
"sectantWarrior",
|
||||
"skier",
|
||||
"spiritSpring",
|
||||
"spiritWinter"
|
||||
],
|
||||
AlwaysFriends: [
|
||||
"bossZryachiy",
|
||||
"followerZryachiy",
|
||||
"gifter",
|
||||
"peacefullZryachiyEvent",
|
||||
"ravangeZryachiyEvent"
|
||||
],
|
||||
BearEnemyChance: 100,
|
||||
BearPlayerBehaviour: "AlwaysEnemies",
|
||||
BotRole: "",
|
||||
ChancedEnemies: [],
|
||||
Neutral: [],
|
||||
SavagePlayerBehaviour: "AlwaysEnemies",
|
||||
UsecEnemyChance: 100,
|
||||
UsecPlayerBehaviour: "AlwaysEnemies",
|
||||
Warn: []
|
||||
};
|
|
@ -0,0 +1,189 @@
|
|||
export const Customs_SpawnZones =
|
||||
[
|
||||
"ZoneBrige",
|
||||
"ZoneCrossRoad",
|
||||
"ZoneDormitory",
|
||||
"ZoneGasStation",
|
||||
"ZoneFactoryCenter",
|
||||
"ZoneFactorySide",
|
||||
"ZoneOldAZS",
|
||||
"ZoneBlockPost",
|
||||
"ZoneTankSquare",
|
||||
"ZoneWade",
|
||||
"ZoneCustoms",
|
||||
"ZoneScavBase"
|
||||
]
|
||||
|
||||
export const Customs_SnipeSpawnZones =
|
||||
[
|
||||
"ZoneSnipeBrige",
|
||||
"ZoneSnipeTower",
|
||||
"ZoneSnipeFactory",
|
||||
"ZoneBlockPostSniper"
|
||||
]
|
||||
export const Factory_SpawnZones =
|
||||
[
|
||||
"BotZone"
|
||||
]
|
||||
export const Interchange_SpawnZones =
|
||||
[
|
||||
"ZoneCenterBot",
|
||||
"ZoneIDEA",
|
||||
"ZoneCenter",
|
||||
"ZoneIDEAPark",
|
||||
"ZoneTrucks",
|
||||
"ZoneRoad",
|
||||
"ZoneOLI",
|
||||
"ZoneGoshan",
|
||||
"ZoneOLIPark",
|
||||
"ZonePowerStation"
|
||||
]
|
||||
export const Labs_GateSpawnZones =
|
||||
[
|
||||
"BotZoneGate1",
|
||||
"BotZoneGate2"
|
||||
]
|
||||
export const Labs_NonGateSpawnZones =
|
||||
[
|
||||
"BotZoneBasement",
|
||||
"BotZoneFloor1",
|
||||
"BotZoneFloor2"
|
||||
]
|
||||
export const Lighthouse_NonWaterTreatmentSpawnZones =
|
||||
[
|
||||
"Zone_Containers",
|
||||
"Zone_Rocks",
|
||||
"Zone_Chalet",
|
||||
"Zone_Village",
|
||||
"Zone_Bridge",
|
||||
"Zone_OldHouse",
|
||||
"Zone_LongRoad",
|
||||
"Zone_RoofBeach",
|
||||
"Zone_DestroyedHouse",
|
||||
"Zone_RoofContainers",
|
||||
"Zone_Blockpost",
|
||||
"Zone_RoofRocks",
|
||||
"Zone_TreatmentRocks",
|
||||
"Zone_TreatmentContainers",
|
||||
"Zone_TreatmentBeach",
|
||||
"Zone_Hellicopter",
|
||||
"Zone_SniperPeak",
|
||||
"Zone_Island"
|
||||
]
|
||||
export const Lighthouse_WaterTreatmentSpawnZones =
|
||||
[
|
||||
"Zone_Containers",
|
||||
"Zone_Rocks",
|
||||
"Zone_Chalet",
|
||||
"Zone_Village",
|
||||
"Zone_Bridge",
|
||||
"Zone_OldHouse",
|
||||
"Zone_LongRoad",
|
||||
"Zone_RoofBeach",
|
||||
"Zone_DestroyedHouse",
|
||||
"Zone_RoofContainers",
|
||||
"Zone_Blockpost",
|
||||
"Zone_RoofRocks",
|
||||
"Zone_TreatmentRocks",
|
||||
"Zone_TreatmentContainers",
|
||||
"Zone_TreatmentBeach",
|
||||
"Zone_Hellicopter",
|
||||
"Zone_Island"
|
||||
]
|
||||
export const Lighthouse_SnipeSpawnZones =
|
||||
[
|
||||
"Zone_SniperPeak"
|
||||
]
|
||||
|
||||
export const Reserve_SpawnZones =
|
||||
[
|
||||
"ZoneRailStrorage",
|
||||
"ZonePTOR1",
|
||||
"ZonePTOR2",
|
||||
"ZoneBarrack",
|
||||
"ZoneBunkerStorage",
|
||||
"ZoneSubStorage",
|
||||
"ZoneSubCommand"
|
||||
]
|
||||
export const GroundZero_SpawnZones =
|
||||
[
|
||||
"ZoneSandbox"
|
||||
]
|
||||
export const GroundZero_SnipeSpawnZones =
|
||||
[
|
||||
"ZoneSandSnipeCenter",
|
||||
"ZoneSandSnipeCenter2"
|
||||
]
|
||||
export const Shoreline_SpawnZones =
|
||||
[
|
||||
"ZoneGreenHouses",
|
||||
"ZoneIsland",
|
||||
"ZoneForestGasStation",
|
||||
"ZoneGasStation",
|
||||
"ZonePowerStation",
|
||||
"ZoneBunker",
|
||||
"ZoneBusStation",
|
||||
"ZonePort",
|
||||
"ZoneForestTruck",
|
||||
"ZoneForestSpawn",
|
||||
"ZoneSanatorium1",
|
||||
"ZoneSanatorium2",
|
||||
"ZoneStartVillage",
|
||||
"ZoneMeteoStation",
|
||||
"ZoneRailWays",
|
||||
"ZoneSmuglers",
|
||||
"ZonePassClose",
|
||||
"ZoneTunnel"
|
||||
]
|
||||
export const Shoreline_SnipeSpawnZones =
|
||||
[
|
||||
"ZoneBunkeSniper",
|
||||
"ZonePowerStationSniper"
|
||||
]
|
||||
export const Streets_SpawnZones =
|
||||
[
|
||||
"ZoneSW01",
|
||||
"ZoneConstruction",
|
||||
"ZoneCarShowroom",
|
||||
"ZoneCinema",
|
||||
"ZoneFactory",
|
||||
"ZoneHotel_1",
|
||||
"ZoneHotel_2",
|
||||
"ZoneConcordia_1",
|
||||
"ZoneConcordiaParking",
|
||||
"ZoneColumn",
|
||||
"ZoneSW00",
|
||||
"ZoneStilo",
|
||||
"ZoneCard1",
|
||||
"ZoneMvd",
|
||||
"ZoneClimova"
|
||||
]
|
||||
export const Streets_SnipeSpawnZones =
|
||||
[
|
||||
"ZoneSnipeCinema",
|
||||
"ZoneSnipeBuilding",
|
||||
"ZoneSnipeSW01",
|
||||
"ZoneSnipeStilo",
|
||||
"ZoneSnipeCard",
|
||||
"ZoneSnipeCarShowroom"
|
||||
]
|
||||
export const Woods_SpawnZones =
|
||||
[
|
||||
"ZoneWoodCutter",
|
||||
"ZoneHouse",
|
||||
"ZoneBigRocks",
|
||||
"ZoneRoad",
|
||||
"ZoneHighRocks",
|
||||
"ZoneMiniHouse",
|
||||
"ZoneRedHouse",
|
||||
"ZoneScavBase2",
|
||||
"ZoneClearVill",
|
||||
"ZoneBrokenVill",
|
||||
"ZoneUsecBase",
|
||||
"ZoneStoneBunker",
|
||||
"ZoneDepo"
|
||||
]
|
||||
export const Woods_SnipeSpawnZones =
|
||||
[
|
||||
"ZoneHighRocks"
|
||||
]
|
|
@ -0,0 +1,53 @@
|
|||
export const pmcUSECData =
|
||||
[
|
||||
{
|
||||
"BossChance": 100,
|
||||
"BossDifficult": "normal",
|
||||
"BossEscortAmount": "0",
|
||||
"BossEscortDifficult": "normal",
|
||||
"BossEscortType": "pmcUSEC",
|
||||
"BossName": "pmcUSEC",
|
||||
"BossPlayer": false,
|
||||
"BossZone": "",
|
||||
"Delay": 0,
|
||||
"DependKarma": false,
|
||||
"DependKarmaPVE": false,
|
||||
"ForceSpawn": false,
|
||||
"IgnoreMaxBots": true,
|
||||
"RandomTimeSpawn": false,
|
||||
"SpawnMode": [
|
||||
"pve"
|
||||
],
|
||||
"Supports": null,
|
||||
"Time": -1,
|
||||
"TriggerId": "",
|
||||
"TriggerName": ""
|
||||
}
|
||||
]
|
||||
|
||||
export const pmcBEARData =
|
||||
[
|
||||
{
|
||||
"BossChance": 100,
|
||||
"BossDifficult": "normal",
|
||||
"BossEscortAmount": "0",
|
||||
"BossEscortDifficult": "normal",
|
||||
"BossEscortType": "pmcBEAR",
|
||||
"BossName": "pmcBEAR",
|
||||
"BossPlayer": false,
|
||||
"BossZone": "",
|
||||
"Delay": 0,
|
||||
"DependKarma": false,
|
||||
"DependKarmaPVE": false,
|
||||
"ForceSpawn": false,
|
||||
"IgnoreMaxBots": true,
|
||||
"RandomTimeSpawn": false,
|
||||
"SpawnMode": [
|
||||
"pve"
|
||||
],
|
||||
"Supports": null,
|
||||
"Time": -1,
|
||||
"TriggerId": "",
|
||||
"TriggerName": ""
|
||||
}
|
||||
]
|
|
@ -0,0 +1,18 @@
|
|||
import { WildSpawnType } from "@spt/models/eft/common/ILocationBase";
|
||||
|
||||
export const scavData =
|
||||
{
|
||||
"BotPreset": "easy",
|
||||
"BotSide": "Savage",
|
||||
"SpawnMode": [
|
||||
"pve"
|
||||
],
|
||||
"SpawnPoints": "ZoneBrige",
|
||||
"WildSpawnType": WildSpawnType.ASSAULT,
|
||||
"isPlayers": false,
|
||||
"number": 0,
|
||||
"slots_max": 0,
|
||||
"slots_min": 0,
|
||||
"time_max": -1,
|
||||
"time_min": -1
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
import { inject, injectable } from "tsyringe";
|
||||
import type { FileSystemSync } from "@spt/utils/FileSystemSync";
|
||||
import type { ILogger } from "@spt/models/spt/utils/ILogger";
|
||||
import path from "node:path";
|
||||
import { MinMax } from "@spt/models/common/MinMax";
|
||||
|
||||
@injectable()
|
||||
export class ModConfig
|
||||
{
|
||||
public static config: Config;
|
||||
private lol: string;
|
||||
|
||||
constructor(
|
||||
@inject("PrimaryLogger") private logger: ILogger,
|
||||
@inject("FileSystemSync") private fileSystemSync: FileSystemSync
|
||||
)
|
||||
{
|
||||
ModConfig.config = this.fileSystemSync.readJson(path.resolve(__dirname, "../../config/config.json"));
|
||||
}
|
||||
}
|
||||
export interface Config
|
||||
{
|
||||
pmcDifficulty: Record<DifficultyConfig, number>,
|
||||
pmcConfig: PMCConfig,
|
||||
scavConfig: ScavConfig,
|
||||
bossDifficulty: Record<DifficultyConfig, number>,
|
||||
bossConfig: BossConfig,
|
||||
configAppSettings: ConfigAppSettings,
|
||||
}
|
||||
export interface PMCConfig
|
||||
{
|
||||
startingPMCs: PMCStartingConfig,
|
||||
waves: WaveConfig,
|
||||
}
|
||||
export interface ScavConfig
|
||||
{
|
||||
startingScavs: ScavStartingConfig,
|
||||
waves: ScavWaveConfig,
|
||||
}
|
||||
export interface ScavStartingConfig
|
||||
{
|
||||
enable: boolean,
|
||||
maxBotSpawns: ValidLocations,
|
||||
maxBotsPerZone: number,
|
||||
startingMarksman: boolean,
|
||||
}
|
||||
export interface ScavWaveConfig
|
||||
{
|
||||
enable: boolean,
|
||||
enableCustomFactory: boolean,
|
||||
startSpawns: number,
|
||||
stopSpawns: number,
|
||||
activeTimeMin: number,
|
||||
activeTimeMax: number,
|
||||
quietTimeMin: number,
|
||||
quietTimeMax: number,
|
||||
checkToSpawnTimer: number,
|
||||
pendingBotsToTrigger: number,
|
||||
}
|
||||
export type DifficultyConfig = "easy" | "normal" | "hard" | "impossible";
|
||||
export interface PMCStartingConfig
|
||||
{
|
||||
enable: boolean,
|
||||
ignoreMaxBotCaps: boolean,
|
||||
groupChance: number,
|
||||
maxGroupSize: number,
|
||||
maxGroupCount: number,
|
||||
mapLimits: MinMaxLocations
|
||||
}
|
||||
export interface WaveConfig
|
||||
{
|
||||
enable: boolean,
|
||||
ignoreMaxBotCaps: boolean,
|
||||
groupChance: number,
|
||||
maxGroupSize: number,
|
||||
maxGroupCount: number,
|
||||
maxBotsPerWave: number,
|
||||
delayBeforeFirstWave: number,
|
||||
secondsBetweenWaves: number,
|
||||
stopWavesBeforeEndOfRaidLimit: number
|
||||
}
|
||||
export interface BossConfig
|
||||
{
|
||||
bossKnight: BossLocationInfo,
|
||||
bossBully: BossLocationInfo,
|
||||
bossTagilla: BossLocationInfo,
|
||||
bossKilla: BossLocationInfo,
|
||||
bossZryachiy: BossLocationInfo,
|
||||
bossGluhar: BossLocationInfo,
|
||||
bossSanitar: BossLocationInfo,
|
||||
bossKolontay: BossLocationInfo,
|
||||
bossBoar: BossLocationInfo,
|
||||
bossKojaniy: BossLocationInfo,
|
||||
bossPartisan: BossLocationInfo,
|
||||
sectantPriest: BossLocationInfo,
|
||||
arenaFighterEvent: BossLocationInfo,
|
||||
pmcBot: SpecialLocationInfo,
|
||||
exUsec: SpecialLocationInfo,
|
||||
gifter: BossLocationInfo,
|
||||
}
|
||||
export interface BossLocationInfo
|
||||
{
|
||||
enable: boolean,
|
||||
time: number,
|
||||
spawnChance: ValidLocations,
|
||||
bossZone: ValidLocations;
|
||||
}
|
||||
export interface SpecialLocationInfo
|
||||
{
|
||||
enable: boolean,
|
||||
addExtraSpawns: boolean,
|
||||
disableVanillaSpawns: boolean,
|
||||
time: number,
|
||||
spawnChance: ValidLocations,
|
||||
bossZone: ValidLocations;
|
||||
}
|
||||
export interface ValidLocations
|
||||
{
|
||||
bigmap: number | string,
|
||||
factory4_day: number | string,
|
||||
factory4_night: number | string,
|
||||
interchange: number | string,
|
||||
laboratory: number | string,
|
||||
lighthouse: number | string,
|
||||
rezervbase: number | string,
|
||||
sandbox: number | string,
|
||||
sandbox_high: number | string,
|
||||
shoreline: number | string,
|
||||
tarkovstreets: number | string,
|
||||
woods: number | string,
|
||||
}
|
||||
export interface MinMaxLocations
|
||||
{
|
||||
bigmap: MinMax,
|
||||
factory4_day: MinMax,
|
||||
factory4_night: MinMax,
|
||||
interchange: MinMax,
|
||||
laboratory: MinMax,
|
||||
lighthouse: MinMax,
|
||||
rezervbase: MinMax,
|
||||
sandbox: MinMax,
|
||||
sandbox_high: MinMax,
|
||||
shoreline: MinMax,
|
||||
tarkovstreets: MinMax,
|
||||
woods: MinMax,
|
||||
}
|
||||
|
||||
export interface ConfigAppSettings
|
||||
{
|
||||
showUndo: boolean,
|
||||
showDefault: boolean,
|
||||
disableAnimations: boolean
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
// SPT
|
||||
import { DependencyContainer, Lifecycle } from "tsyringe";
|
||||
import { PreSptModLoader } from "@spt/loaders/PreSptModLoader";
|
||||
import { ILogger } from "@spt/models/spt/utils/ILogger";
|
||||
import { StaticRouterModService } from "@spt/services/mod/staticRouter/StaticRouterModService";
|
||||
import { DatabaseService } from "@spt/services/DatabaseService";
|
||||
import { FileSystemSync } from "@spt/utils/FileSystemSync";
|
||||
|
||||
// Custom
|
||||
import { ModConfig } from "./Globals/ModConfig";
|
||||
import { MapSpawnControl } from "./Controls/MapSpawnControl";
|
||||
import { BossSpawnControl } from "./Controls/BossSpawnControl";
|
||||
import { ICloner } from "@spt/utils/cloners/ICloner";
|
||||
import { VanillaAdjustmentControl } from "./Controls/VanillaAdjustmentControl";
|
||||
import { PMCSpawnControl } from "./Controls/PMCSpawnControl";
|
||||
import { StaticRouterHooks } from "./Routers/StaticRouterHooks";
|
||||
import { WeightedRandomHelper } from "@spt/helpers/WeightedRandomHelper";
|
||||
import { ScavSpawnControl } from "./Controls/ScavSpawnControl";
|
||||
|
||||
export class InstanceManager
|
||||
{
|
||||
//#region accessible in or after preSptLoad
|
||||
public modName: string;
|
||||
public container: DependencyContainer;
|
||||
public preSptModLoader: PreSptModLoader;
|
||||
public logger: ILogger;
|
||||
public fileSystemSync: FileSystemSync;
|
||||
public cloner: ICloner;
|
||||
public staticRouterModService: StaticRouterModService;
|
||||
|
||||
public staticRouterHooks: StaticRouterHooks;
|
||||
public modConfig: ModConfig;
|
||||
//#endregion
|
||||
|
||||
//#region accessible in or after postDBLoad
|
||||
public databaseService: DatabaseService;
|
||||
public weightedRandomHelper: WeightedRandomHelper;
|
||||
public vanillaAdjustmentControl: VanillaAdjustmentControl;
|
||||
public bossSpawnControl: BossSpawnControl;
|
||||
public pmcSpawnControl: PMCSpawnControl;
|
||||
public scavSpawnControl: ScavSpawnControl;
|
||||
public mapSpawnControl: MapSpawnControl;
|
||||
//#endregion
|
||||
|
||||
//#region accessible in or after PostSptLoad
|
||||
|
||||
//#endregion
|
||||
|
||||
// Call at the start of the mods postDBLoad method
|
||||
public preSptLoad(container: DependencyContainer, mod: string): void
|
||||
{
|
||||
this.modName = mod;
|
||||
this.container = container;
|
||||
|
||||
// SPT Classes
|
||||
this.preSptModLoader = container.resolve<PreSptModLoader>("PreSptModLoader");
|
||||
this.logger = container.resolve<ILogger>("WinstonLogger");
|
||||
this.fileSystemSync = container.resolve<FileSystemSync>("FileSystemSync");
|
||||
this.cloner = container.resolve<ICloner>("PrimaryCloner");
|
||||
this.staticRouterModService = container.resolve<StaticRouterModService>("StaticRouterModService");
|
||||
|
||||
// Custom Classes
|
||||
this.container.register<VanillaAdjustmentControl>("VanillaAdjustmentControl", VanillaAdjustmentControl, { lifecycle: Lifecycle.Singleton })
|
||||
this.container.register<BossSpawnControl>("BossSpawnControl", BossSpawnControl, { lifecycle: Lifecycle.Singleton })
|
||||
this.container.register<ScavSpawnControl>("ScavSpawnControl", ScavSpawnControl, { lifecycle: Lifecycle.Singleton })
|
||||
this.container.register<PMCSpawnControl>("PMCSpawnControl", PMCSpawnControl, { lifecycle: Lifecycle.Singleton })
|
||||
this.container.register<MapSpawnControl>("MapSpawnControl", MapSpawnControl, { lifecycle: Lifecycle.Singleton })
|
||||
|
||||
this.container.register<StaticRouterHooks>("StaticRouterHooks", StaticRouterHooks, { lifecycle: Lifecycle.Singleton })
|
||||
this.staticRouterHooks = container.resolve<StaticRouterHooks>("StaticRouterHooks");
|
||||
|
||||
// Custom Special
|
||||
|
||||
// Resolve this last to set mod configs
|
||||
this.container.register<ModConfig>("ModConfig", ModConfig, { lifecycle: Lifecycle.Singleton })
|
||||
this.modConfig = container.resolve<ModConfig>("ModConfig");
|
||||
}
|
||||
|
||||
public postDBLoad(container: DependencyContainer): void
|
||||
{
|
||||
// SPT Classes
|
||||
this.databaseService = container.resolve<DatabaseService>("DatabaseService");
|
||||
this.weightedRandomHelper = container.resolve<WeightedRandomHelper>("WeightedRandomHelper");
|
||||
this.vanillaAdjustmentControl = container.resolve<VanillaAdjustmentControl>("VanillaAdjustmentControl");
|
||||
this.bossSpawnControl = container.resolve<BossSpawnControl>("BossSpawnControl");
|
||||
this.scavSpawnControl = container.resolve<ScavSpawnControl>("ScavSpawnControl");
|
||||
this.pmcSpawnControl = container.resolve<PMCSpawnControl>("PMCSpawnControl");
|
||||
this.mapSpawnControl = container.resolve<MapSpawnControl>("MapSpawnControl");
|
||||
}
|
||||
|
||||
public postSptLoad(container: DependencyContainer): void
|
||||
{
|
||||
// SPT Classes
|
||||
this.databaseService = container.resolve<DatabaseService>("DatabaseService");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
import { inject, injectable } from "tsyringe";
|
||||
import { StaticRouterModService } from "@spt/services/mod/staticRouter/StaticRouterModService";
|
||||
import { MapSpawnControl } from "../Controls/MapSpawnControl";
|
||||
import path from "node:path";
|
||||
import { FileSystemSync } from "@spt/utils/FileSystemSync";
|
||||
|
||||
@injectable()
|
||||
export class StaticRouterHooks
|
||||
{
|
||||
public cacheRebuilt: boolean = false;
|
||||
public mapToRebuild: string = "";
|
||||
public bossTrackingData: BossTrackingData = null;
|
||||
|
||||
constructor(
|
||||
@inject("StaticRouterModService") protected staticRouterService: StaticRouterModService,
|
||||
@inject("MapSpawnControl") protected mapSpawnControl: MapSpawnControl,
|
||||
@inject("FileSystemSync") protected fileSystem: FileSystemSync
|
||||
)
|
||||
{}
|
||||
|
||||
public registerRouterHooks(): void
|
||||
{
|
||||
|
||||
this.staticRouterService.registerStaticRouter(
|
||||
"ABPS-StartMatchRouter",
|
||||
[
|
||||
{
|
||||
url: "/client/match/local/start",
|
||||
action: async (url, info, sessionId, output) =>
|
||||
{
|
||||
this.mapToRebuild = info.location;
|
||||
if (this.cacheRebuilt)
|
||||
{
|
||||
this.cacheRebuilt = false;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
}
|
||||
],
|
||||
"ABPS"
|
||||
);
|
||||
|
||||
this.staticRouterService.registerStaticRouter(
|
||||
"ABPS-EndMatchRouter",
|
||||
[
|
||||
{
|
||||
url: "/client/match/local/end",
|
||||
action: async (url, info, sessionId, output) =>
|
||||
{
|
||||
if (!this.cacheRebuilt)
|
||||
{
|
||||
this.mapSpawnControl.rebuildCache(this.mapToRebuild);
|
||||
this.cacheRebuilt = true;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
}
|
||||
],
|
||||
"ABPS"
|
||||
);
|
||||
|
||||
this.staticRouterService.registerStaticRouter(
|
||||
"ABPS-BossTrackingRoutes",
|
||||
[
|
||||
{
|
||||
url: "/abps/save",
|
||||
action: async (url, info: BossTrackingData, sessionId, output) => this.saveBossTrackingData(info)
|
||||
},
|
||||
{
|
||||
url: "/abps/load",
|
||||
action: async (url, info, sessionId, output) => JSON.stringify(this.bossTrackingData)
|
||||
}
|
||||
],
|
||||
"ABPS"
|
||||
);
|
||||
|
||||
this.load();
|
||||
}
|
||||
|
||||
private async saveBossTrackingData(payload: BossTrackingData): Promise<string>
|
||||
{
|
||||
if (!payload)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.bossTrackingData = payload;
|
||||
}
|
||||
|
||||
await this.save();
|
||||
return JSON.stringify({ success: true });
|
||||
}
|
||||
|
||||
private async save(): Promise<void>
|
||||
{
|
||||
try
|
||||
{
|
||||
const filename = path.join(__dirname, "../../bossTrackingData.json");
|
||||
await this.fileSystem.writeJson(filename, this.bossTrackingData, 2);
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
console.error("[ABPS] Failed to save boss tracking data! " + error);
|
||||
}
|
||||
}
|
||||
|
||||
public async load(): Promise<void>
|
||||
{
|
||||
const filename = path.join(__dirname, "../../bossTrackingData.json");
|
||||
if (this.fileSystem.exists(filename))
|
||||
{
|
||||
const jsonData = this.fileSystem.readJson(filename);
|
||||
this.bossTrackingData = jsonData;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.bossTrackingData = {};
|
||||
await this.save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type BossTrackingInfo = {
|
||||
spawnedLastRaid: boolean,
|
||||
chance: number,
|
||||
};
|
||||
|
||||
type BossTrackingData = Record<string, Record<string, BossTrackingInfo>>;
|
|
@ -0,0 +1,8 @@
|
|||
import { ExhaustableArray } from "@spt/models/spt/server/ExhaustableArray";
|
||||
import { ICloner } from "@spt/utils/cloners/ICloner";
|
||||
import { RandomUtil } from "@spt/utils/RandomUtil";
|
||||
|
||||
export function createExhaustableArray<T>(itemsToAddToArray: T[], randomUtil: RandomUtil, cloner: ICloner): ExhaustableArray<T>
|
||||
{
|
||||
return new ExhaustableArray<T>(itemsToAddToArray, randomUtil, cloner);
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
import { DependencyContainer } from "tsyringe";
|
||||
import { IPreSptLoadMod } from "@spt/models/external/IPreSptLoadMod";
|
||||
import { IPostDBLoadMod } from "@spt/models/external/IPostDBLoadMod";
|
||||
import { InstanceManager } from "./InstanceManager";
|
||||
import { ILogger } from "@spt/models/spt/utils/ILogger";
|
||||
import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
|
||||
import { ICoreConfig } from "@spt/models/spt/config/ICoreConfig";
|
||||
import { ConfigServer } from "@spt/servers/ConfigServer";
|
||||
import { FileSystemSync } from "@spt/utils/FileSystemSync";
|
||||
|
||||
import { minVersion, satisfies, SemVer } from "semver";
|
||||
import path from "node:path";
|
||||
|
||||
import { ILocationBase } from "@spt/models/eft/common/ILocationBase";
|
||||
import { IRaidChanges } from "@spt/models/spt/location/IRaidChanges";
|
||||
|
||||
|
||||
class ABPS implements IPreSptLoadMod, IPostDBLoadMod
|
||||
{
|
||||
// Create InstanceManager - Thank you Cj as per usual
|
||||
private instance: InstanceManager = new InstanceManager();
|
||||
|
||||
// PreSPTLoad
|
||||
public preSptLoad(container: DependencyContainer): void
|
||||
{
|
||||
const logger = container.resolve<ILogger>("WinstonLogger");
|
||||
if (!this.validSptVersion(container))
|
||||
{
|
||||
logger.error(`[ABPS] This version of ABPS was not made for your version of SPT. Disabling. Requires ${this.validMinimumSptVersion(container)} or higher.`);
|
||||
return;
|
||||
}
|
||||
|
||||
this.instance.preSptLoad(container, "ABPS");
|
||||
this.instance.staticRouterHooks.registerRouterHooks();
|
||||
|
||||
container.afterResolution("RaidTimeAdjustmentService", (_t, result: any) =>
|
||||
{
|
||||
result.adjustWaves = (mapBase: ILocationBase, raidAdjustments: IRaidChanges) =>
|
||||
{
|
||||
this.instance.mapSpawnControl.adjustWaves(mapBase, raidAdjustments);
|
||||
}
|
||||
}, {frequency: "Always"});
|
||||
}
|
||||
|
||||
// PostDBLoad
|
||||
public postDBLoad(container: DependencyContainer): void
|
||||
{
|
||||
this.instance.postDBLoad(container);
|
||||
this.instance.mapSpawnControl.configureInitialData();
|
||||
}
|
||||
|
||||
// Version Validation
|
||||
public validSptVersion(container: DependencyContainer): boolean
|
||||
{
|
||||
const fileSysem = container.resolve<FileSystemSync>("FileSystemSync");
|
||||
const configServer = container.resolve<ConfigServer>("ConfigServer");
|
||||
const sptConfig = configServer.getConfig<ICoreConfig>(ConfigTypes.CORE);
|
||||
|
||||
const sptVersion = globalThis.G_SPTVERSION || sptConfig.sptVersion;
|
||||
const packageJsonPath: string = path.join(__dirname, "../package.json");
|
||||
const modSptVersion = fileSysem.readJson(packageJsonPath).sptVersion;
|
||||
|
||||
return satisfies(sptVersion, modSptVersion);
|
||||
}
|
||||
|
||||
public validMinimumSptVersion(container: DependencyContainer): SemVer
|
||||
{
|
||||
const fileSysem = container.resolve<FileSystemSync>("FileSystemSync");
|
||||
const packageJsonPath: string = path.join(__dirname, "../package.json");
|
||||
const modSptVersion = fileSysem.readJson(packageJsonPath).sptVersion;
|
||||
|
||||
return minVersion(modSptVersion)
|
||||
}
|
||||
}
|
||||
|
||||
export const mod = new ABPS();
|
|
@ -1,28 +0,0 @@
|
|||
[General]
|
||||
gameName=spt
|
||||
modid=0
|
||||
version=d2025.1.13.0
|
||||
newestVersion=
|
||||
category="1,"
|
||||
nexusFileStatus=1
|
||||
installationFile=Additional Clothing BEAR 310.zip
|
||||
repository=Nexus
|
||||
ignoredVersion=
|
||||
comments=
|
||||
notes=
|
||||
nexusDescription=
|
||||
url=
|
||||
hasCustomURL=false
|
||||
lastNexusQuery=
|
||||
lastNexusUpdate=
|
||||
nexusLastModified=2025-01-13T13:28:06Z
|
||||
nexusCategory=0
|
||||
converted=false
|
||||
validated=false
|
||||
color=@Variant(\0\0\0\x43\0\xff\xff\0\0\0\0\0\0\0\0)
|
||||
tracked=0
|
||||
|
||||
[installedFiles]
|
||||
1\modid=0
|
||||
1\fileid=0
|
||||
size=1
|
|
@ -1,24 +0,0 @@
|
|||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <https://unlicense.org>
|
|
@ -1,423 +0,0 @@
|
|||
{
|
||||
"manifest": [
|
||||
{
|
||||
"key": "Tops/Gorka4MC_Top.bundle",
|
||||
"dependencyKeys": [
|
||||
"cubemaps",
|
||||
"shaders",
|
||||
"assets/content/characters/character/skeleton.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Hands/Gorka4MC_Hands.bundle",
|
||||
"dependencyKeys": [
|
||||
"cubemaps",
|
||||
"assets/content/hands/bear/bear_hands_watch_textures.bundle",
|
||||
"assets/content/textures/holemanager/round_spec_mask.bundle",
|
||||
"assets/content/hands/bear/bear_watch.bundle",
|
||||
"shaders"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Bottoms/EMR_voin.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/characters/character/skeleton.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Tops/EMR_SPN.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/characters/character/skeleton.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Hands/EMR_SPN_Hands.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/hands/bear/bear_hands_watch_texture.bundles",
|
||||
"assets/content/textures/holemanager/round_spec_mask.bundle",
|
||||
"assets/content/hands/bear/bear_watch.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Tops/EMRAutumnSumrak.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/characters/character/skeleton.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Hands/Sumrak_EMRAutumn_Hands.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/hands/usec/materials/watch_usec_textures",
|
||||
"assets/content/textures/holemanager/round_spec_mask.bundle",
|
||||
"assets/content/hands/bear/bear_watch.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Tops/EMRSumrak.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/characters/character/skeleton.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Hands/Sumrak_EMR_Hands.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/hands/usec/materials/watch_usec_textures",
|
||||
"assets/content/textures/holemanager/round_spec_mask.bundle",
|
||||
"assets/content/hands/bear/bear_watch.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Bottoms/BEARTacticalEMR.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/characters/character/skeleton.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Bottoms/TIGR_SURPAT.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/characters/character/skeleton.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Bottoms/TIGR_EMR.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/characters/character/skeleton.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Tops/Top_SS_SPN.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/characters/character/skeleton.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Hands/Hands_SS_SPN.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/hands/bear/bear_hands_watch_texture.bundles",
|
||||
"assets/content/textures/holemanager/round_spec_mask.bundle",
|
||||
"assets/content/hands/bear/bear_watch.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Tops/Top_Adaptive_SS.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/characters/character/skeleton.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Hands/Hands_AdaptiveSS.bundle",
|
||||
"dependencyKeys": [
|
||||
"cubemaps",
|
||||
"shaders",
|
||||
"assets/content/hands/usec/materials/watch_usec_textures",
|
||||
"assets/content/textures/holemanager/round_spec_mask.bundle",
|
||||
"assets/content/hands/bear/bear_watch.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Bottoms/SRVV_SS.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/characters/character/skeleton.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Hands/Hands_SURPAT_lynx.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/hands/usec/materials/watch_usec_textures",
|
||||
"assets/content/hands/bear/bear_hands_watch_texture.bundles",
|
||||
"assets/content/textures/holemanager/round_spec_mask.bundle",
|
||||
"assets/content/hands/bear/bear_watch.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Tops/Top_SURPAT_lynx.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/characters/character/skeleton.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Hands/Hands_MC_lynx.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/hands/usec/materials/watch_usec_textures",
|
||||
"assets/content/hands/bear/bear_hands_watch_texture.bundles",
|
||||
"assets/content/textures/holemanager/round_spec_mask.bundle",
|
||||
"assets/content/hands/bear/bear_watch.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Tops/Top_MC_lynx.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/characters/character/skeleton.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Bottoms/MC_voin.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/characters/character/skeleton.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Bottoms/TIGR_MC.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/characters/character/skeleton.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Hands/Hands_EMR_lynx.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/hands/usec/materials/watch_usec_textures",
|
||||
"assets/content/hands/bear/bear_hands_watch_texture.bundles",
|
||||
"assets/content/textures/holemanager/round_spec_mask.bundle",
|
||||
"assets/content/hands/bear/bear_watch.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Tops/EMR_lynx.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/characters/character/skeleton.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Tops/Top_MC_SPN.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/characters/character/skeleton.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Hands/Hands_MC_SPN.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/hands/bear/bear_hands_watch_texture.bundles",
|
||||
"assets/content/textures/holemanager/round_spec_mask.bundle",
|
||||
"assets/content/hands/bear/bear_watch.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Bottoms/SRVV_MC.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/characters/character/skeleton.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Bottoms/ReconMC.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/characters/character/skeleton.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Tops/Top_SURPAT_Polevoi.bundle",
|
||||
"dependencyKeys": [
|
||||
"cubemaps",
|
||||
"shaders",
|
||||
"assets/content/characters/character/skeleton.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Hands/Hands_SURPAT_Polevoi.bundle",
|
||||
"dependencyKeys": [
|
||||
"cubemaps",
|
||||
"assets/content/hands/bear/bear_hands_watch_texture.bundles",
|
||||
"assets/content/textures/holemanager/round_spec_mask.bundle",
|
||||
"assets/content/hands/bear/bear_watch.bundle",
|
||||
"shaders"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Tops/Top_Gorka5EMRAutumn.bundle",
|
||||
"dependencyKeys": [
|
||||
"cubemaps",
|
||||
"shaders",
|
||||
"assets/content/characters/character/skeleton.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Hands/Hands_Gorka5EMRAutumn.bundle",
|
||||
"dependencyKeys": [
|
||||
"cubemaps",
|
||||
"assets/content/hands/bear/bear_hands_watch_texture.bundles",
|
||||
"assets/content/textures/holemanager/round_spec_mask.bundle",
|
||||
"assets/content/hands/bear/bear_watch.bundle",
|
||||
"shaders"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Bottoms/ReconSURPAT.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/characters/character/skeleton.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Bottoms/BEARTacticalSS.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/characters/character/skeleton.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Bottoms/URON_SURPAT.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/characters/character/skeleton.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Bottoms/URON_SS.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/characters/character/skeleton.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Tops/Top_SummerFieldEMR.bundle",
|
||||
"dependencyKeys": [
|
||||
"cubemaps",
|
||||
"shaders",
|
||||
"assets/content/characters/character/skeleton.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Hands/Hands_SummerFieldEMR.bundle",
|
||||
"dependencyKeys": [
|
||||
"cubemaps",
|
||||
"assets/content/hands/bear/bear_hands_watch_texture.bundles",
|
||||
"assets/content/textures/holemanager/round_spec_mask.bundle",
|
||||
"assets/content/hands/bear/bear_watch.bundle",
|
||||
"shaders"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Tops/Top_TigrEMR.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Hands/Hands_TigrEMR.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/hands/bear/bear_hands_watch_texture.bundles",
|
||||
"assets/content/textures/holemanager/round_spec_mask.bundle",
|
||||
"assets/content/hands/bear/bear_watch.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Tops/Top_GhostEMR.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/characters/character/skeleton.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Hands/Hands_GhostEMR.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/hands/bear/bear_hands_watch_texture.bundles",
|
||||
"assets/content/textures/holemanager/round_spec_mask.bundle",
|
||||
"assets/content/hands/bear/bear_watch.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Tops/Top_InfilEMR.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/characters/character/skeleton.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Hands/Hands_InfilEMR.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/hands/usec/materials/watch_usec_textures",
|
||||
"assets/content/textures/holemanager/round_spec_mask.bundle",
|
||||
"assets/content/hands/bear/bear_watch.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Bottoms/Bottom_InfilEMR.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/characters/character/skeleton.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Bottoms/Bottom_GhostEMR.bundle",
|
||||
"dependencyKeys": [
|
||||
"shaders",
|
||||
"cubemaps",
|
||||
"assets/content/characters/character/skeleton.bundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "Bottoms/Bottom_SummerFieldEMR.bundle",
|
||||
"dependencyKeys": [
|
||||
"cubemaps",
|
||||
"shaders",
|
||||
"assets/content/characters/character/skeleton.bundle"
|
||||
]
|
||||
}
|
||||
|
||||
]
|
||||
}
|
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Bottoms/BEARTacticalEMR.bundle (Stored with Git LFS)
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Bottoms/BEARTacticalEMR.bundle (Stored with Git LFS)
Binary file not shown.
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Bottoms/BEARTacticalSS.bundle (Stored with Git LFS)
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Bottoms/BEARTacticalSS.bundle (Stored with Git LFS)
Binary file not shown.
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Bottoms/Bottom_GhostEMR.bundle (Stored with Git LFS)
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Bottoms/Bottom_GhostEMR.bundle (Stored with Git LFS)
Binary file not shown.
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Bottoms/Bottom_InfilEMR.bundle (Stored with Git LFS)
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Bottoms/Bottom_InfilEMR.bundle (Stored with Git LFS)
Binary file not shown.
Binary file not shown.
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Bottoms/EMR_voin.bundle (Stored with Git LFS)
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Bottoms/EMR_voin.bundle (Stored with Git LFS)
Binary file not shown.
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Bottoms/MC_voin.bundle (Stored with Git LFS)
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Bottoms/MC_voin.bundle (Stored with Git LFS)
Binary file not shown.
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Bottoms/ReconMC.bundle (Stored with Git LFS)
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Bottoms/ReconMC.bundle (Stored with Git LFS)
Binary file not shown.
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Bottoms/ReconSURPAT.bundle (Stored with Git LFS)
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Bottoms/ReconSURPAT.bundle (Stored with Git LFS)
Binary file not shown.
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Bottoms/SRVV_MC.bundle (Stored with Git LFS)
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Bottoms/SRVV_MC.bundle (Stored with Git LFS)
Binary file not shown.
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Bottoms/SRVV_SS.bundle (Stored with Git LFS)
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Bottoms/SRVV_SS.bundle (Stored with Git LFS)
Binary file not shown.
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Bottoms/TIGR_EMR.bundle (Stored with Git LFS)
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Bottoms/TIGR_EMR.bundle (Stored with Git LFS)
Binary file not shown.
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Bottoms/TIGR_MC.bundle (Stored with Git LFS)
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Bottoms/TIGR_MC.bundle (Stored with Git LFS)
Binary file not shown.
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Bottoms/TIGR_SURPAT.bundle (Stored with Git LFS)
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Bottoms/TIGR_SURPAT.bundle (Stored with Git LFS)
Binary file not shown.
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Bottoms/URON_SS.bundle (Stored with Git LFS)
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Bottoms/URON_SS.bundle (Stored with Git LFS)
Binary file not shown.
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Bottoms/URON_SURPAT.bundle (Stored with Git LFS)
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Bottoms/URON_SURPAT.bundle (Stored with Git LFS)
Binary file not shown.
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Hands/EMR_SPN_Hands.bundle (Stored with Git LFS)
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Hands/EMR_SPN_Hands.bundle (Stored with Git LFS)
Binary file not shown.
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Hands/Gorka4MC_Hands.bundle (Stored with Git LFS)
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Hands/Gorka4MC_Hands.bundle (Stored with Git LFS)
Binary file not shown.
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Hands/Hands_AdaptiveSS.bundle (Stored with Git LFS)
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Hands/Hands_AdaptiveSS.bundle (Stored with Git LFS)
Binary file not shown.
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Hands/Hands_EMR_lynx.bundle (Stored with Git LFS)
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Hands/Hands_EMR_lynx.bundle (Stored with Git LFS)
Binary file not shown.
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Hands/Hands_GhostEMR.bundle (Stored with Git LFS)
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Hands/Hands_GhostEMR.bundle (Stored with Git LFS)
Binary file not shown.
Binary file not shown.
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Hands/Hands_InfilEMR.bundle (Stored with Git LFS)
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Hands/Hands_InfilEMR.bundle (Stored with Git LFS)
Binary file not shown.
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Hands/Hands_MC_SPN.bundle (Stored with Git LFS)
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Hands/Hands_MC_SPN.bundle (Stored with Git LFS)
Binary file not shown.
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Hands/Hands_MC_lynx.bundle (Stored with Git LFS)
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Hands/Hands_MC_lynx.bundle (Stored with Git LFS)
Binary file not shown.
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Hands/Hands_SS_SPN.bundle (Stored with Git LFS)
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Hands/Hands_SS_SPN.bundle (Stored with Git LFS)
Binary file not shown.
Binary file not shown.
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Hands/Hands_SURPAT_lynx.bundle (Stored with Git LFS)
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Hands/Hands_SURPAT_lynx.bundle (Stored with Git LFS)
Binary file not shown.
Binary file not shown.
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Hands/Hands_TigrEMR.bundle (Stored with Git LFS)
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Hands/Hands_TigrEMR.bundle (Stored with Git LFS)
Binary file not shown.
Binary file not shown.
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Hands/Sumrak_EMR_Hands.bundle (Stored with Git LFS)
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Hands/Sumrak_EMR_Hands.bundle (Stored with Git LFS)
Binary file not shown.
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Tops/EMRAutumnSumrak.bundle (Stored with Git LFS)
BIN
mods/Additional Clothing BEAR/user/mods/Additional Clothing BEAR/bundles/Tops/EMRAutumnSumrak.bundle (Stored with Git LFS)
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue