Browse Source

Initial commit

jamesperet 2 years ago
commit
30828f0581
100 changed files with 4166 additions and 0 deletions
  1. 102 0
      CharacterGenerator.prefab
  2. 10 0
      CharacterGenerator.prefab.meta
  3. 48 0
      CharacterManager.prefab
  4. 10 0
      CharacterManager.prefab.meta
  5. 8 0
      Editor.meta
  6. 8 0
      Editor/Icons.meta
  7. BIN
      Editor/Icons/People.png
  8. 91 0
      Editor/Icons/People.png.meta
  9. BIN
      Editor/Icons/Person.png
  10. 91 0
      Editor/Icons/Person.png.meta
  11. 8 0
      Runtime.meta
  12. 8 0
      Runtime/Actions.meta
  13. 67 0
      Runtime/Actions/CharacterAimAction.cs
  14. 11 0
      Runtime/Actions/CharacterAimAction.cs.meta
  15. 81 0
      Runtime/Actions/CharacterEquipItemAction.cs
  16. 11 0
      Runtime/Actions/CharacterEquipItemAction.cs.meta
  17. 103 0
      Runtime/Actions/CharacterFollowTargetAction.cs
  18. 11 0
      Runtime/Actions/CharacterFollowTargetAction.cs.meta
  19. 71 0
      Runtime/Actions/CharacterHandWeaponAttackAction.cs
  20. 11 0
      Runtime/Actions/CharacterHandWeaponAttackAction.cs.meta
  21. 84 0
      Runtime/Actions/CharacterMoveAction.cs
  22. 11 0
      Runtime/Actions/CharacterMoveAction.cs.meta
  23. 112 0
      Runtime/Actions/CharacterMoveToPositionAction.cs
  24. 11 0
      Runtime/Actions/CharacterMoveToPositionAction.cs.meta
  25. 69 0
      Runtime/Actions/CharacterPickupItemAction.cs
  26. 11 0
      Runtime/Actions/CharacterPickupItemAction.cs.meta
  27. 38 0
      Runtime/Actions/CharacterRelaxIdleAction.cs
  28. 11 0
      Runtime/Actions/CharacterRelaxIdleAction.cs.meta
  29. 81 0
      Runtime/Actions/CharacterReloadFirearmAction.cs
  30. 11 0
      Runtime/Actions/CharacterReloadFirearmAction.cs.meta
  31. 53 0
      Runtime/Actions/CharacterShootAction.cs
  32. 11 0
      Runtime/Actions/CharacterShootAction.cs.meta
  33. 44 0
      Runtime/Actions/CharacterTurnToPointAction.cs
  34. 11 0
      Runtime/Actions/CharacterTurnToPointAction.cs.meta
  35. 57 0
      Runtime/Actions/CharacterUnarmedAttackAction.cs
  36. 11 0
      Runtime/Actions/CharacterUnarmedAttackAction.cs.meta
  37. 39 0
      Runtime/Actions/CharacterUnequipItemAction.cs
  38. 11 0
      Runtime/Actions/CharacterUnequipItemAction.cs.meta
  39. 69 0
      Runtime/Actions/DropItemAction.cs
  40. 11 0
      Runtime/Actions/DropItemAction.cs.meta
  41. 62 0
      Runtime/Actions/UseInstantEffectItemAction.cs
  42. 11 0
      Runtime/Actions/UseInstantEffectItemAction.cs.meta
  43. 83 0
      Runtime/Actions/ZombieAttackAction.cs
  44. 11 0
      Runtime/Actions/ZombieAttackAction.cs.meta
  45. 165 0
      Runtime/Actions/ZombieFollowTargetAction.cs
  46. 11 0
      Runtime/Actions/ZombieFollowTargetAction.cs.meta
  47. 49 0
      Runtime/Actions/ZombieIdleAction.cs
  48. 11 0
      Runtime/Actions/ZombieIdleAction.cs.meta
  49. 154 0
      Runtime/Actions/ZombieMoveToPositionAction.cs
  50. 11 0
      Runtime/Actions/ZombieMoveToPositionAction.cs.meta
  51. 8 0
      Runtime/Behaviors.meta
  52. 112 0
      Runtime/Behaviors/BehaviorDebuger.cs
  53. 11 0
      Runtime/Behaviors/BehaviorDebuger.cs.meta
  54. 21 0
      Runtime/Behaviors/BehaviorDebugerDataUi.cs
  55. 11 0
      Runtime/Behaviors/BehaviorDebugerDataUi.cs.meta
  56. 203 0
      Runtime/Behaviors/BehaviorDebugerUi.cs
  57. 11 0
      Runtime/Behaviors/BehaviorDebugerUi.cs.meta
  58. 8 0
      Runtime/Behaviors/TasksActions.meta
  59. 30 0
      Runtime/Behaviors/TasksActions/CancelActionsTaskAction.cs
  60. 11 0
      Runtime/Behaviors/TasksActions/CancelActionsTaskAction.cs.meta
  61. 39 0
      Runtime/Behaviors/TasksActions/ChangeHitpointsTaskAction.cs
  62. 11 0
      Runtime/Behaviors/TasksActions/ChangeHitpointsTaskAction.cs.meta
  63. 43 0
      Runtime/Behaviors/TasksActions/CharacteCheckDamageTaskAction.cs
  64. 11 0
      Runtime/Behaviors/TasksActions/CharacteCheckDamageTaskAction.cs.meta
  65. 51 0
      Runtime/Behaviors/TasksActions/CharacteCheckForInteractionTaskAction.cs
  66. 11 0
      Runtime/Behaviors/TasksActions/CharacteCheckForInteractionTaskAction.cs.meta
  67. 33 0
      Runtime/Behaviors/TasksActions/CharacterAimTaskAction.cs
  68. 11 0
      Runtime/Behaviors/TasksActions/CharacterAimTaskAction.cs.meta
  69. 25 0
      Runtime/Behaviors/TasksActions/CharacterEquipWeaponTaskAction.cs
  70. 11 0
      Runtime/Behaviors/TasksActions/CharacterEquipWeaponTaskAction.cs.meta
  71. 51 0
      Runtime/Behaviors/TasksActions/CharacterHandWeaponAttackTaskAction.cs
  72. 11 0
      Runtime/Behaviors/TasksActions/CharacterHandWeaponAttackTaskAction.cs.meta
  73. 23 0
      Runtime/Behaviors/TasksActions/CharacterIdleTaskAction.cs
  74. 11 0
      Runtime/Behaviors/TasksActions/CharacterIdleTaskAction.cs.meta
  75. 60 0
      Runtime/Behaviors/TasksActions/CharacterMoveToPositionTaskAction.cs
  76. 11 0
      Runtime/Behaviors/TasksActions/CharacterMoveToPositionTaskAction.cs.meta
  77. 96 0
      Runtime/Behaviors/TasksActions/CharacterMoveToTargetTaskAction.cs
  78. 11 0
      Runtime/Behaviors/TasksActions/CharacterMoveToTargetTaskAction.cs.meta
  79. 50 0
      Runtime/Behaviors/TasksActions/CharacterReloadTaskAction.cs
  80. 11 0
      Runtime/Behaviors/TasksActions/CharacterReloadTaskAction.cs.meta
  81. 69 0
      Runtime/Behaviors/TasksActions/CharacterShootTaskAction.cs
  82. 11 0
      Runtime/Behaviors/TasksActions/CharacterShootTaskAction.cs.meta
  83. 51 0
      Runtime/Behaviors/TasksActions/CharacterUnarmedAttackTaskAction.cs
  84. 11 0
      Runtime/Behaviors/TasksActions/CharacterUnarmedAttackTaskAction.cs.meta
  85. 29 0
      Runtime/Behaviors/TasksActions/CharacterUnequipWeaponTaskAction.cs
  86. 11 0
      Runtime/Behaviors/TasksActions/CharacterUnequipWeaponTaskAction.cs.meta
  87. 68 0
      Runtime/Behaviors/TasksActions/DialogueTradeTaskAction.cs
  88. 11 0
      Runtime/Behaviors/TasksActions/DialogueTradeTaskAction.cs.meta
  89. 28 0
      Runtime/Behaviors/TasksActions/GetArenaRoundTaskAction.cs
  90. 11 0
      Runtime/Behaviors/TasksActions/GetArenaRoundTaskAction.cs.meta
  91. 26 0
      Runtime/Behaviors/TasksActions/VariableIsNullTaskCondition.cs
  92. 11 0
      Runtime/Behaviors/TasksActions/VariableIsNullTaskCondition.cs.meta
  93. 47 0
      Runtime/CharacterAnimator.cs
  94. 11 0
      Runtime/CharacterAnimator.cs.meta
  95. 303 0
      Runtime/CharacterController.cs
  96. 11 0
      Runtime/CharacterController.cs.meta
  97. 264 0
      Runtime/CharacterGenerator.cs
  98. 11 0
      Runtime/CharacterGenerator.cs.meta
  99. 90 0
      Runtime/CharacterManager.cs
  100. 11 0
      Runtime/CharacterManager.cs.meta

+ 102 - 0
CharacterGenerator.prefab

@@ -0,0 +1,102 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!1 &7068961173843485952
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 7686989134225945538}
+  - component: {fileID: 675346338255240050}
+  m_Layer: 0
+  m_Name: CharacterGenerator
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &7686989134225945538
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7068961173843485952}
+  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_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &675346338255240050
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7068961173843485952}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: e1751006faeecae44a0de9ad0dd1e9f9, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  characterTemplatePrefab: {fileID: 5337197014172717765, guid: dfa7140cec3127d419d0e473072b4f76, type: 3}
+  modelList:
+  - {fileID: 11400000, guid: 535009b47307c004cb2636a3376968db, type: 2}
+  - {fileID: 11400000, guid: c291462f17c37374bb719e5e18ecacd7, type: 2}
+  - {fileID: 11400000, guid: dc985acc0429ae14d82361801ae2ff75, type: 2}
+  - {fileID: 11400000, guid: 92d76cc8e30b08b46837bf3dd7bc8290, type: 2}
+  - {fileID: 11400000, guid: fe2d25866066d9b4fad21e092bce9f44, type: 2}
+  - {fileID: 11400000, guid: 171ecf90b56e7f24b97f0ddba65278a5, type: 2}
+  - {fileID: 11400000, guid: a13bcae36376d1b439c843088a9b14ae, type: 2}
+  - {fileID: 11400000, guid: b92930c82237bce478ec357d13657e8c, type: 2}
+  - {fileID: 11400000, guid: a35b8589ac3cbf443800ef99fde1e75e, type: 2}
+  - {fileID: 11400000, guid: e8900f034df516049bf81462e3e7e8d2, type: 2}
+  - {fileID: 11400000, guid: 196ff8c0173d05940ada65eadaab1f6e, type: 2}
+  - {fileID: 11400000, guid: f4d61aabfa69f824fba27f5b5dc9de6e, type: 2}
+  - {fileID: 11400000, guid: 471bd8870f023e04c9cf1a9b991385c0, type: 2}
+  - {fileID: 11400000, guid: 8865c0449fb342e4ebdc8dbf1dafe6aa, type: 2}
+  - {fileID: 11400000, guid: 123106b426aa52546add5e7612acf903, type: 2}
+  - {fileID: 11400000, guid: 3c2ec5495301548479c669385d75d490, type: 2}
+  - {fileID: 11400000, guid: 2360fe07250efde43a17a0b03a9339c6, type: 2}
+  - {fileID: 11400000, guid: 71102b1805eed5042bf06073a88091cd, type: 2}
+  - {fileID: 11400000, guid: 81a67fcd22e77f74e84a564ec563bda6, type: 2}
+  - {fileID: 11400000, guid: 0baf5d0d502ea5549904662ac5dd2544, type: 2}
+  - {fileID: 11400000, guid: 95c5338f7fbcb5744b96f7dfff50e5da, type: 2}
+  - {fileID: 11400000, guid: fe783fa13e6b6834c8d5944d9c016202, type: 2}
+  attachmentList:
+  - {fileID: 1668522598004895191, guid: 3e50203f5ae7c0344a329a6b62c97e21, type: 3}
+  - {fileID: 7273525969673868924, guid: f4a0d586f0f66094fad42a7321380367, type: 3}
+  - {fileID: 3040375321991730667, guid: 9c8e5c1b8e6178045bbbd2232ce32ef1, type: 3}
+  - {fileID: 4449477603875427338, guid: bfa0cb130f973014892cf258c84a4d36, type: 3}
+  - {fileID: 2471888018012477334, guid: a3af10025342d0449b8657fed0803d94, type: 3}
+  - {fileID: 4695922413020658502, guid: 90bc4dd35000f4c42a531c69878d81d3, type: 3}
+  - {fileID: 923775054116990909, guid: 7edb95c5db467424fab93e02e30b098f, type: 3}
+  - {fileID: 4325926411410164515, guid: cbf1d395c0e999045a95e863d8e541e2, type: 3}
+  - {fileID: 6543265906354144191, guid: 381581992eacfd2448def4da4c28c469, type: 3}
+  - {fileID: 1798949510627768296, guid: 336c7a6f17f87734cb2197e2307609ee, type: 3}
+  - {fileID: 7943130419488318719, guid: f7c557861fe601e40a9cbf7eee31944a, type: 3}
+  - {fileID: 2060073602265363017, guid: 260705c1fbb54d14f8a959277ff8a0d9, type: 3}
+  - {fileID: 4151393126566175866, guid: ee5f649275c6df448b368a700051f56b, type: 3}
+  - {fileID: 7105429832087851605, guid: f2269d10de4a9f547ab9dfb4c262d7f1, type: 3}
+  - {fileID: 2508003905066464989, guid: 7b71a7582b00bf5459966292c067f993, type: 3}
+  - {fileID: 4340789361747537540, guid: 829293c87d5d4af43a957184c5226351, type: 3}
+  - {fileID: 4975003781838317384, guid: 1a011a012d2a6374eb1763bbb5c4db4b, type: 3}
+  - {fileID: 148400543839866356, guid: 8a342d095f0307049b781188c326b90d, type: 3}
+  - {fileID: 6539249233523154721, guid: cd059ae5196fa2e4bbb3845d1b2bd179, type: 3}
+  - {fileID: 223222829435824308, guid: 691e9a88288aae141b3f5101e0cf7aee, type: 3}
+  - {fileID: 1949368270377495737, guid: ab47917233fc55646aaf78c9b01d09ab, type: 3}
+  - {fileID: 5711737043693594991, guid: c740a7c02ffa8de4cb932afe6156c6cf, type: 3}
+  - {fileID: 951557644771610828, guid: d496ec21ccfec974aad9649f411d83b8, type: 3}
+  - {fileID: 4092429824228569959, guid: 35fe1d766f52d4846b36269d847d67f4, type: 3}
+  - {fileID: 6704497324175784856, guid: a75c2a667e70b1d4fba3087ef70dc2ef, type: 3}
+  - {fileID: 2496624311411999554, guid: 7922924c67be81942bd85fca97242fc2, type: 3}
+  - {fileID: 3657234865874006817, guid: 85204b88b50e56f4e8e50d0b697dca7e, type: 3}
+  - {fileID: 1513173758651762311, guid: 199eb5163074c074aa5e6b2d8a3ece71, type: 3}
+  - {fileID: 3395617717957831109, guid: 9aaf6be3a54838143bb3c4b6abe3ffce, type: 3}
+  - {fileID: 5125642054731478970, guid: 18d3009ee0d62694ba8afa4a3cf41460, type: 3}
+  - {fileID: 2219934251009871561, guid: 4c72e2d1199b700478d67f7a0d22ad3a, type: 3}
+  - {fileID: 4430435587276356401, guid: 9fef8be8e9d4c5d4687fdfb3af9597d3, type: 3}

+ 10 - 0
CharacterGenerator.prefab.meta

@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: ed0a30d5c3864304893aee2de647297c
+labels:
+- Manager
+- SneakyShit
+PrefabImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 48 - 0
CharacterManager.prefab

@@ -0,0 +1,48 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!1 &1796506434059338607
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 7217660054515966427}
+  - component: {fileID: 8193770060931854890}
+  m_Layer: 0
+  m_Name: CharacterManager
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &7217660054515966427
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1796506434059338607}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: -0.90482044, y: 0.4541942, z: 392.14008}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &8193770060931854890
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1796506434059338607}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: e96760a27e63517428791717f4af4c90, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  sceneCharacters: []
+  worldCharacterNames: []
+  spawnerIds: []

+ 10 - 0
CharacterManager.prefab.meta

@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: fe18e03b51007684baf2ba9b6c79756a
+labels:
+- Manager
+- SneakyShit
+PrefabImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Editor.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: d008fe5bc2a6f6643ba06e3f7c07378d
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Editor/Icons.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 0b368283e41eece4db72dbb929045afa
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Editor/Icons/People.png


