Added the actual functional effects, not just the base.

This commit is contained in:
sarah committed 2026-09-05 17:05:54 +02:00
1 parent 9de8af0d2b
commit 1452a4a96d
6 files changed
+1102 -88

No files matched your search

+861 -2
View File
@@ -180,8 +180,40 @@ function GetResolvedFunctionalEffectCooldown(
Effect,
AtTime
) {
return GetFunctionalEffectCooldown(
Effect
const BaseCooldown =
GetFunctionalEffectCooldown(
Effect
);
if (BaseCooldown <= 0) {
return 0;
}
const Accelerator =
GetStrongestFunctionalEffectAffectingPlot(
SaveData,
GardenIndex,
PlotIndex,
"CooldownReduction",
AtTime
);
const Reduction = Math.max(
0,
Math.min(
1,
GetFunctionalEffectAmount(
Accelerator?.Effect
)
)
);
return Math.max(
FunctionalEffectMinimumCooldown,
Math.floor(
BaseCooldown *
(1 - Reduction)
)
);
}
@@ -1002,6 +1034,833 @@ function GetStrongestFunctionalEffectAffectingAnyPlot(
}
function DoesFunctionalPlantHaveEffectType(
Plant,
Type
) {
return GetPlantFunctionalEffects(
Plant
).some(
Effect =>
String(Effect.Type) ===
String(Type)
);
}
function CanFunctionalPlantUseAssignedSeed(
Plant
) {
return DoesFunctionalPlantHaveEffectType(
Plant,
"Plant"
);
}
function GetFunctionalPercentageAmount(
Effect,
Fallback = 0
) {
return Math.max(
0,
Math.min(
1,
GetFunctionalEffectAmount(
Effect,
Fallback
)
)
);
}
function GetFunctionalRandomItem(
SaveData,
Items
) {
if (!Array.isArray(Items) || Items.length === 0) {
return null;
}
if (Items.length === 1) {
return Items[0];
}
const Random =
typeof GetSimulationRandom === "function"
? GetSimulationRandom(
SaveData
)
: Math.random();
return Items[
Math.min(
Items.length - 1,
Math.floor(
Random * Items.length
)
)
];
}
function AddFunctionalCurrencyReward(
SaveData,
Currency,
Amount
) {
const RewardAmount = Number(
Amount
);
if (
!Number.isFinite(RewardAmount) ||
RewardAmount <= 0
) {
return 0;
}
SaveData.Currency ??= {};
SaveData.Currency[Currency] ??= 0;
SaveData.Currency[Currency] += RewardAmount;
SaveData.Statistics ??= {};
SaveData.Statistics.CurrencyEarned ??= {};
SaveData.Statistics.CurrencyEarned[
Currency
] ??= 0;
SaveData.Statistics.CurrencyEarned[
Currency
] += RewardAmount;
return RewardAmount;
}
function IsGardenPlotHarvestDisabled(
SaveData,
GardenIndex,
PlotIndex,
AtTime
) {
return (
GetStrongestFunctionalEffectAffectingPlot(
SaveData,
GardenIndex,
PlotIndex,
"DisableHarvest",
AtTime
) !== null
);
}
function IsGardenPlotMutationDisabled(
SaveData,
GardenIndex,
PlotIndex,
AtTime
) {
return (
GetStrongestFunctionalEffectAffectingPlot(
SaveData,
GardenIndex,
PlotIndex,
"DisableMutation",
AtTime
) !== null
);
}
function DoesMutationPatternInvolveDisableMutation(
SaveData,
GardenIndex,
OriginX,
OriginY,
Pattern
) {
const Garden =
GetFunctionalGarden(
SaveData,
GardenIndex
);
if (
Garden === null ||
!Array.isArray(Pattern)
) {
return false;
}
for (
let LocalY = 0;
LocalY < Pattern.length;
LocalY++
) {
const Row = Pattern[LocalY];
if (!Array.isArray(Row)) {
continue;
}
for (
let LocalX = 0;
LocalX < Row.length;
LocalX++
) {
const Matcher = Row[LocalX];
if (
Matcher === null ||
Matcher === "Any" ||
Matcher === "Empty"
) {
continue;
}
const PlotIndex =
GetFunctionalPlotIndex(
Garden,
OriginX + LocalX,
OriginY + LocalY
);
if (PlotIndex === null) {
continue;
}
const Plot =
Garden.Plots?.[PlotIndex] ?? null;
if (Plot === null) {
continue;
}
const Plant =
Plants?.[Plot.Plant];
if (
Plant !== undefined &&
DoesFunctionalPlantHaveEffectType(
Plant,
"DisableMutation"
)
) {
return true;
}
}
}
return false;
}
function GetGardenPlotGrowthAdvance(
SaveData,
GardenIndex,
PlotIndex,
AtTime
) {
const Effect =
GetStrongestFunctionalEffectAffectingPlot(
SaveData,
GardenIndex,
PlotIndex,
"GrowthAdvance",
AtTime
);
return GetFunctionalPercentageAmount(
Effect?.Effect
);
}
function GetGardenPlotHarvestYieldBonus(
SaveData,
GardenIndex,
PlotIndex,
AtTime
) {
const Effect =
GetStrongestFunctionalEffectAffectingPlot(
SaveData,
GardenIndex,
PlotIndex,
"HarvestYieldBonus",
AtTime
);
return GetFunctionalPercentageAmount(
Effect?.Effect
);
}
function PlantGardenPlot(
SaveData,
GardenIndex,
PlotIndex,
PlantKey,
AtTime,
Options = {}
) {
const Garden =
GetFunctionalGarden(
SaveData,
GardenIndex
);
const Plant =
Plants?.[PlantKey];
if (
Garden === null ||
Plant === undefined ||
Garden.Plots?.[PlotIndex] !== null
) {
return {
Changed: false,
Planted: false
};
}
const ConsumeSeed =
Options.ConsumeSeed === true;
if (ConsumeSeed) {
if (
typeof TakeSeed !== "function" ||
!TakeSeed(
SaveData,
Plant.Id,
1
)
) {
return {
Changed: false,
Planted: false,
MissingSeed: true
};
}
}
const GrowthAdvance =
Options.ApplyGrowthAdvance === false
? 0
: GetGardenPlotGrowthAdvance(
SaveData,
GardenIndex,
PlotIndex,
AtTime
);
const GrowthTime = Math.max(
0,
Number(
Plant.GrowthTime ?? 0
) || 0
);
const PlantedAt =
Number(AtTime) -
GrowthTime * GrowthAdvance;
const Rotation =
FunctionalDirectionOffsets[
Options.Rotation
] !== undefined
? Options.Rotation
: "East";
Garden.Plots[PlotIndex] = {
Plant: PlantKey,
PlantedAt,
Rotation
};
return {
Changed: true,
Planted: true,
PlantKey,
PlotIndex,
GrowthAdvance,
PlantedAt
};
}
function HarvestGardenPlot(
SaveData,
GardenIndex,
PlotIndex,
AtTime,
Options = {}
) {
const Garden =
GetFunctionalGarden(
SaveData,
GardenIndex
);
const Plot =
Garden?.Plots?.[PlotIndex] ?? null;
if (Plot === null) {
return {
Changed: false,
Harvested: false
};
}
const Plant =
Plants?.[Plot.Plant];
if (
Plant === undefined ||
!IsFunctionalPlantMatureAtTime(
Plot,
Plant,
AtTime
)
) {
return {
Changed: false,
Harvested: false,
Immature: Plant !== undefined
};
}
if (
Options.ExcludeFunctional === true &&
IsFunctionalPlant(
Plant
)
) {
return {
Changed: false,
Harvested: false,
Excluded: true
};
}
if (
IsGardenPlotHarvestDisabled(
SaveData,
GardenIndex,
PlotIndex,
AtTime
)
) {
return {
Changed: false,
Harvested: false,
Disabled: true
};
}
const BaseReward =
typeof GetPlantHarvestReward === "function"
? GetPlantHarvestReward(
SaveData,
Plant.Id
)
: null;
if (BaseReward === null) {
return {
Changed: false,
Harvested: false,
RewardUnavailable: true
};
}
const YieldBonus =
GetGardenPlotHarvestYieldBonus(
SaveData,
GardenIndex,
PlotIndex,
AtTime
);
const RewardAmount = Math.ceil(
BaseReward *
(1 + YieldBonus)
);
AddFunctionalCurrencyReward(
SaveData,
"Dew",
RewardAmount
);
Garden.Plots[PlotIndex] = null;
return {
Changed: true,
Harvested: true,
Plant,
PlantKey: Plot.Plant,
Rotation:
GetFunctionalPlotRotation(
Plot
),
RewardAmount,
YieldBonus
};
}
function GetFunctionalEligibleSourceTargets(
SaveData,
Targets,
AtTime,
RequireMature = true
) {
return Targets.filter(
Target => {
const Plot = Target.Plot;
if (Plot === null) {
return false;
}
const Plant =
Plants?.[Plot.Plant];
if (Plant === undefined) {
return false;
}
return (
!RequireMature ||
IsFunctionalPlantMatureAtTime(
Plot,
Plant,
AtTime
)
);
}
);
}
function SelectFunctionalTarget(
SaveData,
Targets,
Random
) {
if (Targets.length === 0) {
return null;
}
return Random === true
? GetFunctionalRandomItem(
SaveData,
Targets
)
: Targets[0];
}
function HandleFunctionalHarvest(
Context
) {
const Targets =
Context.GetTargets();
let Changed = false;
for (const Target of Targets) {
const Result =
HarvestGardenPlot(
Context.SaveData,
Target.GardenIndex,
Target.PlotIndex,
Context.AtTime,
{
ExcludeFunctional:
Context.Effect.ExcludeFunctional === true
}
);
Changed =
Changed ||
Result.Changed === true;
}
return {Changed};
}
function HandleFunctionalDuplicate(
Context
) {
const SourceArea =
GetFunctionalEffectArea(
Context.Effect,
"Source",
"Behind"
);
const TargetArea =
GetFunctionalEffectArea(
Context.Effect,
"Target",
"Front"
);
const Sources =
GetFunctionalEligibleSourceTargets(
Context.SaveData,
GetFunctionalAreaTargets(
Context.SaveData,
Context.GardenIndex,
Context.PlotIndex,
SourceArea
),
Context.AtTime,
Context.Effect.RequireMatureSource !== false
);
const EmptyTargets =
GetFunctionalAreaTargets(
Context.SaveData,
Context.GardenIndex,
Context.PlotIndex,
TargetArea
).filter(
Target => Target.Plot === null
);
const Source =
SelectFunctionalTarget(
Context.SaveData,
Sources,
Context.Effect.RandomSource === true
);
const Target =
SelectFunctionalTarget(
Context.SaveData,
EmptyTargets,
Context.Effect.RandomTarget === true
);
if (
Source === null ||
Target === null
) {
return {Changed: false};
}
return PlantGardenPlot(
Context.SaveData,
Context.GardenIndex,
Target.PlotIndex,
Source.Plot.Plant,
Context.AtTime,
{
ConsumeSeed: false
}
);
}
function HandleFunctionalPlant(
Context
) {
const AssignedSeed =
typeof Context.Plot.AssignedSeed === "string"
? Context.Plot.AssignedSeed
: null;
if (
AssignedSeed === null ||
Plants?.[AssignedSeed] === undefined
) {
return {Changed: false};
}
const TargetArea =
GetFunctionalEffectArea(
Context.Effect,
"Target",
"Front"
);
const EmptyTargets =
GetFunctionalAreaTargets(
Context.SaveData,
Context.GardenIndex,
Context.PlotIndex,
TargetArea
).filter(
Target => Target.Plot === null
);
const Target =
SelectFunctionalTarget(
Context.SaveData,
EmptyTargets,
Context.Effect.RandomTarget === true
);
if (Target === null) {
return {Changed: false};
}
return PlantGardenPlot(
Context.SaveData,
Context.GardenIndex,
Target.PlotIndex,
AssignedSeed,
Context.AtTime,
{
ConsumeSeed: true
}
);
}
function HandleFunctionalReplant(
Context
) {
const Targets =
Context.GetTargets();
let Changed = false;
for (const Target of Targets) {
const ExistingPlot = Target.Plot;
if (ExistingPlot === null) {
continue;
}
const ExistingPlant =
Plants?.[ExistingPlot.Plant];
if (ExistingPlant === undefined) {
continue;
}
const ConsumeSeed =
Context.Effect.ConsumeSeed !== false;
if (
ConsumeSeed &&
(
typeof GetSeedCount !== "function" ||
GetSeedCount(
Context.SaveData,
ExistingPlant.Id
) < 1
)
) {
continue;
}
const Rotation =
GetFunctionalPlotRotation(
ExistingPlot
);
const HarvestResult =
HarvestGardenPlot(
Context.SaveData,
Target.GardenIndex,
Target.PlotIndex,
Context.AtTime,
{
ExcludeFunctional:
Context.Effect.ExcludeFunctional === true
}
);
if (!HarvestResult.Harvested) {
continue;
}
const PlantResult =
PlantGardenPlot(
Context.SaveData,
Target.GardenIndex,
Target.PlotIndex,
HarvestResult.PlantKey,
Context.AtTime,
{
ConsumeSeed,
Rotation
}
);
Changed =
Changed ||
HarvestResult.Changed === true ||
PlantResult.Changed === true;
}
return {Changed};
}
function SetFunctionalPlantAssignedSeed(
Plot,
PlantKey
) {
if (
Plot === null ||
typeof Plot !== "object" ||
Plants?.[PlantKey] === undefined
) {
return false;
}
Plot.AssignedSeed = PlantKey;
return true;
}
function ClearFunctionalPlantAssignedSeed(
Plot
) {
if (
Plot === null ||
typeof Plot !== "object"
) {
return false;
}
delete Plot.AssignedSeed;
return true;
}
RegisterFunctionalEffectHandler(
"Harvest",
HandleFunctionalHarvest
);
RegisterFunctionalEffectHandler(
"Duplicate",
HandleFunctionalDuplicate
);
RegisterFunctionalEffectHandler(
"Plant",
HandleFunctionalPlant
);
RegisterFunctionalEffectHandler(
"Replant",
HandleFunctionalReplant
);
function CreateFunctionalProcessingResult() {
return {
Attempted: false,