openvibers/openvibe.games Commits

First steps: a Craft a Stone Pickaxe step after the axe, and the gather hint asks for five stones (nothing said to make a pickaxe before the quarry, and one stone finished gathering) (#128)

OP OpenVibers committed 24 days ago · 0e1b97b70a · 3 files, +36 −5

Changes

ddiff --git a/CHANGELOG.md b/CHANGELOG.md
iindex 6fce3d9..41b9dd9 100644
---- a/CHANGELOG.md
++++ b/CHANGELOG.md
@@@ -8,6 +8,10 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
### Fixed
++- **No step said to make a pickaxe.** Scraplandia's first steps went from the Stone Axe to "Mine at the quarry", whose
++ hint only said a Stone Pickaxe breaks the deposits, and the gather step finished after a single stone. A new
++ "Craft a Stone Pickaxe" step follows the axe (2 Wood Planks and 3 Stones), and the gather hint says a log and five
++ stones make the first two tools: one pile and one log are exactly both recipes.
- **Townsfolk in the Salvage Rush arena.** The 90-second scrap round ran the content's seven NPC spawns, laid out for
the procedural world: townsfolk and a warden wandered inside the arena and Rustjaw thugs stood just past its edge.
A world definition can now name its own NPCs (`npcSpawns`; `[]` is none), and the arena has none. A map's own NPCs
ddiff --git a/apps/client/src/ui/firstSteps.test.ts b/apps/client/src/ui/firstSteps.test.ts
iindex 16df650..e73aacf 100644
---- a/apps/client/src/ui/firstSteps.test.ts
++++ b/apps/client/src/ui/firstSteps.test.ts
@@@ -44,6 +44,9 @@ describe('first steps', () => {
expect(current()).toContain('Craft a Stone Axe')
items = { stone_axe: 1 }
fs.update()
++ expect(current()).toContain('Craft a Stone Pickaxe')
++ items = { stone_axe: 1, stone_pickaxe: 1 }
++ fs.update()
expect(current()).toContain('Chop an oak')
levels = { woodcutting: 2 }
fs.update()
@@@ -52,7 +55,7 @@ describe('first steps', () => {
levels = {}
fs.update()
expect(current()).toContain('Mine at the quarry')
-- expect(root.querySelector('.first-steps-head')?.textContent).toContain('3/6')
++ expect(root.querySelector('.first-steps-head')?.textContent).toContain('4/7')
})
it('finishes with a haul and then hides', () => {
@@@ -83,7 +86,7 @@ describe('first steps', () => {
it('progress() unions what was done with what is done now', () => {
const view = { count: () => 0, level: (s: string) => (s === 'mining' ? 2 : 1), hauled: false }
-- expect(progress(view, { done: ['gather'] })).toEqual(['gather', 'mine'])
++ expect(progress(view, { done: ['gather'] })).toEqual(['gather', 'pickaxe', 'mine'])
})
})
@@@ -110,6 +113,22 @@ describe('the waypoint hooks', () => {
expect(steps.birdAt).toBeNull()
})
++ it('makes the pickaxe a step of its own, right after the axe, from the same gate piles', () => {
++ const ids = FIRST_STEPS.map((s) => s.id)
++ expect(ids.indexOf('pickaxe')).toBe(ids.indexOf('axe') + 1)
++ const pickaxe = FIRST_STEPS.find((s) => s.id === 'pickaxe')!
++ expect(pickaxe.hint).toMatch(/2 Wood Planks and 3 Stones/)
++ expect(
++ pickaxe.done({
++ count: (i) => (i === 'stone_pickaxe' ? 1 : 0),
++ level: () => 1,
++ hauled: false,
++ }),
++ ).toBe(true)
++ expect(pickaxe.done({ count: () => 0, level: () => 1, hauled: false })).toBe(false)
++ expect(FIRST_STEPS[0]?.hint).toMatch(/five stones/)
++ })
++
it('gives the outdoor steps somewhere to point', () => {
const toward = Object.fromEntries(FIRST_STEPS.map((s) => [s.id, s.toward]))
expect(toward.gather?.nodes).toEqual(['branch_pile', 'loose_stones'])
ddiff --git a/apps/client/src/ui/firstSteps.ts b/apps/client/src/ui/firstSteps.ts
iindex d12edd9..aa85aa5 100644
---- a/apps/client/src/ui/firstSteps.ts
++++ b/apps/client/src/ui/firstSteps.ts
@@@ -3,7 +3,7 @@
* used to arrive with an empty hotbar and nothing to say what Scraplandia is about (owner, 2026-10-19: "so boring").
*
* The steps follow Scrap Island (apps/server/src/maps/scrapIsland.ts) and the tool chain: branches and loose stones
-- * need no tool → planks → a Stone Axe → an oak in the west forest → a Stone Pickaxe → the quarry → the scrapyard →
++ * need no tool → planks → a Stone Axe and a Stone Pickaxe → an oak in the west forest → the quarry → the scrapyard →
* a haul at the recovery bird. Each step reads what the client already knows (inventory, skill levels, the
* extraction announce); progress only moves forward and is kept in this browser. The panel can be closed for good.
*/
@@@ -33,7 +33,9 @@ export const FIRST_STEPS: FirstStep[] = [
{
id: 'gather',
title: 'Gather branches and stones',
-- hint: 'Piles just inside every city gate. Look at one and press E.',
++ // A pile holds five stones and a log makes four planks: exactly the axe (2 planks, 2 stones) and the pickaxe
++ // (2 planks, 3 stones). The hint said nothing of how many, and nothing said to make a pickaxe.
++ hint: 'Piles just inside every city gate. Look at one and press E: a log and five stones make your first two tools.',
done: (v) =>
(v.count('wood_log') > 0 || v.count('wood_plank') > 0 || v.count('stone_axe') > 0) &&
(v.count('stone') > 0 || v.count('stone_axe') > 0),
@@@ -45,6 +47,12 @@ export const FIRST_STEPS: FirstStep[] = [
hint: 'Tab → Crafting: turn a log into Wood Planks, then make the axe.',
done: (v) => v.count('stone_axe') > 0 || v.level('woodcutting') >= 2,
},
++ {
++ id: 'pickaxe',
++ title: 'Craft a Stone Pickaxe',
++ hint: 'Tab → Crafting: 2 Wood Planks and 3 Stones. Short of stones? The gate piles refill every two minutes.',
++ done: (v) => v.count('stone_pickaxe') > 0 || v.level('mining') >= 2,
++ },
{
id: 'chop',
title: 'Chop an oak',
@@@ -55,7 +63,7 @@ export const FIRST_STEPS: FirstStep[] = [
{
id: 'mine',
title: 'Mine at the quarry',
-- hint: 'South-west of town. A Stone Pickaxe breaks the stone deposits.',
++ hint: 'South-west of town. Hold the pickaxe and swing at the stone deposits.',
done: (v) => v.level('mining') >= 2,
toward: { nodes: ['stone_deposit'], zone: 'quarry' },
},