天堂开发笔记(四)

开发记录

道具使用

能够喝药水、使用武器、使用装备、选择箭矢

[Recv C] C_OPCODE_USEITEM 请求使用道具
0000: 18 e8 0b 30 13 00 f3 04                            ...0....

[Send C] S_OPCODE_SKILLSOUNDGFX 产生自身动画
0000: 56 e0 0b 30 13 bf 00 00 00 00 00 00 00 00 00 00    V..0............

[Send C] S_OPCODE_SKILLHASTE 魔法或物品产生的加速效果
0000: 0b e0 0b 30 13 01 08 07                            ...0....

[Send C] S_OPCODE_ITEMSTATUS 物品状态更新
0000: 5f e8 0b 30 13 c7 bf bb af d7 d4 ce d2 bc d3 cb    _..0............
0010: d9 d2 a9 cb ae 20 28 32 39 29 00 1d 00 00 00 00    ..... (29)......

[Send C] S_OPCODE_ITEMSTATUS 物品状态更新
0000: 5f e8 0b 30 13 c7 bf bb af d7 d4 ce d2 bc d3 cb    _..0............
0010: d9 d2 a9 cb ae 20 28 32 39 29 00 1d 00 00 00 00    ..... (29)......

[Send C] S_OPCODE_ACTIVESPELLS 激活的符咒
0000: 64 0a 00 00                                        d...

[Handle] ==end==
0000: 18 e8 0b 30 13 00 f3 04                            ...0....

[Recv C] C_OPCODE_USEITEM 请求使用道具
0000: 18 e9 0b 30 13 00 00 00                            ...0....

[Send C] S_OPCODE_SKILLSOUNDGFX 产生自身动画
0000: 56 e0 0b 30 13 c5 00 00 00 00 00 00 00 00 00 00    V..0............

[Send C] S_OPCODE_SERVERMSG 系統訊息
0000: 78 4d 00 00                                        xM..

[Send C] S_OPCODE_HPUPDATE 體力與最大體力更新
0000: 26 10 00 10 00 00 00 00                            &.......

[Send C] S_OPCODE_ITEMSTATUS 物品状态更新
0000: 5f e9 0b 30 13 b9 c5 b4 fa d6 d5 bc ab cc e5 c1    _..0............
0010: a6 bb d6 b8 b4 bc c1 20 28 31 39 39 29 00 c7 00    ....... (199)...
0020: 00 00 00 00                                        ....

[Send C] S_OPCODE_ITEMSTATUS 物品状态更新
0000: 5f e9 0b 30 13 b9 c5 b4 fa d6 d5 bc ab cc e5 c1    _..0............
0010: a6 bb d6 b8 b4 bc c1 20 28 31 39 39 29 00 c7 00    ....... (199)...
0020: 00 00 00                                           ...

[Send C] S_OPCODE_ACTIVESPELLS 激活的符咒
0000: 64 0a 00 00                                        d...

[Handle] ==end==
0000: 18 e9 0b 30 13 00 00 00                            ...0....

[Recv C] C_OPCODE_USEITEM 请求使用道具
0000: 18 02 0c 30 13 00 f3 04                            ...0....

[Send C] S_OPCODE_ITEMNAME 物品名稱
0000: 6e 02 0c 30 13 c1 d4 c8 cb d6 ae b9 ad 20 28 24    n..0......... ($
0010: 39 29 00 00                                        9)..

