GcResource解析与自定义
最近研究了某游戏的resource文件内容,本文将通过分析这些resource文件的内容,并通过Grasscutter代码的resource部分来分析一些功能
目录
代码与resource文件的获取
在GitHub上我们可以找到Grasscutter程序代码,而resource文件你可以通过dc,GitHub,Gitlab或者某些论坛获得,文章末尾友情链接我会给出更多地址来提供参考
resource文件整体分布情况
大部分resource文件分布情况如同下列结构
none
--Root
--BinOutput
--ExcelBinOutput
--Readable
--Scripts
--Subtitle
--TextMap
--QuestEncryptionKeys.json
其中我们需要重点分析BinOutput与ExcelBinoutput文件夹,需要注意的是不同resource文件的BinOutput并不完全相同,我在正文给的BinOutput是如下结构:
none
--BinOutput
--Ability
--AbilityGroup
--Avatar
--Gadget
--HomeworldDefaultSave
--LevelDesign
--LevelEntity
--Quest
--Scene
--Talent
而友情链接中的某些resource文件可能会比上述多出一些文件,当然我们并不需要分析那么多,上述文件除去任务场景与关卡部分无需分析外其他的都需要分析。
而ExcelBinOutput文件夹大部分resource文件都相同,而且其本质是将excel转化为json格式文件,我们在后需用到后会另外说明
需要查看的代码文件
为什么查看代码,有下面2点原因
查看代码可以更快找到需要分析的文件
分析角色数据加载过程,可以更方便的理解角色技能加载过程
打开割草机源代码后其分布方式为如下结构:
none
--Grasscutter\src\main\java\emu\grasscutter
--auth
--command
--config
--data
--database
--game
--net
--plugin
--scripts
--server
--task
--tools
--utils
--GameConstants.java
--Grasscutter.java
我们重点查看data文件夹下的代码,data文件夹下为如下结构
none
--data
--binout
--AbilityData.java
--AbilityEmbryoEntry.java
--AbilityModifier.java
--AbilityModifierEntry.java
--ConfigGadget.java
--ConfigGadgetCombat.java
--ConfigGadgetCombatProperty.java
--HomeworldDefaultSaveData.java
--MainQuestData.java
--OpenConfigEntry.java
--SceneNpcBornData.java
--SceneNpcBornEntry.java
--ScenePointEntry.java
--ScriptSceneData.java
--common
--CurveInfo.java
--DynamicFloat.java
--FightPropData.java
--ItemParamData.java
--ItemParamStringData.java
--ItemUseData.java
--OpenCondData.java
--PointData.java
--PropGrowCurve.java
--excels
--More Files
--......
--DataLoader.java
--GameData.java
--GameDepot.java
--GameResource.java
--ResourceLoader.java
--ResourceType.java
其中那些java文件只是用来加载resource文件的代码,我们主要是分析resource文件中的结构,不需要理解加载过程,而binout,common,excels文件夹分别是BinOutput与ExcelBinOutput文件夹的对应,common中大部分为角色怪物的数值管理,所以我们主要分析这三个文件夹即可。
在开始正文之前,我们需要了解ResourceType.java文件,而此文件代码如下所示
复制成功
java
@Retention(RetentionPolicy.RUNTIME)
public @interface ResourceType {
/** Names of the file that this Resource loads from */
String[] name();
// Load priority
//dictates which order to load this resource, with "highest" being loaded first
LoadPriority loadPriority() default LoadPriority.NORMAL;
public enum LoadPriority {
HIGHEST (4),
HIGH (3),
NORMAL (2),
LOW (1),
LOWEST (0);
private final int value;
LoadPriority(int value) {
this.value = value;
}
public int value() {
return value;
}
public static List<LoadPriority> getInOrder() {
return Stream.
of(LoadPriority.values())
.sorted((x, y) -> y.value() - x.value())
.toList();
}
}
}
可以知道这是一个注解并存在两个方法,name方法与loadPriority方法,前者返回所加载的resource文件的名字,后者返回这个文件的加载优先级,内部有一个枚举,定义了5个优先级并存储了一个int值,我们并不关心优先级的问题,所以可以暂时不用了解这些细节,只需要记得name方法作用即可,在之后更新文章可能会补上这些细节
正文
角色分析与修改
角色数值修改
想要分析数值我们就应该打开excels文件夹以及resource文件下的ExcelBinoutput文件夹,excels文件中可以看到以Avtar为前缀的文件,我们需要查看如下文件:
复制成功
none
--AvatarTalentData.java
--AvatarCostumeData.java
--AvatarCurveData.java
--AvatarData.java
--AvatarFetterLevelData.java
--AvatarFlycloakData.java
--AvatarLevelData.java
--AvatarPromoteData.java
--AvatarSkillData.java
--AvatarSkillDepotData.java
这些代码与如下ExcelBinOutput文件夹下的文件有如下对应关系和所管理的信息
none
--AvatarCodexExcelConfigData.json
--AvatarExtraPropExcelConfigData.json
--AvatarHeroEntityExcelConfigData.json
--AvatarRenameExcelConfigData.json
--AvatarReplaceCostumeExcelConfigData.json
--AvatarCostumeExcelConfigData.json ———— AvatarCostumeData.java //AvatarCostume角色装扮
--AvatarCurveExcelConfigData.json ———— AvatarCurveData.java //AvatarCurve角色成长曲线
--AvatarExcelConfigData.json ———— AvatarData.java //AvatarData角色信息
--AvatarFettersLevelExcelConfigData.json ———— AvatarFetterLevelData.java //Fetters角色好感度
--AvatarFlycloakExcelConfigData.json ———— AvatarFlycloakData.java //Flycloak风之翼
--AvatarLevelExcelConfigData.json ———— AvatarLevelData.java //AvatarLevel角色等级
--AvatarPromoteExcelConfigData.json ———— AvatarPromoteData.java //AvatarPromote角色突破加成信息
--AvatarSkillDepotExcelConfigData.json ———— AvatarSkillDepotData.java //AvatarSkillDepot角色技能id
--AvatarSkillExcelConfigData.json ———— AvatarSkillData.java //AvatarSkill角色技能数值
--AvatarTalentExcelConfigData.json ———— AvatarTalentData.java //AvatarTalent角色命之座
其中前五个分别是关于角色我只有第二个第三个不太清楚是什么,第一个关于角色卡池,第四个是给散兵重命名使用的,第五个国服和谐衣服的替换信息。
到现在为止我们已经清楚了文件的分布情况,如果对游戏制作有过了解,我们可以知道游戏中的角色所拥有的生命攻击力等一系列属性是通过基准值然后配合适的成长曲线来得到一个角色整体的数值,很明显,角色基准值存在于AvatarExcelConfigData.json中,打开这个文件,会有很多元素,我们选取一个做例子即可,如下为流浪者的例子:
json
{
"useType": "AVATAR_FORMAL",
"bodyType": "BODY_BOY",
"scriptDataPathHash": 7535910857308706620,
"iconName": "UI_AvatarIcon_Wanderer",
"sideIconName": "UI_AvatarIcon_Side_Wanderer",
"qualityType": "QUALITY_ORANGE",
"chargeEfficiency": 1.0,
"FBNHGKAFFPH": 13675355868156444375,
"initialWeapon": 14101,
"weaponType": "WEAPON_CATALYST",
"JMLNMPCLJPD": 9507362657214146851,
"imageName": "AvatarImage_Forward_Wanderer",
"gachaCardNameHash": 15207342994011728145,
"manekinPathHash": 10780170038532152145,
"coopPicNameHash": 1193927649272196557,
"cutsceneShow": "",
"skillDepotId": 7501,
"staminaRecoverSpeed": 25.0,
"candSkillDepotIds": [],
"manekinJsonConfigHash": 7616567263950851290,
"manekinMotionConfig": 103,
"descTextMapHash": 431267537,
"avatarIdentityType": "AVATAR_IDENTITY_NORMAL",
"avatarPromoteId": 75,
"avatarPromoteRewardLevelList": [
1,
3,
5
],
"avatarPromoteRewardIdList": [
900621,
900623,
900625
],
"featureTagGroupID": 10000075,
"infoDescTextMapHash": 431267537,
"hpBase": 791.255615234375,
"attackBase": 2005.5093994140625,
"defenseBase": 47.26570129394531,
"critical": 0.65000000074505806,
"criticalHurt": 2.5,
"propGrowCurves": [{
"type": "FIGHT_PROP_BASE_HP",
"growCurve": "GROW_CURVE_HP_S5"
},
{
"type": "FIGHT_PROP_BASE_ATTACK",
"growCurve": "GROW_CURVE_ATTACK_S5"
},
{
"type": "FIGHT_PROP_BASE_DEFENSE",
"growCurve": "GROW_CURVE_HP_S5"
}
],
"GJCPCNGOAGI": 3219451257085689470,
"prefabPathHash": 856195021060268183,
"id": 10000075,
"nameTextMapHash": 3230559562,
"DAHDIAPDAPB": 7282644589411446706,
"prefabPathRemoteHash": 6239069962102566643,
"controllerPathHash": 371987683098638875,
"controllerPathRemoteHash": 7218336410258283899,
"LODPatternName": ""
},
我们如何知道这是我们想修改的角色,看相关name或者id即可,比如iconName(图标名称)出现流浪者英文字眼,即正确,我们很容易找到hpBase(基础生命值),attackBase(基础攻击力),defenseBase(基础防御力),critical(暴击率),criticalHurt(暴击伤害),staminaRecoverSpeed(体力恢复速度),chargeEfficiency(充能效率)等键,直接修改这些基础值可以达到想要的结果,通过修改曲线参数或曲线公式只能修改生命值,攻击力,防御力这三个角色属性。
我们发现像元素伤害,精通,治疗等相关进阶信息不在这里,原因是所有角色的这些信息初始值均为0,而突破存在加成这些的并不适合使用成长曲线计算,而是直接给出一个固定值,也就是突变,所以这类数值并不能找到基准值,那我们如何修改这些突变值?
还记得AvatarPromote是角色关于突破的么,打开那个AvatarPromoteExcelConfigData.json文件,我们可以发现有如下的文件结构:
json
{
"avatarPromoteId": 2,
"promoteLevel": 1,
"promoteAudio": "",
"scoinCost": 20000,
"costItems": [
{
"id": 12,
"count": 12,
},
{},
{},
{}
],
"unlockMaxLevel": 20,
"addProps": [
{
"propType": "FIGHT_PROP_BASE_HP"
},
{
"propType": "FIGHT_PROP_BASE_DEFENSE"
},
{
"propType": "FIGHT_PROP_BASE_ATTACK"
},
{
"propType": "FIGHT_PROP_CRITICAL_HURT"
}
],
"requiredPlayerLevel": 15,
},
可以看到四个键,分别为avatarPromoteId(角色突破id),promoteAudio(突破音效),promoteLevel(突破等级(从0到6)),costItems(花费物品),unlockMaxLevel(解锁的最大等级),addProps(哪些属性被增加)。再看AvatarExcelConfigData.json示例的avatarPromoteId键,可以得知,通过修改AvatarExcelConfigData.json中想修改的角色的avatarPromoteId可以更改角色突破所突变值(角色面板所存在的属性)。修改unlockMaxLevel可以更改角色突破后能升级到最大的等级。同样的你可以修改addProps数组中的每个propType键值可以更改角色的突破属性。而propType相关东西你可以查看代码或者通过翻译得到对应翻译,下面是所有属性类型对应翻译以及其属于的数值类型(按照是否可以曲线计算分类分为基础类型和突变数值):
propType | 中文 | 数值类型 | 面板是否可见 | propType | 中文 | 数值类型 | 面板是否可见 |
---|---|---|---|---|---|---|---|
FIGHT_PROP_BASE_HP | 基础血量生命值 | 基础类型 | 可见 | FIGHT_PROP_WIND_ADD_HURT | 风元素伤害加成 | 突变数值 | 可见 |
FIGHT_PROP_BASE_DEFENSE | 基础防御力 | 基础类型 | 可见 | FIGHT_PROP_ROCK_ADD_HURT | 岩元素伤害加成 | 突变数值 | 可见 |
FIGHT_PROP_BASE_ATTACK | 基础攻击力 | 基础类型 | 可见 | FIGHT_PROP_ELEC_ADD_HURT | 雷元素伤害加成 | 突变数值 | 可见 |
FIGHT_PROP_CRITICAL | 暴击率 | 突变数值 | 可见 | FIGHT_PROP_GRASS_ADD_HURT | 草元素伤害加成 | 突变数值 | 可见 |
FIGHT_PROP_CRITICAL_HURT | 暴击伤害 | 突变数值 | 可见 | FIGHT_PROP_WATER_ADD_HURT | 水元素伤害加成 | 突变数值 | 可见 |
FIGHT_PROP_HP_PERCENT | 百分比生命值 | 突变数值 | 可见 | FIGHT_PROP_FIRE_ADD_HURT | 火元素伤害加成 | 突变数值 | 可见 |
FIGHT_PROP_ATTACK_PERCENT | 百分比攻击力 | 突变数值 | 可见 | FIGHT_PROP_ICE_ADD_HURT | 冰元素伤害加成 | 突变数值 | 可见 |
FIGHT_PROP_DEFENSE_PERCENT | 百分比防御力 | 突变数值 | 可见 | FIGHT_PROP_PHYSICAL_ADD_HURT | 物理伤害加成 | 突变数值 | 可见 |
FIGHT_PROP_ELEMENT_MASTERY | 元素精通 | 突变数值 | 可见 | ||||
FIGHT_PROP_CHARGE_EFFICIENCY | 充能效率 | 突变数值 | 可见 | ||||
FIGHT_PROP_HEAL_ADD | 治疗加成 | 突变数值 | 可见 | ||||
FIGHT_PROP_HEALED_ADD | 受治疗加成 | 突变数值 | 可见 | ||||
FIGHT_PROP_WIND_SUB_HURT | 风元素减伤加成 | 突变数值 | 可见 | ||||
FIGHT_PROP_ROCK_SUB_HURT | 岩元素减伤加成 | 突变数值 | 可见 | ||||
FIGHT_PROP_ELEC_SUB_HURT | 雷元素减伤加成 | 突变数值 | 可见 | ||||
FIGHT_PROP_GRASS_SUB_HURT | 草元素减伤加成 | 突变数值 | 可见 | ||||
FIGHT_PROP_WATER_SUB_HURT | 水元素减伤加成 | 突变数值 | 可见 | ||||
FIGHT_PROP_FIRE_SUB_HURT | 火元素减伤加成 | 突变数值 | 可见 | ||||
FIGHT_PROP_ICE_SUB_HURT | 冰元素减伤加成 | 突变数值 | 可见 | ||||
FIGHT_PROP_PHYSICAL_SUB_HURT | 物理减伤加成 | 突变数值 | 可见 | ||||
SKILL_CD_MINUS_RATIO | 冷却缩减 | 突变数值 | 可见 | ||||
SHIELD_COST_MINUS_RATIO | 护盾强效 | 突变数值 | 可见 |
获取到这些propType对应值后,我们很容易修改出我们想要的突破属性,如下,我将流浪者的80-90级突破属性修改为,增加暴击率40%,增加暴击伤害100%
json
{
"avatarPromoteId": 75,
"promoteLevel": 6,
"promoteAudio": "",
"scoinCost": 120000,
"costItems": [
{
"id": 104154,
"count": 6
},
{
"id": 113038,
"count": 20
},
{
"id": 101213,
"count": 60
},
{
"id": 112046,
"count": 24
}
],
"unlockMaxLevel": 90,
"addProps": [
{
"propType": "FIGHT_PROP_BASE_HP",
"value": 3249.3232421875
},
{
"propType": "FIGHT_PROP_BASE_DEFENSE",
"value": 194.10299682617188
},
{
"propType": "FIGHT_PROP_BASE_ATTACK",
"value": 104.74773406982422
},
{
"propType": "FIGHT_PROP_CRITICAL",
"value": 0.49200000166893005
}
],
"requiredPlayerLevel": 50
},//原版
{
"avatarPromoteId": 75,
"promoteLevel": 6,
"promoteAudio": "",
"scoinCost": 120000,
"costItems": [
{
"id": 104154,
"count": 6
},
{
"id": 113038,
"count": 20
},
{
"id": 101213,
"count": 60
},
{
"id": 112046,
"count": 24
}
],
"unlockMaxLevel": 90,
"addProps": [
{
"propType": "FIGHT_PROP_BASE_HP",
"value": 3249.3232421875
},
{
"propType": "FIGHT_PROP_CRITICAL_HURT",
"value": 1
},
{
"propType": "FIGHT_PROP_BASE_ATTACK",
"value": 104.74773406982422
},
{
"propType": "FIGHT_PROP_CRITICAL",
"value": 0.40
}
],
"requiredPlayerLevel": 50
},//修改后
角色数值修改进阶
我们并不满足只修改基础面板,通过上面基础修改,我们只是掌握了基础值,突破属性修改,如果你仔细阅读过代码与AvatarExcelConfigData.json文件,会发现每个角色对象中存在一个propGrowCurves数组,这个数组中每个对象存在两个键分别是type与growCurve,这个数组决定了每个角色升级所使用的基础数值升级曲线,growCurve决定角色升级曲线时是使用5星角色还是4星角色,growCurve有如下类型:
growCurve | 中文名 |
---|---|
GROW_CURVE_HP_S5 | 五星血量升级曲线 |
GROW_CURVE_ATTACK_S5 | 五星攻击升级曲线 |
GROW_CURVE_HP_S4 | 四星血量升级曲线 |
GROW_CURVE_ATTACK_S4 | 四星攻击升级曲线 |
有趣的是,防御的升级曲线在这个res中与血量升级曲线共用,非常偷懒。不过也简化了数值修改。
我们还可以修改一些虽然角色属性可见,但不能突破所获取的,比如冷却缩减,护盾强效,与之前相同,只需修改AvatarPromoteExcelConfigData文件中你想修改的突破属性即可,
而修改曲线公式,需要你修改AvtarData.java文件中代码,代码所在位置为如下函数:
java
public float getBaseHp(int level){
....
}
public float getBaseAttack(int level){
....
}
public float getBaseDefense(int level){
....
}
public float getGrowthCurveById(int level, FightProperty prop){
....
}
其中返回基础属性的函数通过基准值与对应曲线相乘得到结果返回,而曲线通过getGrowthCurveById函数进行计算,我们重点要改getGrowthCurveById函数计算方式,当然一种粗暴的方法就是直接修改getBase*函数计算过程,至于公式你可以自己定义,此处不再多说。
角色突破与升级物品修改
修改AvatarPromoteExcelConfigData.json中对应id的costItems可以更改角色突破需要的物品,修改scoinCost键可以改变每次突破所用的金币,比如全设置为如下所示,就相当于不需要物品,就能突破。
json
"costItems": [
{
"id": 104151,
"count": 1
},
{},
{
"id": 101220,
"count": 3
},
{
"id": 112065,
"count": 3
}
],//修改前
"costItems": [
{
},
{},
{
},
{
}
],//修改后
修改AvatarExcelConfigData.json中你想修改的角色的avatarPromoteRewardLevelList与avatarPromoteRewardIdList中值可以分别修改角色在哪个突破等级给奖励以及奖励的物品分别是什么,这个你可以对照物品id表进行修改,需要注意的是,每个突破奖励所给的东西只能是一个,而不能给多个,当然如果有错请反馈给我,我会改正。
角色技能命座讲解
在讲解角色技能命座前,我们有必要了解一下整个游戏运行时是如何让实体与大世界地图中的物品产生行为与交互。
在游戏中,无论是角色的技能与命座,还是怪物的技能,亦或者是大世界可交互点(最重要的是解密机关)都统一由一堆有ConfigAbility的文件进行管理,这些文件被存放在BinOutput/Ability/Temp文件夹中,而这个文件夹的结构为:
none
--BinOutput/Ability/Temp
--ActivityAbilities -- more files
--AnimalAbilities -- more files
--AvatarAbilities -- more files
--ChallengeAbilities -- more files
--EquipAbilities -- more files
--GadgetAbilities -- more files
--LevelAbilities -- more files
--MonsterAbilities -- more files
--MonsterAffixAbilities -- more files
--QATestAbilities -- more files
--QuestAbilities -- more files
--TeamAbilities -- more files
--ConfigAbility_Activity.json
--ConfigAbility_Activity_ArenaChallenge2.json
--ConfigAbility_Activity_Blocking.json
--ConfigAbility_Activity_BuoyantCombat.json
--ConfigAbility_Activity_CatchAnimal.json
--ConfigAbility_Activity_Challenge.json
--ConfigAbility_Activity_DragonSpine.json
--ConfigAbility_Activity_EffigyChallenge2.json
--ConfigAbility_Activity_Endora.json
--ConfigAbility_Activity_FleurFair.json
--ConfigAbility_Activity_Lannaluo.json
--ConfigAbility_Activity_LudiHarpastum.json
--ConfigAbility_Activity_MistTrial.json
--ConfigAbility_Activity_ToMoon.json
--ConfigAbility_Amber.json
--ConfigAbility_Challenge_DragonSpine.json
--ConfigAbility_DebugTest.json
--ConfigAbility_Element.json
--ConfigAbility_EnergyDisk_Buff.json
--ConfigAbility_FireGadget.json
--ConfigAbility_Fishing.json
--ConfigAbility_FlyItem.json
--ConfigAbility_Gear.json
--ConfigAbility_GrassGadget.json
--ConfigAbility_HideSeek.json
--ConfigAbility_InteractGadget.json
--ConfigAbility_Level.json
--ConfigAbility_LevelBuff.json
--ConfigAbility_LevelBuff_EnergyDisk.json
--ConfigAbility_LevelBuff_V2.json
--ConfigAbility_MichiaeMatsuri.json
--ConfigAbility_Paimon.json
--ConfigAbility_Reputation.json
--ConfigAbility_RogueDungeon.json
--ConfigAbility_Scene_Weather.json
--ConfigAbility_TD_Test.json
--ConfigAbility_Team.json
--ConfigAbility_TowerDefence_V3.json
--ConfigAbility_Watcher.json
--ConfigAbility_WaterGadget.json
--ItemAbilities.json
--TempAbilities.json
--TempAbilities2.json
--TempGearGadgetAbilities.json
--TempInteractiveGadgetAbilities.json
很容易的发现每个文件夹的前缀单词代表着存储的Ability所管理的东西。不在文件夹中的一般是杂项,不需要专门分类
而这些Ability产生的实体对象,效果被Gadget包装并调用,所有的ConfigGadget文件被放在Gadget文件夹中,并没有进行分类(Gadget--more files
),Ability不光被Gadget包装,还被Talent包装,Talent文件夹下存在四个文件夹:AvatarTalents(角色),EquipTalents(装备),RelicTalents(圣遗物),TeamTalents(队伍),而所有的Avtar(角色),Monster(怪物)中包含Ability与Model,combat,角色(怪物)行为,所以,Ability,Gadget,Talent,Avtar,AvtarData,AvtarSkillData,AvtarSkillDepotData,TalentSkillData关系如下:
none
符号含义:
-> :右边包装左边
- :派生
—— :右边包含左边
Ability->Talent
Ability->Gadget
Talent-AvtarTalents
Talent-EquipTalents
Talent-RelicTalents
Talent-TeamTalents
Ability——Avtar
AvtarData——Avtar
AvtarSkillData——Avtar
AvtarSkillDepotData——Avtar
TalentSkillData——Avtar
这些是一些粗糙的原理,通过看代码或者看res可以稍微猜出原理。
现在我们终于可以进行技能命座的讲解了,现在我们还是以流浪者为例子讲解技能命座,
打开AvatarAbilities文件夹下关于流浪者的配置文件:
json
//文件名:ConfigAbility_Avatar_Wanderer.json
[
{},
{},
{},
//....
//一共37个数组元素
]
整个文件呈如上结构,大部分角色的Ability有重击(弓箭角色为R键攻击),普通攻击,普通攻击子弹(长柄角色重击与远程攻击角色),e技能,q技能,镜头控制,下落攻击组成,还有一些角色命座出现的新效果也会在这里存放,当然有些角色比较复杂(修改角色普工形态的尤其复杂),我们之后分类讨论再说。
我们以现在这个角色的一段普通攻击做例子:
json
//文件名:ConfigAbility_Avatar_Wanderer.json
[
{
"Default": {
"$type": "ConfigAbility",
"abilityName": "Avatar_Wanderer_Attack01",
//"isDynamicAbility": true&false
"onAbilityStart":[
{
"$type": "TriggerBullet",
"bulletID": 41075101,
"born":{
"$type": "ConfigBornBySelf",
"offset":{
"x": 0.4,
"y": 1.2,
"z": 0.2
},
"direction":{
"$type": "ConfigDirectionByAttackTarget"
}
}
},
{
"$type": "FireEffect",
"effectPattern": "Eff_Avatar_Boy_Catalyst_Wanderer_NormalAttack_01_Cast",
"born": {
"$type": "ConfigBornBySelf",
"offset": {
"x": 0.0,
"y": 0.0,
"z": 0.0
}
}
}
]
}
}//普工第一击
]
json
{
"Default": {
"$type": "ConfigAbility",
"abilityName": "Avatar_Wanderer_NormalAttack_Bullet_1",
"onAdded": [
{
"$type": "AttachEffect",
"effectPattern": "Eff_Avatar_Boy_Catalyst_Wanderer_NormalAttack_01_Bullet"
},
{
"$type": "ApplyModifier",
"modifierName": "Avatar_Wanderer_HoverAttack_01_Bullet_AngularVelocity_Timer"
}
],
"onAbilityStart": [
{
"$type": "TriggerAttackEvent",
"targetType": "Enemy",
"attackEvent": {
"attackPattern": {
"$type": "ConfigAttackSphere",
"triggerType": "TriggerNoRepeat",
"radius": 1.0,
"born": {
"$type": "ConfigBornByCollisionPoint"
}
},
"attackInfo": {
"canBeModifiedBy": "OriginOwner",
"attackTag": "NormalAttack_01",
"attenuationTag": "NormalAttack",
"attackProperty": {
"damagePercentage": "%NormalAttack_01_Damage",
"elementType": "Wind",
"elementDurability": 25,
"strikeType": "Default",
"enBreak": 12.8205
},
"hitPattern": {
"onHitEffectName": "Default",
"hitImpulseType": "LV2",
"reboundRatio": 0,
"hitHaltTime": 0.0,
"hitHaltTimeScale": 0.05,
"muteHitText": false
}
}
}
},
{
"$type": "KillSelf"
}
],
"modifiers": {
"Avatar_Wanderer_HoverAttack_01_Bullet_AngularVelocity_Timer": {
"duration": 0.2,
"onRemoved": [
{
"$type": "ApplyModifier",
"modifierName": "Avatar__Wanderer_HoverAttack_01_Bullet_AngularVelocity"
}
]
},
"Avatar__Wanderer_HoverAttack_01_Bullet_AngularVelocity": {
"properties": {
"Actor_BulletMoveAngularVelocityRatio": 10
}
}
},
"onKill": [
{
"$type": "FireEffect",
"effectPattern": "Eff_Avatar_Boy_Catalyst_Wanderer_NormalAttack_Bullet_1_Hit"
}
],
"abilitySpecials": {
"NormalAttack_01_Damage": 0.0
}
}
},//普工第一击子弹
查看文件可以知道,文件中每个数组元素中都嵌套一个名为default
的对象,default
中存在两个键和多个其他的键与数组,"$type"
键决定这个属于那种配置,这里应该是ConfigAbility,abilityName
决定这个Ability的名字,而之后就是多个数组,数组个数取决于这个Ability属于哪种类型,所有Ability至少存在一个数组,下面是所有可能的数组与对象:
json
"onAdded": [] //添加
"onAbilityStart": [] //能力初始化
"abilityMixins": [] //Ability状态
"modifiers": {} //修饰
"abilitySpecials": {} //传入参数
"onRemoved": [] //移除
"onKill": [] //销毁
//一些特殊的
"onAvatarOut": [] //
"onAbilityStart": [] //
"onFieldEnter": [] //
"onFieldExit": [] //
这些数组在不同武器类型的,不同Ability中所存在的数组各不相同,我们将列出如下表格来给出这些Ability
可能存在的数组(需要注意的是,这些只是我所见到的,如果存在错误,请联系我):
武器类型 | Abilities 所代表的角色行为 | 该Abilities 可能存在的数组与对象 |
---|---|---|
单手剑 | 普攻与重击 | abilityMixins onAdded modifiers abilitySpecials onAbilityStart |
单手剑 | 下落攻击(不可能有其他的) | abilityMixins onAdded modifiers abilitySpecials onAbilityStart |
单手剑 | 元素战技 | abilityMixins onAbilityStart modifiers onAdded abilitySpecials |
单手剑 | 元素爆发 | abilityMixins onAbilityStart modifiers abilitySpecials onAdded onKill |
大剑 | 普攻与重击 | abilityMixins modifiers abilitySpecials onAdded |
大剑 | 下落攻击(不可能有其他的) | abilityMixins onAdded modifiers abilitySpecials onAbilityStart |
大剑 | 元素战技 | onAdded onRemoved abilityMixins modifiers abilitySpecials onAbilityStart |
大剑 | 元素爆发 | abilityMixins onAdded onKill onAbilityStart modifiers abilitySpecials |
长柄武器 | 普攻与重击 | abilityMixins modifiers abilitySpecials onAdded |
长柄武器 | 重击子弹(突刺与转圈) | … |
长柄武器 | 下落攻击(不可能有其他的) | abilityMixins onAdded modifiers abilitySpecials onAbilityStart |
长柄武器 | 元素战技 | onAdded abilityMixins modifiers abilitySpecials onAbilityStart onKill |
长柄武器 | 元素爆发 | onAbilityStart modifiers abilityMixins abilitySpecials onAdded onKill |
弓箭 | 普攻 | modifiers abilityMixins onAbilityStart |
弓箭 | 重击 | onAdded abilityMixins onAbilityStart abilitySpecials modifiers |
弓箭 | 下落攻击(不可能有其他的) | abilityMixins onAdded modifiers abilitySpecials onAbilityStart |
弓箭 | 子弹 | abilityMixins onAbilityStart abilitySpecials onAdded modifiers |
弓箭 | 元素战技 | onKill onAdded abilityMixins modifiers abilitySpecials |
弓箭 | 元素爆发 | onAdded abilityMixins onAbilityStart modifiers onKill abilitySpecials |
法器 | 普攻 | abilityMixins modifiers abilitySpecials onAbilityStart |
法器 | 重击 | abilityMixins modifiers abilitySpecials onAdded onAbilityStart |
法器 | 下落攻击(不可能有其他的) | abilityMixins onAdded modifiers abilitySpecials onAbilityStart |
法器 | 子弹 | onAdded onAbilityStart modifiers onKill abilitySpecials |
法器 | 元素战技 | abilityMixins onAbilityStart modifiers abilitySpecials onAdded onKill |
法器 | 元素爆发 | onAbilityStart onAdded abilityMixins modifiers abilitySpecials onKill |
注:
- 近战角色中只有长柄武器存在子弹Ability,而其他类型的近战角色不存在子弹效果,且普攻与重击去除特殊效果外,只用一个Ability即可完成,
- 远程角色由于每次攻击有子弹生成,所以会存在三部分Ability(重击,普攻Normal Attack,攻击控制(与重击嵌合在一起))
这些就是常见的情况,当然有些可能存在特殊的技能,我们不在这里做讨论。
然而只是了解可能存在的对象我们并不能获取更多的信息,我们必须知道这些常见数组与对象中一些常见的东西才可以,在这里,我们会介绍onAdded []
,onAbilityStart []
,abilityMixins []
,modifiers {}
,abilitySpecials
,onKill
等参数。
下面是角色普攻重击中存在的键(默认以流浪者为例,如果以其他角色为例会专门说明):
json
//流浪者普攻重击Extract Attack
//AbilityName:Avatar_Wanderer_ExtraAttack
//abilityMixins
"abilityMixins":
[
{
"$type": "ButtonHoldChargeMixin", //对象类型,这里为输入hold(键盘,手柄,触摸屏等)
"skillID": 10751, //技能ID,这里指代这个按键按住后触发哪个技能
"chargeTime": 0.15, //蓄力时间
"secondChargeTime": 0.1, //二次蓄力时间
"OnBeginUncharged": //未输入开始
[
{
"$type": "SetAnimatorTrigger",//设置动画触发器
"triggerID": "DoSkill",//触发器类型,这里是角色要做技能会触发
"predicates"://表达式
[
{
"$type" : "ByAnimatorInt",
"value" : 0,
"parameter" : "ComboCount",//连击数,记录角色该进行哪段普攻了
"logic" : "Equal",
}
]
},
{
"$type": "SetAnimatorInt",
"intID": "SkillID",//参数id,这里这个值代表对SkillID(10751)中存储的技能进行修改
"value": 99,//值
"predicates"://表达式
[
{
"$type" : "ByAnimatorInt",
"value" : 0,
"parameter" : "ComboCount",//连击数,记录角色该播放哪段动画
"logic" : "Equal",
}
]
}
// {
// "$type": "SetAnimatorBool", //设置动画bool值
// "boolID": "IsCharging", //对哪个值进行修改,这里决定角色是否进行蓄力
// "value": false,
// },
],
"OnReleaseUncharged": //未输入结束
[
{
"$type":"SetAnimatorTrigger",
"triggerID": "DoSkill"
},
{
"$type": "SetAnimatorInt",
"intID": "SkillID",
"value": 1
}
],
"OnBeginCharged": //开始输入
[
{
"$type": "SetAnimatorTrigger",
"triggerID": "DoSkill"
},
{
"$type": "SetAnimatorInt",
"intID": "SkillID",
"value": 6
},
// {
// "$type": "SetAnimatorBool",
// "boolID": "IsCharging",
// "value": true,
// },
],
"OnReleaseCharged": //输入结束
[
// {
// "$type": "SetAnimatorBool",
// "boolID": "IsCharging",
// "value": false,
// },
{
"$type": "SetAnimatorTrigger",
"triggerID": "DoSkill"
},
{
"$type": "SetAnimatorInt",
"intID": "SkillID",
"value": 1
}
],
"OnBeginSecondCharged": //第二次输入
[
{
"$type": "SetAnimatorTrigger",
"triggerID": "DoSkill"
},
{
"$type":"Predicated",
"target":"Self",
"targetPredicates":
[
{
"$type": "ByLocalAvatarStamina",
"stamina": "%ExtraAttack_Catalyst_Stamina_Cost",
"logic": "GreaterOrEqual"
}
],
"successActions":
[
{
"$type": "SetAnimatorInt",
"intID": "SkillID",
"value": 6
}
],
"failActions":
[
{
"$type": "SetAnimatorInt",
"intID": "SkillID",
"value": 1
}
]
},
{
"$type": "SetAnimatorBool",
"boolID": "IsCharging",
"value": false
}
],
"chargeStateIDs": //状态ID,这里指代角色一次普通攻击周期下所有的攻击状态
[
"Attack01", //第一段攻击
"Attack02", //第二段攻击
"Attack03", //第三段攻击
"ExtraAttack_BS", //重击前摇
"ExtraAttack_Charge", //重击蓄力
"ExtraAttack", //重击
"ExtraAttack_AS" //重击后摇
]
},
{
"$type": "AttachToStateIDMixin", //这个参数是指对某个StateIDs附加一些参数
"stateIDs": ["ExtraAttack_Charge"],//修改或附加参数的stateIDs,这里对普攻进行修改
"modifierName": "ExtraAttack_StaminaCost" //要修改stateIDs中哪个参数
}
]
//modifiers
"modifiers":
{
"ExtraAttack_StaminaCost": //"modifierName": "ExtraAttack_StaminaCost"
{
"onAdded": //添加参数
[
{
"$type" : "AvatarSkillStart",
"skillID" : 10003,
"costStaminaRatio":"%ExtraAttack_Catalyst_Stamina_Cost" //消耗体力值
}
]
}
}
//abilitySpecials
"abilitySpecials"
{
"ExtraAttack_Catalyst_Stamina_Cost": 0 //这里赋值给的是修正值,不是在基准值上给,
}
//流浪者重击蓄力ExtraAttack_Charge
//AbilityName:Avatar_Wanderer_ExtraAttack_Charge
//abilityMixins
"abilityMixins":
[]
//onAbilityStart
"onAbilityStart":
[
{
"$type" : "Predicated",
"target" : "Self",
"targetPredicates" ://目标表达式
[
{
"$type":"ByHasAttackTarget"
}
],
"successActions"://表达式为真
[
{
"$type": "ApplyModifier",
"modifierName":"Avatar_Wanderer_ExtraAttack_Charge_HasTarget"
},
],
"failActions"://表达式为假
[
{
"$type": "ApplyModifier",
"modifierName":"Avatar_Wanderer_ExtraAttack_Charge_NoTarget"
}
]
}
]
//modifiers
"modifiers":
{
"Avatar_Wanderer_ExtraAttack_Charge_HasTarget":
{
"duration":0.5,
"onAdded":
[
{
"$type": "SetGlobalPos",//设置位置
"target": "SelfAttackTarget",//目标
"key": "_ABILITY_Wanderer_ExtraAttack_Pos",
"born":
{
"$type": "ConfigBornByAttachPoint",
"attachPointName": "Fx_ChestNode",
"attachPointTargetType": "Target",
"direction":
{
"$type": "ConfigDirectionByEntity"
// "randomAngleHor": 360,
},
"setTarget": false
}
},
{
"$type": "FireEffect",
"effectPattern": "Eff_Avatar_Boy_Catalyst_Wanderer_ExtraAttack_Alert",
"born":
{
"$type": "ConfigBornByGlobalValue",
"positionKey": "_ABILITY_Wanderer_ExtraAttack_Pos"
// "onGround": true,
}
}
]
},
"Avatar_Wanderer_ExtraAttack_Charge_NoTarget":
{
"duration":0.5,
"onAdded":
[
{
"$type": "SetGlobalPos",
"key": "_ABILITY_Wanderer_ExtraAttack_Pos",
"born":
{
"$type": "ConfigBornBySelf",
"offset":
{
"x": 0.0,
"y": 1.0,
"z": 5.0
}
}
},
{
"$type":"FireEffect",
"effectPattern":"Eff_Avatar_Boy_Catalyst_Wanderer_ExtraAttack_Alert",
"born":
{
"$type": "ConfigBornByGlobalValue",
"positionKey":"_ABILITY_Wanderer_ExtraAttack_Pos"
// "onGround": true,
}
}
]
}
}
//流浪者普攻Normal Attack
//AbilityName: Avatar_Wanderer_Attack0X X取决于角色有几段普通攻击
//onAbilityStart
"onAbilityStart":
[
{
"$type": "TriggerBullet", //角色进行攻击后产生子弹
"bulletID": 41075101, //子弹ID
"born": //生成信息
{
"$type": "ConfigBornBySelf", //生成类型,自身生成一般这里是
"offset": //生成时偏移位置
{
"x": 0.4,
"y": 1.2,
"z": 0.2
},
"direction": //生成的子弹指向数据
{
"$type": "ConfigDirectionByAttackTarget"
}
}
},
{
"$type":"FireEffect", //角色普攻时的图形特效
"effectPattern":"Eff_Avatar_Boy_Catalyst_Wanderer_NormalAttack_01_Cast", //使用的图形特效名字
"born":
{
"$type": "ConfigBornBySelf",
"offset":
{
"x": 0.0,
"y": 0.0,
"z": 0.0
}
}
}
]
//AbilityName:Avatar_Wanderer_NormalAttack_Bullet_X X取决于哪段普攻,此处为第一段普攻的子弹
//onAdded
"onAdded":
[
{
"$type": "AttachEffect", //附加图形特效
"effectPattern": "Eff_Avatar_Boy_Catalyst_Wanderer_NormalAttack_01_Bullet" //附加或修改的图形特效名字
},
{
"$type":"ApplyModifier", //应用修改
"modifierName":"Avatar_Wanderer_HoverAttack_01_Bullet_AngularVelocity_Timer"
}
]
//onAbilityStart
"onAbilityStart":
[
{
"$type": "TriggerAttackEvent", //触发攻击事件
"targetType": "Enemy", //攻击目标
"attackEvent": //攻击事件
{
"attackPattern": //攻击图形特效
{
"$type": "ConfigAttackSphere", //特效类型
"triggerType": "TriggerNoRepeat", //触发类型
"radius": 1.0, //特效半径
"born":
{
"$type": "ConfigBornByCollisionPoint" //在哪里触发图形特效,这里是指与碰撞体接触触发
}
},
"attackInfo": //攻击信息
{
"canBeModifiedBy": "OriginOwner", //可以被谁修改
"attackTag":"NormalAttack_01", //攻击标签,是指哪段普攻触发的攻击
"attenuationTag": "NormalAttack", //符合哪种衰减
"attackProperty": //攻击属性
{
"damagePercentage": "%NormalAttack_01_Damage", //百分比攻击值
"elementType": "Wind", //元素附着
"elementDurability": 25, //元素衰减
"strikeType": "Default", //削韧类型
"enBreak": 12.8205 //抗打断
},
"hitPattern": //击中图形特效
{
"onHitEffectName": "Default",
"hitImpulseType": "LV2",
"reboundRatio" : 0,
"hitHaltTime" : 0.0,
"hitHaltTimeScale" : 0.05,
"muteHitText" : false
}
}
}
},
{
"$type": "KillSelf" //子弹销毁
}
],
//modifiers
"modifiers"
{
"Avatar_Wanderer_HoverAttack_01_Bullet_AngularVelocity_Timer"://{"$type":"ApplyModifier", "modifierName":"Avatar_Wanderer_HoverAttack_01_Bullet_AngularVelocity_Timer"}
{
"duration":0.2, //经过多少秒后产生修改
"onRemoved": //执行的修改
[
{
"$type":"ApplyModifier",
"modifierName":"Avatar__Wanderer_HoverAttack_01_Bullet_AngularVelocity"
}
]
},
"Avatar__Wanderer_HoverAttack_01_Bullet_AngularVelocity": //普攻子弹的角速度
{
"properties":
{
"Actor_BulletMoveAngularVelocityRatio":10 //加速度大小比例
}
}
},
//onKill
"onKill":
[
{
"$type": "FireEffect",
"effectPattern": "Eff_Avatar_Boy_Catalyst_Wanderer_NormalAttack_Bullet_1_Hit"
}
],
//abilitySpecials
"abilitySpecials":
{
"NormalAttack_01_Damage": 0.0 //普攻伤害修正值
}
如上所示名为Avatar_Wanderer_ExtraAttack(流浪者)的Ability除去基本信息有abilityMixins []
,modifiers {}
,abilitySpecials {}
等额外信息,abilityMixins
数组中至少存在两个对象,一个管理角色在按下普攻键进行普攻时进行的动作与普攻序列,另一个对象对普攻或重击进行修改或附加东西,而附加或修改的东西会在modifiers {}
中实现,abilitySpecials {}
中的每个键一般赋值给modifiers {}
中每个对象的中要修改的键。当然abilitySpecials {}
不光修改modifiers {}
中的值,还会修改onAbilityStart []
,abilityMixins []
,modifiers {}
中某些对象中的键值,或者更准确的说,键后对应的值如果带百分号且后面跟的与modifiers {}
中某个个键相同,则代表修改了对应项。
而另外一个名为Avatar_Wanderer_ExtraAttack_Charge的Ability管理角色蓄力(也就是跟重击相关),需要注意的是,所有法器角色都具有这种类似的重击蓄力的Ability
而在角色进行普攻时,又会根据是否为远程角色分成有普攻子弹或无普攻子弹生成的类别,前面表格下面备注已经说了这个情况,我们需要知道的是,法器与弓箭角色在进行普攻或重击时,会有普攻或重击的子弹生成,法器角色每段普工或重击都有对应的子弹Ability,而弓箭角色普攻子弹除去一些特殊的普攻表现(如夜阑的最后一段普攻)基本共用一个Ability,远程角色普攻时会触发对应普攻动作然后触发对应子弹生成(在对应普攻的onAbilityStart []
中有一个类型为TriggerBullet
的对象用于触发),然后普攻重击对应的子弹的Ability的onAbilityStart []
数组下存储至少两个对象,第一个对象是子弹挂载的攻击信息,类型为TriggerAttackEvent
,第二个对象是子弹销毁,两个结构如下:
json
{
"$type":,
"targetType":,
"attackEvent":
{
"attackPattern":{},
"attackInfo":{}
}
}
{
"$type": "KillSelf"
//在其他某些角色可能使用另外一种销毁方式,另外一种销毁方式与此方式大致相同,多了几个键
}
attackEvent
下的attackPattern
与attackInfo
有如下结构:
json
"attackEvent":
{
"attackPattern":
{
"$type":,
"triggerType":,
"radius":,
"born":
{
"$type": "ConfigBornByCollisionPoint",
//"offset"可能存在,内部三个键,分别为x,y,z
}
},
"attackInfo":
{
"canBeModifiedBy":,
"attackTag":,
"attenuationTag":,
"attenuationGroup":,
"attackProperty":
{
"damagePercentage":,
"strikeType":,
"elementDurability":,
"overrideByWeapon":,
"attackType":,
"enBreak":,
},
"hitPattern":
{
"onHitEffectName":,
"hitImpulseType":,
"reboundRatio":,
"canBeDefenceHalt":,
"hitHaltTime":,
"hitHaltTimeScale":,
"muteHitText":
},
"forceCameraShake": false,
"cameraShake":
{
"shakeType":,
"shakeRange":,
"shakeTime":,
"shakeDistance":,
//"shakeDir":与born结构类似
}
}
}
在近战角色下,并没有子弹一说,所以普攻相关信息会放在Ability Name为ExtractAttack之下,同时这个Ability同时管理游戏输入,而伤害管理会放在另外一个名为NormalAttack_DamageHandler的Ability中,这两个一般为如下结构:
json
//莱伊拉普攻重击ExtraAttack
//AbilityName:Avatar_Layla_ExtraAttack
//abilityMixins
"abilityMixins":
[
{
"$type": "ButtonHoldChargeMixin",
"skillID": 10741,
"chargeTime": 0.12,
"secondChargeTime": 0.2,
"OnBeginUncharged":[],
"OnReleaseUncharged":[],
"OnBeginCharged":[],
"OnReleaseCharged":[],
"OnBeginSecondCharged":[],
"OnReleaseSecondCharged":[],
"chargeStateIDs":[
"Attack01",
"Attack02",
"Attack03",
"Run"
]
},
{
"$type": "AttachToStateIDMixin",
"stateIDs": [
"ExtraAttack"
],
"modifierName": "ExtraAttack_StaminaCost"
}
],
//modifiers
"modifiers":
{
"ExtraAttack_StaminaCost":{
"onAdded":[
{
"$type": "AvatarSkillStart",
"skillID": 10001,
"costStaminaRatio": "%ExtraAttack_Sword_Stamina_Cost"
}
]
}
},
//abilitySpecials
"abilitySpecials":
{
"ExtraAttack_Sword_Stamina_Cost": 0,
"Flexible_Stamina":-2,
}
//莱伊拉普攻伤害管理NormalAttack_DamageHandler
//AbilityName:Avatar_Layla_NormalAttack_DamageHandler
//abilityMixins
"abilityMixins":
[
{
"$type": "ModifyDamageMixin", //修改伤害
"animEventNames": [
"ATK01"
],//动画事件名
"damagePercentage": "%Attack_01"
},
{
//...
},
{
//...
},
{
//...
},
{
"$type": "ModifyDamageMixin",
"animEventNames": [
"ExtraAttack_2"
],
"damagePercentage":"%ExtraAttack2"
}
],
"abilitySpecials":
{
"Attack_01": 0,
"Attack_02": 0,
"Attack_03": 0,
"ExtraAttack1": 0,
"ExtraAttack2": 0
}
可以发现近战角色重击Ability基本与法器角色一样,而伤害管理统一在后缀为DamageHandler的Ability中,与法器角色每个子弹存在一个TriggerAttackEvent
对象不同,由于近战角色没有子弹生成,所以伤害管理不需要这种方法,反而是在abilityMixins []
写下"$type": "ModifyDamageMixin"
对象即可,没有复杂的AttackEvent对象。
但是长柄武器重击会生成子弹,所以我们这里需要看一下长柄武器的ExtractAbility方式:
json
//赛诺普攻重击ExtraAttack
///AbilityName:Avatar_Cyno_ExtraAttack
//abilityMixins
"abilityMixins":
[
{
"$type": "ButtonHoldChargeMixin",
//... 与之前类似
},
{
"$type": "AttachToStateIDMixin",
//... 与之前类似
},
{
"$type": "AttachToStateIDMixin",
//与前一个一样是管理体力
}
{
"$type": "AttachToStateIDMixin",
"stateIDs":
[
"ExtraAttack"
],
"modifierName": "ExtraAttack_AttachEffect"
},
{
"$type": "AttachToStateIDMixin",
"stateIDs":
[
"ExtraAttack_BS"
],
"modifierName": "ExtraAttack_BS_AttachEffect"
},
{
"$type": "AttachToStateIDMixin",
"stateIDs":
[
"ExtraAttack"
],
"modifierName": "ExtraAttack_CloseCollider"
},
{
"$type": "AttachToStateIDMixin",
"stateIDs":
[
"Cyno_ExtraAttack_BurstMode"
],
"modifierName": "ExtraAttack_CloseCollider"
},
{
"$type": "AttachToNormalizedTimeMixin",
"stateID": "Katana_Attack05",
"normalizeStart": 0,
"normalizeEnd": 0.17,
"modifierName": "Avatar_Cyno_Attack05_TurndDirection"
}
],
//modifiers
"modifiers":
{
"ExtraAttack_StaminaCost":
{
"onAdded":
[
{
"$type": "AvatarSkillStart",
//skillID
//costStaminaRatio
}
]
},
"ExtraAttack_StaminaCost_BurstMode":
{
//与体力管理类似
},
"ExtraAttack_AttachEffect":
{
"onAdded":
[
{
"$type": "AttachEffect",
"effectPattern": "Eff_Avatar_Boy_Pole_Cyno_ExtraAttack_Sprint",
"born":
{
"$type": "ConfigBornByTarget",
"offset":
{
"x": 0.0,
"y": -0.3,
"z": 0.0
}
}
}
]
},
"ExtraAttack_BS_AttachEffect":
{
//与上一个类似
},
"ExtraAttack_CloseCollider":
{
"onAdded":
[
{
"$type": "TriggerSetPassThrough",
"passThrough": true,
"doOffStage": true
},
{
"$type": "EnableHDMesh",
"enable": false,
"hdMeshKey": "Default"
}
],
"onRemoved":
[
{
"$type": "TriggerSetPassThrough",
"passThrough": false,
"doOffStage": true,
"canBeHandledOnRecover": true
},
{
"$type": "EnableHDMesh",
"enable": true,
"hdMeshKey": "Default"
},
{
"$type":"KillGadget",
"gadgetInfo":
{
"$type":"SelectTargetsByChildren",
"configID":41071003,
"sortType":"Default"
},
"doOffStage":true
}
]
},
"Avatar_Cyno_Attack05_TurndDirection":
{
"modifierMixins":
[
{
"$type": "AvatarSteerByCameraMixin",
"stateIDs": ["Katana_Attack05"],
"angularSpeed": 600,
"canReviveStamina": true,
"isCheckOnAttach": true
}
]
},
"Avatar_Cyno_Attack03_FireHitEffect_Handler":
{
"onAttackLanded":
[
{
"$type": "Predicated",
"target": "Target",
"targetPredicates":
[
{
"$type": "ByEntityTypes",
"entityTypes": ["Monster"]
},
{
"$type": "ByTargetGlobalValue",
"key": "_ANIMAL_ENTITY_TYPE",
"value": 0,
"compareType": "NoneOrEqual"
}
],
"successActions":
[
{
"$type": "SetGlobalDir",
"target": "Target",
"key": "_Avatar_Cyno_Attack03_Hit",
"born":
{
"$type": "ConfigBornByHitPoint"
},
"setTarget": false
},
{
"$type": "SetGlobalValue",
"key": "_Avatar_Cyno_Attack03_Hit_0",
"value": 0
},
{
"$type": "SetGlobalValue",
"key": "_Avatar_Cyno_Attack03_Hit_1",
"value": 0
},
{
"$type": "SetGlobalValueToOverrideMap",
"globalValueKey": "_Avatar_Cyno_Attack03_Hit_2",
"overrideMapKey": "Attack03_HitDir"
},
{
"$type": "SetGlobalValue",
"key": "_Avatar_Cyno_Attack03_Hit_2",
"value": "-1*%Attack03_HitDir"
},
{
"$type": "FireEffect",
"effectPattern": "Eff_Avatar_Boy_Pole_Cyno_BurstMode_NormalAttack_03_Hit",
"born":
{
"$type": "ConfigBornBySelf",
"direction":
{
"$type": "ConfigDirectionByGlobalValue",
"directionKey": "_Avatar_Cyno_Attack03_Hit"
}
}
}
]
}
]
}
},
//abilitySpecials
"abilitySpecials":
{
"ExtraAttack_Pole_Stamina_Cost": 0,
"ExtraAttack_BurstMode_Stamina_Cost": 0,
"Flexible_Stamina":-2,
"Attack03_HitDir": 0,
}
//AbilityName:Avatar_Cyno_ExtraAttack_CreateBullet
//onAbilityStart
"onAbilityStart"
[
{
"$type": "TriggerBullet",
"bulletID": 41071003,
"campID": 1001,
"campTargetType": "Enemy"
}
]
//AbilityName:Avatar_Cyno_ExtraAttack_Bullet
//onAbilityStart
"onAbilityStart":
[
{
"$type": "Predicated",
"target": "Target",
"targetPredicates":
[
{
"$type": "ByEntityTypes",
"entityTypes": ["MonsterEquip"]
}
],
"successActions":
[
{
"$type": "DamageByAttackValue",
"target": "Target",
"attackInfo":
{
"canBeModifiedBy": "OriginOwner",
"attackTag": "ExtraAttack",
"attenuationTag": "ExtraAttack",
"attenuationGroup": "Avatar_Pole_ExtraAttack",
"attackProperty":
{
"damagePercentage": "%ExtraAttack_Normal",
"strikeType": "Spear",
"elementDurability": 25,
"overrideByWeapon": true,
"attackType": "Melee",
"enBreak": 120
},
"hitPattern":
{
"onHitEffectName": "default",
"hitImpulseType": "LV6",
"reboundRatio": 0,
"canBeDefenceHalt": true,
"hitHaltTime": 0.0,
"hitHaltTimeScale": 0.01,
"muteHitText": false
},
"forceCameraShake": false,
"cameraShake":
{
"shakeType": "CustomVector",
"shakeRange": 0.36,
"shakeTime": 0.12,
"shakeDistance": 30,
"shakeDir":
{
"x": 0,
"y": -1,
"z": 0,
},
}
}
}
],
"failActions":
[
{
"$type": "TriggerAttackEvent",
"targetType": "Enemy",
"attackEvent":
{
"attackPattern": {},
"attackInfo": {}
}
}
]
}
]
//abilitySpecials
"abilitySpecials":
{
"ExtraAttack_Normal": 0
}
我们可以看到赛诺这个角色进行普攻与重击时,与所有都一致,但是长柄武器在重击时,会生成一个子弹,并且这个子弹有一个专门的伤害管理,名字后缀一般为ExtraAttack_Bullet
。内部存在onAbilityStart []
与abilitySpecials {}
。近战角色在攻击时存在打中实体与不打中实体的情况,普通攻击很好理解,因为近战普攻不存在子弹生成,所以容易理解,但重击时会生成子弹,所以子弹有两种情况,打中与不打中。即successActions
与failActions
,successActions
情况下直接使用attackInfo {}
,而failActions
情况下使用attackEvent {}
,这点需要尤其注意。
下面我们看角色元素战技存在键(这里以珊瑚宫心海为例,如果以其他角色为例会专门说明):
json
//珊瑚宫心海元素战技Avatar_Kokomi_ElementalArt
//AbilityName:Avatar_Kokomi_ElementalArt
//abilityMixins
"abilityMixins":
[
//清除水母
{
"$type": "AttachToNormalizedTimeMixin",
"stateID": "Kokomi_ElementalArt",
"modifierName": "Avatar_Kokomi_ElementalArt_KillGadget",//这里
"normalizeStart" : 0.1,
"normalizeEnd" : 1.0
}
]
//onAbilityStart
"onAbilityStart":
[
//CD
{
"$type": "AvatarSkillStart",
"skillID": 10542,
"cdRatio": 1 //比率
},
//水母
{
"$type": "CreateGadget",
"gadgetID": 41054002,
"campID": 1001,
"campTargetType": "Enemy",
"born":
{
"$type": "ConfigBornByTarget",
"offset"://生成位置偏移
{
"x": 0.0,
"y": 0.0,
"z": 3.0
}
}
},
//给自身进行水附着
{
"$type": "AttachModifier",
"modifierName": "Avatar_Kokomi_ElementalArt_WaterBuff"
}
]
//modifiers
"modifiers":
{
"Avatar_Kokomi_ElementalArt_WaterBuff":
{
"stacking": "Refresh",//刷新
"duration": 0.2,//需要时间
"elementType": "Water",//元素类型
"elementDurability": 25//元素量
},
"Avatar_Kokomi_ElementalArt_KillGadget":
{
"onAdded":
[
{
"$type": "KillGadget",
"gadgetInfo":
{
"$type": "SelectTargetsByChildren",
"configID": 41054002,
"sortType": "Default"
}
}
]
}
}
//战技创造的水母Kokomi_ElementalArt_Gadget
//AbilityName:Kokomi_ElementalArt_Gadget
//abilityMixins
"abilityMixins":
[
{
"$type": "AttachModifierToSelfGlobalValueMixin",
"globalValueKey": "_ABILITY_Kokomi_ElementalArt_Burst_Flag", //变量名称
"valueSteps": [-0.5, 0.5, 1.5],
"removeAppliedModifier": true,
"modifierNameSteps": ["Blank", "Burst_Effect"] //modifierName顺序 即在modifiers中这两个对象相对位置必须与这里一致
}
]
//onAdded
"onAdded":
[
{
"$type":"ApplyModifier",
"modifierName": "UNIQUE_Kokomi_ElementalArt_Gadget_LifeTime" //水母生存时间
},
{
"$type" : "SetGlobalValue", //设置公共变量
"target": "Self",
"key" : "_ABILITY_Kokomi_ElementalArt_Burst_Flag",//变量名称
"value" : 1,//变量值
"predicates":
[
{
"$type": "ByTargetGlobalValue",
"key": "_ABILITY_Kokomi_ElementalBurst_Flag",
"value": 1,
"compareType": "Equal",
"target":"Owner"
}
]
}
]
//onAbilityStart
"onAbilityStart":
[
{
"$type": "ApplyModifier",
"modifierName": "UNIQUE_Kokomi_ElementalArt_Gadget_LifeTime"
}
]
//onFieldEnter
[
//心海元素爆发后给水母增加或更新效果
{
"$type": "Predicated",
"target": "Target",
"targetPredicates":
[
{
"$type": "ByTargetType",
"targetType": "Owner",
"isTarget": true
},
{
"$type":"ByEntityTypes",
"target":"Target",
"entityTypes":["Avatar"]
},
{
"$type": "ByTargetGlobalValue",
"key": "_ABILITY_Kokomi_ElementalBurst_Flag",
"value": 1,
"compareType": "Equal",
"target":"Owner"
}
],
"successActions":
[
{
"$type" : "SetGlobalValue",
"target": "Self",
"key" : "_ABILITY_Kokomi_ElementalArt_Burst_Flag",
"value" : 1
}
]
}
]
//onFieldExit
"onFieldExit":
[
//元素爆发结束后,若水母还未消失,移除水母身上效果
{
"$type": "Predicated",
"target": "Target",
"targetPredicates":
[
{
"$type": "ByTargetType",
"targetType": "Owner",
"isTarget": true
},
{
"$type":"ByEntityTypes",
"target":"Target",
"entityTypes":["Avatar"]
}
],
"successActions":
[
{
"$type" : "SetGlobalValue",
"target": "Self",
"key" : "_ABILITY_Kokomi_ElementalArt_Burst_Flag",
"value" : 0
}
]
}
]
//onKill
"onKill":
[]
//modifiers
"modifiers":
{
//这里顺序与之前modifierNameSteps一致
"Blank":
{},
"Burst_Effect":
{
//水母的发光效果控制
"onAdded":
[
{
"$type": "SetAnimatorBool",
"boolID": "Burst",
"value": true
}
],
"onRemoved":
[
{
"$type": "SetAnimatorBool",
"boolID": "Burst",
"value": false
}
]
},
"UNIQUE_Kokomi_ElementalArt_Gadget_LifeTime":
{
"duration": "%ElementalArt_Gadget_Duration",//持续时间
"isUnique": true,
"stacking": "Refresh",
"onAdded":
[
{
"$type": "SetAnimatorBool",
"boolID": "FadeOut",
"value": false
},
{
"$type":"AttachEffect",
"effectPattern":"Eff_Avatar_Girl_Catalyst_Kokomi_ElementalArt_Gadget_Field"
}
],
"onAttackLanded":
[
{
"$type": "Predicated",
"target": "Target",
"targetPredicates":
[
{
"$type": "ByAttackTags",
"attackTags": ["Elemental_Art"]
},
{
"$type": "ByEntityTypes",
"entityTypes": ["Monster"]
},
{
"$type": "ByTargetGlobalValue",
"key": "_ANIMAL_ENTITY_TYPE",
"value": 0,
"compareType": "NoneOrEqual"
}
],
"successActions":
[
{
"$type": "ApplyModifier",
"modifierName": "Avatar_Kokomi_ElementalArt_ElemBall"
}
]
}
],
"onRemoved":
[
{
"$type": "SetAnimatorBool",
"boolID": "FadeOut",
"value": true
},
{
"$type":"FireEffect",
"effectPattern":"Eff_Avatar_Girl_Catalyst_Kokomi_ElementalArt_Gadget_Die",
"born":
{
"$type": "ConfigBornByAttachPoint",
"attachPointName": "RootNode",
"offset":
{
"x": 0.0,
"y": 0.0,
"z": 0.0
}
}
},
{
"$type": "KillSelf",
"duration": 0.5
}
]
},
"Avatar_Kokomi_ElementalArt_ElemBall": //水母攻击产生的元素球
{
"duration": 1.0,
"stacking": "Unique",
"onAdded":
[
{
"$type": "Randomed",
"chance": 0.67,
"successActions":
[
{
"$type": "GenerateElemBall",
"configID": 2018,
"baseEnergy": 3,
"ratio": 1,
"born":
{
"$type": "ConfigBornByAttachPoint",
"attachPointName": "RootNode",
"offset" :
{
"x": 0.0,
"y": 0.0,
"z": 0.0
}
}
}
]
}
]
}
}
//abilitySpecials
"abilitySpecials":
{
"ElementalArt_Gadget_Duration": 0
}
//水母的攻击与恢复Kokomi_ElementalArt_Gadget_Controller
//abilityName:Kokomi_ElementalArt_Gadget_Controller
//onAbilityStart
"onAbilityStart":
[
{
"$type": "Predicated",
"target": "Caster",
"targetPredicates":
[
{
"$type": "ByUnlockTalentParam",
"talentParam": "Avatar_Kokomi_Talent_ExtraHealLowHPTarget"
}
],
"successActions":
[
//解锁命之座2的话:血量百分比小于等于阈值就提升回复量
{
"$type": "ApplyModifier",
"modifierName": "Avatar_Kokomi_ElementalArt_Heal_Talent_ExtraHealLowHPTarget",
"otherTargets":
{
"$type": "SelectTargetsByShape",
"shapeName": "CircleR6",
"centerBasedOn": "Self",
"campTargetType": "SelfCamp",
"campBasedOn": "Self",
"entityTypePriority": ["Avatar"]
},
"predicates":
[
{
"$type" : "ByTargetHPRatio",
"HPRatio" : "%Talent_ExtraHealLowHPTarget_Threshold",
"logic" : "LesserOrEqual"
},
{
"$type" : "ByEntityTypes",
"entityTypes" : ["Avatar"]
}
]
},
//解锁命之座2的话:血量大于阈值就还是默认回复量
{
"$type": "ApplyModifier",
"modifierName": "Avatar_Kokomi_ElementalArt_Heal",
"otherTargets":
{
"$type": "SelectTargetsByShape",
"shapeName": "CircleR6",
"centerBasedOn": "Self",
"campTargetType": "SelfCamp",
"campBasedOn": "Self",
"entityTypePriority": ["Avatar"]
},
"predicates":
[
{
"$type" : "ByTargetHPRatio",
"HPRatio" : "%Talent_ExtraHealLowHPTarget_Threshold",
"logic" : "Greater"
},
{
"$type" : "ByEntityTypes",
"entityTypes" : ["Avatar"]
}
]
}
],
"failActions":
[
//没有解锁命之座2的话:默认回复量
{
"$type": "ApplyModifier",
"modifierName": "Avatar_Kokomi_ElementalArt_Heal",
"otherTargets":
{
"$type": "SelectTargetsByShape",
"shapeName": "CircleR6",
"centerBasedOn": "Self",
"campTargetType": "SelfCamp",
"campBasedOn": "Self",
"entityTypePriority": ["Avatar"]
},
"predicates":
[
{
"$type" : "ByEntityTypes",
"entityTypes" : ["Avatar"]
}
]
}
]
},
{
//治疗场特效
"$type": "FireEffect",
"effectPattern": "Eff_Avatar_Girl_Catalyst_Kokomi_ElementalArt_Gadget_HealWave"
},
{
//爆发状态下的冲击波特效
"$type": "FireEffect",
"effectPattern": "Eff_Avatar_Girl_Catalyst_Kokomi_ElementalArt_Gadget_ShockWave",
"predicates":
[
{
"$type": "ByTargetGlobalValue",
"key": "_ABILITY_Kokomi_ElementalArt_Burst_Flag",
"forceByCaster": true,
"value": 1,
"compareType": "Equal"
}
]
},
{
"$type": "FireEffect",
"effectPattern": "Eff_Avatar_Girl_Catalyst_Kokomi_ElementalArt_Gadget_ShockWave_2",
"predicates":
[
{
"$type": "ByTargetGlobalValue",
"key": "_ABILITY_Kokomi_ElementalArt_Burst_Flag",
"forceByCaster": true,
"value": 0,
"compareType": "Equal"
}
]
},
{
//非爆发状态下的攻击盒
"$type" : "TriggerAttackEvent",
"targetType" : "Enemy",
"attackEvent":
{
"attackPattern" :
{
"$type" : "ConfigAttackSphere",
"triggerType" : "TriggerNoRepeat",
"radius" : 6,
"born":
{
"$type": "ConfigBornByAttachPoint",
"attachPointName": "RootNode",
"offset":
{
"x": 0.0,
"y": 0.0,
"z": 0.0
}
}
},
"attackInfo":
{
"canBeModifiedBy" : "OriginOwner",
"attackTag":"Elemental_Art",
// "attenuationTag": "Elemental_Art",
"attackProperty":
{
"damagePercentage" : "%ElementalArt_Damage_Percentage",
"elementType": "Water",
"elementDurability": 25,
"strikeType": "Default",
"enBreak": 50
},
"hitPattern" :
{
"onHitEffectName" : "Eff_Avatar_Girl_Catalyst_Kokomi_ElementalArt_Gadget_Hit",
"hitImpulseType":"LV1",
"reboundRatio" : 0,
"hitHaltTime" : 0.0,
"hitHaltTimeScale" : 0.0,
"muteHitText" : false
}
}
},
"predicates":
[
{
"$type": "ByTargetGlobalValue",
"key": "_ABILITY_Kokomi_ElementalArt_Burst_Flag",
"forceByCaster": true,
"value": 0,
"compareType": "Equal"
}
]
},
{
//爆发状态下的攻击盒
"$type" : "TriggerAttackEvent",
"targetType" : "Enemy",
"attackEvent":
{
"attackPattern" :
{
"$type" : "ConfigAttackSphere",
"triggerType" : "TriggerNoRepeat",
"radius" : 6,
"born":
{
"$type": "ConfigBornByAttachPoint",
"attachPointName": "RootNode",
"offset":
{
"x": 0.0,
"y": 0.0,
"z": 0.0
}
}
},
"attackInfo":
{
"canBeModifiedBy" : "OriginOwner",
"attackTag":"Elemental_Art",
// "attenuationTag": "Elemental_Art",
"attackProperty":
{
"damagePercentage" : "%ElementalArt_Damage_Percentage",
"damageExtra" : "%FIGHT_PROP_MAX_HP*%ElementalArt_Damage_MaxHP_Percentage",
"elementType": "Water",
"elementDurability": 25,
"strikeType": "Default",
"enBreak": 100
},
"hitPattern" :
{
"onHitEffectName":"Eff_Avatar_Girl_Catalyst_Kokomi_ElementalArt_Gadget_Hit",
"hitImpulseType":"LV1",
"reboundRatio" : 0,
"hitHaltTime" : 0.0,
"hitHaltTimeScale" : 0.05,
"muteHitText" : false
}
}
},
"predicates":
[
{
"$type": "ByTargetGlobalValue",
"key": "_ABILITY_Kokomi_ElementalArt_Burst_Flag",
"forceByCaster": true,
"value": 1,
"compareType": "Equal"
}
]
}
],
//modifiers
"modifiers":
{
"Avatar_Kokomi_ElementalArt_Heal"://默认回复量
{
"duration": 1.0,
"onAdded":
[
{
"$type": "HealHP",
"amountByCasterMaxHPRatio": "%ElementalArt_Heal_MaxHP_Base_Percentage",
"amount": "%ElementalArt_Heal_Base_Amount"
}
]
},
"Avatar_Kokomi_ElementalArt_Heal_Talent_ExtraHealLowHPTarget"://解锁命之座后的回复量
{
"duration": 1.0,
"onAdded":
[
{
"$type": "HealHP",
"amountByCasterMaxHPRatio": "%ElementalArt_Heal_MaxHP_Base_Percentage+%Talent_ExtraHealLowHPTarget_ElementalArt_MaxHP_Extra_Percentage",
"amount": "%ElementalArt_Heal_Base_Amount"
}
]
}
},
//abilitySpecials
"abilitySpecials":
{
"ElementalArt_Heal_MaxHP_Base_Percentage": 0,//根据百分比生命值治疗修正值
"ElementalArt_Heal_Base_Amount": 0,//基础治疗量修正值
"ElementalArt_Damage_Percentage": 0,//百分比伤害修正值
"ElementalArt_Damage_MaxHP_Percentage": 0,//根据百分比生命值造成伤害修正值
"Talent_ExtraHealLowHPTarget_Threshold": 0,//解锁命座2后额外百分比生命值的治疗量
"Talent_ExtraHealLowHPTarget_ElementalArt_MaxHP_Extra_Percentage": 0//
}
我们可以看到心海元素战技由三个Ability组成,Avatar_Kokomi_ElementalArt
管理角色使用技能后的逻辑,由于战技会创造水母召唤物,所以这里很容易存在创建召唤物的Ability(Kokomi_ElementalArt_Gadget
),召唤物到目前为止具有攻击 嘲讽 恢复 元素附着 提供buff等等能力。我们通过了解心海技能得知,心海的水母具有攻击,恢复,元素附着等能力,心海在进入退出水母圈范围有不同效果。
可以发现心海的水母具体由两个Ability管理,Kokomi_ElementalArt_Gadget
管理水母的状态,而Kokomi_ElementalArt_Gadget_Controller
管理水母的攻击与恢复。第一个Ability管理水母的持续时间(modifiers中的UNIQUE_Kokomi_ElementalArt_Gadget_LifeTime对象
),状态机(modifiers中的Blank与Burst_Effect对象共同被abilityMixins使用并控制
),水母命中敌人时的元素球掉落(modifiers的Avatar_Kokomi_ElementalArt_ElemBall对象
),监测水母在场时是否开大(onAdded添加标签onFieldEnter与onFieldExit根据标签控制水母不同状态的状态),第二个Ability更多是管理水母的参数。这些参数对象被放在onAbilityStart中并通过abilitySpecials进行修正。需要注意的是这里治疗量在modifiers中管理并计算,并被onAbilityStart使用。
我们还可以再看一个例子:
json
//流浪者元素战技ElementalArt
//AbilityName:Avatar_Wanderer_ElementalArt_Launch
//onAbilityStart
"onAbilityStart":
[
{
"$type":"TriggerAbility", //触发能力
"abilityName": "Avatar_Wanderer_ElementalArt_HoverAir"
}
]
//AbilityName:Avatar_Wanderer_ElementalArt_Ring
//abilityMixins
"abilityMixins":
[
{
"$type": "AttachModifierToSelfGlobalValueMixin",
"globalValueKey": "_ABILITY_Wanderer_ElementalArt_MixType_Fire",
"valueSteps": [-1, 0.5, 1.5],
"removeAppliedModifier": true,
"modifierNameSteps":
[
"Blank",
"Wanderer_PermanentSkill_1_Fire"
]
},
{
"$type": "AttachModifierToSelfGlobalValueMixin",
"globalValueKey": "_ABILITY_Wanderer_ElementalArt_MixType_Water",
"valueSteps": [-1, 0.5, 1.5],
"removeAppliedModifier": true,
"modifierNameSteps":
[
"Blank",
"Wanderer_PermanentSkill_1_Water"
]
},
{
"$type": "AttachModifierToSelfGlobalValueMixin",
"globalValueKey": "_ABILITY_Wanderer_ElementalArt_MixType_Electric",
"valueSteps": [-1, 0.5, 1.5],
"removeAppliedModifier": true,
"modifierNameSteps":
[
"Blank",
"Wanderer_PermanentSkill_1_Electric"
]
},
{
"$type": "AttachModifierToSelfGlobalValueMixin",
"globalValueKey": "_ABILITY_Wanderer_ElementalArt_MixType_Ice",
"valueSteps": [-1, 0.5, 1.5],
"removeAppliedModifier": true,
"modifierNameSteps":
[
"Blank",
"Wanderer_PermanentSkill_1_Ice"
]
}
]
//onAdded
"onAdded":
[
{
"$type" : "SetGlobalValue",
"target": "Self",
"key" : "_ABILITY_Wanderer_ElementalArt_MixType_Fire",
"value" : 0
},
{
"$type" : "SetGlobalValue",
"target": "Self",
"key" : "_ABILITY_Wanderer_ElementalArt_MixType_Water",
"value" : 0
},
{
"$type" : "SetGlobalValue",
"target": "Self",
"key" : "_ABILITY_Wanderer_ElementalArt_MixType_Electric",
"value" : 0
},
{
"$type" : "SetGlobalValue",
"target": "Self",
"key" : "_ABILITY_Wanderer_ElementalArt_MixType_Ice",
"value" : 0
},
{
"$type": "TriggerAttackEvent",
"targetType": "Enemy",
"attackEvent":
{
"attackPattern" :
{
"$type": "ConfigAttackCircle",
"triggerType": "TriggerNoRepeat",
"height": 8.0,
"radius": 6.0,
"born":
{
"$type": "ConfigBornBySelf",
"offset":
{
"x": 0.0,
"y": -4.0,
"z": 0.0
}
}
},
"attackInfo":
{
"canBeModifiedBy": "OriginOwner",
"attackTag": "Elemental_Art",
"attenuationTag": "Elemental_Art",
"attackProperty":
{
"damagePercentage": "%ElementalArt_Damage",
"elementType": "Wind",
"elementDurability": 25,
"strikeType": "Default",
"enBreak": 12.8205
},
"hitPattern" :
{
"onHitEffectName": "Default",
"hitImpulseType": "LV3",
"reboundRatio" : 0,
"hitHaltTime" : 0.0,
"hitHaltTimeScale" : 0.05,
"muteHitText" : false
}
}
}
}
]
//onKill
"onKill":
[
{
"$type" : "SetGlobalValue",
"target": "Self",
"key" : "_ABILITY_Wanderer_ElementalArt_MixType_Fire",
"value" : 0
},
{
"$type" : "SetGlobalValue",
"target": "Self",
"key" : "_ABILITY_Wanderer_ElementalArt_MixType_Water",
"value" : 0
},
{
"$type" : "SetGlobalValue",
"target": "Self",
"key" : "_ABILITY_Wanderer_ElementalArt_MixType_Electric",
"value" : 0
},
{
"$type" : "SetGlobalValue",
"target": "Self",
"key" : "_ABILITY_Wanderer_ElementalArt_MixType_Ice",
"value" : 0
}
]
//onAbilityStart
"onAbilityStart":
[
{
"$type": "RandomAction",
"randomCount": 1, //成功执行随机事件的最少次数
"randomQueue": //随机队列
[
{
"randomPredicates": //随机判据,满足则执行
[
{
"$type": "ByTargetGlobalValue",
"key": "_ABILITY_Wanderer_ElementalArt_MixType_Fire",
"value": 0,
"compareType": "Equal"
}
],
"actionQueue": //事件队列
[
{
"$type":"SetGlobalValue",
"key":"_ABILITY_Wanderer_ElementalArt_MixType_Fire",
"value":1,
"doOffStage":true,
}
]
},
{
"randomPredicates":
[
{
"$type": "ByTargetGlobalValue",
"key": "_ABILITY_Wanderer_ElementalArt_MixType_Water",
"value": 0,
"compareType": "Equal"
}
],
"actionQueue":
[
{
"$type":"SetGlobalValue",
"key":"_ABILITY_Wanderer_ElementalArt_MixType_Water",
"value":1,
"doOffStage":true
}
]
},
{
"randomPredicates":
[
{
"$type": "ByTargetGlobalValue",
"key": "_ABILITY_Wanderer_ElementalArt_MixType_Electric",
"value": 0,
"compareType": "Equal"
}
],
"actionQueue":
[
{
"$type":"SetGlobalValue",
"key":"_ABILITY_Wanderer_ElementalArt_MixType_Electric",
"value":1,
"doOffStage":true
},
]
},
{
"randomPredicates":
[
{
"$type": "ByTargetGlobalValue",
"key": "_ABILITY_Wanderer_ElementalArt_MixType_Ice",
"value": 0,
"compareType": "Equal"
},
],
"actionQueue":
[
{
"$type":"SetGlobalValue",
"key":"_ABILITY_Wanderer_ElementalArt_MixType_Ice",
"value":1,
"doOffStage":true
}
]
}
]
}
]
//modifiers
"modifiers":
{
"Blank":
{
},
"Wanderer_PermanentSkill_1_Electric":
{
"onAdded":
[
{
"$type": "AttachEffect",
"effectPattern": "Eff_Avatar_Boy_Catalyst_Wanderer_PermanentSkill_1_Electric"
},
{
"$type":"AttachModifier",
"target": "Owner",
"modifierName":"Wanderer_PermanentSkill_1_Electric_Buff_Handler"
}
]
},
"Wanderer_PermanentSkill_1_Water":
{
"onAdded":
[
{
"$type": "AttachEffect",
"effectPattern": "Eff_Avatar_Boy_Catalyst_Wanderer_PermanentSkill_1_Water",
},
{
"$type":"AttachModifier",
"target": "Owner",
"modifierName":"Wanderer_PermanentSkill_1_Water_Buff"
}
]
},
"Wanderer_PermanentSkill_1_Fire":
{
"onAdded":
[
{
"$type": "AttachEffect",
"effectPattern": "Eff_Avatar_Boy_Catalyst_Wanderer_PermanentSkill_1_Fire"
},
{
"$type":"AttachModifier",
"target": "Owner",
"modifierName":"Wanderer_PermanentSkill_1_Fire_Buff"
}
]
},
"Wanderer_PermanentSkill_1_Ice":
{
"onAdded":
[
{
"$type": "AttachEffect",
"effectPattern": "Eff_Avatar_Boy_Catalyst_Wanderer_PermanentSkill_1_Ice",
},
{
"$type":"AttachModifier",
"target": "Owner",
"modifierName":"Wanderer_PermanentSkill_1_Ice_Buff"
}
]
},
"Wanderer_PermanentSkill_1_Fire_Buff":
{
"stacking": "Unique",
// "state": "AttackUp",
"isLimitedProperties": true,
"properties":
{
"Actor_AttackRatio": "%PermanentSkill_1_Fire_Atk_Ratio"
}
},
"Wanderer_PermanentSkill_1_Water_Buff":
{
"onAdded":
[
{
"$type": "ManipulateStrafeStamina",
"value": "%PermanentSkill_1_Water_Add_Stamina"
}
]
},
"Wanderer_PermanentSkill_1_Ice_Buff":
{
"stacking": "Unique",
// "state": "AttackUp",
"isLimitedProperties": true,
"properties":
{
"Actor_CriticalDelta": "%PermanentSkill_1_Ice_Crit_Ratio"
}
},
"Wanderer_PermanentSkill_1_Electric_Buff_Handler":
{
"onHittingOther":
[
{
"$type":"Predicated",
"target":"Other", //这里需要填other
"targetPredicates":
[
{
"$type":"ByAttackTags",
"attackTags":["NormalAttack_01","NormalAttack_02","NormalAttack_03","NormalAttack_04","ExtraAttack"]
},
{
"$type" : "ByEntityTypes",
"entityTypes" : ["Monster"]
},
{
"$type": "ByTargetGlobalValue",
"key": "_ANIMAL_ENTITY_TYPE",
"value": 0,
"compareType": "NoneOrEqual"
}
],
"successActions":
[
{
"$type":"ApplyModifier",
"target": "Self",
"modifierName":"UNIQUE_Wanderer_PermanentSkill_1_Electric_Buff"
}
]
}
],
},
"UNIQUE_Wanderer_PermanentSkill_1_Electric_Buff":
{
"isUnique": true,
"duration": 0.2,
"stacking": "Unique",
"onAdded":
[
{
"$type": "ReviveElemEnergy",
"value": "%PermanentSkill_1_Electric_Add_Energy"
}
]
}
}
//abilitySpecials
"abilitySpecials":
{
"ElementalArt_Damage": 0,
"PermanentSkill_1_Fire_Atk_Ratio": 0,
"PermanentSkill_1_Water_Add_Stamina": 0,
"PermanentSkill_1_Ice_Crit_Ratio": 0,
"PermanentSkill_1_Electric_Add_Energy": 0,
}
//AbilityName:Avatar_Wanderer_ElementalArt_HoverAir
//onAdded
"onAdded":
[
{
"$type": "SetGlobalValue",
"key": "_ABILITY_Avatar_Wanderer_HoverAir_Flag",
"value": 0,
"doOffStage": true
}
]
//onAbilityStart
"onAbilityStart":
[
{
"$type": "KillGadget",
"doOffStage": true,
"gadgetInfo":
{
"$type": "SelectTargetsByChildren",
"configID": 41075301
}
},
{
"$type": "CreateGadget",
"gadgetID": 41075301,
"campID": 1001,
"campTargetType": "Enemy",
"doOffStage": true,
"born":
{
"$type": "ConfigBornBySelf"
}
},
{
"$type": "RemoveUniqueModifier",
"modifierName": "UNIQUE_Avatar_Wanderer_ElementalArt_HoverAir_Handler"
},
{
"$type": "AttachModifier",
"modifierName": "UNIQUE_Avatar_Wanderer_ElementalArt_HoverAir_Handler"
},
{
"$type": "AttachModifier",
"modifierName": "Avatar_Wanderer_Constellation_6_Handler",
"predicates":
[
{
"$type" : "ByUnlockTalentParam",
"talentParam": "Wanderer_Constellation_6"
}
]
},
{
"$type":"FireEffect",
"effectPattern": "Eff_Avatar_Boy_Catalyst_Wanderer_ElementalArt_BS"
}
]
//abilityMixins
"abilityMixins":
[
{
"$type": "AttachModifierToSelfGlobalValueMixin",
"globalValueKey": "_ABILITY_Avatar_Wanderer_HoverAir_Flag",
"valueSteps": [-0.5, 0.5, 1.5],
"removeAppliedModifier": true,
"modifierNameSteps": ["Blank", "Avatar_Wanderer_HoverAir_WeaponVisible_Handler"]
},
{
"$type":"AttachToNormalizedTimeMixin",
"stateID":"Wanderer_ElementalArt_Air_BS",
"modifierName":"RushMove",
"normalizeStart":0.03,
"normalizeEnd":0.5
},
{
"$type": "AvatarStrafeMixin",
"configList":
[
{
"stateIds":
[
"Wanderer_ElementalArt_Air_BS"
],
"useRootMotion": true
},
{
"stateIds":
[
"Wanderer_ElementalBurst_Air",
"Wanderer_ElementalBurst_Air_AS"
],
"strafeMoveSpeed": 0.5,
"useRootMotion": true
},
{
"stateIds":
[
"Wanderer_ElementalArt_HoverAir",
// "Wanderer_ElementalArt_HoverAir_BS",
// "Wanderer_ElementalArt_HoverAir_AS",
"Wanderer_ElementalArt_HoverAir_Standby"
],
"strafeMoveSpeed": 6.0,
"rotateToTarget": true
},
{
"stateIds":
[
"Wanderer_ElementalArt_HoverAir_Dash_ToRun",
],
"strafeMoveSpeed": 6.0,
"rotateToTarget": true,
"angularSpeed": 270
},
{
"stateIds":
[
"Wanderer_ElementalArt_HoverAir_Dash_BS",
"Wanderer_ElementalArt_HoverAir_Dash_Hold",
"Wanderer_ElementalArt_HoverAir_Dash_AS"
],
"useRootMotion": true,
"angularSpeed": 480
},
{
"stateIds":
[
"Wanderer_ElementalArt_HoverAir_Up_BS",
"Wanderer_ElementalArt_HoverAir_Up_Hold",
],
"strafeMoveSpeed": 3.0,
"dropSpeed": -3.0
},
{
"stateIds":
[
"Wanderer_ElementalArt_HoverAir_Up_AS"
],
"strafeMoveSpeed": 6.0,
"dropSpeed": -0.2
},
{
"stateIds":
[
"Hit_Throw_Hover",
"Hit_ThrowAir_Hover"
],
// "strafeMoveSpeed": 0.1,
"useRootMotion": true,
"useGravity": true
},
{
"stateIds":
[
"Wanderer_ElementalArt_HoverAir_HitRetreat",
"Hit_ThrowGround_Hover"
],
// "strafeMoveSpeed": 0.1,
"useRootMotion": true
},
{
"stateIds":
[
"Katana_Attack01",
"Katana_Attack02",
"Katana_Attack03",
"ExtraAttack_Air_BS",
"ExtraAttack_Air_Charge",
"ExtraAttack_Air",
"ExtraAttack_Air_AS"
],
"strafeMoveSpeed": 0.5,
"rotateToTarget": true,
"angularSpeed": 10
},
{
"stateIds":
[
"Katana_Attack03_AS",
],
"strafeMoveSpeed": 0.5,
"rotateToTarget": true,
"angularSpeed": 10,
"useRootMotion": true
}
],
"onExitStrafeStates":
[
{
"$type": "RemoveUniqueModifier",
"modifierName": "UNIQUE_Avatar_Wanderer_ElementalArt_HoverAir_Handler"
}
]
},
{
"$type": "AttachToAnimatorStateIDMixin",
"stateIDs":
[
"Wanderer_ElementalArt_HoverAir",
"Wanderer_Hover_MoveAS",
"Wanderer_ElementalArt_HoverAir_Dash_AS",
"Wanderer_ElementalArt_HoverAir_Up_AS"
],
"modifierName": "Avatar_Wanderer_Kasa_Ring_Idle"
},
{
"$type": "AttachToAnimatorStateIDMixin",
"stateIDs":
[
"Wanderer_Hover_MoveBS",
"Wanderer_Hover_MoveHold",
"Wanderer_ElementalArt_HoverAir_Dash_ToRun",
"Wanderer_ElementalArt_HoverAir_Up_BS",
"Wanderer_ElementalArt_HoverAir_Up_Hold"
// "Wanderer_ElementalArt_HoverAir_Dash_BS",
],
"modifierName": "Avatar_Wanderer_Kasa_Ring_Move"
},
{
"$type": "AttachToAnimatorStateIDMixin",
"stateIDs":
[
"Wanderer_ElementalArt_HoverAir_Dash_BS"
// "Wanderer_Hover_MoveAS",
],
"modifierName": "Avatar_Wanderer_Kasa_Ring_Dash"
},
{
"$type": "AttachToAnimatorStateIDMixin",
"stateIDs":
[
"Wanderer_ElementalArt_HoverAir_Dash_Hold"
// "Wanderer_Hover_MoveAS",
],
"modifierName": "Avatar_Wanderer_Kasa_Ring_DashHold"
},
{
"$type": "AttachToAnimatorStateIDMixin",
"stateIDs":
[
"Wanderer_ElementalArt_HoverAir_HitRetreat",
"Hit_ThrowGround_Hover"
],
"modifierName": "Avatar_Wanderer_Kasa_Ring_Recovery"
},
{
"$type": "AttachToStateIDMixin",
"stateIDs":
[
"Wanderer_ElementalArt_HoverAir_Dash_Hold"
],
"modifierName": "ScreenEffect"
},
{
"$type": "AttachToStateIDMixin",
"stateIDs": ["Wanderer_ElementalArt_HoverAir_Dash_BS"],
"modifierName": "Oil_Dash_BS"
},
{
"$type": "AttachToStateIDMixin",
"stateIDs": ["Wanderer_ElementalArt_HoverAir_Dash_Hold"],
"modifierName": "Oil_Dash_Hold"
},
{
"$type": "AttachToStateIDMixin",
"stateIDs": ["Wanderer_ElementalArt_HoverAir_Up_BS"],
"modifierName": "Oil_Up_BS"
},
{
"$type": "AttachToStateIDMixin",
"stateIDs": ["Wanderer_ElementalArt_HoverAir_Up_Hold"],
"modifierName": "Oil_Up_Hold"
},
{
"$type": "AttachToStateIDMixin",
"stateIDs": ["Wanderer_ElementalArt_Air_AS"],
"modifierName": "Avatar_Wanderer_ElementalArt_HoverAir_Remover"
},
{
"$type": "AttachToStateIDMixin",
"stateIDs": ["Wanderer_ElementalArt_Air_BS"],
"modifierName": "Initialize"
},
{
"$type" : "AttachToNormalizedTimeMixin",
"stateID" : "Wanderer_ElementalArt_HoverAir_HitRetreat",
"modifierName" : "Boy_Catalyst_HitFallToGround_Visible_Handler",
"normalizeStart":0.02,
"normalizeEnd":0.1
},
{
"$type" : "AttachToNormalizedTimeMixin",
"stateID" : "Wanderer_ElementalArt_HoverAir_HitRetreat",
"modifierName" : "Boy_Catalyst_HitFallToGround_ShowSpark",
"normalizeStart":0.11,
"normalizeEnd":1.0
},
{
"$type" : "AttachToNormalizedTimeMixin",
"stateID" : "Hit_ThrowGround_Hover",
"modifierName" : "Boy_Catalyst_HitFallToGround_Visible_Handler",
"normalizeStart":0.02,
"normalizeEnd":0.1
},
{
"$type" : "AttachToNormalizedTimeMixin",
"stateID" : "Hit_ThrowGround_Hover",
"modifierName" : "Boy_Catalyst_HitFallToGround_ShowSpark",
"normalizeStart":0.11,
"normalizeEnd":1.0
},
{
"$type": "AttachToStateIDMixin",
"stateIDs": ["Wanderer_ElementalArt_HoverAir"],
"modifierName": "HitMixin"
},
{
"$type": "AttachToStateIDMixin",
"stateIDs": ["Hit_Throw_Hover","Hit_ThrowAir_Hover",],
"modifierName": "Recover_Mark"
}
]
//modifiers
"modifiers":
{
}
//abilitySpecials
"abilitySpecials":
{
"Constellation_2_AtkSpeed_Ratio": 0,
"Constellation_6_Revive_Stamina": 0
}
sa
由此我们可以知道所有角色名为ExtractAttack的Ability的特点:
- 都存在三个基本数组对象:
abilityMixins []
,modifiers {}
,abilitySpecials {}
. abilityMixins []
管理角色的进行普通攻击时输入监听,以及不同输入下的动画播放,攻击动作序列,和角色重击时体力消耗(通过修正值进行修改)。modifiers {}
管理
Comments 1 条评论
博主 拾伍ovo