Implements proximity-based street conversations between player characters and peers (human or agentic NPC). New PersonTalk model, controller, and migrations store daily message threads that persist across sessions and provide context for future interactions. Agent replies include backoff throttling and fallback persona handling to avoid dead-end chats. Frontend changes refactor the chat panel to support both character and agent peers, opening automatically when the player moves within range, polling for replies, rendering day separators, and displaying rate-limit warnings. Styling updated to a transparent blurred panel. Translations extended with new hint text and rate-limit messages across en, es, and pt_BR.
379 lines
25 KiB
PHP
Executable File
379 lines
25 KiB
PHP
Executable File
@extends('layouts.app')
|
||
|
||
@section('title', __('city.title'))
|
||
|
||
@section('content')
|
||
<div style="max-width: 1280px; margin: 0 auto;">
|
||
<div style="display:flex; justify-content:space-between; align-items:center; gap:1rem; flex-wrap:wrap; margin-bottom:1rem;">
|
||
<h1 style="margin:0; color:#fff;">🏙️ {{ __('city.title') }}</h1>
|
||
<div style="display:flex; gap:.6rem; align-items:center; flex-wrap:wrap;">
|
||
<span id="hud-clock" style="background:rgba(15,23,42,.85); border:1px solid var(--border); border-radius:.5rem;
|
||
padding:.35rem .6rem; font-size:.85rem; color:#fde68a; font-variant-numeric:tabular-nums;">🕒 --:--</span>
|
||
<span id="hud-weather" style="background:rgba(15,23,42,.85); border:1px solid var(--border); border-radius:.5rem;
|
||
padding:.35rem .6rem; font-size:.85rem; color:#7dd3fc;">☀️ —</span>
|
||
<span id="stats" style="color:var(--muted); font-size:.9rem;"></span>
|
||
<button type="button" id="audio-toggle" class="btn" aria-label="{{ __('city.audio') }}" title="{{ __('city.audio') }}">🔊</button>
|
||
<button type="button" id="reload" class="btn">{{ __('city.refresh') }}</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="scene"
|
||
style="position:relative; width:100%; height:min(78vh, 720px); border-radius:1rem; overflow:hidden;
|
||
background:#0b1220; border:1px solid var(--border); box-shadow:0 20px 50px rgba(0,0,0,.45);">
|
||
<div id="loading" style="position:absolute; inset:0; display:grid; place-items:center; color:var(--muted);">
|
||
{{ __('city.loading') }}
|
||
</div>
|
||
<div id="error" style="position:absolute; inset:0; display:none; place-items:center; color:#fecaca;">
|
||
{{ __('city.error') }}
|
||
</div>
|
||
|
||
{{-- Minimap --}}
|
||
<div style="position:absolute; right:.7rem; bottom:4.6rem; z-index:12;">
|
||
<canvas id="minimap" width="160" height="160"
|
||
style="display:block; border-radius:.6rem; border:1px solid var(--border);
|
||
box-shadow:0 8px 20px rgba(0,0,0,.4);"
|
||
aria-label="{{ __('city.hud_minimap') }}"></canvas>
|
||
<div style="margin-top:.3rem; font-size:.62rem; color:#cbd5e1; background:rgba(15,23,42,.8);
|
||
border:1px solid var(--border); border-radius:.4rem; padding:.25rem .4rem; line-height:1.45;">
|
||
<span style="color:#f472b6;">●</span> você
|
||
<span style="color:#38bdf8;">●</span> jogadores
|
||
<span style="color:#facc15;">●</span> pedestres<br>
|
||
<span style="color:#94a3b8;">■</span> carros
|
||
<span style="color:#a78bfa;">■</span> motos
|
||
<span style="color:#4ade80;">■</span> bikes
|
||
<span style="color:#60a5fa;">■</span> ônibus<br>
|
||
<span style="color:#f59e0b;">■</span> lojas
|
||
<span style="color:#22c55e;">●</span> praças
|
||
</div>
|
||
</div>
|
||
|
||
{{-- Virtual joystick (mobile) --}}
|
||
<div id="joystick-base"
|
||
style="display:none; position:absolute; left:1.1rem; bottom:1.4rem; z-index:14;
|
||
width:110px; height:110px; border-radius:50%;
|
||
background:rgba(15,23,42,.55); border:2px solid rgba(148,163,184,.35);
|
||
touch-action:none;">
|
||
<div id="joystick-knob"
|
||
style="position:absolute; left:50%; top:50%; width:44px; height:44px; margin:-22px 0 0 -22px;
|
||
border-radius:50%; background:rgba(56,189,248,.75); border:2px solid #e0f2fe;"></div>
|
||
</div>
|
||
<style>
|
||
@media (max-width: 820px), (pointer: coarse) {
|
||
#joystick-base { display: block !important; }
|
||
#minimap { width:120px !important; height:120px !important; }
|
||
}
|
||
</style>
|
||
|
||
{{-- Pedestrian red-light wait banner --}}
|
||
<div id="ped-wait"
|
||
style="display:none; position:absolute; bottom:4.2rem; left:50%; transform:translateX(-50%);
|
||
z-index:20; background:rgba(127,29,29,.92); color:#fecaca; border:1px solid #f87171;
|
||
border-radius:.6rem; padding:.5rem 1rem; font-size:.95rem; font-weight:600; white-space:nowrap;">
|
||
</div>
|
||
|
||
{{-- Gym equipment proximity prompt --}}
|
||
<div id="exercise-prompt"
|
||
style="display:none; position:absolute; bottom:1.4rem; left:50%; transform:translateX(-50%);
|
||
z-index:20; background:rgba(20,83,45,.92); color:#bbf7d0; border:1px solid #4ade80;
|
||
border-radius:.6rem; padding:.5rem 1rem; font-size:.95rem; font-weight:600; white-space:nowrap;">
|
||
</div>
|
||
|
||
{{-- Hospital admission banner --}}
|
||
<div id="hospital-banner"
|
||
style="display:none; position:absolute; top:5.2rem; left:50%; transform:translateX(-50%);
|
||
z-index:20; background:rgba(127,29,29,.92); color:#fecaca; border:1px solid #f87171;
|
||
border-radius:.6rem; padding:.55rem 1rem; font-size:.95rem; font-weight:600;">
|
||
🏥
|
||
</div>
|
||
|
||
{{-- Character vitals and actions --}}
|
||
<div id="char-panel"
|
||
style="position:absolute; top:.7rem; left:.7rem; z-index:12; width:250px;
|
||
background:rgba(15,23,42,.93); border:1px solid var(--border);
|
||
border-radius:.75rem; padding:.75rem; font-size:.8rem; color:var(--muted);">
|
||
<div style="color:#fff; font-weight:700; margin-bottom:.4rem;" id="char-name">—</div>
|
||
<div>{{ __('city.hud_hunger') }}: <span id="hud-hunger" style="color:#fca5a5;">—</span></div>
|
||
<div>{{ __('city.hud_thirst') }}: <span id="hud-thirst" style="color:#7dd3fc;">—</span></div>
|
||
<div>{{ __('city.hud_energy') }}: <span id="hud-energy" style="color:#86efac;">—</span></div>
|
||
<div>{{ __('city.hud_health') }}: <span id="hud-health" style="color:#f9a8d4;">—</span></div>
|
||
<div>{{ __('city.hud_money') }}: <span id="hud-money" style="color:#fde68a;">—</span></div>
|
||
<div>{{ __('city.hud_state') }}: <span id="hud-char-state" style="color:#c4b5fd;">—</span></div>
|
||
<div>{{ __('city.hud_education') }}: <span id="hud-education">—</span></div>
|
||
<div>{{ __('city.hud_exercise') }}: <span id="hud-exercise-count" style="color:#c4b5fd;">—</span></div>
|
||
<div style="margin-top:.35rem; color:#cbd5e1;">{{ __('city.hud_inventory') }}: <span id="hud-inv">—</span></div>
|
||
|
||
<div style="margin-top:.6rem; color:#fff; font-weight:600;">{{ __('city.hud_actions') }}</div>
|
||
<div style="display:flex; flex-wrap:wrap; gap:.3rem; margin-top:.3rem;">
|
||
<button type="button" class="btn char-act" data-act="eat" style="padding:.25rem .45rem; font-size:.75rem;">{{ __('city.act_eat') }}</button>
|
||
<button type="button" class="btn char-act" data-act="drink" style="padding:.25rem .45rem; font-size:.75rem;">{{ __('city.act_drink') }}</button>
|
||
<button type="button" class="btn char-act" data-act="sleep" style="padding:.25rem .45rem; font-size:.75rem;">{{ __('city.act_sleep') }}</button>
|
||
<button type="button" class="btn char-act" data-act="wake" style="padding:.25rem .45rem; font-size:.75rem;">{{ __('city.act_wake') }}</button>
|
||
<button type="button" class="btn char-act" data-act="work" style="padding:.25rem .45rem; font-size:.75rem;">{{ __('city.act_work') }}</button>
|
||
<button type="button" class="btn char-act" data-act="stop-work" style="padding:.25rem .45rem; font-size:.75rem;">{{ __('city.act_stop') }}</button>
|
||
<button type="button" class="btn char-act" data-act="study" style="padding:.25rem .45rem; font-size:.75rem;">{{ __('city.act_study') }}</button>
|
||
<button type="button" class="btn char-act" data-act="buy" style="padding:.25rem .45rem; font-size:.75rem;">{{ __('city.act_buy') }}</button>
|
||
<button type="button" class="btn char-act" data-act="sell" style="padding:.25rem .45rem; font-size:.75rem;">{{ __('city.act_sell_v') }}</button>
|
||
<button type="button" class="btn char-act" data-act="build" style="padding:.25rem .45rem; font-size:.75rem;">{{ __('city.act_build') }}</button>
|
||
<button type="button" id="btn-market" class="btn" style="padding:.25rem .45rem; font-size:.75rem;">{{ __('city.act_market') }}</button>
|
||
<button type="button" id="btn-customize" class="btn" style="padding:.25rem .45rem; font-size:.75rem;">{{ __('city.act_customize') }}</button>
|
||
<button type="button" id="btn-ride-bus" class="btn" style="padding:.25rem .45rem; font-size:.75rem;">{{ __('city.act_ride_bus') }}</button>
|
||
<button type="button" id="btn-ride-train" class="btn" style="padding:.25rem .45rem; font-size:.75rem;">{{ __('city.act_ride_train') }}</button>
|
||
</div>
|
||
|
||
{{-- Marketplace --}}
|
||
<div id="market-panel" style="display:none; margin-top:.55rem; border-top:1px solid var(--border); padding-top:.45rem;">
|
||
<div style="color:#fff; font-weight:600;">🛒 {{ __('city.act_market') }}</div>
|
||
<div id="market-list" style="max-height:120px; overflow:auto; font-size:.75rem;"></div>
|
||
<div style="display:flex; gap:.25rem; margin-top:.3rem; flex-wrap:wrap;">
|
||
<select id="market-item" style="flex:1; min-width:70px; padding:.2rem; background:#0b1220; color:var(--text); border:1px solid var(--border); border-radius:.3rem; font-size:.7rem;">
|
||
<option value="product">product</option>
|
||
<option value="food">food</option>
|
||
<option value="water">water</option>
|
||
<option value="materials">materials</option>
|
||
</select>
|
||
<input id="market-qty" type="number" min="1" max="100" value="1" style="width:48px; padding:.2rem; background:#0b1220; color:var(--text); border:1px solid var(--border); border-radius:.3rem; font-size:.7rem;">
|
||
<input id="market-price" type="number" min="0.5" step="0.5" value="5" style="width:52px; padding:.2rem; background:#0b1220; color:var(--text); border:1px solid var(--border); border-radius:.3rem; font-size:.7rem;">
|
||
<button type="button" id="market-sell" class="btn" style="padding:.2rem .4rem; font-size:.7rem;">OK</button>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- Appearance customization --}}
|
||
<div id="customize-panel" style="display:none; margin-top:.55rem; border-top:1px solid var(--border); padding-top:.45rem;">
|
||
<div style="color:#fff; font-weight:600;">🎨 {{ __('city.act_customize') }}</div>
|
||
<div style="display:grid; grid-template-columns:1fr 1fr; gap:.25rem; font-size:.72rem; margin-top:.3rem;">
|
||
<label>skin <select id="cz-skin"><option>1</option><option>2</option><option>3</option><option>4</option></select></label>
|
||
<label>hair <select id="cz-hair"><option>1</option><option>2</option><option>3</option><option>4</option></select></label>
|
||
<label>shirt <select id="cz-shirt"><option>1</option><option>2</option><option>3</option><option>4</option><option>5</option></select></label>
|
||
<label>face <select id="cz-face"><option>1</option><option>2</option><option>3</option></select></label>
|
||
<label>beard <select id="cz-beard"><option>0</option><option>1</option><option>2</option></select></label>
|
||
<label>acc <select id="cz-accessory"><option>0</option><option>1</option><option>2</option></select></label>
|
||
</div>
|
||
<button type="button" id="customize-save" class="btn" style="margin-top:.35rem; width:100%; padding:.3rem; font-size:.75rem;">💾</button>
|
||
</div>
|
||
|
||
{{-- Missions journal --}}
|
||
<div style="margin-top:.55rem; border-top:1px solid var(--border); padding-top:.45rem;">
|
||
<div style="color:#fff; font-weight:600;">📜 {{ __('admin.world.missions') }}</div>
|
||
<div id="mission-list" style="max-height:100px; overflow:auto; font-size:.72rem; margin-top:.25rem;"></div>
|
||
</div>
|
||
|
||
<div style="margin-top:.6rem; color:#fff; font-weight:600;">{{ __('city.hud_jobs') }}</div>
|
||
<select id="job-select" style="width:100%; margin-top:.25rem; padding:.3rem; background:#0b1220; color:var(--text); border:1px solid var(--border); border-radius:.4rem;">
|
||
<option value="">—</option>
|
||
</select>
|
||
<button type="button" id="job-apply" class="btn" style="margin-top:.3rem; width:100%; padding:.3rem; font-size:.75rem;">{{ __('city.act_apply') }}</button>
|
||
|
||
<div style="margin-top:.6rem; color:#fff; font-weight:600;">{{ __('city.hud_social') }}</div>
|
||
<select id="citizen-select" style="width:100%; margin-top:.25rem; padding:.3rem; background:#0b1220; color:var(--text); border:1px solid var(--border); border-radius:.4rem;">
|
||
<option value="">—</option>
|
||
</select>
|
||
<div style="display:flex; gap:.3rem; margin-top:.3rem; flex-wrap:wrap;">
|
||
<button type="button" id="soc-friend" class="btn" style="padding:.25rem .4rem; font-size:.75rem;">{{ __('city.act_friend') }}</button>
|
||
<button type="button" id="soc-marry" class="btn" style="padding:.25rem .4rem; font-size:.75rem;">{{ __('city.act_marry') }}</button>
|
||
<button type="button" id="soc-child" class="btn" style="padding:.25rem .4rem; font-size:.75rem;">{{ __('city.act_child') }}</button>
|
||
</div>
|
||
<div id="char-msg" style="margin-top:.4rem; min-height:1.1em; color:#93c5fd;"></div>
|
||
</div>
|
||
|
||
{{-- Audio mixer (music / SFX / master volumes) --}}
|
||
<div id="audio-panel"
|
||
style="position:absolute; top:.7rem; right:.7rem; z-index:12; width:220px; display:none;
|
||
background:rgba(15,23,42,.93); border:1px solid var(--border);
|
||
border-radius:.75rem; padding:.75rem; font-size:.8rem; color:var(--muted);">
|
||
<div style="color:#fff; font-weight:700; margin-bottom:.5rem;">🎵 {{ __('city.audio') }}</div>
|
||
|
||
<label style="display:flex; justify-content:space-between; gap:.4rem; margin-bottom:.15rem;">
|
||
<span>{{ __('city.vol_master') }}</span>
|
||
<span id="vol-master-out" style="color:#e2e8f0; font-variant-numeric:tabular-nums;">85%</span>
|
||
</label>
|
||
<input type="range" id="vol-master" min="0" max="1" step="0.01" value="0.85" style="width:100%;">
|
||
|
||
<label style="display:flex; justify-content:space-between; gap:.4rem; margin:.45rem 0 .15rem;">
|
||
<span>{{ __('city.vol_music') }}</span>
|
||
<span id="vol-music-out" style="color:#e2e8f0; font-variant-numeric:tabular-nums;">70%</span>
|
||
</label>
|
||
<input type="range" id="vol-music" min="0" max="1" step="0.01" value="0.7" style="width:100%;">
|
||
|
||
<label style="display:flex; justify-content:space-between; gap:.4rem; margin:.45rem 0 .15rem;">
|
||
<span>{{ __('city.vol_sfx') }}</span>
|
||
<span id="vol-sfx-out" style="color:#e2e8f0; font-variant-numeric:tabular-nums;">100%</span>
|
||
</label>
|
||
<input type="range" id="vol-sfx" min="0" max="1" step="0.01" value="1" style="width:100%;">
|
||
|
||
<button type="button" id="vol-mute" class="btn" style="margin-top:.55rem; width:100%; padding:.3rem;"
|
||
aria-label="{{ __('city.mute') }}">🔊</button>
|
||
<p style="margin:.45rem 0 0; font-size:.7rem; color:#64748b;">{{ __('city.audio_hint') }}</p>
|
||
</div>
|
||
|
||
{{-- Click-to-start overlay (pointer lock gate) --}}
|
||
<div id="start-gate"
|
||
style="position:absolute; inset:0; display:grid; place-items:center; background:rgba(11,18,32,.75);
|
||
cursor:pointer; z-index:10; text-align:center;">
|
||
<div>
|
||
<div style="font-size:3rem; margin-bottom:.5rem;">🎮</div>
|
||
<p style="color:#fff; font-size:1.1rem; margin:0 0 .3rem;">{{ __('city.hint_fps') }}</p>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- HUD bottom-left: POSIÇÃO panel (like example images) --}}
|
||
<div id="hud-pos"
|
||
style="position:absolute; left:.6rem; bottom:.6rem; z-index:5; display:none;
|
||
background:rgba(10,15,28,.88); border:1px solid rgba(148,163,184,.25); border-radius:.4rem;
|
||
padding:.5rem .7rem; font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:.72rem;
|
||
color:#94a3b8; line-height:1.55; min-width:170px; pointer-events:none;">
|
||
<div style="color:#e2e8f0; font-weight:700; letter-spacing:.06em; font-size:.65rem; margin-bottom:.2rem;">{{ __('city.position') }}</div>
|
||
<div id="pos-xyz">x:0.0 y:1.7 z:0.0</div>
|
||
<div id="pos-ground">—</div>
|
||
<div id="pos-tris">—</div>
|
||
</div>
|
||
|
||
{{-- HUD bottom-right: selected / hint --}}
|
||
<div id="hud-hint"
|
||
style="position:absolute; right:.6rem; bottom:.6rem; z-index:5; display:flex; gap:.5rem;
|
||
pointer-events:none; flex-wrap:wrap; justify-content:flex-end;">
|
||
<span id="selected" style="background:rgba(15,23,42,.85); border:1px solid var(--border); border-radius:.5rem;
|
||
padding:.35rem .6rem; font-size:.8rem; color:#7dd3fc; display:none;"></span>
|
||
<span id="hint" style="background:rgba(15,23,42,.85); border:1px solid var(--border); border-radius:.5rem;
|
||
padding:.35rem .6rem; font-size:.75rem; color:var(--muted);">{{ __('city.hint') }}</span>
|
||
</div>
|
||
|
||
{{-- Chat panel (bottom-right, transparent — opens on bump) --}}
|
||
<div id="chat-panel"
|
||
style="position:absolute; right:.6rem; bottom:3.2rem; z-index:15; width:280px; display:none;
|
||
background:rgba(15,23,42,.62); backdrop-filter:blur(9px); -webkit-backdrop-filter:blur(9px);
|
||
border:1px solid rgba(148,163,184,.3); border-radius:.6rem;
|
||
overflow:hidden; box-shadow:0 12px 30px rgba(0,0,0,.45); flex-direction:column;">
|
||
<div id="chat-header"
|
||
style="display:flex; align-items:center; justify-content:space-between; gap:.5rem;
|
||
padding:.55rem .7rem; background:rgba(30,41,59,.55); border-bottom:1px solid rgba(148,163,184,.25);">
|
||
<div style="display:flex; align-items:center; gap:.5rem; min-width:0;">
|
||
<span id="chat-dot" style="width:8px; height:8px; border-radius:50%; background:#22c55e; flex-shrink:0;"></span>
|
||
<div style="min-width:0;">
|
||
<div id="chat-name" style="font-weight:700; font-size:.85rem; color:#fff; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;"></div>
|
||
<div id="chat-status" style="font-size:.7rem; color:var(--muted);"></div>
|
||
</div>
|
||
</div>
|
||
<div style="display:flex; gap:.3rem;">
|
||
<span id="chat-time" style="font-size:.65rem; color:var(--muted); align-self:center;"></span>
|
||
<button type="button" id="chat-close"
|
||
style="background:transparent; border:none; color:var(--muted); cursor:pointer; font-size:1rem; padding:0 .2rem;"
|
||
aria-label="Close">×</button>
|
||
</div>
|
||
</div>
|
||
<div id="chat-messages"
|
||
style="padding:.6rem .7rem; overflow-y:auto; max-height:260px; display:flex; flex-direction:column;
|
||
gap:.5rem; font-size:.78rem; line-height:1.5;"></div>
|
||
<form id="chat-form"
|
||
style="display:flex; gap:.4rem; padding:.5rem .6rem; border-top:1px solid var(--border); background:rgba(11,18,32,.7);">
|
||
<input id="chat-input" type="text" maxlength="500" required
|
||
placeholder="{{ __('city.chat_placeholder') }}"
|
||
style="flex:1; min-width:0; padding:.45rem .6rem; border-radius:.4rem; border:1px solid var(--border);
|
||
background:#0b1220; color:var(--text); font-size:.8rem;">
|
||
<button type="submit" class="btn btn-primary" style="padding:.4rem .7rem; font-size:.75rem;">
|
||
{{ __('city.chat_send') }}
|
||
</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
@endsection
|
||
|
||
@push('styles')
|
||
<style>
|
||
#scene canvas { display: block; touch-action: none; }
|
||
#chat-messages::-webkit-scrollbar { width: 6px; }
|
||
#chat-messages::-webkit-scrollbar-thumb { background: #334155; border-radius: 3px; }
|
||
.chat-bubble {
|
||
padding:.4rem .6rem; border-radius:.5rem; max-width:92%; word-break:break-word;
|
||
}
|
||
.chat-bubble.user {
|
||
background:rgba(14,165,233,.22); border:1px solid rgba(14,165,233,.4); color:#bae6fd; align-self:flex-end;
|
||
}
|
||
.chat-bubble.npc {
|
||
background:rgba(51,65,85,.55); border:1px solid rgba(148,163,184,.2); color:#e2e8f0; align-self:flex-start;
|
||
}
|
||
.chat-bubble.meta {
|
||
background:transparent; border:none; color:var(--muted); font-size:.7rem; align-self:center;
|
||
}
|
||
@media (max-width: 640px) {
|
||
#scene { height: 62vh !important; }
|
||
#hint { display: none; }
|
||
#chat-panel { width: calc(100% - 1.2rem); right: .6rem; left: .6rem; }
|
||
}
|
||
</style>
|
||
@endpush
|
||
|
||
@push('scripts')
|
||
<script>
|
||
window.CITY_CONFIG = {
|
||
dataUrl: @json(route('city.data')),
|
||
csrf: @json(csrf_token()),
|
||
i18n: {
|
||
stores: @json(__('city.stores_count')),
|
||
agents: @json(__('city.agents_count')),
|
||
vehicles: @json(__('city.vehicles_count')),
|
||
pedestrians: @json(__('city.pedestrians_count')),
|
||
open: @json(__('city.open')),
|
||
closed: @json(__('city.closed')),
|
||
selected: @json(__('city.selected')),
|
||
position: @json(__('city.position')),
|
||
onGround: @json(__('city.on_ground')),
|
||
tris: @json(__('city.triangles')),
|
||
chatThinking: @json(__('city.chat_thinking')),
|
||
chatResponding: @json(__('city.chat_responding')),
|
||
chatWith: @json(__('city.chat_with')),
|
||
chatSend: @json(__('city.chat_send')),
|
||
chatError: @json(__('city.chat_error')),
|
||
talkRateLimited: @json(__('city.talk_ratelimited')),
|
||
clock: @json(__('city.clock')),
|
||
weather: @json(__('city.weather')),
|
||
weather_clear: @json(__('city.weather_clear')),
|
||
weather_cloudy: @json(__('city.weather_cloudy')),
|
||
weather_rain: @json(__('city.weather_rain')),
|
||
weather_storm: @json(__('city.weather_storm')),
|
||
state_awake: @json(__('city.hud_state')),
|
||
actionOk: @json(__('city.action_ok')),
|
||
notFound: @json(__('city.action_unknown')),
|
||
jobs: @json(__('city.hud_jobs')),
|
||
applyJob: @json(__('city.apply_job')),
|
||
buyHint: @json(__('city.buy_hint')),
|
||
noFood: @json(__('city.no_food')),
|
||
noMoney: @json(__('city.no_money')),
|
||
noHouse: @json(__('city.no_house')),
|
||
noJob: @json(__('city.no_job')),
|
||
noMaterials: @json(__('city.no_materials')),
|
||
siteTaken: @json(__('city.site_taken')),
|
||
buildStarted: @json(__('city.build_started')),
|
||
outOfBounds: @json(__('city.out_of_bounds')),
|
||
socialFriendSent: @json(__('city.social_friend_sent')),
|
||
socialFriendOk: @json(__('city.social_friend_ok')),
|
||
socialMarriedOk: @json(__('city.social_married_ok')),
|
||
socialChildOk: @json(__('city.social_child_ok')),
|
||
chatSent: @json(__('city.chat_sent')),
|
||
me: @json(__('city.me')),
|
||
citizens: @json(__('city.citizens_near')),
|
||
hunger: @json(__('city.hud_hunger')),
|
||
thirst: @json(__('city.hud_thirst')),
|
||
energy: @json(__('city.hud_energy')),
|
||
money: @json(__('city.hud_money')),
|
||
education: @json(__('city.hud_education')),
|
||
inventory: @json(__('city.hud_inventory')),
|
||
hospitalHit: @json(__('city.hospital_hit')),
|
||
hospitalBlocked: @json(__('city.hospital_blocked')),
|
||
hospitalTitle: @json(__('city.hospital_title')),
|
||
hospitalLeft: @json(__('city.hospital_left')),
|
||
hospitalReleased: @json(__('city.hospital_released')),
|
||
exerciseUse: @json(__('city.exercise_use')),
|
||
exerciseActive: @json(__('city.exercise_active')),
|
||
exerciseStopHint: @json(__('city.exercise_stopHint')),
|
||
exerciseStart: @json(__('city.exerciseStart')),
|
||
exerciseStop: @json(__('city.exerciseStop')),
|
||
exerciseMaxHealth: @json(__('city.exercise_max_health')),
|
||
pedRed: @json(__('city.ped_red')),
|
||
},
|
||
citySlug: @json($city->slug),
|
||
};
|
||
</script>
|
||
<script type="module" src="{{ asset('js/city/app.js') }}?v={{ filemtime(public_path('js/city/app.js')) }}"></script>
|
||
@endpush
|