成就系统

tech2022-09-19  96

目录

简介及需求数据结构数据库数据数据内容 成就设计成就配置成就管理成就事件成就触发成就验证及统计成就达成及领奖累计重置 总结

简介及需求

成就系统是游戏常见的功能模块,主要就是在用户达成某种条件时进行判定记录成就,难点在于嵌入各种各样的其它功能。

数据结构

数据库数据

--保存数据字段 { "achievement" ,"mediumblob" ,{ achievements = {}, point = 0, pointReward = {}, countdata = {}, isrecord = {}, } ,"成就数据" }, --成就类加载数据 function Achievement:onLoad() self.cache = self.player.cache.achievement self.cache.countdata = self.cache.countdata or {} self.cache.isrecord = self.cache.isrecord or {} self.ConfigList = groupby(server.configCenter.AchievementConfig) end

数据内容

统计类型的数据种类繁多,还在不断更新增加中,其它的不需统计数据发成就id和value值即可

#成就信息 sc_achievement_info 31301 { request { achievements 0 : *group_data #成就分组 point 1 : integer #成就点 countdata 2 : valuedata #成就达成值 } } # 成就数据 .achievement_data { id 0 : integer #成就id time 1 : integer #获得时间 groupID 2 : integer #组id typeID 3 : integer #子类型id value 4 : integer #达到数值 --更新成就才有此字段 point 5 : integer #成就点 } .type_data { typeid 0: integer achievedata 1: *achievement_data } # 成就类型数据 .group_data { groupid 0 : integer typedata 1 : *type_data #组类型数据 } #更新成就 sc_achievement_update 31302 { request { achievementdata 0 : achievement_data } } # 成就统计达成数据 .valuedata { equip_gem 0 : integer #宝石等级 equip_jinglian 1 : integer #精炼等级 equip_wash 2 : integer #重铸次数 pet_compose 3 : integer #宠物合成次数 partner_unlock 4 : integer #仙君解锁个数 partner_call 5 : integer #仙君召唤次数 sign 6 : integer #累计签到次数 sect 7 : integer #门派技能 union 8 : integer #帮派技能 xiulian_role 9 : integer #角色修炼技能 xiulian_pet 10 : integer #宠物修炼技能 chat_speak 11 : integer #世界聊天次数 money 12 : integer #累计获得银币 fengyao 13 : integer #封妖任务次数 chumo 14 : integer #除魔任务次数 chumo_leader 15 : integer #带队除魔任务次数 yaowang 16 : integer #击杀妖王统计 shengxiao 17 : integer #累计击杀十二生肖 xingguan 18 : integer #累计击杀九曜星官 union_guildcontribute 19 : integer #累计帮派贡献 union_donate 20 : integer #累计上交帮派日志 union_daytask 21 : integer #累计帮派日常 kid_num 22 : integer #拥有子女数量 pet_wash 23 : integer #宠物洗练次数 pet_skill_learn 24 : integer #宠物技能学习次数 pet_catch 25 : integer #捕捉宠物累积次数 partner_call_ten 26 : integer #仙君十连召唤次数 mount_num 27 : integer #激活坐骑数 fashion_dress 28 : integer #同时激活时装数 fashion_headshow 29 : integer #同时激活头像数 fashion_touxiangkuang 30 : integer #同时激活头像框数 fashion_qipao 31 : integer #同时激活气泡数 bianshen_count 32 : integer #使用变身卡次数 union_qiyuan 33 : integer #帮派祈愿次数 pet_skill_special 34 : integer #变异宠物数量 partner_quality4 35 : integer #橙色仙君数量 partner_quality5 36 : integer #红色仙君数量 kid_growup_num 37 : integer #拥有成年子女数量 mount_top_num 38 : integer #拥有9阶坐骑数量 fashion_have 39 : integer #永久装扮数量 industry1 40 : integer #采矿等级 industry2 41 : integer #炼药等级 industry3 42 : integer #钓鱼等级 energyUse1 43 : integer #累计烹饪次数 energyUse2 44 : integer #累计炼药次数 energyUse3 45 : integer #累计附魔次数 worldAnswer_num 46 : integer #累计世界答题次数 friend_num 47 : integer #好友数量 vipCard_count1 48 : integer #累计购买周卡次数 vipCard_count2 49 : integer #累计购买月卡次数 building_level1 50 : integer #房屋等级 building_level2 51 : integer #农田等级 building_level3 52 : integer #牧场等级 building_level4 53 : integer #树圃等级 building_speed 54 : integer #累计使用家园卡次数 house_plant 55 : integer #累计种植农田次数 house_animal 56 : integer #累计牧场养殖次数 house_tree 57 : integer #累计家园祈愿次数 house_environment 58 : integer #家园环境度 active_point_150 59 : integer #每日活跃度达成150点累计 battle_all_shengxiao 60 : integer #累计击败十二生肖种类 battle_id_all_shengxiao 61 : integer #累计击败五星十二生肖 battle_all_xingguan 62 : integer #累计击败星官种类 battle_id_all_xingguan 63 : integer #累计击败五星星官 mission_list 64 : integer #累计完成师门任务 mission_yabiao 65 : integer #累计完成运镖任务 mission_xuncheng 66 : integer #累计完成巡城任务 mission_xianyuan 67 : integer #累计完成仙缘任务 achieve_all_xianyuan 68 : integer #累计完成仙缘种类 baotu_count 69 : integer #累计挖宝次数 baotuxiaoyao_count 70 : integer #累计逍遥宝图挖宝次数 baotu_item_low 71 : integer #累计挖到低阶兽决 baotu_item_high 72 : integer #累计挖到高阶兽决 }

