diff --git a/Assets/BossRoom/GameData/Action/Boss/BossImpTrampleAttack.asset b/Assets/BossRoom/GameData/Action/Boss/BossImpTrampleAttack.asset index 22e378459..3cfd05360 100644 --- a/Assets/BossRoom/GameData/Action/Boss/BossImpTrampleAttack.asset +++ b/Assets/BossRoom/GameData/Action/Boss/BossImpTrampleAttack.asset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:042274c3870033c4f5bf81bb62fed2740a97a9541df03ab5cc7a885000dc9bcc -size 935 +oid sha256:818857ebae4fad947db07995cf25acf9838d60e6c8c60ec16c9238c1b16546b3 +size 955 diff --git a/Assets/BossRoom/GameData/Character/ImpBoss/BaseHP.asset b/Assets/BossRoom/GameData/Character/ImpBoss/BaseHP.asset index af834102e..f33bba7e8 100644 --- a/Assets/BossRoom/GameData/Character/ImpBoss/BaseHP.asset +++ b/Assets/BossRoom/GameData/Character/ImpBoss/BaseHP.asset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f657f7081f4fb2c005104ef7612e7c8816ac8ce2aa6485b146767190c7264841 +oid sha256:d3026ee5a68e09d7653227c668997ab9b0b38255444254da1ffbfe025ebcf619 size 408 diff --git a/Assets/BossRoom/Models/Animation Controllers/CharacterSetController.controller b/Assets/BossRoom/Models/Animation Controllers/CharacterSetController.controller index 0ad2e669c..a0057dbea 100644 --- a/Assets/BossRoom/Models/Animation Controllers/CharacterSetController.controller +++ b/Assets/BossRoom/Models/Animation Controllers/CharacterSetController.controller @@ -273,7 +273,7 @@ AnimatorStateTransition: m_TransitionDuration: 0.12049153 m_TransitionOffset: 0 m_ExitTime: 0.1350613 - m_HasExitTime: 1 + m_HasExitTime: 0 m_HasFixedDuration: 1 m_InterruptionSource: 0 m_OrderedInterruption: 1 @@ -1851,6 +1851,7 @@ AnimatorState: m_CycleOffset: 0 m_Transitions: - {fileID: -5472320550880040946} + - {fileID: 8725031495282662693} m_StateMachineBehaviours: [] m_Position: {x: 50, y: 50, z: 0} m_IKOnFeet: 0 @@ -2477,7 +2478,7 @@ AnimatorStateTransition: m_TransitionDuration: 0.07605173 m_TransitionOffset: 0 m_ExitTime: 0.042834345 - m_HasExitTime: 1 + m_HasExitTime: 0 m_HasFixedDuration: 1 m_InterruptionSource: 0 m_OrderedInterruption: 1 @@ -3054,6 +3055,31 @@ AnimatorStateTransition: m_InterruptionSource: 0 m_OrderedInterruption: 1 m_CanTransitionToSelf: 1 +--- !u!1101 &8725031495282662693 +AnimatorStateTransition: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_Conditions: + - m_ConditionMode: 1 + m_ConditionEvent: Stunned + m_EventTreshold: 0 + m_DstStateMachine: {fileID: 0} + m_DstState: {fileID: -1989540649778147493} + m_Solo: 0 + m_Mute: 0 + m_IsExit: 0 + serializedVersion: 3 + m_TransitionDuration: 0.25 + m_TransitionOffset: 0 + m_ExitTime: 0.8214297 + m_HasExitTime: 0 + m_HasFixedDuration: 1 + m_InterruptionSource: 0 + m_OrderedInterruption: 1 + m_CanTransitionToSelf: 1 --- !u!1101 &8727437690882463675 AnimatorStateTransition: m_ObjectHideFlags: 1 diff --git a/Assets/BossRoom/Prefabs/Game/BreakablePillar.prefab b/Assets/BossRoom/Prefabs/Game/BreakablePillar.prefab index 5cbf64cf6..0d6a60b18 100644 --- a/Assets/BossRoom/Prefabs/Game/BreakablePillar.prefab +++ b/Assets/BossRoom/Prefabs/Game/BreakablePillar.prefab @@ -14,6 +14,7 @@ GameObject: - component: {fileID: -8903857516321632127} - component: {fileID: 1460791283510277443} - component: {fileID: 7670444733571025649} + - component: {fileID: 6825752226794478105} m_Layer: 6 m_Name: BreakablePillar m_TagString: Untagged @@ -79,6 +80,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: eb44a31731a459546bdf01f1af48173c, type: 3} m_Name: m_EditorClassIdentifier: + m_MaxHealth: {fileID: 0} + m_NetworkHealthState: {fileID: 0} + m_Collider: {fileID: 1460791283510277443} + m_SpecialDamageFlags: 6 --- !u!65 &1460791283510277443 BoxCollider: m_ObjectHideFlags: 0 @@ -109,6 +114,22 @@ MonoBehaviour: m_UnbrokenGameObjects: - {fileID: 3658718798844854089} m_NetState: {fileID: 7561466626167410996} +--- !u!54 &6825752226794478105 +Rigidbody: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 884761565141663561} + serializedVersion: 2 + m_Mass: 1 + m_Drag: 0 + m_AngularDrag: 0.05 + m_UseGravity: 1 + m_IsKinematic: 0 + m_Interpolate: 0 + m_Constraints: 126 + m_CollisionDetection: 0 --- !u!1001 &2926384259182416435 PrefabInstance: m_ObjectHideFlags: 0 diff --git a/Assets/BossRoom/Prefabs/GameDataSource.prefab b/Assets/BossRoom/Prefabs/GameDataSource.prefab index 7099e31de..a60c09c40 100644 --- a/Assets/BossRoom/Prefabs/GameDataSource.prefab +++ b/Assets/BossRoom/Prefabs/GameDataSource.prefab @@ -72,3 +72,4 @@ MonoBehaviour: - {fileID: 11400000, guid: 90a7c42b138147742a5ef0e724143a74, type: 2} - {fileID: 11400000, guid: c8770f39d4807a842bea85cfb3b8a649, type: 2} - {fileID: 11400000, guid: 0626aa2c2ce0d3a4ab4cad814432c2e5, type: 2} + - {fileID: 11400000, guid: 08dc234d2353e0f489e45a0a4a09bf60, type: 2} diff --git a/Assets/BossRoom/Scripts/Server/Game/Action/TrampleAction.cs b/Assets/BossRoom/Scripts/Server/Game/Action/TrampleAction.cs index fedd5f28d..0e13040a6 100644 --- a/Assets/BossRoom/Scripts/Server/Game/Action/TrampleAction.cs +++ b/Assets/BossRoom/Scripts/Server/Game/Action/TrampleAction.cs @@ -132,9 +132,7 @@ private void CollideWithVictim(ServerCharacter victim) if (chanceToStun > 0 && Random.Range(0,1) < chanceToStun) { // we're stunned! No collision behavior for the victim. Stun ourselves and abort. - m_WasStunned = true; - m_Movement.CancelMove(); - m_Parent.NetState.RecvCancelAllActionsClientRpc(); + StunSelf(); return; } @@ -156,23 +154,44 @@ private void CollideWithVictim(ServerCharacter victim) victimMovement.StartKnockback(m_Parent.transform.position, Description.KnockbackSpeed, Description.KnockbackDuration); } + // called by owning class when parent's Collider collides with stuff public override void OnCollisionEnter(Collision collision) { - var actionStage = GetCurrentStage(); // we only detect other possible victims when we start charging - if (actionStage != ActionStage.Charging) + if (GetCurrentStage() != ActionStage.Charging) return; - if (m_CollidedAlready.Contains(collision.collider)) + Collide(collision.collider); + } + + // here we handle colliding with anything (whether a victim or not) + private void Collide(Collider collider) + { + if (m_CollidedAlready.Contains(collider)) return; // already hit them! - m_CollidedAlready.Add(collision.collider); + m_CollidedAlready.Add(collider); - var victim = collision.collider.gameObject.GetComponent(); + var victim = collider.gameObject.GetComponent(); if (victim) { CollideWithVictim(victim); } + else if (!m_WasStunned) + { + // they aren't a living, breathing victim, but they might still be destructible... + var damageable = collider.gameObject.GetComponent(); + if (damageable != null) + { + damageable.ReceiveHP(this.m_Parent, -Description.SplashDamage); + + // lastly, a special case: if the trampler runs into certain breakables, they are stunned! + if ((damageable.GetSpecialDamageFlags() & IDamageable.SpecialDamageFlags.StunOnTrample) == IDamageable.SpecialDamageFlags.StunOnTrample) + { + StunSelf(); + } + } + } } private void SimulateCollisionWithNearbyFoes() @@ -184,13 +203,18 @@ private void SimulateCollisionWithNearbyFoes() int numResults = ActionUtils.DetectNearbyEntities(true, true, m_Parent.GetComponent(), k_PhysicalTouchDistance, out results); for (int i = 0; i < numResults; i++) { - m_CollidedAlready.Add(results[i].collider); - var serverChar = results[i].collider.GetComponent(); - if (serverChar) - { - CollideWithVictim(serverChar); - } + Collide(results[i].collider); + } + } + + private void StunSelf() + { + if (!m_WasStunned) + { + m_Movement.CancelMove(); + m_Parent.NetState.RecvCancelAllActionsClientRpc(); } + m_WasStunned = true; } public override bool ChainIntoNewAction(ref ActionRequestData newAction) diff --git a/Assets/BossRoom/Scripts/Server/Game/Character/ServerCharacter.cs b/Assets/BossRoom/Scripts/Server/Game/Character/ServerCharacter.cs index 83f9b80ff..6986ee231 100644 --- a/Assets/BossRoom/Scripts/Server/Game/Character/ServerCharacter.cs +++ b/Assets/BossRoom/Scripts/Server/Game/Character/ServerCharacter.cs @@ -270,5 +270,10 @@ private void OnStoppedChargingUp() { m_ActionPlayer.OnGameplayActivity(Action.GameplayActivity.StoppedChargingUp); } + + public IDamageable.SpecialDamageFlags GetSpecialDamageFlags() + { + return IDamageable.SpecialDamageFlags.None; + } } } diff --git a/Assets/BossRoom/Scripts/Server/Game/Entity/IDamageable.cs b/Assets/BossRoom/Scripts/Server/Game/Entity/IDamageable.cs index a2e72446e..b892cbdfa 100644 --- a/Assets/BossRoom/Scripts/Server/Game/Entity/IDamageable.cs +++ b/Assets/BossRoom/Scripts/Server/Game/Entity/IDamageable.cs @@ -1,3 +1,4 @@ +using System; using UnityEngine; namespace BossRoom.Server @@ -24,6 +25,23 @@ public interface IDamageable /// The transform of this object. /// Transform transform { get; } + + [Flags] + public enum SpecialDamageFlags + { + None = 0, + UnusedFlag = 1 << 0, // does nothing; see comments below + StunOnTrample = 1 << 1, + NotDamagedByPlayers = 1 << 2, + + // The "UnusedFlag" flag does nothing. It exists to work around a Unity editor quirk involving [Flags] enums: + // if you enable all the flags, Unity stores the value as 0xffffffff (labeled "Everything"), meaning that not + // only are all the currently-existing flags enabled, but any future flags you added later would also be enabled! + // This is not future-proof and can cause hard-to-track-down problems, when prefabs magically inherit a new flag + // you just added. So we have the Unused flag, which should NOT do anything, and shouldn't be selected on prefabs. + // It's just there so that we can select all the "real" flags and not get it turned into "Everything" in the editor. + } + SpecialDamageFlags GetSpecialDamageFlags(); } } diff --git a/Assets/BossRoom/Scripts/Server/Game/Entity/ServerBreakableLogic.cs b/Assets/BossRoom/Scripts/Server/Game/Entity/ServerBreakableLogic.cs index d27af3672..531efccb7 100644 --- a/Assets/BossRoom/Scripts/Server/Game/Entity/ServerBreakableLogic.cs +++ b/Assets/BossRoom/Scripts/Server/Game/Entity/ServerBreakableLogic.cs @@ -21,6 +21,10 @@ public class ServerBreakableLogic : NetworkBehaviour, IDamageable [SerializeField] Collider m_Collider; + [SerializeField] + [Tooltip("Indicate which special interaction behaviors are needed for this breakable")] + IDamageable.SpecialDamageFlags m_SpecialDamageFlags; + private NetworkBreakableState m_State; private void Awake() @@ -47,6 +51,16 @@ public void ReceiveHP(ServerCharacter inflicter, int HP) { if (HP < 0) { + if (inflicter && !inflicter.IsNpc) + { + bool isNotDamagedByPlayers = (GetSpecialDamageFlags() & IDamageable.SpecialDamageFlags.NotDamagedByPlayers) == IDamageable.SpecialDamageFlags.NotDamagedByPlayers; + if (isNotDamagedByPlayers) + { + // a player tried to damage us, but we are immune to player damage! + return; + } + } + if (m_NetworkHealthState) { m_NetworkHealthState.HitPoints.Value = Mathf.Max(m_NetworkHealthState.HitPoints.Value + HP, 0); @@ -79,6 +93,11 @@ public void Unbreak() m_NetworkHealthState.HitPoints.Value = m_MaxHealth.Value; } + public IDamageable.SpecialDamageFlags GetSpecialDamageFlags() + { + return m_SpecialDamageFlags; + } + #if UNITY_EDITOR private void OnValidate() {