From 30d60a43e80fb93c5cc372bbb580cd6cd30edfd4 Mon Sep 17 00:00:00 2001 From: cpojer Date: Wed, 30 Oct 2024 14:16:13 +0900 Subject: [PATCH] Fix an issue where the order of objectives affected whether an optional objective was triggered or not. GitOrigin-RevId: 3f1c3e93ee329348d2f2239013e15d6302eb9a6f --- apollo/Objective.tsx | 1 - athena/Objectives.tsx | 10 ++- hera/editor/panels/EffectsPanel.tsx | 87 +++++++++++------------ hera/editor/panels/ObjectivePanel.tsx | 69 +++++++++--------- hera/editor/selectors/EffectSelector.tsx | 9 ++- tests/__tests__/CustomObjectives.test.tsx | 66 ++++++++++++++++- 6 files changed, 155 insertions(+), 87 deletions(-) diff --git a/apollo/Objective.tsx b/apollo/Objective.tsx index e1d08e38..30165177 100644 --- a/apollo/Objective.tsx +++ b/apollo/Objective.tsx @@ -136,7 +136,6 @@ export function applyObjectives( optionalObjective = null; reevaluate = true; - map = gameState.at(-1)![1]; const [objectiveId, objective] = checkObjectives(previousMap, map, lastActionResponse) || []; diff --git a/athena/Objectives.tsx b/athena/Objectives.tsx index 5166d0ec..330c9b73 100644 --- a/athena/Objectives.tsx +++ b/athena/Objectives.tsx @@ -627,8 +627,11 @@ export function decodeObjective(objective: PlainObjective): Objective { } } +const sortObjective = ([, objective]: [number, Objective]) => + objective.type === Criteria.Default ? -1 : objective.optional ? 0 : 1; + export function encodeObjectives(objectives: Objectives): PlainObjectives { - return sortBy([...objectives], ([id]) => id).map(([id, objective]) => [ + return sortBy([...objectives], sortObjective).map(([id, objective]) => [ id, encodeObjective(objective), ]); @@ -636,7 +639,10 @@ export function encodeObjectives(objectives: Objectives): PlainObjectives { export function decodeObjectives(objectives: PlainObjectives) { return ImmutableMap( - objectives.map(([id, objective]) => [id, decodeObjective(objective)]), + sortBy( + objectives.map(([id, objective]) => [id, decodeObjective(objective)]), + sortObjective, + ), ); } diff --git a/hera/editor/panels/EffectsPanel.tsx b/hera/editor/panels/EffectsPanel.tsx index 2db1bb2b..51700c70 100644 --- a/hera/editor/panels/EffectsPanel.tsx +++ b/hera/editor/panels/EffectsPanel.tsx @@ -4,6 +4,7 @@ import { Crystal } from '@deities/athena/invasions/Crystal.tsx'; import MapData from '@deities/athena/MapData.tsx'; import { Criteria } from '@deities/athena/Objectives.tsx'; import isPresent from '@deities/hephaestus/isPresent.tsx'; +import sortBy from '@deities/hephaestus/sortBy.tsx'; import UnknownTypeError from '@deities/hephaestus/UnknownTypeError.tsx'; import Box from '@deities/ui/Box.tsx'; import Button from '@deities/ui/Button.tsx'; @@ -92,59 +93,55 @@ export default function EffectsPanel({ }, [effects]); const possibleEffects = useMemo( - () => - [ - ...(['win', 'lose', 'draw'] as const).map((id) => - conditionsByID?.has(id) ? null : ( + () => [ + ...(['win', 'lose', 'draw'] as const).map((id) => + conditionsByID?.has(id) ? null : ( + { + setShowNewEffects(false); + setEditorState(selectObjectiveEffect(editor, id)); + }} + > + + + ), + ), + sortBy([...objectives], ([id]) => id) + .map(([id, condition]) => { + if (condition.type === Criteria.Default || conditionsByID?.has(id)) { + return null; + } + + const type = condition.optional ? 'OptionalObjective' : 'GameEnd'; + return ( { setShowNewEffects(false); - setEditorState(selectObjectiveEffect(editor, id)); + setEditorState(selectObjectiveEffect(editor, id, condition)); }} > - - - ), - ), - ...objectives - .map((condition, id) => { - if ( - condition.type === Criteria.Default || - conditionsByID?.has(id) - ) { - return null; - } - - const type = condition.optional ? 'OptionalObjective' : 'GameEnd'; - return ( - { - setShowNewEffects(false); - setEditorState(selectObjectiveEffect(editor, id, condition)); + - - - ); - }) - .values(), - ].filter(isPresent), + objectives={objectives} + trigger={type} + /> + + ); + }) + .filter(isPresent), + ], [conditionsByID, editor, setEditorState, objectives], ); diff --git a/hera/editor/panels/ObjectivePanel.tsx b/hera/editor/panels/ObjectivePanel.tsx index 79d353c3..6e2db288 100644 --- a/hera/editor/panels/ObjectivePanel.tsx +++ b/hera/editor/panels/ObjectivePanel.tsx @@ -12,6 +12,7 @@ import { validateObjective, } from '@deities/athena/Objectives.tsx'; import groupBy from '@deities/hephaestus/groupBy.tsx'; +import sortBy from '@deities/hephaestus/sortBy.tsx'; import levelUsesObjective from '@deities/hermes/levelUsesObjective.tsx'; import toLevelMap from '@deities/hermes/toLevelMap.tsx'; import { ClientLevelID } from '@deities/hermes/Types.tsx'; @@ -251,43 +252,37 @@ export default function ObjectivePanel({ return ( - {[ - ...objectives - .map((objective, id) => ( - level && levelUsesObjective(id, level), - ) || null - } - canDelete={ - objectives.size > 1 || objective.type !== Criteria.Default - } - canEditPerformance={canEditPerformance} - hasContentRestrictions={hasContentRestrictions} - id={id} - isAdmin={isAdmin} - key={id} - map={mapWithActivePlayers} - objective={objective} - onChange={(objective) => updateObjective(id, objective)} - selectEffect={() => - setEditorState(selectObjectiveEffect(editor, id, objective)) - } - selectLocation={() => { - if (objectiveHasVectors(objective)) { - setEditorState({ - objective: { objective, objectiveId: id }, - }); - } - }} - tags={tags} - user={user} - validate={validate} - /> - )) - .values(), - ]} + {sortBy([...objectives], ([id]) => id).map(([id, objective]) => ( + level && levelUsesObjective(id, level), + ) || null + } + canDelete={objectives.size > 1 || objective.type !== Criteria.Default} + canEditPerformance={canEditPerformance} + hasContentRestrictions={hasContentRestrictions} + id={id} + isAdmin={isAdmin} + key={id} + map={mapWithActivePlayers} + objective={objective} + onChange={(objective) => updateObjective(id, objective)} + selectEffect={() => + setEditorState(selectObjectiveEffect(editor, id, objective)) + } + selectLocation={() => { + if (objectiveHasVectors(objective)) { + setEditorState({ + objective: { objective, objectiveId: id }, + }); + } + }} + tags={tags} + user={user} + validate={validate} + /> + ))}