--------------------------------------------------------------------- -- 本文件定义了一个自动杀怪的逻辑。 -- CREATED BY: Shizhenhua, 2013/8/20 --------------------------------------------------------------------- local AI_STATE_PETROL = 0 -- 四处游荡 local AI_STATE_COMBAT = 1 -- 寻找怪物,战斗 local AI_STATE_DEAD = 2 -- 死亡 local AI_STATE_GOHOME = 3 -- 回城 AutoKillMonster = PolicyBase:new( { cnt_time = Counter:new(), -- 自动打怪的持续时间 cnt_assist = Counter:new(), -- 施放辅助技能的定时器 config = {}, -- 配置数据 human_attacker = 0 -- 攻击我的玩家ID }) -- 初始化策略 function AutoKillMonster:Init() -- 注册状态 self:RegisterState(AI_STATE_PETROL, State_Petrol) self:RegisterState(AI_STATE_COMBAT, State_Combat) self:RegisterState(AI_STATE_DEAD, State_Dead) self:RegisterState(AI_STATE_GOHOME, State_GoHome) -- 注册系统事件 self:RegisterEvent(EVENT_BEHURT, self.OnEvent_BeHurt) self:RegisterEvent(EVENT_SKILLINTERRUPT, self.OnEvent_SkillInterrupt) self:RegisterEvent(EVENT_RETURNTOWNOK, self.OnEvent_ReturnTownOK) self:RegisterEvent(EVENT_CONFIGCHANGED, self.OnEvent_ConfigChanged) end -- 进入该策略 function AutoKillMonster:OnEnter() -- 获取配置数据,设置定时器 self.config = PlayerAPI.GetConfigData() self.cnt_time:SetPeriod(self.config.keeping_time) self.cnt_assist:SetPeriod(self.config.assist_interval) self.cnt_time:Reset() self.cnt_assist:Reset() self.human_attacker = 0 -- 先进入游荡状态 self:ChangeState(AI_STATE_PETROL) end -- 离开该策略 function AutoKillMonster:OnLeave() end -- 更新该逻辑 function AutoKillMonster:OnTick(deltatime) -- 玩家死亡 if PlayerAPI.IsDead() then --self:ChangeState(AI_STATE_DEAD) PlayerAPI.StopPolicy() return end -- 施放辅助技能 if self.cnt_assist:IncCounter(deltatime) then local assist_skill = self.config.assist_skill if assist_skill.is_combo and assist_skill.id >= 0 then PlayerAPI.CastComboSkill(assist_skill.id, true) elseif assist_skill.id > 0 then PlayerAPI.CastSkill(assist_skill.id) end self.cnt_assist:Reset() end -- 修炼时间到,武器持久为0,回城 if self.cnt_time:IncCounter(deltatime) or PlayerAPI.GetWeaponEndurance() == 0 then if not PlayerAPI.HaveAction() and not PlayerAPI.IsDead() and self.human_attacker == 0 then self:ChangeState(AI_STATE_GOHOME) self.cnt_time:Reset() end end -- 判断攻击自己的玩家是否离开视野 if self.human_attacker ~= 0 and not PlayerAPI.IsInSlice(self.human_attacker) then self.human_attacker = 0 PlayerAPI.SetForceAttack(false) end -- 调用基类函数,更新当前状态的逻辑 PolicyBase.OnTick(self, deltatime) end -- 响应被打事件 function AutoKillMonster:OnEvent_BeHurt(attacker) if IsPlayerID(attacker) and self.human_attacker == 0 then self.human_attacker = attacker PlayerAPI.SetForceAttack(true) end if self.cur_state == AI_STATE_PETROL then -- 取消移动 PlayerAPI.CancelAction() -- 进入战斗状态 self:ChangeState(AI_STATE_COMBAT) end end -- 响应技能被中断 function AutoKillMonster:OnEvent_SkillInterrupt(skill_id) if self.cur_state == AI_STATE_GOHOME and skill_id == 167 then -- 处理回城被打断的情况 local state = self.stateMap[self.cur_state] state:OnEvent_SkillInterrupt() end end -- 回城术施放成功 function AutoKillMonster:OnEvent_ReturnTownOK() if self.cur_state == AI_STATE_GOHOME then local state = self.stateMap[self.cur_state] state.intown = true end end -- 配置数据发生改变 function AutoKillMonster:OnEvent_ConfigChanged() self.config = PlayerAPI.GetConfigData() self.cnt_time:SetPeriod(self.config.keeping_time) self.cnt_assist:SetPeriod(self.config.assist_interval) end -- 获取可用的回城香 function AutoKillMonster:GetTownScroll() local slot = -1 local types = {2100, 26652, 33917, 36906} for i=1,table.getn(types) do slot = PlayerAPI.GetItemIndex(PACK_INVENTORY, types[i]) if slot ~= -1 then break end end return slot end --------------------------------------------------------------------- -- 定义本策略的各个状态 --------------------------------------------------------------------- -- 游荡状态 --------------------------------------------------------------------- State_Petrol = State:new(AutoKillMonster, { cnt_keeping = Counter:new(), }) -- 游荡 function State_Petrol:OnEnter() self.cnt_keeping:SetPeriod(60000) self.cnt_keeping:Reset() end function State_Petrol:OnLeave() end function State_Petrol:OnTick(deltatime) -- 一分钟内找不到攻击目标则取消自动打怪 if self.cnt_keeping:IncCounter(deltatime) then PlayerAPI.StopPolicy() self.cnt_keeping:Reset() return end if PlayerAPI.HaveAction() then return end if PlayerAPI.GetSelectedTarget() ~= 0 then self.policy:ChangeState(AI_STATE_COMBAT) else local monster = PlayerAPI.SelectMonster() if monster ~= 0 then self.policy:ChangeState(AI_STATE_COMBAT) else local pos = PlayerAPI.GetPos() pos.x = pos.x + math.random(-100, 100) pos.z = pos.z + math.random(-100, 100) PlayerAPI.MoveTo(pos.x, pos.z) end end end --------------------------------------------------------------------- -- 战斗状态 --------------------------------------------------------------------- State_Combat = State:new(AutoKillMonster, { }) -- 战斗 function State_Combat:OnEnter() end function State_Combat:OnLeave() end function State_Combat:OnTick(deltatime) -- 等待玩家行为完成 if PlayerAPI.HaveAction() then return end -- 处理被玩家袭击的逻辑 if self.policy.human_attacker ~= 0 then if PlayerAPI.GetSelectedTarget() ~= self.policy.human_attacker then PlayerAPI.SelectTarget(self.policy.human_attacker) else local attack_skill = self.policy.config.attack_skill if attack_skill.is_combo then PlayerAPI.CastComboSkill(attack_skill.id) else PlayerAPI.CastSkill(attack_skill.id) end end else -- 打怪 local curSel = PlayerAPI.GetSelectedTarget() if curSel == 0 then -- 优先拾取附近的物品(50米范围) if self.policy.config.autopick then local matter, tid = PlayerAPI.SearchMatter() if matter ~= 0 and PlayerAPI.MatterCanPickup(matter, tid) then PlayerAPI.Pickup(matter) PlayerAPI.AddIdleAction(1000) return end end -- 选取最近的怪物 local monster = PlayerAPI.SelectMonster() if monster ~= 0 then PlayerAPI.SelectTarget(monster) else -- 找不到可攻击目标,进入游荡状态 self.policy:ChangeState(AI_STATE_PETROL) end else if not PlayerAPI.NpcCanAttack(curSel) then PlayerAPI.Unselect() else -- 攻击目标 local attack_skill = self.policy.config.attack_skill if attack_skill.is_combo then PlayerAPI.CastComboSkill(attack_skill.id) else PlayerAPI.CastSkill(attack_skill.id) end end end end if not PlayerAPI.HaveAction() then PlayerAPI.AddIdleAction(1000) end end --------------------------------------------------------------------- -- 死亡状态 --------------------------------------------------------------------- local REVIVEMETHOD_INTOWN = 0 -- 回城复活 local REVIVEMETHOD_BYITEM = 1 -- 复活卷轴 local REVIVEMETHOD_BYOTHER = 2 -- 被其他人复活 State_Dead = State:new(AutoKillMonster, { revived = false, -- 是否已经执行复活操作 revive_method = REVIVEMETHOD_INTOWN, cnt_waithelp = Counter:new(), }) -- 死亡状态 function State_Dead:OnEnter() self.revived = false self.revive_method = REVIVEMETHOD_INTOWN self.cnt_waithelp:SetPeriod(30000) -- 等待别人施救30秒钟 self.cnt_waithelp:Reset() end function State_Dead:OnLeave() end function State_Dead:OnTick(deltatime) if not PlayerAPI.IsDead() then if self.revive_method ~= REVIVEMETHOD_INTOWN then -- 继续自动打怪 self.policy:ChangeState(AI_STATE_COMBAT) else -- 回城复活后停止策略 PlayerAPI.StopPolicy() end elseif not self.revived then -- 有玩家施法相救,这里我们同意复活 if PlayerAPI.IsRevivedByOther() then PlayerAPI.AcceptRevive() self.revive_method = REVIVEMETHOD_BYOTHER self.revived = true PlayerAPI.AddIdleAction(5000) return end -- 30秒内无人复活,自己使用复活卷轴或回城复活 if self.cnt_waithelp:IncCounter(deltatime) then if PlayerAPI.GetItemCount(PACK_INVENTORY, 3043) > 0 then if PlayerAPI.ReviveByItem() then self.revive_method = REVIVEMETHOD_BYITEM else PlayerAPI.ReviveInTown() self.revive_method = REVIVEMETHOD_INTOWN end else PlayerAPI.ReviveInTown() self.revive_method = REVIVEMETHOD_INTOWN end PlayerAPI.AddIdleAction(5000) self.revived = true self.cnt_waithelp:Reset() end end end --------------------------------------------------------------------- -- 回城状态 --------------------------------------------------------------------- State_GoHome = State:new(AutoKillMonster, { intown = false, -- 是否已经回城 behurt_count = 0, -- 回城被打断的次数 }) -- 回城 function State_GoHome:OnEnter() self.intown = false end function State_GoHome:OnLeave() end function State_GoHome:OnTick(deltatime) if PlayerAPI.HaveAction() then return end -- 如果有怪在不断的捣乱,先杀了它们 if PlayerAPI.GetSelectedTarget() ~= 0 then self:KillMonster() return end if not self.intown then if not PlayerAPI.CastSkill(167) then -- 回城术 local slot = self.policy:GetTownScroll() if slot ~= -1 then PlayerAPI.UseItem(slot) else PlayerAPI.StopPolicy() self.behurt_count = 0 end else PlayerAPI.AddIdleAction(1000) end else -- 停止策略 PlayerAPI.StopPolicy() self.behurt_count = 0 end end -- 杀死捣乱的怪 function State_GoHome:KillMonster() local curSel = PlayerAPI.GetSelectedTarget() if curSel == 0 then return end if not IsNPCID(curSel) or not PlayerAPI.NpcCanAttack(curSel) then PlayerAPI.Unselect() return end -- 攻击目标 local attack_skill = self.policy.config.attack_skill if attack_skill.is_combo then PlayerAPI.CastComboSkill(attack_skill.id) else PlayerAPI.CastSkill(attack_skill.id) end end function State_GoHome:OnEvent_SkillInterrupt() if PlayerAPI.GetWeaponEndurance() == 0 then local slot = self.policy:GetTownScroll() if slot ~= -1 then PlayerAPI.UseItem(slot) end else if self.behurt_count >= 3 then local slot = self.policy:GetTownScroll() -- 回城香 if slot ~= -1 then PlayerAPI.UseItem(slot) end else self.behurt_count = self.behurt_count + 1 end end end --------------------------------------------------------------------- -- 注册本策略 AIManager:RegisterPolicy("AutoKillMonster", AutoKillMonster)