D&F - Frida

D&F - Frida

Tim 1403 2024-08-04

站在了巨人的肩膀头上,感谢造轮子的大佬。根据自己的喜好进行了修改 自用Frida

仅供测试使用

换装

装备栏检索全部格子,时装和宠物栏只检索最上面两行

注意:1️⃣时装和宠物换装后外观不会改变,但是属性变化了(不知道有没有刷新外观的接口)2️⃣镶嵌换不了

fr_db_suit1.png

fr_db_suit2.png

函数

部分函数

读取套装

从数据库读取指定套装

/**
 * 根据套装编号获取指定换装
 * 
 * 20250102 by Tim
 * @param cid 
 * @param num 套装编号
 */
function get_user_equ_replace(cid, num) {

	var suit_record = {};

	var selectQuery = `SELECT  cid, suit_num, equip_0, equip_1, equip_2, equip_3, equip_4,  equip_5,
        equip_6, equip_7, equip_8, equip_9,  equip_10,  equip_11, equip_12, equip_13, equip_14,
        equip_15,  equip_16,  equip_17,  equip_18, equip_19,  equip_20,  equip_21, equip_22
    FROM user_equ_replace
    WHERE cid = ${cid} AND suit_num = ${num}; `;
	if (api_MySQL_exec(mysql_frida, selectQuery)) {
		// 获取查询的行数
		var rows = MySQL_get_n_rows(mysql_frida);
		if (rows > 0) {
			// 查询成功,读取数据
			MySQL_fetch(mysql_frida); // 获取单行数据 
			//读取套装
			for (let index = 0; index <= 22; index++) {
				suit_record[index] = {};
				suit_record[index] = JSON.parse(api_MySQL_get_str(mysql_frida, 0 + 2 + index));
				// log(index + ' ' + api_MySQL_get_str(mysql_frida, 0 + 2 + index));
			}
			return suit_record;
		}
	}

}

保存套装

保存到数据库

20250103 数据库改为保存 equBackPack.add(7).readU32()

/**
 * 保存用户指定套装
 * 
 * 20250102 by Tim
 * @param user 
 * @param suit_num 
 */
function saveEquSuit(user, suit_num) {
	let userSuit = {};
	let inven = CUserCharacInfo_getCurCharacInvenW(user);
	let itemSize = 61;  // 每个物品的大小
	for (let index = 0; index <= 22; index++) {
		let equ = CInventory_GetInvenRef(inven, INVENTORY_TYPE.INVENTORY_TYPE_BODY, index);//身上的装备
		let data = Memory.readByteArray(equ, itemSize);
		let str = arrayBufferToHexStr(data);
		let item_id = Inven_Item_getKey(equ);

		userSuit[index] = {};
		userSuit[index].id = item_id;
		userSuit[index].data = str; 
		// log(index + ' ' + JSON.stringify(userSuit[index]));
	}
	let charac_no = CUserCharacInfo_getCurCharacNo(user);
	//写入数据库
	api_MySQL_exec(mysql_frida, `
						INSERT INTO user_equ_replace (
							cid, suit_num, equip_0, equip_1, equip_2, equip_3, equip_4, equip_5, equip_6,
							equip_7, equip_8, equip_9, equip_10, equip_11, equip_12, equip_13, equip_14,
							equip_15, equip_16, equip_17, equip_18, equip_19, equip_20, equip_21, equip_22
						) VALUES (
							${charac_no}, ${suit_num},
							'${JSON.stringify(userSuit[0])}', '${JSON.stringify(userSuit[1])}', '${JSON.stringify(userSuit[2])}', '${JSON.stringify(userSuit[3])}', '${JSON.stringify(userSuit[4])}',
							'${JSON.stringify(userSuit[5])}', '${JSON.stringify(userSuit[6])}', '${JSON.stringify(userSuit[7])}', '${JSON.stringify(userSuit[8])}', '${JSON.stringify(userSuit[9])}',
							'${JSON.stringify(userSuit[10])}', '${JSON.stringify(userSuit[11])}', '${JSON.stringify(userSuit[12])}', '${JSON.stringify(userSuit[13])}', '${JSON.stringify(userSuit[14])}',
							'${JSON.stringify(userSuit[15])}', '${JSON.stringify(userSuit[16])}', '${JSON.stringify(userSuit[17])}', '${JSON.stringify(userSuit[18])}', '${JSON.stringify(userSuit[19])}',
							'${JSON.stringify(userSuit[20])}', '${JSON.stringify(userSuit[21])}', '${JSON.stringify(userSuit[22])}'
						)
						ON DUPLICATE KEY UPDATE
							equip_0 = '${JSON.stringify(userSuit[0])}', equip_1 = '${JSON.stringify(userSuit[1])}', equip_2 = '${JSON.stringify(userSuit[2])}',
							equip_3 = '${JSON.stringify(userSuit[3])}', equip_4 = '${JSON.stringify(userSuit[4])}', equip_5 = '${JSON.stringify(userSuit[5])}',
							equip_6 = '${JSON.stringify(userSuit[6])}', equip_7 = '${JSON.stringify(userSuit[7])}', equip_8 = '${JSON.stringify(userSuit[8])}',
							equip_9 = '${JSON.stringify(userSuit[9])}', equip_10 = '${JSON.stringify(userSuit[10])}', equip_11 = '${JSON.stringify(userSuit[11])}',
							equip_12 = '${JSON.stringify(userSuit[12])}', equip_13 = '${JSON.stringify(userSuit[13])}', equip_14 = '${JSON.stringify(userSuit[14])}',
							equip_15 = '${JSON.stringify(userSuit[15])}', equip_16 = '${JSON.stringify(userSuit[16])}', equip_17 = '${JSON.stringify(userSuit[17])}',
							equip_18 = '${JSON.stringify(userSuit[18])}', equip_19 = '${JSON.stringify(userSuit[19])}', equip_20 = '${JSON.stringify(userSuit[20])}',
							equip_21 = '${JSON.stringify(userSuit[21])}', equip_22 = '${JSON.stringify(userSuit[22])}';
					`);

	api_CUser_SendNotiPacketMessage(user, '保存成功!', 1);
}