成就设计

成就配置

配置表格: 项目代码对应配置:

local AchievementConfig = {} --成就类型 AchievementConfig.Type = { level = {groupID=1,typeID=1}, --等级 prop = {groupID=1,typeID=2}, --属性 equip = {groupID=1,typeID=3}, --装备 pet = {groupID=1,typeID=4}, --宠物 partner = {groupID=1,typeID=5}, --仙君 child = {groupID=1,typeID=6}, --子女 mount = {groupID=1,typeID=7}, --坐骑 sign = {groupID=1,typeID=8}, --累计签到 guanzhi = {groupID=1,typeID=9}, --官职 skill = {groupID=2,typeID=1}, --门派技能 guildskill = {groupID=2,typeID=2}, --帮派技能 xiulian = {groupID=2,typeID=3}, --修炼技能 fishdrug = {groupID=2,typeID=4}, --副职业技能 bianshen = {groupID=2,typeID=6}, --变身 worldchat = {groupID=3,typeID=1}, --世界聊天 friend = {groupID=3,typeID=2}, --统计好友数量 money = {groupID=3,typeID=3}, --统计银币数量 vipCard = {groupID=3,typeID=4}, --统计vip信息 house = {groupID=3,typeID=5}, --统计家园信息 houseplan = {groupID=3,typeID=6}, --统计家园农作信息 environment = {groupID=3,typeID=7}, --统计家园风水环境信息 mission = {groupID=4,typeID=1}, --主线任务完成 fb = {groupID=4,typeID=2}, --副本完成 active = {groupID=5,typeID=1}, --活跃度 chumofengyao = {groupID=5,typeID=2}, --封妖除魔任务 yaowang = {groupID=5,typeID=3}, --妖王 shengxiao = {groupID=5,typeID=4}, --生肖 xingguan = {groupID=5,typeID=5}, --星官 sect = {groupID=5,typeID=6}, --门派任务 baotu = {groupID=5,typeID=7}, --挖宝 xuncheng = {groupID=5,typeID=8}, --累计完成运镖皇城任务 mission3 = {groupID=5,typeID=9}, --累计完成300环任务链 xianyuan = {groupID=5,typeID=10}, --累计完成仙缘任务 union = {groupID=6,typeID=1}, --帮派 } --tupe为1统计数+1,type=2特殊处理 AchievementConfig.CountType = { equip_wash = {name = "equip_wash",type = 1}, --锻造装备次数 pet_wash = {name = "pet_wash",type = 1}, --宠物洗练次数 pet_compose = {name = "pet_compose",type = 1}, --宠物合成次数 pet_skill_learn = {name = "pet_skill_learn",type = 1}, --宠物技能学习次数 pet_catch = {name = "pet_catch",type = 1}, --捕捉宠物累积次数 partner_call = {name = "partner_call",type = 1}, --仙君召唤次数 partner_call_ten = {name = "partner_call_ten",type = 1}, --仙君十连召唤次数 chat_speak = {name = "chat_speak",type = 1}, --世界频道发言 money = {name = "money",type = 1}, --累计获得银币 active_point = {name = "active_point",type = 2},--每日活跃度达成 fengyao = {name = "fengyao",type = 1}, --累计制服捣乱妖怪 chumo = {name = "chumo",type = 1}, --除魔任务统计 chumo_leader = {name = "chumo_leader",type = 1}, --带队完成除魔任务统计 yaowang = {name = "yaowang",type = 1}, --击杀妖王统计 shengxiao = {name = "shengxiao",type = 1}, --累计击杀十二生肖 xingguan = {name = "xingguan",type = 1}, --累计击杀九曜星官 union_guildcontribute = {name = "union_guildcontribute",type = 1}, --累计帮派贡献 union_rob = {name = "union_rob",type = 1}, --累计击杀帮派强盗 union_donate = {name = "union_donate",type = 1}, --累计上交帮派日志 union_store = {name = "union_store",type = 1}, --累计帮派跑商 union_daytask = {name = "union_daytask",type = 1}, --累计帮派日常 union_qiyuan = {name = "union_qiyuan",type = 1}, --累计帮派祈愿次数 bianshen_count = {name = "bianshen_count",type = 1}, --累计使用变身卡次数 fashion_have = {name = "fashion_have",type = 1}, --累计激活永久装扮 energyUse1 = {name = "energyUse1",type = 1}, --累计烹饪次数 energyUse2 = {name = "energyUse2",type = 1}, --累计炼药次数 energyUse3 = {name = "energyUse3",type = 1}, --累计附魔次数 worldAnswer_num = {name = "worldAnswer_num",type = 1}, --累计世界答题次数 worldAnswer_lucky = {name = "worldAnswer_lucky",type = 1}, --累计世界答题幸运奖励次数 vipCard_count1 = {name = "vipCard_count1",type = 1}, --累计购买周卡次数 vipCard_count2 = {name = "vipCard_count2",type = 1}, --累计购买月卡次数 building_speed = {name = "building_speed",type = 1}, --累计使用家园卡次数 house_plant = {name = "house_plant",type = 1}, --累计种植农田次数 house_animal = {name = "house_animal",type = 1}, --累计牧场养殖次数 house_tree = {name = "house_tree",type = 1}, --累计家园祈愿次数 fbdifu1 = {name = "fbdifu1",type = 1}, --累计通关副本普通地府次数 fbdifu2 = {name = "fbdifu2",type = 1}, --累计通关副本精英地府次数 active_point_150 = {name = "active_point_150",type = 1,isrecord = true}, --累计每日活跃度达到150次数,每日只能达成一次 battle_all_shengxiao = {name = "battle_all_shengxiao",type = 1}, --这个手动特殊存,累计击败所有种类的十二生肖 battle_id_all_shengxiao = {name = "battle_id_all_shengxiao",type = 1,all={2003,2013,2023,2033,2043,2053,2063,2073,2083,2093,2103,2113}}, --这个手动特殊存,累计击败所有五星十二生肖 battle_all_xingguan = {name = "battle_all_xingguan",type = 1}, --这个手动特殊存,累计击败所有种类的星官 battle_id_all_xingguan = {name = "battle_id_all_xingguan",type = 1,all={2003,2013,2023,2033,2043,2053,2063,2073,2083,2093,2103,2113}}, --这个手动特殊存,累计击败所有五星星官 mission_list = {name = "mission_list",type = 1}, --累计师门任务次数 mission_yabiao = {name = "mission_yabiao",type = 1}, --累计运镖任务次数 mission_xuncheng = {name = "mission_xuncheng",type = 1}, --累计巡城任务次数 mission_xianyuan = {name = "mission_xianyuan",type = 1}, --累计仙缘任务次数 achieve_all_xianyuan = {name = "achieve_all_xianyuan",type = 1,all={5701,5702,5703,5704,5705,5706,5707,5708,5709,5710,5711,5712,5713,5714}}, --这个手动特殊存,累计完成所有仙缘 baotu_count = {name = "baotu_count",type = 1}, --累计挖宝次数 baotuxiaoyao_count = {name = "baotuxiaoyao_count",type = 1}, --累计逍遥宝图挖宝次数 baotu_item_low = {name = "baotu_item_low",type = 1,all={1501,1502,1503,1504,1505,1506,1507,1508,1509,1510,1511,1512,1513,1514,1515,1516,1517,1518,1519,1520,1521,1522,1523,1524,1525,1526,1527,1528,1529,1530,1531,1532,1533,1534,1535,1536,1537,1538,1539,1540,1541,1542,1543,1544,1545,1546,1547}},--累计挖到兽决 baotu_item_high = {name = "baotu_item_high",type = 1,all={1551,1552,1553,1554,1555,1556,1557,1558,1559,1560,1561,1562,1563,1564,1565,1566,1567,1568,1569,1570,1571,1572,1573,1574,1575,1576,1577,1578,1579,1580,1581,1582,1583,1584,1585,1586,1587,1588,1589,1590,1591,1592,1593,1594,1595,1596,1597}},--累计挖到高级兽决 roleaddexp_count = {name = "roleaddexp_count",type = 1}, --累计人物经验书 }

