道具一键合成思路

道具一键合成思路

需求:

  • 对于穿戴中的装备,按照品质从低到高,依次提升品质。把较低品质的装备都提升到同一品质,然后再一起提升
  • 对于背包内的道具,从最低阶开始合成,每次都把所有品质网上提一级,直到合成到顶级或者材料不够为止

思路:

  1. 先把合成涉及的材料的道具id找到,记录背包内道具数量。以key, value形式记录道具id,数量

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    
    /** 记录背包内合成所需道具的数量 */
    private getBagSource(): Map<ItemId, number> {
        let bagList = new Map<ItemId, number>();
        const bagModule = this.agent.getModule(ModuleNames.ModuleBag);
        const configM = ConfigMgr.instance.getConfig(ConfigFiles.configPetEquip);
        for (const cfg of configM.cfgs.values()) {
            if (cfg.totalEquipCost.length > 0) {
                for (const [itemId, v] of cfg.totalEquipCost) {
                    const count = bagModule.getItemCountByItemId(BagId.PetEquip, itemId);
                    if (count > 0) {
                        bagList.set(itemId, count);
                    }
                }
            }
        }
        return bagList;
    }
    
  2. 一键合成顺序。按策划规则

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    
    private getInitEquipList(): Array<PetEquip> {
        let arr: Array<PetEquip> = [];
        let datas = this.toDb();
        for (const data of datas[0]) {
            let copyEquip = new PetEquip(0);
            copyEquip.petEquipFromDb(data);
            arr.push(copyEquip);
        }
        arr.sort((a, b): number => {
            if (a.color == b.color) {
                return a.sType - b.sType;
            }
            return a.color - b.color;
        });
        return arr;
    }
    
  3. 合成,检查消耗。

    实际拥有的道具数量 = 背包内数量bagList + 新生成的中间状态道具数量newList - 消耗的道具usedList。这里采取的是bfs,根据实际道具数量生成目标道具target所需要的消耗材料。比如合成一个道具a需要3个道具b,合成一个道具b需要3个道具c。假设背包里有1个道具b,10个道具c,那么根据已有道具生成道具a的消耗材料 = 1个道具b + 6个道具c

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    
    //背包内资源数量
    let bagList = this.getBagSource();
    //消耗数量
    let usedList = new Map<ItemId, number>();
    //新生成数量
    let newList = new Map<ItemId, number>();
    
    /**
     * 根据背包内已有材料,生成合成目标道具id所需消耗
     * @param targetItemId 要合成的目标道具id
     * @param bagList 背包里已有的道具数量
     * @param usedList 已使用的道具数量
     * @param newList 新增的道具数量
     * @param speed 合成目标道具数量
     * @param includeMainId 是否包含主武器id,穿戴中的装备作为材料
     */
    private findTargetCost(
        targetItemId: ItemId,
        bagList: Map<ItemId, number>,
        usedList: Map<ItemId, number>,
        newList: Map<ItemId, number>,
        speed: number,
        includeMainId: boolean): void {
    
        const configM = ConfigMgr.instance.getConfig(ConfigFiles.configPetEquip);
        const cfg = configM.cfgs.get(targetItemId);
    
        if (cfg) {
            let _cost = cfg.subCost;
            if (!includeMainId) {
                _cost = cfg.totalEquipCost;
            }
            //到底了,最低品质的材料
            if (!_cost || _cost.length <= 0) {
                let tmp = usedList.get(cfg.itemId) || 0;
                usedList.set(cfg.itemId, tmp + speed);
            }
            for (const [itemId, count] of _cost) {
                const bagCount = bagList.get(itemId) || 0;
                const newCount = newList.get(itemId) || 0;
                const usedCount = usedList.get(itemId) || 0;
                const realCOunt = bagCount + newCount - usedCount;
                if (count * speed > realCOunt) {
                    //缺少的道具
                    const num = count * speed - realCOunt;
                    this.findTargetCost(itemId, bagList, usedList, newList, num, false);
                }
                else {
                    let tmp = usedList.get(itemId) || 0;
                    usedList.set(itemId, tmp + count * speed);
                }
            }
        }
    }
    

    检查消耗,消耗回滚。usedList是通过地址作为参数传递的,所以在进行合成之前需要深拷贝一份旧的消耗,如果道具不足,则回滚消耗,结束合成,否则继续。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    /** 检查消耗 */
    private checkCost(bagList: Map<ItemId, number>, usedList: Map<ItemId, number>, newList: Map<ItemId, number>): boolean {
        for (const [itemId, count] of usedList) {
            const bagCount = bagList.get(itemId) || 0;
            const newCount = newList.get(itemId) || 0;
            if (count > bagCount + newCount) {
                return false;
            }
        }
        return true;
    }
    
    let oldUsedList = new Map<ItemId, number>(usedList);
    this.findTargetCost(cfg.nextColorItemId, bagList, usedList, newList, 1, true);
    if (this.checkCost(bagList, usedList, newList)) {
    
    }
    else {
        //回滚
        usedList = oldUsedList;
    }
    
  4. 提升合成速度。让合成速率成指数级增长,减少接口执行时间

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    /** 根据上一次合成调整合成速度 */
    private genComposeSpeed(curSpeed: number, lastResult: ErrorCode): number {
        if (lastResult == ErrorCode.Ok) {
            return curSpeed * 2;
        }
        else {
            return Math.floor(curSpeed / 2);
        }
    }
    
Built with Hugo
Theme Stack designed by Jimmy