[Send C] S_OPCODE_OWNCHARSTATUS 角色屬性與能力值
0000: 22 e0 0b 30 13 01 00 00 00 00 14 08 09 0c 0e 0c    "..0............
0010: 10 00 10 00 01 00 01 00 0a 10 65 99 97 28 00 00    ..........e..(..
0020: 00 00 00 00 00                                     .....

[Send C] S_OPCODE_CHARVISUALUPDATE 切換物件外觀動作
0000: 12 e0 0b 30 13 14 00 00                            ...0....

[Handle] ==end==
0000: 18 02 0c 30 13 00 f3 04                            ...0....

[Recv C] C_OPCODE_USEITEM 请求使用道具
0000: 18 fa 0b 30 13 00 fd 44                            ...0...D

[Send C] S_OPCODE_SPMR 魔法攻擊力與魔法防禦力
0000: 53 00 0a 00                                        S...

[Send C] S_OPCODE_SPMR 魔法攻擊力與魔法防禦力
0000: 53 00 0a 00                                        S...

[Send C] S_OPCODE_ITEMNAME 物品名稱
0000: 6e fa 0b 30 13 c3 f0 c4 a7 bd e4 d6 b8 20 28 24    n..0......... ($
0010: 31 31 37 29 00 00 00 00                            117)....

[Send C] S_OPCODE_OWNCHARSTATUS 角色屬性與能力值
0000: 22 e0 0b 30 13 01 00 00 00 00 14 08 09 0c 0e 0c    "..0............
0010: 10 00 10 00 01 00 01 00 0a 10 65 99 97 28 00 00    ..........e..(..
0020: 00 00 00 00 00                                     .....

[Send C] S_OPCODE_OWNCHARATTRDEF 角色屬性值
0000: 51 0a 00 00 00 00 00 00                            Q.......

[Send C] S_OPCODE_OWNCHARSTATUS 角色屬性與能力值
0000: 22 e0 0b 30 13 01 00 00 00 00 14 08 09 0c 0e 0c    "..0............
0010: 10 00 10 00 01 00 01 00 0a 10 65 99 97 28 00 00    ..........e..(..
0020: 00 00 00 00 00                                     .....

[Send C] S_OPCODE_SPMR 魔法攻擊力與魔法防禦力
0000: 53 00 0a 00                                        S...

[Handle] ==end==
0000: 18 fa 0b 30 13 00 fd 44                            ...0...D

[Recv C] C_OPCODE_USEITEM 请求使用道具
0000: 18 e2 0b 30 13 00 18 45                            ...0...E

[Send C] S_OPCODE_SERVERMSG 系統訊息
0000: 78 c4 01 01 ba da c9 ab c3 d7 cb f7 c0 f2 bc fd    x...............
0010: 20 28 31 30 30 30 29 00                             (1000).

[Handle] ==end==
0000: 18 e2 0b 30 13 00 18 45                            ...0...E

[Recv C] S_OPCODE_CHARRESET 角色重置
0000: 2b 00 00 00                                        +...

[Handle] ==end==
0000: 2b 00 00 00                                        +...

[Send C] S_OPCODE_DISCONNECT 立即中斷連線
0000: 58 f4 01 00 00 00 00 00                            X.......

Java版本的道具使用将所有逻辑都写在了一个函数中,不方便后期添加和调试,于是我重构了下,道具使用分为材料道具使用(etcitem)、武器道具使用(weapon)和防具道具使用(armor)

C_ItemUse

道具使用主流程,做一些共性判断,检测玩家当前状态是否能够使用道具,然后根据请求使用的道具类型调用不同类型道具的处理函数C_ArmorItem、C_WeaponItem

C_ArmorItem

处理防具使用,先执行判断检测

  • 检测是否存在等级限制
  • 检测是否存在职业限制
  • 检测装备槽是否有空位
  • 检测是否和已经装备的防具有冲突

然后装备上或脱下道具,并更新玩家状态然后返回更新后的状态到客户端

EquipmentSlot

在实现武器/防具的使用前,需要先实现玩家装备槽

属性:

  • 装备槽所属的角色
  • 当前装备的套装
  • 当前装备的道具

方法:

  • 穿上道具,并更新角色属性
  • 脱下道具,并更新角色属性

C_WeaponItem

处理武器使用,先执行判断检测

  • 检测是否存在等级限制
  • 检测是否存在职业限制
  • 检测是否和已经装备的防具有冲突

然后装备上或脱下或切换道具,并更新玩家状态然后返回更新后的状态到客户端

C_EtcItem

处理材料使用,先执行判断检测

  • 检测是否存在等级限制
  • 特殊类型的道具特殊处理
  • 根据道具模板ID选择对应的道具处理类

道具处理类

C_EtcItemBase

道具处理基类抽象

属性

  • item_ids:标明当前类能处理的道具种类

方法

  • 返回禁止使用道具信息到客户端
  • 处理道具的使用

角色属性计算

力量、敏捷、体质、智力、精神、魅力

# 万能药水使用总数
_elixirStats = 0
# 力量
_str = 0
_trueStr = 0
_baseStr = 0
_originalStr = 0
# 体质
_con = 0
_trueCon = 0
_baseCon = 0
_originalCon = 0
# 敏捷
_dex = 0
_trueDex = 0
_baseDex = 0
_originalDex = 0
# 魅力
_cha = 0
_trueCha = 0
_baseCha = 0
_originalCha = 0
# 智力
_int = 0
_trueInt = 0
_baseInt = 0
_originalInt = 0
# 精神
_wis = 0
_trueWis = 0
_baseWis = 0
_originalWis = 0

为什么每种属性都用四种值表示?
以力量属性为例,角色力量属性的来源分为:职业的基础属性、创建角色奖励玩家的属性、50级以后的属性奖励、万能药水以及装备/武器的属性。
现在我们来看看如何描述这些属性来源:

  • _originalStr(下面两项属PcInstance)
    代表职业的基础属性+创建角色奖励玩家的属性,代表原始力量值,这个值只有在C_CreateChar和C_CharReset才会被改变
  • _baseStr
    代表_originalStr+万能药水+50级以后的属性奖励,这个值就是对应Characters的str字段值
  • _trueStr(下面两项属characters)
    代表_baseStr+装备/武器的属性,在装备或使用武器/装备造成的力量变动时候使用
  • _str
    代表角色力量属性有效值,确保_trueStr在[1,127]区间,为什么_str而不直接在_trueStr上设置[1,127]区间呢? 举个例子:假设当前_baseStr=125,准备使用的装备增加i=3点力量,那么_trueStr=_baseStr+i => 128、_str => 127,如果去掉_str,即_trueStr=127,那么当脱下装备的时候,_trueStr -= i => 124,把_baseStr也多扣了1,所以我们需要_trueStr来计算使用或脱下装备造成的属性改动,使用_str来表示力量属性的真正有效值

命中、伤害

# 近战伤害
_dmgup = 0
_trueDmgup = 0
_baseDmgup = 0
_originalDmgup = 0
_dmgModifierByArmor = 0
# 远程伤害
_bowDmgup = 0
_trueBowDmgup = 0
_baseBowDmgup = 0
_originalBowDmgup = 0
_bowDmgModifierByArmor = 0
# 近战命中
_hitup = 0
_trueHitup = 0
_baseHitup = 0
_originalHitup = 0
_hitModifierByArmor = 0
# 远程命中
_bowHitup = 0
_trueBowHitup = 0
_baseBowHitup = 0
_originalBowHitup = 0
_bowHitModifierByArmor = 0
# 魔法伤害
_originalMagicDamge = 0
# 魔法命中
_originalMagicHit = 0
# 魔法暴击
_originalMagicCritical = 0

和前面的力量属性很类似,这边的命中和伤害用了五种值表示
以伤害为例(命中同理),伤害加成的来源分为:人物属性值产生的伤害加成、武器产生的伤害加成、人物等级产生的伤害加成、魔法产生的伤害加成

  • _dmgModifierByArmor(下面三项属PcInstance)
    代表装备产生的伤害加成
  • _originalDmgup
    代表人物属性值产生的伤害,在resetOriginalDmgup函数中根据角色的_originalStr属性计算伤害加成
  • _baseDmgup
    代表人物等级产生的伤害加成,在resetBaseDmgup函数中根据角色等级计算伤害加成
  • _trueDmgup(下面两项属characters)
    代表_baseDmgup+魔法产生的伤害加成
  • _dmgup
    代表角色空手时的有效伤害加成和力量属性的_str一个意思
  • _originalMagicHit
    代表人物属性值产生的魔法命中,在resetOriginalMagicHit函数中根据角色的_originalInt属性计算魔法命中
  • _originalMagicCritical
    代表人物属性值产生的魔法暴击,在resetOriginalMagicCritical函数中根据角色的_originalInt属性计算魔法暴击

和力量属性不同的是,角色最终的伤害加成并不仅仅是简单的_dmgup + _originalDmgup + _dmgModifierByArmor,这个值是在calcPcPcDamage、calcPcNpcDamage、calcNpcPcDamage中动态计算出来的,和角色攻击对象也有关联,需要扣除攻击对象的伤害减免

防御

_ac = 0
_trueAc = 0
_baseAc = 0
_originalAc = 0

和前面的力量属性很类似,这边的防御也用了四种值表示
防御的来源分为:人物属性值产生的防御、装备产生的防御、人物等级产生的防御、魔法产生的防御

  • _originalAc(下面两项属PcInstance)
    代表人物属性值产生的防御,在resetOriginalAc函数中根据角色的_originalDex属性计算防御
  • _baseAc
    代表人物等级产生的防御,在resetBaseAc函数中根据角色等级和敏捷计算防御
  • _trueAc(下面两项属characters)
    代表_baseAc + _originalAc + 装备产生的防御 + 魔法产生的防御
  • _ac
    代表角色防御有效值

血量、魔量

# 血量
_currentHp = 0
_maxHp = 0
_trueMaxHp = 0
_baseMaxHp = 0
_originalHpup = 0
_advenHp = 0
# 魔量
_currentMp = 0
_maxMp = 0
_trueMaxMp = 0
_baseMaxMp = 0
_originalMpup = 0
_advenMp = 0

这些值的概念和防御非常类似

  • _originalHpup(下面两项属PcInstance)
    代表人物属性值产生的血量,在resetOriginalHpup函数中根据角色的_originalCon属性计算血量
  • _baseMaxHp
    代表random(_originalHpup) + 等级产生的血量,这个值就是对应Characters的MaxHp字段值
  • _trueMaxHp(下面三项属characters)
    代表_baseMaxHp + 装备产生的血量 + 魔法产生的血量
  • _maxHp
    代表角色血量上限,即_trueMaxHp的有效值
  • _currentHp
    代表角色当前血量值

体力回复量、魔力回复量

# 体力回复量
_hpr = 0
_trueHpr = 0
_originalHpr = 0
# 魔力回复量
_mpr = 0
_trueMpr = 0
_originalMpr = 0

以体力回复量为例,角色的体力回复量来源分为:人物属性产生的回复量、装备产生的回复量、药水产生的回复量(回血量和等级无关,所以没有_baseHpr)

  • _originalHpr
    代表人物属性值产生的体力回复量,在resetOriginalHpr函数中根据角色的_originalCon属性计算回血量
  • _trueHpr
    代表套装产生的回血量
  • _hpr
    代表角色体力回复量有效值

魔法防御、魔法攻击

# 魔防
_mr = 0
_trueMr = 0
_baseMr = 0
_originalMr = 0
# 魔攻
_sp = 0

魔防来源:人物属性产生的魔防、装备产生的魔防、魔法产生的魔防、人物等级产生的魔防

  • _originalMr
    代表人物属性值产生的魔防,在resetOriginalMr函数中根据角色的_originalWis属性计算魔防
  • _baseMr
    代表人物等级产生的魔防,在resetBaseMr函数中根据角色等级和精神计算魔防
  • _trueMr
    代表 _originalMr + _baseMr + 装备和魔法产生的魔防
  • _mr
    代表角色魔防有效值

魔攻本来也可以这么弄,但是原先的代码没这么设计,后期可以改成和魔防一样

重量减免、伤害减免、魔法消耗减免

# 重量减免
_weightReduction = 0
_originalStrWeightReduction = 0
_originalConWeightReduction = 0
# 伤害减免
_damageReductionByArmor = 0
# 魔法消耗减免
_originalMagicConsumeReduction = 0

负重减免可以提供角色更多的负重量,伤害减免可以使角色受到的伤害值减小,魔法消耗减免可以减少用户使用魔法时的魔量。其中伤害减免的来源:人物等级、防御值、魔法、装备,后期也可以改造成和前面的属性值一样的模式

属性防御、抗性

# 属性防御
_wind = 0
_trueWind = 0
_water = 0
_trueWater = 0
_fire = 0
_trueFire = 0
_earth = 0
_trueEarth = 0
# 眩晕抗性
_registStun = 0
_trueRegistStun = 0
# 石化抗性
_registStone = 0
_trueRegistStone = 0
# 睡眠抗性
_registSleep = 0
_trueRegistSleep = 0
# 冰冻抗性
_registFreeze = 0
_trueRegistFreeze = 0
# 支撑抗性
_registSustain = 0
_trueRegistSustain = 0
# 闇暗抗性
_registBlind = 0
_trueRegistBlind = 0

属性防御和抗性的来源基本就是装备和魔法

移速

# 一段加速
_moveSpeed
# 二段加速
_braveSpeed

一段就是绿色药水,二段就是勇敢药水,只有有和没有两种状态,没有其他特殊计算

其他属性

后期补充,目前对属性调整比较重要的就这些,其他的后面补充的时候再添加上

BUG修复

描述:灭魔戒子使用只加2点魔防,打印发送和接收数据包的日志,发现"没什么"不同
解决办法:新增日志打印加密和解密前后的数据包,发现两个数据包是没有发送出去的,仔细分析代码是自己自作聪明在不该填充0字节的时候给特殊数据包填充0字节导致数据包正常发送,导致后面的数据包解析出了问题

原文地址:https://www.cnblogs.com/silvermagic/p/7666360.html