0
0
mirror of https://github.com/sp-tarkov/server.git synced 2025-02-13 09:50:43 -05:00

Merge branch 'master' of https://dev.sp-tarkov.com/SPT-AKI/Server into 3.8.0

# Conflicts:
#	project/assets/configs/core.json
#	project/package.json
#	project/src/generators/RagfairOfferGenerator.ts
This commit is contained in:
Dev 2023-12-19 17:31:19 +00:00
commit 90324ed343
27 changed files with 2174 additions and 2205 deletions

View File

@ -106,10 +106,10 @@ Player profile is stored in SPT folder as a JSON file, allowing for changes to p
- followerKojaniy - followerKojaniy
- followerSanitar - followerSanitar
- followerzryachiy - followerzryachiy
- gifter (santa) - gifter (Santa)
- ~~Gives gifts~~ NOT IMPLEMENTED - Gives gifts (partially implemented)
- marksman - marksman
- pmcBot (raider) - pmcBot (Raider)
- sectantPriest (Cultist) - sectantPriest (Cultist)
- sectantWarrior (Cultist) - sectantWarrior (Cultist)
- Gear - Gear
@ -239,7 +239,7 @@ Player profile is stored in SPT folder as a JSON file, allowing for changes to p
- Negative effects removal rate x2 - Negative effects removal rate x2
- Illumination - Illumination
- Intel centre - Intel centre
- ~~Unlocks scav tasks from fence~~ NOT IMPLEMENTED - ~~Unlocks scav tasks from fence~~ NOT IMPLEMENTED - unlocks at level 5
- ~~Reduces insurance return time by 20%~~ NOT IMPLEMENTED - ~~Reduces insurance return time by 20%~~ NOT IMPLEMENTED
- Quest money reward boost - Quest money reward boost
- Lavatory - Lavatory
@ -287,7 +287,15 @@ Player profile is stored in SPT folder as a JSON file, allowing for changes to p
- Airdrops - Airdrops
- Randomised chance of spawning - Randomised chance of spawning
- Fire red flare to request an airdrop - Fire red flare to request an airdrop
- ~~Drops 1 of 3 randomised loot crate types~~ NOT IMPLEMENTED - Drops 'themed' crates:
- Weapons / armor
- Only weapons and armor
- Food / medical
- Only food and medical items
- Barter goods
- Only barter goods
- Mixed
- A mixture of any of the above items
- Drops lootable crate in: - Drops lootable crate in:
- Customs - Customs
- Reserve - Reserve

View File

@ -789,6 +789,86 @@
"messageText": "caw caw", "messageText": "caw caw",
"collectionTimeHours": 48, "collectionTimeHours": 48,
"associatedEvent": "Promo" "associatedEvent": "Promo"
},
"CWX": {
"items": [{
"_id": "a89275c1b18274ef7432a6d9",
"_tpl": "5c13cef886f774072e618e82",
"slotId": "main",
"upd": {
"StackObjectsCount": 2
},
"parentId": "64b996c9d0de4697180359b6"
}
],
"sender": "System",
"messageText": "un oh stinky",
"collectionTimeHours": 48,
"associatedEvent": "Promo"
},
"TERKOIZ": {
"items": [{
"_id": "a89275c1b18274ef7432a6d9",
"_tpl": "5a0eb38b86f774153b320eb0",
"slotId": "main",
"upd": {
"StackObjectsCount": 1
},
"parentId": "64b996c9d0de4697180359b6"
}
],
"sender": "System",
"messageText": "Out of the way, i'm a motorist",
"collectionTimeHours": 48,
"associatedEvent": "Promo"
},
"WAFFLE": {
"items": [{
"_id": "a89275c1b18274ef7432a6d9",
"_tpl": "57347d90245977448f7b7f65",
"slotId": "main",
"upd": {
"StackObjectsCount": 1
},
"parentId": "64b996c9d0de4697180359b6"
},{
"_id": "a89275c1b18274ef7432a6d9",
"_tpl": "575146b724597720a27126d5",
"slotId": "main",
"upd": {
"StackObjectsCount": 1
},
"parentId": "64b996c9d0de4697180359b6"
}
],
"sender": "System",
"messageText": "JONKLER NO",
"collectionTimeHours": 48,
"associatedEvent": "Promo"
},
"NIGHTWING": {
"items": [{
"_id": "a89275c1b18274ef7432a6d9",
"_tpl": "57347d90245977448f7b7f65",
"slotId": "main",
"upd": {
"StackObjectsCount": 1
},
"parentId": "64b996c9d0de4697180359b6"
},{
"_id": "a89275c1b18274ef7432a6d3",
"_tpl": "575146b724597720a27126d5",
"slotId": "main",
"upd": {
"StackObjectsCount": 1
},
"parentId": "64b996c9d0de4697180359b6"
}
],
"sender": "System",
"messageText": "JONKLER NO",
"collectionTimeHours": 48,
"associatedEvent": "Promo"
}, },
"BSGBIRTHDAY2023": { "BSGBIRTHDAY2023": {
"sender": "System", "sender": "System",

View File

@ -7,7 +7,7 @@
"54cb50c76803fa8b248b4571": 75, "54cb50c76803fa8b248b4571": 75,
"54cb57776803fa99248b456e": 85 "54cb57776803fa99248b456e": 85
}, },
"blacklistedEquipment": [], "blacklistedEquipment": ["SpecialSlot1", "SpecialSlot2", "SpecialSlot3"],
"returnTimeOverrideSeconds": 0, "returnTimeOverrideSeconds": 0,
"runIntervalSeconds": 600 "runIntervalSeconds": 600
} }

