添加示例项目
This commit is contained in:
22
AGENTS.md
Normal file
22
AGENTS.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# Repository Guidelines
|
||||||
|
|
||||||
|
## Project Structure & Module Organization
|
||||||
|
This repository is a DP-S game-server hotfix tree. `Main.nut` is the entry point and hot-loads five roots: `OfficialConfig/`, `OfficialProject/`, `_DPS_/_Core/`, `_DPS_/_BuiltProject/`, and `MyProject/`. Put shared framework code, hooks, and callback glue in `_DPS_/_Core/`. Treat `_DPS_/_BuiltProject/` as bundled baseline features. Add official feature modules under `OfficialProject/<功能名>/`, usually with a matching `<功能名>.nut` and optional `Proj.ifo`; keep module JSON beside it in `OfficialConfig/`. Use `MyProject/` for local or experimental scripts. Runtime outputs belong in `log/`; native binaries and maintenance scripts live in `lib/`.
|
||||||
|
|
||||||
|
## Build, Test, and Development Commands
|
||||||
|
There is no standalone compile step for `.nut` scripts; the server reloads them through `GameManager.OpenHotFix(...)` in `Main.nut`.
|
||||||
|
|
||||||
|
- `git status` - check the workspace before editing or submitting.
|
||||||
|
- `git diff --stat` - review the size and scope of your change.
|
||||||
|
- `Get-Content Main.nut` - confirm hotfix load order and active roots.
|
||||||
|
- `Get-ChildItem OfficialProject, OfficialConfig, MyProject` - inspect feature and config layout.
|
||||||
|
- `bash lib/strip_other_funcs_unix.sh lib/libAurora.so` - maintenance-only helper for the Aurora binary; do not run unless you are intentionally updating symbols.
|
||||||
|
|
||||||
|
## Coding Style & Naming Conventions
|
||||||
|
Use 4-space indentation and keep lines readable. Follow existing Squirrel patterns: `PascalCase` for helper functions, callback maps like `Cb_*`, and descriptive feature names for folders and main scripts. Keep one primary feature per folder/file pair, for example `OfficialProject/战力榜/战力榜.nut`. Name configs by feature, optionally with a server suffix such as `战力榜配置_南瓜.json`. Prefer small, focused hooks over large unrelated edits.
|
||||||
|
|
||||||
|
## Testing Guidelines
|
||||||
|
This repo has no automated test suite yet. Validate changes on a development server by reloading the affected hotfix path, exercising the related GM command, callback, or dungeon flow, and checking `log/` for regressions. When a module reads JSON, test both the script change and the matching config file together.
|
||||||
|
|
||||||
|
## Commit & Pull Request Guidelines
|
||||||
|
Recent history favors Conventional Commit prefixes such as `feat`, `fix`, `refactor`, and `docs`, often with a scope: `feat(偷窃系统): ...`. Keep new commits in that style even though older messages are mixed. PRs should explain gameplay impact, list touched paths, call out config or data migrations, and include screenshots or log snippets when the change affects announcements, UI text, or player-visible flows.
|
||||||
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表示都是允许的"
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user