Merge remote-tracking branch 'origin/implement_task_UI' into feature/hp_interact_npc

This commit is contained in:
Tungdv
2025-11-18 14:34:58 +07:00
13 changed files with 5863 additions and 524 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,95 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &2014844157387861405
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8395333742829132721}
- component: {fileID: 3685582830533743809}
- component: {fileID: 6404897883559725565}
- component: {fileID: 6445602249794385720}
m_Layer: 5
m_Name: TreeView
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &8395333742829132721
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2014844157387861405}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: -151.28992, y: 336.93002}
m_SizeDelta: {x: 319.58, y: 0}
m_Pivot: {x: 0, y: 1}
--- !u!114 &3685582830533743809
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2014844157387861405}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 8688b7d87bac4c16b9eaa3408f8ea419, type: 3}
m_Name:
m_EditorClassIdentifier:
m_pTreeViewItemPrefab: {fileID: 4314770845850481090, guid: 8752f9e95e4124abfb0d46a2cbe805e4, type: 3}
_currentSelectedItem: {fileID: 0}
m_aTreeViewItems: []
--- !u!114 &6404897883559725565
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2014844157387861405}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 59f8146938fff824cb5fd77236b75775, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Padding:
m_Left: 0
m_Right: 0
m_Top: 0
m_Bottom: 0
m_ChildAlignment: 0
m_Spacing: 0
m_ChildForceExpandWidth: 0
m_ChildForceExpandHeight: 1
m_ChildControlWidth: 0
m_ChildControlHeight: 0
m_ChildScaleWidth: 0
m_ChildScaleHeight: 0
m_ReverseArrangement: 0
--- !u!114 &6445602249794385720
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2014844157387861405}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3}
m_Name:
m_EditorClassIdentifier:
m_HorizontalFit: 0
m_VerticalFit: 2
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 9456de25596014039bd4d0d3927b709a
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -10,6 +10,8 @@ GameObject:
m_Component:
- component: {fileID: 5053903421260846465}
- component: {fileID: 4314770845850481090}
- component: {fileID: 4762263782091224632}
- component: {fileID: 4986645933044111193}
m_Layer: 5
m_Name: TreeViewItem
m_TagString: Untagged
@@ -30,13 +32,12 @@ RectTransform:
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 3882154025378162395}
- {fileID: 5827054231092576763}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 250, y: 80}
m_SizeDelta: {x: 312.2704, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &4314770845850481090
MonoBehaviour:
@@ -52,10 +53,56 @@ MonoBehaviour:
m_EditorClassIdentifier:
m_text: {fileID: 1383932928540251694}
m_Button: {fileID: 1762532130762754577}
_levelSprites:
- {fileID: 21300000, guid: e09a5d2cb3c3f4c858754a1e90a44abd, type: 3}
- {fileID: 21300000, guid: 73873399fec964578b62204f20c40517, type: 3}
_expandButton: {fileID: 1715406348461528812}
_collapseButton: {fileID: 8676942769405651249}
m_uItemData: 0
_treeLevel: 0
OnClick:
m_PersistentCalls:
m_Calls: []
--- !u!114 &4762263782091224632
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 700152255263326765}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 59f8146938fff824cb5fd77236b75775, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Padding:
m_Left: 0
m_Right: 0
m_Top: 0
m_Bottom: 0
m_ChildAlignment: 0
m_Spacing: 0
m_ChildForceExpandWidth: 0
m_ChildForceExpandHeight: 0
m_ChildControlWidth: 0
m_ChildControlHeight: 0
m_ChildScaleWidth: 0
m_ChildScaleHeight: 0
m_ReverseArrangement: 0
--- !u!114 &4986645933044111193
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 700152255263326765}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3}
m_Name:
m_EditorClassIdentifier:
m_HorizontalFit: 0
m_VerticalFit: 2
--- !u!1 &2040002976300010419
GameObject:
m_ObjectHideFlags: 0
@@ -69,7 +116,7 @@ GameObject:
- component: {fileID: 9062463037674165507}
- component: {fileID: 1762532130762754577}
m_Layer: 5
m_Name: Image
m_Name: MainButton
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
@@ -86,13 +133,16 @@ RectTransform:
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Children:
- {fileID: 5827054231092576763}
- {fileID: 7277676979067820762}
- {fileID: 2849245307131571463}
m_Father: {fileID: 5053903421260846465}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_SizeDelta: {x: 313, y: 91}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &2230410216357545400
CanvasRenderer:
@@ -122,7 +172,7 @@ MonoBehaviour:
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 0}
m_Sprite: {fileID: 21300000, guid: e09a5d2cb3c3f4c858754a1e90a44abd, type: 3}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
@@ -187,6 +237,7 @@ GameObject:
- component: {fileID: 5827054231092576763}
- component: {fileID: 5842649278580849339}
- component: {fileID: 1383932928540251694}
- component: {fileID: 3802392566423567257}
m_Layer: 5
m_Name: Text (TMP)
m_TagString: Untagged
@@ -201,17 +252,17 @@ RectTransform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2916175606199835458}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 5053903421260846465}
m_Father: {fileID: 3882154025378162395}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 3.5497}
m_SizeDelta: {x: 0, y: -7.0993}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &5842649278580849339
CanvasRenderer:
@@ -250,8 +301,8 @@ MonoBehaviour:
m_fontMaterials: []
m_fontColor32:
serializedVersion: 2
rgba: 4278190080
m_fontColor: {r: 0, g: 0, b: 0, a: 1}
rgba: 4294967295
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
m_enableVertexGradient: 0
m_colorMode: 3
m_fontColorGradient:
@@ -268,12 +319,12 @@ MonoBehaviour:
m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 61.25
m_fontSizeBase: 36
m_fontSize: 40
m_fontSizeBase: 40
m_fontWeight: 400
m_enableAutoSizing: 1
m_fontSizeMin: 18
m_fontSizeMax: 72
m_fontSizeMin: 15
m_fontSizeMax: 40
m_fontStyle: 0
m_HorizontalAlignment: 2
m_VerticalAlignment: 512
@@ -312,3 +363,305 @@ MonoBehaviour:
m_hasFontAssetChanged: 0
m_baseMaterial: {fileID: 0}
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
--- !u!114 &3802392566423567257
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2916175606199835458}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3}
m_Name:
m_EditorClassIdentifier:
m_IgnoreLayout: 1
m_MinWidth: -1
m_MinHeight: -1
m_PreferredWidth: -1
m_PreferredHeight: -1
m_FlexibleWidth: -1
m_FlexibleHeight: -1
m_LayoutPriority: 1
--- !u!1 &4773363917894322918
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2849245307131571463}
- component: {fileID: 8656005255261122099}
- component: {fileID: 9103345587361145036}
- component: {fileID: 8676942769405651249}
- component: {fileID: 2374156541160748953}
m_Layer: 5
m_Name: CollapseBtn
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &2849245307131571463
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4773363917894322918}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: -1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 3882154025378162395}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0.5}
m_AnchorMax: {x: 0, y: 0.5}
m_AnchoredPosition: {x: 35, y: 5.8}
m_SizeDelta: {x: 31, y: 21}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &8656005255261122099
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4773363917894322918}
m_CullTransparentMesh: 1
--- !u!114 &9103345587361145036
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4773363917894322918}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 21300000, guid: 9de07872267c5419b9fa9c849eb45858, type: 3}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!114 &8676942769405651249
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4773363917894322918}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Navigation:
m_Mode: 0
m_WrapAround: 0
m_SelectOnUp: {fileID: 0}
m_SelectOnDown: {fileID: 0}
m_SelectOnLeft: {fileID: 0}
m_SelectOnRight: {fileID: 0}
m_Transition: 1
m_Colors:
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
m_ColorMultiplier: 1
m_FadeDuration: 0.1
m_SpriteState:
m_HighlightedSprite: {fileID: 0}
m_PressedSprite: {fileID: 0}
m_SelectedSprite: {fileID: 0}
m_DisabledSprite: {fileID: 0}
m_AnimationTriggers:
m_NormalTrigger: Normal
m_HighlightedTrigger: Highlighted
m_PressedTrigger: Pressed
m_SelectedTrigger: Selected
m_DisabledTrigger: Disabled
m_Interactable: 1
m_TargetGraphic: {fileID: 9103345587361145036}
m_OnClick:
m_PersistentCalls:
m_Calls: []
--- !u!114 &2374156541160748953
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4773363917894322918}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3}
m_Name:
m_EditorClassIdentifier:
m_IgnoreLayout: 1
m_MinWidth: -1
m_MinHeight: -1
m_PreferredWidth: -1
m_PreferredHeight: -1
m_FlexibleWidth: -1
m_FlexibleHeight: -1
m_LayoutPriority: 1
--- !u!1 &6863650808120944178
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 7277676979067820762}
- component: {fileID: 885853373149276158}
- component: {fileID: 1569122208421759741}
- component: {fileID: 1715406348461528812}
- component: {fileID: 9213068811979301399}
m_Layer: 5
m_Name: ExpandBtn
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &7277676979067820762
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6863650808120944178}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 3882154025378162395}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0.5}
m_AnchorMax: {x: 0, y: 0.5}
m_AnchoredPosition: {x: 35, y: 0}
m_SizeDelta: {x: 31, y: 21}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &885853373149276158
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6863650808120944178}
m_CullTransparentMesh: 1
--- !u!114 &1569122208421759741
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6863650808120944178}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 21300000, guid: 9de07872267c5419b9fa9c849eb45858, type: 3}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!114 &1715406348461528812
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6863650808120944178}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Navigation:
m_Mode: 0
m_WrapAround: 0
m_SelectOnUp: {fileID: 0}
m_SelectOnDown: {fileID: 0}
m_SelectOnLeft: {fileID: 0}
m_SelectOnRight: {fileID: 0}
m_Transition: 1
m_Colors:
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
m_ColorMultiplier: 1
m_FadeDuration: 0.1
m_SpriteState:
m_HighlightedSprite: {fileID: 0}
m_PressedSprite: {fileID: 0}
m_SelectedSprite: {fileID: 0}
m_DisabledSprite: {fileID: 0}
m_AnimationTriggers:
m_NormalTrigger: Normal
m_HighlightedTrigger: Highlighted
m_PressedTrigger: Pressed
m_SelectedTrigger: Selected
m_DisabledTrigger: Disabled
m_Interactable: 1
m_TargetGraphic: {fileID: 1569122208421759741}
m_OnClick:
m_PersistentCalls:
m_Calls: []
--- !u!114 &9213068811979301399
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6863650808120944178}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3}
m_Name:
m_EditorClassIdentifier:
m_IgnoreLayout: 1
m_MinWidth: -1
m_MinHeight: -1
m_PreferredWidth: -1
m_PreferredHeight: -1
m_FlexibleWidth: -1
m_FlexibleHeight: -1
m_LayoutPriority: 1
@@ -208,8 +208,8 @@ namespace BrewMonster.Scripts.Task
m_ExlusiveAwardTaskMap[pTask.m_FixedData.m_ID] = pTask;
#if _TASK_CLIENT
if (pTask.m_FixedData.m_ulDelvNPC != 0 && pTask.m_FixedData.m_bCanSeekOut)
m_TasksCanSeekOut.Add(pTask);
if (pTask.m_FixedData.m_ulDelvNPC != 0 && pTask.m_FixedData.m_bCanSeekOut)
m_TasksCanSeekOut.Add(pTask);
#endif
AddTaskToMap(pTask);
@@ -217,7 +217,7 @@ namespace BrewMonster.Scripts.Task
private void AddTaskToMap(ATaskTempl pTempl)
{
if (pTempl.m_FixedData.m_enumMethod == (ulong)TaskMethod.enumTMProtectNPC && pTempl.m_FixedData.m_ulNPCToProtect > 0)
if (pTempl.m_FixedData.m_enumMethod == (ulong)TaskCompletionMethod.enumTMProtectNPC && pTempl.m_FixedData.m_ulNPCToProtect > 0)
m_ProtectNPCMap[pTempl.m_FixedData.m_ulNPCToProtect] = pTempl;
m_AllTemplMap[pTempl.m_FixedData.m_ID] = pTempl;
@@ -310,6 +310,54 @@ namespace BrewMonster.Scripts.Task
// }
return false;
}
// 可接任务列表 // Available tasks list
public void GetAvailableTasks(TaskInterface pPlayer, List<ATaskTempl> lst)
{
if (lst == null) return;
if (lst.Capacity < 256) lst.Capacity = 256; // 预留容量 // reserve capacity
string log = "";
int count = m_TasksCanSeekOut.Count;
for (int i = 0; i < count; i++)
{
ATaskTempl pTempl = m_TasksCanSeekOut[i];
if (pTempl == null) continue;
// 如果等级条件不满足则跳过 // Skip if level requirements are not met
if (!pTempl.CheckReachLevel(pPlayer)) continue;
// 玩家可接此任务则加入列表 // If player can accept this task, add to list
var failCode = pPlayer.CanDeliverTask(pTempl.m_FixedData.m_ID);
if (failCode == 0)
{
lst.Add(pTempl);
}
else
{
log += $"Task ID {pTempl.m_FixedData.m_ID} Fail : {failCode} \n";
}
if (i % 1000 == 0)
{
Debug.Log($"--- {i % 1000} Find Available Task --- \n {log}");
log = "";
}
}
}
// 占位:可接返回0,不可接返回非0 // Placeholder: return 0 if deliverable, non-zero otherwise
// private int CanDeliverTask(TaskInterface pPlayer, uint templId)
// {
// // 后续可替换为正式逻辑 // Replace with real logic later
// var impl = pPlayer;
// return (impl != null && impl.IsDeliverLegal()) ? 0 : 1;
// }
#endif
}
}
@@ -446,6 +446,8 @@ namespace BrewMonster.Scripts.Task
public bool IsDeliverLegal()
{
// return !m_pHost->IsTrading() && m_pHost->GetBoothState() == 0 && !m_pHost->IsDead();
return true;
// TODO: implement
return m_pHost.IsTrading() && m_pHost.GetBoothState() == 0 && !m_pHost.IsDead();
}
@@ -513,7 +515,8 @@ namespace BrewMonster.Scripts.Task
// resolve template for top-level entries; children left unresolved in C#
if (entry.m_ParentIndex == (char)0xff)
{
entry.m_ulTemplAddr = 0u;
// entry.m_ulTemplAddr = 0u;
entry.m_ulTemplAddr = pMan.GetTopTaskByID(entry.m_ID) != null ? 1u : 0u;
ATaskTempl topTempl = pMan.GetTopTaskByID(entry.m_ID);
if (topTempl != null)
@@ -576,6 +579,12 @@ namespace BrewMonster.Scripts.Task
{
return EC_Game.GetGameRun().GetCommonData(lKey);
}
// C++: long CECTaskInterface::GetGlobalValue(long lKey)
public long GetGlobalValue(long key)
{
// NOTE: Engine exposes only int common data; cast to long
return EC_Game.GetGameRun().GetCommonData((int)key);
}
public byte GetShapeMask()
{
@@ -600,13 +609,13 @@ namespace BrewMonster.Scripts.Task
ATaskTempl pTempl = GetTaskTemplMan().GetTaskTemplByID(task_id);
if (pTempl == null) return false;
if (pTempl.m_FixedData.m_enumMethod == (uint)TaskMethod.enumTMSimpleClientTask && pTempl.m_FixedData.m_uiEmotion != 0)
if (pTempl.m_FixedData.m_enumMethod == (uint)TaskCompletionMethod.enumTMSimpleClientTask && pTempl.m_FixedData.m_uiEmotion != 0)
{
if (m_emotionTask != null && m_emotionTask.TryGetValue(task_id, out bool finished))
return finished;
return false;
}
else if (pTempl.m_FixedData.m_enumMethod == (uint)TaskMethod.enumTMSimpleClientTaskForceNavi)
else if (pTempl.m_FixedData.m_enumMethod == (uint)TaskCompletionMethod.enumTMSimpleClientTaskForceNavi)
{
return GetForceNavigateFinishFlag();
}
@@ -637,6 +646,145 @@ namespace BrewMonster.Scripts.Task
return false;
}
// ===== Additional TaskInterface methods ported from C++ =====
public uint GetMaxHistoryLevel()
{
// TODO: Use reincarnation tome when available (GetReincarnationTome().max_level)
return (uint)m_pHost.GetBasicProps().iLevel;
}
public uint GetReincarnationCount()
{
// TODO: Hook to host reincarnation count when available
return 0u;
}
public bool IsRealmExpFull()
{
// TODO: Implement via host API when available
return false;
}
public uint GetReputation()
{
// TODO: Expose reputation on host; return 0 for now
return 0u;
}
public int GetFactionRole()
{
// TODO: Expose faction role id on host
return 0;
}
public bool IsInFaction(uint factionId)
{
// TODO: Expose faction id on host; cannot verify now
return false;
}
public bool IsMale()
{
return m_pHost.m_iGender == GENDER.GENDER_MALE;
}
public uint GetPlayerOccupation()
{
return (uint)m_pHost.m_iProfession;
}
public uint GetCurPeriod()
{
// Maps to "second level" in basic props (realm level)
return (uint)m_pHost.GetBasicProps().iLevel2;
}
public bool IsGM()
{
// TODO: Expose GM flag on host
return false;
}
public bool IsShieldUser()
{
// TODO: Expose ShieldUser flag on host
return false;
}
public bool IsMarried()
{
// TODO: Expose spouse id on host
return false;
}
public bool IsWeddingOwner()
{
// TODO: Expose wedding scene info and compare with host id
return false;
}
public uint GetInvEmptySlot()
{
return (uint)EC_Inventory.GetEmptySlotNum(EC_Inventory.IVTRTYPE_PACK);
}
public int GetFactionContrib()
{
return m_pHost.GetContribInfo().cumulate_contrib;
}
public int GetForce()
{
// TODO: Expose force id on host
return 0;
}
public int GetForceReputation()
{
// TODO: Expose force reputation on host
return 0;
}
public int GetForceContribution()
{
// TODO: Expose force contribution on host
return 0;
}
public int GetExp()
{
return m_pHost.GetBasicProps().iExp;
}
public int GetSP()
{
return m_pHost.GetBasicProps().iSP;
}
public int GetForceActivityLevel()
{
// TODO: Expose force activity level on host
return -1;
}
public bool IsKing()
{
// TODO: Expose king status on host
return false;
}
public bool IsInTeam()
{
// TODO: Implement team system and check membership
return false;
}
public uint GetAccountTotalCash()
{
// TODO: Expose account total cash on host/session
return 0u;
}
#if _TASK_CLIENT
// Prepare award preview based on task and state
public void GetTaskAwardPreview(uint ulTaskId, ref Task_Award_Preview p, bool bActiveTask=true)
@@ -808,6 +956,23 @@ namespace BrewMonster.Scripts.Task
return 0u;
}
public uint CanDeliverTask(uint ulTaskId)
{
ATaskTempl pTempl = GetTaskTemplMan().GetTopTaskByID(ulTaskId);
if (pTempl == null) return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_NO_TASK;
if (!IsDeliverLegal()) return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_INDETERMINATE;
// return pTempl->CheckPrerequisite(this, static_cast<ActiveTaskList*>(GetActiveTaskList()), GetCurTime(), true, true, false);
return pTempl.CheckPrerequisite(this, GetActiveTaskList(), GetCurTime(), true, true, false);
// if (!pTempl.CheckReachLevel(this)) return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_BELOW_LEVEL;
// uint keyCheck = pTempl.CheckGlobalKeyValue(this, false);
// if (keyCheck != 0u) return keyCheck;
return 0u;
}
#endif
@@ -886,7 +1051,7 @@ namespace BrewMonster.Scripts.Task
if (pTempl.m_FixedData.m_ulGoldWanted != 0) pInfo.m_ulGoldWanted = pTempl.m_FixedData.m_ulGoldWanted;
// 任务类型分支 // Task method branches
if (pTempl.m_FixedData.m_enumMethod == (uint)TaskMethod.enumTMCollectNumArticle)
if (pTempl.m_FixedData.m_enumMethod == (uint)TaskCompletionMethod.enumTMCollectNumArticle)
{
for (int j = 0; j < pTempl.m_FixedData.m_ulItemsWanted; j++)
{
@@ -896,7 +1061,7 @@ namespace BrewMonster.Scripts.Task
pInfo.m_ItemsWanted[j].m_ulItemsGained = ATaskTempl._get_item_count(this, iw.m_ulItemTemplId, iw.m_bCommonItem);
}
}
else if (pTempl.m_FixedData.m_enumMethod == (uint)TaskMethod.enumTMKillNumMonster)
else if (pTempl.m_FixedData.m_enumMethod == (uint)TaskCompletionMethod.enumTMKillNumMonster)
{
int ulItemCount = 0;
int ulMonsterCount = 0;
@@ -927,7 +1092,7 @@ namespace BrewMonster.Scripts.Task
}
}
}
else if (pTempl.m_FixedData.m_enumMethod == (uint)TaskMethod.enumTMKillPlayer)
else if (pTempl.m_FixedData.m_enumMethod == (uint)TaskCompletionMethod.enumTMKillPlayer)
{
int ulItemCount = 0;
int ulPlayerCount = 0;
@@ -958,20 +1123,20 @@ namespace BrewMonster.Scripts.Task
}
}
}
else if (pTempl.m_FixedData.m_enumMethod == (uint)TaskMethod.enumTMProtectNPC)
else if (pTempl.m_FixedData.m_enumMethod == (uint)TaskCompletionMethod.enumTMProtectNPC)
{
pInfo.m_ulNPCToProtect = pTempl.m_FixedData.m_ulNPCToProtect;
pInfo.m_ulProtectTime = pTempl.m_FixedData.m_ulProtectTimeLen;
}
else if (pTempl.m_FixedData.m_enumMethod == (uint)TaskMethod.enumTMWaitTime)
else if (pTempl.m_FixedData.m_enumMethod == (uint)TaskCompletionMethod.enumTMWaitTime)
{
pInfo.m_ulWaitTime = pTempl.m_FixedData.m_ulWaitTime;
}
else if (pTempl.m_FixedData.m_enumMethod == (uint)TaskMethod.enumTMGlobalValOK)
else if (pTempl.m_FixedData.m_enumMethod == (uint)TaskCompletionMethod.enumTMGlobalValOK)
{
pTempl.GetGlobalTaskChar(this, pInfo.m_TaskCharArr);
}
else if (pTempl.m_FixedData.m_enumMethod == (uint)TaskMethod.enumTMReachLevel)
else if (pTempl.m_FixedData.m_enumMethod == (uint)TaskCompletionMethod.enumTMReachLevel)
{
pInfo.m_ulReachLevel = pTempl.m_FixedData.m_ulReachLevel;
pInfo.m_ulReachReincarnation = pTempl.m_FixedData.m_ulReachReincarnationCount;
@@ -41,11 +41,44 @@ namespace BrewMonster.Scripts.Task
bool HasTask(uint ulTaskId);
#if _TASK_CLIENT
#if _TASK_CLIENT
void GetTaskAwardPreview(uint ulTaskId,ref Task_Award_Preview p, bool bActiveTask = true);
uint GetTaskCount();
uint GetTaskId(uint ulIndex);
#endif
uint CanDeliverTask(uint ulTaskId);
#endif
// bool HasTask(uint taskId);
// bool CheckTaskForbid(uint taskId);
long GetGlobalValue(long key);
// uint GetPlayerLevel();
uint GetMaxHistoryLevel();
uint GetReincarnationCount();
bool IsRealmExpFull();
uint GetReputation();
// uint GetGoldNum();
int GetFactionRole();
bool IsInFaction(uint factionId);
bool IsMale();
uint GetPlayerOccupation();
uint GetCurPeriod();
bool IsGM();
bool IsShieldUser();
bool IsMarried();
// bool IsAtCrossServer();
bool IsWeddingOwner();
uint GetInvEmptySlot();
int GetFactionContrib();
// byte GetShapeMask();
int GetForce();
int GetForceReputation();
int GetForceContribution();
int GetExp();
int GetSP();
int GetForceActivityLevel();
bool IsKing();
bool IsInTeam();
uint GetAccountTotalCash();
}
}
+14 -13
View File
@@ -49,7 +49,7 @@ namespace PerfectWorld.Scripts.Task
// nsigned short m_wMonsterNum[MAX_MONSTER_WANTED];
public ushort[] m_wMonsterNum = new ushort[TaskInterfaceConstants.MAX_MONSTER_WANTED]; // Monster numbers
public int m_iUsefulData1;
public char m_iUsefulData2;
public byte m_iUsefulData2; // char in C++, but using byte here for simplicity
public void ReadFromBuffer(byte[] buffer, ref int offset)
{
@@ -69,24 +69,25 @@ namespace PerfectWorld.Scripts.Task
m_ulCapTemplAddr = BitConverter.ToUInt32(buffer, offset);
offset += 4;
int localOffset = offset; // store current offset for reading additional fields from union
// Read remaining buffer data
Array.Copy(buffer, offset, m_BufData, 0, m_BufData.Length);
// offset += bufDataLength; // in C++ have union, so we dont plus offset here
offset += m_BufData.Length; // in C++ have union, so we dont plus offset here
// Additional fields can be read here as needed
m_wMonsterNum = new ushort[TaskInterfaceConstants.MAX_MONSTER_WANTED];
for (int i = 0; i < TaskInterfaceConstants.MAX_MONSTER_WANTED; i++)
{
m_wMonsterNum[i] = BitConverter.ToUInt16(buffer, offset);
// offset += 2; // in C++ have union, so we dont plus offset here
m_wMonsterNum[i] = BitConverter.ToUInt16(buffer, localOffset);
localOffset += 2; // in C++ have union, so we dont plus offset here
}
m_iUsefulData1 = BitConverter.ToInt32(buffer, offset);
// offset += 4; // in C++ have union, so we dont plus offset here
m_iUsefulData1 = BitConverter.ToInt32(buffer, localOffset);
localOffset += 4; // in C++ have union, so we dont plus offset here
m_iUsefulData2 = buffer[localOffset++]; // in C++ have union, so we dont plus offset here
m_iUsefulData2 = (char)buffer[offset]; // in C++ have union, so we dont plus offset here
offset += m_BufData.Length;
}
@@ -216,13 +217,13 @@ namespace PerfectWorld.Scripts.Task
// --- Methods ---
public void ReadFromBuffer(byte[] buffer)
{
// header use same data slot with m_uTaskCount etc. cause C++ use union here
// so, we dont plus into offset after copy header
// NOTE: union
// cause C++ use union here, header use same data slot with the rest of properties like m_uTaskCount etc.
// so, we dont need to read other properties again, just copy the header part
int offset = 0;
Array.Copy(buffer, offset, header, 0, header.Length);
// offset += header.Length;
m_uTaskCount = buffer[offset++];
m_uUsedCount = buffer[offset++];
m_Version = BitConverter.ToUInt16(buffer, offset);
@@ -231,7 +232,7 @@ namespace PerfectWorld.Scripts.Task
m_uListState = buffer[offset++];
m_uTopHideTaskCount = buffer[offset++];
_flags = buffer[offset++];
for (int i = 0; i < m_uTaskCount; i++)
{
ActiveTaskEntry entry = new ActiveTaskEntry();
@@ -5,6 +5,270 @@ namespace BrewMonster.Scripts.Task
{
public partial class ATaskTempl
{
public uint GetID()
{
return m_FixedData.m_ID;
}
// Process Part
public uint CheckPrerequisite(
TaskInterface pTask,
ActiveTaskList pList,
uint ulCurTime,
bool bCheckPrevTask = true,
bool bCheckTeam = true,
bool bCheckBudge = true,
bool bCheckLevel = true)
{
uint ulRet = 0u;
// Ǹڵ // English: Not the root node
if (m_pParent != null)
{
ulRet = (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_NOT_ROOT;
goto ret_here;
}
if (bCheckBudge)
{
ulRet = CheckBudget(pList);
if (ulRet != 0u) goto ret_here;
}
// else if (pList->GetEntry(m_ID)) // English: Already has the same task
else if (pTask.HasTask(m_FixedData.m_ID))
{
ulRet = (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_SAME_TASK;
goto ret_here;
}
// Ƿ // English: Is task forbidden
if (pTask.CheckTaskForbid(m_FixedData.m_ID))
{
ulRet = (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_TASK_FORBID;
goto ret_here;
}
// ΪPQжǷѾPQ // English: If current is PQ task, ensure no existing PQ task
if (m_FixedData.m_bPQTask)
{
for (byte i = 0; i < pList.m_uTaskCount; i++)
{
var CurEntry = pList.m_TaskEntries[i];
if (CurEntry == null) continue;
ATaskTempl pTempl = CurEntry.GetTempl();
if (pTempl != null && pTempl.m_FixedData.m_bPQTask)
{
ulRet = (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_ALREADY_HAS_PQ;
goto ret_here;
}
}
}
ulRet = CheckGivenItems(pTask);
if (ulRet != 0u) goto ret_here;
// Ƿʱ // English: Check if within delivery timetable
ulRet = CheckTimetable(ulCurTime);
if (ulRet != 0u) goto ret_here;
// ʱ // English: Check deliver time
ulRet = CheckDeliverTime(pTask, ulCurTime);
if (ulRet != 0u) goto ret_here;
ulRet = CheckFnshLst(pTask, ulCurTime);
if (ulRet != 0u) goto ret_here;
// Ƿ˺ɴ // English: Check daily deliver count limit
ulRet = CheckDeliverCount(pTask);
if (ulRet != 0u) goto ret_here;
// Ƿֵ // English: Check RMB/account balance
ulRet = CheckAccountRMB(pTask);
if (ulRet != 0u) goto ret_here;
// Ƿɫ¼ʱ // English: Check character time requirements
ulRet = CheckCharTime(pTask);
if (ulRet != 0u) goto ret_here;
// Check Level // English: Level constraints
if (bCheckLevel)
{
ulRet = CheckLevel(pTask);
if (ulRet != 0u) goto ret_here;
}
// ת // English: Reincarnation constraints
ulRet = CheckReincarnation(pTask);
if (ulRet != 0u) goto ret_here;
// ȼ // English: Realm level constraints
ulRet = CheckRealmLevel(pTask);
if (ulRet != 0u) goto ret_here;
// Ƿ // English: Realm exp full check
ulRet = CheckRealmExpFull(pTask);
if (ulRet != 0u) goto ret_here;
// // English: Reputation check
ulRet = CheckRepu(pTask);
if (ulRet != 0u) goto ret_here;
// Ѻ // English: Deposit check
ulRet = CheckDeposit(pTask);
if (ulRet != 0u) goto ret_here;
// Ʒ // English: Items check
ulRet = CheckItems(pTask);
if (ulRet != 0u) goto ret_here;
// // English: Faction check
ulRet = CheckFaction(pTask);
if (ulRet != 0u) goto ret_here;
// Ա // English: Gender check
ulRet = CheckGender(pTask);
if (ulRet != 0u) goto ret_here;
// ְҵ // English: Occupation check
ulRet = CheckOccupation(pTask);
if (ulRet != 0u) goto ret_here;
// ضʱ // English: Specific period check
ulRet = CheckPeriod(pTask);
if (ulRet != 0u) goto ret_here;
// ǷGM // English: GM check
ulRet = CheckGM(pTask);
if (ulRet != 0u) goto ret_here;
// Ƿû // English: Shielded user check
ulRet = CheckShieldUser(pTask);
if (ulRet != 0u) goto ret_here;
// // English: Previous task check
if (bCheckPrevTask)
{
ulRet = CheckPreTask(pTask);
if (ulRet != 0u) goto ret_here;
}
// // English: Mutex task check
ulRet = CheckMutexTask(pTask, ulCurTime);
if (ulRet != 0u) goto ret_here;
// 򴥷 // English: In-zone trigger check
ulRet = CheckInZone(pTask);
if (ulRet != 0u) goto ret_here;
// // English: Team task check
if (bCheckTeam)
{
ulRet = CheckTeamTask(pTask);
if (ulRet != 0u) goto ret_here;
}
// // English: Spouse check
ulRet = CheckSpouse(pTask);
if (ulRet != 0u) goto ret_here;
ulRet = CheckWeddingOwner(pTask);
if (ulRet != 0u) goto ret_here;
// // English: Marriage check
ulRet = CheckMarriage(pTask);
if (ulRet != 0u) goto ret_here;
// // English: Living skill check
ulRet = CheckLivingSkill(pTask);
if (ulRet != 0u) goto ret_here;
// // English: Special award activity check
ulRet = CheckSpecialAward(pTask);
if (ulRet != 0u) goto ret_here;
// ȫkey/value // English: Global key/value
ulRet = CheckGlobalKeyValue(pTask, false);
if (ulRet != 0u) goto ret_here;
if (m_FixedData.m_bCompareItemAndInventory)
{
ulRet = CheckIvtrEmptySlot(pTask);
if (ulRet != 0u) goto ret_here;
}
// ɹ׶ // English: Faction contribution check
ulRet = CheckFactionContrib(pTask);
if (ulRet != 0u) goto ret_here;
// ¼ɽɸ // English: Recorded tasks number check
ulRet = CheckRecordTasksNum(pTask);
if (ulRet != 0u) goto ret_here;
// ״̬ // English: Transform mask check
ulRet = CheckTransform(pTask);
if (ulRet != 0u) goto ret_here;
// // English: Force check
ulRet = CheckForce(pTask);
if (ulRet != 0u) goto ret_here;
// // English: Force reputation check
ulRet = CheckForceReputation(pTask);
if (ulRet != 0u) goto ret_here;
// ս // English: Force contribution check
ulRet = CheckForceContribution(pTask);
if (ulRet != 0u) goto ret_here;
// ֵ // English: EXP check
ulRet = CheckExp(pTask);
if (ulRet != 0u) goto ret_here;
// Ԫֵ // English: SP check
ulRet = CheckSP(pTask);
if (ulRet != 0u) goto ret_here;
// Ծȼ // English: Force activity level check
ulRet = CheckForceActivityLevel(pTask);
if (ulRet != 0u) goto ret_here;
// // English: King check
ulRet = CheckKing(pTask);
if (ulRet != 0u) goto ret_here;
// // English: Not in team check
ulRet = CheckNotInTeam(pTask);
if (ulRet != 0u) goto ret_here;
// ƺ // English: Title check
ulRet = CheckTitle(pTask);
if (ulRet != 0u) goto ret_here;
// ʷƽ׶ // English: History stage check
ulRet = CheckHistoryStage(pTask);
if (ulRet != 0u) goto ret_here;
// ռ // English: Card collection count check
ulRet = CheckCardCollection(pTask);
if (ulRet != 0u) goto ret_here;
// ijƷӵ // English: Specific card rank count check
ulRet = CheckCardRankCount(pTask);
if (ulRet != 0u) goto ret_here;
// 󣬲ܽȡǿƶ // English: No navigate when in transform shape
ulRet = CheckInTransformShape(pTask);
if (ulRet != 0u) goto ret_here;
ret_here:
// TODO: pTask.GetPlayerId() not available in managed interface; use 0
string log = $"CheckPrerequisite: ret = {ulRet}";
CECTaskInterface.WriteLog(0, (int)m_FixedData.m_ID, 1, log);
return ulRet;
}
#if _TASK_CLIENT
// bool CanShowTask (TaskInterface* pTask) const;
// bool HasShowCond() const;
@@ -150,7 +414,7 @@ namespace BrewMonster.Scripts.Task
// const talk_proc* GetUnfinishedTalk() const { return &m_ExeTalk; }
// const talk_proc* GetAwardTalk() const { return &m_AwardTalk; }
//
// unsigned long GetDeliverNPC() const { return m_ulDelvNPC; }
public uint GetDeliverNPC() { return m_FixedData.m_ulDelvNPC; }
public uint GetAwardNPC() { return m_FixedData.m_ulAwardNPC; }
//
// void SaveToTextFile(FILE* fp);
@@ -290,5 +554,498 @@ namespace BrewMonster.Scripts.Task
return m.m_FixedData.m_bKeyTask;
}
// ===== Missing methods converted from C++ (TaskTempl.inl) =====
// 保留原中文注释,并在旁加入英文翻译
// inline unsigned long _get_item_count(TaskInterface* pTask, unsigned long ulItemId, bool bCommon)
// 获取道具数量(通用/任务) // English: Get item count (common/task)
// public static uint _get_item_count(TaskInterface pTask, uint ulItemId, bool bCommon)
// {
// return bCommon ? pTask.GetCommonItemCount(ulItemId) : pTask.GetTaskItemCount(ulItemId);
// }
// inline unsigned long ATaskTempl::CheckBudget(ActiveTaskList* pList) const
// 检查任务栏容量与空间 // English: Check task list budget and space
public uint CheckBudget(ActiveTaskList pList)
{
// TODO: Convert full logic with TASK_HIDDEN_COUNT/TASK_TITLE_TASK_COUNT/TASK_ACTIVE_LIST_MAX_LEN and list counters when constants and fields are available
// 占位返回通过 // English: Placeholder pass
return 0u;
}
// inline unsigned long ATaskTempl::CheckGivenItems(TaskInterface* pTask) const
// 检查交付所需道具容量合法性 // English: Check deliverable item capacity
public uint CheckGivenItems(TaskInterface pTask)
{
// TODO: Use m_FixedData.m_ulGivenItems, m_ulGivenCmnCount, m_ulGivenTskCount and pTask.CanDeliver* API when fields confirmed
return 0u;
}
// inline unsigned long ATaskTempl::CheckTimetable(unsigned long ulCurTime) const
// 检查任务可接时间表 // English: Check task timetable window
public uint CheckTimetable(uint ulCurTime)
{
// TODO: Implement judge_time_date against m_FixedData.m_tmStart/m_tmEnd/m_tmType
return 0u;
}
// inline unsigned long ATaskTempl::CheckDeliverTime(TaskInterface* pTask, unsigned long ulCurTime) const
// 检查任务发放频率限制(日/周/月/年) // English: Check deliver frequency limits (day/week/month/year)
public uint CheckDeliverTime(TaskInterface pTask, uint ulCurTime)
{
// TODO: Implement with FinishedTimeList/FinishedCntList and timezone bias when types are available
return 0u;
}
// inline unsigned long ATaskTempl::CheckFnshLst(TaskInterface* pTask, unsigned long ulCurTime) const
// 检查完成与失败记录是否允许重复领取 // English: Check finished/failed list for redo permissions
public uint CheckFnshLst(TaskInterface pTask, uint ulCurTime)
{
// TODO: Implement using FinishedTaskList and m_FixedData.m_bCanRedo/m_bCanRedoAfterFailure
return 0u;
}
// inline unsigned long ATaskTempl::CheckDeliverCount(TaskInterface* pTask) const
// 检查周期内角色/账号次数限制 // English: Check period deliver counts for role/account
public uint CheckDeliverCount(TaskInterface pTask)
{
// TODO: Implement with FinishedCountList/FinishedTaskList based on account/role limits
return 0u;
}
// inline unsigned long ATaskTempl::CheckAccountRMB(TaskInterface* pTask) const
// 检查账号现金(RMB)范围 // English: Check account total cash (RMB) range
public uint CheckAccountRMB(TaskInterface pTask)
{
if (m_FixedData.m_ulPremRMBMin != 0u && m_FixedData.m_ulPremRMBMax != 0u)
{
uint total = pTask.GetAccountTotalCash();
if (total < m_FixedData.m_ulPremRMBMin || total > m_FixedData.m_ulPremRMBMax)
{
return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_RMB_NOT_ENOUGH;
}
}
return 0u;
}
// inline unsigned long ATaskTempl::CheckCharTime(TaskInterface* pTask) const
// 检查角色创建/登录时间窗口 // English: Check character time window
public uint CheckCharTime(TaskInterface pTask)
{
// TODO: Implement using m_FixedData.m_bCharTime, m_iCharStartTime/m_iCharEndTime, m_tmCharEndTime and pTask time APIs
return 0u;
}
// inline unsigned long ATaskTempl::CheckLevel(TaskInterface* pTask) const
// 等级上下限 // English: Level min/max
public uint CheckLevel(TaskInterface pTask)
{
uint level = m_FixedData.m_bPremCheckMaxHistoryLevel > 0 ? pTask.GetMaxHistoryLevel() : pTask.GetPlayerLevel();
if (m_FixedData.m_ulPremise_Lev_Min != 0u && level < m_FixedData.m_ulPremise_Lev_Min)
return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_BELOW_LEVEL;
if (m_FixedData.m_ulPremise_Lev_Max != 0u && level > m_FixedData.m_ulPremise_Lev_Max)
return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_ABOVE_LEVEL;
return 0u;
}
// inline unsigned long ATaskTempl::CheckReincarnation(TaskInterface* pTask) const
// 转生次数上下限 // English: Reincarnation count min/max
public uint CheckReincarnation(TaskInterface pTask)
{
if (m_FixedData.m_bPremCheckReincarnation)
{
uint count = pTask.GetReincarnationCount();
if (count < m_FixedData.m_ulPremReincarnationMin) return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_BELOW_REINCARNATION;
if (count > m_FixedData.m_ulPremReincarnationMax) return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_ABOVE_REINCARNATION;
}
return 0u;
}
// inline unsigned long ATaskTempl::CheckRealmLevel(TaskInterface* pTask) const
// 修真境界等级 // English: Realm level
public uint CheckRealmLevel(TaskInterface pTask)
{
if (m_FixedData.m_bPremCheckRealmLevel)
{
uint level = GetRealmLevel(pTask);
if (level < m_FixedData.m_ulPremRealmLevelMin) return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_BELOW_REALMLEVEL;
if (level > m_FixedData.m_ulPremRealmLevelMax) return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_ABOVE_REALMLEVEL;
}
return 0u;
}
// inline unsigned long ATaskTempl::CheckRealmExpFull(TaskInterface* pTask) const
// 修真经验是否已满 // English: Realm EXP full check
public uint CheckRealmExpFull(TaskInterface pTask)
{
if (m_FixedData.m_bPremCheckRealmExpFull)
{
if (!pTask.IsRealmExpFull()) return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_REALM_EXP_FULL;
}
return 0u;
}
// inline unsigned long ATaskTempl::CheckRepu(TaskInterface* pTask) const
// 声望上下限 // English: Reputation min/max
public uint CheckRepu(TaskInterface pTask)
{
if (m_FixedData.m_lPremise_Reputation != 0 && pTask.GetReputation() < (uint)m_FixedData.m_lPremise_Reputation)
return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_BELOW_REPU;
if (m_FixedData.m_lPremise_RepuMax != 0 && pTask.GetReputation() > (uint)m_FixedData.m_lPremise_RepuMax)
return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_BELOW_REPU;
return 0u;
}
// inline unsigned long ATaskTempl::CheckDeposit(TaskInterface* pTask) const
// 寄存金(金币) // English: Deposit (gold)
public uint CheckDeposit(TaskInterface pTask)
{
if (m_FixedData.m_ulPremise_Deposit != 0u && pTask.GetGoldNum() < m_FixedData.m_ulPremise_Deposit)
return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_NO_DEPOSIT;
return 0u;
}
// inline unsigned long ATaskTempl::CheckItems(TaskInterface* pTask) const
// 前置道具检查(任一/全部) // English: Prerequisite item check (any/ALL)
public uint CheckItems(TaskInterface pTask)
{
// TODO: Implement using m_FixedData.m_ulPremItems, m_bPremItemsAnyOne, m_PremItems[]
return 0u;
}
// inline unsigned long ATaskTempl::CheckFaction(TaskInterface* pTask) const
// 家族/帮派及职位 // English: Faction/clan and role
public uint CheckFaction(TaskInterface pTask)
{
int role = pTask.GetFactionRole();
bool roleOk = role <= m_FixedData.m_iPremise_FactionRole;
if (m_FixedData.m_ulPremise_Faction != 0u && !(pTask.IsInFaction(m_FixedData.m_ulPremise_Faction) && roleOk))
return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_CLAN;
return 0u;
}
// inline unsigned long ATaskTempl::CheckGender(TaskInterface* pTask) const
// 性别 // English: Gender
public uint CheckGender(TaskInterface pTask)
{
bool isMale = pTask.IsMale();
if (m_FixedData.m_ulGender == TaskTemplConstants.TASK_GENDER_MALE && !isMale) return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_WRONG_GENDER;
if (m_FixedData.m_ulGender == TaskTemplConstants.TASK_GENDER_FEMALE && isMale) return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_WRONG_GENDER;
return 0u;
}
// inline unsigned long ATaskTempl::CheckOccupation(TaskInterface* pTask) const
// 职业 // English: Occupation
public uint CheckOccupation(TaskInterface pTask)
{
if (m_FixedData.m_ulOccupations == 0u) return 0u;
uint current = pTask.GetPlayerOccupation();
for (uint i = 0; i < m_FixedData.m_ulOccupations; i++)
{
if (m_FixedData.m_Occupations[i] == current)
return 0u;
}
return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_NOT_IN_OCCU;
}
// inline unsigned long ATaskTempl::CheckPeriod(TaskInterface* pTask) const
// 历练阶段(区间) // English: Period check (interval)
public uint CheckPeriod(TaskInterface pTask)
{
uint cur = pTask.GetCurPeriod();
if (cur < m_FixedData.m_ulPremise_Period) return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_WRONG_PERIOD;
if (m_FixedData.m_ulPremise_Period < 20u) return 0u;
if (m_FixedData.m_ulPremise_Period < 30u) return cur < 30u ? 0u : (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_WRONG_PERIOD;
if (m_FixedData.m_ulPremise_Period < 40u) return cur < 40u ? 0u : (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_WRONG_PERIOD;
return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_WRONG_PERIOD;
}
// inline unsigned long ATaskTempl::CheckGM(TaskInterface* pTask) const
// GM 限制 // English: GM check
public uint CheckGM(TaskInterface pTask)
{
return m_FixedData.m_bGM ? (pTask.IsGM() ? 0u : (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_GM) : 0u;
}
// inline unsigned long ATaskTempl::CheckShieldUser(TaskInterface* pTask) const
// 屏蔽用户 // English: Shielded user
public uint CheckShieldUser(TaskInterface pTask)
{
return m_FixedData.m_bShieldUser ? (pTask.IsShieldUser() ? 0u : (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_SHIELD_USER) : 0u;
}
// inline unsigned long ATaskTempl::CheckPreTask(TaskInterface* pTask) const
// 前置任务 // English: Previous tasks
public uint CheckPreTask(TaskInterface pTask)
{
// TODO: Implement using FinishedTaskList and m_FixedData.m_ulPremise_Tasks[*]
return 0u;
}
// (No inline in provided snippet) 互斥任务 // English: Mutex task
public uint CheckMutexTask(TaskInterface pTask, uint ulCurTime)
{
// TODO: Implement when mutex task data is available
return 0u;
}
// inline unsigned long ATaskTempl::CheckInZone(TaskInterface* pTask) const
// 区域检查 // English: In-zone check
public uint CheckInZone(TaskInterface pTask)
{
// TODO: Implement worldId + region bounding box check using m_FixedData.m_ulDelvWorld and m_pDelvRegion
return 0u;
}
// inline unsigned long ATaskTempl::CheckTeamTask(TaskInterface* pTask) const
// 组队接任务要求 // English: Team-task requirements
public uint CheckTeamTask(TaskInterface pTask)
{
// TODO: Implement full team captain and member checks per HasAllTeamMemsWanted
return 0u;
}
// inline unsigned long ATaskTempl::CheckSpouse(TaskInterface* pTask) const
// 配偶要求 // English: Spouse requirement
public uint CheckSpouse(TaskInterface pTask)
{
if (m_FixedData.m_bPremise_Spouse && !pTask.IsMarried())
return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_INDETERMINATE;
return 0u;
}
// inline unsigned long ATaskTempl::CheckWeddingOwner(TaskInterface* pTask) const
// 婚礼举办者检查 // English: Wedding owner check
public uint CheckWeddingOwner(TaskInterface pTask)
{
if (m_FixedData.m_bPremiseWeddingOwner)
{
if (pTask.IsAtCrossServer()) return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_CROSSSERVER_NO_MARRIAGE;
if (!pTask.IsWeddingOwner()) return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_WEDDING_OWNER;
}
return 0u;
}
// inline unsigned long ATaskTempl::CheckMarriage(TaskInterface* pTask) const
// 结婚任务条件 // English: Marriage task requirements
public uint CheckMarriage(TaskInterface pTask)
{
// TODO: Implement two-person team with opposite gender per original logic if APIs exist
return 0u;
}
// inline unsigned long ATaskTempl::CheckLivingSkill(TaskInterface* pTask) const
// 生活技能等级 // English: Living skill level
public uint CheckLivingSkill(TaskInterface pTask)
{
// TODO: Loop m_FixedData.m_lSkillLev[MAX_LIVING_SKILLS] with skill ids and pTask.HasLivingSkill/GetLivingSkillLevel
return 0u;
}
// inline unsigned long ATaskTempl::CheckIvtrEmptySlot(TaskInterface* pTask) const
// 背包空位检查 // English: Inventory empty slot check
public uint CheckIvtrEmptySlot(TaskInterface pTask)
{
if (!m_FixedData.m_bCompareItemAndInventory) return 0u;
if (pTask.GetInvEmptySlot() < m_FixedData.m_ulInventorySlotNum)
{
return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_NOT_IVTRSLOTNUM;
}
return 0u;
}
// inline unsigned long ATaskTempl::CheckFactionContrib(TaskInterface* pTask) const
// 家族贡献 // English: Faction contribution
public uint CheckFactionContrib(TaskInterface pTask)
{
int contrib = pTask.GetFactionContrib();
if (m_FixedData.m_iPremiseFactionContrib != 0 && contrib < m_FixedData.m_iPremiseFactionContrib)
return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_BELOW_FACTION_CONTRIB;
return 0u;
}
// inline unsigned long ATaskTempl::CheckRecordTasksNum(TaskInterface* pTask) const
// 完成记录任务数量 // English: Finished-record tasks count
public uint CheckRecordTasksNum(TaskInterface pTask)
{
// TODO: Implement using FinishedTaskList scanning for recorded tasks count
return 0u;
}
// inline unsigned long ATaskTempl::CheckTransform(TaskInterface* pTask) const
// 变身形态 // English: Transform mask
public uint CheckTransform(TaskInterface pTask)
{
byte playerShapeType = pTask.GetShapeMask();
// 0xFF 不限制 // English: 0xFF = no restriction
if (m_FixedData.m_ucPremiseTransformedForm == 0xFF) return 0u;
// 职业变身 // English: Occupation transform
if (m_FixedData.m_ucPremiseTransformedForm == 0x80)
{
if ((playerShapeType >> 6) != 2) return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_TRANSFORM_MASK;
return 0u;
}
// 指定形态 // English: Specific form
if (m_FixedData.m_ucPremiseTransformedForm != playerShapeType)
return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_TRANSFORM_MASK;
return 0u;
}
// inline unsigned long ATaskTempl::CheckForce(TaskInterface* pTask) const
// 势力检查 // English: Force check
public uint CheckForce(TaskInterface pTask)
{
if (m_FixedData.m_bPremCheckForce)
{
if (pTask.IsAtCrossServer()) return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_CROSSSERVER_NO_FORCE;
if (m_FixedData.m_iPremForce == -1)
{
if (pTask.GetForce() == 0) return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_FORCE;
}
else if (pTask.GetForce() != m_FixedData.m_iPremForce)
{
return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_FORCE;
}
}
return 0u;
}
// inline unsigned long ATaskTempl::CheckForceReputation(TaskInterface* pTask) const
// 势力声望 // English: Force reputation
public uint CheckForceReputation(TaskInterface pTask)
{
if (m_FixedData.m_iPremForceReputation != 0)
{
if (pTask.IsAtCrossServer()) return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_CROSSSERVER_NO_FORCE;
if (pTask.GetForceReputation() < m_FixedData.m_iPremForceReputation)
return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_FORCE_REPUTATION;
}
return 0u;
}
// inline unsigned long ATaskTempl::CheckForceContribution(TaskInterface* pTask) const
// 势力贡献 // English: Force contribution
public uint CheckForceContribution(TaskInterface pTask)
{
if (m_FixedData.m_iPremForceContribution != 0)
{
if (pTask.IsAtCrossServer()) return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_CROSSSERVER_NO_FORCE;
if (pTask.GetForceContribution() < m_FixedData.m_iPremForceContribution)
return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_FORCE_REPUTATION;
}
return 0u;
}
// inline unsigned long ATaskTempl::CheckExp(TaskInterface* pTask) const
// 势力经验 // English: Force EXP
public uint CheckExp(TaskInterface pTask)
{
if (m_FixedData.m_iPremForceExp != 0)
{
if (pTask.IsAtCrossServer()) return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_CROSSSERVER_NO_FORCE;
if (pTask.GetExp() < m_FixedData.m_iPremForceExp) return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_EXP;
}
return 0u;
}
// inline unsigned long ATaskTempl::CheckSP(TaskInterface* pTask) const
// 势力SP // English: Force SP
public uint CheckSP(TaskInterface pTask)
{
if (m_FixedData.m_iPremForceSP != 0)
{
if (pTask.IsAtCrossServer()) return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_CROSSSERVER_NO_FORCE;
if (pTask.GetSP() < m_FixedData.m_iPremForceSP) return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_SP;
}
return 0u;
}
// inline unsigned long ATaskTempl::CheckForceActivityLevel(TaskInterface* pTask) const
// 势力活跃等级 // English: Force activity level
public uint CheckForceActivityLevel(TaskInterface pTask)
{
if (m_FixedData.m_iPremForceActivityLevel != -1)
{
if (pTask.IsAtCrossServer()) return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_CROSSSERVER_NO_FORCE;
if (m_FixedData.m_iPremForceActivityLevel != pTask.GetForceActivityLevel())
return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_FORCE_AL;
}
return 0u;
}
// inline unsigned long ATaskTempl::CheckKing(TaskInterface* pTask) const
// 王检查 // English: King check
public uint CheckKing(TaskInterface pTask)
{
if (m_FixedData.m_bPremIsKing && !pTask.IsKing())
return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_KING;
return 0u;
}
// inline unsigned long ATaskTempl::CheckNotInTeam(TaskInterface* pTask) const
// 不在队伍 // English: Not in team
public uint CheckNotInTeam(TaskInterface pTask)
{
if (m_FixedData.m_bPremNotInTeam && pTask.IsInTeam())
return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_IN_TEAM;
return 0u;
}
// inline unsigned long ATaskTempl::CheckTitle(TaskInterface* pTask) const
// 称号检查 // English: Title check
public uint CheckTitle(TaskInterface pTask)
{
// TODO: Implement using m_FixedData.m_iPremTitleNumTotal/m_iPremTitleNumRequired and award title arrays
return 0u;
}
// inline unsigned long ATaskTempl::CheckHistoryStage(TaskInterface* pTask) const
// 历史阶段 // English: History stage
public uint CheckHistoryStage(TaskInterface pTask)
{
// TODO: Implement using pTask.GetCurHistoryStageIndex() and m_FixedData.m_iPremHistoryStageIndex[2]
return 0u;
}
// inline unsigned long ATaskTempl::CheckCardCollection(TaskInterface* pTask) const
// 将星卡收集数量 // English: General card collection count
public uint CheckCardCollection(TaskInterface pTask)
{
// TODO: Implement using pTask.GetObtainedGeneralCardCount() and m_FixedData.m_ulPremGeneralCardCount
return 0u;
}
// inline unsigned long ATaskTempl::CheckCardRankCount(TaskInterface* pTask) const
// 指定品级将星卡数量 // English: Specific rank general card count
public uint CheckCardRankCount(TaskInterface pTask)
{
// TODO: Implement using pTask.GetObtainedGeneralCardCountByRank(rank) and m_FixedData fields
return 0u;
}
// inline unsigned long ATaskTempl::CheckInTransformShape(TaskInterface* pTask) const
// 变身中禁止导航 // English: No navigate while in shaped
public uint CheckInTransformShape(TaskInterface pTask)
{
if (m_FixedData.m_enumMethod == (uint)TaskCompletionMethod.enumTMSimpleClientTaskForceNavi && pTask.GetShapeMask() != 0)
{
return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_NO_NAVIGATE_INSHPAED;
}
return 0u;
}
// 特殊活动奖励检查 // English: Special award activity check
public uint CheckSpecialAward(TaskInterface pTask)
{
// 非“特殊活动奖励”类型则直接通过 // English: Pass if not a special-award dynamic task
if (m_FixedData.m_DynTaskType != (byte)DynTaskType.enumDTTSpecialAward) return 0u;
// 未配置特殊奖励标识则失败 // English: Fail if special award id not configured
if (m_FixedData.m_ulSpecialAward == 0u) return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_SPECIAL_AWARD;
// TODO: 获取玩家特殊奖励信息并校验 // English: Fetch player's special-award info and validate against required id
// 受限于当前 TaskInterface 未暴露获取接口,暂时视为通过 // English: Interface lacks API; treat as pass for now
return 0u;
}
}
}
+26 -26
View File
@@ -1132,27 +1132,27 @@ namespace BrewMonster.Scripts.Task
/// <summary>
/// Completion Method
/// </summary>
public enum TaskMethod
{
enumTMNone = 0, // None
enumTMKillNumMonster, // Kill a number of monsters
enumTMCollectNumArticle, // Collect a number of items
enumTMTalkToNPC, // Talk to a specific NPC
enumTMReachSite, // Reach a specific location
enumTMWaitTime, // Wait for a specified time
enumTMAnswerQuestion, // Answer a question
enumTMTinyGame, // Mini-game
enumTMProtectNPC, // Protect a specific NPC
enumTMNPCReachSite, // NPC reaches a specific location
enumTMGlobalValOK, // Global variable condition satisfied
enumTMLeaveSite, // Leave a specific location
enumTMReachTreasureZone, // Reach the treasure area
enumTMKillPlayer, // Kill another player
enumTMTransform, // Transform state
enumTMReachLevel, // Check level: normal level, rebirth count, realm level
enumTMSimpleClientTask, // Simple client task (only client-side validation, currently just checks UI triggers)
enumTMSimpleClientTaskForceNavi // Force navigation
}
// public enum TaskCompletionMethod
// {
// enumTMNone = 0, // None
// enumTMKillNumMonster, // Kill a number of monsters
// enumTMCollectNumArticle, // Collect a number of items
// enumTMTalkToNPC, // Talk to a specific NPC
// enumTMReachSite, // Reach a specific location
// enumTMWaitTime, // Wait for a specified time
// enumTMAnswerQuestion, // Answer a question
// enumTMTinyGame, // Mini-game
// enumTMProtectNPC, // Protect a specific NPC
// enumTMNPCReachSite, // NPC reaches a specific location
// enumTMGlobalValOK, // Global variable condition satisfied
// enumTMLeaveSite, // Leave a specific location
// enumTMReachTreasureZone, // Reach the treasure area
// enumTMKillPlayer, // Kill another player
// enumTMTransform, // Transform state
// enumTMReachLevel, // Check level: normal level, rebirth count, realm level
// enumTMSimpleClientTask, // Simple client task (only client-side validation, currently just checks UI triggers)
// enumTMSimpleClientTaskForceNavi // Force navigation
// }
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct COMPARE_KEY_VALUE
@@ -3989,13 +3989,13 @@ namespace BrewMonster.Scripts.Task
// 根据完成方式设置掩码 // Set mask according to completion method
uint method = m_FixedData.m_enumMethod;
if (method == (uint)TaskMethod.enumTMKillNumMonster)
if (method == (uint)TaskCompletionMethod.enumTMKillNumMonster)
m_ulMask = (uint)TaskInterfaceConstants.TASK_MASK_KILL_MONSTER;
else if (method == (uint)TaskMethod.enumTMCollectNumArticle)
else if (method == (uint)TaskCompletionMethod.enumTMCollectNumArticle)
m_ulMask = (uint)TaskInterfaceConstants.TASK_MASK_COLLECT_ITEM;
else if (method == (uint)TaskMethod.enumTMTalkToNPC)
else if (method == (uint)TaskCompletionMethod.enumTMTalkToNPC)
m_ulMask = (uint)TaskInterfaceConstants.TASK_MASK_TALK_TO_NPC;
else if (method == (uint)TaskMethod.enumTMKillPlayer)
else if (method == (uint)TaskCompletionMethod.enumTMKillPlayer)
m_ulMask = (uint)TaskInterfaceConstants.TASK_MASK_KILL_PLAYER;
// PQ子任务使用对应掩码 // PQ subtask uses corresponding mask
@@ -4031,7 +4031,7 @@ namespace BrewMonster.Scripts.Task
m_FixedData.m_ulNextSibling = (m_pNextSibling != null) ? m_pNextSibling.m_FixedData.m_ID : 0u;
m_FixedData.m_ulPrevSibling = (m_pPrevSibling != null) ? m_pPrevSibling.m_FixedData.m_ID : 0u;
m_FixedData.m_ulFirstChild = (m_pFirstChild != null) ? m_pFirstChild.m_FixedData.m_ID : 0u;
if (m_pFirstChild != null) m_FixedData.m_enumMethod = (uint)TaskMethod.enumTMNone;
if (m_pFirstChild != null) m_FixedData.m_enumMethod = (uint)TaskCompletionMethod.enumTMNone;
}
// 添加子任务到层级结构 // Add sub task to hierarchy
@@ -1,6 +1,11 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
namespace BrewMonster.PerfectWorld.Scripts.Task.UI
{
@@ -8,10 +13,18 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
{
[SerializeField] private TaskTreeViewItem m_pTreeViewItemPrefab;
private TaskTreeViewItem[] m_aTreeViewItems;
[Header("DEBUG")]
[SerializeField] private TaskTreeViewItem _currentSelectedItem = null;
[SerializeField] private TaskTreeViewItem[] m_aTreeViewItems;
private void Start()
{
EventBus.Subscribe<TaskItemClickEvent>(evt =>
{
SetSelectedItem(evt.Data);
});
}
public void SetItemData(TaskTreeViewItem item, uint taskType)
{
item.SetItemData(taskType);
@@ -27,7 +40,7 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
if (m_aTreeViewItems == null)
{
m_aTreeViewItems = GetComponentsInChildren<TaskTreeViewItem>();
m_aTreeViewItems = GetComponentsInChildren<TaskTreeViewItem>(true);
}
for (int i = 0; i < m_aTreeViewItems.Length - 1; i++)
@@ -46,6 +59,7 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
// Create a new item GameObject and component
TaskTreeViewItem pItem = Instantiate(m_pTreeViewItemPrefab);
GameObject go = pItem.gameObject;
// go.name = $"Task_{}";
if (pItem == null) return null;
// Parent: root (this) if null; otherwise under given parent item
@@ -67,11 +81,79 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
// var label = go.GetComponentInChildren<TMPro.TMP_Text>(true);
// if (label != null) label.text = text ?? string.Empty;
pItem.SetItemText(text);
pItem.SetTreeLevel(pParent != null ? pParent.GetTreeLevel() + 1 : 0);
// Refresh local cache of items
m_aTreeViewItems = GetComponentsInChildren<TaskTreeViewItem>();
m_aTreeViewItems = GetComponentsInChildren<TaskTreeViewItem>(true);
// pParent.RefreshLayout();
if(pParent) pParent.SetExpand(false); // Collapse parent to show new item only when expanded
return pItem;
}
public void DeleteAllItems()
{
List<Transform> childrenCopy = new();
foreach (Transform child in transform)
{
// Destroy(child.GetComponent<TaskTreeViewItem>());
childrenCopy.Add(child);
}
foreach (var child in childrenCopy)
{
child.SetParent(null);
Destroy(child.gameObject);
}
m_aTreeViewItems = null;
// m_aTreeViewItems = GetComponentsInChildren<TaskTreeViewItem>(true);
_currentSelectedItem = null;
}
public TaskTreeViewItem GetItemByData(uint taskType)
{
if (m_aTreeViewItems == null)
{
m_aTreeViewItems = GetComponentsInChildren<TaskTreeViewItem>(true);
}
foreach (var item in m_aTreeViewItems)
{
if (item.GetItemData() == taskType)
{
return item;
}
}
return null;
}
public TaskTreeViewItem GetFirstChild()
{
return transform.childCount == 0 ? null : transform.GetChild(0).GetComponent<TaskTreeViewItem>();
}
public TaskTreeViewItem GetSelectedItem()
{
return _currentSelectedItem;
}
void SetSelectedItem(uint idItem)
{
_currentSelectedItem = GetItemByData(idItem);
}
public void RefreshLayout()
{
var parent = GetComponent<RectTransform>();
// Force Unity to rebuild layout immediately
parent.ForceUpdateRectTransforms();
LayoutRebuilder.ForceRebuildLayoutImmediate(parent);
}
}
}
@@ -1,3 +1,4 @@
using System;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
@@ -6,20 +7,53 @@ using UnityEngine.UI;
namespace BrewMonster.PerfectWorld.Scripts.Task.UI
{
public class TaskTreeViewItem : MonoBehaviour, IPointerClickHandler
public class TaskTreeViewItem : MonoBehaviour
{
[SerializeField] private TMP_Text m_text;
[SerializeField] private Button m_Button;
[SerializeField] private Sprite[] _levelSprites;
[SerializeField] private Button _expandButton;
[SerializeField] private Button _collapseButton;
[Header("DEBUG")]
[SerializeField] private uint m_uItemData;
[SerializeField] private int _treeLevel;
private RectTransform _rectTransform;
public UnityEvent<uint> OnClick = new UnityEvent<uint>();
#region UNITY_METHODS
private void Awake()
{
m_Button.onClick.AddListener(OnBtnClick);
_expandButton.onClick.AddListener(OnExpandBtnClicked);
_collapseButton.onClick.AddListener(OnCollapseBtnClicked);
_expandButton.gameObject.SetActive(false);
_collapseButton.gameObject.SetActive(false);
_rectTransform = GetComponent<RectTransform>();
}
// private void Start()
// {
// RectTransform parent = transform.parent.GetComponent<RectTransform>();
// if (parent != null && parent.GetComponent<ContentSizeFitter>())
// {
// // Force Unity to rebuild layout immediately
// parent.ForceUpdateRectTransforms();
// LayoutRebuilder.ForceRebuildLayoutImmediate(parent);
// }
// }
#endregion
#region PUBLIC_METHODS
public void SetItemData(uint uItemData)
{
m_uItemData = uItemData;
gameObject.name = $"Task_{uItemData}";
}
public uint GetItemData()
@@ -43,12 +77,71 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
m_text.text = text;
}
}
public void SetTreeLevel(int level)
{
_treeLevel = level;
Image btnImage = m_Button.GetComponent<Image>();
btnImage.sprite = _treeLevel < _levelSprites.Length ? _levelSprites[_treeLevel] : _levelSprites[^1];
btnImage.SetNativeSize();
}
public int GetTreeLevel() => _treeLevel;
public void SetExpand(bool expand)
{
var children = GetComponentsInChildren<TaskTreeViewItem>(true);
public void OnPointerClick(PointerEventData eventData)
for (int i=1; i<children.Length; i++)
{
if(children[i].GetTreeLevel() == _treeLevel + 1)
children[i].gameObject.SetActive(expand);
}
_expandButton.gameObject.SetActive(!expand);
_collapseButton.gameObject.SetActive(expand);
RefreshLayout();
}
#endregion
// public void OnPointerClick(PointerEventData eventData)
// {
// OnClick.Invoke(m_uItemData);
// EventBus.Publish(new TaskItemClickEvent() { Data = m_uItemData });
// // TaskWindow.Instance.OnEventLButtonDown_Tv_Quest(m_uItemData);
// }
public void RefreshLayout()
{
var rectTransform = _rectTransform;
if (rectTransform == null)
{
return;
}
// Force Unity to rebuild layout immediately
rectTransform.ForceUpdateRectTransforms();
LayoutRebuilder.ForceRebuildLayoutImmediate(rectTransform);
transform.parent.SendMessage("RefreshLayout");
}
void OnBtnClick()
{
OnClick.Invoke(m_uItemData);
// EventBus.Publish(new TaskItemClickEvent() { Data = m_uItemData });
TaskWindow.Instance.OnEventLButtonDown_Tv_Quest(m_uItemData);
EventBus.Publish(new TaskItemClickEvent() { Data = m_uItemData });
}
void OnExpandBtnClicked()
{
SetExpand(expand: true);
}
void OnCollapseBtnClicked()
{
SetExpand(false);
}
}
+410 -66
View File
@@ -7,6 +7,8 @@ using BrewMonster.Network;
using BrewMonster.Scripts.Task;
using CSNetwork.GPDataType;
using ModelRenderer.Scripts.GameData;
using NUnit.Framework;
using PerfectWorld.Scripts.Task;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
@@ -16,7 +18,7 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
/// <summary>
/// This is DlgTask.cpp
/// </summary>
public class TaskWindow : MonoSingleton<TaskWindow>
public class TaskWindow : MonoBehaviour
{
#if UNITY_EDITOR
[ContextMenu("Generate Tasks")]
@@ -94,9 +96,12 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
[SerializeField] protected Button m_pBtn_bShowTrace; // PAUISTILLIMAGEBUTTON -> Button
[SerializeField] protected Button m_pBtn_FinishTask; // PAUISTILLIMAGEBUTTON -> Button
[SerializeField] protected TMP_Text m_pTxt_BaseAward; // PAUILABEL -> TMP_Text
[Space(10)]
[SerializeField] protected Button Btn_TreasureMap; // PAUILABEL -> TMP_Text
[SerializeField] protected Button Btn_TreasureMap;
[SerializeField] protected Button Btn_Focus;
[SerializeField] protected GameObject Lab_QuestNO; // the title label of m_pTxt_QuestNO
// PAUIIMAGEPICTURE m_pImg_Item[CDLGTASK_AWARDITEM_MAX];
// Use fixed-size array semantics via initialization length
@@ -125,26 +130,68 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
// [中文] 任务跟踪计时器
// [English] Task trace counter
private CECCounter m_TaskTraceCounter; // CECCounter -> object placeholder
private CECCounter m_TaskTraceCounter = new (); // CECCounter -> object placeholder
#region Unity METHODS
private void Start()
private void OnEnable()
{
OnInitDialog();
OnShowDialog();
}
private void Awake()
{
EventBus.Subscribe<TaskItemClickEvent>(evt =>
{
OnEventLButtonDown_Tv_Quest(evt.Data);
});
// EventBus.Subscribe<TaskItemClickEvent>(evt =>
// {
// OnEventLButtonDown_Tv_Quest(evt.Data);
// });
m_pBtn_HaveQuest.onClick.AddListener(OnCommand_havequest);
m_pBtn_SearchQuest.onClick.AddListener(OnCommand_searchquest);
OnInitDialog();
}
private void Update()
{
Tick();
}
#endregion
#region PUBLIC METHODS
public void OnCommand_searchquest(string szCommand) {}
public void OnCommand_havequest(string szCommand) {}
public void OnCommand_searchquest()
{
// if (m_szName != "Win_Quest") return;
m_iType = 1;
// TODO
// PAUIOBJECT pObj = GetDlgItem("Img_New");
// if (pObj && IsShow()) pObj->Show(false);
// if(GetDlgItem("Lab_Trace")) GetDlgItem("Lab_Trace")->Show(false);
if(m_pBtn_bShowTrace) m_pBtn_bShowTrace.gameObject.SetActive(false);
m_pBtn_Abandon.gameObject.SetActive(false);
Btn_Focus.gameObject.SetActive(false);
Lab_QuestNO.gameObject.SetActive(false);
m_pTxt_QuestNO.gameObject.SetActive(false);
m_pBtn_SearchQuest.interactable = false;
m_pBtn_HaveQuest.interactable = true;
SearchForTask();
}
public void OnCommand_havequest()
{
m_iType = 0;
// TODO: if(GetDlgItem("Lab_Trace")) GetDlgItem("Lab_Trace")->Show(true);
if(m_pBtn_bShowTrace) m_pBtn_bShowTrace.gameObject.SetActive(true);
m_pBtn_Abandon.gameObject.SetActive(true);
Btn_Focus.gameObject.SetActive(true);
Lab_QuestNO.gameObject.SetActive(true);
m_pTxt_QuestNO.gameObject.SetActive(true);
m_pBtn_SearchQuest.interactable = true;
m_pBtn_HaveQuest.interactable = false;
UpdateTask();
}
public void OnCommand_showtrace(string szCommand) {}
public void OnCommand_focus(string szCommand) {}
public void OnCommand_abandon(string szCommand) {}
@@ -155,7 +202,36 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
public void OnEventLButtonDown_Tv_Quest(uint itemData)
{
UpdateTask((int)itemData);
// UpdateTask((int)itemData);
// POINT ptPos = pObj->GetPos();
// A3DVIEWPORTPARAM *p = m_pA3DEngine->GetActiveViewport()->GetParam();
// int x = GET_X_LPARAM(lParam) - ptPos.x - p->X;
// int y = GET_Y_LPARAM(lParam) - ptPos.y - p->Y;
// PAUITREEVIEW pTree = (PAUITREEVIEW)pObj;
//
// if( AUI_PRESS(VK_SHIFT) && m_iType == 0)
// {
// P_AUITREEVIEW_ITEM pItem = pTree->HitTest(x, y);
//
// if( pItem ) OnCommand_focus("focus");
// }
// P_AUITREEVIEW_ITEM pItem = pTree->GetSelectedItem();
// var pItem = m_pTv_Quest.GetItemByData(itemData);
int idTask = (int)itemData;
// int idTask(0);
// if( pItem && pTree->GetParentItem(pItem) != pTree->GetRootItem())
// idTask = pTree->GetItemData(pItem);
//
if (idTask == 0) return;
//
// if (m_szName == "Win_Quest" && CDlgAutoHelp::IsAutoHelp())
// {
// if(pTree->GetHitArea(x,y) == AUITREEVIEW_RECT_FRAME)
// CDlgWikiShortcut::PopQuestWiki(GetGameUIMan(),idTask);
// }
m_idSelTask = idTask;
}
// void OnEventMouseMove_Txt_QuestItem(WPARAM wParam, LPARAM lParam, AUIObject *pObj);
// void OnEventLButtonDown_Txt_QuestItem(WPARAM wParam, LPARAM lParam, AUIObject *pObj);
@@ -184,9 +260,9 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
private static string GetTaskNameWithColor(ATaskTempl pTempl)
{
if (pTempl == null) return string.Empty;
var type = (BrewMonster.Scripts.Task.ENUM_TASK_TYPE)pTempl.m_FixedData.m_ulType;
var type = (ENUM_TASK_TYPE)pTempl.m_FixedData.m_ulType;
string rawName = ModelRenderer.Scripts.Common.ByteToStringUtils.UshortArrayToUnicodeString(pTempl.m_FixedData.m_szName);
if (type == BrewMonster.Scripts.Task.ENUM_TASK_TYPE.enumTTQiShaList && !string.IsNullOrEmpty(rawName) && rawName[0] == '^')
if (type == ENUM_TASK_TYPE.enumTTQiShaList && !string.IsNullOrEmpty(rawName) && rawName[0] == '^')
{
// 如果是七杀榜任务且已经加了颜色,则颜色不变 // If QiShaList task already has color, keep it
return rawName;
@@ -221,7 +297,50 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
return string.Empty;
}
//
// void TickTaskTrace();
private bool Tick()
{
// if( m_szName == "Win_Quest" && IsShow() )
{
var pTree = m_pTv_Quest;
var pItem = pTree.GetSelectedItem();
if( pItem )
{
for( int i = 0; i < m_ImgCount; i++ )
m_pImg_Item[i].gameObject.SetActive(false);
m_pTxt_BaseAward.gameObject.SetActive(false);
// if( pTree->GetParentItem(pItem) != pTree->GetRootItem() )
if( pTree.transform != pItem.transform.parent )
{
if (m_iType == 0)
{
UpdateTask((int)pTree.GetItemData(pItem));
}
else if (m_iType == 1)
{
SearchForTask((int)pTree.GetItemData(pItem));
}
}
else
{
m_idLastTask = -2;
m_pTxt_Content.SetText("");
m_pTxt_QuestItem.SetText("");
m_pBtn_Abandon.interactable = false;
UpdateTaskConfirm(0, false);
Btn_TreasureMap.interactable = false;
}
}
// TODO
// UpdateGotoNPC();
}
// return CDlgBase::Tick();
return true;
}
//
// void RefreshTaskTrace();
public bool UpdateTask(int idTask = -1)
@@ -270,7 +389,7 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
bLastTaskChanged = true;
}
m_pBtn_Abandon.gameObject.SetActive(pMan.CanGiveUpTask((uint)idTask));
m_pBtn_Abandon.interactable = pMan.CanGiveUpTask((uint)idTask);
// Get info
Task_State_info tsi = new Task_State_info();
@@ -280,11 +399,11 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
strNewTextItem = "";
// Base desc
UpdateTaskBaseDesc(strNewTextItem, tsi);
UpdateTaskBaseDesc(ref strNewTextItem, tsi);
// Award NPC
int nANPC = (int)pTemp.GetAwardNPC();
UpdateAwardNPC(strNewTextItem, nANPC);
UpdateAwardNPC(ref strNewTextItem, nANPC);
// Complete condition
UpdateCompleteCondition(ref strNewTextItem, ref strNewHintItem, tsi);
@@ -293,7 +412,7 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
UpdateItemWanted(ref strNewTextItem, tsi, idTask);
// Treasure Map
UpdateTreasureMap(strNewTextItem);
UpdateTreasureMap(ref strNewTextItem);
// Task Confirm
UpdateTaskConfirm(idTask, pTemp.m_FixedData.m_enumFinishType == (uint)TaskFinishType.enumTFTConfirm);
@@ -310,9 +429,13 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
if (Btn_TreasureMap != null)
{
Btn_TreasureMap.gameObject.
SetActive(pTemp.m_FixedData.m_enumMethod == (uint)TaskMethod.enumTMReachTreasureZone);
SetActive(pTemp.m_FixedData.m_enumMethod == (uint)TaskCompletionMethod.enumTMReachTreasureZone);
}
}
else
{
Debug.LogError($"Task {idTask} not found ATaskTempl !!!");
}
}
else
{
@@ -339,7 +462,127 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
return true;
}
//
// bool SearchForTask(int idTask = -1);
// Guard: only handle search list when current UI type is 1 (search)
public bool SearchForTask(int idTask = -1)
{
if (m_iType != 1)
{
return true;
}
// Setup managers and UI references
ATaskTemplMan pMan = EC_Game.GetTaskTemplateMan();
CECTaskInterface pTask = GetHostPlayer().GetTaskInterface();
var pTextDesc = m_pTxt_Content;
var pTextItem = m_pTxt_QuestItem;
// Track composed text buffers and change flag
string strNewTextItem = "";
string strNewHintItem = "";
bool bLastTaskChanged = false;
// Simplified: assume we are in quest UI context if tree exists
bool bQuestUI = m_pTv_Quest != null;
// When a concrete task id is provided
if (idTask >= 0)
{
ATaskTempl pTemp = pMan != null ? pMan.GetTaskTemplByID((uint)idTask) : null;
if (pTemp != null)
{
// Update description when the selected task changes
if (idTask != m_idLastTask)
{
if (pTextDesc != null) pTextDesc.SetText(pTemp.GetDescription());
m_idLastTask = idTask;
bLastTaskChanged = true;
}
// Optional: update tree item text if needed (skip if API not available)
if (bQuestUI)
{
var pItem = m_pTv_Quest.GetSelectedItem();
if (pItem != null)
{
uint id = m_pTv_Quest.GetItemData(pItem);
// NOTE: ATaskTemplMan.IsTaskToPush may be conditionally compiled; avoid hard dependency
// If needed, uncomment when method is available:
// if (pMan.IsTaskToPush((int)id)) m_pTv_Quest.SetItemText(pItem, GetTaskNameWithColor(pTemp));
}
}
// Get task state info
Task_State_info tsi = default;
if (pTask != null) pTask.GetTaskStateInfo((uint)idTask, ref tsi, false);
// Reset composed text buffer
strNewTextItem = "";
// Append: base description
UpdateTaskBaseDesc(ref strNewTextItem, tsi);
// Append: deliver NPC
UpdateDeliverNPC(ref strNewTextItem, (int)pTemp.GetDeliverNPC());
// Append: award NPC
int nANPC = (int)pTemp.GetAwardNPC();
UpdateAwardNPC(ref strNewTextItem, nANPC);
// Append: completion conditions
UpdateCompleteCondition(ref strNewTextItem, ref strNewHintItem, tsi);
// Append: wanted items
UpdateItemWanted(ref strNewTextItem, tsi, idTask);
// Preview and show awards
Task_Award_Preview award = default;
if (pTask != null) pTask.GetTaskAwardPreview((uint)idTask, ref award);
UpdateBaseAward(award);
UpdateItemAward(award);
}
else
{
// No template found for id: clear content
m_idLastTask = -2;
if (m_pTxt_Content != null) m_pTxt_Content.SetText("");
if (m_pTxt_QuestItem != null) m_pTxt_QuestItem.SetText("");
}
}
else
{
// zhangyitian 20140521 先将可接任务列表清空,再判断是否有可接任务
// zhangyitian 20140521 First clear the available tasks list, then check if there are available tasks
// 修正了原先没有可接任务时,可接任务列表显示已接任务的问题
// Fix: prevent accepted tasks from showing when there are no available tasks
ClearContent(false);
// TaskTemplLst ttl;
List<ATaskTempl> ttl = new List<ATaskTempl>(); // TaskTemplLst -> List<ATaskTempl>
pMan.GetAvailableTasks(pTask, ttl);
if( ttl.Count <= 0 ) return true;
for(int i = 0; i < ttl.Count; i++ )
{
int id = (int)ttl[i].GetID();
AddTaskNode(id);
}
SortTaskNodeByType();
// string strTemp;
// ActiveTaskList pLst = (ActiveTaskList)pTask.GetActiveTaskList();
// int iMaxTaskCount = pLst->GetMaxSimultaneousCount();
// strTemp.Format(_AL("%d/%d"), pTask->GetTaskCount(), iMaxTaskCount);
// m_pTxt_QuestNO->SetText(strTemp);
}
// Apply colors and set composed text into UI
bool hasTempl = idTask >= 0 && pMan != null && pMan.GetTaskTemplByID((uint)idTask) != null;
SetTextItemText(strNewTextItem, hasTempl && !bLastTaskChanged, strNewHintItem);
// Done
return true;
}
//
// //бɽѽ zhangyitian
// bool UpdateQuestView();
@@ -421,7 +664,11 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
}
//
// virtual bool OnInitDialog();
// virtual void OnShowDialog();
void OnShowDialog()
{
if (m_idSelTask != 0)
UpdateTask();
}
// virtual void OnHideDialog();
// virtual bool OnChangeLayout(PAUIOBJECT pMine, PAUIOBJECT pTheir);
// virtual void OnChangeLayoutEnd(bool bAllDone);
@@ -464,8 +711,8 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
if (pTextItem == null) return;
// Preserve scroll position if inside a ScrollRect
UnityEngine.UI.ScrollRect scrollRect = pTextItem.GetComponentInParent<UnityEngine.UI.ScrollRect>();
float oldNormPos = scrollRect != null ? scrollRect.verticalNormalizedPosition : 0f;
// UnityEngine.UI.ScrollRect scrollRect = pTextItem.GetComponentInParent<UnityEngine.UI.ScrollRect>();
// float oldNormPos = scrollRect != null ? scrollRect.verticalNormalizedPosition : 0f;
if (!string.Equals(strNewTextItem, pTextItem.text))
{
@@ -473,11 +720,11 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
// TODO: apply hint to a tooltip UI if available (strNewHintItem)
}
if (keepScrollPos && scrollRect != null)
{
// Restore previous scroll position
scrollRect.verticalNormalizedPosition = oldNormPos;
}
// if (keepScrollPos && scrollRect != null)
// {
// // Restore previous scroll position
// scrollRect.verticalNormalizedPosition = oldNormPos;
// }
}
// void SetTaskText(PAUIOBJECT pObj, ACString* pStr);
@@ -495,36 +742,43 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
var sb = new System.Text.StringBuilder();
int colCount = 0;
const int col = 3;
int cellSpace = 30;
if (award.m_ulGold > 0)
{
sb.Append(string.Format(GetStringFromTable(3201), award.m_ulGold));
if ((++colCount) % col == 0) sb.Append("\r");
var text = $"{GetStringFromTable(3201)} {award.m_ulGold}";
sb.Append(text);
sb.Append(' ', cellSpace - text.Length);
if ((++colCount) % col == 0) sb.Append("\n");
}
if (award.m_ulExp > 0)
{
sb.Append(string.Format(GetStringFromTable(3202), award.m_ulExp));
if ((++colCount) % col == 0) sb.Append("\r");
var text = $"{GetStringFromTable(3201)} {award.m_ulExp}";
sb.Append(text);
sb.Append(' ', cellSpace - text.Length);
if ((++colCount) % col == 0) sb.Append("\n");
}
if (award.m_ulSP > 0)
{
sb.Append(string.Format(GetStringFromTable(3203), award.m_ulSP));
if ((++colCount) % col == 0) sb.Append("\r");
var text = $"{GetStringFromTable(3201)} {award.m_ulSP}";
sb.Append(text);
sb.Append(' ', cellSpace - text.Length);
if ((++colCount) % col == 0) sb.Append("\n");
}
if (award.m_ulRealmExp > 0)
{
sb.Append(string.Format(GetStringFromTable(3207), award.m_ulRealmExp));
if ((++colCount) % col == 0) sb.Append("\r");
sb.Append($"{GetStringFromTable(3207)} {award.m_ulRealmExp}");
if ((++colCount) % col == 0) sb.Append("\n");
}
if (award.m_iForceContrib > 0)
{
sb.Append(string.Format(GetStringFromTable(3205), award.m_iForceContrib));
if ((++colCount) % col == 0) sb.Append("\r");
sb.Append($"{GetStringFromTable(3205)} {award.m_iForceContrib}");
if ((++colCount) % col == 0) sb.Append("\n");
}
if (award.m_iForceRepu > 0)
{
sb.Append(string.Format(GetStringFromTable(3206), award.m_iForceRepu));
if ((++colCount) % col == 0) sb.Append("\r");
sb.Append($"{GetStringFromTable(3206)} {award.m_iForceRepu}");
if ((++colCount) % col == 0) sb.Append("\n");
}
if (sb.Length > 0 && m_pTxt_BaseAward != null)
@@ -543,7 +797,7 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
{
if (m_pTxt_BaseAward != null && m_pTxt_BaseAward.gameObject.activeSelf)
{
string strAward = (GetStringFromTable(3204) ?? string.Empty) + "\r" + (m_pTxt_BaseAward.text ?? string.Empty);
string strAward = (GetStringFromTable(3204) ?? string.Empty) + "\n" + (m_pTxt_BaseAward.text ?? string.Empty);
m_pTxt_BaseAward.text = strAward;
}
else if (m_pTxt_BaseAward != null)
@@ -589,7 +843,7 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
else txtRT.anchoredPosition = pos;
}
}
private void UpdateTaskBaseDesc(string strText, Task_State_info tsi)
private void UpdateTaskBaseDesc(ref string strText, Task_State_info tsi)
{
// Build the base description text from task state
var sb = new System.Text.StringBuilder();
@@ -641,35 +895,120 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
}
// Apply to content text
if (m_pTxt_Content != null)
{
m_pTxt_Content.text += sb.ToString();
}
// if (m_pTxt_Content != null)
// {
// m_pTxt_Content.text += sb.ToString();
// }
strText += sb.ToString();
}
private static string FormatTime(int nSec, string desc, int timeLimit)
{
var ts = System.TimeSpan.FromSeconds(System.Math.Max(0, nSec));
string label = string.IsNullOrEmpty(desc) ? string.Empty : desc;
return $"{label}{ts:hh\\:mm\\:ss}\r";
return $"{label}{ts:hh\\:mm\\:ss}\n";
}
private static string GetStringFromTable(int id)
{
return BrewMonster.Network.EC_Game.GetFixedMsgs()?.GetWideString(id) ?? string.Empty;
// TODO: return AUIManager.GetStringFromTable(id);
// HARD CODED STRINGS
switch (id)
{
case 3101:
return "Hàng ngày";
case 3102:
return "Tu chân";
case 3103:
return "Chủ tuyến";
case 3104:
return "Phụ tuyến";
case 3105:
return "Event";
case 3106:
return "7 Killer List";
case 3107:
return "Bang hội";
case 3108:
return "Management";
case 3109:
return "Huyền thoại";
case 3110:
return "Câu hỏi";
case 3201:
return "Gold:";
case 3202:
return "EXP:";
case 3203:
return "SP:";
case 3207:
return "Realm EXP:";
case 3205:
return "Contribution:";
case 3206:
return "Reputation:";
case 7621:
return "NPC giao nhiệm vụ: ";
default:
return $"UnKnown_{id} ";
}
}
private static string GetStringFromTable(uint id)
{
return BrewMonster.Network.EC_Game.GetFixedMsgs()?.GetWideString((int)id) ?? string.Empty;
// return AUIManager.GetStringFromTable(id);
return GetStringFromTable((int)id);
}
private static string GetFixedMsg(uint id)
{
return BrewMonster.Network.EC_Game.GetFixedMsgs()?.GetWideString((int)id) ?? string.Empty;
}
// void UpdateDeliverNPC(ACString& strText, int nDNPC);
private A3DVECTOR3 UpdateAwardNPC(string strText, int nANPC)
private void UpdateDeliverNPC(ref string strText, int nDNPC)
{
// [中文] 交付NPC
// [English] Deliver NPC
if (nDNPC == 0)
{
return;
}
// [中文] 从元素数据中查找NPC
// [English] Lookup NPC from element data
string npcName = string.Empty;
var edm = BrewMonster.ElementDataManProvider.GetElementDataMan();
if (edm != null)
{
if (edm.essence_id_data_type_map.TryGetValue((uint)nDNPC, out var dtype)
&& dtype == DATA_TYPE.DT_NPC_ESSENCE
&& edm.essence_id_data_map.TryGetValue((uint)nDNPC, out var obj)
&& obj is NPC_ESSENCE npc)
{
npcName = npc.Name;
}
}
if (string.IsNullOrEmpty(npcName)) npcName = nDNPC.ToString();
// [中文] 追加到内容文本
// [English] Append to content text
var sb = new System.Text.StringBuilder();
sb.Append(GetStringFromTable(7620));
sb.Append(npcName);
sb.Append("\n");
// if (m_pTxt_QuestItem != null)
// {
// Debug.Log($"UpdateDeliverNPC: {sb.ToString()}");
// m_pTxt_QuestItem.text += sb.ToString();
// }
strText += sb.ToString();
}
private A3DVECTOR3 UpdateAwardNPC(ref string strText, int nANPC)
{
A3DVECTOR3 ret = new A3DVECTOR3(0f);
// Award NPC
@@ -697,11 +1036,14 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
var sb = new System.Text.StringBuilder();
sb.Append(GetStringFromTable(7621));
sb.Append(npcName);
sb.Append("\r");
if (m_pTxt_Content != null)
{
m_pTxt_Content.text += sb.ToString();
}
sb.Append("\n");
// if (m_pTxt_Content != null)
// {
// Debug.Log($"Award NPC: {sb.ToString()}");
// m_pTxt_QuestItem.text += sb.ToString();
// }
strText += sb.ToString();
return ret;
}
@@ -821,7 +1163,7 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
{
uint killed = tsi.m_PlayerWanted[index].m_ulPlayersKilled;
uint toKill = tsi.m_PlayerWanted[index].m_ulPlayersToKill;
return $" {killed}/{toKill}\r";
return $" {killed}/{toKill}\n";
}
// Get host reincarnation count (fallback implementation)
@@ -872,14 +1214,14 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
// If task is KillPlayer, also add player requirements line
// 若为击杀玩家任务,同时追加玩家需求行
if (pTempl.m_FixedData.m_enumMethod == (uint)TaskMethod.enumTMKillPlayer && i < TaskInterfaceConstants.MAX_PLAYER_WANTED)
if (pTempl.m_FixedData.m_enumMethod == (uint)TaskCompletionMethod.enumTMKillPlayer && i < TaskInterfaceConstants.MAX_PLAYER_WANTED)
{
strText += GetKillPlayerRequirements(tsi, i);
}
}
}
private void UpdateTreasureMap(string strText)
private void UpdateTreasureMap(ref string strText)
{
// if (IsTreasureMapSelected())
// {
@@ -924,7 +1266,7 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
}
// TODO: Clear Tree quest view
// m_pTv_Quest.DeleteAllItems();
m_pTv_Quest.DeleteAllItems();
}
// // add node to task tree
void AddTaskNode(int id)
@@ -943,7 +1285,8 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
uint nAfterType = 0;
TaskTreeViewItem pAfter = null, pParent = null;
// P_AUITREEVIEW_ITEM pItem = pTreeTask->GetFirstChildItem(pTreeTask->GetRootItem());
var pItem = pTreeTask.transform.parent.GetChild(0).GetComponent<TaskTreeViewItem>();
// var pItem = pTreeTask.transform.parent.GetChild(0).GetComponent<TaskTreeViewItem>();
var pItem = pTreeTask.GetFirstChild();
while( pItem )
{
uint nType = pItem.GetItemData();
@@ -958,6 +1301,7 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
pItem = pTreeTask.GetNextSiblingItem(pItem);
}
// add Biggest node if not exist
if(pParent ==null)
{
pParent = pTreeTask.InsertItem(GetStringFromTable(3101 + nTaskType - 100), null, pAfter);
@@ -966,7 +1310,7 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
pTreeTask.SetItemData(pParent, nTaskType);
//if(nTaskType == enumTTLevel2)
//pTreeTask.SetItemTextColor(pParent, GetTaskColor(pTemp));
// pTreeTask.SetItemTextColor(pParent, GetTaskColor(pTemp));
}
CECTaskInterface pTask = GetHostPlayer().GetTaskInterface();
@@ -1000,7 +1344,7 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
// Collect direct children under the tree root (this component's transform)
int childCount = pTreeTask.transform.childCount;
var items = new System.Collections.Generic.List<(uint type, TaskTreeViewItem item)>(childCount);
var items = new List<(uint type, TaskTreeViewItem item)>(childCount);
for (int i = 0; i < childCount; i++)
{
var child = pTreeTask.transform.GetChild(i).GetComponent<TaskTreeViewItem>();