mirror of
https://git.srhtnin.garden/sarah/srhtnin.github.io.git
synced 2026-10-13 18:38:11 +02:00
Added effects engine.
This commit is contained in:
1 parent
132aba0b9a
commit
9de8af0d2b
9 files changed
+1684
-12
No files matched your search
@@ -211,6 +211,7 @@ $PageSection = "Admin";
|
|||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
<script src="/Scripts/Garden/FunctionalEffects.js"></script>
|
||||||
<script src="/Scripts/Garden/Save.js"></script>
|
<script src="/Scripts/Garden/Save.js"></script>
|
||||||
<script src="/Scripts/Garden/AdminValidation.js"></script>
|
<script src="/Scripts/Garden/AdminValidation.js"></script>
|
||||||
<script src="/Scripts/Garden/AdminMassPlantEditor.js"></script>
|
<script src="/Scripts/Garden/AdminMassPlantEditor.js"></script>
|
||||||
|
|||||||
@@ -443,6 +443,7 @@ $PageSection = "Admin";
|
|||||||
<script src="/Scripts/Garden/PlantImages.js"></script>
|
<script src="/Scripts/Garden/PlantImages.js"></script>
|
||||||
<script src="/Scripts/Garden/Plants.js"></script>
|
<script src="/Scripts/Garden/Plants.js"></script>
|
||||||
<script src="/Scripts/Garden/Mutations.js"></script>
|
<script src="/Scripts/Garden/Mutations.js"></script>
|
||||||
|
<script src="/Scripts/Garden/FunctionalEffects.js"></script>
|
||||||
<script src="/Scripts/Garden/Save.js"></script>
|
<script src="/Scripts/Garden/Save.js"></script>
|
||||||
<script src="/Scripts/Garden/Economy.js"></script>
|
<script src="/Scripts/Garden/Economy.js"></script>
|
||||||
<script src="/Scripts/Garden/AdminValidation.js"></script>
|
<script src="/Scripts/Garden/AdminValidation.js"></script>
|
||||||
|
|||||||
@@ -290,6 +290,7 @@ $PageSection = "Garden";
|
|||||||
<script src="/Scripts/Garden/PlantImages.js"></script>
|
<script src="/Scripts/Garden/PlantImages.js"></script>
|
||||||
<script src="/Scripts/Garden/Plants.js"></script>
|
<script src="/Scripts/Garden/Plants.js"></script>
|
||||||
<script src="/Scripts/Garden/Mutations.js"></script>
|
<script src="/Scripts/Garden/Mutations.js"></script>
|
||||||
|
<script src="/Scripts/Garden/FunctionalEffects.js"></script>
|
||||||
<script src="/Scripts/Garden/Save.js"></script>
|
<script src="/Scripts/Garden/Save.js"></script>
|
||||||
<script src="/Scripts/Garden/Content.js"></script>
|
<script src="/Scripts/Garden/Content.js"></script>
|
||||||
<script src="/Scripts/Garden/Economy.js"></script>
|
<script src="/Scripts/Garden/Economy.js"></script>
|
||||||
|
|||||||
@@ -58,6 +58,153 @@ function ValidateAdminKey(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function ValidateAdminFunctionalEffects(
|
||||||
|
Effects
|
||||||
|
) {
|
||||||
|
const Functional =
|
||||||
|
Effects?.Functional;
|
||||||
|
|
||||||
|
if (Functional === undefined) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Array.isArray(Functional)) {
|
||||||
|
throw new Error(
|
||||||
|
"Effects.Functional must be an array."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Functional.length > 32) {
|
||||||
|
throw new Error(
|
||||||
|
"Effects.Functional cannot contain more than 32 effects."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const SeenKeys = new Set();
|
||||||
|
|
||||||
|
for (
|
||||||
|
let EffectIndex = 0;
|
||||||
|
EffectIndex < Functional.length;
|
||||||
|
EffectIndex++
|
||||||
|
) {
|
||||||
|
const Effect =
|
||||||
|
Functional[EffectIndex];
|
||||||
|
|
||||||
|
if (!IsAdminPlainObject(Effect)) {
|
||||||
|
throw new Error(
|
||||||
|
"Functional effect " +
|
||||||
|
(EffectIndex + 1) +
|
||||||
|
" must be an object."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ValidateAdminKey(
|
||||||
|
String(
|
||||||
|
Effect.Type ?? ""
|
||||||
|
).trim(),
|
||||||
|
"Functional effect type"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (Effect.Key !== undefined) {
|
||||||
|
const EffectKey = String(
|
||||||
|
Effect.Key ?? ""
|
||||||
|
).trim();
|
||||||
|
|
||||||
|
ValidateAdminKey(
|
||||||
|
EffectKey,
|
||||||
|
"Functional effect key"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (SeenKeys.has(EffectKey)) {
|
||||||
|
throw new Error(
|
||||||
|
"Functional effect keys must be unique within a plant."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
SeenKeys.add(EffectKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const Field of [
|
||||||
|
"Area",
|
||||||
|
"Source",
|
||||||
|
"Target"
|
||||||
|
]) {
|
||||||
|
if (Effect[Field] === undefined) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Area = String(
|
||||||
|
Effect[Field]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
typeof FunctionalEffectAreas !==
|
||||||
|
"undefined" &&
|
||||||
|
!FunctionalEffectAreas.includes(
|
||||||
|
Area
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
throw new Error(
|
||||||
|
"Functional effect " +
|
||||||
|
Field.toLowerCase() +
|
||||||
|
" must be Front, Behind, Cardinal, Adjacent or Farm."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Effect.Cooldown !== undefined) {
|
||||||
|
ValidateAdminInteger(
|
||||||
|
Number(
|
||||||
|
Effect.Cooldown
|
||||||
|
),
|
||||||
|
"Functional effect cooldown",
|
||||||
|
typeof FunctionalEffectMinimumCooldown !==
|
||||||
|
"undefined"
|
||||||
|
? FunctionalEffectMinimumCooldown
|
||||||
|
: 1000
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Effect.Amount !== undefined) {
|
||||||
|
const Amount = Number(
|
||||||
|
Effect.Amount
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!Number.isFinite(Amount)) {
|
||||||
|
throw new Error(
|
||||||
|
"Functional effect amount must be a number."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
Effect.RequireMature !== undefined &&
|
||||||
|
typeof Effect.RequireMature !==
|
||||||
|
"boolean"
|
||||||
|
) {
|
||||||
|
throw new Error(
|
||||||
|
"Functional effect RequireMature must be On or Off."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
typeof IsFunctionalEffectActive ===
|
||||||
|
"function" &&
|
||||||
|
IsFunctionalEffectActive(
|
||||||
|
Effect
|
||||||
|
) &&
|
||||||
|
Effect.Cooldown === undefined
|
||||||
|
) {
|
||||||
|
throw new Error(
|
||||||
|
"Active functional effects need a cooldown."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function ValidateAdminPlant(
|
function ValidateAdminPlant(
|
||||||
Plant,
|
Plant,
|
||||||
Catalogue,
|
Catalogue,
|
||||||
@@ -205,6 +352,10 @@ function ValidateAdminPlant(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ValidateAdminFunctionalEffects(
|
||||||
|
Plant.Effects
|
||||||
|
);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
Plant.DirectionalSprites !== undefined &&
|
Plant.DirectionalSprites !== undefined &&
|
||||||
typeof Plant.DirectionalSprites !== "boolean"
|
typeof Plant.DirectionalSprites !== "boolean"
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
@@ -1669,11 +1669,35 @@ function CreatePlotElement(
|
|||||||
Plant
|
Plant
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const CooldownState =
|
||||||
|
Progress >= 1 &&
|
||||||
|
typeof GetFunctionalPlantCooldownDisplayState ===
|
||||||
|
"function"
|
||||||
|
? GetFunctionalPlantCooldownDisplayState(
|
||||||
|
Plot,
|
||||||
|
Plant,
|
||||||
|
GetSimulationTime(
|
||||||
|
GameSave
|
||||||
|
)
|
||||||
|
)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
const BorderProgress =
|
||||||
|
CooldownState === null
|
||||||
|
? Progress
|
||||||
|
: CooldownState.Progress;
|
||||||
|
|
||||||
Tile.style.setProperty(
|
Tile.style.setProperty(
|
||||||
"--GrowthProgress",
|
"--GrowthProgress",
|
||||||
`${Progress * 100}%`
|
`${BorderProgress * 100}%`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (CooldownState !== null) {
|
||||||
|
Tile.classList.add(
|
||||||
|
"GardenPlotFunctionalCooldown"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const ImagePath =
|
const ImagePath =
|
||||||
GetPlantImage(
|
GetPlantImage(
|
||||||
@@ -2004,6 +2028,31 @@ function CreateGardenPlotTimer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
Progress >= 1 &&
|
||||||
|
typeof GetFunctionalPlantCooldownDisplayState ===
|
||||||
|
"function"
|
||||||
|
) {
|
||||||
|
const CooldownState =
|
||||||
|
GetFunctionalPlantCooldownDisplayState(
|
||||||
|
Plot,
|
||||||
|
Plant,
|
||||||
|
GetSimulationTime(
|
||||||
|
GameSave
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (CooldownState !== null) {
|
||||||
|
Timer.textContent =
|
||||||
|
FormatGardenRemainingTime(
|
||||||
|
CooldownState.Remaining
|
||||||
|
);
|
||||||
|
|
||||||
|
return Timer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (Progress >= 1) {
|
if (Progress >= 1) {
|
||||||
Timer.textContent =
|
Timer.textContent =
|
||||||
"Ready";
|
"Ready";
|
||||||
|
|||||||
+72
-1
@@ -15,7 +15,7 @@ const MaximumGardenNameLength = 32;
|
|||||||
const StartingGardenWidth = 4;
|
const StartingGardenWidth = 4;
|
||||||
const StartingGardenHeight = 4;
|
const StartingGardenHeight = 4;
|
||||||
|
|
||||||
const CurrentSaveVersion = 7;
|
const CurrentSaveVersion = 8;
|
||||||
|
|
||||||
|
|
||||||
function CreateSimulationRandomState() {
|
function CreateSimulationRandomState() {
|
||||||
@@ -288,6 +288,77 @@ function NormalizeGardenData(
|
|||||||
? Plot.Rotation
|
? Plot.Rotation
|
||||||
: "East";
|
: "East";
|
||||||
|
|
||||||
|
if (
|
||||||
|
Plot.FunctionalCooldowns === null ||
|
||||||
|
typeof Plot.FunctionalCooldowns !==
|
||||||
|
"object" ||
|
||||||
|
Array.isArray(
|
||||||
|
Plot.FunctionalCooldowns
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Plot.FunctionalCooldowns = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
for (
|
||||||
|
const [CooldownKey, CooldownValue]
|
||||||
|
of Object.entries(
|
||||||
|
Plot.FunctionalCooldowns
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
let StartedAt = 0;
|
||||||
|
let Until = 0;
|
||||||
|
|
||||||
|
if (
|
||||||
|
CooldownValue !== null &&
|
||||||
|
typeof CooldownValue ===
|
||||||
|
"object" &&
|
||||||
|
!Array.isArray(
|
||||||
|
CooldownValue
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
StartedAt = Math.max(
|
||||||
|
0,
|
||||||
|
Math.floor(
|
||||||
|
Number(
|
||||||
|
CooldownValue.StartedAt ?? 0
|
||||||
|
) || 0
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
Until = Math.max(
|
||||||
|
StartedAt,
|
||||||
|
Math.floor(
|
||||||
|
Number(
|
||||||
|
CooldownValue.Until ?? 0
|
||||||
|
) || 0
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
Until = Math.max(
|
||||||
|
0,
|
||||||
|
Math.floor(
|
||||||
|
Number(
|
||||||
|
CooldownValue
|
||||||
|
) || 0
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Until <= 0) {
|
||||||
|
delete Plot.FunctionalCooldowns[
|
||||||
|
CooldownKey
|
||||||
|
];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Plot.FunctionalCooldowns[
|
||||||
|
CooldownKey
|
||||||
|
] = {
|
||||||
|
StartedAt,
|
||||||
|
Until
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
delete Plot.VisualVariant;
|
delete Plot.VisualVariant;
|
||||||
delete Plot.AddedTags;
|
delete Plot.AddedTags;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,6 +91,28 @@ function MergeSimulationMutationResult(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function MergeSimulationFunctionalResult(
|
||||||
|
Target,
|
||||||
|
Source
|
||||||
|
) {
|
||||||
|
if (Source === null || Source === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Target.FunctionalAttempted =
|
||||||
|
Target.FunctionalAttempted ||
|
||||||
|
Source.Attempted === true;
|
||||||
|
|
||||||
|
Target.Changed =
|
||||||
|
Target.Changed ||
|
||||||
|
Source.Changed === true;
|
||||||
|
|
||||||
|
Target.FunctionalActivations.push(
|
||||||
|
...(Source.Activations ?? [])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function CreateSimulationResult(
|
function CreateSimulationResult(
|
||||||
StartTime,
|
StartTime,
|
||||||
TargetTime
|
TargetTime
|
||||||
@@ -100,6 +122,7 @@ function CreateSimulationResult(
|
|||||||
TargetTime,
|
TargetTime,
|
||||||
Advanced: TargetTime > StartTime,
|
Advanced: TargetTime > StartTime,
|
||||||
Attempted: false,
|
Attempted: false,
|
||||||
|
FunctionalAttempted: false,
|
||||||
Changed: false,
|
Changed: false,
|
||||||
Dirty: false,
|
Dirty: false,
|
||||||
CaughtUp: StartTime >= TargetTime,
|
CaughtUp: StartTime >= TargetTime,
|
||||||
@@ -107,7 +130,8 @@ function CreateSimulationResult(
|
|||||||
Steps: 0,
|
Steps: 0,
|
||||||
SuccessfulMutations: [],
|
SuccessfulMutations: [],
|
||||||
NewlyDiscoveredMutations: [],
|
NewlyDiscoveredMutations: [],
|
||||||
NewlyDiscoveredPlants: []
|
NewlyDiscoveredPlants: [],
|
||||||
|
FunctionalActivations: []
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,6 +159,7 @@ function FinalizeSimulationResult(
|
|||||||
|
|
||||||
Result.Dirty =
|
Result.Dirty =
|
||||||
Result.Attempted ||
|
Result.Attempted ||
|
||||||
|
Result.FunctionalAttempted ||
|
||||||
Result.Changed;
|
Result.Changed;
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
@@ -324,18 +349,27 @@ function GetNextSimulationEventTime(
|
|||||||
TargetTime
|
TargetTime
|
||||||
);
|
);
|
||||||
|
|
||||||
if (MaturityTime === null) {
|
const FunctionalTime =
|
||||||
return MutationTime;
|
typeof GetNextFunctionalEffectEventTime ===
|
||||||
}
|
"function"
|
||||||
|
? GetNextFunctionalEffectEventTime(
|
||||||
|
SaveData,
|
||||||
|
CurrentTime,
|
||||||
|
TargetTime
|
||||||
|
)
|
||||||
|
: null;
|
||||||
|
|
||||||
if (MutationTime === null) {
|
const EventTimes = [
|
||||||
return MaturityTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Math.min(
|
|
||||||
MaturityTime,
|
MaturityTime,
|
||||||
MutationTime
|
MutationTime,
|
||||||
|
FunctionalTime
|
||||||
|
].filter(
|
||||||
|
Time => Time !== null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return EventTimes.length === 0
|
||||||
|
? null
|
||||||
|
: Math.min(...EventTimes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -387,6 +421,22 @@ function AdvanceGameSimulation(
|
|||||||
MutationResult
|
MutationResult
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
typeof ProcessFunctionalEffectsAtTime ===
|
||||||
|
"function"
|
||||||
|
) {
|
||||||
|
const FunctionalResult =
|
||||||
|
ProcessFunctionalEffectsAtTime(
|
||||||
|
SaveData,
|
||||||
|
CurrentTime
|
||||||
|
);
|
||||||
|
|
||||||
|
MergeSimulationFunctionalResult(
|
||||||
|
Result,
|
||||||
|
FunctionalResult
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (CurrentTime >= SafeTargetTime) {
|
if (CurrentTime >= SafeTargetTime) {
|
||||||
Result.CaughtUp = true;
|
Result.CaughtUp = true;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -754,6 +754,15 @@ input, button, textarea, select {
|
|||||||
--GrowthColour: var(--Yellow);
|
--GrowthColour: var(--Yellow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.GardenPlotFunctionalCooldown,
|
||||||
|
.GardenPlotFunctionalCooldown:hover {
|
||||||
|
--GrowthColour: var(--Blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
.GardenPlotFunctionalCooldown .GardenPlotTimer {
|
||||||
|
color: var(--Blue);
|
||||||
|
}
|
||||||
|
|
||||||
.SeedList {
|
.SeedList {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
|
|||||||
Reference in new issue
Block a user