Ejemplo n.º 1
0
    /// <summary>
    /// honk on world click
    /// </summary>
    public void ServerPerformInteraction(PositionalHandApply interaction)
    {
        bool inCloseRange = Validations.IsInReach(interaction.TargetVector);
        var  targetObject = interaction.TargetObject;
        var  targetHealth = targetObject != null?targetObject.GetComponent <LivingHealthBehaviour>() : null;

        bool isCrit = Random.Range(0f, 1f) <= CritChance;

        // honking in someone's face
        if (inCloseRange && (targetHealth != null))
        {
            interaction.Performer.GetComponent <WeaponNetworkActions>().RpcMeleeAttackLerp(interaction.TargetVector, gameObject);
            Chat.AddAttackMsgToChat(interaction.Performer, targetObject, BodyPartType.None, gameObject);

            ClassicHonk();

            if (isCrit)
            {
                StartCoroutine(CritHonk(interaction, targetHealth));
            }
        }
        else
        {
            ClassicHonk();
        }

        StartCoroutine(StartCooldown());
    }
Ejemplo n.º 2
0
 private void AttackFlesh(Vector2 dir, LivingHealthBehaviour healthBehaviour)
 {
     healthBehaviour.ApplyDamageToBodypart(gameObject, hitDamage, AttackType.Melee, DamageType.Brute, defaultTarget.Randomize());
     Chat.AddAttackMsgToChat(gameObject, healthBehaviour.gameObject, defaultTarget, null, attackVerb);
     SoundManager.PlayNetworkedAtPos("BladeSlice", transform.position, sourceObj: gameObject);
     ServerDoLerpAnimation(dir);
 }
Ejemplo n.º 3
0
    //We need to slow the attack down because clients are behind server
    IEnumerator AttackFleshRoutine(Vector2 dir, LivingHealthBehaviour healthBehaviour)
    {
        if (healthBehaviour.connectionToClient == null)
        {
            yield break;
        }

        ServerDoLerpAnimation(dir);

        Debug.Log(
            $"CONN CLIENT TIME: {healthBehaviour.connectionToClient.lastMessageTime} Network time: {(float) NetworkTime.time}");
        if (PlayerManager.LocalPlayerScript != null &&
            PlayerManager.LocalPlayerScript.playerHealth != null &&
            PlayerManager.LocalPlayerScript.playerHealth == healthBehaviour ||
            healthBehaviour.RTT == 0f)
        {
            yield return(WaitFor.EndOfFrame);
        }
        else
        {
            Debug.Log($"WAIT FOR ATTACK: {healthBehaviour.RTT / 2f}");
            yield return(WaitFor.Seconds(healthBehaviour.RTT / 2f));
        }

        if (Vector3.Distance(transform.position, healthBehaviour.transform.position) < 1.5f)
        {
            healthBehaviour.ApplyDamageToBodypart(gameObject, hitDamage, AttackType.Melee, DamageType.Brute,
                                                  defaultTarget.Randomize());
            Chat.AddAttackMsgToChat(gameObject, healthBehaviour.gameObject, defaultTarget, null, attackVerb);
            SoundManager.PlayNetworkedAtPos("BladeSlice", transform.position, sourceObj: gameObject);
        }
    }
