mirror of
https://git.srhtnin.garden/sarah/srhtnin.github.io.git
synced 2026-10-13 18:38:11 +02:00
Added the actual functional effects, not just the base.
This commit is contained in:
1 parent
9de8af0d2b
commit
1452a4a96d
6 files changed
+1102
-88
No files matched your search
@@ -98,13 +98,29 @@ function ValidateAdminFunctionalEffects(
|
||||
);
|
||||
}
|
||||
|
||||
const EffectType = String(
|
||||
Effect.Type ?? ""
|
||||
).trim();
|
||||
|
||||
ValidateAdminKey(
|
||||
String(
|
||||
Effect.Type ?? ""
|
||||
).trim(),
|
||||
EffectType,
|
||||
"Functional effect type"
|
||||
);
|
||||
|
||||
if (
|
||||
typeof IsKnownFunctionalEffectType ===
|
||||
"function" &&
|
||||
!IsKnownFunctionalEffectType(
|
||||
EffectType
|
||||
)
|
||||
) {
|
||||
throw new Error(
|
||||
"Unknown functional effect type: " +
|
||||
EffectType +
|
||||
"."
|
||||
);
|
||||
}
|
||||
|
||||
if (Effect.Key !== undefined) {
|
||||
const EffectKey = String(
|
||||
Effect.Key ?? ""
|
||||
@@ -175,16 +191,41 @@ function ValidateAdminFunctionalEffects(
|
||||
"Functional effect amount must be a number."
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
[
|
||||
"GrowthAdvance",
|
||||
"MutationChanceBonus",
|
||||
"CooldownReduction",
|
||||
"HarvestYieldBonus"
|
||||
].includes(EffectType) &&
|
||||
(Amount < 0 || Amount > 1)
|
||||
) {
|
||||
throw new Error(
|
||||
"Functional percentage amounts must be between 0 and 1."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
Effect.RequireMature !== undefined &&
|
||||
typeof Effect.RequireMature !==
|
||||
"boolean"
|
||||
) {
|
||||
throw new Error(
|
||||
"Functional effect RequireMature must be On or Off."
|
||||
);
|
||||
for (const BooleanField of [
|
||||
"RequireMature",
|
||||
"RequireMatureSource",
|
||||
"RandomSource",
|
||||
"RandomTarget",
|
||||
"ExcludeFunctional",
|
||||
"ConsumeSeed"
|
||||
]) {
|
||||
if (
|
||||
Effect[BooleanField] !== undefined &&
|
||||
typeof Effect[BooleanField] !==
|
||||
"boolean"
|
||||
) {
|
||||
throw new Error(
|
||||
"Functional effect " +
|
||||
BooleanField +
|
||||
" must be On or Off."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
|
||||
@@ -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,
|
||||
|
||||
+64
-56
@@ -2185,28 +2185,27 @@ async function PlantSeed(
|
||||
}
|
||||
|
||||
|
||||
if (
|
||||
!TakeSeed(
|
||||
const PlantResult =
|
||||
PlantGardenPlot(
|
||||
GameSave,
|
||||
SelectedSeedId
|
||||
)
|
||||
) {
|
||||
GameSave.ActiveGardenIndex,
|
||||
PlotIndex,
|
||||
PlantKey,
|
||||
ActionTime,
|
||||
{
|
||||
ConsumeSeed: true,
|
||||
Rotation:
|
||||
GardenPlotDefaultRotation
|
||||
}
|
||||
);
|
||||
|
||||
if (!PlantResult.Planted) {
|
||||
EnsureSelectedSeed();
|
||||
RenderSeeds();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
GameSave.Garden.Plots[
|
||||
PlotIndex
|
||||
] = {
|
||||
Plant: PlantKey,
|
||||
PlantedAt: ActionTime,
|
||||
Rotation: GardenPlotDefaultRotation
|
||||
};
|
||||
|
||||
|
||||
SetGardenMessage(
|
||||
"Planted " +
|
||||
Plant.Name +
|
||||
@@ -2307,40 +2306,47 @@ async function PlantManySeeds() {
|
||||
}
|
||||
|
||||
|
||||
if (
|
||||
!TakeSeed(
|
||||
GameSave,
|
||||
SelectedSeedId,
|
||||
PlantCount
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const PlantedAt = ActionTime;
|
||||
let PlantedCount = 0;
|
||||
|
||||
for (
|
||||
let Index = 0;
|
||||
Index < PlantCount;
|
||||
Index++
|
||||
) {
|
||||
GameSave.Garden.Plots[
|
||||
EmptyPlotIndexes[Index]
|
||||
] = {
|
||||
Plant: PlantKey,
|
||||
PlantedAt: PlantedAt,
|
||||
Rotation: GardenPlotDefaultRotation
|
||||
};
|
||||
const PlantResult =
|
||||
PlantGardenPlot(
|
||||
GameSave,
|
||||
GameSave.ActiveGardenIndex,
|
||||
EmptyPlotIndexes[Index],
|
||||
PlantKey,
|
||||
ActionTime,
|
||||
{
|
||||
ConsumeSeed: true,
|
||||
Rotation:
|
||||
GardenPlotDefaultRotation
|
||||
}
|
||||
);
|
||||
|
||||
if (!PlantResult.Planted) {
|
||||
break;
|
||||
}
|
||||
|
||||
PlantedCount++;
|
||||
}
|
||||
|
||||
if (PlantedCount <= 0) {
|
||||
EnsureSelectedSeed();
|
||||
RenderSeeds();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
SetGardenMessage(
|
||||
"Magic trowel planted " +
|
||||
PlantCount.toLocaleString() +
|
||||
PlantedCount.toLocaleString() +
|
||||
" " +
|
||||
Plant.Name +
|
||||
(PlantCount === 1
|
||||
(PlantedCount === 1
|
||||
? " seed."
|
||||
: " seeds.")
|
||||
);
|
||||
@@ -2391,38 +2397,40 @@ async function HarvestPlant(
|
||||
}
|
||||
|
||||
|
||||
const RewardAmount =
|
||||
GetPlantHarvestReward(
|
||||
const HarvestResult =
|
||||
HarvestGardenPlot(
|
||||
GameSave,
|
||||
Plant.Id
|
||||
GameSave.ActiveGardenIndex,
|
||||
PlotIndex,
|
||||
ActionTime
|
||||
);
|
||||
|
||||
if (RewardAmount === null) {
|
||||
SetGardenMessage(
|
||||
"Couldn't calculate the harvest reward for " +
|
||||
Plant.Name +
|
||||
"."
|
||||
);
|
||||
if (!HarvestResult.Harvested) {
|
||||
if (HarvestResult.Disabled) {
|
||||
SetGardenMessage(
|
||||
Plant.Name +
|
||||
" can't be harvested right now."
|
||||
);
|
||||
} else if (
|
||||
HarvestResult.RewardUnavailable
|
||||
) {
|
||||
SetGardenMessage(
|
||||
"Couldn't calculate the harvest reward for " +
|
||||
Plant.Name +
|
||||
"."
|
||||
);
|
||||
}
|
||||
|
||||
RenderGame();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
GiveReward({
|
||||
Currency: "Dew",
|
||||
Amount: RewardAmount
|
||||
});
|
||||
|
||||
GameSave.Garden.Plots[
|
||||
PlotIndex
|
||||
] = null;
|
||||
|
||||
|
||||
SetGardenMessage(
|
||||
"Harvested " +
|
||||
Plant.Name +
|
||||
" for " +
|
||||
RewardAmount +
|
||||
HarvestResult.RewardAmount +
|
||||
" Dew."
|
||||
);
|
||||
|
||||
|
||||
@@ -131,7 +131,7 @@ function CheckGardenMutations(
|
||||
);
|
||||
|
||||
|
||||
const Chance = Math.max(
|
||||
const BaseChance = Math.max(
|
||||
0,
|
||||
Math.min(
|
||||
Number(
|
||||
@@ -142,6 +142,31 @@ function CheckGardenMutations(
|
||||
)
|
||||
);
|
||||
|
||||
const Catalyst =
|
||||
typeof GetStrongestFunctionalEffectAffectingAnyPlot ===
|
||||
"function"
|
||||
? GetStrongestFunctionalEffectAffectingAnyPlot(
|
||||
SaveData,
|
||||
SaveData.ActiveGardenIndex ?? 0,
|
||||
Candidate.Cells,
|
||||
"MutationChanceBonus",
|
||||
AtTime
|
||||
)
|
||||
: null;
|
||||
|
||||
const CatalystBonus =
|
||||
typeof GetFunctionalPercentageAmount ===
|
||||
"function"
|
||||
? GetFunctionalPercentageAmount(
|
||||
Catalyst?.Effect
|
||||
)
|
||||
: 0;
|
||||
|
||||
const Chance = Math.min(
|
||||
1,
|
||||
BaseChance + CatalystBonus
|
||||
);
|
||||
|
||||
|
||||
const Succeeded =
|
||||
GetSimulationRandom(
|
||||
@@ -386,6 +411,42 @@ function CreateMutationCandidate(
|
||||
}
|
||||
|
||||
|
||||
const GardenIndex =
|
||||
Math.max(
|
||||
0,
|
||||
Number(
|
||||
SaveData.ActiveGardenIndex ?? 0
|
||||
) || 0
|
||||
);
|
||||
|
||||
if (
|
||||
typeof IsGardenPlotMutationDisabled ===
|
||||
"function" &&
|
||||
Cells.some(
|
||||
PlotIndex =>
|
||||
IsGardenPlotMutationDisabled(
|
||||
SaveData,
|
||||
GardenIndex,
|
||||
PlotIndex,
|
||||
AtTime
|
||||
)
|
||||
) &&
|
||||
!(
|
||||
typeof DoesMutationPatternInvolveDisableMutation ===
|
||||
"function" &&
|
||||
DoesMutationPatternInvolveDisableMutation(
|
||||
SaveData,
|
||||
GardenIndex,
|
||||
OriginX,
|
||||
OriginY,
|
||||
Orientation.Pattern
|
||||
)
|
||||
)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
Mutation: Mutation,
|
||||
|
||||
@@ -789,6 +850,23 @@ function ApplyMutationResult(
|
||||
: "East";
|
||||
}
|
||||
|
||||
if (
|
||||
NewPlot !== null &&
|
||||
typeof NewPlot === "object" &&
|
||||
ExistingPlot !== null &&
|
||||
typeof ExistingPlot === "object" &&
|
||||
typeof ExistingPlot.AssignedSeed ===
|
||||
"string" &&
|
||||
typeof CanFunctionalPlantUseAssignedSeed ===
|
||||
"function" &&
|
||||
CanFunctionalPlantUseAssignedSeed(
|
||||
Plants?.[NewPlot.Plant]
|
||||
)
|
||||
) {
|
||||
NewPlot.AssignedSeed =
|
||||
ExistingPlot.AssignedSeed;
|
||||
}
|
||||
|
||||
|
||||
SaveData.Garden.Plots[
|
||||
PlotIndex
|
||||
|
||||
@@ -288,6 +288,17 @@ function NormalizeGardenData(
|
||||
? Plot.Rotation
|
||||
: "East";
|
||||
|
||||
if (
|
||||
typeof Plot.AssignedSeed ===
|
||||
"string" &&
|
||||
Plot.AssignedSeed.trim().length > 0
|
||||
) {
|
||||
Plot.AssignedSeed =
|
||||
Plot.AssignedSeed.trim();
|
||||
} else {
|
||||
delete Plot.AssignedSeed;
|
||||
}
|
||||
|
||||
if (
|
||||
Plot.FunctionalCooldowns === null ||
|
||||
typeof Plot.FunctionalCooldowns !==
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
const SimulationMinimumEventInterval = 1000;
|
||||
const MaximumSimulationSteps = 250000;
|
||||
const MaximumSimulationSameTimePasses = 100;
|
||||
|
||||
|
||||
function GetSimulationTime(
|
||||
@@ -410,31 +411,47 @@ function AdvanceGameSimulation(
|
||||
) {
|
||||
Result.Steps = Step + 1;
|
||||
|
||||
const MutationResult =
|
||||
CheckAllGardenMutationsAtTime(
|
||||
SaveData,
|
||||
CurrentTime
|
||||
);
|
||||
|
||||
MergeSimulationMutationResult(
|
||||
Result,
|
||||
MutationResult
|
||||
);
|
||||
|
||||
if (
|
||||
typeof ProcessFunctionalEffectsAtTime ===
|
||||
"function"
|
||||
for (
|
||||
let SameTimePass = 0;
|
||||
SameTimePass <
|
||||
MaximumSimulationSameTimePasses;
|
||||
SameTimePass++
|
||||
) {
|
||||
const FunctionalResult =
|
||||
ProcessFunctionalEffectsAtTime(
|
||||
const MutationResult =
|
||||
CheckAllGardenMutationsAtTime(
|
||||
SaveData,
|
||||
CurrentTime
|
||||
);
|
||||
|
||||
MergeSimulationFunctionalResult(
|
||||
MergeSimulationMutationResult(
|
||||
Result,
|
||||
FunctionalResult
|
||||
MutationResult
|
||||
);
|
||||
|
||||
let FunctionalResult = null;
|
||||
|
||||
if (
|
||||
typeof ProcessFunctionalEffectsAtTime ===
|
||||
"function"
|
||||
) {
|
||||
FunctionalResult =
|
||||
ProcessFunctionalEffectsAtTime(
|
||||
SaveData,
|
||||
CurrentTime
|
||||
);
|
||||
|
||||
MergeSimulationFunctionalResult(
|
||||
Result,
|
||||
FunctionalResult
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
MutationResult.Changed !== true &&
|
||||
FunctionalResult?.Changed !== true
|
||||
) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (CurrentTime >= SafeTargetTime) {
|
||||
|
||||
Reference in new issue
Block a user