Refactor: Update various functions with changes from code review
This commit is contained in:
parent
927273d71d
commit
1fc35881d8
@ -166,12 +166,12 @@ export class QuestController
|
||||
|
||||
/**
|
||||
* Is the quest for the opposite side the player is on
|
||||
* @param side player side (usec/bear)
|
||||
* @param questId questId to check
|
||||
* @param playerSide Player side (usec/bear)
|
||||
* @param questId QuestId to check
|
||||
*/
|
||||
protected questIsForOtherSide(side: string, questId: string): boolean
|
||||
protected questIsForOtherSide(playerSide: string, questId: string): boolean
|
||||
{
|
||||
const isUsec = side.toLowerCase() === "usec";
|
||||
const isUsec = playerSide.toLowerCase() === "usec";
|
||||
if (isUsec && this.questConfig.bearOnlyQuests.includes(questId))
|
||||
{
|
||||
// player is usec and quest is bear only, skip
|
||||
@ -295,18 +295,17 @@ export class QuestController
|
||||
*/
|
||||
protected getRepeatableQuestFromProfile(pmcData: IPmcData, acceptedQuest: IAcceptQuestRequestData): IRepeatableQuest
|
||||
{
|
||||
let result: IRepeatableQuest;
|
||||
for (const repeatable of pmcData.RepeatableQuests)
|
||||
for (const repeatableQuest of pmcData.RepeatableQuests)
|
||||
{
|
||||
result = repeatable.activeQuests.find(x => x._id === acceptedQuest.qid);
|
||||
const result = repeatableQuest.activeQuests.find(x => x._id === acceptedQuest.qid);
|
||||
if (result)
|
||||
{
|
||||
this.logger.debug(`Accepted repeatable quest ${acceptedQuest.qid} from ${repeatable.name}`);
|
||||
this.logger.debug(`Accepted repeatable quest ${acceptedQuest.qid} from ${repeatableQuest.name}`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -324,11 +324,26 @@ export class BotEquipmentModGenerator
|
||||
*/
|
||||
protected setScopeSpawnChancesToFull(modSpawnChances: ModsChances): void
|
||||
{
|
||||
modSpawnChances["mod_scope"] = 100;
|
||||
modSpawnChances["mod_scope_000"] = 100;
|
||||
modSpawnChances["mod_scope_001"] = 100;
|
||||
modSpawnChances["mod_scope_002"] = 100;
|
||||
modSpawnChances["mod_scope_003"] = 100;
|
||||
if (!modSpawnChances)
|
||||
{
|
||||
this.logger.warning("Unable to adjust scope spawn chances as spawn chance object is empty");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const fullSpawnChancePercent = 100;
|
||||
const scopeMods = [
|
||||
"mod_scope",
|
||||
"mod_scope_000",
|
||||
"mod_scope_001",
|
||||
"mod_scope_002",
|
||||
"mod_scope_003"
|
||||
];
|
||||
|
||||
for (const modName of scopeMods)
|
||||
{
|
||||
modSpawnChances[modName] = fullSpawnChancePercent;
|
||||
}
|
||||
}
|
||||
|
||||
protected sortModKeys(unsortedKeys: string[]): string[]
|
||||
@ -423,7 +438,7 @@ export class BotEquipmentModGenerator
|
||||
}
|
||||
|
||||
/**
|
||||
* randomly choose if a mod should be spawned, 100% for required mods OR mod is ammo slot
|
||||
* Randomly choose if a mod should be spawned, 100% for required mods OR mod is ammo slot
|
||||
* never return true for an item that has 0% spawn chance
|
||||
* @param itemSlot slot the item sits in
|
||||
* @param modSlot slot the mod sits in
|
||||
|
@ -257,23 +257,19 @@ export class BotInventoryGenerator
|
||||
*/
|
||||
protected getFilteredDynamicModsForItem(itemTpl: string, equipmentBlacklist: EquipmentFilterDetails[]): Record<string, string[]>
|
||||
{
|
||||
const results = this.botEquipmentModPoolService.getModsForGearSlot(itemTpl);
|
||||
for (const modSlot in results)
|
||||
const modPool = this.botEquipmentModPoolService.getModsForGearSlot(itemTpl);
|
||||
for (const modSlot of Object.keys(modPool))
|
||||
{
|
||||
const blacklistedMods = equipmentBlacklist[0].equipment[modSlot];
|
||||
if (!blacklistedMods)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const filteredMods = results[modSlot].filter(x => !blacklistedMods.includes(x));
|
||||
const blacklistedMods = equipmentBlacklist[0].equipment[modSlot] || [];
|
||||
const filteredMods = modPool[modSlot].filter(x => !blacklistedMods.includes(x));
|
||||
|
||||
if (filteredMods.length > 0)
|
||||
{
|
||||
results[modSlot] = filteredMods;
|
||||
modPool[modSlot] = filteredMods;
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
return modPool;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -41,64 +41,64 @@ export class BotGeneratorHelper
|
||||
*/
|
||||
public generateExtraPropertiesForItem(itemTemplate: ITemplateItem, botRole: string = null): { upd?: Upd }
|
||||
{
|
||||
const properties: Upd = {};
|
||||
const itemProperties: Upd = {};
|
||||
|
||||
if (itemTemplate._props.MaxDurability)
|
||||
{
|
||||
if (itemTemplate._props.weapClass) // Is weapon
|
||||
{
|
||||
properties.Repairable = this.generateWeaponRepairableProperties(itemTemplate, botRole);
|
||||
itemProperties.Repairable = this.generateWeaponRepairableProperties(itemTemplate, botRole);
|
||||
}
|
||||
else if (itemTemplate._props.armorClass) // Is armor
|
||||
{
|
||||
properties.Repairable = this.generateArmorRepairableProperties(itemTemplate, botRole);
|
||||
itemProperties.Repairable = this.generateArmorRepairableProperties(itemTemplate, botRole);
|
||||
}
|
||||
}
|
||||
|
||||
if (itemTemplate._props.HasHinge)
|
||||
{
|
||||
properties.Togglable = { On: true };
|
||||
itemProperties.Togglable = { On: true };
|
||||
}
|
||||
|
||||
if (itemTemplate._props.Foldable)
|
||||
{
|
||||
properties.Foldable = { Folded: false };
|
||||
itemProperties.Foldable = { Folded: false };
|
||||
}
|
||||
|
||||
if (itemTemplate._props.weapFireType?.length)
|
||||
{
|
||||
if (itemTemplate._props.weapFireType.includes("fullauto"))
|
||||
{
|
||||
properties.FireMode = { FireMode: "fullauto" };
|
||||
itemProperties.FireMode = { FireMode: "fullauto" };
|
||||
}
|
||||
else
|
||||
{
|
||||
properties.FireMode = { FireMode: this.randomUtil.getArrayValue(itemTemplate._props.weapFireType) };
|
||||
itemProperties.FireMode = { FireMode: this.randomUtil.getArrayValue(itemTemplate._props.weapFireType) };
|
||||
}
|
||||
}
|
||||
|
||||
if (itemTemplate._props.MaxHpResource)
|
||||
{
|
||||
properties.MedKit = { HpResource: itemTemplate._props.MaxHpResource };
|
||||
itemProperties.MedKit = { HpResource: itemTemplate._props.MaxHpResource };
|
||||
}
|
||||
|
||||
if (itemTemplate._props.MaxResource && itemTemplate._props.foodUseTime)
|
||||
{
|
||||
properties.FoodDrink = { HpPercent: itemTemplate._props.MaxResource };
|
||||
itemProperties.FoodDrink = { HpPercent: itemTemplate._props.MaxResource };
|
||||
}
|
||||
|
||||
if ([BaseClasses.FLASHLIGHT, BaseClasses.TACTICAL_COMBO].includes(<BaseClasses>itemTemplate._parent))
|
||||
{
|
||||
// Get chance from botconfig for bot type, use 50% if no value found
|
||||
const lightLaserActiveChance = this.getBotEquipmentSettingFromConfig(botRole, "lightLaserIsActiveChancePercent", 50);
|
||||
properties.Light = { IsActive: (this.randomUtil.getChance100(lightLaserActiveChance)), SelectedMode: 0 };
|
||||
itemProperties.Light = { IsActive: (this.randomUtil.getChance100(lightLaserActiveChance)), SelectedMode: 0 };
|
||||
}
|
||||
|
||||
if (itemTemplate._parent === BaseClasses.NIGHTVISION)
|
||||
{
|
||||
// Get chance from botconfig for bot type, use 50% if no value found
|
||||
const nvgActiveChance = this.getBotEquipmentSettingFromConfig(botRole, "nvgIsActiveChancePercent", 50);
|
||||
properties.Togglable = { On: (this.randomUtil.getChance100(nvgActiveChance)) };
|
||||
itemProperties.Togglable = { On: (this.randomUtil.getChance100(nvgActiveChance)) };
|
||||
}
|
||||
|
||||
// Togglable face shield
|
||||
@ -106,11 +106,11 @@ export class BotGeneratorHelper
|
||||
{
|
||||
// Get chance from botconfig for bot type, use 75% if no value found
|
||||
const faceShieldActiveChance = this.getBotEquipmentSettingFromConfig(botRole, "faceShieldIsActiveChancePercent", 75);
|
||||
properties.Togglable = { On: (this.randomUtil.getChance100(faceShieldActiveChance)) };
|
||||
itemProperties.Togglable = { On: (this.randomUtil.getChance100(faceShieldActiveChance)) };
|
||||
}
|
||||
|
||||
return Object.keys(properties).length
|
||||
? { upd: properties }
|
||||
return Object.keys(itemProperties).length
|
||||
? { upd: itemProperties }
|
||||
: {};
|
||||
}
|
||||
|
||||
|
@ -48,6 +48,7 @@ export class BotWeaponGeneratorHelper
|
||||
}
|
||||
else if (parentItem._id === BaseClasses.UBGL)
|
||||
{
|
||||
// underbarrel launchers can only have 1 chambered grenade
|
||||
chamberBulletCount = 1;
|
||||
}
|
||||
else
|
||||
|
@ -477,35 +477,38 @@ class ItemHelper
|
||||
}
|
||||
|
||||
/**
|
||||
* split item stack if it exceeds StackMaxSize
|
||||
* split item stack if it exceeds its StackMaxSize property
|
||||
* @param itemToSplit item being split into smaller stacks
|
||||
* @returns Array of split items
|
||||
*/
|
||||
public splitStack(item: Item): Item[]
|
||||
public splitStack(itemToSplit: Item): Item[]
|
||||
{
|
||||
if (!(("upd" in item) && ("StackObjectsCount" in item.upd)))
|
||||
if (!(itemToSplit?.upd?.StackObjectsCount != null))
|
||||
{
|
||||
return [item];
|
||||
return [itemToSplit];
|
||||
}
|
||||
|
||||
const maxStack = this.databaseServer.getTables().templates.items[item._tpl]._props.StackMaxSize;
|
||||
let count = item.upd.StackObjectsCount;
|
||||
const maxStackSize = this.databaseServer.getTables().templates.items[itemToSplit._tpl]._props.StackMaxSize;
|
||||
let remainingCount = itemToSplit.upd.StackObjectsCount;
|
||||
const stacks: Item[] = [];
|
||||
|
||||
// If the current count is already equal or less than the max
|
||||
// then just return the item as is.
|
||||
if (count <= maxStack)
|
||||
if (remainingCount <= maxStackSize)
|
||||
{
|
||||
stacks.push(this.jsonUtil.clone(item));
|
||||
stacks.push(this.jsonUtil.clone(itemToSplit));
|
||||
|
||||
return stacks;
|
||||
}
|
||||
|
||||
while (count)
|
||||
while (remainingCount)
|
||||
{
|
||||
const amount = Math.min(count, maxStack);
|
||||
const newStack = this.jsonUtil.clone(item);
|
||||
const amount = Math.min(remainingCount, maxStackSize);
|
||||
const newStack = this.jsonUtil.clone(itemToSplit);
|
||||
|
||||
newStack._id = this.hashUtil.generate();
|
||||
newStack.upd.StackObjectsCount = amount;
|
||||
count -= amount;
|
||||
remainingCount -= amount;
|
||||
stacks.push(newStack);
|
||||
}
|
||||
|
||||
@ -514,19 +517,19 @@ class ItemHelper
|
||||
|
||||
/**
|
||||
* Find Barter items in the inventory
|
||||
* @param {string} by
|
||||
* @param {string} by tpl or id
|
||||
* @param {Object} pmcData
|
||||
* @param {string} barterItemId
|
||||
* @returns Array of Item objects
|
||||
*/
|
||||
public findBarterItems(by: string, pmcData: IPmcData, barterItemId: string): Item[]
|
||||
public findBarterItems(by: "tpl" | "id", pmcData: IPmcData, barterItemId: string): Item[]
|
||||
{
|
||||
// find required items to take after buying (handles multiple items)
|
||||
const barterIDs = typeof barterItemId === "string"
|
||||
? [barterItemId]
|
||||
: barterItemId;
|
||||
let itemsArray: Item[] = [];
|
||||
|
||||
let barterItems: Item[] = [];
|
||||
for (const barterID of barterIDs)
|
||||
{
|
||||
const filterResult = pmcData.Inventory.items.filter(item =>
|
||||
@ -536,10 +539,15 @@ class ItemHelper
|
||||
: (item._id === barterID);
|
||||
});
|
||||
|
||||
itemsArray = Object.assign(itemsArray, filterResult);
|
||||
barterItems = Object.assign(barterItems, filterResult);
|
||||
}
|
||||
|
||||
return itemsArray;
|
||||
if (barterItems.length === 0)
|
||||
{
|
||||
this.logger.warning(`No items found for barter Id: ${barterIDs}`);
|
||||
}
|
||||
|
||||
return barterItems;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -800,6 +808,7 @@ class ItemHelper
|
||||
|
||||
// Add new stack-size-correct items to ammo box
|
||||
let currentStoredCartridgeCount = 0;
|
||||
// Location in ammoBox cartridges will be placed
|
||||
let location = 0;
|
||||
while (currentStoredCartridgeCount < ammoBoxMaxCartridgeCount)
|
||||
{
|
||||
@ -808,7 +817,7 @@ class ItemHelper
|
||||
? ammoBoxMaxCartridgeCount
|
||||
: cartridgeMaxStackSize;
|
||||
|
||||
// Add cartridge item object into items array
|
||||
// Add cartridge item into items array
|
||||
ammoBox.push(this.createCartridges(ammoBox[0]._id, cartridgeTpl, cartridgeCountToAdd, location));
|
||||
|
||||
currentStoredCartridgeCount += cartridgeCountToAdd;
|
||||
@ -832,7 +841,7 @@ class ItemHelper
|
||||
minSizePercent = 0.25
|
||||
): void
|
||||
{
|
||||
// no caliber defined, choose one
|
||||
// no caliber defined, choose one at random
|
||||
if (!caliber)
|
||||
{
|
||||
caliber = this.getRandomValidCaliber(magTemplate);
|
||||
|
@ -60,20 +60,16 @@ export class QuestHelper
|
||||
/**
|
||||
* Get status of a quest in player profile by its id
|
||||
* @param pmcData Profile to search
|
||||
* @param questID Quest id to look up
|
||||
* @param questId Quest id to look up
|
||||
* @returns QuestStatus enum
|
||||
*/
|
||||
public getQuestStatus(pmcData: IPmcData, questID: string): QuestStatus
|
||||
public getQuestStatus(pmcData: IPmcData, questId: string): QuestStatus
|
||||
{
|
||||
for (const quest of pmcData.Quests)
|
||||
{
|
||||
if (quest.qid === questID)
|
||||
{
|
||||
return quest.status;
|
||||
}
|
||||
}
|
||||
const quest = pmcData.Quests.find(q => q.qid === questId);
|
||||
|
||||
return QuestStatus.Locked;
|
||||
return quest
|
||||
? quest.status
|
||||
: QuestStatus.Locked;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -191,6 +187,11 @@ export class QuestHelper
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* take reward item from quest and set FiR status + fix stack sizes + fix mod Ids
|
||||
* @param reward Reward item to fix
|
||||
* @returns Fixed rewards
|
||||
*/
|
||||
protected processReward(reward: Reward): Reward[]
|
||||
{
|
||||
let rewardItems: Reward[] = [];
|
||||
@ -252,22 +253,16 @@ export class QuestHelper
|
||||
/**
|
||||
* Gets a flat list of reward items for the given quest at a specific state (e.g. Fail/Success)
|
||||
* @param quest quest to get rewards for
|
||||
* @param state Quest status that holds the items (Started, Success, Fail)
|
||||
* @param status Quest status that holds the items (Started, Success, Fail)
|
||||
* @returns array of items with the correct maxStack
|
||||
*/
|
||||
public getQuestRewardItems(quest: IQuest, state: QuestStatus): Reward[]
|
||||
public getQuestRewardItems(quest: IQuest, status: QuestStatus): Reward[]
|
||||
{
|
||||
let questRewards = [];
|
||||
|
||||
// Iterate over all quest rewards
|
||||
for (const reward of quest.rewards[QuestStatus[state]]) // get string version of QuestStatus
|
||||
{
|
||||
// Gather up item rewards
|
||||
if ("Item" === reward.type)
|
||||
{
|
||||
questRewards = questRewards.concat(this.processReward(reward));
|
||||
}
|
||||
}
|
||||
// Iterate over all rewards with the desired status, flatten out items that have a type of Item
|
||||
const questRewards = quest.rewards[QuestStatus[status]]
|
||||
.flatMap((reward: Reward) => reward.type === "Item"
|
||||
? this.processReward(reward)
|
||||
: []);
|
||||
|
||||
return questRewards;
|
||||
}
|
||||
@ -319,47 +314,52 @@ export class QuestHelper
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: what is going on here
|
||||
* @param acceptedQuestId Quest to add to profile
|
||||
* Get quests that can be shown to player after starting a quest
|
||||
* @param startedQuestId Quest started by player
|
||||
* @param sessionID Session id
|
||||
* @returns Array of quests in profile + quest passed in as param
|
||||
* @returns Quests accessible to player incuding newly unlocked quests now quest (startedQuestId) was started
|
||||
*/
|
||||
public acceptedUnlocked(acceptedQuestId: string, sessionID: string): IQuest[]
|
||||
public acceptedUnlocked(startedQuestId: string, sessionID: string): IQuest[]
|
||||
{
|
||||
const profile: IPmcData = this.profileHelper.getPmcProfile(sessionID);
|
||||
// Get quest acceptance data from profile
|
||||
const profileQuest = profile.Quests.find(x => x.qid === startedQuestId);
|
||||
|
||||
const quests = this.getQuestsFromDb().filter((q) =>
|
||||
// Get quests that
|
||||
const eligibleQuests = this.getQuestsFromDb().filter((quest) =>
|
||||
{
|
||||
const acceptedQuestCondition = q.conditions.AvailableForStart.find(
|
||||
c =>
|
||||
// Quest is accessible to player when the accepted quest passed into param is started
|
||||
// e.g. Quest A passed in, quest B is looped over and has requirement of A to be started, include it
|
||||
const acceptedQuestCondition = quest.conditions.AvailableForStart.find(x =>
|
||||
{
|
||||
return c._parent === "Quest"
|
||||
&& c._props.target === acceptedQuestId
|
||||
&& c._props.status[0] === QuestStatus.Started;
|
||||
return x._parent === "Quest"
|
||||
&& x._props.target === startedQuestId
|
||||
&& x._props.status[0] === QuestStatus.Started;
|
||||
});
|
||||
|
||||
// Not found, skip quest
|
||||
if (!acceptedQuestCondition)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const profileQuest = profile.Quests.find(x => x.qid === acceptedQuestId);
|
||||
|
||||
return profileQuest && (profileQuest.status === QuestStatus.Started || profileQuest.status === QuestStatus.AvailableForFinish);
|
||||
// Include if quest found in profile and is started or ready to hand in
|
||||
return profileQuest && ([QuestStatus.Started, QuestStatus.AvailableForFinish].includes(profileQuest.status));
|
||||
});
|
||||
|
||||
return this.getQuestsWithOnlyLevelRequirementStartCondition(quests);
|
||||
return this.getQuestsWithOnlyLevelRequirementStartCondition(eligibleQuests);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: what is going on here
|
||||
* @param failedQuestId
|
||||
* @param sessionID Session id
|
||||
* Get quests that can be shown to player after failing a quest
|
||||
* @param failedQuestId Id of the quest failed by player
|
||||
* @param sessionId Session id
|
||||
* @returns
|
||||
*/
|
||||
public failedUnlocked(failedQuestId: string, sessionID: string): IQuest[]
|
||||
public failedUnlocked(failedQuestId: string, sessionId: string): IQuest[]
|
||||
{
|
||||
const profile = this.profileHelper.getPmcProfile(sessionID);
|
||||
const profile = this.profileHelper.getPmcProfile(sessionId);
|
||||
const profileQuest = profile.Quests.find(x => x.qid === failedQuestId);
|
||||
|
||||
const quests = this.getQuestsFromDb().filter((q) =>
|
||||
{
|
||||
@ -376,8 +376,6 @@ export class QuestHelper
|
||||
return false;
|
||||
}
|
||||
|
||||
const profileQuest = profile.Quests.find(x => x.qid === failedQuestId);
|
||||
|
||||
return profileQuest && (profileQuest.status === QuestStatus.Fail);
|
||||
});
|
||||
|
||||
@ -430,14 +428,7 @@ export class QuestHelper
|
||||
const item = pmcData.Inventory.items[inventoryItemIndex];
|
||||
item.upd.StackObjectsCount = newStackSize;
|
||||
|
||||
output.profileChanges[sessionID].items.change.push({
|
||||
"_id": item._id,
|
||||
"_tpl": item._tpl,
|
||||
"parentId": item.parentId,
|
||||
"slotId": item.slotId,
|
||||
"location": item.location,
|
||||
"upd": { "StackObjectsCount": item.upd.StackObjectsCount }
|
||||
});
|
||||
this.addItemStackSizeChangeIntoEventResponse(output, sessionID, item);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -448,6 +439,24 @@ export class QuestHelper
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add item stack change object into output route event response
|
||||
* @param output Response to add item change event into
|
||||
* @param sessionId Session id
|
||||
* @param item Item that was adjusted
|
||||
*/
|
||||
protected addItemStackSizeChangeIntoEventResponse(output: IItemEventRouterResponse, sessionId: string, item: Item): void
|
||||
{
|
||||
output.profileChanges[sessionId].items.change.push({
|
||||
"_id": item._id,
|
||||
"_tpl": item._tpl,
|
||||
"parentId": item.parentId,
|
||||
"slotId": item.slotId,
|
||||
"location": item.location,
|
||||
"upd": { "StackObjectsCount": item.upd.StackObjectsCount }
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get quests, strip all requirement conditions except level
|
||||
* @param quests quests to process
|
||||
|
Loading…
Reference in New Issue
Block a user