public override void OnGameTick(float deltaTime) { if (entity.Pos.Y < -30) { entity.ReceiveDamage(new DamageSource() { Source = EnumDamageSource.Void, Type = EnumDamageType.Gravity }, 4); } secondsSinceLastUpdate += deltaTime; if (secondsSinceLastUpdate >= 1) { secondsSinceLastUpdate = 0; if (entity.Alive && Health < MaxHealth) { float recoverySpeed = 0.01f; EntityBehaviorHunger ebh = entity.GetBehavior <EntityBehaviorHunger>(); if (ebh != null) { EntityPlayer plr = (EntityPlayer)entity; if (plr != null && entity.World.PlayerByUid(plr.PlayerUID).WorldData.CurrentGameMode == EnumGameMode.Creative) { return; } // When below 75% satiety, autoheal starts dropping recoverySpeed = GameMath.Clamp(0.01f * ebh.Saturation / ebh.MaxSaturation * 1 / 0.75f, 0, 0.01f); ebh.ConsumeSaturation(150f * recoverySpeed); } Health = Math.Min(Health + recoverySpeed, MaxHealth); } int rainy = entity.World.BlockAccessor.GetRainMapHeightAt((int)entity.ServerPos.X, (int)entity.ServerPos.Z); if (entity.World.Side == EnumAppSide.Server && entity is EntityPlayer && rainy <= entity.ServerPos.Y) { WeatherSystemBase wsys = entity.Api.ModLoader.GetModSystem <WeatherSystemBase>(); var state = wsys.GetPrecipitationState(entity.ServerPos.XYZ); if (state != null && state.ParticleSize > 0.6 && state.Type == EnumPrecipitationType.Hail && entity.World.Rand.NextDouble() < state.Level / 2) { entity.ReceiveDamage(new DamageSource() { Source = EnumDamageSource.Weather, Type = EnumDamageType.BluntAttack }, (float)state.ParticleSize / 15f); } } } }
/// <summary> /// Consumes a meal /// </summary> /// <param name="world"></param> /// <param name="eatingPlayer"></param> /// <param name="contentStacks"></param> /// <param name="recipeCode"></param> /// <param name="remainingServings"></param> /// <returns>Amount of servings left</returns> public virtual float Consume(IWorldAccessor world, IPlayer eatingPlayer, ItemSlot inSlot, ItemStack[] contentStacks, float remainingServings, bool mulwithStackSize) { float[] nmul = GetNutritionHealthMul(null, inSlot, eatingPlayer.Entity); FoodNutritionProperties[] multiProps = GetContentNutritionProperties(world, inSlot, contentStacks, eatingPlayer.Entity, mulwithStackSize, nmul[0], nmul[1]); if (multiProps == null) { return(remainingServings); } float totalHealth = 0; EntityBehaviorHunger ebh = eatingPlayer.Entity.GetBehavior <EntityBehaviorHunger>(); float satiablePoints = ebh.MaxSaturation - ebh.Saturation; float mealSatpoints = 0; for (int i = 0; i < multiProps.Length; i++) { FoodNutritionProperties nutriProps = multiProps[i]; if (nutriProps == null) { continue; } mealSatpoints += nutriProps.Satiety; } float servingsNeeded = GameMath.Clamp(satiablePoints / Math.Max(1, mealSatpoints), 0, 1); float servingsToEat = Math.Min(remainingServings, servingsNeeded); // Affect the players body temperature by eating meals with a larger temperature difference float temp = inSlot.Itemstack.Collectible.GetTemperature(world, inSlot.Itemstack); var bh = eatingPlayer.Entity.GetBehavior <EntityBehaviorBodyTemperature>(); if (bh != null && Math.Abs(temp - bh.CurBodyTemperature) > 10) { float intensity = Math.Min(1, (temp - bh.CurBodyTemperature) / 30f); bh.CurBodyTemperature += GameMath.Clamp(mealSatpoints * servingsToEat / 80f * intensity, 0, 5); } for (int i = 0; i < multiProps.Length; i++) { FoodNutritionProperties nutriProps = multiProps[i]; if (nutriProps == null) { continue; } float mul = servingsToEat; float sat = mul * nutriProps.Satiety; eatingPlayer.Entity.ReceiveSaturation(sat, nutriProps.FoodCategory, 10 + sat / 70f * 60f, 1f); if (nutriProps.EatenStack?.ResolvedItemstack != null) { if (eatingPlayer == null || !eatingPlayer.InventoryManager.TryGiveItemstack(nutriProps.EatenStack.ResolvedItemstack.Clone(), true)) { world.SpawnItemEntity(nutriProps.EatenStack.ResolvedItemstack.Clone(), eatingPlayer.Entity.SidedPos.XYZ); } } totalHealth += mul * nutriProps.Health; } if (totalHealth != 0) { eatingPlayer.Entity.ReceiveDamage(new DamageSource() { Source = EnumDamageSource.Internal, Type = totalHealth > 0 ? EnumDamageType.Heal : EnumDamageType.Poison }, Math.Abs(totalHealth)); } return(Math.Max(0, remainingServings - servingsToEat)); }
/// <summary> /// Consumes a meal /// </summary> /// <param name="world"></param> /// <param name="eatingPlayer"></param> /// <param name="contentStacks"></param> /// <param name="recipeCode"></param> /// <param name="remainingServings"></param> /// <returns>Amount of servings left</returns> public static float Consume(IWorldAccessor world, IPlayer eatingPlayer, ItemSlot inSlot, ItemStack[] contentStacks, float remainingServings, bool mulwithStackSize) { FoodNutritionProperties[] multiProps = GetContentNutritionProperties(world, inSlot, contentStacks, eatingPlayer.Entity); if (multiProps == null) { return(remainingServings); } float totalHealth = 0; EntityBehaviorHunger ebh = eatingPlayer.Entity.GetBehavior <EntityBehaviorHunger>(); float satiablePoints = ebh.MaxSaturation - ebh.Saturation; float mealSatpoints = 0; for (int i = 0; i < multiProps.Length; i++) { FoodNutritionProperties nutriProps = multiProps[i]; if (nutriProps == null) { continue; } mealSatpoints += nutriProps.Satiety * (mulwithStackSize ? contentStacks[i].StackSize : 1); } float servingsNeeded = GameMath.Clamp(satiablePoints / Math.Max(1, mealSatpoints), 0, 1); float servingsToEat = Math.Min(remainingServings, servingsNeeded); for (int i = 0; i < multiProps.Length; i++) { FoodNutritionProperties nutriProps = multiProps[i]; if (nutriProps == null) { continue; } float mul = servingsToEat * (mulwithStackSize ? contentStacks[i].StackSize : 1); float sat = mul * nutriProps.Satiety; eatingPlayer.Entity.ReceiveSaturation(sat, nutriProps.FoodCategory, 10 + sat / 70f * 60f, 1f); if (nutriProps.EatenStack?.ResolvedItemstack != null) { if (eatingPlayer == null || !eatingPlayer.InventoryManager.TryGiveItemstack(nutriProps.EatenStack.ResolvedItemstack.Clone(), true)) { world.SpawnItemEntity(nutriProps.EatenStack.ResolvedItemstack.Clone(), eatingPlayer.Entity.SidedPos.XYZ); } } totalHealth += mul * nutriProps.Health; } if (totalHealth != 0) { eatingPlayer.Entity.ReceiveDamage(new DamageSource() { Source = EnumDamageSource.Internal, Type = totalHealth > 0 ? EnumDamageType.Heal : EnumDamageType.Poison }, Math.Abs(totalHealth)); } return(Math.Max(0, remainingServings - servingsToEat)); }
public override void OnGameTick(float deltaTime) { entity.World.FrameProfiler.Mark("not-bhhealth"); if (entity.Pos.Y < -30) { entity.ReceiveDamage(new DamageSource() { Source = EnumDamageSource.Void, Type = EnumDamageType.Gravity }, 4); } secondsSinceLastUpdate += deltaTime; if (secondsSinceLastUpdate >= 1) { secondsSinceLastUpdate = 0; if (entity.Alive) { float health = Health; // higher performance to read this TreeAttribute only once float maxHealth = MaxHealth; if (health < maxHealth) { float recoverySpeed = 0.01f; // Only players have the hunger behavior, and the different nutrient saturations if (entity is EntityPlayer plr) { EntityBehaviorHunger ebh = entity.GetBehavior <EntityBehaviorHunger>(); if (ebh != null) { if (entity.World.PlayerByUid(plr.PlayerUID).WorldData.CurrentGameMode == EnumGameMode.Creative) { return; } // When below 75% satiety, autoheal starts dropping recoverySpeed = GameMath.Clamp(0.01f * ebh.Saturation / ebh.MaxSaturation * 1 / 0.75f, 0, 0.01f); ebh.ConsumeSaturation(150f * recoverySpeed); } } Health = Math.Min(health + recoverySpeed, maxHealth); } } if (entity is EntityPlayer && entity.World.Side == EnumAppSide.Server) { // A costly check every 1s for hail damage, but it applies only to players who are in the open int rainy = entity.World.BlockAccessor.GetRainMapHeightAt((int)entity.ServerPos.X, (int)entity.ServerPos.Z); if (entity.ServerPos.Y >= rainy) { WeatherSystemBase wsys = entity.Api.ModLoader.GetModSystem <WeatherSystemBase>(); var state = wsys.GetPrecipitationState(entity.ServerPos.XYZ); if (state != null && state.ParticleSize >= 0.5 && state.Type == EnumPrecipitationType.Hail && entity.World.Rand.NextDouble() < state.Level / 2) { entity.ReceiveDamage(new DamageSource() { Source = EnumDamageSource.Weather, Type = EnumDamageType.BluntAttack }, (float)state.ParticleSize / 15f); } } } } }