成就按类型分组发送给客户端,也可以按组验证查询成就

local groupby = function(list) local achievelist = {} for _,v in pairs(list) do if not achievelist[v.groupID] then achievelist[v.groupID] = {} end if not achievelist[v.groupID][v.typeID] then achievelist[v.groupID][v.typeID] = {} end table.insert(achievelist[v.groupID][v.typeID],v) end return achievelist end function Achievement:onLoad() self.cache = self.player.cache.achievement self.cache.countdata = self.cache.countdata or {} self.cache.isrecord = self.cache.isrecord or {} self.ConfigList = groupby(server.configCenter.AchievementConfig) end --获取分组list function Achievement:GetConfigList(groupID,typeID) return self.ConfigList[groupID][typeID] end

成就管理

成就事件

登陆注册事件,触发成就验证方法为onEventCheck,事件详情请看事件系统设计

function Achievement:onLogin() if not self.achievementEvent then self.achievementEvent = self.player:SubEvent(server.enEvent.PlayerEvnt.EVENTID_ACHIEVEMENT_CHECK,self.onEventCheck,self) end if not self.propChangeE then self.propChangeE = self.player:SubEvent(server.enEvent.PlayerEvnt.EVENTID_ENTITY_RPOP_CHANGE,self.onEntityPropChange,self) end if not self.TaskEvent then self.TaskEvent = self.player:SubEvent(server.enEvent.PlayerEvnt.EVENTID_ENTITY_SUBMIT_TASK,self.onTaskSubmit,self) end if not self.BattleEndEvent then self.BattleEndEvent = self.player:SubEvent(server.enEvent.PlayerEvnt.EVENTID_ENTITY_BATTLE_END,self.onBattleEnd,self) end end

