Skip to content

Commit

Permalink
Extract equipment complexity to its own hook
Browse files Browse the repository at this point in the history
  • Loading branch information
tiliv committed Apr 25, 2024
1 parent b8dd08c commit 71631e4
Show file tree
Hide file tree
Showing 2 changed files with 208 additions and 187 deletions.
200 changes: 13 additions & 187 deletions src/components/DisplayStats.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,14 @@ import { useEffect, useState } from 'react';

import ScreenStack from './ScreenStack';
import useStats from '../hooks/useStats';
import useEquipment from '../hooks/useEquipment';
import useInventory from '../hooks/useInventory';
import { keyAlias, minifyNumbers, bufferizeList } from '../utils';
import useEquipmentBuffers from '../hooks/useEquipmentBuffers';
import { keyAlias, minifyNumbers } from '../utils';

const TABS = ['Equip', 'Magic', 'Log']

const ABBREVIATIONS = {
weapon: 'Wp',
shield: 'Sh',
head: 'Hd',
body: 'Bd',
arms: 'Ar',
waist: 'Ws',
legs: 'Lg',
feet: 'Ft',
};
const EQUIPMENT_ORDER = [
'weapon', 'body', 'legs', 'feet',
'head', 'arms', 'shield', 'waist',
];

function farColumns(info1, info2) {
function label(data) {
const { kind='?', icon, stats: { A=0, D=0 }={} } = data;
return `${ABBREVIATIONS[kind]} ${minifyNumbers(A || D)}`;
}
return (
label(info1 || {}).split('')
.concat(
['', '', '', '', '', '', ''],
label(info2 || {}).split('')
)
);
}