Ejemplo n.º 4
0
    /// <summary>
    /// honk on world click
    /// </summary>
    public void ServerPerformInteraction(PositionalHandApply interaction)
    {
        Vector3 performerWorldPos = interaction.PerformerPlayerScript.WorldPos;
        bool    inCloseRange      = Validations.IsReachableByPositions(performerWorldPos, performerWorldPos + (Vector3)interaction.TargetVector, true, context: interaction.TargetObject);
        var     targetObject      = interaction.TargetObject;
        var     targetHealth      = targetObject != null?targetObject.GetComponent <LivingHealthMasterBase>() : null;

        bool isCrit = Random.Range(0f, 1f) <= CritChance;

        // honking in someone's face
        if (inCloseRange && (targetHealth != null))
        {
            interaction.Performer.GetComponent <WeaponNetworkActions>().RpcMeleeAttackLerp(interaction.TargetVector, gameObject);
            Chat.AddAttackMsgToChat(interaction.Performer, targetObject, BodyPartType.None, gameObject);

            ClassicHonk();

            if (isCrit && interaction.Intent == Intent.Harm)
            {
                StartCoroutine(CritHonk(interaction, targetHealth));
            }
        }
        else
        {
            ClassicHonk();
        }

        StartCoroutine(StartCooldown());
    }
        private bool TryDamage(RaycastHit2D hit)
        {
            var coll      = hit.collider;
            var integrity = coll.GetComponent <Integrity>();

            if (integrity == null)
            {
                return(false);
            }

            float newDamage = projectileKineticDamage.DamageByPressureModifier(damageData.Damage);

            integrity.ApplyDamage(newDamage, damageData.AttackType, damageData.DamageType);

            Chat.AddAttackMsgToChat(
                shooter,
                coll.gameObject,
                BodyPartType.None,
                weapon.gameObject);

            Logger.LogTraceFormat(
                "Hit {0} for {1} with Integrity! bullet absorbed",
                Category.Firearms,
                integrity.gameObject.name,
                newDamage);

            return(true);
        }
Ejemplo n.º 6
0
        //We need to slow the attack down because clients are behind server
        private async Task AttackFleshRoutine(Vector2 dir, LivingHealthBehaviour targetHealth, LivingHealthMasterBase livingHealth,
                                              Vector3 worldPos, NetworkConnection ctc, float rtt)
        {
            if (targetHealth == null && livingHealth == null)
            {
                return;
            }
            if (ctc == null)
            {
                return;
            }

            ServerDoLerpAnimation(dir);

            if (PlayerManager.LocalPlayerScript != null &&
                PlayerManager.LocalPlayerScript.playerHealth != null &&
                PlayerManager.LocalPlayerScript.playerHealth == livingHealth ||
                rtt < 0.02f)
            {
                //Wait until the end of the frame
                await Task.Delay(1);
            }
            else
            {
                //Wait until RTT/2 seconds?
                Logger.Log($"WAIT FOR ATTACK: {rtt / 2f}", Category.Mobs);
                await Task.Delay((int)(rtt * 500));
            }

            if (Vector3.Distance(mobTile.WorldPositionServer, worldPos) < 1.5f)
            {
                var bodyPartTarget = defaultTarget.Randomize();
                if (targetHealth != null)
                {
                    targetHealth.ApplyDamageToBodyPart(gameObject, hitDamage, AttackType.Melee, DamageType.Brute,
                                                       bodyPartTarget);
                    Chat.AddAttackMsgToChat(gameObject, targetHealth.gameObject, bodyPartTarget, null, attackVerb);
                }
                else
                {
                    livingHealth.ApplyDamageToBodyPart(gameObject, hitDamage, AttackType.Melee, DamageType.Brute,
                                                       bodyPartTarget);
                    Chat.AddAttackMsgToChat(gameObject, livingHealth.gameObject, bodyPartTarget, null, attackVerb);
                }
                SoundManager.PlayNetworkedAtPos(attackSound, mobTile.WorldPositionServer, sourceObj: gameObject);
            }
        }
Ejemplo n.º 7
0
        private bool TryStun(RaycastHit2D hit)
        {
            var coll   = hit.collider;
            var player = coll.GetComponent <RegisterPlayer>();

            if (player == null)
            {
                return(false);
            }

            player.ServerStun(stunTime, willDisarm);

            Chat.AddAttackMsgToChat(shooter, coll.gameObject, targetZone, weapon.gameObject);
            Logger.LogTraceFormat($"{shooter} stunned {player.gameObject.name} for {stunTime} seconds with {weapon.name}", Category.Firearms);

            return(true);
        }
