/// <summary> /// Deserializes the alloy /// </summary> /// <param name="reader"></param> /// <param name="resolver"></param> public void FromBytes(BinaryReader reader, IWorldAccessor resolver) { Code = reader.ReadString(); Ingredients = new CookingRecipeIngredient[reader.ReadInt32()]; for (int i = 0; i < Ingredients.Length; i++) { Ingredients[i] = new CookingRecipeIngredient(); Ingredients[i].FromBytes(reader, resolver.ClassRegistry); Ingredients[i].Resolve(resolver, "[FromBytes]"); } //NameComponentOrder = reader.ReadIntArray(); if (!reader.ReadBoolean()) { Shape = new CompositeShape() { Base = new AssetLocation(reader.ReadString()) }; } PerishableProps = new TransitionableProperties(); PerishableProps.FromBytes(reader, resolver.ClassRegistry); // CanBeServedInto = new JsonItemStack(); // CanBeServedInto.FromBytes(reader, resolver.ClassRegistry); // CanBeServedInto.Resolve(resolver, "[FromBytes]"); }
private void OnEvery3Second(float dt) { if (!inventory[0].Empty && CurrentRecipe == null) { FindMatchingRecipe(); } if (CurrentRecipe != null && Sealed && CurrentRecipe.SealHours > 0) { if (api.World.Calendar.TotalHours - SealedSinceTotalHours > CurrentRecipe.SealHours) { ItemStack mixedStack = CurrentRecipe.Output.ResolvedItemstack.Clone(); mixedStack.StackSize = CurrentOutSize; // Carry over freshness TransitionableProperties perishProps = mixedStack.Collectible.GetTransitionableProperties(api.World, mixedStack, null)?[0]; if (perishProps != null) { ItemSlot[] slots = new ItemSlot[inventory.Count]; for (int i = 0; i < inventory.Count; i++) { slots[i] = inventory[i]; } BlockCookingContainer.CarryOverFreshness(api, slots, new ItemStack[] { mixedStack }, perishProps); } if (BlockLiquidContainerBase.GetStackProps(mixedStack) != null) { inventory[0].Itemstack = null; inventory[1].Itemstack = mixedStack; } else { inventory[1].Itemstack = null; inventory[0].Itemstack = mixedStack; } inventory[0].MarkDirty(); inventory[1].MarkDirty(); MarkDirty(true); api.World.BlockAccessor.MarkBlockEntityDirty(pos); Sealed = false; } } else { Sealed = false; MarkDirty(true); } }
public override void DoSmelt(IWorldAccessor world, ISlotProvider cookingSlotsProvider, ItemSlot inputSlot, ItemSlot outputSlot) { ItemStack[] stacks = GetCookingStacks(cookingSlotsProvider); CookingRecipe recipe = GetMatchingCookingRecipe(world, stacks); Block block = world.GetBlock(CodeWithVariant("type", "cooked")); ItemStack outputStack = new ItemStack(block); if (recipe != null) { int quantityServings = recipe.GetQuantityServings(stacks); for (int i = 0; i < stacks.Length; i++) { CookingRecipeIngredient ingred = recipe.GetIngrendientFor(stacks[i]); ItemStack cookedStack = ingred.GetMatchingStack(stacks[i])?.CookedStack?.ResolvedItemstack.Clone(); if (cookedStack != null) { stacks[i] = cookedStack; } } // Carry over and set perishable properties TransitionableProperties cookedPerishProps = recipe.PerishableProps.Clone(); cookedPerishProps.TransitionedStack.Resolve(world, "cooking container perished stack"); CarryOverFreshness(api, cookingSlotsProvider.Slots, stacks, cookedPerishProps); for (int i = 0; i < stacks.Length; i++) { stacks[i].StackSize /= quantityServings; // whats this good for? Probably doesn't do anything meaningful } // Disabled. Let's sacrifice mergability for letting players select how meals should look and be named like //stacks = stacks.OrderBy(stack => stack.Collectible.Code.ToShortString()).ToArray(); // Required so that different arrangments of ingredients still create mergable meal bowls ((BlockCookedContainer)block).SetContents(recipe.Code, quantityServings, outputStack, stacks); outputStack.Collectible.SetTemperature(world, outputStack, GetIngredientsTemperature(world, stacks)); outputSlot.Itemstack = outputStack; inputSlot.Itemstack = null; for (int i = 0; i < cookingSlotsProvider.Slots.Length; i++) { cookingSlotsProvider.Slots[i].Itemstack = null; } return; } }
public override ItemStack OnTransitionNow(ItemSlot slot, TransitionableProperties props) { ItemStack compassStack = base.OnTransitionNow(slot, props); var x = slot.Itemstack?.Attributes.TryGetInt("compass-target-x"); var z = slot.Itemstack?.Attributes.TryGetInt("compass-target-z"); if (x != null && z != null) { var targetPos = new BlockPos((int)x, 0, (int)z); var y = ((ICoreServerAPI)api).World.BlockAccessor.GetTerrainMapheightAt(targetPos); targetPos.Y = y; (compassStack.Collectible as BlockCompass).SetTargetPos(compassStack, targetPos); } return(base.OnTransitionNow(slot, props)); }
public override ItemStack OnTransitionNow(ItemSlot slot, TransitionableProperties props) { if (props.Type == EnumTransitionType.Ripen) { BlockPos pos = slot.Inventory.Pos; if (pos != null) { Room room = api.ModLoader.GetModSystem <RoomRegistry>().GetRoomForPosition(pos); int lightlevel = api.World.BlockAccessor.GetLightLevel(pos, EnumLightLevelType.OnlySunLight); if (room.ExitCount > 0 && lightlevel < 2) { return(new ItemStack(api.World.GetItem(new AssetLocation("cheese-blue-4slice")))); } } } return(base.OnTransitionNow(slot, props)); }
public bool TryCraftNow(ICoreAPI api, double nowSealedHours, ItemSlot[] inputslots) { if (SealHours > 0 && nowSealedHours < SealHours) { return(false); } var matched = pairInput(inputslots); ItemStack mixedStack = Output.ResolvedItemstack.Clone(); mixedStack.StackSize = getOutputSize(matched); if (mixedStack.StackSize < 0) { return(false); } // Carry over freshness TransitionableProperties[] props = mixedStack.Collectible.GetTransitionableProperties(api.World, mixedStack, null); TransitionableProperties perishProps = props != null && props.Length > 0 ? props[0] : null; if (perishProps != null) { CollectibleObject.CarryOverFreshness(api, inputslots, new ItemStack[] { mixedStack }, perishProps); } ItemStack remainStack = null; foreach (var val in matched) { if (val.Value.ConsumeQuantity != null) { remainStack = val.Key.Itemstack; remainStack.StackSize -= (int)val.Value.ConsumeQuantity * (mixedStack.StackSize / Output.StackSize); if (remainStack.StackSize <= 0) { remainStack = null; } break; } } // Slot 0: Input/Item slot // Slot 1: Liquid slot if (shouldBeInLiquidSlot(mixedStack)) { inputslots[0].Itemstack = remainStack; inputslots[1].Itemstack = mixedStack; } else { inputslots[1].Itemstack = remainStack; inputslots[0].Itemstack = mixedStack; } inputslots[0].MarkDirty(); inputslots[1].MarkDirty(); return(true); }
public static string PerishableInfoCompact(ICoreAPI Api, ItemSlot contentSlot, float ripenRate, bool withStackName = true) { StringBuilder dsc = new StringBuilder(); if (withStackName) { dsc.Append(contentSlot.Itemstack.GetName()); } TransitionState[] transitionStates = contentSlot.Itemstack?.Collectible.UpdateAndGetTransitionStates(Api.World, contentSlot); if (transitionStates != null) { for (int i = 0; i < transitionStates.Length; i++) { string comma = ", "; TransitionState state = transitionStates[i]; TransitionableProperties prop = state.Props; float perishRate = contentSlot.Itemstack.Collectible.GetTransitionRateMul(Api.World, contentSlot, prop.Type); if (perishRate <= 0) { continue; } float transitionLevel = state.TransitionLevel; float freshHoursLeft = state.FreshHoursLeft / perishRate; switch (prop.Type) { case EnumTransitionType.Perish: if (transitionLevel > 0) { dsc.Append(comma + Lang.Get("{0}% spoiled", (int)Math.Round(transitionLevel * 100))); } else { double hoursPerday = Api.World.Calendar.HoursPerDay; if (freshHoursLeft / hoursPerday >= Api.World.Calendar.DaysPerYear) { dsc.Append(comma + Lang.Get("fresh for {0} years", Math.Round(freshHoursLeft / hoursPerday / Api.World.Calendar.DaysPerYear, 1))); } else if (freshHoursLeft > hoursPerday) { dsc.Append(comma + Lang.Get("fresh for {0} days", Math.Round(freshHoursLeft / hoursPerday, 1))); } else { dsc.Append(comma + Lang.Get("fresh for {0} hours", Math.Round(freshHoursLeft, 1))); } } break; case EnumTransitionType.Ripen: if (transitionLevel > 0) { dsc.Append(comma + Lang.Get("{1:0.#} days left to ripen ({0}%)", (int)Math.Round(transitionLevel * 100), (state.TransitionHours - state.TransitionedHours) / Api.World.Calendar.HoursPerDay / ripenRate)); } else { double hoursPerday = Api.World.Calendar.HoursPerDay; if (freshHoursLeft / hoursPerday >= Api.World.Calendar.DaysPerYear) { dsc.Append(comma + Lang.Get("will ripen in {0} years", Math.Round(freshHoursLeft / hoursPerday / Api.World.Calendar.DaysPerYear, 1))); } else if (freshHoursLeft > hoursPerday) { dsc.Append(comma + Lang.Get("will ripen in {0} days", Math.Round(freshHoursLeft / hoursPerday, 1))); } else { dsc.Append(comma + Lang.Get("will ripen in {0} hours", Math.Round(freshHoursLeft, 1))); } } break; } } } return(dsc.ToString()); }
public string CrockInfoCompact(ItemSlot inSlot) { BlockMeal mealblock = Api.World.GetBlock(new AssetLocation("bowl-meal")) as BlockMeal; BlockCrock crock = inSlot.Itemstack.Collectible as BlockCrock; IWorldAccessor world = Api.World; CookingRecipe recipe = crock.GetCookingRecipe(world, inSlot.Itemstack); ItemStack[] stacks = crock.GetNonEmptyContents(world, inSlot.Itemstack); if (stacks == null || stacks.Length == 0) { return(Lang.Get("Empty Crock") + "\n"); } StringBuilder dsc = new StringBuilder(); if (recipe != null) { double servings = inSlot.Itemstack.Attributes.GetDecimal("quantityServings"); if (recipe != null) { if (servings == 1) { dsc.Append(Lang.Get("{0}x {1}.", servings, recipe.GetOutputName(world, stacks))); } else { dsc.Append(Lang.Get("{0}x {1}.", servings, recipe.GetOutputName(world, stacks))); } } } else { int i = 0; foreach (var stack in stacks) { if (stack == null) { continue; } if (i++ > 0) { dsc.Append(", "); } dsc.Append(stack.StackSize + "x " + stack.GetName()); } dsc.Append("."); } DummyInventory dummyInv = new DummyInventory(Api); ItemSlot contentSlot = BlockCrock.GetDummySlotForFirstPerishableStack(Api.World, stacks, null, dummyInv); dummyInv.OnAcquireTransitionSpeed = (transType, stack, mul) => { return(mul * crock.GetContainingTransitionModifierContained(world, inSlot, transType) * inv.GetTransitionSpeedMul(transType, stack)); }; TransitionState[] transitionStates = contentSlot.Itemstack?.Collectible.UpdateAndGetTransitionStates(Api.World, contentSlot); bool addNewLine = true; if (transitionStates != null) { for (int i = 0; i < transitionStates.Length; i++) { TransitionState state = transitionStates[i]; TransitionableProperties prop = state.Props; float perishRate = contentSlot.Itemstack.Collectible.GetTransitionRateMul(world, contentSlot, prop.Type); if (perishRate <= 0) { continue; } addNewLine = false; float transitionLevel = state.TransitionLevel; float freshHoursLeft = state.FreshHoursLeft / perishRate; switch (prop.Type) { case EnumTransitionType.Perish: if (transitionLevel > 0) { dsc.AppendLine(" " + Lang.Get("{0}% spoiled", (int)Math.Round(transitionLevel * 100))); } else { double hoursPerday = Api.World.Calendar.HoursPerDay; if (freshHoursLeft / hoursPerday >= Api.World.Calendar.DaysPerYear) { dsc.AppendLine(" " + Lang.Get("Fresh for {0} years", Math.Round(freshHoursLeft / hoursPerday / Api.World.Calendar.DaysPerYear, 1))); } /*else if (freshHoursLeft / hoursPerday >= Api.World.Calendar.DaysPerMonth) - confusing. 12 days per months and stuff.. * { * dsc.AppendLine(Lang.Get("<font color=\"orange\">Perishable.</font> Fresh for {0} months", Math.Round(freshHoursLeft / hoursPerday / Api.World.Calendar.DaysPerMonth, 1))); * }*/ else if (freshHoursLeft > hoursPerday) { dsc.AppendLine(" " + Lang.Get("Fresh for {0} days", Math.Round(freshHoursLeft / hoursPerday, 1))); } else { dsc.AppendLine(" " + Lang.Get("Fresh for {0} hours", Math.Round(freshHoursLeft, 1))); } } break; } } } if (addNewLine) { dsc.AppendLine(""); } return(dsc.ToString()); }
public static string PerishableInfoCompact(ICoreAPI Api, ItemSlot contentSlot, float cureRate, bool withStackName = true) { if (contentSlot.Empty) { return(""); } StringBuilder dsc = new StringBuilder(); if (withStackName) { dsc.Append(contentSlot.Itemstack.GetName()); } TransitionState[] transitionStates = contentSlot.Itemstack?.Collectible.UpdateAndGetTransitionStates(Api.World, contentSlot); bool nowSpoiling = false; if (transitionStates != null) { bool appendLine = false; foreach (TransitionState state in transitionStates) { TransitionableProperties prop = state.Props; float perishRate = contentSlot.Itemstack.Collectible.GetTransitionRateMul(Api.World, contentSlot, prop.Type); float transitionLevel = state.TransitionLevel; float freshHoursLeft = state.FreshHoursLeft / perishRate; float transitionHoursLeft = (state.TransitionHours - state.TransitionedHours) / 3; double hoursPerday = Api.World.Calendar.HoursPerDay; switch (prop.Type) { case EnumTransitionType.Perish: appendLine = true; if (transitionLevel > 0f) { nowSpoiling = true; dsc.Append(", " + Lang.Get("{0}% spoiled", new object[] { (int)Math.Round(transitionLevel * 100f) })); } else { if (freshHoursLeft / hoursPerday >= Api.World.Calendar.DaysPerYear) { dsc.Append(", " + Lang.Get("fresh for {0} years", Math.Round(freshHoursLeft / hoursPerday / Api.World.Calendar.DaysPerYear, 1))); } else if (freshHoursLeft > hoursPerday) { dsc.Append(", " + Lang.Get("fresh for {0} days", Math.Round(freshHoursLeft / hoursPerday, 1))); } else { dsc.Append(", " + Lang.Get("fresh for {0} hours", Math.Round(freshHoursLeft, 1))); } } break; case EnumTransitionType.Dry: if (nowSpoiling) { break; } appendLine = true; if (transitionLevel > 0) { dsc.Append(", " + Lang.Get("{1:0.#} days left to dry ({0}%)", (int)Math.Round(transitionLevel * 100), transitionHoursLeft / hoursPerday)); } else { if (transitionHoursLeft / hoursPerday >= Api.World.Calendar.DaysPerYear) { dsc.Append(", " + Lang.Get("will dry in {0} years", Math.Round(transitionHoursLeft / hoursPerday / Api.World.Calendar.DaysPerYear, 1))); } else if (transitionHoursLeft > hoursPerday) { dsc.Append(", " + Lang.Get("will dry in {0} days", Math.Round(transitionHoursLeft / hoursPerday, 1))); } else { dsc.Append(", " + Lang.Get("will dry in {0} hours", Math.Round(transitionHoursLeft, 1))); } } break; case EnumTransitionType.Cure: if (nowSpoiling) { break; } appendLine = true; if (transitionLevel > 0) { dsc.Append(", " + Lang.Get("{1:0.#} days left to cure ({0}%)", (int)Math.Round(transitionLevel * 100), transitionHoursLeft / hoursPerday / cureRate)); } else { if (freshHoursLeft / hoursPerday >= Api.World.Calendar.DaysPerYear) { dsc.Append(", " + Lang.Get("will cure in {0} years", Math.Round(freshHoursLeft / hoursPerday / Api.World.Calendar.DaysPerYear, 1))); } else if (freshHoursLeft > hoursPerday) { dsc.Append(", " + Lang.Get("will cure in {0} days", Math.Round(freshHoursLeft / hoursPerday, 1))); } else { dsc.Append(", " + Lang.Get("will cure in {0} hours", Math.Round(freshHoursLeft, 1))); } } break; } } if (appendLine) { dsc.AppendLine(); } } return(dsc.ToString()); }
public static void CarryOverFreshness(ICoreAPI api, ItemSlot[] inputSlots, ItemStack[] outStacks, TransitionableProperties perishProps) { float transitionedHoursRelative = 0; int quantity = 0; for (int i = 0; i < inputSlots.Length; i++) { ItemSlot slot = inputSlots[i]; if (slot.Empty) { continue; } TransitionState state = slot.Itemstack.Collectible.UpdateAndGetTransitionState(api.World, slot, EnumTransitionType.Perish); if (state == null) { continue; } quantity++; float val = state.TransitionedHours / (state.TransitionHours + state.FreshHours); transitionedHoursRelative += val; } transitionedHoursRelative /= Math.Max(1, quantity); for (int i = 0; i < outStacks.Length; i++) { if (!(outStacks[i].Attributes["transitionstate"] is ITreeAttribute)) { outStacks[i].Attributes["transitionstate"] = new TreeAttribute(); } float transitionHours = perishProps.TransitionHours.nextFloat(1, api.World.Rand); float freshHours = perishProps.FreshHours.nextFloat(1, api.World.Rand); ITreeAttribute attr = (ITreeAttribute)outStacks[i].Attributes["transitionstate"]; attr.SetDouble("createdTotalHours", api.World.Calendar.TotalHours); attr.SetDouble("lastUpdatedTotalHours", api.World.Calendar.TotalHours); attr["freshHours"] = new FloatArrayAttribute(new float[] { freshHours }); attr["transitionHours"] = new FloatArrayAttribute(new float[] { transitionHours }); attr["transitionedHours"] = new FloatArrayAttribute(new float[] { Math.Max(0, transitionedHoursRelative * 0.8f * (transitionHours + freshHours) - 2) }); } }