name: 'Gerudo Fortress',
short: 'GF',
type: 'Overworld',
+ throughway: 'hw.dcol',
},
{
id: 'dcol',
name: 'Desert Colossus',
short: 'DCol',
type: 'Overworld',
+ throughway: 'hw.gf',
},
],
},
name: 'Main',
short: 'Main',
type: 'Dungeon',
+ throughway: 'deku.end',
},
{
id: 'end',
name: 'End',
short: 'End',
type: 'ChildBoss',
+ throughway: 'deku.main',
},
],
},
name: 'Main',
short: 'Main',
type: 'Dungeon',
+ throughway: 'dc.end',
},
{
id: 'end',
name: 'End',
short: 'End',
type: 'ChildBoss',
+ throughway: 'dc.main',
},
],
},
name: 'Main',
short: 'Main',
type: 'Dungeon',
+ throughway: 'jabu.end',
},
{
id: 'end',
name: 'End',
short: 'End',
type: 'ChildBoss',
+ throughway: 'jabu.main',
},
],
},
short: 'Main',
spacer: true,
type: 'Dungeon',
+ throughway: 'forest.end',
},
{
id: 'end',
short: 'End',
spacer: true,
type: 'AdultBoss',
+ throughway: 'forest.main',
},
],
},
name: 'Main',
short: 'Main',
type: 'Dungeon',
+ throughway: 'fire.end',
},
{
id: 'end',
name: 'End',
short: 'End',
type: 'AdultBoss',
+ throughway: 'fire.main',
},
],
},
name: 'Main',
short: 'Main',
type: 'Dungeon',
+ throughway: 'water.end',
},
{
id: 'end',
name: 'End',
short: 'End',
type: 'AdultBoss',
+ throughway: 'water.main',
},
],
},
name: 'Main',
short: 'Main',
type: 'Dungeon',
+ throughway: 'shadow.end',
},
{
id: 'end',
name: 'End',
short: 'End',
type: 'AdultBoss',
+ throughway: 'shadow.main',
},
],
},
name: 'Main',
short: 'Main',
type: 'Dungeon',
+ throughway: 'spirit.end',
},
{
id: 'end',
name: 'End',
short: 'End',
type: 'AdultBoss',
+ throughway: 'spirit.main',
},
],
},
short: 'Main',
spacer: true,
type: 'Dungeon',
+ throughway: 'igc.end',
},
{
id: 'end',
short: 'End',
spacer: true,
type: 'SpecialBoss',
+ throughway: 'igc.main',
},
],
},
};
};
+const resolvePath = (connections, from) => {
+ if (!connections[from]) return { dst: null, via: [] };
+ const dstEntrance = getEntrance(connections[from]);
+ if (!dstEntrance || !dstEntrance.throughway) return { dst: connections[from], via: [] };
+ const path = resolvePath(connections, dstEntrance.throughway);
+ if (!path.dst) return { dst: connections[from], via: path.via };
+ return { dst: path.dst, via: [connections[from], ...path.via] };
+};
+
const vecAdd = (a, b) => ({ x: a.x + b.x, y: a.y + b.y });
const vecMul = (v, f) => ({ x: v.x * f, y: v.y * f });
return cs.join(' ');
}, [connections, entrance, isDragging]);
- const destination = React.useMemo(() => {
- return getEntrance(connections[entrance.id]) || getRoom(connections[entrance.id]);
+ const path = React.useMemo(() => {
+ return resolvePath(connections, entrance.id);
}, [connections, entrance]);
+ const destination = React.useMemo(() => {
+ return getEntrance(path.dst) || getRoom(path.dst);
+ }, [path]);
+
const onClick = React.useCallback((e) => {
onMapEntranceClick(entrance);
e.preventDefault();
e.stopPropagation();
}, [connections, entrance, setConnection]);
+ const description = React.useMemo(() => {
+ const parts = [
+ entranceShort(destination),
+ ...path.via.map((id) => `via ${entranceShort(getEntrance(id))}`),
+ `@ ${entranceShort(getEntrance(entrance.id))}`,
+ ];
+ return parts.join(' ');
+ }, [destination, entrance, path]);
+
if (destination) {
return <rect
x={entrance.pos.x - 3}
onClick={onClick}
onContextMenu={onContext}
>
- <title>{destination.name} @ {entrance.name}</title>
+ <title>{description}</title>
</rect>;
}
}),
};
-const MapConnector = ({ from, to }) => {
+const MapConnector = ({ from, to, via }) => {
+ const className = React.useMemo(() => {
+ const cs = ['connector'];
+ if (via.length) cs.push('is-via');
+ return cs.join(' ');
+ }, [via]);
return <line
- className="connector"
+ className={className}
x1={from.pos.x}
y1={from.pos.y}
x2={to.pos.x}
x: PropTypes.number,
y: PropTypes.number,
})
- })
+ }),
+ via: PropTypes.arrayOf(PropTypes.string),
};
const MapAnnotation = ({ annotation }) => {
const connectors = React.useMemo(() => {
const cs = [];
- Object.entries(connections).forEach(([from, to]) => {
+ Object.entries(connections).forEach(([from]) => {
const fromEntrance = getEntrance(from);
if (!fromEntrance) return;
- if (from > to && !fromEntrance.oneway) return;
+ const path = resolvePath(connections, from);
+ if (!path.dst) return;
+ if (from > path.dst && !fromEntrance.oneway) return;
const fromMap = getMapEntrance(from);
if (!fromMap) return;
- const toMap = getMapEntrance(to);
+ const toMap = getMapEntrance(path.dst);
if (!toMap) return;
cs.push({
from: fromMap,
to: toMap,
+ via: path.via,
});
});
return cs;
key={`${c.from.id}-${c.to.id}`}
from={c.from}
to={c.to}
+ via={c.via}
/>
)}
</g>