换装(新)

通过接口实现换装(未找到换宠物的方法)

/**
 * 换装HOOK
 * @param a1		User指针
 * @param a2		换装类型 0:装备 1:时装
 * @param a3		背包slot
 * @param a4		穿戴栏slot (10-21)
 * @retval			返回值 0代表成功
 */
var CUser_change_equip = new NativeFunction(ptr(0x0865EED2), 'int', ['pointer', 'int', 'int', 'int'], { "abi": "sysv" });

换装(旧)

/**
 * 交换装备
 * 
 * 20250102 by Tim
 * @param user 
 * @param minIndex 栏位格子的开始索引
 * @param maxIndex 栏位格子的结束索引
 * @param bodyIndex 身上装备的位置索引
 * @param suit 保存的换装套装
 * @param inventoryType 栏位类型 INVENTORY_TYPE
 * @param itemspaceType 更新栏位的类型 ENUM_ITEMSPACE
 */
function exchangeEqu(user, minIndex, maxIndex, bodyIndex, suit, inventoryType, itemspaceType) {

	let inven = CUserCharacInfo_getCurCharacInvenW(user);
	let itemSize = 61;  // 每个物品的大小

	//范围内循环匹配
	for (let i = minIndex; i <= maxIndex; i++) {
		let equBackPack = CInventory_GetInvenRef(inven, inventoryType, i);//背包装备
		let dataBackPack = Memory.readByteArray(equBackPack, itemSize);
		let item_id = Inven_Item_getKey(equBackPack);//背包装备id
		let str = arrayBufferToHexStr(dataBackPack);
		//匹配
		if (suit.data != str || suit.id != item_id || !suit.id)
			continue;

		let equ = CInventory_GetInvenRef(inven, INVENTORY_TYPE.INVENTORY_TYPE_BODY, bodyIndex);//身上的装备
		let data = Memory.readByteArray(equ, itemSize);

		// 交换物品的数据
		Memory.writeByteArray(equBackPack, data);
		Memory.writeByteArray(equ, dataBackPack);

		CUser_SendUpdateItemList(user, 1, inventoryType - 1, i);//更新槽位(0:物品 1:时装 2:宠物 3:身上)
		CUser_SendUpdateItemList(user, 1, 3, bodyIndex);//更新身上的
		CUser_SendNotiPacket(user, 1, 2, 1);
		CUser_send_itemspace(user, itemspaceType);
		break;
	}
}

/**
 * 角色更换指定套装
 * 
 * 20250102 by Tim
 * @param user 
 * @param suit_num 套装编号
 */
