Private
Public Access
1
0

reinit branch

This commit is contained in:
2026-03-11 01:46:34 +01:00
commit bff9251737
129 changed files with 16115 additions and 0 deletions

View File

@@ -0,0 +1,504 @@
using OrekiWoofsBeehives.BlockEntities;
using OrekiWoofsBeehives.Behaviors;
using System;
using System.Collections.Generic;
using System.Text;
using Vintagestory.API.Config;
namespace OrekiWoofsBeehives.Helpers;
public static class BeehiveInfoStringBuilder
{
public static void BuildBeehiveInfo(
StringBuilder builder,
BeehiveStats stats,
BlockEntityReusableBeehive beehive)
{
var verbosity = Config.Instance.GetEffectiveInformationVerbosity();
if (verbosity == 0)
return;
if (beehive.Api?.World != null && beehive.Api.World.Calendar.TotalDays < beehive.NextSwarmAllowedTotalDays)
builder.AppendLine(Lang.Get("orekiwoofsbeehives:beehive-info-recently-swarmed", Config.Instance.SwarmCooldownDays));
if (beehive.IsSwarmBuildingNearby())
builder.AppendLine($"<font color=\"#00bb00\">{Lang.Get("orekiwoofsbeehives:beehive-info-source-swarm-forming")}</font>");
else if (!beehive.IsReadyToStartSwarm() && beehive.IsReadyToStartSwarm(ignoreDayTime: true))
builder.AppendLine($"<font color=\"#00bb00\">{Lang.Get("orekiwoofsbeehives:beehive-info-ready-waiting-morning")}</font>");
if (!beehive.SwarmsDisabled && !beehive.IsSwarmBuildingNearby()
&& beehive.PreSwarmProgress > 0 && !beehive.IsReadyToStartSwarm(ignoreDayTime: true))
AppendPreSwarmProgress(builder, beehive, stats, verbosity);
if (verbosity >= 4)
AppendScoutingProgress(builder, beehive);
if (beehive.IsReceivingIncomingSwarm)
builder.AppendLine($"<font color=\"#00bb00\">{Lang.Get("orekiwoofsbeehives:beehive-info-incoming-swarm")}</font>");
if (!beehive.IsReceivingIncomingSwarm && beehive.BeePopulation < Config.Instance.BeehiveConsideredEmptyBelowPopulation)
{
builder.AppendLine($"<font color=\"#ffff00\">{Lang.GetWithFallback("orekiwoofsbeehives:beehive-info-no-bees-use-skep-or-wait-for-swarm", "orekiwoofsbeehives:beehive-info-no-bees")}</font>");
return;
}
if (beehive.IsReadyToStartSwarm())
builder.AppendLine($"<font color=\"#ffaa00\">{Lang.Get("orekiwoofsbeehives:beehive-info-ready-to-swarm")}</font>");
AppendPopulationInfo(builder, stats, beehive, verbosity);
if (verbosity >= 1)
AppendFlowerInfo(builder, stats, beehive, verbosity);
if (verbosity >= 3)
AppendFrameInfo(builder, stats);
AppendHoneyProgress(builder, stats, beehive, verbosity);
if (verbosity >= 3)
AppendFeedInfo(builder, beehive, stats);
AppendFrameStatusMessages(builder, stats, beehive, verbosity);
AppendPopulationChange(builder, stats, verbosity);
AppendCropBoostEffectiveness(builder, beehive, verbosity);
AppendTemperatureInfo(builder, stats, verbosity);
if (verbosity >= 3)
AppendHoneyProduction(builder, stats);
if (Config.Instance.EnableSwarms && beehive.SwarmsDisabled)
builder.AppendLine(Lang.Get("orekiwoofsbeehives:beehive-info-swarms-disabled"));
}
private static void AppendScoutingProgress(StringBuilder builder, BlockEntityReusableBeehive beehive)
{
var scoutingProgressString = Lang.Get("orekiwoofsbeehives:beehiveScoutingProgress");
var scanningProgress = beehive.GetScanningProgress();
var rescanningProgress = beehive.GetRescanningProgress();
builder.AppendLine($"{scoutingProgressString}: {scanningProgress * 100:F1}% (+ {rescanningProgress * 100:F1}%)");
}
private static void AppendPreSwarmProgress(
StringBuilder builder,
BlockEntityReusableBeehive beehive,
BeehiveStats stats,
int verbosity)
{
if (verbosity == 1)
{
builder.AppendLine($"<font color=\"#aaffaa\">{Lang.Get("orekiwoofsbeehives:beehive-info-pre-swarm-building")}</font>");
return;
}
var cfg = Config.Instance;
var isIncreasing = stats.Components.Temperature >= cfg.MaxTemperatureGrowth;
string detail;
if (isIncreasing)
{
var hoursLeft = (1.0 - beehive.PreSwarmProgress) * cfg.PreSwarmDurationHours;
var hoursPerDay = beehive.Api?.World?.Calendar?.HoursPerDay ?? 24.0;
if (hoursLeft < 1)
{
detail = Lang.Get("orekiwoofsbeehives:beehive-info-pre-swarm-time-lessthanhourleft");
}
else if (hoursLeft < hoursPerDay)
{
detail = Lang.Get("orekiwoofsbeehives:beehive-info-pre-swarm-time-hours", $"{hoursLeft:F0}");
}
else
{
var daysLeft = (int)Math.Round(hoursLeft / hoursPerDay);
detail = daysLeft == 1
? Lang.Get("orekiwoofsbeehives:beehive-info-pre-swarm-time-1day")
: Lang.Get("orekiwoofsbeehives:beehive-info-pre-swarm-time-days", daysLeft);
}
}
else
{
detail = Lang.Get("orekiwoofsbeehives:beehive-info-pre-swarm-paused");
}
builder.AppendLine($"<font color=\"#aaffaa\">{Lang.Get("orekiwoofsbeehives:beehive-info-pre-swarm-progress", detail)}</font>");
}
private static void AppendPopulationInfo(
StringBuilder builder,
BeehiveStats stats,
BlockEntityReusableBeehive beehive,
int verbosity)
{
var cfg = Config.Instance;
if (verbosity == 1)
{
var percentage = beehive.BeePopulation / cfg.MaxBeePopulation;
string levelKey = percentage switch
{
(<= 0) => "orekiwoofsbeehives:beehive-info-population-none",
(<= 0.25) => "orekiwoofsbeehives:beehive-info-population-low",
(<= 0.60) => "orekiwoofsbeehives:beehive-info-population-medium",
(<= 0.80) => "orekiwoofsbeehives:beehive-info-population-high",
_ => "orekiwoofsbeehives:beehive-info-population-veryhigh",
};
builder.AppendLine(Lang.Get(levelKey));
}
else if (verbosity == 2)
{
builder.AppendLine(FormatLang("orekiwoofsbeehives:beehive-info-population-v2", new Dictionary<string, string>
{
["beePopulation"] = $"{beehive.BeePopulation:N0}",
["maxBeePopulation"] = $"{cfg.MaxBeePopulation:N0}",
["beeProductionMultiplier"] = $"{stats.BeeProductionMultiplier:F1}"
}));
}
else
{
builder.AppendLine(FormatLang("orekiwoofsbeehives:beehive-info-population", new Dictionary<string, string>
{
["beePopulation"] = $"{beehive.BeePopulation:N0}",
["maxBeePopulation"] = $"{cfg.MaxBeePopulation:N0}",
["beeProductionMultiplier"] = $"{stats.BeeProductionMultiplier:F1}"
}));
}
}
private static void AppendFlowerInfo(
StringBuilder builder,
BeehiveStats stats,
BlockEntityReusableBeehive beehive,
int verbosity)
{
var effectiveFlowers = stats.Components.EffectiveFlowers;
if (verbosity < 3)
{
var scanningProgress = beehive.GetScanningProgress();
var scoutingSuffix = (!beehive.WasFullyScanned && scanningProgress < 1f)
? " (" + Lang.Get("orekiwoofsbeehives:beehive-info-flowers-scanning-suffix") + $" - {scanningProgress * 100:F0}%)"
: string.Empty;
builder.AppendLine(FormatLang("orekiwoofsbeehives:beehive-info-flowers-simple", new Dictionary<string, string>
{
["flowersAround"] = $"{beehive.FlowersAround}",
["cropsAround"] = $"{beehive.CropsAround}"
}) + scoutingSuffix);
}
else
{
builder.AppendLine(FormatLang("orekiwoofsbeehives:beehive-info-flowers", new Dictionary<string, string>
{
["flowersAround"] = $"{beehive.FlowersAround}",
["cropsAround"] = $"{beehive.CropsAround}",
["effectiveFlowers"] = $"{effectiveFlowers:F1}",
["flowerProductionMultiplier"] = $"{stats.FlowerProductionMultiplier:F1}"
}));
}
if (beehive.WasFullyScanned && beehive.FlowersAround.HasValue)
{
var cfg = Config.Instance;
int flowersAround = beehive.FlowersAround.Value;
if (flowersAround < cfg.FlowerThreshold)
{
int flowersNeeded = cfg.FlowerThreshold - flowersAround;
builder.AppendLine($"<font color=\"#ff0000\">{FormatLang("orekiwoofsbeehives:beehive-info-flowers-warning-causing-deaths", new Dictionary<string, string>
{
["flowersNeeded"] = $"{flowersNeeded}"
})}</font>");
}
else if (effectiveFlowers < cfg.MaxFlowersForHoneyProduction)
{
builder.AppendLine(Lang.Get("orekiwoofsbeehives:beehive-info-flowers-warning-suboptimal"));
}
}
}
private static void AppendFrameInfo(
StringBuilder builder,
BeehiveStats stats)
{
var cfg = Config.Instance;
var filledFrames = stats.Components.FilledFramesCount;
var emptyFrames = stats.Components.EmptyFrames;
var totalFrames = stats.Components.TotalFrames;
if (filledFrames > 0 && emptyFrames > 0)
{
builder.AppendLine(FormatLang("orekiwoofsbeehives:beehive-info-frames-mixed", new Dictionary<string, string>
{
["filledFrames"] = $"{filledFrames}",
["filledFrameBonus"] = $"{filledFrames * cfg.BonusGrowthPerFilledFrame:N0}",
["emptyFrames"] = $"{emptyFrames}"
}));
}
else if (filledFrames > 0)
{
builder.AppendLine(FormatLang("orekiwoofsbeehives:beehive-info-frames-filled", new Dictionary<string, string>
{
["filledFrames"] = $"{filledFrames}",
["filledFrameBonus"] = $"{filledFrames * cfg.BonusGrowthPerFilledFrame:N0}"
}));
}
else if (emptyFrames > 0)
{
builder.AppendLine(FormatLang("orekiwoofsbeehives:beehive-info-frames-empty", new Dictionary<string, string>
{
["emptyFrames"] = $"{emptyFrames}"
}));
}
else
{
builder.AppendLine(FormatLang("orekiwoofsbeehives:beehive-info-frames-total", new Dictionary<string, string>
{
["totalFrames"] = $"{totalFrames}"
}));
}
}
private static void AppendHoneyProgress(
StringBuilder builder,
BeehiveStats stats,
BlockEntityReusableBeehive beehive,
int verbosity)
{
var emptyFrameSlot = beehive.GetFirstEmptyFrameSlot();
var totalFrames = stats.Components.TotalFrames;
if (verbosity == 1)
{
if (emptyFrameSlot >= 0)
{
if (stats.FramesPerDay <= 0)
{
builder.AppendLine(Lang.Get("orekiwoofsbeehives:beehive-info-progress-v1-noproduction"));
}
else
{
var daysToFill = (1.0 - beehive.HoneyProgress) / stats.FramesPerDay;
if (daysToFill < 1.0)
builder.AppendLine(Lang.Get("orekiwoofsbeehives:beehive-info-progress-v1-lessthanday"));
else
builder.AppendLine(FormatLang("orekiwoofsbeehives:beehive-info-progress-v1-days", new Dictionary<string, string>
{
["days"] = $"{Math.Ceiling(daysToFill):F0}"
}));
}
}
else if (totalFrames == 0)
{
builder.AppendLine(Lang.Get("orekiwoofsbeehives:beehive-info-no-frames"));
}
}
else
{
if (emptyFrameSlot >= 0)
{
if (stats.FramesPerDay > 0)
{
builder.AppendLine(FormatLang("orekiwoofsbeehives:beehive-info-progress-filling", new Dictionary<string, string>
{
["honeyProgress"] = $"{beehive.HoneyProgress * 100:F1}",
["daysToFill"] = $"{(1.0 - beehive.HoneyProgress) / stats.FramesPerDay:F1}"
}));
}
else
{
builder.AppendLine(FormatLang("orekiwoofsbeehives:beehive-info-progress-noproduction", new Dictionary<string, string>
{
["honeyProgress"] = $"{beehive.HoneyProgress * 100:F1}"
}));
}
}
else if (totalFrames > 0 && verbosity < 3)
builder.AppendLine($"<font color=\"#00bb00\">{Lang.Get("orekiwoofsbeehives:beehive-info-all-filled")}</font>");
else if (totalFrames == 0 && verbosity < 3)
builder.AppendLine(Lang.Get("orekiwoofsbeehives:beehive-info-no-frames"));
}
}
private static void AppendTemperatureInfo(
StringBuilder builder,
BeehiveStats stats,
int verbosity)
{
var temperature = stats.Components.Temperature;
var temperatureMultiplier = stats.Components.TemperatureMultiplier;
var cfg = Config.Instance;
if (verbosity is >= 1 and < 3)
{
if (temperature <= cfg.MinTemperatureGrowth)
builder.AppendLine(Lang.Get("orekiwoofsbeehives:beehive-info-temperature-overwintering"));
else if (temperature < cfg.MaxTemperatureGrowth)
builder.AppendLine(Lang.Get("orekiwoofsbeehives:beehive-info-temperature-cold"));
}
else
{
builder.AppendLine(FormatLang("orekiwoofsbeehives:beehive-info-temperature", new Dictionary<string, string>
{
["temperature"] = $"{temperature:F1}",
["multiplier"] = $"{temperatureMultiplier:F2}"
}));
}
if (stats.Components.IsGreenhouse && Config.Instance.GreenhouseAffectsBeehive)
builder.AppendLine(Lang.Get("game:greenhousetempbonus"));
if (cfg.WinterHardMode
&& stats.Components.FilledFramesCount <= 0
&& temperature <= cfg.MinTemperatureGrowth)
builder.AppendLine($"<font color=\"#ff0000\">{Lang.Get("orekiwoofsbeehives:beehive-info-winter-starving")}</font>");
}
private static void AppendFrameStatusMessages(
StringBuilder builder,
BeehiveStats stats,
BlockEntityReusableBeehive beehive,
int verbosity)
{
if (verbosity >= 3)
return;
var cfg = Config.Instance;
var percentage = beehive.BeePopulation / cfg.MaxBeePopulation;
var filledFrames = stats.Components.FilledFramesCount;
var emptyFrames = stats.Components.EmptyFrames;
if (filledFrames > 0 && percentage > 0 && percentage <= 0.80)
{
builder.AppendLine(Lang.Get("orekiwoofsbeehives:beehive-info-frames-boosting"));
}
if (emptyFrames > 0 && percentage > 0 && percentage <= 0.60)
{
builder.AppendLine(Lang.Get("orekiwoofsbeehives:beehive-info-frames-sacrificing"));
}
}
private static void AppendPopulationChange(StringBuilder builder, BeehiveStats stats, int verbosity)
{
if (verbosity == 1)
{
var netChange = stats.DailyNetPopulationChange;
var statusKey =
netChange < 0 ? "orekiwoofsbeehives:beehive-info-population-status-decreasing"
: netChange <= 100 ? "orekiwoofsbeehives:beehive-info-population-status-stagnant"
: netChange <= 300 ? "orekiwoofsbeehives:beehive-info-population-status-slowgrowth"
: "orekiwoofsbeehives:beehive-info-population-status-growing";
builder.AppendLine(Lang.Get(statusKey));
}
else
{
var changeSign = stats.DailyNetPopulationChange >= 0 ? "+" : "";
builder.AppendLine(FormatLang("orekiwoofsbeehives:beehive-info-population-change", new Dictionary<string, string>
{
["changeSign"] = changeSign,
["netChange"] = $"{stats.DailyNetPopulationChange:N0}",
["dailyGrowth"] = $"{stats.Components.DailyGrowth:N0}",
["dailyDeaths"] = $"{stats.Components.DailyDeaths:N0}"
}));
}
}
private static void AppendCropBoostEffectiveness(StringBuilder builder, BlockEntityReusableBeehive beehive, int verbosity)
{
var cfg = Config.Instance;
if (!cfg.YieldBoost && !cfg.SpeedBoost)
return;
float populationScale = BlockBehaviorBeehiveAffected.GetPopulationBoostScale(beehive.BeePopulation, cfg);
if (populationScale <= 0f)
{
builder.AppendLine($"<font color=\"#ffff00\">{Lang.Get("orekiwoofsbeehives:blockinfo-crop-boost-population-too-low")}</font>");
return;
}
if (verbosity == 1)
{
var levelText = populationScale < 0.34f
? Lang.Get("orekiwoofsbeehives:blockinfo-crop-boost-level-low")
: populationScale < 0.67f
? Lang.Get("orekiwoofsbeehives:blockinfo-crop-boost-level-medium")
: Lang.Get("orekiwoofsbeehives:blockinfo-crop-boost-level-high");
builder.AppendLine(Lang.Get("orekiwoofsbeehives:blockinfo-crop-boost-effectiveness", levelText));
return;
}
var resultingBoostParts = new List<string>();
if (cfg.YieldBoost)
{
var yieldBonusFactor = Math.Max(0f, cfg.YieldMultiplier - 1f);
var yieldPercent = (yieldBonusFactor * populationScale * 100f).ToString("N0");
resultingBoostParts.Add(Lang.Get("orekiwoofsbeehives:blockinfo-crop-boost-result-yield", yieldPercent));
}
if (cfg.SpeedBoost)
{
var speedPercent = (cfg.GrowthSpeedBonus * populationScale * 100f).ToString("N0");
resultingBoostParts.Add(Lang.Get("orekiwoofsbeehives:blockinfo-crop-boost-result-speed", speedPercent));
}
var effectivenessPercent = (populationScale * 100f).ToString("N0");
var cropBoostLine = Lang.Get("orekiwoofsbeehives:blockinfo-crop-boost-effectiveness", effectivenessPercent + "%");
if (resultingBoostParts.Count > 0)
cropBoostLine += " (" + string.Join(", ", resultingBoostParts) + ")";
builder.AppendLine(cropBoostLine);
}
private static void AppendHoneyProduction(StringBuilder builder, BeehiveStats stats)
{
if (stats.FramesPerDay > 0)
{
builder.AppendLine(FormatLang("orekiwoofsbeehives:beehive-info-honey-production", new Dictionary<string, string>
{
["framesPerDay"] = $"{stats.FramesPerDay:F2}",
["daysPerFrame"] = $"{1.0 / stats.FramesPerDay:F1}"
}));
}
else
{
builder.AppendLine(FormatLang("orekiwoofsbeehives:beehive-info-honey-production-simple", new Dictionary<string, string>
{
["framesPerDay"] = $"{stats.FramesPerDay:F2}"
}));
}
}
private static void AppendFeedInfo(StringBuilder builder, BlockEntityReusableBeehive beehive, BeehiveStats stats)
{
if (!beehive.TryGetCurrentFeedStatus(out double remaining))
return;
var daysPerFrame = stats.FeedConsumedPerDay > 0
? 1.0 / stats.FeedConsumedPerDay
: 0.0;
builder.AppendLine(FormatLang("orekiwoofsbeehives:beehive-info-feed-current", new Dictionary<string, string>
{
["feedRemainingPercent"] = $"{remaining * 100:F0}",
["daysPerFrame"] = $"{daysPerFrame:F1}"
}));
}
private static string FormatLang(string langKey, Dictionary<string, string> values)
{
var result = Lang.Get(langKey);
foreach (var kvp in values)
result = result.Replace($">>>{kvp.Key}<<<", kvp.Value);
return result;
}
}