'city10'], [ 'name' => 'City10', // Performance-tuned size: 72 blocks (9 × 8) after the // 40-unit road grid and its outer margin are derived from // these bounds (layout −160..200 × −160..160). 'bounds_min_x' => -120, 'bounds_max_x' => 160, 'bounds_min_z' => -120, 'bounds_max_z' => 120, 'is_active' => true, 'expansions' => 0, ], ); // --- Control tower agent (airport clearances) --------------------- // Positioned at the north airport tower; model comes from // AI_ATC_MODEL (poolside/laguna-xs-2.1:free by default) and is // re-validated against the allow-list before use. $tower = Airports::geometry($city)['sites'][0]['tower']['center']; $atcModel = (string) config('ai.atc_model'); if (! in_array($atcModel, config('ai.allowed_models', []), true)) { $atcModel = 'poolside/laguna-xs-2.1:free'; } AiAgent::updateOrCreate( ['name' => 'Torre de Controle City10'], [ 'type' => 'atc', 'model' => $atcModel, 'system_prompt' => 'Você é a torre de controle aéreo do Aeroporto City10 Norte. ' .'Autorize decolagens e pousos com linguagem formal, curta e clássica de controle ' .'de tráfego aéreo, sempre em português, citando o voo, a companhia e a pista.', 'current_goal' => 'Gerenciar decolagens, pousos e o tráfego dos dois aeroportos com segurança', 'status' => 'active', 'pos_x' => (float) $tower[0], 'pos_y' => 0, 'pos_z' => (float) $tower[1], ], ); $bakery = Store::where('type', 'bakery')->orderBy('id')->first(); $market = Store::where('type', 'market')->orderBy('id')->first(); Job::updateOrCreate( ['city_id' => $city->id, 'title' => 'Padeiro'], ['store_id' => $bakery?->id, 'salary' => 12, 'requires_education' => 0], ); Job::updateOrCreate( ['city_id' => $city->id, 'title' => 'Operador de mercado'], ['store_id' => $market?->id, 'salary' => 10, 'requires_education' => 0], ); Job::updateOrCreate( ['city_id' => $city->id, 'title' => 'Servidor público'], ['salary' => 15, 'requires_education' => 30], ); Job::updateOrCreate( ['city_id' => $city->id, 'title' => 'Professor'], ['salary' => 14, 'requires_education' => 60], ); // City hospital: accident victims are admitted here for one game hour. Building::updateOrCreate( [ 'city_id' => $city->id, 'type' => Building::TYPE_HOSPITAL, ], [ 'owner_character_id' => null, 'name' => 'Hospital Municipal', 'pos_x' => 60, 'pos_z' => -60, 'width' => 14, 'depth' => 12, 'height' => 8, 'is_complete' => true, 'build_progress' => 100, ], ); // Civic buildings: school and city hall. Building::updateOrCreate( ['city_id' => $city->id, 'type' => 'school'], [ 'owner_character_id' => null, 'name' => 'Escola Municipal', 'pos_x' => -20, 'pos_z' => 60, 'width' => 16, 'depth' => 12, 'height' => 7, 'is_complete' => true, 'build_progress' => 100, ], ); Building::updateOrCreate( ['city_id' => $city->id, 'type' => 'city_hall'], [ 'owner_character_id' => null, 'name' => 'Prefeitura', 'pos_x' => 20, 'pos_z' => 60, 'width' => 18, 'depth' => 14, 'height' => 10, 'is_complete' => true, 'build_progress' => 100, ], ); Mission::updateOrCreate( ['code' => 'exercise-5'], [ 'city_id' => $city->id, 'title' => 'Shape em dia', 'description' => 'Complete 5 séries de ginástica nas praças.', 'metric' => 'exercise_count', 'target' => 5, 'reward' => 25, 'is_active' => true, ], ); Mission::updateOrCreate( ['code' => 'build-home'], [ 'city_id' => $city->id, 'title' => 'Lar doce lar', 'description' => 'Construa a sua primeira casa.', 'metric' => 'buildings', 'target' => 1, 'reward' => 50, 'is_active' => true, ], ); Mission::updateOrCreate( ['code' => 'learn-20'], [ 'city_id' => $city->id, 'title' => 'Estudioso', 'description' => 'Alcance 20% de educação.', 'metric' => 'education', 'target' => 20, 'reward' => 30, 'is_active' => true, ], ); User::query()->where('is_active', true)->where('status', '!=', User::STATUS_ACTIVE) ->update(['status' => User::STATUS_ACTIVE]); User::query()->where('is_active', false)->where('status', User::STATUS_PENDING) ->update(['status' => User::STATUS_BANNED]); User::query()->where('status', User::STATUS_ACTIVE)->each(function (User $user) use ($city): void { Character::ensureForUser($user, $city); }); // Backfill fitness columns for characters created before the migration. Character::query()->whereNull('health')->update(['health' => 100]); Character::query()->whereNull('exercise_count')->update(['exercise_count' => 0]); } }