Compare commits
3 commits
1854d79d07
...
407cffddd5
| Author | SHA1 | Date | |
|---|---|---|---|
| 407cffddd5 | |||
| 395345ad51 | |||
| ccea395b0b |
16 changed files with 624 additions and 0 deletions
BIN
BepInEx/plugins/Kat.FastSellInFlea.dll
Normal file
BIN
BepInEx/plugins/Kat.FastSellInFlea.dll
Normal file
Binary file not shown.
BIN
BepInEx/plugins/Tyfon.UIFixes.Net.dll
Normal file
BIN
BepInEx/plugins/Tyfon.UIFixes.Net.dll
Normal file
Binary file not shown.
BIN
BepInEx/plugins/Tyfon.UIFixes.dll
Normal file
BIN
BepInEx/plugins/Tyfon.UIFixes.dll
Normal file
Binary file not shown.
42
user/mods/redlaser42-Increase Climb Height/config ReadMe.txt
Normal file
42
user/mods/redlaser42-Increase Climb Height/config ReadMe.txt
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
Here are the game's defaults with my experience tweaking them:
|
||||
|
||||
"InteractMaxHeight": 1.31,
|
||||
This one setting is 99% of the mod. It's the height a climb will be attempted. You could bump this up to make things feel more grippy, but how high your character moves up won't change.
|
||||
|
||||
"InteractMaxLength": 10,
|
||||
This is how close in front of you a wall needs to be to attempt a climb. I left this at default. It didn't help get to more ledges because where you climb up to does not go further out.
|
||||
|
||||
"MinDistantToInteract": 0.5,
|
||||
IDK what this does but was with the other two. Didn't notice any effect.
|
||||
|
||||
|
||||
"BaseJumpPenalty": 0.3,
|
||||
Inertia penalty for jumping. I set this to 0 for off.
|
||||
|
||||
"MaxOneHandAnimationHeight": 2.3,
|
||||
How high a the one handed climb animation transitions into a two handed climb. One hands are slightly faster, so this could be boosted, but wouldn't above 3.5. I left this at default.
|
||||
|
||||
"MaxWithoutHandHeight": 0.65,
|
||||
How high you can do a no-handed step up. I left this at default. Looks wonky past 2
|
||||
|
||||
|
||||
"VaultingInputTime": 0.5,
|
||||
I didn't notice an effect lowering this to 0. I could still vault as quick as I could press a key.
|
||||
|
||||
"AnimationVerticalSpeed": 1.1,
|
||||
"AnimationForwardSpeed": 0.8,
|
||||
How fast you climb. Left at default. Adjust .1 at a time.
|
||||
|
||||
|
||||
"GridOffsetX": 0,
|
||||
"GridOffsetY": 0,
|
||||
"GridOffsetZ": 0,
|
||||
"GridSizeX": 0,
|
||||
"GridSizeY": 1.8,
|
||||
"GridSizeZ": 2,
|
||||
"OffsetFactor": 0.1,
|
||||
"SteppingLengthX": 0.1,
|
||||
"SteppingLengthY": 0.1,
|
||||
"SteppingLengthZ": 0.1
|
||||
Everything above is under "Grid Settings". I tweaked these settings, but it was hard to tell what was happening.
|
||||
I didn't notice any effect except making the grid too small or large prevents you from climbing. Left all at defaults.
|
||||
26
user/mods/redlaser42-Increase Climb Height/config.json
Normal file
26
user/mods/redlaser42-Increase Climb Height/config.json
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"InteractMaxHeight": 1.72,
|
||||
"InteractMaxLength": 10,
|
||||
"MinDistantToInteract": 0.5,
|
||||
|
||||
"BaseJumpPenalty": 0,
|
||||
|
||||
"MaxOneHandAnimationHeight": 2.3,
|
||||
"MaxWithoutHandHeight": 0.65,
|
||||
|
||||
"VaultingInputTime": 0.5,
|
||||
|
||||
"AnimationVerticalSpeed": 1.1,
|
||||
"AnimationForwardSpeed": 0.8,
|
||||
|
||||
"GridOffsetX": 0,
|
||||
"GridOffsetY": 0,
|
||||
"GridOffsetZ": 0,
|
||||
"GridSizeX": 0,
|
||||
"GridSizeY": 1.8,
|
||||
"GridSizeZ": 2,
|
||||
"OffsetFactor": 0.1,
|
||||
"SteppingLengthX": 0.1,
|
||||
"SteppingLengthY": 0.1,
|
||||
"SteppingLengthZ": 0.1
|
||||
}
|
||||
32
user/mods/redlaser42-Increase Climb Height/package.json
Normal file
32
user/mods/redlaser42-Increase Climb Height/package.json
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"name": "Increase Climb Height",
|
||||
"version": "1.2.0",
|
||||
"sptVersion": "~3.11",
|
||||
"loadBefore": [],
|
||||
"loadAfter": [],
|
||||
"incompatibilities": [],
|
||||
"isBundleMod": false,
|
||||
"main": "src/mod.js",
|
||||
"scripts": {
|
||||
"setup": "npm i",
|
||||
"build": "node ./build.mjs",
|
||||
"buildinfo": "node ./build.mjs --verbose"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "20.11",
|
||||
"@typescript-eslint/eslint-plugin": "7.2",
|
||||
"@typescript-eslint/parser": "7.2",
|
||||
"archiver": "^6.0",
|
||||
"eslint": "8.57",
|
||||
"fs-extra": "11.2",
|
||||
"ignore": "^5.2",
|
||||
"tsyringe": "4.8.0",
|
||||
"typescript": "5.4",
|
||||
"winston": "3.12"
|
||||
},
|
||||
"author": "redlaser42",
|
||||
"contributors": [],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
}
|
||||
}
|
||||
58
user/mods/redlaser42-Increase Climb Height/src/mod.js
Normal file
58
user/mods/redlaser42-Increase Climb Height/src/mod.js
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.mod = void 0;
|
||||
const config_json_1 = __importDefault(require("./../config.json"));
|
||||
const cfMaxLength = config_json_1.default.InteractMaxLength;
|
||||
const cfMaxHeight = config_json_1.default.InteractMaxHeight;
|
||||
const cfMinDistantToInteract = config_json_1.default.MinDistantToInteract;
|
||||
const cfMaxOneHandHeight = config_json_1.default.MaxOneHandAnimationHeight;
|
||||
const cfMaxWithoutHandHeight = config_json_1.default.MaxWithoutHandHeight;
|
||||
const cfBaseJumpPenalty = config_json_1.default.BaseJumpPenalty;
|
||||
const cfVaultingInputTime = config_json_1.default.VaultingInputTime;
|
||||
const cfSpeedRangeX = config_json_1.default.AnimationForwardSpeed;
|
||||
const cfSpeedRangeY = config_json_1.default.AnimationVerticalSpeed;
|
||||
const cfGridOffsetX = config_json_1.default.GridOffsetX;
|
||||
const cfGridOffsetY = config_json_1.default.GridOffsetY;
|
||||
const cfGridOffsetZ = config_json_1.default.GridOffsetZ;
|
||||
const cfGridSizeX = config_json_1.default.GridSizeX;
|
||||
const cfGridSizeY = config_json_1.default.GridSizeY;
|
||||
const cfGridSizeZ = config_json_1.default.GridSizeZ;
|
||||
const cfOffsetFactor = config_json_1.default.OffsetFactor;
|
||||
const cfSteppingLengthX = config_json_1.default.SteppingLengthX;
|
||||
const cfSteppingLengthY = config_json_1.default.SteppingLengthY;
|
||||
const cfSteppingLengthZ = config_json_1.default.SteppingLengthZ;
|
||||
class Mod {
|
||||
postDBLoad(container) {
|
||||
// get database from server
|
||||
const databaseServer = container.resolve("DatabaseServer");
|
||||
// Get all the in-memory json found in /assets/database
|
||||
const tables = databaseServer.getTables();
|
||||
tables.globals.config.VaultingSettings.MovesSettings.ClimbSettings.MoveRestrictions.MaxLength = cfMaxLength;
|
||||
tables.globals.config.VaultingSettings.MovesSettings.ClimbSettings.MoveRestrictions.MaxHeight = cfMaxHeight;
|
||||
tables.globals.config.VaultingSettings.MovesSettings.ClimbSettings.MoveRestrictions.MinDistantToInteract = cfMinDistantToInteract;
|
||||
tables.globals.config.VaultingSettings.MovesSettings.ClimbSettings.AutoMoveRestrictions.MaxLength = cfMaxLength;
|
||||
tables.globals.config.VaultingSettings.MovesSettings.ClimbSettings.AutoMoveRestrictions.MaxHeight = cfMaxHeight;
|
||||
tables.globals.config.VaultingSettings.MovesSettings.ClimbSettings.AutoMoveRestrictions.MinDistantToInteract = cfMinDistantToInteract;
|
||||
tables.globals.config.VaultingSettings.MovesSettings.ClimbSettings.SpeedRange.x = cfSpeedRangeX;
|
||||
tables.globals.config.VaultingSettings.MovesSettings.ClimbSettings.SpeedRange.y = cfSpeedRangeY;
|
||||
tables.globals.config.VaultingSettings.MovesSettings.ClimbSettings.MaxOneHandHeight = cfMaxOneHandHeight;
|
||||
tables.globals.config.VaultingSettings.MovesSettings.ClimbSettings.MaxWithoutHandHeight = cfMaxWithoutHandHeight;
|
||||
tables.globals.config.Inertia.BaseJumpPenalty = cfBaseJumpPenalty;
|
||||
tables.globals.config.VaultingSettings.GridSettings.SteppingLengthY = cfSteppingLengthY;
|
||||
tables.globals.config.VaultingSettings.GridSettings.SteppingLengthX = cfSteppingLengthX;
|
||||
tables.globals.config.VaultingSettings.GridSettings.SteppingLengthZ = cfSteppingLengthZ;
|
||||
tables.globals.config.VaultingSettings.GridSettings.GridOffsetY = cfGridOffsetY;
|
||||
tables.globals.config.VaultingSettings.GridSettings.GridOffsetX = cfGridOffsetX;
|
||||
tables.globals.config.VaultingSettings.GridSettings.GridOffsetZ = cfGridOffsetZ;
|
||||
tables.globals.config.VaultingSettings.GridSettings.GridSizeY = cfGridSizeY;
|
||||
tables.globals.config.VaultingSettings.GridSettings.GridSizeX = cfGridSizeX;
|
||||
tables.globals.config.VaultingSettings.GridSettings.GridSizeZ = cfGridSizeZ;
|
||||
tables.globals.config.VaultingSettings.GridSettings.OffsetFactor = cfOffsetFactor;
|
||||
tables.globals.config.VaultingSettings.VaultingInputTime = cfVaultingInputTime;
|
||||
}
|
||||
}
|
||||
exports.mod = new Mod();
|
||||
//# sourceMappingURL=mod.js.map
|
||||
10
user/mods/redlaser42-Increase Climb Height/src/mod.js.map
Normal file
10
user/mods/redlaser42-Increase Climb Height/src/mod.js.map
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"version": 3,
|
||||
"file": "mod.js",
|
||||
"sourceRoot": "",
|
||||
"sources": [
|
||||
"mod.ts"
|
||||
],
|
||||
"names": [],
|
||||
"mappings": "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"
|
||||
}
|
||||
68
user/mods/redlaser42-Increase Climb Height/src/mod.ts
Normal file
68
user/mods/redlaser42-Increase Climb Height/src/mod.ts
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
import { DependencyContainer } from "tsyringe";
|
||||
|
||||
import { IPostDBLoadMod } from "@spt/models/external/IPostDBLoadMod";
|
||||
import { DatabaseServer } from "@spt/servers/DatabaseServer";
|
||||
import { IDatabaseTables } from "@spt/models/spt/server/IDatabaseTables";
|
||||
|
||||
import config from "./../config.json";
|
||||
|
||||
const cfMaxLength = config.InteractMaxLength;
|
||||
const cfMaxHeight = config.InteractMaxHeight;
|
||||
const cfMinDistantToInteract = config.MinDistantToInteract;
|
||||
const cfMaxOneHandHeight = config.MaxOneHandAnimationHeight;
|
||||
const cfMaxWithoutHandHeight = config.MaxWithoutHandHeight;
|
||||
const cfBaseJumpPenalty = config.BaseJumpPenalty;
|
||||
const cfVaultingInputTime = config.VaultingInputTime;
|
||||
const cfSpeedRangeX = config.AnimationForwardSpeed;
|
||||
const cfSpeedRangeY = config.AnimationVerticalSpeed;
|
||||
|
||||
const cfGridOffsetX = config.GridOffsetX;
|
||||
const cfGridOffsetY = config.GridOffsetY;
|
||||
const cfGridOffsetZ = config.GridOffsetZ;
|
||||
const cfGridSizeX = config.GridSizeX;
|
||||
const cfGridSizeY = config.GridSizeY;
|
||||
const cfGridSizeZ = config.GridSizeZ;
|
||||
const cfOffsetFactor = config.OffsetFactor;
|
||||
const cfSteppingLengthX = config.SteppingLengthX;
|
||||
const cfSteppingLengthY = config.SteppingLengthY;
|
||||
const cfSteppingLengthZ = config.SteppingLengthZ;
|
||||
|
||||
class Mod implements IPostDBLoadMod {
|
||||
public postDBLoad(container: DependencyContainer): void {
|
||||
// get database from server
|
||||
const databaseServer = container.resolve<DatabaseServer>("DatabaseServer");
|
||||
|
||||
// Get all the in-memory json found in /assets/database
|
||||
const tables: IDatabaseTables = databaseServer.getTables();
|
||||
|
||||
tables.globals.config.VaultingSettings.MovesSettings.ClimbSettings.MoveRestrictions.MaxLength = cfMaxLength;
|
||||
tables.globals.config.VaultingSettings.MovesSettings.ClimbSettings.MoveRestrictions.MaxHeight = cfMaxHeight;
|
||||
tables.globals.config.VaultingSettings.MovesSettings.ClimbSettings.MoveRestrictions.MinDistantToInteract = cfMinDistantToInteract;
|
||||
tables.globals.config.VaultingSettings.MovesSettings.ClimbSettings.AutoMoveRestrictions.MaxLength = cfMaxLength;
|
||||
tables.globals.config.VaultingSettings.MovesSettings.ClimbSettings.AutoMoveRestrictions.MaxHeight = cfMaxHeight;
|
||||
tables.globals.config.VaultingSettings.MovesSettings.ClimbSettings.AutoMoveRestrictions.MinDistantToInteract = cfMinDistantToInteract;
|
||||
|
||||
tables.globals.config.VaultingSettings.MovesSettings.ClimbSettings.SpeedRange.x = cfSpeedRangeX;
|
||||
tables.globals.config.VaultingSettings.MovesSettings.ClimbSettings.SpeedRange.y = cfSpeedRangeY;
|
||||
|
||||
tables.globals.config.VaultingSettings.MovesSettings.ClimbSettings.MaxOneHandHeight = cfMaxOneHandHeight;
|
||||
tables.globals.config.VaultingSettings.MovesSettings.ClimbSettings.MaxWithoutHandHeight = cfMaxWithoutHandHeight;
|
||||
|
||||
tables.globals.config.Inertia.BaseJumpPenalty = cfBaseJumpPenalty;
|
||||
|
||||
tables.globals.config.VaultingSettings.GridSettings.SteppingLengthY = cfSteppingLengthY;
|
||||
tables.globals.config.VaultingSettings.GridSettings.SteppingLengthX = cfSteppingLengthX;
|
||||
tables.globals.config.VaultingSettings.GridSettings.SteppingLengthZ = cfSteppingLengthZ;
|
||||
tables.globals.config.VaultingSettings.GridSettings.GridOffsetY = cfGridOffsetY;
|
||||
tables.globals.config.VaultingSettings.GridSettings.GridOffsetX = cfGridOffsetX;
|
||||
tables.globals.config.VaultingSettings.GridSettings.GridOffsetZ = cfGridOffsetZ;
|
||||
tables.globals.config.VaultingSettings.GridSettings.GridSizeY = cfGridSizeY;
|
||||
tables.globals.config.VaultingSettings.GridSettings.GridSizeX = cfGridSizeX;
|
||||
tables.globals.config.VaultingSettings.GridSettings.GridSizeZ = cfGridSizeZ;
|
||||
tables.globals.config.VaultingSettings.GridSettings.OffsetFactor = cfOffsetFactor;
|
||||
|
||||
tables.globals.config.VaultingSettings.VaultingInputTime = cfVaultingInputTime;
|
||||
}
|
||||
}
|
||||
|
||||
export const mod = new Mod();
|
||||
3
user/mods/tyfon-uifixes/config/config.json
Normal file
3
user/mods/tyfon-uifixes/config/config.json
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"putToolsBack": true
|
||||
}
|
||||
32
user/mods/tyfon-uifixes/package.json
Normal file
32
user/mods/tyfon-uifixes/package.json
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"name": "uifixes",
|
||||
"version": "4.2.1",
|
||||
"main": "src/mod.js",
|
||||
"license": "MIT",
|
||||
"author": "Tyfon",
|
||||
"sptVersion": "~3.11",
|
||||
"loadBefore": [],
|
||||
"loadAfter": [],
|
||||
"incompatibilities": [],
|
||||
"contributors": [],
|
||||
"isBundleMod": false,
|
||||
"scripts": {
|
||||
"setup": "npm i",
|
||||
"build": "node ./build.mjs",
|
||||
"buildinfo": "node ./build.mjs --verbose"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "22.12.0",
|
||||
"@typescript-eslint/eslint-plugin": "7.2",
|
||||
"@typescript-eslint/parser": "7.2",
|
||||
"archiver": "^6.0",
|
||||
"eslint": "8.57",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"fs-extra": "11.2",
|
||||
"ignore": "^5.2",
|
||||
"tsyringe": "4.8.0",
|
||||
"typescript": "5.8.2",
|
||||
"winston": "3.12"
|
||||
}
|
||||
}
|
||||
57
user/mods/tyfon-uifixes/src/assortUnlocks.ts
Normal file
57
user/mods/tyfon-uifixes/src/assortUnlocks.ts
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import type { DependencyContainer } from "tsyringe";
|
||||
|
||||
import type { ILogger } from "@spt/models/spt/utils/ILogger";
|
||||
import type { DatabaseService } from "@spt/services/DatabaseService";
|
||||
import type { StaticRouterModService } from "@spt/services/mod/staticRouter/StaticRouterModService";
|
||||
|
||||
export const assortUnlocks = (container: DependencyContainer) => {
|
||||
const logger = container.resolve<ILogger>("PrimaryLogger");
|
||||
const staticRouterModService = container.resolve<StaticRouterModService>("StaticRouterModService");
|
||||
const databaseService = container.resolve<DatabaseService>("DatabaseService");
|
||||
|
||||
const loadAssortmentUnlocks = () => {
|
||||
const traders = databaseService.getTraders();
|
||||
const quests = databaseService.getQuests();
|
||||
const result: Record<string, string> = {};
|
||||
|
||||
for (const traderId in traders) {
|
||||
const trader = traders[traderId];
|
||||
if (trader.questassort) {
|
||||
for (const questStatus in trader.questassort) {
|
||||
// Explicitly check that quest status is an expected value - some mods accidently import in such a way that adds a "default" value
|
||||
if (!["started", "success", "fail"].includes(questStatus)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const assortId in trader.questassort[questStatus]) {
|
||||
const questId = trader.questassort[questStatus][assortId];
|
||||
|
||||
if (!quests[questId]) {
|
||||
logger.warning(
|
||||
`UIFixes: Trader ${traderId} questassort references unknown quest ${JSON.stringify(questId)}! Check that whatever mod added that trader and/or quest is installed correctly.`
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
result[assortId] = quests[questId].name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
staticRouterModService.registerStaticRouter(
|
||||
"UIFixesRoutes",
|
||||
[
|
||||
{
|
||||
url: "/uifixes/assortUnlocks",
|
||||
action: async (url, info, sessionId, output) => {
|
||||
return JSON.stringify(loadAssortmentUnlocks());
|
||||
}
|
||||
}
|
||||
],
|
||||
"custom-static-ui-fixes"
|
||||
);
|
||||
};
|
||||
39
user/mods/tyfon-uifixes/src/keepQuickBinds.ts
Normal file
39
user/mods/tyfon-uifixes/src/keepQuickBinds.ts
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import type { DependencyContainer } from "tsyringe";
|
||||
|
||||
import type { InRaidHelper } from "@spt/helpers/InRaidHelper";
|
||||
import type { ILogger } from "@spt/models/spt/utils/ILogger";
|
||||
import type { ICloner } from "@spt/utils/cloners/ICloner";
|
||||
|
||||
export const keepQuickBinds = (container: DependencyContainer) => {
|
||||
const logger = container.resolve<ILogger>("PrimaryLogger");
|
||||
const cloner = container.resolve<ICloner>("RecursiveCloner");
|
||||
|
||||
container.afterResolution(
|
||||
"InRaidHelper",
|
||||
(_, inRaidHelper: InRaidHelper) => {
|
||||
const original = inRaidHelper.deleteInventory;
|
||||
|
||||
inRaidHelper.deleteInventory = (pmcData, sessionId) => {
|
||||
// Copy the existing quickbinds
|
||||
const fastPanel = cloner.clone(pmcData.Inventory.fastPanel);
|
||||
|
||||
// Nukes the inventory and the fastpanel
|
||||
const result = original.call(inRaidHelper, pmcData, sessionId);
|
||||
|
||||
// Restore the quickbinds for items that still exist
|
||||
try {
|
||||
for (const index in fastPanel) {
|
||||
if (pmcData.Inventory.items.find(i => i._id == fastPanel[index])) {
|
||||
pmcData.Inventory.fastPanel[index] = fastPanel[index];
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`UIFixes: Failed to restore quickbinds\n ${error}`);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
},
|
||||
{ frequency: "Always" }
|
||||
);
|
||||
};
|
||||
61
user/mods/tyfon-uifixes/src/linkedSlotSearch.ts
Normal file
61
user/mods/tyfon-uifixes/src/linkedSlotSearch.ts
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
import type { DependencyContainer } from "tsyringe";
|
||||
|
||||
import type { ItemHelper } from "@spt/helpers/ItemHelper";
|
||||
import type { ITemplateItem } from "@spt/models/eft/common/tables/ITemplateItem";
|
||||
import type { ILogger } from "@spt/models/spt/utils/ILogger";
|
||||
import type { RagfairLinkedItemService } from "@spt/services/RagfairLinkedItemService";
|
||||
import type { DatabaseService } from "@spt/services/DatabaseService";
|
||||
|
||||
export const linkedSlotSearch = (container: DependencyContainer) => {
|
||||
const logger = container.resolve<ILogger>("PrimaryLogger");
|
||||
const itemHelper = container.resolve<ItemHelper>("ItemHelper");
|
||||
const databaseService = container.resolve<DatabaseService>("DatabaseService");
|
||||
|
||||
container.afterResolution(
|
||||
"RagfairLinkedItemService",
|
||||
(_, linkedItemService: RagfairLinkedItemService) => {
|
||||
const original = linkedItemService.getLinkedItems;
|
||||
|
||||
linkedItemService.getLinkedItems = linkedSearchId => {
|
||||
const [tpl, slotName] = linkedSearchId.split(":", 2);
|
||||
|
||||
if (slotName) {
|
||||
logger.info(`UIFixes: Finding items for specific slot ${tpl}:${slotName}`);
|
||||
const allItems = databaseService.getItems();
|
||||
const resultSet = getSpecificFilter(allItems[tpl], slotName);
|
||||
|
||||
// Default Inventory, for equipment slots
|
||||
if (tpl === "55d7217a4bdc2d86028b456d") {
|
||||
const categories = [...resultSet];
|
||||
const items = Object.keys(allItems).filter(tpl => itemHelper.isOfBaseclasses(tpl, categories));
|
||||
|
||||
// Send the categories along too, some of them might actually be items
|
||||
return new Set(items.concat(categories));
|
||||
}
|
||||
|
||||
return resultSet;
|
||||
}
|
||||
|
||||
return original.call(linkedItemService, tpl);
|
||||
};
|
||||
},
|
||||
{ frequency: "Always" }
|
||||
);
|
||||
};
|
||||
|
||||
const getSpecificFilter = (item: ITemplateItem, slotName: string): Set<string> => {
|
||||
const results = new Set<string>();
|
||||
|
||||
// For whatever reason, all chamber slots have the name "patron_in_weapon"
|
||||
const groupName = slotName === "patron_in_weapon" ? "Chambers" : "Slots";
|
||||
const group = item._props[groupName] ?? [];
|
||||
|
||||
const sub = group.find(slot => slot._name === slotName);
|
||||
for (const filter of sub?._props?.filters ?? []) {
|
||||
for (const f of filter.Filter) {
|
||||
results.add(f);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
};
|
||||
30
user/mods/tyfon-uifixes/src/mod.ts
Normal file
30
user/mods/tyfon-uifixes/src/mod.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import type { DependencyContainer } from "tsyringe";
|
||||
|
||||
import type { IPreSptLoadMod } from "@spt/models/external/IPreSptLoadMod";
|
||||
|
||||
import { assortUnlocks } from "./assortUnlocks";
|
||||
import { keepQuickBinds } from "./keepQuickBinds";
|
||||
import { linkedSlotSearch } from "./linkedSlotSearch";
|
||||
import { putToolsBack } from "./putToolsBack";
|
||||
|
||||
import config from "../config/config.json";
|
||||
|
||||
class UIFixes implements IPreSptLoadMod {
|
||||
public preSptLoad(container: DependencyContainer): void {
|
||||
// Keep quickbinds for items that aren't actually lost on death
|
||||
keepQuickBinds(container);
|
||||
|
||||
// Better tool return - starting production
|
||||
if (config.putToolsBack) {
|
||||
putToolsBack(container);
|
||||
}
|
||||
|
||||
// Slot-specific linked search
|
||||
linkedSlotSearch(container);
|
||||
|
||||
// Show unlocking quest on locked offers
|
||||
assortUnlocks(container);
|
||||
}
|
||||
}
|
||||
|
||||
export const mod = new UIFixes();
|
||||
166
user/mods/tyfon-uifixes/src/putToolsBack.ts
Normal file
166
user/mods/tyfon-uifixes/src/putToolsBack.ts
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
import type { DependencyContainer } from "tsyringe";
|
||||
|
||||
import type { HideoutHelper } from "@spt/helpers/HideoutHelper";
|
||||
import type { InventoryHelper } from "@spt/helpers/InventoryHelper";
|
||||
import type { ItemHelper } from "@spt/helpers/ItemHelper";
|
||||
import type { IPmcData } from "@spt/models/eft/common/IPmcData";
|
||||
import type { IItem } from "@spt/models/eft/common/tables/IItem";
|
||||
import type { IHideoutSingleProductionStartRequestData } from "@spt/models/eft/hideout/IHideoutSingleProductionStartRequestData";
|
||||
import type { ILogger } from "@spt/models/spt/utils/ILogger";
|
||||
import type { ICloner } from "@spt/utils/cloners/ICloner";
|
||||
|
||||
const returnToProperty = "uifixes.returnTo";
|
||||
|
||||
export const putToolsBack = (container: DependencyContainer) => {
|
||||
const logger = container.resolve<ILogger>("PrimaryLogger");
|
||||
const cloner = container.resolve<ICloner>("RecursiveCloner");
|
||||
const itemHelper = container.resolve<ItemHelper>("ItemHelper");
|
||||
|
||||
container.afterResolution(
|
||||
"HideoutHelper",
|
||||
(_, hideoutHelper: HideoutHelper) => {
|
||||
const original = hideoutHelper.registerProduction;
|
||||
|
||||
hideoutHelper.registerProduction = (pmcData, body, sessionID) => {
|
||||
const result = original.call(hideoutHelper, pmcData, body, sessionID);
|
||||
|
||||
// The items haven't been deleted yet, augment the list with their parentId
|
||||
try {
|
||||
const bodyAsSingle = body as IHideoutSingleProductionStartRequestData;
|
||||
if (bodyAsSingle && bodyAsSingle.tools?.length > 0) {
|
||||
const requestTools = bodyAsSingle.tools;
|
||||
const tools = pmcData.Hideout.Production[body.recipeId].sptRequiredTools;
|
||||
for (let i = 0; i < tools.length; i++) {
|
||||
const originalTool = pmcData.Inventory.items.find(x => x._id === requestTools[i].id);
|
||||
|
||||
// If the tool is in the stash itself, skip it. Same check as InventoryHelper.isItemInStash
|
||||
if (
|
||||
originalTool.parentId === pmcData.Inventory.stash &&
|
||||
originalTool.slotId === "hideout"
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
tools[i][returnToProperty] = [originalTool.parentId, originalTool.slotId];
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`UIFixes: Failed to save tool origin\n ${error}`);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
},
|
||||
{ frequency: "Always" }
|
||||
);
|
||||
|
||||
// Better tool return - returning the tool
|
||||
container.afterResolution(
|
||||
"InventoryHelper",
|
||||
(_, inventoryHelper: InventoryHelper) => {
|
||||
const original = inventoryHelper.addItemToStash;
|
||||
|
||||
inventoryHelper.addItemToStash = (sessionId, request, pmcData, output) => {
|
||||
const itemWithModsToAddClone = cloner.clone(request.itemWithModsToAdd);
|
||||
|
||||
// If a tool marked with uifixes is there, try to return it to its original container
|
||||
const tool = itemWithModsToAddClone[0];
|
||||
if (tool[returnToProperty]) {
|
||||
try {
|
||||
const [containerId, slotId] = tool[returnToProperty];
|
||||
|
||||
// Clean the item
|
||||
delete tool[returnToProperty];
|
||||
|
||||
const [foundContainerFS2D, foundSlotId] = findGridFS2DForItems(
|
||||
inventoryHelper,
|
||||
containerId,
|
||||
slotId,
|
||||
itemWithModsToAddClone,
|
||||
pmcData
|
||||
);
|
||||
|
||||
if (foundContainerFS2D) {
|
||||
// At this point everything should succeed
|
||||
inventoryHelper.placeItemInContainer(
|
||||
foundContainerFS2D,
|
||||
itemWithModsToAddClone,
|
||||
containerId,
|
||||
foundSlotId
|
||||
);
|
||||
|
||||
// protected function, bypass typescript
|
||||
inventoryHelper["setFindInRaidStatusForItem"](itemWithModsToAddClone, request.foundInRaid);
|
||||
|
||||
// Add item + mods to output and profile inventory
|
||||
output.profileChanges[sessionId].items.new.push(...itemWithModsToAddClone);
|
||||
pmcData.Inventory.items.push(...itemWithModsToAddClone);
|
||||
|
||||
logger.debug(
|
||||
`Added ${itemWithModsToAddClone[0].upd?.StackObjectsCount ?? 1} item: ${
|
||||
itemWithModsToAddClone[0]._tpl
|
||||
} with: ${itemWithModsToAddClone.length - 1} mods to ${containerId}`
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`UIFixes: Encounted an error trying to put tool back.\n ${error}`);
|
||||
}
|
||||
|
||||
logger.info("UIFixes: Unable to put tool back in its original container, returning it to stash.");
|
||||
}
|
||||
|
||||
return original.call(inventoryHelper, sessionId, request, pmcData, output);
|
||||
};
|
||||
},
|
||||
{ frequency: "Always" }
|
||||
);
|
||||
|
||||
function findGridFS2DForItems(
|
||||
inventoryHelper: InventoryHelper,
|
||||
containerId: string,
|
||||
startingGrid: string,
|
||||
items: IItem[],
|
||||
pmcData: IPmcData
|
||||
): [number[][], string] | undefined {
|
||||
const container = pmcData.Inventory.items.find(x => x._id === containerId);
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
|
||||
const [foundTemplate, containerTemplate] = itemHelper.getItem(container._tpl);
|
||||
if (!foundTemplate || !containerTemplate) {
|
||||
return;
|
||||
}
|
||||
|
||||
let originalGridIndex = containerTemplate._props.Grids.findIndex(g => g._name === startingGrid);
|
||||
if (originalGridIndex < 0) {
|
||||
originalGridIndex = 0;
|
||||
}
|
||||
|
||||
// Loop through grids, starting from the original grid
|
||||
for (
|
||||
let gridIndex = originalGridIndex;
|
||||
gridIndex < containerTemplate._props.Grids.length + originalGridIndex;
|
||||
gridIndex++
|
||||
) {
|
||||
const grid = containerTemplate._props.Grids[gridIndex % containerTemplate._props.Grids.length];
|
||||
const gridItems = pmcData.Inventory.items.filter(
|
||||
x => x.parentId === containerId && x.slotId === grid._name
|
||||
);
|
||||
|
||||
const containerFS2D = inventoryHelper.getContainerMap(
|
||||
grid._props.cellsH,
|
||||
grid._props.cellsV,
|
||||
gridItems,
|
||||
containerId
|
||||
);
|
||||
|
||||
// will change the array so clone it
|
||||
if (inventoryHelper.canPlaceItemInContainer(cloner.clone(containerFS2D), items)) {
|
||||
return [containerFS2D, grid._name];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue