Web Game · Reverse Engineering

XP Games

Windows XP 스타일의
지뢰찾기 · 솔리테어 · 3D 핀볼.
원본을 REA로 분석 후 같은 규칙으로 다시 만들었습니다.

> XP GAMES
$ ls apps/
minesweeper solitaire pinball about

$ cat ported-from.txt
- minesweeper ← winXP (React)
- solitaire   ← Solitaire (VB.NET)
- pinball     ← SpaceCadetPinball (C++)

$ node serve.mjs
http://localhost:3000

$
online · xpgames.proj.pe.kr
[dblclick] open · [drag] move window

[+]Overview

// 어떤 서비스인가요?

XP Games는 Windows XP 스타일 바탕화면에서 고전 게임을 실행하는 웹 서비스입니다. 아이콘을 더블클릭하면 게임 창이 열리고, 창을 끌어 옮기거나 최소화·닫기를 할 수 있습니다.

단순히 비슷하게 만든 것이 아니라, 원본 프로그램과 소스를 REA(리버스 엔지니어링 도구)로 분석해서 지뢰 배치, 점수 계산, 물리 판정 같은 규칙을 원본과 똑같이 동작합니다. 원본에 있던 버그 중 게임 상태가 깨지는 것만 골라 고쳤습니다.

의존성 없이 Node.js만 있으면 github에서 받은 소스를 로컬에서 바로 실행할 수 있고, PC와 모바일 모두에서 플레이할 수 있습니다.

게임원본옮긴 방법
지뢰찾기 Minesweeper 앱을 REA로 분석해 HTML/JS로 구현
솔리테어 VB.NET 소스를 빌드한 뒤 어셈블리를 분석하고 HTML/JS로 구현
3D 핀볼 원본 pinball.exe를 디컴파일한 C++ 엔진을 HTML/JS로 이식

바탕화면과 창 조작

동작PC모바일
앱 열기아이콘 더블클릭 (최소화한 창이면 다시 표시)아이콘 한 번 탭 (더블탭은 브라우저 확대에 쓰이므로)
창 이동제목 표시줄 끌기제목 표시줄 끌기. 창이 화면보다 넓으면 끌어서 보고 싶은 부분을 맞춤
최소화최소화 버튼 (게임 상태 유지)최소화 버튼 탭
닫기닫기 버튼 / Exit 메뉴. 다시 열면 새 게임PC와 같음
활성 창창을 클릭하면 맨 앞으로, 바탕화면을 클릭하면 모두 비활성PC와 같음 (탭)

[+]Games

// 게임별 소개

지뢰찾기 플레이 화면
minesweeper.gif
01 · apps/minesweeper

지뢰찾기

  • 난이도 초급 9×9 / 지뢰 10, 중급 16×16 / 40, 고급 16×30 / 99
  • 첫 클릭 지뢰는 첫 클릭 순간에 배치되고, 클릭한 칸은 제외됩니다. 첫 칸은 지뢰가 아니지만 숫자일 수는 있습니다.
  • 연쇄 열기 0인 칸은 주변으로 퍼지며 열리고, 깃발 칸에서 멈춥니다.
  • 승패 안전한 칸을 모두 열면 승리(남은 지뢰에 깃발 자동 표시). 지면 모든 지뢰를 보여 주고 잘못 꽂은 깃발은 X로 표시합니다.
  • 카운터·타이머 지뢰 카운터는 전체 지뢰 − 깃발 수(음수면 -03), 타이머는 첫 클릭부터 999초까지.

조작법

동작PC모바일
칸 열기왼쪽 클릭덮인 칸 탭
깃발 / ?오른쪽 클릭0.4초 길게 누르기 (진동)
주변 칸 열기왼쪽+오른쪽 동시 클릭열린 숫자 칸 탭
새 게임얼굴 버튼얼굴 버튼 탭

원본과의 차이

  • 동시 클릭 버그 수정 원본은 if (mineIndex)로 검사해서 0번 칸(왼쪽 위)의 지뢰를 놓쳤습니다. 이 버전은 그 경우에도 게임 오버가 됩니다.
  • 연쇄 열기 재귀 대신 반복문으로 바꿨고, 결과는 같습니다.
  • 미구현 Custom, Sound, Best Times, Help 메뉴와 F2는 원본에서도 동작하지 않아 똑같이 비워 두었습니다.
솔리테어 플레이 화면
solitaire.gif
02 · apps/solitaire

솔리테어

원본 저장소에는 VB.NET 소스만 있어서, dotnet build로 solitaire.dll을 만든 뒤 REA의 managed 어셈블리 분석으로 타입·메서드·문자열을 확인했습니다. 게임 로직이 모인 GameForm 클래스(메서드 167개)와 디자이너 파일의 컨트롤 위치·순서까지 규칙으로 옮겼습니다.

  • 넘기기 기본은 Draw Three. 펼친 3장 중 맨 위 카드만 옮길 수 있습니다.
  • 쌓기 줄에는 색이 다르고 하나 작은 카드, 빈 줄에는 K만. 위쪽 칸에는 A부터 같은 무늬로 쌓습니다.
  • Undo 한 단계만 되돌립니다. 카드 뒤집기는 되돌릴 수 없습니다.
  • 승리 52장이 모두 위쪽 칸에 올라가면 카드가 튀어 내려오는 애니메이션과 "Deal Again?"이 나옵니다.