View File

@ -807,7 +807,7 @@
}, },
"rewardBaseTypeBlacklist": ["543be5e94bdc2df1348b4568", "5b3f15d486f77432d0509248", "59f32c3b86f77472a31742f0", "59f32bb586f774757e1e8442"], "rewardBaseTypeBlacklist": ["543be5e94bdc2df1348b4568", "5b3f15d486f77432d0509248", "59f32c3b86f77472a31742f0", "59f32bb586f774757e1e8442"],
"rewardBlacklist": ["627bce33f21bc425b06ab967"], "rewardBlacklist": ["627bce33f21bc425b06ab967"],
"rewardAmmoStackMinSize": 20 "rewardAmmoStackMinSize": 5
}, { }, {
"id": "618035d38012292db3081bf0", "id": "618035d38012292db3081bf0",
"name": "Weekly", "name": "Weekly",
@ -1544,7 +1544,7 @@
}, },
"rewardBaseTypeBlacklist": ["543be5e94bdc2df1348b4568", "5b3f15d486f77432d0509248", "59f32c3b86f77472a31742f0", "59f32bb586f774757e1e8442"], "rewardBaseTypeBlacklist": ["543be5e94bdc2df1348b4568", "5b3f15d486f77432d0509248", "59f32c3b86f77472a31742f0", "59f32bb586f774757e1e8442"],
"rewardBlacklist": ["627bce33f21bc425b06ab967"], "rewardBlacklist": ["627bce33f21bc425b06ab967"],
"rewardAmmoStackMinSize": 15 "rewardAmmoStackMinSize": 5
}, { }, {
"id": "62825ef60e88d037dc1eb426", "id": "62825ef60e88d037dc1eb426",
"name": "Daily_Savage", "name": "Daily_Savage",
@ -1903,7 +1903,7 @@
}, },
"rewardBaseTypeBlacklist": ["543be5e94bdc2df1348b4568", "5b3f15d486f77432d0509248"], "rewardBaseTypeBlacklist": ["543be5e94bdc2df1348b4568", "5b3f15d486f77432d0509248"],
"rewardBlacklist": ["627bce33f21bc425b06ab967"], "rewardBlacklist": ["627bce33f21bc425b06ab967"],
"rewardAmmoStackMinSize": 15 "rewardAmmoStackMinSize": 5
} }
], ],
"locationIdMap": { "locationIdMap": {

View File

@ -1,12 +1,12 @@
{ {
"runIntervalSeconds": 45, "runIntervalSeconds": 45,
"sell": { "sell": {
"simulatedSellHours": 12,
"fees": true, "fees": true,
"chance": { "chance": {
"base": 50, "base": 50,
"overpriced": 1.7, "sellMultiplier": 1.24,
"underpriced": 2 "maxSellChancePercent": 100,
"minSellChancePercent": 0
}, },
"time": { "time": {
"base": 1.5, "base": 1.5,

View File

@ -104,8 +104,8 @@
"mod_scope_001": 50, "mod_scope_001": 50,
"mod_scope_002": 40, "mod_scope_002": 40,
"mod_scope_003": 40, "mod_scope_003": 40,
"mod_sight_front": 95, "mod_sight_front": 100,
"mod_sight_rear": 95, "mod_sight_rear": 100,
"mod_stock": 100, "mod_stock": 100,
"mod_stock_000": 100, "mod_stock_000": 100,
"mod_stock_001": 100, "mod_stock_001": 100,

View File

@ -101,8 +101,8 @@
"mod_scope_001": 50, "mod_scope_001": 50,
"mod_scope_002": 40, "mod_scope_002": 40,
"mod_scope_003": 40, "mod_scope_003": 40,
"mod_sight_front": 95, "mod_sight_front": 100,
"mod_sight_rear": 95, "mod_sight_rear": 100,
"mod_stock": 100, "mod_stock": 100,
"mod_stock_000": 100, "mod_stock_000": 100,
"mod_stock_001": 100, "mod_stock_001": 100,

View File

@ -42,7 +42,7 @@
], ],
"BossLocationSpawn": [ "BossLocationSpawn": [
{ {
"BossChance": 35, "BossChance": 20,
"BossDifficult": "normal", "BossDifficult": "normal",
"BossEscortAmount": "2", "BossEscortAmount": "2",
"BossEscortDifficult": "normal", "BossEscortDifficult": "normal",

File diff suppressed because it is too large Load Diff

View File

@ -61,10 +61,13 @@ export class RagfairCallbacks implements OnLoad, OnUpdate
{ {
// There is a flag inside this class that only makes it run once. // There is a flag inside this class that only makes it run once.
this.ragfairServer.addPlayerOffers(); this.ragfairServer.addPlayerOffers();
await this.ragfairServer.update();
// function below used to be split, merged // Check player offers and mail payment to player if sold
this.ragfairController.update(); this.ragfairController.update();
// Process all offers / expire offers
await this.ragfairServer.update();
return true; return true;
} }
return false; return false;

View File

@ -64,7 +64,7 @@ export class ApplicationContext
public clearValues(type: ContextVariableType): void public clearValues(type: ContextVariableType): void
{ {
this.variables.has(type) if (this.variables.has(type))
{ {
this.variables.delete(type); this.variables.delete(type);
} }

View File

@ -181,7 +181,7 @@ export class RagfairController
protected getSpecificCategories(pmcProfile: IPmcData, searchRequest: ISearchRequestData, offers: IRagfairOffer[]): Record<string, number> protected getSpecificCategories(pmcProfile: IPmcData, searchRequest: ISearchRequestData, offers: IRagfairOffer[]): Record<string, number>
{ {
// Linked/required search categories // Linked/required search categories
const playerHasFleaUnlocked = pmcProfile.Info.Level > this.databaseServer.getTables().globals.config.RagFair.minUserLevel; const playerHasFleaUnlocked = pmcProfile.Info.Level >= this.databaseServer.getTables().globals.config.RagFair.minUserLevel;
let offerPool = []; let offerPool = [];
if (this.isLinkedSearch(searchRequest) || this.isRequiredSearch(searchRequest)) if (this.isLinkedSearch(searchRequest) || this.isRequiredSearch(searchRequest))
{ {
@ -307,6 +307,9 @@ export class RagfairController
return info.neededSearchId !== ""; return info.neededSearchId !== "";
} }
/**
* Check all profiles and sell player offers / send player money for listing if it sold
*/
public update(): void public update(): void
{ {
for (const sessionID in this.saveServer.getProfiles()) for (const sessionID in this.saveServer.getProfiles())

View File

@ -603,7 +603,7 @@ export class BotLootGenerator
{ {
const randomSize = itemTemplate._props.StackMaxSize === 1 const randomSize = itemTemplate._props.StackMaxSize === 1
? 1 ? 1
: this.randomUtil.getInt(itemTemplate._props.StackMinRandom, itemTemplate._props.StackMaxRandom); : this.randomUtil.getInt(itemTemplate._props.StackMinRandom, Math.min(itemTemplate._props.StackMaxRandom, 60));
if (!ammoItem.upd) if (!ammoItem.upd)
{ {

View File

@ -276,8 +276,9 @@ export class RagfairOfferGenerator
{ {
if (this.ragfairServerHelper.isPlayer(userID)) if (this.ragfairServerHelper.isPlayer(userID))
{ {
// Player offer // Player offer = current time + offerDurationTimeInHour;
return this.timeUtil.getTimestamp() + Math.round(12 * TimeUtil.ONE_HOUR_AS_SECONDS); const offerDurationTimeHours = this.databaseServer.getTables().globals.config.RagFair.offerDurationTimeInHour;
return this.timeUtil.getTimestamp() + Math.round(offerDurationTimeHours * TimeUtil.oneHourAsSeconds);
} }
if (this.ragfairServerHelper.isTrader(userID)) if (this.ragfairServerHelper.isTrader(userID))

View File

@ -916,7 +916,7 @@ export class RepeatableQuestGenerator
{ {
// Add a random default preset weapon as reward // Add a random default preset weapon as reward
const defaultPresets = Object.values(this.presetHelper.getDefaultPresets()); const defaultPresets = Object.values(this.presetHelper.getDefaultPresets());
const defaultPreset = this.randomUtil.getArrayValue(defaultPresets); const defaultPreset = this.jsonUtil.clone(this.randomUtil.getArrayValue(defaultPresets));
// use _encyclopedia as its always the base items _tpl, items[0] isnt guaranteed to be base item // use _encyclopedia as its always the base items _tpl, items[0] isnt guaranteed to be base item
rewards.Success.push(this.generateRewardItem(defaultPreset._encyclopedia, 1, rewardIndex, defaultPreset._items)); rewards.Success.push(this.generateRewardItem(defaultPreset._encyclopedia, 1, rewardIndex, defaultPreset._items));
@ -929,6 +929,7 @@ export class RepeatableQuestGenerator
{ {
let rewardItemStackCount = 1; let rewardItemStackCount = 1;
const itemSelected = rewardItemPool[this.randomUtil.randInt(rewardItemPool.length)]; const itemSelected = rewardItemPool[this.randomUtil.randInt(rewardItemPool.length)];
if (this.itemHelper.isOfBaseclass(itemSelected._id, BaseClasses.AMMO)) if (this.itemHelper.isOfBaseclass(itemSelected._id, BaseClasses.AMMO))
{ {
// Dont reward ammo that stacks to less than what's defined in config // Dont reward ammo that stacks to less than what's defined in config
@ -937,14 +938,22 @@ export class RepeatableQuestGenerator
continue; continue;
} }
// Randomise the cartridge count returned // The budget for this ammo stack
rewardItemStackCount = this.randomUtil.randInt( const stackRoubleBudget = roublesBudget / rewardNumItems;
repeatableConfig.rewardAmmoStackMinSize,
itemSelected._props.StackMaxSize, const singleCartridgePrice = this.handbookHelper.getTemplatePrice(itemSelected._id);
);
// Get a stack size of ammo that fits rouble budget
const stackSizeThatFitsBudget = Math.round(stackRoubleBudget / singleCartridgePrice);
// Get itemDbs max stack size for ammo - dont go above 100 (some mods mess around with stack sizes)
const stackMaxCount = Math.min(itemSelected._props.StackMaxSize, 100);
// Choose smallest value between budget fitting size and stack max
rewardItemStackCount = Math.min(stackSizeThatFitsBudget, stackMaxCount);
} }
// 25% chance to double reward stack (item should be stackable and not weapon) // 25% chance to double,triple quadruple reward stack (Only occurs when item is stackable and not weapon or ammo)
if (this.canIncreaseRewardItemStackSize(itemSelected, 70000)) if (this.canIncreaseRewardItemStackSize(itemSelected, 70000))
{ {
rewardItemStackCount = this.getRandomisedRewardItemStackSizeByPrice(itemSelected); rewardItemStackCount = this.getRandomisedRewardItemStackSizeByPrice(itemSelected);

View File

@ -523,7 +523,7 @@ export class InRaidHelper
// Add the new items // Add the new items
serverProfile.Inventory.items = [...postRaidProfile.Inventory.items, ...serverProfile.Inventory.items]; serverProfile.Inventory.items = [...postRaidProfile.Inventory.items, ...serverProfile.Inventory.items];
serverProfile.Inventory.fastPanel = postRaidProfile.Inventory.fastPanel; serverProfile.Inventory.fastPanel = postRaidProfile.Inventory.fastPanel; // Quick access items bar
serverProfile.InsuredItems = insured; serverProfile.InsuredItems = insured;
return serverProfile; return serverProfile;

View File

@ -1032,7 +1032,14 @@ export class ItemHelper
const cartridgeMaxStackSize = cartridgeDetails[1]._props.StackMaxSize; const cartridgeMaxStackSize = cartridgeDetails[1]._props.StackMaxSize;
// Get max number of cartridges in magazine, choose random value between min/max // Get max number of cartridges in magazine, choose random value between min/max
const magazineCartridgeMaxCount = magTemplate._props.Cartridges[0]._max_count; const magazineCartridgeMaxCount = magTemplate._props.Cartridges[0]?._max_count;
if (!magazineCartridgeMaxCount)
{
this.logger.warning(`Magazine: ${magTemplate._id} ${magTemplate._name} lacks a Cartridges array, unable to fill magazine with ammo`);
return;
}
const desiredStackCount = this.randomUtil.getInt( const desiredStackCount = this.randomUtil.getInt(
Math.round(minSizePercent * magazineCartridgeMaxCount), Math.round(minSizePercent * magazineCartridgeMaxCount),
magazineCartridgeMaxCount, magazineCartridgeMaxCount,

View File

@ -599,8 +599,7 @@ export class RagfairOfferHelper
return false; return false;
} }
if ( if (this.isConditionItem(item)
(item.upd.MedKit || item.upd.Repairable)
&& !this.itemQualityInRange(item, searchRequest.conditionFrom, searchRequest.conditionTo) && !this.itemQualityInRange(item, searchRequest.conditionFrom, searchRequest.conditionTo)
) )
{ {
@ -670,6 +669,20 @@ export class RagfairOfferHelper
return true; return true;
} }
/**
* Does the passed in item have a condition property
* @param item Item to check
* @returns True if has condition
*/
protected isConditionItem(item: Item): boolean
{
// thanks typescript, undefined assertion is not returnable since it
// tries to return a multitype object
return (item.upd.MedKit || item.upd.Repairable || item.upd.Resource || item.upd.FoodDrink || item.upd.Key || item.upd.RepairKit)
? true
: false;
}
/** /**
* Is items quality value within desired range * Is items quality value within desired range
* @param item Item to check quality of * @param item Item to check quality of

View File

@ -5,6 +5,7 @@ import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
import { IRagfairConfig } from "@spt-aki/models/spt/config/IRagfairConfig"; import { IRagfairConfig } from "@spt-aki/models/spt/config/IRagfairConfig";
import { ILogger } from "@spt-aki/models/spt/utils/ILogger"; import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
import { ConfigServer } from "@spt-aki/servers/ConfigServer"; import { ConfigServer } from "@spt-aki/servers/ConfigServer";
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
import { RandomUtil } from "@spt-aki/utils/RandomUtil"; import { RandomUtil } from "@spt-aki/utils/RandomUtil";
import { TimeUtil } from "@spt-aki/utils/TimeUtil"; import { TimeUtil } from "@spt-aki/utils/TimeUtil";
@ -17,6 +18,7 @@ export class RagfairSellHelper
@inject("WinstonLogger") protected logger: ILogger, @inject("WinstonLogger") protected logger: ILogger,
@inject("RandomUtil") protected randomUtil: RandomUtil, @inject("RandomUtil") protected randomUtil: RandomUtil,
@inject("TimeUtil") protected timeUtil: TimeUtil, @inject("TimeUtil") protected timeUtil: TimeUtil,
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
@inject("ConfigServer") protected configServer: ConfigServer, @inject("ConfigServer") protected configServer: ConfigServer,
) )
{ {
@ -36,32 +38,28 @@ export class RagfairSellHelper
qualityMultiplier: number, qualityMultiplier: number,
): number ): number
{ {
const baseSellChancePercent = this.ragfairConfig.sell.chance.base * qualityMultiplier; const sellConfig = this.ragfairConfig.sell.chance;
const listedPriceAboveAverage = playerListedPriceRub > averageOfferPriceRub; // Base sell chance modified by items quality
// Get sell chance multiplier const baseSellChancePercent = sellConfig.base * qualityMultiplier;
const multiplier = listedPriceAboveAverage
? this.ragfairConfig.sell.chance.overpriced // Player price is over average listing price
: this.getSellMultiplierWhenPlayerPriceIsBelowAverageListingPrice(
averageOfferPriceRub,
playerListedPriceRub,
);
return Math.round(baseSellChancePercent * (averageOfferPriceRub / playerListedPriceRub * multiplier)); // Modfier gets applied twice to either penalize or incentivize over/under pricing (Probably a cleaner way to do this)
} const sellModifier = (averageOfferPriceRub / playerListedPriceRub) * sellConfig.sellMultiplier;
let sellChance = Math.round((baseSellChancePercent * sellModifier) * sellModifier);
/** // Adjust sell chance if below config value
* Get percent chance to sell an item when price is below items average listing price if (sellChance < sellConfig.minSellChancePercent)
* @param playerListedPriceRub Price player listed item for in roubles {
* @param averageOfferPriceRub Price of average offer in roubles sellChance = sellConfig.minSellChancePercent;
* @returns percent value }
*/
protected getSellMultiplierWhenPlayerPriceIsBelowAverageListingPrice( // Adjust sell chance if above config value
averageOfferPriceRub: number, if (sellChance > sellConfig.maxSellChancePercent)
playerListedPriceRub: number, {
): number sellChance = sellConfig.maxSellChancePercent;
{ }
return (playerListedPriceRub < averageOfferPriceRub) ? this.ragfairConfig.sell.chance.underpriced : 1;
return sellChance;
} }
/** /**
@ -75,10 +73,7 @@ export class RagfairSellHelper
const startTime = this.timeUtil.getTimestamp(); const startTime = this.timeUtil.getTimestamp();
// Get a time in future to stop simulating sell chances at // Get a time in future to stop simulating sell chances at
const endTime = startTime + this.timeUtil.getHoursAsSeconds(this.ragfairConfig.sell.simulatedSellHours); const endTime = startTime + this.timeUtil.getHoursAsSeconds(this.databaseServer.getTables().globals.config.RagFair.offerDurationTimeInHour);
// TODO - Write comment - what is going on here
const chance = 100 - Math.min(Math.max(sellChancePercent, 0), 100);
let sellTime = startTime; let sellTime = startTime;
let remainingCount = itemSellCount; let remainingCount = itemSellCount;
@ -107,10 +102,13 @@ export class RagfairSellHelper
if (this.randomUtil.getChance100(sellChancePercent)) if (this.randomUtil.getChance100(sellChancePercent))
{ {
// Passed roll check, item will be sold // Passed roll check, item will be sold
sellTime += Math.max( // Weight time to sell towards selling faster based on how cheap the item sold
Math.round(chance / 100 * this.ragfairConfig.sell.time.max * 60), const weighting = (100 - sellChancePercent) / 100;
this.ragfairConfig.sell.time.min * 60, let maximumTime = weighting * (this.ragfairConfig.sell.time.max * 60);
); const minimumTime = this.ragfairConfig.sell.time.min * 60;
if (maximumTime < minimumTime) maximumTime = minimumTime + 5;
// Sell time will be random between min/max
sellTime += Math.floor(Math.random() * (maximumTime - minimumTime) + minimumTime);
result.push({ sellTime: sellTime, amount: boughtAmount }); result.push({ sellTime: sellTime, amount: boughtAmount });

View File

@ -160,7 +160,7 @@ export class RagfairServerHelper
MessageType.MESSAGE_WITH_ITEMS, MessageType.MESSAGE_WITH_ITEMS,
RagfairServerHelper.goodsReturnedTemplate, RagfairServerHelper.goodsReturnedTemplate,
returnedItems, returnedItems,
this.timeUtil.getHoursAsSeconds(this.questConfig.redeemTime), this.timeUtil.getHoursAsSeconds(this.databaseServer.getTables().globals.config.RagFair.yourOfferDidNotSellMaxStorageTimeInHour),
); );
} }

View File

@ -27,6 +27,9 @@ export enum Ammo762x54
T46M_GZH = "5e023cf8186a883be655e54f", T46M_GZH = "5e023cf8186a883be655e54f",
BT_GZH = "5e023d34e8a400319a28ed44", BT_GZH = "5e023d34e8a400319a28ed44",
BS_GZH = "5e023d48186a883be655e551", BS_GZH = "5e023d48186a883be655e551",
FMJ = "64b8f7968532cf95ee0a0dbf",
SP_BT = "64b8f7b5389d7ffd620ccba2",
HP_BT = "64b8f7c241772715af0f9c3d",
} }
export enum Ammo86x70 export enum Ammo86x70
@ -43,6 +46,7 @@ export enum Ammo46x30
ACTION_SX = "5ba26812d4351e003201fef1", ACTION_SX = "5ba26812d4351e003201fef1",
FMJ_SX = "5ba2678ad4351e44f824b344", FMJ_SX = "5ba2678ad4351e44f824b344",
SUBSONIC_SX = "5ba26844d4351e00334c9475", SUBSONIC_SX = "5ba26844d4351e00334c9475",
JSP_SX = "64b6979341772715af0f9c39",
} }
export enum Ammo57x28 export enum Ammo57x28
@ -95,6 +99,7 @@ export enum Ammo9x19
LUGER_CCI = "5a3c16fe86f77452b62de32a", LUGER_CCI = "5a3c16fe86f77452b62de32a",
PBP_GZH = "5efb0da7a29a85116f6ea05f", PBP_GZH = "5efb0da7a29a85116f6ea05f",
QUAKEMAKER = "5efb0e16aeb21837e749c7ff", QUAKEMAKER = "5efb0e16aeb21837e749c7ff",
FMJ_M882 = "64b7bbb74b75259c590fa897",
} }
export enum Ammo9x21 export enum Ammo9x21
@ -161,6 +166,7 @@ export enum Ammo762x35
AP = "5fd20ff893a8961fc660a954", AP = "5fd20ff893a8961fc660a954",
V_MAX = "6196364158ef8c428c287d9f", V_MAX = "6196364158ef8c428c287d9f",
WHISPER = "6196365d58ef8c428c287da1", WHISPER = "6196365d58ef8c428c287da1",
CBJ = "64b8725c4b75259c590fa899",
} }
export enum Ammo762x39 export enum Ammo762x39
@ -171,6 +177,9 @@ export enum Ammo762x39
T45M1_GZH = "59e4cf5286f7741778269d8a", T45M1_GZH = "59e4cf5286f7741778269d8a",
BP_GZH = "59e0d99486f7744a32234762", BP_GZH = "59e0d99486f7744a32234762",
MAI_AP = "601aa3d2b2bcb34913271e6d", MAI_AP = "601aa3d2b2bcb34913271e6d",
PP_GZH = "64b7af434b75259c590fa893",
SP = "64b7af734b75259c590fa895",
FMJ = "64b7af5a8532cf95ee0a0dbd",
} }
export enum Ammo9x39 export enum Ammo9x39
@ -215,6 +224,7 @@ export enum Ammo12Gauge
SUPERFORMANCE_HP_SLUG = "5d6e68d1a4b93622fe60e845", SUPERFORMANCE_HP_SLUG = "5d6e68d1a4b93622fe60e845",
COPPER_SABOT_PREMIER_HP_SLUG = "5d6e68b3a4b9361bca7e50b5", COPPER_SABOT_PREMIER_HP_SLUG = "5d6e68b3a4b9361bca7e50b5",
LEAD_SLUG = "58820d1224597753c90aeb13", LEAD_SLUG = "58820d1224597753c90aeb13",
PIRANHA = "64b8ee384b75259c590fa89b",
} }
export enum Ammo20Gauge export enum Ammo20Gauge

View File

@ -120,10 +120,13 @@ export interface IScavRaidTimeLocationSettings
{ {
/** Should loot be reduced by same percent length of raid is reduced by */ /** Should loot be reduced by same percent length of raid is reduced by */
reduceLootByPercent: boolean; reduceLootByPercent: boolean;
/** Smallest % of container loot that should be spawned */
minStaticLootPercent: number; minStaticLootPercent: number;
/** Smallest % of loose loot that should be spawned */
minDynamicLootPercent: number; minDynamicLootPercent: number;
/** Chance raid time is reduced */ /** Chance raid time is reduced */
reducedChancePercent: number; reducedChancePercent: number;
/** How much should raid time be reduced - weighted */
reductionPercentWeights: Record<string, number>; reductionPercentWeights: Record<string, number>;
/** Should bot waves be removed / spawn times be adjusted */ /** Should bot waves be removed / spawn times be adjusted */
adjustWaves: boolean; adjustWaves: boolean;

View File

@ -23,17 +23,20 @@ export interface Sell
time: Time; time: Time;
/** Player offer reputation gain/loss settings */ /** Player offer reputation gain/loss settings */
reputation: Reputation; reputation: Reputation;
/** How many hours are simulated to figure out if player offer was sold */
simulatedSellHours: number;
/**Seconds from clicking remove to remove offer from market */ /**Seconds from clicking remove to remove offer from market */
expireSeconds: number; expireSeconds: number;
} }
export interface Chance export interface Chance
{ {
/** Base chance percent to sell an item */
base: number; base: number;
overpriced: number; /** Value to multiply the sell chance by */
underpriced: number; sellMultiplier: number;
/** Max possible sell chance % for a player listed offer */
maxSellChancePercent: number;
/** Min possible sell chance % for a player listed offer */
minSellChancePercent: number;
} }
export interface Time extends MinMax export interface Time extends MinMax

View File

@ -78,7 +78,7 @@ export class RagfairServer
* Get traders who need to be periodically refreshed * Get traders who need to be periodically refreshed
* @returns string array of traders * @returns string array of traders
*/ */
protected getUpdateableTraders(): string[] public getUpdateableTraders(): string[]
{ {
return Object.keys(this.ragfairConfig.traders).filter((x) => this.ragfairConfig.traders[x]); return Object.keys(this.ragfairConfig.traders).filter((x) => this.ragfairConfig.traders[x]);
} }

View File

@ -431,7 +431,7 @@ export class BotEquipmentFilterService
{ {
if (showEditWarnings) if (showEditWarnings)
{ {
this.logger.warning( this.logger.debug(
`Tried to edit a non-existent item for slot: ${poolAdjustmentKey} ${itemToEditKey}`, `Tried to edit a non-existent item for slot: ${poolAdjustmentKey} ${itemToEditKey}`,
); );
} }

View File

@ -242,7 +242,7 @@ export class InsuranceService
continue; continue;
} }
// Skip items we should never return // Skip slots we should never return
if (this.insuranceConfig.blacklistedEquipment.includes(preRaidItem.slotId)) if (this.insuranceConfig.blacklistedEquipment.includes(preRaidItem.slotId))
{ {
continue; continue;

View File

@ -243,15 +243,18 @@ export class RagfairOfferService
); );
} }
profile.RagfairInfo.rating -= this.ragfairConfig.sell.reputation.loss; // Reduce player ragfair rep
profile.RagfairInfo.rating -= this.databaseServer.getTables().globals.config.RagFair.ratingDecreaseCount;
profile.RagfairInfo.isRatingGrowing = false; profile.RagfairInfo.isRatingGrowing = false;
if (offer.items[0].upd.StackObjectsCount > offer.items[0].upd.OriginalStackObjectsCount) const firstOfferItem = offer.items[0];
if (firstOfferItem.upd.StackObjectsCount > firstOfferItem.upd.OriginalStackObjectsCount)
{ {
offer.items[0].upd.StackObjectsCount = offer.items[0].upd.OriginalStackObjectsCount; offer.items[0].upd.StackObjectsCount = firstOfferItem.upd.OriginalStackObjectsCount;
} }
delete offer.items[0].upd.OriginalStackObjectsCount; delete offer.items[0].upd.OriginalStackObjectsCount;
// Send failed offer items to player in mail
this.ragfairServerHelper.returnItems(profile.sessionId, offer.items); this.ragfairServerHelper.returnItems(profile.sessionId, offer.items);
profile.RagfairInfo.offers.splice(offerIndex, 1); profile.RagfairInfo.offers.splice(offerIndex, 1);