Ejemplo n.º 1
0
        private float handleDamaged(IPlayer player, float damage, DamageSource dmgSource)
        {
            EnumDamageType type = dmgSource.Type;
            double         angleProtectionRange = 120 / 2 * GameMath.DEG2RAD;

            // Reduce damage if player holds a shield
            ItemSlot[] shieldSlots = new ItemSlot[] { player.Entity.LeftHandItemSlot, player.Entity.RightHandItemSlot };
            foreach (var shieldSlot in shieldSlots)
            {
                var attr = shieldSlot.Itemstack?.ItemAttributes?["shield"];
                if (attr == null || !attr.Exists)
                {
                    continue;
                }

                string usetype = player.Entity.Controls.Sneak ? "active" : "passive";

                float dmgabsorb = attr["damageAbsorption"][usetype].AsFloat(0);
                float chance    = attr["protectionChance"][usetype].AsFloat(0);
                (player as IServerPlayer)?.SendMessage(GlobalConstants.DamageLogChatGroup, Lang.Get("{0:0.#} of {1:0.#} damage blocked by shield", Math.Min(dmgabsorb, damage), damage), EnumChatType.Notification);

                double dx;
                double dz;
                if (dmgSource.HitPosition != null)
                {
                    dx = dmgSource.HitPosition.X;
                    dz = dmgSource.HitPosition.Z;
                }
                else if (dmgSource.SourceEntity != null)
                {
                    dx = dmgSource.SourceEntity.Pos.X - player.Entity.Pos.X;
                    dz = dmgSource.SourceEntity.Pos.Z - player.Entity.Pos.Z;
                }
                else if (dmgSource.SourcePos != null)
                {
                    dx = dmgSource.SourcePos.X - player.Entity.Pos.X;
                    dz = dmgSource.SourcePos.Z - player.Entity.Pos.Z;
                }
                else
                {
                    break;
                }

                double attackYaw = Math.Atan2((double)dx, (double)dz);
                double playerYaw = player.Entity.Pos.Yaw + GameMath.PIHALF;

                bool inProtectionRange = Math.Abs(GameMath.AngleRadDistance((float)playerYaw, (float)attackYaw)) < angleProtectionRange;

                if (inProtectionRange && api.World.Rand.NextDouble() < chance)
                {
                    damage = Math.Max(0, damage - dmgabsorb);

                    var loc = shieldSlot.Itemstack.ItemAttributes["blockSound"].AsString("held/shieldblock");
                    api.World.PlaySoundAt(AssetLocation.Create(loc, shieldSlot.Itemstack.Collectible.Code.Domain).WithPathPrefixOnce("sounds/").WithPathAppendixOnce(".ogg"), player, null);

                    if (api.Side == EnumAppSide.Server)
                    {
                        shieldSlot.Itemstack.Collectible.DamageItem(api.World, dmgSource.SourceEntity, shieldSlot, 1);
                        shieldSlot.MarkDirty();
                    }
                }
            }

            if (damage <= 0)
            {
                return(0);
            }
            // The code below only the server needs to execute
            if (api.Side == EnumAppSide.Client)
            {
                return(damage);
            }

            // Does not protect against non-attack damages

            if (type != EnumDamageType.BluntAttack && type != EnumDamageType.PiercingAttack && type != EnumDamageType.SlashingAttack)
            {
                return(damage);
            }
            if (dmgSource.Source == EnumDamageSource.Internal || dmgSource.Source == EnumDamageSource.Suicide)
            {
                return(damage);
            }

            ItemSlot   armorSlot;
            IInventory inv = player.InventoryManager.GetOwnInventory(GlobalConstants.characterInvClassName);
            double     rnd = api.World.Rand.NextDouble();


            int attackTarget;

            if ((rnd -= 0.2) < 0)
            {
                // Head
                armorSlot    = inv[12];
                attackTarget = 0;
            }
            else if ((rnd -= 0.5) < 0)
            {
                // Body
                armorSlot    = inv[13];
                attackTarget = 1;
            }
            else
            {
                // Legs
                armorSlot    = inv[14];
                attackTarget = 2;
            }

            // Apply full damage if no armor is in this slot
            if (armorSlot.Empty || !(armorSlot.Itemstack.Item is ItemWearable))
            {
                EnumCharacterDressType[] dressTargets = clothingDamageTargetsByAttackTacket[attackTarget];
                EnumCharacterDressType   target       = dressTargets[api.World.Rand.Next(dressTargets.Length)];

                ItemSlot targetslot = player.Entity.GearInventory[(int)target];
                if (!targetslot.Empty)
                {
                    // Wolf: 10 hp damage = 10% condition loss
                    // Ram: 10 hp damage = 2.5% condition loss
                    // Bronze locust: 10 hp damage = 5% condition loss
                    float mul = 0.25f;
                    if (type == EnumDamageType.SlashingAttack)
                    {
                        mul = 1f;
                    }
                    if (type == EnumDamageType.PiercingAttack)
                    {
                        mul = 0.5f;
                    }

                    float diff = -damage / 100 * mul;

                    if (Math.Abs(diff) > 0.05)
                    {
                        api.World.PlaySoundAt(ripSound, player.Entity);
                    }

                    (targetslot.Itemstack.Collectible as ItemWearable)?.ChangeCondition(targetslot, diff);
                }

                return(damage);
            }

            ProtectionModifiers protMods = (armorSlot.Itemstack.Item as ItemWearable).ProtectionModifiers;

            int   weaponTier  = dmgSource.DamageTier;
            float flatDmgProt = protMods.FlatDamageReduction;
            float percentProt = protMods.RelativeProtection;

            for (int tier = 1; tier <= weaponTier; tier++)
            {
                bool aboveTier = tier > protMods.ProtectionTier;

                float flatLoss = aboveTier ? protMods.PerTierFlatDamageReductionLoss[1] : protMods.PerTierFlatDamageReductionLoss[0];
                float percLoss = aboveTier ? protMods.PerTierRelativeProtectionLoss[1] : protMods.PerTierRelativeProtectionLoss[0];

                if (aboveTier && protMods.HighDamageTierResistant)
                {
                    flatLoss /= 2;
                    percLoss /= 2;
                }

                flatDmgProt -= flatLoss;
                percentProt *= 1 - percLoss;
            }

            // Durability loss is the one before the damage reductions
            float durabilityLoss    = 0.5f + damage * Math.Max(0.5f, (weaponTier - protMods.ProtectionTier) * 3);
            int   durabilityLossInt = GameMath.RoundRandom(api.World.Rand, durabilityLoss);

            // Now reduce the damage
            damage  = Math.Max(0, damage - flatDmgProt);
            damage *= 1 - Math.Max(0, percentProt);

            armorSlot.Itemstack.Collectible.DamageItem(api.World, player.Entity, armorSlot, durabilityLossInt);

            if (armorSlot.Empty)
            {
                api.World.PlaySoundAt(new AssetLocation("sounds/effect/toolbreak"), player);
            }

            return(damage);
        }
