Skip to content

Game state

Coins, levels, quest progress and inventories belong to the game. You read them with hooks.

src/status.ts2
export const StatusPanel = (): Component => {
const poison = useServerState(Varps.POISON);
const stamina = useServerState(Varbits.STAMINA_ACTIVE);
const shown = useServerState(ItemVarps.SHOWCASED);

One hook reads both kinds of game variable: whole values (Varps) and fields packed inside one (Varbits). A reference can say what the variable holds. VarpRef<3997, 'item'> reads back as an Item and goes straight into an item prop:

src/refs-interactivity-state.ts2
export declare const ItemVarps: {
readonly SHOWCASED: VarpRef<3997, 'item'>;
};
src/status.ts2
<sprite x="right" y="center" w={36} h={32} item={shown} itemCountMode="never" />
src/skills.ts2
const attack = useSkill(Skills.ATTACK);
src/skills.ts2
const baseAttack = useSkillBase(Skills.ATTACK);

useSkill is the level now, boosts included; useSkillBase is the level underneath. Show the first; check requirements against the second, so a potion does not unlock a door. To pass a skill to a child component, pass its level:

src/skills.ts2
const SkillTile = ({ icon, level, base, x, y }: {
icon: Sprite | null; level: Int; base: Int; x: Int; y: Int;
}): Component => (

useInventory returns a handle to the whole container:

src/inventory.ts2
const inventory = useInventory(Inventories.INVENTORY);
inventory[slot]the item in a slot, or -1 if it is empty
inventory.count(slot)how many of the item in a slot
inventory.total(item)how many of an item across the whole container
inventory.sizehow many slots there are
inventory.map(fn)one component per slot — see Rendering lists

Game state has no setter. To change it, send the server an interaction, such as a right-click option:

src/inventory.ts2
<sprite x="center" y="center" w={36} h={32} item={item} itemCount={count}
options={['Use', '', '', '', 'Drop', '', '', '', '', 'Examine']} />

Showing a value before the server confirms it

Section titled “Showing a value before the server confirms it”

predictServerState overwrites the client’s copy, so a toggle can look switched the moment it is clicked:

src/status.ts2
<layer w="fill" h={24} onClick={() => { predictServerState(Varbits.STAMINA_ACTIVE, 1 - stamina); }}>

The next server update replaces it. For a value your interface owns, use interface state.

useServerStateOnce reads a value while the component builds and follows nothing afterwards:

src/once.ts2
const atOpen = useServerStateOnce(Varps.POISON);
const now = useServerState(Varps.POISON);

When now moves the component redraws, and atOpen keeps the value from when the panel opened. For an editable copy, seed a cell with it:

src/once.ts2
const [stamina, setStamina] = useState(useServerStateOnce(Varbits.STAMINA_ACTIVE));

useDerived redraws only when a function’s result changes:

src/once.ts2
const combatLevel = (): Int => {
const attack = useSkill(Skills.ATTACK);
const strength = useSkill(Skills.STRENGTH);
const defence = useSkill(Skills.DEFENCE);
const hitpoints = useSkill(Skills.HITPOINTS);
return (attack + strength + defence + hitpoints) / 4;
};
src/once.ts2
const level = useDerived(() => combatLevel());

The reference has a page for each: useServerState, useSkill, useSkillBase, useInventory, predictServerState, useServerStateOnce and useDerived.