feat(city): add airports, ATC agent, luminous signs, and AI model fallback chain

- Add two airports (north/south) with full geometry: runways, taxiways,
  aprons, terminals, hangars, stands, and helipads; walkable airport
  grounds extend beyond city bounds.
- Introduce ATC AI agent ("Torre de Controle City10") using AI_ATC_MODEL
  to generate takeoff clearances; includes dispatch endpoint with
  30-second cooldown and deterministic fallback on failure.
- Implement AI model fallback chain: preferred model → AI_FALLBACK_MODEL
  before failing, applied in ChatController and PersonTalkController.
- Add luminous sign labels (letreiros) for plazas, beach, food, hospital,
  school, city hall, and airports with day/night glow.
- Fix city presence cache: compute is_me per viewer instead of baking
  into shared per-second cache to prevent cross-user flag leakage.
- Add tests: AirportTest, CityPresenceTest, SignLabelsTest, and
  PersonTalkTest fallback model retry scenario.
This commit is contained in:
2026-10-31 22:06:18 -03:00
parent a12807492f
commit e7498e1566
26 changed files with 2226 additions and 108 deletions
+7
View File
@@ -219,6 +219,13 @@
"city.beach_start": "Resting on the sand…",
"city.beach_prompt": "Relax at the beach",
"city.beach_active": "Relaxing at the beach",
"city.atc_missing": "No control tower configured.",
"city.sign_plaza": "Plaza",
"city.sign_beach": "Beach",
"city.sign_food": "Food",
"city.sign_hospital": "Hospital",
"city.sign_school": "School",
"city.sign_cityhall": "City Hall",
"city.exercise_need_equipment": "Get closer to plaza gym equipment.",
"city.exercise_need_awake": "You must be awake to exercise.",
"city.exercise_tired": "You are too tired to exercise.",
+7
View File
@@ -219,6 +219,13 @@
"city.beach_start": "Descansando en la arena…",
"city.beach_prompt": "Relajar en la playa",
"city.beach_active": "Relajándote en la playa",
"city.atc_missing": "Ninguna torre de control configurada.",
"city.sign_plaza": "Plaza",
"city.sign_beach": "Playa",
"city.sign_food": "Comida",
"city.sign_hospital": "Hospital",
"city.sign_school": "Escuela",
"city.sign_cityhall": "Alcaldía",
"city.exercise_need_equipment": "Acérquese a un equipo de la plaza.",
"city.exercise_need_awake": "Debe estar despierto para ejercitarse.",
"city.exercise_tired": "Está demasiado cansado para ejercitarse.",
+7
View File
@@ -219,6 +219,13 @@
"city.beach_start": "Descansando na areia…",
"city.beach_prompt": "Relaxar na praia",
"city.beach_active": "Relaxando na praia",
"city.atc_missing": "Nenhuma torre de controle configurada.",
"city.sign_plaza": "Praça",
"city.sign_beach": "Praia",
"city.sign_food": "Comidas",
"city.sign_hospital": "Hospital",
"city.sign_school": "Escola",
"city.sign_cityhall": "Prefeitura",
"city.exercise_need_equipment": "Aproxime-se de um equipamento da praça.",
"city.exercise_need_awake": "Você precisa estar acordado para se exercitar.",
"city.exercise_tired": "Você está cansado demais para se exercitar.",