+ 91 - 0
Editor/Icons/People.png.meta

@@ -0,0 +1,91 @@
+fileFormatVersion: 2
+guid: 860884f74e203dd48a30ab1bae5a2b61
+TextureImporter:
+  internalIDToNameTable: []
+  externalObjects: {}
+  serializedVersion: 10
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 1
+    sRGBTexture: 1
+    linearTexture: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapsPreserveCoverage: 0
+    alphaTestReferenceValue: 0.5
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: 0.25
+    normalMapFilter: 0
+  isReadable: 0
+  streamingMipmaps: 0
+  streamingMipmapsPriority: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 6
+  cubemapConvolution: 0
+  seamlessCubemap: 0
+  textureFormat: -1
+  maxTextureSize: 2048
+  textureSettings:
+    serializedVersion: 2
+    filterMode: -1
+    aniso: -1
+    mipBias: -100
+    wrapU: 1
+    wrapV: 1
+    wrapW: 1
+  nPOTScale: 0
+  lightmap: 0
+  compressionQuality: 50
+  spriteMode: 1
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: 0.5, y: 0.5}
+  spritePixelsToUnits: 100
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spriteGenerateFallbackPhysicsShape: 1
+  alphaUsage: 1
+  alphaIsTransparency: 1
+  spriteTessellationDetail: -1
+  textureType: 8
+  textureShape: 1
+  singleChannelComponent: 0
+  maxTextureSizeSet: 0
+  compressionQualitySet: 0
+  textureFormatSet: 0
+  platformSettings:
+  - serializedVersion: 3
+    buildTarget: DefaultTexturePlatform
+    maxTextureSize: 2048
+    resizeAlgorithm: 0
+    textureFormat: -1
+    textureCompression: 1
+    compressionQuality: 50
+    crunchedCompression: 0
+    allowsAlphaSplitting: 0
+    overridden: 0
+    androidETC2FallbackOverride: 0
+    forceMaximumCompressionQuality_BC6H_BC7: 0
+  spriteSheet:
+    serializedVersion: 2
+    sprites: []
+    outline: []
+    physicsShape: []
+    bones: []
+    spriteID: 5e97eb03825dee720800000000000000
+    internalID: 0
+    vertices: []
+    indices: 
+    edges: []
+    weights: []
+    secondaryTextures: []
+  spritePackingTag: 
+  pSDRemoveMatte: 0
+  pSDShowRemoveMatteOption: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Editor/Icons/Person.png


+ 91 - 0
Editor/Icons/Person.png.meta

@@ -0,0 +1,91 @@
+fileFormatVersion: 2
+guid: bf5cdb1f2df5ae94dad40ef42856cbe4
+TextureImporter:
+  internalIDToNameTable: []
+  externalObjects: {}
+  serializedVersion: 10
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 1
+    sRGBTexture: 1
+    linearTexture: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapsPreserveCoverage: 0
+    alphaTestReferenceValue: 0.5
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: 0.25
+    normalMapFilter: 0
+  isReadable: 0
+  streamingMipmaps: 0
+  streamingMipmapsPriority: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 6
+  cubemapConvolution: 0
+  seamlessCubemap: 0
+  textureFormat: -1
+  maxTextureSize: 2048
+  textureSettings:
+    serializedVersion: 2
+    filterMode: -1
+    aniso: -1
+    mipBias: -100
+    wrapU: 1
+    wrapV: 1
+    wrapW: 1
+  nPOTScale: 0
+  lightmap: 0
+  compressionQuality: 50
+  spriteMode: 1
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: 0.5, y: 0.5}
+  spritePixelsToUnits: 100
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spriteGenerateFallbackPhysicsShape: 1
+  alphaUsage: 1
+  alphaIsTransparency: 1
+  spriteTessellationDetail: -1
+  textureType: 8
+  textureShape: 1
+  singleChannelComponent: 0
+  maxTextureSizeSet: 0
+  compressionQualitySet: 0
+  textureFormatSet: 0
+  platformSettings:
+  - serializedVersion: 3
+    buildTarget: DefaultTexturePlatform
+    maxTextureSize: 2048
+    resizeAlgorithm: 0
+    textureFormat: -1
+    textureCompression: 1
+    compressionQuality: 50
+    crunchedCompression: 0
+    allowsAlphaSplitting: 0
+    overridden: 0
+    androidETC2FallbackOverride: 0
+    forceMaximumCompressionQuality_BC6H_BC7: 0
+  spriteSheet:
+    serializedVersion: 2
+    sprites: []
+    outline: []
+    physicsShape: []
+    bones: []
+    spriteID: 5e97eb03825dee720800000000000000
+    internalID: 0
+    vertices: []
+    indices: 
+    edges: []
+    weights: []
+    secondaryTextures: []
+  spritePackingTag: 
+  pSDRemoveMatte: 0
+  pSDShowRemoveMatteOption: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Runtime.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: a06b28f356fea854c82731950fab08a4
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Runtime/Actions.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 431d5c30c9bc3d6438fe715460e520f3
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 67 - 0
Runtime/Actions/CharacterAimAction.cs

@@ -0,0 +1,67 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using RootMotion.FinalIK;
+using KairoEngine.Core;
+
+namespace KairoEngine.CharacterSystem
+{
+    public class CharacterAimAction : IAction
+    {
+        CharacterController character;
+        Transform target;
+        AimController aimController;
+        GameObject aimTarget;
+
+        // Constructor
+        public CharacterAimAction(CharacterController character, Transform target)
+        {
+            this.character = character;
+            this.target = target;
+        }
+
+        public void Start()
+        {
+            aimController = character.GetComponentInChildren<AimController>();
+            if(aimController != null)
+            {
+                if(aimController.target != null)
+                {
+                    aimTarget = aimController.target.gameObject;
+                }
+                else
+                {
+                    aimTarget = new GameObject(character.unique_name + "_AimTarget");
+                    aimController.target = aimTarget.transform;
+                }
+                
+            }
+            else
+            {
+                End();
+            }
+            aimTarget.transform.position = new Vector3(target.position.x, target.position.y + 1.4f, target.position.z);
+        }
+
+        public void Update() 
+        { 
+            aimTarget.transform.position = new Vector3(target.position.x, target.position.y + 1.4f, target.position.z);
+        }
+
+        public void End() 
+        { 
+            if(aimController != null)
+            {
+                aimController.target = null;
+            }
+            target = null;
+            GameObject.Destroy(aimTarget);
+        }
+
+        public bool IsDone()
+        {
+            if(target == null) return true;
+            else return false;
+        }
+    }
+}

+ 11 - 0
Runtime/Actions/CharacterAimAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f5ed4238ffb1e4541847d0d8a1032710
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 81 - 0
Runtime/Actions/CharacterEquipItemAction.cs

@@ -0,0 +1,81 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using KairoEngine.Core;
+using KairoEngine.Inventory;
+
+namespace KairoEngine.CharacterSystem
+{
+    public class CharacterEquipItemAction : IAction
+    {
+        ItemRef itemRef;
+        CharacterController character; // Reference to the character that will move
+
+        // Constructor
+        public CharacterEquipItemAction(ItemRef itemRef, CharacterController character)
+        {
+            this.itemRef = itemRef;
+            this.character = character;
+        }
+
+        public void Start()
+        {
+            //Debug.Log("Equipping Item");
+            if(itemRef.item.category != ItemType.firearm && itemRef.item.category != ItemType.handWeapon) return;
+            if(character.HasEquipedItem())
+            {
+                GameObject.Destroy(character.GetEquipedGameObject());
+                character.SetEquipedItem(null);
+            }
+            GameObject weaponObj;
+            ItemBaseHoldable holdableItem = (ItemBaseHoldable)itemRef.item;
+            weaponObj = GameObject.Instantiate(holdableItem.holdablePrefab, character.rightHand.transform);
+            holdableItem.Setup(weaponObj, 1f);
+            character.animator.SetInteger("Mode", holdableItem.animationMode);
+            character.SetEquipedItem(itemRef);
+            character.SetEquipedGameObject(weaponObj);
+            if(itemRef.item.category == ItemType.firearm)
+            {
+                ItemBaseFirearm weaponItem = (ItemBaseFirearm)itemRef.item;
+                if(weaponItem.firearmType == FirearmType.pistol) character.animator.SetBool("Pistol", true);
+                else character.animator.SetBool("Pistol", false);
+                Firearm firearm = character.GetEquipedGameObject().GetComponent<Firearm>();
+                if(firearm != null) 
+                {
+                    ItemFirearmRef firearmRef = itemRef as ItemFirearmRef;
+                    if(firearmRef == null)
+                    {
+                        Debug.LogError("Cast is not working for item " + itemRef.item.title);
+                        //firearmRef = new ItemFirearmRef(weaponItem, itemRef.quantity, weaponItem.ammoType, 0);
+                        //itemRef = firearmRef;
+                        //character.itemContainer.UpdateItem(itemRef);
+                    }
+                    firearm.itemFirearmRef = firearmRef;
+                }
+            }
+            else if(itemRef.item.category == ItemType.handWeapon)
+            {
+                ItemBaseHandWeapon weaponItem = (ItemBaseHandWeapon)itemRef.item;
+                DamageEmitter damageEmitter = character.GetEquipedGameObject().GetComponent<DamageEmitter>();
+                damageEmitter.character = character;
+                damageEmitter.damage = weaponItem.damage;
+                HandWeapon handWeapon = weaponObj.GetComponent<HandWeapon>();
+                if(handWeapon != null)
+                {
+                    handWeapon.weaponCollider.enabled = false;
+                    handWeapon.damageTrigger.enabled = true;
+                }
+            }
+            
+        }
+
+        public void Update() { }
+
+        public void End() { }
+
+        public bool IsDone()
+        {
+            return true;
+        }
+    }
+}

+ 11 - 0
Runtime/Actions/CharacterEquipItemAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 39657a9858669ba49ae2ab58df630e4c
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 103 - 0
Runtime/Actions/CharacterFollowTargetAction.cs

@@ -0,0 +1,103 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.Events;
+using KairoEngine.Core;
+
+namespace KairoEngine.CharacterSystem
+{
+    /// <summary>
+    /// Action to move a character in a certain direction and speed.
+    /// </summary>
+    public class CharacterFollowTargetAction : IAction
+    {
+        CharacterController character;
+        Transform target;
+        float speed = 1f;
+        float animationSpeed = 1f;
+        float targetDistance;
+        bool done = false;
+        
+
+        // Constructor
+        public CharacterFollowTargetAction(CharacterController character, Transform target, float targetDistance, float speed, float animationSpeed = 1f)
+        {
+            this.character = character;
+            this.target = target;
+            this.targetDistance = targetDistance;
+            this.speed = speed;
+            this.animationSpeed = animationSpeed;
+            
+        }
+
+        public void Start()
+        {
+            character.navMeshAgent.destination = target.position;
+            character.navMeshAgent.updatePosition = true;
+            character.navMeshAgent.updateRotation = false;
+            character.navMeshAgent.isStopped = false;
+            character.navMeshAgent.speed = speed;
+        }
+
+        public void Update()
+        {
+            if(Vector3.Distance(character.navMeshAgent.destination, target.position) > targetDistance)
+            {
+                character.navMeshAgent.destination = target.position;
+            }
+            if (character.navMeshAgent == null) return;
+            if (character.navMeshAgent.pathPending)
+            {
+                //Debug.Log("Calculating path");
+                return;
+            } else
+            {
+                //Debug.Log($"Following path with {character.navMeshAgent.path.corners.Length} corners ({character.unique_name})");
+            }
+            if (character.navMeshAgent.path == null) {
+                //Debug.Log("No path");
+                return;
+            }
+            if (character.navMeshAgent.path.corners.Length == 0)
+            {
+                //End();
+                return;
+            }
+            if (character.navMeshAgent.isStopped) return;
+            //Debug.Log($"Remaining distance: {character.navMeshAgent.remainingDistance} ({character.unique_name})");
+            if (character.navMeshAgent.remainingDistance < character.navMeshAgent.stoppingDistance)
+            {
+                character.navMeshAgent.isStopped = true;
+                character.navMeshAgent.path.ClearCorners();
+                //End();
+                return;
+            }
+            TurnToPoint(character.navMeshAgent.steeringTarget);
+            Vector3 heading = character.navMeshAgent.steeringTarget - character.transform.position;
+            float distance = heading.magnitude;
+            Vector3 direction = heading / distance;
+            character.animator.SetFloat("horizontal", 0);
+            character.animator.SetFloat("vertical", animationSpeed);
+        }
+
+        private void TurnToPoint(Vector3 point)
+        {
+            Quaternion targetRotation = Quaternion.LookRotation (point - character.transform.position);
+            character.animator.transform.rotation = Quaternion.Slerp (character.animator.transform.rotation, targetRotation, 100f * Time.deltaTime);
+        }
+
+        public void End()
+        {
+            character.animator.SetFloat("horizontal", 0);
+            character.animator.SetFloat("vertical", 0);
+            character.navMeshAgent.isStopped = true;
+            character.navMeshAgent.speed = 0;
+            done = true;
+        }
+
+        public bool IsDone()
+        {
+            return done;
+        }
+    }
+}

+ 11 - 0
Runtime/Actions/CharacterFollowTargetAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 9c1a53356fc941247aa36e02b33a9d19
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 71 - 0
Runtime/Actions/CharacterHandWeaponAttackAction.cs

@@ -0,0 +1,71 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.Events;
+using KairoEngine.Core;
+using KairoEngine.Inventory;
+using KairoEngine.SFX;
+
+namespace KairoEngine.CharacterSystem
+{
+    /// <summary>
+    /// Action to move a character in a certain direction and speed.
+    /// </summary>
+    public class CharacterHandWeaponAttackAction : IAction
+    {
+        CharacterController character; // Reference to the character that will move
+        Vector3 targetPosition;
+        bool done = false;
+        GameObject particleSystem;
+        HandWeapon handWeaponScript;
+
+
+        // Constructor
+        public CharacterHandWeaponAttackAction(CharacterController character, Vector3 targetPosition)
+        {
+            this.character = character;
+            this.targetPosition = targetPosition; 
+        }
+
+        public void Start()
+        {
+            character.animator.SetTrigger("Attack");
+            character.rightHand.GetComponentInChildren<DamageEmitter>().enabled = true;
+            GenericEvents.StartListening(character.unique_name + "-AnimationMeleeEnd", End);
+            ItemRef itemRef = character.GetEquipedItem();
+            ItemBaseHandWeapon handWeapon = (ItemBaseHandWeapon)itemRef.item;
+            SoundController.EmmitSound(handWeapon.attackSound, targetPosition);
+            GameObject weapon = character.GetEquipedGameObject();
+            particleSystem = weapon.GetComponent<HandWeapon>().particleSystemGroup;
+            particleSystem.SetActive(true);
+            ParticleSystem[] systems = particleSystem.GetComponentsInChildren<ParticleSystem>();
+            foreach (var system in systems)
+            {
+                system.loop = true;
+                system.Play();
+            }
+            handWeaponScript = weapon.GetComponent<HandWeapon>();
+            if(handWeaponScript != null) handWeaponScript.damageTrigger.enabled = true;
+        }
+
+        public void Update() { }
+
+        public void End()
+        {
+            done = true;
+            GenericEvents.StopListening(character.unique_name + "-AnimationMeleeEnd", End);
+            character.rightHand.GetComponentInChildren<DamageEmitter>().enabled = false;
+            ParticleSystem[] systems = particleSystem.GetComponentsInChildren<ParticleSystem>();
+            foreach (var system in systems)
+            {
+                system.loop = false;
+            }
+            //if(handWeaponScript != null) handWeaponScript.damageTrigger.enabled = false;
+        }
+
+        public bool IsDone()
+        {
+            return done;
+        }
+    }
+}

+ 11 - 0
Runtime/Actions/CharacterHandWeaponAttackAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 292cfeaf87894bf40b3b08f647d626e2
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 84 - 0
Runtime/Actions/CharacterMoveAction.cs