function changeEquSuit(user, suit_num) {
	let charac_no = CUserCharacInfo_getCurCharacNo(user);
	let userSuit = get_user_equ_replace(charac_no, suit_num);//从数据库读取保存的套装
	if (!userSuit)
		return;
	for (const key in userSuit) {

		let bodyIndex = parseInt(key);
		if (bodyIndex >= 0 && bodyIndex <= 9) {
			//检查时装 0~13
			exchangeEqu(user, 0, 13, bodyIndex, userSuit[bodyIndex], INVENTORY_TYPE.INVENTORY_TYPE_AVARTAR, ENUM_ITEMSPACE.ENUM_ITEMSPACE_AVATAR);
		}
		else if (bodyIndex >= 10 && bodyIndex <= 21) {
			//检查装备 9-56
			exchangeEqu(user, 9, 56, bodyIndex, userSuit[bodyIndex], INVENTORY_TYPE.INVENTORY_TYPE_ITEM, ENUM_ITEMSPACE.ENUM_ITEMSPACE_INVENTORY);
		} else if (bodyIndex == 22) {
			//检查宠物 0~13
			exchangeEqu(user, 0, 13, bodyIndex, userSuit[bodyIndex], INVENTORY_TYPE.INVENTORY_TYPE_CREATURE, ENUM_ITEMSPACE.ENUM_ITEMSPACE_CREATURE);
		}
	}
}

效果

深渊奖励(旧)

退出副本后统计奖励

函数

//20240801 by Tim 添加道具
var CUser_AddItem = new NativeFunction(ptr(0x867B6D4), 'int', ['pointer', 'int', 'int', 'int', 'pointer', 'int'], {"abi":"sysv"});

//20240801 by Tim 给角色发道具
function api_CUser_AddItem(user, item_id, item_cnt)
{
	var item_space = Memory.alloc(4);
	var slot = CUser_AddItem(user, item_id, item_cnt, 6, item_space, 0);

	if(slot >= 0)
	{
		//通知客户端有游戏道具更新
		CUser_SendUpdateItemList(user, 1, item_space.readInt(), slot);
	}

	return;
}

//20240801 by Tim 深渊奖励
var userAddItemCountDic={};
var userDungeonStateDic={};
var awardMessages=[
    "『金光三闪闪, 爽!』",
    "『史诗四连爆, 赞!』",
    "『五彩史诗雨, 强!』",
    "『六星连珠现, 牛!』",
    "『史诗满屏飞, 逆天啦!』"];
function hook_history_log2() {
    // cHistoryTrace::operator()
    Interceptor.attach(ptr(0x854f990), {
        onEnter: function(args) {
            // 解析日志内容: "18000008",18000008,D,145636,"nickname",1,72,8,0,192.168.200.1,192.168.200.1,50963,11, DungeonLeave,"龍人之塔",0,0,"aabb","aabb","N/A","N/A","N/A"
            var history_log = args[1].readUtf8String(-1);
            var group = history_log.split(",");
            // 角色信息
            var account_id = parseInt(group[1]);
            var time_hh_mm_ss = group[3];
            var charac_name = group[4];
            var charac_no = group[5];
            var charac_level = group[6];
            var charac_job = group[7];
            var charac_growtype = group[8];
            var user_web_address = group[9];
            var user_peer_ip2 = group[10];
            var user_port = group[11];
            var channel_index = group[12]; // 当前频道id
            // 玩家游戏事件
            var game_event = group[13].slice(1); // 删除多余空格
            var Dungeon_nameget = group[14];
            var item_id = parseInt(group[15]); // 本次操作道具id
            var item_cnt = parseInt(group[17]); // 本次操作道具数量
            var reason = parseInt(group[18]); // 本次操作原因
            if (game_event) {
                console.log('history_log', history_log)
            }

            // 触发游戏事件的角色
            var user = GameWorld_find_user_from_world_byaccid(G_GameWorld(), account_id);
            if (user.isNull()) {
                return;
            }
            // DungeonLeave离开副本 DungeonEnter进入副本 KillMob杀死怪物 Money+
            if(game_event == "DungeonEnter")
            {
                //进入副本改变状态
                userAddItemCountDic[user] = 0;
                userDungeonStateDic[user] = true;
            }
            else if (game_event == "Item+") {
                var itemData = CDataManager_find_item(G_CDataManager(), item_id);
                var needLevel = CItem_getUsableLevel(itemData); // 等级
                var inEquRarity = CItem_getRarity(itemData); // 稀有度
                // 道具增加: Item+
                // reason 4副本内拾取 | inEquRarity 4史诗品级
                if (reason == 4 &&  userDungeonStateDic[user]) {
                    if (inEquRarity == 4) {                        
                        userAddItemCountDic[user]++;
                        //api_gameWorld_SendNotiPacketMessage('玩家[' + api_CUserCharacInfo_getCurCharacName(user) + ']' + ']在地下城中获得了[' + api_CItem_getItemName(item_id) + '] x1', 14);
                    }
                }
            } else if (game_event == "DungeonLeave") {
              //计算奖励
              userDungeonStateDic[user] = false;
              var addItemCount = userAddItemCountDic[user];
               userAddItemCountDic[user] = 0;//清空
              if(addItemCount <3){ 
                return ;
              }
              //奖励划分
             var message="";
             if(addItemCount==3)
                message=awardMessages[0];
             else if (addItemCount==4)
                 message=awardMessages[1];
             else if (addItemCount==5)
                 message=awardMessages[2];
             else if (addItemCount==6)
                 message=awardMessages[3];
             else
                message=awardMessages[4];
              var goldnum=addItemCount-2;//金币
              var cashnum=(addItemCount-3)*200+300;
              api_GameWorld_SendNotiPacketMessage(message + ' 玩家[' + api_CUserCharacInfo_getCurCharacName(user)  + ']在地下城中获得了【' + addItemCount + '】个史诗, 奖励:\r\n璀璨水晶x'+addItemCount + " \r\n100万金币x"+goldnum + " \r\n"+cashnum+"点券", 14);
                api_CUser_AddItem(user,400001000,addItemCount);
                api_CUser_AddItem(user,3340,goldnum);
                api_recharge_cash_cera(user,cashnum);
            }            
        },
        onLeave: function(retval) {}
    });
}