成就触发

1.写入方法内,以仙君抽奖为例,在仙君抽奖方法中触发抽奖统计和解锁仙君数量验证

--触发仙君抽奖 local args = {} args.myEntityID = self.player.entityID args.require = AchievementConfig.CountType.partner_call.name args.countType = AchievementConfig.CountType.partner_call.name args.groupdata = AchievementConfig.Type.partner args.value = itemcfg.num args.EventID = server.enEvent.PlayerEvnt.EVENTID_ACHIEVEMENT_CHECK self.player:FireEvent(args.EventID,args) --触发仙君增加 local args = {} args.myEntityID = self.player.entityID args.require = "partner_unlock" args.value = count args.groupdata = AchievementConfig.Type.partner args.EventID = server.enEvent.PlayerEvnt.EVENTID_ACHIEVEMENT_CHECK self.player:FireEvent(args.EventID,args)

2.原有事件触发

--触发人物升级 function Achievement:onLevelUp() local args = {require = "level",value = self.player.cache.level,groupdata = AchievementConfig.Type.level}--对应finishRequire的 {"level",type,value=100} self:onEventCheck(args) end --任务提交判定成就 function Achievement:onTaskSubmit(args) local isachieve = false --正常主线是这样的 local config = server.configCenter.missionConfig[args.missionID] local tab = {require = "mission",id = args.missionID, value = 1} --主线 if config.mType == "main_line" then tab.groupdata = AchievementConfig.Type.mission isachieve = true --封妖 elseif args.missionID == 113 then tab.groupdata = AchievementConfig.Type.chumofengyao tab.countType = AchievementConfig.CountType.fengyao.name isachieve = true --除魔 elseif args.missionID == 112 then tab.groupdata = AchievementConfig.Type.chumofengyao tab.countType = AchievementConfig.CountType.chumo.name isachieve = true --队长除魔触发带队除魔统计统计 local team = server.teamMgr:getTeam(self.player.prop.teamid) if team and team.leader.dbid == self.player.dbid and #team.memlist >= 2 then local tab2 = {groupdata = AchievementConfig.Type.chumofengyao,require = AchievementConfig.CountType.chumo_leader.name,countType = AchievementConfig.CountType.chumo_leader.name} self:onEventCheck(tab2) end --帮派日常 elseif args.missionID == 116 then tab.groupdata = AchievementConfig.Type.union tab.countType = AchievementConfig.CountType.union_daytask.name isachieve = true --运镖日常 elseif args.missionID == 114then tab.groupdata = AchievementConfig.Type.xuncheng tab.countType = AchievementConfig.CountType.mission_yabiao.name isachieve = true --巡城日常 elseif args.missionID == 115then tab.groupdata = AchievementConfig.Type.xuncheng tab.countType = AchievementConfig.CountType.mission_xuncheng.name isachieve = true --师门任务累计 elseif config.name == "师门任务" then local tab2 = {groupdata = AchievementConfig.Type.sect,require = AchievementConfig.CountType.mission_list.name,id = args.missionID,countType = AchievementConfig.CountType.mission_list.name} self:onEventCheck(tab2) --仙缘 elseif config.mType == "xianyuan" then tab.groupdata = AchievementConfig.Type.xianyuan isachieve = true --完成累计仙缘次数 local tab2 = {groupdata = AchievementConfig.Type.xianyuan,require = "mission",type = "xianyuan",countType = AchievementConfig.CountType.xianyuan.name} self:onEventCheck(tab2) --判定是仙缘id if lua_util.inArray(args.cfgId,AchievementConfig.CountType.achieve_all_xianyuan.all) then local idname = AchievementConfig.CountType.achieve_all_xianyuan.name self.cache.countdata[idname] = self.cache.countdata[idname] or {} if not self.cache.countdata[idname][args.cfgId] then self.cache.countdata[idname][args.cfgId] = true local tab2 = {require = "achieve_all",groupdata = AchievementConfig.Type.xianyuan,countType = AchievementConfig.CountType.achieve_all_xianyuan.name} self:onEventCheck(tab2) end end end --触发misson任务 if isachieve then self:onEventCheck(tab) end end