Ejemplo n.º 8
0
        private void TryFacehug(Vector3 dir, LivingHealthBehaviour player)
        {
            var playerInventory = player.gameObject.GetComponent <PlayerScript>()?.Equipment;

            if (playerInventory == null)
            {
                return;
            }

            string verb;
            bool   success;

            if (HasAntihuggerItem(playerInventory))
            {
                verb    = "tried to hug";
                success = false;
            }
            else
            {
                verb    = "hugged";
                success = true;
            }

            mobMeleeAction.ServerDoLerpAnimation(dir);

            Chat.AddAttackMsgToChat(
                gameObject,
                player.gameObject,
                BodyPartType.Head,
                null,
                verb);

            SoundManager.PlayNetworkedAtPos(
                "bite",
                player.gameObject.RegisterTile().WorldPositionServer,
                1f,
                true,
                player.gameObject);

            if (success)
            {
                RegisterPlayer registerPlayer = player.gameObject.GetComponent <RegisterPlayer>();
                Facehug(playerInventory, registerPlayer);
            }
        }
Ejemplo n.º 9
0
        private bool TryDamage(RaycastHit2D hit)
        {
            var coll      = hit.collider;
            var integrity = coll.GetComponent <Integrity>();

            if (integrity == null)
            {
                return(false);
            }

            integrity.ApplyDamage(damageData.Damage, damageData.AttackType, damageData.DamageType);

            Chat.AddAttackMsgToChat(shooter, coll.gameObject, BodyPartType.None, weapon.gameObject);
            Logger.LogTraceFormat("Hit {0} for {1} with HealthBehaviour! bullet absorbed", Category.Firearms,
                                  integrity.gameObject.name, damageData.Damage);

            return(true);
        }
Ejemplo n.º 10
0
    /// <summary>
    /// Invoked when BulletColliderBehavior passes the event up to us.
    /// </summary>
    public void HandleTriggerEnter2D(Collider2D coll)
    {
        //only harm others if it's not a suicide
        if (coll.gameObject == shooter && !isSuicide)
        {
            return;
        }

        //only harm the shooter if it's a suicide
        if (coll.gameObject != shooter && isSuicide)
        {
            return;
        }

        //body or object?
        var livingHealth = coll.GetComponent <LivingHealthBehaviour>();
        var integrity    = coll.GetComponent <Integrity>();

        if (integrity != null)
        {
            //damage object
            integrity.ApplyDamage(damage, attackType, damageType);
            Chat.AddAttackMsgToChat(shooter, coll.gameObject, BodyPartType.None, weapon.gameObject);
            Logger.LogTraceFormat("Hit {0} for {1} with HealthBehaviour! bullet absorbed", Category.Firearms, integrity.gameObject.name, damage);
        }
        else
        {
            //damage human if there is one
            if (livingHealth == null || livingHealth.IsDead)
            {
                return;
            }

            // Trigger for things like stuns
            GetComponent <BulletHitTrigger>()?.BulletHitInteract(coll.gameObject);

            var aim = isSuicide ? bodyAim : bodyAim.Randomize();
            livingHealth.ApplyDamageToBodypart(shooter, damage, attackType, damageType, aim);
            Chat.AddAttackMsgToChat(shooter, coll.gameObject, aim, weapon.gameObject);
            Logger.LogTraceFormat("Hit {0} for {1} with HealthBehaviour! bullet absorbed", Category.Firearms, livingHealth.gameObject.name, damage);
        }

        DespawnThis();
    }
Ejemplo n.º 11
0
    public void CmdRequestPunchAttack(GameObject victim, Vector2 punchDirection, BodyPartType damageZone)
    {
        var victimHealth       = victim.GetComponent <LivingHealthBehaviour>();
        var victimRegisterTile = victim.GetComponent <RegisterTile>();
        var rng = new System.Random();

        if (!playerScript.IsInReach(victim, true) || !victimHealth)
        {
            return;
        }

        // If the punch is not self inflicted, do the simple lerp attack animation.
        if (victim != gameObject)
        {
            RpcMeleeAttackLerp(punchDirection, null);
            playerMove.allowInput = false;
        }

        // This is based off the alien/humanoid/attack_hand punch code of TGStation's codebase.
        // Punches have 90% chance to hit, otherwise it is a miss.
        if (90 >= rng.Next(1, 100))
        {
            // The punch hit.
            victimHealth.ApplyDamage(gameObject, (int)fistDamage, AttackType.Melee, DamageType.Brute, damageZone);
            if (fistDamage > 0)
            {
                Chat.AddAttackMsgToChat(gameObject, victim, damageZone);
            }

            // Make a random punch hit sound.
            SoundManager.PlayNetworkedAtPos("Punch#", victimRegisterTile.WorldPosition);

            StartCoroutine(AttackCoolDown());
        }
        else
        {
            // The punch missed.
            string victimName = victim.Player()?.Name;
            SoundManager.PlayNetworkedAtPos("PunchMiss", transform.position);
            Chat.AddCombatMsgToChat(gameObject, $"You attempted to punch {victimName} but missed!",
                                    $"{gameObject.Player()?.Name} has attempted to punch {victimName}!");
        }
    }