调用

// 加载主功能
function start() {
    console.log('==========================================================frida start df_game_r.js - dp2.9 start ===========================================================');
     hook_history_log2();// 深渊奖励 
    console.log('==========================================================frida start df_game_r.js - dp2.9 end =============================================================');
}

效果

旧版dnf_log1.png

新版
dnf_log51.png

超链接消息 - 多表情

根据初六的dp2插件拓展,支持多个表情显示(没怎么测试)

函数

/**
 * 多表情超链接高亮消息
 * @param {*} user  用户
 * @param {*} strarr 消息数组【消息类型str/其他,消息,rgba,Symbol】 
 * @param {*} msgtype 广播类型
 
    //0为上方系统公告栏
 
    //1为下方对话框/绿色

    //2为下方对话框/蓝色

    //3为下方对话框/白色

    //5为下方对话框/白色

    //6为下方对话框/紫色

    //7为下方对话框/绿色

    //8为下方对话框/橙色

    //9为下方对话框/蓝色

    //10为喇叭,但是会乱码    
    //11为喇叭
    //12为喇叭
    //13为喇叭
    //14为喇叭
 * @param {*} type 发给 1(个人)/0(全部) 
 */
function api_SendHyperLinkChatMsg_multi_emoji(user, strarr, msgtype, type) {
    const bufferSize = 255;
    const strptr = Memory.alloc(bufferSize);
    let startlen = 0;
    let cnt = 0;

    // 准备表情符号数据
    const emojiBytes1 = [0xc2, 0x80, 0x20];
    strptr.add(startlen).writeByteArray(emojiBytes1);
    startlen += emojiBytes1.length;

    // 处理消息字符串数组
    for (const item of strarr) {
        const [strtype, msgContent, flags, symbol] = item;

        // strptr.add(startlen).writeByteArray([0xc2, 0x80]);
        // startlen += 2; // 更新起始长度

        // 准备表情符号数据
        const emojiBytes = symbol >= 1 ? [0xc2, 0x80, 0x20, 0x1e, 0x20, symbol, 0x1f] : [0xc2, 0x80, 0x20];
        strptr.add(startlen).writeByteArray(emojiBytes);
        startlen += emojiBytes.length;

        const msgstr = (strtype === 'str') ? msgContent + '' : '[' + api_CItem_GetItemName(parseInt(msgContent)) + ']';
        const str_ptr = Memory.allocUtf8String(msgstr);
        const str_len = strlen(str_ptr);
        strptr.add(startlen).writeByteArray(str_ptr.readByteArray(str_len));
        startlen += str_len;

        // 检查是否需要添加额外的字节 
        if (flags[3] === 255) {
            strptr.add(startlen).writeByteArray([0xc2, 0x80]);
            startlen += 2;
            cnt++;
        }
    }
    // 结束字符串并准备数据包
    strptr.add(startlen).writeByteArray([0xc2, 0x80]);
    startlen += 2;
    const packet_guard = api_PacketGuard_PacketGuard();
    InterfacePacketBuf_put_header(packet_guard, 0, 370);
    InterfacePacketBuf_put_byte(packet_guard, msgtype);
    InterfacePacketBuf_put_short(packet_guard, 0);
    InterfacePacketBuf_put_byte(packet_guard, 0);
    InterfacePacketBuf_put_int(packet_guard, startlen);
    InterfacePacketBuf_put_str(packet_guard, strptr, startlen);
    InterfacePacketBuf_put_byte(packet_guard, cnt);
    // 处理附加信息
    for (const item of strarr) {
        const [_, msgtype, flags, symbo] = item;
        if (flags[3] === 255) {
            const RbgInfoptr = Memory.alloc(104);
            RbgInfoptr.writeByteArray(flags);
            // 处理消息类型
            if (typeof msgtype === 'number') {
                RbgInfoptr.add(0x4).writeU32(msgtype);
                const Citem = CDataManager_find_item(G_CDataManager(), msgtype);
                if (!CItem_is_stackable(Citem)) {
                    RbgInfoptr.add(0x8).writeU32(get_rand_int(0));
                    RbgInfoptr.add(0xe).writeU16(CEquipItem_get_endurance(Citem));
                }
            }
            InterfacePacketBuf_put_binary(packet_guard, RbgInfoptr, 104);
        }
    }
    // 完成数据包
    InterfacePacketBuf_finalize(packet_guard, 1);
    // 根据类型发送数据包
    if (type === 1) {
        CUser_SendPacket(user, 1, packet_guard);
    }
    else {
        GameWorld_send_all_with_state(G_GameWorld(), packet_guard, 3); // 只给状态 >= 3 的玩家发送公告
    }
    // 清理数据包
    Destroy_PacketGuard_PacketGuard(packet_guard);
}

