Skip to content

Commit f273fa2

Browse files
cpojerconnorlindsey
andcommitted
Make playground maps shareable by persisting data to the URL (#18) (#32)
Co-authored-by: Connor Lindsey <[email protected]> GitOrigin-RevId: 80499df94c87243652a05c36fa5c43bd079fae6b
1 parent e893189 commit f273fa2

13 files changed

+108
-498
lines changed

.eslintrc.cjs

-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ module.exports = {
4747
],
4848
plugins: ['@deities'],
4949
rules: {
50-
'@typescript-eslint/array-type': [2, { default: 'generic' }],
5150
'@typescript-eslint/no-restricted-imports': [
5251
2,
5352
{

apollo/lib/gameHasEnded.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { ActionResponse } from '../ActionResponse.tsx';
22

33
export default function gameHasEnded(
4-
gameState: ReadonlyArray<readonly [ActionResponse, ...Array<unknown>]> | null,
4+
gameState: ReadonlyArray<readonly [ActionResponse, ...unknown[]]> | null,
55
) {
66
return !!(
77
gameState?.length &&

art/Sprites.tsx

+1-4
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,7 @@ type Resource = Readonly<[name: string, url: string]>;
1212
type Resources = ReadonlyArray<Resource>;
1313
type PaletteSwapFn = typeof paletteSwap;
1414
type PaletteSwapParameters = Parameters<PaletteSwapFn>;
15-
type DropFirstInTuple<T extends Array<unknown>> = T extends [
16-
unknown,
17-
...infer Rest,
18-
]
15+
type DropFirstInTuple<T extends unknown[]> = T extends [unknown, ...infer Rest]
1916
? Rest
2017
: never;
2118
type MaybePaletteSwapParameters = [

hera/GameMap.tsx

+5-19
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ import { resetBehavior, setBaseClass } from './behavior/Behavior.tsx';
6262
import MenuBehavior from './behavior/Menu.tsx';
6363
import NullBehavior from './behavior/NullBehavior.tsx';
6464
import Cursor from './Cursor.tsx';
65-
import MapEditorExtraCursors from './editor/MapEditorMirrorCursors.tsx';
6665
import { EditorState } from './editor/Types.tsx';
6766
import addEndTurnAnimations from './lib/addEndTurnAnimations.tsx';
6867
import animateSupply from './lib/animateSupply.tsx';
@@ -1722,25 +1721,12 @@ export default class GameMap extends Component<Props, State> {
17221721
{(propsShowCursor || propsShowCursor == null) &&
17231722
showCursor &&
17241723
!replayState.isReplaying && (
1725-
<>
1726-
<Cursor
1727-
position={position}
1728-
size={tileSize}
1729-
zIndex={zIndex - 4}
1730-
/>
1731-
{editor?.mode === 'design' && (
1732-
<MapEditorExtraCursors
1733-
color="red"
1734-
drawingMode={editor?.drawingMode}
1735-
mapSize={map.size}
1736-
origin={position}
1737-
size={tileSize}
1738-
zIndex={zIndex}
1739-
/>
1740-
)}
1741-
</>
1724+
<Cursor
1725+
position={position}
1726+
size={tileSize}
1727+
zIndex={zIndex - 4}
1728+
/>
17421729
)}
1743-
17441730
<MapAnimations
17451731
actions={this._actions}
17461732
animationComplete={this._animationComplete}

hera/editor/MapEditor.tsx

-1
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,6 @@ const getEditorBaseState = (
134134
effects = new Map([...effects, ['Start', startScenario]]);
135135
}
136136
return {
137-
drawingMode: 'regular',
138137
effects,
139138
isDrawing: false,
140139
isErasing: false,

hera/editor/MapEditorMirrorCursors.tsx

-28
This file was deleted.

hera/editor/Types.tsx

-7
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,9 @@ type UndoKey =
3838

3939
export type UndoEntry = readonly [UndoKey, MapData];
4040
export type UndoStack = ReadonlyArray<UndoEntry>;
41-
export type DrawingMode =
42-
| 'regular'
43-
| 'horizontal'
44-
| 'vertical'
45-
| 'horizontal-vertical'
46-
| 'diagonal';
4741

4842
export type EditorState = Readonly<{
4943
condition?: readonly [WinConditionsWithVectors, number];
50-
drawingMode: DrawingMode;
5144
effects: Effects;
5245
isDrawing: boolean;
5346
isErasing: boolean;

hera/editor/behavior/DesignBehavior.tsx

+12-57
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import verifyTiles from '@deities/athena/lib/verifyTiles.tsx';
2323
import Building from '@deities/athena/map/Building.tsx';
2424
import { getDecoratorLimit } from '@deities/athena/map/Configuration.tsx';
2525
import Entity from '@deities/athena/map/Entity.tsx';
26-
import { PlayerID, PlayerIDs } from '@deities/athena/map/Player.tsx';
2726
import Unit from '@deities/athena/map/Unit.tsx';
2827
import Vector from '@deities/athena/map/Vector.tsx';
2928
import MapData from '@deities/athena/MapData.tsx';
@@ -49,7 +48,6 @@ import {
4948
} from '../../Types.tsx';
5049
import FlashFlyout from '../../ui/FlashFlyout.tsx';
5150
import { FlyoutItem } from '../../ui/Flyout.tsx';
52-
import getSymmetricPositions from '../lib/getSymmetricPositions.ts';
5351
import updateUndoStack from '../lib/updateUndoStack.tsx';
5452
import { EditorState } from '../Types.tsx';
5553

@@ -164,11 +162,7 @@ export default class DesignBehavior {
164162
subVector?: Vector,
165163
): StateLike | null {
166164
if (editor?.isDrawing && editor.selected) {
167-
const vectors = [
168-
vector,
169-
...getSymmetricPositions(vector, editor.drawingMode, state.map.size),
170-
];
171-
return this.draw(vectors, state, actions, editor);
165+
return this.put(vector, state, actions, editor);
172166
}
173167

174168
const { animations, map } = state;
@@ -234,46 +228,11 @@ export default class DesignBehavior {
234228
return null;
235229
}
236230

237-
private draw(
238-
vectors: Array<Vector>,
239-
state: State,
240-
actions: Actions,
241-
editor: EditorState,
242-
): StateLike | null {
243-
let newState: StateLike | null = null;
244-
const players = Array.from(
245-
new Set([...state.map.active, ...PlayerIDs.filter((id) => id !== 0)]),
246-
).slice(0, vectors.length);
247-
vectors.forEach((vector, index) => {
248-
const currentPlayerIndex = players.indexOf(
249-
state.map.getCurrentPlayer().id,
250-
);
251-
const playerId =
252-
players[
253-
((currentPlayerIndex >= 0 ? currentPlayerIndex : 0) + index) %
254-
players.length
255-
];
256-
257-
newState = {
258-
...newState,
259-
...this.put(
260-
vector,
261-
{ ...state, ...newState },
262-
actions,
263-
editor,
264-
playerId,
265-
),
266-
};
267-
});
268-
return newState;
269-
}
270-
271231
private put(
272232
vector: Vector,
273233
state: State,
274234
actions: Actions,
275235
editor: EditorState,
276-
playerId: PlayerID,
277236
): StateLike | null {
278237
if (shouldPlaceDecorator(editor)) {
279238
return null;
@@ -340,14 +299,7 @@ export default class DesignBehavior {
340299
);
341300
} else if (selected.unit) {
342301
this.previous = null;
343-
return this.putUnit(
344-
selected.unit,
345-
vector,
346-
state,
347-
actions,
348-
editor,
349-
playerId,
350-
);
302+
return this.putUnit(selected.unit, vector, state, actions, editor);
351303
} else if (selected.building) {
352304
this.previous = null;
353305
return this.putBuilding(
@@ -356,7 +308,6 @@ export default class DesignBehavior {
356308
state,
357309
actions,
358310
editor,
359-
playerId,
360311
);
361312
}
362313
return null;
@@ -552,7 +503,6 @@ export default class DesignBehavior {
552503
state: State,
553504
actions: Actions,
554505
editor: EditorState,
555-
playerId: PlayerID,
556506
): StateLike | null {
557507
const { map } = state;
558508
const { units } = map;
@@ -571,7 +521,12 @@ export default class DesignBehavior {
571521
...spawn(
572522
actions,
573523
state,
574-
[[vector, unit.removeLeader().setPlayer(playerId)]],
524+
[
525+
[
526+
vector,
527+
unit.removeLeader().setPlayer(map.getCurrentPlayer().id),
528+
],
529+
],
575530
null,
576531
({ map }) => {
577532
updateUndoStack(actions, editor, [
@@ -596,7 +551,6 @@ export default class DesignBehavior {
596551
state: State,
597552
actions: Actions,
598553
editor: EditorState,
599-
playerId: PlayerID,
600554
): StateLike | null {
601555
const { animations, map } = state;
602556
const { buildings, units } = map;
@@ -614,13 +568,14 @@ export default class DesignBehavior {
614568
const config = map.config.copy({
615569
blocklistedBuildings: new Set(),
616570
});
571+
const player = map.getCurrentPlayer();
617572
const isAlwaysNeutral = building.info.isStructure();
618573

619574
const tryToPlaceBuilding = (state: State): StateLike | null => {
620575
let { map } = state;
621576
map = map.copy({
622577
active: getActivePlayers(map),
623-
buildings: map.buildings.set(vector, building.setPlayer(playerId)),
578+
buildings: map.buildings.set(vector, building.setPlayer(player.id)),
624579
});
625580

626581
const { editorPlaceOn, placeOn } = building.info.configuration;
@@ -663,7 +618,7 @@ export default class DesignBehavior {
663618
return canBuild(
664619
getTemporaryMapForBuilding(temporaryMap, vector, building),
665620
building.info,
666-
isAlwaysNeutral ? 0 : playerId,
621+
isAlwaysNeutral ? 0 : player,
667622
vector,
668623
true,
669624
) && !(building.info.isHQ() && map.currentPlayer === 0)
@@ -681,7 +636,7 @@ export default class DesignBehavior {
681636
return newState;
682637
},
683638
type: 'createBuilding',
684-
variant: isAlwaysNeutral ? 0 : playerId,
639+
variant: isAlwaysNeutral ? 0 : player.id,
685640
}),
686641
map: state.map.copy({ buildings: buildings.delete(vector) }),
687642
}

0 commit comments

Comments
 (0)