Files
DP-S_Script/示例项目/怪物攻城/怪物攻城.nut
2026-04-16 16:27:53 +08:00

398 lines
17 KiB
Plaintext

//活动开始阶段
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();
}
}