# 小r战斗系统

一个支持非常多种技能的回合制自动战斗系统，适合场景：挂机游戏

通过简单的编写就可以添加新的技能，如果格式足够标准，这个技能会自然的与其他技能进行化学反应
而不需要作者投入时间去处理各个技能之间的联动

战斗结算极为高速，一次战斗大概耗时3ms~10ms


## 战斗系统的原理

### buff
buff是什么？我们最常见听说的buff是攻击力+xx% 生命恢复+xx%等等。也有人听过debuff的概念。
这里我们扩展BUFF的概念，将所有东西全部视为buff。除了上面提到的，角色的所有技能也全部以buff
形式附加在角色身上

### 为什么这么做？
在一些复杂游戏中，经常会出现角色玩到一半出现新技能的情况（比如大乔一开大，你就可以点击她的传送按钮）。
与其将这些技能特殊处理，不如将所有的技能都视为是后天获得的，统一管理。

buff是本系统的第一公民。

### 抽离buff的共性
我们注意到所有buff都可以抽象成同一种结构：

如果 A 则 B。

这里前一个A是`触发条件`（也可以叫`trigger` `触发时点` `时点`，反正都是我自己起的名字），它会因为特定`事件`而触发。后一个是`动作`，这是一个非常大的抽象。因为它可以模拟所有游戏规则。足以容纳游戏巨大的复杂度。
具体的说，这是为《炉石传说》《游戏王》等极端复杂游戏设计的系统，包容普通的游戏结算算是绰绰有余的了。


### 例子1
下面我们以一个例子示范：

小明（基础攻击100）有2个buff:
* 攻击力+100
* 攻击力+100%

现在需要计算小明的攻击力，这个步骤可以在buff附加好的一瞬间就主动去进行以便后续计算，也可以在需要时再计算（懒加载），这就决定了2种不同的触发时点，这里以简单的第二种作为例子：

1. 要计算攻击力了，发送`计算攻击力数据包`，里面记录了小明的基础攻击`100`，要计算攻击力的人`小明`
2. buff1触发条件：如果要计算攻击力，且计算攻击力的人是`小明`（或者说，计算攻击力的人是本buff的拥有者），则数据包内的攻击`+100`
3. buff2触发条件，同上，数据包内的攻击力`x2`。

随着2个buff正确响应，最后数据包内的攻击力变成了`400`，取出即可。

### 例子1深入思考
我们这里默许了小明计算攻击力时，是先加后乘，但是不同游戏攻击力计算公式有别。如果先乘后加，最后结果就是`300`

有的游戏非常疯狂：随着buff施加顺序的不同，结果也不同，如果变更buff顺序就会影响结果。

或者游戏默认规律就是先加后乘。这样收益是最大化的，很多游戏都这么干。

无论如何，这两个buff的触发时点是相同的，为了正确确定他们的顺序，需要一个优先级机制协调一下。

对于一些更加复杂的情况，可以强行将它们分为2个时点分别进行。

究竟何时应该计算小明的攻击力？如果一个游戏攻击力会频繁的被调用，但是修改的频率稍低，最好的选择是使用一个缓存处理。只在需要的时候刷新。

在本系统中有一个`暴怒`技能，玩家血量越低，攻击力越高。这使得很难决定何时才应该刷新攻击力。（只要生命变动就得改）

讨论性能问题为时尚早。所以我没写缓存。也就不需要考虑上面的复杂问题了。

### 例子2
第一个例子只是正常Buff的结算而已。第二个例子会讲解技能是如何成为buff的。

其实别无二致，只需要一个`施加技能`触发的`事件`即可。施加技能在一般游戏里可能是玩家按下了按钮，在挂机游戏里当然是由一个死循环反复触发的。

如果 `施加技能` 则 `开始技能结算`
然后`开始技能结算`里又开始调用`获取攻击力``获取防御力`等等例子1里提过的很乏味的内容了
普攻也是一种技能。

### 其他细节

* 可堆叠层数，且最大层数有限的buff，是需要考虑合并操作的。
* 有些buff会使你免疫另一些buff。
* 有些buff有持续时间
* 有些buff会往全局变量里写东西
* 有些buff会扭曲其他buff的效果

看起来只是小细节实际上每个处理起来都很麻烦。因为buff的行为只是一个封装好的函数而已，
除非去修改字节码，函数流程已经固定了，自然承受不起合并甚至扭曲的摧残，只能写一些很丑的代码放一些全局变量之类的打好补丁。


### 实现细节

`msgManager.py`是负责管理buff的地方，它负责让所有buff都在合适的时机运行。

这是个美差，因为buff已经自带了判断函数。

他要做的就是在受到消息时依次问每个buff要不要行动就行了。

这个模式可以认为是观察者模式或者分发生产模式或者别的什么。我不熟悉。

数据包也是个重点，例子1里提到了`计算攻击力数据包`，实际上事件非常多样，所以真正的数据包种类繁多。

但是完全没必要写几百个数据包类，全部塞在一个里面（`msgPack.py`）才是最好的。

## 特殊适配的部分

我针对即将做的游戏进行了特殊适配，失去了一些一般性。不过可以比较轻松的调整。

目前把所有技能作为词条附着在角色身上

没有魔力，基本没有主动技能

没有`日志系统`

## 战斗示例

`skilltest.py`里有很多战斗测试，运行查看log即可

## 完整设计
如果对本系统是如何作用于炉石等游戏的感兴趣，可阅读`https://zhuanlan.zhihu.com/p/534675937`