|
|
-- Migration 000019: Wider spiral world — ~3× spacing vs 000018, four new towns on the ring
|
|
|
-- (midpoints along progression segments Willowdale→Thornwatch→Ashengard→Redcliff→Boghollow),
|
|
|
-- full ring roads + road_waypoints recomputed from town centers (same rules as 000017/000018).
|
|
|
|
|
|
-- Level bands (1–40, non-overlapping) follow road order by level_min.
|
|
|
UPDATE towns SET level_min = 1, level_max = 4 WHERE name = 'Willowdale';
|
|
|
UPDATE towns SET level_min = 9, level_max = 12 WHERE name = 'Thornwatch';
|
|
|
UPDATE towns SET level_min = 17, level_max = 20 WHERE name = 'Ashengard';
|
|
|
UPDATE towns SET level_min = 25, level_max = 27 WHERE name = 'Redcliff';
|
|
|
UPDATE towns SET level_min = 31, level_max = 33 WHERE name = 'Boghollow';
|
|
|
UPDATE towns SET level_min = 34, level_max = 37 WHERE name = 'Cinderkeep';
|
|
|
UPDATE towns SET level_min = 38, level_max = 40 WHERE name = 'Starfall';
|
|
|
|
|
|
-- Positions: 000018 layout scaled ×3 from origin (stronger separation); new towns at segment midpoints.
|
|
|
UPDATE towns SET world_x = 7860, world_y = 2400 WHERE name = 'Willowdale';
|
|
|
UPDATE towns SET world_x = 8778, world_y = 3174 WHERE name = 'Thornwatch';
|
|
|
UPDATE towns SET world_x = 8697, world_y = 4752 WHERE name = 'Ashengard';
|
|
|
UPDATE towns SET world_x = 7197, world_y = 6168 WHERE name = 'Redcliff';
|
|
|
UPDATE towns SET world_x = 4605, world_y = 6378 WHERE name = 'Boghollow';
|
|
|
UPDATE towns SET world_x = 1899, world_y = 4713 WHERE name = 'Cinderkeep';
|
|
|
UPDATE towns SET world_x = 393, world_y = 1980 WHERE name = 'Starfall';
|
|
|
|
|
|
INSERT INTO towns (name, biome, world_x, world_y, radius, level_min, level_max) VALUES
|
|
|
('Mossharbor', 'meadow', 8319, 2787, 14.0, 5, 8),
|
|
|
('Emberwell', 'forest', 8738, 3963, 15.0, 13, 16),
|
|
|
('Frostmark', 'ruins', 7947, 5460, 14.0, 21, 24),
|
|
|
('Duskwatch', 'swamp', 5901, 6273, 14.0, 28, 30)
|
|
|
ON CONFLICT (name) DO NOTHING;
|
|
|
|
|
|
-- NPCs for new settlements (idempotent).
|
|
|
INSERT INTO npcs (town_id, name, type, offset_x, offset_y)
|
|
|
SELECT t.id, v.npc_name, v.npc_type, v.ox, v.oy
|
|
|
FROM (VALUES
|
|
|
('Mossharbor', 'Harbor-ward Lissa', 'quest_giver', -2.5::double precision, 1.0::double precision),
|
|
|
('Mossharbor', 'Dock Trader Milo', 'merchant', 2.5, 0.0),
|
|
|
('Emberwell', 'Ranger Kess', 'quest_giver', 1.0, -2.0),
|
|
|
('Emberwell', 'Ember Outfitter', 'merchant', -2.0, 2.0),
|
|
|
('Frostmark', 'Warden Torvik', 'quest_giver', -1.5, 1.5),
|
|
|
('Frostmark', 'Relic Peddler', 'merchant', 2.0, -1.0),
|
|
|
('Duskwatch', 'Sister Morah', 'quest_giver', 0.0, 2.5),
|
|
|
('Duskwatch', 'Bog Imports', 'merchant', -2.5, -1.0)
|
|
|
) AS v(town_name, npc_name, npc_type, ox, oy)
|
|
|
JOIN towns t ON t.name = v.town_name
|
|
|
WHERE NOT EXISTS (
|
|
|
SELECT 1 FROM npcs n WHERE n.town_id = t.id AND n.name = v.npc_name
|
|
|
);
|
|
|
|
|
|
-- Quest level windows: align with new town bands and progression.
|
|
|
UPDATE quests SET min_level = 1, max_level = 4 WHERE title = 'Wolf Cull';
|
|
|
UPDATE quests SET min_level = 1, max_level = 8 WHERE title = 'Deliver to Thornwatch';
|
|
|
UPDATE quests SET min_level = 2, max_level = 8 WHERE title = 'Boar Hunt';
|
|
|
UPDATE quests SET min_level = 9, max_level = 12 WHERE title IN ('Spider Infestation', 'Spider Fang Collection');
|
|
|
UPDATE quests SET min_level = 9, max_level = 14 WHERE title = 'Forest Patrol';
|
|
|
UPDATE quests SET min_level = 13, max_level = 20 WHERE title IN ('Undead Purge', 'Ancient Relics', 'Report to Redcliff');
|
|
|
UPDATE quests SET min_level = 21, max_level = 27 WHERE title IN ('Orc Raider Cleanup', 'Ore Samples');
|
|
|
UPDATE quests SET min_level = 28, max_level = 33 WHERE title IN ('Swamp Creatures', 'Venomous Harvest', 'Message to Cinderkeep');
|
|
|
UPDATE quests SET min_level = 34, max_level = 37 WHERE title IN ('Demon Slayer', 'Infernal Cores');
|
|
|
UPDATE quests SET min_level = 38, max_level = 40 WHERE title IN ('Titan''s Challenge', 'Void Fragments', 'Full Circle');
|
|
|
|
|
|
-- Replace road graph: bidirectional ring in level order + wrap Starfall → Willowdale.
|
|
|
DELETE FROM road_waypoints;
|
|
|
DELETE FROM roads;
|
|
|
|
|
|
INSERT INTO roads (from_town_id, to_town_id, distance)
|
|
|
SELECT f.id, t.id, 1000.0
|
|
|
FROM (VALUES
|
|
|
('Willowdale', 'Mossharbor'),
|
|
|
('Mossharbor', 'Thornwatch'),
|
|
|
('Thornwatch', 'Emberwell'),
|
|
|
('Emberwell', 'Ashengard'),
|
|
|
('Ashengard', 'Frostmark'),
|
|
|
('Frostmark', 'Redcliff'),
|
|
|
('Redcliff', 'Duskwatch'),
|
|
|
('Duskwatch', 'Boghollow'),
|
|
|
('Boghollow', 'Cinderkeep'),
|
|
|
('Cinderkeep', 'Starfall'),
|
|
|
('Starfall', 'Willowdale')
|
|
|
) AS seg(from_name, to_name)
|
|
|
JOIN towns f ON f.name = seg.from_name
|
|
|
JOIN towns t ON t.name = seg.to_name;
|
|
|
|
|
|
INSERT INTO roads (from_town_id, to_town_id, distance)
|
|
|
SELECT t.id, f.id, 1000.0
|
|
|
FROM (VALUES
|
|
|
('Willowdale', 'Mossharbor'),
|
|
|
('Mossharbor', 'Thornwatch'),
|
|
|
('Thornwatch', 'Emberwell'),
|
|
|
('Emberwell', 'Ashengard'),
|
|
|
('Ashengard', 'Frostmark'),
|
|
|
('Frostmark', 'Redcliff'),
|
|
|
('Redcliff', 'Duskwatch'),
|
|
|
('Duskwatch', 'Boghollow'),
|
|
|
('Boghollow', 'Cinderkeep'),
|
|
|
('Cinderkeep', 'Starfall'),
|
|
|
('Starfall', 'Willowdale')
|
|
|
) AS seg(from_name, to_name)
|
|
|
JOIN towns f ON f.name = seg.from_name
|
|
|
JOIN towns t ON t.name = seg.to_name;
|
|
|
|
|
|
-- Canonical polylines (same segment rule as Go road_graph / 000017 — no jitter).
|
|
|
INSERT INTO road_waypoints (road_id, seq, x, y)
|
|
|
SELECT
|
|
|
r.id,
|
|
|
gs.seq,
|
|
|
CASE
|
|
|
WHEN gs.seq = 0 THEN f.world_x
|
|
|
WHEN gs.seq = seg.nseg THEN t.world_x
|
|
|
ELSE f.world_x + (t.world_x - f.world_x) * (gs.seq::double precision / seg.nseg::double precision)
|
|
|
END,
|
|
|
CASE
|
|
|
WHEN gs.seq = 0 THEN f.world_y
|
|
|
WHEN gs.seq = seg.nseg THEN t.world_y
|
|
|
ELSE f.world_y + (t.world_y - f.world_y) * (gs.seq::double precision / seg.nseg::double precision)
|
|
|
END
|
|
|
FROM roads r
|
|
|
INNER JOIN towns f ON f.id = r.from_town_id
|
|
|
INNER JOIN towns t ON t.id = r.to_town_id
|
|
|
CROSS JOIN LATERAL (
|
|
|
SELECT GREATEST(
|
|
|
1,
|
|
|
FLOOR(
|
|
|
SQRT(POWER(t.world_x - f.world_x, 2) + POWER(t.world_y - f.world_y, 2)) / 20.0
|
|
|
)::integer
|
|
|
) AS nseg
|
|
|
) seg
|
|
|
CROSS JOIN LATERAL generate_series(0, seg.nseg) AS gs(seq);
|