和战斗相关的模块有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'发送回玩家进程并写回

英雄远征Erlang源码分析(9)-战斗流程解析相关推荐

  1. 英雄远征Erlang源码分析(1)-源码结构解析

    偶然得到了一份英雄远征的Erlang服务端源代码,想着通过对源代码的分析,来熟悉使用Erlang编程语言的游戏服务器的设计,游戏中关键逻辑的实现. 解压压缩文件后,在Idea内导入文件夹创建相关工程, ...

  2. 英雄远征Erlang源码分析(13)-总结 附上可执行的服务端和客户端代码

    总结:其实也没有什么好总结的......英雄远征这套源码虽然说体积并不大,麻雀虽小五脏俱全,对于MMORPG网游的一些基本系统都有完备的实现,虽然实现方法不一定是最好的.除去场景,战斗,组队,任务等那 ...

  3. 英雄远征Erlang源码分析(2)-网关服务器的启动

    上一篇文章解析了游戏源码的结构,我们知道该源码包含两个服务器的启动脚本:网关服务器和游戏服务器,其中网关服务器用于在玩家选择进入游戏服务器之前获取服务器列表,游戏服务器则处理玩家进入游戏服务器后的登录 ...

  4. 英雄远征Erlang源码分析(12)-任务模块解析

    与玩家任务相关的模块有:lib_task.erl(玩家任务相关操作),mod_task.erl(定时回写任务数据) 玩家任务的初始化: 在登录的时候调用lib_task:flush_role_task ...

  5. 英雄远征Erlang源码分析(5)-协议解析与玩家登录处理

    现在,客户端与服务器的连接算是正式建立了,此时用户需要做的第一件事就是登陆.不过在登录之前,我们要先研究下前后端通信的协议. 客户端与服务端建立连接后,通过提前制定好的协议进行交互.具体的协议文档在d ...

  6. 英雄远征Erlang源码分析(3)-游戏服务器的启动

    上一篇文件介绍了网关服务器的启动,其功能主要用于给客户端返回可选的游戏服务器列表,让客户端去连接.其实有些游戏的网关部分使用的是PHP搭建,代码的维护和Erlang是分开的.现在让我们来看游戏服务器的 ...

  7. 英雄远征Erlang源码分析(10)-队伍相关

    组队相关模块有mod_team.erl和lib_team.erl 通过24000协议请求,调用mod_team:start(Uid,Pid,Nick,TeamName)开启组队进程,创建队伍 组队st ...

  8. 英雄远征Erlang源码分析(8)-怪物相关

    与怪物相关的模块有三个:mod_mon_create.erl,mod_mon_active.erl,lib_mon.erl mod_mon_create:创建负责创建怪物的进程,通过mod_mon_c ...

  9. 英雄远征Erlang源码分析(7)-场景与副本

    场景和副本是玩家活动的区域,场景在服务器启动的时候由mod_scene进程创建,场景信息保存在?ETS_SCENE中,并一直存在:副本在玩家请求进入的时候会创建副本服务进程,当玩家离开的时候会撤销进程 ...

最新文章

  1. 在CentOS 6.3 64bit上安装MySQL for python模块
  2. vue入门实践,style和数据绑定
  3. 2021春季每日一题 【week2 未完结】
  4. Web服务初探:用Demo学Web服务系列(7)——XML的相关知识
  5. C++三五法则,看看你能不能理解(推荐)
  6. MongoDB优化之二:常见优化方法
  7. 流言终结者- Flutter和RN谁才是更好的跨端开发方案?
  8. 【MATLAB基础】——函数的使用
  9. mysql关键字及其用法_mysql的优化-explain
  10. 手机号归属地数据库;根据手机号查找对应的归属地;
  11. 【第3版emWin教程】第14章 emWin6.x的2D图形库之基本绘图
  12. 软件配合实现的“一键开关机电路
  13. 最低销售量计算机公式,最低、最高、安全库存量的计算公式
  14. ubuntu安装discourse论坛----结合在apache服务上建立虚拟主机
  15. cmake:add_library生成静态库和动态库
  16. 怕抢不到演唱会门票?AI帮你做攻略!
  17. QTextEdit和QTextDocument(一)
  18. 虚拟机能ping通宿主机但是ping不通百度
  19. Unity Vuforia AR基础
  20. ACE网络编程开发网

热门文章

  1. Idea快捷键大全(Windows)保存起来,用着就来看看。。
  2. 2500块接的外包Python项目,一款加密的直播引流软件
  3. 龙湖千丁基于 ACK@Edge 的云原生智慧停车系统架构实践
  4. mysql bigd_mysql 5.7 配置多实例 — mysqld_multi 方式
  5. python遥感图像处理_基于Python的矿山遥感监测系统开发方法
  6. 还在用chatGPT聊天?《元宇宙2086》已开始用AIGC做漫画连载了!
  7. 在CNKI上导出TXT文件
  8. .mdf和.ldf数据库文件导入到SQL Server数据库
  9. 计算机实验网上邻居与用户共享,教您如何局域网 网上邻居共享 共享文件 图文教程...
  10. 如何与程控仪器通过GPIB接口进行通信