chroma_solstice/docs/adding-npcs.md
2026-08-08 00:09:50 -04:00

1.9 KiB

Adding a talkable NPC

An NPC/sign is just an immovable Entity that mixes in Dialogable. Bumping it (a rejected move) opens the dialogue box. Talking is the same everywhere — you only supply art + a story.

1. Write the story

Create stories/<name>.ink — a line, a few choices, an ending:

yo wassup

* kick the sign
    it doesnt budge.
* [say nothing] you have nothing to say to a sign.
- -> END

2. Compile it

The game can't parse .ink (LÖVE has no lpeg), so compile to a .lua book:

lua tools/compile_ink.lua <name>

Re-run this every time you edit the .ink — the game loads the .lua, not the .ink. (Needs lua + lua-lpeg installed.)

3. Load the book

In main.lua, next to startSignBook:

<name>Book = require "stories.<name>"

4. Make the entity

In npc.lua, copy Sign — pick your art and name your book:

Oracle = class("Oracle", Entity)
Oracle:include(Dialogable)

function Oracle:initialize(x, y)
	self.book = oracleBook            -- from step 3
	Entity.initialize(self, {
		x = x, y = y, color = "red",
		collision = "unmoveable",
		sprites = {
			red   = loadSprite("art/npc/oracle_r.png"),
			green = loadSprite("art/npc/oracle_g.png"),
			blue  = loadSprite("art/npc/oracle_b.png"),
		},
	})
end

Per-channel art lives in art/npc/ as <name>_r/_g/_b.png (16px cells).

5. Place it in a room

Map a save class to your entity in Room:createEntity (room.lua), alongside the npcSign branch:

if class == "oracle" then
	local entity = Oracle:new(x, y)
	self:registerNpc(entity)
	return entity
end

Then add it to a room's rooms/<room>.sav objects list:

{ class = "oracle", x = 4, y = 8 }

That's it — walk into it and it talks. NPCs are stamped into every colour's collision matrix, so they block movement and obey the world's colour rules (a red-only player reads them in red).