원형 탄막이 플레이어를 조준하는 방식
엘리의 공격은 초기 탄환 수가 16개인 조준 원형 탄막을 요청합니다. 보조 함수 하나가 각 탄환의 방향을 계산합니다. 같은 원형 탄막을 고정 방향으로 발사하거나 플레이어 쪽으로 회전할 수 있습니다.
REA로 TH04가 원형 탄막을 만들고 플레이어를 조준하는 방식을 찾아줘. 계산을 설명하고 코드도 보여줘.
원본 실행 파일과 체크아웃한 재구성 저장소를 로컬에 준비한 상태에서 사용하는 예제 프롬프트입니다.
TH04는 시계 방향 한 바퀴를 256각도 단위로 표현합니다. 탄환이 16개면 인덱스마다 16단위씩 더합니다: 0, 16, 32, …, 240. 플레이어 방향을 더하면 모든 위치가 함께 회전합니다.
복구된 소스의 발사 템플릿
bullet_template.angle = 0;
bullet_template.group = BG_RING_AIMED;
bullet_template.count = 16;
bullet_template_tune();
난이도와 성능 조정 전에 패턴을 선택하는 코드입니다. 공격 소스 읽기.
REA가 반환하는 내용
각 탄환의 속도와 각도를 정하는 함수 bullet_velocity_and_angle_set()을 분석합니다. REA는 명령어, 의사 코드, 참조를 반환합니다. 결과의 세 부분으로 이 패턴을 설명할 수 있습니다.
-
코드를 읽기 전에 DOS 이미지 검증
에이전트 → REAopen_binary {"path": "MAIN.EXE"} inspect_native_load_image {}REA → 에이전트 · 선택한 필드status: "verified" format: "dos-mz" load_segment: 4096 header_bytes: 6144 module_bytes: 150114로드된 코드와 재배치 기록이 제공된 실행 파일에 대응하는지 검증합니다. 위 경로는 표시를 위해 줄였습니다.
-
원형 탄막의 곱셈·나눗셈 읽기
에이전트 → REA ·analyze_function{"procedure": "0x2cfc8"}REA → 에이전트 · 명령어 발췌문0x2d0eb: MOV AX, SI 0x2d0ed: SHL AX, 0x8 0x2d0f0: MOV DL, byte ptr [0x53af] 0x2d0f9: IDIV BXSI에는 탄환 인덱스가 있습니다. 시프트로 256을 곱한 뒤,DS:53AF에서 읽은 탄환 수로 나눕니다. 유지보수 중인 소스에서는 이 필드를bullet_template.count라고 부릅니다. 전체 과정은 아래에 있습니다. -
패턴이 플레이어 쪽으로 향하는 위치 찾기
같은 함수 결과 · 조준 부분 발췌0x2d190: SUB AX, word ptr [0x53a6] 0x2d198: SUB AX, word ptr [0x53a4] 0x2d19d: CALLF 0x1000:1da8 0x2d1a2: ADD word ptr [BP + -0x2], AX대응하는 유지보수 C++ 코드group_angle_offset += iatan2( player_pos.cur.y - bullet_template.origin.y, player_pos.cur.x - bullet_template.origin.x );명령어의 피연산자에서 두 좌표의 차이와 방향 보조 함수를 확인할 수 있습니다. 반환된 각도는 원형 탄막의 상대 각도에 더해집니다. 소스의 이름은 주소의 의미를 알려주고, REA는 그 뒤의 원본 연산을 확인하게 해줍니다.
어셈블리에서 읽기 쉬운 C++로
단계를 선택해 원본 명령어와 각도 계산을 연결해 보세요. 이 요약은 조준 원형 탄막 경로를 따릅니다. 전체 소스는 확산형, 중첩형, 무작위 패턴도 처리합니다.
0x2cfcf: MOV SI, word ptr [BP + 0x4]
0x2d0eb: MOV AX, SI
0x2d0ed: SHL AX, 0x8
0x2d0f0: MOV DL, byte ptr [0x53af]
0x2d0f4: MOV DH, 0x0
0x2d0f6: PUSH DX
0x2d0f7: CWD
0x2d0f8: POP BX
0x2d0f9: IDIV BX
0x2d0fb: MOV word ptr [BP + -0x2], AX
0x2d18d: MOV AX, [0x4650]
0x2d190: SUB AX, word ptr [0x53a6]
0x2d194: PUSH AX
0x2d195: MOV AX, [0x464e]
0x2d198: SUB AX, word ptr [0x53a4]
0x2d19c: PUSH AX
0x2d19d: CALLF 0x1000:1da8
0x2d1a2: ADD word ptr [BP + -0x2], AX
0x2d1b9: MOV AL, byte ptr [BP + -0x2]
0x2d1bc: ADD AL, byte ptr [0x53ad]
0x2d1c0: MOV [0xbcc8], AL
unsigned char aimed_ring_angle(
int index, int count,
int player_direction,
unsigned char rotation)
{
int angle = index;
angle = (angle * 256) / count;
angle += player_direction;
angle += rotation;
return (unsigned char)angle;
}
01 · 탄환 인덱스를 읽습니다. 스택 인수를 SI에 로드합니다. 탄환 16발로 이루어진 원형 탄막에서 이 인덱스는 0부터 15까지입니다.
02 · 한 바퀴에 걸쳐 방향을 균등하게 배치합니다. SHL AX,8 명령은 256을 곱합니다. 탄환 개수를 워드 크기로 0 확장한 뒤, IDIV 명령으로 곱한 결과를 그 개수로 나눕니다. 개수가 16이면 인덱스가 하나 증가할 때마다 각도가 16단위씩 증가합니다.
03 · 플레이어 방향을 더합니다. 두 번의 뺄셈으로 플레이어 좌표에서 원점 좌표를 뺍니다. 방향 계산 도우미는 AX로 각도를 반환합니다. 이 각도를 더하면 원형 탄막 전체가 플레이어 쪽으로 회전합니다.
04 · 패턴의 회전을 더합니다. ADD AL,[0x53ad] 명령으로 템플릿 각도를 더합니다. Elly의 초기 템플릿에서는 이 각도가 0입니다. 다른 패턴은 같은 도우미에 회전값을 적용해 사용할 수 있습니다.
05 · 최종 각도를 한 바이트에 저장합니다. 저장 명령은 AL 값을 생성 각도 필드에 기록합니다. 부호 없는 바이트로 형 변환할 때와 마찬가지로, 값이 255를 넘으면 0부터 순환합니다. 주변 소스는 이 각도와 속력을 속도 벡터로 변환합니다.
어셈블리는 조준 원형 탄막 분기, 조준 계산, 최종 저장을 발췌한 것입니다. 위 C++는 읽기 쉬운 요약입니다. 아래 컴파일러 검증은 연결된 프로젝트의 실제 유지보수 소스에 적용됩니다.
원형 탄막과 조준의 유지보수 소스 읽기
angle_offset = (i * BULLET_ANGLE_FULL_TURN) / count;
if (i >= (count - 1)) {
group_complete = true;
}
goto aim_or_no_aim;
aim:
group_angle_offset += iatan2(
(player_pos.cur.y - bullet_template.origin.y),
(player_pos.cur.x - bullet_template.origin.x)
);
no_aim:
vector2_near(
bullet_template.velocity,
(group_angle_offset + bullet_template.angle),
speed
);
bullet_spawn_angle = (group_angle_offset + bullet_template.angle);
유지보수 소스 검증
TH04 프로젝트에 기록된 검사에서는 버전을 고정한 Turbo C++ 4.0J 도구 모음으로 이 도우미 함수를 포함한 탄환 생성 코드를 컴파일합니다.
2,139바이트 일치
컴파일된 탄환 생성 코드는 원본 실행 파일의 2,139바이트 구간과 일치합니다.
독립적인 클린 빌드 두 번
별도로 빌드한 두 결과가 같은 바이트로 일치합니다. 기록된 입력 해시는 여기서 보여주는 유지보수 소스와 일치합니다.
2026년 10월 3일 기록. 컴파일러 검증 읽기.
대상 식별 정보와 분석 범위
| 원본 대상 | MAIN.EXE, 156,258바이트, DOS MZ |
|---|---|
| 보조 함수 진입점 | REA가 로드한 이미지의 0x2cfc8 |
| 원본 파일 오프셋 |
address_to_file_offset이 반환한 0x1e7c8
|
| 기록된 코드 분석 | REA 4.1.0 · 2026년 10월 7일 |
컴파일러 검사는 이 도우미 함수를 포함한 전체 탄환 추가 코드 섹션을 다룹니다. MAP 기여분과 겹치는 재배치도 비교합니다.
REA는 로드 세그먼트 0x1000에서 정적 DOS 로드 이미지를 검증했습니다. 주소는 이 분석 이미지를 기준으로 합니다. 함수 결과는 전체 517바이트 범위 안의 두 구간에 본문 503바이트가 있다고 보고합니다. 위 발췌 명령어는 이 구간에 속합니다.
소스의 이름과 컴파일러 검증은 TH04 체크포인트 0d72e980에서 가져왔습니다. 이전 재구성 관찰에는 프로젝트 자체 분석 스크립트를 사용했으며, 이 페이지는 같은 원본 대상을 REA로 새로 분석한 결과를 추가합니다. 게임의 식별 정보는 저장소 매니페스트로 고정돼 있지만, 독립적인 무변경 덤프의 출처 확인은 아직 남아 있습니다.
그림은 각도 계산을 설명합니다. 전체 게임의 조작, 타이밍, PC-98 하드웨어 동작은 재구성 프로젝트에서 별도로 런타임 검증합니다.
전체 TH04 재구성
프로젝트는 유지보수 중인 C++과 어셈블리로 게임의 DOS 프로그램 네 개를 빌드합니다. 소스는 탄환 생성 외에도 스테이지, 보스, 렌더링, 입력, 메뉴, 엔딩, 점수 처리를 다룹니다.
- 탄환 생성 소스전체 보조 함수, 다른 패턴 유형, 템플릿 조정.
- DOS 빌드·실행 가이드소스를 빌드하고 프로젝트의 PC-98 에뮬레이터 환경에서 테스트합니다.
- 현재 프로젝트 상태DOS 검증과 별도로 진행하는 네이티브 x64 이식.