Ejemplo n.º 12
0
        private void TryFacehug(Vector3 dir, LivingHealthMasterBase livingHealth)
        {
            var playerInventory = livingHealth.gameObject.GetComponent <PlayerScript>()?.Equipment;

            if (playerInventory == null)
            {
                return;
            }

            string verb;
            bool   success;

            if (HasAntihuggerItem(playerInventory))
            {
                verb    = "tried to hug";
                success = false;
            }
            else
            {
                verb    = "hugged";
                success = true;
            }

            ServerDoLerpAnimation(dir);

            Chat.AddAttackMsgToChat(
                gameObject,
                livingHealth.gameObject,
                BodyPartType.Head,
                null,
                verb);

            AudioSourceParameters audioSourceParameters = new AudioSourceParameters(pitch: 1f);

            SoundManager.PlayNetworkedAtPos(bite, livingHealth.gameObject.RegisterTile().WorldPositionServer,
                                            audioSourceParameters, true, livingHealth.gameObject);

            if (success)
            {
                RegisterPlayer registerPlayer = livingHealth.gameObject.GetComponent <RegisterPlayer>();
                Facehug(playerInventory, registerPlayer);
            }
        }
        private bool TryDamage(RaycastHit2D hit)
        {
            var coll         = hit.collider;
            var livingHealth = coll.GetComponent <LivingHealthBehaviour>();

            if (livingHealth == null)
            {
                return(false);
            }


            livingHealth.ApplyDamageToBodypart(shooter, damageData.Damage, damageData.AttackType, damageData.DamageType, targetZone);

            Chat.AddAttackMsgToChat(shooter, coll.gameObject, targetZone, weapon.gameObject);
            Logger.LogTraceFormat("Hit {0} for {1} with HealthBehaviour! bullet absorbed", Category.Firearms,
                                  livingHealth.gameObject.name, damageData.Damage);

            return(true);
        }
