Jacob Schmidt 9d80e32918 Add player guide and roster member map focus
- add player-facing docs and synced screenshots
- let CAD roster entries center the map on a member
- refresh garage and economy UI bridges and docs
2026-05-19 18:55:51 -05:00

1 line
18 KiB
JavaScript

!function(){const e=window.ForgeWebUI;(window.GarageApp=window.GarageApp||{}).runtime=e,window.AppRuntime=e}(),function(){const e=window.GarageApp=window.GarageApp||{},a={garageName:"Vehicle Garage",capacityUsed:0,capacityMax:5,nearbyCount:0,spawnBlocked:!1,spawnStatus:"Ready"},r={vehicles:[]},t={vehicles:[]};function s(e,a){var r;Object.keys(e).forEach(a=>delete e[a]),Object.assign(e,(r=a,JSON.parse(JSON.stringify(r))))}e.data={categories:[{id:"all",label:"All"},{id:"car",label:"Cars"},{id:"armor",label:"Armor"},{id:"air",label:"Air"},{id:"naval",label:"Naval"},{id:"other",label:"Other"}],session:Object.assign({},a),garage:Object.assign({},r),nearby:Object.assign({},t),applyHydratePayload(e){s(this.session,Object.assign({},a,e?.session||{})),s(this.garage,Object.assign({},r,e?.garage||{})),s(this.nearby,Object.assign({},t,e?.nearby||{}))}}}(),function(){const e=window.GarageApp=window.GarageApp||{},{createSignal:a}=e.runtime;e.store=new class{constructor(){[this.getSelectedKind,this.setSelectedKind]=a(""),[this.getSelectedId,this.setSelectedId]=a(""),[this.getSearchQuery,this.setSearchQuery]=a(""),[this.getCategoryFilter,this.setCategoryFilter]=a("all"),[this.getPendingAction,this.setPendingAction]=a(""),[this.getNotice,this.setNotice]=a({type:"",text:""})}getSelection(){return{id:this.getSelectedId(),kind:this.getSelectedKind()}}clearSelection(){this.setSelectedKind(""),this.setSelectedId("")}select(e,a){this.setSelectedKind(String(e||"")),this.setSelectedId(String(a||""))}startAction(e){this.setPendingAction(String(e||""))}finishAction(){this.setPendingAction("")}matchesSelection(e){if(!e||"object"!=typeof e)return!1;const a=this.getSelection();return!(!a.kind||!a.id)&&("stored"===a.kind?"stored"===e.entryKind&&String(e.plate||"")===a.id:"nearby"===a.kind&&("nearby"===e.entryKind&&String(e.netId||"")===a.id))}ensureSelection(){const a=Array.isArray(e.data?.garage?.vehicles)?e.data.garage.vehicles:[],r=Array.isArray(e.data?.nearby?.vehicles)?e.data.nearby.vehicles:[];if([...a,...r].some(e=>this.matchesSelection(e)))return;const t=a[0]||null;if(t)return void this.select("stored",t.plate||"");const s=r[0]||null;s?this.select("nearby",s.netId||""):this.clearSelection()}hydrateFromPayload(){this.finishAction(),this.ensureSelection()}}}(),function(){const e=window.GarageApp=window.GarageApp||{},a=e.store,r=window.ForgeWebUI.createBridge({closeEvent:"garage::close",globalName:"ForgeBridge",readyEvent:"garage::ready"});function t(r){e.data.applyHydratePayload(r),a.hydrateFromPayload(r)}r.on("garage::hydrate",t),r.on("garage::sync",t),r.on("garage::retrieve::success",r=>{a.finishAction(),e.actions&&e.actions.showNotice("success",r.message||"Vehicle retrieved from the garage.")}),r.on("garage::retrieve::failure",r=>{a.finishAction(),e.actions&&e.actions.showNotice("error",r.message||"Unable to retrieve vehicle.")}),r.on("garage::store::success",r=>{a.finishAction(),e.actions&&e.actions.showNotice("success",r.message||"Vehicle stored in the garage.")}),r.on("garage::store::failure",r=>{a.finishAction(),e.actions&&e.actions.showNotice("error",r.message||"Unable to store vehicle.")}),r.on("garage::service::success",r=>{a.finishAction(),e.actions&&e.actions.showNotice("success",r.message||"Service request sent.")}),r.on("garage::service::failure",r=>{a.finishAction(),e.actions&&e.actions.showNotice("error",r.message||"Unable to service vehicle.")}),e.bridge={notifyReady:function(){return r.ready({loaded:!0})},receive:r.receive,requestClose:function(){return r.close({})},requestRefresh:function(){return r.send("garage::refresh",{})},requestRearm:function(e){return r.send("garage::vehicle::rearm::request",e)},requestRefuel:function(e){return r.send("garage::vehicle::refuel::request",e)},requestRepair:function(e){return r.send("garage::vehicle::repair::request",e)},requestRetrieve:function(e){return r.send("garage::vehicle::retrieve::request",e)},requestStore:function(e){return r.send("garage::vehicle::store::request",e)},sendEvent:r.send}}(),function(){const e=window.GarageApp=window.GarageApp||{},a=e.store;let r=null;function t(){const r=a.getSelection();return"stored"===r.kind?(Array.isArray(e.data?.garage?.vehicles)?e.data.garage.vehicles:[]).find(e=>String(e.plate||"")===r.id)||null:"nearby"===r.kind&&(Array.isArray(e.data?.nearby?.vehicles)?e.data.nearby.vehicles:[]).find(e=>String(e.netId||"")===r.id)||null}function s(e,t){a.setNotice({type:e,text:t}),r&&clearTimeout(r),r=setTimeout(()=>{a.setNotice({type:"",text:""}),r=null},3200)}e.actions={showNotice:s,closeGarage:function(){const a=e.bridge;if(a&&"function"==typeof a.requestClose){if(a.requestClose())return!0}return s("error","Garage bridge is unavailable."),!1},refreshGarage:function(){const a=e.bridge;if(a&&"function"==typeof a.requestRefresh){if(a.requestRefresh())return!0}return s("error","Garage refresh bridge is unavailable."),!1},applySearchQuery:function(e){a.setSearchQuery(String(e||"").trim())},clearSearch:function(){a.setSearchQuery("")},selectCategory:function(e){a.setCategoryFilter(String(e||"all").trim()||"all")},selectEntry:function(e,r){a.select(e,r)},getSelectedEntry:t,requestRearmSelected:function(){const r=t();if(!r||"nearby"!==r.entryKind)return s("error","Select a nearby vehicle to rearm."),!1;const i=e.bridge;return i&&"function"==typeof i.requestRearm?(a.startAction("rearm"),!!i.requestRearm({netId:r.netId||""})||(a.finishAction(),s("error","Garage rearm bridge is unavailable."),!1)):(s("error","Garage rearm bridge is unavailable."),!1)},requestRefuelSelected:function(){const r=t();if(!r||"nearby"!==r.entryKind)return s("error","Select a nearby vehicle to refuel."),!1;if(Number(r.fuel||0)>=.999)return s("error","Vehicle fuel tank is already full."),!1;const i=e.bridge;return i&&"function"==typeof i.requestRefuel?(a.startAction("refuel"),!!i.requestRefuel({netId:r.netId||""})||(a.finishAction(),s("error","Garage refuel bridge is unavailable."),!1)):(s("error","Garage refuel bridge is unavailable."),!1)},requestRepairSelected:function(){const r=t();if(!r||"nearby"!==r.entryKind)return s("error","Select a nearby vehicle to repair."),!1;if(Number(r.health||0)>=.999)return s("error","Vehicle has no reported damage."),!1;const i=e.bridge;return i&&"function"==typeof i.requestRepair?(a.startAction("repair"),!!i.requestRepair({netId:r.netId||""})||(a.finishAction(),s("error","Garage repair bridge is unavailable."),!1)):(s("error","Garage repair bridge is unavailable."),!1)},requestRetrieveSelected:function(){const r=t();if(!r||"stored"!==r.entryKind)return s("error","Select a stored vehicle to retrieve."),!1;if(e.data?.session?.spawnBlocked)return s("error","The garage spawn area is blocked."),!1;const i=e.bridge;return i&&"function"==typeof i.requestRetrieve?(a.startAction("retrieve"),!!i.requestRetrieve({plate:r.plate||""})||(a.finishAction(),s("error","Garage retrieve bridge is unavailable."),!1)):(s("error","Garage retrieve bridge is unavailable."),!1)},requestStoreSelected:function(){const r=t();if(!r||"nearby"!==r.entryKind)return s("error","Select a nearby vehicle to store."),!1;if(!1===r.isEmpty)return s("error","All crew must exit the vehicle before storing it."),!1;const i=e.bridge;return i&&"function"==typeof i.requestStore?(a.startAction("store"),!!i.requestStore({netId:r.netId||""})||(a.finishAction(),s("error","Garage store bridge is unavailable."),!1)):(s("error","Garage store bridge is unavailable."),!1)}}}(),function(){const e=window.GarageApp=window.GarageApp||{},{h:a}=e.runtime,r=window.SharedUI.componentFns.WindowTitleBar,t=e.store,s=e.actions,{categories:i,garage:n,nearby:c,session:l}=e.data;function o(e){return Math.max(0,Math.min(100,Math.round(100*Number(e||0))))}function g(e){const a=i.find(a=>a.id===String(e||"other").toLowerCase());return a?a.label:"Other"}function d(e){return`${Math.round(Number(e||0))} m`}function u(e){return String(e||"").trim()||"Untracked"}function m(e,a){return(e||[]).filter(e=>("all"===a.categoryFilter||String(e.category||"").toLowerCase()===a.categoryFilter)&&function(e,a){const r=String(e||"").trim().toLowerCase();return!r||a.some(e=>String(e||"").toLowerCase().includes(r))}(a.searchQuery,[e.displayName,e.classname,e.plate,e.netId,e.category]))}function p(e,r,t=""){return a("div",{className:t?`garage-stat-card is-${t}`:"garage-stat-card"},a("span",{className:"garage-stat-label"},e),a("span",{className:"garage-stat-value"},r))}function h(e,r,t){return a("div",{className:"garage-meter"},a("div",{className:"garage-meter-label-row"},a("span",{className:"garage-meter-label"},e),a("span",{className:"garage-meter-value"},`${r}%`)),a("div",{className:"garage-meter-track"},a("span",{className:`garage-meter-fill is-${t}`,style:{width:`${r}%`}})))}function y(e,r,t,i,n){return a("section",{className:"garage-card garage-list-card"},a("div",{className:"garage-card-header"},a("div",null,a("span",{className:"garage-eyebrow"},r),a("h2",{className:"garage-section-title"},e)),a("span",{className:"garage-pill"},`${i.length} ${1===i.length?"Vehicle":"Vehicles"}`)),a("div",{className:"garage-card-body garage-scroll-body","data-preserve-scroll-id":t},i.length>0?i.map(e=>function(e,r){const t="stored"===e.entryKind?String(e.plate||""):String(e.netId||""),i="nearby"===e.entryKind;return a("button",{type:"button",className:(n=e,c=r,n&&c&&String(n.entryKind||"")===String(c.entryKind||"")&&String(n.plate||"")===String(c.plate||"")&&String(n.netId||"")===String(c.netId||"")?"garage-vehicle-item is-selected":"garage-vehicle-item"),onClick:()=>s.selectEntry(e.entryKind,t)},a("div",{className:"garage-vehicle-item-head"},a("div",{className:"garage-vehicle-copy"},a("span",{className:"garage-vehicle-title"},e.displayName||e.classname||"Vehicle"),a("span",{className:"garage-vehicle-meta"},i?`Nearby ${d(e.distance)}`:`Plate ${u(e.plate)}`)),a("span",{className:i&&!1===e.isEmpty?"garage-badge is-warning":"garage-badge"},i?!1===e.isEmpty?"Crewed":"Empty":g(e.category))),a("div",{className:"garage-inline-meters"},h("Health",o(e.health),"health"),h("Fuel",o(e.fuel),"fuel")));var n,c}(e,n)):a("div",{className:"garage-empty-state"},a("h3",{className:"garage-empty-title"},"No matching vehicles"),a("p",{className:"garage-empty-copy"},"Adjust the current search or category filter to view more records."))))}function b(e){const r=(Array.isArray(e)?e:[]).slice().sort((e,a)=>Number(a.value||0)-Number(e.value||0)).slice(0,6).filter(e=>Number(e.value||0)>0);return 0===r.length?a("div",{className:"garage-empty-inline"},"No subsystem damage reported."):a("div",{className:"garage-hitpoint-grid"},r.map(e=>{return a("div",{className:"garage-hitpoint-row"},a("div",{className:"garage-hitpoint-copy"},a("span",{className:"garage-hitpoint-name"},(r=e.name,String(r||"").replace(/^Hit/i,"").replace(/([a-z])([A-Z])/g,"$1 $2").replace(/_/g," ").trim()||"Subsystem")),e.selection?a("span",{className:"garage-hitpoint-selection"},e.selection):null),a("span",{className:"garage-hitpoint-value"},`${Math.round(100*Number(e.value||0))}%`));var r}))}e.components=e.components||{},e.components.App=function(){const e={categoryFilter:t.getCategoryFilter(),notice:t.getNotice(),pendingAction:t.getPendingAction(),searchQuery:t.getSearchQuery(),selectedId:t.getSelectedId(),selectedKind:t.getSelectedKind()},v=function(e){return"stored"===e.selectedKind?(n.vehicles||[]).find(a=>String(a.plate||"")===e.selectedId)||null:"nearby"===e.selectedKind&&(c.vehicles||[]).find(a=>String(a.netId||"")===e.selectedId)||null}(e),f=m(n.vehicles||[],e),N=m(c.vehicles||[],e),S=e.searchQuery?`Search: ${e.searchQuery}`:"Live";return a("div",{className:"garage-shell"},r({kicker:"FORGE Logistics",title:"Vehicle Garage",onClose:()=>s.closeGarage(),closeLabel:"Close garage interface"}),e.notice.text?a("div",{className:"garage-toast-stack"},a("div",{className:"error"===e.notice.type?"garage-toast is-error":"garage-toast is-success"},e.notice.text)):null,a("div",{className:"garage-layout"},a("aside",{className:"garage-sidebar"},a("section",{className:"garage-module"},a("div",{className:"garage-module-header"},a("div",null,a("span",{className:"garage-eyebrow"},"Search"),a("h2",{className:"garage-section-title"},"Vehicle Records")),a("span",{className:"garage-pill"},S)),a("div",{className:"garage-search-form"},a("input",{id:"garage-search-input",type:"text",className:"garage-search-input",placeholder:"Search by name, plate, or category",value:e.searchQuery}),a("div",{className:"garage-search-actions"},a("button",{type:"button",className:"garage-btn garage-btn-primary",onClick:()=>s.applySearchQuery(document.getElementById("garage-search-input")?.value||"")},"Apply Search"),a("button",{type:"button",className:"garage-btn garage-btn-secondary",onClick:()=>s.clearSearch()},"Clear")))),a("section",{className:"garage-module"},a("div",{className:"garage-module-header"},a("div",null,a("span",{className:"garage-eyebrow"},"Filter"),a("h2",{className:"garage-section-title"},"Vehicle Categories"))),a("div",{className:"garage-category-grid"},i.map(r=>a("button",{type:"button",className:e.categoryFilter===r.id?"garage-chip is-active":"garage-chip",onClick:()=>s.selectCategory(r.id)},r.label)))),a("section",{className:"garage-module"},a("div",{className:"garage-module-header"},a("div",null,a("span",{className:"garage-eyebrow"},"Status"),a("h2",{className:"garage-section-title"},"Garage Summary")),a("button",{type:"button",className:"garage-btn garage-btn-secondary",disabled:Boolean(e.pendingAction),onClick:()=>s.refreshGarage()},"Refresh")),a("div",{className:"garage-summary-grid"},p("Stored",`${l.capacityUsed}/${l.capacityMax}`),p("Nearby",l.nearbyCount,"accent"),p("Spawn Lane",l.spawnStatus,l.spawnBlocked?"danger":"")))),a("main",{className:"garage-main"},a("section",{className:"garage-panel"},a("div",{className:"garage-panel-header"},a("div",null,a("span",{className:"garage-eyebrow"},"Operations Bay"),a("h1",{className:"garage-title"},l.garageName||"Vehicle Garage")),a("span",{className:"garage-pill"},`${l.capacityUsed}/${l.capacityMax} Stored`)),a("div",{className:"garage-panel-intro"},a("p",{className:"garage-copy"},"Retrieve stored vehicles into the active spawn lane or store nearby empty vehicles back into persistent ownership records.")),a("div",{className:"garage-dashboard"},y("Stored Vehicles","Persistent Records","garage-stored-list",f,v),y("Nearby Vehicles","Store Window","garage-nearby-list",N,v),function(e,r){if(!e)return a("section",{className:"garage-card garage-detail-card"},a("div",{className:"garage-card-header"},a("div",null,a("span",{className:"garage-eyebrow"},"Selection"),a("h2",{className:"garage-section-title"},"Vehicle Detail"))),a("div",{className:"garage-card-body garage-detail-empty"},a("h3",{className:"garage-empty-title"},"Select a vehicle"),a("p",{className:"garage-empty-copy"},"Choose a stored record to retrieve or a nearby vehicle to store.")));const t="stored"===e.entryKind,i=String(r.pendingAction||""),n=Boolean(i),c=t&&!l.spawnBlocked&&!n,m=!t&&!1!==e.isEmpty&&!n,y=!t&&Number(e.fuel||0)<.999&&!n,v=!t&&Number(e.health||0)<.999&&!n,f=!t&&!n;return a("section",{className:"garage-card garage-detail-card"},a("div",{className:"garage-card-header"},a("div",null,a("span",{className:"garage-eyebrow"},t?"Stored Record":"Nearby Vehicle"),a("h2",{className:"garage-section-title"},e.displayName||e.classname||"Vehicle")),a("span",{className:"nearby"===e.entryKind&&!1===e.isEmpty?"garage-badge is-warning":"garage-badge"},t?`Plate ${u(e.plate)}`:!1===e.isEmpty?"Crewed":"Ready")),a("div",{className:"garage-card-body garage-detail-body"},a("div",{className:"garage-detail-grid"},a("div",{className:"garage-detail-copy"},a("div",{className:"garage-detail-meta"},p("Category",g(e.category)),p("Status",(N=e)?"stored"===N.entryKind?"Stored":!1===N.isEmpty?"Crewed":"Ready":"-","nearby"===e.entryKind&&!1===e.isEmpty?"danger":""),p(t?"Record":"Distance",t?u(e.plate):d(e.distance),t?"":"accent")),a("div",{className:"garage-meter-stack"},h("Health",o(e.health),"health"),h("Fuel",o(e.fuel),"fuel")),a("div",{className:"garage-action-row"},t?a("button",{type:"button",className:"garage-btn garage-btn-primary",disabled:!c,onClick:()=>s.requestRetrieveSelected()},"retrieve"===i?"Retrieving...":"Retrieve Vehicle"):a("button",{type:"button",className:"garage-btn garage-btn-primary",disabled:!m,onClick:()=>s.requestStoreSelected()},"store"===i?"Storing...":"Store Vehicle"),a("button",{type:"button",className:"garage-btn garage-btn-secondary",disabled:!y,onClick:()=>s.requestRefuelSelected()},"refuel"===i?"Refueling...":"Refuel"),a("button",{type:"button",className:"garage-btn garage-btn-secondary",disabled:!v,onClick:()=>s.requestRepairSelected()},"repair"===i?"Repairing...":"Repair"),a("button",{type:"button",className:"garage-btn garage-btn-secondary",disabled:!f,onClick:()=>s.requestRearmSelected()},"rearm"===i?"Rearming...":"Rearm"),a("button",{type:"button",className:"garage-btn garage-btn-secondary garage-action-refresh",disabled:n,onClick:()=>s.refreshGarage()},"Refresh")),a("p",{className:"garage-detail-note"},t?l.spawnBlocked?"The garage spawn lane is currently blocked.":"Retrieve this stored vehicle into the active spawn lane before refuel, rearm, or repair service.":!1===e.isEmpty?"Only empty nearby vehicles can be stored.":"Store this nearby vehicle or request organization-billed refuel, rearm, and repair service.")),a("div",{className:"garage-detail-subsystems"},a("div",{className:"garage-subsystem-header"},a("span",{className:"garage-eyebrow"},"Subsystems"),a("span",{className:"garage-detail-caption"},"Highest damage first")),b(e.hitPoints)))));var N}(v,e))))),a("footer",{className:"garage-footer-bar"},a("div",{className:"garage-footer"},a("div",{className:"garage-footer-block"},a("span",{className:"garage-footer-title"},"Storage Capacity"),a("span",{className:"garage-footer-copy"},`${l.capacityUsed} of ${l.capacityMax} vehicle slot(s) are currently occupied.`)),a("div",{className:"garage-footer-block"},a("span",{className:"garage-footer-title"},"Retrieval Window"),a("span",{className:"garage-footer-copy"},l.spawnBlocked?"Spawn lane is blocked. Clear the bay before retrieving another vehicle.":"Spawn lane is clear. Stored vehicles can be retrieved immediately.")),a("div",{className:"garage-footer-block"},a("span",{className:"garage-footer-title"},"Store Rules"),a("span",{className:"garage-footer-copy"},"Only nearby empty vehicles can be stored. Nearby count updates from the live world state.")))))}}(),function(){const e=window.ForgeWebUI,a=window.GarageApp;e.createApp({name:"garage",root:"#app",setup({root:r}){e.mount(r,()=>a.components.App(),{preserveScroll:!0}),a.bridge&&a.bridge.notifyReady()}}).start()}();