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