You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
100 lines
4.3 KiB
SQL
100 lines
4.3 KiB
SQL
-- 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 $$;
|