@@ -0,0 +1,84 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.Events;
+using KairoEngine.Core;
+
+namespace KairoEngine.CharacterSystem
+{
+    /// <summary>
+    /// Action to move a character in a certain direction and speed.
+    /// </summary>
+    public class CharacterMoveAction : IAction
+    {
+        CharacterController character; // Reference to the character that will move
+        Vector2 direction;
+        Vector2 lookDirection;
+        bool done = false;
+
+        float speed = 1f;
+
+        // Constructor
+        public CharacterMoveAction(CharacterController character, Vector2 direction, Vector2 lookDirection, float speed)
+        {
+            this.character = character;
+            this.direction = direction;
+            this.lookDirection = lookDirection;
+            this.speed = speed;
+            
+        }
+
+        public void Start()
+        {
+            UpdateLookDirection();
+            GenericEvents.StartListening(character.unique_name + "-AnimationStepDone", End);
+            character.animator.SetFloat("horizontal", (int)lookDirection.x);
+            character.animator.SetFloat("vertical", (int)lookDirection.y);
+            character.transform.Translate(new Vector3(direction.x * speed * Time.deltaTime, 0, direction.y * speed * Time.deltaTime));
+        }
+
+        public void Update()
+        {
+            UpdateLookDirection();
+            character.animator.SetFloat("horizontal", (int)lookDirection.x);
+            character.animator.SetFloat("vertical", (int)lookDirection.y);
+            character.transform.Translate(new Vector3(direction.x * speed * Time.deltaTime, 0, direction.y * speed * Time.deltaTime));
+        }
+
+        public void End()
+        {
+            if(direction.x > 0.1f || direction.y > 0.1f || direction.x < -0.1f || direction.y < -0.1f) return;
+            character.animator.SetFloat("horizontal", 0);
+            character.animator.SetFloat("vertical", 0);
+            GenericEvents.StopListening(character.unique_name + "-AnimationStepDone", End);
+            done = true;
+        }
+
+        public bool IsDone()
+        {
+            return done;
+        }
+
+        public void UpdateLookDirection()
+        {
+            if(speed == 1.25f)
+            {
+                if(lookDirection.x > 0.1f) lookDirection.x = 1;
+                else if(lookDirection.x < -0.1f) lookDirection.x = -1;
+                else lookDirection.x = 0;
+                if(lookDirection.y > 0.1f) lookDirection.y = 1;
+                else if(lookDirection.y < -0.1f) lookDirection.y = -1;
+                else lookDirection.y = 0;
+            }
+            else
+            {
+                if(lookDirection.x > 0.9f) lookDirection.x = 2;
+                else if(lookDirection.x < -0.9f) lookDirection.x = -2;
+                else lookDirection.x = 0;
+                if(lookDirection.y > 0.9f) lookDirection.y = 2;
+                else if(lookDirection.y < -0.9f) lookDirection.y = -2;
+                else lookDirection.y = 0;
+            }
+        }
+    }
+}

+ 11 - 0
Runtime/Actions/CharacterMoveAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f0732a8eedfd7824888b536ff4de912e
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 112 - 0
Runtime/Actions/CharacterMoveToPositionAction.cs

@@ -0,0 +1,112 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.Events;
+using KairoEngine.Core;
+
+namespace KairoEngine.CharacterSystem
+{
+    /// <summary>
+    /// Action to move a character in a certain direction and speed.
+    /// </summary>
+    public class CharacterMoveToPositionAction : IAction
+    {
+        CharacterController character;
+        Vector3 targetPosition;
+        float speed = 1f;
+        float animationSpeed = 1f;
+        bool done = false;
+        
+
+        // Constructor
+        public CharacterMoveToPositionAction(CharacterController character, Vector3 targetPosition, float speed, float animationSpeed = 1f, float stoppingDistance = 1f)
+        {
+            this.character = character;
+            this.targetPosition = targetPosition;
+            this.speed = speed;
+            this.animationSpeed = animationSpeed;
+            character.navMeshAgent.destination = targetPosition;
+            character.navMeshAgent.stoppingDistance = stoppingDistance;
+            character.navMeshAgent.isStopped = false;
+            character.navMeshAgent.speed = speed;
+        }
+
+        public void Start()
+        {            
+            //character.navMeshAgent.updatePosition = false;
+            //character.navMeshAgent.updateRotation = false;
+            character.navMeshAgent.isStopped = false;
+            character.navMeshAgent.speed = speed;
+        }
+
+        public void Update()
+        {
+            if (character.navMeshAgent == null) return;
+            if (character.navMeshAgent.pathPending)
+            {
+                //Debug.Log("Calculating path");
+                return;
+            } else
+            {
+                character.navMeshAgent.updatePosition = true;
+                character.navMeshAgent.isStopped = false;
+                //Debug.Log($"Following path with {character.navMeshAgent.path.corners.Length} corners ({character.unique_name})");
+            }
+            if (character.navMeshAgent.path == null) {
+                //Debug.Log("No path");
+                return;
+            }
+            if (character.navMeshAgent.path.corners.Length == 0)
+            {
+                GenericEvents.Trigger(character.unique_name + "-ArrivedInPositionAction");
+                End();
+                return;
+            }
+            if (character.navMeshAgent.isStopped) return;
+            //Debug.Log($"Remaining distance: {character.navMeshAgent.remainingDistance} ({character.unique_name})");
+            if (character.navMeshAgent.remainingDistance < character.navMeshAgent.stoppingDistance)
+            {
+                character.navMeshAgent.isStopped = true;
+                character.navMeshAgent.path.ClearCorners();
+                GenericEvents.Trigger(character.unique_name + "-ArrivedInPositionAction");
+                End();
+                return;
+            }
+            TurnToPoint(character.navMeshAgent.steeringTarget);
+            Vector3 heading = character.navMeshAgent.steeringTarget - character.transform.position;
+            float distance = heading.magnitude;
+            Vector3 direction = heading / distance;
+            Move(speed, direction);
+        }
+
+        private void Move(float speed, Vector3 direction)
+        {
+            //Debug.Log(direction);
+            character.animator.SetFloat("horizontal", 0);
+            character.animator.SetFloat("vertical", animationSpeed);
+            //character.transform.Translate(new Vector3(direction.x * speed * Time.deltaTime, 0, direction.z * speed * Time.deltaTime));
+            //if(character.navMeshAgent.isStopped == false) character.navMeshAgent.nextPosition = character.transform.position;
+        }
+
+        private void TurnToPoint(Vector3 point)
+        {
+            Quaternion targetRotation = Quaternion.LookRotation (new Vector3(point.x, character.transform.position.y, point.z) - character.transform.position);
+            character.animator.transform.rotation = Quaternion.Slerp (character.animator.transform.rotation, targetRotation, 100f * Time.deltaTime);
+        }
+
+        public void End()
+        {
+            character.animator.SetFloat("horizontal", 0);
+            character.animator.SetFloat("vertical", 0);
+            character.navMeshAgent.isStopped = true;
+            character.navMeshAgent.updatePosition = false;
+            character.navMeshAgent.speed = 0;
+            done = true;
+        }
+
+        public bool IsDone()
+        {
+            return done;
+        }
+    }
+}

+ 11 - 0
Runtime/Actions/CharacterMoveToPositionAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 1b4f88ee6c600974abf826c990dd07dd
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 69 - 0
Runtime/Actions/CharacterPickupItemAction.cs

@@ -0,0 +1,69 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using KairoEngine.Core;
+using KairoEngine.Inventory;
+using KairoEngine.SFX;
+
+namespace KairoEngine.CharacterSystem
+{
+    public class CharacterPickupItemAction : IAction
+    {
+        CharacterController character; // Reference to the character that will move
+        ItemContainer itemContainer;
+        WorldItem worldItem;
+
+        // Constructor
+        public CharacterPickupItemAction(CharacterController character, WorldItem worldItem, ItemContainer itemContainer = null)
+        {
+            this.character = character;
+            this.worldItem = worldItem;
+            if(itemContainer == null) this.itemContainer = character.gameObject.GetComponent<ItemContainer>();
+            else this.itemContainer = itemContainer;
+            if(this.itemContainer == null)
+            {
+                Debug.LogError("Character does not have an ItemContainer (" + character.name + ").");
+            }
+        }
+
+        public void Start()
+        {
+            if(Vector3.Distance(character.transform.position, worldItem.transform.position) <= 3)
+            {
+                ItemBase item = ItemLibrary.GetItemByName(worldItem.itemName);
+                if(item.category == ItemType.firearm)
+                {
+                    ItemBaseFirearm itemFirearm = (ItemBaseFirearm)item;
+                    ItemBaseAmmo itemAmmo = (ItemBaseAmmo)ItemLibrary.GetItemByName(worldItem.itemAmmoName);
+                    ItemFirearmRef firearmRef = new ItemFirearmRef(itemFirearm, worldItem.quantity, itemAmmo, worldItem.ammoQuantity);
+                    itemContainer.AddItem(firearmRef);
+                    SoundController.EmmitSound("pickup_weapon", character.transform.position);
+                }
+                else if(item.category == ItemType.ammo)
+                {
+                    ItemBase itemBase = ItemLibrary.GetItemByName(worldItem.itemName);
+                    ItemRef itemRef = new ItemRef(itemBase, worldItem.quantity, worldItem.lastUsed);
+                    itemContainer.AddItem(itemRef);
+                    SoundController.EmmitSound("pickup_ammo", character.transform.position);
+                }
+                else
+                {
+                    ItemBase itemBase = ItemLibrary.GetItemByName(worldItem.itemName);
+                    ItemRef itemRef = new ItemRef(itemBase, worldItem.quantity, worldItem.lastUsed);
+                    itemContainer.AddItem(itemRef);
+                    SoundController.EmmitSound("pickup_item", character.transform.position);
+                }
+                GameObject.Destroy(worldItem.gameObject);
+            }
+        }
+
+        public void Update() { }
+
+        public void End() { }
+
+        public bool IsDone()
+        {
+            return true;
+        }
+    }
+}

+ 11 - 0
Runtime/Actions/CharacterPickupItemAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 357cb1cd8a9ea874eb179c1c946fe160
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 38 - 0
Runtime/Actions/CharacterRelaxIdleAction.cs

@@ -0,0 +1,38 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using KairoEngine.Core;
+
+namespace KairoEngine.CharacterSystem
+{
+    public class CharacterRelaxIdleAction : IAction
+    {
+        CharacterController character;
+
+        // Constructor
+        public CharacterRelaxIdleAction(CharacterController character)
+        {
+            this.character = character;
+        }
+
+        public void Start()
+        {
+            character.animator.SetInteger("Mode", 3);
+        }
+
+        public void Update()
+        {
+
+        }
+
+        public void End() 
+        { 
+            character.animator.SetInteger("Mode", 0);
+        }
+
+        public bool IsDone()
+        {
+            return false;
+        }
+    }
+}

+ 11 - 0
Runtime/Actions/CharacterRelaxIdleAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: fbd61039830d53a478ebabc8d4886108
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 81 - 0
Runtime/Actions/CharacterReloadFirearmAction.cs

@@ -0,0 +1,81 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using KairoEngine.Core;
+using KairoEngine.Inventory;
+using KairoEngine.SFX;
+
+namespace KairoEngine.CharacterSystem
+{
+    // Todo: Enable floating message when cant reload
+
+    public class CharacterReloadFirearmAction : IAction
+    {
+        CharacterController character; // Reference to the character that will move
+        ItemFirearmRef firearmRef;
+        ItemContainer itemContainer;
+        bool isDone = false;
+
+        float counter = 0f;
+        ItemBaseFirearm itemFirearm;
+
+        // Constructor
+        public CharacterReloadFirearmAction(CharacterController character, ItemFirearmRef firearmRef)
+        {
+            this.character = character;
+            this.firearmRef = firearmRef;
+            itemContainer = character.gameObject.GetComponent<ItemContainer>();
+            if(itemContainer == null)
+            {
+                Debug.LogError("Character does not have an ItemContainer (" + character.name + ").");
+            }
+        }
+
+        public void Start()
+        {
+            ItemRef ammoRef = itemContainer.GetItem(firearmRef.ammoType);
+            itemFirearm = (ItemBaseFirearm)firearmRef.item;
+            if(ammoRef == null) 
+            {
+                
+                FloatingMessageEvents.Send("Out of ammo!", character.gameObject.transform.position, 1f, 1f, 16f);
+                End();
+                return;
+            }
+            int reloadAmmo = 0;
+            if(ammoRef.quantity >= itemFirearm.ammoCapacity - firearmRef.ammo) 
+            {
+                reloadAmmo = itemFirearm.ammoCapacity - firearmRef.ammo;
+                ammoRef.quantity -= reloadAmmo;
+            }
+            else
+            {
+                reloadAmmo = ammoRef.quantity;
+                ammoRef.quantity = 0;
+            }
+            if(ammoRef.quantity <= 0) itemContainer.RemoveItem(ammoRef);
+            else itemContainer.UpdateItem(ammoRef);
+            firearmRef.ammo += reloadAmmo;
+            SoundController.EmmitSound(itemFirearm.reloadSound, character.transform.position);
+            character.animator.SetTrigger("Reload");
+            GenericEvents.Trigger(character.unique_name + "-Reloading");
+        }
+
+        public void Update() 
+        { 
+            counter += Time.deltaTime;
+            if(counter > itemFirearm.reloadSpeed) End();
+        }
+
+        public void End() 
+        { 
+            GenericEvents.Trigger(character.unique_name + "-ReloadDone");
+            isDone = true;
+        }
+
+        public bool IsDone()
+        {
+            return isDone;
+        }
+    }
+}

+ 11 - 0
Runtime/Actions/CharacterReloadFirearmAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c8cb3b5330510cf45b99c8938c0434d2
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 53 - 0
Runtime/Actions/CharacterShootAction.cs

@@ -0,0 +1,53 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using KairoEngine.Core;
+using KairoEngine.Inventory;
+
+namespace KairoEngine.CharacterSystem
+{
+    public class CharacterShootAction : IAction
+    {
+        CharacterController character;
+        Firearm firearm;
+        bool isDone = false;
+
+        // Constructor
+        public CharacterShootAction(CharacterController character)
+        {
+            this.character = character;
+        }
+
+        public void Start()
+        {
+            if(character.HasEquipedItem() == false) return;
+            if(character.GetEquipedItem().item.category != ItemType.firearm) return;
+            firearm = character.GetEquipedGameObject().GetComponent<Firearm>();
+            ItemBaseFirearm weaponItem = (ItemBaseFirearm)firearm.itemFirearmRef.item;
+            if(weaponItem.firearmType == FirearmType.pistol) character.animator.SetBool("Pistol", true);
+            else character.animator.SetBool("Pistol", false);
+            if(firearm.isReady)
+            {
+                firearm.Fire();
+                if(firearm.itemFirearmRef.ammo > 0) character.animator.SetTrigger("Attack");
+                isDone = true;
+            }
+        }
+
+        public void Update()
+        {
+            if(firearm.isReady && !isDone)
+            {
+                firearm.Fire();
+                isDone = true;
+            }
+        }
+
+        public void End() { }
+
+        public bool IsDone()
+        {
+            return isDone;
+        }
+    }
+}

+ 11 - 0
Runtime/Actions/CharacterShootAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 0075a04a3d49cc148b9620f16dc54d82
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 44 - 0
Runtime/Actions/CharacterTurnToPointAction.cs

@@ -0,0 +1,44 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.Events;
+using KairoEngine.Core;
+
+namespace KairoEngine.CharacterSystem
+{
+    /// <summary>
+    /// Action to turn a character towards a point.
+    /// </summary>
+    public class CharacterTurnToPointAction : IAction
+    {
+        CharacterController character; // Reference to the character that will move
+        Vector3 point; // Where to turn
+
+        // Constructor
+        public CharacterTurnToPointAction(CharacterController character, Vector3 point)
+        {
+            this.character = character;
+            this.point = point;
+            this.point.y = 0f;
+        }
+
+        public void Start()
+        {
+            Quaternion targetRotation = Quaternion.LookRotation (point - character.transform.position);
+            character.animator.transform.rotation = Quaternion.Slerp (character.animator.transform.rotation, targetRotation, 100f * Time.deltaTime);
+        }
+
+        public void Update()
+        {
+            Quaternion targetRotation = Quaternion.LookRotation (point - character.transform.position);
+            character.animator.transform.rotation = Quaternion.Slerp (character.animator.transform.rotation, targetRotation, 100f * Time.deltaTime);
+        }
+
+        public void End() { }
+
+        public bool IsDone()
+        {
+            return true;
+        }
+    }
+}

+ 11 - 0
Runtime/Actions/CharacterTurnToPointAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ce8490c0bb0d3074796d8a0a4a80ae07
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 57 - 0
Runtime/Actions/CharacterUnarmedAttackAction.cs