Ejemplo n.º 14
0
    public void ServerPerformMeleeAttack(GameObject victim, Vector2 attackDirection,
                                         BodyPartType damageZone, LayerType layerType)
    {
        if (Cooldowns.IsOnServer(playerScript, CommonCooldowns.Instance.Melee))
        {
            return;
        }
        var weapon = playerScript.playerNetworkActions.GetActiveHandItem();

        var tiles = victim.GetComponent <InteractableTiles>();

        if (tiles)
        {
            //validate based on position of target vector
            if (!Validations.CanApply(playerScript, victim, NetworkSide.Server, targetVector: attackDirection))
            {
                return;
            }
        }
        else
        {
            //validate based on position of target object
            if (!Validations.CanApply(playerScript, victim, NetworkSide.Server))
            {
                return;
            }
        }

        if (!playerMove.allowInput ||
            playerScript.IsGhost ||
            !victim ||
            !playerScript.playerHealth.serverPlayerConscious
            )
        {
            return;
        }

        var isWeapon = weapon != null;
        ItemAttributesV2 weaponAttr = isWeapon ? weapon.GetComponent <ItemAttributesV2>() : null;
        var       damage            = isWeapon ? weaponAttr.ServerHitDamage : fistDamage;
        var       damageType        = isWeapon ? weaponAttr.ServerDamageType : DamageType.Brute;
        var       attackSoundName   = isWeapon ? weaponAttr.ServerHitSound : "Punch#";
        LayerTile attackedTile      = null;
        bool      didHit            = false;

        ItemAttributesV2 weaponStats = null;

        if (isWeapon)
        {
            weaponStats = weapon.GetComponent <ItemAttributesV2>();
        }


        // If Tilemap LayerType is not None then it is a tilemap being attacked
        if (layerType != LayerType.None)
        {
            var tileChangeManager = victim.GetComponent <TileChangeManager>();
            if (tileChangeManager == null)
            {
                return;                                        //Make sure its on a matrix that is destructable
            }
            //Tilemap stuff:
            var tileMapDamage = victim.GetComponentInChildren <MetaTileMap>().Layers[layerType].gameObject
                                .GetComponent <TilemapDamage>();
            if (tileMapDamage != null)
            {
                if (isWeapon && weaponStats != null &&
                    weaponStats.hitSoundSettings == SoundItemSettings.OnlyObject)
                {
                    attackSoundName = "";
                }
                var worldPos = (Vector2)transform.position + attackDirection;
                attackedTile = tileChangeManager.InteractableTiles.LayerTileAt(worldPos, true);
                tileMapDamage.DoMeleeDamage(worldPos,
                                            gameObject, (int)damage);
                didHit = true;
            }
        }
        else
        {
            //a regular object being attacked

            LivingHealthBehaviour victimHealth = victim.GetComponent <LivingHealthBehaviour>();

            var integrity = victim.GetComponent <Integrity>();
            if (integrity != null)
            {
                //damaging an object
                if (isWeapon && weaponStats != null &&
                    weaponStats.hitSoundSettings == SoundItemSettings.Both)
                {
                    SoundManager.PlayNetworkedAtPos(integrity.soundOnHit, gameObject.WorldPosServer(), Random.Range(0.9f, 1.1f));
                }
                else if (isWeapon && weaponStats != null &&
                         weaponStats.hitSoundSettings == SoundItemSettings.OnlyObject && integrity.soundOnHit != "")
                {
                    SoundManager.PlayNetworkedAtPos(integrity.soundOnHit, gameObject.WorldPosServer(), Random.Range(0.9f, 1.1f));
                    attackSoundName = "";
                }
                integrity.ApplyDamage((int)damage, AttackType.Melee, damageType);
                didHit = true;
            }
            else
            {
                //damaging a living thing
                var rng = new System.Random();
                // This is based off the alien/humanoid/attack_hand punch code of TGStation's codebase.
                // Punches have 90% chance to hit, otherwise it is a miss.
                if (isWeapon || 90 >= rng.Next(1, 100))
                {
                    // The attack hit.
                    victimHealth.ApplyDamageToBodypart(gameObject, (int)damage, AttackType.Melee, damageType, damageZone);
                    didHit = true;
                }
                else
                {
                    // The punch missed.
                    string victimName = victim.Player()?.Name;
                    SoundManager.PlayNetworkedAtPos("PunchMiss", transform.position);
                    Chat.AddCombatMsgToChat(gameObject, $"You attempted to punch {victimName} but missed!",
                                            $"{gameObject.Player()?.Name} has attempted to punch {victimName}!");
                }
            }
        }

        //common logic to do if we hit something
        if (didHit)
        {
            if (!string.IsNullOrEmpty(attackSoundName))
            {
                SoundManager.PlayNetworkedAtPos(attackSoundName, transform.position);
            }

            if (damage > 0)
            {
                Chat.AddAttackMsgToChat(gameObject, victim, damageZone, weapon, attackedTile: attackedTile);
            }
            if (victim != gameObject)
            {
                RpcMeleeAttackLerp(attackDirection, weapon);
                //playerMove.allowInput = false;
            }
        }

        Cooldowns.TryStartServer(playerScript, CommonCooldowns.Instance.Melee);
    }
