initial commit
30
.gitignore
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
## ALT-Mods
|
||||
*.exe
|
||||
*.zip
|
||||
bin/
|
||||
obj/
|
||||
*.editorconfig
|
||||
|
||||
## visual studio
|
||||
.vs
|
||||
.idea
|
||||
slnx.sqlite
|
||||
slnx-journal.sqlite
|
||||
|
||||
## nodejs
|
||||
node_modules
|
||||
node.exe
|
||||
package-lock.json
|
||||
|
||||
## windows
|
||||
desktop.ini
|
||||
|
||||
## ALT-Mods
|
||||
Faupi-HideoutMod/Project/bin
|
||||
Faupi-HideoutMod/Project/obj
|
||||
|
||||
Faupi-MunitionsExpert/MunitionsExpert/bin
|
||||
Faupi-MunitionsExpert/MunitionsExpert/obj
|
||||
|
||||
KcY-SeeItemValue/itemValue/bin
|
||||
KcY-SeeItemValue/itemValue/obj
|
@ -0,0 +1,32 @@
|
||||
University of Illinois/NCSA Open Source License Copyright (c) 2021 Faupi. All rights reserved.
|
||||
|
||||
Developed by:
|
||||
|
||||
Faupi
|
||||
|
||||
https://github.com/Faupi-SPTarkov/HideoutArchitect
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
with the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimers.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimers in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of Faupi, nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this Software without specific prior
|
||||
written permission.
|
||||
|
||||
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 CONTRIBUTORS
|
||||
OR COPYRIGHT HOLDERS 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 WITH THE SOFTWARE.
|
@ -0,0 +1,9 @@
|
||||
{
|
||||
"NeededForHideoutDefinition": "NextLevel"/*
|
||||
NeededForHideoutDefinition - Defines the logic used to determine which items are marked. See mod page for details.
|
||||
Options:
|
||||
NextLevel: Generally marks items required for the facility's next upgrade
|
||||
NextLevelReady: Marks items required for the facility's next upgrade only when its other facility pre-requisites are fulfilled. (e.g. Items for Lavatory 2 won't be marked until Water Collector 1 is finished.)*/,
|
||||
"TooltipHeaderColor": "#56C427"/*
|
||||
TooltipHeaderColor - Color of the tooltip 'Needed for hideout' header.*/
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "Faupi-HideoutArchitect",
|
||||
"author": "Faupi",
|
||||
"version": "1.4.1",
|
||||
"license": "NCSA Open Source",
|
||||
"main": "./src/hideoutarchitect.js",
|
||||
"akiVersion": "2.3.1"
|
||||
}
|
After Width: | Height: | Size: 553 B |
@ -0,0 +1,47 @@
|
||||
{
|
||||
"en": {
|
||||
"NEEDED FOR HIDEOUT": "Needed for hideout"
|
||||
},
|
||||
"cz": {
|
||||
"NEEDED FOR HIDEOUT": "Potřebné pro úkryt"
|
||||
},
|
||||
"pl": {
|
||||
"NEEDED FOR HIDEOUT": "Potrzebne do kryjówki"
|
||||
},
|
||||
"po": {
|
||||
"NEEDED FOR HIDEOUT": "Necessário para esconderijo"
|
||||
},
|
||||
"ch": {
|
||||
"NEEDED FOR HIDEOUT": "藏身之处所需"
|
||||
},
|
||||
"ru": {
|
||||
"NEEDED FOR HIDEOUT": "Необходим для укрытия"
|
||||
},
|
||||
"es": {
|
||||
"NEEDED FOR HIDEOUT": "Se necesita para el escondite"
|
||||
},
|
||||
"es-mx": {
|
||||
"NEEDED FOR HIDEOUT": "Se necesita para el escondite"
|
||||
},
|
||||
"ge": {
|
||||
"NEEDED FOR HIDEOUT": "Benötigt für Versteck"
|
||||
},
|
||||
"sk": {
|
||||
"NEEDED FOR HIDEOUT": "Potrebné pre úkryt"
|
||||
},
|
||||
"tu": {
|
||||
"NEEDED FOR HIDEOUT": "saklanmak için gerekli"
|
||||
},
|
||||
"it": {
|
||||
"NEEDED FOR HIDEOUT": "Necessario per il nascondiglio"
|
||||
},
|
||||
"jp": {
|
||||
"NEEDED FOR HIDEOUT": "アジトに必要なもの"
|
||||
},
|
||||
"fr": {
|
||||
"NEEDED FOR HIDEOUT": "Nécessaire pour la cachette"
|
||||
},
|
||||
"hu": {
|
||||
"NEEDED FOR HIDEOUT": "Rejtekhelyhez szükséges"
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/* hideoutarchitect.js
|
||||
* license: NCSA
|
||||
* copyright: Faupi
|
||||
* authors:
|
||||
* - Faupi
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
const path = require('path');
|
||||
|
||||
class HideoutArchitect {
|
||||
constructor() {
|
||||
this.mod = require("../package.json");
|
||||
this.translations = require("../res/translations.json");
|
||||
Logger.info(`Loading: ${this.mod.name} ${this.mod.version}`);
|
||||
|
||||
ModLoader.onLoad[this.mod.name] = this.init.bind(this);
|
||||
}
|
||||
|
||||
init(){
|
||||
this.hookRoutes();
|
||||
this.loadLocalization();
|
||||
}
|
||||
|
||||
loadLocalization(){
|
||||
var globalLocale = DatabaseServer.tables.locales.global;
|
||||
|
||||
for(let language in this.translations){
|
||||
if(!language in globalLocale) continue;
|
||||
|
||||
let attrKvPair = this.translations[language];
|
||||
for(let attrKey in attrKvPair){
|
||||
let attrValue = attrKvPair[attrKey];
|
||||
|
||||
globalLocale[language].interface[attrKey] = attrValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log(data){
|
||||
// console.log(data);
|
||||
}
|
||||
|
||||
hookRoutes(){
|
||||
HttpRouter.onStaticRoute["/HideoutArchitect/GetInfo"] = {
|
||||
AttachmentOffset: this.getModInfo.bind(this)
|
||||
};
|
||||
}
|
||||
|
||||
getModInfo(url, info, sessionID, output){
|
||||
var output = {
|
||||
status: 1,
|
||||
data: null
|
||||
};
|
||||
|
||||
// Don't mind this pointless try catch
|
||||
try{
|
||||
output.data = {...this.mod, ...{path: path.resolve(ModLoader.getModPath(this.mod.name))}};
|
||||
output.status = 0;
|
||||
}catch(ex){
|
||||
throw ex;
|
||||
}
|
||||
|
||||
return JsonUtil.serialize(output);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new HideoutArchitect();
|
135
Faupi-HideoutMod/Project/HideoutArchitect.csproj
Normal file
@ -0,0 +1,135 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{21B1900E-2DFA-4C18-A1BD-E10907620FE3}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>HideoutArchitect</RootNamespace>
|
||||
<AssemblyName>HideoutArchitect</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<AssemblyOriginatorKeyFile>
|
||||
</AssemblyOriginatorKeyFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="src\client\HideoutItemViewPanel.cs" />
|
||||
<Compile Include="src\client\Main.cs" />
|
||||
<Compile Include="src\client\ModConfiguration.cs" />
|
||||
<Compile Include="src\client\ModInformation.cs" />
|
||||
<Compile Include="src\client\Patches.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="src\client\Resources.cs" />
|
||||
<Compile Include="src\client\Utils.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="package.json" />
|
||||
<None Include="res\translations.json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="res\icon_neededforhideout_small.png" />
|
||||
<Content Include="src\server\hideoutarchitect.js" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Aki.Common, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\EscapeFromTarkov_Data\Managed\Aki.Common.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Aki.Reflection, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\EscapeFromTarkov_Data\Managed\Aki.Reflection.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\EscapeFromTarkov_Data\Managed\Assembly-CSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="BepInEx">
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\BepInEx\core\BepInEx.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Comfort, Version=1.0.0.4, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\EscapeFromTarkov_Data\Managed\Comfort.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\EscapeFromTarkov_Data\Managed\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Sirenix.Serialization, Version=3.0.4.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\EscapeFromTarkov_Data\Managed\Sirenix.Serialization.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="Unity.TextMeshPro, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\EscapeFromTarkov_Data\Managed\Unity.TextMeshPro.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\EscapeFromTarkov_Data\Managed\UnityEngine.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\EscapeFromTarkov_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UI, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\EscapeFromTarkov_Data\Managed\UnityEngine.UI.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UnityWebRequestModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\EscapeFromTarkov_Data\Managed\UnityEngine.UnityWebRequestModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UnityWebRequestTextureModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\EscapeFromTarkov_Data\Managed\UnityEngine.UnityWebRequestTextureModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UnityWebRequestWWWModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\EscapeFromTarkov_Data\Managed\UnityEngine.UnityWebRequestWWWModule.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>set BuildDir=$(ProjectDir)_Build\Faupi-HideoutArchitect
|
||||
|
||||
powershell -Command "Remove-Item '%25BuildDir%25\*' -Recurse -Force"
|
||||
|
||||
copy "$(TargetPath)" "%25BuildDir%25\module.dll"
|
||||
xcopy "$(ProjectDir)src\server" "%25BuildDir%25\src" /K /D /H /Y /I
|
||||
xcopy "$(ProjectDir)res" "%25BuildDir%25\res" /K /D /H /Y /I
|
||||
copy "$(ProjectDir)package.json" "%25BuildDir%25\package.json"</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<ImportGroup Label=".NET DllExport">
|
||||
<Import Project="../packages/UnmanagedExports.1.2.6/tools/RGiesecke.DllExport.targets" Condition="Exists('../packages/UnmanagedExports.1.2.6/tools/RGiesecke.DllExport.targets')" />
|
||||
<Import Project="../packages/UnmanagedExports.1.2.7/tools/RGiesecke.DllExport.targets" Condition="Exists('../packages/UnmanagedExports.1.2.7/tools/RGiesecke.DllExport.targets')" />
|
||||
</ImportGroup>
|
||||
</Project>
|
25
Faupi-HideoutMod/Project/HideoutArchitect.sln
Normal file
@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.32014.148
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HideoutArchitect", "HideoutArchitect.csproj", "{21B1900E-2DFA-4C18-A1BD-E10907620FE3}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{21B1900E-2DFA-4C18-A1BD-E10907620FE3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{21B1900E-2DFA-4C18-A1BD-E10907620FE3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{21B1900E-2DFA-4C18-A1BD-E10907620FE3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{21B1900E-2DFA-4C18-A1BD-E10907620FE3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {DFEE36A3-C9ED-45DF-9015-A34EC8AB8641}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
32
Faupi-HideoutMod/Project/LICENSE
Normal file
@ -0,0 +1,32 @@
|
||||
University of Illinois/NCSA Open Source License Copyright (c) 2021 Faupi. All rights reserved.
|
||||
|
||||
Developed by:
|
||||
|
||||
Faupi
|
||||
|
||||
https://github.com/Faupi-SPTarkov/HideoutArchitect
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
with the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimers.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimers in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of Faupi, nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this Software without specific prior
|
||||
written permission.
|
||||
|
||||
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 CONTRIBUTORS
|
||||
OR COPYRIGHT HOLDERS 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 WITH THE SOFTWARE.
|
38
Faupi-HideoutMod/Project/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,38 @@
|
||||
using System.Resources;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Hideout Architect")]
|
||||
[assembly: AssemblyDescription("Similar to the Found in raid mark - Adds a Needed for hideout mark to items")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("SPT-AKI - HideoutArchitect")]
|
||||
[assembly: AssemblyCopyright("Faupi © 2021")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("21b1900e-2dfa-4c18-a1bd-e10907620fe3")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.1.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.1.0.0")]
|
||||
[assembly: NeutralResourcesLanguage("en-US")]
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "Faupi-HideoutArchitect",
|
||||
"author": "Faupi",
|
||||
"version": "1.2.1",
|
||||
"license": "NCSA Open Source",
|
||||
"main": "./src/hideoutarchitect.js",
|
||||
"akiVersion": "2.1.1"
|
||||
}
|
After Width: | Height: | Size: 553 B |
@ -0,0 +1,47 @@
|
||||
{
|
||||
"en": {
|
||||
"NEEDED FOR HIDEOUT": "Needed for hideout"
|
||||
},
|
||||
"cz": {
|
||||
"NEEDED FOR HIDEOUT": "Potřebné pro úkryt"
|
||||
},
|
||||
"pl": {
|
||||
"NEEDED FOR HIDEOUT": "Potrzebne do kryjówki"
|
||||
},
|
||||
"po": {
|
||||
"NEEDED FOR HIDEOUT": "Necessário para esconderijo"
|
||||
},
|
||||
"ch": {
|
||||
"NEEDED FOR HIDEOUT": "藏身之处所需"
|
||||
},
|
||||
"ru": {
|
||||
"NEEDED FOR HIDEOUT": "Необходим для укрытия"
|
||||
},
|
||||
"es": {
|
||||
"NEEDED FOR HIDEOUT": "Se necesita para el escondite"
|
||||
},
|
||||
"es-mx": {
|
||||
"NEEDED FOR HIDEOUT": "Se necesita para el escondite"
|
||||
},
|
||||
"ge": {
|
||||
"NEEDED FOR HIDEOUT": "Benötigt für Versteck"
|
||||
},
|
||||
"sk": {
|
||||
"NEEDED FOR HIDEOUT": "Potrebné pre úkryt"
|
||||
},
|
||||
"tu": {
|
||||
"NEEDED FOR HIDEOUT": "saklanmak için gerekli"
|
||||
},
|
||||
"it": {
|
||||
"NEEDED FOR HIDEOUT": "Necessario per il nascondiglio"
|
||||
},
|
||||
"jp": {
|
||||
"NEEDED FOR HIDEOUT": "アジトに必要なもの"
|
||||
},
|
||||
"fr": {
|
||||
"NEEDED FOR HIDEOUT": "Nécessaire pour la cachette"
|
||||
},
|
||||
"hu": {
|
||||
"NEEDED FOR HIDEOUT": "Rejtekhelyhez szükséges"
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/* hideoutarchitect.js
|
||||
* license: NCSA
|
||||
* copyright: Faupi
|
||||
* authors:
|
||||
* - Faupi
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
const path = require('path');
|
||||
|
||||
class HideoutArchitect {
|
||||
constructor() {
|
||||
this.mod = require("../package.json");
|
||||
this.translations = require("../res/translations.json");
|
||||
Logger.info(`Loading: ${this.mod.name} ${this.mod.version}`);
|
||||
|
||||
ModLoader.onLoad[this.mod.name] = this.init.bind(this);
|
||||
}
|
||||
|
||||
init(){
|
||||
this.hookRoutes();
|
||||
this.loadLocalization();
|
||||
}
|
||||
|
||||
loadLocalization(){
|
||||
var globalLocale = DatabaseServer.tables.locales.global;
|
||||
|
||||
for(let language in this.translations){
|
||||
if(!language in globalLocale) continue;
|
||||
|
||||
let attrKvPair = this.translations[language];
|
||||
for(let attrKey in attrKvPair){
|
||||
let attrValue = attrKvPair[attrKey];
|
||||
|
||||
globalLocale[language].interface[attrKey] = attrValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log(data){
|
||||
// console.log(data);
|
||||
}
|
||||
|
||||
hookRoutes(){
|
||||
HttpRouter.onStaticRoute["/HideoutArchitect/GetInfo"] = {
|
||||
AttachmentOffset: this.getModInfo.bind(this)
|
||||
};
|
||||
}
|
||||
|
||||
getModInfo(url, info, sessionID, output){
|
||||
var output = {
|
||||
status: 1,
|
||||
data: null
|
||||
};
|
||||
|
||||
// Don't mind this pointless try catch
|
||||
try{
|
||||
output.data = {...this.mod, ...{path: path.resolve(ModLoader.getModPath(this.mod.name))}};
|
||||
output.status = 0;
|
||||
}catch(ex){
|
||||
throw ex;
|
||||
}
|
||||
|
||||
return JsonUtil.serialize(output);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new HideoutArchitect();
|
BIN
Faupi-HideoutMod/Project/icon_neededforhideout_small.pdn
Normal file
8
Faupi-HideoutMod/Project/package.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "Faupi-HideoutArchitect",
|
||||
"author": "Faupi",
|
||||
"version": "1.2.1",
|
||||
"license": "NCSA Open Source",
|
||||
"main": "./src/hideoutarchitect.js",
|
||||
"akiVersion": "2.1.1"
|
||||
}
|
BIN
Faupi-HideoutMod/Project/res/icon_neededforhideout_small.png
Normal file
After Width: | Height: | Size: 553 B |
47
Faupi-HideoutMod/Project/res/translations.json
Normal file
@ -0,0 +1,47 @@
|
||||
{
|
||||
"en": {
|
||||
"NEEDED FOR HIDEOUT": "Needed for hideout"
|
||||
},
|
||||
"cz": {
|
||||
"NEEDED FOR HIDEOUT": "Potřebné pro úkryt"
|
||||
},
|
||||
"pl": {
|
||||
"NEEDED FOR HIDEOUT": "Potrzebne do kryjówki"
|
||||
},
|
||||
"po": {
|
||||
"NEEDED FOR HIDEOUT": "Necessário para esconderijo"
|
||||
},
|
||||
"ch": {
|
||||
"NEEDED FOR HIDEOUT": "藏身之处所需"
|
||||
},
|
||||
"ru": {
|
||||
"NEEDED FOR HIDEOUT": "Необходим для укрытия"
|
||||
},
|
||||
"es": {
|
||||
"NEEDED FOR HIDEOUT": "Se necesita para el escondite"
|
||||
},
|
||||
"es-mx": {
|
||||
"NEEDED FOR HIDEOUT": "Se necesita para el escondite"
|
||||
},
|
||||
"ge": {
|
||||
"NEEDED FOR HIDEOUT": "Benötigt für Versteck"
|
||||
},
|
||||
"sk": {
|
||||
"NEEDED FOR HIDEOUT": "Potrebné pre úkryt"
|
||||
},
|
||||
"tu": {
|
||||
"NEEDED FOR HIDEOUT": "saklanmak için gerekli"
|
||||
},
|
||||
"it": {
|
||||
"NEEDED FOR HIDEOUT": "Necessario per il nascondiglio"
|
||||
},
|
||||
"jp": {
|
||||
"NEEDED FOR HIDEOUT": "アジトに必要なもの"
|
||||
},
|
||||
"fr": {
|
||||
"NEEDED FOR HIDEOUT": "Nécessaire pour la cachette"
|
||||
},
|
||||
"hu": {
|
||||
"NEEDED FOR HIDEOUT": "Rejtekhelyhez szükséges"
|
||||
}
|
||||
}
|
97
Faupi-HideoutMod/Project/src/client/HideoutItemViewPanel.cs
Normal file
@ -0,0 +1,97 @@
|
||||
using EFT.Hideout;
|
||||
using EFT.InventoryLogic;
|
||||
using EFT.UI;
|
||||
using EFT.UI.DragAndDrop;
|
||||
using JetBrains.Annotations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace HideoutArchitect
|
||||
{
|
||||
public class HideoutItemViewPanel : UIElement
|
||||
{
|
||||
public Image iconImage; //_questIconImage
|
||||
public TextMeshProUGUI tooltipLabel; //_questItemLabel
|
||||
public SimpleTooltip tooltip; //simpleTooltip_0
|
||||
public string tooltipString; //string_3
|
||||
public ItemView itemView;
|
||||
|
||||
public bool initialized;
|
||||
|
||||
public void Init()
|
||||
{
|
||||
if (initialized) return;
|
||||
|
||||
HoverTrigger orAddComponent = base.gameObject.GetOrAddComponent<HoverTrigger>();
|
||||
orAddComponent.OnHoverStart += this.ShowTooltip;
|
||||
orAddComponent.OnHoverEnd += this.HideTooltip;
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
public void Show(Item item, ItemView itemView, [CanBeNull] SimpleTooltip tooltip)
|
||||
{
|
||||
Init();
|
||||
|
||||
this.itemView = itemView;
|
||||
|
||||
if (this.tooltipLabel != null)
|
||||
this.tooltipLabel.gameObject.SetActive(true);
|
||||
this.tooltip = tooltip;
|
||||
|
||||
UpdateTooltip();
|
||||
|
||||
if (HideoutArchitect.IsNeededForHideoutUpgrades(item))
|
||||
base.ShowGameObject();
|
||||
}
|
||||
|
||||
public void UpdateTooltip()
|
||||
{
|
||||
List<string> parts = new List<string>() { $"<color={HideoutArchitect.ModConfig.TooltipHeaderColor}><b>{"NEEDED FOR HIDEOUT".Localized().ToSentenceCase()}:</b></color>" };
|
||||
|
||||
List<AreaData> areasToUpgrade = HideoutArchitect.GetApplicableUpgrades(this.itemView.Item);
|
||||
if (areasToUpgrade == null || areasToUpgrade.Count < 1) return;
|
||||
|
||||
areasToUpgrade.ForEach(a =>
|
||||
{
|
||||
try
|
||||
{
|
||||
parts.Add($"<color=white>{a.Template.Name.ToSentenceCase() /*Already localized*/}:</color> {"LVL".Localized().ToSentenceCase()} {a.CurrentLevel + 1}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError(ex);
|
||||
}
|
||||
});
|
||||
|
||||
tooltipString = String.Join("\n", parts.Select(a => a.Trim()));
|
||||
}
|
||||
|
||||
private void ShowTooltip(PointerEventData arg)
|
||||
{
|
||||
if (!(this.tooltip == null) && !string.IsNullOrEmpty(this.tooltipString))
|
||||
{
|
||||
this.tooltip.Show(this.tooltipString, null, 0f, null, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void HideTooltip(PointerEventData arg)
|
||||
{
|
||||
if (!(this.tooltip == null) && !string.IsNullOrEmpty(this.tooltipString))
|
||||
{
|
||||
this.tooltip.Close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
135
Faupi-HideoutMod/Project/src/client/Main.cs
Normal file
@ -0,0 +1,135 @@
|
||||
using Comfort.Common;
|
||||
using EFT.Hideout;
|
||||
using EFT.InventoryLogic;
|
||||
using HideoutArchitect.Patches;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using BepInEx;
|
||||
using UnityEngine;
|
||||
using Hideout = GClass1588;
|
||||
using Requirement = GClass1612;
|
||||
|
||||
namespace HideoutArchitect
|
||||
{
|
||||
[BepInPlugin("com.FAUPI.HideoutArchitect", "FAUPI-HideoutArchitect", "2.0.0")]
|
||||
public class HideoutArchitect : BaseUnityPlugin
|
||||
{
|
||||
private void Awake()
|
||||
{
|
||||
_ = ModConfig; // Load the mod config
|
||||
_ = Resources.LoadTexture("neededforhideout", Path.Combine(ModInfo.path, "res/icon_neededforhideout_small.png"));
|
||||
Patcher.PatchAll();
|
||||
}
|
||||
|
||||
private static ModConfiguration _modConfig;
|
||||
public static ModConfiguration ModConfig
|
||||
{
|
||||
private set
|
||||
{
|
||||
_modConfig = value;
|
||||
}
|
||||
get
|
||||
{
|
||||
if (_modConfig == null)
|
||||
_modConfig = ModConfiguration.Load(ModInfo);
|
||||
return _modConfig;
|
||||
}
|
||||
}
|
||||
|
||||
private static ModInformation _modInfo;
|
||||
public static ModInformation ModInfo
|
||||
{
|
||||
private set
|
||||
{
|
||||
_modInfo = value;
|
||||
}
|
||||
get
|
||||
{
|
||||
if (_modInfo == null)
|
||||
_modInfo = ModInformation.Load();
|
||||
return _modInfo;
|
||||
}
|
||||
}
|
||||
|
||||
private static Transform _gameObjectStorage;
|
||||
public static Transform GameObjectStorage
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_gameObjectStorage == null)
|
||||
{
|
||||
GameObject storage = new GameObject("HideoutArchitect Storage");
|
||||
UnityEngine.Object.DontDestroyOnLoad(storage);
|
||||
storage.SetActive(false);
|
||||
_gameObjectStorage = storage.transform;
|
||||
}
|
||||
|
||||
return _gameObjectStorage;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<AreaData> GetApplicableUpgrades(Item item)
|
||||
{
|
||||
List<AreaData> areas = Singleton<Hideout>.Instance.AreaDatas.Where(area =>
|
||||
{
|
||||
bool areaActive = area.Status != EAreaStatus.NotSet && area.Template.Enabled == true;
|
||||
|
||||
List<Requirement> targetedRequirements;
|
||||
switch (ModConfig.NeededForHideoutDefinition)
|
||||
{
|
||||
case ENeededDefinition.NextLevel:
|
||||
case ENeededDefinition.NextLevelReady:
|
||||
targetedRequirements = area.NextStage.Requirements.Value as List<Requirement>;
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException(Enum.GetName(typeof(ENeededDefinition), ModConfig.NeededForHideoutDefinition));
|
||||
}
|
||||
|
||||
bool areaHasRequirements = targetedRequirements != null && targetedRequirements.Count > 0;
|
||||
|
||||
bool itemFitsRequirements = targetedRequirements.Any(genericRequirement =>
|
||||
{
|
||||
ItemRequirement itemRequirement = genericRequirement as ItemRequirement;
|
||||
if (itemRequirement == null) return false;
|
||||
return itemRequirement.TemplateId == item.TemplateId;
|
||||
});
|
||||
|
||||
bool fitsSpecialFilter = false;
|
||||
switch (ModConfig.NeededForHideoutDefinition)
|
||||
{
|
||||
case ENeededDefinition.NextLevel:
|
||||
fitsSpecialFilter = true; // None, we're only getting the item req
|
||||
break;
|
||||
|
||||
case ENeededDefinition.NextLevelReady:
|
||||
fitsSpecialFilter = targetedRequirements.All(genericRequirement => // Check if area requirement is fulfilled
|
||||
{
|
||||
if (genericRequirement is AreaRequirement)
|
||||
{
|
||||
return genericRequirement.Fulfilled; // If area requirements are fulfilled
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
);
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException(Enum.GetName(typeof(ENeededDefinition), ModConfig.NeededForHideoutDefinition));
|
||||
}
|
||||
return areaActive && areaHasRequirements && itemFitsRequirements && fitsSpecialFilter;
|
||||
}).ToList();
|
||||
|
||||
return areas;
|
||||
}
|
||||
|
||||
public static bool IsNeededForHideoutUpgrades(Item item)
|
||||
{
|
||||
List<AreaData> data = GetApplicableUpgrades(item);
|
||||
return data != null && data.Count > 0;
|
||||
}
|
||||
}
|
||||
}
|
128
Faupi-HideoutMod/Project/src/client/ModConfiguration.cs
Normal file
@ -0,0 +1,128 @@
|
||||
using Aki.Common.Utils;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HideoutArchitect
|
||||
{
|
||||
public enum ENeededDefinition
|
||||
{
|
||||
NextLevel,
|
||||
NextLevelReady
|
||||
}
|
||||
public class ModConfiguration
|
||||
{
|
||||
private string _tooltipHeaderColor = "#56C427";
|
||||
|
||||
[JsonConverter(typeof(Utils.StringEnumCommentConverter), "\n\tNeededForHideoutDefinition - Defines the logic used to determine which items are marked. See mod page for details. \n\tOptions: \n\t\tNextLevel: Generally marks items required for the facility's next upgrade\n\t\tNextLevelReady: Marks items required for the facility's next upgrade only when its other facility pre-requisites are fulfilled. (e.g. Items for Lavatory 2 won't be marked until Water Collector 1 is finished.)")]
|
||||
public ENeededDefinition NeededForHideoutDefinition = ENeededDefinition.NextLevel;
|
||||
|
||||
[JsonConverter(typeof(Utils.JsonCommentConverter), "\n\tTooltipHeaderColor - Color of the tooltip 'Needed for hideout' header.")]
|
||||
public string TooltipHeaderColor
|
||||
{
|
||||
get => _tooltipHeaderColor;
|
||||
set
|
||||
{
|
||||
if (value.IsValidHexColor())
|
||||
_tooltipHeaderColor = value;
|
||||
}
|
||||
}
|
||||
|
||||
public ModConfiguration()
|
||||
{
|
||||
}
|
||||
|
||||
public static ModConfiguration Load(ModInformation ModInfo)
|
||||
{
|
||||
string path = VFS.Combine(ModInfo.path, "config.jsonc");
|
||||
Debug.LogError($"Loading config from '{path}'");
|
||||
|
||||
ModConfiguration ModConfig;
|
||||
|
||||
string configJson = null;
|
||||
try
|
||||
{
|
||||
if (!VFS.Exists(path))
|
||||
throw new Exception($"No config on path {path} exists!");
|
||||
|
||||
configJson = VFS.ReadTextFile(path);
|
||||
ModConfig = JsonConvert.DeserializeObject<ModConfiguration>(configJson);
|
||||
}
|
||||
catch (Exception configReadingException)
|
||||
{
|
||||
string loadErrorMsg = $"[{ModInfo.name}] Could not load config!";
|
||||
Debug.LogError(loadErrorMsg);
|
||||
Debug.LogError(configReadingException);
|
||||
|
||||
// Recreate/fill config file
|
||||
JObject defaultConfig = JObject.Parse(JsonConvert.SerializeObject(new ModConfiguration()));
|
||||
if (configJson != null)
|
||||
{
|
||||
void LogBadJsonFormatting(Exception exception = null)
|
||||
{
|
||||
string mergeLoadedConfigMsg = $"[{ModInfo.name}] There was a {(exception != null ? "fatal " : string.Empty)}problem with loading config as JSON, there's likely a bad typo.";
|
||||
Debug.LogError(mergeLoadedConfigMsg);
|
||||
Debug.LogError(exception);
|
||||
Debug.LogError("Restoring config defaults completely.");
|
||||
}
|
||||
|
||||
if (configJson.IsValidJson())
|
||||
{
|
||||
try
|
||||
{
|
||||
Debug.LogError($"[{ModInfo.name}] Merging existing config data with defaults.");
|
||||
// If the file loaded at least partially, overwrite the defaults with it
|
||||
JObject loadedConfigPart = JObject.Parse(configJson);
|
||||
defaultConfig.Merge(loadedConfigPart, new JsonMergeSettings
|
||||
{
|
||||
// union array values together to avoid duplicates
|
||||
MergeArrayHandling = MergeArrayHandling.Union
|
||||
});
|
||||
}
|
||||
catch (Exception mergeLoadedConfigException)
|
||||
{
|
||||
LogBadJsonFormatting(mergeLoadedConfigException);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogBadJsonFormatting();
|
||||
}
|
||||
}
|
||||
|
||||
string fixedConfigJson = defaultConfig.ToString();
|
||||
try
|
||||
{
|
||||
Debug.LogError($"[{ModInfo.name}] Parsing default config to JSON\nJson: {fixedConfigJson}");
|
||||
ModConfig = JsonConvert.DeserializeObject<ModConfiguration>(fixedConfigJson);
|
||||
}
|
||||
catch (Exception configReconstructionException)
|
||||
{
|
||||
string fillErrorMsg = $"[{ModInfo.name}] Could not restore config values!";
|
||||
Debug.LogError(fillErrorMsg);
|
||||
Debug.LogError("Yell at Faupi with the logs.");
|
||||
|
||||
throw configReconstructionException; // Throw because at this point we can't really continue
|
||||
}
|
||||
|
||||
string completeConfigJson = JsonConvert.SerializeObject(ModConfig, Formatting.Indented);
|
||||
if (completeConfigJson != configJson) // There's a difference between the config file and actual config
|
||||
{
|
||||
try
|
||||
{
|
||||
Debug.LogError($"[{ModInfo.name}] Writing fixed config...");
|
||||
VFS.WriteTextFile(path, completeConfigJson.ToString(), false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Debug.LogError($"[{ModInfo.name}] There was a problem with writing the config.");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ModConfig;
|
||||
}
|
||||
}
|
||||
}
|
41
Faupi-HideoutMod/Project/src/client/ModInformation.cs
Normal file
@ -0,0 +1,41 @@
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Assertions;
|
||||
|
||||
namespace HideoutArchitect
|
||||
{
|
||||
public class ModInformation
|
||||
{
|
||||
public string name;
|
||||
public string author;
|
||||
public string version;
|
||||
public string license;
|
||||
public string main;
|
||||
public string path;
|
||||
|
||||
public static ModInformation Load()
|
||||
{
|
||||
ModInformation ModInfo;
|
||||
|
||||
JObject response = JObject.Parse(Aki.Common.Http.RequestHandler.GetJson($"/HideoutArchitect/GetInfo"));
|
||||
try
|
||||
{
|
||||
Assert.IsTrue(response.Value<int>("status") == 0);
|
||||
ModInfo = response["data"].ToObject<ModInformation>();
|
||||
}
|
||||
catch (Exception getModInfoException)
|
||||
{
|
||||
string errMsg = $"[{typeof(HideoutArchitect)}] Package.json couldn't be found! Make sure you've installed the mod on the server as well!";
|
||||
Debug.LogError(errMsg);
|
||||
throw getModInfoException;
|
||||
}
|
||||
|
||||
return ModInfo;
|
||||
}
|
||||
}
|
||||
}
|
121
Faupi-HideoutMod/Project/src/client/Patches.cs
Normal file
@ -0,0 +1,121 @@
|
||||
using EFT.InventoryLogic;
|
||||
using EFT.UI;
|
||||
using EFT.UI.DragAndDrop;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using Aki.Reflection.Patching;
|
||||
|
||||
namespace HideoutArchitect.Patches
|
||||
{
|
||||
class Patcher
|
||||
{
|
||||
public static void PatchAll()
|
||||
{
|
||||
new PatchManager().RunPatches();
|
||||
}
|
||||
}
|
||||
|
||||
public class PatchManager
|
||||
{
|
||||
public PatchManager()
|
||||
{
|
||||
this._patches = new List<ModulePatch>
|
||||
{
|
||||
new ItemViewPatches.GridItemViewUpdateInfoPatch(),
|
||||
new ItemViewPatches.ItemViewInitPatch(),
|
||||
new ItemViewPatches.NewGridItemViewPatch()
|
||||
};
|
||||
}
|
||||
|
||||
public void RunPatches()
|
||||
{
|
||||
foreach (ModulePatch patch in this._patches)
|
||||
{
|
||||
patch.Enable();
|
||||
}
|
||||
}
|
||||
|
||||
private readonly List<ModulePatch> _patches;
|
||||
}
|
||||
|
||||
public static class ItemViewPatches
|
||||
{
|
||||
public static Dictionary<ItemView, HideoutItemViewPanel> hideoutPanels = new Dictionary<ItemView, HideoutItemViewPanel>();
|
||||
|
||||
public static void SetHideoutItemViewPanel(this ItemView __instance)
|
||||
{
|
||||
if (!hideoutPanels.TryGetValue(__instance, out HideoutItemViewPanel hideoutItemViewPanel))
|
||||
return;
|
||||
|
||||
ItemUiContext itemUiContext = typeof(ItemView).GetField("ItemUiContext", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(__instance) as ItemUiContext;
|
||||
|
||||
if (hideoutItemViewPanel != null)
|
||||
{
|
||||
hideoutItemViewPanel.Show(__instance.Item, __instance, itemUiContext?.Tooltip);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public class NewGridItemViewPatch : ModulePatch
|
||||
{
|
||||
protected override MethodBase GetTargetMethod()
|
||||
{
|
||||
return typeof(GridItemView).GetMethod("NewGridItemView", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
}
|
||||
|
||||
[PatchPostfix]
|
||||
private static void PatchPostfix(ref GridItemView __instance, Item item)
|
||||
{
|
||||
if (hideoutPanels.ContainsKey(__instance)) return;
|
||||
try
|
||||
{
|
||||
QuestItemViewPanel questIconPanel = typeof(ItemView).GetField("_questsItemViewPanel", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(__instance) as QuestItemViewPanel;
|
||||
HideoutItemViewPanel hideoutIconPanel = GameObject.Instantiate(Resources.GetEditOffsetWindowTemplate(questIconPanel), questIconPanel.transform.parent);
|
||||
hideoutIconPanel.transform.SetAsFirstSibling();
|
||||
hideoutPanels[__instance] = hideoutIconPanel;
|
||||
|
||||
hideoutIconPanel.gameObject.SetActive(true);
|
||||
}
|
||||
catch {
|
||||
// Item doesn't have a "quest item" icon panel, so it's probably static
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ItemViewInitPatch : ModulePatch
|
||||
{
|
||||
protected override MethodBase GetTargetMethod()
|
||||
{
|
||||
return typeof(ItemView).GetMethod("Init", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
}
|
||||
|
||||
[PatchPostfix]
|
||||
private static void PatchPostfix(ref ItemView __instance)
|
||||
{
|
||||
__instance.SetHideoutItemViewPanel();
|
||||
}
|
||||
}
|
||||
|
||||
public class GridItemViewUpdateInfoPatch : ModulePatch
|
||||
{
|
||||
protected override MethodBase GetTargetMethod()
|
||||
{
|
||||
return typeof(GridItemView).GetMethod("UpdateInfo", BindingFlags.Instance | BindingFlags.Public);
|
||||
}
|
||||
|
||||
[PatchPostfix]
|
||||
private static void PatchPostfix(ref GridItemView __instance)
|
||||
{
|
||||
if (!__instance.IsSearched)
|
||||
return;
|
||||
|
||||
if (!hideoutPanels.TryGetValue(__instance, out HideoutItemViewPanel hideoutItemViewPanel))
|
||||
return;
|
||||
hideoutItemViewPanel.iconImage.gameObject.SetActive(HideoutArchitect.IsNeededForHideoutUpgrades(__instance.Item));
|
||||
|
||||
__instance.SetHideoutItemViewPanel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
81
Faupi-HideoutMod/Project/src/client/Resources.cs
Normal file
@ -0,0 +1,81 @@
|
||||
using EFT.UI;
|
||||
using EFT.UI.DragAndDrop;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace HideoutArchitect
|
||||
{
|
||||
public static class Resources
|
||||
{
|
||||
public static Dictionary<string, Sprite> iconCache = new Dictionary<string, Sprite>();
|
||||
static HideoutItemViewPanel hideoutItemViewTemplate;
|
||||
|
||||
public static HideoutItemViewPanel GetEditOffsetWindowTemplate(QuestItemViewPanel original = null)
|
||||
{
|
||||
if (hideoutItemViewTemplate != null)
|
||||
return hideoutItemViewTemplate;
|
||||
|
||||
if (original == null)
|
||||
throw new ArgumentNullException("original", "Can't be null if template isn't created yet!");
|
||||
|
||||
QuestItemViewPanel clone = GameObject.Instantiate<QuestItemViewPanel>(original);
|
||||
GameObject newObject = clone.gameObject;
|
||||
clone.transform.parent = HideoutArchitect.GameObjectStorage;
|
||||
newObject.name = "HideoutItem";
|
||||
|
||||
HideoutItemViewPanel result = newObject.AddComponent<HideoutItemViewPanel>();
|
||||
|
||||
//Copy fields over
|
||||
result.CopyFieldsFromQuestView(clone);
|
||||
|
||||
//Set custom sprite
|
||||
if(result.iconImage != null)
|
||||
{
|
||||
result.iconImage.sprite = iconCache["neededforhideout"] ?? UnityEngine.Resources.Load<Sprite>("characteristics/icons/icon_info_faction");
|
||||
}
|
||||
|
||||
GameObject.DestroyImmediate(clone);
|
||||
|
||||
hideoutItemViewTemplate = result;
|
||||
return hideoutItemViewTemplate;
|
||||
}
|
||||
|
||||
public static void CopyFieldsFromQuestView(this HideoutItemViewPanel hideoutItem, QuestItemViewPanel questItem)
|
||||
{
|
||||
hideoutItem.iconImage = typeof(QuestItemViewPanel).GetField("_questIconImage", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(questItem) as Image;
|
||||
hideoutItem.tooltipLabel = typeof(QuestItemViewPanel).GetField("_questItemLabel", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(questItem) as TextMeshProUGUI;
|
||||
hideoutItem.tooltip = typeof(QuestItemViewPanel).GetField("simpleTooltip_0", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(questItem) as SimpleTooltip;
|
||||
hideoutItem.tooltipString = typeof(QuestItemViewPanel).GetField("string_4", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(questItem) as string;
|
||||
}
|
||||
|
||||
|
||||
public static async Task LoadTexture(string id, string path)
|
||||
{
|
||||
using (UnityWebRequest uwr = UnityWebRequestTexture.GetTexture(path))
|
||||
{
|
||||
uwr.SendWebRequest();
|
||||
|
||||
while (!uwr.isDone)
|
||||
await Task.Delay(100);
|
||||
|
||||
if (uwr.responseCode != 200)
|
||||
{
|
||||
//Logger.Error($"[{HideoutArchitect.ModInfo.name}] Request error {uwr.responseCode}: {uwr.error}");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get downloaded asset bundle
|
||||
//Logger.Info($"[{HideoutArchitect.ModInfo.name}] Retrieved texture! {id.ToString()} from {path}");
|
||||
Texture2D cachedTexture = DownloadHandlerTexture.GetContent(uwr);
|
||||
iconCache.Add(id, Sprite.Create(cachedTexture, new Rect(0, 0, cachedTexture.width, cachedTexture.height), new Vector2(0, 0)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
113
Faupi-HideoutMod/Project/src/client/Utils.cs
Normal file
@ -0,0 +1,113 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HideoutArchitect
|
||||
{
|
||||
public static class Utils
|
||||
{
|
||||
public static string ToSentenceCase(this string text)
|
||||
{
|
||||
string result = text;
|
||||
try
|
||||
{
|
||||
// start by converting entire string to lower case
|
||||
var lowerCase = text.ToLower();
|
||||
// matches the first sentence of a string, as well as subsequent sentences
|
||||
var r = new Regex(@"(^[a-z])|\.\s+(.)", RegexOptions.ExplicitCapture);
|
||||
// MatchEvaluator delegate defines replacement of setence starts to uppercase
|
||||
result = r.Replace(lowerCase, s => s.Value.ToUpper());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError($"Error converting string case for '{text}': {ex}");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static bool IsValidHexColor(this string inputColor)
|
||||
{
|
||||
//Taken from https://stackoverflow.com/a/13035186
|
||||
if (Regex.Match(inputColor, "^#(?:[0-9a-fA-F]{3}){1,2}$").Success)
|
||||
return true;
|
||||
|
||||
var result = System.Drawing.Color.FromName(inputColor);
|
||||
return result.IsKnownColor;
|
||||
}
|
||||
|
||||
public static bool IsValidJson(this string strInput)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(strInput)) { return false; }
|
||||
strInput = strInput.Trim();
|
||||
if ((strInput.StartsWith("{") && strInput.EndsWith("}")) || //For object
|
||||
(strInput.StartsWith("[") && strInput.EndsWith("]"))) //For array
|
||||
{
|
||||
try
|
||||
{
|
||||
var obj = JToken.Parse(strInput);
|
||||
return true;
|
||||
}
|
||||
catch (JsonReaderException jex)
|
||||
{
|
||||
//Exception in parsing json
|
||||
Debug.LogError(jex.Message);
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex) //some other exception
|
||||
{
|
||||
Debug.LogError(ex.ToString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public class StringEnumCommentConverter : StringEnumConverter
|
||||
{
|
||||
//modification of https://stackoverflow.com/a/65001212
|
||||
private readonly string _comment;
|
||||
public StringEnumCommentConverter(string comment)
|
||||
{
|
||||
_comment = comment;
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
base.WriteJson(writer, value, serializer);
|
||||
writer.WriteComment(_comment); // append comment
|
||||
}
|
||||
}
|
||||
|
||||
public class JsonCommentConverter : JsonConverter
|
||||
{
|
||||
//modification of https://stackoverflow.com/a/65001212
|
||||
private readonly string _comment;
|
||||
public JsonCommentConverter(string comment)
|
||||
{
|
||||
_comment = comment;
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
|
||||
JsonSerializer serializer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
writer.WriteValue(value);
|
||||
writer.WriteComment(_comment); // append comment
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType) => true;
|
||||
public override bool CanRead => false;
|
||||
}
|
||||
}
|
||||
}
|
68
Faupi-HideoutMod/Project/src/server/hideoutarchitect.js
Normal file
@ -0,0 +1,68 @@
|
||||
/* hideoutarchitect.js
|
||||
* license: NCSA
|
||||
* copyright: Faupi
|
||||
* authors:
|
||||
* - Faupi
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
const path = require('path');
|
||||
|
||||
class HideoutArchitect {
|
||||
constructor() {
|
||||
this.mod = require("../package.json");
|
||||
this.translations = require("../res/translations.json");
|
||||
Logger.info(`Loading: ${this.mod.name} ${this.mod.version}`);
|
||||
|
||||
ModLoader.onLoad[this.mod.name] = this.init.bind(this);
|
||||
}
|
||||
|
||||
init(){
|
||||
this.hookRoutes();
|
||||
this.loadLocalization();
|
||||
}
|
||||
|
||||
loadLocalization(){
|
||||
var globalLocale = DatabaseServer.tables.locales.global;
|
||||
|
||||
for(let language in this.translations){
|
||||
if(!language in globalLocale) continue;
|
||||
|
||||
let attrKvPair = this.translations[language];
|
||||
for(let attrKey in attrKvPair){
|
||||
let attrValue = attrKvPair[attrKey];
|
||||
|
||||
globalLocale[language].interface[attrKey] = attrValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log(data){
|
||||
// console.log(data);
|
||||
}
|
||||
|
||||
hookRoutes(){
|
||||
HttpRouter.onStaticRoute["/HideoutArchitect/GetInfo"] = {
|
||||
AttachmentOffset: this.getModInfo.bind(this)
|
||||
};
|
||||
}
|
||||
|
||||
getModInfo(url, info, sessionID, output){
|
||||
var output = {
|
||||
status: 1,
|
||||
data: null
|
||||
};
|
||||
|
||||
// Don't mind this pointless try catch
|
||||
try{
|
||||
output.data = {...this.mod, ...{path: path.resolve(ModLoader.getModPath(this.mod.name))}};
|
||||
output.status = 0;
|
||||
}catch(ex){
|
||||
throw ex;
|
||||
}
|
||||
|
||||
return JsonUtil.serialize(output);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new HideoutArchitect();
|
4
Faupi-HideoutMod/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
# HideoutArchitect
|
||||
## Faupi-HideoutArchitect for EFT - SPT-AKI
|
||||
### CURRENT AKI VERSION: 2.2.1
|
||||
### GAMEVERSION: 0.12.12.15.16584
|
32
Faupi-MunitionsExpert/MunitionsExpert/LICENSE
Normal file
@ -0,0 +1,32 @@
|
||||
University of Illinois/NCSA Open Source License Copyright (c) 2021 Faupi. All rights reserved.
|
||||
|
||||
Developed by:
|
||||
|
||||
Faupi
|
||||
|
||||
https://github.com/Faupi-SPTarkov/MunitionsExpert
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
with the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimers.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimers in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of Faupi, nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this Software without specific prior
|
||||
written permission.
|
||||
|
||||
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 CONTRIBUTORS
|
||||
OR COPYRIGHT HOLDERS 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 WITH THE SOFTWARE.
|
113
Faupi-MunitionsExpert/MunitionsExpert/MunitionsExpert.csproj
Normal file
@ -0,0 +1,113 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{C5889536-4EE7-40BC-A8FD-7F1A80C3F3E5}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>MunitionsExpert</RootNamespace>
|
||||
<AssemblyName>Faupi-MunitionsExpert</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;/noentry</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<AssemblyOriginatorKeyFile>
|
||||
</AssemblyOriginatorKeyFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="src\client\StaticIconsPatch.cs" />
|
||||
<Compile Include="src\client\CachedAttributesPatch.cs" />
|
||||
<Compile Include="src\client\ModInformation.cs" />
|
||||
<Compile Include="src\client\Attributes.cs" />
|
||||
<Compile Include="src\client\MunitionsExpert.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="src\server\ammostats.js" />
|
||||
<Content Include="res\armorDamage.png" />
|
||||
<Content Include="res\ricochet.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="LICENSE" />
|
||||
<None Include="package.json" />
|
||||
<None Include="res\translations.json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="0Harmony">
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\BepInEx\core\0Harmony.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Aki.Common">
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\EscapeFromTarkov_Data\Managed\Aki.Common.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Aki.Reflection">
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\EscapeFromTarkov_Data\Managed\Aki.Reflection.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp">
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\EscapeFromTarkov_Data\Managed\Assembly-CSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="BepInEx">
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\BepInEx\core\BepInEx.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Comfort">
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\EscapeFromTarkov_Data\Managed\Comfort.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\References\EFT-Managed\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="UnityEngine">
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\EscapeFromTarkov_Data\Managed\UnityEngine.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.CoreModule">
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\EscapeFromTarkov_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UnityWebRequestModule">
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\EscapeFromTarkov_Data\Managed\UnityEngine.UnityWebRequestModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UnityWebRequestTextureModule">
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\EscapeFromTarkov_Data\Managed\UnityEngine.UnityWebRequestTextureModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.UnityWebRequestWWWModule">
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\EscapeFromTarkov_Data\Managed\UnityEngine.UnityWebRequestWWWModule.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="_Build\Faupi-MunitionsExpert\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>set BuildDir=$(ProjectDir)_Build\Faupi-MunitionsExpert
|
||||
|
||||
powershell -Command "Remove-Item '%25BuildDir%25\*' -Recurse -Force"
|
||||
|
||||
copy "$(TargetPath)" "%25BuildDir%25\module.dll"
|
||||
xcopy "$(ProjectDir)src\server" "%25BuildDir%25\src" /K /D /H /Y /I
|
||||
xcopy "$(ProjectDir)res" "%25BuildDir%25\res" /K /D /H /Y /I
|
||||
copy "$(ProjectDir)package.json" "%25BuildDir%25\package.json"</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
</Project>
|
25
Faupi-MunitionsExpert/MunitionsExpert/MunitionsExpert.sln
Normal file
@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.32014.148
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MunitionsExpert", "MunitionsExpert.csproj", "{C5889536-4EE7-40BC-A8FD-7F1A80C3F3E5}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{C5889536-4EE7-40BC-A8FD-7F1A80C3F3E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C5889536-4EE7-40BC-A8FD-7F1A80C3F3E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C5889536-4EE7-40BC-A8FD-7F1A80C3F3E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C5889536-4EE7-40BC-A8FD-7F1A80C3F3E5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C4FBDDAB-36FB-44F2-8D1D-4E7AF0E20BF1}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
@ -0,0 +1,38 @@
|
||||
using System.Resources;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("MunitionsExpert - Ammo stats in inspect view")]
|
||||
[assembly: AssemblyDescription("Adds ammo stats to inspect view as well as improving the format a little")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("SPT-AKI - MunitionsExpert")]
|
||||
[assembly: AssemblyCopyright("Faupi © 2021")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("c5889536-4ee7-40bc-a8fd-7f1a80c3f3e5")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.2.1.0")]
|
||||
[assembly: AssemblyFileVersion("1.2.1.0")]
|
||||
[assembly: NeutralResourcesLanguage("en-US")]
|
@ -0,0 +1,32 @@
|
||||
University of Illinois/NCSA Open Source License Copyright (c) 2021 Faupi. All rights reserved.
|
||||
|
||||
Developed by:
|
||||
|
||||
Faupi
|
||||
|
||||
https://github.com/Faupi-SPTarkov/MunitionsExpert
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
with the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimers.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimers in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of Faupi, nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this Software without specific prior
|
||||
written permission.
|
||||
|
||||
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 CONTRIBUTORS
|
||||
OR COPYRIGHT HOLDERS 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 WITH THE SOFTWARE.
|
@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "Faupi-MunitionsExpert",
|
||||
"author": "Faupi",
|
||||
"version": "1.4.1",
|
||||
"license": "NCSA Open Source",
|
||||
"main": "./src/ammostats.js",
|
||||
"akiVersion": "2.3.1",
|
||||
"updatedBy": "CWX"
|
||||
}
|
After Width: | Height: | Size: 701 B |
After Width: | Height: | Size: 732 B |
@ -0,0 +1,137 @@
|
||||
{
|
||||
"en": {
|
||||
"DAMAGE": "Damage",
|
||||
"PENETRATION": "Armor penetration",
|
||||
"ARMOR DAMAGE": "Damage to armor",
|
||||
"FRAGMENTATION CHANCE": "Fragmentation chance",
|
||||
"RICOCHET CHANCE": "Ricochet chance",
|
||||
"ME_class": "Class",
|
||||
"ME_noarmor": "Unarmored"
|
||||
},
|
||||
"cz": {
|
||||
"DAMAGE": "Poškození",
|
||||
"PENETRATION": "Průbojnost",
|
||||
"ARMOR DAMAGE": "Poškození brnění",
|
||||
"FRAGMENTATION CHANCE": "Šance na fragmentaci",
|
||||
"RICOCHET CHANCE": "Šance na odraz",
|
||||
"ME_class": "Třída",
|
||||
"ME_noarmor": "Neobrněný"
|
||||
},
|
||||
"pl": {
|
||||
"DAMAGE": "Szkoda",
|
||||
"PENETRATION": "Penetracja pancerza",
|
||||
"ARMOR DAMAGE": "Uszkodzenie zbroi",
|
||||
"FRAGMENTATION CHANCE": "Szansa na fragmentację",
|
||||
"RICOCHET CHANCE": "Szansa na rykoszet",
|
||||
"ME_class": "Klasa",
|
||||
"ME_noarmor": "Nieumiejętny"
|
||||
},
|
||||
"po": {
|
||||
"DAMAGE": "Dano",
|
||||
"PENETRATION": "Penetração de armadura",
|
||||
"ARMOR DAMAGE": "Danos à armadura",
|
||||
"FRAGMENTATION CHANCE": "Chance de fragmentação",
|
||||
"RICOCHET CHANCE": "Chance de ricochete",
|
||||
"ME_class": "Classe",
|
||||
"ME_noarmor": "Sem armadura"
|
||||
},
|
||||
"ch": {
|
||||
"DAMAGE": "损坏",
|
||||
"PENETRATION": "护甲穿透",
|
||||
"ARMOR DAMAGE": "对盔甲的伤害",
|
||||
"FRAGMENTATION CHANCE": "碎片机会",
|
||||
"RICOCHET CHANCE": "跳弹机会",
|
||||
"ME_class": "类",
|
||||
"ME_noarmor": "无所作为"
|
||||
},
|
||||
"ru": {
|
||||
"DAMAGE": "Повреждать",
|
||||
"PENETRATION": "Бронепробиваемость",
|
||||
"ARMOR DAMAGE": "Повреждение брони",
|
||||
"FRAGMENTATION CHANCE": "Вероятность фрагментации",
|
||||
"RICOCHET CHANCE": "Шанс рикошета",
|
||||
"ME_class": "Класс",
|
||||
"ME_noarmor": "Без оружия"
|
||||
},
|
||||
"es": {
|
||||
"DAMAGE": "Daño",
|
||||
"PENETRATION": "Penetración de armadura",
|
||||
"ARMOR DAMAGE": "Daño a la armadura",
|
||||
"FRAGMENTATION CHANCE": "Posibilidad de fragmentación",
|
||||
"RICOCHET CHANCE": "Oportunidad de rebote",
|
||||
"ME_class": "Clase",
|
||||
"ME_noarmor": "Sin armadura"
|
||||
},
|
||||
"es-mx": {
|
||||
"DAMAGE": "Daño",
|
||||
"PENETRATION": "Penetración de armadura",
|
||||
"ARMOR DAMAGE": "Daño a la armadura",
|
||||
"FRAGMENTATION CHANCE": "Posibilidad de fragmentación",
|
||||
"RICOCHET CHANCE": "Oportunidad de rebote",
|
||||
"ME_class": "Clase",
|
||||
"ME_noarmor": "Sin armadura"
|
||||
},
|
||||
"ge": {
|
||||
"DAMAGE": "Schaden",
|
||||
"PENETRATION": "Rüstungsdurchdringung",
|
||||
"ARMOR DAMAGE": "Beschädigung der Rüstung",
|
||||
"FRAGMENTATION CHANCE": "Fragmentierung Chance",
|
||||
"RICOCHET CHANCE": "Querschläger-Chance",
|
||||
"ME_class": "Klasse",
|
||||
"ME_noarmor": "Ungepanzert"
|
||||
},
|
||||
"sk": {
|
||||
"DAMAGE": "Poškodenie",
|
||||
"PENETRATION": "Prienik do brnenia",
|
||||
"ARMOR DAMAGE": "Poškodenie brnenia",
|
||||
"FRAGMENTATION CHANCE": "Šanca na fragmentáciu",
|
||||
"RICOCHET CHANCE": "Šanca na odraz",
|
||||
"ME_class": "Trieda",
|
||||
"ME_noarmor": "Neozbrojený"
|
||||
},
|
||||
"tu": {
|
||||
"DAMAGE": "Hasar",
|
||||
"PENETRATION": "Zırh penetrasyon",
|
||||
"ARMOR DAMAGE": "Zırhta hasar",
|
||||
"FRAGMENTATION CHANCE": "Parçalanma şansı",
|
||||
"RICOCHET CHANCE": "Sekme şansı",
|
||||
"ME_class": "Sınıf",
|
||||
"ME_noarmor": "zırhsız"
|
||||
},
|
||||
"it": {
|
||||
"DAMAGE": "Danno",
|
||||
"PENETRATION": "Penetrazione dell'armatura",
|
||||
"ARMOR DAMAGE": "Danni all'armatura",
|
||||
"FRAGMENTATION CHANCE": "Possibilità di frammentazione",
|
||||
"RICOCHET CHANCE": "Possibilità di rimbalzo",
|
||||
"ME_class": "Classe",
|
||||
"ME_noarmor": "Disarmato"
|
||||
},
|
||||
"jp": {
|
||||
"DAMAGE": "ダメージ",
|
||||
"PENETRATION": "装甲貫通",
|
||||
"ARMOR DAMAGE": "鎧の損傷",
|
||||
"FRAGMENTATION CHANCE": "断片化の可能性",
|
||||
"RICOCHET CHANCE": "跳ね返るチャンス",
|
||||
"ME_class": "クラス",
|
||||
"ME_noarmor": "無装甲"
|
||||
},
|
||||
"fr": {
|
||||
"DAMAGE": "Dommage",
|
||||
"PENETRATION": "Pénétration d'armure",
|
||||
"ARMOR DAMAGE": "Dommages à l'armure",
|
||||
"FRAGMENTATION CHANCE": "Chance de fragmentation",
|
||||
"RICOCHET CHANCE": "Chance de ricochet",
|
||||
"ME_class": "Classe",
|
||||
"ME_noarmor": "Sans armure"
|
||||
},
|
||||
"hu": {
|
||||
"DAMAGE": "Kár",
|
||||
"PENETRATION": "Páncélátütő",
|
||||
"ARMOR DAMAGE": "A páncél sérülése",
|
||||
"FRAGMENTATION CHANCE": "Töredezettség esélye",
|
||||
"RICOCHET CHANCE": "Ricochet esély",
|
||||
"ME_class": "Osztály",
|
||||
"ME_noarmor": "Fegyvertelen"
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
/* ammostats.js
|
||||
* license: NCSA
|
||||
* copyright: Faupi
|
||||
* authors:
|
||||
* - Faupi
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
const path = require('path');
|
||||
const cfg = require("./config.json");
|
||||
const DATABASE = DatabaseServer.tables.templates.items;
|
||||
|
||||
class AmmoStats {
|
||||
constructor() {
|
||||
this.mod = require("../package.json");
|
||||
this.translations = require("../res/translations.json");
|
||||
Logger.info(`Loading: ${this.mod.name} ${this.mod.version}`);
|
||||
|
||||
ModLoader.onLoad[this.mod.name] = this.init.bind(this);
|
||||
}
|
||||
|
||||
init(){
|
||||
this.hookRoutes();
|
||||
this.updateLocalization();
|
||||
this.changeBulletColour();
|
||||
}
|
||||
|
||||
updateLocalization(){
|
||||
var globalLocale = DatabaseServer.tables.locales.global;
|
||||
|
||||
for(let language in this.translations){
|
||||
if(!language in globalLocale) continue;
|
||||
|
||||
let attrKvPair = this.translations[language];
|
||||
for(let attrKey in attrKvPair){
|
||||
let attrValue = attrKvPair[attrKey];
|
||||
|
||||
globalLocale[language].interface[attrKey] = attrValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hookRoutes(){
|
||||
HttpRouter.onStaticRoute["/MunitionsExpert/GetInfo"] = {
|
||||
MunitionsExpert: this.getModInfo.bind(this)
|
||||
};
|
||||
}
|
||||
|
||||
getModInfo(url, info, sessionID, output){
|
||||
var output = {
|
||||
status: 1,
|
||||
data: null
|
||||
};
|
||||
|
||||
// Don't mind this pointless try catch
|
||||
try{
|
||||
output.data = {...this.mod, ...{path: path.resolve(ModLoader.getModPath(this.mod.name))}};
|
||||
output.status = 0;
|
||||
}catch(ex){
|
||||
throw ex;
|
||||
}
|
||||
|
||||
return JsonUtil.serialize(output);
|
||||
}
|
||||
|
||||
changeBulletColour()
|
||||
{
|
||||
if(cfg.BulletBackgroundColours === true)
|
||||
{
|
||||
for (const i in DATABASE) {
|
||||
let item = DATABASE[i]
|
||||
|
||||
//set baground colour of ammo depending on pen
|
||||
if (item._parent === "5485a8684bdc2da71d8b4567") {
|
||||
let pen = item._props.PenetrationPower
|
||||
let colour = ""
|
||||
|
||||
pen > 60 ? colour = "red" : //SuperPen
|
||||
pen > 50 ? colour = "yellow" : //HighPen
|
||||
pen > 40 ? colour = "violet" : //MedHighPen
|
||||
pen > 30 ? colour = "blue" : //MedPen
|
||||
pen > 20 ? colour = "green" : //LowMedPen
|
||||
colour = "grey" //LowPen
|
||||
item._props.BackgroundColor = colour
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new AmmoStats();
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"BulletBackgroundColours": true
|
||||
}
|
BIN
Faupi-MunitionsExpert/MunitionsExpert/res/armorDamage.png
Normal file
After Width: | Height: | Size: 701 B |
BIN
Faupi-MunitionsExpert/MunitionsExpert/res/ricochet.png
Normal file
After Width: | Height: | Size: 732 B |
137
Faupi-MunitionsExpert/MunitionsExpert/res/translations.json
Normal file
@ -0,0 +1,137 @@
|
||||
{
|
||||
"en": {
|
||||
"DAMAGE": "Damage",
|
||||
"PENETRATION": "Armor penetration",
|
||||
"ARMOR DAMAGE": "Damage to armor",
|
||||
"FRAGMENTATION CHANCE": "Fragmentation chance",
|
||||
"RICOCHET CHANCE": "Ricochet chance",
|
||||
"ME_class": "Class",
|
||||
"ME_noarmor": "Unarmored"
|
||||
},
|
||||
"cz": {
|
||||
"DAMAGE": "Poškození",
|
||||
"PENETRATION": "Průbojnost",
|
||||
"ARMOR DAMAGE": "Poškození brnění",
|
||||
"FRAGMENTATION CHANCE": "Šance na fragmentaci",
|
||||
"RICOCHET CHANCE": "Šance na odraz",
|
||||
"ME_class": "Třída",
|
||||
"ME_noarmor": "Neobrněný"
|
||||
},
|
||||
"pl": {
|
||||
"DAMAGE": "Szkoda",
|
||||
"PENETRATION": "Penetracja pancerza",
|
||||
"ARMOR DAMAGE": "Uszkodzenie zbroi",
|
||||
"FRAGMENTATION CHANCE": "Szansa na fragmentację",
|
||||
"RICOCHET CHANCE": "Szansa na rykoszet",
|
||||
"ME_class": "Klasa",
|
||||
"ME_noarmor": "Nieumiejętny"
|
||||
},
|
||||
"po": {
|
||||
"DAMAGE": "Dano",
|
||||
"PENETRATION": "Penetração de armadura",
|
||||
"ARMOR DAMAGE": "Danos à armadura",
|
||||
"FRAGMENTATION CHANCE": "Chance de fragmentação",
|
||||
"RICOCHET CHANCE": "Chance de ricochete",
|
||||
"ME_class": "Classe",
|
||||
"ME_noarmor": "Sem armadura"
|
||||
},
|
||||
"ch": {
|
||||
"DAMAGE": "损坏",
|
||||
"PENETRATION": "护甲穿透",
|
||||
"ARMOR DAMAGE": "对盔甲的伤害",
|
||||
"FRAGMENTATION CHANCE": "碎片机会",
|
||||
"RICOCHET CHANCE": "跳弹机会",
|
||||
"ME_class": "类",
|
||||
"ME_noarmor": "无所作为"
|
||||
},
|
||||
"ru": {
|
||||
"DAMAGE": "Повреждать",
|
||||
"PENETRATION": "Бронепробиваемость",
|
||||
"ARMOR DAMAGE": "Повреждение брони",
|
||||
"FRAGMENTATION CHANCE": "Вероятность фрагментации",
|
||||
"RICOCHET CHANCE": "Шанс рикошета",
|
||||
"ME_class": "Класс",
|
||||
"ME_noarmor": "Без оружия"
|
||||
},
|
||||
"es": {
|
||||
"DAMAGE": "Daño",
|
||||
"PENETRATION": "Penetración de armadura",
|
||||
"ARMOR DAMAGE": "Daño a la armadura",
|
||||
"FRAGMENTATION CHANCE": "Posibilidad de fragmentación",
|
||||
"RICOCHET CHANCE": "Oportunidad de rebote",
|
||||
"ME_class": "Clase",
|
||||
"ME_noarmor": "Sin armadura"
|
||||
},
|
||||
"es-mx": {
|
||||
"DAMAGE": "Daño",
|
||||
"PENETRATION": "Penetración de armadura",
|
||||
"ARMOR DAMAGE": "Daño a la armadura",
|
||||
"FRAGMENTATION CHANCE": "Posibilidad de fragmentación",
|
||||
"RICOCHET CHANCE": "Oportunidad de rebote",
|
||||
"ME_class": "Clase",
|
||||
"ME_noarmor": "Sin armadura"
|
||||
},
|
||||
"ge": {
|
||||
"DAMAGE": "Schaden",
|
||||
"PENETRATION": "Rüstungsdurchdringung",
|
||||
"ARMOR DAMAGE": "Beschädigung der Rüstung",
|
||||
"FRAGMENTATION CHANCE": "Fragmentierung Chance",
|
||||
"RICOCHET CHANCE": "Querschläger-Chance",
|
||||
"ME_class": "Klasse",
|
||||
"ME_noarmor": "Ungepanzert"
|
||||
},
|
||||
"sk": {
|
||||
"DAMAGE": "Poškodenie",
|
||||
"PENETRATION": "Prienik do brnenia",
|
||||
"ARMOR DAMAGE": "Poškodenie brnenia",
|
||||
"FRAGMENTATION CHANCE": "Šanca na fragmentáciu",
|
||||
"RICOCHET CHANCE": "Šanca na odraz",
|
||||
"ME_class": "Trieda",
|
||||
"ME_noarmor": "Neozbrojený"
|
||||
},
|
||||
"tu": {
|
||||
"DAMAGE": "Hasar",
|
||||
"PENETRATION": "Zırh penetrasyon",
|
||||
"ARMOR DAMAGE": "Zırhta hasar",
|
||||
"FRAGMENTATION CHANCE": "Parçalanma şansı",
|
||||
"RICOCHET CHANCE": "Sekme şansı",
|
||||
"ME_class": "Sınıf",
|
||||
"ME_noarmor": "zırhsız"
|
||||
},
|
||||
"it": {
|
||||
"DAMAGE": "Danno",
|
||||
"PENETRATION": "Penetrazione dell'armatura",
|
||||
"ARMOR DAMAGE": "Danni all'armatura",
|
||||
"FRAGMENTATION CHANCE": "Possibilità di frammentazione",
|
||||
"RICOCHET CHANCE": "Possibilità di rimbalzo",
|
||||
"ME_class": "Classe",
|
||||
"ME_noarmor": "Disarmato"
|
||||
},
|
||||
"jp": {
|
||||
"DAMAGE": "ダメージ",
|
||||
"PENETRATION": "装甲貫通",
|
||||
"ARMOR DAMAGE": "鎧の損傷",
|
||||
"FRAGMENTATION CHANCE": "断片化の可能性",
|
||||
"RICOCHET CHANCE": "跳ね返るチャンス",
|
||||
"ME_class": "クラス",
|
||||
"ME_noarmor": "無装甲"
|
||||
},
|
||||
"fr": {
|
||||
"DAMAGE": "Dommage",
|
||||
"PENETRATION": "Pénétration d'armure",
|
||||
"ARMOR DAMAGE": "Dommages à l'armure",
|
||||
"FRAGMENTATION CHANCE": "Chance de fragmentation",
|
||||
"RICOCHET CHANCE": "Chance de ricochet",
|
||||
"ME_class": "Classe",
|
||||
"ME_noarmor": "Sans armure"
|
||||
},
|
||||
"hu": {
|
||||
"DAMAGE": "Kár",
|
||||
"PENETRATION": "Páncélátütő",
|
||||
"ARMOR DAMAGE": "A páncél sérülése",
|
||||
"FRAGMENTATION CHANCE": "Töredezettség esélye",
|
||||
"RICOCHET CHANCE": "Ricochet esély",
|
||||
"ME_class": "Osztály",
|
||||
"ME_noarmor": "Fegyvertelen"
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
namespace MunitionsExpert
|
||||
{
|
||||
public static class Attributes
|
||||
{
|
||||
public enum ENewItemAttributeId
|
||||
{
|
||||
Damage,
|
||||
ArmorDamage,
|
||||
Penetration,
|
||||
FragmentationChance,
|
||||
RicochetChance
|
||||
}
|
||||
|
||||
public static string GetName(this ENewItemAttributeId id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case ENewItemAttributeId.Damage:
|
||||
return "DAMAGE";
|
||||
case ENewItemAttributeId.ArmorDamage:
|
||||
return "ARMOR DAMAGE";
|
||||
case ENewItemAttributeId.Penetration:
|
||||
return "PENETRATION";
|
||||
case ENewItemAttributeId.FragmentationChance:
|
||||
return "FRAGMENTATION CHANCE";
|
||||
case ENewItemAttributeId.RicochetChance:
|
||||
return "RICOCHET CHANCE";
|
||||
default:
|
||||
return id.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
using Aki.Reflection.Patching;
|
||||
using EFT.InventoryLogic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using ItemAttributes = GClass2090;
|
||||
|
||||
namespace MunitionsExpert
|
||||
{
|
||||
internal class CachedAttributesPatch : ModulePatch
|
||||
{
|
||||
protected override MethodBase GetTargetMethod()
|
||||
{
|
||||
return typeof(AmmoTemplate).GetMethod("GetCachedReadonlyQualities", BindingFlags.Instance | BindingFlags.Public);
|
||||
}
|
||||
|
||||
[PatchPostfix]
|
||||
private static void PatchPostfix(ref AmmoTemplate __instance, ref List<ItemAttributes> __result)
|
||||
{
|
||||
if (!__result.Any((ItemAttributes a) => (Attributes.ENewItemAttributeId)a.Id == Attributes.ENewItemAttributeId.Damage))
|
||||
{
|
||||
//MunitionsExpert.FormatExistingAttributes(ref __result, __instance);
|
||||
MunitionsExpert.AddNewAttributes(ref __result, __instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
using Aki.Common.Http;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Assertions;
|
||||
|
||||
namespace MunitionsExpert
|
||||
{
|
||||
public class ModInformation
|
||||
{
|
||||
public string name;
|
||||
public string author;
|
||||
public string version;
|
||||
public string license;
|
||||
public string main;
|
||||
public string path;
|
||||
|
||||
public static ModInformation Load()
|
||||
{
|
||||
ModInformation ModInfo;
|
||||
|
||||
JObject response = JObject.Parse(RequestHandler.GetJson($"/MunitionsExpert/GetInfo"));
|
||||
try
|
||||
{
|
||||
Assert.IsTrue(response.Value<int>("status") == 0);
|
||||
ModInfo = response["data"].ToObject<ModInformation>();
|
||||
}
|
||||
catch (Exception getModInfoException)
|
||||
{
|
||||
string errMsg = $"[{typeof(MunitionsExpert)}] Package.json couldn't be found! Make sure you've installed the mod on the server as well!";
|
||||
Debug.LogError(errMsg);
|
||||
throw getModInfoException;
|
||||
}
|
||||
|
||||
return ModInfo;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,166 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using EFT.InventoryLogic;
|
||||
using UnityEngine.Networking;
|
||||
using System.Threading.Tasks;
|
||||
using BepInEx;
|
||||
using Comfort.Common;
|
||||
|
||||
using ItemAttribute = GClass2090;
|
||||
using ItemAttributeCharacteristic = BulletClass; // left in as commented code uses this class
|
||||
using static MunitionsExpert.Attributes;
|
||||
using ServerSettings = GClass1103;
|
||||
|
||||
|
||||
namespace MunitionsExpert
|
||||
{
|
||||
[BepInPlugin("com.FAUPI.MunitionsExpert", "FAUPI-MunitionsExpert", "1.4.0")]
|
||||
public class MunitionsExpert : BaseUnityPlugin
|
||||
{
|
||||
private void Awake()
|
||||
{
|
||||
new CachedAttributesPatch().Enable();
|
||||
new StaticIconsPatch().Enable();
|
||||
CacheIcons();
|
||||
}
|
||||
|
||||
private static ModInformation _modInfo;
|
||||
public static ModInformation ModInfo
|
||||
{
|
||||
private set
|
||||
{
|
||||
_modInfo = value;
|
||||
}
|
||||
get
|
||||
{
|
||||
if (_modInfo == null)
|
||||
_modInfo = ModInformation.Load();
|
||||
return _modInfo;
|
||||
}
|
||||
}
|
||||
|
||||
public static Dictionary<Enum, Sprite> iconCache = new Dictionary<Enum, Sprite>();
|
||||
public static List<ItemAttribute> penAttributes = new List<ItemAttribute>(); // For refreshing armor class rating
|
||||
public static string modName = ModInfo.name;
|
||||
|
||||
public static void CacheIcons()
|
||||
{
|
||||
iconCache.Add(ENewItemAttributeId.Damage, Resources.Load<Sprite>("characteristics/icons/icon_info_damage"));
|
||||
iconCache.Add(ENewItemAttributeId.FragmentationChance, Resources.Load<Sprite>("characteristics/icons/icon_info_shrapnelcount"));
|
||||
iconCache.Add(EItemAttributeId.LightBleedingDelta, Resources.Load<Sprite>("characteristics/icons/icon_info_bloodloss"));
|
||||
iconCache.Add(EItemAttributeId.HeavyBleedingDelta, Resources.Load<Sprite>("characteristics/icon_info_hydration"));
|
||||
iconCache.Add(ENewItemAttributeId.Penetration, Resources.Load<Sprite>("characteristics/icon_info_penetration"));
|
||||
_ = LoadTexture(ENewItemAttributeId.ArmorDamage, Path.Combine(ModInfo.path, "res/armorDamage.png"));
|
||||
_ = LoadTexture(ENewItemAttributeId.RicochetChance, Path.Combine(ModInfo.path, "res/ricochet.png"));
|
||||
}
|
||||
|
||||
public static async Task LoadTexture(Enum id, string path)
|
||||
{
|
||||
using (UnityWebRequest uwr = UnityWebRequestTexture.GetTexture(path))
|
||||
{
|
||||
uwr.SendWebRequest();
|
||||
|
||||
while (!uwr.isDone)
|
||||
await Task.Delay(5);
|
||||
|
||||
if (uwr.responseCode != 200)
|
||||
{
|
||||
//Log.Error($"[{modName}] Request error {uwr.responseCode}: {uwr.error}");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get downloaded asset bundle
|
||||
//Log.Info($"[{modName}] Retrieved texture! {id.ToString()} from {path}");
|
||||
Texture2D cachedTexture = DownloadHandlerTexture.GetContent(uwr);
|
||||
iconCache.Add(id, Sprite.Create(cachedTexture, new Rect(0, 0, cachedTexture.width, cachedTexture.height), new Vector2(0, 0)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddNewAttributes(ref List<ItemAttribute> attributes, AmmoTemplate template)
|
||||
{
|
||||
int projCount = template.ProjectileCount;
|
||||
int totalDamage = template.Damage * template.ProjectileCount;
|
||||
|
||||
string damageStr = totalDamage.ToString(); // Total damage
|
||||
if (template.ProjectileCount > 1)
|
||||
{
|
||||
damageStr += $" ({template.Damage} x {template.ProjectileCount})"; // Add the "damage calculation" after total damage (damage per pellet * pellet count)
|
||||
}
|
||||
|
||||
ItemAttribute at_damage = new ItemAttribute(ENewItemAttributeId.Damage)
|
||||
{
|
||||
Name = ENewItemAttributeId.Damage.GetName(),
|
||||
Base = () => totalDamage,
|
||||
StringValue = () => damageStr,
|
||||
DisplayType = () => EItemAttributeDisplayType.Compact
|
||||
};
|
||||
attributes.Add(at_damage);
|
||||
|
||||
if (template.ArmorDamage > 0)
|
||||
{
|
||||
ItemAttribute at_armordmg = new ItemAttribute(ENewItemAttributeId.ArmorDamage)
|
||||
{
|
||||
Name = ENewItemAttributeId.ArmorDamage.GetName(),
|
||||
Base = () => template.ArmorDamage,
|
||||
StringValue = () => $"{(template.ArmorDamage).ToString()}%",
|
||||
DisplayType = () => EItemAttributeDisplayType.Compact
|
||||
};
|
||||
attributes.Add(at_armordmg);
|
||||
}
|
||||
|
||||
if (template.PenetrationPower > 0)
|
||||
{
|
||||
string getStringValue()
|
||||
{
|
||||
int ratedClass = 0;
|
||||
|
||||
if (!Singleton<ServerSettings>.Instantiated) { return $"CLASS_DATA_MISSING {template.PenetrationPower.ToString()}"; }
|
||||
ServerSettings.GClass1148.GClass1149[] classes = Singleton<ServerSettings>.Instance.Armor.ArmorClass;
|
||||
for (int i = 0; i < classes.Length; i++)
|
||||
{
|
||||
if (classes[i].Resistance > template.PenetrationPower) continue;
|
||||
ratedClass = Math.Max(ratedClass, i);
|
||||
}
|
||||
|
||||
return $"{(ratedClass > 0 ? $"{"ME_class".Localized()} {ratedClass}" : "ME_noarmor".Localized())} ({template.PenetrationPower.ToString()})";
|
||||
}
|
||||
|
||||
ItemAttribute at_pen = new ItemAttribute(ENewItemAttributeId.Penetration)
|
||||
{
|
||||
Name = ENewItemAttributeId.Penetration.GetName(),
|
||||
Base = () => template.PenetrationPower,
|
||||
StringValue = getStringValue,
|
||||
DisplayType = () => EItemAttributeDisplayType.Compact
|
||||
};
|
||||
attributes.Add(at_pen);
|
||||
}
|
||||
|
||||
if (template.FragmentationChance > 0)
|
||||
{
|
||||
ItemAttribute at_frag = new ItemAttribute(ENewItemAttributeId.FragmentationChance)
|
||||
{
|
||||
Name = ENewItemAttributeId.FragmentationChance.GetName(),
|
||||
Base = () => template.FragmentationChance,
|
||||
StringValue = () => $"{(template.FragmentationChance * 100).ToString()}%",
|
||||
DisplayType = () => EItemAttributeDisplayType.Compact
|
||||
};
|
||||
attributes.Add(at_frag);
|
||||
}
|
||||
|
||||
if (template.RicochetChance > 0)
|
||||
{
|
||||
ItemAttribute at_ricochet = new ItemAttribute(ENewItemAttributeId.RicochetChance)
|
||||
{
|
||||
Name = ENewItemAttributeId.RicochetChance.GetName(),
|
||||
Base = () => template.RicochetChance,
|
||||
StringValue = () => $"{(template.RicochetChance * 100).ToString()}%",
|
||||
DisplayType = () => EItemAttributeDisplayType.Compact
|
||||
};
|
||||
attributes.Add(at_ricochet);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Aki.Reflection.Patching;
|
||||
using EFT.UI;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MunitionsExpert
|
||||
{
|
||||
internal class StaticIconsPatch : ModulePatch
|
||||
{
|
||||
protected override MethodBase GetTargetMethod()
|
||||
{
|
||||
return typeof(StaticIcons).GetMethod("GetAttributeIcon", BindingFlags.Instance | BindingFlags.Public);
|
||||
}
|
||||
|
||||
[PatchPrefix]
|
||||
private static bool PatchPrefix(ref Sprite __result, Enum id)
|
||||
{
|
||||
if (id == null || !MunitionsExpert.iconCache.ContainsKey(id))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Sprite sprite = MunitionsExpert.iconCache[id];
|
||||
|
||||
if (sprite != null)
|
||||
{
|
||||
__result = sprite;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/* ammostats.js
|
||||
* license: NCSA
|
||||
* copyright: Faupi
|
||||
* authors:
|
||||
* - Faupi
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
const path = require('path');
|
||||
|
||||
class AmmoStats {
|
||||
constructor() {
|
||||
this.mod = require("../package.json");
|
||||
this.translations = require("../res/translations.json");
|
||||
Logger.info(`Loading: ${this.mod.name} ${this.mod.version}`);
|
||||
|
||||
ModLoader.onLoad[this.mod.name] = this.init.bind(this);
|
||||
}
|
||||
|
||||
init(){
|
||||
this.hookRoutes();
|
||||
this.updateLocalization();
|
||||
}
|
||||
|
||||
updateLocalization(){
|
||||
var globalLocale = DatabaseServer.tables.locales.global;
|
||||
|
||||
for(let language in this.translations){
|
||||
if(!language in globalLocale) continue;
|
||||
|
||||
let attrKvPair = this.translations[language];
|
||||
for(let attrKey in attrKvPair){
|
||||
let attrValue = attrKvPair[attrKey];
|
||||
|
||||
globalLocale[language].interface[attrKey] = attrValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hookRoutes(){
|
||||
HttpRouter.onStaticRoute["/MunitionsExpert/GetInfo"] = {
|
||||
MunitionsExpert: this.getModInfo.bind(this)
|
||||
};
|
||||
}
|
||||
|
||||
getModInfo(url, info, sessionID, output){
|
||||
var output = {
|
||||
status: 1,
|
||||
data: null
|
||||
};
|
||||
|
||||
// Don't mind this pointless try catch
|
||||
try{
|
||||
output.data = {...this.mod, ...{path: path.resolve(ModLoader.getModPath(this.mod.name))}};
|
||||
output.status = 0;
|
||||
}catch(ex){
|
||||
throw ex;
|
||||
}
|
||||
|
||||
return JsonUtil.serialize(output);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new AmmoStats();
|
4
Faupi-MunitionsExpert/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
# Faupi-MunitionsExpert
|
||||
## Faupi-MunitionsExpert for EFT - SPT-AKI
|
||||
### CURRENT AKI VERSION: 2.3.0
|
||||
### GAMEVERSION: 0.12.12.15.17107
|
@ -0,0 +1,34 @@
|
||||
University of Illinois/NCSA Open Source License
|
||||
|
||||
Copyright (c) [year] [fullname]. All rights reserved.
|
||||
|
||||
Developed by: [SEE ITEM VALUE]
|
||||
[KcY]
|
||||
[https://github.com/KeiranY/TarkovLoader]
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal with the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimers.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimers in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of [fullname], [project] nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this Software without specific prior written permission.
|
||||
|
||||
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
|
||||
CONTRIBUTORS OR COPYRIGHT HOLDERS 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 WITH
|
||||
THE SOFTWARE.
|
@ -0,0 +1,2 @@
|
||||
const { Mod } = require("./src/mod.js");
|
||||
module.exports.mod = new Mod();
|
@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "SeeItemValue",
|
||||
"author": "KcY",
|
||||
"version": "1.2.1",
|
||||
"license": "NCSA Open Source",
|
||||
"main": "modloader.js",
|
||||
"akiVersion": "2.3.1",
|
||||
"UpdatedBy": "CWX"
|
||||
}
|
||||
|
@ -0,0 +1,4 @@
|
||||
{
|
||||
"TraderPrice": false,
|
||||
"TraderMultiplier": 0.54
|
||||
}
|
@ -0,0 +1,123 @@
|
||||
"use strict";
|
||||
|
||||
const cfg = require("./config.json");
|
||||
const database = DatabaseServer.tables;
|
||||
const livePrice = database.templates.prices;
|
||||
const handbookTable = database.templates.handbook;
|
||||
const therapist = database.traders["54cb57776803fa99248b456e"].base
|
||||
const ragman = database.traders["5ac3b934156ae10c4430e83c"].base
|
||||
const jaeger = database.traders["5c0647fdd443bc2504c2d371"].base
|
||||
const mechanic = database.traders["5a7c2eca46aef81a7ca2145d"].base
|
||||
const prapor = database.traders["54cb50c76803fa8b248b4571"].base
|
||||
const peacekeeper = database.traders["5935c25fb3acc3127c3d8cd9"].base
|
||||
const skier = database.traders["58330581ace78e27b8b10cee"].base
|
||||
const fence = database.traders["579dc571d53a0658a154fbec"].base
|
||||
const tradersArr = [therapist, ragman, jaeger, mechanic, prapor, peacekeeper, skier, fence];
|
||||
|
||||
class Mod
|
||||
{
|
||||
name = "KcY-SeeItemValue";
|
||||
version = "1.2.0";
|
||||
static price = "";
|
||||
|
||||
constructor()
|
||||
{
|
||||
Logger.info(`Loading: ${this.name} : ${this.version}`);
|
||||
ModLoader.onLoad[this.name] = this.init.bind(this);
|
||||
}
|
||||
|
||||
init()
|
||||
{
|
||||
this.onLoadMod();
|
||||
}
|
||||
|
||||
onLoadMod()
|
||||
{
|
||||
HttpRouter.onDynamicRoute["/cwx/seeitemvalue/"] = {
|
||||
ItemValueMod: this.onRequestConfig.bind(this)
|
||||
};
|
||||
}
|
||||
|
||||
onRequestConfig(url, info, sessionID)
|
||||
{
|
||||
const splittedUrl = url.split("/");
|
||||
const id = splittedUrl[splittedUrl.length - 1].toLowerCase();
|
||||
|
||||
return HttpResponse.noBody(this.getIdPrice(id));
|
||||
}
|
||||
|
||||
getIdPrice(id)
|
||||
{
|
||||
let sPrice = 1;
|
||||
let sMutli = 1;
|
||||
let parentId = "";
|
||||
|
||||
// if TraderPrice in cfg is False get price from flea AVG
|
||||
if(cfg.TraderPrice === false)
|
||||
{
|
||||
const result = livePrice[id];
|
||||
if(typeof result != `undefined`)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
// will still default to Handbook if no price is found for flea AVG
|
||||
}
|
||||
// if TraderPrice in cfg is True get price from handbook
|
||||
// as traders have a modifier, avg is 0.54, closest we can get without checking against each trader
|
||||
// thanks to TEOA for this info
|
||||
for(let i in handbookTable.Items)
|
||||
{
|
||||
if(handbookTable.Items[i].Id === id)
|
||||
{
|
||||
parentId = handbookTable.Items[i].ParentId;
|
||||
sMutli = this.getBestTraderMulti(parentId);
|
||||
sPrice = handbookTable.Items[i].Price;
|
||||
let result = parseInt(sPrice*sMutli);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return sPrice;
|
||||
}
|
||||
|
||||
getBestTraderMulti(parentId)
|
||||
{
|
||||
let traderSellCat = "";
|
||||
let traderMulti = 0.54;
|
||||
let traderName = ""; // could be used later to be passed back to module to show trader and price
|
||||
let altTraderSellCat = "";
|
||||
|
||||
for(let i in handbookTable.Categories)
|
||||
{
|
||||
if(handbookTable.Categories[i].Id === parentId)
|
||||
{
|
||||
traderSellCat = handbookTable.Categories[i].Id;
|
||||
altTraderSellCat = handbookTable.Categories[i].ParentId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for(let iter = 0; iter < 8; iter++)
|
||||
{
|
||||
if(tradersArr[iter].sell_category.includes(traderSellCat))
|
||||
{
|
||||
traderMulti = (100 - tradersArr[iter].loyaltyLevels[0].buy_price_coef) / 100;
|
||||
traderName = tradersArr[iter].nickname;
|
||||
return traderMulti;
|
||||
}
|
||||
}
|
||||
|
||||
for(let iter = 0; iter < 8; iter++)
|
||||
{
|
||||
if(tradersArr[iter].sell_category.includes(altTraderSellCat))
|
||||
{
|
||||
traderMulti = (100 - tradersArr[iter].loyaltyLevels[0].buy_price_coef) / 100;
|
||||
traderName = tradersArr[iter].nickname;
|
||||
return traderMulti;
|
||||
}
|
||||
}
|
||||
return cfg.TraderMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.Mod = Mod;
|
7
KcY-SeeItemValue/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# SeeItemValue
|
||||
## KcY-SeeItemValue for EFT - SPT-AKI
|
||||
### CURRENT AKI VERSION: 2.2.1
|
||||
### GAMEVERSION: 0.12.12.15.16584
|
||||
|
||||
ItemValue is the project folder
|
||||
KcY-SeeItemValue is what is uploaded to the hub
|
71
KcY-SeeItemValue/itemValue/Patches.cs
Normal file
@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Aki.Reflection.Patching;
|
||||
using Aki.Reflection.Utils;
|
||||
using EFT;
|
||||
using EFT.InventoryLogic;
|
||||
using Ammo = BulletClass;
|
||||
using Grenade = GClass2079;
|
||||
using GrenadeTemplate = GClass1975;
|
||||
using ItemAttribute = GClass2090;
|
||||
using SecureContainer = GClass2038;
|
||||
using SecureContainerTemplate = GClass1937;
|
||||
|
||||
namespace itemValueMod
|
||||
{
|
||||
public class ItemPatch : ModulePatch
|
||||
{
|
||||
protected override MethodBase GetTargetMethod()
|
||||
{
|
||||
return typeof(Item).GetConstructor(new Type[] { typeof(string), typeof(ItemTemplate) });
|
||||
}
|
||||
|
||||
[PatchPostfix]
|
||||
private static void PatchPostFix(ref Item __instance, string id, ItemTemplate template)
|
||||
{
|
||||
ItemValue.AddItemValue(ref __instance, id, template);
|
||||
}
|
||||
}
|
||||
|
||||
public class AmmoPatch : ModulePatch
|
||||
{
|
||||
protected override MethodBase GetTargetMethod()
|
||||
{
|
||||
return typeof(Ammo).GetConstructor(new Type[] { typeof(string), typeof(AmmoTemplate) });
|
||||
}
|
||||
|
||||
[PatchPostfix]
|
||||
private static void PatchPostFix(ref Ammo __instance, string id, AmmoTemplate template)
|
||||
{
|
||||
ItemValue.AddItemValue(ref __instance, id, template);
|
||||
}
|
||||
}
|
||||
|
||||
public class GrenadePatch : ModulePatch
|
||||
{
|
||||
protected override MethodBase GetTargetMethod()
|
||||
{
|
||||
return typeof(Grenade).GetConstructor(new Type[] { typeof(string), typeof(GrenadeTemplate) });
|
||||
}
|
||||
|
||||
[PatchPostfix]
|
||||
private static void PatchPostFix(ref Grenade __instance, string id, GrenadeTemplate template)
|
||||
{
|
||||
ItemValue.AddItemValue(ref __instance, id, template);
|
||||
}
|
||||
}
|
||||
|
||||
public class SecureContainerPatch : ModulePatch
|
||||
{
|
||||
protected override MethodBase GetTargetMethod()
|
||||
{
|
||||
return typeof(SecureContainer).GetConstructor(new Type[] { typeof(string), typeof(SecureContainerTemplate) });
|
||||
}
|
||||
|
||||
[PatchPostfix]
|
||||
private static void PatchPostFix(ref SecureContainer __instance, string id, SecureContainerTemplate template)
|
||||
{
|
||||
ItemValue.AddItemValue(ref __instance, id, template);
|
||||
}
|
||||
}
|
||||
}
|
17
KcY-SeeItemValue/itemValue/Program.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using BepInEx;
|
||||
using HarmonyLib;
|
||||
|
||||
namespace itemValueMod
|
||||
{
|
||||
[BepInPlugin("com.KcY.SeeItemValue", "KcY-SeeItemValue", "1.2.0")]
|
||||
public class Plugin : BaseUnityPlugin
|
||||
{
|
||||
private void Awake()
|
||||
{
|
||||
new ItemPatch().Enable();
|
||||
new AmmoPatch().Enable();
|
||||
new GrenadePatch().Enable();
|
||||
new SecureContainerPatch().Enable();
|
||||
}
|
||||
}
|
||||
}
|
34
KcY-SeeItemValue/itemValue/_built/LICENSE
Normal file
@ -0,0 +1,34 @@
|
||||
University of Illinois/NCSA Open Source License
|
||||
|
||||
Copyright (c) [year] [fullname]. All rights reserved.
|
||||
|
||||
Developed by: [SEE ITEM VALUE]
|
||||
[KcY]
|
||||
[https://github.com/KeiranY/TarkovLoader]
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal with the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimers.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimers in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of [fullname], [project] nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this Software without specific prior written permission.
|
||||
|
||||
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
|
||||
CONTRIBUTORS OR COPYRIGHT HOLDERS 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 WITH
|
||||
THE SOFTWARE.
|
2
KcY-SeeItemValue/itemValue/_built/modloader.js
Normal file
@ -0,0 +1,2 @@
|
||||
const { Mod } = require("./src/mod.js");
|
||||
module.exports.mod = new Mod();
|
BIN
KcY-SeeItemValue/itemValue/_built/module.dll
Normal file
10
KcY-SeeItemValue/itemValue/_built/package.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "SeeItemValue",
|
||||
"author": "KcY",
|
||||
"version": "1.1.0",
|
||||
"license": "NCSA Open Source",
|
||||
"main": "modloader.js",
|
||||
"akiVersion": "2.2.1",
|
||||
"UpdatedBy": "CWX"
|
||||
}
|
||||
|
4
KcY-SeeItemValue/itemValue/_built/src/config.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"TraderPrice": false,
|
||||
"TraderMultiplier": 0.54
|
||||
}
|
123
KcY-SeeItemValue/itemValue/_built/src/mod.js
Normal file
@ -0,0 +1,123 @@
|
||||
"use strict";
|
||||
|
||||
const cfg = require("./config.json");
|
||||
const database = DatabaseServer.tables;
|
||||
const livePrice = database.templates.prices;
|
||||
const handbookTable = database.templates.handbook;
|
||||
const therapist = DatabaseServer.tables.traders["54cb57776803fa99248b456e"].base
|
||||
const ragman = DatabaseServer.tables.traders["5ac3b934156ae10c4430e83c"].base
|
||||
const jaeger = DatabaseServer.tables.traders["5c0647fdd443bc2504c2d371"].base
|
||||
const mechanic = DatabaseServer.tables.traders["5a7c2eca46aef81a7ca2145d"].base
|
||||
const prapor = DatabaseServer.tables.traders["54cb50c76803fa8b248b4571"].base
|
||||
const peacekeeper = DatabaseServer.tables.traders["5935c25fb3acc3127c3d8cd9"].base
|
||||
const skier = DatabaseServer.tables.traders["58330581ace78e27b8b10cee"].base
|
||||
const fence = DatabaseServer.tables.traders["579dc571d53a0658a154fbec"].base
|
||||
const tradersArr = [therapist, ragman, jaeger, mechanic, prapor, peacekeeper, skier, fence];
|
||||
|
||||
class Mod
|
||||
{
|
||||
name = "KcY-SeeItemValue";
|
||||
version = "1.1.0";
|
||||
static price = "";
|
||||
|
||||
constructor()
|
||||
{
|
||||
Logger.info(`Loading: ${this.name} : ${this.version}`);
|
||||
ModLoader.onLoad[this.name] = this.init.bind(this);
|
||||
}
|
||||
|
||||
init()
|
||||
{
|
||||
this.onLoadMod();
|
||||
}
|
||||
|
||||
onLoadMod()
|
||||
{
|
||||
HttpRouter.onDynamicRoute["/cwx/itemvaluemod/"] = {
|
||||
ItemValueMod: this.onRequestConfig.bind(this)
|
||||
};
|
||||
}
|
||||
|
||||
onRequestConfig(url, info, sessionID)
|
||||
{
|
||||
const splittedUrl = url.split("/");
|
||||
const id = splittedUrl[splittedUrl.length - 1].toLowerCase();
|
||||
|
||||
return HttpResponse.noBody(this.getIdPrice(id));
|
||||
}
|
||||
|
||||
getIdPrice(id)
|
||||
{
|
||||
let sPrice = 1;
|
||||
let sMutli = 1;
|
||||
let parentId = "";
|
||||
|
||||
// if TraderPrice in cfg is False get price from flea AVG
|
||||
if(cfg.TraderPrice === false)
|
||||
{
|
||||
const result = livePrice[id];
|
||||
if(typeof result != `undefined`)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
// will still default to Handbook if no price is found for flea AVG
|
||||
}
|
||||
// if TraderPrice in cfg is True get price from handbook
|
||||
// as traders have a modifier, avg is 0.54, closest we can get without checking against each trader
|
||||
// thanks to TEOA for this info
|
||||
for(let i in handbookTable.Items)
|
||||
{
|
||||
if(handbookTable.Items[i].Id === id)
|
||||
{
|
||||
parentId = handbookTable.Items[i].ParentId;
|
||||
sMutli = this.getBestTraderMulti(parentId);
|
||||
sPrice = handbookTable.Items[i].Price;
|
||||
let result = parseInt(sPrice*sMutli);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return sPrice;
|
||||
}
|
||||
|
||||
getBestTraderMulti(parentId)
|
||||
{
|
||||
let traderSellCat = "";
|
||||
let traderMulti = 0.54;
|
||||
let traderName = ""; // could be used later to be passed back to module to show trader and price
|
||||
let altTraderSellCat = "";
|
||||
|
||||
for(let i in handbookTable.Categories)
|
||||
{
|
||||
if(handbookTable.Categories[i].Id === parentId)
|
||||
{
|
||||
traderSellCat = handbookTable.Categories[i].Id;
|
||||
altTraderSellCat = handbookTable.Categories[i].ParentId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for(let iter = 0; iter < 8; iter++)
|
||||
{
|
||||
if(tradersArr[iter].sell_category.includes(traderSellCat))
|
||||
{
|
||||
traderMulti = (100 - tradersArr[iter].loyaltyLevels[0].buy_price_coef) / 100;
|
||||
traderName = tradersArr[iter].nickname;
|
||||
return traderMulti;
|
||||
}
|
||||
}
|
||||
|
||||
for(let iter = 0; iter < 8; iter++)
|
||||
{
|
||||
if(tradersArr[iter].sell_category.includes(altTraderSellCat))
|
||||
{
|
||||
traderMulti = (100 - tradersArr[iter].loyaltyLevels[0].buy_price_coef) / 100;
|
||||
traderName = tradersArr[iter].nickname;
|
||||
return traderMulti;
|
||||
}
|
||||
}
|
||||
return cfg.TraderMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.Mod = Mod;
|
7
KcY-SeeItemValue/itemValue/itemGetter.cs
Normal file
@ -0,0 +1,7 @@
|
||||
//namespace itemValueMod
|
||||
//{
|
||||
// public struct itemGetter
|
||||
// {
|
||||
// public double sPrice { get; set; }
|
||||
// }
|
||||
//}
|
25
KcY-SeeItemValue/itemValue/itemValue.sln
Normal file
@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.32014.148
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "itemValueMod", "itemValueMod.csproj", "{F237CF5E-96D2-41B7-94C4-6990890886C3}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{F237CF5E-96D2-41B7-94C4-6990890886C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F237CF5E-96D2-41B7-94C4-6990890886C3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F237CF5E-96D2-41B7-94C4-6990890886C3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F237CF5E-96D2-41B7-94C4-6990890886C3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {E5B08F5A-DDB9-426E-B149-18108C64B406}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
78
KcY-SeeItemValue/itemValue/itemValueMod.cs
Normal file
@ -0,0 +1,78 @@
|
||||
/* Original Author: KyC
|
||||
* CWX - updated to work for 2.3.0 AKI
|
||||
* Client version: 0.12.12.15.17107
|
||||
* - removed the need for KyC's ModLoader
|
||||
* - Commented out the code for stackCount total worth
|
||||
* - Commented out the code for weapon parts total worth
|
||||
* - Commented out the code for container total worth
|
||||
* - Commented out the code for magazine total worth
|
||||
*/
|
||||
|
||||
using Aki.Common.Http;
|
||||
using Aki.Common.Utils;
|
||||
using EFT.InventoryLogic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ItemAttribute = GClass2090;
|
||||
|
||||
namespace itemValueMod
|
||||
{
|
||||
public class ItemValue
|
||||
{
|
||||
public static void AddItemValue<T>(ref T __instance, string id, ItemTemplate template) where T : Item
|
||||
{
|
||||
// Remove item if it has no value
|
||||
// if (Math.Round(__instance.Value()) == 0) return;
|
||||
|
||||
// Make a copy of the existing attributes list, this is needed for inherited types of Item that use a global attributes list (ammo)
|
||||
var atts = new List<ItemAttribute>();
|
||||
atts.AddRange(__instance.Attributes);
|
||||
__instance.Attributes = atts;
|
||||
ItemAttribute attr = new ItemAttribute(EItemAttributeId.MoneySum)
|
||||
{
|
||||
StringValue = new Func<string>(__instance.ValueStr), // ₽
|
||||
Name = "RUB ₽", //new Func<string>(ValueExtension.ValueTrName).ToString(),
|
||||
DisplayType = new Func<EItemAttributeDisplayType>(() => EItemAttributeDisplayType.Compact)
|
||||
};
|
||||
__instance.Attributes.Add(attr);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ValueExtension
|
||||
{
|
||||
public static double Value(this Item item)
|
||||
{
|
||||
var template = item.Template;
|
||||
string itemId = template._id;
|
||||
double _price;
|
||||
var json = RequestHandler.GetJson($"/cwx/seeitemvalue/{itemId}"); // CWX - sends ID to server
|
||||
_price = Json.Deserialize<int>(json);
|
||||
|
||||
var medKit = item.GetItemComponent<MedKitComponent>();
|
||||
if (medKit != null)
|
||||
{
|
||||
_price *= medKit.HpResource / medKit.MaxHpResource;
|
||||
}
|
||||
|
||||
var repair = item.GetItemComponent<RepairableComponent>();
|
||||
if (repair != null)
|
||||
{
|
||||
_price *= repair.Durability / repair.MaxDurability;
|
||||
}
|
||||
|
||||
var dogtag = item.GetItemComponent<DogtagComponent>();
|
||||
if (dogtag != null)
|
||||
{
|
||||
_price *= dogtag.Level;
|
||||
}
|
||||
|
||||
//_price *= item.StackObjectsCount;
|
||||
|
||||
return _price;
|
||||
}
|
||||
public static string ValueStr(this Item item)
|
||||
{
|
||||
return Math.Round(item.Value()).ToString();
|
||||
}
|
||||
}
|
||||
}
|
42
KcY-SeeItemValue/itemValue/itemValueMod.csproj
Normal file
@ -0,0 +1,42 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<Version>1.2.0</Version>
|
||||
<AssemblyName>KcY-SeeItemValue</AssemblyName>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="0Harmony">
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\BepInEx\core\0Harmony.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Aki.Common">
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\EscapeFromTarkov_Data\Managed\Aki.Common.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Aki.Reflection">
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\EscapeFromTarkov_Data\Managed\Aki.Reflection.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Assembly-CSharp">
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\EscapeFromTarkov_Data\Managed\Assembly-CSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="BepInEx">
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\BepInEx\core\BepInEx.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Comfort">
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\EscapeFromTarkov_Data\Managed\Comfort.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ItemComponent.Types">
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\EscapeFromTarkov_Data\Managed\ItemComponent.Types.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\EscapeFromTarkov_Data\Managed\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine">
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\EscapeFromTarkov_Data\Managed\UnityEngine.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.CoreModule">
|
||||
<HintPath>..\..\..\..\..\..\..\AKI PROJECT\AKI 2.3.0 17107 Bepin\EscapeFromTarkov_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|