@@ -0,0 +1,57 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.Events;
+using KairoEngine.Core;
+
+namespace KairoEngine.CharacterSystem
+{
+    /// <summary>
+    /// Action to move a character in a certain direction and speed.
+    /// </summary>
+    public class CharacterUnarmedAttackAction : IAction
+    {
+        CharacterController character; // Reference to the character that will move
+        Vector3 targetPosition;
+        bool done = false;
+
+
+        // Constructor
+        public CharacterUnarmedAttackAction(CharacterController character, Vector3 targetPosition)
+        {
+            this.character = character;
+            this.targetPosition = targetPosition; 
+        }
+
+        public void Start()
+        {
+            if(Random.Range(0, 2) == 0)
+            {
+                character.animator.SetTrigger("AttackL");
+                character.rightUnarmedObject.SetActive(true);
+            }
+            else
+            {
+                character.animator.SetTrigger("AttackR");
+                character.leftUnarmedObject.SetActive(true);
+            }
+            
+            GenericEvents.StartListening(character.unique_name + "-AnimationMeleeEnd", End);
+        }
+
+        public void Update() { }
+
+        public void End()
+        {
+            done = true;
+            GenericEvents.StopListening(character.unique_name + "-AnimationMeleeEnd", End);
+            character.rightUnarmedObject.SetActive(false);
+            character.leftUnarmedObject.SetActive(false);
+        }
+
+        public bool IsDone()
+        {
+            return done;
+        }
+    }
+}

+ 11 - 0
Runtime/Actions/CharacterUnarmedAttackAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8b907a4c0b59bba419707a44d91955b1
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 39 - 0
Runtime/Actions/CharacterUnequipItemAction.cs

@@ -0,0 +1,39 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using KairoEngine.Core;
+
+namespace KairoEngine.CharacterSystem
+{
+    public class CharacterUnequipItemAction : IAction
+    {
+        CharacterController character; // Reference to the character that will move
+
+        // Constructor
+        public CharacterUnequipItemAction(CharacterController character)
+        {
+
+            this.character = character;
+        }
+
+        public void Start()
+        {
+            if(character.HasEquipedItem())
+            {
+                GameObject.Destroy(character.GetEquipedGameObject());
+                character.SetEquipedItem(null);
+                character.SetEquipedGameObject(null);
+                character.animator.SetInteger("Mode", 0);
+            }
+        }
+
+        public void Update() { }
+
+        public void End() { }
+
+        public bool IsDone()
+        {
+            return true;
+        }
+    }
+}

+ 11 - 0
Runtime/Actions/CharacterUnequipItemAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 228d33404f20f4144a3119f3b9f5848b
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 69 - 0
Runtime/Actions/DropItemAction.cs

@@ -0,0 +1,69 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using KairoEngine.Core;
+using KairoEngine.Inventory;
+
+namespace KairoEngine.CharacterSystem
+{
+    public class DropItemAction : IAction
+    {
+        ItemContainer itemContainer; // Reference to the character that will move
+
+        ItemRef itemRef;
+        
+        public DropItemAction(ItemContainer itemContainer, ItemRef itemRef)
+        {
+            this.itemContainer = itemContainer;
+            this.itemRef = itemRef;
+        }
+
+        public void Start()
+        {
+            itemContainer.RemoveItem(itemRef);
+            Vector3 pos = itemContainer.transform.position;
+            pos.y += 1.5f;
+            pos.x += Random.Range(-1, 1);
+            pos.z += Random.Range(-1, 1);
+            GameObject obj = GameObject.Instantiate(itemRef.item.prefab, pos, itemContainer.transform.rotation);
+            WorldItem worldItem = obj.GetComponent<WorldItem>();
+            worldItem.itemName = itemRef.item.title;
+            worldItem.quantity = itemRef.quantity;
+            worldItem.lastUsed = itemRef.lastUsed;
+            SerializerWorldItem serializer = obj.GetComponent<SerializerWorldItem>();
+            serializer.loadedFromData = true;
+            if(itemRef.item.category == ItemType.firearm)
+            {
+                ItemFirearmRef firearmRef = (ItemFirearmRef)itemRef;
+                worldItem.itemAmmoName = firearmRef.ammoType.title;
+                worldItem.ammoQuantity = firearmRef.ammo;
+            }
+            CharacterController character = itemContainer.GetComponent<CharacterController>();
+            if(character !=null)
+            {
+                if(character.GetEquipedItem() == itemRef)
+                {
+                    GameObject.Destroy(character.GetEquipedGameObject());
+                    character.SetEquipedItem(null);
+                    character.SetEquipedGameObject(null);
+                    character.animator.SetInteger("Mode", 0);
+                }
+            }
+        }
+
+        public void Update()
+        {
+            
+        }
+
+        public void End()
+        {
+            
+        }
+
+        public bool IsDone()
+        {
+            return true;
+        }
+    }
+}

+ 11 - 0
Runtime/Actions/DropItemAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8fdf3b40f56f79948aa7c798791c0c0b
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 62 - 0
Runtime/Actions/UseInstantEffectItemAction.cs

@@ -0,0 +1,62 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using KairoEngine.Core;
+using KairoEngine.Inventory;
+using KairoEngine.Stats;
+
+namespace KairoEngine.CharacterSystem
+{
+    // Todo: Fix status effect controller link
+    public class UseInstantEffectItemAction : IAction
+    {
+        ItemContainer itemContainer; // Reference to the character that will move
+
+        ItemRef itemRef;
+        
+        public UseInstantEffectItemAction(ItemContainer itemContainer, ItemRef itemRef)
+        {
+            this.itemContainer = itemContainer;
+            this.itemRef = itemRef;
+        }
+
+        public void Start()
+        {
+            ItemBaseInstantEffect item = (ItemBaseInstantEffect)itemRef.item;
+            StatusEffectsController statusEffectsController = itemContainer.GetComponent<StatusEffectsController>();
+            if(statusEffectsController == null)
+            {
+                Debug.LogError("Missing StatusEffectsController in " + itemContainer.gameObject.name);
+                return;
+            }
+            // ! Fix: Change status effect controller
+            //statusEffectsController.Add(item.statusEffect);
+            Debug.LogError("Missing Status Effect Controller");
+            itemRef.quantity -= 1;
+            itemRef.lastUsed = 0f;
+            if(itemRef.quantity <= 0)
+            {
+                itemContainer.RemoveItem(itemRef);
+            } 
+            else
+            {
+                itemContainer.UpdateItem(itemRef);
+            }
+        }
+
+        public void Update()
+        {
+            
+        }
+
+        public void End()
+        {
+            
+        }
+
+        public bool IsDone()
+        {
+            return true;
+        }
+    }
+}

+ 11 - 0
Runtime/Actions/UseInstantEffectItemAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 7af4a4afa16873441a2c5e63f4a6842a
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 83 - 0
Runtime/Actions/ZombieAttackAction.cs

@@ -0,0 +1,83 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.Events;
+using KairoEngine.Core;
+
+namespace KairoEngine.CharacterSystem
+{
+    /// <summary>
+    /// Action to move a character in a certain direction and speed.
+    /// </summary>
+    public class ZombieAttackAction : IAction
+    {
+        CharacterController character; // Reference to the character that will move
+        Vector3 targetPosition;
+        string varient;
+        bool done = false;
+
+        float counter = 0f;
+        bool hit = false;
+
+
+        /// <summary>
+        /// Action that will make a character follow a target playing a zombie animation.
+        /// </summary>
+        /// <param name="character">The CharacterController performing the action.</param>
+        /// <param name="targetPosition">The target position that the attack will hit.</param>
+        /// <param name="varient">Use "AttackL", "AttackR" or "Attack".</param>
+        public ZombieAttackAction(CharacterController character, Vector3 targetPosition, string varient)
+        {
+            this.character = character;
+            this.targetPosition = targetPosition; 
+            this.varient = varient;
+            this.counter = 0f;
+        }
+
+        public void Start()
+        {
+            if(varient == "AttackL") character.animator.SetTrigger("AttackL");
+            else if(varient == "AttackR") character.animator.SetTrigger("AttackR");
+            else character.animator.SetTrigger("Attack");        
+            GenericEvents.StartListening(character.unique_name + "-AnimationHit", Hit);
+        }
+
+        public void Update() 
+        { 
+            if(hit)
+            {
+                counter += Time.deltaTime;
+                if(counter > 0.2f)
+                {
+                    End();
+                }
+            }
+        }
+
+        public void Hit()
+        {
+            hit = true;
+            GenericEvents.StopListening(character.unique_name + "-AnimationHit", End);
+            if(varient == "AttackL") character.leftUnarmedObject.SetActive(true);
+            else if(varient == "AttackR") character.rightUnarmedObject.SetActive(true);
+            else
+            {
+                character.rightUnarmedObject.SetActive(true);
+                character.leftUnarmedObject.SetActive(true);
+            }
+
+        }
+
+        public void End()
+        {
+            done = true;
+            character.rightUnarmedObject.SetActive(false);
+            character.leftUnarmedObject.SetActive(false);
+        }
+
+        public bool IsDone()
+        {
+            return done;
+        }
+    }
+}

+ 11 - 0
Runtime/Actions/ZombieAttackAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8ff5b1043c27a894d83d968d1784442f
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 165 - 0
Runtime/Actions/ZombieFollowTargetAction.cs

@@ -0,0 +1,165 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.Events;
+using KairoEngine.Core;
+
+namespace KairoEngine.CharacterSystem
+{
+    /// <summary>
+    /// Action to make a Zombie follow a target transform using one of many animation varients.
+    /// </summary>
+    public class ZombieFollowTargetAction : IAction
+    {
+        CharacterController character;
+        Transform target;
+        float targetDistance;
+        int varient;
+        float speed;
+        float animationSpeed;
+        bool done = false;
+        
+
+        /// <summary>
+        /// Action that will make a character follow a target transform playing a zombie walk or run animation varient.
+        /// </summary>
+        /// <param name="character">The CharacterController performing the action</param>
+        /// <param name="target">The target Transform to be followed</param>
+        /// <param name="targetDistance">Stop following when this distance is reached</param>
+        /// <param name="varient">Type of zombie animation to play. 1 to 7 are walk animations and 8 to 9 are run animations</param>
+        public ZombieFollowTargetAction(CharacterController character, Transform target, float targetDistance, int varient)
+        {
+            if(target == null) Debug.LogError("target Transform cannot be null in ZombieFollowTargetAction");
+            if(character == null) Debug.LogError("character CharacterController cannot be null in ZombieFollowTargetAction");
+            this.character = character;
+            this.target = target;
+            this.targetDistance = targetDistance;
+            this.varient = varient;
+            switch(varient)
+            {
+                case 1:
+                    speed = 1.2f;
+                    animationSpeed = 1f;
+                    break;
+                case 2:
+                    speed = 1.2f;
+                    animationSpeed = 1f;
+                    break;
+                case 3:
+                    speed = 1.2f;
+                    animationSpeed = 1f;
+                    break;
+                case 4:
+                    speed = 1.2f;
+                    animationSpeed = 1f;
+                    break;
+                case 5:
+                    speed = 1.2f;
+                    animationSpeed = 1f;
+                    break;
+                case 6:
+                    speed = 1.2f;
+                    animationSpeed = 1f;
+                    break;
+                case 7:
+                    speed = 1.2f;
+                    animationSpeed = 1f;
+                    break;
+                case 8:
+                    speed = 2f;
+                    animationSpeed = 2f;
+                    break;
+                case 9:
+                    speed = 2.2f;
+                    animationSpeed = 2f;
+                    break;
+                default:
+                    speed = 1f;
+                    animationSpeed = 1f;
+                    break;
+            }
+        }
+
+        public void Start()
+        {
+            character.navMeshAgent.destination = target.position;
+            character.navMeshAgent.updatePosition = true;
+            character.navMeshAgent.updateRotation = false;
+            character.navMeshAgent.isStopped = false;
+            character.navMeshAgent.speed = speed;
+            character.navMeshAgent.stoppingDistance = targetDistance;
+        }
+
+        public void Update()
+        {
+            character.animator.SetFloat("ZombieMoveVarient", varient);
+
+            if(Vector3.Distance(character.transform.position, target.position) > targetDistance)
+            {
+                character.navMeshAgent.destination = target.position;
+                character.navMeshAgent.isStopped = false;
+                character.navMeshAgent.updatePosition = true;
+            }
+            if (character.navMeshAgent == null) return;
+            if (character.navMeshAgent.pathPending)
+            {
+                //Debug.Log("Calculating path");
+                return;
+            } else
+            {
+                //Debug.Log($"Following path with {character.navMeshAgent.path.corners.Length} corners ({character.unique_name})");
+            }
+            if (character.navMeshAgent.path == null) {
+                //Debug.Log("No path");
+                return;
+            }
+            if (character.navMeshAgent.path.corners.Length == 0)
+            {
+                return;
+            }
+            if (character.navMeshAgent.isStopped) return;
+            //Debug.Log($"Remaining distance: {character.navMeshAgent.remainingDistance} ({character.unique_name})");
+            if (character.navMeshAgent.remainingDistance < character.navMeshAgent.stoppingDistance)
+            {
+                character.navMeshAgent.isStopped = true;
+                character.navMeshAgent.path.ClearCorners();
+                Stop();
+                return;
+            }
+            TurnToPoint(character.navMeshAgent.steeringTarget);
+            Vector3 heading = character.navMeshAgent.steeringTarget - character.transform.position;
+            float distance = heading.magnitude;
+            Vector3 direction = heading / distance;
+            character.animator.SetFloat("horizontal", 0);
+            character.animator.SetFloat("vertical", animationSpeed);
+        }
+
+        private void TurnToPoint(Vector3 point)
+        {
+            Quaternion targetRotation = Quaternion.LookRotation (point - character.transform.position);
+            character.animator.transform.rotation = Quaternion.Slerp (character.animator.transform.rotation, targetRotation, 100f * Time.deltaTime);
+        }
+
+        private void Stop()
+        {
+            character.animator.SetFloat("horizontal", 0);
+            character.animator.SetFloat("vertical", 0);
+            character.navMeshAgent.isStopped = true;
+            character.navMeshAgent.updatePosition = false;
+            character.navMeshAgent.speed = 0;
+            character.navMeshAgent.stoppingDistance = 0;
+            character.navMeshAgent.destination = character.transform.position;
+        }
+
+        public void End()
+        {
+            Stop();
+            done = true;
+        }
+
+        public bool IsDone()
+        {
+            return done;
+        }
+    }
+}

+ 11 - 0
Runtime/Actions/ZombieFollowTargetAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d67c4892b0521f6448b635b87dc44812
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 49 - 0
Runtime/Actions/ZombieIdleAction.cs

@@ -0,0 +1,49 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.Events;
+using KairoEngine.Core;
+
+namespace KairoEngine.CharacterSystem
+{
+    /// <summary>
+    /// Action to move a character in a certain direction and speed.
+    /// </summary>
+    public class ZombieIdleAction : IAction
+    {
+        CharacterController character; // Reference to the character that will perform the action
+        int varient;
+        bool done = false;
+
+
+        /// <summary>
+        /// Action that will make a character play an zombie idle animation.
+        /// </summary>
+        /// <param name="character">The CharacterController performing the action.</param>
+        /// <param name="varient">Use numbers 1 to 8 for different animations.</param>
+        public ZombieIdleAction(CharacterController character, int varient)
+        {
+            this.character = character;
+            this.varient = varient;
+        }
+
+        public void Start()
+        {
+            float v = (float)varient;
+            character.animator.SetFloat("ZombieIdleVarient", v);
+            character.animator.SetFloat("vertical", 0);
+        }
+
+        public void Update() { }
+
+        public void End()
+        {
+            done = true;
+        }
+
+        public bool IsDone()
+        {
+            return done;
+        }
+    }
+}

+ 11 - 0
Runtime/Actions/ZombieIdleAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 7f87b5c9dbdc67f46811366743f1bc82
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 154 - 0
Runtime/Actions/ZombieMoveToPositionAction.cs