Ejemplo n.º 15
0
    public void CmdRequestMeleeAttack(GameObject victim, Vector2 attackDirection,
                                      BodyPartType damageZone, LayerType layerType)
    {
        var weapon = playerScript.playerNetworkActions.GetActiveHandItem();

        var tiles = victim.GetComponent <InteractableTiles>();

        if (tiles)
        {
            //validate based on position of target vector
            if (!Validations.CanApply(playerScript, victim, NetworkSide.Server, targetVector: attackDirection))
            {
                return;
            }
        }
        else
        {
            //validate based on position of target object
            if (!Validations.CanApply(playerScript, victim, NetworkSide.Server))
            {
                return;
            }
        }

        if (!playerMove.allowInput ||
            playerScript.IsGhost ||
            !victim ||
            !playerScript.playerHealth.serverPlayerConscious
            )
        {
            return;
        }

        if (!allowAttack)
        {
            return;
        }

        var isWeapon = weapon != null;
        ItemAttributesV2 weaponAttr = isWeapon ? weapon.GetComponent <ItemAttributesV2>() : null;
        var       damage            = isWeapon ? weaponAttr.ServerHitDamage : fistDamage;
        var       damageType        = isWeapon ? weaponAttr.ServerDamageType : DamageType.Brute;
        var       attackSoundName   = isWeapon ? weaponAttr.ServerHitSound : "Punch#";
        LayerTile attackedTile      = null;

        bool didHit = false;


        // If Tilemap LayerType is not None then it is a tilemap being attacked
        if (layerType != LayerType.None)
        {
            var tileChangeManager = victim.GetComponent <TileChangeManager>();
            if (tileChangeManager == null)
            {
                return;                                        //Make sure its on a matrix that is destructable
            }
            //Tilemap stuff:
            var tileMapDamage = victim.GetComponentInChildren <MetaTileMap>().Layers[layerType].gameObject
                                .GetComponent <TilemapDamage>();
            if (tileMapDamage != null)
            {
                var worldPos = (Vector2)transform.position + attackDirection;
                attackedTile = tileChangeManager.InteractableTiles.LayerTileAt(worldPos);
                tileMapDamage.DoMeleeDamage(worldPos,
                                            gameObject, (int)damage);
                didHit = true;
            }
        }
        else
        {
            //a regular object being attacked

            //butchering
            //TODO: Move butchering logic to IF2, it should be a progress action done on corpses (make a Corpse component probably)
            LivingHealthBehaviour victimHealth = victim.GetComponent <LivingHealthBehaviour>();
            if (victimHealth != null && victimHealth.IsDead && isWeapon && weaponAttr.HasTrait(KnifeTrait))
            {
                if (victim.GetComponent <SimpleAnimal>())
                {
                    SimpleAnimal attackTarget = victim.GetComponent <SimpleAnimal>();
                    RpcMeleeAttackLerp(attackDirection, weapon);
                    playerMove.allowInput = false;
                    attackTarget.Harvest();
                    SoundManager.PlayNetworkedAtPos("BladeSlice", transform.position);
                }
                else
                {
                    PlayerHealth attackTarget = victim.GetComponent <PlayerHealth>();
                    RpcMeleeAttackLerp(attackDirection, weapon);
                    playerMove.allowInput = false;
                    attackTarget.Harvest();
                    SoundManager.PlayNetworkedAtPos("BladeSlice", transform.position);
                }
            }

            var integrity = victim.GetComponent <Integrity>();
            if (integrity != null)
            {
                //damaging an object
                integrity.ApplyDamage((int)damage, AttackType.Melee, damageType);
                didHit = true;
            }
            else
            {
                //damaging a living thing
                var rng = new System.Random();
                // This is based off the alien/humanoid/attack_hand punch code of TGStation's codebase.
                // Punches have 90% chance to hit, otherwise it is a miss.
                if (isWeapon || 90 >= rng.Next(1, 100))
                {
                    // The attack hit.
                    victimHealth.ApplyDamageToBodypart(gameObject, (int)damage, AttackType.Melee, damageType, damageZone);
                    didHit = true;
                }
                else
                {
                    // The punch missed.
                    string victimName = victim.Player()?.Name;
                    SoundManager.PlayNetworkedAtPos("PunchMiss", transform.position);
                    Chat.AddCombatMsgToChat(gameObject, $"You attempted to punch {victimName} but missed!",
                                            $"{gameObject.Player()?.Name} has attempted to punch {victimName}!");
                }
            }
        }

        //common logic to do if we hit something
        if (didHit)
        {
            SoundManager.PlayNetworkedAtPos(attackSoundName, transform.position);
            if (damage > 0)
            {
                Chat.AddAttackMsgToChat(gameObject, victim, damageZone, weapon, attackedTile: attackedTile);
            }
            if (victim != gameObject)
            {
                RpcMeleeAttackLerp(attackDirection, weapon);
                playerMove.allowInput = false;
            }
        }

        //no matter what, start a cooldown for attacking again so they can't spam attack requests
        StartCoroutine(AttackCoolDown());
    }
