Files
vending-machine-game/index.html
T
HamedandClaude Opus 5.5 0939dac9cd Start at the factory, add PWA install and GPS real-world mode
The game now begins inside the Negin Sazan Pishgam Radmehr Atousa
vending-machine factory on the Mashhad–Chenaran road, and the world
extends ~20 km along the real driving route to Park Mellat and
Ferdowsi University.

- Factory compound: production hall with assembly line, office, yard,
  gate and company signs; first mission at its half-price demo machine
- Map data merged from four OSM extracts (factory zone, route corridor,
  region main roads, city zone), clipped to a 15 x 18 km region
- City meshes chunked and culled by distance; traffic recycled around
  the player; minimap and city map drawn from cached tiles + overview
- The Robot Market robot no longer walks with the family: it comes out
  of a machine when they arrive, greets them with expression portraits
  and goes back inside when they leave
- PWA: manifest, icons from the robot avatar, offline service worker
  generated at build time, install button / iOS steps, update prompt;
  Vazirmatn font bundled instead of Google Fonts
- Real-world mode: safety notice, GPS + compass tracking with accuracy
  smoothing, 20-40 m arrival radius, speed lock and in-person bonus

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 08:56:06 +03:30

174 lines
8.7 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="fa" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">
<meta name="theme-color" content="#0d1412">
<title>عملیات مشهد | روبات مارکت</title>
<meta name="description" content="از کارخانهٔ روبات مارکت تا بوستان ملت: دستگاه‌های وندینگ را در مشهد پیدا کن و امتیاز بگیر.">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="روبات مارکت">
<link rel="manifest" href="./manifest.webmanifest">
<link rel="icon" type="image/png" href="./icons/favicon-64.png">
<link rel="apple-touch-icon" href="./icons/apple-touch-icon.png">
</head>
<body>
<canvas id="world"></canvas>
<div id="loading">در حال ساختن شهر مشهد…</div>
<!-- Mission briefing over the map of Iran -->
<section id="briefing">
<div class="brief-map"><canvas id="iran"></canvas></div>
<div class="brief-panel">
<img class="brief-robot" src="./robot/front.webp" alt="روبات راهنمای روبات مارکت" width="136" height="223">
<small class="tag">عملیات ۰۱ · خراسان رضوی</small>
<h1>عملیات مشهد</h1>
<p class="sub">روبات مارکت · شکار دستگاه‌های وندینگ</p>
<pre id="brief-text" aria-live="polite"></pre>
<button id="start-mission" type="button">شروع عملیات</button>
<div class="brief-actions">
<button id="real-mode" type="button" class="ghost">📍 بازی در دنیای واقعی (GPS)</button>
<button id="install" type="button" class="ghost" hidden>⬇ نصب بازی روی گوشی</button>
</div>
<p class="keys">حرکت: W A S D · دویدن: Shift · دوربین: ماوس · سوار و پیاده شدن: F · خرید: E · نقشه: M</p>
</div>
</section>
<!-- In-game HUD -->
<div id="hud" hidden>
<canvas id="compass" width="560" height="44"></canvas>
<button id="minimap-button" type="button" aria-label="باز کردن نقشهٔ شهر (M)">
<canvas id="minimap" width="220" height="220"></canvas>
<span class="map-hint">نقشه · M</span>
</button>
<div id="location"><span id="street">مشهد</span><small id="mode-label">پیاده</small><small id="gps-status" hidden></small></div>
<aside id="objectives">
<h2>مأموریت‌ها</h2>
<ol id="mission-list"></ol>
</aside>
<div id="waypoint" hidden><i></i><b id="waypoint-name"></b><span id="waypoint-distance"></span></div>
<div id="prompt" hidden></div>
<div id="subtitle" hidden><img id="subtitle-face" alt="" hidden><b id="subtitle-speaker"></b><span id="subtitle-text"></span></div>
<div id="awards" aria-live="polite"></div>
<div id="banner" hidden></div>
<div id="status">
<div class="stat"><small>بودجه</small><strong id="balance">۵۰۰</strong><span>هتومان</span></div>
<div class="stat"><small>ساعت</small><strong id="clock">۰۸:۳۰</strong></div>
<div class="stat" id="speed-stat" hidden><small>سرعت</small><strong id="speed">۰</strong><span>km/h</span></div>
</div>
<div id="rank"><b id="rank-name">تازه‌وارد</b><span id="xp">۰ XP</span><div class="bar"><i id="xp-bar"></i></div></div>
<div id="toolbar">
<button id="gps-toggle" type="button">📍 دنیای واقعی</button>
<button id="sound" type="button" aria-pressed="false">صدا: خاموش</button>
<button id="quality" type="button">گرافیک</button>
<button id="restart" type="button">شروع دوباره</button>
</div>
<div id="touch" hidden>
<div id="stick"><i></i></div>
<div class="touch-buttons">
<button type="button" data-key="f">F</button>
<button type="button" data-key="e">E</button>
<button type="button" data-key="shift">دویدن</button>
</div>
</div>
<div id="crosshair"></div>
<small id="attribution">نقشه: © مشارکت‌کنندگان OpenStreetMap</small>
</div>
<!-- Payment at the card reader -->
<section id="payment" hidden>
<small>کارت‌خوان روبات مارکت</small>
<h2 id="payment-title"></h2>
<p id="payment-step"></p>
<div class="actions">
<button id="swipe" type="button" disabled>کشیدن کارت · C</button>
<button id="cancel-payment" type="button" class="ghost">انصراف</button>
</div>
</section>
<dialog id="map-dialog">
<header>
<div class="tabs" role="tablist">
<button type="button" role="tab" data-tab="city" aria-selected="true">مشهد</button>
<button type="button" role="tab" data-tab="iran" aria-selected="false">ایران</button>
</div>
<button type="button" class="close" id="map-close" aria-label="بستن">✕</button>
</header>
<div class="map-body">
<div class="map-view">
<canvas id="fullmap"></canvas>
<canvas id="iran-map" hidden></canvas>
<p class="map-help">کشیدن: جابه‌جایی · چرخ ماوس: زوم · کلیک روی دستگاه: انتخاب</p>
</div>
<aside class="map-side">
<h3>دستگاه‌های روبات مارکت</h3>
<div id="machine-detail" hidden>
<h4 id="detail-name"></h4>
<p id="detail-address"></p>
<p id="detail-meta"></p>
<p id="detail-products"></p>
<button id="route-button" type="button">مسیریابی تا اینجا</button>
</div>
<ul id="machine-list"></ul>
</aside>
</div>
</dialog>
<dialog id="shop">
<header>
<div>
<small id="shop-category"></small>
<h2 id="shop-name"></h2>
<p id="shop-address"></p>
</div>
<button type="button" class="close" id="shop-close" aria-label="بستن">✕</button>
</header>
<p id="shop-note"></p>
<div id="products"></div>
<p class="rate">۱۰ هتومان = ۱۰۰٬۰۰۰ ریال · مبالغ نمایشی‌اند و پرداخت واقعی انجام نمی‌شود.</p>
</dialog>
<dialog id="real-intro">
<img src="./robot/serious.webp" alt="" width="72" height="68">
<h2>بازی در دنیای واقعی</h2>
<p>با روشن کردن این حالت، موقعیت گوشی شما (GPS) روی نقشهٔ بازی نمایش داده می‌شود. وقتی واقعاً به محل یک دستگاه روبات مارکت برسید، می‌توانید خرید کنید و ۲۰۰ امتیاز اضافه بگیرید.</p>
<ul>
<li>هنگام راه رفتن به خیابان و ماشین‌ها نگاه کنید، نه به صفحه.</li>
<li>بچه‌ها فقط همراه یک بزرگ‌تر بازی کنند.</li>
<li>هنگام رانندگی از این حالت استفاده نکنید؛ در سرعت بالا خرید غیرفعال می‌شود.</li>
<li>موقعیت شما فقط روی همین گوشی می‌ماند و جایی ارسال نمی‌شود.</li>
</ul>
<div class="actions">
<button type="button" id="real-go">قبول دارم، شروع کن</button>
<button type="button" id="real-cancel" class="ghost">انصراف</button>
</div>
</dialog>
<dialog id="ios-install">
<h2>نصب روی آیفون</h2>
<ol>
<li>در Safari دکمهٔ <b>Share</b> (مربع با فلش رو به بالا) را بزنید.</li>
<li>گزینهٔ <b>Add to Home Screen</b> را انتخاب کنید.</li>
<li>روبات مارکت مثل یک اپ روی صفحهٔ اصلی گوشی شما قرار می‌گیرد و آفلاین هم اجرا می‌شود.</li>
</ol>
<button type="button" id="ios-close">متوجه شدم</button>
</dialog>
<div id="update-toast" hidden>نسخهٔ جدید بازی آماده است <button type="button" id="update-reload">به‌روزرسانی</button></div>
<dialog id="end">
<small id="end-tag">پایان عملیات</small>
<h2 id="end-title"></h2>
<p id="end-text"></p>
<ul id="end-stats"></ul>
<div class="actions">
<button id="again" type="button">عملیات دوباره</button>
<button id="continue" type="button" class="ghost">ادامهٔ گشت در شهر</button>
</div>
</dialog>
<script type="module" src="/src/main.js"></script>
</body>
</html>