@@ -0,0 +1,154 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.Events;
+using KairoEngine.Core;
+
+namespace KairoEngine.CharacterSystem
+{
+    /// <summary>
+    /// Action to move a character in a certain direction and speed.
+    /// </summary>
+    public class ZombieMoveToPositionAction : IAction
+    {
+        CharacterController character;
+        Vector3 targetPosition;
+        int varient;
+        float speed = 1f;
+        float animationSpeed = 1f;
+        bool done = false;
+        
+
+        // Constructor
+        public ZombieMoveToPositionAction(CharacterController character, Vector3 targetPosition, int varient)
+        {
+            this.character = character;
+            this.targetPosition = targetPosition;
+            this.varient = varient;
+            switch(varient)
+            {
+                case 1:
+                    speed = 1.2f;
+                    animationSpeed = 1f;
+                    break;
+                case 2:
+                    speed = 1.2f;
+                    animationSpeed = 1f;
+                    break;
+                case 3:
+                    speed = 1.2f;
+                    animationSpeed = 1f;
+                    break;
+                case 4:
+                    speed = 1.2f;
+                    animationSpeed = 1f;
+                    break;
+                case 5:
+                    speed = 1.2f;
+                    animationSpeed = 1f;
+                    break;
+                case 6:
+                    speed = 1.2f;
+                    animationSpeed = 1f;
+                    break;
+                case 7:
+                    speed = 1.2f;
+                    animationSpeed = 1f;
+                    break;
+                case 8:
+                    speed = 2f;
+                    animationSpeed = 2f;
+                    break;
+                case 9:
+                    speed = 2.2f;
+                    animationSpeed = 2f;
+                    break;
+                default:
+                    speed = 1f;
+                    animationSpeed = 1f;
+                    break;
+            }
+        }
+
+        public void Start()
+        {
+            character.navMeshAgent.destination =targetPosition;
+            character.navMeshAgent.updatePosition = false;
+            character.navMeshAgent.updateRotation = false;
+            character.navMeshAgent.isStopped = true;
+            character.navMeshAgent.speed = speed;
+            character.navMeshAgent.stoppingDistance = 0.5f;
+        }
+
+        public void Update()
+        {
+            character.animator.SetFloat("ZombieMoveVarient", varient);
+            if (character.navMeshAgent == null) return;
+            if (character.navMeshAgent.pathPending)
+            {
+                //Debug.Log("Calculating path");
+                return;
+            } else
+            {
+                character.navMeshAgent.updatePosition = true;
+                character.navMeshAgent.isStopped = false;
+                //Debug.Log($"Following path with {character.navMeshAgent.path.corners.Length} corners ({character.unique_name})");
+            }
+            if (character.navMeshAgent.path == null) {
+                //Debug.Log("No path");
+                return;
+            }
+            if (character.navMeshAgent.path.corners.Length == 0)
+            {
+                GenericEvents.Trigger(character.unique_name + "-ArrivedInPositionAction");
+                End();
+                return;
+            }
+            if (character.navMeshAgent.isStopped) return;
+            //Debug.Log($"Remaining distance: {character.navMeshAgent.remainingDistance} ({character.unique_name})");
+            if (character.navMeshAgent.remainingDistance < character.navMeshAgent.stoppingDistance)
+            {
+                character.navMeshAgent.isStopped = true;
+                character.navMeshAgent.path.ClearCorners();
+                GenericEvents.Trigger(character.unique_name + "-ArrivedInPositionAction");
+                End();
+                return;
+            }
+            TurnToPoint(character.navMeshAgent.steeringTarget);
+            Vector3 heading = character.navMeshAgent.steeringTarget - character.transform.position;
+            float distance = heading.magnitude;
+            Vector3 direction = heading / distance;
+            Move(speed, direction);
+        }
+
+        private void Move(float speed, Vector3 direction)
+        {
+            //Debug.Log(direction);
+            character.animator.SetFloat("horizontal", 0);
+            character.animator.SetFloat("vertical", animationSpeed);
+            //character.transform.Translate(new Vector3(direction.x * speed * Time.deltaTime, 0, direction.z * speed * Time.deltaTime));
+            //if(character.navMeshAgent.isStopped == false) character.navMeshAgent.nextPosition = character.transform.position;
+        }
+
+        private void TurnToPoint(Vector3 point)
+        {
+            Quaternion targetRotation = Quaternion.LookRotation (point - character.transform.position);
+            character.animator.transform.rotation = Quaternion.Slerp (character.animator.transform.rotation, targetRotation, 100f * Time.deltaTime);
+        }
+
+        public void End()
+        {
+            character.animator.SetFloat("horizontal", 0);
+            character.animator.SetFloat("vertical", 0);
+            character.navMeshAgent.isStopped = true;
+            character.navMeshAgent.updatePosition = false;
+            character.navMeshAgent.speed = 0;
+            done = true;
+        }
+
+        public bool IsDone()
+        {
+            return done;
+        }
+    }
+}

+ 11 - 0
Runtime/Actions/ZombieMoveToPositionAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 030378675b7b93b48b056cc64f4bbc2c
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Runtime/Behaviors.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: f6c27a4875f0a5f47afb9f55f6bfacfe
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 112 - 0
Runtime/Behaviors/BehaviorDebuger.cs

@@ -0,0 +1,112 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using Sirenix.OdinInspector;
+using QFSW.QC;
+using KairoEngine.Core;
+
+namespace KairoEngine.CharacterSystem
+{
+    public class BehaviorDebuger : MonoBehaviour
+    {
+        public static BehaviorDebuger Instance { get; private set; }
+        public GameObject debugWindowPrefab;
+        public Transform windowContainer;
+
+        public bool showDebugger = false;
+        private bool debugerInitialized = false;
+        public List<BehaviorDebugerUi> debugerWindows = new List<BehaviorDebugerUi>();
+
+        private void Start()
+        {
+            if (Instance == null) Instance = this;
+        }
+
+        void Update()
+        {
+            for (int i = 0; i < debugerWindows.Count; i++)
+            {
+                var window = debugerWindows[i];
+                if(window == null) 
+                {
+                    debugerWindows.RemoveAt(i);
+                    break;
+                }
+                if(window.character == null)
+                {
+                    Destroy(window.gameObject);
+                    debugerWindows.RemoveAt(i);
+                    break;
+                }
+            }
+            if (debugerInitialized = true && showDebugger == false) StopDebuger();
+            if (showDebugger == false) return;
+            if (debugerInitialized == false) StartDebuger();
+        }
+
+        [Command("ai-debuger", "Show de AI behavior debuger windows")]
+        public static string ToogleDebuger()
+        {
+            if(Instance == null) return "AI Debuger not loaded yet.";
+            if (Instance.showDebugger == true) 
+            {
+                Instance.StopDebuger();
+                return "Debuger is OFF";
+            }
+            else 
+            {
+                Instance.StartDebuger();
+                return "Debuger is ON";
+            }
+        }
+
+        public void StartDebuger()
+        {
+            if (debugerInitialized == true) return;
+            debugerInitialized = true;
+            showDebugger = true;
+            //Debug.Log($"Initializing debuger windows ({CharacterManager.instance.sceneCharacters.Count.ToString()})");
+            for (int i = 0; i < CharacterManager.instance.sceneCharacters.Count; i++)
+            {
+                CharacterController character = CharacterManager.instance.sceneCharacters[i];
+                if(character != null) CreateDebugWindow(character);
+            }
+            RegisterEvents.OnRegisterCharacter += CreateDebugWindow;
+        }
+
+        public void StopDebuger()
+        {
+            for (int i = 0; i < debugerWindows.Count; i++)
+            {
+                if(debugerWindows[i] != null) Destroy(debugerWindows[i].gameObject);
+            }
+            debugerWindows.Clear();
+            RegisterEvents.OnRegisterCharacter -= CreateDebugWindow;
+            debugerInitialized = false;
+            showDebugger = false;
+        }
+
+        private void CreateDebugWindow(CharacterController targetCharacter)
+        {
+            for (int i = 0; i < debugerWindows.Count; i++)
+            {
+                if(debugerWindows[i].character.unique_name == targetCharacter.unique_name) 
+                {
+                    //Debug.Log($"Character already registered ({targetCharacter.unique_name})");
+                    return;
+                }
+            }
+
+            EventResponse<CharacterController> response = EventManager.request.GetCharacterController("PlayerCharacter");
+            if(response.status != EventResponseStatus.OK) return;
+            if(targetCharacter.unique_name == response.value.unique_name) return;
+            GameObject window = Instantiate(debugWindowPrefab, windowContainer);
+            BehaviorDebugerUi debuger = window.GetComponent<BehaviorDebugerUi>();
+            debuger.Initialize(targetCharacter);
+            debugerWindows.Add(debuger);
+            Debug.Log("Created AI Debug window for character " + targetCharacter.unique_name);
+        }
+    }
+}
+
+

+ 11 - 0
Runtime/Behaviors/BehaviorDebuger.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8e0dff39075aa3144b5cbfdc491d4b57
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 21 - 0
Runtime/Behaviors/BehaviorDebugerDataUi.cs

@@ -0,0 +1,21 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.UI;
+using TMPro;
+using Sirenix.OdinInspector;
+
+namespace KairoEngine
+{
+    public class BehaviorDebugerDataUi : MonoBehaviour
+    {
+        public TextMeshProUGUI label;
+        public TextMeshProUGUI value;
+
+        public void Setup(string label, string value, Color color)
+        {
+            this.label.text = label;
+            this.value.text = "<color=#" + ColorUtility.ToHtmlStringRGB(color) + ">" + value + "</color>";
+        }
+    }
+}

+ 11 - 0
Runtime/Behaviors/BehaviorDebugerDataUi.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e7ebc88893305c441a5ca10270684e54
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 203 - 0
Runtime/Behaviors/BehaviorDebugerUi.cs

@@ -0,0 +1,203 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+//using KairoEngine.Utilities;
+using TMPro;
+using Sirenix.OdinInspector;
+using NodeCanvas.Framework;
+using KairoEngine.Core;
+
+namespace KairoEngine.CharacterSystem
+{
+    public class BehaviorDebugerUi : MonoBehaviour
+    {
+        public Transform windowTransform;
+        public Transform dataContainer;
+
+        public TextMeshProUGUI titleUi;
+        public GameObject behaviorDataUiPrefab;
+
+        public float windowDistance = 3.5f;
+
+        public Color whiteColor;
+        public Color redColor;
+        public Color blueColor;
+        public Color greenColor;
+        public Color grayColor;
+        public Color magentaColor;
+
+        [ReadOnly] public KairoEngine.CharacterSystem.CharacterController character;
+
+        [ReadOnly] public Blackboard blackboard;
+
+        [ReadOnly] public KairoEngine.CharacterSystem.CharacterController targetCharacter;
+
+        public List<BehaviorDebugerDataUi> dataSlots;
+        private bool initialized = false;
+
+        public void Initialize(KairoEngine.CharacterSystem.CharacterController debugCharacter)
+        {
+            if(debugCharacter == null) 
+            {
+                Destroy(this.gameObject);
+                return;
+            }
+            initialized = true;
+            character = debugCharacter;
+            blackboard = debugCharacter.GetComponent<Blackboard>();
+            if(blackboard == null) 
+            {
+                Debug.LogError("Could not find Blackboard component in " + character.unique_name);
+                //Destroy(this.gameObject);
+                //return;
+            }
+            titleUi.text = character.unique_name;
+            for (int i = 0; i < 4; i++)
+            {
+                GameObject slot = Instantiate(behaviorDataUiPrefab, dataContainer);
+                BehaviorDebugerDataUi slotData = slot.GetComponent<BehaviorDebugerDataUi>();
+                if(slotData != null) dataSlots.Add(slotData);
+                else Debug.LogError("Could not find component BehaviorDebugerDataUi in " + slot.name);
+                
+            }
+            UpdateData();
+            UpdatePanelPosition(character.transform, windowTransform);
+        }
+
+        void Update()
+        {
+            if(initialized == false) return;
+            UpdateData();
+            if(character != null) UpdatePanelPosition(character.transform, windowTransform);
+        }
+
+        private void UpdatePanelPosition(Transform target, Transform targetPanel)
+        {
+            Vector3 pos = new Vector3(target.position.x, target.position.y + windowDistance, target.position.z);
+            Vector3 screenPos = Camera.main.WorldToScreenPoint(pos);
+            targetPanel.GetComponent<RectTransform>().position = screenPos;
+        }
+
+        private void UpdateData()
+        {
+            if(character == null)
+            {
+                Destroy(this.gameObject);
+                return;
+            }
+            if(blackboard == null)
+            {
+                blackboard = character.GetComponent<Blackboard>();
+                if(blackboard == null) return;
+            }
+            string characterState = "";
+            Color stateColor = greenColor;
+            //Debug.Log(behavior.stateMachine.currentState.GetType().ToString());
+            string currentState = blackboard.GetVariable<string>("currentState").value;
+            switch (currentState)
+            {
+                case "Idle":
+                    characterState = "Idle";
+                    break;
+                case "Shooting":
+                    characterState = "Shoot";
+                    break;
+                case "Moving":
+                    characterState = "Move";
+                    break;
+                case "Aiming":
+                    characterState = "Aim";
+                    break;
+                case "Melee Attack":
+                    characterState = "Melee Attack";
+                    break;
+                case "Unarmed Attack":
+                    characterState = "Unarmed Attack";
+                    break;
+                case "Reloading":
+                    characterState = "Reload";
+                    break;
+                case "Equiping Weapon":
+                    characterState = "Equip Weapon";
+                    break;
+                case "Dead":
+                    characterState = "Dead";
+                    stateColor = redColor;
+                    break;
+                default:
+                    characterState = "Undefined State";
+                    stateColor = redColor;
+                    break;
+            }
+            if(characterState == "")
+            {
+                characterState = "NULL";
+                stateColor = grayColor;
+            }
+            string target = "";
+            string distance = "";
+            Color targetColor = greenColor;
+            Color distanceColor = whiteColor;
+            Transform currentTarget = blackboard.GetVariable<Transform>("target").value;
+            float currentAttackDisntace = blackboard.GetVariable<float>("attackDistance").value;
+            Vector3 currentTargetPosition = blackboard.GetVariable<Vector3>("targetPosition").value;
+            if(currentTarget != null)
+            {
+                if(targetCharacter == null) targetCharacter = currentTarget.root.GetComponentInChildren<CharacterController>();
+                if(targetCharacter != null)  target = targetCharacter.unique_name;
+                else target = currentTarget.name;
+                float d = Vector3.Distance(currentTarget.position, character.transform.position);
+                d = KairoEngine.Core.Utilities.Round(d, 1);
+                if(d <= currentAttackDisntace) distanceColor = blueColor;
+                else distanceColor = redColor;
+                distance = d.ToString() + "m/" + KairoEngine.Core.Utilities.Round(currentAttackDisntace, 1) + "m";
+                
+            } 
+            else if(currentTargetPosition != new Vector3())
+            {
+                targetCharacter = null;
+                target = currentTargetPosition.ToString();
+                targetColor = grayColor;
+                float d = Vector3.Distance(currentTargetPosition, character.transform.position);
+                d = KairoEngine.Core.Utilities.Round(d, 1);
+                if(d <= currentAttackDisntace) distanceColor = blueColor;
+                else distanceColor = redColor;
+                distance = d.ToString() + "m/" + KairoEngine.Core.Utilities.Round(currentAttackDisntace, 1) + "m";
+            }
+            else
+            {
+                targetCharacter = null;
+                target = "NULL";
+                targetColor = character.HasEquipedItem() ? redColor : grayColor;
+                distance = "NULL/" + KairoEngine.Core.Utilities.Round(currentAttackDisntace, 1) + "m";
+                distanceColor = grayColor;
+            }
+            string weapon = "";
+            Color weaponColor = magentaColor;
+            if(character.HasEquipedItem())
+            {
+                weapon = character.GetEquipedItem().item.title;
+            }
+            else
+            {
+                weapon = "NULL";
+                weaponColor = grayColor;
+            }
+            if(currentState != "Dead")
+            {
+                dataSlots[0].Setup("State:", characterState, stateColor);
+                dataSlots[1].Setup("Target:", target, targetColor);
+                dataSlots[2].Setup("Distance:", distance, distanceColor);
+                dataSlots[3].Setup("Weapon:", weapon, weaponColor);
+            }
+            else
+            {
+                dataSlots[0].Setup("State:", characterState, stateColor);
+                dataSlots[1].Setup("Target:", "NULL", grayColor);
+                dataSlots[2].Setup("Distance:", "NULL", grayColor);
+                dataSlots[3].Setup("Weapon:", "NULL", grayColor);
+            }
+            
+        }
+    }
+}

+ 11 - 0
Runtime/Behaviors/BehaviorDebugerUi.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 03e69bb937d550c44b6d8b77173189be
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Runtime/Behaviors/TasksActions.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: ad1eedaf0a2199d4bb7aaf0588f98be4
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 30 - 0
Runtime/Behaviors/TasksActions/CancelActionsTaskAction.cs

@@ -0,0 +1,30 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using NodeCanvas.Framework;
+using ParadoxNotion.Design;
+using KairoEngine.Core;
+
+namespace KairoEngine.CharacterSystem
+{
+    [Category("KairoEngine")]
+    public class CharacterCancelActionsTaskAction : ActionTask
+    {
+        [BlackboardOnly, RequiredField] public BBParameter<CharacterController> character;
+
+        protected override string info 
+        {
+            get { return "Cancel Actions"; }
+        }
+        
+        protected override void OnExecute()
+        {
+            if(character.value == false) EndAction(false);
+            ICommand cancelActionsCommand = new CancelAtionsCommand(character.value);
+            CommandInvoker.AddCommand(cancelActionsCommand);
+            EndAction(true);
+        }
+    }
+}
+
+

+ 11 - 0
Runtime/Behaviors/TasksActions/CancelActionsTaskAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 849233917f9ecc54fae49d9279ca09a1
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 39 - 0
Runtime/Behaviors/TasksActions/ChangeHitpointsTaskAction.cs

