feat: add factory sample machines and robot pricing conversations
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
import iran from '../../data/iran.json';
|
||||
import { CATEGORIES, lockedPlaces } from '../../constants/locations.js';
|
||||
import { catalog, priceAt, isOpen, fa } from '../economy/gameState.js';
|
||||
import { drawFullMap, drawIran } from '../world/mapRender.js';
|
||||
import { formatDistance } from '../../utils/geo.js';
|
||||
/**
|
||||
* Runs the size canvas operation for this subsystem.
|
||||
* @param {*} context - context.
|
||||
* @param {*} c - c.
|
||||
* @returns {*} Operation result, when applicable.
|
||||
*/
|
||||
export function sizeCanvas(context, c) {
|
||||
const r = c.getBoundingClientRect(),
|
||||
dpr = Math.min(devicePixelRatio, 2);
|
||||
c.width = Math.max(1, r.width * dpr);
|
||||
c.height = Math.max(1, r.height * dpr);
|
||||
return dpr;
|
||||
}
|
||||
/**
|
||||
* Runs the render map operation for this subsystem.
|
||||
* @param {*} context - context.
|
||||
* @returns {*} Operation result, when applicable.
|
||||
*/
|
||||
export function renderMap(context) {
|
||||
if (!context.ui.read('map-dialog').open) return;
|
||||
if (context.mapTab === 'city') {
|
||||
const dpr = context.sizeCanvas(context.mapCanvas);
|
||||
const pos = context.mode === 'drive' ? context.car : context.player;
|
||||
drawFullMap(context.mapCanvas.getContext('2d'), context.mapAssets, context.mapView, {
|
||||
dpr,
|
||||
markers: context.markers(),
|
||||
route: context.route?.points,
|
||||
selected: context.selected,
|
||||
player: {
|
||||
x: pos.x,
|
||||
z: pos.z,
|
||||
heading: context.mode === 'drive' ? context.car.heading : context.player.heading,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
const dpr = context.sizeCanvas(context.iranCanvas),
|
||||
c = context.iranCanvas.getContext('2d');
|
||||
c.setTransform(dpr, 0, 0, dpr, 0, 0);
|
||||
drawIran(c, iran, {
|
||||
width: context.iranCanvas.width / dpr,
|
||||
height: context.iranCanvas.height / dpr,
|
||||
t: context.elapsed,
|
||||
cities: context.CITIES,
|
||||
});
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Runs the render machine list operation for this subsystem.
|
||||
* @param {*} context - context.
|
||||
* @returns {*} Operation result, when applicable.
|
||||
*/
|
||||
export function renderMachineList(context) {
|
||||
const pos = context.mode === 'drive' ? context.car : context.player;
|
||||
const visited = new Set(context.state.purchases.map((p) => p.machineId));
|
||||
const items = context.activeStations().map((s) => ({
|
||||
id: s.def.id,
|
||||
name: s.def.name,
|
||||
icon: CATEGORIES[s.def.category].icon,
|
||||
category: CATEGORIES[s.def.category].label,
|
||||
visited: visited.has(s.def.id),
|
||||
open: isOpen(s.def, context.state.minutes),
|
||||
selected: s.def.id === context.selected,
|
||||
distance: formatDistance(Math.hypot(s.x - pos.x, s.z - pos.z)),
|
||||
}));
|
||||
context.ui.patch('machine-list', {
|
||||
items: [
|
||||
...items,
|
||||
...lockedPlaces.map((p) => ({
|
||||
...p,
|
||||
id: p.name,
|
||||
locked: true,
|
||||
})),
|
||||
],
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Runs the select machine operation for this subsystem.
|
||||
* @param {*} context - context.
|
||||
* @param {*} id - id.
|
||||
* @param {*} center - center.
|
||||
* @returns {*} Operation result, when applicable.
|
||||
*/
|
||||
export function selectMachine(context, id, center = false) {
|
||||
context.selected = id;
|
||||
const s = context.stationById(id),
|
||||
def = s.def;
|
||||
if (center) {
|
||||
context.mapView.cx = s.x;
|
||||
context.mapView.cz = s.z;
|
||||
context.mapView.mpp = Math.min(context.mapView.mpp, 1.4);
|
||||
}
|
||||
context.ui.patch('machine-detail', {
|
||||
hidden: false,
|
||||
});
|
||||
context.ui.patch('detail-name', {
|
||||
text: `${CATEGORIES[def.category].icon} ${def.name}`,
|
||||
});
|
||||
context.ui.patch('detail-address', {
|
||||
text: `📍 ${def.address}`,
|
||||
});
|
||||
context.ui.patch('detail-meta', {
|
||||
text: `🕒 ${context.hoursText(def)} · ${isOpen(def, context.state.minutes) ? 'الان باز است' : 'الان بسته است'} · ${def.note}`,
|
||||
});
|
||||
context.ui.patch('detail-products', {
|
||||
text: def.products
|
||||
.map((id) => `${catalog[id].icon} ${catalog[id].name} ${fa(priceAt(def, id))}`)
|
||||
.join(' · '),
|
||||
});
|
||||
context.ui.patch('route-button', {
|
||||
text: context.waypoint === id ? 'مسیر فعال است ✓' : 'مسیریابی تا اینجا',
|
||||
});
|
||||
context.renderMachineList();
|
||||
context.renderMap();
|
||||
}
|
||||
/**
|
||||
* Runs the open map operation for this subsystem.
|
||||
* @param {*} context - context.
|
||||
* @returns {*} Operation result, when applicable.
|
||||
*/
|
||||
export function openMap(context) {
|
||||
if (context.anyDialogOpen()) return;
|
||||
document.exitPointerLock?.();
|
||||
context.keys.clear();
|
||||
const pos = context.mode === 'drive' ? context.car : context.player;
|
||||
Object.assign(context.mapView, {
|
||||
cx: pos.x,
|
||||
cz: pos.z,
|
||||
mpp: 2.2,
|
||||
});
|
||||
context.ui.open('map-dialog');
|
||||
context.selected ??= context.objectiveStation()?.def.id ?? null;
|
||||
if (context.selected) context.selectMachine(context.selected);
|
||||
context.renderMachineList();
|
||||
context.renderMap();
|
||||
}
|
||||
Reference in New Issue
Block a user