Ejemplo n.º 2
0
        public override void OnLoaded(ICoreAPI api)
        {
            base.OnLoaded(api);

            string strdress           = Attributes["clothescategory"].AsString();
            EnumCharacterDressType dt = EnumCharacterDressType.Unknown;

            Enum.TryParse(strdress, true, out dt);
            DressType = dt;


            JsonObject jsonObj = Attributes?["footStepSound"];

            if (jsonObj?.Exists == true)
            {
                string soundloc = jsonObj.AsString(null);
                if (soundloc != null)
                {
                    AssetLocation loc = AssetLocation.Create(soundloc, Code.Domain).WithPathPrefixOnce("sounds/");

                    if (soundloc.EndsWith("*"))
                    {
                        loc.Path       = loc.Path.TrimEnd('*');
                        FootStepSounds = api.Assets.GetLocations(loc.Path, loc.Domain).ToArray();
                    }
                    else
                    {
                        FootStepSounds = new AssetLocation[] { loc };
                    }
                }
            }

            jsonObj = Attributes?["statModifiers"];
            if (jsonObj?.Exists == true)
            {
                try
                {
                    StatModifers = jsonObj.AsObject <StatModifiers>();
                }
                catch (Exception e)
                {
                    api.World.Logger.Error("Failed loading statModifiers for item/block {0}. Will ignore. Exception: {1}", Code, e);
                    StatModifers = null;
                }
            }

            ProtectionModifiers defMods = null;

            jsonObj = Attributes?["defaultProtLoss"];
            if (jsonObj?.Exists == true)
            {
                try
                {
                    defMods = jsonObj.AsObject <ProtectionModifiers>();
                }
                catch (Exception e)
                {
                    api.World.Logger.Error("Failed loading defaultProtLoss for item/block {0}. Will ignore. Exception: {1}", Code, e);
                }
            }

            jsonObj = Attributes?["protectionModifiers"];
            if (jsonObj?.Exists == true)
            {
                try
                {
                    ProtectionModifiers = jsonObj.AsObject <ProtectionModifiers>();
                }
                catch (Exception e)
                {
                    api.World.Logger.Error("Failed loading protectionModifiers for item/block {0}. Will ignore. Exception: {1}", Code, e);
                    ProtectionModifiers = null;
                }
            }


            if (ProtectionModifiers != null && ProtectionModifiers.PerTierFlatDamageReductionLoss == null)
            {
                ProtectionModifiers.PerTierFlatDamageReductionLoss = defMods?.PerTierFlatDamageReductionLoss;
            }
            if (ProtectionModifiers != null && ProtectionModifiers.PerTierRelativeProtectionLoss == null)
            {
                ProtectionModifiers.PerTierRelativeProtectionLoss = defMods?.PerTierRelativeProtectionLoss;
            }
        }