@@ -0,0 +1,39 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using NodeCanvas.Framework;
+using ParadoxNotion.Design;
+
+namespace KairoEngine.CharacterSystem
+{
+    public class ChangeHitpointsTaskAction : ActionTask
+    {
+        [BlackboardOnly] public BBParameter<CharacterController> character;
+        public int hitpoints;
+        public GameObject fxPrefab;
+
+        protected override string info 
+        {
+            get 
+            { 
+                return $"Change Hitpoints ({hitpoints})";
+            }
+        }
+
+        protected override void OnExecute()
+        {
+            DamageController damageController = CharacterManager.GetCharacter("Player_Character")?.GetComponent<DamageController>();
+            if(damageController == null) return;
+            if(hitpoints > 0)
+            {
+                damageController.Heal(hitpoints);
+                GameObject.Instantiate(fxPrefab, damageController.transform.position, damageController.transform.rotation);
+            }
+            else if(hitpoints < 0)
+            {
+                
+            }
+        }
+
+    }
+}

+ 11 - 0
Runtime/Behaviors/TasksActions/ChangeHitpointsTaskAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 0e0e54d7d0c5b5548b68027571e716ac
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 43 - 0
Runtime/Behaviors/TasksActions/CharacteCheckDamageTaskAction.cs

@@ -0,0 +1,43 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using NodeCanvas.Framework;
+using ParadoxNotion.Design;
+using KairoEngine.Core;
+using KairoEngine.Inventory;
+
+namespace KairoEngine.CharacterSystem
+{
+    [Category("KairoEngine")]
+    public class CharacteCheckDamageTaskAction : ActionTask
+    {
+        [BlackboardOnly] public BBParameter<Transform> target;
+        [BlackboardOnly] public BBParameter<Vector3> targetPosition;
+
+        private float waitTime = 0f;
+        private float counter = 0f;
+
+        private ItemBaseFirearm firearm;
+        private int burstCount = 0;
+
+        protected override string info 
+        {
+            get { return "Check for damage"; }
+        }
+
+        protected override void OnExecute()
+        {
+            DamageEvents.OnDamage += OnDamage;
+        }
+
+        private void OnDamage(DamageData damageData)
+        {
+            DamageEvents.OnDamage -= OnDamage;
+            if(target != null) EndAction(true);
+            targetPosition = damageData.sourcePosition;
+            EndAction(true);
+        }
+    }
+}
+
+

+ 11 - 0
Runtime/Behaviors/TasksActions/CharacteCheckDamageTaskAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: af3f7ffbefca68b43bed68e05331f752
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 51 - 0
Runtime/Behaviors/TasksActions/CharacteCheckForInteractionTaskAction.cs

@@ -0,0 +1,51 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using NodeCanvas.Framework;
+using ParadoxNotion.Design;
+using KairoEngine.Core;
+
+namespace KairoEngine.CharacterSystem
+{
+    [Category("KairoEngine")]
+    public class CharacteCheckForInteractionTaskAction : ActionTask
+    {
+        [BlackboardOnly] public BBParameter<CharacterController> character;
+        [BlackboardOnly] public BBParameter<GameObject> interactionTarget;
+        [BlackboardOnly] public BBParameter<bool> isInteracting;
+
+        public float timer = 2f;
+        private float counter = 0f;
+
+        protected override string info 
+        {
+            get { return "Check for interaction"; }
+        }
+
+        protected override void OnExecute()
+        {
+            InteractionEvents.StartListening($"{character.value.unique_name}-StartDialogue", OnInteraction);
+            counter = 0f;
+        }
+
+        protected override void OnUpdate()
+        {
+            counter += Time.deltaTime;
+            if(counter > timer)
+            {
+                InteractionEvents.StopListening($"{character.value.unique_name}-StartDialogue", OnInteraction);
+                EndAction(false);
+            }
+        }
+
+        private void OnInteraction(EventData eventData)
+        {
+            InteractionEvents.StopListening($"{character.value.unique_name}-StartDialogue", OnInteraction);
+            interactionTarget.value = eventData.obj;
+            isInteracting.value = true;
+            EndAction(true);
+        }
+    }
+}
+
+

+ 11 - 0
Runtime/Behaviors/TasksActions/CharacteCheckForInteractionTaskAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c462b7e5ec2ff5d46ad0cd95dbc0f557
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 33 - 0
Runtime/Behaviors/TasksActions/CharacterAimTaskAction.cs

@@ -0,0 +1,33 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using NodeCanvas.Framework;
+using ParadoxNotion.Design;
+using KairoEngine.Core;
+
+namespace KairoEngine.CharacterSystem
+{
+    [Category("KairoEngine")]
+    public class CharacterAimTaskAction : ActionTask
+    {
+        [BlackboardOnly, RequiredField] public BBParameter<CharacterController> character;
+        [BlackboardOnly, RequiredField] public BBParameter<Transform> target;
+
+        protected override string info 
+        {
+            get { return "Aim at Target"; }
+        }
+
+        protected override void OnExecute()
+        {
+            if(target.value == false) EndAction(false);
+            ICommand mousePosCommand = new TurnCommand(character.value, target.value.position);
+            CommandInvoker.AddCommand(mousePosCommand);
+            ICommand aimCommand = new CharacterAimCommand(character.value, target.value);
+            CommandInvoker.AddCommand(aimCommand);
+            EndAction(true);
+        }
+    }
+}
+
+

+ 11 - 0
Runtime/Behaviors/TasksActions/CharacterAimTaskAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 012c97ba9c0abd04697230cafd819d6f
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 25 - 0
Runtime/Behaviors/TasksActions/CharacterEquipWeaponTaskAction.cs

@@ -0,0 +1,25 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using NodeCanvas.Framework;
+using ParadoxNotion.Design;
+using KairoEngine.Core;
+using KairoEngine.Inventory;
+
+namespace KairoEngine.CharacterSystem
+{
+    [Category("KairoEngine")]
+    public class CharacterEquipWeaponTaskAction : ActionTask
+    {
+        [BlackboardOnly, RequiredField] public BBParameter<CharacterController> character;
+        [BlackboardOnly, RequiredField] public BBParameter<ItemRef> itemRef;
+        protected override void OnExecute()
+        {
+            ICommand command = new EquipItemCommand(itemRef.value, character.value);
+            CommandInvoker.AddCommand(command);
+            EndAction(true);
+        }
+    }
+}
+
+

+ 11 - 0
Runtime/Behaviors/TasksActions/CharacterEquipWeaponTaskAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: fdb5c2daf374fc44282c03082f71c6a0
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 51 - 0
Runtime/Behaviors/TasksActions/CharacterHandWeaponAttackTaskAction.cs

@@ -0,0 +1,51 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using NodeCanvas.Framework;
+using ParadoxNotion.Design;
+using KairoEngine.Core;
+
+namespace KairoEngine.CharacterSystem
+{
+    [Category("KairoEngine")]
+    public class CharacterHandWeaponAttackTaskAction : ActionTask
+    {
+        [BlackboardOnly, RequiredField] public BBParameter<CharacterController> character;
+        [BlackboardOnly, RequiredField] public BBParameter<Transform> target;
+
+
+        protected override string info {
+            get { return "Melee Attack Target"; }
+        }
+
+        protected override void OnExecute()
+        {
+            ICommand cancelCommand = new CancelAtionsCommand(character.value);
+            CommandInvoker.AddCommand(cancelCommand);
+        }
+
+        protected override void OnUpdate()
+        {
+            if(target.value == null || character.value == null) EndAction(false);
+            ICommand turnCommand = new TurnCommand(character.value, target.value.position);
+            CommandInvoker.AddCommand(turnCommand);
+            ICommand attackCommand = new CharacterHandWeaponAttackCommand(character.value, target.value.position);
+            CommandInvoker.AddCommand(attackCommand);
+            GenericEvents.StartListening(character.value.unique_name + "-AnimationMeleeEnd", End);
+        }
+
+        protected override void OnStop()
+        {
+           GenericEvents.StopListening(character.value.unique_name + "-AnimationMeleeEnd", End);
+        }
+
+
+        private void End()
+        {
+            GenericEvents.StopListening(character.value.unique_name + "-AnimationMeleeEnd", End);
+            EndAction(true);
+        }
+    }
+}
+
+

+ 11 - 0
Runtime/Behaviors/TasksActions/CharacterHandWeaponAttackTaskAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ce2e09c7dc7b65a469aa38587b0ead1f
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 23 - 0
Runtime/Behaviors/TasksActions/CharacterIdleTaskAction.cs

@@ -0,0 +1,23 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using NodeCanvas.Framework;
+using ParadoxNotion.Design;
+using KairoEngine.Core;
+
+namespace KairoEngine.CharacterSystem
+{
+    [Category("KairoEngine")]
+    public class CharacterIdleTaskAction : ActionTask
+    {
+        [BlackboardOnly, RequiredField] public BBParameter<CharacterController> character;
+        protected override void OnExecute()
+        {
+            ICommand cancelCommand = new CancelAtionsCommand(character.value);
+            CommandInvoker.AddCommand(cancelCommand);
+            EndAction(true);
+        }
+    }
+}
+
+

+ 11 - 0
Runtime/Behaviors/TasksActions/CharacterIdleTaskAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 062858a79429683449352a617715d203
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 60 - 0
Runtime/Behaviors/TasksActions/CharacterMoveToPositionTaskAction.cs

@@ -0,0 +1,60 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using NodeCanvas.Framework;
+using ParadoxNotion.Design;
+using KairoEngine.Core;
+
+namespace KairoEngine.CharacterSystem
+{
+    [Category("KairoEngine")]
+    public class CharacterMoveToPositionTaskAction : ActionTask
+    {
+        [BlackboardOnly, RequiredField] public BBParameter<CharacterController> character;
+        [BlackboardOnly, RequiredField] public BBParameter<Vector3> position;
+        [RequiredField] public BBParameter<float> stoppingDistance = 1f;
+
+        public MoveSpeed moveSpeed = MoveSpeed.walk;
+
+        protected override string info {
+            get { return "Move character to position"; }
+        }
+
+        protected override void OnExecute()
+        {
+            float translationSpeed = 1.25f;
+            float animationSpeed = 1f;
+            if(moveSpeed == MoveSpeed.run)
+            {
+                translationSpeed = 3.5f;
+                animationSpeed = 2f;
+            }
+            GenericEvents.StartListening(character.value.unique_name + "-ArrivedInPositionAction", End);
+            ICommand movecommand = new CharacterMoveToPositionCommand(character.value, position.value, translationSpeed, animationSpeed, stoppingDistance.value);
+            CommandInvoker.AddCommand(movecommand);
+        }
+
+        protected override void OnUpdate()
+        {
+            float distance = Vector3.Distance(character.value.transform.position, position.value);
+            if(distance < stoppingDistance.value) End();
+        }
+
+        protected override void OnStop()
+        {
+            End();
+        }
+
+
+        private void End()
+        {
+            GenericEvents.StopListening(character.value.unique_name + "-ArrivedInPositionAction", End);
+            ICommand stopCommand = new CharacterStopMoveCommand(character.value);
+            CommandInvoker.AddCommand(stopCommand);
+            EndAction(true);
+        }
+
+    }
+}
+
+

+ 11 - 0
Runtime/Behaviors/TasksActions/CharacterMoveToPositionTaskAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e0ef7bf9276a7ae48ab8d421f45bb431
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 96 - 0
Runtime/Behaviors/TasksActions/CharacterMoveToTargetTaskAction.cs

@@ -0,0 +1,96 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using NodeCanvas.Framework;
+using ParadoxNotion.Design;
+using KairoEngine.Core;
+
+namespace KairoEngine.CharacterSystem
+{
+    public enum MoveSpeed
+    {
+        walk,
+        run
+    }
+
+    [Category("KairoEngine")]
+    public class CharacterMoveToTargetTaskAction : ActionTask
+    {
+        [BlackboardOnly, RequiredField] public BBParameter<CharacterController> character;
+        [BlackboardOnly, RequiredField] public BBParameter<Transform> target;
+        [RequiredField] public BBParameter<float> attackDistance = 1f;
+
+        public MoveSpeed moveSpeed = MoveSpeed.walk;
+
+        public BBParameter<float> lostTargetTimer = 1f; 
+        private float counter = 0f;
+        private Transform _target;
+
+        private Vector3 pos;
+        private bool success = true;
+        private bool done = false;
+
+        protected override string info {
+            get { return "Move character to target"; }
+        }
+
+        protected override void OnExecute()
+        {
+            _target = target.value;
+            IssueCommand();
+            counter = 0f;
+        }
+
+        protected override void OnUpdate()
+        {
+            if(target.value == null && !done)
+            {
+                counter += Time.deltaTime;
+                if(counter > lostTargetTimer.value)
+                {
+                    EndAction(false);
+                } 
+            }
+            else counter = 0f;
+            float distance = Vector3.Distance(character.value.transform.position, _target.position);
+            if(distance < attackDistance.value) EndAction(true);
+            float distanceFromTarget = Vector3.Distance(_target.position, pos);
+            if(distanceFromTarget > 1f && !done) 
+            {
+                GenericEvents.StopListening(character.value.unique_name + "-ArrivedInPositionAction", End);
+                IssueCommand();
+                done = false;
+            }
+        }
+
+        protected override void OnStop()
+        {
+            GenericEvents.StopListening(character.value.unique_name + "-ArrivedInPositionAction", End);
+            ICommand stopCommand = new CharacterStopMoveCommand(character.value);
+            CommandInvoker.AddCommand(stopCommand);
+        }
+
+        private void End()
+        {
+            EndAction(success);
+        }
+
+        private void IssueCommand()
+        {
+            float translationSpeed = 1.25f;
+            float animationSpeed = 1f;
+            if(moveSpeed == MoveSpeed.run)
+            {
+                translationSpeed = 3.5f;
+                animationSpeed = 2f;
+            }
+            pos = _target.position;
+            GenericEvents.StartListening(character.value.unique_name + "-ArrivedInPositionAction", End);
+            ICommand movecommand = new CharacterMoveToPositionCommand(character.value, pos, translationSpeed, animationSpeed, attackDistance.value);
+            CommandInvoker.AddCommand(movecommand);
+            
+        }
+    }
+}
+
+

+ 11 - 0
Runtime/Behaviors/TasksActions/CharacterMoveToTargetTaskAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8b0cbaf763a463749bd4da14eda470b2
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 50 - 0
Runtime/Behaviors/TasksActions/CharacterReloadTaskAction.cs

@@ -0,0 +1,50 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using NodeCanvas.Framework;
+using ParadoxNotion.Design;
+using KairoEngine.Core;
+using KairoEngine.Inventory;
+
+namespace KairoEngine.CharacterSystem
+{
+    [Category("KairoEngine")]
+    public class CharacterReloadTaskAction : ActionTask
+    {
+        [BlackboardOnly, RequiredField] public BBParameter<CharacterController> character;
+
+        private bool done = false;
+
+        protected override string info 
+        {
+            get { return "Reload Firearm"; }
+        }
+
+        protected override void OnExecute()
+        {
+            done = false;
+            ItemFirearmRef firearmRef = (ItemFirearmRef)character.value.GetEquipedItem(); 
+            if(firearmRef == null) EndAction(false);
+            if(character.value.HasSpareAmmo(firearmRef))
+            {
+                CharacterReloadFirearmCommand reloadCommand = new CharacterReloadFirearmCommand(character.value, firearmRef);
+                CommandInvoker.AddCommand(reloadCommand);
+                GenericEvents.StartListening(character.value.unique_name + "-ReloadDone", End);
+            }
+            else EndAction(true);
+        }
+
+        protected override void OnUpdate()
+        {
+            if(done == true) EndAction(true);
+        }
+
+        private void End()
+        {
+            GenericEvents.StopListening(character.value.unique_name + "-ReloadDone", End);
+            done = true;
+        }
+    }
+}
+
+

+ 11 - 0
Runtime/Behaviors/TasksActions/CharacterReloadTaskAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8eae949f6583c004e80645aa4df14311
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 69 - 0
Runtime/Behaviors/TasksActions/CharacterShootTaskAction.cs