调用

api_SendHyperLinkChatMsg_multi_emoji(user, [
                    ['str', '玩家', [150, 255, 30, 255], 1],
                    ['str', '『test』', [0, 136, 255, 255], 3],
                    ['str', '爆出', [150, 255, 30, 255], 32],
                    ['item', 3340, [150, 255, 30, 255], 32],
                ], 8, 1);

效果

dnf_log4.png

字符串转高亮超链接数组

将字符串转化成高亮超链接数组。做了一些限制,其中字符串不能太长,会导致异常(高亮超链接函数那块不会修改)。

函数

/**
 * 将字符串转化成高亮超链接数组
 * @param {*} str 字符串
 * @param {*} rgba 指定rgba 
*/
function hyperLinkChatStrConvertArray(str, rgba) {
     // 如果包含 \r  \n \t或空字符串,直接返回一个数组。字符串太长也不行 
    if (str.includes('\r') || str.includes('\n') || str.includes('\t') || str.includes(' ') || str.length >= 15) {       
        return [['str', str, rgba]];
    }
    let result = [];
    for (let i = 0; i < str.length; i++) {
        // 将字符和rgba值作为一个数组添加到结果数组中
        result.push(['str', str[i], rgba]);
    }
    return result;
}

调用

var array = hyperLinkChatStrConvertArray('完成悬赏任务!', [150, 255, 30, 255])

效果

dnf_log8.png

悬赏功能

悬赏功能为全服共享,以下部分函数,需要搭配 frida_config.json 文件。

处理悬赏

/**
 * 处理悬赏
 * 
 * //20241222 by Tim
 * @param {*} user 
 * @param {*} target_id 目标id (装备id/副本id)
 * @param {*} type 类型(装备/副本)
 * @returns 
 */
