public void Init(BaseCharacterMono caster, Damage damage, Vector3 targetPos, BaseCharacterMono target = null)
        {
            Caster        = caster.Character;
            CasterMono    = caster;
            _damage       = damage;
            Target        = target;
            HaveTransform = Target != null;

            transform.LookAt(new Vector3(targetPos.x, targetPos.y, targetPos.z));

            //resize for attack range and radius
            var boxCollider    = GetComponent <BoxCollider>();
            var casterNavAgent = caster.GetComponent <NavMeshAgent>();
            var attackRange    = caster.Character.AttackRange;

            boxCollider.size    = new Vector3(casterNavAgent.radius + 0.25f, casterNavAgent.height, attackRange);
            transform.position += transform.forward * (attackRange / 2);
            transform.position += new Vector3(0, casterNavAgent.height / 2, 0);

            if (caster.Character.CharacterType == CharacterType.Player)
            {
                var player   = (PlayerCharacter)caster.Character;
                var classDef = Rm_RPGHandler.Instance.Player.CharacterDefinitions.First(c => c.ID == player.PlayerCharacterID);
                ImpactPrefabPath = classDef.AutoAttackImpactPrefabPath;
                ImpactSound      = classDef.AutoAttackImpactSound;

                var weapon = player.Equipment.EquippedWeapon as Weapon;
                weapon = weapon ?? player.Equipment.EquippedOffHand as Weapon;
                if (weapon != null)
                {
                    var wepDef = Rm_RPGHandler.Instance.Items.WeaponTypes.First(w => w.ID == weapon.WeaponTypeID);
                    ImpactPrefabPath = wepDef.AutoAttackImpactPrefabPath;
                    ImpactSound      = wepDef.AutoAttackImpactSound;
                }
            }
            else
            {
                var cc = (CombatCharacter)caster.Character;
                ImpactPrefabPath = cc.AutoAttackImpactPrefabPath;
                ImpactSound      = cc.AutoAttackImpactSound;
            }

            Destroy(gameObject, 0.25f);
            _initialised = true;
        }
        //todo: rethink these, we should add skill or talent, so we can first check if we are immune/susceptible to it
        //in which case we can pre-multiply the damage or just not apply the skill and return "Immune"

        public bool IsFriendly(BaseCharacter target)
        {
            if (target == null)
            {
                return(true);
            }

            //pet can't be attacked if it's idle only
            var targetIsPet = target.CharacterMono.GetComponent <PetMono>();

            if (targetIsPet != null && targetIsPet.PetData.CurrentBehaviour == PetBehaviour.PetOnly)
            {
                return(true);
            }

            //pet can't attack player
            if (CharacterMono == null)
            {
                return(true);
            }

            var iAmPet = CharacterMono.GetComponent <PetMono>();

            if (iAmPet != null && target is PlayerCharacter)
            {
                return(true);
            }

            if (iAmPet)
            {
                return(GetObject.PlayerCharacter.IsFriendly(target));
            }

            if (targetIsPet)
            {
                return(IsFriendly(GetObject.PlayerCharacter));
            }

            var allReps     = Rm_RPGHandler.Instance.Repositories.Quests.AllReputations;
            var players     = new PlayerCharacter[2];
            var combatChars = new CombatCharacter[2];

            switch (CharacterType)
            {
            case CharacterType.Player:
                players[0] = (PlayerCharacter)this;
                break;

            case CharacterType.NPC:
            case CharacterType.Enemy:
                combatChars[0] = (CombatCharacter)this;
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            switch (target.CharacterType)
            {
            case CharacterType.Player:
                players[players[0] == null ? 0 : 1] = (PlayerCharacter)target;
                break;

            case CharacterType.NPC:
            case CharacterType.Enemy:
                combatChars[combatChars[0] == null ? 0 : 1] = (CombatCharacter)target;
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            if (players.Count(p => p != null) == 2)
            {
                return(true);
            }
            else if (players.Count(p => p != null) == 1 && combatChars.Count(p => p != null) == 1)
            {
                var targetChar   = combatChars[0];
                var rep          = allReps.FirstOrDefault(r => r.ID == targetChar.ReputationId);
                var playerRepVal = GetObject.PlayerSave.QuestLog.AllReputations.FirstOrDefault(r => r.ReputationID == targetChar.ReputationId);
                if (rep != null && playerRepVal != null)
                {
                    return(!rep.AttackIfBelowReputation || playerRepVal.Value >= rep.BelowReputationValue);
                }
                else
                {
                    Debug.LogError("Could not find reputation for  " + targetChar.Name + "[ RepId: " + targetChar.ReputationId + "]");
                }
            }
            else
            {
                var myrep    = allReps.FirstOrDefault(r => r.ID == combatChars[0].ReputationId);
                var enemyrep = allReps.FirstOrDefault(r => r.ID == combatChars[1].ReputationId);


                if (myrep == enemyrep)
                {
                    return(true);
                }

                //EE
                if (myrep.EnemyFactions.First(e => e.ID == enemyrep.ID).IsTrue&&
                    enemyrep.EnemyFactions.First(e => e.ID == myrep.ID).IsTrue)
                {
                    return(false);
                }
                else if (myrep.EnemyFactions.First(e => e.ID == enemyrep.ID).IsTrue || enemyrep.EnemyFactions.First(e => e.ID == myrep.ID).IsTrue)
                {
                    return(false);
                }
                else
                {
                    return(true);
                }
            }

            return(true);
        }