@@ -0,0 +1,69 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using NodeCanvas.Framework;
+using ParadoxNotion.Design;
+using KairoEngine.Core;
+using KairoEngine.Inventory;
+
+namespace KairoEngine.CharacterSystem
+{
+    [Category("KairoEngine")]
+    public class CharacterShootTaskAction : ActionTask
+    {
+        [BlackboardOnly, RequiredField] public BBParameter<CharacterController> character;
+        [BlackboardOnly, RequiredField] public BBParameter<Transform> target;
+
+        private float waitTime = 0f;
+        private float counter = 0f;
+
+        private ItemBaseFirearm firearm;
+        private int burstCount = 0;
+
+        protected override string info 
+        {
+            get { return "Shoot at Target"; }
+        }
+
+        protected override void OnExecute()
+        {
+            if(character.value == null) EndAction(false);
+            if(target.value == null) EndAction(true);
+            if(character.value.GetEquipedItem() == null) EndAction(false);
+            firearm = (ItemBaseFirearm)character.value.GetEquipedItem().item;
+            waitTime = firearm.firingSpeed;
+            counter = 0f;
+            burstCount = 0;
+            ICommand shootCommand = new ShootCommand(character.value);
+            CommandInvoker.AddCommand(shootCommand);
+        }
+
+        protected override void OnUpdate()
+        {
+            if(character.value == null || firearm == null) EndAction(false);
+            if(target.value != null)
+            {
+                ICommand mousePosCommand = new TurnCommand(character.value, target.value.position);
+                CommandInvoker.AddCommand(mousePosCommand);
+            }
+            counter += Time.deltaTime;
+            if(counter > waitTime) 
+            {
+                if(firearm.isAutomatic)
+                {
+                    burstCount += 1;
+                    if(burstCount <= firearm.ammoCapacity/4)
+                    {
+                        counter = 0f;
+                        ICommand shootCommand = new ShootCommand(character.value);
+                        CommandInvoker.AddCommand(shootCommand);
+                    } 
+                    else EndAction(true);
+                }
+                else EndAction(true);
+            }
+        }
+    }
+}
+
+

+ 11 - 0
Runtime/Behaviors/TasksActions/CharacterShootTaskAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: cbdbbdb4c91ce3c41a8f491250d0d951
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 51 - 0
Runtime/Behaviors/TasksActions/CharacterUnarmedAttackTaskAction.cs

@@ -0,0 +1,51 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using NodeCanvas.Framework;
+using ParadoxNotion.Design;
+using KairoEngine.Core;
+
+namespace KairoEngine.CharacterSystem
+{
+    [Category("KairoEngine")]
+    public class CharacterUnarmedAttackTaskAction : ActionTask
+    {
+        [BlackboardOnly, RequiredField] public BBParameter<CharacterController> character;
+        [BlackboardOnly, RequiredField] public BBParameter<Transform> target;
+
+
+        protected override string info {
+            get { return "Unarmed Attack"; }
+        }
+
+        protected override void OnExecute()
+        {
+            ICommand cancelCommand = new CancelAtionsCommand(character.value);
+            CommandInvoker.AddCommand(cancelCommand);
+        }
+
+        protected override void OnUpdate()
+        {
+            if(target.value == null) EndAction(false);
+            ICommand turnCommand = new TurnCommand(character.value, target.value.position);
+            CommandInvoker.AddCommand(turnCommand);
+            ICommand attackCommand = new CharacterUnarmedAttackCommand(character.value, target.value.position);
+            CommandInvoker.AddCommand(attackCommand);
+            GenericEvents.StartListening(character.value.unique_name + "-AnimationMeleeEnd", End);
+        }
+
+        protected override void OnStop()
+        {
+           GenericEvents.StopListening(character.value.unique_name + "-AnimationMeleeEnd", End);
+        }
+
+
+        private void End()
+        {
+            GenericEvents.StopListening(character.value.unique_name + "-AnimationMeleeEnd", End);
+            EndAction(true);
+        }
+    }
+}
+
+

+ 11 - 0
Runtime/Behaviors/TasksActions/CharacterUnarmedAttackTaskAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 99645936b5b9abd4397b34222381cdca
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 29 - 0
Runtime/Behaviors/TasksActions/CharacterUnequipWeaponTaskAction.cs

@@ -0,0 +1,29 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using NodeCanvas.Framework;
+using ParadoxNotion.Design;
+using KairoEngine.Core;
+
+namespace KairoEngine.CharacterSystem
+{
+    [Category("KairoEngine")]
+    public class CharacterUnequipWeaponTaskAction : ActionTask
+    {
+        [BlackboardOnly, RequiredField] public BBParameter<CharacterController> character;
+
+        protected override string info 
+        {
+            get { return "Unequip Weapon"; }
+        }
+
+        protected override void OnExecute()
+        {
+            UnequipItemCommand unequipItemCommand = new UnequipItemCommand(character.value);
+            CommandInvoker.AddCommand(unequipItemCommand);
+            EndAction(true);
+        }
+    }
+}
+
+

+ 11 - 0
Runtime/Behaviors/TasksActions/CharacterUnequipWeaponTaskAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c53d82d85c587374e8bdc28eca9ef76c
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 68 - 0
Runtime/Behaviors/TasksActions/DialogueTradeTaskAction.cs

@@ -0,0 +1,68 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using NodeCanvas.Framework;
+using ParadoxNotion.Design;
+using KairoEngine.Core;
+using KairoEngine.Inventory;
+
+namespace KairoEngine.CharacterSystem
+{
+    public enum TradeType
+    {
+        Buy,
+        Sell
+    }
+    public class DialogueTradeTaskAction : ActionTask
+    {
+        [BlackboardOnly] public BBParameter<CharacterController> character;
+        public TradeType tradeType = TradeType.Buy;
+        private bool closed = false;
+        private string containerName;
+        private ItemContainer itemContainer;
+
+        protected override string info 
+        {
+            get 
+            { 
+                if(tradeType == TradeType.Buy) return "Buy Items";
+                else return "Sell Items"; 
+            }
+        }
+
+        protected override void OnExecute()
+        {
+            containerName = "";
+            if(tradeType == TradeType.Buy) 
+            {
+                containerName = "Buy Items";
+                itemContainer = character.value.GetComponent<ItemContainer>();
+            }
+            else 
+            {
+                containerName = "Sell Items";
+                itemContainer = character.value.GetComponents<ItemContainer>()[1];
+            }
+            ICommand openItemContainerCommand = new OpenItemContainerCommand(containerName, itemContainer);
+            CommandInvoker.AddCommand(openItemContainerCommand);
+            GenericEvents.StartListening("TradeFinished", OnTradeFinish);
+        }
+
+        protected override void OnStop()
+        {
+            GenericEvents.StopListening("TradeFinished", OnTradeFinish);
+            if(closed == false)
+            {
+                ICommand closeItemContainerCommand = new CloseItemContainerCommand(containerName);
+                CommandInvoker.AddCommand(closeItemContainerCommand);
+            }
+        }
+
+        void OnTradeFinish()
+        {
+            GenericEvents.StopListening("TradeFinished", OnTradeFinish);
+            closed = true;
+            EndAction(true);
+        }
+    }
+}

+ 11 - 0
Runtime/Behaviors/TasksActions/DialogueTradeTaskAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 059950461af78e545a23ab908d00d27d
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 28 - 0
Runtime/Behaviors/TasksActions/GetArenaRoundTaskAction.cs

@@ -0,0 +1,28 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using NodeCanvas.Framework;
+using ParadoxNotion.Design;
+//using KairoEngine.Gameplay.Arena;
+
+namespace KairoEngine
+{
+    // Todo: Refactor not to reference the ArenaControllerV2 directly
+
+    [Category("KairoEngine")]
+    public class GetArenaRoundTaskAction : ActionTask
+    {
+        [BlackboardOnly, RequiredField] public BBParameter<int> round;
+        protected override void OnExecute()
+        {
+            /*
+            ArenaControllerV2 arenaController = ArenaControllerV2.instance;
+            if(arenaController == null) return;
+            round.value = arenaController.round;
+            EndAction(true);
+            */
+        }
+    }
+}
+
+

+ 11 - 0
Runtime/Behaviors/TasksActions/GetArenaRoundTaskAction.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: faf4a60aad9a1c24fb9040a570c3bbe3
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 26 - 0
Runtime/Behaviors/TasksActions/VariableIsNullTaskCondition.cs

@@ -0,0 +1,26 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using NodeCanvas.Framework;
+using ParadoxNotion.Design;
+
+namespace KairoEngine
+{
+    [Category("KairoEngine")]
+    public class VariableIsNullTaskCondition<T> : ConditionTask
+    {
+        public BBParameter<T> variable;
+
+        protected override string info {
+            get { return variable + " == NULL"; }
+        }
+
+        protected override bool OnCheck()
+        {
+            if(variable.value == null) return true;
+            else return false;
+        }
+    }
+}
+
+

+ 11 - 0
Runtime/Behaviors/TasksActions/VariableIsNullTaskCondition.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 45a0c00ab1816534d84fd101d57b01cd
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 47 - 0
Runtime/CharacterAnimator.cs

@@ -0,0 +1,47 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using KairoEngine.Core;
+
+namespace KairoEngine.CharacterSystem
+{
+    public class CharacterAnimator : MonoBehaviour
+    {
+        private CharacterController character;
+        public void Start()
+        {
+            character = gameObject.GetComponentInParent<CharacterController>();
+            if(character == null) Debug.LogError("Missing character controller for " + gameObject.transform.parent.name);
+            
+        }
+
+        public void FootR()
+        {
+            if(character == null) return;
+            GenericEvents.Trigger(character.unique_name + "-AnimationStepDone");
+        }
+
+        public void FootL()
+        {
+            if(character == null) return;
+            GenericEvents.Trigger(character.unique_name + "-AnimationStepDone");
+        }
+
+        public void Hit()
+        {
+            if(character == null) return;
+            GenericEvents.Trigger(character.unique_name + "-AnimationHit");
+        }
+
+        public void Shoot()
+        {
+            
+        }
+
+        public void MeleeEnd()
+        {
+            if(character == null) return;
+            GenericEvents.Trigger(character.unique_name + "-AnimationMeleeEnd");
+        }
+    }
+}

+ 11 - 0
Runtime/CharacterAnimator.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 43c0b2781e525784db639aba87d6e6ef
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 303 - 0
Runtime/CharacterController.cs

@@ -0,0 +1,303 @@
+ using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.AI;
+using RootMotion.Dynamics;
+using SensorToolkit;
+using Sirenix.OdinInspector;
+using KairoEngine.Core;
+using KairoEngine.Inventory;
+
+namespace KairoEngine.CharacterSystem
+{
+    public class CharacterController : MonoBehaviour
+    {
+        [HorizontalGroup("Name"), LabelText("Name")] public string characterName;
+        [HorizontalGroup("Name", 0.2f), ReadOnly, HideLabel] public string id;
+        public string unique_name
+        {
+            get { return $"{characterName}_{id}"; }
+        }
+        public Race race;
+        public Faction faction;
+        public Gender gender;
+        public int age;
+        public Animator animator;
+        public NavMeshAgent navMeshAgent;
+        public TriggerSensor visionSensor;
+        public RangeSensor hearingSensor;
+        public SkinnedMeshRenderer meshRenderer;
+        public DamageController damageController;
+        public PuppetMaster puppetMaster;
+        public GameObject puppetMasterRoot;
+        public ItemContainer itemContainer;
+        public Transform rootTransform;
+
+        public GameObject head;
+        public GameObject rightHand;
+        public GameObject leftHand;
+
+        public GameObject rightUnarmedObject;
+        public GameObject leftUnarmedObject;
+
+        [ReadOnly] public string bodyModelName;
+        [ReadOnly] public string bodyMaterialName;
+        [ReadOnly] public string headAttachmentName;
+        [ReadOnly] public string faceAttachmentName;
+
+        private ItemRef equipedItem;
+        private GameObject equipedGameObject;
+        private bool isDead = false;
+        private float deadTime = 0f;
+        private bool removeColliders = false;
+
+        public void Start()
+        {
+            if(rightUnarmedObject != null) rightUnarmedObject.SetActive(false);
+            else Debug.LogError(unique_name + " has no rightUnarmedObject!");
+            if(leftUnarmedObject != null) leftUnarmedObject.SetActive(false);
+            else Debug.LogError(unique_name + " has no leftUnarmedObject!");
+            if(rootTransform != null) rootTransform.parent = null;
+            // Register this character in CharacterManager
+            RegisterEvents.RegisterCharacter(this);
+        }
+
+        public void Die()
+        {
+            if(isDead == true) return;
+            animator.SetTrigger("Death");
+            isDead = true;
+            ActionController actionController = gameObject.GetComponent<ActionController>();
+            if(HasEquipedItem())
+            {
+                ItemContainer itemContainer = gameObject.GetComponent<ItemContainer>();
+                //DropItemAction action = new DropItemAction(itemContainer, GetEquipedItem());
+                CharacterUnequipItemAction action = new CharacterUnequipItemAction(this);
+                actionController.AddAction(action);
+                GameObject.Destroy(GetEquipedGameObject());
+                SetEquipedItem(null);
+                SetEquipedGameObject(null);
+            }
+            actionController.CancelActions();
+            actionController.enabled = false;
+            if(navMeshAgent != null) navMeshAgent.enabled = false;
+            // Remove character rigidbody
+            Rigidbody rigidbody = gameObject.GetComponent<Rigidbody>();
+            if(rigidbody != null) Destroy(rigidbody);
+            rigidbody = gameObject.GetComponentInChildren<Rigidbody>();
+            if(rigidbody != null) Destroy(rigidbody);
+            // Disable character collider
+            CapsuleCollider collider = gameObject.GetComponent<CapsuleCollider>();
+            if(collider != null) collider.enabled = false;
+            BoxCollider boxCollider = gameObject.GetComponentInChildren<BoxCollider>();
+            if(boxCollider != null) boxCollider.enabled = false;
+            // Remove hand damage objects
+            Rigidbody rightHandRigidbody = rightHand.GetComponentInChildren<Rigidbody>();
+            Rigidbody leftHandRigidbody = leftHand.GetComponentInChildren<Rigidbody>();
+            if(rightHandRigidbody != null) Destroy(rightHandRigidbody);
+            if(leftHandRigidbody != null) Destroy(leftHandRigidbody);
+            // Remove Head rigidbody and DamagePoint
+            Rigidbody headRigidbody =  head.GetComponent<Rigidbody>();
+            if(headRigidbody != null) Destroy(headRigidbody);
+            DamagePoint damagePoint = head.GetComponent<DamagePoint>();
+            if(damagePoint != null) Destroy(damagePoint);
+            if(visionSensor != null) visionSensor.gameObject.SetActive(false);
+            if(hearingSensor != null) hearingSensor.gameObject.SetActive(false);
+            // Disable IKs
+            SetAimIK setAimIK = gameObject.GetComponentInChildren<SetAimIK>();
+            if(setAimIK != null)
+            {
+                setAimIK.aimIK.enabled = false;
+                setAimIK.limbIK.enabled = false;
+                setAimIK.secondHandOnGun.enabled = false;
+                setAimIK.aimController.enabled = false;
+                setAimIK.enabled = false;
+            }
+            //animator.enabled = false;
+            if(puppetMaster != null)
+            {
+                puppetMaster.mode = PuppetMaster.Mode.Active;
+                puppetMaster.pinWeight = 0f;
+                puppetMaster.mappingWeight = 1f;
+                puppetMaster.muscleWeight = 0.4f;
+            }
+            puppetMaster.gameObject.SetActive(true);
+        }
+
+        public bool IsDead() 
+        { 
+            return isDead; 
+        }
+
+        public void Injury()
+        {
+            animator.SetTrigger("Injury");
+        }
+
+        public void Update()
+        {
+            animator.transform.localPosition = new Vector3(0, 0, 0);
+            if(isDead)
+            {
+                deadTime += Time.deltaTime;
+                puppetMaster.gameObject.SetActive(true);
+                if(deadTime > 5f && removeColliders == false)
+                {
+                    removeColliders = true;
+                    puppetMaster.state = PuppetMaster.State.Dead;
+                    //RemoveColliders();
+                }
+            }
+        }
+
+        public bool HasEquipedItem()
+        {
+            if(equipedItem != null) return true;
+            else return false;
+        }
+
+        public ItemRef GetEquipedItem()
+        {
+            return equipedItem;
+        }
+
+        public void SetEquipedItem(ItemRef itemRef)
+        {
+            equipedItem = itemRef;
+        }
+
+        public GameObject GetEquipedGameObject()
+        {
+            return equipedGameObject;
+        }
+
+        public void SetEquipedGameObject(GameObject obj)
+        {
+            equipedGameObject = obj;
+        }
+
+        public bool HasRangedWeapon()
+        {
+            ItemRef itemRef = GetEquipedItem();
+            if(itemRef != null)
+            {
+                if(itemRef.item.category == ItemType.firearm) return true;
+            }
+            return false;
+        }
+
+        public bool HasMeleeWeapon()
+        {
+            ItemRef itemRef = GetEquipedItem();
+            if(itemRef != null)
+            {
+                if(itemRef.item.category == ItemType.handWeapon) return true;
+            }
+            return false;
+        }
+
+        public bool HasAmmo()
+        {
+            if(HasRangedWeapon() == false) return false;
+            ItemRef itemRef = GetEquipedItem();
+            if(itemRef == null) return false;
+            ItemFirearmRef firearmRef = (ItemFirearmRef)itemRef;
+            if(firearmRef == null) return false;
+            if(firearmRef.ammo > 0) return true;
+            else return false;
+        }
+
+        public bool HasSpareAmmo(ItemRef itemRef = null)
+        {
+            if(itemRef == null) itemRef = GetEquipedItem();
+            if(itemRef == null) return false;
+            ItemBaseFirearm firearmItem = (ItemBaseFirearm)itemRef.item;
+            if(firearmItem == null) return false;
+            ItemContainer itemContainer = GetComponent<ItemContainer>();
+            if(itemContainer == null) return false;
+            for (int i = 0; i < itemContainer.inventory.Count; i++)
+            {
+                if(itemContainer.inventory[i].item.title == firearmItem.ammoType.title) return true;
+            }
+            return false;
+        }
+
+        public bool IsEnemy(Transform objTransform)
+        {
+            CharacterController targetCharacter = objTransform.GetComponentInParent<CharacterController>();
+            if(targetCharacter == null) return false;
+            if(targetCharacter.IsDead()) return false;
+            return faction.IsEnemy(targetCharacter.faction.title);
+        }
+
+        public ItemRef GetEquipableWeapon()
+        {
+            ItemContainer itemContainer = GetComponent<ItemContainer>();
+            if(itemContainer == null) return null;
+            for (int i = 0; i < itemContainer.inventory.Count; i++)
+            {
+                if(itemContainer.inventory[i].item.category == ItemType.firearm)
+                {
+                    if(HasSpareAmmo(itemContainer.inventory[i]))
+                    {
+                        return itemContainer.inventory[i];
+                    }
+                }
+            }
+            for (int i = 0; i < itemContainer.inventory.Count; i++)
+            {
+                if(itemContainer.inventory[i].item.category == ItemType.handWeapon)
+                {
+                    return itemContainer.inventory[i];
+                }
+            }
+            return null;
+        }
+
+        public float GetAttackDistance(ItemRef itemRef = null)
+        {
+            if(itemRef == null) itemRef = GetEquipedItem();
+            if(itemRef == null) return 0.8f;
+            
+            if(itemRef.item.category == ItemType.firearm)
+            {
+                ItemBaseFirearm firearmItem = (ItemBaseFirearm)itemRef.item;
+                return ((firearmItem.maxDistance - firearmItem.halfDistance)/2) + firearmItem.halfDistance;
+            }
+            else if(itemRef.item.category == ItemType.handWeapon)
+            {
+                ItemBaseHandWeapon handWeapon = (ItemBaseHandWeapon)itemRef.item;
+                return handWeapon.attackDistance;
+            }
+            return 0.8f;
+        }
+
+        public void RemoveColliders()
+        {
+            if(puppetMaster != null)
+            {
+                //puppetMaster.pinWeight = 0f;
+                //puppetMaster.mappingWeight = 1f;
+                //puppetMaster.muscleWeight = 0f;
+                puppetMaster.state = PuppetMaster.State.Frozen;
+            }
+            
+            // Collider[] colliders = gameObject.transform.root.GetComponentsInChildren<Collider>();
+            // for (int i = 0; i < colliders.Length; i++)
+            // {
+            //     Destroy(colliders[i]);
+            // }
+            // ConfigurableJoint[] joints = gameObject.transform.root.GetComponentsInChildren<ConfigurableJoint>();
+            // for (int i = 0; i < joints.Length; i++)
+            // {
+            //     Destroy(joints[i]);
+            // }
+            // Rigidbody[] rigidbodies = gameObject.transform.root.GetComponentsInChildren<Rigidbody>();
+            // for (int i = 0; i < rigidbodies.Length; i++)
+            // {
+            //     Destroy(rigidbodies[i]);
+            // }
+            
+        }
+    }
+}

