feat(world): add persistent citizen simulation with needs, jobs, and social features
- Adds Character model with survival needs (hunger, thirst, energy) and state machine - Implements city:tick world ticker for offline progression every minute - Adds city territory expansion and building construction system - Introduces job economy, inventory, and transaction audit trail - Adds social graph (friends, marriage, children) and character chat - Implements admin approval workflow for new registrations - Adds hospital admission system for traffic accidents - Includes comprehensive feature tests and world seeders
This commit is contained in:
Executable
+56
@@ -0,0 +1,56 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', __('admin.cities.title'))
|
||||
|
||||
@section('content')
|
||||
<div style="max-width: 960px; margin: 0 auto;">
|
||||
<div class="card" style="margin-bottom:1.25rem;">
|
||||
<h1 style="margin-top:0; color:#fff;">🗺️ {{ __('admin.cities.title') }}</h1>
|
||||
@if (session('status'))
|
||||
<p style="color:#4ade80;">{{ session('status') }}</p>
|
||||
@endif
|
||||
@if ($errors->any())
|
||||
<p style="color:var(--danger);">{{ $errors->first() }}</p>
|
||||
@endif
|
||||
<p style="color:var(--muted);">{{ __('admin.cities.hint') }}</p>
|
||||
|
||||
<form method="POST" action="{{ route('admin.cities.store') }}" style="display:flex; gap:.6rem; margin-top:1rem; flex-wrap:wrap;">
|
||||
@csrf
|
||||
<input type="text" name="name" required maxlength="120" placeholder="{{ __('admin.cities.name') }}"
|
||||
style="flex:1; min-width:200px; padding:.6rem .8rem; border-radius:.55rem; border:1px solid var(--border); background:#0b1220; color:var(--text);">
|
||||
<button type="submit" class="btn btn-primary">{{ __('admin.cities.create') }}</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<table style="width:100%; border-collapse:collapse; color:var(--muted);">
|
||||
<thead>
|
||||
<tr style="text-align:left; border-bottom:1px solid var(--border);">
|
||||
<th style="padding:.5rem;">{{ __('admin.cities.name') }}</th>
|
||||
<th style="padding:.5rem;">{{ __('admin.cities.bounds') }}</th>
|
||||
<th style="padding:.5rem;">{{ __('admin.cities.expansions') }}</th>
|
||||
<th style="padding:.5rem;">{{ __('admin.citizens.actions') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($cities as $city)
|
||||
<tr style="border-bottom:1px solid var(--border);">
|
||||
<td style="padding:.5rem; color:#fff;">{{ $city->name }} @if($city->is_active)<span class="badge badge-user">ativo</span>@endif</td>
|
||||
<td style="padding:.5rem;">
|
||||
X [{{ $city->bounds_min_x }}, {{ $city->bounds_max_x }}] ·
|
||||
Z [{{ $city->bounds_min_z }}, {{ $city->bounds_max_z }}]
|
||||
</td>
|
||||
<td style="padding:.5rem;">{{ $city->expansions }}/{{ \App\Models\City::MAX_EXPANSIONS }}</td>
|
||||
<td style="padding:.5rem;">
|
||||
<form method="POST" action="{{ route('admin.cities.expand', $city) }}">
|
||||
@csrf
|
||||
<button type="submit" class="btn">{{ __('admin.cities.expand') }}</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', __('admin.citizens.title'))
|
||||
|
||||
@section('content')
|
||||
<div style="max-width: 960px; margin: 0 auto;">
|
||||
<div class="card" style="margin-bottom:1.25rem;">
|
||||
<h1 style="margin-top:0; color:#fff;">👥 {{ __('admin.citizens.title') }}</h1>
|
||||
@if (session('status'))
|
||||
<p style="color:#4ade80;">{{ session('status') }}</p>
|
||||
@endif
|
||||
<p style="color:var(--muted);">{{ __('admin.citizens.hint') }}</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<table style="width:100%; border-collapse:collapse; color:var(--muted);">
|
||||
<thead>
|
||||
<tr style="text-align:left; border-bottom:1px solid var(--border);">
|
||||
<th style="padding:.5rem;">{{ __('admin.citizens.name') }}</th>
|
||||
<th style="padding:.5rem;">{{ __('Email') }}</th>
|
||||
<th style="padding:.5rem;">{{ __('admin.citizens.status') }}</th>
|
||||
<th style="padding:.5rem;">{{ __('admin.citizens.character') }}</th>
|
||||
<th style="padding:.5rem;">{{ __('admin.citizens.actions') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($users as $u)
|
||||
<tr style="border-bottom:1px solid var(--border);">
|
||||
<td style="padding:.5rem; color:#fff;">{{ $u->name }}</td>
|
||||
<td style="padding:.5rem;">{{ $u->email }}</td>
|
||||
<td style="padding:.5rem;">
|
||||
<span class="badge {{ $u->status === 'active' ? 'badge-user' : 'badge-admin' }}">{{ $u->status }}</span>
|
||||
</td>
|
||||
<td style="padding:.5rem;">{{ $u->character?->name ?? '—' }}</td>
|
||||
<td style="padding:.5rem; display:flex; gap:.4rem; flex-wrap:wrap;">
|
||||
@if ($u->status === 'pending')
|
||||
<form method="POST" action="{{ route('admin.citizens.approve', $u) }}">
|
||||
@csrf
|
||||
<button type="submit" class="btn btn-primary">{{ __('admin.citizens.approve') }}</button>
|
||||
</form>
|
||||
@endif
|
||||
@if ($u->status !== 'banned' && $u->id !== auth()->id())
|
||||
<form method="POST" action="{{ route('admin.citizens.ban', $u) }}">
|
||||
@csrf
|
||||
<button type="submit" class="btn">{{ __('admin.citizens.ban') }}</button>
|
||||
</form>
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
<div style="margin-top:1rem;">{{ $users->links() }}</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
Regular → Executable
Regular → Executable
Regular → Executable
Executable
+17
@@ -0,0 +1,17 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', __('auth.pending_title'))
|
||||
|
||||
@section('content')
|
||||
<div style="max-width: 480px; margin: 0 auto; text-align: center;">
|
||||
<div class="card">
|
||||
<h2 style="margin-top:0; color:#fff;">⏳ {{ __('auth.pending_title') }}</h2>
|
||||
<p style="color:var(--muted);">{{ __('auth.pending_body') }}</p>
|
||||
<p style="color:var(--muted); font-size:.9rem;">{{ auth()->user()?->email }}</p>
|
||||
<form method="POST" action="{{ route('logout') }}" style="margin-top:1.5rem;">
|
||||
@csrf
|
||||
<button type="submit" class="btn">{{ __('Logout') }}</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
Regular → Executable
Regular → Executable
+151
-871
File diff suppressed because it is too large
Load Diff
Regular → Executable
Regular → Executable
+2
@@ -109,6 +109,8 @@
|
||||
<a href="{{ route('city.viewer') }}">{{ __('nav.city') }}</a>
|
||||
@if (auth()->user()->isAdmin())
|
||||
<a href="{{ route('admin.stores.index') }}" class="badge badge-admin" style="text-decoration:none;">{{ __('nav.admin') }}</a>
|
||||
<a href="{{ route('admin.citizens.index') }}">{{ __('nav.citizens') }}</a>
|
||||
<a href="{{ route('admin.cities.index') }}">{{ __('nav.cities') }}</a>
|
||||
@endif
|
||||
<form method="POST" action="{{ route('logout') }}">
|
||||
@csrf
|
||||
|
||||
Regular → Executable
Regular → Executable
Regular → Executable
Reference in New Issue
Block a user