-- Migration 000026: Town buildings — server-driven layout for towns. -- Each NPC gets an assigned building; buildings have typed appearances per NPC role. -- ============================================================ -- Town buildings: persistent structures placed in towns. -- ============================================================ CREATE TABLE IF NOT EXISTS town_buildings ( id BIGSERIAL PRIMARY KEY, town_id BIGINT NOT NULL REFERENCES towns(id) ON DELETE CASCADE, building_type TEXT NOT NULL CHECK (building_type IN ( 'house.quest_giver', 'house.merchant', 'house.healer', 'decoration.well', 'decoration.stall', 'decoration.signpost' )), offset_x DOUBLE PRECISION NOT NULL DEFAULT 0, offset_y DOUBLE PRECISION NOT NULL DEFAULT 0, facing TEXT NOT NULL DEFAULT 'south' CHECK (facing IN ('north','south','east','west')), footprint_w DOUBLE PRECISION NOT NULL DEFAULT 2.0, footprint_h DOUBLE PRECISION NOT NULL DEFAULT 2.0, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE INDEX IF NOT EXISTS idx_town_buildings_town ON town_buildings(town_id); -- ============================================================ -- Link NPCs to their buildings (nullable for migration transition). -- ============================================================ ALTER TABLE npcs ADD COLUMN IF NOT EXISTS building_id BIGINT REFERENCES town_buildings(id) ON DELETE SET NULL; -- ============================================================ -- Seed buildings for all existing towns, then link NPCs. -- Layout strategy per town: -- - NPC buildings are placed in a semicircle around the town center -- - quest_giver at ~10 o'clock, merchant at ~2 o'clock, healer at ~6 o'clock -- - A well decoration at center, signpost near entrance -- ============================================================ -- Helper: create buildings for each town with NPCs, using deterministic offsets by NPC type. -- quest_giver houses: upper-left zone -- merchant houses: upper-right zone -- healer houses: lower-center zone DO $$ DECLARE t RECORD; n RECORD; new_building_id BIGINT; btype TEXT; ox DOUBLE PRECISION; oy DOUBLE PRECISION; npc_idx INTEGER; BEGIN FOR t IN SELECT id, radius FROM towns ORDER BY id LOOP npc_idx := 0; FOR n IN SELECT id, type FROM npcs WHERE town_id = t.id ORDER BY id LOOP -- Determine building type from NPC type btype := 'house.' || n.type; -- Spread NPCs in a semicircle; scale offset by town radius -- Each NPC gets a distinct angular position CASE n.type WHEN 'quest_giver' THEN ox := -0.45 * t.radius; oy := -0.25 * t.radius; WHEN 'merchant' THEN ox := 0.45 * t.radius; oy := -0.25 * t.radius; WHEN 'healer' THEN ox := 0.0; oy := 0.45 * t.radius; ELSE ox := npc_idx * 2.0; oy := 0.0; END CASE; -- Stagger if multiple NPCs of same type (add small offset per index) ox := ox + (npc_idx % 3) * 1.5; INSERT INTO town_buildings (town_id, building_type, offset_x, offset_y, facing, footprint_w, footprint_h) VALUES (t.id, btype, ox, oy, 'south', 2.5, 2.0) RETURNING id INTO new_building_id; -- Link NPC to their building UPDATE npcs SET building_id = new_building_id WHERE id = n.id; -- Move NPC offset to be at the building entrance (slightly in front) UPDATE npcs SET offset_x = ox, offset_y = oy + 1.2 WHERE id = n.id; npc_idx := npc_idx + 1; END LOOP; -- Add a well decoration at town center INSERT INTO town_buildings (town_id, building_type, offset_x, offset_y, facing, footprint_w, footprint_h) VALUES (t.id, 'decoration.well', 0, 0, 'south', 1.5, 1.5); -- Add a signpost near the entrance (south edge) INSERT INTO town_buildings (town_id, building_type, offset_x, offset_y, facing, footprint_w, footprint_h) VALUES (t.id, 'decoration.signpost', 0, 0.6 * t.radius, 'south', 0.5, 0.5); END LOOP; END $$;