From 2906206f0c8cf6d9509e4a2c6d22f01cac1da04b Mon Sep 17 00:00:00 2001 From: SoulliesOfficial Date: Mon, 27 Oct 2025 07:04:34 -0400 Subject: [PATCH] keyword + animation --- .gitignore | 3 + Assets/ExportedMods/Basic.umod | 4 +- .../Attack/CardData_Basic_DualStrike.asset | 4 +- .../Attack/CardData_Basic_Strike.asset | 5 +- .../Item/CardData_Basic_HiddenBlade.asset | 3 +- .../CardData_Basic_HolyWaterPreparation.asset | 3 +- .../Basic/Cards/Scripts/General/Cohesion.cs | 1 + .../Scripts/General/FightingInspiration.cs | 2 +- .../Scripts/General/HolyWaterPreparation.cs | 2 +- .../Basic/Cards/Scripts/General/Strike.cs | 13 +- .../CharacterViews/Animations/Attack.anim | 51 ------ .../CharacterViews/Animations/Idle.anim | 57 +------ .../CharacterViews/Animations/Skill.anim | 51 ------ .../CombatViews/MarshalOfTheUnderworld.prefab | 4 +- .../CharacterViews/Controller.controller | 2 +- .../CombatBuffs/General/Protecting.cs | 2 +- Assets/Mods/Basic/References.meta | 8 + .../Basic_EditKeywordsReference.asset | 93 +++++++++++ .../Basic_EditKeywordsReference.asset.meta | 8 + .../References/Basic_ModEditReference.asset | 15 ++ .../Basic_ModEditReference.asset.meta | 8 + .../Base/Interpreters/BuffTextInterpreter.cs | 9 +- .../Base/Interpreters/CardTextInterpreter.cs | 10 +- .../Interpreters/DynamicTextInterpreter.cs | 42 ++--- .../MainGame/Card/CardAssistanceFunctions.cs | 38 +++-- .../MainGame/Card/CardData/CardData.cs | 155 +++--------------- Assets/Scripts/MainGame/Card/CardLogicBase.cs | 12 +- .../MainGame/Card/CardMainFunctions.cs | 9 +- .../Card/CardSubmodules/ContentSubmodule.cs | 5 +- .../MainGame/Card/CardView/CardViewBase.cs | 10 +- .../HandCardView/HandCardView_Operations.cs | 2 +- .../MainGame/Card/Editor/CardDataEditor.cs | 124 +++++++++++++- .../CardLogicComponent_GenerateCards.cs | 12 +- .../MainGame/Commands/Cmd_PlayAnimation.cs | 53 ++++++ Assets/Scripts/Mod/EditReferences.meta | 8 + .../EditReferences/EditKeywordsReference.cs | 12 ++ .../EditKeywordsReference.cs.meta | 2 + .../Mod/EditReferences/ModEditReference.cs | 12 ++ .../EditReferences/ModEditReference.cs.meta | 2 + .../CommandQueue/CommandGroup.cs | 40 +++++ 40 files changed, 512 insertions(+), 384 deletions(-) create mode 100644 Assets/Mods/Basic/References.meta create mode 100644 Assets/Mods/Basic/References/Basic_EditKeywordsReference.asset create mode 100644 Assets/Mods/Basic/References/Basic_EditKeywordsReference.asset.meta create mode 100644 Assets/Mods/Basic/References/Basic_ModEditReference.asset create mode 100644 Assets/Mods/Basic/References/Basic_ModEditReference.asset.meta create mode 100644 Assets/Scripts/Mod/EditReferences.meta create mode 100644 Assets/Scripts/Mod/EditReferences/EditKeywordsReference.cs create mode 100644 Assets/Scripts/Mod/EditReferences/EditKeywordsReference.cs.meta create mode 100644 Assets/Scripts/Mod/EditReferences/ModEditReference.cs create mode 100644 Assets/Scripts/Mod/EditReferences/ModEditReference.cs.meta diff --git a/.gitignore b/.gitignore index 22e7db62..eb5f0d49 100644 --- a/.gitignore +++ b/.gitignore @@ -63,6 +63,9 @@ sysinfo.txt *.unitypackage.meta *.app +#UMod files +*.umod + # Crashlytics generated file crashlytics-build.properties diff --git a/Assets/ExportedMods/Basic.umod b/Assets/ExportedMods/Basic.umod index d852d11b..83ba130c 100644 --- a/Assets/ExportedMods/Basic.umod +++ b/Assets/ExportedMods/Basic.umod @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:39d88e90dbb11efee3ca5e4f4a7481bd74f431b18f6db3355d14e58ed3f96e0a -size 475934421 +oid sha256:d86bc6fd5a9d75f4809195e63520072cd83c20e817c1430a192956d56cf56034 +size 475961539 diff --git a/Assets/Mods/Basic/Cards/Data/General/Attack/CardData_Basic_DualStrike.asset b/Assets/Mods/Basic/Cards/Data/General/Attack/CardData_Basic_DualStrike.asset index d34ea493..e56d16cd 100644 --- a/Assets/Mods/Basic/Cards/Data/General/Attack/CardData_Basic_DualStrike.asset +++ b/Assets/Mods/Basic/Cards/Data/General/Attack/CardData_Basic_DualStrike.asset @@ -17,8 +17,10 @@ MonoBehaviour: displayName: Card_Basic_DualStrike_DisplayName cardRarity: 10 cardType: 0 - tags: [] + keywords: + - Strike cardSprite: {fileID: 21300000, guid: b5ebf255ba7f19543b7faea59e86ea77, type: 3} + cardLayoutTags: [] functionText: Card_Basic_DualStrike_FunctionText cardDescription: '$Keyword("Strike"), deal $Attribute("Damage") damage twice. ' baseWeight: 1 diff --git a/Assets/Mods/Basic/Cards/Data/General/Attack/CardData_Basic_Strike.asset b/Assets/Mods/Basic/Cards/Data/General/Attack/CardData_Basic_Strike.asset index 96fa63a8..bbf9351f 100644 --- a/Assets/Mods/Basic/Cards/Data/General/Attack/CardData_Basic_Strike.asset +++ b/Assets/Mods/Basic/Cards/Data/General/Attack/CardData_Basic_Strike.asset @@ -17,10 +17,11 @@ MonoBehaviour: displayName: Card_Basic_Strike_DisplayName cardRarity: 10 cardType: 0 - tags: + keywords: + - Strike - TargetEnemies - - Physics cardSprite: {fileID: 21300000, guid: 54336fab907a76a4095ff5607e0b86c8, type: 3} + cardLayoutTags: [] functionText: Card_Basic_Strike_FunctionText cardDescription: Card_Basic_Strike_Description baseWeight: 1 diff --git a/Assets/Mods/Basic/Cards/Data/General/Item/CardData_Basic_HiddenBlade.asset b/Assets/Mods/Basic/Cards/Data/General/Item/CardData_Basic_HiddenBlade.asset index e21156a9..3c6155d0 100644 --- a/Assets/Mods/Basic/Cards/Data/General/Item/CardData_Basic_HiddenBlade.asset +++ b/Assets/Mods/Basic/Cards/Data/General/Item/CardData_Basic_HiddenBlade.asset @@ -17,8 +17,9 @@ MonoBehaviour: displayName: Card_Basic_HiddenBlade_DisplayName cardRarity: 0 cardType: 50 - tags: [] + keywords: [] cardSprite: {fileID: 21300000, guid: 8be7e5378b35956469dceadef0180595, type: 3} + cardLayoutTags: [] functionText: Card_Basic_HiddenBlade_FunctionText cardDescription: $Keyword("Retain"), $Keyword("Exhaust"), $Keyword("Prick"), deal $Attribute("Damage") damage. diff --git a/Assets/Mods/Basic/Cards/Data/General/Skill/CardData_Basic_HolyWaterPreparation.asset b/Assets/Mods/Basic/Cards/Data/General/Skill/CardData_Basic_HolyWaterPreparation.asset index 59437e32..b59ff326 100644 --- a/Assets/Mods/Basic/Cards/Data/General/Skill/CardData_Basic_HolyWaterPreparation.asset +++ b/Assets/Mods/Basic/Cards/Data/General/Skill/CardData_Basic_HolyWaterPreparation.asset @@ -44,6 +44,5 @@ MonoBehaviour: upgradeCards: [] customDescriptions: [] prefabRefs: [] - derivativeCardDataRefs: - - CardData_Basic_HolyWaterPreparation + derivativeCardDataRefs: [] derivativeCharacterDataRefs: [] diff --git a/Assets/Mods/Basic/Cards/Scripts/General/Cohesion.cs b/Assets/Mods/Basic/Cards/Scripts/General/Cohesion.cs index c5d16971..b4030d21 100644 --- a/Assets/Mods/Basic/Cards/Scripts/General/Cohesion.cs +++ b/Assets/Mods/Basic/Cards/Scripts/General/Cohesion.cs @@ -35,6 +35,7 @@ namespace Continentis.Mods.Basic.Cards private void SelectEffect(CardInstance card) { card.cardLogic.ModifyAttribute("StaminaCost", -1); + card.cardLogic.contentSubmodule.keywords.Add("Retain"); card.cardLogic.contentSubmodule.originalFunctionText += " + $Keyword(\"Retain\")"; CardTextInterpreter.InterpretText(card.cardLogic, true); card.handCardView.Setup(); diff --git a/Assets/Mods/Basic/Cards/Scripts/General/FightingInspiration.cs b/Assets/Mods/Basic/Cards/Scripts/General/FightingInspiration.cs index 9ddfeebb..78fd6e4b 100644 --- a/Assets/Mods/Basic/Cards/Scripts/General/FightingInspiration.cs +++ b/Assets/Mods/Basic/Cards/Scripts/General/FightingInspiration.cs @@ -34,7 +34,7 @@ namespace Continentis.Mods.Basic.Cards private bool CardFilter(CardData cardData) { - return cardData.cardType == CardType.Attack && cardData.HasTag("Physics"); + return cardData.cardType == CardType.Attack && cardData.HasKeyword("Physics"); } } } \ No newline at end of file diff --git a/Assets/Mods/Basic/Cards/Scripts/General/HolyWaterPreparation.cs b/Assets/Mods/Basic/Cards/Scripts/General/HolyWaterPreparation.cs index b6ab8cb1..a4749290 100644 --- a/Assets/Mods/Basic/Cards/Scripts/General/HolyWaterPreparation.cs +++ b/Assets/Mods/Basic/Cards/Scripts/General/HolyWaterPreparation.cs @@ -24,7 +24,7 @@ namespace Continentis.Mods.Basic.Cards mainGroup.AddCommand(new Cmd_PlayAnimation(user.characterView, "Skill")); mainGroup.AddCommand(new Cmd_Function(() => { - CardData holyWaterCardData = LogicComponent().GetDerivativeCardData(0); + CardData holyWaterCardData = GetDerivativeCardData(0); CardInstance.GenerateCardInstance(holyWaterCardData, user.team, "Hand"); })); diff --git a/Assets/Mods/Basic/Cards/Scripts/General/Strike.cs b/Assets/Mods/Basic/Cards/Scripts/General/Strike.cs index 8d2ed24e..0e609164 100644 --- a/Assets/Mods/Basic/Cards/Scripts/General/Strike.cs +++ b/Assets/Mods/Basic/Cards/Scripts/General/Strike.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using Continentis.MainGame.Card; using Continentis.MainGame.Character; using Continentis.MainGame.Commands; @@ -14,18 +15,22 @@ namespace Continentis.Mods.Basic.Cards { AddLogicComponent(); } - + protected override CommandBase PlayEffect(List targetList) { CommandGroup mainGroup = TargetListCommandGroup(targetList, new Cmd_PlayAnimation(user.characterView, "Attack"), new Cmd_PlaySFX("SFX_Basic_SwordStrike"), - new Cmd_SpawnVFX("VFX_Basic_RedImpact"), - new Cmd_ParamFunction(target => user.Attack(target, GetFinalDamage(target)))); + new Cmd_SpawnVFX("VFX_Basic_RedImpact")); + + foreach (Cmd_PlayAnimation cmd in mainGroup.GetAllCommands()) + { + cmd.AddAction(0.7f, "Target", target => user.Attack(target, GetFinalDamage(target))); + } return mainGroup; } - + public override void ApplyAttributeChangesByCard() { LogicComponent().SetDamage_Strike(); diff --git a/Assets/Mods/Basic/Characters/CharacterViews/Animations/Attack.anim b/Assets/Mods/Basic/Characters/CharacterViews/Animations/Attack.anim index e935024e..9deffec9 100644 --- a/Assets/Mods/Basic/Characters/CharacterViews/Animations/Attack.anim +++ b/Assets/Mods/Basic/Characters/CharacterViews/Animations/Attack.anim @@ -17,27 +17,6 @@ AnimationClip: m_PositionCurves: [] m_ScaleCurves: [] m_FloatCurves: - - serializedVersion: 2 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: Infinity - outSlope: Infinity - tangentMode: 103 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: m_IsActive - path: Body/Firearm - classID: 1 - script: {fileID: 0} - flags: 16 - serializedVersion: 2 curve: serializedVersion: 2 @@ -103,15 +82,6 @@ AnimationClip: m_Extent: {x: 0, y: 0, z: 0} m_ClipBindingConstant: genericBindings: - - serializedVersion: 2 - path: 539894089 - attribute: 2086281974 - script: {fileID: 0} - typeID: 1 - customType: 0 - isPPtrCurve: 0 - isIntCurve: 0 - isSerializeReferenceCurve: 0 - serializedVersion: 2 path: 2073732236 attribute: 3843704414 @@ -143,27 +113,6 @@ AnimationClip: m_HeightFromFeet: 0 m_Mirror: 0 m_EditorCurves: - - serializedVersion: 2 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: Infinity - outSlope: Infinity - tangentMode: 103 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: m_IsActive - path: Body/Firearm - classID: 1 - script: {fileID: 0} - flags: 16 - serializedVersion: 2 curve: serializedVersion: 2 diff --git a/Assets/Mods/Basic/Characters/CharacterViews/Animations/Idle.anim b/Assets/Mods/Basic/Characters/CharacterViews/Animations/Idle.anim index 556af772..4176b61a 100644 --- a/Assets/Mods/Basic/Characters/CharacterViews/Animations/Idle.anim +++ b/Assets/Mods/Basic/Characters/CharacterViews/Animations/Idle.anim @@ -7,7 +7,7 @@ AnimationClip: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_Name: Idle - serializedVersion: 6 + serializedVersion: 7 m_Legacy: 0 m_Compressed: 0 m_UseHighQualityCurve: 1 @@ -17,26 +17,8 @@ AnimationClip: m_PositionCurves: [] m_ScaleCurves: [] m_FloatCurves: - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: Infinity - outSlope: Infinity - tangentMode: 103 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: m_IsActive - path: Body/Firearm - classID: 1 - script: {fileID: 0} - - curve: + - serializedVersion: 2 + curve: serializedVersion: 2 m_Curve: - serializedVersion: 3 @@ -73,6 +55,7 @@ AnimationClip: path: Body classID: 114 script: {fileID: 11500000, guid: ed8b1ae4e4e52b34ea557c1c11e076fc, type: 3} + flags: 16 m_PPtrCurves: [] m_SampleRate: 60 m_WrapMode: 0 @@ -81,13 +64,6 @@ AnimationClip: m_Extent: {x: 0, y: 0, z: 0} m_ClipBindingConstant: genericBindings: - - serializedVersion: 2 - path: 713069421 - attribute: 2086281974 - script: {fileID: 0} - typeID: 1 - customType: 0 - isPPtrCurve: 0 - serializedVersion: 2 path: 2073732236 attribute: 1181594048 @@ -95,6 +71,8 @@ AnimationClip: typeID: 114 customType: 0 isPPtrCurve: 0 + isIntCurve: 0 + isSerializeReferenceCurve: 0 pptrCurveMapping: [] m_AnimationClipSettings: serializedVersion: 2 @@ -117,26 +95,8 @@ AnimationClip: m_HeightFromFeet: 0 m_Mirror: 0 m_EditorCurves: - - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: Infinity - outSlope: Infinity - tangentMode: 103 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: m_IsActive - path: Body/Firearm - classID: 1 - script: {fileID: 0} - - curve: + - serializedVersion: 2 + curve: serializedVersion: 2 m_Curve: - serializedVersion: 3 @@ -173,6 +133,7 @@ AnimationClip: path: Body classID: 114 script: {fileID: 11500000, guid: ed8b1ae4e4e52b34ea557c1c11e076fc, type: 3} + flags: 16 m_EulerEditorCurves: [] m_HasGenericRootTransform: 0 m_HasMotionFloatCurves: 0 diff --git a/Assets/Mods/Basic/Characters/CharacterViews/Animations/Skill.anim b/Assets/Mods/Basic/Characters/CharacterViews/Animations/Skill.anim index bc824bbc..c3eb3e84 100644 --- a/Assets/Mods/Basic/Characters/CharacterViews/Animations/Skill.anim +++ b/Assets/Mods/Basic/Characters/CharacterViews/Animations/Skill.anim @@ -17,27 +17,6 @@ AnimationClip: m_PositionCurves: [] m_ScaleCurves: [] m_FloatCurves: - - serializedVersion: 2 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: Infinity - outSlope: Infinity - tangentMode: 103 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: m_IsActive - path: Body/Firearm - classID: 1 - script: {fileID: 0} - flags: 16 - serializedVersion: 2 curve: serializedVersion: 2 @@ -94,15 +73,6 @@ AnimationClip: m_Extent: {x: 0, y: 0, z: 0} m_ClipBindingConstant: genericBindings: - - serializedVersion: 2 - path: 539894089 - attribute: 2086281974 - script: {fileID: 0} - typeID: 1 - customType: 0 - isPPtrCurve: 0 - isIntCurve: 0 - isSerializeReferenceCurve: 0 - serializedVersion: 2 path: 2073732236 attribute: 1181594048 @@ -134,27 +104,6 @@ AnimationClip: m_HeightFromFeet: 0 m_Mirror: 0 m_EditorCurves: - - serializedVersion: 2 - curve: - serializedVersion: 2 - m_Curve: - - serializedVersion: 3 - time: 0 - value: 0 - inSlope: Infinity - outSlope: Infinity - tangentMode: 103 - weightedMode: 0 - inWeight: 0 - outWeight: 0 - m_PreInfinity: 2 - m_PostInfinity: 2 - m_RotationOrder: 4 - attribute: m_IsActive - path: Body/Firearm - classID: 1 - script: {fileID: 0} - flags: 16 - serializedVersion: 2 curve: serializedVersion: 2 diff --git a/Assets/Mods/Basic/Characters/CharacterViews/CombatViews/MarshalOfTheUnderworld.prefab b/Assets/Mods/Basic/Characters/CharacterViews/CombatViews/MarshalOfTheUnderworld.prefab index db595dc0..2bbe8e6b 100644 --- a/Assets/Mods/Basic/Characters/CharacterViews/CombatViews/MarshalOfTheUnderworld.prefab +++ b/Assets/Mods/Basic/Characters/CharacterViews/CombatViews/MarshalOfTheUnderworld.prefab @@ -455,7 +455,7 @@ SpriteRenderer: m_SortingLayerID: 0 m_SortingLayer: 0 m_SortingOrder: 0 - m_Sprite: {fileID: 6991849013916550155, guid: 671c5c2c0a10455c9c046b8e8e5011a7, type: 3} + m_Sprite: {fileID: 4723107735738678597, guid: 671c5c2c0a10455c9c046b8e8e5011a7, type: 3} m_Color: {r: 1, g: 1, b: 1, a: 1} m_FlipX: 0 m_FlipY: 0 @@ -495,7 +495,7 @@ MonoBehaviour: m_CategoryHash: 9.365925e-16 m_labelHash: 0.00000040954276 m_SpriteKey: 8.913528e-15 - m_SpriteHash: 673223268 + m_SpriteHash: 288431053 --- !u!1 &4492774868295366629 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/Mods/Basic/Characters/CharacterViews/Controller.controller b/Assets/Mods/Basic/Characters/CharacterViews/Controller.controller index daf12ceb..e744bb8a 100644 --- a/Assets/Mods/Basic/Characters/CharacterViews/Controller.controller +++ b/Assets/Mods/Basic/Characters/CharacterViews/Controller.controller @@ -423,7 +423,7 @@ AnimatorStateMachine: m_StateMachineTransitions: {} m_StateMachineBehaviours: [] m_AnyStatePosition: {x: 0, y: 250, z: 0} - m_EntryPosition: {x: 0, y: -140, z: 0} + m_EntryPosition: {x: -120, y: -140, z: 0} m_ExitPosition: {x: 0, y: 290, z: 0} m_ParentStateMachinePosition: {x: 800, y: 20, z: 0} m_DefaultState: {fileID: 6342953676309033787} diff --git a/Assets/Mods/Basic/Characters/CombatBuffs/General/Protecting.cs b/Assets/Mods/Basic/Characters/CombatBuffs/General/Protecting.cs index ba37af4f..7c63a42c 100644 --- a/Assets/Mods/Basic/Characters/CombatBuffs/General/Protecting.cs +++ b/Assets/Mods/Basic/Characters/CombatBuffs/General/Protecting.cs @@ -25,7 +25,7 @@ namespace Continentis.Mods.Basic.Buffs .AddParameterGetter("Target", () => target.data.displayName);//TODO: 以后增加角色的ContentSubmodule this.iconSubmodule = new IconSubmodule(this).SetTextFunctions("Count"); - + this.combatRoundTimeSubmodule = new CountSubmodule(this, actionCount); this.eventSubmodule = new EventSubmodule(this); diff --git a/Assets/Mods/Basic/References.meta b/Assets/Mods/Basic/References.meta new file mode 100644 index 00000000..9e2c56a3 --- /dev/null +++ b/Assets/Mods/Basic/References.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3da21070bbc4b3142a117111283c301f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mods/Basic/References/Basic_EditKeywordsReference.asset b/Assets/Mods/Basic/References/Basic_EditKeywordsReference.asset new file mode 100644 index 00000000..8d3449ea --- /dev/null +++ b/Assets/Mods/Basic/References/Basic_EditKeywordsReference.asset @@ -0,0 +1,93 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 634ae9a7ace35674aac295f34a73f088, type: 3} + m_Name: Basic_EditKeywordsReference + m_EditorClassIdentifier: GameAPI::Continentis.Mods.EditKeywordsReference + keywordRefs: + dictionaryList: + - Key: TargetSelf + Value: + index: 0 + isKeyDuplicated: 0 + - Key: TargetEnemies + Value: + index: 1 + isKeyDuplicated: 0 + - Key: TargetAllies + Value: + index: 2 + isKeyDuplicated: 0 + - Key: TargetAll + Value: + index: 3 + isKeyDuplicated: 0 + - Key: Strike + Value: + index: 4 + isKeyDuplicated: 0 + - Key: Prick + Value: + index: 5 + isKeyDuplicated: 0 + - Key: Slash + Value: + index: 6 + isKeyDuplicated: 0 + - Key: Arcane + Value: + index: 7 + isKeyDuplicated: 0 + - Key: Sorcery + Value: + index: 8 + isKeyDuplicated: 0 + - Key: Swiftness + Value: + index: 9 + isKeyDuplicated: 0 + - Key: Fortitude + Value: + index: 10 + isKeyDuplicated: 0 + - Key: Prediction + Value: + index: 11 + isKeyDuplicated: 0 + - Key: Exhaust + Value: + index: 12 + isKeyDuplicated: 0 + - Key: Instant + Value: + index: 13 + isKeyDuplicated: 0 + - Key: Unplayable + Value: + index: 14 + isKeyDuplicated: 0 + - Key: Innate + Value: + index: 15 + isKeyDuplicated: 0 + - Key: Tardy + Value: + index: 16 + isKeyDuplicated: 0 + - Key: Retain + Value: + index: 17 + isKeyDuplicated: 0 + - Key: Ethereal + Value: + index: 18 + isKeyDuplicated: 0 + dividerPosProp: 0.3 diff --git a/Assets/Mods/Basic/References/Basic_EditKeywordsReference.asset.meta b/Assets/Mods/Basic/References/Basic_EditKeywordsReference.asset.meta new file mode 100644 index 00000000..296a740b --- /dev/null +++ b/Assets/Mods/Basic/References/Basic_EditKeywordsReference.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: af4030fdce3a4774b90f808d1a3bced8 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mods/Basic/References/Basic_ModEditReference.asset b/Assets/Mods/Basic/References/Basic_ModEditReference.asset new file mode 100644 index 00000000..27cff415 --- /dev/null +++ b/Assets/Mods/Basic/References/Basic_ModEditReference.asset @@ -0,0 +1,15 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: afb8fcbb8d897e449a135120c7516dbd, type: 3} + m_Name: Basic_ModEditReference + m_EditorClassIdentifier: GameAPI::Continentis.Mods.ModEditReference + cardKeywordsReference: {fileID: 11400000, guid: af4030fdce3a4774b90f808d1a3bced8, type: 2} diff --git a/Assets/Mods/Basic/References/Basic_ModEditReference.asset.meta b/Assets/Mods/Basic/References/Basic_ModEditReference.asset.meta new file mode 100644 index 00000000..3603d648 --- /dev/null +++ b/Assets/Mods/Basic/References/Basic_ModEditReference.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: eca19f3199465f448830fa0e3ff71dc6 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/MainGame/Base/Interpreters/BuffTextInterpreter.cs b/Assets/Scripts/MainGame/Base/Interpreters/BuffTextInterpreter.cs index b7a3673c..2914d717 100644 --- a/Assets/Scripts/MainGame/Base/Interpreters/BuffTextInterpreter.cs +++ b/Assets/Scripts/MainGame/Base/Interpreters/BuffTextInterpreter.cs @@ -13,12 +13,7 @@ namespace Continentis.MainGame static BuffTextInterpreter() { TextInterpreter = new Interpreter(); - TextInterpreter.SetFunction("Value", new Func((cv) => DynamicTextInterpreter.GetValue(cv, false))); - TextInterpreter.SetFunction("Value", new Func((cv, bv) => DynamicTextInterpreter.GetValue(cv, bv, true, false))); - TextInterpreter.SetFunction("Value", - new Func((cv, bv, high) => DynamicTextInterpreter.GetValue(cv, bv, high, false))); - TextInterpreter.SetFunction("Value", - new Func((cv, bv, high, percent) => DynamicTextInterpreter.GetValue(cv, bv, high, percent))); + DynamicTextInterpreter.InitializeInterpreter(ref TextInterpreter); foreach (KeyValuePair keyword in MainGameManager.Instance.keywordData.interpretedKeywords) { @@ -34,7 +29,7 @@ namespace Continentis.MainGame TextInterpreter.SetFunction("ParameterFloat", new Func((paramName) => GetParameterFloat(buff, paramName))); TextInterpreter.SetFunction("ParameterString", new Func((paramName) => GetParameterString(buff, paramName))); string descriptionToParse = buff.contentSubmodule.originalFunctionText; - string result = DynamicTextInterpreter.Parse(TextInterpreter, descriptionToParse, new List(), new List()); + string result = DynamicTextInterpreter.Parse(TextInterpreter, descriptionToParse); buff.contentSubmodule.interpretedFunctionText = result; } } diff --git a/Assets/Scripts/MainGame/Base/Interpreters/CardTextInterpreter.cs b/Assets/Scripts/MainGame/Base/Interpreters/CardTextInterpreter.cs index b721883f..0d26c4dc 100644 --- a/Assets/Scripts/MainGame/Base/Interpreters/CardTextInterpreter.cs +++ b/Assets/Scripts/MainGame/Base/Interpreters/CardTextInterpreter.cs @@ -13,11 +13,7 @@ namespace Continentis.MainGame static CardTextInterpreter() { TextInterpreter = new Interpreter(); - - TextInterpreter.SetFunction("Value", new Func((cv) => DynamicTextInterpreter.GetValue(cv, false))); - TextInterpreter.SetFunction("Value", new Func((cv, bv) => DynamicTextInterpreter.GetValue(cv, bv, true, false))); - TextInterpreter.SetFunction("Value", new Func((cv, bv, high) => DynamicTextInterpreter.GetValue(cv, bv, high, false))); - TextInterpreter.SetFunction("Value", new Func((cv, bv, high, percent) => DynamicTextInterpreter.GetValue(cv, bv, high, percent))); + DynamicTextInterpreter.InitializeInterpreter(ref TextInterpreter); foreach (KeyValuePair keyword in MainGameManager.Instance.keywordData.interpretedKeywords) { @@ -27,7 +23,7 @@ namespace Continentis.MainGame public static void InterpretText(CardLogicBase card, bool overrideDescription = false) { - card.contentSubmodule.keywords.Clear(); + //card.contentSubmodule.keywords.Clear(); foreach (KeyValuePair attribute in card.attributeSubmodule.attributeGroup.current) { @@ -40,7 +36,7 @@ namespace Continentis.MainGame TextInterpreter.SetFunction("Attribute", new Func((name, high, percent) => GetAttribute(card, name, high, percent))); string descriptionToParse = card.contentSubmodule.originalFunctionText; - string result = DynamicTextInterpreter.Parse(TextInterpreter, descriptionToParse, card.contentSubmodule.keywords, card.contentSubmodule.hintKeywords); + string result = DynamicTextInterpreter.Parse(TextInterpreter, descriptionToParse); card.contentSubmodule.interpretedFunctionText = result; diff --git a/Assets/Scripts/MainGame/Base/Interpreters/DynamicTextInterpreter.cs b/Assets/Scripts/MainGame/Base/Interpreters/DynamicTextInterpreter.cs index 34f1b99e..8187fc33 100644 --- a/Assets/Scripts/MainGame/Base/Interpreters/DynamicTextInterpreter.cs +++ b/Assets/Scripts/MainGame/Base/Interpreters/DynamicTextInterpreter.cs @@ -9,19 +9,34 @@ namespace Continentis.MainGame { public partial class DynamicTextInterpreter { - public static string Parse(Interpreter interpreter, string template, List keywords, List hintKeywords) + public static void InitializeInterpreter(ref Interpreter interpreter) { - interpreter.UnsetFunction("Keyword"); - interpreter.SetFunction("Keyword", new Func(kw => SetKeyword(ref keywords, kw, "#FFA500"))); - interpreter.UnsetFunction("HintKeyword"); - interpreter.SetFunction("HintKeyword", new Func(kw => SetKeyword(ref hintKeywords, kw, "#FFA500"))); - interpreter.SetFunction("HintKeyword", new Func((kw, colorHex) => SetKeyword(ref hintKeywords, kw, colorHex))); - interpreter.UnsetFunction("DescKeyword"); + interpreter.SetFunction("Keyword", new Func(kw => SetKeyword(kw, "#FFA500"))); + interpreter.SetFunction("HintKeyword", new Func(kw => SetKeyword(kw, "#FFA500"))); + interpreter.SetFunction("HintKeyword", new Func(SetKeyword)); interpreter.SetFunction("DescKeyword", new Func(kw =>DescKeyword(kw, "#FFA500"))); interpreter.SetFunction("DescKeyword", new Func(DescKeyword)); - interpreter.UnsetFunction("ColorText"); interpreter.SetFunction("ColorText", new Func(ColorText)); + + interpreter.SetFunction("Value", new Func((cv) => GetValue(cv, false))); + interpreter.SetFunction("Value", new Func((cv, bv) => GetValue(cv, bv, true, false))); + interpreter.SetFunction("Value", new Func((cv, bv, high) => GetValue(cv, bv, high, false))); + interpreter.SetFunction("Value", new Func((cv, bv, high, percent) => GetValue(cv, bv, high, percent))); + + //本地函数,用于添加关键词到集合中并返回格式化后的关键词字符串 + string SetKeyword(string keyword, string colorHex) + { + if (!string.IsNullOrEmpty(keyword)) + { + return Keyword(keyword, colorHex); + } + return string.Empty; + } + } + + public static string Parse(Interpreter interpreter, string template) + { try { while (template.Contains("$")) @@ -49,17 +64,6 @@ namespace Continentis.MainGame } return template; - - //本地函数,用于添加关键词到集合中并返回格式化后的关键词字符串 - string SetKeyword(ref List collection, string keyword, string colorHex) - { - if (!string.IsNullOrEmpty(keyword) && !collection.Contains(keyword)) - { - collection.Add(keyword); - } - - return Keyword(keyword, colorHex); - } } private static int FindMatchingClosingParenthesis(string text, int startIndex) diff --git a/Assets/Scripts/MainGame/Card/CardAssistanceFunctions.cs b/Assets/Scripts/MainGame/Card/CardAssistanceFunctions.cs index 4a86551b..f647bd4a 100644 --- a/Assets/Scripts/MainGame/Card/CardAssistanceFunctions.cs +++ b/Assets/Scripts/MainGame/Card/CardAssistanceFunctions.cs @@ -13,15 +13,10 @@ namespace Continentis.MainGame.Card #region Fundamental public partial class CardLogicBase { - public bool HasTag(string tag) + public List GetElementalKeywords(List overrideKeywords = null) { - return tags.Contains(tag); - } - - public List GetElementTags(List tags = null) - { - tags ??= this.tags; - return tags.Filtered((tag) => MainGameManager.Instance.elementTags.Contains(tag)); + overrideKeywords ??= contentSubmodule.keywords; + return overrideKeywords.Filtered(kw => MainGameManager.Instance.elementTags.Contains(kw)); } public bool HasKeyword(string keyword) @@ -95,15 +90,22 @@ namespace Continentis.MainGame.Card { CommandBase clone = template.Clone(); + List allCommands = new List(); + if (clone is CommandGroup group) { - foreach (CommandBase cmd in group.commands) - { - cmd.selfContext.context["Target"] = target; - } - }//TODO: 变成递归 + allCommands.AddRange(group.GetAllCommands(true)); + } + else + { + allCommands.Add(clone); + } + + foreach (CommandBase cmd in allCommands) + { + cmd.selfContext.context["Target"] = target; + } - clone.selfContext.context["Target"] = target; singleGroup.AddCommand(clone); } @@ -132,17 +134,17 @@ namespace Continentis.MainGame.Card protected virtual int GetFinalDamage(CharacterBase target, List elementalTags, out float baseDamageAfterOffset, out float elementalMultiplier, out float magicMultiplier, out float finalMultiplier) { - elementalTags ??= GetElementTags(); + elementalTags ??= GetElementalKeywords(); //----计算基础伤害增量---- int physicsOffset = 0; - if (HasTag("Physics") || HasKeyword("Slash") || HasKeyword("Prick") || HasKeyword("Strike")) + if (HasKeyword("Physics") || HasKeyword("Slash") || HasKeyword("Prick") || HasKeyword("Strike")) { physicsOffset = user.GetAttribute("PhysicsDamageDealtOffset"); //物理伤害基础增量 } int magicOffset = 0; - if (HasTag("Magic") || HasKeyword("Arcane") || HasKeyword("Sorcery")) + if (HasKeyword("Magic") || HasKeyword("Arcane") || HasKeyword("Sorcery")) { magicOffset = user.GetAttribute("MagicDamageDealtOffset"); //魔法伤害基础增量 } @@ -159,7 +161,7 @@ namespace Continentis.MainGame.Card //计算通用的魔法伤害加成 magicMultiplier = 1; - if (HasTag("Magic") || HasKeyword("Arcane") || HasKeyword("Sorcery")) + if (HasKeyword("Magic") || HasKeyword("Arcane") || HasKeyword("Sorcery")) { magicMultiplier = user.GetRawAttribute("MagicDamageDealtMultiplier", 1) * target.GetRawAttribute("MagicDamageGainMultiplier", 1); diff --git a/Assets/Scripts/MainGame/Card/CardData/CardData.cs b/Assets/Scripts/MainGame/Card/CardData/CardData.cs index 3acad5a8..a43784d1 100644 --- a/Assets/Scripts/MainGame/Card/CardData/CardData.cs +++ b/Assets/Scripts/MainGame/Card/CardData/CardData.cs @@ -24,55 +24,47 @@ namespace Continentis.MainGame.Card Curse = 40, Item = 50, } - + [CreateAssetMenu(menuName = "Continentis/MainGame/Card/CardData", fileName = "CardData")] public partial class CardData : ScriptableObject { - [Header("Fundamental")] - public string modName; + [Header("Fundamental")] public string modName; public string className; public string displayName; public Rarity cardRarity; public CardType cardType; - public List tags; - + public List keywords; + public Sprite cardSprite; - + public List cardLayoutTags; + public string functionText; public string cardDescription; - - [Header("Intention")] - public float baseWeight = 1f; - - [Header("Attributes")] - [Tooltip("可变属性,这个属性会自动设置BaseAttr进入Original,设置Attr,BaseAttrOffset=0,以及DisplayAttr进入Current")] + + [Header("Intention")] public float baseWeight = 1f; + + [Header("Attributes")] [Tooltip("可变属性,这个属性会自动设置BaseAttr进入Original,设置Attr,BaseAttrOffset=0,以及DisplayAttr进入Current")] public SerializableDictionary variableAttributes = new SerializableDictionary(); - + [Tooltip("基础属性,不会改变,通常情况下不会直接使用")] public SerializableDictionary originalAttributes = new SerializableDictionary(); - - [FormerlySerializedAs("endowingCurrentAttributes")] [Tooltip("初始化时赋予给CurrentAttributes的属性,第一栏是属性名,第二栏是初始化时使用对应名称的OriginalAttributes的,留空则默认为0,如果是float数字则直接使用该数字")] + + [FormerlySerializedAs("endowingCurrentAttributes")] + [Tooltip("初始化时赋予给CurrentAttributes的属性,第一栏是属性名,第二栏是初始化时使用对应名称的OriginalAttributes的,留空则默认为0,如果是float数字则直接使用该数字")] public SerializableDictionary runtimeCurrentAttributes = new SerializableDictionary(); - [Header("Upgrade")] - public CardUpgradeNode upgradeNode; - - [Header("References")] - public List prefabRefs = new List(); + [Header("Upgrade")] public CardUpgradeNode upgradeNode; + + [Header("References")] public List prefabRefs = new List(); public List derivativeCardDataRefs = new List(); public List derivativeCharacterDataRefs = new List(); } public partial class CardData { - public bool HasTag(string tag) - { - return tags.Contains(tag); - } - public bool HasKeyword(string keyword) { - return functionText.Contains($"$Keyword(\"{keyword}\")"); + return keywords.Contains(keyword); } } @@ -83,10 +75,10 @@ namespace Continentis.MainGame.Card return ModManager.GetData(dataID); } } - + public partial class CardData { - + /// /// 通过索引获取衍生卡牌数据 /// @@ -94,7 +86,7 @@ namespace Continentis.MainGame.Card { return ModManager.GetData(derivativeCardDataRefs[index]); } - + /// /// 通过索引获取衍生角色数据 /// @@ -105,109 +97,4 @@ namespace Continentis.MainGame.Card return ModManager.GetData(derivativeCharacterDataRefs[index]); } } - -#if UNITY_EDITOR - public partial class CardData - {/* - private void SetCardIdentifier() - { - cardIdentifier = cardClass.Name; - - int underscoreIndex = cardClass.Name.IndexOf('_'); - string cardNamePart = cardClass.Name.Substring(underscoreIndex + 1); - string result = Regex.Replace(cardNamePart, "([a-z])([A-Z])", "$1 $2"); - cardName = result; - } - - private void CreateUpgradeNode() - { - upgradeNode = new CardUpgradeNode(this); - } - - private IEnumerable> GetLogicTypes() - { - IEnumerable types = AppDomain.CurrentDomain.GetAssemblies() - .SelectMany(assembly => assembly.GetTypes()) - .Where(t => typeof(CardLogicBase).IsAssignableFrom(t) && !t.IsAbstract && !t.IsInterface); - - // 我们将从命名空间中移除这个公共前缀,让路径更简洁 - string commonNamespacePrefix = "Continentis.Mods"; - - foreach (var type in types) - { - string path = "Uncategorized/" + type.Name; // 默认路径 - - if (type.Namespace != null && type.Namespace.StartsWith(commonNamespacePrefix)) - { - // 1. 移除公共前缀 - string formattedNamespace = type.Namespace.Substring(commonNamespacePrefix.Length); - - // 2. 移除特定的子命名空间部分(例如 "Cards") - formattedNamespace = formattedNamespace.Replace(".Cards", ""); - - // 3. 将点 '.' 替换为斜杠 '/' 来创建分组 - formattedNamespace = formattedNamespace.Replace('.', '/'); - - // 4. 组合成最终的路径 - path = formattedNamespace + "/" + type.Name; - } - - yield return new ValueDropdownItem(path, type); - } - } - - [FoldoutGroup("Functions")] - [Button("从所有的DefaultCollection中粘贴默认属性")] - public void PasteDefaultAttributes() - { - List targetCollections = new List(); - string[] guids = AssetDatabase.FindAssets("t:CardAttributesDefaultCollection"); - - foreach (string guid in guids) - { - // 将GUID转换为资产的路径 - string path = AssetDatabase.GUIDToAssetPath(guid); - - // 2. 验证每个资产的路径是否完全符合您指定的结构 - // 使用 Path.GetDirectoryName 获取文件所在的目录 - // 并统一使用'/'作为路径分隔符,以兼容不同操作系统 - string directory = Path.GetDirectoryName(path)?.Replace('\\', '/'); - Debug.Log($"Checking asset at path: {path}, directory: {directory}"); - - // 加载资产以检查其命名空间 - ScriptableObject collection = AssetDatabase.LoadAssetAtPath(path); - Type assetType = collection.GetType(); - string assetNamespace = assetType.Namespace; - - // 检查目录是否有效,是否在"Assets/Mods/"下,并且是否以"/Characters/DefaultCollections"结尾 - if (!string.IsNullOrEmpty(directory) && - assetNamespace == typeof(CardAttributesDefaultCollection).Namespace && - directory.StartsWith("Assets/Mods/") && - directory.EndsWith("/Cards/DefaultCollections")) - { - // 3. 如果路径和命名空间都符合要求,则将该资产添加到目标列表中 - CardAttributesDefaultCollection defaultList = collection as CardAttributesDefaultCollection; - targetCollections.Add(defaultList); - Debug.Log($"Loaded DefaultStringList from: {path}"); - } - } - - Dictionary variableAttributes = new Dictionary(); - Dictionary originalAttributes = new Dictionary(); - Dictionary endowingCurrentAttributes = new Dictionary(); - - foreach (CardAttributesDefaultCollection collection in targetCollections) - { - collection.variableAttributes.PasteDictionary(variableAttributes); - collection.originalAttributes.PasteDictionary(originalAttributes); - collection.endowingCurrentAttributes.PasteDictionary(endowingCurrentAttributes); - } - - variableAttributes.PasteDictionary(this.variableAttributes); - originalAttributes.PasteDictionary(this.originalAttributes); - endowingCurrentAttributes.PasteDictionary(this.endowingCurrentAttributes); - Debug.Log($"Pasted default attributes to file {this.name}"); - }*/ - } -#endif } \ No newline at end of file diff --git a/Assets/Scripts/MainGame/Card/CardLogicBase.cs b/Assets/Scripts/MainGame/Card/CardLogicBase.cs index c6c5051a..129b2c4c 100644 --- a/Assets/Scripts/MainGame/Card/CardLogicBase.cs +++ b/Assets/Scripts/MainGame/Card/CardLogicBase.cs @@ -23,7 +23,6 @@ namespace Continentis.MainGame.Card [Header("Card Base Info")] public Guid cardID; - public List tags; public int upgradeLevel; [Header("Submodules")] @@ -63,8 +62,7 @@ namespace Continentis.MainGame.Card public void Setup() { this.cardID = Guid.NewGuid(); - - this.tags = new List(cardData.tags); + this.attributeSubmodule = new AttributeSubmodule(this); this.weightSubmodule = new WeightSubmodule(this); this.eventSubmodule = new EventSubmodule(this); @@ -140,6 +138,14 @@ namespace Continentis.MainGame.Card } } + + /// + /// 获取衍生卡牌数据 + /// + public CardData GetDerivativeCardData(int index) + { + return ModManager.GetData(cardData.derivativeCardDataRefs[index]); + } } /// diff --git a/Assets/Scripts/MainGame/Card/CardMainFunctions.cs b/Assets/Scripts/MainGame/Card/CardMainFunctions.cs index da1c05ab..5d12688b 100644 --- a/Assets/Scripts/MainGame/Card/CardMainFunctions.cs +++ b/Assets/Scripts/MainGame/Card/CardMainFunctions.cs @@ -74,13 +74,13 @@ namespace Continentis.MainGame.Card return; } - if (targetCount == 0 || cardData.tags.Contains("TargetSelf")) // 卡牌目标为自身 + if (targetCount == 0 || HasKeyword("TargetSelf")) // 卡牌目标为自身 { valid.Add(user); invalid.AddRange(characters); invalid.Remove(user); } - else if (cardData.tags.Contains("TargetAllies")) // 卡牌目标为友方单位 + else if (HasKeyword("TargetAllies")) // 卡牌目标为友方单位 { if(user.fraction is Fraction.Ally or Fraction.Player) { @@ -111,7 +111,7 @@ namespace Continentis.MainGame.Card } } } - else if (cardData.tags.Contains("TargetEnemies")) // 卡牌目标为敌人 + else if (HasKeyword("TargetEnemies")) // 卡牌目标为敌人 { if (user.fraction is Fraction.Ally or Fraction.Player) { @@ -155,12 +155,13 @@ namespace Continentis.MainGame.Card } } } - else if(cardData.tags.Contains("TargetAll")) // 卡牌目标为全体 + else if(HasKeyword("TargetAll")) // 卡牌目标为全体 { valid.AddRange(characters); } else { + valid.AddRange(characters);// 默认卡牌目标为所有单位 Debug.Log("No valid target found"); } } diff --git a/Assets/Scripts/MainGame/Card/CardSubmodules/ContentSubmodule.cs b/Assets/Scripts/MainGame/Card/CardSubmodules/ContentSubmodule.cs index dd5a0c7f..7c3fb31e 100644 --- a/Assets/Scripts/MainGame/Card/CardSubmodules/ContentSubmodule.cs +++ b/Assets/Scripts/MainGame/Card/CardSubmodules/ContentSubmodule.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using SLSFramework.General; using UnityEngine; @@ -7,7 +8,6 @@ namespace Continentis.MainGame.Card public class ContentSubmodule : SubmoduleBase { public List keywords; - public List hintKeywords; public string cardName; public Sprite cardSprite; @@ -18,8 +18,7 @@ namespace Continentis.MainGame.Card public ContentSubmodule(CardLogicBase card) : base(card) { - keywords = new List(); - hintKeywords = new List(); + keywords = card.cardData.keywords; cardName = card.cardData.displayName.Localize(); cardSprite = card.cardData.cardSprite; originalFunctionText = card.cardData.functionText.Localize(); diff --git a/Assets/Scripts/MainGame/Card/CardView/CardViewBase.cs b/Assets/Scripts/MainGame/Card/CardView/CardViewBase.cs index 512fa020..cb58623f 100644 --- a/Assets/Scripts/MainGame/Card/CardView/CardViewBase.cs +++ b/Assets/Scripts/MainGame/Card/CardView/CardViewBase.cs @@ -59,7 +59,6 @@ namespace Continentis.MainGame.Card List allKeywords = new List(); allKeywords.AddRange(cardLogic.contentSubmodule.keywords); - allKeywords.AddRange(cardLogic.contentSubmodule.hintKeywords); keywordList.Enable(allKeywords); } @@ -99,10 +98,11 @@ namespace Continentis.MainGame.Card if (string.IsNullOrEmpty(collectionName)) collectionName = "Basic"; CardViewCollection collection = MainGameManager.Instance.basePrefabs.cardViewCollections[collectionName]; - List elementTags = cardLogic.GetElementTags(); - string firstElementTag = elementTags.Count > 0 ? elementTags[0] : "Default"; - if (!collection.cardViews.ContainsKey(firstElementTag)) firstElementTag = "Default"; - cardBackground.sprite = collection.cardViews[firstElementTag].background; + + List layoutTags = cardLogic.cardData.cardLayoutTags; //TODO:后续可扩展为动态布局标签 + string firstLayoutTag = layoutTags.Count > 0 ? layoutTags[0] : "Default"; + if (!collection.cardViews.ContainsKey(firstLayoutTag)) firstLayoutTag = "Default"; + cardBackground.sprite = collection.cardViews[firstLayoutTag].background; cardTypeText.text = cardLogic.contentSubmodule.cardType.ToString(); diff --git a/Assets/Scripts/MainGame/Card/CardView/HandCardView/HandCardView_Operations.cs b/Assets/Scripts/MainGame/Card/CardView/HandCardView/HandCardView_Operations.cs index 7274ec52..0cdf21ea 100644 --- a/Assets/Scripts/MainGame/Card/CardView/HandCardView/HandCardView_Operations.cs +++ b/Assets/Scripts/MainGame/Card/CardView/HandCardView/HandCardView_Operations.cs @@ -248,7 +248,7 @@ namespace Continentis.MainGame.Card return; } - if (!cardLogic.HasTag("TargetSelf")) + if (!cardLogic.HasKeyword("TargetSelf")) { if (!validTargets.Contains(hoveringCharacter)) { diff --git a/Assets/Scripts/MainGame/Card/Editor/CardDataEditor.cs b/Assets/Scripts/MainGame/Card/Editor/CardDataEditor.cs index 92bc4a64..ced62bf5 100644 --- a/Assets/Scripts/MainGame/Card/Editor/CardDataEditor.cs +++ b/Assets/Scripts/MainGame/Card/Editor/CardDataEditor.cs @@ -1,14 +1,17 @@ #if UNITY_EDITOR using System; +using System.Collections.Generic; +using System.Linq; using UnityEditor; using UnityEngine; using SLSFramework.UModAssistance; using Continentis.MainGame.Character; +using Continentis.Mods; namespace Continentis.MainGame.Card { [CustomEditor(typeof(CardData))] - public class CardDataEditor : DataEditor + public partial class CardDataEditor : DataEditor { // 存储我们需要自定义绘制的属性的引用 private SerializedProperty modNameProp; @@ -16,9 +19,10 @@ namespace Continentis.MainGame.Card private SerializedProperty displayNameProp; private SerializedProperty cardRarityProp; private SerializedProperty cardTypeProp; - private SerializedProperty tagsProp; + private SerializedProperty keywordsProp; private SerializedProperty cardSpriteProp; + private SerializedProperty cardLayoutTagsProp; private SerializedProperty functionTextProp; private SerializedProperty cardDescriptionProp; @@ -33,19 +37,22 @@ namespace Continentis.MainGame.Card private SerializedProperty prefabsProp; private SerializedProperty derivativeCardsProp; private SerializedProperty derivativeCharactersProp; - + protected override void OnEnable() { base.OnEnable(); + LoadAllKeywordsFromEditRefs(); + // 在启用时,根据我们修改后的字段名找到对应的SerializedProperty modNameProp = serializedObject.FindProperty("modName"); classNameProp = serializedObject.FindProperty("className"); displayNameProp = serializedObject.FindProperty("displayName"); cardRarityProp = serializedObject.FindProperty("cardRarity"); cardTypeProp = serializedObject.FindProperty("cardType"); - tagsProp = serializedObject.FindProperty("tags"); + keywordsProp = serializedObject.FindProperty("keywords"); cardSpriteProp = serializedObject.FindProperty("cardSprite"); + cardLayoutTagsProp = serializedObject.FindProperty("cardLayoutTags"); functionTextProp = serializedObject.FindProperty("functionText"); cardDescriptionProp = serializedObject.FindProperty("cardDescription"); baseWeightProp = serializedObject.FindProperty("baseWeight"); @@ -86,8 +93,14 @@ namespace Continentis.MainGame.Card EditorGUILayout.PropertyField(cardRarityProp); EditorGUILayout.PropertyField(cardTypeProp); - EditorGUILayout.PropertyField(tagsProp, true); + EditorGUILayout.PropertyField(keywordsProp, true); + if (keywordsProp.isExpanded) + { + DrawKeywordSelector(); + } + EditorGUILayout.PropertyField(cardSpriteProp); + EditorGUILayout.PropertyField(cardLayoutTagsProp, true); EditorGUILayout.PropertyField(functionTextProp); EditorGUILayout.PropertyField(cardDescriptionProp); @@ -114,5 +127,106 @@ namespace Continentis.MainGame.Card serializedObject.ApplyModifiedProperties(); } } + + public partial class CardDataEditor + { + private List allAvailableKeywords; + + /// + /// 使用 AssetDatabase 查找项目中的所有 KeywordDatabase 并合并它们的列表 + /// + private void LoadAllKeywordsFromEditRefs() + { + // 使用 HashSet 来自动处理重复的关键词 + HashSet allKeywordsSet = new HashSet(); + + // 1. 查找项目中所有类型为 "KeywordDatabase" 的 + // "t:KeywordDatabase" 是一个搜索过滤器,t: 表示按类型搜索 + string[] guids = AssetDatabase.FindAssets("t:ModEditReference"); + + foreach (string guid in guids) + { + // 2. 将 GUID 转换为资产路径 + string assetPath = AssetDatabase.GUIDToAssetPath(guid); + + // 3. 加载该路径下的 ScriptableObject + ModEditReference editRef = AssetDatabase.LoadAssetAtPath(assetPath); + EditKeywordsReference cardKeywordsRef = editRef.cardKeywordsReference; + + if (cardKeywordsRef != null && cardKeywordsRef.keywordRefs != null) + { + // 4. 将词库中的所有词添加到 Set 中 + foreach (string keyword in cardKeywordsRef.keywordRefs.Keys) + { + if (!string.IsNullOrEmpty(keyword)) + { + allKeywordsSet.Add(keyword); + } + } + } + } + + // 5. 将 Set 转换为 List 并排序,以便在菜单中清晰显示 + allAvailableKeywords = allKeywordsSet.ToList(); + allAvailableKeywords.Sort(); + } + + private void DrawKeywordSelector() + { + // 1. 检查是否找到了任何关键词 + if (allAvailableKeywords == null || allAvailableKeywords.Count == 0) + { + EditorGUILayout.HelpBox("在项目中没有找到任何 KeywordDatabase,或者词库为空。", MessageType.Warning); + // 显示一个刷新按钮,以防用户刚刚创建了词库 + if (GUILayout.Button("Refresh Keyword Edit References")) + { + LoadAllKeywordsFromEditRefs(); + } + return; + } + + List currentKeywords = (target as CardData)!.keywords; + + // 2. 找出尚未添加的关键词 + List keywordsToAdd = allAvailableKeywords.Except(currentKeywords).ToList(); + + // 3. 如果所有关键词都添加了,显示提示 + if (keywordsToAdd.Count == 0) + { + EditorGUILayout.HelpBox("所有可用的关键词都已添加。", MessageType.Info); + } + else + { + // 4. 绘制 "Add Keyword" 按钮 + if (GUILayout.Button("Add Keyword from Edit Refs...")) + { + GenericMenu menu = new GenericMenu(); + foreach (string keyword in keywordsToAdd) + { + menu.AddItem(new GUIContent(keyword), false, () => { + AddKeywordToList(keyword); + }); + } + menu.ShowAsContext(); + } + } + + // 5. (可选) 添加一个手动刷新按钮 + // 因为 AssetDatabase.FindAssets() 速度很快,所以我们也可以在每次GUI绘制时都调用 + // 但如果词库很多,使用按钮刷新更好。 + /*if (GUILayout.Button("Refresh Keyword Databases")) + { + LoadAllKeywordsFromEditRefs(); + }*/ + } + + private void AddKeywordToList(string keyword) + { + keywordsProp.InsertArrayElementAtIndex(keywordsProp.arraySize); + SerializedProperty newElement = keywordsProp.GetArrayElementAtIndex(keywordsProp.arraySize - 1); + newElement.stringValue = keyword; + serializedObject.ApplyModifiedProperties(); + } + } } #endif \ No newline at end of file diff --git a/Assets/Scripts/MainGame/Card/LogicComponents/CardLogicComponent_GenerateCards.cs b/Assets/Scripts/MainGame/Card/LogicComponents/CardLogicComponent_GenerateCards.cs index a21955c9..c37caa0e 100644 --- a/Assets/Scripts/MainGame/Card/LogicComponents/CardLogicComponent_GenerateCards.cs +++ b/Assets/Scripts/MainGame/Card/LogicComponents/CardLogicComponent_GenerateCards.cs @@ -15,7 +15,7 @@ namespace Continentis.Mods.Basic.Cards public override void Initialize(CardLogicBase card) { base.Initialize(card); - cardFilter = cardData => !cardData.HasTag("Unobtainable"); + cardFilter = cardData => !cardData.HasKeyword("Unobtainable"); } /// @@ -24,18 +24,10 @@ namespace Continentis.Mods.Basic.Cards public void SetFilter(Func filter) { List> originalFilters = new List>(); - originalFilters.Add(cardData => !cardData.HasTag("Unobtainable")); + originalFilters.Add(cardData => !cardData.HasKeyword("Unobtainable")); if (filter != null) originalFilters.Add(filter); this.cardFilter = cardData => originalFilters.All(f => f(cardData)); } - - /// - /// 获取衍生卡牌数据 - /// - public CardData GetDerivativeCardData(int index) - { - return card.cardData.GetDerivativeCardData(index); - } /// /// 从指定的cardDataID中,根据needFilter决定是否进行过滤,获取符合条件的卡牌数据列表 diff --git a/Assets/Scripts/MainGame/Commands/Cmd_PlayAnimation.cs b/Assets/Scripts/MainGame/Commands/Cmd_PlayAnimation.cs index beca4f25..fb803a89 100644 --- a/Assets/Scripts/MainGame/Commands/Cmd_PlayAnimation.cs +++ b/Assets/Scripts/MainGame/Commands/Cmd_PlayAnimation.cs @@ -1,8 +1,11 @@ using System; +using System.Collections.Generic; +using System.Linq; using Continentis.MainGame.Character; using SLSFramework.General; using UniRx; using UnityEngine; +using UnityEngine.Events; namespace Continentis.MainGame.Commands { @@ -14,6 +17,11 @@ namespace Continentis.MainGame.Commands private float overrideDuration; private string stateName; private int layer; + + //在动画的normalizedTime执行函数 + private AnimationClip clip; + private float clipScaledLength => clip.length / animator.speed; + private Dictionary animationActions; public Cmd_PlayAnimation(CombatCharacterViewBase characterView, string stateName, bool waitForFinish = false, float overrideDuration = -1, int layer = 0) : base(null) @@ -21,9 +29,36 @@ namespace Continentis.MainGame.Commands this.characterView = characterView; this.animator = characterView.animator; this.stateName = stateName; + this.clip = characterView.animationClips[stateName]; this.waitForFinish = waitForFinish; this.overrideDuration = overrideDuration; this.layer = layer; + this.animationActions = new Dictionary(); + } + + public Cmd_PlayAnimation AddAction(float normalizedDuration, Action action) + { + animationActions[normalizedDuration] = action; + return this; + } + + public Cmd_PlayAnimation AddAction(int frame, Action action) + { + float normalizedDuration = frame / (clip.frameRate * clip.length); + return AddAction(normalizedDuration, action); + } + + public Cmd_PlayAnimation AddAction(float normalizedDuration, string selfContextKey, Action action) + { + T param = selfContext.GetInfo(selfContextKey); + animationActions[normalizedDuration] = () => action(param); + return this; + } + + public Cmd_PlayAnimation AddAction(int frame, string selfContextKey, Action action) + { + float normalizedDuration = frame / (clip.frameRate * clip.length); + return AddAction(normalizedDuration, selfContextKey, action); } protected override IObservable OnExecute(CommandContext outerContext) @@ -47,6 +82,24 @@ namespace Continentis.MainGame.Commands } animator.CrossFade(stateName, 0f, layer, 0f); + + //监听动画进度以执行函数,独立Observable + if (animationActions.Count > 0) + { + Observable.EveryUpdate().TakeUntil(Observable.Timer(TimeSpan.FromSeconds(clipScaledLength))).Subscribe(_ => + { + float normalizedTime = animator.GetCurrentAnimatorStateInfo(layer).normalizedTime % 1f; + foreach (var kvp in animationActions.ToList()) + { + if (normalizedTime >= kvp.Key) + { + kvp.Value?.Invoke(); + animationActions.Remove(kvp.Key); //确保只执行一次 + } + } + }); + } + if (waitForFinish) { float animationDuration = overrideDuration >= 0 ? overrideDuration : characterView.animationClips[stateName].length; diff --git a/Assets/Scripts/Mod/EditReferences.meta b/Assets/Scripts/Mod/EditReferences.meta new file mode 100644 index 00000000..9fcf75a0 --- /dev/null +++ b/Assets/Scripts/Mod/EditReferences.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9510942ad8df1f7418b4474e196ce728 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Mod/EditReferences/EditKeywordsReference.cs b/Assets/Scripts/Mod/EditReferences/EditKeywordsReference.cs new file mode 100644 index 00000000..0c64a8ea --- /dev/null +++ b/Assets/Scripts/Mod/EditReferences/EditKeywordsReference.cs @@ -0,0 +1,12 @@ +using SLSFramework.General; +using UnityEngine; + +namespace Continentis.Mods +{ + [CreateAssetMenu(fileName = "EditKeywordsReference", menuName = "Continentis/Mod/Edit/Keywords Reference", order = 3)] + public class EditKeywordsReference : ScriptableObject + { + [KeyWidth(0.3f)] + public SerializableDictionary keywordRefs; + } +} \ No newline at end of file diff --git a/Assets/Scripts/Mod/EditReferences/EditKeywordsReference.cs.meta b/Assets/Scripts/Mod/EditReferences/EditKeywordsReference.cs.meta new file mode 100644 index 00000000..c12c0ec2 --- /dev/null +++ b/Assets/Scripts/Mod/EditReferences/EditKeywordsReference.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 634ae9a7ace35674aac295f34a73f088 \ No newline at end of file diff --git a/Assets/Scripts/Mod/EditReferences/ModEditReference.cs b/Assets/Scripts/Mod/EditReferences/ModEditReference.cs new file mode 100644 index 00000000..6d87cee9 --- /dev/null +++ b/Assets/Scripts/Mod/EditReferences/ModEditReference.cs @@ -0,0 +1,12 @@ +using SLSFramework.General; +using UnityEngine; +using UnityEngine.Serialization; + +namespace Continentis.Mods +{ + [CreateAssetMenu(fileName = "ModEditReference", menuName = "Continentis/Mod/Edit Reference", order = 2)] + public class ModEditReference : ScriptableObject + { + [FormerlySerializedAs("keywordsReference")] public EditKeywordsReference cardKeywordsReference; + } +} \ No newline at end of file diff --git a/Assets/Scripts/Mod/EditReferences/ModEditReference.cs.meta b/Assets/Scripts/Mod/EditReferences/ModEditReference.cs.meta new file mode 100644 index 00000000..b0c63c53 --- /dev/null +++ b/Assets/Scripts/Mod/EditReferences/ModEditReference.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: afb8fcbb8d897e449a135120c7516dbd \ No newline at end of file diff --git a/Assets/Scripts/ScriptExtensions/CommandQueue/CommandGroup.cs b/Assets/Scripts/ScriptExtensions/CommandQueue/CommandGroup.cs index a49b038f..9affb846 100644 --- a/Assets/Scripts/ScriptExtensions/CommandQueue/CommandGroup.cs +++ b/Assets/Scripts/ScriptExtensions/CommandQueue/CommandGroup.cs @@ -47,6 +47,46 @@ namespace SLSFramework.General commands.Add(command); return this; } + + /// + /// 获取所有子指令,包含嵌套的指令组中的指令。 + /// + /// 是否也包含CommandGroup,false则不会将CommandGroup返回 + /// + public List GetAllCommands(bool alsoIncludeGroups = false) + { + //CommandBase可能也是CommandGroup,需要递归获取 + List allCommands = new List(); + + if (alsoIncludeGroups) + { + allCommands.Add(this); + } + + foreach (CommandBase cmd in commands) + { + if (cmd is CommandGroup group) + { + if (alsoIncludeGroups) + { + allCommands.Add(group); + } + + allCommands.AddRange(group.GetAllCommands(alsoIncludeGroups)); + } + else + { + allCommands.Add(cmd); + } + } + + return allCommands; + } + + public List GetAllCommands() where T : CommandBase + { + return GetAllCommands(true).OfType().ToList(); + } protected override IObservable OnExecute(CommandContext outerContext) {