ed8dbbd195
Boogidy, boogidy, boogidy. Let's go racing! 🏎️ Removes the over-complicated and super-slow setup we had with ESLint & Prettier in favour of Biome. The largest change with the formatting is moving from Allman braces to 1TBS braces. Other than that, it's *pretty much* the same. Ah, and that Biome runs formatting and linting on the entire project about x10 faster than the old system ran formatting on one file. Seriously, the guy who came up with that last solution should be fired. :runs: I've kept all of the formatting and linting commands the same as before, with the main mamma-jamma being: `npm run format`, which applies formatting and linting changes to the entire project. Formatting-on-save works (quickly!) by (1) ensuring that you're working within the VSC workspace (as you should be), and (2) have the recommended Biome VSC extension installed. The link to the Biome extension is in the README. This limits our options on code formatting going forward; Biome, like prettier, is very opinionated with very few formatting options available. But I see this as a good thing. I'd rather spend my time arguing about which gun in Tarkov is the best, rather than coding brace styles... ...It's the TOZ, and it always will be. Don't DM me. Co-authored-by: chomp <chomp@noreply.dev.sp-tarkov.com> Reviewed-on: https://dev.sp-tarkov.com/SPT/Server/pulls/383 Co-authored-by: Refringe <me@refringe.com> Co-committed-by: Refringe <me@refringe.com>
238 lines
8.8 KiB
TypeScript
238 lines
8.8 KiB
TypeScript
import { inject, injectable } from "tsyringe";
|
|
import { HealthHelper } from "@spt/helpers/HealthHelper";
|
|
import { InventoryHelper } from "@spt/helpers/InventoryHelper";
|
|
import { ItemHelper } from "@spt/helpers/ItemHelper";
|
|
import { IPmcData } from "@spt/models/eft/common/IPmcData";
|
|
import { BodyPart, IHealthTreatmentRequestData } from "@spt/models/eft/health/IHealthTreatmentRequestData";
|
|
import { IOffraidEatRequestData } from "@spt/models/eft/health/IOffraidEatRequestData";
|
|
import { IOffraidHealRequestData } from "@spt/models/eft/health/IOffraidHealRequestData";
|
|
import { ISyncHealthRequestData } from "@spt/models/eft/health/ISyncHealthRequestData";
|
|
import { IWorkoutData } from "@spt/models/eft/health/IWorkoutData";
|
|
import { IItemEventRouterResponse } from "@spt/models/eft/itemEvent/IItemEventRouterResponse";
|
|
import { IProcessBuyTradeRequestData } from "@spt/models/eft/trade/IProcessBuyTradeRequestData";
|
|
import { Traders } from "@spt/models/enums/Traders";
|
|
import { ILogger } from "@spt/models/spt/utils/ILogger";
|
|
import { EventOutputHolder } from "@spt/routers/EventOutputHolder";
|
|
import { LocalisationService } from "@spt/services/LocalisationService";
|
|
import { PaymentService } from "@spt/services/PaymentService";
|
|
import { ICloner } from "@spt/utils/cloners/ICloner";
|
|
import { HttpResponseUtil } from "@spt/utils/HttpResponseUtil";
|
|
|
|
@injectable()
|
|
export class HealthController
|
|
{
|
|
constructor(
|
|
@inject("PrimaryLogger") protected logger: ILogger,
|
|
@inject("EventOutputHolder") protected eventOutputHolder: EventOutputHolder,
|
|
@inject("ItemHelper") protected itemHelper: ItemHelper,
|
|
@inject("PaymentService") protected paymentService: PaymentService,
|
|
@inject("InventoryHelper") protected inventoryHelper: InventoryHelper,
|
|
@inject("LocalisationService") protected localisationService: LocalisationService,
|
|
@inject("HttpResponseUtil") protected httpResponse: HttpResponseUtil,
|
|
@inject("HealthHelper") protected healthHelper: HealthHelper,
|
|
@inject("PrimaryCloner") protected cloner: ICloner,
|
|
)
|
|
{}
|
|
|
|
/**
|
|
* stores in-raid player health
|
|
* @param pmcData Player profile
|
|
* @param info Request data
|
|
* @param sessionID Player id
|
|
* @param addEffects Should effects found be added or removed from profile
|
|
* @param deleteExistingEffects Should all prior effects be removed before apply new ones
|
|
*/
|
|
public saveVitality(
|
|
pmcData: IPmcData,
|
|
info: ISyncHealthRequestData,
|
|
sessionID: string,
|
|
addEffects = true,
|
|
deleteExistingEffects = true,
|
|
): void
|
|
{
|
|
this.healthHelper.saveVitality(pmcData, info, sessionID, addEffects, deleteExistingEffects);
|
|
}
|
|
|
|
/**
|
|
* When healing in menu
|
|
* @param pmcData Player profile
|
|
* @param request Healing request
|
|
* @param sessionID Player id
|
|
* @returns IItemEventRouterResponse
|
|
*/
|
|
public offraidHeal(
|
|
pmcData: IPmcData,
|
|
request: IOffraidHealRequestData,
|
|
sessionID: string,
|
|
): IItemEventRouterResponse
|
|
{
|
|
const output = this.eventOutputHolder.getOutput(sessionID);
|
|
|
|
// Update medkit used (hpresource)
|
|
const healingItemToUse = pmcData.Inventory.items.find((item) => item._id === request.item);
|
|
if (!healingItemToUse)
|
|
{
|
|
const errorMessage = this.localisationService.getText(
|
|
"health-healing_item_not_found",
|
|
healingItemToUse._id,
|
|
);
|
|
this.logger.error(errorMessage);
|
|
|
|
return this.httpResponse.appendErrorToOutput(output, errorMessage);
|
|
}
|
|
|
|
// Ensure item has a upd object
|
|
this.itemHelper.addUpdObjectToItem(healingItemToUse);
|
|
|
|
if (healingItemToUse.upd.MedKit)
|
|
{
|
|
healingItemToUse.upd.MedKit.HpResource -= request.count;
|
|
}
|
|
else
|
|
{
|
|
// Get max healing from db
|
|
const maxhp = this.itemHelper.getItem(healingItemToUse._tpl)[1]._props.MaxHpResource;
|
|
healingItemToUse.upd.MedKit = { HpResource: maxhp - request.count }; // Subtract amout used from max
|
|
}
|
|
|
|
// Resource in medkit is spent, delete it
|
|
if (healingItemToUse.upd.MedKit.HpResource <= 0)
|
|
{
|
|
this.inventoryHelper.removeItem(pmcData, request.item, sessionID, output);
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
/**
|
|
* Handle Eat event
|
|
* Consume food/water outside of a raid
|
|
* @param pmcData Player profile
|
|
* @param request Eat request
|
|
* @param sessionID Session id
|
|
* @returns IItemEventRouterResponse
|
|
*/
|
|
public offraidEat(pmcData: IPmcData, request: IOffraidEatRequestData, sessionID: string): IItemEventRouterResponse
|
|
{
|
|
const output = this.eventOutputHolder.getOutput(sessionID);
|
|
let resourceLeft = 0;
|
|
|
|
const itemToConsume = pmcData.Inventory.items.find((item) => item._id === request.item);
|
|
if (!itemToConsume)
|
|
{
|
|
// Item not found, very bad
|
|
return this.httpResponse.appendErrorToOutput(
|
|
output,
|
|
this.localisationService.getText("health-unable_to_find_item_to_consume", request.item),
|
|
);
|
|
}
|
|
|
|
const consumedItemMaxResource = this.itemHelper.getItem(itemToConsume._tpl)[1]._props.MaxResource;
|
|
if (consumedItemMaxResource > 1)
|
|
{
|
|
// Ensure item has a upd object
|
|
this.itemHelper.addUpdObjectToItem(itemToConsume);
|
|
|
|
if (itemToConsume.upd.FoodDrink === undefined)
|
|
{
|
|
itemToConsume.upd.FoodDrink = { HpPercent: consumedItemMaxResource - request.count };
|
|
}
|
|
else
|
|
{
|
|
itemToConsume.upd.FoodDrink.HpPercent -= request.count;
|
|
}
|
|
|
|
resourceLeft = itemToConsume.upd.FoodDrink.HpPercent;
|
|
}
|
|
|
|
// Remove item from inventory if resource has dropped below threshold
|
|
if (consumedItemMaxResource === 1 || resourceLeft < 1)
|
|
{
|
|
this.inventoryHelper.removeItem(pmcData, request.item, sessionID, output);
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
/**
|
|
* Handle RestoreHealth event
|
|
* Occurs on post-raid healing page
|
|
* @param pmcData player profile
|
|
* @param healthTreatmentRequest Request data from client
|
|
* @param sessionID Session id
|
|
* @returns IItemEventRouterResponse
|
|
*/
|
|
public healthTreatment(
|
|
pmcData: IPmcData,
|
|
healthTreatmentRequest: IHealthTreatmentRequestData,
|
|
sessionID: string,
|
|
): IItemEventRouterResponse
|
|
{
|
|
const output = this.eventOutputHolder.getOutput(sessionID);
|
|
const payMoneyRequest: IProcessBuyTradeRequestData = {
|
|
Action: healthTreatmentRequest.Action,
|
|
tid: Traders.THERAPIST,
|
|
scheme_items: healthTreatmentRequest.items,
|
|
type: "",
|
|
item_id: "",
|
|
count: 0,
|
|
scheme_id: 0,
|
|
};
|
|
|
|
this.paymentService.payMoney(pmcData, payMoneyRequest, sessionID, output);
|
|
if (output.warnings.length > 0)
|
|
{
|
|
return output;
|
|
}
|
|
|
|
for (const bodyPartKey in healthTreatmentRequest.difference.BodyParts)
|
|
{
|
|
// Get body part from request + from pmc profile
|
|
const partRequest: BodyPart = healthTreatmentRequest.difference.BodyParts[bodyPartKey];
|
|
const profilePart = pmcData.Health.BodyParts[bodyPartKey];
|
|
|
|
// Bodypart healing is chosen when part request hp is above 0
|
|
if (partRequest.Health > 0)
|
|
{
|
|
// Heal bodypart
|
|
profilePart.Health.Current = profilePart.Health.Maximum;
|
|
}
|
|
|
|
// Check for effects to remove
|
|
if (partRequest.Effects?.length > 0)
|
|
{
|
|
// Found some, loop over them and remove from pmc profile
|
|
for (const effect of partRequest.Effects)
|
|
{
|
|
delete pmcData.Health.BodyParts[bodyPartKey].Effects[effect];
|
|
}
|
|
|
|
// Remove empty effect object
|
|
if (Object.keys(pmcData.Health.BodyParts[bodyPartKey].Effects).length === 0)
|
|
{
|
|
delete pmcData.Health.BodyParts[bodyPartKey].Effects;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Inform client of new post-raid, post-therapist heal values
|
|
output.profileChanges[sessionID].health = this.cloner.clone(pmcData.Health);
|
|
|
|
return output;
|
|
}
|
|
|
|
/**
|
|
* applies skills from hideout workout.
|
|
* @param pmcData Player profile
|
|
* @param info Request data
|
|
* @param sessionID
|
|
*/
|
|
public applyWorkoutChanges(pmcData: IPmcData, info: IWorkoutData, sessionId: string): void
|
|
{
|
|
// https://dev.sp-tarkov.com/SPT/Server/issues/2674
|
|
// TODO:
|
|
// Health effects (fractures etc) are handled in /player/health/sync.
|
|
pmcData.Skills.Common = info.skills.Common;
|
|
}
|
|
}
|