feat: archon hunt rewards #1713
@ -53,6 +53,9 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res)
 | 
				
			|||||||
    logger.debug("mission report:", missionReport);
 | 
					    logger.debug("mission report:", missionReport);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const inventory = await getInventory(accountId);
 | 
					    const inventory = await getInventory(accountId);
 | 
				
			||||||
 | 
					    const firstCompletion = missionReport.SortieId
 | 
				
			||||||
 | 
					        ? inventory.CompletedSorties.indexOf(missionReport.SortieId) == -1
 | 
				
			||||||
 | 
					        : false;
 | 
				
			||||||
    const inventoryUpdates = await addMissionInventoryUpdates(inventory, missionReport);
 | 
					    const inventoryUpdates = await addMissionInventoryUpdates(inventory, missionReport);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (
 | 
					    if (
 | 
				
			||||||
@ -69,7 +72,7 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const { MissionRewards, inventoryChanges, credits, AffiliationMods, SyndicateXPItemReward } =
 | 
					    const { MissionRewards, inventoryChanges, credits, AffiliationMods, SyndicateXPItemReward } =
 | 
				
			||||||
        await addMissionRewards(inventory, missionReport);
 | 
					        await addMissionRewards(inventory, missionReport, firstCompletion);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await inventory.save();
 | 
					    await inventory.save();
 | 
				
			||||||
    const inventoryResponse = await getInventoryResponse(inventory, true);
 | 
					    const inventoryResponse = await getInventoryResponse(inventory, true);
 | 
				
			||||||
 | 
				
			|||||||
@ -91,7 +91,8 @@ import {
 | 
				
			|||||||
    ICrewMemberSkill,
 | 
					    ICrewMemberSkill,
 | 
				
			||||||
    ICrewMemberSkillEfficiency,
 | 
					    ICrewMemberSkillEfficiency,
 | 
				
			||||||
    ICrewMemberDatabase,
 | 
					    ICrewMemberDatabase,
 | 
				
			||||||
    ICrewMemberClient
 | 
					    ICrewMemberClient,
 | 
				
			||||||
 | 
					    ISortieRewardAttenuation
 | 
				
			||||||
} from "../../types/inventoryTypes/inventoryTypes";
 | 
					} from "../../types/inventoryTypes/inventoryTypes";
 | 
				
			||||||
import { IOid } from "../../types/commonTypes";
 | 
					import { IOid } from "../../types/commonTypes";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
@ -1276,6 +1277,14 @@ lastSortieRewardSchema.set("toJSON", {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const sortieRewardAttenutationSchema = new Schema<ISortieRewardAttenuation>(
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Tag: String,
 | 
				
			||||||
 | 
					        Atten: Number
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    { _id: false }
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const lockedWeaponGroupSchema = new Schema<ILockedWeaponGroupDatabase>(
 | 
					const lockedWeaponGroupSchema = new Schema<ILockedWeaponGroupDatabase>(
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        s: Schema.Types.ObjectId,
 | 
					        s: Schema.Types.ObjectId,
 | 
				
			||||||
@ -1495,6 +1504,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
 | 
				
			|||||||
        CompletedSorties: [String],
 | 
					        CompletedSorties: [String],
 | 
				
			||||||
        LastSortieReward: { type: [lastSortieRewardSchema], default: undefined },
 | 
					        LastSortieReward: { type: [lastSortieRewardSchema], default: undefined },
 | 
				
			||||||
        LastLiteSortieReward: { type: [lastSortieRewardSchema], default: undefined },
 | 
					        LastLiteSortieReward: { type: [lastSortieRewardSchema], default: undefined },
 | 
				
			||||||
 | 
					        SortieRewardAttenuation: { type: [sortieRewardAttenutationSchema], default: undefined },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Resource Extractor Drones
 | 
					        // Resource Extractor Drones
 | 
				
			||||||
        Drones: [droneSchema],
 | 
					        Drones: [droneSchema],
 | 
				
			||||||
 | 
				
			|||||||
@ -412,7 +412,9 @@ export const addMissionInventoryUpdates = async (
 | 
				
			|||||||
                break;
 | 
					                break;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            case "SortieId": {
 | 
					            case "SortieId": {
 | 
				
			||||||
 | 
					                if (inventory.CompletedSorties.indexOf(value) == -1) {
 | 
				
			||||||
                    inventory.CompletedSorties.push(value);
 | 
					                    inventory.CompletedSorties.push(value);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            case "SeasonChallengeCompletions": {
 | 
					            case "SeasonChallengeCompletions": {
 | 
				
			||||||
@ -569,7 +571,8 @@ export const addMissionRewards = async (
 | 
				
			|||||||
        RegularCredits: creditDrops,
 | 
					        RegularCredits: creditDrops,
 | 
				
			||||||
        VoidTearParticipantsCurrWave: voidTearWave,
 | 
					        VoidTearParticipantsCurrWave: voidTearWave,
 | 
				
			||||||
        StrippedItems: strippedItems
 | 
					        StrippedItems: strippedItems
 | 
				
			||||||
    }: IMissionInventoryUpdateRequest
 | 
					    }: IMissionInventoryUpdateRequest,
 | 
				
			||||||
 | 
					    firstCompletion: boolean
 | 
				
			||||||
): Promise<AddMissionRewardsReturnType> => {
 | 
					): Promise<AddMissionRewardsReturnType> => {
 | 
				
			||||||
    if (!rewardInfo) {
 | 
					    if (!rewardInfo) {
 | 
				
			||||||
        //TODO: if there is a case where you can have credits collected during a mission but no rewardInfo, add credits needs to be handled earlier
 | 
					        //TODO: if there is a case where you can have credits collected during a mission but no rewardInfo, add credits needs to be handled earlier
 | 
				
			||||||
@ -583,22 +586,12 @@ export const addMissionRewards = async (
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //TODO: check double reward merging
 | 
					    //TODO: check double reward merging
 | 
				
			||||||
    const MissionRewards: IMissionReward[] = getRandomMissionDrops(rewardInfo, wagerTier);
 | 
					    const MissionRewards: IMissionReward[] = getRandomMissionDrops(inventory, rewardInfo, wagerTier, firstCompletion);
 | 
				
			||||||
    logger.debug("random mission drops:", MissionRewards);
 | 
					    logger.debug("random mission drops:", MissionRewards);
 | 
				
			||||||
    const inventoryChanges: IInventoryChanges = {};
 | 
					    const inventoryChanges: IInventoryChanges = {};
 | 
				
			||||||
    const AffiliationMods: IAffiliationMods[] = [];
 | 
					    const AffiliationMods: IAffiliationMods[] = [];
 | 
				
			||||||
    let SyndicateXPItemReward;
 | 
					    let SyndicateXPItemReward;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (rewardInfo.sortieTag == "Final") {
 | 
					 | 
				
			||||||
        inventory.LastSortieReward = [
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                SortieId: new Types.ObjectId(rewardInfo.sortieId!.split("_")[1]),
 | 
					 | 
				
			||||||
                StoreItem: MissionRewards[0].StoreItem,
 | 
					 | 
				
			||||||
                Manifest: "/Lotus/Types/Game/MissionDecks/SortieRewards"
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        ];
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let missionCompletionCredits = 0;
 | 
					    let missionCompletionCredits = 0;
 | 
				
			||||||
    //inventory change is what the client has not rewarded itself, also the client needs to know the credit changes for display
 | 
					    //inventory change is what the client has not rewarded itself, also the client needs to know the credit changes for display
 | 
				
			||||||
    if (levelKeyName) {
 | 
					    if (levelKeyName) {
 | 
				
			||||||
@ -962,11 +955,78 @@ function getLevelCreditRewards(node: IRegion): number {
 | 
				
			|||||||
    //TODO: get dark sektor fixed credit rewards and railjack bonus
 | 
					    //TODO: get dark sektor fixed credit rewards and railjack bonus
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function getRandomMissionDrops(RewardInfo: IRewardInfo, tierOverride: number | undefined): IMissionReward[] {
 | 
					function getRandomMissionDrops(
 | 
				
			||||||
 | 
					    inventory: TInventoryDatabaseDocument,
 | 
				
			||||||
 | 
					    RewardInfo: IRewardInfo,
 | 
				
			||||||
 | 
					    tierOverride: number | undefined,
 | 
				
			||||||
 | 
					    firstCompletion: boolean
 | 
				
			||||||
 | 
					): IMissionReward[] {
 | 
				
			||||||
    const drops: IMissionReward[] = [];
 | 
					    const drops: IMissionReward[] = [];
 | 
				
			||||||
    if (RewardInfo.sortieTag == "Final") {
 | 
					    if (RewardInfo.sortieTag == "Final" && firstCompletion) {
 | 
				
			||||||
 | 
					        const arr = RewardInfo.sortieId!.split("_");
 | 
				
			||||||
 | 
					        let sortieId = arr[1];
 | 
				
			||||||
 | 
					        if (sortieId == "Lite") {
 | 
				
			||||||
 | 
					            sortieId = arr[2];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // TODO: Some way to get from sortieId to reward to make this faster + more reliable at week rollover.
 | 
				
			||||||
 | 
					            const boss = getWorldState().LiteSorties[0].Boss as
 | 
				
			||||||
 | 
					                | "SORTIE_BOSS_AMAR"
 | 
				
			||||||
 | 
					                | "SORTIE_BOSS_NIRA"
 | 
				
			||||||
 | 
					                | "SORTIE_BOSS_BOREAL";
 | 
				
			||||||
 | 
					            let crystalType = {
 | 
				
			||||||
 | 
					                SORTIE_BOSS_AMAR: "/Lotus/StoreItems/Types/Gameplay/NarmerSorties/ArchonCrystalAmar",
 | 
				
			||||||
 | 
					                SORTIE_BOSS_NIRA: "/Lotus/StoreItems/Types/Gameplay/NarmerSorties/ArchonCrystalNira",
 | 
				
			||||||
 | 
					                SORTIE_BOSS_BOREAL: "/Lotus/StoreItems/Types/Gameplay/NarmerSorties/ArchonCrystalBoreal"
 | 
				
			||||||
 | 
					            }[boss];
 | 
				
			||||||
 | 
					            const attenTag = {
 | 
				
			||||||
 | 
					                SORTIE_BOSS_AMAR: "NarmerSortieAmarCrystalRewards",
 | 
				
			||||||
 | 
					                SORTIE_BOSS_NIRA: "NarmerSortieNiraCrystalRewards",
 | 
				
			||||||
 | 
					                SORTIE_BOSS_BOREAL: "NarmerSortieBorealCrystalRewards"
 | 
				
			||||||
 | 
					            }[boss];
 | 
				
			||||||
 | 
					            const attenIndex = inventory.SortieRewardAttenuation?.findIndex(x => x.Tag == attenTag) ?? -1;
 | 
				
			||||||
 | 
					            const mythicProbability =
 | 
				
			||||||
 | 
					                0.2 + (inventory.SortieRewardAttenuation?.find(x => x.Tag == attenTag)?.Atten ?? 0);
 | 
				
			||||||
 | 
					            if (Math.random() < mythicProbability) {
 | 
				
			||||||
 | 
					                crystalType += "Mythic";
 | 
				
			||||||
 | 
					                if (attenIndex != -1) {
 | 
				
			||||||
 | 
					                    inventory.SortieRewardAttenuation!.splice(attenIndex, 1);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                if (attenIndex == -1) {
 | 
				
			||||||
 | 
					                    inventory.SortieRewardAttenuation ??= [];
 | 
				
			||||||
 | 
					                    inventory.SortieRewardAttenuation.push({
 | 
				
			||||||
 | 
					                        Tag: attenTag,
 | 
				
			||||||
 | 
					                        Atten: 0.2
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    inventory.SortieRewardAttenuation![attenIndex].Atten += 0.2;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            drops.push({ StoreItem: crystalType, ItemCount: 1 });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const drop = getRandomRewardByChance(
 | 
				
			||||||
 | 
					                ExportRewards["/Lotus/Types/Game/MissionDecks/ArchonSortieRewards"][0]
 | 
				
			||||||
 | 
					            )!;
 | 
				
			||||||
 | 
					            drops.push({ StoreItem: drop.type, ItemCount: drop.itemCount });
 | 
				
			||||||
 | 
					            inventory.LastLiteSortieReward = [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    SortieId: new Types.ObjectId(sortieId),
 | 
				
			||||||
 | 
					                    StoreItem: drop.type,
 | 
				
			||||||
 | 
					                    Manifest: "/Lotus/Types/Game/MissionDecks/ArchonSortieRewards"
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ];
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
            const drop = getRandomRewardByChance(ExportRewards["/Lotus/Types/Game/MissionDecks/SortieRewards"][0])!;
 | 
					            const drop = getRandomRewardByChance(ExportRewards["/Lotus/Types/Game/MissionDecks/SortieRewards"][0])!;
 | 
				
			||||||
            drops.push({ StoreItem: drop.type, ItemCount: drop.itemCount });
 | 
					            drops.push({ StoreItem: drop.type, ItemCount: drop.itemCount });
 | 
				
			||||||
 | 
					            inventory.LastSortieReward = [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    SortieId: new Types.ObjectId(sortieId),
 | 
				
			||||||
 | 
					                    StoreItem: drop.type,
 | 
				
			||||||
 | 
					                    Manifest: "/Lotus/Types/Game/MissionDecks/SortieRewards"
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            ];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (RewardInfo.periodicMissionTag?.startsWith("HardDaily")) {
 | 
					    if (RewardInfo.periodicMissionTag?.startsWith("HardDaily")) {
 | 
				
			||||||
        drops.push({
 | 
					        drops.push({
 | 
				
			||||||
 | 
				
			|||||||
@ -285,6 +285,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
 | 
				
			|||||||
    CompletedSorties: string[];
 | 
					    CompletedSorties: string[];
 | 
				
			||||||
    LastSortieReward?: ILastSortieRewardClient[];
 | 
					    LastSortieReward?: ILastSortieRewardClient[];
 | 
				
			||||||
    LastLiteSortieReward?: ILastSortieRewardClient[];
 | 
					    LastLiteSortieReward?: ILastSortieRewardClient[];
 | 
				
			||||||
 | 
					    SortieRewardAttenuation?: ISortieRewardAttenuation[];
 | 
				
			||||||
    Drones: IDroneClient[];
 | 
					    Drones: IDroneClient[];
 | 
				
			||||||
    StepSequencers: IStepSequencer[];
 | 
					    StepSequencers: IStepSequencer[];
 | 
				
			||||||
    ActiveAvatarImageType: string;
 | 
					    ActiveAvatarImageType: string;
 | 
				
			||||||
@ -746,6 +747,11 @@ export interface ILastSortieRewardDatabase extends Omit<ILastSortieRewardClient,
 | 
				
			|||||||
    SortieId: Types.ObjectId;
 | 
					    SortieId: Types.ObjectId;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface ISortieRewardAttenuation {
 | 
				
			||||||
 | 
					    Tag: string;
 | 
				
			||||||
 | 
					    Atten: number;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface ILibraryDailyTaskInfo {
 | 
					export interface ILibraryDailyTaskInfo {
 | 
				
			||||||
    EnemyTypes: string[];
 | 
					    EnemyTypes: string[];
 | 
				
			||||||
    EnemyLocTag: string;
 | 
					    EnemyLocTag: string;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user