조작법

동작PC모바일
카드 넘기기덱 클릭덱 탭
카드 옮기기끌기끌기 (6px 넘게 움직여야 인식)
뒷면 뒤집기줄 클릭줄 탭
위쪽 칸으로더블클릭0.4초 안에 같은 자리 더블탭
전부 위쪽 칸으로오른쪽 클릭없음 (한 장씩 더블탭)

점수

상황StandardVegas
새 게임0−$52
넘긴 카드 → 줄+5-
위쪽 칸에 올리기+10+$5
위쪽 칸 → 줄−15-
뒷면 카드 뒤집기+5-
10초마다 (Timed)−2−$2

원본과의 차이

원본 동작을 최대한 그대로 옮기고, 게임 상태가 깨지거나 게임이 끝나지 않는 버그만 고쳤습니다.

  • 실패한 드롭이 Undo를 덮어쓰던 버그 놓을 수 없는 자리에 놓아도 Undo 정보가 바뀌어 카드가 복제되거나 사라지던 문제를 고쳤습니다.
  • Draw Three Undo 덱의 마지막 카드를 넘긴 직후 Undo하면 카드 한 장을 잃던 문제를 고쳤습니다.
  • 원래 자리에 놓기 연산자 우선순위 때문에 같은 칸에 다시 놓으면 점수가 계속 오르던 문제를 고쳤습니다.
  • 승리 처리 오른쪽 클릭으로 끝낸 게임도 승리 애니메이션을 보여 주고, 이긴 뒤에는 시계가 멈춥니다.
  • 설정 저장 원본의 settings.xml 대신 브라우저 localStorage에 저장합니다.
3D 핀볼 플레이 화면
pinball.gif
03 · apps/pinball

3D 핀볼

원본 pinball.exe를 디컴파일한 C++ 엔진을 파일 단위로 1:1 대응시켜 JS로 옮겼습니다. 메시지 글꼴은 REA의 PE 리소스 분석으로 PBMSG_FT 리소스를 찾아, 디컴파일 저장소의 데이터와 SHA-256이 같은 것을 확인했습니다.

  • 데이터 pinball.dat의 그룹마다 그림, 깊이 맵, 충돌 형상, 부품 목록이 들어 있습니다.
  • 화면 600×416 화면에 깊이 맵으로 부품을 겹쳐 그리고, 바뀐 영역만 다시 그립니다.
  • 물리 초당 120번 갱신. 공을 광선처럼 쏘아 10×15 격자 안의 선·원·플리퍼와 충돌을 계산합니다.
  • 규칙 부품이 메시지 코드를 보내면 control 모듈이 점수·조명·미션을 바꿉니다.

조작법

동작PC모바일
왼쪽 플리퍼Z / 마우스 왼쪽왼쪽 터치 영역
오른쪽 플리퍼/ / 마우스 오른쪽가운데 터치 영역
플런저스페이스 누르고 놓기오른쪽 영역 길게 누르고 떼기
테이블 흔들기X / . / ↑없음
새 게임 · 일시정지F2 · F3Game 메뉴

모바일은 손가락마다 따로 인식해서 두 손가락으로 양쪽 플리퍼를 동시에 쓸 수 있습니다. 치트 코드도 원본처럼 입력할 수 있지만, 쓰면 최고 점수에 오르지 않습니다.

원본과의 차이

  • 게임 데이터 미포함 테이블 데이터(pinball.dat)는 Microsoft 소유라 저장소에 넣지 않았습니다. 원본 Windows XP의 파일을 직접 넣어야 합니다.
  • 소리 재생하지 않고, WAV 길이만 읽어 원본과 같은 대기 시간을 씁니다.
  • 실수 정밀도 원본은 32비트 float, 이 버전은 64비트로 계산해서 공 궤적이 아주 미세하게 다를 수 있습니다.
  • 안전장치 범위를 벗어난 메모리를 읽던 범퍼 로직을 의도대로 고치고, 격자 배치 반복문에 횟수 제한을 두었습니다.

[+]License

// 라이선스

이 저장소의 코드는 MIT 라이선스입니다. 다른 프로젝트에서 가져온 부분은 각 프로젝트의 라이선스를 따릅니다.

  • 지뢰찾기 이미지, XP 창/메뉴 스타일 winXP (MIT, © 2019 Shizuku Yang)
  • 솔리테어 카드 이미지와 아이콘 DualBrain/Solitaire (MIT, © Cory Smith)
  • 3D 핀볼 엔진 SpaceCadetPinball (MIT, © 2020-2021 Andrey Muzychenko). 게임 데이터는 Microsoft 소유이며 포함하지 않습니다.