添加示例项目
This commit is contained in:
169
示例项目/DPS启动器/DPS启动器.nut
Normal file
169
示例项目/DPS启动器/DPS启动器.nut
Normal file
@@ -0,0 +1,169 @@
|
||||
class _DPS_Login_Gateway_ {
|
||||
|
||||
//数据库连接
|
||||
MysqlObject = null;
|
||||
|
||||
PackHandleMap = null;
|
||||
|
||||
|
||||
constructor() {
|
||||
PackHandleMap = {};
|
||||
|
||||
MysqlObject = Mysql(Str_Ptr("127.0.0.1"), 3306, Str_Ptr("taiwan_cain"), Str_Ptr("game"), Str_Ptr("uu5!^%jg"));
|
||||
MysqlObject.Exec_Sql(format("SET NAMES %s", "latin1"));
|
||||
|
||||
//创建一个Http Server
|
||||
try {
|
||||
local HS = HttpServer("0.0.0.0", "41817");
|
||||
HS.Listen(function(SocketObject, Header, Msg) {
|
||||
getroottable()._DPS_Login_Gateway_Object_._HttpServer_Event_DPS_(SocketObject, Header, Msg);
|
||||
});
|
||||
} catch (exception) {
|
||||
|
||||
}
|
||||
|
||||
PackHandleMap["/GetConfig"] <- function(SocketObject, Header, Jso) {
|
||||
local Config = sq_ReadJsonFile("/dp_s/OfficialConfig/登录器配置.json");
|
||||
//读取DPS登录器的配置并发送
|
||||
SocketObject.Write(Config);
|
||||
}
|
||||
|
||||
|
||||
PackHandleMap["/Login"] <- function(SocketObject, Header, Jso) {
|
||||
if (!Jso.rawin("account")) return;
|
||||
if (!Jso.rawin("passwd")) return;
|
||||
local account = Jso.account;
|
||||
local passwd = Jso.passwd;
|
||||
local passwd_hash = MD5_Hash(passwd);
|
||||
|
||||
|
||||
//正则表达式 只允许字母和数字
|
||||
local regex = regexp("^[A-Za-z0-9]{1,19}$");
|
||||
if (!regex.match(account)) {
|
||||
SocketObject.Write({
|
||||
error = "账号只能包含字母和数字且长度小于20"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
local sql = format("select UID from d_taiwan.accounts where accountname='%s' and password='%s';", account, passwd_hash);
|
||||
local Ret = MysqlObject.Select(sql, ["int"]);
|
||||
if (Ret && Ret.len() > 0) {
|
||||
local Uid = Ret[0][0];
|
||||
local str = format("%08x010101010101010101010101010101010101010101010101010101010101010155914510010403030101", Uid);
|
||||
local Byte = Sq_Rsa_Private_Encrypt(str);
|
||||
local EnStr = MD5.base64_encode(Byte);
|
||||
//发送登录Token
|
||||
SocketObject.Write({
|
||||
token = EnStr
|
||||
});
|
||||
} else {
|
||||
SocketObject.Write({
|
||||
error = "账号或密码错误!"
|
||||
});
|
||||
}
|
||||
}.bindenv(this);
|
||||
|
||||
|
||||
PackHandleMap["/Register"] <- function(SocketObject, Header, Jso) {
|
||||
|
||||
if (!Jso.rawin("account")) return;
|
||||
if (!Jso.rawin("passwd")) return;
|
||||
|
||||
local account = Jso.account;
|
||||
local passwd = Jso.passwd;
|
||||
|
||||
|
||||
//正则表达式 只允许字母和数字
|
||||
local regex = regexp("^[A-Za-z0-9]{1,19}$");
|
||||
if (account.len() == 0 || !regex.match(account)) {
|
||||
SocketObject.Write({
|
||||
error = "账号只能包含字母和数字且长度大于0小于20"
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (passwd.len() == 0 || !regex.match(passwd)) {
|
||||
SocketObject.Write({
|
||||
error = "密码只能包含字母和数字且长度大于0小于20"
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (GetAccountByName(account) != null) {
|
||||
SocketObject.Write({
|
||||
error = "账号已存在"
|
||||
})
|
||||
return;
|
||||
}
|
||||
local passwd_hash = MD5_Hash(passwd);
|
||||
|
||||
|
||||
local sql = format("INSERT INTO d_taiwan.accounts(accountname, password)VALUES( '%s' , '%s');", account, passwd_hash);
|
||||
MysqlObject.Exec_Sql(sql);
|
||||
local Ret = MysqlObject.Select("SELECT LAST_INSERT_ID()", ["int"]);
|
||||
if (Ret && Ret.len() > 0) {
|
||||
local Uid = Ret[0][0].tostring();
|
||||
MysqlObject.Exec_Sql(format("INSERT INTO d_taiwan.member_info(m_id, user_id)VALUES('%s','%s');", Uid, Uid));
|
||||
MysqlObject.Exec_Sql(format("INSERT INTO d_taiwan.member_white_account(m_id)VALUES('%s')", Uid));
|
||||
MysqlObject.Exec_Sql(format("INSERT INTO taiwan_login.member_login(m_id)VALUES('%s')", Uid));
|
||||
MysqlObject.Exec_Sql(format("INSERT INTO taiwan_billing.cash_cera(account, cera,mod_tran,mod_date, reg_date)VALUES('%s',0,0,NOW(), NOW())", Uid));
|
||||
MysqlObject.Exec_Sql(format("INSERT INTO taiwan_billing.cash_cera_point(account, cera_point,mod_date, reg_date)VALUES('%s',0,NOW(), NOW())", Uid));
|
||||
SocketObject.Write({
|
||||
success = "账号注册成功,现在您可以登录了!"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
}.bindenv(this);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
function GetAccountByName(account) {
|
||||
local sql = format("select UID , accountname, password from d_taiwan.accounts where accountname='%s'", account);
|
||||
local Ret = MysqlObject.Select(sql, ["int", "string", "string"]);
|
||||
print(Ret);
|
||||
if (!Ret || Ret.len() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
uid = Ret[0][0],
|
||||
account = Ret[0][1],
|
||||
passwd = Ret[0][2]
|
||||
}
|
||||
}
|
||||
|
||||
function _HttpServer_Event_DPS_(SocketObject, Header, Msg) {
|
||||
if (PackHandleMap.rawin(Header.path)) {
|
||||
local Jso = null;
|
||||
try {
|
||||
Jso = Json.Decode(Msg);
|
||||
} catch (exception) {
|
||||
|
||||
}
|
||||
if (!Jso) return;
|
||||
PackHandleMap[Header.path](SocketObject, Header, Jso);
|
||||
|
||||
} else {
|
||||
SocketObject.Write({
|
||||
error = "error url"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function MD5_Hash(str) {
|
||||
local Ctx = Memory.alloc(0x100);
|
||||
MD5.MD5_Init(Ctx.C_Object);
|
||||
MD5.MD5_Update(Ctx.C_Object, Memory.allocUtf8String(str).C_Object, str.len());
|
||||
local Result = Memory.alloc(16);
|
||||
MD5.MD5_Final(Result.C_Object, Ctx.C_Object);
|
||||
return MD5.hex_encode(Result.readUtf8String(16));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function _DPS_Login_Gateway_Init_(){
|
||||
getroottable()._DPS_Login_Gateway_Object_ <- _DPS_Login_Gateway_();
|
||||
print("\x1b[96m" + "############DPS启动器网关工作中############" + "\x1b[0m");
|
||||
}
|
||||
11
示例项目/DPS启动器/Proj.ifo
Normal file
11
示例项目/DPS启动器/Proj.ifo
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ProjectName": "DPS启动器",
|
||||
"ProjectDescribe": "DPS作为网关,QT编写的纯净登录器",
|
||||
"ProjectAuthor": "倾泪寒",
|
||||
"ProjectVersion": 1.0,
|
||||
"ProjectConfig": "登录器配置.json",
|
||||
"ProjectFiles": [
|
||||
"DPS启动器.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_DPS_Login_Gateway_Init_"
|
||||
}
|
||||
51
示例项目/DPS启动器/登录器配置.json
Normal file
51
示例项目/DPS启动器/登录器配置.json
Normal file
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"noticeclass": [
|
||||
"公告",
|
||||
"活动",
|
||||
"玩法"
|
||||
],
|
||||
"notice": [
|
||||
{
|
||||
"type": "img",
|
||||
"category": 3,
|
||||
"text": "安图恩攻坚战来袭,荒古武器等你拿!",
|
||||
"link": "https://dnf.qq.com/cp/a20260108festivalgift/",
|
||||
"content": "http://192.168.200.25:3000/Lenheart/ImageHosting/raw/branch/main/anton.png"
|
||||
},
|
||||
{
|
||||
"type": "img",
|
||||
"category": 2,
|
||||
"text": "命运序列礼包,2026新春礼包上线!",
|
||||
"content": "http://192.168.200.25:3000/Lenheart/ImageHosting/raw/branch/main/mingyunxulie.png",
|
||||
"link": "https://dnf.qq.com/cp/a20260108festivalgift/"
|
||||
},
|
||||
{
|
||||
"type": "img",
|
||||
"category": 3,
|
||||
"text": "终结狄瑞吉的不灭灾厄,终结不灭的宿命把!",
|
||||
"content": "http://192.168.200.25:3000/Lenheart/ImageHosting/raw/branch/main/diruiji.png",
|
||||
"link": "https://dnf.qq.com/cp/a20260108diregieactivity/"
|
||||
},
|
||||
{
|
||||
"type": "link",
|
||||
"category": 1,
|
||||
"text": "1月9日 5点停机更新公告",
|
||||
"link": "https://dnf.qq.com/webplat/info/news_version3/119/495/498/m21449/202601/980616.shtml"
|
||||
},
|
||||
{
|
||||
"type": "link",
|
||||
"category": 2,
|
||||
"text": "DNF吧双福利来袭!感染之地挑战和盖楼互动,7000Q币狂送不停!",
|
||||
"link": "https://dnf.qq.com/webplat/info/news_version3/119/495/496/m22999/202512/979722.shtml"
|
||||
},
|
||||
{
|
||||
"type": "link",
|
||||
"category": 1,
|
||||
"text": "关于1月8日初始化欢乐代币券的公告",
|
||||
"link": "https://dnf.qq.com/webplat/info/news_version3/119/495/498/m21449/202512/980292.shtml"
|
||||
}
|
||||
],
|
||||
"scriptMd5": "",
|
||||
"pluginsMd5": [],
|
||||
"updateUrl": "www.baidu.com"
|
||||
}
|
||||
145
示例项目/GM便捷操作台/GM便捷操作台.nut
Normal file
145
示例项目/GM便捷操作台/GM便捷操作台.nut
Normal file
@@ -0,0 +1,145 @@
|
||||
function _Dps_GmConvenienceConsole_Logic_() {
|
||||
local Config = GlobalConfig.Get("GM便捷操作台_Lenheart.json");
|
||||
|
||||
|
||||
Gm_InputFunc_Handle[Config["发送道具指令"]] <- function(SUser, CmdString) {
|
||||
local count = -1;
|
||||
local pos = 0;
|
||||
local handler = [];
|
||||
do {
|
||||
local start = pos;
|
||||
pos = CmdString.find(" ", pos + 1);
|
||||
if (pos != null) {
|
||||
handler.append(CmdString.slice(start + 1, pos));
|
||||
} else
|
||||
handler.append(CmdString.slice(start + 1));
|
||||
count = count + 1
|
||||
} while (pos != null)
|
||||
|
||||
//得到空格数量
|
||||
if (count == 1) {
|
||||
local Ret = SUser.GiveItem(handler[1].tointeger(), 1);
|
||||
if (!Ret) SUser.SendNotiPacketMessage("发送失败背包是不是满了", 8);
|
||||
} else if (count == 2) {
|
||||
local Ret = SUser.GiveItem(handler[1].tointeger(), handler[2].tointeger());
|
||||
if (!Ret) SUser.SendNotiPacketMessage("发送失败背包是不是满了", 8);
|
||||
}
|
||||
}
|
||||
|
||||
Gm_InputFunc_Handle[Config["转职觉醒指令"]] <- function(SUser, CmdString) {
|
||||
local count = -1;
|
||||
local pos = 0;
|
||||
local handler = [];
|
||||
do {
|
||||
local start = pos;
|
||||
pos = CmdString.find(" ", pos + 1);
|
||||
if (pos != null) {
|
||||
handler.append(CmdString.slice(start + 1, pos));
|
||||
} else
|
||||
handler.append(CmdString.slice(start + 1));
|
||||
count = count + 1
|
||||
} while (pos != null)
|
||||
|
||||
//得到空格数量
|
||||
if (count == 1) {
|
||||
SUser.ChangeGrowType(handler[1].tointeger(), 0);
|
||||
SUser.SendNotiPacket(0, 2, 0);
|
||||
SUser.InitSkillW(handler[1].tointeger(), 0);
|
||||
} else if (count == 2) {
|
||||
SUser.ChangeGrowType(handler[1].tointeger(), handler[2].tointeger());
|
||||
SUser.SendNotiPacket(0, 2, 0);
|
||||
SUser.InitSkillW(handler[1].tointeger(), handler[2].tointeger());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Gm_InputFunc_Handle[Config["完成任务指令"]] <- function(SUser, CmdString) {
|
||||
local count = -1;
|
||||
local pos = 0;
|
||||
local handler = [];
|
||||
do {
|
||||
local start = pos;
|
||||
pos = CmdString.find(" ", pos + 1);
|
||||
if (pos != null) {
|
||||
handler.append(CmdString.slice(start + 1, pos));
|
||||
} else
|
||||
handler.append(CmdString.slice(start + 1));
|
||||
count = count + 1
|
||||
} while (pos != null)
|
||||
|
||||
//得到空格数量
|
||||
if (count == 1) {
|
||||
SUser.ClearQuest_Gm(handler[1].tointeger());
|
||||
}
|
||||
}
|
||||
|
||||
Gm_InputFunc_Handle[Config["设置等级指令"]] <- function(SUser, CmdString) {
|
||||
local count = -1;
|
||||
local pos = 0;
|
||||
local handler = [];
|
||||
do {
|
||||
local start = pos;
|
||||
pos = CmdString.find(" ", pos + 1);
|
||||
if (pos != null) {
|
||||
handler.append(CmdString.slice(start + 1, pos));
|
||||
} else
|
||||
handler.append(CmdString.slice(start + 1));
|
||||
count = count + 1
|
||||
} while (pos != null)
|
||||
|
||||
//得到空格数量
|
||||
if (count == 1) {
|
||||
SUser.SetCharacLevel(handler[1].tointeger());
|
||||
}
|
||||
}
|
||||
|
||||
//获取位置信息
|
||||
Gm_InputFunc_Handle[Config["获取位置指令"]] <- function(SUser, CmdString) {
|
||||
local Location = SUser.GetLocation();
|
||||
SUser.SendNotiPacketMessage("X坐标: " + Location.Pos.X, 8);
|
||||
SUser.SendNotiPacketMessage("Y坐标: " + Location.Pos.Y, 8);
|
||||
SUser.SendNotiPacketMessage("城镇编号: " + Location.Town, 8);
|
||||
SUser.SendNotiPacketMessage("区域编号: " + Location.Area, 8);
|
||||
};
|
||||
|
||||
//踢人下线
|
||||
Gm_InputFunc_Handle[Config["踢玩家下线指令"]] <- function(SUser, CmdString) {
|
||||
local count = -1;
|
||||
local pos = 0;
|
||||
local handler = [];
|
||||
do {
|
||||
local start = pos;
|
||||
pos = CmdString.find(" ", pos + 1);
|
||||
if (pos != null) {
|
||||
handler.append(CmdString.slice(start + 1, pos));
|
||||
} else
|
||||
handler.append(CmdString.slice(start + 1));
|
||||
count = count + 1
|
||||
} while (pos != null)
|
||||
|
||||
//得到空格数量
|
||||
if (count == 1) {
|
||||
local TUser = World.GetUserByName(handler[1]);
|
||||
if(TUser)TUser.Kick();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
function _Dps_GmConvenienceConsole_Main_() {
|
||||
_Dps_GmConvenienceConsole_Logic_();
|
||||
}
|
||||
|
||||
function _Dps_GmConvenienceConsole_Main_Reload_(OldConfig) {
|
||||
|
||||
foreach (Key,Value in OldConfig) {
|
||||
try {
|
||||
Gm_InputFunc_Handle.rawdelete(Key);
|
||||
} catch (exception){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
_Dps_GmConvenienceConsole_Logic_();
|
||||
}
|
||||
16
示例项目/GM便捷操作台/GM便捷操作台_Lenheart.json
Normal file
16
示例项目/GM便捷操作台/GM便捷操作台_Lenheart.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"发送道具指令": "GiveItem",
|
||||
"转职觉醒指令": "GrowType",
|
||||
"完成任务指令": "MakeQuest",
|
||||
"设置等级指令": "SetLevel",
|
||||
"获取位置指令": "GetLocation",
|
||||
"踢玩家下线指令": "KickPlayer",
|
||||
|
||||
"发送道具指令例子": "当有一个空格时跟道具编号 当有两个空格时 跟道具编号和发送数量 例: '//GiveItem 3037' '//GiveItem 3037 100'",
|
||||
"转职觉醒指令例子": "当有一个空格时跟转职职业 当有两个空格时 跟转职职业和是否觉醒 例: '//GrowType 1' '//GrowType 1 1'",
|
||||
"完成任务指令例子": "当有一个空格时跟任务编号 例: '//MakeQuest 1'",
|
||||
"设置等级指令例子": "当有一个空格时跟设定等级 例: '//SetLevel 100'",
|
||||
"获取位置指令例子": "无特殊用法 '//GetLocation'",
|
||||
"踢玩家下线指令例子": "当有一个空格时跟想要踢除的玩家名字 例: '//KickPlayer 倾泪寒'",
|
||||
"说明" : "所有指令都可更改 相对于的触发方式输入自己设定的指令即可"
|
||||
}
|
||||
11
示例项目/GM便捷操作台/Proj.ifo
Normal file
11
示例项目/GM便捷操作台/Proj.ifo
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ProjectName": "GM便捷操作台",
|
||||
"ProjectDescribe": "本项目提供了许多GM的便捷操作 方便平时调试或写代码 \n输入'//' + 设定的指令即可执行逻辑 ",
|
||||
"ProjectAuthor": "倾泪寒",
|
||||
"ProjectVersion": 1.0,
|
||||
"ProjectConfig": "GM便捷操作台_Lenheart.json",
|
||||
"ProjectFiles": [
|
||||
"GM便捷操作台.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_Dps_GmConvenienceConsole_Main_"
|
||||
}
|
||||
290
示例项目/NPC商店限购/NPC商店限购.nut
Normal file
290
示例项目/NPC商店限购/NPC商店限购.nut
Normal file
@@ -0,0 +1,290 @@
|
||||
g_ShopLimitCache <- {};
|
||||
|
||||
class _Shop_Limit_Bynangua {
|
||||
function get_trade_time() {
|
||||
local currentDate = date()
|
||||
local year = currentDate.year
|
||||
local month = currentDate.month + 1
|
||||
local day = currentDate.day
|
||||
local hour = currentDate.hour
|
||||
local minute = currentDate.min
|
||||
local second = currentDate.sec
|
||||
return format("%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, minute, second)
|
||||
}
|
||||
|
||||
// 计算下个月的1号早上6点
|
||||
function GetFirstOfNextMonth() {
|
||||
local currentDate = date()
|
||||
local year = currentDate.year
|
||||
local month = currentDate.month + 2 // +2是因为month是从0开始的,且要算下个月
|
||||
local day = 1
|
||||
local hour = 6
|
||||
local minute = 0
|
||||
local second = 0
|
||||
return format("%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, minute, second)
|
||||
}
|
||||
|
||||
// 计算下周一早上6点
|
||||
function GetNextMonday() {
|
||||
local currentDate = date()
|
||||
local day = currentDate.wday // 0是周日,1-6是周一到周六
|
||||
local diff = (day == 0) ? 1 : (8 - day)
|
||||
currentDate.day += diff
|
||||
local year = currentDate.year
|
||||
local month = currentDate.month + 1
|
||||
local day = currentDate.day
|
||||
local hour = 6
|
||||
local minute = 0
|
||||
local second = 0
|
||||
return format("%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, minute, second)
|
||||
}
|
||||
|
||||
// 计算第二天早上6点
|
||||
function GetSixAMNextDay() {
|
||||
local currentDate = date()
|
||||
local year = currentDate.year
|
||||
local month = currentDate.month + 1
|
||||
local day = currentDate.day + 1
|
||||
local hour = 6
|
||||
local minute = 0
|
||||
local second = 0
|
||||
return format("%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, minute, second)
|
||||
}
|
||||
|
||||
// 获取刷新时间
|
||||
function GetRefreshTime(refresh_month, refresh_weeks, refresh_days) {
|
||||
if (refresh_month == 1) {
|
||||
return GetFirstOfNextMonth()
|
||||
} else if (refresh_weeks == 1) {
|
||||
return GetNextMonday()
|
||||
} else if (refresh_days == 1) {
|
||||
return GetSixAMNextDay()
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
function HandlePurchase(SUser, item_id, item_shop_id, item_info, item_cnt) {
|
||||
local charac_no = SUser.GetCID();
|
||||
local cache_key = charac_no + "_" + item_id + "_" + item_shop_id;
|
||||
|
||||
if (g_ShopLimitCache.rawin(cache_key)) {
|
||||
local cache_data = g_ShopLimitCache[cache_key];
|
||||
local buy_count = cache_data.buy_count;
|
||||
local refresh_time = cache_data.refresh_time;
|
||||
local current_time = get_trade_time();
|
||||
|
||||
if (current_time >= refresh_time) {
|
||||
if (item_cnt > item_info[1]) {
|
||||
SUser.SendNotiPacketMessage("购买失败,可购买数量剩余 " + item_info[1] + " 个", 8);
|
||||
return true;
|
||||
}
|
||||
|
||||
local new_refresh_time = GetRefreshTime(item_info[2], item_info[3], item_info[4]);
|
||||
g_ShopLimitCache[cache_key] <- {
|
||||
buy_count = item_cnt,
|
||||
refresh_time = new_refresh_time
|
||||
};
|
||||
|
||||
updateDatabaseAsync(charac_no, item_id, item_shop_id, item_cnt, new_refresh_time);
|
||||
} else {
|
||||
local remaining = item_info[1] - buy_count;
|
||||
if (item_cnt > remaining) {
|
||||
if (remaining == 0) {
|
||||
local refresh_msg = "";
|
||||
if (item_info[2] == 1) { // 月刷新
|
||||
refresh_msg = "每月一日上午六点";
|
||||
} else if (item_info[3] == 1) { // 周刷新
|
||||
refresh_msg = "每周一日上午六点";
|
||||
} else if (item_info[4] == 1) { // 日刷新
|
||||
refresh_msg = "每日一日上午六点";
|
||||
}
|
||||
SUser.SendNotiPacketMessage("当前商品已售罄,将在" + refresh_msg + "刷新", 8);
|
||||
} else {
|
||||
SUser.SendNotiPacketMessage("购买失败,可购买数量剩余 " + remaining + " 个", 8);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
g_ShopLimitCache[cache_key] <- {
|
||||
buy_count = buy_count + item_cnt,
|
||||
refresh_time = refresh_time
|
||||
};
|
||||
|
||||
updateDatabaseAsync(charac_no, item_id, item_shop_id, buy_count + item_cnt, refresh_time);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
local SqlObj = MysqlPool.GetInstance().GetConnect();
|
||||
local query = "SELECT id, charac_no, item_id, buy_count, item_shop, refresh_time FROM DP_S.restrict_npc_shop_buy WHERE charac_no=" + charac_no + " AND item_id=" + item_id + " AND item_shop=" + item_shop_id;
|
||||
local column_type_list = ["int", "int", "int", "int", "int", "string"];
|
||||
local result = SqlObj.Select(query, column_type_list);
|
||||
MysqlPool.GetInstance().PutConnect(SqlObj);
|
||||
|
||||
if (result.len() == 0) {
|
||||
if (item_cnt > item_info[1]) {
|
||||
SUser.SendNotiPacketMessage("购买失败,可购买数量剩余 " + item_info[1] + " 个", 8);
|
||||
return true;
|
||||
}
|
||||
|
||||
local refresh_time = GetRefreshTime(item_info[2], item_info[3], item_info[4]);
|
||||
|
||||
g_ShopLimitCache[cache_key] <- {
|
||||
buy_count = item_cnt,
|
||||
refresh_time = refresh_time
|
||||
};
|
||||
|
||||
updateDatabaseAsync(charac_no, item_id, item_shop_id, item_cnt, refresh_time);
|
||||
} else {
|
||||
local buy_count = result[0][3];
|
||||
local refresh_time = result[0][5];
|
||||
local current_time = get_trade_time();
|
||||
|
||||
g_ShopLimitCache[cache_key] <- {
|
||||
buy_count = buy_count,
|
||||
refresh_time = refresh_time
|
||||
};
|
||||
|
||||
if (current_time >= refresh_time) {
|
||||
if (item_cnt > item_info[1]) {
|
||||
SUser.SendNotiPacketMessage("购买失败,可购买数量剩余 " + item_info[1] + " 个", 8);
|
||||
return true;
|
||||
}
|
||||
|
||||
local new_refresh_time = GetRefreshTime(item_info[2], item_info[3], item_info[4]);
|
||||
g_ShopLimitCache[cache_key] <- {
|
||||
buy_count = item_cnt,
|
||||
refresh_time = new_refresh_time
|
||||
};
|
||||
|
||||
updateDatabaseAsync(charac_no, item_id, item_shop_id, item_cnt, new_refresh_time);
|
||||
} else {
|
||||
local remaining = item_info[1] - buy_count;
|
||||
if (item_cnt > remaining) {
|
||||
if (remaining == 0) {
|
||||
local refresh_msg = "";
|
||||
if (item_info[2] == 1) { // 月刷新
|
||||
refresh_msg = "每月一日上午六点";
|
||||
} else if (item_info[3] == 1) { // 周刷新
|
||||
refresh_msg = "每周一日上午六点";
|
||||
} else if (item_info[4] == 1) { // 日刷新
|
||||
refresh_msg = "每日一日上午六点";
|
||||
}
|
||||
SUser.SendNotiPacketMessage("当前商品已售罄,将在" + refresh_msg + "刷新", 8);
|
||||
} else {
|
||||
SUser.SendNotiPacketMessage("购买失败,可购买数量剩余 " + remaining + " 个", 8);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
g_ShopLimitCache[cache_key] <- {
|
||||
buy_count = buy_count + item_cnt,
|
||||
refresh_time = refresh_time
|
||||
};
|
||||
|
||||
updateDatabaseAsync(charac_no, item_id, item_shop_id, buy_count + item_cnt, refresh_time);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 更新缓存到数据库
|
||||
function updateDatabaseAsync(charac_no, item_id, item_shop_id, buy_count, refresh_time) {
|
||||
local SqlObj = MysqlPool.GetInstance().GetConnect();
|
||||
// 使用 ON DUPLICATE KEY UPDATE 来更新已存在的记录
|
||||
local query = "INSERT INTO DP_S.restrict_npc_shop_buy (charac_no, item_id, buy_count, item_shop, refresh_time) " +
|
||||
"VALUES (" + charac_no + ", " + item_id + ", " + buy_count + ", " + item_shop_id + ", '" + refresh_time + "') " +
|
||||
"ON DUPLICATE KEY UPDATE buy_count = VALUES(buy_count), refresh_time = VALUES(refresh_time)";
|
||||
SqlObj.Select(query, []);
|
||||
MysqlPool.GetInstance().PutConnect(SqlObj);
|
||||
}
|
||||
|
||||
// 服务器启动时加载缓存
|
||||
function loadShopLimitCache() {
|
||||
local SqlObj = MysqlPool.GetInstance().GetConnect();
|
||||
local query = "SELECT charac_no, item_id, item_shop, buy_count, refresh_time FROM DP_S.restrict_npc_shop_buy";
|
||||
local column_type_list = ["int", "int", "int", "int", "string"];
|
||||
local result = SqlObj.Select(query, column_type_list);
|
||||
MysqlPool.GetInstance().PutConnect(SqlObj);
|
||||
|
||||
foreach(row in result) {
|
||||
local cache_key = row[0] + "_" + row[1] + "_" + row[2];
|
||||
g_ShopLimitCache[cache_key] <- {
|
||||
buy_count = row[3],
|
||||
refresh_time = row[4]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 服务器关闭时保存缓存
|
||||
Cb_Server_Close_Enter_Func.ShopLimitSave <- function(arg) {
|
||||
foreach(cache_key, data in g_ShopLimitCache) {
|
||||
local parts = split(cache_key, "_");
|
||||
local charac_no = parts[0].tointeger();
|
||||
local item_id = parts[1].tointeger();
|
||||
local item_shop = parts[2].tointeger();
|
||||
updateDatabaseAsync(charac_no, item_id, item_shop, data.buy_count, data.refresh_time);
|
||||
}
|
||||
g_ShopLimitCache <- {};
|
||||
}
|
||||
|
||||
function _Dps_Shop_Limit_Main_() {
|
||||
CreateShopLimitTable();
|
||||
loadShopLimitCache();
|
||||
Cb_BuyItem_check_error_Leave_Func.Shop_Limit_ByNangua <- function(args) {
|
||||
local Config = GlobalConfig.Get("NPC商店限购配置_Nangua.json");
|
||||
local shop_limit_config = Config["商店限购配置"];
|
||||
local is_buy = false;
|
||||
local SUser = User(args[1]);
|
||||
local msg_base = args[2];
|
||||
local Item_id = NativePointer(msg_base).add(13).readU32();
|
||||
local item_shop = NativePointer(msg_base).add(21).readU32();
|
||||
local item_cnt = NativePointer(msg_base).add(17).readU32();
|
||||
local item_shop_id = item_shop.tostring();
|
||||
if (item_shop_id in shop_limit_config) {
|
||||
local items_list = shop_limit_config[item_shop_id];
|
||||
foreach(item_info in items_list) {
|
||||
if (item_info[0] == Item_id) {
|
||||
is_buy = _Shop_Limit_Bynangua.HandlePurchase(SUser, Item_id, item_shop, item_info, item_cnt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_buy) {
|
||||
return 19;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function CreateShopLimitTable() {
|
||||
local Config = GlobalConfig.Get("NPC商店限购配置_Nangua.json");
|
||||
local PoolObj = MysqlPool.GetInstance();
|
||||
local Ip = Config["数据库IP 不是外置数据库不要更改"];
|
||||
local Port = Config["数据库端口 不懂不要更改"];
|
||||
local DbName = Config["数据库用户名 本地用户名不懂不要更改"];
|
||||
local Password = Config["数据库密码 本地密码不懂不要更改"];
|
||||
|
||||
PoolObj.SetBaseConfiguration(Ip, Port, DbName, Password);
|
||||
PoolObj.PoolSize = 10;
|
||||
PoolObj.Init();
|
||||
|
||||
// 建库建表SQL
|
||||
local CreateSql1 = "create database if not exists DP_S default charset utf8;";
|
||||
local CreateSql2 = "CREATE TABLE IF NOT EXISTS DP_S.restrict_npc_shop_buy (" +
|
||||
"id int(11) AUTO_INCREMENT, " +
|
||||
"charac_no int(11) NOT NULL, " +
|
||||
"item_id int(11) NOT NULL, " +
|
||||
"buy_count int(11) NOT NULL, " +
|
||||
"item_shop int(11) NOT NULL, " +
|
||||
"refresh_time varchar(255) NOT NULL, " +
|
||||
"PRIMARY KEY (id), " +
|
||||
"UNIQUE KEY unique_purchase (charac_no, item_id, item_shop)" +
|
||||
") ENGINE=InnoDB DEFAULT CHARSET=utf8;";
|
||||
|
||||
// 执行SQL
|
||||
local SqlObj = MysqlPool.GetInstance().GetConnect();
|
||||
SqlObj.Exec_Sql(CreateSql1);
|
||||
SqlObj.Exec_Sql(CreateSql2);
|
||||
MysqlPool.GetInstance().PutConnect(SqlObj);
|
||||
}
|
||||
20
示例项目/NPC商店限购/NPC商店限购配置_Nangua.json
Normal file
20
示例项目/NPC商店限购/NPC商店限购配置_Nangua.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"提示1": "15代表商店NPC编号[道具ID,限购数量,每月一号刷新,周一刷新,每天上午六点刷新]",
|
||||
"提示2":"月周日在对应的位置填1代表生效如[2680313, 10, 0, 0, 1]代表道具ID为2680313的道具在15号商店限购10个,每天上午六点刷新",
|
||||
"提示3":"月周日在对应的位置填1代表生效如[2680313, 10, 0, 1, 0]代表道具ID为2680313的道具在15号商店限购10个,每周一上午六点刷新",
|
||||
"提示4":"月周日在对应的位置填1代表生效如[2680313, 10, 1, 0, 0]代表道具ID为2680313的道具在15号商店限购10个,每月一号上午六点刷新",
|
||||
"商店限购配置": {
|
||||
"15": [
|
||||
[2680313, 10, 0, 0, 1],
|
||||
[326211, 10, 0, 0, 1]
|
||||
],
|
||||
"16": [
|
||||
[2680314, 10, 0, 0, 1],
|
||||
[326211, 10, 0, 0, 1]
|
||||
]
|
||||
},
|
||||
"数据库IP 不是外置数据库不要更改": "127.0.0.1",
|
||||
"数据库端口 不懂不要更改": 3306,
|
||||
"数据库用户名 本地用户名不懂不要更改": "game",
|
||||
"数据库密码 本地密码不懂不要更改": "uu5!^%jg"
|
||||
}
|
||||
11
示例项目/NPC商店限购/Proj.ifo
Normal file
11
示例项目/NPC商店限购/Proj.ifo
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ProjectName": "NPC商店限购",
|
||||
"ProjectDescribe": "指定NPC商店的指定物品的可购买数量,可设为每日、每周一、每月1号的上午六点刷新",
|
||||
"ProjectAuthor": "南瓜",
|
||||
"ProjectVersion": 1.0,
|
||||
"ProjectConfig": "NPC商店限购配置_Nangua.json",
|
||||
"ProjectFiles": [
|
||||
"NPC商店限购.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_Dps_Shop_Limit_Main_"
|
||||
}
|
||||
11
示例项目/SP_TP属性石返还/Proj.ifo
Normal file
11
示例项目/SP_TP属性石返还/Proj.ifo
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ProjectName": "SP_TP属性石返还",
|
||||
"ProjectDescribe": "初始化以及转职时返还使用过的sp/tp以及属性石,不是直接返还属性石或者SP/TP书而是直接增加,使用此项目前增加的sp/tp属性石都不会返还,使用后才会增加记录从而进行返还",
|
||||
"ProjectAuthor": "小南瓜",
|
||||
"ProjectVersion": 1.2,
|
||||
"ProjectConfig": "SP_TP属性石返还_Nangua.json",
|
||||
"ProjectFiles": [
|
||||
"SP_TP属性石返还.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_Dps_SPTP_Attributes_Main_"
|
||||
}
|
||||
309
示例项目/SP_TP属性石返还/SP_TP属性石返还.nut
Normal file
309
示例项目/SP_TP属性石返还/SP_TP属性石返还.nut
Normal file
@@ -0,0 +1,309 @@
|
||||
// 创建数据库和表
|
||||
function createAttributesTable() {
|
||||
local Config = GlobalConfig.Get("SP_TP属性石返还_Nangua.json");
|
||||
local PoolObj = MysqlPool.GetInstance();
|
||||
local Ip = Config["数据库IP 不是外置数据库不要更改"];
|
||||
local Port = Config["数据库端口 不懂不要更改"];
|
||||
local DbName = Config["数据库用户名 本地用户名不懂不要更改"];
|
||||
local Password = Config["数据库密码 本地密码不懂不要更改"];
|
||||
|
||||
PoolObj.SetBaseConfiguration(Ip, Port, DbName, Password);
|
||||
PoolObj.PoolSize = 10;
|
||||
PoolObj.Init();
|
||||
|
||||
local CreateSql1 = "create database if not exists DP_S default charset utf8;";
|
||||
local CreateSql2 = "CREATE TABLE IF NOT EXISTS DP_S.charac_attributes (" +
|
||||
"id int(11) AUTO_INCREMENT, " +
|
||||
"charac_no int(11) NOT NULL, " +
|
||||
"item_id int(11) DEFAULT NULL, " +
|
||||
"type int(11) DEFAULT NULL, " +
|
||||
"guildExpBook int(11) DEFAULT NULL, " +
|
||||
"total_sp int(11) DEFAULT 0, " +
|
||||
"total_tp int(11) DEFAULT 0, " +
|
||||
"PRIMARY KEY (id), " +
|
||||
"UNIQUE KEY unique_char_item (charac_no, item_id)" +
|
||||
") ENGINE=InnoDB DEFAULT CHARSET=utf8;";
|
||||
|
||||
local SqlObj = MysqlPool.GetInstance().GetConnect();
|
||||
SqlObj.Exec_Sql(CreateSql1);
|
||||
SqlObj.Exec_Sql(CreateSql2);
|
||||
MysqlPool.GetInstance().PutConnect(SqlObj);
|
||||
}
|
||||
|
||||
// 初始化技能时返还SP/TP
|
||||
Cb_SkillInit_process_skill_Leave_Func.SkillInitByNangua <- function(args) {
|
||||
local SUser = User(args[1]);
|
||||
local Skill = SUser.GetSkillW();
|
||||
local charac_no = SUser.GetCID();
|
||||
|
||||
local SqlObj = MysqlPool.GetInstance().GetConnect();
|
||||
local query = "SELECT IFNULL(total_sp, 0) as total_sp, IFNULL(total_tp, 0) as total_tp " +
|
||||
"FROM DP_S.charac_attributes WHERE charac_no = " + charac_no + " AND item_id IS NULL";
|
||||
|
||||
local result = SqlObj.Select(query, ["int", "int"]);
|
||||
MysqlPool.GetInstance().PutConnect(SqlObj);
|
||||
|
||||
local total_sp = 0;
|
||||
local total_tp = 0;
|
||||
if (result.len() > 0) {
|
||||
total_sp = result[0][0];
|
||||
total_tp = result[0][1];
|
||||
}
|
||||
|
||||
local SkillTreeIndex = Sq_CallFunc(S_Ptr("0x0822f33c"), "int", ["pointer"], SUser.C_Object);
|
||||
local remain_sp_0 = Sq_CallFunc(S_Ptr("0x08603528"), "int", ["pointer", "int"], Skill, 0);
|
||||
local remain_sp_1 = Sq_CallFunc(S_Ptr("0x08603528"), "int", ["pointer", "int"], Skill, 1);
|
||||
local remain_tp_0 = Sq_CallFunc(S_Ptr("0x086035f2"), "int", ["pointer", "int"], Skill, 2);
|
||||
local remain_tp_1 = Sq_CallFunc(S_Ptr("0x086035f2"), "int", ["pointer", "int"], Skill, 3);
|
||||
|
||||
if (SkillTreeIndex == -1 || SkillTreeIndex == 0) {
|
||||
Sq_CallFunc(S_Ptr("0x086034f8"), "int", ["pointer", "int", "int"], Skill, remain_sp_0 + total_sp, 0);
|
||||
Sq_CallFunc(S_Ptr("0x08603590"), "int", ["pointer", "int", "int"], Skill, remain_tp_0 + total_tp, 2);
|
||||
}
|
||||
if (SkillTreeIndex == 1) {
|
||||
Sq_CallFunc(S_Ptr("0x086034f8"), "int", ["pointer", "int", "int"], Skill, remain_sp_1 + total_sp, 1);
|
||||
Sq_CallFunc(S_Ptr("0x08603590"), "int", ["pointer", "int", "int"], Skill, remain_tp_1 + total_tp, 3);
|
||||
}
|
||||
}
|
||||
|
||||
// 转职时返还SP/TP和属性石
|
||||
Cb_User_set_grow_Leave_Func.changegrowByNangua <- function(args) {
|
||||
local SUser = User(args[0]);
|
||||
local grow = args[2];
|
||||
local charac_no = SUser.GetCID();
|
||||
local Skill = SUser.GetSkillW();
|
||||
|
||||
local SqlObj = MysqlPool.GetInstance().GetConnect();
|
||||
|
||||
// 查询SP/TP
|
||||
local querySpTp = "SELECT IFNULL(total_sp, 0) as total_sp, IFNULL(total_tp, 0) as total_tp " +
|
||||
"FROM DP_S.charac_attributes WHERE charac_no = " + charac_no + " AND item_id IS NULL";
|
||||
local spTpResult = SqlObj.Select(querySpTp, ["int", "int"]);
|
||||
|
||||
local total_sp = 0;
|
||||
local total_tp = 0;
|
||||
if (spTpResult.len() > 0) {
|
||||
total_sp = spTpResult[0][0];
|
||||
total_tp = spTpResult[0][1];
|
||||
}
|
||||
|
||||
// 根据转职类型决定是否查询属性石
|
||||
local attrResult = [];
|
||||
if (grow == 0) {
|
||||
local queryAttr = "SELECT type, guildExpBook FROM DP_S.charac_attributes " +
|
||||
"WHERE charac_no = " + charac_no + " AND item_id IS NOT NULL";
|
||||
attrResult = SqlObj.Select(queryAttr, ["int", "int"]);
|
||||
}
|
||||
|
||||
MysqlPool.GetInstance().PutConnect(SqlObj);
|
||||
|
||||
// 处理SP/TP
|
||||
local SkillTreeIndex = Sq_CallFunc(S_Ptr("0x0822f33c"), "int", ["pointer"], SUser.C_Object);
|
||||
local remain_sp_0 = Sq_CallFunc(S_Ptr("0x08603528"), "int", ["pointer", "int"], Skill, 0);
|
||||
local remain_sp_1 = Sq_CallFunc(S_Ptr("0x08603528"), "int", ["pointer", "int"], Skill, 1);
|
||||
local remain_tp_0 = Sq_CallFunc(S_Ptr("0x086035f2"), "int", ["pointer", "int"], Skill, 2);
|
||||
local remain_tp_1 = Sq_CallFunc(S_Ptr("0x086035f2"), "int", ["pointer", "int"], Skill, 3);
|
||||
|
||||
if (SkillTreeIndex == -1) {
|
||||
Sq_CallFunc(S_Ptr("0x086034f8"), "int", ["pointer", "int", "int"], Skill, remain_sp_0 + total_sp, 0);
|
||||
Sq_CallFunc(S_Ptr("0x08603590"), "int", ["pointer", "int", "int"], Skill, remain_tp_0 + total_tp, 2);
|
||||
Sq_CallFunc(S_Ptr("0x866C46A"), "void", ["pointer"], SUser.C_Object);
|
||||
}
|
||||
if (SkillTreeIndex == 0 || SkillTreeIndex == 1) {
|
||||
Sq_CallFunc(S_Ptr("0x086034f8"), "int", ["pointer", "int", "int"], Skill, remain_sp_0 + total_sp, 0);
|
||||
Sq_CallFunc(S_Ptr("0x086034f8"), "int", ["pointer", "int", "int"], Skill, remain_sp_1 + total_sp, 1);
|
||||
Sq_CallFunc(S_Ptr("0x08603590"), "int", ["pointer", "int", "int"], Skill, remain_tp_0 + total_tp, 2);
|
||||
Sq_CallFunc(S_Ptr("0x08603590"), "int", ["pointer", "int", "int"], Skill, remain_tp_1 + total_tp, 3);
|
||||
Sq_CallFunc(S_Ptr("0x866C46A"), "void", ["pointer"], SUser.C_Object);
|
||||
}
|
||||
|
||||
// 处理属性石(仅当 grow == 0 时)
|
||||
if (grow == 0 && attrResult.len() > 0) {
|
||||
local userAddInfo = Sq_CallFunc(S_Ptr("0x086960d8"), "pointer", ["pointer"], SUser.C_Object);
|
||||
|
||||
foreach (idx, row in attrResult) {
|
||||
local type = row[0];
|
||||
local guildExpBook = row[1];
|
||||
|
||||
switch (type) {
|
||||
case 2:
|
||||
NativePointer(userAddInfo).writeU32(NativePointer(userAddInfo).readU32() + guildExpBook);
|
||||
break;
|
||||
case 3:
|
||||
NativePointer(userAddInfo).add(4).writeU32(NativePointer(userAddInfo).add(4).readU32() + guildExpBook);
|
||||
break;
|
||||
case 4:
|
||||
NativePointer(userAddInfo).add(8).writeU16(NativePointer(userAddInfo).add(8).readU16() + guildExpBook);
|
||||
break;
|
||||
case 5:
|
||||
NativePointer(userAddInfo).add(10).writeU16(NativePointer(userAddInfo).add(10).readU16() + guildExpBook);
|
||||
break;
|
||||
case 6:
|
||||
NativePointer(userAddInfo).add(12).writeU16(NativePointer(userAddInfo).add(12).readU16() + guildExpBook);
|
||||
break;
|
||||
case 7:
|
||||
NativePointer(userAddInfo).add(14).writeU16(NativePointer(userAddInfo).add(14).readU16() + guildExpBook);
|
||||
break;
|
||||
case 8:
|
||||
NativePointer(userAddInfo).add(66).writeU32(NativePointer(userAddInfo).add(66).readU32() + guildExpBook);
|
||||
break;
|
||||
case 9:
|
||||
for (local j = 0; j < 4; j++) {
|
||||
local offset = 2 * j * 8;
|
||||
local ptr = NativePointer(userAddInfo).add(offset);
|
||||
ptr.writeU16(ptr.readU16() + guildExpBook);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
api_recover_attributes(SUser, type, guildExpBook, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 使用道具时更新数据库
|
||||
Cb_User_increase_status_Enter_Func.UseItemByNangua <- function(args) {
|
||||
local SUser = User(args[0]);
|
||||
local Slot = args[1];
|
||||
local userItem = Memory.alloc(128);
|
||||
local InvenObj = SUser.GetInven();
|
||||
if (!InvenObj) {
|
||||
return;
|
||||
}
|
||||
|
||||
Sq_CallFunc(S_Ptr("0x084fb918"), "pointer", ["pointer", "pointer", "int", "int"], userItem.C_Object, InvenObj.C_Object, 1, Slot);
|
||||
local item_id = NativePointer(userItem.C_Object).add(2).readU32();
|
||||
local charac_no = SUser.GetCID();
|
||||
|
||||
local SqlObj = MysqlPool.GetInstance().GetConnect();
|
||||
|
||||
// SP道具
|
||||
if (item_id == 1031) {
|
||||
updateSPTP(SqlObj, charac_no, 5, false);
|
||||
} else if (item_id == 1038) {
|
||||
updateSPTP(SqlObj, charac_no, 20, false);
|
||||
}
|
||||
// TP道具
|
||||
else if (item_id == 1204) {
|
||||
updateSPTP(SqlObj, charac_no, 1, true);
|
||||
} else if (item_id == 1205) {
|
||||
updateSPTP(SqlObj, charac_no, 5, true);
|
||||
}
|
||||
// 属性石
|
||||
else {
|
||||
local type = -1;
|
||||
local guildExpBook = 0;
|
||||
|
||||
switch (item_id) {
|
||||
case 1039: type = 4; guildExpBook = 50; break;
|
||||
case 1040: type = 6; guildExpBook = 50; break;
|
||||
case 1041: type = 5; guildExpBook = 50; break;
|
||||
case 1042: type = 7; guildExpBook = 50; break;
|
||||
case 1043: type = 2; guildExpBook = 250; break;
|
||||
case 1044: type = 3; guildExpBook = 250; break;
|
||||
case 1045: type = 8; guildExpBook = 10; break;
|
||||
case 1046: type = 9; guildExpBook = 10; break;
|
||||
}
|
||||
|
||||
if (type != -1) {
|
||||
local query = "INSERT INTO DP_S.charac_attributes (charac_no, item_id, type, guildExpBook) " +
|
||||
"VALUES (" + charac_no + ", " + item_id + ", " + type + ", " + guildExpBook + ") " +
|
||||
"ON DUPLICATE KEY UPDATE guildExpBook = guildExpBook + " + guildExpBook;
|
||||
SqlObj.Select(query, []);
|
||||
}
|
||||
}
|
||||
|
||||
MysqlPool.GetInstance().PutConnect(SqlObj);
|
||||
}
|
||||
|
||||
Cb_ChangeGrowType_Item_Leave_Func.ApplyAttributesByNangua <- function(args) {
|
||||
local SUser = User(args[0]);
|
||||
local slot = args[2];
|
||||
local charac_no = SUser.GetCID();
|
||||
|
||||
local userItem = Memory.alloc(128);
|
||||
local InvenObj = SUser.GetInven();
|
||||
if (!InvenObj) return;
|
||||
|
||||
Sq_CallFunc(S_Ptr("0x084fb918"), "pointer", ["pointer", "pointer", "int", "int"], userItem.C_Object, InvenObj.C_Object, 1, slot);
|
||||
local item_id = NativePointer(userItem.C_Object).add(2).readU32();
|
||||
if (!(item_id == 2660779 || item_id == 2660702)) return;
|
||||
|
||||
local SqlObj = MysqlPool.GetInstance().GetConnect();
|
||||
local query = "SELECT type, guildExpBook FROM DP_S.charac_attributes " +
|
||||
"WHERE charac_no = " + charac_no + " AND item_id IS NOT NULL";
|
||||
local attrResult = SqlObj.Select(query, ["int", "int"]);
|
||||
MysqlPool.GetInstance().PutConnect(SqlObj);
|
||||
|
||||
if (attrResult.len() == 0) return;
|
||||
|
||||
local userAddInfo = Sq_CallFunc(S_Ptr("0x086960d8"), "pointer", ["pointer"], SUser.C_Object);
|
||||
|
||||
foreach (row in attrResult) {
|
||||
local type = row[0];
|
||||
local guildExpBook = row[1];
|
||||
|
||||
switch (type) {
|
||||
case 2: NativePointer(userAddInfo).writeU32(NativePointer(userAddInfo).readU32() + guildExpBook); break;
|
||||
case 3: NativePointer(userAddInfo).add(4).writeU32(NativePointer(userAddInfo).add(4).readU32() + guildExpBook); break;
|
||||
case 4: NativePointer(userAddInfo).add(8).writeU16(NativePointer(userAddInfo).add(8).readU16() + guildExpBook); break;
|
||||
case 5: NativePointer(userAddInfo).add(10).writeU16(NativePointer(userAddInfo).add(10).readU16() + guildExpBook); break;
|
||||
case 6: NativePointer(userAddInfo).add(12).writeU16(NativePointer(userAddInfo).add(12).readU16() + guildExpBook); break;
|
||||
case 7: NativePointer(userAddInfo).add(14).writeU16(NativePointer(userAddInfo).add(14).readU16() + guildExpBook); break;
|
||||
case 8: NativePointer(userAddInfo).add(66).writeU32(NativePointer(userAddInfo).add(66).readU32() + guildExpBook); break;
|
||||
case 9:
|
||||
for (local j = 0; j < 4; j++) {
|
||||
local ptr = NativePointer(userAddInfo).add(2 * j * 8);
|
||||
ptr.writeU16(ptr.readU16() + guildExpBook);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
api_recover_attributes(SUser, type, guildExpBook, -1);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新SP/TP值
|
||||
function updateSPTP(SqlObj, charac_no, value, is_tp) {
|
||||
local query = "SELECT id, total_sp, total_tp FROM DP_S.charac_attributes " +
|
||||
"WHERE charac_no = " + charac_no + " AND item_id IS NULL";
|
||||
local result = SqlObj.Select(query, ["int", "int", "int"]);
|
||||
|
||||
if (result.len() > 0) {
|
||||
local current_sp = result[0][1];
|
||||
local current_tp = result[0][2];
|
||||
local new_sp = is_tp ? current_sp : (current_sp + value);
|
||||
local new_tp = is_tp ? (current_tp + value) : current_tp;
|
||||
|
||||
query = "UPDATE DP_S.charac_attributes " +
|
||||
"SET total_sp = " + new_sp + ", total_tp = " + new_tp + " " +
|
||||
"WHERE charac_no = " + charac_no + " AND item_id IS NULL";
|
||||
} else {
|
||||
query = "INSERT INTO DP_S.charac_attributes (charac_no, total_sp, total_tp) " +
|
||||
"VALUES (" + charac_no + ", " +
|
||||
(is_tp ? "0" : value.tostring()) + ", " +
|
||||
(is_tp ? value.tostring() : "0") + ")";
|
||||
}
|
||||
|
||||
SqlObj.Select(query, []);
|
||||
}
|
||||
|
||||
// 发包更新增加玩家属性
|
||||
function api_recover_attributes(SUser, type, guildExpBook, slof) {
|
||||
local Pack = Packet();
|
||||
Pack.Put_Header(1, 32);
|
||||
Pack.Put_Byte(1);
|
||||
Pack.Put_Short(slof);
|
||||
Pack.Put_Byte(type);
|
||||
Pack.Put_Int(guildExpBook);
|
||||
Pack.Put_Short(0);
|
||||
Pack.Put_Short(0);
|
||||
Pack.Finalize(true);
|
||||
SUser.Send(Pack);
|
||||
Pack.Delete();
|
||||
}
|
||||
|
||||
// 主函数
|
||||
function _Dps_SPTP_Attributes_Main_() {
|
||||
createAttributesTable();
|
||||
}
|
||||
7
示例项目/SP_TP属性石返还/SP_TP属性石返还_Nangua.json
Normal file
7
示例项目/SP_TP属性石返还/SP_TP属性石返还_Nangua.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"提示":"挂载后只有新使用的sp,tp,属性石会返还,之前使用过的不会返还",
|
||||
"数据库IP 不是外置数据库不要更改": "127.0.0.1",
|
||||
"数据库端口 不懂不要更改": 3306,
|
||||
"数据库用户名 本地用户名不懂不要更改": "game",
|
||||
"数据库密码 本地密码不懂不要更改": "uu5!^%jg"
|
||||
}
|
||||
11
示例项目/一键分解卷/Proj.ifo
Normal file
11
示例项目/一键分解卷/Proj.ifo
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ProjectName": "一键分解卷",
|
||||
"ProjectDescribe": "使用道具将需要分解的装备分解,如未开启副职业及开启摆摊分解则调用诺顿分解机分解",
|
||||
"ProjectAuthor": "南瓜",
|
||||
"ProjectVersion": 1.3,
|
||||
"ProjectConfig": "一键分解卷_Lenheart.json",
|
||||
"ProjectFiles": [
|
||||
"一键分解卷.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_Dps_OneClickDisassemblyOfRoll_Main_"
|
||||
}
|
||||
92
示例项目/一键分解卷/一键分解卷.nut
Normal file
92
示例项目/一键分解卷/一键分解卷.nut
Normal file
@@ -0,0 +1,92 @@
|
||||
function _Dps_OneClickDisassemblyOfRoll_Logic_() {
|
||||
local Config = GlobalConfig.Get("一键分解卷_Lenheart.json");
|
||||
//分解券
|
||||
Cb_Use_Item_Sp_Func[Config["分解卷的道具ID"]] <- function(SUser, ItemId) {
|
||||
local index = 0;
|
||||
local InvenObj = SUser.GetInven();
|
||||
if (InvenObj) {
|
||||
for (local i = Config["一键分解的起始位置_就是背包从第几格开始"]; i <= Config["一键分解的结束位置_就是背包到第几格结束"]; i++) { // 遍历9到16号背包格子
|
||||
local ItemObj = InvenObj.GetSlot(1, i);
|
||||
if (!ItemObj.IsEmpty) {
|
||||
local item_id = ItemObj.GetIndex(); // 获取物品ID
|
||||
local PvfItemObj = PvfItem.GetPvfItemById(item_id);
|
||||
local CItem_get_rarity = PvfItemObj.GetRarity(); // 装备品级
|
||||
local item_upgrade = ItemObj.GetUpgrade();
|
||||
local item_name = PvfItem.GetNameById(item_id);
|
||||
if (CItem_get_rarity <= Config["分解品级(含)"]) { // 粉装及以下品级装备
|
||||
|
||||
// 检查副职业是否开启
|
||||
local checkTag = Sq_CallFunc(S_Ptr("0x822f8d4"), "int", ["pointer"], SUser.C_Object);
|
||||
local is = SUser.GetCurCharacExpertJob();
|
||||
if (!is) {
|
||||
// 如果副职业未开启则调用诺顿分解机
|
||||
SUser.DisPatcher_DisJointItem_disjoint(i, 28, S_Ptr("0x0"));
|
||||
} else {
|
||||
// 如果副职业已开启则调用自身分解机
|
||||
SUser.DisPatcher_DisJointItem_disjoint(i, 239, SUser.C_Object);
|
||||
}
|
||||
if (item_upgrade > 0) {
|
||||
item_name = "+" + item_upgrade + item_name;
|
||||
}
|
||||
local newItemObj = InvenObj.GetSlot(1, i);
|
||||
if (newItemObj.IsEmpty) { // 如果分解成功
|
||||
index++;
|
||||
SUser.SendUpdateItemList(1, 0, i);
|
||||
local AdMsgObj = AdMsg();
|
||||
AdMsgObj.PutType(Config["分解成功提示发送位置"]);
|
||||
if (Config["分解成功提示发送位置"] != 14) {
|
||||
AdMsgObj.PutString(" ");
|
||||
}
|
||||
AdMsgObj.PutString(" 成功分解装备");
|
||||
AdMsgObj.PutEquipment("[" + item_name + "]", ItemObj, DisJointItemBynangua.RarityColor(item_id));
|
||||
AdMsgObj.Finalize();
|
||||
SUser.Send(AdMsgObj.MakePack());
|
||||
AdMsgObj.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (index > 0) {
|
||||
SUser.SendNotiPacketMessage("恭喜: " + index + " 件装备分解成功。", 8);
|
||||
} else {
|
||||
SUser.SendNotiPacketMessage("装备分解失败,道具已返还", 8);
|
||||
}
|
||||
if (Config["是否返还分解券道具(true代表返还,false代表不返还)"]) {
|
||||
Timer.setTimeout(function() {
|
||||
SUser.GiveItem(ItemId, 1);
|
||||
}, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class DisJointItemBynangua {
|
||||
function RarityColor(item_id) {
|
||||
local PvfItemObj = PvfItem.GetPvfItemById(item_id);
|
||||
if (PvfItemObj == null) {
|
||||
return;
|
||||
}
|
||||
local CItem_get_rarity = PvfItemObj.GetRarity(); // 装备品级
|
||||
return DisJointItemBynangua.rarityColorMap[(CItem_get_rarity).tostring()];
|
||||
}
|
||||
rarityColorMap = {
|
||||
"0": [255, 255, 255], // 普通
|
||||
"1": [104, 213, 237], // 高级
|
||||
"2": [179, 107, 255], // 稀有
|
||||
"3": [255, 0, 255], // 神器
|
||||
"4": [255, 180, 0], // 史诗
|
||||
"5": [255, 102, 102], // 勇者
|
||||
"6": [255, 20, 147], // 深粉红色
|
||||
"7": [255, 215, 0] // 金色
|
||||
};
|
||||
}
|
||||
|
||||
function _Dps_OneClickDisassemblyOfRoll_Main_() {
|
||||
_Dps_OneClickDisassemblyOfRoll_Logic_();
|
||||
}
|
||||
|
||||
function _Dps_OneClickDisassemblyOfRoll_Main_Reload_(OldConfig) {
|
||||
Cb_Use_Item_Sp_Func.rawdelete(OldConfig["分解卷的道具ID"]);
|
||||
_Dps_OneClickDisassemblyOfRoll_Logic_();
|
||||
}
|
||||
9
示例项目/一键分解卷/一键分解卷_Lenheart.json
Normal file
9
示例项目/一键分解卷/一键分解卷_Lenheart.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"分解卷的道具ID": 7577,
|
||||
"是否返还分解券道具(true代表返还,false代表不返还)": true,
|
||||
"一键分解的起始位置_就是背包从第几格开始": 9,
|
||||
"一键分解的结束位置_就是背包到第几格结束": 16,
|
||||
"分解品级(含)": 4,
|
||||
"分解成功提示发送位置": 3,
|
||||
"提示":"起始位置快捷栏(快捷栏3-8),装备栏(快捷栏9-56,如第一排为9-16,第二排为17-24,第三排为25-32,第四排为33-40,第五排为41-48,第六排为49-56)"
|
||||
}
|
||||
11
示例项目/一键存入个人金库/Proj.ifo
Normal file
11
示例项目/一键存入个人金库/Proj.ifo
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ProjectName": "一键存入个人金库",
|
||||
"ProjectDescribe": "使用之前,请务必保证安装了群内的 \"客户端消息框233.dll\" 插件,这个插件放入你客户端的插件加载目录即可,在游戏中输入 //yjcc 即可一键存入个人金库,也可以在游戏中的快捷喊话中添加为快捷键 配置中可更改 yjcc 关键字",
|
||||
"ProjectAuthor": "倾泪寒 & 南瓜",
|
||||
"ProjectVersion": 1.3,
|
||||
"ProjectConfig": "一键存入个人金库_Lenheart.json",
|
||||
"ProjectFiles": [
|
||||
"一键入库.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_Dps_OneClickStorage_Main_"
|
||||
}
|
||||
116
示例项目/一键存入个人金库/一键入库.nut
Normal file
116
示例项目/一键存入个人金库/一键入库.nut
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
文件名:一键入库.nut
|
||||
路径:MyProject/一键入库.nut
|
||||
创建日期:2025-03-25 14:42
|
||||
文件用途:一键入库
|
||||
*/
|
||||
|
||||
function _Dps_OneClickStorage_Logic_() {
|
||||
local Config = GlobalConfig.Get("一键存入个人金库_Lenheart.json");
|
||||
//在游戏中输入//一键入库即可调用
|
||||
Gm_InputFunc_Handle[Config["一键存仓命令"]] <- function(SUser, Cmd) {
|
||||
// 获取角色背包
|
||||
local InvenObj = SUser.GetInven();
|
||||
// 角色仓库
|
||||
local CargoObj = Sq_CallFunc(S_Ptr("0x08151a94"), "pointer", ["pointer"], SUser.C_Object);
|
||||
// 添加计数器
|
||||
local transferCount = 0;
|
||||
// 遍历背包消耗品栏及材料栏
|
||||
for (local i = 57; i <= 152; ++i) {
|
||||
// 获取背包物品
|
||||
local ItemObj = InvenObj.GetSlot(1, i);
|
||||
// 获取背包物品ID
|
||||
local Item_Id = ItemObj.GetIndex();
|
||||
local ItemName = PvfItem.GetNameById(Item_Id);
|
||||
// 如果物品ID为0或3037,跳过(在此可以添加其他需要跳过的物品ID)
|
||||
if (Item_Id == 0 || Config["指定道具ID不存入"].find(Item_Id) != null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 角色仓库是否存在背包物品
|
||||
local CargoSlot = Sq_CallFunc(S_Ptr("0x850bc14"), "int", ["pointer", "int"], CargoObj, Item_Id);
|
||||
// 如果角色仓库中没有该物品,跳过
|
||||
if (CargoSlot == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 获取仓库物品指针
|
||||
local cargoItemPointer = NativePointer(CargoObj).add(4).readPointer();
|
||||
// 获取角色仓库物品对象
|
||||
local cargoItemObj = NativePointer(cargoItemPointer).add(61 * CargoSlot);
|
||||
// 获取角色仓库物品ID
|
||||
local cargoItemId = NativePointer(cargoItemPointer).add(61 * CargoSlot + 2).readU32();
|
||||
// 获取角色仓库物品数量
|
||||
local cargoItemCount = Sq_CallFunc(S_Ptr("0x80F783A"), "int", ["pointer"], cargoItemObj.C_Object);
|
||||
|
||||
// 获取物品对象
|
||||
local PvfItem = PvfItem.GetPvfItemById(cargoItemId);
|
||||
|
||||
// 获取物品可堆叠数量
|
||||
local getStackableLimit = Sq_CallFunc(S_Ptr("0x0822C9FC"), "int", ["pointer"], PvfItem.C_Object);
|
||||
|
||||
// 如果仓库已达堆叠上限,跳过此物品
|
||||
if (cargoItemCount >= getStackableLimit) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 获取背包物品数量
|
||||
local inventoryItemCount = Sq_CallFunc(S_Ptr("0x80F783A"), "int", ["pointer"], ItemObj.C_Object);
|
||||
// 获取物品是否可堆叠
|
||||
local checkStackableLimit = Sq_CallFunc(S_Ptr("0x08501A79"), "int", ["int", "int"], cargoItemId, cargoItemCount + inventoryItemCount);
|
||||
// 尝试将物品储存至角色仓库中
|
||||
local tryAddStackItem = Sq_CallFunc(S_Ptr("0x0850B4B0"), "int", ["pointer", "pointer", "int"], CargoObj, ItemObj.C_Object, CargoSlot);
|
||||
if (tryAddStackItem >= 0) {
|
||||
// 正式将物品插入角色仓库中
|
||||
Sq_CallFunc(S_Ptr("0x850b672"), "pointer", ["pointer", "pointer", "int"], CargoObj, ItemObj.C_Object, CargoSlot);
|
||||
// 删除背包中的物品
|
||||
ItemObj.Delete();
|
||||
transferCount++;
|
||||
SUser.SendNotiPacketMessage("[ " + ItemName + " ]" + "成功入库 x " + inventoryItemCount, 8);
|
||||
}
|
||||
|
||||
// 处理可堆叠物品
|
||||
if (checkStackableLimit == 0) {
|
||||
// 获取物品总数
|
||||
local totalCount = cargoItemCount + inventoryItemCount;
|
||||
|
||||
// 如果总数不超过上限,全部堆到仓库
|
||||
if (totalCount <= getStackableLimit) {
|
||||
// 将物品堆到仓库
|
||||
Sq_CallFunc(S_Ptr("0x80CB884"), "int", ["pointer", "int"], cargoItemObj.C_Object, totalCount);
|
||||
// 删除背包中的物品
|
||||
ItemObj.Delete();
|
||||
transferCount++;
|
||||
SUser.SendNotiPacketMessage("[ " + ItemName + " ]" + "成功入库 x " + inventoryItemCount, 8);
|
||||
} else {
|
||||
// 如果总数超过上限
|
||||
// 将仓库的物品数量设置为最大数量
|
||||
Sq_CallFunc(S_Ptr("0x80CB884"), "int", ["pointer", "int"], cargoItemObj.C_Object, getStackableLimit);
|
||||
// 将背包数量减去转移至仓库的数量
|
||||
local transferAmount = getStackableLimit - cargoItemCount;
|
||||
Sq_CallFunc(S_Ptr("0x80CB884"), "int", ["pointer", "int"], ItemObj.C_Object, totalCount - getStackableLimit);
|
||||
transferCount++;
|
||||
SUser.SendNotiPacketMessage("[ " + ItemName + " ]" + "成功入库 x " + transferAmount, 8);
|
||||
}
|
||||
}
|
||||
|
||||
// 通知客户端更新背包
|
||||
SUser.SendUpdateItemList(1, 0, i);
|
||||
}
|
||||
|
||||
if (transferCount == 0) {
|
||||
SUser.SendNotiBox("没有可转移的物品!", 1);
|
||||
}
|
||||
// 通知客户端更新仓库
|
||||
SUser.SendItemSpace(2);
|
||||
}
|
||||
}
|
||||
//启动函数 自定义的需要写在ifo中
|
||||
function _Dps_OneClickStorage_Main_() {
|
||||
_Dps_OneClickStorage_Logic_();
|
||||
}
|
||||
|
||||
function _Dps_OneClickStorage_Main_Reload(OldConfig) {
|
||||
Gm_InputFunc_Handle.rawdelete(OldConfig["一键存仓命令"]);
|
||||
_Dps_OneClickStorage_Logic_();
|
||||
}
|
||||
4
示例项目/一键存入个人金库/一键存入个人金库_Lenheart.json
Normal file
4
示例项目/一键存入个人金库/一键存入个人金库_Lenheart.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"一键存仓命令": "yjcc",
|
||||
"指定道具ID不存入": [3037, 3038]
|
||||
}
|
||||
11
示例项目/上线自动完成任务/Proj.ifo
Normal file
11
示例项目/上线自动完成任务/Proj.ifo
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ProjectName": "上线自动完成任务",
|
||||
"ProjectDescribe": "上线自动完成任务",
|
||||
"ProjectAuthor": "倾泪寒",
|
||||
"ProjectVersion": 1.0,
|
||||
"ProjectConfig": "上线自动完成任务_Lenheart.json",
|
||||
"ProjectFiles": [
|
||||
"上线自动完成任务.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_Dps_AutomaticallyCompleteTasksOnline_Main_"
|
||||
}
|
||||
9
示例项目/上线自动完成任务/上线自动完成任务.nut
Normal file
9
示例项目/上线自动完成任务/上线自动完成任务.nut
Normal file
@@ -0,0 +1,9 @@
|
||||
function _Dps_AutomaticallyCompleteTasksOnline_Main_() {
|
||||
Cb_History_MileageSet_Func["_DPS_上线自动完成任务_"] <- function(SUser, Data) {
|
||||
local Config = GlobalConfig.Get("上线自动完成任务_Lenheart.json");
|
||||
local QuestArr = Config["需要完成的任务编号"];
|
||||
foreach(QuestId in QuestArr) {
|
||||
SUser.ClearQuest_Gm(QuestId);
|
||||
}
|
||||
}
|
||||
}
|
||||
4
示例项目/上线自动完成任务/上线自动完成任务_Lenheart.json
Normal file
4
示例项目/上线自动完成任务/上线自动完成任务_Lenheart.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"需要完成的任务编号" : [674,649,675,650],
|
||||
"注意事项": "请确保你的任务需求等级是1级,否则可能无法完成。请在PVF中更改任务需要的等级。"
|
||||
}
|
||||
11
示例项目/交易邮件播报/Proj.ifo
Normal file
11
示例项目/交易邮件播报/Proj.ifo
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ProjectName": "交易邮件播报",
|
||||
"ProjectDescribe": "交易邮件播报",
|
||||
"ProjectAuthor": "巅峰 & 倾泪寒",
|
||||
"ProjectVersion": 1.2,
|
||||
"ProjectConfig": "交易邮件播报.json",
|
||||
"ProjectFiles": [
|
||||
"交易邮件播报.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_Dps_JYYJBB_Main_"
|
||||
}
|
||||
4
示例项目/交易邮件播报/交易邮件播报.json
Normal file
4
示例项目/交易邮件播报/交易邮件播报.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
|
||||
"提示": "暂时没写配置"
|
||||
}
|
||||
126
示例项目/交易邮件播报/交易邮件播报.nut
Normal file
126
示例项目/交易邮件播报/交易邮件播报.nut
Normal file
@@ -0,0 +1,126 @@
|
||||
function _Dps_JYYJBB_Main_() {
|
||||
|
||||
Cb_History_ItemUp_Func["交易邮件播报"] <- function(SUser, args) {
|
||||
local reason = args[18];
|
||||
if (reason == "1") {
|
||||
local pvfitem = PvfItem.GetNameById(args[15].tointeger());
|
||||
local LoginMsgObj = AdMsg();
|
||||
LoginMsgObj.PutType(14);
|
||||
LoginMsgObj.PutColorString("玩家[", [255, 255, 0]);
|
||||
LoginMsgObj.PutColorString(SUser.GetCharacName(), [255, 0, 0]);
|
||||
LoginMsgObj.PutColorString("]", [255, 255, 0]);
|
||||
LoginMsgObj.PutColorString("获得", [255, 255, 0]);
|
||||
LoginMsgObj.PutColorString("[" + args[20] + "]", [255, 255, 0]);
|
||||
LoginMsgObj.PutColorString("交易的道具", [255, 255, 0]);
|
||||
LoginMsgObj.PutColorString(pvfitem, [255, 255, 0]);
|
||||
LoginMsgObj.PutColorString(args[17] + "个", [255, 255, 0]);
|
||||
LoginMsgObj.Finalize();
|
||||
World.SendAll(LoginMsgObj.MakePack());
|
||||
LoginMsgObj.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Cb_History_MoneyUp_Func["交易邮件播报"] <- function(SUser, args) {
|
||||
local reason = args[16];
|
||||
if (reason == "1") {
|
||||
local LoginMsgObj = AdMsg();
|
||||
LoginMsgObj.PutType(14);
|
||||
LoginMsgObj.PutColorString("玩家[", [255, 255, 0]);
|
||||
LoginMsgObj.PutColorString(SUser.GetCharacName(), [255, 0, 0]);
|
||||
LoginMsgObj.PutColorString("]", [255, 255, 0]);
|
||||
LoginMsgObj.PutColorString("获得", [255, 255, 0]);
|
||||
LoginMsgObj.PutColorString("[" + getFirstBracketContent(args[17]) + "]", [255, 255, 0]);
|
||||
LoginMsgObj.PutColorString("交易的", [255, 255, 0]);
|
||||
LoginMsgObj.PutColorString(args[15], [255, 255, 0]);
|
||||
LoginMsgObj.PutColorString("金币", [255, 255, 0]);
|
||||
LoginMsgObj.Finalize();
|
||||
World.SendAll(LoginMsgObj.MakePack());
|
||||
LoginMsgObj.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
Cb_MailBox11_Send_Leave_Func["交易邮件播报"] <- function(args) {
|
||||
local jewelSocketID = NativePointer(args[0]).readPointer();
|
||||
local SUser = User(jewelSocketID);
|
||||
local name = SUser.GetCharacName();
|
||||
local receive_name = NativePointer(args[1]).add(17).readUtf8String();
|
||||
local send_gold_count = NativePointer(args[1]).add(46).readU32();
|
||||
local send_item_id = NativePointer(args[1]).add(57).readU32();
|
||||
local send_item_count = NativePointer(args[1]).add(61).readU32(); //发送道具数量
|
||||
local item_name;
|
||||
if (send_item_id > 0) {
|
||||
item_name = PvfItem.GetNameById(send_item_id);
|
||||
}
|
||||
// 发送世界公告播报
|
||||
if (send_gold_count > 0 && send_item_id > 0) {
|
||||
local LoginMsgObj = AdMsg();
|
||||
LoginMsgObj.PutType(14);
|
||||
LoginMsgObj.PutColorString("玩家[", [255, 255, 0]);
|
||||
LoginMsgObj.PutColorString(SUser.GetCharacName(), [0, 255, 0]);
|
||||
LoginMsgObj.PutColorString("]", [255, 255, 0]);
|
||||
LoginMsgObj.PutColorString("刚刚通过邮件向", [255, 255, 0]);
|
||||
LoginMsgObj.PutColorString("[" + receive_name + "]", [0, 255, 0]);
|
||||
LoginMsgObj.PutColorString("发送了", [255, 255, 0]);
|
||||
LoginMsgObj.PutColorString("金币*" + send_gold_count, [255, 170, 0]);
|
||||
LoginMsgObj.PutColorString("和", [255, 255, 0]);
|
||||
LoginMsgObj.PutColorString(send_item_count + "个", [255, 255, 0]);
|
||||
LoginMsgObj.PutColorString(item_name, [255, 255, 0]);
|
||||
LoginMsgObj.Finalize();
|
||||
World.SendAll(LoginMsgObj.MakePack());
|
||||
LoginMsgObj.Delete();
|
||||
} else if (send_gold_count > 0) {
|
||||
local LoginMsgObj = AdMsg();
|
||||
LoginMsgObj.PutType(14);
|
||||
LoginMsgObj.PutColorString("玩家[", [255, 255, 0]);
|
||||
LoginMsgObj.PutColorString(SUser.GetCharacName(), [0, 255, 0]);
|
||||
LoginMsgObj.PutColorString("]", [255, 255, 0]);
|
||||
LoginMsgObj.PutColorString("刚刚通过邮件向", [255, 255, 0]);
|
||||
LoginMsgObj.PutColorString("[" + receive_name + "]", [0, 255, 0]);
|
||||
LoginMsgObj.PutColorString("发送了", [255, 255, 0]);
|
||||
LoginMsgObj.PutColorString("金币*" + send_gold_count, [255, 170, 0]);
|
||||
LoginMsgObj.Finalize();
|
||||
World.SendAll(LoginMsgObj.MakePack());
|
||||
LoginMsgObj.Delete();
|
||||
} else if (send_item_id > 0) {
|
||||
local LoginMsgObj = AdMsg();
|
||||
LoginMsgObj.PutType(14);
|
||||
LoginMsgObj.PutColorString("玩家[", [255, 255, 0]);
|
||||
LoginMsgObj.PutColorString(SUser.GetCharacName(), [0, 255, 0]);
|
||||
LoginMsgObj.PutColorString("]", [255, 255, 0]);
|
||||
LoginMsgObj.PutColorString("刚刚通过邮件向", [255, 255, 0]);
|
||||
LoginMsgObj.PutColorString("[" + receive_name + "]", [0, 255, 0]);
|
||||
LoginMsgObj.PutColorString("发送了", [255, 255, 0]);
|
||||
LoginMsgObj.PutColorString(send_item_count + "个", [255, 255, 0]);
|
||||
LoginMsgObj.PutColorString(item_name, [255, 255, 0]);
|
||||
LoginMsgObj.Finalize();
|
||||
World.SendAll(LoginMsgObj.MakePack());
|
||||
LoginMsgObj.Delete();
|
||||
} else {
|
||||
local LoginMsgObj = AdMsg();
|
||||
LoginMsgObj.PutType(14);
|
||||
LoginMsgObj.PutColorString("玩家[", [255, 255, 0]);
|
||||
LoginMsgObj.PutColorString(SUser.GetCharacName(), [0, 255, 0]);
|
||||
LoginMsgObj.PutColorString("]", [255, 255, 0]);
|
||||
LoginMsgObj.PutColorString("刚刚通过邮件向", [255, 255, 0]);
|
||||
LoginMsgObj.PutColorString("[" + receive_name + "]", [0, 255, 0]);
|
||||
LoginMsgObj.PutColorString("发送了一封邮件", [255, 255, 0]);
|
||||
LoginMsgObj.Finalize();
|
||||
World.SendAll(LoginMsgObj.MakePack());
|
||||
LoginMsgObj.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function getFirstBracketContent(str) {
|
||||
local startPos = str.find("(");
|
||||
if (startPos == null) return null;
|
||||
local endPos = str.find(")", startPos + 1);
|
||||
if (endPos == null) return null;
|
||||
// 提取括号内的内容(不包括括号本身)
|
||||
return str.slice(startPos + 1, endPos);
|
||||
}
|
||||
12
示例项目/任务清除卷/Proj.ifo
Normal file
12
示例项目/任务清除卷/Proj.ifo
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ProjectName": "任务清除卷",
|
||||
"ProjectDescribe": "清理各类型任务以及重置相关任务",
|
||||
"ProjectAuthor": "南瓜",
|
||||
"ProjectVersion": 1.3,
|
||||
"ProjectConfig": "任务相关配置_南瓜.json",
|
||||
"ProjectFiles": [
|
||||
"任务清除卷.nut"
|
||||
],
|
||||
"ProjectIcon":"http://103.36.223.176:5244/d/DP_S/logo2.png?sign=aH3AjsyJgmomCqT3To_QfDY6a2RlSI-T3eUmtW0raoA=:0",
|
||||
"ProjectRunFunc": "_Dps_QuestInfo_nangua_Main_"
|
||||
}
|
||||
231
示例项目/任务清除卷/任务清除卷.nut
Normal file
231
示例项目/任务清除卷/任务清除卷.nut
Normal file
@@ -0,0 +1,231 @@
|
||||
_NG_QUEST_GRADE_COMMON_UNIQUE <- 5 //普通任务
|
||||
_NG_QUEST_GRADE_EPIC <- 0 //主线任务
|
||||
_NG_QUEST_GRADE_ACHIEVEMENT <- 2 //成就任务
|
||||
|
||||
// 任务类型与排除列表的映射
|
||||
_QUEST_EXCLUDE_MAP <- {
|
||||
[_NG_QUEST_GRADE_COMMON_UNIQUE] = "普通任务需排除任务ID",
|
||||
[_NG_QUEST_GRADE_ACHIEVEMENT] = "成就任务需排除任务ID",
|
||||
[_NG_QUEST_GRADE_EPIC] = "主线任务需排除任务ID"
|
||||
}
|
||||
|
||||
function clear_all_quest_by_character_level_nangua(SUser, Item_id) {
|
||||
local Cofig = GlobalConfig.Get("任务相关配置_南瓜.json");
|
||||
local poolMapping = {
|
||||
[Cofig["主线任务完成券道具ID"]] = _NG_QUEST_GRADE_EPIC,
|
||||
[Cofig["普通任务完成券道具ID"]] = _NG_QUEST_GRADE_COMMON_UNIQUE,
|
||||
[Cofig["成就任务完成券道具ID"]] = _NG_QUEST_GRADE_ACHIEVEMENT
|
||||
};
|
||||
// 获取对应的type
|
||||
local quest_type = poolMapping[Item_id];
|
||||
// 玩家任务信息
|
||||
local user_quest = SUser.GetQuest();
|
||||
|
||||
// 玩家已完成任务信息
|
||||
local WongWork_CQuestClear = NativePointer(user_quest).add(4);
|
||||
// 玩家当前等级
|
||||
local charac_lv = SUser.GetCharacLevel();
|
||||
// 本次完成任务数量
|
||||
local clear_quest_cnt = 0;
|
||||
// 获取pvf数据
|
||||
local data_manager = Sq_CallFunc(S_Ptr("0x80CC19B"), "pointer");
|
||||
|
||||
// 使用全局排除列表
|
||||
local exclude_quset_id = _QUEST_EXCLUDE_MAP.rawin(quest_type) ? Cofig[_QUEST_EXCLUDE_MAP[quest_type]] : [];
|
||||
|
||||
//完成当前已接任务
|
||||
for (local i = 0; i < 20; i++) {
|
||||
// 任务id
|
||||
local doing_quest_id = NativePointer(user_quest).add(4 * (i + 7500 + 2)).readInt();
|
||||
|
||||
if (doing_quest_id > 0) {
|
||||
// 获取当前任务的数据
|
||||
local quest = Sq_CallFunc(S_Ptr("0x835FDC6"), "pointer", ["pointer", "int"], data_manager, doing_quest_id);
|
||||
if (quest) {
|
||||
// 任务类型
|
||||
local quest_grade = NativePointer(quest).add(8).readInt();
|
||||
|
||||
// 判断任务类型并且不在排除列表中
|
||||
if (quest_grade == quest_type && exclude_quset_id.find(doing_quest_id) == null) {
|
||||
// 无条件完成任务
|
||||
SUser.ClearQuest_Gm(doing_quest_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 遍历所有任务ID
|
||||
for (local quest_id = 1; quest_id < 30000; quest_id++) {
|
||||
// 检查任务是否在排除列表中
|
||||
if (exclude_quset_id.find(quest_id) != null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 跳过已完成的任务
|
||||
local isCleared = isClearedQuest(WongWork_CQuestClear.C_Object, quest_id);
|
||||
if (isCleared) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 获取任务数据
|
||||
local quest = Sq_CallFunc(S_Ptr("0x835FDC6"), "pointer", ["pointer", "int"], data_manager, quest_id);
|
||||
if (quest) {
|
||||
// 任务类型
|
||||
local quest_grade = NativePointer(quest).add(8).readInt();
|
||||
|
||||
if (quest_grade == quest_type) {
|
||||
// 只判断任务最低等级要求 忽略 职业/前置 等任务要求 可一次性完成当前等级所有任务
|
||||
local quest_min_lv = NativePointer(quest).add(0x20).readInt();
|
||||
|
||||
if (quest_min_lv <= charac_lv) {
|
||||
Sq_CallFunc(S_Ptr("0x808BA78"), "int", ["pointer", "int"], WongWork_CQuestClear.C_Object, quest_id);
|
||||
|
||||
// 本次自动完成任务计数
|
||||
clear_quest_cnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 通知客户端更新
|
||||
if (clear_quest_cnt > 0) {
|
||||
local Pack = Packet();
|
||||
Sq_CallFunc(S_Ptr("0x868B044"), "int", ["pointer"], SUser.C_Object);
|
||||
Sq_CallFunc(S_Ptr("0x86ABBA8"), "int", ["pointer", "pointer"], user_quest, Pack.C_Object);
|
||||
SUser.Send(Pack);
|
||||
Pack.Delete();
|
||||
// 公告通知客户端本次自动完成任务数据
|
||||
SUser.SendNotiPacketMessage("已自动完成当前等级任务数量: " + clear_quest_cnt, 8);
|
||||
}else{
|
||||
SUser.SendNotiPacketMessage("没有可清理的任务", 8);
|
||||
SUser.GiveItem(Item_id, 1);
|
||||
}
|
||||
}
|
||||
|
||||
//指定每日任务完成券
|
||||
function QUEST_ByMRFuncBynangua(SUser, ItemId) {
|
||||
local Cofig = GlobalConfig.Get("任务相关配置_南瓜.json");
|
||||
// 玩家已完成任务信息
|
||||
local user_quest = SUser.GetQuest();
|
||||
local WongWork_CQuestClear = NativePointer(user_quest).add(4);
|
||||
|
||||
// 是否有任务已被清理
|
||||
local anyTaskCleared = false;
|
||||
|
||||
// 遍历并完成每一个任务
|
||||
for (local i = 0; i < Cofig["指定完成每日任务ID"].len(); i++) {
|
||||
local quest_id = Cofig["指定完成每日任务ID"][i];
|
||||
local isCleared = isClearedQuest(WongWork_CQuestClear.C_Object, quest_id);
|
||||
|
||||
if (isCleared) {
|
||||
continue;
|
||||
} else {
|
||||
SUser.ClearQuest_Gm(quest_id);
|
||||
anyTaskCleared = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (anyTaskCleared) {
|
||||
SUser.SendNotiPacketMessage("指定每日任务已完成!", 8);
|
||||
} else {
|
||||
SUser.SendNotiPacketMessage("没有可清理的任务", 8);
|
||||
SUser.GiveItem(ItemId, 1);
|
||||
}
|
||||
}
|
||||
|
||||
//指定每日任务重置券
|
||||
function QUEST_ByCZMRFuncBynangua(SUser, ItemId) {
|
||||
local Cofig = GlobalConfig.Get("任务相关配置_南瓜.json");
|
||||
// 玩家已完成任务信息
|
||||
local user_quest = SUser.GetQuest();
|
||||
local WongWork_CQuestClear = NativePointer(user_quest).add(4);
|
||||
|
||||
// 是否有任务被重置
|
||||
local anyTaskReset = false;
|
||||
|
||||
// 遍历并重置每一个任务
|
||||
for (local i = 0; i < Cofig["指定完成每日任务ID"].len(); i++) {
|
||||
local quest_id = Cofig["指定完成每日任务ID"][i];
|
||||
local isCleared = isClearedQuest(WongWork_CQuestClear.C_Object, quest_id);
|
||||
|
||||
if (!isCleared) {
|
||||
continue;
|
||||
} else {
|
||||
Sq_CallFunc(S_Ptr("0x808BAAC"), "int", ["pointer", "int"], WongWork_CQuestClear.C_Object, quest_id);
|
||||
anyTaskReset = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (anyTaskReset) {
|
||||
//通知客户端更新任务列表
|
||||
Sq_CallFunc(S_Ptr("0x868B044"), "int", ["pointer"], SUser.C_Object);
|
||||
local Pack = Packet();
|
||||
Sq_CallFunc(S_Ptr("0x86ABBA8"), "int", ["pointer", "pointer"], user_quest, Pack.C_Object);
|
||||
SUser.Send(Pack);
|
||||
Pack.Delete();
|
||||
SUser.SendNotiPacketMessage("指定每日任务已重置!", 8);
|
||||
} else {
|
||||
SUser.SendNotiPacketMessage("没有可重置的任务", 8);
|
||||
SUser.GiveItem(ItemId, 1);
|
||||
}
|
||||
}
|
||||
|
||||
//重置所有任务为未完成状态
|
||||
function QUEST_ByALLFuncBynangua(SUser, ItemId) {
|
||||
local GetState = SUser.GetState()
|
||||
local user_quest = SUser.GetQuest();
|
||||
local WongWork_CQuestClear = NativePointer(user_quest).add(4);
|
||||
//清空已接任务列表
|
||||
for (local i = 0; i < 20; i++) {
|
||||
NativePointer(user_quest).add(4 * (i + 7500 + 2)).writeInt(0);
|
||||
}
|
||||
//所有任务设置未完成状态
|
||||
for (local i = 0; i < 29999; i++) {
|
||||
Sq_CallFunc(S_Ptr("0x808BAAC"), "int", ["pointer", "int"], WongWork_CQuestClear.C_Object, i);
|
||||
}
|
||||
//通知客户端更新任务列表
|
||||
Sq_CallFunc(S_Ptr("0x868B044"), "int", ["pointer"], SUser.C_Object);
|
||||
local Pack = Packet();
|
||||
Sq_CallFunc(S_Ptr("0x86ABBA8"), "int", ["pointer", "pointer"], user_quest, Pack.C_Object);
|
||||
SUser.Send(Pack);
|
||||
Pack.Delete();
|
||||
SUser.SendNotiPacketMessage("所有任务已重置!", 8);
|
||||
}
|
||||
|
||||
function isClearedQuest(C_Object, questID) {
|
||||
return Sq_CallFunc(S_Ptr("0x808BAE0"), "bool", ["pointer", "int"], C_Object, questID);
|
||||
}
|
||||
|
||||
//加载入口
|
||||
function _Dps_QuestInfo_nangua_Main_() {
|
||||
_Dps_QuestInfo_nangua_Logic_();
|
||||
}
|
||||
|
||||
//重载入口
|
||||
function _Dps_QuestInfo_nangua_Main_Reload_(OldConfig) {
|
||||
Cb_Use_Item_Sp_Func.rawdelete(OldConfig["主线任务完成券道具ID"].tointeger());
|
||||
Cb_Use_Item_Sp_Func.rawdelete(OldConfig["普通任务完成券道具ID"].tointeger());
|
||||
Cb_Use_Item_Sp_Func.rawdelete(OldConfig["成就任务完成券道具ID"].tointeger());
|
||||
Cb_Use_Item_Sp_Func.rawdelete(OldConfig["指定每日任务完成券道具ID"].tointeger());
|
||||
Cb_Use_Item_Sp_Func.rawdelete(OldConfig["指定每日任务重置券道具ID"].tointeger());
|
||||
Cb_Use_Item_Sp_Func.rawdelete(OldConfig["重置所有任务道具ID"].tointeger());
|
||||
|
||||
//重新注册
|
||||
_Dps_QuestInfo_nangua_Logic_();
|
||||
}
|
||||
|
||||
function _Dps_QuestInfo_nangua_Logic_() {
|
||||
local Cofig = GlobalConfig.Get("任务相关配置_南瓜.json");
|
||||
// 主线任务完成券
|
||||
Cb_Use_Item_Sp_Func[Cofig["主线任务完成券道具ID"]] <- clear_all_quest_by_character_level_nangua;
|
||||
// 普通任务完成券
|
||||
Cb_Use_Item_Sp_Func[Cofig["普通任务完成券道具ID"]] <- clear_all_quest_by_character_level_nangua;
|
||||
// 成就任务完成券
|
||||
Cb_Use_Item_Sp_Func[Cofig["成就任务完成券道具ID"]] <- clear_all_quest_by_character_level_nangua;
|
||||
// 每日任务完成券
|
||||
Cb_Use_Item_Sp_Func[Cofig["指定每日任务完成券道具ID"]] <- QUEST_ByMRFuncBynangua;
|
||||
// 每日任务重置券
|
||||
Cb_Use_Item_Sp_Func[Cofig["指定每日任务重置券道具ID"]] <- QUEST_ByCZMRFuncBynangua;
|
||||
// 所有任务重置券
|
||||
Cb_Use_Item_Sp_Func[Cofig["重置所有任务道具ID"]] <- QUEST_ByALLFuncBynangua;
|
||||
}
|
||||
12
示例项目/任务清除卷/任务相关配置_南瓜.json
Normal file
12
示例项目/任务清除卷/任务相关配置_南瓜.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"主线任务完成券道具ID":2021458801,
|
||||
"普通任务完成券道具ID":2021458802,
|
||||
"成就任务完成券道具ID":2021458804,
|
||||
"重置所有任务道具ID":2021458813,
|
||||
"指定每日任务完成券道具ID":2021458803,
|
||||
"指定每日任务重置券道具ID":20214588091,
|
||||
"指定完成每日任务ID":[2411, 2412],
|
||||
"主线任务需排除任务ID":[1111111],
|
||||
"普通任务需排除任务ID":[4443, 7898, 7889, 7895, 7892, 7873, 7876, 7870, 7879, 4065, 4068, 999, 7827, 7817, 7824, 7820, 7834, 7837, 7831, 7840, 4427, 4428, 4429, 4430, 4431, 4432, 4433, 4434, 4435, 7848, 7842, 7845, 7851, 7866, 7855, 7862, 7859, 7814, 7810, 7807, 7803, 7886, 7882, 2708, 2710, 2712, 2702],
|
||||
"成就任务需排除任务ID":[1111111]
|
||||
}
|
||||
12
示例项目/任务清除卷2/Proj.ifo
Normal file
12
示例项目/任务清除卷2/Proj.ifo
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ProjectName": "任务清除卷2",
|
||||
"ProjectDescribe": "清理各类型任务以及重置相关任务,除了7577类道具 也可以使用礼包类道具触发",
|
||||
"ProjectAuthor": "倾泪寒",
|
||||
"ProjectVersion": 1.0,
|
||||
"ProjectConfig": "任务相关配置_2.json",
|
||||
"ProjectFiles": [
|
||||
"任务清除卷.nut"
|
||||
],
|
||||
"ProjectIcon":"http://103.36.223.176:5244/d/DP_S/logo2.png?sign=aH3AjsyJgmomCqT3To_QfDY6a2RlSI-T3eUmtW0raoA=:0",
|
||||
"ProjectRunFunc": "_Dps_QuestInfo_nangua_Main_2"
|
||||
}
|
||||
260
示例项目/任务清除卷2/任务清除卷.nut
Normal file
260
示例项目/任务清除卷2/任务清除卷.nut
Normal file
@@ -0,0 +1,260 @@
|
||||
_NG_QUEST_GRADE_COMMON_UNIQUE <- 5 //普通任务
|
||||
_NG_QUEST_GRADE_EPIC <- 0 //主线任务
|
||||
_NG_QUEST_GRADE_ACHIEVEMENT <- 2 //成就任务
|
||||
|
||||
// 任务类型与排除列表的映射
|
||||
_QUEST_EXCLUDE_MAP2 <- {
|
||||
[_NG_QUEST_GRADE_COMMON_UNIQUE] = "普通任务需排除任务ID",
|
||||
[_NG_QUEST_GRADE_ACHIEVEMENT] = "成就任务需排除任务ID",
|
||||
[_NG_QUEST_GRADE_EPIC] = "主线任务需排除任务ID"
|
||||
}
|
||||
|
||||
function clear_all_quest_by_character_level_nangua2(SUser, Date) {
|
||||
|
||||
local Item_id = Date[15].tointeger();
|
||||
|
||||
if (Date[18] != "3") {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
local Cofig = GlobalConfig.Get("任务相关配置_2.json");
|
||||
local poolMapping = {
|
||||
[Cofig["主线任务完成券道具ID"]] = _NG_QUEST_GRADE_EPIC,
|
||||
[Cofig["普通任务完成券道具ID"]] = _NG_QUEST_GRADE_COMMON_UNIQUE,
|
||||
[Cofig["成就任务完成券道具ID"]] = _NG_QUEST_GRADE_ACHIEVEMENT
|
||||
};
|
||||
// 获取对应的type
|
||||
local quest_type = poolMapping[Item_id];
|
||||
// 玩家任务信息
|
||||
local user_quest = SUser.GetQuest();
|
||||
|
||||
// 玩家已完成任务信息
|
||||
local WongWork_CQuestClear = NativePointer(user_quest).add(4);
|
||||
// 玩家当前等级
|
||||
local charac_lv = SUser.GetCharacLevel();
|
||||
// 本次完成任务数量
|
||||
local clear_quest_cnt = 0;
|
||||
// 获取pvf数据
|
||||
local data_manager = Sq_CallFunc(S_Ptr("0x80CC19B"), "pointer");
|
||||
|
||||
// 使用全局排除列表
|
||||
local exclude_quset_id = _QUEST_EXCLUDE_MAP2.rawin(quest_type) ? Cofig[_QUEST_EXCLUDE_MAP2[quest_type]] : [];
|
||||
|
||||
//完成当前已接任务
|
||||
for (local i = 0; i< 20; i++) {
|
||||
// 任务id
|
||||
local doing_quest_id = NativePointer(user_quest).add(4 * (i + 7500 + 2)).readInt();
|
||||
|
||||
if (doing_quest_id > 0) {
|
||||
// 获取当前任务的数据
|
||||
local quest = Sq_CallFunc(S_Ptr("0x835FDC6"), "pointer", ["pointer", "int"], data_manager, doing_quest_id);
|
||||
if (quest) {
|
||||
// 任务类型
|
||||
local quest_grade = NativePointer(quest).add(8).readInt();
|
||||
|
||||
// 判断任务类型并且不在排除列表中
|
||||
if (quest_grade == quest_type && exclude_quset_id.find(doing_quest_id) == null) {
|
||||
// 无条件完成任务
|
||||
SUser.ClearQuest_Gm(doing_quest_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 遍历所有任务ID
|
||||
for (local quest_id = 1; quest_id< 30000; quest_id++) {
|
||||
// 检查任务是否在排除列表中
|
||||
if (exclude_quset_id.find(quest_id) != null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 跳过已完成的任务
|
||||
local isCleared = isClearedQuest(WongWork_CQuestClear.C_Object, quest_id);
|
||||
if (isCleared) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 获取任务数据
|
||||
local quest = Sq_CallFunc(S_Ptr("0x835FDC6"), "pointer", ["pointer", "int"], data_manager, quest_id);
|
||||
if (quest) {
|
||||
// 任务类型
|
||||
local quest_grade = NativePointer(quest).add(8).readInt();
|
||||
|
||||
if (quest_grade == quest_type) {
|
||||
// 只判断任务最低等级要求 忽略 职业/前置 等任务要求 可一次性完成当前等级所有任务
|
||||
local quest_min_lv = NativePointer(quest).add(0x20).readInt();
|
||||
|
||||
if (quest_min_lv <= charac_lv) {
|
||||
Sq_CallFunc(S_Ptr("0x808BA78"), "int", ["pointer", "int"], WongWork_CQuestClear.C_Object, quest_id);
|
||||
|
||||
// 本次自动完成任务计数
|
||||
clear_quest_cnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 通知客户端更新
|
||||
if (clear_quest_cnt > 0) {
|
||||
local Pack = Packet();
|
||||
Sq_CallFunc(S_Ptr("0x868B044"), "int", ["pointer"], SUser.C_Object);
|
||||
Sq_CallFunc(S_Ptr("0x86ABBA8"), "int", ["pointer", "pointer"], user_quest, Pack.C_Object);
|
||||
SUser.Send(Pack);
|
||||
Pack.Delete();
|
||||
// 公告通知客户端本次自动完成任务数据
|
||||
SUser.SendNotiPacketMessage("已自动完成当前等级任务数量: " + clear_quest_cnt, 8);
|
||||
} else {
|
||||
SUser.SendNotiPacketMessage("没有可清理的任务", 8);
|
||||
}
|
||||
}
|
||||
|
||||
//指定每日任务完成券
|
||||
function QUEST_ByMRFuncBynangua2(SUser, Date) {
|
||||
|
||||
local ItemId = Date[15].tointeger();
|
||||
|
||||
if (Date[18] != "3") {
|
||||
return;
|
||||
}
|
||||
local Cofig = GlobalConfig.Get("任务相关配置_2.json");
|
||||
// 玩家已完成任务信息
|
||||
local user_quest = SUser.GetQuest();
|
||||
local WongWork_CQuestClear = NativePointer(user_quest).add(4);
|
||||
|
||||
// 是否有任务已被清理
|
||||
local anyTaskCleared = false;
|
||||
|
||||
// 遍历并完成每一个任务
|
||||
for (local i = 0; i< Cofig["指定完成每日任务ID"].len(); i++) {
|
||||
local quest_id = Cofig["指定完成每日任务ID"][i];
|
||||
local isCleared = isClearedQuest(WongWork_CQuestClear.C_Object, quest_id);
|
||||
|
||||
if (isCleared) {
|
||||
continue;
|
||||
} else {
|
||||
SUser.ClearQuest_Gm(quest_id);
|
||||
anyTaskCleared = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (anyTaskCleared) {
|
||||
SUser.SendNotiPacketMessage("指定每日任务已完成!", 8);
|
||||
} else {
|
||||
SUser.SendNotiPacketMessage("没有可清理的任务", 8);
|
||||
}
|
||||
}
|
||||
|
||||
//指定每日任务重置券
|
||||
function QUEST_ByCZMRFuncBynangua2(SUser, Date) {
|
||||
local ItemId = Date[15].tointeger();
|
||||
|
||||
if (Date[18] != "3") {
|
||||
return;
|
||||
}
|
||||
local Cofig = GlobalConfig.Get("任务相关配置_2.json");
|
||||
// 玩家已完成任务信息
|
||||
local user_quest = SUser.GetQuest();
|
||||
local WongWork_CQuestClear = NativePointer(user_quest).add(4);
|
||||
|
||||
// 是否有任务被重置
|
||||
local anyTaskReset = false;
|
||||
|
||||
// 遍历并重置每一个任务
|
||||
for (local i = 0; i< Cofig["指定完成每日任务ID"].len(); i++) {
|
||||
local quest_id = Cofig["指定完成每日任务ID"][i];
|
||||
local isCleared = isClearedQuest(WongWork_CQuestClear.C_Object, quest_id);
|
||||
|
||||
if (!isCleared) {
|
||||
continue;
|
||||
} else {
|
||||
Sq_CallFunc(S_Ptr("0x808BAAC"), "int", ["pointer", "int"], WongWork_CQuestClear.C_Object, quest_id);
|
||||
anyTaskReset = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (anyTaskReset) {
|
||||
//通知客户端更新任务列表
|
||||
Sq_CallFunc(S_Ptr("0x868B044"), "int", ["pointer"], SUser.C_Object);
|
||||
local Pack = Packet();
|
||||
Sq_CallFunc(S_Ptr("0x86ABBA8"), "int", ["pointer", "pointer"], user_quest, Pack.C_Object);
|
||||
SUser.Send(Pack);
|
||||
Pack.Delete();
|
||||
SUser.SendNotiPacketMessage("指定每日任务已重置!", 8);
|
||||
} else {
|
||||
SUser.SendNotiPacketMessage("没有可重置的任务", 8);
|
||||
}
|
||||
}
|
||||
|
||||
//重置所有任务为未完成状态
|
||||
function QUEST_ByALLFuncBynangua2(SUser, Date) {
|
||||
local ItemId = Date[15].tointeger();
|
||||
|
||||
if (Date[18] != "3") {
|
||||
return;
|
||||
}
|
||||
local GetState = SUser.GetState()
|
||||
local user_quest = SUser.GetQuest();
|
||||
local WongWork_CQuestClear = NativePointer(user_quest).add(4);
|
||||
//清空已接任务列表
|
||||
for (local i = 0; i< 20; i++) {
|
||||
NativePointer(user_quest).add(4 * (i + 7500 + 2)).writeInt(0);
|
||||
}
|
||||
//所有任务设置未完成状态
|
||||
for (local i = 0; i< 29999; i++) {
|
||||
Sq_CallFunc(S_Ptr("0x808BAAC"), "int", ["pointer", "int"], WongWork_CQuestClear.C_Object, i);
|
||||
}
|
||||
//通知客户端更新任务列表
|
||||
Sq_CallFunc(S_Ptr("0x868B044"), "int", ["pointer"], SUser.C_Object);
|
||||
local Pack = Packet();
|
||||
Sq_CallFunc(S_Ptr("0x86ABBA8"), "int", ["pointer", "pointer"], user_quest, Pack.C_Object);
|
||||
SUser.Send(Pack);
|
||||
Pack.Delete();
|
||||
SUser.SendNotiPacketMessage("所有任务已重置!", 8);
|
||||
}
|
||||
|
||||
function isClearedQuest(C_Object, questID) {
|
||||
return Sq_CallFunc(S_Ptr("0x808BAE0"), "bool", ["pointer", "int"], C_Object, questID);
|
||||
}
|
||||
|
||||
//加载入口
|
||||
function _Dps_QuestInfo_nangua_Main_2() {
|
||||
_Dps_QuestInfo_nangua_Logic_2();
|
||||
}
|
||||
|
||||
//重载入口
|
||||
function _Dps_QuestInfo_nangua_Main_Reload_2(OldConfig) {
|
||||
|
||||
}
|
||||
|
||||
function _Dps_QuestInfo_nangua_Logic_2() {
|
||||
local Cofig = GlobalConfig.Get("任务相关配置_2.json");
|
||||
// 主线任务完成券
|
||||
Cb_History_ItemDown_Func["任务完成券"] <- Cb_History_ItemDown_FuncMapRW;
|
||||
}
|
||||
|
||||
|
||||
function Cb_History_ItemDown_FuncMapRW(SUser, Date) {
|
||||
local Cofig = GlobalConfig.Get("任务相关配置_2.json");
|
||||
|
||||
switch (Date[15].tointeger()) {
|
||||
case Cofig["主线任务完成券道具ID"]:
|
||||
clear_all_quest_by_character_level_nangua2(SUser, Date);
|
||||
break;
|
||||
case Cofig["普通任务完成券道具ID"]:
|
||||
clear_all_quest_by_character_level_nangua2(SUser, Date);
|
||||
break;
|
||||
case Cofig["成就任务完成券道具ID"]:
|
||||
clear_all_quest_by_character_level_nangua2(SUser, Date);
|
||||
break;
|
||||
case Cofig["指定每日任务完成券道具ID"]:
|
||||
QUEST_ByMRFuncBynangua2(SUser, Date);
|
||||
break;
|
||||
case Cofig["指定每日任务重置券道具ID"]:
|
||||
QUEST_ByCZMRFuncBynangua2(SUser, Date);
|
||||
break;
|
||||
case Cofig["重置所有任务道具ID"]:
|
||||
QUEST_ByALLFuncBynangua2(SUser, Date);
|
||||
break;
|
||||
}
|
||||
}
|
||||
12
示例项目/任务清除卷2/任务相关配置_2.json
Normal file
12
示例项目/任务清除卷2/任务相关配置_2.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"主线任务完成券道具ID":2021458801,
|
||||
"普通任务完成券道具ID":2021458802,
|
||||
"成就任务完成券道具ID":2021458804,
|
||||
"重置所有任务道具ID":2021458813,
|
||||
"指定每日任务完成券道具ID":2021458803,
|
||||
"指定每日任务重置券道具ID":20214588091,
|
||||
"指定完成每日任务ID":[2411, 2412],
|
||||
"主线任务需排除任务ID":[1111111],
|
||||
"普通任务需排除任务ID":[4443, 7898, 7889, 7895, 7892, 7873, 7876, 7870, 7879, 4065, 4068, 999, 7827, 7817, 7824, 7820, 7834, 7837, 7831, 7840, 4427, 4428, 4429, 4430, 4431, 4432, 4433, 4434, 4435, 7848, 7842, 7845, 7851, 7866, 7855, 7862, 7859, 7814, 7810, 7807, 7803, 7886, 7882, 2708, 2710, 2712, 2702],
|
||||
"成就任务需排除任务ID":[1111111]
|
||||
}
|
||||
11
示例项目/修复卡NPC商店道具/Proj.ifo
Normal file
11
示例项目/修复卡NPC商店道具/Proj.ifo
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ProjectName": "修复卡NPC商店道具",
|
||||
"ProjectDescribe": "修复了客户端通过BUG卡NPC商店道具的问题",
|
||||
"ProjectAuthor": "倾泪寒",
|
||||
"ProjectVersion": 1.0,
|
||||
"ProjectConfig": "",
|
||||
"ProjectFiles": [
|
||||
"修复卡NPC商店道具.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_Dps_RepairCardNpcStoreProps_Main_"
|
||||
}
|
||||
12
示例项目/修复卡NPC商店道具/修复卡NPC商店道具.nut
Normal file
12
示例项目/修复卡NPC商店道具/修复卡NPC商店道具.nut
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
|
||||
|
||||
function _Dps_RepairCardNpcStoreProps_Main_()
|
||||
{
|
||||
Cb_BuyItem_Get_Data_Leave_Func["_DPS_RepairCardNpcStoreProps_"] <- function (args)
|
||||
{
|
||||
if(NativePointer(args[3]).add(156).readInt() < 0){
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
12
示例项目/全职业通用转职书/Proj.ifo
Normal file
12
示例项目/全职业通用转职书/Proj.ifo
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ProjectName": "全职业通用转职书",
|
||||
"ProjectDescribe": "全职业都可用的转职书。每个转职职业是个数组,可以写多个转职卷编号,仿照7577的道具类型即可,使用\",\"隔开。",
|
||||
"ProjectAuthor": "倾泪寒",
|
||||
"ProjectVersion": 1.0,
|
||||
"ProjectConfig": "",
|
||||
"ProjectConfig": "全职业通用转职书_Lenheart.json",
|
||||
"ProjectFiles": [
|
||||
"全职业通用转职书.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_Dps_GeneralJobTransferCertificateForAllProfessions_Main_"
|
||||
}
|
||||
50
示例项目/全职业通用转职书/全职业通用转职书.nut
Normal file
50
示例项目/全职业通用转职书/全职业通用转职书.nut
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
文件名:全职业通用转职书.nut
|
||||
路径:OfficialProject/全职业通用转职书/全职业通用转职书.nut
|
||||
创建日期:2025-10-24 22:26
|
||||
文件用途:
|
||||
*/
|
||||
|
||||
//重载入口
|
||||
function _Dps_GeneralJobTransferCertificateForAllProfessions_Main_Reload_(OldConfig) {
|
||||
//先销毁原来注册的
|
||||
local JobArr = [];
|
||||
JobArr.push(GlobalConfig["转职初始职业"]);
|
||||
JobArr.push(GlobalConfig["转职第一职业"]);
|
||||
JobArr.push(GlobalConfig["转职第二职业"]);
|
||||
JobArr.push(GlobalConfig["转职第三职业"]);
|
||||
JobArr.push(GlobalConfig["转职第四职业"]);
|
||||
JobArr.push(GlobalConfig["转职第五职业"]);
|
||||
|
||||
foreach(Index, arr in JobArr) {
|
||||
foreach(ItemId in arr) {
|
||||
if (Cb_Use_Item_Sp_Func.rawin(ItemId)) Cb_Use_Item_Sp_Func.rawdelete(ItemId);
|
||||
}
|
||||
}
|
||||
|
||||
//重新注册
|
||||
_Dps_GeneralJobTransferCertificateForAllProfessions_Main_();
|
||||
}
|
||||
|
||||
function _Dps_GeneralJobTransferCertificateForAllProfessions_Main_() {
|
||||
local Config = GlobalConfig.Get("全职业通用转职书_Lenheart.json");
|
||||
local JobArr = [];
|
||||
JobArr.push(Config["转职初始职业"]);
|
||||
JobArr.push(Config["转职第一职业"]);
|
||||
JobArr.push(Config["转职第二职业"]);
|
||||
JobArr.push(Config["转职第三职业"]);
|
||||
JobArr.push(Config["转职第四职业"]);
|
||||
JobArr.push(Config["转职第五职业"]);
|
||||
|
||||
|
||||
|
||||
foreach(Index, arr in JobArr) {
|
||||
foreach(ItemId in arr) {
|
||||
Cb_Use_Item_Sp_Func[ItemId] <- function(SUser, ItemId) {
|
||||
SUser.ChangeGrowType(Index, 0);
|
||||
SUser.SendNotiPacket(0, 2, 0);
|
||||
SUser.InitSkillW(0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
8
示例项目/全职业通用转职书/全职业通用转职书_Lenheart.json
Normal file
8
示例项目/全职业通用转职书/全职业通用转职书_Lenheart.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"转职初始职业":[7577],
|
||||
"转职第一职业":[7577],
|
||||
"转职第二职业":[7577],
|
||||
"转职第三职业":[7577],
|
||||
"转职第四职业":[7577],
|
||||
"转职第五职业":[7577]
|
||||
}
|
||||
11
示例项目/副本使用道具奖励/Proj.ifo
Normal file
11
示例项目/副本使用道具奖励/Proj.ifo
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ProjectName": "副本使用道具奖励",
|
||||
"ProjectDescribe": "特定副本使用特定道具会返还自定义的奖励",
|
||||
"ProjectAuthor": "至尚 & 倾泪寒",
|
||||
"ProjectVersion": 1.0,
|
||||
"ProjectConfig": "副本使用道具奖励.json",
|
||||
"ProjectFiles": [
|
||||
"副本使用道具奖励.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_Dps_ReturnDuplicateItems_Main_"
|
||||
}
|
||||
7
示例项目/副本使用道具奖励/副本使用道具奖励.json
Normal file
7
示例项目/副本使用道具奖励/副本使用道具奖励.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"副本返还配置列表": [
|
||||
[1,1106,3037,10],
|
||||
[2,1108,3038,10]
|
||||
],
|
||||
"提示": "第一个为副本id 第二个为使用的道具id 第三个为返还的道具id 第四个为返还的数量"
|
||||
}
|
||||
32
示例项目/副本使用道具奖励/副本使用道具奖励.nut
Normal file
32
示例项目/副本使用道具奖励/副本使用道具奖励.nut
Normal file
@@ -0,0 +1,32 @@
|
||||
|
||||
function _Dps_ReturnDuplicateItems_Main_() {
|
||||
local Config = GlobalConfig.Get("副本使用道具奖励.json");
|
||||
//分解券
|
||||
|
||||
Cb_History_ItemDown_Func.DWSSSS <- function(user, date) {
|
||||
|
||||
|
||||
local itemId = date[15].tointeger();
|
||||
|
||||
local PartyObj = user.GetParty();
|
||||
|
||||
if (date[18].tointeger()!= 3) return;
|
||||
|
||||
if (PartyObj) {
|
||||
local Bfobj = PartyObj.GetBattleField();
|
||||
local DgnObj = Bfobj.GetDgn();
|
||||
|
||||
if (DgnObj) {
|
||||
local Dungeon_Id = DgnObj.GetId();
|
||||
local FBSYDJ = Config["副本返还配置列表"];
|
||||
foreach(ints in FBSYDJ) {
|
||||
|
||||
if (ints[0] == Dungeon_Id && itemId == ints[1]) {
|
||||
|
||||
user.GiveItem(ints[2].tointeger(), ints[3].tointeger());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
示例项目/副本内禁止丢弃物品/Proj.ifo
Normal file
11
示例项目/副本内禁止丢弃物品/Proj.ifo
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ProjectName": "副本内禁止丢弃物品",
|
||||
"ProjectDescribe": "副本内禁止丢弃物品及金币",
|
||||
"ProjectAuthor": "倾泪寒&南瓜",
|
||||
"ProjectVersion": 1.0,
|
||||
"ProjectConfig": "",
|
||||
"ProjectFiles": [
|
||||
"副本内禁止丢弃物品.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_Dps_DgnCannotDropItem_Main_"
|
||||
}
|
||||
27
示例项目/副本内禁止丢弃物品/副本内禁止丢弃物品.nut
Normal file
27
示例项目/副本内禁止丢弃物品/副本内禁止丢弃物品.nut
Normal file
@@ -0,0 +1,27 @@
|
||||
Cb_DropItem_check_error_Enter_Func.Rindro <- function(args){
|
||||
getroottable()._EmptyHook_Flag_ = true;
|
||||
args[1] = getroottable()._EmptyCharacInfo_Flag_.C_Object;
|
||||
return args;
|
||||
}
|
||||
Cb_DropItem_check_error_Leave_Func.Rindro <- function(args){
|
||||
if(getroottable()._EmptyHook_Flag_){
|
||||
getroottable()._EmptyHook_Flag_ = false;
|
||||
return 19;
|
||||
}
|
||||
}
|
||||
|
||||
function _Dps_DgnCannotDropItem_Main_() {
|
||||
_Jump_DropItem_check_error_();
|
||||
}
|
||||
|
||||
function _Jump_DropItem_check_error_() {
|
||||
//如果没有创建过这个模拟内存就创建
|
||||
if(!getroottable().rawin("_EmptyCharacInfo_Flag_")){
|
||||
getroottable()._EmptyCharacInfo_Flag_ <- Memory.alloc(17);
|
||||
Memory.reset(getroottable()._EmptyCharacInfo_Flag_,17);
|
||||
}
|
||||
//如果没有创建过这个跳转Flag就创建并初始化
|
||||
if(!getroottable().rawin("_EmptyHook_Flag_")){
|
||||
getroottable()._EmptyHook_Flag_ <- false;
|
||||
}
|
||||
}
|
||||
11
示例项目/副本播报/Proj.ifo
Normal file
11
示例项目/副本播报/Proj.ifo
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ProjectName": "副本播报",
|
||||
"ProjectDescribe": "通关及未通关时播报耗时时长",
|
||||
"ProjectAuthor": "南瓜",
|
||||
"ProjectVersion": 1.3,
|
||||
"ProjectConfig": "副本播报配置_Nangua.json",
|
||||
"ProjectFiles": [
|
||||
"副本播报.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_Dps_send_dungeon_msg_Main_"
|
||||
}
|
||||
227
示例项目/副本播报/副本播报.nut
Normal file
227
示例项目/副本播报/副本播报.nut
Normal file
@@ -0,0 +1,227 @@
|
||||
dungeon_cleared <- {};
|
||||
dungeon_cache <- {};
|
||||
function _Dps_send_dungeon_msg_Main_() {
|
||||
//进入副本加载完毕时
|
||||
Cb_Party_OnStartMapFinishLoading_Enter_Func.EnterStartMapByNangua <- function(args) {
|
||||
local Cofig = GlobalConfig.Get("副本播报配置_Nangua.json");
|
||||
local PartyObj = Party(args[0]);
|
||||
|
||||
if(!PartyObj || !Cofig["副本播报开关(true开启,false关闭)"])
|
||||
return
|
||||
for (local i = 0; i < 4; ++i) {
|
||||
local SUser = PartyObj.GetUser(i);
|
||||
if (SUser) {
|
||||
if (Cofig["指定角色CID不播报"].find(SUser.GetCID()) != null && _clear_dgn_Bynangua.CParty_get_member_count(PartyObj.C_Object) < 2) {
|
||||
return;
|
||||
}
|
||||
if(SUser.GetCID() in dungeon_cache){
|
||||
dungeon_cache.rawdelete(SUser.GetCID());
|
||||
}
|
||||
dungeon_cleared[SUser.GetCID()] <- false; // 进入副本时初始化标志为未通关
|
||||
|
||||
local Bfobj = PartyObj.GetBattleField();
|
||||
local DgnObj = Bfobj.GetDgn();
|
||||
local DgnID = DgnObj.GetId();
|
||||
local Dungeon_Name = DgnObj.GetName();
|
||||
local dungeon_type = NativePointer(Bfobj.C_Object).add(460).readU8(); // 0 为普通副本,1 为非常困难深渊,2 为困难深渊
|
||||
local dungeon_diff = Sq_CallFunc(S_Ptr("0x080F981C"), "int", ["pointer"], Bfobj.C_Object); // 获取副本难度
|
||||
local diff_name = Cofig["副本难度命名"][(dungeon_diff).tostring()]; // 获取副本难度名称
|
||||
local dgntypeName = _clear_dgn_Bynangua.DungeonType[(dungeon_type).tostring()];
|
||||
|
||||
local DgnData = {
|
||||
"entered": true,
|
||||
"Dungeon_Name": Dungeon_Name,
|
||||
"dgntypeName": dgntypeName,
|
||||
"diff_name": diff_name,
|
||||
"totalTime": 0,
|
||||
"HellParty_time_recorded": false,
|
||||
"last_HellParty_time": 0,
|
||||
"is_HellParty_room": false
|
||||
};
|
||||
//以角色ID为键记录副本信息
|
||||
dungeon_cache[SUser.GetCID()] <- DgnData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//清理房间完毕时
|
||||
Cb_Battle_Field_onClearMap_Leave_Func.onClearMapByNangua <- function(args) {
|
||||
local Cofig = GlobalConfig.Get("副本播报配置_Nangua.json");
|
||||
local retval = args.pop();
|
||||
local CBattle_Field = args[0];
|
||||
local PartyObj = Party(NativePointer(CBattle_Field).add(-2852).C_Object);
|
||||
if(!PartyObj)
|
||||
return
|
||||
local DgnId = NativePointer(args[0]).add(404).readInt();
|
||||
if (!Cofig["副本播报开关(true开启,false关闭)"]) {
|
||||
return;
|
||||
}
|
||||
if (retval == DgnId) {
|
||||
for (local i = 0; i < 4; ++i) {
|
||||
local SUser = PartyObj.GetUser(i);
|
||||
if (SUser) {
|
||||
if (dungeon_cache.rawin(SUser.GetCID()) && dungeon_cache[SUser.GetCID()].rawin("entered")) {
|
||||
local time = Sq_CallFunc(S_Ptr("0x085B6768"), "int", ["pointer"], PartyObj.C_Object);
|
||||
if (!dungeon_cache[SUser.GetCID()]["is_HellParty_room"]) {
|
||||
dungeon_cache[SUser.GetCID()]["totalTime"] += time;
|
||||
} else {
|
||||
dungeon_cache[SUser.GetCID()]["is_HellParty_room"] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//放弃副本或未通关副本时
|
||||
Cb_Party_giveup_game_Enter_Func.giveupByNangua <- function(args) {
|
||||
local Cofig = GlobalConfig.Get("副本播报配置_Nangua.json");
|
||||
local PartyObj = Party(args[0]);
|
||||
local killcount = Sq_CallFunc(S_Ptr("0x085BF456"), "int", ["pointer"], NativePointer(args[0]).add(812).C_Object);
|
||||
if (!PartyObj) return;
|
||||
if (!Cofig["副本播报开关(true开启,false关闭)"]) return;
|
||||
local SUser = User(args[1]);
|
||||
local Party_Master = PartyObj.GetMaster();
|
||||
local MasterName = Party_Master.GetCharacName();
|
||||
local formattedTime = "";
|
||||
local DgnId = NativePointer(args[0]).add(814 * 4).readInt();
|
||||
local name = SUser.GetCharacName();
|
||||
|
||||
// 如果副本ID不在允许播报的数组内则跳出
|
||||
if (Cofig["不需要播报的副本ID(实例中的ID为怪物攻城的副本ID尽量不要删)"].find(DgnId) != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (SUser.GetCID() in dungeon_cache) {
|
||||
local dungeonInfo = dungeon_cache[SUser.GetCID()];
|
||||
local dgnTypeName = dungeonInfo["dgntypeName"];
|
||||
local dungeonName = dungeonInfo["Dungeon_Name"];
|
||||
local diffName = dungeonInfo["diff_name"];
|
||||
local totalTime = 0;
|
||||
if (dungeon_cache.rawin(SUser.GetCID()) && dungeon_cache[SUser.GetCID()].rawin("totalTime")) {
|
||||
totalTime = dungeon_cache[SUser.GetCID()]["totalTime"];
|
||||
formattedTime = _clear_dgn_Bynangua.formatMilliseconds(totalTime);
|
||||
}
|
||||
if (dungeon_cleared.rawin(SUser.GetCID()) && dungeon_cleared[SUser.GetCID()] == true) {
|
||||
dungeon_cache.rawdelete(SUser.GetCID());
|
||||
dungeon_cleared[SUser.GetCID()] <- false;
|
||||
} else {
|
||||
// 发送未通关信息
|
||||
if (totalTime == 0) {
|
||||
World.SendNotiPacketMessage(format(Cofig["未通过一个小地图播报信息"], name, dgnTypeName, dungeonName, diffName, killcount), Cofig["发送信息位置"]);
|
||||
} else if (MasterName == SUser.GetCharacName()) {
|
||||
World.SendNotiPacketMessage(format(Cofig["放弃副本"], name, dgnTypeName, dungeonName, diffName, formattedTime, killcount), Cofig["发送信息位置"]);
|
||||
} else {
|
||||
World.SendNotiPacketMessage(format(Cofig["在队伍中提前退出副本"], name, MasterName, dgnTypeName, dungeonName, diffName, formattedTime, killcount), Cofig["发送信息位置"])
|
||||
}
|
||||
dungeon_cache.rawdelete(SUser.GetCID());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Cb_Field_KillHellPartyGroupMonsterCnt_Leave_Func.KillHellPartyGroupMonsterCntByNangua <- function(args){
|
||||
local Cofig = GlobalConfig.Get("副本播报配置_Nangua.json");
|
||||
local CBattle_Field = args[0];
|
||||
local PartyObj = Party(NativePointer(CBattle_Field).add(-2852).C_Object);
|
||||
if(!PartyObj)
|
||||
return
|
||||
if (!Cofig["副本播报开关(true开启,false关闭)"]) {
|
||||
return;
|
||||
}
|
||||
local time = Sq_CallFunc(S_Ptr("0x085B6768"), "int", ["pointer"], PartyObj.C_Object);
|
||||
local CBattle_Field_IsKilledAllHellGruoups = Sq_CallFunc(S_Ptr("0x085BF250"), "int", ["pointer"], CBattle_Field);
|
||||
for (local i = 0; i < 4; ++i) {
|
||||
local SUser = PartyObj.GetUser(i);
|
||||
if (SUser) {
|
||||
if (dungeon_cache.rawin(SUser.GetCID()) && dungeon_cache[SUser.GetCID()].rawin("entered")) {
|
||||
dungeon_cache[SUser.GetCID()]["is_HellParty_room"] = true;
|
||||
if (CBattle_Field_IsKilledAllHellGruoups == 1) {
|
||||
dungeon_cache[SUser.GetCID()]["HellParty_time_recorded"] <- true;
|
||||
dungeon_cache[SUser.GetCID()]["last_HellParty_time"] = time;
|
||||
dungeon_cache[SUser.GetCID()]["totalTime"] += time;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//通关副本时
|
||||
Cb_CParty_SetBestClearTime_Enter_Func.ClearTimeByNangua <- function (args) {
|
||||
local Cofig = GlobalConfig.Get("副本播报配置_Nangua.json");
|
||||
local PartyObj = Party(args[0]);
|
||||
local killcount = Sq_CallFunc(S_Ptr("0x085BF456"), "int", ["pointer"], NativePointer(args[0]).add(812).C_Object);
|
||||
if(!PartyObj || !Cofig["副本播报开关(true开启,false关闭)"])
|
||||
return
|
||||
local dungeon_diff = args[2];
|
||||
local clearTime = args[3];
|
||||
local Bfobj = PartyObj.GetBattleField();
|
||||
local DgnObj = Bfobj.GetDgn();
|
||||
local diff_name = Cofig["副本难度命名"][(dungeon_diff).tostring()];
|
||||
if (DgnObj) {
|
||||
local Dungeon_Name = DgnObj.GetName();
|
||||
local MemberNames = [];
|
||||
for (local i = 0; i < 4; ++i) {
|
||||
local SUser = PartyObj.GetUser(i);
|
||||
if (SUser) {
|
||||
if (Cofig["指定角色CID不播报"].find(SUser.GetCID()) != null && _clear_dgn_Bynangua.CParty_get_member_count(PartyObj.C_Object) < 2) {
|
||||
return;
|
||||
}
|
||||
local name = SUser.GetCharacName();
|
||||
MemberNames.append(name);
|
||||
dungeon_cleared[SUser.GetCID()] <- true;
|
||||
}
|
||||
}
|
||||
|
||||
local joinedNames = _clear_dgn_Bynangua.join(MemberNames, ", ");
|
||||
local time = _clear_dgn_Bynangua.formatMilliseconds(clearTime);
|
||||
World.SendNotiPacketMessage(format(Cofig["通关播报信息"], joinedNames, Dungeon_Name, diff_name, time, killcount), Cofig["发送信息位置"]);
|
||||
for (local i = 0; i < 4; ++i) {
|
||||
local TUser = PartyObj.GetUser(i);
|
||||
if (TUser) {
|
||||
local CID = TUser.GetCID();
|
||||
if (CID) {
|
||||
dungeon_cache.rawdelete(CID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _clear_dgn_Bynangua {
|
||||
DungeonType = {
|
||||
"0": "",
|
||||
"1": "非常困难级深渊-",
|
||||
"2": "困难级深渊-",
|
||||
};
|
||||
|
||||
function join(array, delimiter) {
|
||||
local result = "";
|
||||
for (local i = 0; i < array.len(); ++i) {
|
||||
if (i > 0) {
|
||||
result += delimiter;
|
||||
}
|
||||
result += array[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function formatMilliseconds(ms) {
|
||||
local str = "";
|
||||
local minutes = ms / 60000;
|
||||
local seconds = (ms % 60000) / 1000;
|
||||
local milliseconds = (ms % 1000) / 10;
|
||||
if (minutes > 0) {
|
||||
str = minutes + "分" +
|
||||
(seconds < 10 ? "0" : "") + seconds + "秒" +
|
||||
(milliseconds < 10 ? "0" : "") + milliseconds;
|
||||
} else {
|
||||
str = seconds + "秒" +
|
||||
(milliseconds < 10 ? "0" : "") + milliseconds;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
function CParty_get_member_count(C_Object) {
|
||||
return Sq_CallFunc(S_Ptr("0x0859A16A"), "int", ["pointer"], C_Object);
|
||||
}
|
||||
}
|
||||
|
||||
18
示例项目/副本播报/副本播报配置_Nangua.json
Normal file
18
示例项目/副本播报/副本播报配置_Nangua.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"副本播报开关(true开启,false关闭)":true,
|
||||
"不需要播报的副本ID(实例中的ID为怪物攻城的副本ID尽量不要删)":[20002, 20001, 20002, 20003, 20004, 20005, 20006, 20007, 20008, 20009, 20010, 20020, 20021, 20022, 20023, 20024],
|
||||
"指定角色CID不播报":[1111111, 2222222],
|
||||
"提示": "角色ID可以查看数据库中 taiwan_cain → charac_info → charac_no代表角色ID",
|
||||
"通关播报信息":"玩家[%s]通关[%s - %s]用时:[%s],击杀怪物数量<%d>",
|
||||
"未通过一个小地图播报信息":"玩家[%s]在[%s%s-%s]中连一个地图都没通过,击杀怪物数量<%d>",
|
||||
"放弃副本":"很遗憾,玩家[%s]在[%s%s-%s]中被打的落荒而逃,用时: %s,击杀怪物数量<%d>",
|
||||
"在队伍中提前退出副本":"玩家[%s]在<%s>的队伍中,提前退出了[%s%s-%s],用时: %s,击杀怪物数量<%d>",
|
||||
"发送信息位置":14,
|
||||
"副本难度命名" : {
|
||||
"0": "普通级",
|
||||
"1": "冒险级",
|
||||
"2": "勇士级",
|
||||
"3": "王者级",
|
||||
"4": "地狱级"
|
||||
}
|
||||
}
|
||||
11
示例项目/副本难度解锁券/Proj.ifo
Normal file
11
示例项目/副本难度解锁券/Proj.ifo
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ProjectName": "副本难度解锁券",
|
||||
"ProjectDescribe": "使用指定道具解锁当前账号副本所有难度",
|
||||
"ProjectAuthor": "南瓜",
|
||||
"ProjectVersion": 1.0,
|
||||
"ProjectConfig": "副本难度解锁_Nangua.json",
|
||||
"ProjectFiles": [
|
||||
"副本难度解锁券.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_Dps_unlock_all_dgn_diff_Main_"
|
||||
}
|
||||
4
示例项目/副本难度解锁券/副本难度解锁_Nangua.json
Normal file
4
示例项目/副本难度解锁券/副本难度解锁_Nangua.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"解锁成功提示信息": "已将该账号的副本难度开启,将自动返回选择角色界面...",
|
||||
"副本难度解锁券道具ID": 7577
|
||||
}
|
||||
12
示例项目/副本难度解锁券/副本难度解锁券.nut
Normal file
12
示例项目/副本难度解锁券/副本难度解锁券.nut
Normal file
@@ -0,0 +1,12 @@
|
||||
function _Dps_unlock_all_dgn_diff_Main_() {
|
||||
local Cofig = GlobalConfig.Get("副本难度解锁_Nangua.json");
|
||||
Cb_Use_Item_Sp_Func[Cofig["副本难度解锁券道具ID"]] <- function(SUser, ItemId) {
|
||||
local a3 = Memory.allocUtf8String("3");
|
||||
Sq_CallFunc(S_Ptr("0x0820BA90"), "int", ["pointer", "int", "pointer"], SUser.C_Object, 120, a3.C_Object);
|
||||
|
||||
Timer.SetTimeOut(function(SUser) {
|
||||
Sq_CallFunc(S_Ptr("0x8686FEE"), "int", ["pointer", "int"], SUser.C_Object, 1);
|
||||
}, 1, SUser);
|
||||
SUser.SendNotiPacketMessage(Cofig["解锁成功提示信息"], 8);
|
||||
}
|
||||
}
|
||||
11
示例项目/副本需要持有道具进入/Proj.ifo
Normal file
11
示例项目/副本需要持有道具进入/Proj.ifo
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ProjectName": "副本需要持有道具进入",
|
||||
"ProjectDescribe": "副本需要持有道具进入",
|
||||
"ProjectAuthor": "凌众",
|
||||
"ProjectVersion": 1.0,
|
||||
"ProjectConfig": "副本需要持有道具进入_Lenheart.json",
|
||||
"ProjectFiles": [
|
||||
"副本需要持有道具进入.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_Dps_MapNeedItem_Main_"
|
||||
}
|
||||
38
示例项目/副本需要持有道具进入/副本需要持有道具进入.nut
Normal file
38
示例项目/副本需要持有道具进入/副本需要持有道具进入.nut
Normal file
@@ -0,0 +1,38 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function _Dps_MapNeedItem_Main_() {
|
||||
|
||||
// 禁止进入副本
|
||||
Cb_SelectDungeon_Check_Error_Leave_Func.MapNeedItem <- function (args) {
|
||||
|
||||
|
||||
local Config = GlobalConfig.Get("副本需要持有道具进入_Lenheart.json");
|
||||
|
||||
local body = Config["副本需要持有道具才允许进入"];
|
||||
|
||||
local SUser = User(args[1]);
|
||||
|
||||
local mapid = NativePointer(args[2]).add(13).readShort();
|
||||
if(body.rawin(mapid.tostring())){
|
||||
local ItemId = body[mapid.tostring()];
|
||||
local PartyObj = SUser.GetParty();
|
||||
if (!PartyObj) {
|
||||
return;
|
||||
}
|
||||
for (local i = 0; i < 4; ++i) {
|
||||
local PSUser = PartyObj.GetUser(i);
|
||||
if (PSUser) {
|
||||
local InvenObj = SUser.GetInven();
|
||||
local SlotIdx = InvenObj.GetSlotById(ItemId);
|
||||
if(SlotIdx == -1){
|
||||
SUser.SendNotiBox(Config["公告"]+PvfItem.GetNameById(ItemId),1);
|
||||
return 1; // 禁止进入副本
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
7
示例项目/副本需要持有道具进入/副本需要持有道具进入_Lenheart.json
Normal file
7
示例项目/副本需要持有道具进入/副本需要持有道具进入_Lenheart.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"公告": "缺少进入凭证:",
|
||||
"副本需要持有道具才允许进入":{
|
||||
"65":3037,
|
||||
"64":3038
|
||||
}
|
||||
}
|
||||
11
示例项目/史诗免确认/Proj.ifo
Normal file
11
示例项目/史诗免确认/Proj.ifo
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ProjectName": "史诗免确认",
|
||||
"ProjectDescribe": "史诗免确认",
|
||||
"ProjectAuthor": "倾泪寒",
|
||||
"ProjectVersion": 1.1,
|
||||
"ProjectConfig": "",
|
||||
"ProjectFiles": [
|
||||
"史诗免确认.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_Dps_EpicNoConfirmationRequired_Main_"
|
||||
}
|
||||
7
示例项目/史诗免确认/史诗免确认.nut
Normal file
7
示例项目/史诗免确认/史诗免确认.nut
Normal file
@@ -0,0 +1,7 @@
|
||||
function _Dps_EpicNoConfirmationRequired_Main_() {
|
||||
NativePointer("0x085A56CE").add(2).writeU8(9);
|
||||
Cb_CItem_IsRoutingItem_Leave_Func["DPSOFFICIAL"] <- function (args)
|
||||
{
|
||||
return 0
|
||||
}
|
||||
}
|
||||
11
示例项目/史诗掉落奖励/Proj.ifo
Normal file
11
示例项目/史诗掉落奖励/Proj.ifo
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ProjectName": "史诗掉落奖励",
|
||||
"ProjectDescribe": "获取指定数量获得奖励以及指定道具获得奖励",
|
||||
"ProjectAuthor": "南瓜",
|
||||
"ProjectVersion": 1.1,
|
||||
"ProjectConfig": "史诗掉落奖励配置_南瓜.json",
|
||||
"ProjectFiles": [
|
||||
"史诗掉落奖励.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_Dps_SSDL_nangua_Main_"
|
||||
}
|
||||
333
示例项目/史诗掉落奖励/史诗掉落奖励.nut
Normal file
333
示例项目/史诗掉落奖励/史诗掉落奖励.nut
Normal file
@@ -0,0 +1,333 @@
|
||||
_SpecialItemBynangua <- {
|
||||
"Rarity4": {},
|
||||
"Rarity3": {},
|
||||
"Rarity2": {}
|
||||
}
|
||||
|
||||
function _Dps_SSDL_nangua_Main_() {
|
||||
//进入副本
|
||||
Cb_History_DungeonEnter_Func.RindroSSEnterByNangua <- function(SUser, Data) {
|
||||
_SpecialItemBynangua.Rarity4.rawset(SUser.GetCID(), []);
|
||||
_SpecialItemBynangua.Rarity3.rawset(SUser.GetCID(), []);
|
||||
_SpecialItemBynangua.Rarity2.rawset(SUser.GetCID(), []);
|
||||
}
|
||||
|
||||
//离开副本
|
||||
Cb_History_DungeonLeave_Func.RindroSSLeaveByNangua <- function(SUser, Data) {
|
||||
local Cofig = GlobalConfig.Get("史诗掉落奖励配置_南瓜.json");
|
||||
local PartyObj = SUser.GetParty();
|
||||
if (!PartyObj) return;
|
||||
local Bfobj = PartyObj.GetBattleField();
|
||||
local DgnObj = Bfobj.GetDgn();
|
||||
if (DgnObj) {
|
||||
local Dungeon_Name = DgnObj.GetName();
|
||||
|
||||
// 处理史诗装备
|
||||
if (_SpecialItemBynangua.Rarity4.rawin(SUser.GetCID())) {
|
||||
local ItemObjS = _SpecialItemBynangua.Rarity4[SUser.GetCID()];
|
||||
if (ItemObjS != null && ItemObjS.len() > 0) {
|
||||
local config = Cofig["奖励控制"]["多件SS对应奖励(史诗)"];
|
||||
local key = ItemObjS.len().tostring();
|
||||
if (config.rawin(key)) {
|
||||
Nangua_SSMSG.SendTitle(SUser, Dungeon_Name, "中获得史诗装备");
|
||||
foreach(ItemObj in ItemObjS) {
|
||||
local item_id = ItemObj.GetIndex();
|
||||
Nangua_SSMSG.ItemMsg(item_id, ItemObj);
|
||||
}
|
||||
Nangua_SSMSG.SendCntMsg(ItemObjS.len());
|
||||
Nangua_SSMSG.SendMiddle();
|
||||
ProcessRewards(SUser, config[key]);
|
||||
Nangua_SSMSG.EndMsg();
|
||||
}
|
||||
}
|
||||
_SpecialItemBynangua.Rarity4.rawset(SUser.GetCID(), []);
|
||||
}
|
||||
|
||||
// 处理神器装备
|
||||
if (_SpecialItemBynangua.Rarity3.rawin(SUser.GetCID())) {
|
||||
local ItemObjS = _SpecialItemBynangua.Rarity3[SUser.GetCID()];
|
||||
if (ItemObjS != null && ItemObjS.len() > 0) {
|
||||
local config = Cofig["奖励控制"]["多件神器对应奖励"];
|
||||
local key = ItemObjS.len().tostring();
|
||||
if (config.rawin(key)) {
|
||||
Nangua_SSMSG.SendTitle(SUser, Dungeon_Name, "中获得神器装备");
|
||||
foreach(ItemObj in ItemObjS) {
|
||||
local item_id = ItemObj.GetIndex();
|
||||
Nangua_SSMSG.ItemMsg(item_id, ItemObj);
|
||||
}
|
||||
Nangua_SSMSG.SendCntMsg(ItemObjS.len());
|
||||
Nangua_SSMSG.SendMiddle();
|
||||
ProcessRewards(SUser, config[key]);
|
||||
Nangua_SSMSG.EndMsg();
|
||||
}
|
||||
}
|
||||
_SpecialItemBynangua.Rarity3.rawset(SUser.GetCID(), []);
|
||||
}
|
||||
|
||||
// 处理稀有装备
|
||||
if (_SpecialItemBynangua.Rarity2.rawin(SUser.GetCID())) {
|
||||
local ItemObjS = _SpecialItemBynangua.Rarity2[SUser.GetCID()];
|
||||
if (ItemObjS != null && ItemObjS.len() > 0) {
|
||||
local config = Cofig["奖励控制"]["多件稀有对应奖励"];
|
||||
local key = ItemObjS.len().tostring();
|
||||
if (config.rawin(key)) {
|
||||
Nangua_SSMSG.SendTitle(SUser, Dungeon_Name, "中获得稀有装备");
|
||||
foreach(ItemObj in ItemObjS) {
|
||||
local item_id = ItemObj.GetIndex();
|
||||
Nangua_SSMSG.ItemMsg(item_id, ItemObj);
|
||||
}
|
||||
Nangua_SSMSG.SendCntMsg(ItemObjS.len());
|
||||
Nangua_SSMSG.SendMiddle();
|
||||
ProcessRewards(SUser, config[key]);
|
||||
Nangua_SSMSG.EndMsg();
|
||||
}
|
||||
}
|
||||
_SpecialItemBynangua.Rarity2.rawset(SUser.GetCID(), []);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Cb_UserHistoryLog_ItemAdd_Enter_Func.ItemAddByNangua <- function(args) {
|
||||
local Cofig = GlobalConfig.Get("史诗掉落奖励配置_南瓜.json");
|
||||
local SUser = User(NativePointer(args[0]).readPointer());
|
||||
local InvenObj = SUser.GetInven();
|
||||
local ItemObj = Item(args[4]);
|
||||
local type = args[5];
|
||||
local PartyObj = SUser.GetParty();
|
||||
if (!PartyObj) return;
|
||||
local Bfobj = PartyObj.GetBattleField();
|
||||
local DgnObj = Bfobj.GetDgn();
|
||||
if (!DgnObj) return;
|
||||
local Dungeon_Name = DgnObj.GetName();
|
||||
if (!ItemObj) return;
|
||||
local item_id = ItemObj.GetIndex();
|
||||
local ItemType = Sq_CallFunc(S_Ptr("0x085018D2"), "int", ["pointer", "int"], InvenObj.C_Object, item_id);
|
||||
local pvfitem = PvfItem.GetPvfItemById(item_id);
|
||||
|
||||
// 史诗装备记录
|
||||
if (pvfitem.GetRarity() == 4 && type == 4 && ItemType == 1 && Cofig["奖励控制"]["多件史诗奖励控制开关"]) {
|
||||
if (!_SpecialItemBynangua.Rarity4.rawin(SUser.GetCID())) {
|
||||
_SpecialItemBynangua.Rarity4.rawset(SUser.GetCID(), []);
|
||||
}
|
||||
_SpecialItemBynangua.Rarity4[SUser.GetCID()].append(ItemObj);
|
||||
}
|
||||
// 神器装备记录
|
||||
else if (pvfitem.GetRarity() == 3 && type == 4 && ItemType == 1 && Cofig["奖励控制"]["多件神器奖励控制开关"]) {
|
||||
if (!_SpecialItemBynangua.Rarity3.rawin(SUser.GetCID())) {
|
||||
_SpecialItemBynangua.Rarity3.rawset(SUser.GetCID(), []);
|
||||
}
|
||||
_SpecialItemBynangua.Rarity3[SUser.GetCID()].append(ItemObj);
|
||||
}
|
||||
// 稀有装备记录
|
||||
else if (pvfitem.GetRarity() == 2 && type == 4 && ItemType == 1 && Cofig["奖励控制"]["多件稀有奖励控制开关"]) {
|
||||
if (!_SpecialItemBynangua.Rarity2.rawin(SUser.GetCID())) {
|
||||
_SpecialItemBynangua.Rarity2.rawset(SUser.GetCID(), []);
|
||||
}
|
||||
_SpecialItemBynangua.Rarity2[SUser.GetCID()].append(ItemObj);
|
||||
}
|
||||
|
||||
// 指定道具奖励逻辑保持不变
|
||||
if (!Cofig["指定道具奖励控制"]["指定道具奖励控制开关"]) return;
|
||||
local Itemid = item_id.tostring();
|
||||
if (Cofig["指定道具奖励控制"]["指定道具对应奖励"].rawin(Itemid) && type == 4) {
|
||||
Nangua_SSMSG.SendTitle(SUser, Dungeon_Name, "中获得特定道具");
|
||||
Nangua_SSMSG.ItemMsg(item_id, ItemObj);
|
||||
Nangua_SSMSG.SendMiddle();
|
||||
ProcessRewards(SUser, Cofig["指定道具奖励控制"]["指定道具对应奖励"][Itemid]);
|
||||
Nangua_SSMSG.EndMsg();
|
||||
}
|
||||
}
|
||||
// 处理奖励逻辑
|
||||
function ProcessRewards(SUser, rewards) {
|
||||
local Cofig = GlobalConfig.Get("史诗掉落奖励配置_南瓜.json");
|
||||
local config = Cofig["信息播报"];
|
||||
local totalRewards = [];
|
||||
local rewardMessages = [];
|
||||
// 遍历奖励列表
|
||||
foreach(reward in rewards) {
|
||||
local itemId = reward[0];
|
||||
local itemCnt = reward[1];
|
||||
if (itemId == 0) {
|
||||
// 点券奖励
|
||||
local ceraMsgObj = AdMsg();
|
||||
ceraMsgObj.PutType(config["发送位置"]);
|
||||
if (config["发送位置"] != 14) {
|
||||
ceraMsgObj.PutString(" ");
|
||||
}
|
||||
ceraMsgObj.PutColorString("点券", config["内容颜色"]);
|
||||
ceraMsgObj.PutColorString("[" + itemCnt + "]", [255, 20, 0]);
|
||||
ceraMsgObj.Finalize();
|
||||
World.SendAll(ceraMsgObj.MakePack());
|
||||
ceraMsgObj.Delete();
|
||||
SUser.RechargeCera(itemCnt);
|
||||
} else {
|
||||
totalRewards.append([itemId, itemCnt]);
|
||||
local itemName = PvfItem.GetNameById(itemId);
|
||||
local color = Nangua_SSMSG.RarityColor(itemId);
|
||||
rewardMessages.append([itemName, itemCnt, color]);
|
||||
}
|
||||
}
|
||||
Nangua_SSMSG.api_CUser_Add_Item_list(SUser, totalRewards);
|
||||
// 发送奖励物品信息通知
|
||||
if (rewardMessages.len() > 0) {
|
||||
local rewardMsgObj = AdMsg();
|
||||
rewardMsgObj.PutType(config["发送位置"]);
|
||||
if (config["发送位置"] != 14) {
|
||||
rewardMsgObj.PutString(" ");
|
||||
}
|
||||
foreach(message in rewardMessages) {
|
||||
rewardMsgObj.PutColorString("[" + message[0] + "]", message[2]);
|
||||
rewardMsgObj.PutColorString("<" + message[1] + ">", [255, 20, 0]);
|
||||
rewardMsgObj.PutColorString("个", config["内容颜色"]);
|
||||
}
|
||||
rewardMsgObj.Finalize();
|
||||
World.SendAll(rewardMsgObj.MakePack());
|
||||
rewardMsgObj.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Nangua_SSMSG {
|
||||
function SendTitle(SUser, Dungeon_Name, msg) {
|
||||
local Cofig = GlobalConfig.Get("史诗掉落奖励配置_南瓜.json");
|
||||
local config = Cofig["信息播报"];
|
||||
local title = AdMsg();
|
||||
title.PutType(config["发送位置"]);
|
||||
if (config["发送位置"] != 14) {
|
||||
title.PutString(" ");
|
||||
}
|
||||
title.PutColorString(config["标题"][0], config["标题"][1]);
|
||||
title.PutColorString("恭喜玩家", config["内容颜色"]);
|
||||
title.PutColorString("[" + SUser.GetCharacName() + "]", [255, 20, 0]);
|
||||
title.PutColorString("在", config["内容颜色"]);
|
||||
title.PutColorString("[" + Dungeon_Name + "]", [255, 20, 0]);
|
||||
title.PutColorString("" + msg + "", config["内容颜色"]);
|
||||
title.Finalize();
|
||||
World.SendAll(title.MakePack());
|
||||
title.Delete();
|
||||
}
|
||||
|
||||
function SendMiddle() {
|
||||
local Cofig = GlobalConfig.Get("史诗掉落奖励配置_南瓜.json");
|
||||
local config = Cofig["信息播报"];
|
||||
local MiddleMsgObj = AdMsg();
|
||||
MiddleMsgObj.PutType(config["发送位置"]);
|
||||
if (config["发送位置"] != 14) {
|
||||
MiddleMsgObj.PutString(" ");
|
||||
}
|
||||
MiddleMsgObj.PutColorString("特此奖励:", config["内容颜色"]);
|
||||
MiddleMsgObj.Finalize();
|
||||
World.SendAll(MiddleMsgObj.MakePack());
|
||||
MiddleMsgObj.Delete();
|
||||
}
|
||||
|
||||
function SendCntMsg(cnt) {
|
||||
local Cofig = GlobalConfig.Get("史诗掉落奖励配置_南瓜.json");
|
||||
local config = Cofig["信息播报"];
|
||||
local CntMsgObj = AdMsg();
|
||||
CntMsgObj.PutType(config["发送位置"]);
|
||||
if (config["发送位置"] != 14) {
|
||||
CntMsgObj.PutString(" ");
|
||||
}
|
||||
CntMsgObj.PutColorString("合计", config["内容颜色"]);
|
||||
CntMsgObj.PutColorString("[" + cnt + "]", [255, 20, 0]);
|
||||
CntMsgObj.PutColorString("件装备", config["内容颜色"]);
|
||||
CntMsgObj.Finalize();
|
||||
World.SendAll(CntMsgObj.MakePack());
|
||||
CntMsgObj.Delete();
|
||||
}
|
||||
|
||||
function ItemMsg(item_id, ItemObj) {
|
||||
local Cofig = GlobalConfig.Get("史诗掉落奖励配置_南瓜.json");
|
||||
local config = Cofig["信息播报"];
|
||||
local MsgObj = AdMsg();
|
||||
MsgObj.PutType(config["发送位置"]);
|
||||
if (config["发送位置"] != 14) {
|
||||
MsgObj.PutString(" ");
|
||||
}
|
||||
MsgObj.PutEquipment("[" + PvfItem.GetNameById(item_id) + "]", ItemObj, Nangua_SSMSG.RarityColor(item_id));
|
||||
MsgObj.Finalize();
|
||||
World.SendAll(MsgObj.MakePack());
|
||||
MsgObj.Delete();
|
||||
}
|
||||
|
||||
function EndMsg() {
|
||||
local Cofig = GlobalConfig.Get("史诗掉落奖励配置_南瓜.json");
|
||||
local config = Cofig["信息播报"];
|
||||
local endMsgObj = AdMsg();
|
||||
endMsgObj.PutType(config["发送位置"]);
|
||||
if (config["发送位置"] != 14) {
|
||||
endMsgObj.PutString(" ");
|
||||
}
|
||||
endMsgObj.PutColorString(config["结尾"][0], config["结尾"][1]);
|
||||
endMsgObj.Finalize();
|
||||
World.SendAll(endMsgObj.MakePack());
|
||||
endMsgObj.Delete();
|
||||
}
|
||||
function api_CUser_Add_Item_list(SUser, item_list) {
|
||||
for (local i = 0; i < item_list.len(); i++) {
|
||||
local item_id = item_list[i][0]; // 道具代码
|
||||
local quantity = item_list[i][1]; // 道具数量
|
||||
local cnt = Nangua_SSMSG.checkInventorySlot(SUser, item_id);
|
||||
if (cnt == 1) {
|
||||
SUser.GiveItem(item_id, quantity); //使用窗口发送奖励
|
||||
} else {
|
||||
local RewardItems = [];
|
||||
RewardItems.append([item_id, quantity]);
|
||||
local title = "GM"
|
||||
local Text = "由于背包空间不足,已通过邮件发送,请查收!"
|
||||
//角色类 发送邮件函数 (标题, 正文, 金币, 道具列表[[3037,100],[3038,100]])
|
||||
SUser.ReqDBSendMultiMail(title, Text, 0, RewardItems)
|
||||
}
|
||||
}
|
||||
Nangua_SSMSG.SendItemWindowNotification(SUser, item_list);
|
||||
}
|
||||
function SendItemWindowNotification(SUser, item_list) {
|
||||
local Pack = Packet();
|
||||
Pack.Put_Header(1, 163); //协议
|
||||
Pack.Put_Byte(1); //默认1
|
||||
Pack.Put_Short(0); //槽位id 填入0即可
|
||||
Pack.Put_Int(0); //未知 0以上即可
|
||||
Pack.Put_Short(item_list.len()); //道具组数
|
||||
//写入道具代码和道具数量
|
||||
for (local i = 0; i < item_list.len(); i++) {
|
||||
Pack.Put_Int(item_list[i][0]); //道具代码
|
||||
Pack.Put_Int(item_list[i][1]); //道具数量 装备/时装时 任意均可
|
||||
}
|
||||
Pack.Finalize(true); //确定发包内容
|
||||
SUser.Send(Pack); //发包
|
||||
Pack.Delete(); //清空buff区
|
||||
}
|
||||
/**
|
||||
* 根据道具类型背包空格数量
|
||||
* @param {pointer} SUser - 用户
|
||||
* @param {int} item_id - 需要查找的道具ID
|
||||
* @returns {int} - 空格数量
|
||||
*/
|
||||
function checkInventorySlot(SUser, itemid) {
|
||||
local InvenObj = SUser.GetInven();
|
||||
local type = Sq_CallFunc(S_Ptr("0x085018D2"), "int", ["pointer", "int"], InvenObj.C_Object, itemid);
|
||||
local cnt = Sq_CallFunc(S_Ptr("0x08504F64"), "int", ["pointer", "int", "int"], InvenObj.C_Object, type, 1);
|
||||
|
||||
return cnt;
|
||||
}
|
||||
function RarityColor(item_id) {
|
||||
local PvfItemObj = PvfItem.GetPvfItemById(item_id);
|
||||
if (PvfItemObj == null) {
|
||||
return;
|
||||
}
|
||||
local CItem_get_rarity = PvfItemObj.GetRarity(); // 装备品级
|
||||
return Nangua_SSMSG.rarityColorMap[(CItem_get_rarity).tostring()];
|
||||
}
|
||||
//品级对应的RGB
|
||||
rarityColorMap = {
|
||||
"0": [255, 255, 255], // 普通
|
||||
"1": [104, 213, 237], // 高级
|
||||
"2": [179, 107, 255], // 稀有
|
||||
"3": [255, 0, 255], // 神器
|
||||
"4": [255, 180, 0], // 史诗
|
||||
"5": [255, 102, 102], // 勇者
|
||||
"6": [255, 20, 147], // 深粉红色
|
||||
"7": [255, 215, 0] // 金色
|
||||
};
|
||||
}
|
||||
94
示例项目/史诗掉落奖励/史诗掉落奖励配置_南瓜.json
Normal file
94
示例项目/史诗掉落奖励/史诗掉落奖励配置_南瓜.json
Normal file
@@ -0,0 +1,94 @@
|
||||
{
|
||||
"奖励控制": {
|
||||
"开关说明(true为开启,false为关闭)这是提示请无视,后面的0也不用管":0,
|
||||
"多件史诗奖励控制开关": true,
|
||||
"多件神器奖励控制开关": false,
|
||||
"多件稀有奖励控制开关": false,
|
||||
"稀有装备开关如果开启会导致可以在副本内丢弃拾取领取奖励,需搭配禁止丢弃物品使用(这是提示请无视,后面的0也不用管)":0,
|
||||
"tips>>>如果奖励填0代表点券(这是提示请无视,后面的0也不用管)":0,
|
||||
"多件SS对应奖励(史诗)": {
|
||||
"2": [
|
||||
[3038, 2],
|
||||
[3037, 10]
|
||||
],
|
||||
"3": [
|
||||
[0, 10000],
|
||||
[123014, 10]
|
||||
],
|
||||
"4": [
|
||||
[0, 50000],
|
||||
[3037, 2000],
|
||||
[3038, 2000]
|
||||
],
|
||||
"5": [
|
||||
[0, 50000],
|
||||
[3037, 2000],
|
||||
[3038, 2000]
|
||||
]
|
||||
},
|
||||
"多件神器对应奖励": {
|
||||
"2": [
|
||||
[3038, 1],
|
||||
[3037, 5]
|
||||
],
|
||||
"3": [
|
||||
[0, 5000],
|
||||
[123014, 5]
|
||||
],
|
||||
"4": [
|
||||
[0, 20000],
|
||||
[3037, 1000],
|
||||
[3038, 1000]
|
||||
],
|
||||
"5": [
|
||||
[0, 20000],
|
||||
[3037, 1000],
|
||||
[3038, 1000]
|
||||
]
|
||||
},
|
||||
"多件稀有对应奖励": {
|
||||
"2": [
|
||||
[3038, 1],
|
||||
[3037, 2]
|
||||
],
|
||||
"3": [
|
||||
[0, 2000],
|
||||
[123014, 2]
|
||||
],
|
||||
"4": [
|
||||
[0, 10000],
|
||||
[3037, 500],
|
||||
[3038, 500]
|
||||
],
|
||||
"5": [
|
||||
[0, 10000],
|
||||
[3037, 500],
|
||||
[3038, 500]
|
||||
]
|
||||
}
|
||||
},
|
||||
"指定道具奖励控制": {
|
||||
"指定道具奖励控制开关": true,
|
||||
"指定道具对应奖励": {
|
||||
"3037": [
|
||||
[3038, 2],
|
||||
[3037, 10]
|
||||
],
|
||||
"3038": [
|
||||
[0, 10000],
|
||||
[123014, 10]
|
||||
],
|
||||
"3039": [
|
||||
[0, 50000],
|
||||
[3037, 2000],
|
||||
[3038, 2000]
|
||||
]
|
||||
}
|
||||
},
|
||||
"信息播报":{
|
||||
"发送位置":14,
|
||||
"标题":["-----------☆天降鸿运☆--------------", [255, 130, 0]],
|
||||
"内容颜色":[255, 120, 0],
|
||||
"结尾":["-----------☆恭喜这逼☆--------------", [255, 130, 0]]
|
||||
}
|
||||
}
|
||||
11
示例项目/史诗药剂/Proj.ifo
Normal file
11
示例项目/史诗药剂/Proj.ifo
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ProjectName": "史诗药剂",
|
||||
"ProjectDescribe": "在单人深渊中使用指定ID的道具使玩家获得爆率加成。(组队无效),史诗药剂道具的冷却时间和持续时间需一致!!",
|
||||
"ProjectAuthor": "倾泪寒 & 南瓜",
|
||||
"ProjectVersion": 1.7,
|
||||
"ProjectConfig": "史诗药剂配置文件.json",
|
||||
"ProjectFiles": [
|
||||
"史诗药剂.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_Dps_EpicPotion_Main_"
|
||||
}
|
||||
47
示例项目/史诗药剂/史诗药剂.nut
Normal file
47
示例项目/史诗药剂/史诗药剂.nut
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
文件名:史诗药剂.nut
|
||||
路径:MyProject/史诗药剂.nut
|
||||
创建日期:2025-03-28 10:21
|
||||
文件用途:史诗药剂
|
||||
*/
|
||||
|
||||
//启动函数 自定义的需要写在ifo中
|
||||
function _Dps_EpicPotion_Main_() {
|
||||
//注册获取道具稀有度进入回调
|
||||
Cb_GetItemRarity_Enter_Func["史诗药剂_逻辑"] <- function(args) {
|
||||
// print("获取道具稀有度进入回调");
|
||||
local Cofig = GlobalConfig.Get("史诗药剂配置文件.json");
|
||||
local Addr = NativePointer(args[0]);
|
||||
local VectorSize = (Addr.add(4).readU32() - Addr.readU32()) / 4;
|
||||
// 遍历队伍成员,找到使用了史诗药剂的玩家
|
||||
local userWithPotion = null;
|
||||
for (local i = 0; i< VectorSize; i++) {
|
||||
local elementAddr = NativePointer(Addr.readPointer()).add(i * 4);
|
||||
local user = elementAddr.readPointer();
|
||||
if (user && Sq_CallFunc(S_Ptr("0x865E994"), "int", ["pointer", "int"], user, Cofig["史诗药剂ID"])) {
|
||||
userWithPotion = User(user);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (userWithPotion && Haker.NextReturnAddress == "0x853583a") {
|
||||
local partyobj = userWithPotion.GetParty();
|
||||
// 检查是否单人
|
||||
if (Sq_CallFunc(S_Ptr("0x0859A16A"), "int", ["pointer", ], partyobj.C_Object) == 1) {
|
||||
local MaxRoll = NativePointer(args[1]).add(16).readU32();
|
||||
local odds = Cofig["史诗药剂默认加成几率"]; // 默认药剂的增加几率
|
||||
// 检查是否VIP玩家
|
||||
local charac_no = userWithPotion.GetCID();
|
||||
local cfg = Cofig["指定角色ID额外叠加加成几率"];
|
||||
local key = charac_no.tostring();
|
||||
if (cfg != null && cfg.rawin(key)) {
|
||||
odds = cfg[key];
|
||||
//print("VIP玩家:" + key + " 加成几率:" + odds);
|
||||
}
|
||||
// 计算新的roll值
|
||||
args[2] = MathClass.getMin(args[2] + args[2] * odds, MaxRoll);
|
||||
// print("新的roll值:" + args[2] + " 加成几率:" + odds + " 最大roll值:" + MaxRoll + " 角色ID:" + charac_no);
|
||||
}
|
||||
}
|
||||
return args;
|
||||
}
|
||||
}
|
||||
14
示例项目/史诗药剂/史诗药剂配置文件.json
Normal file
14
示例项目/史诗药剂/史诗药剂配置文件.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"史诗药剂ID": 2600010,
|
||||
"史诗药剂默认加成几率": 0.2,
|
||||
"指定角色ID额外叠加加成几率": {
|
||||
"1": 1.0,
|
||||
"2": 1.0
|
||||
},
|
||||
"提示1": "史诗药剂道具的冷却时间和持续时间需一致否则无效!!!",
|
||||
"提示2": "比如默认几率是0.2,指定角色ID是1,那么最终几率是0.2+1=1.2",
|
||||
"提示3": "群文件中有史诗药剂的stk文件,可以自行修改!!!",
|
||||
"提示4": "角色ID可以查看数据库中 taiwan_cain → charac_info → charac_no代表角色ID",
|
||||
"提示5": "0.1几率是加成10%以此类推,受幸运值影响,具体加成请自行测算!",
|
||||
"提示6": "2600010是和平呐喊的道具ID,用此道具有图标提示以及时间提示,但是具体字符串相关自行解决"
|
||||
}
|
||||
11
示例项目/在线泡点/Proj.ifo
Normal file
11
示例项目/在线泡点/Proj.ifo
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ProjectName": "在线泡点",
|
||||
"ProjectDescribe": "根据设定时间间隔给与点券或代币活跃奖励",
|
||||
"ProjectAuthor": "南瓜",
|
||||
"ProjectVersion": 1.0,
|
||||
"ProjectConfig": "在线泡点配置_Nangua.json",
|
||||
"ProjectFiles": [
|
||||
"在线泡点.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_Dps_Online_rewardsBynangua_Main_"
|
||||
}
|
||||
97
示例项目/在线泡点/在线泡点.nut
Normal file
97
示例项目/在线泡点/在线泡点.nut
Normal file
@@ -0,0 +1,97 @@
|
||||
_total_rewardBynangua <- {}; // 存储每个玩家的累计奖励
|
||||
|
||||
function _Online_rewardsBynangua() {
|
||||
local Config = GlobalConfig.Get("在线泡点配置_Nangua.json");
|
||||
local OnlinePlayerList = World.GetOnlinePlayer();
|
||||
|
||||
// 发放奖励
|
||||
foreach(SUser in OnlinePlayerList) {
|
||||
local IP = _Online_rewardsBynangua_api.CUser_get_public_ip_address(SUser);
|
||||
if (!Config["是否发放奖励给假人(true发放/false不发放)"] && IP == Config["离线假人IP"]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 获取奖励类型和数量
|
||||
local isCera = Config["在线泡点配置"]["奖励类型(true点券/false代币)"];
|
||||
local rewardAmount = isCera ? Config["在线泡点配置"]["点券奖励"] : Config["在线泡点配置"]["代币奖励"];
|
||||
|
||||
if (rewardAmount > 0) {
|
||||
// 初始化累计奖励
|
||||
if (!(SUser.GetCID() in _total_rewardBynangua)) {
|
||||
_total_rewardBynangua[SUser.GetCID()] <- 0;
|
||||
}
|
||||
_total_rewardBynangua[SUser.GetCID()] += rewardAmount;
|
||||
|
||||
// 发放奖励
|
||||
if (isCera) {
|
||||
SUser.RechargeCera(rewardAmount);
|
||||
} else {
|
||||
SUser.RechargeCeraPoint(rewardAmount);
|
||||
}
|
||||
|
||||
// 发送消息
|
||||
local AdMsgObj = AdMsg();
|
||||
AdMsgObj.PutType(Config["在线泡点配置"]["信息发送位置"]);
|
||||
if (Config["在线泡点配置"]["信息发送位置"] != 14) {
|
||||
AdMsgObj.PutString(" ");
|
||||
}
|
||||
AdMsgObj.PutImoticon(Config["在线泡点配置"]["图标"]);
|
||||
AdMsgObj.PutColorString(Config["在线泡点配置"]["标题"], Config["在线泡点配置"]["文字颜色rgb"]);
|
||||
AdMsgObj.PutColorString("[" + rewardAmount + "]", Config["在线泡点配置"]["数量颜色rgb"]);
|
||||
AdMsgObj.PutColorString(Config["在线泡点配置"]["奖励内容(代币/点券)"], Config["在线泡点配置"]["文字颜色rgb"]);
|
||||
AdMsgObj.PutColorString(Config["在线泡点配置"]["奖励"], Config["在线泡点配置"]["文字颜色rgb"]);
|
||||
AdMsgObj.PutColorString("[" + _total_rewardBynangua[SUser.GetCID()] + "]", Config["在线泡点配置"]["数量颜色rgb"]);
|
||||
AdMsgObj.PutColorString(Config["在线泡点配置"]["奖励内容(代币/点券)"], Config["在线泡点配置"]["文字颜色rgb"]);
|
||||
AdMsgObj.Finalize();
|
||||
SUser.Send(AdMsgObj.MakePack());
|
||||
AdMsgObj.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 在线泡点活动入口点
|
||||
function _Dps_Online_rewardsBynangua_Main_() {
|
||||
_Dps_Online_rewardsBynangua_Logic_();
|
||||
}
|
||||
|
||||
// 在线泡点活动重载入口点
|
||||
function _Dps_Online_rewardsBynangua_Main_Reload_(OldConfig) {
|
||||
// 先移除旧的定时任务
|
||||
Timer.RemoveCronTask("OnlineRewardTask");
|
||||
|
||||
// 重新注册
|
||||
_Dps_Online_rewardsBynangua_Logic_();
|
||||
// 清理缓存
|
||||
_total_rewardBynangua <- {};
|
||||
}
|
||||
|
||||
// 在线泡点活动逻辑入口点
|
||||
function _Dps_Online_rewardsBynangua_Logic_() {
|
||||
local Config = GlobalConfig.Get("在线泡点配置_Nangua.json");
|
||||
local interval = Config["在线泡点配置"]["时间间隔(分钟)"];
|
||||
local cronExpression = format("0 */%d * * * *", interval);
|
||||
// 注册定时任务
|
||||
Timer.SetCronTask(_Online_rewardsBynangua, {
|
||||
Cron = cronExpression,
|
||||
Name = "OnlineRewardTask"
|
||||
});
|
||||
}
|
||||
|
||||
class _Online_rewardsBynangua_api {
|
||||
function CUser_get_public_ip_address(SUser){
|
||||
local s_addr = Sq_CallFunc(S_Ptr("0x084EC90A"), "int", ["pointer"], SUser.C_Object);
|
||||
if(s_addr){
|
||||
local inet_ntoa = Sq_CallFunc(S_Ptr("0x0807DDC0"), "pointer", ["int"], s_addr);
|
||||
return NativePointer(inet_ntoa).readUtf8String();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 玩家下线时,清空累计奖励
|
||||
Cb_CUser_LogoutToPCRoom_Enter_Func.Online_rewardsBynangua <- function(args) {
|
||||
local SUser = User(args[0]);
|
||||
if (SUser.GetCID() in _total_rewardBynangua) {
|
||||
_total_rewardBynangua.rawdelete(SUser.GetCID());
|
||||
}
|
||||
}
|
||||
17
示例项目/在线泡点/在线泡点配置_Nangua.json
Normal file
17
示例项目/在线泡点/在线泡点配置_Nangua.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"在线泡点配置": {
|
||||
"时间间隔(分钟)":1,
|
||||
"点券奖励":10,
|
||||
"代币奖励":10,
|
||||
"奖励类型(true点券/false代币)":true,
|
||||
"信息发送位置":0,
|
||||
"图标":1,
|
||||
"文字颜色rgb":[120, 255, 0],
|
||||
"数量颜色rgb":[255, 215, 0],
|
||||
"标题":"活跃奖励获得",
|
||||
"奖励内容(代币/点券)":"点券",
|
||||
"奖励":" 累计获得"
|
||||
},
|
||||
"是否发放奖励给假人(true发放/false不发放)":false,
|
||||
"离线假人IP":"10.0.0.1"
|
||||
}
|
||||
11
示例项目/多彩蜜蜡改跨界石/Proj.ifo
Normal file
11
示例项目/多彩蜜蜡改跨界石/Proj.ifo
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ProjectName": "多彩蜜蜡改跨界石",
|
||||
"ProjectDescribe": "将物品跨界存放至账号仓库,需dll或启动器支持,否则无法放入物品",
|
||||
"ProjectAuthor": "南瓜",
|
||||
"ProjectVersion": 1.0,
|
||||
"ProjectConfig": "多彩蜜蜡改跨界石_Nangua.json",
|
||||
"ProjectFiles": [
|
||||
"多彩蜜蜡改跨界石.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_Dps_Cross_Stone_Main_"
|
||||
}
|
||||
108
示例项目/多彩蜜蜡改跨界石/多彩蜜蜡改跨界石.nut
Normal file
108
示例项目/多彩蜜蜡改跨界石/多彩蜜蜡改跨界石.nut
Normal file
@@ -0,0 +1,108 @@
|
||||
function _Dps_Cross_Stone_Main_() {
|
||||
Cb_ModItemattr_Enter_Func.Cross_Stone <- function(args) {
|
||||
local SUser = User(args[1]);
|
||||
local pack = NativePointer(args[2]);
|
||||
local a = NativePointer(pack.add(20).readPointer());
|
||||
local itemSlot = a.add(13).add(6).readShort();
|
||||
local equSlot = a.add(13).add(0).readShort();
|
||||
local InvenObj = SUser.GetInven();
|
||||
if (InvenObj) {
|
||||
local ItemObj = InvenObj.GetSlot(1, itemSlot);
|
||||
if (ItemObj.GetIndex() == 2675422) {
|
||||
Sq_WriteByteArr(S_Ptr("0x820110E"), array(5, 0x90));
|
||||
Sq_WriteByteArr(S_Ptr("0x8201647"), array(5, 0x90));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Cb_ModItemattr_Leave_Func.Cross_Stone <- function(args) {
|
||||
local Config = GlobalConfig.Get("多彩蜜蜡改跨界石_Nangua.json");
|
||||
local SUser = User(args[1]);
|
||||
local pack = NativePointer(args[2]);
|
||||
local a = NativePointer(pack.add(20).readPointer());
|
||||
local itemSlot = a.add(13).add(6).readShort();
|
||||
local equSlot = a.add(13).add(0).readShort();
|
||||
local InvenObj = SUser.GetInven();
|
||||
local result = 0;
|
||||
if (InvenObj) {
|
||||
local ItemObj = InvenObj.GetSlot(1, itemSlot);
|
||||
local equObj = InvenObj.GetSlot(1, equSlot);
|
||||
if (ItemObj.GetIndex() == 2675422) {
|
||||
local PvfItemObj = PvfItem.GetPvfItemById(equObj.GetIndex());
|
||||
local qixi1 = NativePointer(equObj.C_Object).add(31).readU8();
|
||||
local qixi2 = NativePointer(equObj.C_Object).add(32).readU8();
|
||||
local ItemType = NativePointer(PvfItemObj.C_Object).add(141 * 4).readU32();
|
||||
//获取账号金库对象
|
||||
local CargoObj = SUser.GetAccountCargo();
|
||||
//获取账号金库中的一个空格子
|
||||
local EmptySlot = CargoObj.GetEmptySlot();
|
||||
local CheckItemLock = Sq_CallFunc(S_Ptr("0x8646942"), "int", ["pointer", "int", "int"], SUser.C_Object, 1, equSlot);
|
||||
if (CheckItemLock) {
|
||||
_Cross_StoneBynangua.CUser_SendCmdErrorPacket(SUser, 84, 13)
|
||||
} else if(qixi1 > 0 || qixi2 > 0) {
|
||||
_Cross_StoneBynangua.sendNotification(SUser, true, itemSlot, Config["跨界失败提示4"]);
|
||||
_Cross_StoneBynangua.CUser_SendCmdErrorPacket(SUser, 84, 13)
|
||||
} else if (Config["不可跨界装备"].find(equObj.GetIndex()) != null) {
|
||||
_Cross_StoneBynangua.sendNotification(SUser, true, itemSlot, format(Config["跨界失败提示2"], PvfItem.GetNameById(equObj.GetIndex())));
|
||||
_Cross_StoneBynangua.CUser_SendCmdErrorPacket(SUser, 84, 13)
|
||||
} else if (Config["不可跨界的装备类型"].find(ItemType) != null) {
|
||||
_Cross_StoneBynangua.sendNotification(SUser, true, itemSlot, Config["跨界失败提示3"]);
|
||||
_Cross_StoneBynangua.CUser_SendCmdErrorPacket(SUser, 84, 13)
|
||||
} else if (EmptySlot == -1) {
|
||||
_Cross_StoneBynangua.sendNotification(SUser, true, itemSlot, Config["跨界失败提示1"]);
|
||||
_Cross_StoneBynangua.CUser_SendCmdErrorPacket(SUser, 84, 13)
|
||||
} else {
|
||||
local Flag = CargoObj.InsertItem(equObj, EmptySlot);
|
||||
if (Flag == -1) {
|
||||
_Cross_StoneBynangua.sendNotification(SUser, true, itemSlot, Config["跨界失败提示5"]);
|
||||
_Cross_StoneBynangua.CUser_SendCmdErrorPacket(SUser, 84, 13)
|
||||
} else {
|
||||
local num = NativePointer(ItemObj.C_Object).add(7).readU32();
|
||||
_Cross_StoneBynangua.SendConsume(SUser, itemSlot, num);
|
||||
//销毁背包中的道具
|
||||
equObj.Delete();
|
||||
//刷新玩家背包列表
|
||||
SUser.SendUpdateItemList(1, 0, equSlot);
|
||||
//刷新账号金库列表
|
||||
Timer.SetTimeOut(function() {
|
||||
CargoObj.SendItemList();
|
||||
}, 1);
|
||||
_Cross_StoneBynangua.sendNotification(SUser, false, itemSlot, format(Config["跨界成功提示"], PvfItem.GetNameById(equObj.GetIndex())));
|
||||
}
|
||||
}
|
||||
Sq_WriteByteArr(S_Ptr("0x820110E"), [0x3D, 0x4E, 0xD1, 0x28, 0x00]);
|
||||
Sq_WriteByteArr(S_Ptr("0x8201647"), [0xE8, 0xEC, 0x02, 0x00, 0x00]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
class _Cross_StoneBynangua {
|
||||
function sendNotification(SUser, bool, slot, message) {
|
||||
local Config = GlobalConfig.Get("多彩蜜蜡改跨界石_Nangua.json");
|
||||
if(bool){
|
||||
SUser.GiveItem(2675422, 1);
|
||||
SUser.SendUpdateItemList(1, 0, slot);
|
||||
}
|
||||
if (Config["233弹窗提示开启(true开启/false关闭)"]) {
|
||||
SUser.SendNotiBox(message, 1);
|
||||
} else {
|
||||
SUser.SendNotiPacketMessage(message, 8);
|
||||
}
|
||||
}
|
||||
function CUser_SendCmdErrorPacket(SUser, a, b) {
|
||||
return Sq_CallFunc(S_Ptr("0x0867BF42"), "int", ["pointer", "int", "int"], SUser.C_Object, a, b);
|
||||
}
|
||||
function SendConsume(SUser,ItemSlot,num){
|
||||
local Pack = Packet();
|
||||
Pack.Put_Header(1, 84);
|
||||
Pack.Put_Byte(1);
|
||||
Pack.Put_Short(ItemSlot);
|
||||
Pack.Put_Int(num);
|
||||
Pack.Put_Short(2);
|
||||
Pack.Finalize(true);
|
||||
SUser.Send(Pack);
|
||||
Pack.Delete();
|
||||
}
|
||||
}
|
||||
15
示例项目/多彩蜜蜡改跨界石/多彩蜜蜡改跨界石_Nangua.json
Normal file
15
示例项目/多彩蜜蜡改跨界石/多彩蜜蜡改跨界石_Nangua.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"请看这里": "此功能需要登录器支持或者dll支持,否则无法使用(多彩蜜蜡)",
|
||||
"跨界成功提示": "已成功将 [%s] 跨界存放至账号仓库",
|
||||
"跨界失败提示1": "账号仓库已满 无法进行跨界",
|
||||
"跨界失败提示2": "跨界失败, [%s] 不可以跨界",
|
||||
"跨界失败提示3": "跨界失败, 该装备类型无法跨界",
|
||||
"跨界失败提示4": "跨界失败, 携带异界气息的装备无法进行跨界",
|
||||
"跨界失败提示5": "跨界失败",
|
||||
"不可跨界装备": [270981, 33333],
|
||||
"不可跨界的装备类型":[10],
|
||||
"装备类型(10武器 11称号 12上衣 13头肩 14下装 15鞋子 16腰带 17项链 18手镯 19戒指 20左槽 21右槽)":"",
|
||||
"跨界石固定道具ID为2675422更改无效": "",
|
||||
"233弹窗提示开启(true开启/false关闭)":true,
|
||||
"提示":"开启弹窗提示需在群文件下载 <客户端消息框233.dll> 插件,否则会导致游戏崩溃"
|
||||
}
|
||||
11
示例项目/宠物附魔/Proj.ifo
Normal file
11
示例项目/宠物附魔/Proj.ifo
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ProjectName": "宠物附魔",
|
||||
"ProjectDescribe": "可以实现宠物附魔,需要登录器或dll支持!",
|
||||
"ProjectAuthor": "七游云赞助",
|
||||
"ProjectVersion": 1.0,
|
||||
"ProjectConfig": "",
|
||||
"ProjectFiles": [
|
||||
"宠物附魔.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_Dps_PetEnchantment_Main_"
|
||||
}
|
||||
84
示例项目/宠物附魔/宠物附魔.nut
Normal file
84
示例项目/宠物附魔/宠物附魔.nut
Normal file
@@ -0,0 +1,84 @@
|
||||
function _Dps_UpdateCreatureEnchantMysql_(card_id, charac_no, uuid) {
|
||||
local sql = "select card from `taiwan_cain_2nd`.`creature_items_enchant` where ui_id = " + uuid + ";";
|
||||
local column_type_list = ["int"];
|
||||
local SqlObj = MysqlPool.GetInstance().GetConnect();
|
||||
local result = SqlObj.Select(sql, column_type_list);
|
||||
local UpdateSql = "update `taiwan_cain_2nd`.`creature_items_enchant` set `card` = " + card_id + " where `ui_id` = " + uuid + ";";
|
||||
if (result.len() <= 0 || result[0].len() <= 0) {
|
||||
UpdateSql = "INSERT INTO `taiwan_cain_2nd`.`creature_items_enchant`(`ui_id`, `charac_no`, `card`) VALUES (" + uuid + "," + charac_no + "," + card_id + ");";
|
||||
}
|
||||
SqlObj.Exec_Sql(UpdateSql);
|
||||
MysqlPool.GetInstance().PutConnect(SqlObj);
|
||||
}
|
||||
|
||||
function _Dps_GetCreatureEnchantMysql_(charac_no) {
|
||||
local sql = "select ui_id,card from `taiwan_cain_2nd`.`creature_items_enchant` where charac_no = " + charac_no + ";";
|
||||
local column_type_list = ["int", "int"];
|
||||
local SqlObj = MysqlPool.GetInstance().GetConnect();
|
||||
local result = SqlObj.Select(sql, column_type_list);
|
||||
MysqlPool.GetInstance().PutConnect(SqlObj);
|
||||
return result;
|
||||
}
|
||||
|
||||
function _Dps_PetEnchantment_Main_() {
|
||||
//初始建表指令
|
||||
local CreateSql = "CREATE TABLE `taiwan_cain_2nd`.`creature_items_enchant` (`ui_id` int(11) NOT NULL DEFAULT '0',`charac_no` int(11) DEFAULT NULL,`card` int(11) NOT NULL DEFAULT '0',PRIMARY KEY (`ui_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;";
|
||||
local SqlObj = MysqlPool.GetInstance().GetConnect();
|
||||
SqlObj.Exec_Sql(CreateSql);
|
||||
MysqlPool.GetInstance().PutConnect(SqlObj);
|
||||
//忽略宠物附魔错误
|
||||
Sq_WriteByteArr(S_Ptr("0x850dede"), array(2, 0x90));
|
||||
|
||||
Cb_ExpertOnEnchantByBead_Leave_Func["宠物附魔"] <- function(args) {
|
||||
if (args[5] > 56) {
|
||||
local SUser = User(args[1]);
|
||||
local InvenObj = SUser.GetInven();
|
||||
local Bead_id = InvenObj.GetSlot(1, args[3]).GetIndex()
|
||||
local PvfItemObj = PvfItem.GetPvfItemById(InvenObj.GetSlot(1, args[3]).GetIndex())
|
||||
local Card_Id = Sq_CallFunc(S_Ptr("0x0849F530"), "int", ["pointer"], PvfItemObj.C_Object);
|
||||
local a7 = args[5] - 57;
|
||||
local ItemObj = InvenObj.GetSlot(3, a7)
|
||||
local Item_Id = ItemObj.GetIndex();
|
||||
NativePointer(ItemObj.C_Object).add(13).writeU32(Card_Id);
|
||||
if (a7< 140) {
|
||||
local uuid = NativePointer(ItemObj.C_Object).add(7).readInt();
|
||||
_Dps_UpdateCreatureEnchantMysql_(Card_Id, SUser.GetCID(), uuid);
|
||||
}
|
||||
local Pack = Packet();
|
||||
Pack.Put_Header(1, 275);
|
||||
Pack.Put_Byte(1);
|
||||
Pack.Finalize(true);
|
||||
SUser.Send(Pack);
|
||||
Pack.Delete();
|
||||
SUser.SendUpdateItemList(1, 7, a7);
|
||||
InvenObj.DeleteItemCount(Bead_id, 1);
|
||||
SUser.SendUpdateItemList(1, 0, args[3]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Cb_reach_game_world_Func["宠物附魔"] <- function(SUser) {
|
||||
local Data = _Dps_GetCreatureEnchantMysql_(SUser.GetCID());
|
||||
local DMap = {};
|
||||
foreach(data_obj in Data) {
|
||||
local uuid = data_obj[0];
|
||||
local card_id = data_obj[1];
|
||||
DMap.rawset(uuid, card_id);
|
||||
}
|
||||
local InvenObj = SUser.GetInven();
|
||||
for (local i = 0; i< 141; i++) {
|
||||
local equ;
|
||||
if (i == 140) {
|
||||
equ = InvenObj.GetSlot(0, 22); //获取当前格子的宠物
|
||||
} else {
|
||||
equ = InvenObj.GetSlot(3, i);
|
||||
}
|
||||
local equ_uuid = NativePointer(equ.C_Object).add(7).readInt();
|
||||
if (DMap.rawin(equ_uuid)) {
|
||||
NativePointer(equ.C_Object).add(13).writeU32(DMap[equ_uuid]);
|
||||
if (i == 140) SUser.SendUpdateItemList(1, 0, 22);
|
||||
else SUser.SendUpdateItemList(1, 7, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
示例项目/异界重置/Proj.ifo
Normal file
11
示例项目/异界重置/Proj.ifo
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ProjectName": "异界重置",
|
||||
"ProjectDescribe": "异界重置",
|
||||
"ProjectAuthor": "南瓜",
|
||||
"ProjectVersion": 1.1,
|
||||
"ProjectConfig": "异界重置_Lenheart.json",
|
||||
"ProjectFiles": [
|
||||
"异界重置.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_Dps_MapReset_Main_"
|
||||
}
|
||||
39
示例项目/异界重置/异界重置.nut
Normal file
39
示例项目/异界重置/异界重置.nut
Normal file
@@ -0,0 +1,39 @@
|
||||
function ResetDimensionInout(SUser, index) {
|
||||
local data_manager = Sq_CallFunc(S_Ptr("0x80CC19B"), "pointer");
|
||||
local dimensionInout = Sq_CallFunc(S_Ptr("0x0822b612"), "int", ["pointer", "int"], data_manager, index);
|
||||
Sq_CallFunc(S_Ptr("0x0822f184"), "int", ["pointer", "int", "int"], SUser.C_Object, index, dimensionInout);
|
||||
}
|
||||
function ResetE2DgnFuncBynangua(SUser, ItemId) {
|
||||
for (local i = 0; i <= 2; i++) {
|
||||
ResetDimensionInout(SUser, i)
|
||||
}
|
||||
SUser.SendNotiPacketMessage("已重置E2异界地下城次数", 8);
|
||||
}
|
||||
function ResetE3DgnFuncBynangua(SUser, ItemId) {
|
||||
for (local i = 3; i <= 5; i++) {
|
||||
ResetDimensionInout(SUser, i)
|
||||
}
|
||||
SUser.SendNotiPacketMessage("已重置E3异界地下城次数", 8);
|
||||
}
|
||||
//加载入口
|
||||
function _Dps_MapReset_Main_() {
|
||||
_Dps_MapReset_Logic_();
|
||||
}
|
||||
|
||||
//重载入口
|
||||
function _Dps_MapReset_Main_Reload_(OldConfig) {
|
||||
local Cofig = GlobalConfig.Get("异界重置_Lenheart.json");
|
||||
Cb_Use_Item_Sp_Func.rawdelete(OldConfig["重置E2异界地下城次数"].tointeger());
|
||||
Cb_Use_Item_Sp_Func.rawdelete(OldConfig["重置E3异界地下城次数"].tointeger());
|
||||
|
||||
//重新注册
|
||||
_Dps_MapReset_Logic_();
|
||||
}
|
||||
|
||||
function _Dps_MapReset_Logic_() {
|
||||
local Cofig = GlobalConfig.Get("异界重置_Lenheart.json");
|
||||
// E2异界重置券
|
||||
Cb_Use_Item_Sp_Func[Cofig["重置E2异界地下城次数"]] <- ResetE2DgnFuncBynangua;
|
||||
// E3异界重置券
|
||||
Cb_Use_Item_Sp_Func[Cofig["重置E3异界地下城次数"]] <- ResetE3DgnFuncBynangua;
|
||||
}
|
||||
4
示例项目/异界重置/异界重置_Lenheart.json
Normal file
4
示例项目/异界重置/异界重置_Lenheart.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"重置E2异界地下城次数": 2021458805,
|
||||
"重置E3异界地下城次数": 2021458806
|
||||
}
|
||||
11
示例项目/强化增幅药剂/Proj.ifo
Normal file
11
示例项目/强化增幅药剂/Proj.ifo
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ProjectName": "强化增幅药剂",
|
||||
"ProjectDescribe": "使用指定药剂增加强化/增幅",
|
||||
"ProjectAuthor": "Pluto",
|
||||
"ProjectVersion": 1.1,
|
||||
"ProjectConfig": "强化增幅药剂_Pluto.json",
|
||||
"ProjectFiles": [
|
||||
"强化增幅药剂.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_Dps_EnhancementPotion_Main_"
|
||||
}
|
||||
63
示例项目/强化增幅药剂/强化增幅药剂.nut
Normal file
63
示例项目/强化增幅药剂/强化增幅药剂.nut
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
文件名:强化药剂.nut
|
||||
路径:强化药剂/强化药剂.nut
|
||||
创建日期:2025-03-10
|
||||
文件用途:使用强化药剂增加强化成功几率
|
||||
*/
|
||||
|
||||
function _Dps_EnhancementPotion_Main_() {
|
||||
// 注册强化进入回调
|
||||
Cb_WongWork_CItemUpgrade_Enter_Func["强化药剂_逻辑"] <- function(args) {
|
||||
local Config = GlobalConfig.Get("强化增幅药剂_Pluto.json");
|
||||
local SUser = User(args[1]);
|
||||
local invenItem = args[2];
|
||||
local upgradeInfo = args[3];
|
||||
|
||||
// 检查开关
|
||||
if (!Config["开关(true/false)"]) {
|
||||
return args;
|
||||
}
|
||||
|
||||
// 检查用户是否拥有强化药剂
|
||||
local hasPotion = Sq_CallFunc(
|
||||
S_Ptr("0x865E994"),
|
||||
"int",
|
||||
["pointer", "int"],
|
||||
SUser.C_Object,
|
||||
Config["强化药剂ID"]
|
||||
);
|
||||
|
||||
if (!hasPotion) {
|
||||
return args;
|
||||
}
|
||||
|
||||
// 读取基础概率
|
||||
local probBase = NativePointer(args[0]).add(0x4EC).readU32();
|
||||
|
||||
// 获取当前强化等级和目标等级
|
||||
local currentLevel = Sq_CallFunc(S_Ptr("0x080F506C"), "int", ["pointer"], invenItem);
|
||||
local targetLevel = currentLevel + 1;
|
||||
|
||||
// 读取原始失败率
|
||||
local originalFailRate = NativePointer(upgradeInfo).add(32).readU32();
|
||||
|
||||
// 获取概率加成值
|
||||
local charac_no = SUser.GetCID().tostring();
|
||||
local boost = Config["默认增加概率"];
|
||||
|
||||
// 检查是否是指定角色,使用指定角色的概率
|
||||
if (Config["指定角色概率"].rawin(charac_no)) {
|
||||
boost = Config["指定角色概率"][charac_no];
|
||||
}
|
||||
|
||||
// 计算新的失败率
|
||||
if (boost > 0) {
|
||||
local boostAmount = (probBase * boost / 100).tointeger();
|
||||
local newFailRate = originalFailRate - boostAmount;
|
||||
if (newFailRate < 0) newFailRate = 0;
|
||||
NativePointer(upgradeInfo).add(32).writeU32(newFailRate);
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
}
|
||||
11
示例项目/强化增幅药剂/强化增幅药剂_Pluto.json
Normal file
11
示例项目/强化增幅药剂/强化增幅药剂_Pluto.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"开关(true/false)": true,
|
||||
"强化药剂ID": 2600025,
|
||||
"默认增加概率": 10,
|
||||
"指定角色概率": {
|
||||
"1": 100,
|
||||
"2": 50
|
||||
},
|
||||
"概率说明":"概率值10代表增加10%的概率",
|
||||
"指定角色说明":"角色ID可以查看数据库中 taiwan_cain → charac_info → charac_no代表角色ID"
|
||||
}
|
||||
11
示例项目/强化增幅锻造药剂/Proj.ifo
Normal file
11
示例项目/强化增幅锻造药剂/Proj.ifo
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ProjectName": "强化增幅锻造药剂",
|
||||
"ProjectDescribe": "使用药剂或持有指定物品时增加强化/增幅/锻造概率",
|
||||
"ProjectAuthor": "南瓜",
|
||||
"ProjectVersion": 1.0,
|
||||
"ProjectConfig": "强化增幅锻造药剂配置_nangua.json",
|
||||
"ProjectFiles": [
|
||||
"强化增幅锻造药剂.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_Dps_Increase_probability_Main_"
|
||||
}
|
||||
64
示例项目/强化增幅锻造药剂/强化增幅锻造药剂.nut
Normal file
64
示例项目/强化增幅锻造药剂/强化增幅锻造药剂.nut
Normal file
@@ -0,0 +1,64 @@
|
||||
// 强化时使用角色
|
||||
upgrade_user <- null;
|
||||
// 强化时使用材料
|
||||
current_material <- null;
|
||||
// 锻造时使用角色
|
||||
Separate_user <- null;
|
||||
// 强化装备时
|
||||
function _Dps_Increase_probability_Main_() {
|
||||
Cb_WongWork_CItemUpgrade_Enter_Func._Upgrade_Item <- function(args) {
|
||||
upgrade_user = User(args[1]);
|
||||
local upgrade_info_t = args[3];
|
||||
local Upgrade_rand = NativePointer(upgrade_info_t).add(32).readU32();
|
||||
// 如果材料是3242则代表增幅,如果是3171则代表强化
|
||||
current_material = NativePointer(upgrade_info_t).add(44).readU32();
|
||||
}
|
||||
|
||||
// 锻造装备时
|
||||
Cb_WongWork_CItemUpgrade_Separate_Enter_Func.Separate_Upgrade <- function(args) {
|
||||
Separate_user = User(args[1]);
|
||||
local upgrade_info_t = args[3];
|
||||
local Upgrade_rand = NativePointer(upgrade_info_t).add(4).readU32();
|
||||
local Separate_rand = 10 * Upgrade_rand;
|
||||
}
|
||||
// 随机值
|
||||
Cb_CMTRand_randInt_Leave_Func._Upgrade_Item <- function(args) {
|
||||
local address = Haker.NextReturnAddress;
|
||||
local Config = GlobalConfig.Get("强化增幅锻造药剂配置_nangua.json");
|
||||
if(address == "0x8547768") {
|
||||
local rand = args.pop();
|
||||
local charac_no = upgrade_user.GetCID().tostring();
|
||||
if (current_material == Config["强化药剂"]["强化材料(如你的强化材料是3171,则这里写3171)"] && Sq_CallFunc(S_Ptr("0x865E994"), "int", ["pointer", "int"], upgrade_user.C_Object, Config["强化药剂"]["药剂ID"]) && Config["强化药剂"]["开关(true开启/false关闭)"]) {
|
||||
local prob = Config["强化药剂"]["增加概率值"];
|
||||
if (Config["强化药剂"]["指定角色概率值"].rawin(charac_no)) {
|
||||
prob = Config["强化药剂"]["指定角色概率值"][charac_no];
|
||||
}
|
||||
local increase = rand * prob;
|
||||
local result = rand + increase;
|
||||
if (result > 100000) result = 100000;
|
||||
return result;
|
||||
}else if (current_material == Config["增幅药剂"]["增幅材料(如你的增幅材料是3242,则这里写3242)"] && Sq_CallFunc(S_Ptr("0x865E994"), "int", ["pointer", "int"], upgrade_user.C_Object, Config["增幅药剂"]["药剂ID"]) && Config["增幅药剂"]["开关(true开启/false关闭)"]) {
|
||||
local prob = Config["增幅药剂"]["增加概率值"];
|
||||
if (Config["增幅药剂"]["指定角色概率值"].rawin(charac_no)) {
|
||||
prob = Config["增幅药剂"]["指定角色概率值"][charac_no];
|
||||
}
|
||||
local increase = rand * prob;
|
||||
local result = rand + increase;
|
||||
if (result > 100000) result = 100000;
|
||||
return result;
|
||||
}
|
||||
}else if(address == "0x811e506" && Config["锻造药剂"]["开关(true开启/false关闭)"]) {
|
||||
local rand = args.pop();
|
||||
local charac_no = Separate_user.GetCID().tostring();
|
||||
if (Sq_CallFunc(S_Ptr("0x865E994"), "int", ["pointer", "int"], Separate_user.C_Object, Config["锻造药剂"]["药剂ID"])) {
|
||||
local prob = Config["锻造药剂"]["增加概率值"];
|
||||
if (Config["锻造药剂"]["指定角色概率值"].rawin(charac_no)) {
|
||||
prob = Config["锻造药剂"]["指定角色概率值"][charac_no];
|
||||
}
|
||||
local result = rand / (1 + prob);
|
||||
if (result < 1) result = 1;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
35
示例项目/强化增幅锻造药剂/强化增幅锻造药剂配置_nangua.json
Normal file
35
示例项目/强化增幅锻造药剂/强化增幅锻造药剂配置_nangua.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"强化药剂": {
|
||||
"开关(true开启/false关闭)":true,
|
||||
"药剂ID":2600025,
|
||||
"强化材料(如你的强化材料是3171,则这里写3171)":3171,
|
||||
"增加概率值":0.1,
|
||||
"指定角色概率值":{
|
||||
"1":0.1,
|
||||
"2":0.1
|
||||
}
|
||||
},
|
||||
"增幅药剂": {
|
||||
"开关(true开启/false关闭)":true,
|
||||
"药剂ID":2600025,
|
||||
"增幅材料(如你的增幅材料是3242,则这里写3242)":3242,
|
||||
"增加概率值":0.1,
|
||||
"指定角色概率值":{
|
||||
"1":0.1,
|
||||
"2":0.1
|
||||
}
|
||||
},
|
||||
"锻造药剂": {
|
||||
"开关(true开启/false关闭)":true,
|
||||
"药剂ID":2600025,
|
||||
"增加概率值":0.1,
|
||||
"指定角色概率值":{
|
||||
"1":0.1,
|
||||
"2":0.1
|
||||
}
|
||||
},
|
||||
"概率说明1":"1概率值0.1代表10%的概率,10%并不是说提高10%的概率,因为强化时有一个随机数0-10万",
|
||||
"概率说明2":"所以强化时如果随机值是1万,提高10%的概率就是10000*0.1=1000,最终随机数是11000(10000+1000)",
|
||||
"概率说明3":"在强化时如成功率是20%,那么他的随机值就是20000,如果概率值大于20000就会强化成功,如果概率值小于20000就会失败",
|
||||
"指定角色说明":"角色ID可以查看数据库中 taiwan_cain → charac_info → charac_no代表角色ID"
|
||||
}
|
||||
9
示例项目/强化相关概率提升/Proj.ifo
Normal file
9
示例项目/强化相关概率提升/Proj.ifo
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ProjectName": "强化相关概率提升",
|
||||
"ProjectDescribe": "强化、增幅、锻造可以根据角色ID或者穿戴的物品ID提升概率可以叠加概率,指定角色优先级最高",
|
||||
"ProjectAuthor": "小南瓜",
|
||||
"ProjectVersion": 1.0,
|
||||
"ProjectConfig": "强化相关概率配置.json",
|
||||
"ProjectFiles": ["强化增幅锻造.nut"],
|
||||
"ProjectRunFunc": "_Dps_Upgrade_Boost_Main_"
|
||||
}
|
||||
134
示例项目/强化相关概率提升/强化增幅锻造.nut
Normal file
134
示例项目/强化相关概率提升/强化增幅锻造.nut
Normal file
@@ -0,0 +1,134 @@
|
||||
function _Dps_Upgrade_Boost_Main_() {
|
||||
_Dps_Upgrade_Boost_Logic_();
|
||||
}
|
||||
|
||||
function _Dps_Upgrade_Boost_Main_Reload_(OldConfig) {
|
||||
_Dps_Upgrade_Boost_Logic_();
|
||||
}
|
||||
|
||||
function _Dps_Upgrade_Boost_Logic_() {
|
||||
|
||||
Cb_WongWork_CItemUpgrade_Enter_Func._Upgrade_Boost <- function(args) {
|
||||
local SUser = User(args[1]);
|
||||
local characNo = SUser.GetCID();
|
||||
local invenItem = args[2];
|
||||
local upgradeInfo = args[3];
|
||||
local probBase = NativePointer(args[0]).add(0x4EC).readU32();
|
||||
|
||||
local currentLevel = Sq_CallFunc(S_Ptr("0x080F506C"), "int", ["pointer"], invenItem);
|
||||
local targetLevel = currentLevel + 1;
|
||||
|
||||
local originalFailRate = NativePointer(upgradeInfo).add(32).readU32();
|
||||
local isAmplify = _UpgradeBoostHelper.hasAmplifyAbility(invenItem);
|
||||
local upgradeType = isAmplify ? "增幅" : "强化";
|
||||
|
||||
local boost = _UpgradeBoostHelper.getFinalBoost(SUser, targetLevel, upgradeType);
|
||||
|
||||
if (boost > 0) {
|
||||
local boostAmount = (probBase * boost / 100).tointeger();
|
||||
local newFailRate = originalFailRate - boostAmount;
|
||||
if (newFailRate < 0) newFailRate = 0;
|
||||
NativePointer(upgradeInfo).add(32).writeU32(newFailRate);
|
||||
}
|
||||
}
|
||||
|
||||
Cb_WongWork_CItemUpgrade_Separate_Enter_Func._Separate_Boost <- function(args) {
|
||||
local thisPtr = args[0];
|
||||
local SUser = User(args[1]);
|
||||
local invenItem = args[2];
|
||||
local upgradeInfo = args[3];
|
||||
|
||||
local originalFailRate = NativePointer(upgradeInfo).add(4).readU32();
|
||||
local probBase = NativePointer(thisPtr).add(400).readU32();
|
||||
local currentLevel = NativePointer(invenItem).add(51).readU8();
|
||||
local targetLevel = currentLevel + 1;
|
||||
|
||||
local boost = _UpgradeBoostHelper.getFinalBoost(SUser, targetLevel, "锻造");
|
||||
|
||||
if (boost > 0) {
|
||||
local boostAmount = ((probBase / 10) * boost / 100).tointeger();
|
||||
local newFailRate = originalFailRate + boostAmount;
|
||||
if (newFailRate > 10000) newFailRate = 10000;
|
||||
NativePointer(upgradeInfo).add(4).writeU32(newFailRate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _UpgradeBoostHelper {
|
||||
|
||||
function hasAmplifyAbility(invenItem) {
|
||||
return NativePointer(invenItem).add(17).readU8() != 0;
|
||||
}
|
||||
|
||||
function isInRange(level, rangeStr) {
|
||||
local parts = split(rangeStr, "-");
|
||||
|
||||
if (parts.len() == 1) {
|
||||
return level == parts[0].tointeger();
|
||||
} else if (parts.len() == 2) {
|
||||
local min = parts[0].tointeger();
|
||||
local max = parts[1].tointeger();
|
||||
return level >= min && level <= max;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function getBoostFromConfig(config, level, upgradeType) {
|
||||
if (!config.rawin(upgradeType)) return 0;
|
||||
|
||||
local typeConfig = config[upgradeType];
|
||||
|
||||
if (typeof typeConfig == "array") {
|
||||
foreach (rule in typeConfig) {
|
||||
if (rule.rawin("目标等级") && rule.rawin("加成")) {
|
||||
if (_UpgradeBoostHelper.isInRange(level, rule["目标等级"])) {
|
||||
return rule["加成"];
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (typeof typeConfig == "table") {
|
||||
local levelKey = level.tostring();
|
||||
if (typeConfig.rawin(levelKey)) {
|
||||
return typeConfig[levelKey];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function getFinalBoost(user, level, upgradeType) {
|
||||
local Config = GlobalConfig.Get("强化相关概率配置.json");
|
||||
local characNo = user.GetCID();
|
||||
|
||||
// 1. 检查VIP
|
||||
foreach (vip in Config["VIP配置"]) {
|
||||
if (vip["角色ID"] == characNo) {
|
||||
return _UpgradeBoostHelper.getBoostFromConfig(vip, level, upgradeType);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 检查穿戴物品(叠加)
|
||||
local InvenObj = user.GetInven();
|
||||
if (!InvenObj) return 0;
|
||||
|
||||
local totalBoost = 0;
|
||||
|
||||
foreach (itemCfg in Config["物品配置"]) {
|
||||
local itemObj = InvenObj.GetSlot(Inven.INVENTORY_TYPE_BODY, itemCfg["槽位"]);
|
||||
if (itemObj.IsEmpty) continue;
|
||||
|
||||
local itemId = itemObj.GetIndex();
|
||||
|
||||
if (itemId == itemCfg["物品ID"]) {
|
||||
local itemBoost = _UpgradeBoostHelper.getBoostFromConfig(itemCfg, level, upgradeType);
|
||||
totalBoost += itemBoost;
|
||||
}
|
||||
}
|
||||
|
||||
return totalBoost;
|
||||
}
|
||||
}
|
||||
71
示例项目/强化相关概率提升/强化相关概率配置.json
Normal file
71
示例项目/强化相关概率提升/强化相关概率配置.json
Normal file
@@ -0,0 +1,71 @@
|
||||
{
|
||||
"VIP配置": [
|
||||
{
|
||||
"角色ID": 1111111,
|
||||
"备注": "GM测试号",
|
||||
"强化": [
|
||||
{"目标等级": "1-4", "加成": 20},
|
||||
{"目标等级": "5-7", "加成": 15},
|
||||
{"目标等级": "8-10", "加成": 10},
|
||||
{"目标等级": "11-15", "加成": 5}
|
||||
],
|
||||
"增幅": [
|
||||
{"目标等级": "1-4", "加成": 20},
|
||||
{"目标等级": "5-7", "加成": 15},
|
||||
{"目标等级": "8-10", "加成": 10},
|
||||
{"目标等级": "11-15", "加成": 5}
|
||||
],
|
||||
"锻造": [
|
||||
{"目标等级": "1-3", "加成": 10},
|
||||
{"目标等级": "4-7", "加成": 5}
|
||||
]
|
||||
}
|
||||
],
|
||||
"物品配置": [
|
||||
{
|
||||
"槽位": 11,
|
||||
"物品ID": 600330013,
|
||||
"备注": "称号",
|
||||
"强化": [
|
||||
{"目标等级": "1-4", "加成": 20},
|
||||
{"目标等级": "5-10", "加成": 15},
|
||||
{"目标等级": "11-15", "加成": 10}
|
||||
],
|
||||
"增幅": [
|
||||
{"目标等级": "1-4", "加成": 20},
|
||||
{"目标等级": "5-10", "加成": 15},
|
||||
{"目标等级": "11-15", "加成": 10}
|
||||
],
|
||||
"锻造": [
|
||||
{"目标等级": "1-3", "加成": 10},
|
||||
{"目标等级": "4-7", "加成": 5}
|
||||
]
|
||||
},
|
||||
{
|
||||
"槽位": 22,
|
||||
"物品ID": 63118,
|
||||
"备注": "宠物",
|
||||
"强化": [
|
||||
{"目标等级": "1-10", "加成": 15},
|
||||
{"目标等级": "11-15", "加成": 10}
|
||||
],
|
||||
"增幅": [
|
||||
{"目标等级": "1-10", "加成": 15},
|
||||
{"目标等级": "11-15", "加成": 10}
|
||||
],
|
||||
"锻造": [
|
||||
{"目标等级": "1-7", "加成": 8}
|
||||
]
|
||||
}
|
||||
],
|
||||
"配置说明": {
|
||||
"目标等级说明": "目标等级5表示强化到+5(从+4强到+5)",
|
||||
"范围说明": "5-10表示强化到+5~+10都享受此加成",
|
||||
"单个数字": "也可以写单个数字如 10 表示只有+10享受加成",
|
||||
"加成计算": "原概率+加成值,如原本10%加成20则变30%",
|
||||
"优先级": "VIP配置优先,物品配置叠加",
|
||||
"槽位": "身上穿的装备槽位(0-25)//0时装帽子, 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宠物装备绿",
|
||||
"角色ID": "角色ID可以自行查看数据库中 库名taiwan_cain → 表名charac_info → 字段charac_no代表角色ID, 可以理解为角色注册顺序, 第一个注册的角色ID就是1"
|
||||
}
|
||||
}
|
||||
|
||||
11
示例项目/心悦播报/Proj.ifo
Normal file
11
示例项目/心悦播报/Proj.ifo
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ProjectName": "心悦播报",
|
||||
"ProjectDescribe": "登录时根据完成的心悦任务对应等级播报不同的提示",
|
||||
"ProjectAuthor": "南瓜",
|
||||
"ProjectVersion": 1.0,
|
||||
"ProjectConfig": "心悦播报配置_Nangua.json",
|
||||
"ProjectFiles": [
|
||||
"心悦播报.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_Dps_LoginByXY_Main_"
|
||||
}
|
||||
45
示例项目/心悦播报/心悦播报.nut
Normal file
45
示例项目/心悦播报/心悦播报.nut
Normal file
@@ -0,0 +1,45 @@
|
||||
function _Dps_LoginByXY_Main_() {
|
||||
Cb_reach_game_world_Func.LoginByXy <- function(SUser) {
|
||||
local Config = GlobalConfig.Get("心悦播报配置_Nangua.json");
|
||||
local quest = SUser.GetQuest(); // 获取任务对象
|
||||
local WongWork_CQuestClear = NativePointer(quest).add(4);
|
||||
local highestRank = 0;
|
||||
local highestRankConfig = null;
|
||||
foreach(taskConfig in Config["心悦播报配置"]["任务等级配置"]) {
|
||||
local isCleared = _LoginBynangua.isClearedQuest(WongWork_CQuestClear.C_Object, taskConfig["任务ID"]);
|
||||
if (isCleared && taskConfig["心悦等级"] > highestRank) {
|
||||
highestRank = taskConfig["心悦等级"];
|
||||
highestRankConfig = taskConfig;
|
||||
}
|
||||
}
|
||||
|
||||
local config = Config["心悦播报配置"]["心悦会员登录播报"];
|
||||
if (highestRank > 0 && config["开关(true为开启,false为关闭)"]) {
|
||||
Timer.SetTimeOut(function(SUser, config, highestRankConfig) {
|
||||
_LoginBynangua.VIP_LoginBynangua(SUser, config, highestRankConfig);
|
||||
}, 1, SUser, config, highestRankConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//心悦会员登录播报
|
||||
class _LoginBynangua {
|
||||
function VIP_LoginBynangua(SUser, config, rankConfig) {
|
||||
local LoginMsgObj = AdMsg();
|
||||
LoginMsgObj.PutType(config["信息播报发送位置"]);
|
||||
if (config["信息播报发送位置"] != 14) {
|
||||
LoginMsgObj.PutString(" ");
|
||||
}
|
||||
LoginMsgObj.PutImoticon(rankConfig["图标"]);
|
||||
LoginMsgObj.PutColorString(config["标题"], rankConfig["文本颜色"]);
|
||||
LoginMsgObj.PutColorString("<" + rankConfig["心悦等级"] + ">", rankConfig["心悦等级颜色"]);
|
||||
LoginMsgObj.PutColorString("[" + SUser.GetCharacName() + "]", rankConfig["角色名字颜色"]);
|
||||
LoginMsgObj.PutColorString(config["结尾信息内容"], rankConfig["文本颜色"]);
|
||||
LoginMsgObj.Finalize();
|
||||
World.SendAll(LoginMsgObj.MakePack());
|
||||
LoginMsgObj.Delete();
|
||||
}
|
||||
function isClearedQuest(C_Object, questID) {
|
||||
return Sq_CallFunc(S_Ptr("0x808BAE0"), "bool", ["pointer", "int"], C_Object, questID);
|
||||
}
|
||||
}
|
||||
36
示例项目/心悦播报/心悦播报配置_Nangua.json
Normal file
36
示例项目/心悦播报/心悦播报配置_Nangua.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"心悦播报配置":{
|
||||
"心悦会员登录播报":{
|
||||
"开关(true为开启,false为关闭)":true,
|
||||
"信息播报发送位置":14,
|
||||
"标题":" 尊贵心悦",
|
||||
"结尾信息内容":"已登录游戏"
|
||||
},
|
||||
"任务等级配置": [
|
||||
{
|
||||
"任务ID": 102,
|
||||
"心悦等级": 1,
|
||||
"心悦等级颜色":[0, 255, 128],
|
||||
"图标":48,
|
||||
"角色名字颜色":[255, 20, 0],
|
||||
"文本颜色":[255, 120, 0]
|
||||
},
|
||||
{
|
||||
"任务ID": 103,
|
||||
"心悦等级": 2,
|
||||
"心悦等级颜色":[255, 0, 128],
|
||||
"图标":49,
|
||||
"角色名字颜色":[255, 20, 0],
|
||||
"文本颜色":[255, 120, 0]
|
||||
},
|
||||
{
|
||||
"任务ID": 104,
|
||||
"心悦等级": 3,
|
||||
"心悦等级颜色":[255, 255, 0],
|
||||
"图标":50,
|
||||
"角色名字颜色":[255, 20, 0],
|
||||
"文本颜色":[255, 120, 0]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
12
示例项目/怪物攻城/Proj.ifo
Normal file
12
示例项目/怪物攻城/Proj.ifo
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ProjectName": "怪物攻城",
|
||||
"ProjectDescribe": "根据json的时间开启怪物攻城,可实时修改,没有阶段性没有惩罚,单纯杀怪给奖励",
|
||||
"ProjectAuthor": "南瓜",
|
||||
"ProjectVersion": 1.2,
|
||||
"ProjectIcon": "http://su782j8qj.hd-bkt.clouddn.com/image/%E6%80%AA%E7%89%A9%E6%94%BB%E5%9F%8E%E5%9B%BE%E6%A0%87.jpg",
|
||||
"ProjectConfig": "怪物攻城_南瓜.json",
|
||||
"ProjectFiles": [
|
||||
"怪物攻城.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_Dps_VillageAttack_nangua_Main_"
|
||||
}
|
||||
397
示例项目/怪物攻城/怪物攻城.nut
Normal file
397
示例项目/怪物攻城/怪物攻城.nut
Normal file
@@ -0,0 +1,397 @@
|
||||
//活动开始阶段
|
||||
local VILLAGEATTACK_STATE_START = 0;
|
||||
//活动结束阶段
|
||||
local VILLAGEATTACK_STATE_END = 3;
|
||||
|
||||
//怪物攻城活动数据
|
||||
local villageAttackEventInfo = {
|
||||
"state": VILLAGEATTACK_STATE_END, //活动当前状态
|
||||
"score": 0, //当前阶段频道内总PT
|
||||
"start_time": 0, //活动开始时间
|
||||
"defend_success": 0, //怪物攻城活动防守成功
|
||||
"user_pt_info": {}, //角色个人pt数据
|
||||
}
|
||||
|
||||
//重置活动数据
|
||||
function Reset_Villageattack_info() {
|
||||
villageAttackEventInfo.state = VILLAGEATTACK_STATE_START;
|
||||
villageAttackEventInfo.score = 0;
|
||||
villageAttackEventInfo.user_pt_info = {};
|
||||
villageAttackEventInfo.start_time = time();
|
||||
villageAttackEventInfo.defend_success = 0;
|
||||
print(">>>>>>>>>>>>>>活动数据已初始化成功<<<<<<<<<<<<<<")
|
||||
}
|
||||
|
||||
//怪物攻城活动计时器(每5秒触发一次)
|
||||
function Event_Villageattack_Timer() {
|
||||
if (villageAttackEventInfo.state == VILLAGEATTACK_STATE_END)
|
||||
return;
|
||||
//活动结束检测
|
||||
local remain_time = event_villageattack_get_remain_time();
|
||||
if (remain_time <= 0) {
|
||||
//活动结束
|
||||
on_end_event_villageattack();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//计算活动剩余时间
|
||||
function event_villageattack_get_remain_time() {
|
||||
local Config = GlobalConfig.Get("怪物攻城_南瓜.json");
|
||||
local cur_time = time();
|
||||
local event_end_time = villageAttackEventInfo.start_time + Config["怪物攻城配置"]["怪物攻城总时长(秒)"];
|
||||
local remain_time = event_end_time - cur_time;
|
||||
return remain_time;
|
||||
}
|
||||
|
||||
//更新怪物攻城当前进度(广播给频道内在线玩家)
|
||||
function Gameworld_Update_Villageattack_Score() {
|
||||
local Config = GlobalConfig.Get("怪物攻城_南瓜.json");
|
||||
//计算活动剩余时间
|
||||
local remain_time = event_villageattack_get_remain_time();
|
||||
if ((remain_time <= 0) || (villageAttackEventInfo.state == VILLAGEATTACK_STATE_END))
|
||||
return;
|
||||
|
||||
local Pack = Packet();
|
||||
Pack.Put_Header(0, 247); //协议: ENUM_NOTIPACKET_UPDATE_VILLAGE_ATTACKED
|
||||
Pack.Put_Int(remain_time); //活动剩余时间
|
||||
Pack.Put_Int(villageAttackEventInfo.score); //当前频道PT点数
|
||||
Pack.Put_Int(Config["怪物攻城配置"]["怪物攻城胜利所需pt点"]); //成功防守所需点数
|
||||
|
||||
Pack.Finalize(true);
|
||||
World.SendAll(Pack);
|
||||
Pack.Delete();
|
||||
}
|
||||
|
||||
//开启怪物攻城活动
|
||||
function Start_Villageattack() {
|
||||
local Config = GlobalConfig.Get("怪物攻城_南瓜.json");
|
||||
local a3 = Memory.alloc(100);
|
||||
//活动剩余时间
|
||||
NativePointer(a3).add(10).writeInt(Config["怪物攻城配置"]["怪物攻城总时长(秒)"]);
|
||||
//当前频道PT点数
|
||||
NativePointer(a3).add(14).writeInt(villageAttackEventInfo.score);
|
||||
//成功防守所需点数
|
||||
NativePointer(a3).add(18).writeInt(Config["怪物攻城配置"]["怪物攻城胜利所需pt点"]);
|
||||
//开启怪物攻城
|
||||
Sq_CallFunc(S_Ptr("0x84DF47A"), "pointer", ["pointer", "pointer", "pointer"], S_Ptr("0x0"), S_Ptr("0x0"), a3.C_Object);
|
||||
//设置副本难度
|
||||
NativePointer(S_Ptr("0x085B9605")).writeInt(Config["怪物攻城配置"]["活动默认难度(0-4: 普通-英雄)"]);
|
||||
//patch相关函数, 修复活动流程
|
||||
Hook_VillageAttack();
|
||||
print(">>>>>>>>>>>>>>怪物攻城已启动<<<<<<<<<<<<<<<<<<<<");
|
||||
}
|
||||
|
||||
//结束怪物攻城活动(立即销毁攻城怪物, 不开启逆袭之谷, 不发送活动奖励)
|
||||
function end_villageattack() {
|
||||
local GlobalData_s_villageMonsterMgr = NativePointer("0x941F77C").readPointer();
|
||||
Sq_CallFunc(S_Ptr("0x086B43D4"), "pointer", ["pointer", "int"], GlobalData_s_villageMonsterMgr, 2);
|
||||
print(">>>>>>>>>>>>>>怪物攻城已结束<<<<<<<<<<<<<<");
|
||||
}
|
||||
|
||||
// 开始怪物攻城活动
|
||||
function On_Start_Event_VillageattackBynangua() {
|
||||
// 重置活动数据
|
||||
Reset_Villageattack_info();
|
||||
// 注册5秒检查定时器
|
||||
Timer.SetCronTask(Event_Villageattack_Timer, {
|
||||
Cron = "*/5 * * * * *", // 每5秒执行一次
|
||||
Name = "VillageAttackCheckTask"
|
||||
});
|
||||
// 通知全服玩家活动开始 并刷新城镇怪物
|
||||
Start_Villageattack();
|
||||
Gameworld_Update_Villageattack_Score();
|
||||
|
||||
// 发送活动开始公告
|
||||
local Config = GlobalConfig.Get("怪物攻城_南瓜.json");
|
||||
World.SendNotiPacketMessage(Config["怪物攻城公告"]["开始"], Config["怪物攻城公告"]["发送位置"]);
|
||||
}
|
||||
|
||||
Cb_reach_game_world_Func.villageattackByNangua <- function(SUser) {
|
||||
//怪物攻城活动更新进度
|
||||
if (villageAttackEventInfo.state != VILLAGEATTACK_STATE_END) {
|
||||
//通知客户端打开活动UI
|
||||
Notify_Villageattack_Score(SUser);
|
||||
}
|
||||
}
|
||||
|
||||
//通知玩家怪物攻城进度
|
||||
function Notify_Villageattack_Score(SUser) {
|
||||
local Config = GlobalConfig.Get("怪物攻城_南瓜.json");
|
||||
// 玩家当前PT点
|
||||
local charac_no = SUser.GetCID().tostring();
|
||||
local villageattack_pt = 0;
|
||||
|
||||
if (charac_no in villageAttackEventInfo.user_pt_info)
|
||||
villageattack_pt = villageAttackEventInfo.user_pt_info[charac_no][1];
|
||||
|
||||
// 计算活动剩余时间
|
||||
local remain_time = event_villageattack_get_remain_time();
|
||||
|
||||
if ((remain_time <= 0) || (villageAttackEventInfo.state == VILLAGEATTACK_STATE_END))
|
||||
return;
|
||||
// 发包通知角色打开怪物攻城UI并更新当前进度
|
||||
local Pack = Packet();
|
||||
Pack.Put_Header(0, 248);
|
||||
Pack.Put_Int(remain_time); // 活动剩余时间
|
||||
Pack.Put_Int(villageAttackEventInfo.score); // 当前频道PT点数
|
||||
Pack.Put_Int(Config["怪物攻城配置"]["怪物攻城胜利所需pt点"]); // 成功防守所需点数
|
||||
Pack.Put_Int(villageattack_pt); // 个人PT点数
|
||||
Pack.Finalize(true);
|
||||
SUser.Send(Pack);
|
||||
Pack.Delete();
|
||||
}
|
||||
|
||||
//怪物攻城活动相关patch
|
||||
function Hook_VillageAttack() {
|
||||
Cb_CVillageMonster_SendVillageMonsterFightResult_Leave_Func.Bynangua <- function(args) {
|
||||
local Config = GlobalConfig.Get("怪物攻城_南瓜.json");
|
||||
local village_monster = args[0];
|
||||
local SUser = User(args[1]);
|
||||
local result = args[2];
|
||||
if (result) {
|
||||
local bonus_pt = 1;
|
||||
local PartyObj = SUser.GetParty();
|
||||
if (!PartyObj) return;
|
||||
for (local i = 0; i < 4; ++i) {
|
||||
local TUser = PartyObj.GetUser(i);
|
||||
if (TUser) {
|
||||
local charac_no = TUser.GetCID().tostring();
|
||||
if (!(charac_no in villageAttackEventInfo.user_pt_info)){
|
||||
villageAttackEventInfo.user_pt_info[charac_no] <- [TUser.GetUID(), 0];
|
||||
}
|
||||
villageAttackEventInfo.user_pt_info[charac_no][1] += bonus_pt;
|
||||
VillageAttackedRewardSendReward(TUser);
|
||||
}
|
||||
}
|
||||
villageAttackEventInfo.score += bonus_pt;
|
||||
Gameworld_Update_Villageattack_Score();
|
||||
if (villageAttackEventInfo.score >= Config["怪物攻城配置"]["怪物攻城胜利所需pt点"]) {
|
||||
//怪物攻城活动防守成功, 立即结束活动
|
||||
villageAttackEventInfo.defend_success = 1;
|
||||
Timer.SetTimeOut(on_end_event_villageattack, 15);
|
||||
return;
|
||||
}
|
||||
//通知队伍中的所有玩家更新PT点数
|
||||
for (local i = 0; i < 4; ++i) {
|
||||
local TUser = PartyObj.GetUser(i);
|
||||
if (TUser) {
|
||||
Notify_Villageattack_Score(TUser);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//结束怪物攻城活动
|
||||
function on_end_event_villageattack() {
|
||||
local Config = GlobalConfig.Get("怪物攻城_南瓜.json");
|
||||
if (villageAttackEventInfo.state == VILLAGEATTACK_STATE_END)
|
||||
return;
|
||||
// 设置活动状态
|
||||
villageAttackEventInfo.state = VILLAGEATTACK_STATE_END;
|
||||
// 移除5秒检查定时器
|
||||
Timer.RemoveCronTask("VillageAttackCheckTask");
|
||||
// 立即结束怪物攻城活动
|
||||
end_villageattack();
|
||||
local OnlinePlayerList = World.GetOnlinePlayer();
|
||||
// 防守成功
|
||||
if (villageAttackEventInfo.defend_success == 1) {
|
||||
// 频道内在线玩家发奖
|
||||
foreach(SUser in OnlinePlayerList) {
|
||||
local RewardItems = [];
|
||||
|
||||
// 从配置文件中获取固定奖励
|
||||
foreach(reward in Config["怪物攻城配置"]["怪物攻城防守成功固定奖励配置"]) {
|
||||
RewardItems.append([reward[0], reward[1]]);
|
||||
}
|
||||
|
||||
// 发送邮件
|
||||
local title = "<怪物攻城活动>"
|
||||
local Text = "恭喜勇士成功守护我们的家园!"
|
||||
SUser.ReqDBSendMultiMail(title, Text, 0, RewardItems)
|
||||
}
|
||||
|
||||
// 榜一大哥
|
||||
local rank_first_charac_no = 0;
|
||||
local rank_first_account_id = 0;
|
||||
local max_pt = 0;
|
||||
|
||||
// 论功行赏
|
||||
foreach(charac_no, data in villageAttackEventInfo.user_pt_info) {
|
||||
// 发点券
|
||||
local account_id = villageAttackEventInfo.user_pt_info[charac_no][0];
|
||||
local pt = villageAttackEventInfo.user_pt_info[charac_no][1];
|
||||
local reward_cera = pt * Config["怪物攻城配置"]["怪物攻城其余玩家点券奖励"];
|
||||
// 点券奖励 = 个人PT * 10
|
||||
|
||||
local user_pr = World.GetUserByUid(account_id);
|
||||
if(Config["怪物攻城配置"]["怪物攻城其余玩家点券奖励"] > 0){
|
||||
user_pr.RechargeCera(reward_cera);
|
||||
user_pr.SendNotiPacketMessage("<怪物攻城活动> 防守成功, 获得pt点 * " + Config["怪物攻城配置"]["怪物攻城其余玩家点券奖励"] + " 的点券奖励", 14);
|
||||
}
|
||||
// 找出榜一大哥
|
||||
if (pt > max_pt) {
|
||||
rank_first_charac_no = charac_no;
|
||||
rank_first_account_id = account_id;
|
||||
max_pt = pt;
|
||||
}
|
||||
}
|
||||
|
||||
// 频道内公告活动已结束
|
||||
World.SendNotiPacketMessage(Config["怪物攻城公告"]["防守成功"], Config["怪物攻城公告"]["发送位置"]);
|
||||
if (rank_first_charac_no) {
|
||||
// 个人积分排行榜第一名 额外获得10倍点券奖励
|
||||
local user_pr = World.GetUserByUid(rank_first_account_id);
|
||||
if(Config["怪物攻城配置"]["怪物攻城榜一大哥额外点券奖励"] > 0){
|
||||
user_pr.RechargeCera(max_pt * Config["怪物攻城配置"]["怪物攻城榜一大哥额外点券奖励"]);
|
||||
user_pr.SendNotiPacketMessage("<怪物攻城活动> 排行榜第一名, 获得pt点 * " + Config["怪物攻城配置"]["怪物攻城榜一大哥额外点券奖励"] + " 的点券奖励", 14);
|
||||
}
|
||||
if(Config["怪物攻城配置"]["怪物攻城榜一大哥额外奖励道具(true开启/false关闭)"]){
|
||||
local reward_items = {};
|
||||
foreach(reward in Config["怪物攻城配置"]["怪物攻城榜一大哥额外奖励道具"]){
|
||||
reward_items[reward[0]] <- reward[1];
|
||||
}
|
||||
Timer.SetTimeOut(function(){
|
||||
user_pr.SendMail(reward_items, {
|
||||
Title = "<怪物攻城活动>",
|
||||
Text = "恭喜获得排行榜第一名!"
|
||||
});
|
||||
user_pr.SendNotiPacketMessage("<怪物攻城活动> 恭喜获得排行榜第一名,请前往邮箱查看奖励", 14);
|
||||
}, 3);
|
||||
}
|
||||
// 频道内广播本轮活动排行榜第一名玩家名字
|
||||
local rank_first_charac_name = _VillageAttackBynangua.Get_charac_name_ByCID(rank_first_charac_no.tointeger());
|
||||
World.SendNotiPacketMessage("<怪物攻城活动> 恭喜勇士 【" + rank_first_charac_name + "】 成为个人积分排行榜第一名(" + max_pt + "pt)!", 14);
|
||||
}
|
||||
} else {
|
||||
// 防守失败
|
||||
World.SendNotiPacketMessage(Config["怪物攻城公告"]["防守失败"], Config["怪物攻城公告"]["发送位置"]);
|
||||
}
|
||||
|
||||
// 释放空间
|
||||
villageAttackEventInfo.user_pt_info = {};
|
||||
}
|
||||
|
||||
function VillageAttackedRewardSendReward(SUser) {
|
||||
local villageAttack_ConfigBynangua = GlobalConfig.Get("怪物攻城_南瓜.json");
|
||||
local charac_no = SUser.GetCID().tostring();
|
||||
if ((charac_no in villageAttackEventInfo.user_pt_info)) {
|
||||
local Count = villageAttackEventInfo.user_pt_info[charac_no][1];
|
||||
local Config = villageAttack_ConfigBynangua["怪物攻城配置"]["怪物攻城奖励配置"]["击杀次数"];
|
||||
|
||||
if (Config.rawin(Count.tostring())) {
|
||||
local rewardConfig = Config[Count.tostring()];
|
||||
if (rewardConfig) {
|
||||
local title = "<怪物攻城活动>"
|
||||
local Text = "恭喜勇士成功守护我们的家园!"
|
||||
local RewardItems = [];
|
||||
RewardItems.append([rewardConfig[0], rewardConfig[1]]);
|
||||
SUser.ReqDBSendMultiMail(title, Text, 0, RewardItems);
|
||||
}
|
||||
} else {
|
||||
local title = "<怪物攻城活动>"
|
||||
local Text = "恭喜勇士成功守护我们的家园!"
|
||||
// 使用默认奖励配置
|
||||
local defaultRewards = villageAttack_ConfigBynangua["怪物攻城配置"]["不在配置表里的击杀次数默认奖励道具"];
|
||||
local RewardItems = [];
|
||||
RewardItems.append([defaultRewards[0], defaultRewards[1]]);
|
||||
SUser.ReqDBSendMultiMail(title, Text, 0, RewardItems);
|
||||
}
|
||||
}
|
||||
}
|
||||
class _VillageAttackBynangua{
|
||||
function Get_charac_name_ByCID(charac_no) {
|
||||
local Config = GlobalConfig.Get("怪物攻城_南瓜.json");
|
||||
local PoolObj = MysqlPool.GetInstance();
|
||||
local Ip = Config["数据库IP 不是外置数据库不要更改"];
|
||||
local Port = Config["数据库端口 不懂不要更改"];
|
||||
local DbName = Config["数据库用户名 本地用户名不懂不要更改"];
|
||||
local Password = Config["数据库密码 本地密码不懂不要更改"];
|
||||
//设置数据库连接信息
|
||||
PoolObj.SetBaseConfiguration(Ip, Port, DbName, Password);
|
||||
//连接池大小
|
||||
PoolObj.PoolSize = 10;
|
||||
//初始化
|
||||
PoolObj.Init();
|
||||
local sql = "select charac_name from charac_info where charac_no=" + charac_no + ";";
|
||||
local column_type_list = ["string"];
|
||||
local SqlObj = MysqlPool.GetInstance().GetConnect();
|
||||
local result = SqlObj.Select(sql, column_type_list);
|
||||
MysqlPool.GetInstance().PutConnect(SqlObj);
|
||||
if (result.len() > 0) {
|
||||
return result[0][0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 怪物攻城活动入口点
|
||||
function _Dps_VillageAttack_nangua_Main_() {
|
||||
_Dps_VillageAttack_nangua_Logic_();
|
||||
}
|
||||
|
||||
// 怪物攻城活动重载入口点
|
||||
function _Dps_VillageAttack_nangua_Main_Reload_(OldConfig) {
|
||||
// 先移除旧的定时任务
|
||||
Timer.RemoveCronTask("VillageAttackTask");
|
||||
|
||||
// 重新注册
|
||||
_Dps_VillageAttack_nangua_Logic_();
|
||||
}
|
||||
|
||||
// 怪物攻城活动逻辑入口点
|
||||
function _Dps_VillageAttack_nangua_Logic_() {
|
||||
// 从配置中读取开启时间
|
||||
local Config = GlobalConfig.Get("怪物攻城_南瓜.json");
|
||||
local hour = Config["怪物攻城配置"]["开启时间[XX点(24小时制), XX分(0-59)]"][0];
|
||||
local minute = Config["怪物攻城配置"]["开启时间[XX点(24小时制), XX分(0-59)]"][1];
|
||||
|
||||
// cron 表达式 (秒 分 时 日 月 周)
|
||||
local cronExpression = format("0 %d %d * * *", minute, hour);
|
||||
|
||||
// 注册定时任务
|
||||
Timer.SetCronTask(On_Start_Event_VillageattackBynangua, {
|
||||
Cron = cronExpression,
|
||||
Name = "VillageAttackTask"
|
||||
});
|
||||
}
|
||||
//发送Item邮件 Pubilc
|
||||
function User::SendItemMailtest(UID, ItemList, title, content) {
|
||||
local SUser = World.GetUserByUid(UID);
|
||||
local CID = SUser.GetCID();
|
||||
local sql = "select letter_id from taiwan_cain_2nd.postal order by letter_id DESC";
|
||||
local column_type_list = ["int"];
|
||||
|
||||
local SqlObj = MysqlPool.GetInstance().GetConnect();
|
||||
local result = SqlObj.Select(sql, column_type_list);
|
||||
local sl = 1;
|
||||
if (result.len() > 0) {
|
||||
sl = result[0][0] + 1;
|
||||
}
|
||||
|
||||
local time = date();
|
||||
local timeStr = time["year"] + "-" + (time["month"] + 1) + "-" + time["day"] + " " + time["hour"] + ":" + time["min"] + ":" + time["sec"];
|
||||
|
||||
foreach(value in ItemList) {
|
||||
local sql1 = "insert into taiwan_cain_2nd.postal (occ_time,send_charac_name,receive_charac_no,amplify_option,amplify_value,seperate_upgrade,seal_flag,item_id,add_info,upgrade,gold,letter_id,avata_flag,creature_flag) values ('" + timeStr + "','" + title + "'," + CID + ",0,0,0,0," + value.item + "," + value.num + ",0,0," + sl + ",'0','0')";
|
||||
SqlObj.Select(sql1, []);
|
||||
}
|
||||
|
||||
local sql2 = "insert into taiwan_cain_2nd.letter (letter_id,charac_no,send_charac_name,letter_text,reg_date,stat) values ('" + sl + "'," + CID + ",'" + title + "','" + content + "','" + timeStr + "','1')";
|
||||
SqlObj.Select(sql2, []);
|
||||
|
||||
MysqlPool.GetInstance().PutConnect(SqlObj);
|
||||
|
||||
if (SUser) {
|
||||
local Pack = Packet();
|
||||
Pack.Put_Header(0, 9);
|
||||
local MailBox = Sq_CallFunc(S_Ptr("0x0823020C"), "int", ["pointer"], SUser.C_Object);
|
||||
Sq_CallFunc(S_Ptr("0x0823455A"), "int", ["int"], MailBox);
|
||||
local Not_Count = Sq_CallFunc(S_Ptr("0x084ED330"), "int", ["int"], MailBox);
|
||||
Pack.Put_Short(Not_Count);
|
||||
Pack.Finalize(true);
|
||||
SUser.Send(Pack);
|
||||
Pack.Delete();
|
||||
}
|
||||
}
|
||||
63
示例项目/怪物攻城/怪物攻城_南瓜.json
Normal file
63
示例项目/怪物攻城/怪物攻城_南瓜.json
Normal file
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"怪物攻城配置":{
|
||||
"如果攻城开启后没有怪物自行排查PVF是否有攻城副本NPK等":"",
|
||||
"开关(true开启/false关闭)":true,
|
||||
"开启时间[XX点(24小时制), XX分(0-59)]":[20, 30],
|
||||
"怪物攻城胜利所需pt点":300,
|
||||
"怪物攻城总时长(秒)":1800,
|
||||
"活动默认难度(0-4: 普通-英雄)":3,
|
||||
"怪物攻城奖励配置":{
|
||||
"击杀次数":{
|
||||
"1":[3037, 5],
|
||||
"2":[3037, 5],
|
||||
"3":[3037, 20],
|
||||
"4":[1085, 5],
|
||||
"5":[8, 5],
|
||||
"6":[1085, 5],
|
||||
"7":[8, 5],
|
||||
"8":[15, 1],
|
||||
"9":[15, 2],
|
||||
"10":[15, 2],
|
||||
"11":[15, 2],
|
||||
"12":[15, 2],
|
||||
"13":[15, 2],
|
||||
"14":[15, 2],
|
||||
"15":[15, 2],
|
||||
"16":[15, 2],
|
||||
"17":[15, 2],
|
||||
"18":[15, 2],
|
||||
"19":[15, 2],
|
||||
"20":[15, 2],
|
||||
"21":[15, 2],
|
||||
"22":[15, 2],
|
||||
"23":[15, 2],
|
||||
"24":[15, 2],
|
||||
"25":[15, 2],
|
||||
"26":[15, 2],
|
||||
"27":[15, 2],
|
||||
"28":[15, 2],
|
||||
"29":[15, 2],
|
||||
"30":[15, 2]
|
||||
}
|
||||
},
|
||||
"不在配置表里的击杀次数默认奖励道具":[3037, 10],
|
||||
"怪物攻城防守成功固定奖励配置":[[3037, 10], [3038, 10]],
|
||||
"怪物攻城榜一大哥额外点券奖励":10,
|
||||
"怪物攻城其余玩家点券奖励":10,
|
||||
"怪物攻城榜一大哥额外奖励道具(true开启/false关闭)":false,
|
||||
"怪物攻城榜一大哥额外奖励道具":[[3037,20], [3038,20]],
|
||||
"提示1":"点券奖励不想发放,把点券后面的数值改为0就不会发放",
|
||||
"提示2":"点券奖励的发放是由PT点乘以设置的点券,比如设置的是10,那么就是个人PT点*10"
|
||||
},
|
||||
"怪物攻城公告":{
|
||||
"开始":"怪物攻城活动已开始,请各位玩家前往挑战守护我们的家园!",
|
||||
"防守成功":"怪物攻城活动防守成功,感谢各位玩家的努力,奖励已发放!",
|
||||
"防守失败":"怪物攻城活动防守失败,请各位玩家继续努力!",
|
||||
"发送位置":14,
|
||||
">>>发送位置(0系统, 1私聊, 2组队, 3普通, 6公会, 8师徒, 14喇叭, 37系统)":""
|
||||
},
|
||||
"数据库IP 不是外置数据库不要更改": "127.0.0.1",
|
||||
"数据库端口 不懂不要更改": 3306,
|
||||
"数据库用户名 本地用户名不懂不要更改": "game",
|
||||
"数据库密码 本地密码不懂不要更改": "uu5!^%jg"
|
||||
}
|
||||
11
示例项目/战力榜/Proj.ifo
Normal file
11
示例项目/战力榜/Proj.ifo
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ProjectName": "战力榜",
|
||||
"ProjectDescribe": "首先根据使用的登录器在配置文件中选取对应的登录器。PVF相关不提供自行研究,暂不支持RS启动器",
|
||||
"ProjectAuthor": "南瓜",
|
||||
"ProjectVersion": 1.4,
|
||||
"ProjectConfig": "战力榜配置_南瓜.json",
|
||||
"ProjectFiles": [
|
||||
"战力榜.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_Dps_Rank_nangua_Main_"
|
||||
}
|
||||
326
示例项目/战力榜/战力榜.nut
Normal file
326
示例项目/战力榜/战力榜.nut
Normal file
@@ -0,0 +1,326 @@
|
||||
// 排行榜前三名数组 默认数据
|
||||
local Ranklist = {
|
||||
"1": {
|
||||
"rank": 100,
|
||||
"characname": "帝尊天穹",
|
||||
"job": 0,
|
||||
"lev": 60,
|
||||
"Grow": 4,
|
||||
"Guilkey": 0,
|
||||
"GuildName": "诸神之荣丶",
|
||||
"str": "",
|
||||
"equip": [0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0]
|
||||
},
|
||||
"2": {
|
||||
"rank": 90,
|
||||
"characname": "圣皇极境",
|
||||
"job": 1,
|
||||
"lev": 60,
|
||||
"Grow": 4,
|
||||
"Guilkey": 0,
|
||||
"GuildName": "诸神之荣丶",
|
||||
"str": "",
|
||||
"equip": [0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0]
|
||||
},
|
||||
"3": {
|
||||
"rank": 80,
|
||||
"characname": "神王之巅",
|
||||
"job": 2,
|
||||
"lev": 60,
|
||||
"Grow": 4,
|
||||
"Guilkey": 0,
|
||||
"GuildName": "诸神之荣丶",
|
||||
"str": "",
|
||||
"equip": [0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0]
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 获得rank分(排名分数)
|
||||
* 根据配置选择不同的数据库获取战力值
|
||||
* @param {string} charac_no
|
||||
* @returns 返回对应的战力值
|
||||
*/
|
||||
function GetRankNumberBynangua(charac_no) {
|
||||
local Config = GlobalConfig.Get("战力榜配置_南瓜.json");
|
||||
local currentDB = Config["战力榜配置"]["当前选择"];
|
||||
local dbConfig = Config["战力榜配置"]["数据库选择"][currentDB];
|
||||
local SqlObj = MysqlPool.GetInstance().GetConnect();
|
||||
// 构建查询语句 - 直接使用角色ID查询
|
||||
local insertQuery = "SELECT " + dbConfig["字段名"] + " FROM " + dbConfig["数据库名"] + "." + dbConfig["表名"] + " WHERE " + dbConfig["条件字段"] + "=" + charac_no;
|
||||
local column_type_list = ["string"];
|
||||
local result = SqlObj.Select(insertQuery, column_type_list);
|
||||
MysqlPool.GetInstance().PutConnect(SqlObj);
|
||||
if (result.len() > 0) {
|
||||
return result[0][0].tointeger();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//获取个人信息
|
||||
function GetMyEquInfo(SUser) {
|
||||
local MyRanklist = {
|
||||
"rank": 0,
|
||||
"characname": "",
|
||||
"job": 0,
|
||||
"lev": 0,
|
||||
"Grow": 0,
|
||||
"Guilkey": 0,
|
||||
"GuildName": "",
|
||||
"str": "",
|
||||
"equip": []
|
||||
};
|
||||
local Config = GlobalConfig.Get("战力榜配置_南瓜.json");
|
||||
// 检查CID是否在排除列表中
|
||||
if ("角色CID" in Config["战力榜配置"]["排除名单"]) {
|
||||
foreach(excludedCID in Config["战力榜配置"]["排除名单"]["角色CID"]) {
|
||||
if (SUser.GetCID() == excludedCID) {
|
||||
return MyRanklist;
|
||||
}
|
||||
}
|
||||
}
|
||||
MyRanklist.rank = GetRankNumberBynangua(SUser.GetCID());
|
||||
MyRanklist.characname = SUser.GetCharacName();
|
||||
MyRanklist.job = SUser.GetCharacJob();
|
||||
MyRanklist.lev = SUser.GetCharacLevel();
|
||||
MyRanklist.Grow = Sq_CallFunc(S_Ptr("0x815741C"), "int", ["pointer"], SUser.C_Object);
|
||||
MyRanklist.Guilkey = Sq_CallFunc(S_Ptr("0x822F46C"), "int", ["pointer"], SUser.C_Object);
|
||||
MyRanklist.GuildName = SUser.GetGuildName();
|
||||
if (MyRanklist.GuildName.len() == 0) {
|
||||
MyRanklist.GuildName = "天地会"; //当公会不存在时,设置默认公会名字
|
||||
}
|
||||
local InvenObj = SUser.GetInven();
|
||||
if (!InvenObj) {
|
||||
return;
|
||||
}
|
||||
if (InvenObj) {
|
||||
for (local i = 0; i <= 10; i++) {
|
||||
if (i != 9) {
|
||||
local clearAvatar = Sq_CallFunc(S_Ptr("0x0850D374"), "int", ["pointer", "int"], InvenObj.C_Object, i);
|
||||
local ItemObj = InvenObj.GetSlot(0, i);
|
||||
local item_id = clearAvatar > 0 ? clearAvatar : ItemObj.GetIndex();
|
||||
MyRanklist.equip.push(item_id);
|
||||
} else {
|
||||
MyRanklist.equip.push(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return MyRanklist;
|
||||
}
|
||||
|
||||
// 玩家下线时,保存自身信息并且和排行榜进行排名
|
||||
function SetRankingBynangua(SUser) {
|
||||
local IP = Rank_nangua.api_CUser_get_public_ip_address(SUser);
|
||||
if (IP == "10.0.0.1") {
|
||||
return;
|
||||
}
|
||||
local MyRanklist = GetMyEquInfo(SUser);
|
||||
local existingIndex = -1;
|
||||
foreach(index, rankInfo in Ranklist) {
|
||||
if (rankInfo.characname == MyRanklist.characname) {
|
||||
existingIndex = index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (MyRanklist.rank > 0) {
|
||||
if (existingIndex != -1) {
|
||||
Ranklist[existingIndex] = MyRanklist;
|
||||
} else {
|
||||
if (!Ranklist.rawin("4")) {
|
||||
Ranklist["4"] <- {};
|
||||
}
|
||||
Ranklist["4"] = MyRanklist;
|
||||
}
|
||||
|
||||
local rankArray = [];
|
||||
foreach(key, value in Ranklist) {
|
||||
rankArray.append(value);
|
||||
}
|
||||
|
||||
rankArray.sort(function(a, b) {
|
||||
return b.rank - a.rank;
|
||||
});
|
||||
|
||||
// 获取前三名玩家的信息
|
||||
local topThree = rankArray.slice(0, 3);
|
||||
if (Ranklist.rawin("4")) {
|
||||
Ranklist.rawdelete("4");
|
||||
}
|
||||
Ranklist = {
|
||||
"1": topThree[0],
|
||||
"2": topThree[1],
|
||||
"3": topThree[2]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
//清除排名的自定义留言信息
|
||||
function DeleteSpecificMessage() {
|
||||
local G_CGameManager = Sq_CallFunc(S_Ptr("0x080cc18e"), "pointer", []);
|
||||
local Message = Sq_CallFunc(S_Ptr("0x08298EEC"), "pointer", ["pointer"], G_CGameManager);
|
||||
Sq_CallFunc(S_Ptr("0x08600D0C"), "char", ["pointer", "int"], Message, 1);
|
||||
Sq_CallFunc(S_Ptr("0x08600D0C"), "char", ["pointer", "int"], Message, 2);
|
||||
Sq_CallFunc(S_Ptr("0x08600D0C"), "char", ["pointer", "int"], Message, 3);
|
||||
}
|
||||
|
||||
//发送留言信息
|
||||
function UpdateServerMessageByBroadcast(SUser, Ranking, msg) {
|
||||
DeleteSpecificMessage()
|
||||
local Pack = Packet();
|
||||
Pack.Put_Header(0, 192);
|
||||
Pack.Put_Byte(1);
|
||||
Pack.Put_Byte(1);
|
||||
Pack.Put_Byte(Ranking);
|
||||
Rank_nangua.api_InterfacePacketBuf_put_string(Pack, msg);
|
||||
Pack.Finalize(true);
|
||||
SUser.Send(Pack);
|
||||
Pack.Delete();
|
||||
}
|
||||
|
||||
function SendRanklistPacket(SUser, Ranklist, bool) {
|
||||
local Pack = Packet();
|
||||
Pack.Put_Header(0, 182);
|
||||
|
||||
local rankArray = [Ranklist["1"], Ranklist["2"], Ranklist["3"]];
|
||||
|
||||
Pack.Put_Byte(rankArray.len());
|
||||
foreach(index, value in rankArray) {
|
||||
Rank_nangua.api_InterfacePacketBuf_put_string(Pack, value.characname);
|
||||
Pack.Put_Byte(value.lev);
|
||||
Pack.Put_Byte(value.job);
|
||||
Pack.Put_Byte(value.Grow);
|
||||
Rank_nangua.api_InterfacePacketBuf_put_string(Pack, value.GuildName + "");
|
||||
Pack.Put_Int(value.Guilkey);
|
||||
|
||||
for (local i = 0; i < value.equip.len(); i++) {
|
||||
Pack.Put_Int((i != 9) ? value.equip[i] : -1);
|
||||
}
|
||||
}
|
||||
Pack.Finalize(true);
|
||||
|
||||
if (bool) {
|
||||
World.SendAll(Pack);
|
||||
} else {
|
||||
SUser.Send(Pack);
|
||||
}
|
||||
|
||||
Pack.Delete();
|
||||
}
|
||||
|
||||
//因客户端原因,只有名称有变动或排名有变动时才会刷新外观,所以发送一次加空格的名字,然后删除空格再发送一次
|
||||
function SendRankLists(SUser, bool) {
|
||||
local ip = Rank_nangua.api_CUser_get_public_ip_address(SUser);
|
||||
if (ip == "10.0.0.1") {
|
||||
return;
|
||||
}
|
||||
local Config = GlobalConfig.Get("战力榜配置_南瓜.json");
|
||||
foreach(key, value in Ranklist) {
|
||||
value["characname"] = value["characname"] + " ";
|
||||
}
|
||||
SendRanklistPacket(SUser, Ranklist, bool);
|
||||
|
||||
foreach(key, value in Ranklist) {
|
||||
value["characname"] = value["characname"].slice(0, value["characname"].find(" ")) + value["characname"].slice(value["characname"].find(" ") + 1);
|
||||
}
|
||||
//发送排名留言信息
|
||||
UpdateServerMessageByBroadcast(SUser, 1, Config["战力榜配置"]["留言信息"]["第一名"]);
|
||||
UpdateServerMessageByBroadcast(SUser, 2, Config["战力榜配置"]["留言信息"]["第二名"]);
|
||||
UpdateServerMessageByBroadcast(SUser, 3, Config["战力榜配置"]["留言信息"]["第三名"]);
|
||||
SendRanklistPacket(SUser, Ranklist, bool);
|
||||
}
|
||||
|
||||
class Rank_nangua {
|
||||
function api_InterfacePacketBuf_put_string(Pack, s) {
|
||||
local p = Memory.allocUtf8String(s);
|
||||
local len = s.len();
|
||||
Pack.Put_Int(len);
|
||||
Pack.Put_BinaryEx(p.C_Object, len);
|
||||
}
|
||||
function api_CUser_get_public_ip_address(SUser){
|
||||
local s_addr = Sq_CallFunc(S_Ptr("0x084EC90A"), "int", ["pointer"], SUser.C_Object);
|
||||
if(s_addr){
|
||||
local inet_ntoa = Sq_CallFunc(S_Ptr("0x0807DDC0"), "pointer", ["int"], s_addr);
|
||||
return NativePointer(inet_ntoa).readUtf8String();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 创建数据库和表
|
||||
function createRankEventTable() {
|
||||
local CreateSql1 = "create database if not exists DP_S default charset utf8;";
|
||||
local CreateSql2 = "CREATE TABLE IF NOT EXISTS DP_S.event (" +
|
||||
"event_id varchar(30) NOT NULL, " +
|
||||
"event_info mediumtext, " +
|
||||
"PRIMARY KEY (event_id)" +
|
||||
") ENGINE=InnoDB DEFAULT CHARSET=utf8;";
|
||||
local SqlObj = MysqlPool.GetInstance().GetConnect();
|
||||
SqlObj.Exec_Sql(CreateSql1);
|
||||
SqlObj.Exec_Sql(CreateSql2);
|
||||
MysqlPool.GetInstance().PutConnect(SqlObj);
|
||||
}
|
||||
|
||||
// 保存战力榜数据到数据库
|
||||
function saveRanklistToDatabase() {
|
||||
local SqlObj = MysqlPool.GetInstance().GetConnect();
|
||||
local ranklistJson = Json.Encode(Ranklist);
|
||||
local query = "REPLACE INTO DP_S.event (event_id, event_info) VALUES ('ranklist', '" + ranklistJson + "')";
|
||||
SqlObj.Select(query, []);
|
||||
MysqlPool.GetInstance().PutConnect(SqlObj);
|
||||
}
|
||||
|
||||
// 从数据库加载战力榜数据
|
||||
function loadRanklistFromDatabase() {
|
||||
local SqlObj = MysqlPool.GetInstance().GetConnect();
|
||||
local query = "SELECT event_info FROM DP_S.event WHERE event_id = 'ranklist'";
|
||||
local result = SqlObj.Select(query, ["string"]);
|
||||
if (result.len() > 0) {
|
||||
local savedRanklist = Json.Decode(result[0][0]);
|
||||
if (savedRanklist != null) {
|
||||
Ranklist = savedRanklist;
|
||||
}
|
||||
}
|
||||
MysqlPool.GetInstance().PutConnect(SqlObj);
|
||||
}
|
||||
|
||||
// 服务器被Kill时(不含炸频道等)保存战力榜数据
|
||||
Cb_Server_ClossByKill_Leave_Func.ServerClossByKill <- function(args) {
|
||||
local result = args.pop();
|
||||
if (result <= 0) {
|
||||
saveRanklistToDatabase();
|
||||
}
|
||||
}
|
||||
// 服务器异常崩溃时保存战力榜数据
|
||||
Cb_Server_Close_Enter_Func.Server_Close <- function(args) {
|
||||
saveRanklistToDatabase();
|
||||
}
|
||||
|
||||
function _Dps_Rank_nangua_Main_() {
|
||||
local Config = GlobalConfig.Get("战力榜配置_南瓜.json");
|
||||
local PoolObj = MysqlPool.GetInstance();
|
||||
local Ip = Config["数据库IP 不是外置数据库不要更改"];
|
||||
local Port = Config["数据库端口 不懂不要更改"];
|
||||
local DbName = Config["数据库用户名 本地用户名不懂不要更改"];
|
||||
local Password = Config["数据库密码 本地密码不懂不要更改"];
|
||||
PoolObj.SetBaseConfiguration(Ip, Port, DbName, Password);
|
||||
PoolObj.PoolSize = 10;
|
||||
PoolObj.Init();
|
||||
// 创建表
|
||||
createRankEventTable();
|
||||
// 加载战力榜数据
|
||||
loadRanklistFromDatabase();
|
||||
// 玩家下线时
|
||||
Cb_CUser_LogoutToPCRoom_Enter_Func.ReturnSelectCharac <- function(args) {
|
||||
local SUser = User(args[0]);
|
||||
SetRankingBynangua(SUser);
|
||||
SendRankLists(SUser, false);
|
||||
};
|
||||
|
||||
//玩家登录时
|
||||
Cb_reach_game_world_Func.RankByNangua <- function(SUser) {
|
||||
Timer.SetTimeOut(function(SUser) {
|
||||
SendRankLists(SUser, true);
|
||||
}, 3, SUser);
|
||||
};
|
||||
}
|
||||
80
示例项目/战力榜/战力榜配置_南瓜.json
Normal file
80
示例项目/战力榜/战力榜配置_南瓜.json
Normal file
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"战力榜配置": {
|
||||
"当前选择": "长虹",
|
||||
"数据库选择": {
|
||||
"入梦": {
|
||||
"数据库名": "mengyiqu",
|
||||
"表名": "m_ranks",
|
||||
"字段名": "m_rank",
|
||||
"条件字段": "m_cid"
|
||||
},
|
||||
"苍穹": {
|
||||
"数据库名": "d_starsky",
|
||||
"表名": "zhanli",
|
||||
"字段名": "ZLZ",
|
||||
"条件字段": "CID"
|
||||
},
|
||||
"万国": {
|
||||
"数据库名": "d_login",
|
||||
"表名": "zhanli",
|
||||
"字段名": "ZLZ",
|
||||
"条件字段": "CID"
|
||||
},
|
||||
"天子": {
|
||||
"数据库名": "taiwan_cain",
|
||||
"表名": "charac_info",
|
||||
"字段名": "zhandouli",
|
||||
"条件字段": "charac_no"
|
||||
},
|
||||
"晴空": {
|
||||
"数据库名": "qk",
|
||||
"表名": "fightingcapacity",
|
||||
"字段名": "price",
|
||||
"条件字段": "CID"
|
||||
},
|
||||
"黑爵": {
|
||||
"数据库名": "huazhi_v5",
|
||||
"表名": "zhanli",
|
||||
"字段名": "ZLZ",
|
||||
"条件字段": "CID"
|
||||
},
|
||||
"暴雨": {
|
||||
"数据库名": "d_baoyu",
|
||||
"表名": "zhanli",
|
||||
"字段名": "ZLZ",
|
||||
"条件字段": "CID"
|
||||
},
|
||||
"花枝": {
|
||||
"数据库名": "huazhi",
|
||||
"表名": "zhanli",
|
||||
"字段名": "ZLZ",
|
||||
"条件字段": "CID"
|
||||
},
|
||||
"神话": {
|
||||
"数据库名": "asion_login",
|
||||
"表名": "myzhanli",
|
||||
"字段名": "zlz",
|
||||
"条件字段": "zcid"
|
||||
},
|
||||
"长虹": {
|
||||
"数据库名": "d_changhong",
|
||||
"表名": "zhanli",
|
||||
"字段名": "ZLZ",
|
||||
"条件字段": "CID"
|
||||
}
|
||||
},
|
||||
"留言信息": {
|
||||
"第一名": "普天之下,唯我独尊!",
|
||||
"第二名": "四方之内,唯我独霸!",
|
||||
"第三名": "世间万物,唯我独步!"
|
||||
},
|
||||
"排除名单":{
|
||||
"角色CID":[111111, 222222]
|
||||
},
|
||||
"提示":"角色CID可以查看数据库中 taiwan_cain → charac_info → charac_no代表角色ID"
|
||||
},
|
||||
"数据库IP 不是外置数据库不要更改": "127.0.0.1",
|
||||
"数据库端口 不懂不要更改": 3306,
|
||||
"数据库用户名 本地用户名不懂不要更改": "game",
|
||||
"数据库密码 本地密码不懂不要更改": "uu5!^%jg"
|
||||
}
|
||||
11
示例项目/技能拓展14键/Proj.ifo
Normal file
11
示例项目/技能拓展14键/Proj.ifo
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ProjectName": "技能拓展14键",
|
||||
"ProjectDescribe": "14键位技能的服务端修复程序,需要客户端已经加载了14键技能的插件。",
|
||||
"ProjectAuthor": "倾泪寒",
|
||||
"ProjectVersion": 1.0,
|
||||
"ProjectConfig": "",
|
||||
"ProjectFiles": [
|
||||
"技能拓展14键.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_Dps_SkillExpansion_14Keys_Main_"
|
||||
}
|
||||
7
示例项目/技能拓展14键/技能拓展14键.nut
Normal file
7
示例项目/技能拓展14键/技能拓展14键.nut
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
|
||||
|
||||
function _Dps_SkillExpansion_14Keys_Main_()
|
||||
{
|
||||
GameManager.Fix14Skill();
|
||||
}
|
||||
11
示例项目/抗魔值进入副本/Proj.ifo
Normal file
11
示例项目/抗魔值进入副本/Proj.ifo
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ProjectName": "抗魔值进入副本",
|
||||
"ProjectDescribe": "指定的副本按难度及抗魔值才能进入副本",
|
||||
"ProjectAuthor": "南瓜 & 倾泪寒",
|
||||
"ProjectVersion": 1.0,
|
||||
"ProjectConfig": "抗魔值进入副本配置_Nangua.json",
|
||||
"ProjectFiles": [
|
||||
"抗魔值进入副本.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_Dps_anti_evilDgnBynangua_Main_"
|
||||
}
|
||||
123
示例项目/抗魔值进入副本/抗魔值进入副本.nut
Normal file
123
示例项目/抗魔值进入副本/抗魔值进入副本.nut
Normal file
@@ -0,0 +1,123 @@
|
||||
class _evilDgnBynangua {
|
||||
function get_required_gradeBynangua(dgn_id, dgn_diff) {
|
||||
local Config = GlobalConfig.Get("抗魔值进入副本配置_Nangua.json");
|
||||
if (Config["抗魔值进入副本"]["副本配置"].rawin(dgn_id.tostring())) {
|
||||
local requirements = Config["抗魔值进入副本"]["副本配置"][dgn_id.tostring()];
|
||||
for (local i = 0; i < requirements.len(); i += 2) {
|
||||
if (requirements[i] == dgn_diff) {
|
||||
return requirements[i + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function api_CDungeon_getDungeonName(dungeon_id) {
|
||||
local G_CDataManager = Sq_CallFunc(S_Ptr("0x80CC19B"), "pointer", []);
|
||||
local cdungeon = Sq_CallFunc(S_Ptr("0x835F9F8"), "pointer", ["pointer", "int"], G_CDataManager, dungeon_id);
|
||||
if (!cdungeon) {
|
||||
return;
|
||||
}
|
||||
if (cdungeon) {
|
||||
local dgnobj = Sq_CallFunc(S_Ptr("0x81455A6"), "pointer", ["pointer"], cdungeon);
|
||||
local name = NativePointer(dgnobj).readUtf8String();
|
||||
return name;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function join(array, delimiter) {
|
||||
local result = "";
|
||||
for (local i = 0; i < array.len(); ++i) {
|
||||
if (i > 0) {
|
||||
result += delimiter;
|
||||
}
|
||||
result += array[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
getroottable()._Nangua_EquipmentData_List_ <- {};
|
||||
getroottable()._Nangua_EquipmentData_Anti_ <- {};
|
||||
function _Nangua_GetEquipmentData_Anti_(Equipment_id) {
|
||||
try {
|
||||
//如果数据存在 返回数据
|
||||
if (getroottable()._Nangua_EquipmentData_Anti_.rawin(Equipment_id))return getroottable()._Nangua_EquipmentData_Anti_[Equipment_id];
|
||||
//通过装备ID获取装备路径
|
||||
local Path = getroottable()._Nangua_EquipmentData_List_[Equipment_id];
|
||||
Path = "equipment/" + Path;
|
||||
//读取装备数据
|
||||
local Data = ScriptData.GetFileData(Path, function(DataTable, Data) {
|
||||
while (!Data.Eof()) {
|
||||
local Key = Data.Get();
|
||||
if (Key == "[anti evil]") {
|
||||
getroottable()._Nangua_EquipmentData_Anti_[Equipment_id] <- Data.Get();
|
||||
return getroottable()._Nangua_EquipmentData_Anti_[Equipment_id];
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (exception){
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function _Dps_anti_evilDgnBynangua_Main_() {
|
||||
local Config = GlobalConfig.Get("抗魔值进入副本配置_Nangua.json");
|
||||
Script(Config["PVF储存路径_没有更改的话不要改动此配置"]);
|
||||
//if (Config["PVF储存路径_没有更改的话不要改动此配置"].len() > 0) Script(Config["PVF储存路径_没有更改的话不要改动此配置"]);
|
||||
//else Script();
|
||||
|
||||
//读取装备列表
|
||||
getroottable()._Nangua_EquipmentData_List_ = ScriptData.GetFileData("equipment/equipment.lst", function(DataTable, Data) {
|
||||
while (!Data.Eof()) {
|
||||
local Key = Data.Get();
|
||||
//注册装备列表 路径写入 数据未读取
|
||||
DataTable.rawset(Key, Data.Get());
|
||||
}
|
||||
});
|
||||
|
||||
Cb_SelectDungeon_Check_Error_Leave_Func.Check_anti_evilByNangua <- function(args) {
|
||||
local Config = GlobalConfig.Get("抗魔值进入副本配置_Nangua.json");
|
||||
local SUser = User(args[1]);
|
||||
local msg_base = args[2];
|
||||
local PartyObj = SUser.GetParty();
|
||||
local dgn_id = NativePointer(msg_base).add(13).readU16(); // 获取副本ID
|
||||
local dgn_diff = NativePointer(msg_base).add(15).readU8(); // 获取副本难度
|
||||
local required_grade = _evilDgnBynangua.get_required_gradeBynangua(dgn_id, dgn_diff);
|
||||
local diff_name = Config["副本难度命名"][(dgn_diff).tostring()];
|
||||
local Dungeon_Name = _evilDgnBynangua.api_CDungeon_getDungeonName(dgn_id);
|
||||
|
||||
if (PartyObj && Config["抗魔值进入副本"]["抗魔值进入副本开关(true为开启,false为关闭)"]) {
|
||||
local not_enough_users = [];
|
||||
for (local i = 0; i < 4; ++i) {
|
||||
local Tuser = PartyObj.GetUser(i);
|
||||
if (Tuser) {
|
||||
local total_grade = 0;
|
||||
local InvenObj = Tuser.GetInven();
|
||||
if (InvenObj) {
|
||||
for (local j = 0; j <= 25; j++) {
|
||||
local ItemObj = InvenObj.GetSlot(0, j);
|
||||
if (!ItemObj.IsEmpty) {
|
||||
local item_id = ItemObj.GetIndex();
|
||||
print(item_id);
|
||||
local Anti = _Nangua_GetEquipmentData_Anti_(item_id);
|
||||
total_grade += Anti;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 比对抗魔值是否足够
|
||||
if (total_grade < required_grade) {
|
||||
not_enough_users.push(Tuser.GetCharacName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理未达到抗魔值要求的用户
|
||||
if (not_enough_users.len() > 0) {
|
||||
local joinedNames = _evilDgnBynangua.join(not_enough_users, ", ");
|
||||
SUser.SendNotiBox("队伍中玩家[" + joinedNames + "] 抗魔值低于 " + required_grade + " ,无法进入 [" + Dungeon_Name + " - " + diff_name + "]", 2)
|
||||
return 1; // 禁止进入副本
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
23
示例项目/抗魔值进入副本/抗魔值进入副本配置_Nangua.json
Normal file
23
示例项目/抗魔值进入副本/抗魔值进入副本配置_Nangua.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"抗魔值进入副本":{
|
||||
"提示":"抗魔值进入副本配置(副本ID[普通级,所需抗魔值,冒险级,所需抗魔值,勇士级,所需抗魔值,王者级,所需抗魔值,地狱级,所需抗魔值])",
|
||||
"抗魔值进入副本开关(true为开启,false为关闭)":false,
|
||||
"副本配置":{
|
||||
"1":[0, 100, 1, 200, 2, 300, 3, 400, 4, 500, 5, 600],
|
||||
"2":[0, 100, 1, 200, 2, 300, 3, 400, 4, 500, 5, 600],
|
||||
"3":[0, 100, 1, 200, 2, 300, 3, 400, 4, 500, 5, 600],
|
||||
"4":[0, 100, 1, 200, 2, 300, 3, 400, 4, 500, 5, 600],
|
||||
"5":[0, 100, 1, 200, 2, 300, 3, 400, 4, 500, 5, 600],
|
||||
"6":[0, 100, 1, 200, 2, 300, 3, 400, 4, 500, 5, 600],
|
||||
"7":[0, 100, 1, 200, 2, 300, 3, 400, 4, 500, 5, 600]
|
||||
}
|
||||
},
|
||||
"副本难度命名" : {
|
||||
"0": "普通级",
|
||||
"1": "冒险级",
|
||||
"2": "勇士级",
|
||||
"3": "王者级",
|
||||
"4": "地狱级"
|
||||
},
|
||||
"PVF储存路径_没有更改的话不要改动此配置":"/home/neople/game/Script.pvf"
|
||||
}
|
||||
11
示例项目/拓展瞬间移动药剂/Proj.ifo
Normal file
11
示例项目/拓展瞬间移动药剂/Proj.ifo
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ProjectName": "拓展瞬间移动药剂",
|
||||
"ProjectDescribe": "开启后可参考原PVF2600014瞬间移动药剂,复制出不同的移动药剂ID,可无限拓展",
|
||||
"ProjectAuthor": "倾泪寒",
|
||||
"ProjectVersion": 1.0,
|
||||
"ProjectConfig": "",
|
||||
"ProjectFiles": [
|
||||
"拓展瞬间移动药剂.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_Dps_expand_teleport_item_"
|
||||
}
|
||||
4
示例项目/拓展瞬间移动药剂/拓展瞬间移动药剂.nut
Normal file
4
示例项目/拓展瞬间移动药剂/拓展瞬间移动药剂.nut
Normal file
@@ -0,0 +1,4 @@
|
||||
function _Dps_expand_teleport_item_() {
|
||||
NativePointer("0x81D063A").writeS8(0xEB);
|
||||
NativePointer("0x81D0651").writeS8(0xEB);
|
||||
}
|
||||
11
示例项目/指定用户强化必定成功/Proj.ifo
Normal file
11
示例项目/指定用户强化必定成功/Proj.ifo
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ProjectName": "指定用户强化必定成功",
|
||||
"ProjectDescribe": "指定UID用户强化必定成功",
|
||||
"ProjectAuthor": "Pluto",
|
||||
"ProjectVersion": 1.2,
|
||||
"ProjectConfig": "指定用户强化必定成功_Pluto.json",
|
||||
"ProjectFiles": [
|
||||
"指定用户强化必定成功.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_Dps_VipUpgrade_Main_"
|
||||
}
|
||||
52
示例项目/指定用户强化必定成功/指定用户强化必定成功.nut
Normal file
52
示例项目/指定用户强化必定成功/指定用户强化必定成功.nut
Normal file
@@ -0,0 +1,52 @@
|
||||
// ------------------------------------------------------------
|
||||
// 指定用户强化必定成功 by Pluto
|
||||
// ------------------------------------------------------------
|
||||
|
||||
// 核心逻辑函数
|
||||
function _Dps_VipUpgrade_Main_() {
|
||||
|
||||
// 原生 C 函数指针:让装备强化等级 +1
|
||||
local Inven_Item_IncUpgrade_Ptr = S_Ptr("0x0854B4BE");
|
||||
|
||||
// 封装调用函数
|
||||
function IncUpgrade(item) {
|
||||
return Sq_CallFunc(Inven_Item_IncUpgrade_Ptr, "int", ["pointer"], item);
|
||||
}
|
||||
|
||||
// VIP 强化必成功回调
|
||||
Cb_WongWork_CItemUpgrade_Leave_Func.VipUpgrade <- function(args) {
|
||||
|
||||
local Config = GlobalConfig.Get("指定用户强化必定成功_Pluto.json");
|
||||
local vip_user_uid = Config["指定用户的UID"];
|
||||
local vip_user_cid = Config["指定用户的CID"];
|
||||
|
||||
print("=== 强化回调触发 ===");
|
||||
|
||||
// 原函数返回值(不破坏 args)
|
||||
local OldRet = args[args.len() - 1];
|
||||
|
||||
// args[1] 是玩家对象,args[2] 是装备对象
|
||||
local SUser = User(args[1]);
|
||||
local item = args[2];
|
||||
local uid = SUser.GetUID();
|
||||
local cid = SUser.GetCID();
|
||||
|
||||
// 仅对 VIP UID 生效
|
||||
if (vip_user_uid.find(uid) != null || vip_user_cid.find(cid) != null) {
|
||||
if (OldRet == 0) {
|
||||
print("VIP 玩家原强化失败,强制成功: " + SUser.GetCharacName());
|
||||
|
||||
local newLvl = IncUpgrade(item);
|
||||
print("强化后等级: " + newLvl);
|
||||
|
||||
return 1; // 强制返回成功
|
||||
} else {
|
||||
print("VIP 玩家原强化成功,不修改: " + SUser.GetCharacName());
|
||||
}
|
||||
}
|
||||
|
||||
// 默认返回原结果
|
||||
//return OldRet;
|
||||
}
|
||||
}
|
||||
|
||||
4
示例项目/指定用户强化必定成功/指定用户强化必定成功_Pluto.json
Normal file
4
示例项目/指定用户强化必定成功/指定用户强化必定成功_Pluto.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"指定用户的UID":[18000001,18000003],
|
||||
"指定用户的CID":[1,2]
|
||||
}
|
||||
11
示例项目/整点在线奖励/Proj.ifo
Normal file
11
示例项目/整点在线奖励/Proj.ifo
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ProjectName": "整点在线奖励",
|
||||
"ProjectDescribe": "可以设置某一个时间点 全服发放奖励",
|
||||
"ProjectAuthor": "南瓜",
|
||||
"ProjectVersion": 1.3,
|
||||
"ProjectConfig": "整点在线奖励_Lenheart.json",
|
||||
"ProjectFiles": [
|
||||
"整点在线奖励.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_Dps_TimeReward_Main_"
|
||||
}
|
||||
103
示例项目/整点在线奖励/整点在线奖励.nut
Normal file
103
示例项目/整点在线奖励/整点在线奖励.nut
Normal file
@@ -0,0 +1,103 @@
|
||||
// 在线奖励活动入口点
|
||||
function _Dps_TimeReward_Main_() {
|
||||
_Dps_TimeReward_Logic_();
|
||||
}
|
||||
|
||||
// 格式化时间字符串
|
||||
function normalize_time_format(time_str) {
|
||||
local colonPos = time_str.find(":");
|
||||
if (colonPos == null) return null;
|
||||
|
||||
local hour = time_str.slice(0, colonPos).tointeger();
|
||||
local minute = time_str.slice(colonPos + 1).tointeger();
|
||||
|
||||
return format("%02d:%02d", hour, minute);
|
||||
}
|
||||
|
||||
// 在线奖励活动重载入口点
|
||||
function _Dps_TimeReward_Main_Reload_(OldConfig) {
|
||||
// 移除旧配置中的所有定时任务
|
||||
if (OldConfig && "奖励时间和内容" in OldConfig) {
|
||||
foreach(time, reward in OldConfig["奖励时间和内容"]) {
|
||||
local task_id = "TimeRewardTask_" + normalize_time_format(time);
|
||||
Timer.RemoveCronTask(task_id);
|
||||
}
|
||||
}
|
||||
|
||||
// 重新注册
|
||||
_Dps_TimeReward_Logic_();
|
||||
}
|
||||
|
||||
// 在线奖励活动逻辑入口点
|
||||
function _Dps_TimeReward_Logic_() {
|
||||
local Config = GlobalConfig.Get("整点在线奖励_Lenheart.json");
|
||||
|
||||
if(!Config["是否启用在线奖励(true启用/false不启用)"]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 遍历配置的所有奖励时间
|
||||
foreach(time, reward in Config["奖励时间和内容"]) {
|
||||
local hour = time.slice(0, time.find(":")).tointeger();
|
||||
local minute = time.slice(time.find(":") + 1).tointeger();
|
||||
|
||||
// 为每个时间点创建独立的回调函数
|
||||
local callback = function(originalTime = time) {
|
||||
SendTimeReward(originalTime);
|
||||
}
|
||||
|
||||
// 为每个时间点注册一个定时任务
|
||||
local cronExpression = format("0 %d %d * * *", minute, hour);
|
||||
Timer.SetCronTask(callback, {
|
||||
Cron = cronExpression,
|
||||
Name = "TimeRewardTask_" + normalize_time_format(time)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 发放在线奖励
|
||||
function SendTimeReward(rewardTime) {
|
||||
local Config = GlobalConfig.Get("整点在线奖励_Lenheart.json");
|
||||
local OnlinePlayerList = World.GetOnlinePlayer();
|
||||
|
||||
// 直接使用原始时间格式查找奖励
|
||||
local reward = Config["奖励时间和内容"][rewardTime];
|
||||
if (!reward) return;
|
||||
|
||||
// 发放奖励
|
||||
foreach(SUser in OnlinePlayerList) {
|
||||
// 检查是否为假人
|
||||
local IP = _Dps_TimeReward_api.api_CUser_get_public_ip_address(SUser);
|
||||
if (!Config["是否发放奖励给假人(true发放/false不发放)"] && IP == Config["离线假人IP"]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 准备邮件奖励物品列表
|
||||
local RewardItems = [];
|
||||
foreach(itemR in reward) {
|
||||
RewardItems.append([itemR[0], itemR[1]]);
|
||||
}
|
||||
|
||||
// 发送邮件(显示时使用规范化的时间格式)
|
||||
local title = Config["邮件标题"];
|
||||
local Text = format(Config["邮件内容"], normalize_time_format(rewardTime));
|
||||
SUser.ReqDBSendMultiMail(title, Text, 0, RewardItems);
|
||||
}
|
||||
|
||||
// 发送全服公告(显示时使用规范化的时间格式)
|
||||
World.SendNotiPacketMessage(format(Config["公告"], normalize_time_format(rewardTime)), 14);
|
||||
}
|
||||
|
||||
// API类
|
||||
class _Dps_TimeReward_api {
|
||||
// 获取玩家IP地址
|
||||
function api_CUser_get_public_ip_address(SUser){
|
||||
local s_addr = Sq_CallFunc(S_Ptr("0x084EC90A"), "int", ["pointer"], SUser.C_Object);
|
||||
if(s_addr){
|
||||
local inet_ntoa = Sq_CallFunc(S_Ptr("0x0807DDC0"), "pointer", ["int"], s_addr);
|
||||
return NativePointer(inet_ntoa).readUtf8String();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
19
示例项目/整点在线奖励/整点在线奖励_Lenheart.json
Normal file
19
示例项目/整点在线奖励/整点在线奖励_Lenheart.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"是否启用在线奖励(true启用/false不启用)":true,
|
||||
"是否发放奖励给假人(true发放/false不发放)":false,
|
||||
"离线假人IP":"10.0.0.1",
|
||||
"奖励时间和内容":{
|
||||
"12:00":[
|
||||
[3037,10],
|
||||
[3038,11]
|
||||
],
|
||||
"19:30":[
|
||||
[3037,10],
|
||||
[3038,10]
|
||||
]
|
||||
},
|
||||
"邮件标题":"每日在线福利",
|
||||
"邮件内容":"亲爱的玩家,这是[%s]的在线奖励,请查收!",
|
||||
"公告":"今日 [%s] 的在线奖励已发放,请通过邮件查收",
|
||||
"时间格式(24小时制)":"上午8点整则为08:00,晚上19点30分则为19:30,也可以是8:0来表示,也可08:0表示都是允许的"
|
||||
}
|
||||
11
示例项目/时装与宠物清除卷/Proj.ifo
Normal file
11
示例项目/时装与宠物清除卷/Proj.ifo
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ProjectName": "时装与宠物清除卷",
|
||||
"ProjectDescribe": "通过指定ID的道具,将装备背包第前两行的时装或宠物清除。",
|
||||
"ProjectAuthor": "倾泪寒",
|
||||
"ProjectVersion": 1.3,
|
||||
"ProjectConfig": "时装与宠物清除卷_Lenheart.json",
|
||||
"ProjectFiles": [
|
||||
"时装与宠物清除卷.nut"
|
||||
],
|
||||
"ProjectRunFunc": "_Dps_FashionAndPetClearanceRoll_Main_"
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user