Ejemplo n.º 3
0
        private float handleDamaged(IPlayer player, float damage, DamageSource dmgSource)
        {
            // Does not protect against non-attack damages
            EnumDamageType type = dmgSource.Type;

            if (type != EnumDamageType.BluntAttack && type != EnumDamageType.PiercingAttack && type != EnumDamageType.SlashingAttack)
            {
                return(damage);
            }
            if (dmgSource.Source == EnumDamageSource.Internal || dmgSource.Source == EnumDamageSource.Suicide)
            {
                return(damage);
            }

            ItemSlot   armorSlot;
            IInventory inv = player.InventoryManager.GetOwnInventory(GlobalConstants.characterInvClassName);
            double     rnd = api.World.Rand.NextDouble();


            int attackTarget;

            if ((rnd -= 0.2) < 0)
            {
                // Head
                armorSlot    = inv[12];
                attackTarget = 0;
            }
            else if ((rnd -= 0.5) < 0)
            {
                // Body
                armorSlot    = inv[13];
                attackTarget = 1;
            }
            else
            {
                // Legs
                armorSlot    = inv[14];
                attackTarget = 2;
            }

            // Apply full damage if no armor is in this slot
            if (armorSlot.Empty || !(armorSlot.Itemstack.Item is ItemWearable))
            {
                EnumCharacterDressType[] dressTargets = clothingDamageTargetsByAttackTacket[attackTarget];
                EnumCharacterDressType   target       = dressTargets[api.World.Rand.Next(dressTargets.Length)];

                ItemSlot targetslot = player.Entity.GearInventory[(int)target];
                if (!targetslot.Empty)
                {
                    // Wolf: 10 hp damage = 10% condition loss
                    // Ram: 10 hp damage = 2.5% condition loss
                    // Bronze locust: 10 hp damage = 5% condition loss
                    float mul = 0.25f;
                    if (type == EnumDamageType.SlashingAttack)
                    {
                        mul = 1f;
                    }
                    if (type == EnumDamageType.PiercingAttack)
                    {
                        mul = 0.5f;
                    }

                    float diff = -damage / 100 * mul;

                    if (Math.Abs(diff) > 0.05)
                    {
                        api.World.PlaySoundAt(ripSound, player.Entity);
                    }

                    (targetslot.Itemstack.Collectible as ItemWearable)?.ChangeCondition(targetslot, diff);
                }

                return(damage);
            }

            ProtectionModifiers protMods = (armorSlot.Itemstack.Item as ItemWearable).ProtectionModifiers;

            int   weaponTier  = dmgSource.DamageTier;
            float flatDmgProt = protMods.FlatDamageReduction;
            float percentProt = protMods.RelativeProtection;

            for (int tier = 1; tier <= weaponTier; tier++)
            {
                bool aboveTier = tier > protMods.ProtectionTier;

                float flatLoss = aboveTier ? protMods.PerTierFlatDamageReductionLoss[1] : protMods.PerTierFlatDamageReductionLoss[0];
                float percLoss = aboveTier ? protMods.PerTierRelativeProtectionLoss[1] : protMods.PerTierRelativeProtectionLoss[0];

                if (aboveTier && protMods.HighDamageTierResistant)
                {
                    flatLoss /= 2;
                    percLoss /= 2;
                }

                flatDmgProt -= flatLoss;
                percentProt *= 1 - percLoss;
            }

            // Durability loss is the one before the damage reductions
            float durabilityLoss    = 0.5f + damage * Math.Max(0.5f, (weaponTier - protMods.ProtectionTier) * 3);
            int   durabilityLossInt = GameMath.RoundRandom(api.World.Rand, durabilityLoss);

            // Now reduce the damage
            damage  = Math.Max(0, damage - flatDmgProt);
            damage *= 1 - Math.Max(0, percentProt);

            armorSlot.Itemstack.Collectible.DamageItem(api.World, player.Entity, armorSlot, durabilityLossInt);

            if (armorSlot.Empty)
            {
                api.World.PlaySoundAt(new AssetLocation("sounds/effect/toolbreak"), player);
            }

            return(damage);
        }