; ; /* ============================================================================ GALACTIC OPERATIONS — isolated NEXUS-VII -> base RTS tactical bridge ---------------------------------------------------------------------------- The exploration shell and the base game are separate documents so their WebGL renderers never compete. They exchange only short-lived same-tab session records addressed by opaque nonces. The base career remains live for menus, but match setup runs against a throwaway META and every career reward seam is closed while an integrated operation is active. ============================================================================ */ (function(){ const ENTRY_KEY='massfront.galactic.entry.v1'; const REQUEST_PREFIX='massfront.galactic.request.v1.'; const RESULT_PREFIX='massfront.galactic.result.v1.'; const ROUTE_PREFIX='massfront.galactic.route.v1.'; const CLASSIC_FALLBACK_KEY='massfront.galactic.classic-fallback.v1'; const CLASSIC_FALLBACK_SEARCH='?galacticFallback=classic'; const CONTENT_VERSION='catalog-8'; const LEGACY_CONTENT_VERSION='catalog-7'; const NONCE_RE=/^[A-Za-z0-9_-]{16,128}$/; const BASE_ROUTE_IDS=new Set(['operations','development','armory','orders','intel', 'profile','inbox','social','settings','game-version','war-room','mode-training','mode-standard', 'mode-campaign','mode-weekly','new-career-faction']); const PROXY_MAP={nova:'nova',dominion:'legion',syndicate:'syndicate'}; /* Secured menu routes carry only their UGA origin. They must not rewrite the base War Table to a similarly themed homeworld: Veyra is not Nordhall and Karak is not Vespera. Standard mode therefore opens at its real galaxy stage, while authored operations use the separate battlefield authority below after the player explicitly chooses a UGA map. */ const GALACTIC_EXPEDITION_LOCATION_CONTRACT={ aelos:new Set(['nexus_vii','aelos_caldris','aelos_ithara','aelos_zephyros','aelos_embassy_spindle','aelos_logistics_array','aelos_veyra_gate','aelos_heliograph','aelos_freeport']), veyra:new Set(['nexus_vii','veyra_orison','veyra_nacre','veyra_archive_hulk','veyra_aelos_gate','veyra_karak_gate','veyra_lens','veyra_ossuary']), karak:new Set(['nexus_vii','karak_meridian','karak_tethys','karak_colony_spine','karak_lifeboat_field','karak_veyra_gate','karak_spine','karak_hive']) }; function expeditionLocationAllowed(location){ const targets=GALACTIC_EXPEDITION_LOCATION_CONTRACT[location&&location.systemId]; const targetId=location&&location.targetId; if(!targets||(targetId!==null&&targetId!==undefined&&!targets.has(targetId)))return null; return {systemId:location.systemId,targetId:targetId==null?null:targetId}; } const UGA_GROUND_LOCATION_KIND='UgaGroundLocationV1'; function ugaGroundArea(id,systemId,planetId,planetName,siteId,name,missionId,runtimeRegionId,mapNames){ return {schemaVersion:1,id,systemId,planetId,planetName,siteId,name,missionId,recommendedMapId:id+'_standard',maps:[ {id:id+'_compact',size:'compact',name:mapNames[0],runtimeTemplateMapId:runtimeRegionId+'_small'}, {id:id+'_standard',size:'standard',name:mapNames[1],runtimeTemplateMapId:runtimeRegionId+'_medium'}, {id:id+'_large',size:'large',name:mapNames[2],runtimeTemplateMapId:runtimeRegionId+'_large'} ]}; } /* Difficulty layering for a region's three maps, expressed ONLY in values the War Table Standard setup already offers — timeRow 0/300/600/900/1500, paceRow 0.7/1/1.6, crRow 1/0, defFocusRow 0/1. Nothing new is invented here; these are the same functions a Standard match configures, finally driven by which map of the region you dropped on instead of by constants. Before this, every UGA operation ran timeLimit=1200, resPace=1, crateRate=1, defenseFocus=0 no matter the region or the map — so compact and large played identically and the only thing that moved was AI difficulty. 1200 was not even one of the authored timer options. The ladder: compact is a short rich scramble, standard is the neutral reference match, large is a long lean grind that rewards fortifying. */ const UGA_GROUND_TACTICAL_PROFILES={ compact: {tier:1,timeLimit:600, resPace:1.6,crateRate:1,defenseFocus:0,wildcards:0,enemies:1}, standard:{tier:2,timeLimit:900, resPace:1, crateRate:1,defenseFocus:0,wildcards:1,enemies:1}, large: {tier:3,timeLimit:1500,resPace:0.7,crateRate:1,defenseFocus:1,wildcards:2,enemies:2} }; /* Enemies never take sw or se — those are the two HQ landing zones a player can choose, and an enemy sharing the player's spawn is not a difficulty setting, it is a broken match. */ const UGA_ENEMY_ZONES=['ne','nw','c']; function ugaGroundTacticalProfile(size){ return UGA_GROUND_TACTICAL_PROFILES[size]||UGA_GROUND_TACTICAL_PROFILES.standard; } /* The HQ Ship Landing Zone the player actually chose in the deployment planner. Every mission authors two, the operation carries the choice as landingZoneId, and the bridge used to discard it and spawn at 'sw' every single time — so one of the two real decisions on the deployment screen did nothing. The primary zone keeps 'sw', opposite the enemy at 'ne'; the alternate takes 'se', which starts closer to them. That is the tactical difference the choice is offering, expressed in the same spawn zones Standard already uses. tools/test-uga-deployment-bridge.mjs asserts this covers exactly the catalog's landing zones, so adding one without a spawn fails the build. */ const UGA_LANDING_ZONE_SPAWNS={ relay_shadow:'sw', maintenance_spar:'se', customs_ring:'sw', cargo_lock:'se', service_lock:'sw', freight_shadow:'se', broken_spine:'sw', aft_lattice:'se', umbra_platform:'sw', coolant_trench:'se', vault_aperture:'sw', collapsed_gallery:'se', clinic_roof:'sw', transit_court:'se', maintenance_shaft:'sw', sealed_platform:'se', vascular_breach:'sw', thermal_vent:'se' }; function ugaLandingSpawn(landingZoneId){ return UGA_LANDING_ZONE_SPAWNS[landingZoneId]||'sw'; } /* Doctrine decides the landing package, using the two Standard already ships. 'expedition' was hardcoded, so a methodical or containment plan landed with the same HQ-and-Constructor opening as a covert raid. prepared brings HQ, Reactor, Factory and Constructor together; expedition is the build-from-zero opening — which is what rapid and covert are choosing. */ const UGA_DOCTRINE_PACKAGES={methodical:'prepared',containment:'prepared',rapid:'expedition',covert:'expedition'}; function ugaDoctrinePackage(doctrineId){ return UGA_DOCTRINE_PACKAGES[doctrineId]||'expedition'; } /* Player identity and internal terrain-template identity are deliberately separate. Runtime map IDs never cross back into the UGA operation copy. */ const GALACTIC_GROUND_AREA_AUTHORITY={ nova_heliograph_wake:ugaGroundArea('aelos_heliograph','aelos','aelos_caldris','Caldris','aelos_heliograph','Heliograph High Shelf','nova_heliograph_wake','aelos_ridge',['Relay Shadow','Control Spine','Great Divide Array']), dominion_caldris_claim:ugaGroundArea('aelos_caldris_customs','aelos','aelos_caldris','Caldris','aelos_caldris','Caldris Customs Zone','dominion_caldris_claim','aelos_north',['Cargo Lock','Customs Ring','Orbital Apron']), syndicate_black_manifest:ugaGroundArea('aelos_morrow_freeport','aelos','aelos_ithara','Ithara','aelos_freeport','Morrow Freeport','syndicate_black_manifest','aelos_coast',['Service Lock','Freight Shadow','Freeport Concourse']), nova_orison_recovery:ugaGroundArea('veyra_orison_derelict','veyra','veyra_orison','Orison','veyra_orison','Orison Derelict','nova_orison_recovery','nordhall_isles',['Aft Lattice','Broken Spine','Derelict Superstructure']), dominion_lens_perimeter:ugaGroundArea('veyra_lensing_observatory','veyra','veyra_nacre','Nacre','veyra_lens','Lensing Observatory','dominion_lens_perimeter','nordhall_peaks',['Coolant Trench','Calibration Core','Umbra Platform']), syndicate_ossuary_dividend:ugaGroundArea('veyra_ossuary_vault','veyra','veyra_nacre','Nacre','veyra_ossuary','Ossuary Vault','syndicate_ossuary_dividend','nordhall_frost',['Vault Aperture','Phase Engine Gallery','Collapsed Gallery']), uga_pale_bloom:ugaGroundArea('karak_meridian_quarantine','karak','karak_meridian','Meridian K-4','karak_meridian','Meridian Quarantine','uga_pale_bloom','vespera_plateau',['Clinic Roof','Transit Court','Breeder Zone']), uga_silent_spine:ugaGroundArea('karak_transit_spine','karak','karak_meridian','Meridian K-4','karak_spine','Colony Transit Spine','uga_silent_spine','vespera_dunes',['Maintenance Shaft','Sealed Platform','Gestation Junction']), uga_hive_heart:ugaGroundArea('karak_primary_hive','karak','karak_meridian','Meridian K-4','karak_hive','Karak Primary Hive','uga_hive_heart','vespera_spire',['Vascular Breach','Thermal Vent','Hive Core']) }; function playerGroundLocation(area,map){ return {schemaVersion:1,kind:UGA_GROUND_LOCATION_KIND,systemId:area.systemId,planetId:area.planetId, areaId:area.id,siteId:area.siteId,mapId:map.id,size:map.size,display:{ systemName:{aelos:'Aelos',veyra:'Veyra',karak:'Karak'}[area.systemId],planetName:area.planetName, areaName:area.name,mapName:map.name}}; } function operationBattlefield(operation,contentVersion){ const area=GALACTIC_GROUND_AREA_AUTHORITY[operation&&operation.missionId]; if(!area||operation.systemId!==area.systemId||operation.siteId!==area.siteId)return null; const supplied=operation.battlefield&&operation.battlefield.location; const legacyRecovered=!supplied&&contentVersion===LEGACY_CONTENT_VERSION; const mapId=legacyRecovered?area.recommendedMapId:supplied&&supplied.mapId; const map=area.maps.find(entry=>entry.id===mapId); if(!map)return null; const playerLocation=playerGroundLocation(area,map); if(!legacyRecovered&&!sameJson(supplied,playerLocation))return null; return {playerLocation,runtimeMapId:map.runtimeTemplateMapId,runtimeRegionId:map.runtimeTemplateMapId.replace(/_(?:small|medium|large)$/,''),legacyRecovered}; } const OPPONENT_MAP={brood:'horde',nova:'nova',dominion:'legion',syndicate:'syndicate'}; const COMMANDER_ROSTER_FINGERPRINT='fnv1a32:0aadcd2d'; const COMMANDER1_BY_FACTION={nova:'nova_kai',dominion:'legion_vex',syndicate:'syndicate_renn'}; const COMMANDER_AUTHORITY=[ ['nova_kai','nova','nova','Captain Elara Kai','Captain','Kai','LANTERN','VANGUARD','kai'], ['nova_holt','nova','nova','Major Rowan Holt','Major','Holt','ANVIL','ENGINEER','holt'], ['nova_vale','nova','nova','Cmdr. Sera Vale','Commander','Vale','LONGSIGHT','TACTICIAN','vale'], ['legion_vex','legion','dominion','Lord Darion Vex','Lord','Vex','ASCENDANT','JUGGERNAUT','vex'], ['legion_korr','legion','dominion','Marshal Rhea Korr','Marshal','Korr','CADENCE','WARMASTER','korr'], ['legion_dravik','legion','dominion','Prefect Amon Dravik','Prefect','Dravik','REDOUBT','FORTIFIER','dravik'], ['syndicate_renn','syndicate','syndicate','Broker Lys Renn','Broker','Renn','LEDGER','BROKER','renn'], ['syndicate_nyx','syndicate','syndicate','Operative Nyx Calder','Operative','Calder','GHOST','INFILTRATOR','nyx'], ['syndicate_voss','syndicate','syndicate','Director Oren Voss','Director','Voss','CORE','CONTROLLER','voss'] ]; const COMMANDER_BY_ID=Object.fromEntries(COMMANDER_AUTHORITY.map(row=>[row[0],row])); const DEPLOY_UNIT_SPEC={ recon_team:{slotCost:1,type:'Striker',perGroup:1}, line_section:{slotCost:2,type:'Striker',perGroup:2}, support_vehicle:{slotCost:2,type:'Warden',perGroup:1}, armored_element:{slotCost:3,type:'Rhino',perGroup:1} }; const DEPLOY_STRUCTURE_SPEC={ field_relay:{slotCost:1,type:'uplink'}, resource_processor:{slotCost:2,type:'pgen'}, defensive_emplacement:{slotCost:2,type:'turret'}, forward_command:{slotCost:4,type:'fac'} }; /* This receiver cannot consume the exploration ES modules: every root src file is a classic script in one global scope. Keep the small authored mission authority here and lock its parity with tools/test-stage9-galactic-bridge. Accepting only a general shape would let edited sessionStorage invent an operation that the expedition catalog never authored. */ const GALACTIC_MISSION_AUTHORITY={ nova_heliograph_wake:{missionType:'faction_conflict',systemId:'aelos',siteId:'aelos_heliograph',contractFactionId:'nova',opponentFactionId:'dominion',accessFactionId:'nova',objective:{type:'secure_relay',targetIds:['heliograph_control_spine']},landingZoneIds:['relay_shadow','maintenance_spar'],supportIds:['survey_drones','field_lab'],doctrineIds:['methodical','rapid']}, dominion_caldris_claim:{missionType:'faction_conflict',systemId:'aelos',siteId:'aelos_caldris',contractFactionId:'dominion',opponentFactionId:'syndicate',accessFactionId:'dominion',objective:{type:'hold_infrastructure',targetIds:['caldris_customs_core']},landingZoneIds:['customs_ring','cargo_lock'],supportIds:['field_lab','heavy_lift'],doctrineIds:['methodical','rapid']}, syndicate_black_manifest:{missionType:'faction_conflict',systemId:'aelos',siteId:'aelos_freeport',contractFactionId:'syndicate',opponentFactionId:'nova',accessFactionId:'syndicate',objective:{type:'recover_manifest',targetIds:['morrow_archive_stack']},landingZoneIds:['service_lock','freight_shadow'],supportIds:['survey_drones','field_lab'],doctrineIds:['covert','rapid']}, nova_orison_recovery:{missionType:'faction_conflict',systemId:'veyra',siteId:'veyra_orison',contractFactionId:'nova',opponentFactionId:'syndicate',accessFactionId:'nova',objective:{type:'recover_archive',targetIds:['orison_memory_vault']},landingZoneIds:['broken_spine','aft_lattice'],supportIds:['survey_drones','field_lab','medevac'],doctrineIds:['methodical','covert']}, dominion_lens_perimeter:{missionType:'faction_conflict',systemId:'veyra',siteId:'veyra_lens',contractFactionId:'dominion',opponentFactionId:'nova',accessFactionId:'dominion',objective:{type:'secure_observatory',targetIds:['lensing_calibration_core']},landingZoneIds:['umbra_platform','coolant_trench'],supportIds:['field_lab','heavy_lift','medevac'],doctrineIds:['methodical','rapid']}, syndicate_ossuary_dividend:{missionType:'faction_conflict',systemId:'veyra',siteId:'veyra_ossuary',contractFactionId:'syndicate',opponentFactionId:'dominion',accessFactionId:'syndicate',objective:{type:'extract_artifact',targetIds:['ossuary_phase_engine']},landingZoneIds:['vault_aperture','collapsed_gallery'],supportIds:['survey_drones','field_lab','medevac'],doctrineIds:['covert','methodical']}, uga_pale_bloom:{missionType:'uga_brood_purge',systemId:'karak',siteId:'karak_meridian',contractFactionId:null,opponentFactionId:'brood',accessFactionId:null,objective:{type:'purge_brood',infestation:true,hiveTargetIds:['meridian_breeder_nest'],nestCount:1},landingZoneIds:['clinic_roof','transit_court'],supportIds:['survey_drones','field_lab','medevac','heavy_lift'],doctrineIds:['containment','methodical','rapid']}, uga_silent_spine:{missionType:'uga_brood_purge',systemId:'karak',siteId:'karak_spine',contractFactionId:null,opponentFactionId:'brood',accessFactionId:null,objective:{type:'purge_brood',infestation:true,hiveTargetIds:['spine_gestation_cluster','spine_feeder_root'],nestCount:2},landingZoneIds:['maintenance_shaft','sealed_platform'],supportIds:['field_lab','medevac','heavy_lift'],doctrineIds:['containment','methodical']}, uga_hive_heart:{missionType:'uga_brood_purge',systemId:'karak',siteId:'karak_hive',contractFactionId:null,opponentFactionId:'brood',accessFactionId:null,objective:{type:'purge_brood',infestation:true,hiveTargetIds:['karak_hive_heart'],nestCount:1},landingZoneIds:['vascular_breach','thermal_vent'],supportIds:['field_lab','medevac','heavy_lift'],doctrineIds:['containment','methodical']} }; /* UGA objective names are more specific than the base RTS's four proven victory rules. Faction contracts are all battles for control of a named asset, so Domination is the honest production rule: control the theatre when the clock expires, or break hostile command early. Brood operations retain the dedicated hive rule. Never invent a fifth goal ID here: the old `destroy` value was not registered by GOALS, so goalDef silently displayed and executed Annihilation instead of the operation the player accepted. */ const TACTICAL_OBJECTIVE_RULES={ secure_relay:{id:'domination',em:'\u2691',hud:'RELAY',nm:'Relay Security',ds:'Control the most battlefield infrastructure when the clock ends to secure the relay.'}, hold_infrastructure:{id:'domination',em:'\u2691',hud:'HOLD',nm:'Infrastructure Hold',ds:'Hold the most battlefield infrastructure when the clock ends.'}, recover_manifest:{id:'domination',em:'\u25c7',hud:'MANIFEST',nm:'Manifest Recovery',ds:'Control the field when the clock ends so recovery teams can secure the manifest.'}, recover_archive:{id:'domination',em:'\u25c7',hud:'ARCHIVE',nm:'Archive Recovery',ds:'Control the field when the clock ends so recovery teams can secure the archive.'}, secure_observatory:{id:'domination',em:'\u2691',hud:'LENS',nm:'Observatory Security',ds:'Control the most battlefield infrastructure when the clock ends to secure the observatory.'}, extract_artifact:{id:'domination',em:'\u25c7',hud:'ARTIFACT',nm:'Artifact Extraction',ds:'Control the field when the clock ends so the artifact can be extracted.'}, purge_brood:{id:'purge',em:'\ud83d\udc1b',hud:'HIVES',nm:'Brood Purge',ds:'Destroy every active Brood hive before time runs out.'} }; function resolveTacticalObjective(operation){ const objective=operation&&operation.objective,rule=TACTICAL_OBJECTIVE_RULES[objective&&objective.type]; if(!rule)throw new Error('GALACTIC_OPERATION_OBJECTIVE_UNMAPPED'); return Object.freeze({id:rule.id,em:rule.em,hud:rule.hud,nm:rule.nm,ds:rule.ds,objectiveType:objective.type}); } const GROUND_OPERATION_V3_FIELDS=['schemaVersion','kind','profileId','sequence','launchRevision','missionId','missionType','systemId','siteId','sponsorId','contractFactionId','proxyFactionId','playerFactionId','opponentFactionId','commanderId','specialistIds','doctrineId','supportId','landingZoneId','configuration','objective','difficulty','intelligence','battlefield','scanTierAtLaunch','threatAtLaunch','factionSnapshot','personnelSnapshot','deploymentManifest','deploymentCost','rewardModifiers','rewardPlan','returnRoute','commanderRosterFingerprint','commanderIdentity','operationId','resultSeed','returnToken']; const OPERATION_MOD_IDS=new Set(['survey_link','repair_nanites','medical_cache']); const DOCTRINE_SCORE_DELTA={containment:8,methodical:7,rapid:2,covert:5}; const SUPPORT_SCORE_DELTA={survey_drones:4,field_lab:2,medevac:1,heavy_lift:5}; const PLAIN_OBJECT=Object.prototype; const bridge={active:false,status:'idle',reason:'',nonce:'',request:null,report:null, sandboxMeta:null,returning:false,isolated:false,packageApplied:false, packageSummary:null,reportCandidate:null,reportCandidateBytes:'', operationEffects:null,tacticalGoal:null,playerLocation:null,runtimeMapId:'',naniteUnits:[],suppressedPersistentCrates:0, suppressedPostMatchAds:0,suppressedBillboardImpressions:0,menuRouteActive:false}; function clone(value){ return value===undefined?undefined:JSON.parse(JSON.stringify(value)); } function freezeJson(value){ if(value&&typeof value==='object'&&!Object.isFrozen(value)){ for(const key of Object.keys(value))freezeJson(value[key]); Object.freeze(value); } return value; } function normalizeStable(value){ if(value===null||typeof value==='string'||typeof value==='boolean')return value; if(typeof value==='number'){ if(!Number.isFinite(value))throw new TypeError('Deterministic values require finite numbers'); return Object.is(value,-0)?0:value; } if(Array.isArray(value))return value.map(normalizeStable); if(typeof value==='object'&&(Object.getPrototypeOf(value)===PLAIN_OBJECT ||Object.prototype.toString.call(value)==='[object Object]')){ const normalized={}; for(const key of Object.keys(value).sort())if(value[key]!==undefined)normalized[key]=normalizeStable(value[key]); return normalized; } throw new TypeError('Deterministic values require JSON-compatible plain data'); } function stableStringify(value){return JSON.stringify(normalizeStable(value));} function hash32(value){ const text=typeof value==='string'?value:stableStringify(value); let hash=0x811c9dc5; for(let i=0;i>>0).toString(16).padStart(8,'0'); } function envelopeChecksum(value){ const copy=clone(value);delete copy.checksum;return hash32(copy); } function issue(issues,code){issues.push(code);} function result(ok,issues){return Object.freeze({ok,issues:Object.freeze(issues.slice())});} function text(value){return typeof value==='string'?value.trim():'';} function exactKeys(value,keys){ return !!value&&typeof value==='object'&&!Array.isArray(value) &&stableStringify(Object.keys(value).sort())===stableStringify(keys.slice().sort()); } function sameJson(left,right){ try{return stableStringify(left)===stableStringify(right);}catch(e){return false;} } function commanderIdentityFromRoster(entry){ return entry&&{ id:entry.id,sourceFactionId:entry.sourceFactionId,campaignFactionId:entry.campaignFactionId, name:entry.name,rank:entry.rank,shortName:entry.shortName,callsign:entry.callsign, role:entry.role,trait:entry.passive&&entry.passive.perk }; } function validateCommanderRosterSnapshot(snapshot){ const issues=[]; if(!snapshot||typeof snapshot!=='object'||Array.isArray(snapshot))return result(false,['COMMANDER_ROSTER_NOT_OBJECT']); if(!exactKeys(snapshot,['schemaVersion','kind','source','sourceVersion','commanderCount','commander1ByCampaignFaction','commanders','fingerprint']))issue(issues,'COMMANDER_ROSTER_SCHEMA_INVALID'); if(snapshot.schemaVersion!==1||snapshot.kind!=='CommanderRosterSnapshotV1'||snapshot.source!=='massfront-base'||!Number.isInteger(snapshot.sourceVersion)||snapshot.sourceVersion<1)issue(issues,'COMMANDER_ROSTER_VERSION_INVALID'); if(stableStringify(snapshot.commander1ByCampaignFaction)!==stableStringify(COMMANDER1_BY_FACTION))issue(issues,'COMMANDER_ROSTER_COMMANDER1_INVALID'); if(!Array.isArray(snapshot.commanders)||snapshot.commanders.length!==9||snapshot.commanderCount!==9)issue(issues,'COMMANDER_ROSTER_COUNT_INVALID'); else snapshot.commanders.forEach((entry,index)=>{ const row=COMMANDER_AUTHORITY[index]; if(!entry||entry.id!==row[0]||entry.sourceFactionId!==row[1]||entry.campaignFactionId!==row[2] ||entry.name!==row[3]||entry.rank!==row[4]||entry.shortName!==row[5]||entry.callsign!==row[6] ||entry.role!==row[7]||entry.passive?.perk!==row[8])issue(issues,'COMMANDER_ROSTER_AUTHORITY_MISMATCH'); }); let computed=''; try{const payload=clone(snapshot);delete payload.fingerprint;computed='fnv1a32:'+hash32(payload);}catch(e){} if(snapshot.fingerprint!==COMMANDER_ROSTER_FINGERPRINT||computed!==COMMANDER_ROSTER_FINGERPRINT)issue(issues,'COMMANDER_ROSTER_FINGERPRINT_INVALID'); return result(!issues.length,issues); } function describeOperationEffects(operation){ const doctrineId=operation&&operation.doctrineId,supportId=operation&&operation.supportId; const modIds=Array.isArray(operation?.deploymentManifest?.modIds)?operation.deploymentManifest.modIds:[]; const matchApplied=[]; if(modIds.includes('survey_link'))matchApplied.push({layer:'match',source:'mod',id:'survey_link', effect:'deployment-scan',seconds:24,radius:15}); if(modIds.includes('repair_nanites'))matchApplied.push({layer:'match',source:'mod',id:'repair_nanites', effect:'starting-unit-repair-reserve',reserveMaxHpPct:20,repairMaxHpPctPerSecond:1}); const scoreApplied=[ {layer:'score',source:'doctrine',id:doctrineId,effect:'tactical-score',delta:DOCTRINE_SCORE_DELTA[doctrineId]||0}, {layer:'score',source:'support',id:supportId,effect:'tactical-score',delta:SUPPORT_SCORE_DELTA[supportId]||0} ]; const moduleResultApplied=[]; if(modIds.includes('medical_cache'))moduleResultApplied.push({layer:'module-result',source:'mod',id:'medical_cache', effect:'injury-severity-minus-one'}); return freezeJson({matchApplied,scoreApplied,moduleResultApplied, tacticalScoreDelta:scoreApplied.reduce((sum,item)=>sum+item.delta,0)}); } function validateEntryTicket(ticket,now,profileId){ const issues=[],at=Math.max(0,Math.floor(Number(now)||Date.now())); if(!ticket||typeof ticket!=='object'||Array.isArray(ticket))return result(false,['ENTRY_NOT_OBJECT']); if(!exactKeys(ticket,['schemaVersion','kind','profileId','issuedAt','expiresAt','source','entryView','introRequired','commanderRosterSnapshot','commanderRosterFingerprint','commissioning']))issue(issues,'ENTRY_FIELDS_INVALID'); if(ticket.schemaVersion!==2||ticket.kind!=='MassfrontGalacticEntryV2'||ticket.source!=='massfront-base')issue(issues,'ENTRY_SCHEMA_INVALID'); if(ticket.entryView!=='system'&&ticket.entryView!=='campaign_hub')issue(issues,'ENTRY_VIEW_INVALID'); if(typeof ticket.introRequired!=='boolean')issue(issues,'ENTRY_INTRO_INVALID'); if(!text(ticket.profileId)||ticket.profileId!==profileId)issue(issues,'ENTRY_PROFILE_MISMATCH'); if(!Number.isInteger(ticket.issuedAt)||!Number.isInteger(ticket.expiresAt) ||ticket.issuedAt<0||ticket.expiresAt<=ticket.issuedAt ||ticket.expiresAt-ticket.issuedAt>7*24*60*60*1000 ||ticket.expiresAt<=at||ticket.issuedAt>at)issue(issues,'ENTRY_EXPIRED'); issues.push(...validateCommanderRosterSnapshot(ticket.commanderRosterSnapshot).issues); if(ticket.commanderRosterFingerprint!==COMMANDER_ROSTER_FINGERPRINT ||ticket.commanderRosterFingerprint!==ticket.commanderRosterSnapshot?.fingerprint)issue(issues,'ENTRY_COMMANDER_ROSTER_STALE'); const commissioning=ticket.commissioning; if(!exactKeys(commissioning,['factionId','commanderId']))issue(issues,'ENTRY_COMMISSIONING_INVALID'); else if(commissioning.factionId===null&&commissioning.commanderId===null){} else if(!Object.prototype.hasOwnProperty.call(COMMANDER1_BY_FACTION,commissioning.factionId) ||!Object.prototype.hasOwnProperty.call(COMMANDER_BY_ID,commissioning.commanderId) ||COMMANDER1_BY_FACTION[commissioning.factionId]!==commissioning.commanderId)issue(issues,'ENTRY_COMMISSIONING_INVALID'); return result(!issues.length,issues); } function validateRouteRequest(request,nonce,profileId,now){ const issues=[],at=Math.max(0,Math.floor(Number(now)||Date.now())); if(!request||typeof request!=='object'||Array.isArray(request))return result(false,['ROUTE_NOT_OBJECT']); if(!exactKeys(request,['schemaVersion','kind','nonce','profileId','routeId','issuedAt','expiresAt','source','location','checksum']))issue(issues,'ROUTE_FIELDS_INVALID'); if(request.schemaVersion!==2||request.kind!=='MassfrontGalacticRouteRequestV2' ||request.source!=='massfront-exploration')issue(issues,'ROUTE_SCHEMA_INVALID'); if(!NONCE_RE.test(text(nonce))||request.nonce!==nonce)issue(issues,'ROUTE_NONCE_INVALID'); if(!text(profileId)||request.profileId!==profileId)issue(issues,'ROUTE_PROFILE_MISMATCH'); if(!BASE_ROUTE_IDS.has(request.routeId))issue(issues,'ROUTE_TARGET_INVALID'); if(!exactKeys(request.location,['systemId','targetId'])||!expeditionLocationAllowed(request.location))issue(issues,'ROUTE_LOCATION_INVALID'); if(!Number.isInteger(request.issuedAt)||!Number.isInteger(request.expiresAt) ||request.expiresAt<=request.issuedAt||request.expiresAt-request.issuedAt>2*60*1000 ||request.expiresAt<=at||request.issuedAt>at+30000)issue(issues,'ROUTE_EXPIRED'); try{if(request.checksum!==envelopeChecksum(request))issue(issues,'ROUTE_CHECKSUM_INVALID');} catch(e){issue(issues,'ROUTE_CHECKSUM_INVALID');} return result(!issues.length,issues); } function validateTacticalReport(reportValue,operation){ const issues=[],team=new Set([operation&&operation.commanderId,...((operation&&operation.specialistIds)||[])]); if(!reportValue||typeof reportValue!=='object'||Array.isArray(reportValue))return result(false,['REPORT_NOT_OBJECT']); if(reportValue.outcome!=='victory'&&reportValue.outcome!=='setback')issue(issues,'REPORT_OUTCOME_INVALID'); if(!Number.isInteger(reportValue.score)||reportValue.score<0||reportValue.score>100)issue(issues,'REPORT_SCORE_INVALID'); if(typeof reportValue.primaryObjectiveComplete!=='boolean')issue(issues,'REPORT_OBJECTIVE_INVALID'); if(!Number.isInteger(reportValue.secondaryObjectivesComplete)||reportValue.secondaryObjectivesComplete<0||reportValue.secondaryObjectivesComplete>3)issue(issues,'REPORT_SECONDARY_INVALID'); if(!['none','light','moderate','severe'].includes(reportValue.injuryBand))issue(issues,'REPORT_INJURY_BAND_INVALID'); if(!Array.isArray(reportValue.injuredPersonnelIds) ||new Set(reportValue.injuredPersonnelIds).size!==reportValue.injuredPersonnelIds.length ||reportValue.injuredPersonnelIds.some(id=>!team.has(id)))issue(issues,'REPORT_TEAM_INVALID'); else if(reportValue.injuryBand==='none'&&reportValue.injuredPersonnelIds.length)issue(issues,'REPORT_INJURY_CONFLICT'); if(reportValue.outcome==='victory'&&reportValue.primaryObjectiveComplete!==true)issue(issues,'REPORT_VICTORY_OBJECTIVE_INVALID'); if(reportValue.outcome==='setback'&&reportValue.primaryObjectiveComplete!==false)issue(issues,'REPORT_SETBACK_OBJECTIVE_INVALID'); return result(!issues.length,issues); } function validateResultMirror(mirror,nonce,profileId,request,now){ const issues=[],at=Math.max(0,Math.floor(Number(now)||Date.now())); if(!mirror||typeof mirror!=='object'||Array.isArray(mirror))return result(false,['RESULT_NOT_OBJECT']); if(mirror.schemaVersion!==1||mirror.kind!=='MassfrontGalacticTacticalReportV1')issue(issues,'RESULT_SCHEMA_INVALID'); if(mirror.nonce!==nonce||mirror.accountId!==profileId ||mirror.operationId!==request?.operation?.operationId)issue(issues,'RESULT_IDENTITY_INVALID'); if(!Number.isInteger(mirror.issuedAt)||mirror.issuedAtrequest?.expiresAt||mirror.issuedAt>at||at>request?.expiresAt)issue(issues,'RESULT_TIME_INVALID'); try{if(mirror.checksum!==envelopeChecksum(mirror))issue(issues,'RESULT_CHECKSUM_INVALID');} catch(e){issue(issues,'RESULT_CHECKSUM_INVALID');} issues.push(...validateTacticalReport(mirror.report,request&&request.operation).issues); return result(!issues.length,issues); } function validateDeploymentContract(operation){ const issues=[],mission=GALACTIC_MISSION_AUTHORITY[operation&&operation.missionId],manifest=operation&&operation.deploymentManifest,configuration=operation&&operation.configuration; if(!mission||!mission.doctrineIds.includes(operation&&operation.doctrineId) ||configuration?.doctrineId!==operation.doctrineId||configuration?.approach!==operation.doctrineId)issue(issues,'OPERATION_DOCTRINE_INVALID'); if(!mission||!mission.supportIds.includes(operation&&operation.supportId) ||configuration?.supportId!==operation.supportId||configuration?.support!==operation.supportId)issue(issues,'OPERATION_SUPPORT_INVALID'); if(!mission||!mission.landingZoneIds.includes(operation&&operation.landingZoneId) ||configuration?.landingZoneId!==operation.landingZoneId ||operation?.battlefield?.landingZoneId!==operation.landingZoneId)issue(issues,'OPERATION_LANDING_ZONE_INVALID'); if(!manifest||typeof manifest!=='object'||Array.isArray(manifest))return result(false,issues.concat('OPERATION_MANIFEST_INVALID')); if(!Array.isArray(manifest.units)||!Array.isArray(manifest.structures)||!Array.isArray(manifest.modIds))issue(issues,'OPERATION_MANIFEST_SHAPE_INVALID'); const unitIds=new Set(),structureIds=new Set();let unitGroups=0,structureCount=0,slotsUsed=0; for(const entry of Array.isArray(manifest.units)?manifest.units:[]){ const spec=entry&&DEPLOY_UNIT_SPEC[entry.id]; if(!spec||unitIds.has(entry.id)||!Number.isInteger(entry.count)||entry.count<1||entry.count>8 ||entry.slotCost!==spec.slotCost){issue(issues,'OPERATION_MANIFEST_UNIT_INVALID');continue;} unitIds.add(entry.id);unitGroups+=entry.count;slotsUsed+=entry.count*spec.slotCost; } for(const entry of Array.isArray(manifest.structures)?manifest.structures:[]){ const spec=entry&&DEPLOY_STRUCTURE_SPEC[entry.id]; if(!spec||structureIds.has(entry.id)||!Number.isInteger(entry.count)||entry.count<1||entry.count>8 ||entry.slotCost!==spec.slotCost){issue(issues,'OPERATION_MANIFEST_STRUCTURE_INVALID');continue;} structureIds.add(entry.id);structureCount+=entry.count;slotsUsed+=entry.count*spec.slotCost; } const modIds=Array.isArray(manifest.modIds)?manifest.modIds:[]; if(new Set(modIds).size!==modIds.length||modIds.some(id=>!OPERATION_MOD_IDS.has(id)))issue(issues,'OPERATION_MANIFEST_MOD_INVALID'); if(manifest.slotCapacity<8||manifest.slotCapacity>16||!Number.isInteger(manifest.slotCapacity) ||manifest.slotsUsed!==slotsUsed||slotsUsed>manifest.slotCapacity)issue(issues,'OPERATION_MANIFEST_CAPACITY_INVALID'); if(manifest.unitLimit!==4||unitGroups<1||unitGroups>manifest.unitLimit||!unitIds.has('line_section'))issue(issues,'OPERATION_MANIFEST_UNIT_LIMIT_INVALID'); if(manifest.structureLimit!==2||structureCount>manifest.structureLimit)issue(issues,'OPERATION_MANIFEST_STRUCTURE_LIMIT_INVALID'); if(!Number.isInteger(manifest.modLimit)||manifest.modLimit<2||manifest.modLimit>3||modIds.length>manifest.modLimit)issue(issues,'OPERATION_MANIFEST_MOD_LIMIT_INVALID'); try{if(stableStringify(clone(configuration?.deploymentManifest))!==stableStringify(clone(manifest)))issue(issues,'OPERATION_MANIFEST_CONFIGURATION_MISMATCH');} catch(e){issue(issues,'OPERATION_MANIFEST_CONFIGURATION_MISMATCH');} return result(!issues.length,issues); } function validateRequest(envelope,nonce,profileId,now,ticket){ const issues=[],at=Math.max(0,Math.floor(Number(now)||Date.now())); if(!envelope||typeof envelope!=='object'||Array.isArray(envelope))return result(false,['REQUEST_NOT_OBJECT']); const operation=envelope.operation; if(!exactKeys(envelope,['schemaVersion','kind','nonce','accountId','contentVersion','issuedAt','expiresAt','adapter','commanderRosterFingerprint','operation','checksum']))issue(issues,'REQUEST_FIELDS_INVALID'); if(envelope.schemaVersion!==2||envelope.kind!=='GroundOperationRequestV2')issue(issues,'REQUEST_SCHEMA_INVALID'); if(envelope.adapter!=='massfront-solo-v2')issue(issues,'REQUEST_ADAPTER_INVALID'); if(envelope.commanderRosterFingerprint!==COMMANDER_ROSTER_FINGERPRINT)issue(issues,'REQUEST_COMMANDER_ROSTER_INVALID'); if(!NONCE_RE.test(text(nonce))||envelope.nonce!==nonce)issue(issues,'REQUEST_NONCE_INVALID'); if(!text(profileId)||envelope.accountId!==profileId||operation?.profileId!==profileId)issue(issues,'REQUEST_PROFILE_MISMATCH'); if(envelope.contentVersion!==CONTENT_VERSION&&envelope.contentVersion!==LEGACY_CONTENT_VERSION)issue(issues,'REQUEST_CONTENT_VERSION_INVALID'); if(!Number.isInteger(envelope.issuedAt)||!Number.isInteger(envelope.expiresAt) ||envelope.expiresAt<=envelope.issuedAt||at>envelope.expiresAt||envelope.issuedAt>at+30000)issue(issues,'REQUEST_EXPIRED'); try{if(envelope.checksum!==envelopeChecksum(envelope))issue(issues,'REQUEST_CHECKSUM_INVALID');} catch(e){issue(issues,'REQUEST_CHECKSUM_INVALID');} if(!operation||typeof operation!=='object'||Array.isArray(operation))issue(issues,'OPERATION_NOT_OBJECT'); else { if(!exactKeys(operation,GROUND_OPERATION_V3_FIELDS))issue(issues,'OPERATION_FIELDS_INVALID'); const modifiers=operation.rewardModifiers; if(!exactKeys(modifiers,['frontBountyPct','replayScalePct']) ||!Number.isInteger(modifiers.frontBountyPct)||modifiers.frontBountyPct<0||modifiers.frontBountyPct>40 ||!Number.isInteger(modifiers.replayScalePct)||modifiers.replayScalePct<35||modifiers.replayScalePct>100) issue(issues,'OPERATION_REWARD_MODIFIERS_INVALID'); if(operation.schemaVersion!==3||operation.kind!=='GroundOperationV3')issue(issues,'OPERATION_SCHEMA_INVALID'); if(operation.commanderRosterFingerprint!==COMMANDER_ROSTER_FINGERPRINT ||operation.commanderRosterFingerprint!==envelope.commanderRosterFingerprint)issue(issues,'OPERATION_COMMANDER_ROSTER_INVALID'); const mission=GALACTIC_MISSION_AUTHORITY[operation.missionId]; if(!mission||operation.missionType!==mission.missionType||operation.systemId!==mission.systemId||operation.siteId!==mission.siteId)issue(issues,'OPERATION_MISSION_INVALID'); if(operation.sponsorId!=='uga'||operation.contractFactionId!==mission?.contractFactionId)issue(issues,'OPERATION_SPONSOR_INVALID'); if(operation.opponentFactionId!==mission?.opponentFactionId)issue(issues,'OPERATION_OPPONENT_INVALID'); if(!Object.prototype.hasOwnProperty.call(PROXY_MAP,operation.proxyFactionId) ||operation.playerFactionId!==operation.proxyFactionId)issue(issues,'OPERATION_PROXY_INVALID'); if(!mission||!sameJson(operation.objective,mission.objective))issue(issues,'OPERATION_OBJECTIVE_INVALID'); const purge=mission?.missionType==='uga_brood_purge'; if(operation.battlefield?.infestationActive!==purge ||!sameJson(operation.battlefield?.hiveTargetIds||[],purge?operation.objective?.hiveTargetIds||[]:[]))issue(issues,'OPERATION_INFESTATION_INVALID'); if(!operationBattlefield(operation,envelope.contentVersion))issue(issues,'OPERATION_BATTLEFIELD_INVALID'); if(mission&&((mission.accessFactionId===null&&operation.contractFactionId!==null) ||(mission.accessFactionId!==null&&(operation.proxyFactionId!==mission.accessFactionId||operation.contractFactionId!==mission.accessFactionId))))issue(issues,'OPERATION_ACCESS_INVALID'); if(!text(operation.operationId)||!text(operation.resultSeed)||!text(operation.returnToken))issue(issues,'OPERATION_IDENTITY_INVALID'); const commanderRow=COMMANDER_BY_ID[operation.commanderId]; const rosterCommander=Array.isArray(ticket?.commanderRosterSnapshot?.commanders) ?ticket.commanderRosterSnapshot.commanders.find(entry=>entry.id===operation.commanderId):null; const expectedIdentity=commanderIdentityFromRoster(rosterCommander); if(!commanderRow||commanderRow[2]!==operation.proxyFactionId ||!expectedIdentity||!sameJson(operation.commanderIdentity,expectedIdentity) ||operation.personnelSnapshot?.commander?.id!==operation.commanderId)issue(issues,'OPERATION_COMMANDER_INVALID'); if(!text(operation.commanderId)||!Array.isArray(operation.specialistIds) ||operation.specialistIds.length!==3||new Set(operation.specialistIds).size!==3)issue(issues,'OPERATION_TEAM_INVALID'); if(operation.playerCount!==undefined&&operation.playerCount!==1)issue(issues,'OPERATION_PLAYER_COUNT_INVALID'); if(operation.allyCount!==undefined&&operation.allyCount!==0)issue(issues,'OPERATION_ALLY_COUNT_INVALID'); if(Array.isArray(operation.allies)&&operation.allies.length)issue(issues,'OPERATION_ALLIES_INVALID'); issues.push(...validateDeploymentContract(operation).issues); } const commissioning=ticket&&ticket.commissioning; issues.push(...validateEntryTicket(ticket,now,profileId).issues); if(!commissioning||commissioning.factionId===null||commissioning.commanderId===null ||COMMANDER1_BY_FACTION[commissioning.factionId]!==commissioning.commanderId)issue(issues,'REQUEST_COMMISSIONING_REQUIRED'); if(ticket?.commanderRosterFingerprint!==COMMANDER_ROSTER_FINGERPRINT)issue(issues,'REQUEST_ENTRY_ROSTER_INVALID'); return result(!issues.length,issues); } function validateRequestMirror(mirror,nonce,profileId,now,ticket){ const issues=[]; if(!mirror||typeof mirror!=='object'||Array.isArray(mirror))return result(false,['REQUEST_MIRROR_NOT_OBJECT']); if(!exactKeys(mirror,['schemaVersion','kind','adapter','commanderRosterFingerprint','nonce','accountId','operationId','request']))issue(issues,'REQUEST_MIRROR_FIELDS_INVALID'); if(mirror.schemaVersion!==2||mirror.kind!=='MassfrontGalacticRequestMirrorV2')issue(issues,'REQUEST_MIRROR_SCHEMA_INVALID'); if(mirror.adapter!=='massfront-solo-v2')issue(issues,'REQUEST_MIRROR_ADAPTER_INVALID'); if(mirror.commanderRosterFingerprint!==COMMANDER_ROSTER_FINGERPRINT)issue(issues,'REQUEST_MIRROR_ROSTER_INVALID'); if(mirror.nonce!==nonce||mirror.accountId!==profileId ||mirror.operationId!==mirror.request?.operation?.operationId)issue(issues,'REQUEST_MIRROR_IDENTITY_INVALID'); const requestValidation=validateRequest(mirror.request,nonce,profileId,now,ticket); issues.push(...requestValidation.issues); return result(!issues.length,issues); } function readSessionJson(key){ try{const raw=sessionStorage.getItem(key);return raw?JSON.parse(raw):null;} catch(e){return null;} } function readSessionRecord(key){ try{ const serialized=sessionStorage.getItem(key); if(serialized===null)return {present:false,readable:true,serialized:null,value:null}; try{return {present:true,readable:true,serialized,value:JSON.parse(serialized)};} catch(e){return {present:true,readable:false,serialized,value:null};} }catch(e){return {present:true,readable:false,serialized:null,value:null};} } function currentProfileId(){ return typeof PROFILES!=='undefined'&&PROFILES&&text(PROFILES.active)?PROFILES.active:''; } function currentFlagOn(){ return window.__MF_BUILD_HAS_GALACTIC_EXPLORATION===true ||window.__MF_OTA_HAS_GALACTIC_DELIVERY===true; } let classicFallbackActive=String(location.search||'')===CLASSIC_FALLBACK_SEARCH; try{classicFallbackActive=classicFallbackActive||sessionStorage.getItem(CLASSIC_FALLBACK_KEY)==='1';}catch(e){} function classicFallbackOn(){ if(classicFallbackActive)return true; try{return sessionStorage.getItem(CLASSIC_FALLBACK_KEY)==='1';}catch(e){return false;} } function armClassicFallback(){ classicFallbackActive=true; try{sessionStorage.setItem(CLASSIC_FALLBACK_KEY,'1');}catch(e){} return true; } function clearClassicFallback(){ classicFallbackActive=false; try{sessionStorage.removeItem(CLASSIC_FALLBACK_KEY);}catch(e){} return !classicFallbackOn(); } function explorationReturnTarget(query=''){ const target='./modules/space_exploration/index.html'+query; return typeof mfContentExplorationReturnUrl==='function'?mfContentExplorationReturnUrl(target):target; } function stripBridgeQuery(){ if(typeof history==='undefined'||typeof history.replaceState!=='function')return; try{history.replaceState(history.state,'',(location.pathname||'./index.html')+(location.hash||''));}catch(e){} } function consumeRouteRecord(nonce){ try{ sessionStorage.removeItem(ROUTE_PREFIX+nonce); return sessionStorage.getItem(ROUTE_PREFIX+nonce)===null; }catch(e){return false;} } function openBaseRoute(routeId,location){ if(!expeditionLocationAllowed(location))return false; const show=id=>typeof showFrontScreen==='function'&&showFrontScreen(id); if(typeof initAudio==='function')initAudio(); if(typeof sfx==='function')sfx('ui'); bridge.menuRouteActive=true; if(routeId==='operations'||routeId==='mode-weekly'||routeId==='mode-campaign'){ if(typeof MF_TAB_STATE!=='undefined')MF_TAB_STATE.opsScr=routeId==='mode-campaign'?'campaign':'weekly'; if(typeof renderOps==='function')renderOps(); return show('opsScr'); } if(routeId==='development'){ if(typeof renderDevelop==='function')renderDevelop(); return show('devScr'); } if(routeId==='armory'){ if(typeof renderMetaHead==='function')renderMetaHead(); if(typeof renderArmory==='function')renderArmory(); return show('armory'); } if(routeId==='orders'){ if(typeof renderDaily==='function')renderDaily(); return show('dailyScr'); } if(routeId==='intel'){ if(typeof renderCodex==='function')renderCodex(); return show('dossierScr'); } if(routeId==='profile'){ if(typeof renderProfile==='function')renderProfile(); return show('profileScr'); } if(routeId==='inbox'){ if(typeof renderInbox==='function')renderInbox(); return show('inboxScr'); } if(routeId==='social'){ if(typeof MFSocialUI!=='undefined'&&MFSocialUI&&typeof MFSocialUI.open==='function'){ MFSocialUI.open();return true; } bridge.menuRouteActive=false; if(typeof toast==='function')toast('Social Command is not available in this build'); return show('startScreen'); } if(routeId==='settings'){ if(typeof openSettings==='function'){openSettings('menu');return true;} return false; } if(routeId==='game-version'){ if(typeof updOpen!=='undefined')updOpen=true; if(typeof renderUpdatePanel==='function')renderUpdatePanel(); return show('updScr'); } if(routeId==='war-room'){ if(typeof window.openWarRoom!=='function')return false; /* The global strategic-home guard normally sends legacy warScr exits back to UGA. This secured host route is the one deliberate exception: allow the public owner to reveal the real Classic-mode surface once, then restore interception so its Back control returns to UGA. */ warRoomRouteOpening=true; try{return window.openWarRoom()!==false;} finally{warRoomRouteOpening=false;} } if(routeId==='mode-standard'){ if(typeof openSkirmishSetup==='function'){ openSkirmishSetup(); /* The base owner resets to galaxy and renders its own galaxy -> system -> planet -> region -> map -> deploy sequence. The UGA origin is navigation context, never permission to skip it or to relabel a base homeworld as an exploration planet. */ return true; } return false; } if(routeId==='mode-training'){ if(window.MFNewCareerFactionGate&&typeof window.MFNewCareerFactionGate.afterOnboardingChoice==='function'){ window.MFNewCareerFactionGate.afterOnboardingChoice({choice:'training',source:'secured-base-route'}); } if(typeof resumeTrainingMission==='function'){resumeTrainingMission();return true;} return false; } if(routeId==='new-career-faction'){ /* Both the tutorial-complete and tutorial-skip paths converge here. The career gate owns the real faction/Commander 1 grant and continuation; this bridge only authenticates and delivers the same-tab destination. */ bridge.menuRouteActive=false; if(window.MFNewCareerFactionGate&&typeof window.MFNewCareerFactionGate.openFromRoute==='function'){ return window.MFNewCareerFactionGate.openFromRoute({choice:'skipped'})!==false; } return false; } return false; } function baseRouteTargetReady(routeId){ /* galactic-operations.js is intentionally loaded before the new-career takeover. A secured same-tab return can reach bootConfirmed in that narrow gap, so do not consume its one-time nonce until the late owner is actually mounted. Otherwise a valid tutorial/skip return is rejected before career-faction-gate.js has a chance to receive it. */ if(routeId==='new-career-faction') return !!(window.MFNewCareerFactionGate &&typeof window.MFNewCareerFactionGate.openFromRoute==='function'); if(routeId==='mode-training') return !!(window.MFNewCareerFactionGate &&typeof window.MFNewCareerFactionGate.afterOnboardingChoice==='function' &&typeof resumeTrainingMission==='function'); if(routeId==='war-room')return typeof window.openWarRoom==='function'; /* main.js installs the public Standard entry during async boot. Do not consume the one-shot route record in the narrow gap before it exists; otherwise the module reports a secured deployment while the base game can only reject it after the nonce is already gone. */ if(routeId==='mode-standard')return typeof openSkirmishSetup==='function'; return true; } function rejectMenuRoute(code,nonce){ bridge.status='menu-route-rejected';bridge.reason=code||'ROUTE_REJECTED';bridge.menuRouteActive=false; stripBridgeQuery(); if(NONCE_RE.test(nonce||''))consumeRouteRecord(nonce); if(typeof toast==='function')toast('Galactic destination rejected — returned to MASSFRONT home'); if(typeof renderMetaHead==='function')renderMetaHead(); if(typeof showFrontScreen==='function')showFrontScreen('startScreen'); } function rejectBridge(code){ /* Isolation is a property of the bridge match, not of the session. It was set beside active in beginBattle and must be released beside it, or the next ordinary match silently loses every reward: metaGrant, developRecord, endgameRecord, loot and session snapshots all short out on bridge.isolated, and the debrief then renders with no payout. */ bridge.status='rejected';bridge.reason=code||'REJECTED';bridge.active=false;bridge.isolated=false; const say=()=>{if(typeof toast==='function')toast('Galactic operation rejected — return to NEXUS-VII and relaunch');}; if(typeof toast==='function')say();else setTimeout(say,120); /* A rejected deep link must never leave the player at Standard as if the operation had succeeded. Return to the still-pending module state, where the authored abandon action can refund the deployment. A malformed nonce is never reflected into a URL. */ setTimeout(()=>{ const target=explorationReturnTarget(NONCE_RE.test(bridge.nonce)?'?groundRejected='+encodeURIComponent(bridge.nonce):''); try{if(!target)throw new Error('Content return unavailable');location.href=target;} catch(e){bridge.status='return-error';bridge.reason='REJECTION_RETURN_FAILED';} },900); } function sandboxMetaFrom(live){ let temp; try{temp=typeof metaFresh==='function'?metaFresh():{};}catch(e){temp={};} temp.settings=clone(live&&live.settings||{}); temp.owned={};temp.opmods={};temp.wcPref=0;temp.res={};temp.resQueue=[]; temp.mats={alloy:0,circuit:0,isotope:0,relic:0};temp.mods={};temp.equip=[]; temp.inventory={gear:{},consumables:{},equipped:{weapon:'',armor:'',utility:''},ready:[]}; temp.campaign={missions:{}};temp.coreGrantPending=[];temp.standardMatches=99; return temp; } function withSandboxMeta(fn){ const liveMeta=META,liveSave=metaSave; META=bridge.sandboxMeta;metaSave=function(){return true;}; try{return fn();} finally{META=liveMeta;metaSave=liveSave;} } function deploymentPlan(operation){ const validation=validateDeploymentContract(operation); if(!validation.ok)throw new Error(validation.issues.join(',')); const units=[],structures=[],manifest=operation.deploymentManifest; let groupsLeft=4,structuresLeft=2; for(const entry of manifest.units){ const spec=DEPLOY_UNIT_SPEC[entry.id],groups=Math.min(entry.count,groupsLeft); groupsLeft-=groups; for(let group=0;group0)units.push({index,generation:ugen[index],maxHp,reserve:maxHp*.20}); } bridge.naniteUnits=units; return {eligibleUnitCount:units.length,totalReserveHp:Math.round(units.reduce((sum,item)=>sum+item.reserve,0)*100)/100}; } function applyOperationMatchEffects(cx,cy){ const applied=[]; for(const effect of bridge.operationEffects.matchApplied){ if(effect.effect==='deployment-scan'){ if(typeof fogStartScan!=='function')throw new Error('DEPLOYMENT_SCAN_RUNTIME_UNAVAILABLE'); fogStartScan(cx,cy,effect.seconds,effect.radius);applied.push(clone(effect)); }else if(effect.effect==='starting-unit-repair-reserve'){ applied.push(Object.assign(clone(effect),armStartingUnitNanites())); } } return applied; } function repairNanitesTick(dt){ if(!bridge.active||!bridge.naniteUnits.length)return; const seconds=Math.max(0,Number(dt)||0); if(seconds<=0)return; for(const unit of bridge.naniteUnits){ const index=unit.index; if(unit.reserve<=0||index<0||index>=unitHigh||!ualive[index]||uteam[index]!==0||ugen[index]!==unit.generation)continue; const ceiling=Math.min(unit.maxHp,Math.max(0,Number(uhpm[index])||0)); const missing=Math.max(0,ceiling-(Number(uhp[index])||0)); const healed=Math.min(missing,unit.reserve,unit.maxHp*.01*seconds); if(healed>0){uhp[index]+=healed;unit.reserve-=healed;} } } function applyDeploymentPackage(){ if(!bridge.active||bridge.packageApplied||carrier.phase!==2)return false; const plan=deploymentPlan(bridge.request.operation),cx=carrier.x,cy=carrier.y; /* Clinic Roof is a compact casualty-collection perimeter; Transit Court is a wider curbside column. Landing-zone choice therefore changes the real opening layout without moving the authored southwest player start. */ const unitOffsets=plan.landingZoneId==='transit_court' ?[[-132,88],[-88,88],[-44,88],[0,88],[44,88],[88,88],[132,88],[-110,126],[110,126]] :[[-86,96],[-44,120],[0,130],[44,120],[86,96],[-120,68],[120,68],[-138,24],[138,24]]; const structureOffsets=plan.landingZoneId==='transit_court'?[[-145,-58],[145,-58]]:[[-132,-18],[132,-18]]; const spawnedUnits=[],spawnedStructures=[]; for(let index=0;indexentry&&entry.name===item.type),offset=unitOffsets[index]; if(type<0||!offset)throw new Error('DEPLOYMENT_UNIT_MAPPING_FAILED'); const unit=spawnUnit(type,0,cx+offset[0],cy+offset[1]); if(unit<0)throw new Error('DEPLOYMENT_UNIT_SPAWN_FAILED'); spawnedUnits.push(item); } for(let index=0;index({on:!!A.on,diff:A.diff|0,zone:A.zone,ally:false,behavior:'balanced'})),df:defenseFocus,inf:infestationOn?1:0}; } function dismissEntryOverlays(){ for(const id of ['mfIntro','apOverlay','apConfirmOverlay','accDlg','dispatch']){ const el=document.getElementById(id);if(el)el.style.display='none'; } try{if(typeof apGateSatisfied==='function')apGateSatisfied();}catch(e){} } function operationLoadScreenModel(operation,location){ if(!operation||!location||!location.display)return null; const display=location.display,planet=display.planetName||display.systemName||'UGA FRONT'; return {title:display.mapName||display.areaName||'UGA BATTLEFIELD', eyebrow:'DEPLOYING TO · '+planet,poi:display.areaName||'', hook:operation.missionType==='uga_brood_purge'?'UGA CONTAINMENT OPERATION':'UGA PROXY OPERATION', chips:[{key:'SYSTEM',value:display.systemName||location.systemId}, {key:'SCALE',value:location.size},{key:'THREAT',value:'T'+operation.difficulty}].filter(entry=>entry.value)}; } function fillOperationLoadScreen(){ const operation=bridge.request&&bridge.request.operation; const model=operationLoadScreenModel(operation,bridge.playerLocation); if(!model)return false; const setText=(id,value)=>{const el=document.getElementById(id);if(el)el.textContent=value||'';}; setText('loadTitle',model.title);setText('loadEyebrow',model.eyebrow); setText('loadPoi',model.poi);setText('loadHook',model.hook); const host=document.getElementById('loadStats'); if(host){ host.textContent=''; for(const entry of model.chips){ const chip=document.createElement('div'),key=document.createElement('span'),value=document.createElement('span'); chip.className='lsChip';key.className='lsK';value.className='lsV'; key.textContent=entry.key;value.textContent=String(entry.value).toUpperCase(); chip.appendChild(key);chip.appendChild(value);host.appendChild(chip); } } return true; } function beginBattle(){ bridge.active=true;bridge.isolated=true;bridge.status='launching';bridge.reason=''; bridge.sandboxMeta=sandboxMetaFrom(META); const resume=document.getElementById('sessResume');if(resume)resume.remove(); try{withSandboxMeta(configureBattle);} catch(e){rejectBridge('SETUP_FAILED');return;} dismissEntryOverlays(); if(typeof hideFrontScreens==='function')hideFrontScreens(); if(typeof mfLoadScreenFill==='function')mfLoadScreenFill(); fillOperationLoadScreen(); const load=document.getElementById('loadScr');if(load)load.style.display='flex'; requestAnimationFrame(()=>requestAnimationFrame(()=>{ try{ withSandboxMeta(()=>{applyTheme();newSkirmish();}); bridge.status='battle'; if(load)load.style.display='none'; if(typeof stopAttract==='function')stopAttract(); if(typeof mfFlowLayout==='function')mfFlowLayout(); if(typeof toast==='function'){ const op=bridge.request&&bridge.request.operation; const where=bridge.playerLocation?.display?.mapName||bridge.playerLocation?.display?.areaName||'selected battlefield'; toast(op&&op.missionType==='uga_brood_purge' ?('UGA OPERATION · '+where+' — purge the active Brood infestation') :('UGA OPERATION · '+where+' — break the '+String((op&&op.opponentFactionId)||'hostile').toUpperCase()+' hold')); } }catch(e){ if(load)load.style.display='none'; console.error('Galactic operation launch failed',e); rejectBridge('BATTLE_START_FAILED'); } })); } function scoreReport(win,abandoned){ const operation=bridge.request.operation; const elapsed=Math.max(0,Math.floor(Number(stats&&stats.t)||0)); const kills=Math.max(0,Math.floor(Number(stats&&stats.kills&&stats.kills[0])||0)); const losses=Math.max(0,Math.floor(Number(stats&&stats.kills&&stats.kills[1])||0)); const nests=Math.max(0,Math.floor(Number(stats&&stats.nests)||0)); let score=(win?68:14)+Math.min(16,nests*4)+Math.min(12,Math.floor(kills/6)) -Math.min(24,Math.floor(losses/4))-Math.min(8,Math.floor(elapsed/300)); score+=(bridge.operationEffects||describeOperationEffects(operation)).tacticalScoreDelta; score=Math.max(0,Math.min(100,Math.round(score))); if(win)score=Math.max(51,score);else score=Math.min(64,score); let secondary=abandoned?0:0; if(!abandoned&&typeof heroIdx!=='undefined'&&heroIdx>=0)secondary++; if(!abandoned&&losses<=Math.max(4,Math.floor(kills*.45)))secondary++; if(!abandoned&&elapsed>0&&elapsed<=20*60)secondary++; let injuryBand; if(abandoned)injuryBand='moderate'; else if(typeof heroIdx!=='undefined'&&heroIdx<0)injuryBand='severe'; else if(losses===0)injuryBand='none'; else if(losses/Math.max(1,kills+losses)<=.25)injuryBand='light'; else if(losses/Math.max(1,kills+losses)<=.65)injuryBand='moderate'; else injuryBand='severe'; const count={none:0,light:1,moderate:2,severe:3}[injuryBand]; const team=[operation.commanderId,...operation.specialistIds].sort((a,b)=>{ const ah=hash32(operation.resultSeed+':injury:'+a),bh=hash32(operation.resultSeed+':injury:'+b); return ah===bh?String(a).localeCompare(String(b)):ah.localeCompare(bh); }); return {outcome:win?'victory':'setback',score,primaryObjectiveComplete:!!win, secondaryObjectivesComplete:Math.max(0,Math.min(3,secondary)),injuryBand, injuredPersonnelIds:team.slice(0,count)}; } function persistReport(win,abandoned){ if(bridge.report)return true; if(Date.now()>bridge.request.expiresAt){ bridge.status='result-expired';bridge.reason='REQUEST_EXPIRED'; if(typeof toast==='function')toast('Operation link expired — return to NEXUS-VII to abandon or relaunch'); return false; } if(!bridge.reportCandidate){ const reportValue=scoreReport(!!win,!!abandoned); const validation=validateTacticalReport(reportValue,bridge.request.operation); if(!validation.ok){bridge.status='result-error';bridge.reason=validation.issues.join(',');return false;} const candidate={schemaVersion:1,kind:'MassfrontGalacticTacticalReportV1',nonce:bridge.nonce, accountId:bridge.request.accountId,operationId:bridge.request.operation.operationId, issuedAt:Date.now(),report:reportValue}; candidate.checksum=envelopeChecksum(candidate); /* The serialized candidate is the authority after the terminal edge. A denied first write must not let a later RETURN click re-score the same victory as an abandoned setback with a different timestamp. */ bridge.reportCandidateBytes=JSON.stringify(candidate); bridge.reportCandidate=freezeJson(JSON.parse(bridge.reportCandidateBytes)); } const record=bridge.reportCandidate,serialized=bridge.reportCandidateBytes; try{ const key=RESULT_PREFIX+bridge.nonce; sessionStorage.setItem(key,serialized); const stored=sessionStorage.getItem(key),readback=stored&&JSON.parse(stored); if(stored!==serialized||!readback||readback.checksum!==envelopeChecksum(readback) ||stableStringify(readback)!==stableStringify(record))throw new Error('result readback'); }catch(e){ bridge.status='result-storage-error';bridge.reason='RESULT_STORAGE_FAILED'; if(typeof toast==='function')toast('Tactical report could not be secured — remain on this screen and retry'); return false; } bridge.report=clone(record);bridge.status='terminal';bridge.reason=''; return true; } function paintReturnControls(){ if(!bridge.active||(!bridge.report&&bridge.status!=='result-expired'))return; const menu=document.getElementById('restartBtn'),cont=document.getElementById('goContinueBtn'); if(menu)menu.textContent=bridge.report?.report.outcome==='setback'?'↻ RETURN TO RETRY':'← RETURN TO NEXUS-VII'; if(cont){cont.textContent='▶ RETURN TO NEXUS-VII';cont.style.display='none';cont.disabled=false;} const rewards=document.getElementById('goRewards'); if(rewards&&!rewards.querySelector('.mfGalacticReport')){ const notice=document.createElement('div'); notice.className='goNotice mfGalacticReport '+(bridge.report?.report.outcome==='victory'?'good':'bad'); notice.textContent=bridge.report ?'UGA TACTICAL REPORT · '+bridge.report.report.score+'/100 · ' +bridge.report.report.secondaryObjectivesComplete+' SECONDARY OBJECTIVES · RETURN ROUTE VERIFIED' :'UGA LINK EXPIRED · RETURN TO NEXUS-VII TO ABANDON OR RELAUNCH'; rewards.appendChild(notice); } } function returnRejectedToNexus(){ if(bridge.returning)return false; bridge.returning=true;bridge.status='returning-rejected'; const target=explorationReturnTarget('?groundRejected='+encodeURIComponent(bridge.nonce)); try{if(!target)throw new Error('Content return unavailable');location.href=target;return true;} catch(e){bridge.returning=false;bridge.status='return-error';bridge.reason='RETURN_NAVIGATION_FAILED';return false;} } function returnToNexus(){ if(!bridge.active||bridge.returning)return false; if(!bridge.report&&!persistReport(false,true)){ if(bridge.status==='result-expired')return returnRejectedToNexus(); return false; } bridge.returning=true;bridge.status='returning'; const target=explorationReturnTarget('?groundResult='+encodeURIComponent(bridge.nonce)); try{if(!target)throw new Error('Content return unavailable');location.href=target;return true;} catch(e){bridge.returning=false;bridge.status='return-error';bridge.reason='RETURN_NAVIGATION_FAILED';if(typeof toast==='function')toast('NEXUS-VII return route could not be opened');return false;} } function returnExistingReportToNexus(record){ bridge.active=false;bridge.isolated=false;bridge.report=clone(record);bridge.returning=true;bridge.status='returning-existing';bridge.reason=''; const target=explorationReturnTarget('?groundResult='+encodeURIComponent(bridge.nonce)); try{if(!target)throw new Error('Content return unavailable');location.href=target;return true;} catch(e){bridge.returning=false;bridge.status='return-error';bridge.reason='RETURN_NAVIGATION_FAILED';return false;} } /* Close every base-career reward seam. The originals remain byte-for-byte in force for Standard, Campaign, Weekly and Training when no validated Galactic operation is active. */ if(typeof metaGrant==='function'){ const base=metaGrant;metaGrant=function(){if(bridge.isolated)return null;return base.apply(this,arguments);}; } if(typeof developRecord==='function'){ const base=developRecord;developRecord=function(){if(bridge.isolated)return null;return base.apply(this,arguments);}; } if(typeof endgameRecord==='function'){ const base=endgameRecord;endgameRecord=function(){if(bridge.isolated)return null;return base.apply(this,arguments);}; } if(typeof dailyRecord==='function'){ const base=dailyRecord;dailyRecord=function(){if(bridge.isolated)return null;return base.apply(this,arguments);}; } if(typeof mfConquestReward==='function'){ const base=mfConquestReward;mfConquestReward=function(){if(bridge.isolated)return null;return base.apply(this,arguments);}; } if(typeof invGrantMatchLoot==='function'){ const base=invGrantMatchLoot;invGrantMatchLoot=function(){if(bridge.isolated)return null;return base.apply(this,arguments);}; } if(typeof invGrantModeReward==='function'){ const base=invGrantModeReward;invGrantModeReward=function(){if(bridge.isolated)return null;return base.apply(this,arguments);}; } if(typeof sessCanSnapshot==='function'){ const base=sessCanSnapshot;sessCanSnapshot=function(){if(bridge.isolated)return false;return base.apply(this,arguments);}; } if(typeof sessSnapshot==='function'){ const base=sessSnapshot;sessSnapshot=function(){if(bridge.isolated)return false;return base.apply(this,arguments);}; } if(typeof goalDef==='function'){ const base=goalDef;goalDef=function(){ if(bridge.active&&bridge.tacticalGoal)return bridge.tacticalGoal; return base.apply(this,arguments); }; } if(typeof goalStatus==='function'){ const base=goalStatus;goalStatus=function(){ const status=base.apply(this,arguments); if(!bridge.active||!bridge.tacticalGoal||bridge.tacticalGoal.id!=='domination')return status; return bridge.tacticalGoal.em+' '+bridge.tacticalGoal.hud+' · '+String(status||'').replace(/^\u26f3\s*/, ''); }; } if(typeof applyCrate==='function'){ const base=applyCrate;applyCrate=function(kind){ if(bridge.isolated&&(kind?.id==='data'||kind?.id==='mats')){ if(typeof mfCrateClaimer!=='undefined')mfCrateClaimer=-1; bridge.suppressedPersistentCrates++; if(typeof pickupToast==='function')pickupToast(kind,'UGA RECOVERY RESERVED FOR NEXUS-VII DEBRIEF'); else if(typeof toast==='function')toast('UGA recovery reserved for NEXUS-VII debrief'); return null; } return base.apply(this,arguments); }; } if(typeof adShowPostMatchAd==='function'){ const base=adShowPostMatchAd;adShowPostMatchAd=function(){ if(bridge.isolated){bridge.suppressedPostMatchAds++;return null;} return base.apply(this,arguments); }; } if(typeof AD_PROVIDER!=='undefined'&&AD_PROVIDER&&typeof AD_PROVIDER.reportImpression==='function'){ const base=AD_PROVIDER.reportImpression; AD_PROVIDER.reportImpression=function(){ if(bridge.isolated){bridge.suppressedBillboardImpressions++;return null;} return base.apply(this,arguments); }; } if(typeof deployCarrier==='function'){ const base=deployCarrier;deployCarrier=function(){ const out=base.apply(this,arguments); if(bridge.active&&!bridge.packageApplied&&carrier.phase===2){ try{applyDeploymentPackage();} catch(e){ bridge.packageSummary={error:'DEPLOYMENT_PACKAGE_FAILED'}; console.error('Galactic deployment package failed',e); rejectBridge('DEPLOYMENT_PACKAGE_FAILED'); } } return out; }; } if(typeof unitTick==='function'){ const base=unitTick;unitTick=function(dt){ const out=base.apply(this,arguments);repairNanitesTick(dt);return out; }; } if(typeof endGame==='function'){ const base=endGame;endGame=function(win){ const out=base.apply(this,arguments); if(bridge.active){persistReport(!!win,false);setTimeout(paintReturnControls,1520);setTimeout(paintReturnControls,1900);} return out; }; } if(typeof returnToMainMenu==='function'){ const base=returnToMainMenu; /* Protected Training needs the base document to remain alive long enough for its mandatory commissioning gate to mount. This narrow escape hatch bypasses only the Galactic return interception; it still runs the full ordinary menu cleanup owned by main.js/departure.js. */ if(typeof window.__MF_RETURN_TO_BASE_FOR_COMMISSIONING__!=='function') window.__MF_RETURN_TO_BASE_FOR_COMMISSIONING__=function(){return base.apply(this,arguments);}; returnToMainMenu=function(){ if(bridge.active){ /* Protected new-career Training still owes the player the mandatory faction/Commander gate. tutSkip() schedules that gate immediately after this base-menu reset; navigating to NEXUS-VII here unloads the callback before it can run and strands the career in training. */ let gateState=null; try{gateState=window.MFNewCareerFactionGate&&window.MFNewCareerFactionGate.state();}catch(e){} if(gateState&&gateState.phase==='training')return base.apply(this,arguments); return returnToNexus(); } if(bridge.isolated)return returnRejectedToNexus(); return base.apply(this,arguments); }; } if(typeof continueToNextMap==='function'){ const base=continueToNextMap;continueToNextMap=function(){ if(bridge.active)return returnToNexus(); if(bridge.isolated)return returnRejectedToNexus(); return base.apply(this,arguments); }; } if(typeof mfVictoryContinue==='function'){ const base=mfVictoryContinue;mfVictoryContinue=function(){ if(bridge.active)return returnToNexus(); if(bridge.isolated)return returnRejectedToNexus(); return base.apply(this,arguments); }; } let menuReturnContext=null,warRoomRouteOpening=false; const api={validateEntryTicket,validateRouteRequest,validateRequest,validateRequestMirror,validateTacticalReport,validateResultMirror, resolveExpeditionLocation:location=>clone(expeditionLocationAllowed(location)), groundAreaForMission:missionId=>clone(GALACTIC_GROUND_AREA_AUTHORITY[missionId]||null), resolveOperationBattlefield:(operation,contentVersion=CONTENT_VERSION)=>clone(operationBattlefield(operation,contentVersion)), describeOperationLoadScreen:(operation,location)=>clone(operationLoadScreenModel(operation,location)), resolveTacticalObjective:operation=>clone(resolveTacticalObjective(operation)), clearClassicFallback, isMenuReturnContext:value=>value!==null&&value===menuReturnContext&&bridge.status==='menu-route', validateDeploymentContract,describeOperationEffects,checksum:envelopeChecksum}; Object.defineProperties(api,{ active:{enumerable:true,get:()=>bridge.active}, status:{enumerable:true,get:()=>bridge.status}, reason:{enumerable:true,get:()=>bridge.reason}, request:{enumerable:true,get:()=>clone(bridge.request)}, report:{enumerable:true,get:()=>clone(bridge.report)}, operationEffects:{enumerable:true,get:()=>clone(bridge.operationEffects)}, playerLocation:{enumerable:true,get:()=>clone(bridge.playerLocation)}, runtimeMapId:{enumerable:true,get:()=>bridge.runtimeMapId}, packageApplied:{enumerable:true,get:()=>bridge.packageApplied}, packageSummary:{enumerable:true,get:()=>clone(bridge.packageSummary)}, menuRouteActive:{enumerable:true,get:()=>bridge.menuRouteActive}, classicFallbackActive:{enumerable:true,get:()=>classicFallbackOn()}, isolation:{enumerable:true,get:()=>Object.freeze({active:bridge.isolated,droppedSessionPreserved:true, persistentCratesSuppressed:bridge.suppressedPersistentCrates,postMatchAdsSuppressed:bridge.suppressedPostMatchAds, billboardImpressionsSuppressed:bridge.suppressedBillboardImpressions})} }); window.__MF_GALACTIC_BRIDGE=Object.freeze(api); /* Galactic Command owns both strategic-home destinations. Base submenus keep their ordinary Back controls, but any attempt to reveal the retired home or War Room returns to UGA Command. menuRouteActive still records a routed submenu; unconditional interception also prevents unrelated legacy exits from resurrecting a second strategic shell. */ if(typeof showFrontScreen==='function'&&!showFrontScreen.__mfGalacticWarTable){ const baseShowFrontScreen=showFrontScreen; showFrontScreen=function(id){ if(warRoomRouteOpening&&id==='warScr')return baseShowFrontScreen.apply(this,arguments); if(window.__MF_COMMISSIONING_RETURN_ACTIVE__!==true&&!classicFallbackOn()&¤tFlagOn()&&(id==='startScreen'||id==='warScr')){ bridge.menuRouteActive=false; if(typeof mfOpenExploration==='function'){ // Only this synchronous call can authorize returning an existing // neutral career. It grants no faction, personnel, or mission access. menuReturnContext=Object.freeze({kind:'validated-menu-return'}); let opening; try{opening=mfOpenExploration('campaign_hub',{menuReturn:menuReturnContext});} finally{menuReturnContext=null;} Promise.resolve(opening).then(opened=>{ if(!opened)baseShowFrontScreen.call(this,id); }); return true; } } return baseShowFrontScreen.apply(this,arguments); }; showFrontScreen.__mfGalacticWarTable=true; } const search=String(location.search||''); if(search===CLASSIC_FALLBACK_SEARCH){ armClassicFallback();stripBridgeQuery();bridge.status='classic-fallback';bridge.reason=''; let fallbackTries=0; const fallbackTick=function(){ if(++fallbackTries>1200){ bridge.status='classic-fallback-home'; if(typeof showFrontScreen==='function')showFrontScreen('startScreen'); return; } if(typeof bootConfirmed==='undefined'||!bootConfirmed||typeof window.openWarRoom!=='function'){ setTimeout(fallbackTick,50);return; } dismissEntryOverlays(); if(typeof mfDismissIntroForGalacticRoute==='function')mfDismissIntroForGalacticRoute(); bridge.status=window.openWarRoom()===false?'classic-fallback-home':'classic-fallback-war-room'; if(bridge.status==='classic-fallback-home'&&typeof showFrontScreen==='function')showFrontScreen('startScreen'); }; setTimeout(fallbackTick,0);return; } const routeMatch=search.match(/^\?galacticRoute=([A-Za-z0-9_-]{16,128})$/); if(routeMatch){ bridge.nonce=routeMatch[1];bridge.status='waiting-for-base-route'; let routeTries=0; const routeTick=function(){ if(++routeTries>1200){rejectMenuRoute('BASE_BOOT_TIMEOUT',bridge.nonce);return;} if(typeof bootConfirmed==='undefined'||!bootConfirmed){setTimeout(routeTick,50);return;} const profileId=currentProfileId(),now=Date.now(),ticket=readSessionJson(ENTRY_KEY); if(!currentFlagOn()){rejectMenuRoute('EXPERIMENT_DISABLED',bridge.nonce);return;} const entryValidation=validateEntryTicket(ticket,now,profileId); if(!entryValidation.ok){rejectMenuRoute(entryValidation.issues.join(','),bridge.nonce);return;} const request=readSessionJson(ROUTE_PREFIX+bridge.nonce); const routeValidation=validateRouteRequest(request,bridge.nonce,profileId,now); if(!routeValidation.ok){rejectMenuRoute(routeValidation.issues.join(','),bridge.nonce);return;} if(!baseRouteTargetReady(request.routeId)){setTimeout(routeTick,50);return;} if(!consumeRouteRecord(bridge.nonce)){rejectMenuRoute('ROUTE_CONSUME_FAILED',bridge.nonce);return;} /* A validated same-tab submenu handoff is navigation inside one game, not a fresh launch. Dismiss the cinematic only after consuming the secured record so an arbitrary query string cannot suppress it. */ /* revealFront() schedules the ordinary first-run account gate shortly after the shell appears. A valid UGA handoff can finish inside that delay, so dismissing only the cinematic allowed the account modal to reopen over Standard's deployment plan and swallow START BATTLE. Satisfy all entry overlays here, after validation and nonce consumption, just as the ground-operation bridge does. */ dismissEntryOverlays(); if(typeof mfDismissIntroForGalacticRoute==='function')mfDismissIntroForGalacticRoute(); stripBridgeQuery(); bridge.status='menu-route';bridge.reason=''; if(!openBaseRoute(request.routeId,request.location))rejectMenuRoute('ROUTE_TARGET_UNAVAILABLE',bridge.nonce); }; setTimeout(routeTick,0); return; } if(/(?:^\?|&)galacticRoute=/.test(search)){ stripBridgeQuery(); bridge.status='menu-route-rejected';bridge.reason='ROUTE_NONCE_INVALID'; return; } const match=search.match(/^\?groundOperation=([A-Za-z0-9_-]{16,128})$/); if(!match){ if(/(?:^\?|&)groundOperation=/.test(search))rejectBridge('NONCE_INVALID'); return; } bridge.nonce=match[1];bridge.status='waiting-for-base'; let tries=0; const bootTick=function(){ if(++tries>1200){rejectBridge('BASE_BOOT_TIMEOUT');return;} if(typeof bootConfirmed==='undefined'||!bootConfirmed){setTimeout(bootTick,50);return;} const profileId=currentProfileId(),now=Date.now(),ticket=readSessionJson(ENTRY_KEY); if(!currentFlagOn()){rejectBridge('EXPERIMENT_DISABLED');return;} const entryValidation=validateEntryTicket(ticket,now,profileId); if(!entryValidation.ok){rejectBridge(entryValidation.issues.join(','));return;} const requestMirror=readSessionJson(REQUEST_PREFIX+bridge.nonce); const requestValidation=validateRequestMirror(requestMirror,bridge.nonce,profileId,now,ticket); if(!requestValidation.ok){rejectBridge(requestValidation.issues.join(','));return;} const request=requestMirror.request,storedResult=readSessionRecord(RESULT_PREFIX+bridge.nonce); bridge.operationEffects=describeOperationEffects(request.operation); if(storedResult.present){ if(!storedResult.readable){rejectBridge('RESULT_UNREADABLE');return;} const resultValidation=validateResultMirror(storedResult.value,bridge.nonce,profileId,request,now); if(!resultValidation.ok){rejectBridge(resultValidation.issues.join(','));return;} bridge.request=clone(request);returnExistingReportToNexus(storedResult.value);return; } bridge.request=clone(request);beginBattle(); }; setTimeout(bootTick,0); })();