在写AI之前,和创建一个新扩展包一样,要先看一下文件的编码。我们的AI文件依然要采用【格式】中的【以UTF-8无BOM格式编码】这个菜单项。否则有可能最后让我们的工作前功尽弃哦!
</br>好了,现在我们就去写AI了!让孙悟空动起来~
</br>首先,获取问题。
</br>还记得是什么地方开始出现选择的吗?好像是一个提示框,问我们“您想发动技能【变身】吗?”——就是它了。
</br>对应到代码里面,就是:
```
room:askForSkillInvoke(player, "LuaBianshen", data)
```
![](https://img.kancloud.cn/9b/a7/9ba762d5aa41c3fd184dffac78deb6a5_646x91.png)
</br>`askForSkillInvoke`同样是Room的一个成员函数,用于询问是否发动某项技能,其原型为:
```
askForSkillInvoke(player, skill_name, data)
```
![](https://img.kancloud.cn/7d/c5/7dc56407f98a45d452adc9fcf3e45926_1078x27.png)
</br>翻译过来,就是:
askForSkillInvoke(角色对象,技能名字,环境数据)
</br>所以当系统遇到这句话的时候,就会向当前角色(player)询问是否发动技能(skill_name);表现在游戏中,就是弹出那个提示框了。
这,就是我们获取到的问题了。
</br>做一点小笔记:有时Room会轮休,ServerPlayer会来帮它问我们是否发动技能。只不过在ServerPlayer门下干活的`askForSkillInvoke`换成了这个样子:
```
askForSkillInvoke(skill_name, data)
```
![](https://img.kancloud.cn/94/47/9447f0eb67759ff4269fb0ad897137bf_853x26.png)
</br>不过就是没有了那个player参数了,毕竟前面有ServerPlayer撑腰嘛。当然了,效果是一样的。遇到它的时候可不要不认得了~
</br>然后就该在我们的小纸条study-ai.lua里面写上问题的解决方案了。
</br>为了告诉电脑我们写的内容是针对`askForSkillInvoke`这个问题,要这么写:
```
sgs.ai_skill_invoke.LuaBianshen
```
</br>它的取值有两个,`true`发动这个技能,或者`false`不发动。
</br>这一小段的通用格式是:`sgs.ai_skill_invoke.技能名字`
</br>其实呢,`sgs.ai_skill_invoke`是smart-ai.lua中的一个表的名字,这个表里面集中记录了电脑遇到各种可以主动发动的技能时的处理动作。然后那个点`.`看着眼熟吧?它表示后面的技能名字属于这个表,有点类似于结构体和它的成员变量的关系(怪不得用法都一样)。
</br>所以现在我们这样写:
```
sgs.ai_skill_invoke.LuaBianshen = true
```
</br>就表示,电脑遇到系统询问发动变身技能的时候,总是变身。
![](https://img.kancloud.cn/c5/3c/c53cfd7f47601eec81a4e0b94f4519b9_485x95.png)
</br>保存起来,电脑就知道怎么做了。赶紧去游戏中看看热闹吧!
![](https://img.kancloud.cn/b1/c0/b1c01e283970422ae28cf7e3c4737aef_1280x770.png)
</br>从游戏记录中看得更明白:
(我们操控的是孙悟空[1],没有选择变身;电脑操控的是孙悟空[2],发动了变身。)
![](https://img.kancloud.cn/24/50/2450053772fc9f5edf7c737f2f4ebb1b_839x287.png)
</br>然而,有时我们需要电脑按事情情况进行选择,而不是不管三七二十一,一律选`true`,这时我们就要在文件中用到函数了。使用函数计算出什么时候该用`true`,什么时候又该用`false`,使得电脑看上去更加智能。
</br>先把代码改写成函数的样子:
![](https://img.kancloud.cn/58/2b/582bbc891c70e3e93d373285184ff9ed_564x197.png)
</br>还记得解决问题需要那些内容吗?没错,问题本身、环境数据、特征信息以及问题决策。而问题自身和环境数据都是系统提供的,所以我们的函数就带有这样的两个参数:表示问题本身的self,还有表示环境数据的data。并且,连同这个函数一起,构成了对问题的决策。当然啦,现在这个变身的问题条件足够,不需要更多的信息了,所以特征信息的那部分就先不考虑了。
</br>使用函数可以让我们分情况作出不一样的决策。
</br>比如现在我们这样写:
![](https://img.kancloud.cn/2c/dc/2cdcc281593f7f46fd9b89348f715286_583x179.png)
</br>当本角色拥有技能枭姬的时候,发动变身,否则不变身。
</br>孙悟空现在只有无双、美王、变身这三个技能,没有枭姬,肯定是不会变身的了。不过如果是在双将模式,与孙尚香组成双将的话,就会进行变身了。(孙权+孙尚香,想想都好强大的样子……)
</br>单将模式:没有变身。
![](https://img.kancloud.cn/bd/e0/bde0b0f90bc536ee7f4e6c6907060bd5_1280x770.png)
</br>双将模式:副将孙尚香,拥有技能枭姬,发动变身。
![](https://img.kancloud.cn/c7/99/c79904b99ca0290632479cf82ed1ca86_1280x770.png)
</br>哦,同将模式是不能测试双将的,所以双将的那个图,可以用游戏双开完成。只要在技能发动之前退出造成离线就可以了,电脑会自动接管的。或者,托管也可以造成同样的效果。
![](https://img.kancloud.cn/03/ff/03ff209b958a82cff7bdd5af74f2193e_823x272.png)
</br>代码里面还是有点需要总结的地方的:
</br>我们可以通过`self.player`获取到当前的玩家对象,类似地,可以通过`self.room`获取到当前的游戏房间对象。这些内容很多情况下在决策中会起到关键性的作用。所以不要以为问题本身在解决问题的时候毫无用处哦!以后会经常用到它的~
</br>另外,可以通过`hasSkill`方法判断玩家是否拥有某个技能,这为我们的决策提供了更多的配合上的参考。己方有鬼道鬼才什么的就尽管装闪电吧!
</br>不过还是对没有露面的那个特征信息耿耿于怀。那是什么东西啊?
简单看两眼好啦。比如:
</br>sgs.ai_chaofeng.武将名称:定义了一个武将的嘲讽值,默认是0,数目越大,嘲讽越高,惨遭集火的可能性就越大。目前最高的应该是华佗和孙尚香吧,嘲讽值达到了6,最低的应该是神曹操和神关羽,都是-6。
</br>sgs.武将名称_suit_value:定义了一个武将对各种卡牌花色的喜欢程度。卡牌的花色有黑桃(spade)、红心(heart)、草花(club)、方块(diamond)四种。像华佗就喜欢红心和方块的卡牌,甘宁则喜欢黑桃和草花。
</br>sgs.武将名称_keep_value:定义了一个武将对拥有各种卡牌的兴趣程度。像孙尚香就喜欢各种装备,而黄月英则对各种锦囊感兴趣;如果黄盖看到桃子和诸葛连弩两眼发光,也是这个道理。
</br>sgs.ai_use_value.卡牌名称:定义了一种卡牌在武将手里的使用价值,数值高的话就说明,电脑可以通过使用这种卡牌得到更多利益。
</br>sgs.ai_use_priority.卡牌名称:定义了武将使用一种卡牌的优先级,数值越高,电脑就越会优先考虑使用这种卡牌。
</br>诸如此类的数值,具体到不同的武将、技能、卡牌身上都会有所不同,而电脑事先是不好凭空猜到的,当然需要我们先在这张纸条上写好了告诉它喽。
</br>偷偷地告诉自己:这些信息呢,其实我们是可以从旁边那个extension-doc\general_config.lua以及value_config.lua中找到的。
![](https://img.kancloud.cn/3d/09/3d09686baef1874e3ac30ca5f012aedc_634x462.png)
</br>保存一下,我们的AI文件就这样写好了。就是这样。
- 编写说明
- 第一章 创建一个新武将
- 1.1 开发环境准备
- 1.2 创建一个新的武将扩展包
- 1.3 创建我们的新武将
- 第二章 添加技能
- 第三章 武将美化
- 3.1 美化环境准备
- 3.2 添加武将卡牌
- 3.3 添加武将头像
- 3.4 添加武将标签
- 第四章 创建一个新技能
- 第五章 添加音效
- 5.1 打造自己的声音工作室
- 5.2 添加技能使用音效
- 5.3 添加武将阵亡音效
- 第六章 添加提示信息
- 6.1 添加代码注释
- 6.2 显示提示信息
- 6.3 启动全屏信息特效
- 第七章 武将变更
- 第八章 启用AI
- 8.1 创建我们的AI文件
- 8.2 真实的AI
- 8.3 动手写AI
- 第九章 修改距离
- 第十章 技能管理
- 10.1 技能判定
- 10.2 创建技能
- 10.3 获得技能
- 10.4 失去技能
- 第十一章 修改手牌上限
- 第十二章 体力变更
- 12.1 流失体力
- 12.2 制造伤害
- 13.3 恢复体力
- 12.4 流失体力上限
- 12.5 增长体力上限
- 第十三章 游戏进程的变更
- 13.1 创建阶段触发技能
- 13.2 跳过回合阶段
- 13.3 插入一个额外的回合阶段
- 13.4 启用翻面
- 13.5 获得一个额外的回合
- 第十四章 启用标记(Mark)
- 14.1 添加标记
- 14.2 获得标记
- 14.3 失去标记
- 14.4 查看标记数目
- 第十五章 卡牌转换
- 15.1 主动牌的转换
- 15.2 被动牌的转换
- 第十六章 卡牌传递
- 16.1 创建摸牌技能
- 16.2 游戏中摸牌
- 16.3 游戏中弃牌
- 16.4 从其他武将处获得牌
- 16.5 判断目标区域是否有牌
- 16.6 移动场上的牌
- 第十七章 用牌实现技能效果
- 第十八章 启用标志(Flag)
- 第十九章 涉足判定领域
- 19.1 启用判定
- 19.2 更改判定
- 19.3 获得判定牌
- 第二十章 私家牌堆
- 20.1 向牌堆中添加牌
- 20.2 查看牌堆中牌的数量
- 20.3 从牌堆中移除牌
- 第二十一章 牌的锁定
- 第二十二章 免疫牌
- 第二十三章 让房间提供牌
- 23.1 提供主动牌
- 23.2 提供被动牌
- 第二十四章 启用标签(Tag)
- 第二十五章 濒死结算
- 第二十六章 交换座次
- 第二十七章 创建主公技
- 27.1 创建由主公发起的主公技
- 27.2 创建由他人发起的主公技
- 第二十八章 强力技能
- 28.1 直接死亡
- 28.2 改换身份
- 28.3 原地复活
- 28.4 立即胜利