|
2025-12-11 15:06
조회: 24,748
추천: 83
눈사람 구출 작전 자동화 (12/15 수정 5층, 문 5개도 가능!)안녕하세요 이전에 카드 메모리 게임 자동화 스크립트를 만들었던 킹암살입니다. 단순히 귀찮아서 혼자 쓰려고 만든 스크립트를 공유해드렸는데 많은 관심 주셔서 감사했습니다. 유튜브에 소개해주신 갓냥이님도 감사드립니다. (12/13) 5스테이지에서 층수가 증가하는 것을 확인하여 이에 맞게 코드를 수정했습니다. 현재 버전은 스테이지별로 층수를 자동으로 감지하도록 구현되어 있어, 이후 층수가 증가하더라도 문제없이 사용할 수 있습니다. 이 부분은 제 구현 능력이 부족한 탓도 있는 만큼, 더 나은 개선 코드나 조언이 있다면 공유해주시면 감사하겠습니다. (12/15) 9스테이지부터 문이 5개가 되는 것을 확인하여 코드를 수정했습니다. 아직 9스테이지에서 확인해 본 것은 아니나, 자동 층수, 문 개수 감지 코드로 이전 스테이지들까지 문제 없이 실행되는 것을 확인하여 코드를 공유드립니다. 버그 발생시 알려주시면 감사하겠습니다. 해당 스크립트는 웹페이지에서 실행하여야 정상적으로 작동합니다. https://lostark.game.onstove.com/Promotion/Mission/251210 사용 방법 (마이크로소프트 엣지 기준)
요청 딜레이로 인한 버그들이 많아 이들을 방지하려다 보니 한층 한층 플레이가 오래걸립니다. 더 개선하고 싶었으나 토큰이 부족하여 우선은 작동시 문제가 없었던 버전을 공유드립니다. 사용 중 오류나 비정상 동작이 발견되면 댓글로 알려주시면 감사하겠습니다. 수정 사항 (12/12) 1. 층을 인식하는 방식과 문을 찾는 방식을 더 단순하고 안정적으로 바꿨습니다. 2. 정답/오답을 기록하는 로직을 최소한으로 정리하여 속도를 올렸습니다. 3. 자동 클릭 흐름을 간단하게 개선해 불필요한 시도를 줄였습니다. (12/13) 1. 층을 자동으로 인식하게 하여 4층 ,5층에서도 문제가 없도록 변경하였습니다. (12/15) 1. 문을 자동으로 인식하게 하여 9스테이지에서도 문제가 없도록 변경하였습니다. 2. 층수 확인 딜레이를 줄여 게임 속도가 빨라졌습니다. (function () { 'use strict'; if (window.__snowmanAutoV6_Final) return; window.__snowmanAutoV6_Final = true; const sleep = ms => new Promise(r => setTimeout(r, ms)); function detectFloors() { const stage = document.querySelector('.stage'); if (!stage) return []; return Array.from(stage.children) .filter(el => { const name = el.className; if (!name.startsWith('floor')) return false; const num = name.slice(5); return num !== '' && !isNaN(Number(num)); }) .map(el => Number(el.className.slice(5))) .sort((a, b) => a - b); } function getFloorDoors(floor) { const el = document.querySelector('.floor' + floor); if (!el) return []; return Array.from(el.querySelectorAll('button.door')); } function floorFromIndex(idx) { for (const f of FLOORS) { const doors = getFloorDoors(f); if (doors.some(d => Number(d.dataset.idx) === idx)) return f; } return null; } let FLOORS = detectFloors(); const snowCorrect = {}; const snowWrong = {}; let stopFlag = false; let autoRunning = false; function initMemory() { FLOORS.forEach(f => { snowCorrect[f] = null; snowWrong[f] = new Set(); }); } function resetMemory() { FLOORS = detectFloors(); initMemory(); } initMemory(); function detectFloorByCharacter() { for (const f of FLOORS) { const el = document.querySelector('.floor' + f); if (el && el.querySelector('.obj_character')) return f; } return null; } function detectFloorByActiveDoor() { for (const f of FLOORS) { if (getFloorDoors(f).some(b => !b.disabled)) return f; } return null; } function detectFloor() { return detectFloorByCharacter() || detectFloorByActiveDoor() || FLOORS[0]; } async function waitFloorReady(floor, timeout = 1500) { const start = Date.now(); while (Date.now() - start < timeout) { const charFloor = detectFloorByCharacter(); const doors = getFloorDoors(floor).filter(b => !b.disabled); if (charFloor === floor && doors.length > 0) return true; await sleep(40); } return false; } function clickDoor(idx) { const btn = document.querySelector('button.door[data-idx="' + idx + '"]'); if (btn && !btn.disabled) { btn.click(); return true; } return false; } function scanPassedDoors() { FLOORS.forEach(f => { const el = document.querySelector('.floor' + f); if (!el) return; const passed = el.querySelector('button.door--passed'); if (passed) { const idx = Number(passed.dataset.idx); if (!isNaN(idx)) snowCorrect[f] = idx; } }); } function processResponse(clickedIdx, json) { if (typeof clickedIdx !== 'number') return; const floor = floorFromIndex(clickedIdx); if (!floor) return; if (json.isCorrect) { snowCorrect[floor] = clickedIdx; } else { snowWrong[floor].add(clickedIdx); } if (json.isComplete) resetMemory(); } (function hookXHR() { if (window.__snowmanXHRHooked) return; window.__snowmanXHRHooked = true; const OriginalXHR = window.XMLHttpRequest; function WrappedXHR() { const xhr = new OriginalXHR(); let url = null; let body = null; const open = xhr.open; xhr.open = function (m, u) { url = u; return open.apply(xhr, arguments); }; const send = xhr.send; xhr.send = function (data) { body = data; xhr.addEventListener('load', () => { try { if (!url || url.indexOf('SetDoor') === -1) return; let idx = null; if (typeof body === 'string') { const p = body.indexOf('index='); if (p !== -1) idx = Number(body.slice(p + 6)); } processResponse(idx, JSON.parse(xhr.responseText)); } catch {} }); return send.apply(xhr, arguments); }; return xhr; } WrappedXHR.prototype = OriginalXHR.prototype; window.XMLHttpRequest = WrappedXHR; })(); async function playOneStep() { if (stopFlag) return; scanPassedDoors(); const floor = detectFloor(); await waitFloorReady(floor); const doors = getFloorDoors(floor); if (snowCorrect[floor] != null) { if (clickDoor(snowCorrect[floor])) return; snowCorrect[floor] = null; } for (const btn of doors) { const idx = Number(btn.dataset.idx); if (snowWrong[floor].has(idx)) continue; if (clickDoor(idx)) return; } } async function autoLoop() { if (autoRunning) return; autoRunning = true; while (!stopFlag) { try { await playOneStep(); } catch {} await sleep(120); } autoRunning = false; } window.addEventListener('keydown', e => { if (e.key === 'Escape') stopFlag = true; }); autoLoop(); })();
|