成就验证及统计

当触发成就验证事件时,如果有对应的countType则统计,并将value值改为最新的统计值 成就判定,判定成就条件,type,id,value值,配置若有则需要相同,后续兼容包含,战斗回合等相反数值验证

-- 任务条件检查 function Achievement:onEventCheck(args) local achievetype = args.groupdata if not achievetype then return end local configlist = self:GetConfigList(achievetype.groupID,achievetype.typeID) if not configlist then return end --需统计成就数据 args.value = args.value or 1 if args.countType then for _, v in pairs(AchievementConfig.CountType) do if args.countType == v.name then --是否限时计数 if v.isrecord then if self.cache.isrecord[AchievementConfig.CountType.active_point_150.name] then return end self.cache.isrecord[AchievementConfig.CountType.active_point_150.name] = true end --type1累加统计 if v.type == 1 then local count = self.cache.countdata[args.countType] or 0 self.cache.countdata[args.countType] = count + args.value args.value = self.cache.countdata[args.countType] break elseif v.type == 2 then --type2超过历史统计则替换,不过返回 local count = self.cache.countdata[args.countType] or 0 if args.value > count then self.cache.countdata[args.countType] = args.value break end return end end end end for _,v in pairs(configlist) do --未获得成就,完成条件一致 local require = v.finishRequire if not self.cache.achievements[v.id] and require and require[1] == args.require then local issuccess = true --判定存在的完成条件 if require.type and args.type ~= require.type then issuccess = false end if require.id then if type(require.id) == "table" then if not lua_util.inArray(args.id,require.id) then issuccess = false end elseif args.id ~= require.id then issuccess = false end end if require.value then if args.require == "battle_speed" then if args.value > require.value then issuccess = false end else if args.value < require.value then issuccess = false end end end if issuccess then self:AchievementComplete(v.id,args.value) end end end end