export default function DisplayStats({
width, height, world,
width, height, magnification=1,
keyMap={
up: 'w',
down: 's',
Expand All @@ -47,20 +18,9 @@ export default function DisplayStats({
select: ' ',
cancel: 'Escape',
},
magnification=1,
}) {
const { inventory, equipment, setEquipment } = useInventory();
const { name, hp, maxHp, gold, strength, defense, speed } = useStats();
const { buffers, ...slots } = useEquipment(equipment);
const [equippedBuffer, setEquippedBuffer] = useState(null);

const [menuChoice, setMenuChoice] = useState(0);
const [subMenuChoice, setSubMenuChoice] = useState(null);
const [subMenuChoiceBuffer, setSubMenuChoiceBuffer] = useState([]);
const [equipChoice, setEquipChoice] = useState(null);
const [equipmentScrollBuffer, setEquipmentScrollBuffer] = useState(null);
const [equipmentScrollSelectionBuffer, setEquipmentScrollSelectionBuffer] = useState(null);
const [equipScrollOffset, setEquipScrollOffset] = useState(0);

// Change horizontal menu category
useEffect(() => {
Expand All @@ -74,117 +34,14 @@ export default function DisplayStats({
return () => window.removeEventListener('keydown', keydown);
}, []);

// Change vertical menu choice during Equip (unbinds when not on main Equip view)
useEffect(() => {
if (menuChoice !== 0 || equipChoice) return;
const keydown = (e) => {
switch (e.key) {
case keyMap.up:
setSubMenuChoice((choice) => (choice + EQUIPMENT_ORDER.length - 1) % EQUIPMENT_ORDER.length);
break;
case keyMap.down:
setSubMenuChoice((choice) => ((choice === null ? -1 : choice) + 1) % EQUIPMENT_ORDER.length);
break;
case keyMap.select:
setEquipChoice(EQUIPMENT_ORDER[subMenuChoice]);
const currentItem = inventory[EQUIPMENT_ORDER[subMenuChoice]].findIndex(
({ id }) => id === equipment[EQUIPMENT_ORDER[subMenuChoice]].id
);
setEquipScrollOffset(currentItem);
break;
// case keyMap.cancel:
// setSubMenuChoice(null);
// break;
}
}
window.addEventListener('keydown', keydown);
return () => window.removeEventListener('keydown', keydown);
}, [menuChoice, subMenuChoice, equipChoice]);

// Handle equip slot selection view
useEffect(() => {
if (!equipChoice) return;

const keydown = (e) => {
switch (e.key) {
case keyMap.cancel:
setEquipChoice(null);
break;
}
}
window.addEventListener('keydown', keydown);
return () => window.removeEventListener('keydown', keydown);
}, [equipChoice]);

// Create equip menu subMenuChoice's highlight buffer
useEffect(() => {
if (subMenuChoice === null) return;
const buffer = [];
buffer.push('', '', '', '');
buffer.push(...Array.from({ length: subMenuChoice % (EQUIPMENT_ORDER.length / 2) }, () => ''));
buffer.push([...Array.from({ length: subMenuChoice >= (EQUIPMENT_ORDER.length / 2) ? 11 : 0 }, () => ''),
...ABBREVIATIONS[EQUIPMENT_ORDER[subMenuChoice]].split('')
]);
setSubMenuChoiceBuffer(buffer);
}, [subMenuChoice]);

// Create equip menu display buffer
useEffect(() => {
setEquippedBuffer({ fg: '#555', buffer: [
'', '', '', '',
farColumns(slots.weapon, slots.head),
farColumns(slots.body, slots.arms),
farColumns(slots.legs, slots.shield),
farColumns(slots.feet, slots.waist),
]});
}, [slots.weapon, slots.head, slots.body, slots.arms, slots.legs,
slots.shield, slots.feet, slots.waist]);

// Handle equip slot view scrolling
useEffect(() => {
if (!equipChoice) return;
const keydown = (e) => {
switch (e.key) {
case keyMap.up:
setEquipScrollOffset((offset) => {
if (offset === 0) return 0;
return offset - 1;
});
break;
case keyMap.down:
setEquipScrollOffset((offset) => {
if (offset >= inventory[equipChoice].length - 3 + 2) return offset;
return offset + 1;
});
break;
case keyMap.select:
// Equip item
setEquipment(equipChoice, inventory[equipChoice][equipScrollOffset].id);
setEquipChoice(null);
break;
}
}
window.addEventListener('keydown', keydown);
return () => window.removeEventListener('keydown', keydown);
}, [equipChoice, setEquipment]);

// Create equipment scroll buffer
useEffect(() => {
if (!equipChoice) return;
const list = inventory[equipChoice].map(({ id, name }) => {
let label = ` ${name}`;
if (id === equipment[equipChoice].id) {
label = `*${label.slice(1)}`;
}
label = label.padEnd(width, ' ');
return label;
});
const buffer = bufferizeList(5, [''].concat(list, ['']), width, height, equipScrollOffset);
setEquipmentScrollBuffer(buffer);
setEquipmentScrollSelectionBuffer(buffer.map(
(line, i) => i === 6 ? line : ''
));
}, [equipChoice, equipScrollOffset, height, width]);
const equipmentBuffers = useEquipmentBuffers(menuChoice === 0, { width, height, keyMap });
const magicBuffers = [{ fg: 'red', buffer: ['', '', '', '', TABS[1]]}];
const logBuffers = [{ fg: 'green', buffer: ['', '', '', '', TABS[2]]}];
const lowerBuffers = [
...(equipmentBuffers || []),
...(menuChoice === 1 ? magicBuffers : []),
...(menuChoice === 2 ? logBuffers : []),
];

return (
<ScreenStack
Expand Down Expand Up @@ -216,39 +73,8 @@ export default function DisplayStats({
'', '', '',
[...Array.from(TABS.slice(0, menuChoice).join(' '), () => ''), ...(menuChoice ? [''] : []), ...TABS[menuChoice].split('')]
]},
...(
// Equipment
menuChoice === 0 ? (
equipChoice === null ? (
[].concat((buffers || []).map(({ fg, buffer }) => ({
fg: fg, buffer: [].concat(['', '', '', ''], buffer.map(
(line) => [].concat(['', '', '', ''], line)
))
})),
equippedBuffer,
{ bg: '#888', fg: 'black', buffer: subMenuChoiceBuffer },
)) : ([
{ bg: '#888', fg: 'black', buffer: [
'', '', '', '',
`${equipChoice[0].toUpperCase() + equipChoice.slice(1)}:`.padEnd(width - 5, ' ')
+
(inventory[equipChoice][equipScrollOffset]?.stats?.A !== undefined ? (
`Atk ${minifyNumbers(inventory[equipChoice][equipScrollOffset].stats?.A || 0)}`
) : (
`Def ${minifyNumbers(inventory[equipChoice][equipScrollOffset].stats?.D || 0)}`
))
]},
equipmentScrollBuffer && { fg: '#c7c7c7', buffer: equipmentScrollBuffer },
equipmentScrollBuffer && { bg: '#aaa', fg: 'black', buffer: equipmentScrollSelectionBuffer },
])
) : menuChoice === 1 ? (
// Magic
[{fg: 'red', buffer: ['', '', '', '', TABS[menuChoice]]}]
) : menuChoice === 2 ? (
// Log
[{fg: 'green', buffer: ['', '', '', '', TABS[menuChoice]]}]
) : []),
].filter(Boolean)}
...lowerBuffers,
]}
/>
);
}
Loading

0 comments on commit 71631e4

Please sign in to comment.