function handle_offer_reward_record(user, target_id, type) {

    //20241222 by Tim 添加悬赏检查
    if (!global_config['offer_reward']['isEnable'])
        return;
    //判断target_id是否存在配置中
    var targetlist = global_config['offer_reward']['target'];
    if (!targetlist['' + target_id])
        return;
    var targetInfo = targetlist['' + target_id];
    //检查今天是否已存在记录
    var today = get_date();
    var record = get_offer_reward_record_byItem(target_id, today, type);
    if (record)
        return;
    var des = '';
    var targetArray = [];
    //根据类型显示相关
    if (type == 'equ') {
        des = '爆出';
        targetArray = ['item', target_id, getItemRGBAByItemId(target_id)];
    } else {
        des = '通关';
        targetArray = ['str', '[' + api_CDungeon_getDungeonName(target_id) + ']', [244, 0, 123, 255]];
    }
    var noticeArray = [
        ['str', '玩家', [150, 255, 30, 255]],
        ['str', '『' + api_CUserCharacInfo_getCurCharacName(user) + '』', [0, 136, 255, 255]],
        ['str', des, [150, 255, 30, 255]],
        targetArray,
        ...hyperLinkChatStrConvertArray('完成悬赏任务!', [150, 255, 30, 255])
    ];

    var charac_no = CUserCharacInfo_getCurCharacNo(user);
    //20241225 by Tim 添加特殊称号
    if (cidSpecialTitle[charac_no])
        noticeArray.splice(1, 0, ['str', cidSpecialTitle[charac_no][0], cidSpecialTitle[charac_no][1]]);

    api_SendHyperLinkChatMsg_emoji(user, noticeArray, 0, 0, 35);

    //奖励并记录数据库 
    var rewards = targetInfo.reward;
    for (let i = 0; i < rewards.length; i++) {
        const element = rewards[i];
        //发送道具到玩家背包
        api_CUser_AddItem(user, element[0], element[1]);
    }

    api_MySQL_exec(mysql_frida, `insert into offer_reward_record (date, cid, targetid, type) values ('${today}',${charac_no},${target_id},'${type}');`);
}

处理悬赏称号

/**
 * 处理悬赏称号
 * 
 * //20241225 by Tim
 */
function handle_offer_reward_specialTitle(user) {
    //20241225 by Tim 添加悬赏结算
    var charac_no = CUserCharacInfo_getCurCharacNo(user);
    var date = addDaysToDate(-1);
    var offer_reward = global_config['offer_reward'];
    var completeCount = get_offer_reward_record_byUser(charac_no, date);
    if (completeCount > 0 && offer_reward['titles'][completeCount + ''])
        cidSpecialTitle[charac_no] = offer_reward['titles'][completeCount + ''];
    else
        cidSpecialTitle[charac_no] = '';
}

查询悬赏进度

添加到 hook_characterMessageLog 函数中:

if (msg == '查询悬赏') {
    //20241222 by Tim
    if (!global_config['offer_reward']['isEnable']) {
        api_CUser_SendNotiPacketMessage(user, " 暂未开通悬赏!", 8);
        return;
    }
    var isNull = false;
    var today = get_date();
    var record_list = get_offer_reward_record(today);
    if (!record_list)
        isNull = true;

    api_CUser_SendNotiPacketMessage(user, "------------------今日悬赏-----------------", 8);
    var targetlist = global_config['offer_reward']['target'];
    for (const key in targetlist) {
        if (!targetlist.hasOwnProperty(key)) continue;
        var targetid = parseInt(key);
        var status1 = '○';//悬赏状态1
        var status2 = '『未完成』';//悬赏状态2
        var status2Rgba = [255, 0, 0, 255];
        var symbolIndex = 10;
        if (!isNull) {
            var record = record_list.find(x => x.targetid == targetid);
            if (record) {
                status1 = '●';
                status2 = '『' + api_get_charac_name_by_charac_no(record.cid) + '』';
                status2Rgba = [0, 136, 255, 255];
                symbolIndex = 31;
            }
        }
        var des = '';//悬赏前缀说明
        var targetArray = [];//存放悬赏目标
        //区分equ(装备)和dgn(副本)类型 
        if (targetlist[key].type != 'equ') {
            des = targetlist[key].des || '通关副本';
            targetArray = ['str', '[' + api_CDungeon_getDungeonName(targetid) + ']', [244, 0, 123, 255]]
        } else {
            des = targetlist[key].des || '深渊爆出史诗';
            targetArray = ['item', targetid, getItemRGBAByItemId(targetid)]
        }
        api_SendHyperLinkChatMsg_emoji(user, [
            ['str', '   ' + status1 + ' ', [255, 255, 0, 255]],
            ...hyperLinkChatStrConvertArray(des, [150, 255, 30, 255]),
            targetArray,
            ['str', '  -  ', [255, 255, 0, 255]],
            ['str', status2, status2Rgba]
        ], 8, 1, symbolIndex);
    }
    api_CUser_SendNotiPacketMessage(user, "------------------------------------------", 8);
}

效果

悬赏任务dnf_log7.png

称号效果dnf_log61.png

悬赏通知dnf_log8.png

配置说明

fraid_confg.png