Ejemplo n.º 16
0
    public void CmdRequestMeleeAttack(GameObject victim, GameObject weapon, Vector2 stabDirection,
                                      BodyPartType damageZone, LayerType layerType)
    {
        if (!playerMove.allowInput ||
            playerScript.IsGhost ||
            !victim ||
            !playerScript.playerHealth.serverPlayerConscious
            )
        {
            return;
        }

        if (!allowAttack)
        {
            return;
        }

        ItemAttributes weaponAttr = weapon.GetComponent <ItemAttributes>();

        // If Tilemap LayerType is not None then it is a tilemap being attacked
        if (layerType != LayerType.None)
        {
            var tileChangeManager = victim.GetComponent <TileChangeManager>();
            if (tileChangeManager == null)
            {
                return;                                        //Make sure its on a matrix that is destructable
            }
            //Tilemap stuff:
            var tileMapDamage = victim.GetComponentInChildren <MetaTileMap>().Layers[layerType].gameObject
                                .GetComponent <TilemapDamage>();
            if (tileMapDamage != null)
            {
                //Wire cutters should snip the grills instead:
                if (weaponAttr.itemName == "wirecutters" &&
                    tileMapDamage.Layer.LayerType == LayerType.Grills)
                {
                    tileMapDamage.WireCutGrill((Vector2)transform.position + stabDirection);
                    StartCoroutine(AttackCoolDown());
                    return;
                }

                tileMapDamage.DoMeleeDamage((Vector2)transform.position + stabDirection,
                                            gameObject, (int)weaponAttr.hitDamage);

                playerMove.allowInput = false;
                RpcMeleeAttackLerp(stabDirection, weapon);
                StartCoroutine(AttackCoolDown());
                return;
            }
            return;
        }

        //This check cannot be used with TilemapDamage as the transform position is always far away
        if (!playerScript.IsInReach(victim, true))
        {
            return;
        }

        // Consider moving this into a MeleeItemTrigger for knifes
        //Meaty bodies:
        LivingHealthBehaviour victimHealth = victim.GetComponent <LivingHealthBehaviour>();

        if (victimHealth != null && victimHealth.IsDead && weaponAttr.itemType == ItemType.Knife)
        {
            if (victim.GetComponent <SimpleAnimal>())
            {
                SimpleAnimal attackTarget = victim.GetComponent <SimpleAnimal>();
                RpcMeleeAttackLerp(stabDirection, weapon);
                playerMove.allowInput = false;
                attackTarget.Harvest();
                SoundManager.PlayNetworkedAtPos("BladeSlice", transform.position);
            }
            else
            {
                PlayerHealth attackTarget = victim.GetComponent <PlayerHealth>();
                RpcMeleeAttackLerp(stabDirection, weapon);
                playerMove.allowInput = false;
                attackTarget.Harvest();
                SoundManager.PlayNetworkedAtPos("BladeSlice", transform.position);
            }
        }

        if (victim != gameObject)
        {
            RpcMeleeAttackLerp(stabDirection, weapon);
            playerMove.allowInput = false;
        }

        var integrity = victim.GetComponent <Integrity>();

        if (integrity != null)
        {
            //damaging an object
            integrity.ApplyDamage((int)weaponAttr.hitDamage, AttackType.Melee, weaponAttr.damageType);
        }
        else
        {
            //damaging a living thing
            victimHealth.ApplyDamage(gameObject, (int)weaponAttr.hitDamage, AttackType.Melee, weaponAttr.damageType, damageZone);
        }

        SoundManager.PlayNetworkedAtPos(weaponAttr.hitSound, transform.position);


        if (weaponAttr.hitDamage > 0)
        {
            Chat.AddAttackMsgToChat(gameObject, victim, damageZone, weapon);
        }


        StartCoroutine(AttackCoolDown());
    }