feat(偷窃系统): 添加新的偷窃系统功能
- 在FileConfig.json中添加偷窃系统配置 - 实现偷窃系统核心逻辑,包括物品消耗、奖励随机获取和每日重置 - 优化_PVF_Data_类的Seek和Get方法 - 修改Use_Item_Sp.nut中的回调函数为异步执行 - 更新测试命令功能,替换物品掉落为窗口通知
This commit is contained in:
@@ -116,13 +116,11 @@ Gm_InputFunc_Handle["点券"] <- function(SUser, CmdString) {
|
|||||||
|
|
||||||
|
|
||||||
Gm_InputFunc_Handle["test"] <- function(SUser, CmdString) {
|
Gm_InputFunc_Handle["test"] <- function(SUser, CmdString) {
|
||||||
SUser.DropItem(26058, 200, 200);
|
SUser.SendItemWindowNotification([[33900, 1]]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Timer.SetTimeOut(function() {
|
Timer.SetTimeOut(function() {
|
||||||
// _Dps_Equ2AvaJewel_Main_()
|
// _Dps_Equ2AvaJewel_Main_()
|
||||||
// local Pack = Packet();
|
// local Pack = Packet();
|
||||||
|
|||||||
@@ -142,6 +142,11 @@
|
|||||||
"Script": [
|
"Script": [
|
||||||
"换装系统/换装系统.nut"
|
"换装系统/换装系统.nut"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"偷窃系统": {
|
||||||
|
"Script": [
|
||||||
|
"偷窃系统/偷窃系统.nut"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
375
_DPS_/_BuiltProject/偷窃系统/偷窃系统.nut
Normal file
375
_DPS_/_BuiltProject/偷窃系统/偷窃系统.nut
Normal file
@@ -0,0 +1,375 @@
|
|||||||
|
/*
|
||||||
|
File: 偷窃系统.nut
|
||||||
|
Path: _DPS_/_BuiltProject/偷窃系统/偷窃系统.nut
|
||||||
|
*/
|
||||||
|
|
||||||
|
class StealSystem {
|
||||||
|
|
||||||
|
RandomCountMin = 0;
|
||||||
|
RandomCountMax = 0;
|
||||||
|
NpcConfig = null;
|
||||||
|
RequestCache = null;
|
||||||
|
Loaded = false;
|
||||||
|
UseItem = null;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
NpcConfig = {};
|
||||||
|
RequestCache = {};
|
||||||
|
Loaded = InitPvf();
|
||||||
|
if (Loaded) {
|
||||||
|
RegisterClient();
|
||||||
|
InitDailyResetTask();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function RegisterClient() {
|
||||||
|
ClientSocketPackFuncMap.rawset(21017001, function(SUser, Jso) {
|
||||||
|
local ret = false;
|
||||||
|
local npcId = null;
|
||||||
|
try {
|
||||||
|
npcId = Jso.npcid;
|
||||||
|
} catch (exception) {
|
||||||
|
npcId = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
local cid = SUser.GetCID();
|
||||||
|
if (typeof npcId == "integer" && NpcConfig.rawin(npcId)) {
|
||||||
|
if (!RequestCache.rawin(cid)) {
|
||||||
|
RequestCache[cid] <- {};
|
||||||
|
}
|
||||||
|
if (!RequestCache[cid].rawin(npcId)) {
|
||||||
|
ret = true;
|
||||||
|
} else {
|
||||||
|
SUser.SendNotiBox(" 偷窃失败 今日已对该他实施过偷窃", 1);
|
||||||
|
SUser.SendJso({
|
||||||
|
op = 21017002,
|
||||||
|
ret = ret
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print("StealSystem: 21017001 invalid npcid.");
|
||||||
|
SUser.SendJso({
|
||||||
|
op = 21017002,
|
||||||
|
ret = ret
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
local InvenObj = SUser.GetInven();
|
||||||
|
local itemSlot = InvenObj.GetSlotById(UseItem);
|
||||||
|
if (itemSlot == -1) {
|
||||||
|
ret = false;
|
||||||
|
SUser.SendNotiBox(" 偷窃失败 您没有该偷窃消耗物品!", 1);
|
||||||
|
SUser.SendJso({
|
||||||
|
op = 21017002,
|
||||||
|
ret = ret
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
} else if (!InvenObj.DeleteItemCount(UseItem, 1)) {
|
||||||
|
ret = false;
|
||||||
|
SUser.SendJso({
|
||||||
|
op = 21017002,
|
||||||
|
ret = ret
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
RequestCache[cid].rawset(npcId, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
SUser.SendJso({
|
||||||
|
op = 21017002,
|
||||||
|
ret = ret
|
||||||
|
});
|
||||||
|
|
||||||
|
}.bindenv(this));
|
||||||
|
|
||||||
|
ClientSocketPackFuncMap.rawset(21017003, function(SUser, Jso) {
|
||||||
|
local npcId = null;
|
||||||
|
try {
|
||||||
|
npcId = Jso.npcid;
|
||||||
|
} catch (exception) {
|
||||||
|
npcId = null;
|
||||||
|
}
|
||||||
|
if (typeof npcId != "integer") {
|
||||||
|
print("StealSystem: 21017003 invalid npcid.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
local cid = SUser.GetCID();
|
||||||
|
if (!RequestCache.rawin(cid) || !RequestCache[cid].rawin(npcId) || RequestCache[cid][npcId] != 1) {
|
||||||
|
print(format("StealSystem: 21017003 denied for cid=%d npc=%d because 21017001 is not passed.", cid, npcId));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!NpcConfig.rawin(npcId)) {
|
||||||
|
print(format("StealSystem: 21017003 npc config not found for npc=%d.", npcId));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
local groupName = GetRandomGroupName();
|
||||||
|
local groupData = NpcConfig[npcId][groupName];
|
||||||
|
if (groupData.len() == 0) {
|
||||||
|
print(format("StealSystem: 21017003 npc=%d picked empty group %s.", npcId, groupName));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
local drawCount = MathClass.Rand(RandomCountMin, RandomCountMax);
|
||||||
|
if (drawCount <= 0) {
|
||||||
|
print(format("StealSystem: 21017003 draw count <= 0 for npc=%d.", npcId));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
local rewardMap = BuildRewardMap(groupData, drawCount);
|
||||||
|
if (!rewardMap) {
|
||||||
|
print(format("StealSystem: 21017003 failed to build rewards for npc=%d group=%s.", npcId, groupName));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GiveRewardMap(SUser, rewardMap)) {
|
||||||
|
print(format("StealSystem: 21017003 failed to give rewards for cid=%d npc=%d.", cid, npcId));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
local notiadd = [];
|
||||||
|
foreach(Index, Count in rewardMap) {
|
||||||
|
notiadd.append([Index, Count]);
|
||||||
|
}
|
||||||
|
SUser.SendItemWindowNotification(notiadd);
|
||||||
|
|
||||||
|
RequestCache[cid].rawset(npcId, 2);
|
||||||
|
}.bindenv(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
function InitDailyResetTask() {
|
||||||
|
Timer.RemoveCronTask("StealSystemDailyReset");
|
||||||
|
Timer.SetCronTask(function() {
|
||||||
|
RequestCache = {};
|
||||||
|
print("StealSystem: daily request cache reset.");
|
||||||
|
}.bindenv(this), {
|
||||||
|
Cron = "0 0 6 * * *",
|
||||||
|
Name = "StealSystemDailyReset"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function ParseRewardGroup(Data, CloseTag, OutList, Path, NpcId, GroupName) {
|
||||||
|
while (true) {
|
||||||
|
local first = Data.Get();
|
||||||
|
if (first == CloseTag) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (Data.Eof()) {
|
||||||
|
print(format("StealSystem: npc %d %s block missing close tag %s in %s.", NpcId, GroupName, CloseTag, Path));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
local second = Data.Get();
|
||||||
|
if (Data.Eof()) {
|
||||||
|
print(format("StealSystem: npc %d %s block has incomplete entry in %s.", NpcId, GroupName, Path));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
local third = Data.Get();
|
||||||
|
|
||||||
|
if (typeof first != "integer" || typeof second != "integer" || typeof third != "integer") {
|
||||||
|
print(format("StealSystem: npc %d %s block has non-integer entry in %s.", NpcId, GroupName, Path));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
OutList.append({
|
||||||
|
item = first,
|
||||||
|
rate = second,
|
||||||
|
count = third
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function GetRandomGroupName() {
|
||||||
|
local groupNames = ["normal", "rarity", "epic"];
|
||||||
|
return groupNames[MathClass.Rand(0, groupNames.len() - 1)];
|
||||||
|
}
|
||||||
|
|
||||||
|
function RollRewardFromGroup(GroupData) {
|
||||||
|
local totalRate = 0;
|
||||||
|
foreach(_idx, info in GroupData) {
|
||||||
|
if (info.rate > 0) {
|
||||||
|
totalRate += info.rate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (totalRate <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
local randNum = MathClass.Rand(0, totalRate);
|
||||||
|
foreach(_idx, info in GroupData) {
|
||||||
|
if (info.rate <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (randNum< info.rate) {
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
randNum -= info.rate;
|
||||||
|
}
|
||||||
|
return GroupData[GroupData.len() - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
function BuildRewardMap(GroupData, DrawCount) {
|
||||||
|
local rewardMap = {};
|
||||||
|
for (local i = 0; i< DrawCount; i++) {
|
||||||
|
local rewardInfo = RollRewardFromGroup(GroupData);
|
||||||
|
if (!rewardInfo) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!rewardMap.rawin(rewardInfo.item)) {
|
||||||
|
rewardMap[rewardInfo.item] <- 0;
|
||||||
|
}
|
||||||
|
rewardMap[rewardInfo.item] += rewardInfo.count;
|
||||||
|
}
|
||||||
|
return rewardMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
function GiveRewardMap(SUser, RewardMap) {
|
||||||
|
foreach(itemId, itemCount in RewardMap) {
|
||||||
|
if (itemCount <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
local giveRet = SUser.GiveItem(itemId, itemCount);
|
||||||
|
if (!giveRet) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function LoadNpcConfig(NpcId) {
|
||||||
|
local path = format("etc/stealconfig/%d.etc", NpcId);
|
||||||
|
local parseFailed = false;
|
||||||
|
local foundNormal = false;
|
||||||
|
local foundRarity = false;
|
||||||
|
local foundEpic = false;
|
||||||
|
|
||||||
|
local config = ScriptData.GetFileData(path, function(DataTable, Data) {
|
||||||
|
DataTable.normal <- [];
|
||||||
|
DataTable.rarity <- [];
|
||||||
|
DataTable.epic <- [];
|
||||||
|
|
||||||
|
while (!Data.Eof()) {
|
||||||
|
local fragment = Data.Get();
|
||||||
|
if (fragment == "[normal]") {
|
||||||
|
foundNormal = true;
|
||||||
|
if (!ParseRewardGroup(Data, "[/normal]", DataTable.normal, path, NpcId, "normal")) {
|
||||||
|
parseFailed = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (fragment == "[rarity]") {
|
||||||
|
foundRarity = true;
|
||||||
|
if (!ParseRewardGroup(Data, "[/rarity]", DataTable.rarity, path, NpcId, "rarity")) {
|
||||||
|
parseFailed = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (fragment == "[epic]") {
|
||||||
|
foundEpic = true;
|
||||||
|
if (!ParseRewardGroup(Data, "[/epic]", DataTable.epic, path, NpcId, "epic")) {
|
||||||
|
parseFailed = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.bindenv(this));
|
||||||
|
|
||||||
|
if (!config) {
|
||||||
|
print(format("StealSystem: npc %d config file not found: %s.", NpcId, path));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (parseFailed) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!foundNormal || !foundRarity || !foundEpic) {
|
||||||
|
print(format("StealSystem: npc %d config missing required tags in %s.", NpcId, path));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
function InitPvf() {
|
||||||
|
Script();
|
||||||
|
local foundRandomCount = false;
|
||||||
|
local foundNpcTag = false;
|
||||||
|
local parseFailed = false;
|
||||||
|
local minCount = 0;
|
||||||
|
local maxCount = 0;
|
||||||
|
local npcList = [];
|
||||||
|
|
||||||
|
local fileData = ScriptData.GetFileData("etc/steal.etc", function(_n, Data) {
|
||||||
|
while (!Data.Eof()) {
|
||||||
|
local fragment = Data.Get();
|
||||||
|
if (fragment == "[random count]") {
|
||||||
|
local minValue = Data.Get();
|
||||||
|
local maxValue = Data.Get();
|
||||||
|
if (minValue > maxValue) {
|
||||||
|
print("StealSystem: [random count] min is greater than max in etc/steal.etc.");
|
||||||
|
parseFailed = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
minCount = minValue;
|
||||||
|
maxCount = maxValue;
|
||||||
|
foundRandomCount = true;
|
||||||
|
} else if (fragment == "[use item]") {
|
||||||
|
UseItem = Data.Get();
|
||||||
|
} else {
|
||||||
|
foundNpcTag = true;
|
||||||
|
while (true) {
|
||||||
|
local npcId = Data.Get();
|
||||||
|
if (npcId == "[/npc list]") {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (Data.Eof()) {
|
||||||
|
print("StealSystem: [npc list] block missing [/npc list] in etc/steal.etc.");
|
||||||
|
parseFailed = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (typeof npcId != "integer") {
|
||||||
|
print("StealSystem: [npc] contains non-integer npc id in etc/steal.etc.");
|
||||||
|
parseFailed = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
npcList.append(npcId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.bindenv(this));
|
||||||
|
|
||||||
|
if (!fileData) {
|
||||||
|
print("StealSystem: failed to load etc/steal.etc.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (parseFailed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
RandomCountMin = minCount;
|
||||||
|
RandomCountMax = maxCount;
|
||||||
|
NpcConfig = {};
|
||||||
|
|
||||||
|
foreach(_idx, npcId in npcList) {
|
||||||
|
local npcConfig = LoadNpcConfig(npcId);
|
||||||
|
if (!npcConfig) {
|
||||||
|
print(format("StealSystem: skip npc %d due to invalid config.", npcId));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
NpcConfig.rawset(npcId, npcConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Timer.SetTimeOut(function() {
|
||||||
|
local stealSystem = StealSystem();
|
||||||
|
if (!stealSystem.Loaded) {
|
||||||
|
print("StealSystem: initialization failed, object not registered.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getroottable()._StealSystem_ <- stealSystem;
|
||||||
|
}, 1);
|
||||||
@@ -63,40 +63,38 @@ class _PVF_Data_ {
|
|||||||
function Last() {
|
function Last() {
|
||||||
if (Pos > 0) {
|
if (Pos > 0) {
|
||||||
Pos--;
|
Pos--;
|
||||||
return Get();
|
return Data[Pos];
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Seek(i) {
|
function Seek(i) {
|
||||||
if (Pos > 0 && Pos<(Max - 1)) {
|
if (i < 0)
|
||||||
Pos = i;
|
i = 0;
|
||||||
}
|
else if (i > Max)
|
||||||
|
i = Max;
|
||||||
|
Pos = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Seekg(i) {
|
function Seekg(i) {
|
||||||
Pos += i;
|
Seek(Pos + i);
|
||||||
}
|
}
|
||||||
|
|
||||||
function Get() {
|
function Get() {
|
||||||
local Ret = Data[Pos];
|
if (Pos >= Max) {
|
||||||
if (Pos<(Max - 1)) {
|
return null;
|
||||||
Pos++;
|
|
||||||
}
|
}
|
||||||
|
local Ret = Data[Pos];
|
||||||
|
Pos++;
|
||||||
return Ret;
|
return Ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Eof() {
|
function Eof() {
|
||||||
if (Pos == Max - 1)
|
return Pos >= Max;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function Next() {
|
function Next() {
|
||||||
if (Pos<(Max - 1)) {
|
return Get();
|
||||||
Pos++;
|
|
||||||
return Get();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,4 +215,4 @@ class GlobaData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
getroottable().ScriptData <- GlobaData();
|
getroottable().ScriptData <- GlobaData();
|
||||||
|
|||||||
@@ -22,7 +22,9 @@ Cb_History_ItemDown_Func["UseSharedEffectItem"] <- function(SUser, Data) {
|
|||||||
local ItemId = Data[15].tointeger();
|
local ItemId = Data[15].tointeger();
|
||||||
if (ItemId in Cb_Use_Item_Sp_Func) {
|
if (ItemId in Cb_Use_Item_Sp_Func) {
|
||||||
if (SUser) {
|
if (SUser) {
|
||||||
Cb_Use_Item_Sp_Func[ItemId](SUser, ItemId);
|
Timer.SetTimeOut(function() {
|
||||||
|
Cb_Use_Item_Sp_Func[ItemId](SUser, ItemId);
|
||||||
|
}, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user