成就达成及领奖

-- 完成成就 function Achievement:AchievementComplete(achievementid,value) local achievementconfig = server.configCenter.AchievementConfig[achievementid] if not achievementconfig then lua_app.log_info("Achievement:achievementconfig not id ", achievementid) return false end if self.cache.achievements[achievementid] then lua_app.log_info("Achievement:achievementconfig exist id ", achievementid) return false end local achievementdata = {id = achievementid,time = lua_app.now(),groupID = achievementconfig.groupID,typeID = achievementconfig.typeID,value = value or 0,point = achievementconfig.point } --发送更新数据 self:GetReward(achievementid) self.cache.point = self.cache.point + achievementconfig.point server.sendReq(self.player, "sc_achievement_update", {achievementdata = achievementdata }) achievementdata.value = nil self.cache.achievements[achievementid] = achievementdata --成就点奖励 local pointcfg = server.configCenter.AchievementGiftConfig for _,cfg in pairs(pointcfg) do if self.cache.point > cfg.point and not lua_util.inArray(cfg.id,self.cache.pointReward) then local mailconfig = server.configCenter.MailMsgConfig[cfg.mail] server.mailCenter:SendMail(self.player.dbid, mailconfig.title, mailconfig.desc, mailconfig.item) table.insert(self.cache.pointReward,cfg.id) end end end -- 领取奖励 function Achievement:GetReward(achievementid) local achievementconfig = server.configCenter.AchievementConfig[achievementid] if achievementconfig then if achievementconfig.drop then local rewards = server.dropCenter:DropGroup(achievementconfig.drop) if rewards then self.player:GiveItem(rewards, 1, 1,server.baseConfig.YuanbaoRecordType.Achievement) end end end if achievementconfig.title then self.role.titleeffect:ActivatePart({id = achievementconfig.title,time = 0}) end if achievementconfig.tipMsg1 then for _,v in pairs(achievementconfig.tipMsg1) do local dbid = self.player.dbid if server.configCenter.TipMsgConfig[v].target == "union" then dbid = self.player.prop.guildid end if dbid ~= 0 then --超链接 server.chatCenter:ChatLink(v,self.player,nil,achievementconfig.name,{server.ChatLinkType.achievement,self.player.entityID,achievementid,lua_app.now()}) end end end if achievementconfig.tipMsg2 then for _,v in pairs(achievementconfig.tipMsg2) do local dbid = self.player.dbid if server.configCenter.TipMsgConfig[v].target == "union" then dbid = self.player.prop.guildid end if dbid ~= 0 then --server.chatCenter:sendTipMsg(v,dbid,self.player.cache.name,achievementconfig.name) --超链接 server.chatCenter:ChatLink(v,self.player,nil,self.player.cache.name,achievementconfig.name,{server.ChatLinkType.achievement,self.player.entityID,achievementid,lua_app.now()}) end end end end

累计重置

--重置当天累计 function Achievement:onDayTimer() local isrecord = self.cache.isrecord if isrecord[AchievementConfig.CountType.active_point_150.name] then isrecord[AchievementConfig.CountType.active_point_150.name] = false end --经验书 local countdata = self.cache.countdata countdata[AchievementConfig.CountType.roleaddexp_count.name] = 0 end

总结

成就的难点,在于多种复合条件的验证判定,也囊括各种任务,帮派,活动,战斗等事件,非自己做的模块需要多花费时间操作

最新回复(0)