170 - API文档汉化 - 对手
Updated 2 months ago对手
特殊序列器
特殊序列器(Special Sequencers)本质上是“全局能力”——它们监听与卡牌相同的触发器,并能基于这些触发器执行代码(例如当卡牌被打出或死亡时、在每个回合开始时等)。虽然您可以直接继承SpecialBattleSequencer基类,但根据使用场景不同,建议从现有序列器层级结构中选择继承。您可通过dnSpy查看所有可用序列器,但以下三类需特别关注:
- SpecialBattleSequencer:所有特殊序列器的基类,默认情况下使用该基类
- BossBattleSequencer:用于头目战场景
- Part1BossBattleSequencer:专用于第一幕头目战(钓鱼人、矿工、猎人与毛皮商及莱西)
特殊序列器需直接设置在玩家触发战斗的对应地图节点NodeData实例上,通过字符串值关联序列器实现。使用API中的SpecialSequenceManager类进行自定义设置:
public class MyCustomBattleSequencer : Part1BossBattleSequencer
{
public static readonly string ID = SpecialSequenceManager.Add(Plugin.PluginGuid, "MySequencer", typeof(MyCustomBattleSequencer));
}
对手系统
在本API语境中,对手(Opponents)可理解为头目单位。Opponent.Type枚举类型用于标识对手类型。需注意某些IDE中可能将该参数类型简示为Type,请勿与System.Type类型混淆。
与其他系统类似,对手是需要自行编写的类,负责处理战斗中的特殊事件。根据对手类型不同,需选择以下基类之一:
- Opponent:所有对手的基类,通常不应直接继承
- Part1Opponent:用于莱西小屋的常规战斗
- Part1BossOpponent:用于莱西小屋的头目战
- PixelOpponent:用于GBC(即第二章)游戏中的战斗
- PixelBossOpponent:用于GBC游戏中的头目战
- Part3Opponent:用于机托邦的常规战斗
- Part3BossOpponent:用于机托邦的头目战
自定义对手需搭配特殊序列器使用(注:特殊序列器与对手系统为何分离属于设计决策,不作解释)。以下代码演示如何创建关联特殊序列器的对手:
public class MyBossOpponent : Part1BossOpponent
{
public static readonly Opponent.Type ID = OpponentManager.Add(Plugin.PluginGuid, "MyBossOpponent", MyCustomBattleSequencer.ID, typeof(MyBossOpponent)).Id;
}
注意OpponentManager.Add的第三个参数为字符串类型,其值应与前文特殊序列器示例中设置的ID保持一致。
若需为对手类型指定蓝图(blueprint),可参照先前示例设置蓝图,并在Awake
、Start
或IntroSequence
重写方法中进行配置(若未在EncounterData对象中设置):
public override IEnumerator IntroSequence(EncounterData encounter)
{
encounterData.Blueprint = EncounterManager.AllEncountersCopy.Find(enc => enc.name == "TurnPlan_2");
List<List<CardInfo>> plan = EncounterBuilder.BuildOpponentTurnPlan(encounterData.Blueprint, difficulty, removeLockedCards);
base.ReplaceAndAppendTurnPlan(plan);
yield return QueueNewCards();
yield return base.IntroSequence(encounter);
}
AI系统
多数情况下无需自定义AI。默认情况下,游戏会评估电脑准备打出的卡牌,通过暴力测试所有可能的卡槽位置,并模拟每个位置下完整回合的结果,最终选择最优解。仅有极少数例外情况。
例如在矿工头目战中,电脑会始终在0号槽位打出骡子(Pack Mule),1号槽位打出郊狼(Coyote)。为确保固定出牌顺序,该战斗使用自定义AI覆盖默认逻辑。
如需实现自定义AI,需创建继承自DiskCardGame.AI的类,并重写SelectSlotsForCards虚方法。该方法即自定义AI逻辑的实现位置。
通过API中的AIManager类注册新AI,并保留返回的字符串ID引用:
public class MyCustomAI : AI
{
public static readonly string ID = AIManager.Add(Plugin.PluginGuid, "MyAI", typeof(MyCustomAI)).Id;
public override List<CardSlot> SelectSlotsForCards(List<CardInfo> cards, CardSlot[] slots)
{
// 在此实现自定义逻辑
}
}
实际使用自定义AI需在特殊序列器的BuildCustomEncounter方法中设置:
public class MyCustomBattleSequencer : Part1BossBattleSequencer
{
public override EncounterData BuildCustomEncounter(CardBattleNodeData nodeData)
{
EncounterData data = base.BuildCustomEncounter(nodeData);
data.aiId = MyCustomAI.ID;
return data;
}
}
头目面具系统
创建自定义头目对手时,可能需要修改莱西在战斗中佩戴的面具。API提供完整支持方案:
修改现有面具
可替换《邪恶冥刻》中已存在的任何面具(包括原版或其他开发者添加的面具):
MaskManager.Override("guid", "nameOfNewMask", LeshyAnimationController.Mask.Angler, "pathToTexture");
此示例将钓鱼人面具替换为自定义纹理。注意:该方法会同时修改模型以避免UV映射问题。如需保留原模型,需调用.SetModelType(MaskManager.ModelType.Angler)
添加随机选择面具
添加新面具至随机选择池,当莱西佩戴面具时会随机选择:
MaskManager.AddRandom("guid", "nameOfNewMask", LeshyAnimationController.Mask.Prospector, "pathToTexture");
此示例为矿工战斗添加新面具选项,莱西将在默认面具与此新面具间随机选择。可添加数量无限制。
添加自定义面具
基础添加方法:
MaskManager.Add("guid", "nameOfNewMask", "pathToTexture");
添加自定义模型
ResourceLookup resourceLookup = new ResourceLookup();
resourceLookup.FromAssetBundle("pathToAssetBundle", "prefabNameInsideBundle");
MaskManager.ModelType modelType = MaskManager.RegisterPrefab("guid", "nameOfModel", resourceLookup);
var mask = MaskManager.Add("guid", "nameOfMask");
mask.SetModelType(modelType);
佩戴面具指令
强制莱西佩戴指定面具(适用于自定义头目战流程):
LeshyAnimationController.Instance.PutOnMask(LeshyAnimationController.Mask.Woodcarver, false);
添加面具行为
public class Plugin : BaseUnityPlugin
{
private void Awake()
{
MyCustomMask.Setup();
}
}
public class MyCustomMask : MaskBehaviour
{
public static LeshyAnimationController.Mask ID;
public static void Setup()
{
var mask = MaskManager.Add("guid", "nameOfNewMask", "pathToTexture");
mask.SetMaskBehaviour(typeof(MyCustomMask));
ID = mask.ID;
}
}
Pages
- 0 - 邪恶冥刻模组简体中文语言包Wiki
- 100 - API文档汉化 - 首页
- 110 - API文档汉化 - 入门指南
- 120 - API文档汉化 - 卡牌
- 121 - API文档汉化 - 自定义卡牌费用系统
- 122 - API文档汉化 - 会说话的卡牌
- 123 - API文档汉化 - 自定义毛皮
- 130 - API文档汉化 - 能力
- 131 - API文档汉化 - 自定义触发器
- 132 - API文档汉化 - 自定义狙击逻辑
- 133 - API文档汉化 - 伤害护盾行为
- 134 - API文档汉化 - 卡槽修改功能
- 135 - API文档汉化 - 触发器与执行顺序
- 140 - API文档汉化 - 自定义/扩展属性
- 150 - API文档汉化 - 扬升(凯茜模组)
- 160 - API文档汉化 - 地图与遭遇战
- 170 - API文档汉化 - 对手
- 180 - API文档汉化 - 图腾
- 190 - API文档汉化 - 道具
- 1A0 - API文档汉化 - 规则书
- 1A1 - API文档汉化 - 添加自定义页面
- 1A2 - API文档汉化 - 添加文本重定向功能
- 1B0 - API文档汉化 - 本地化
- 1B0 - API文档汉化 - 声音
- 1B0 - API文档汉化 - 资产包
- 1C0 - API文档汉化 - 其他特性
- 200 - JSONLoader文档汉化 - Wiki
- 201 - JSONLoader文档汉化 - 枚举值
- A00-凯茜模组通用信息站汉化-首页
- A10-凯茜模组通用信息站汉化-安装
- A11-凯茜模组通用信息站汉化-技术支持常见问题
- A12-凯茜模组通用信息站汉化-补丁
- A20-凯茜模组通用信息站汉化-入门指南
- A30-凯茜模组通用信息站汉化-一般常见问题
- A40-凯茜模组通用信息站汉化-游戏机制
- A50-凯茜模组通用信息站汉化-装饰选项
- A60-凯茜模组通用信息站汉化-与原版游戏的差异
- A70-凯茜模组通用信息站汉化-解锁
- A71-凯茜模组通用信息站汉化-初始牌组
- A72-凯茜模组通用信息站汉化-道具
- A73-凯茜模组通用信息站汉化-卡牌
- A74-凯茜模组通用信息站汉化-伊耶拉克的细节
- A75-凯茜模组通用信息站汉化-挑战
- A76-凯茜模组通用信息站汉化-最终头目
- A77-凯茜模组通用信息站汉化-成就
- A80-凯茜模组通用信息站汉化-提示:挑战提示
- A81-凯茜模组通用信息站汉化-提示:地图节点
- A82-凯茜模组通用信息站汉化-提示:印记
- A90-凯茜模组通用信息站汉化-背景故事
- AA0-凯茜模组通用信息站汉化-ARG解谜
- AA1-凯茜模组通用信息站汉化-ARG事件概览
- AA2-凯茜模组通用信息站汉化-磐石卡牌
- AA3-凯茜模组通用信息站汉化-命令:DAMPNSOGGY
- AA4-凯茜模组通用信息站汉化-命令:RAZORSHARP
- AA5-凯茜模组通用信息站汉化-命令:PALESICKLY
- AA6-凯茜模组通用信息站汉化-命令:LEMONLIMES
- AA7-凯茜模组通用信息站汉化-命令:THESHIPWILLRISEAGAIN
- AA8-凯茜模组通用信息站汉化-频道:#prospector
- AA9-凯茜模组通用信息站汉化-频道:#angler
- AAA-凯茜模组通用信息站汉化-频道:#trader
- AAB-凯茜模组通用信息站汉化-频道:#_-_-_-_-_
- AAC-凯茜模组通用信息站汉化-管理员笔记
- AAD-凯茜模组通用信息站汉化-木雕师的消息
- AAE-凯茜模组通用信息站汉化-提示和工具
- AAF-凯茜模组通用信息站汉化-ARG文档
- AAG-凯茜模组通用信息站汉化-前传ARG
- AB0-凯茜模组通用信息站汉化-趣事:名人堂
- AB1-凯茜模组通用信息站汉化-趣事:耻辱柱
- AB2-凯茜模组通用信息站汉化-趣事:以及其他有趣内容……
- AB3-凯茜模组通用信息站汉化-趣事:全挑战模式胜利记录
- ABC-凯茜模组通用信息站汉化-趣事:解谜和游戏
- AC0-凯茜模组通用信息站汉化-“作弊”:存档修改
- AC1-凯茜模组通用信息站汉化-“作弊”:重复读档
- AD0-凯茜模组通用信息站汉化-漏洞和代码注释