Implements a flyable quadcopter with WASD/arrow controls, altitude hold, and landing. Features a scissored camera view in a command panel showing real-time feed, telemetry, and control hints. Includes localized strings for English, Spanish, and Portuguese.
418 lines
28 KiB
PHP
Executable File
418 lines
28 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>
|
||
<button type="button" id="btn-drone" class="btn" style="padding:.25rem .45rem; font-size:.75rem;">🚁 {{ __('city.drone') }}</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>
|
||
|
||
{{-- Drone command panel: header/hints opaque, #drone-video is a
|
||
transparent window — the renderer draws the drone camera
|
||
into that exact region (scissored viewport) of the canvas. --}}
|
||
<div id="drone-panel"
|
||
style="display:none; position:absolute; left:50%; top:.9rem; transform:translateX(-50%); z-index:16; width:330px;
|
||
border:1px solid rgba(148,163,184,.55); border-radius:.6rem; overflow:hidden;
|
||
box-shadow:0 12px 30px rgba(0,0,0,.5); background:transparent;">
|
||
<div id="drone-header"
|
||
style="display:flex; align-items:center; justify-content:space-between; gap:.4rem;
|
||
padding:.4rem .6rem; background:rgba(2,8,20,.88);">
|
||
<span style="font-weight:700; font-size:.8rem;">🚁 {{ __('city.drone') }}</span>
|
||
<span id="drone-tele" style="font-size:.72rem; color:#93c5fd;">↑ 0 m</span>
|
||
<button type="button" id="drone-close"
|
||
style="border:0; background:rgba(148,163,184,.18); color:#e2e8f0; border-radius:.35rem; cursor:pointer; padding:.1rem .45rem;">✕</button>
|
||
</div>
|
||
<div id="drone-video"
|
||
style="height:200px; background:transparent;
|
||
border-top:1px solid rgba(148,163,184,.35);
|
||
border-bottom:1px solid rgba(148,163,184,.35);"></div>
|
||
<div id="drone-hints"
|
||
style="padding:.4rem .6rem; font-size:.7rem; color:#cbd5e1; background:rgba(2,8,20,.88);">
|
||
{{ __('city.drone_hint') }}
|
||
</div>
|
||
</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')),
|
||
beachStart: @json(__('city.beach_start')),
|
||
beachPrompt: @json(__('city.beach_prompt')),
|
||
beachActive: @json(__('city.beach_active')),
|
||
signPlaza: @json(__('city.sign_plaza')),
|
||
signBeach: @json(__('city.sign_beach')),
|
||
signFood: @json(__('city.sign_food')),
|
||
signHospital: @json(__('city.sign_hospital')),
|
||
signSchool: @json(__('city.sign_school')),
|
||
signCityhall: @json(__('city.sign_cityhall')),
|
||
signUniversity: @json(__('city.sign_university')),
|
||
signFirestation: @json(__('city.sign_firestation')),
|
||
drone: @json(__('city.drone')),
|
||
droneHint: @json(__('city.drone_hint')),
|
||
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
|