英雄遠征Erlang源碼分析(9)-戰鬥流程解析

和戰鬥相關的模塊有mod_battle.erl

當玩家進程和怪物進程被創建的時候都會通過mod_battle:start_link()創建一個戰鬥進程。

該戰鬥進程的state,用於保存玩家上次出手或者使用技能的時機,用於cd的判斷

-record(state, {
        last_attack_time=0,   % 上次出手時間
        last_skill_time = []  % [{技能id,上次時間}]
}).

開始戰鬥的時候,生成攻擊方和防守方的#battle_status記錄實例,戰鬥中的傷害通過這兩個記錄實例來計算

戰鬥存在三種情況:玩家打怪,怪打玩家,玩家打玩家

戰鬥的大致流程:
    攻擊方指定防守方Id,指定使用的技能Id,向服務器發送攻擊請求(20001,20003)
    進入攻擊方的戰鬥進程內,通過ETS獲取防守方信息,進行攻擊距離,cd,技能配置等檢查
    檢查通過,計算雙方持續效果buff,計算技能buff,計算傷害
    更新持續buff列表,給防守方玩家(怪物)進程發送消息(Hp,Mp,座標變換),更新雙方狀態,回寫ETS,給客戶端廣播戰鬥結果
    
代碼流程:

mod_battle:battle(Pid, Data) ->        發到戰鬥進程處理
start([Aer,Der,SkillId,State]) ->          初始化雙方#battle_status
attack([Aer1,Der1,SkillId],[Aer,State]) ->        判斷攻擊是否有效,保存新的攻擊者狀態
skill(Aer,Der,SkillId,SkillLv,State) ->               判斷技能cd,距離,羣攻單攻
    double_active_skill(Aer,Der,SkillData,State)            羣體技能
    /single_active_skill(Aer,Der,SKillData,State)    ->    單體技能
        cale_aer/der_last_effect/4    計算自身持續buff
        + cale_active_effect/6          計算技能buff
        + cale_hurt/2                        計算傷害

具體戰鬥流程:

先進行出手頻率檢查:Time - State#state.last_attack_time >= Aer#player_status.att_speed

出手頻率檢查通過,進入start([Aer, Der, SkillId, State]).

%%開啓一個戰鬥服務
start([Aer, Der, SkillId, State])->
    Aer1 = init_data(Aer),
    Der1 = init_data(Der),
    attack([Aer1, Der1, SkillId], [Aer, State]).

將#player_status或者#ets_mon轉換爲#battle_status,傳入attack([Aer, Der, SkillId], [AerInit, State])

attack([Aer, Der, SkillId], [AerInit, State])
獲取玩家技能詳細數據,在skill(Aer, Der, SkillId, SkillLv, State)中使用技能
技能使用結果分爲兩種情況:使用成功和使用失敗
    
skill(Aer, Der, SkillId, Lv, State)
使用主動技能,進行如下幾項判斷:
    技能配置是否存在:獲取#ets_skill
    技能cd是否已達到:State#state{last_skill_time = [{SkillId, Time}]
    玩家MP是否足夠:#ets_skill.data內的{mp_out, MpOut}
    攻擊距離是否足夠:#ets_skill.attarea
    主動還是被動技能,被動技能則使用失敗:#ets_skill.type
    判斷是羣攻還是單攻:#ets_skill.mod,分別調用double/single_active_skill/2
    
single_acvite_skill(Aer, Der, SkillData, State)
單體攻擊
計算攻擊方原有加成buff:buff:cale_aer_last_effect(Aer#battle_status.batle_status, Aer, [], NowTime)
其中#batle_status.battle_status爲[{K,V,T}]的列表結構,K爲加成的屬性名稱,V爲加成屬性的值,T爲加成過期時間,與當前時間比較,如果沒過期則給#battle_status計算加成,如果過期了則把該加成去掉,最後返回一個#battle_status
防守方加成buff計算同理
之後計算技能加成:cale_active_effect(Data , Aer1, Der1, Aer#battle_status.battle_status, Der#battle_status.battle_status, Time)
其中Data爲技能效果列表,在#ets_skill.data中,格式爲{K,V}
除了直接加成數值的效果,有一些值得注意的:
    drug:加毒,需要定時給防守一方的戰鬥進程發送消息,造成持續掉血效果
    shield:法盾,持續一定效果,給防禦方的#battle_status.battle_status加效果
    last_def_del:持續減防,帶有概率,在加持續效果之前先進行隨機

通過隨機數值判斷是否打退,若打退則返還新的防守方座標[X, Y]

計算傷害:將攻擊方和防守方的二級屬性傳入cale_hurt,返還[Hpb,Mpb,Hurt,Status]
傷害計算公式:

    命中:Hit = (0.25 + Hita / (Hita + Dodgeb) * 1.3)
    暴擊:Crit = Crita/(Crita + Tenb)
    基本傷害:Att = (Atta*Atta) div (Atta + Defb)
    最終傷害:沒暴擊trunc(Att/3),暴擊trunc(Att*(1+Critical)/3)

給防禦方發送戰鬥結果
    防禦方是怪物:在怪物進程內接收,修改#ets_mon的Hp,Mp,X,Y並寫回?ETS_MON,觸發人物加經驗,任務殺怪,副本殺怪,怪物掉落事件
    防禦方是人物:在玩家進程內接收,修改#player_status,如果玩家死亡則觸發死亡事件

生成戰鬥結果:
    戰鬥成功:調用send_msg,發送20001協議,將攻擊者新狀態寫回
    戰鬥失敗:調用battle_fail,發送20005協議

羣攻的情況:double_active_skill(Aer,Der,SkillData,State)
先計算攻擊方的持續buff效果和技能buff
獲取攻擊者附近的人物和怪:get_user_for_battle和get_mon_for_battle
    從?ETS_ONLINE和?ETS_MON中取
其他計算防禦方的buff,計算傷害同單攻

使用輔助技能:use_assist_skill([Aer,Der,SkillId,State])
    玩家是否有該技能
    技能配置是否存在
    判斷技能cd:#ets_skill.cd
    判斷MP:從#ets_skill.data中取{mp_out, MpOut}
    判斷釋放目標:#ets_skill.obj,或者傳入的Der={}
        以自己爲目標:
        判斷單攻還是羣攻:#ets_skill.mod
            單攻:single_assist_skill(Aer,Der,SkillData) 作用於自己
            判斷是否持續性類型:#ets_skill.lastime > 0
                持續性類型:cale_assist_last_effect,並將新的持續效果發送給玩家進程並寫回,發送20006協議
                一次性使用類型:cale_assist_one_effect,目前只有加血,將血量寫回玩家進程,發送20006協議
            羣攻:double_assist_skill(Aer,_Der,SkillData),這裏是作用於隊伍成員,從?ETS_ONLINE中找,其他同單攻
        以他人爲目標:先用check_attarea/2判斷攻擊距離,之後同上
    修改完畢的#player_status.battle_status,通過'BATTLE_STATUS'發送回玩家進程並寫回

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章