+ 11 - 0
Runtime/CharacterController.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 9cc8266facd8dd24fb5fd60d5e850b97
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 264 - 0
Runtime/CharacterGenerator.cs

@@ -0,0 +1,264 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using Sirenix.OdinInspector;
+using System;
+using System.Linq;
+using UnityEngine.Assertions;
+using NodeCanvas.Framework;
+using KairoEngine.Core;
+using KairoEngine.Inventory;
+
+namespace KairoEngine.CharacterSystem
+{
+    public class CharacterGenerator : MonoBehaviour
+    {
+        public static CharacterGenerator instance;
+        public GameObject characterTemplatePrefab;
+
+        [AssetList(Path = "/Data/Characters/ModelData/", AutoPopulate = true)]
+        public List<ModelData> modelList;
+        
+        [AssetList(Path = "/Data/Characters/Attachments/", AutoPopulate = true)]
+        public List<GameObject> attachmentList;
+
+        void OnEnable()
+        {
+            GenericEvents.StartListening("GenerateCharacter", Create);
+        }
+
+        void OnDisable()
+        {
+            GenericEvents.StopListening("GenerateCharacter", Create);
+        }
+
+        void Awake()
+        {
+            if(instance == null) instance = this;
+            else Destroy(this.gameObject);
+        }
+
+        public void Create(ScriptableObject scriptableObject)
+        {
+            CharacterData characterData = (CharacterData)scriptableObject;
+            Create(characterData);
+        }
+
+        public static CharacterController Create(CharacterData data, Vector3 position, Quaternion rotation)
+        {
+            data.hasSpawned = true;
+            data.position = position;
+            data.rotation = rotation;
+            return Create(data);
+        }
+
+        public static CharacterController Create(CharacterData data)
+        {
+            // Instantiate Template Character Prefab
+            GameObject characterObj = GameObject.Instantiate(instance.characterTemplatePrefab, data.position, data.rotation);
+            characterObj.name = "Character_" + data.characterName;
+            CharacterController characterController = characterObj.GetComponentInChildren<CharacterController>();
+            // Set Body Model
+            ModelData modelData = FindModel(data.bodyModel);
+            if(modelData == null) 
+            {
+                Debug.LogError("No modelData found with name " + data.bodyModel, data);
+                return null;
+            }
+            Material material = GetMaterialInModelData(modelData, data.bodyMaterial);
+            SkinRigger skinRigger = characterObj.GetComponentInChildren<SkinRigger>();
+            if(skinRigger == null) Debug.LogError("Missing SkinRigger component", characterObj);
+            else skinRigger.Setup(modelData, material);
+            // Set Head Attachment
+            if(data.headAttachment != "")
+            {
+                GameObject headAttachmentPrefab = FindAttachment(data.headAttachment);
+                if(headAttachmentPrefab != null) GameObject.Instantiate(headAttachmentPrefab, characterController.head.transform);
+            }
+            // Set Face Attachment
+            if(data.faceAttachment != "")
+            {
+                GameObject faceAttachmentPrefab = FindAttachment(data.faceAttachment);
+                if(faceAttachmentPrefab != null) GameObject.Instantiate(faceAttachmentPrefab, characterController.head.transform);
+            }
+            // Set Name
+            characterController.characterName = data.name;
+            characterController.id = data.id;
+            // Set Faction
+            characterController.faction = data.faction;
+            // Set details
+            characterController.race = data.race;
+            characterController.gender = data.gender;
+            characterController.age = data.age;
+            // Set Visuals
+            characterController.bodyModelName = data.bodyModel;
+            characterController.bodyMaterialName = data.bodyMaterial;
+            characterController.headAttachmentName = data.headAttachment;
+            characterController.faceAttachmentName = data.faceAttachment;
+            // Set Hitpoints and armor
+            characterController.damageController.SetHP(data.hitpoints);
+            characterController.damageController.SetMaxHP(data.maxHitpoints);
+            characterController.damageController.SetArmor(data.armor);
+            // Set inventory items
+            ItemContainer itemContainer = characterController.GetComponent<ItemContainer>();
+            for (int b = 0; b < data.itemList.Count; b++)
+            {
+                if(data.itemList[b].item.category == ItemType.firearm)
+                {
+                    var originalFirearmRef = data.itemList[b] as ItemFirearmRef;
+                    if (originalFirearmRef == null)
+                    {
+                        ItemBaseFirearm itemBaseFirearm = (ItemBaseFirearm)data.itemList[b].item;
+                        ItemBaseAmmo itemBaseAmmo = (ItemBaseAmmo)itemBaseFirearm.ammoType;
+                        int ammo = itemBaseFirearm.ammoCapacity;
+                        ItemFirearmRef firearmRef = new ItemFirearmRef(itemBaseFirearm, data.itemList[b].quantity, itemBaseAmmo, ammo);
+                        itemContainer.AddItem(firearmRef);
+                    }
+                    else
+                    {
+                        ItemFirearmRef newFirearm = new ItemFirearmRef(data.itemList[b].item, data.itemList[b].quantity, originalFirearmRef.ammoType, 
+                            originalFirearmRef.ammo, originalFirearmRef.accuracyModifier, originalFirearmRef.lastUsed);
+                        itemContainer.AddItem(newFirearm);
+                    }
+                    
+                }
+                else
+                {
+                    ItemRef newItem = new ItemRef(data.itemList[b].item, data.itemList[b].quantity, data.itemList[b].lastUsed);
+                    itemContainer.AddItem(newItem);
+                } 
+            }
+            // Set Sensors
+            if(characterController.visionSensor != null) characterController.visionSensor.enabled = data.vision;
+            if(characterController.hearingSensor != null) characterController.hearingSensor.enabled = data.hearing;
+            // Set death stance
+            if(data.isDead)
+            {
+                characterController.Die();
+                SetBones(data.bones, characterController);
+            }
+            // Set Dialogue
+            Blackboard blackboard = characterController.GetComponent<Blackboard>();
+            if(blackboard !=null && data.dialogueTree != null) blackboard.SetVariableValue("dialogueTree", data.dialogueTree);
+            return characterController;
+        }
+
+        public static ModelData FindModel(string title)
+        {
+            for (int i = 0; i < instance.modelList.Count; i++)
+            {
+                if(instance.modelList[i] != null)
+                {
+                    if(instance.modelList[i].name == title) return instance.modelList[i];
+                }
+                
+            }
+            return null;
+        }
+
+        public static Material GetMaterialInModelData(ModelData modelData, string materialName)
+        {
+            if(modelData != null) 
+            {
+                for (int i = 0; i < modelData.materials.Count; i++)
+                {
+                    if(modelData.materials[i].name == materialName) return modelData.materials[i];
+                }
+            }
+            return null;
+        }
+
+        public static GameObject FindAttachment(string title)
+        {
+            for (int i = 0; i < instance.attachmentList.Count; i++)
+            {
+                if(instance.attachmentList[i].name == title) return instance.attachmentList[i];
+            }
+            return null;
+        }
+
+        public static void SetBones(List<DataBone> bones, CharacterController character)
+        {
+            int boneCount = 0;
+            character.animator.enabled = false;
+            Destroy(character.puppetMaster.gameObject);
+            Transform[] transforms = character.transform.root.GetComponentsInChildren<Transform>();
+            for (int i = 0; i < bones.Count; i++)
+            {
+                for (int a = 0; a < transforms.Length; a++)
+                {
+                    if(bones[i].name == transforms[a].gameObject.name)
+                    {
+                        transforms[a].position = bones[i].position;
+                        transforms[a].rotation = bones[i].rotation;
+                        boneCount += 1;
+                    }
+                }
+            }
+            Debug.Log($"Set up {boneCount}/{bones.Count} bones for {character.unique_name}");
+        }
+
+        public static void UpdateBoneOrder(SkinnedMeshRenderer meshRenderer)
+        {
+            Transform[] children = meshRenderer.rootBone.GetComponentsInChildren<Transform>();
+            Transform[] bones = new Transform[meshRenderer.bones.Length];
+            for (int boneOrder = 0; boneOrder < meshRenderer.bones.Length; boneOrder++)
+            {
+                bones[boneOrder] = Array.Find<Transform>(children, c => c.name == meshRenderer.bones[boneOrder].name);
+            }
+            meshRenderer.bones = bones;
+        }
+
+        public static void UpdateBoneOrder2(SkinnedMeshRenderer rend)
+        {
+            //list of bones
+            List<Transform> tList = rend.bones.ToList();
+    
+            //sort alphabetically
+            tList.Sort(CompareTransform);
+    
+            //record bone index mappings (richardf advice)
+            //build a Dictionary<int, int> that records the old bone index => new bone index mappings,
+            //then run through every vertex and just do boneIndexN = dict[boneIndexN] for each weight on each vertex.
+            Dictionary<int, int> remap = new Dictionary<int, int>();
+            for (int i = 0; i < rend.bones.Length; i++)
+            {
+                remap[i] = tList.IndexOf(rend.bones[i]);
+            }
+    
+            //remap bone weight indexes
+            BoneWeight[] bw = rend.sharedMesh.boneWeights;
+            for (int i = 0; i < bw.Length; i++)
+            {
+                bw[i].boneIndex0 = remap[bw[i].boneIndex0];
+                bw[i].boneIndex1 = remap[bw[i].boneIndex1];
+                bw[i].boneIndex2 = remap[bw[i].boneIndex2];
+                bw[i].boneIndex3 = remap[bw[i].boneIndex3];
+            }
+    
+            //remap bindposes
+            Matrix4x4[] bp = new Matrix4x4[rend.sharedMesh.bindposes.Length];
+            for (int i = 0; i < bp.Length; i++)
+            {
+                var r = remap[i];
+                if(bp.Length > r && rend.sharedMesh.bindposes.Length > i)
+                {
+                    bp[r] = rend.sharedMesh.bindposes[i];
+                }
+                
+            }
+    
+            //assign new data
+            rend.bones = tList.ToArray();
+            rend.sharedMesh.boneWeights = bw;
+            rend.sharedMesh.bindposes = bp;
+        }
+ 
+        private static int CompareTransform(Transform A, Transform B)
+        {
+            return A.name.CompareTo(B.name);
+        }
+    }
+}
+
+

+ 11 - 0
Runtime/CharacterGenerator.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e1751006faeecae44a0de9ad0dd1e9f9
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 90 - 0
Runtime/CharacterManager.cs

@@ -0,0 +1,90 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using Sirenix.OdinInspector;
+
+
+namespace KairoEngine.CharacterSystem
+{
+    public class CharacterManager : MonoBehaviour
+    {
+        public static CharacterManager instance;
+
+        public List<CharacterController> sceneCharacters = new List<CharacterController>();
+        public List<string> worldCharacterNames = new List<string>();
+
+        public List<string> spawnerIds = new List<string>();
+
+        void OnEnable()
+        {
+            RegisterEvents.OnRegisterCharacter += RegisterCharacter;
+        }
+
+        void OnDisable()
+        {
+            RegisterEvents.OnRegisterCharacter += RegisterCharacter;
+        }
+
+        void Awake()
+        {
+            if(instance == null) instance = this;
+            else Destroy(this.gameObject);
+        }
+
+        void Update()
+        {
+            for (int i = 0; i < sceneCharacters.Count; i++)
+            {
+                if(sceneCharacters[i] == null)
+                {
+                    sceneCharacters.RemoveAt(i);
+                    i -= 1;
+                } 
+            }
+        }
+
+        private void RegisterCharacter(CharacterController character)
+        {
+            sceneCharacters.Add(character);
+            if(nameIsRegistered(character.unique_name)) return;
+            worldCharacterNames.Add(character.unique_name);
+        }
+
+        public static void RegisterSpawner(string id) => instance.spawnerIds.Add(id);
+
+        public static bool nameIsRegistered(string characterName)
+        {
+            for (int i = 0; i < instance.worldCharacterNames.Count; i++)
+            {
+                if(instance.worldCharacterNames[i] == characterName) return true;
+            }
+            return false;
+        }
+
+        public static bool spawnerIsRegistered(string id)
+        {
+            for (int i = 0; i < instance.spawnerIds.Count; i++)
+            {
+                if(instance.spawnerIds[i] == id) return true;
+            }
+            return false;
+        }
+
+        public static void Reset()
+        {
+            instance.sceneCharacters.Clear();
+            instance.worldCharacterNames.Clear();
+            instance.spawnerIds.Clear();
+        }
+
+        public static CharacterController GetCharacter(string name)
+        {
+            for (int i = 0; i < instance.sceneCharacters.Count; i++)
+            {
+                if(instance.sceneCharacters[i].unique_name == name) return instance.sceneCharacters[i];
+            }
+            return null;
+        }
+    }
+}
+

+ 11 - 0
Runtime/CharacterManager.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e96760a27e63517428791717f4af4c90
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

Some files were not shown because too many files changed in this diff