기본 콘텐츠로 건너뛰기

추천 가젯

Tmux 환경에서 Vim 컴파일 시 발생하는 termio/termios 감지 오류 해결 방법

 리눅스 환경에서 소스코드를 직접 빌드하다 보면 의외의 환경 변수나 터미널 세션 설정 때문에 엉뚱한 빌드 에러를 마주할 때가 있습니다. 대표적인 예로 Tmux 세션 내부에서 Vim 소스를 컴파일할 때 발생하는 termio/termios 감지 오류 가 있습니다. 이번 글에서는 해당 에러가 발생하는 원인과, 단순한 clean 으로는 해결되지 않는 이유 및 올바른 해결 방법을 정리합니다. 1. 문제 원인 Vim의 소스 코드 빌드 과정( configure )은 시스템이 System V 계열인지 Linux 계열인지 판별하기 위해 termio.h 와 termios.h 헤더 파일 및 터미널 인터페이스를 검사(Probe)합니다. 하지만 Tmux 내부(세션 안)에서 컴파일을 진행할 경우 , Tmux가 제공하는 PTY(Pseudo-Terminal) 환경과 TERM=screen 등의 특수한 환경 변수 영향으로 인해 Autoconf가 터미널 인터페이스를 검출하는 과정에서 오동작을 일으킵니다. 그 결과, 실제 시스템 조건과 무관하게 설정 에러를 발생시키게 됩니다. 2. 왜 make clean 으로는 해결되지 않을까? 일반적인 개발 과정에서는 빌드가 꼬였을 때 make clean 을 실행하곤 합니다. 하지만 make clean 은 컴파일된 오브젝트 파일이나 바이너리( .o 파일 등)만 삭제할 뿐, Autotools가 시스템 환경을 탐색한 결과로 남긴 캐시( config.cache 또는 내부 매크로 변수)나 설정 파일들은 그대로 유지 합니다. 일반적인 상황에서는 시스템의 하드웨어/OS 정보가 바뀌지 않기 때문에 이 잔여물이 문제가 되지 않습니다. 그러나 Tmux나 Screen 같은 터미널 멀티플렉서 환경에서 탐색된 왜곡된 정보가 캐시에 박혀버리면, 나중에 Tmux 외부(일반 터미널)로 나와서 빌드를 시도해도 이전의 오염된 캐시 때문에 계속해서 오류가 발생하게 됩니다. 3. 해결 방법 이 문제를 해결하기 위해서는 반드시 Tmux 외부 환경 에서 기존의 오염된 설정 파일을 ...

[리버싱 일기/리메이크] 랑그릿사 2의 마법 데미지 공식은 어떻게 설계되었는가?

필자는 최근 고전 명작 랑그릿사 2 PC판을 기드라로 분석하며, 마법 데미지가 계산되는 내부 로직을 추적했습니다. 각종 구조체와 변수명을 정리하고 나니, 90년대 게임 특유의 실용적이면서도 명쾌한 공식이 모습을 드러냈습니다.

1. 특정 마법의 개별 로직: 토네이도(Tornado)

가장 먼저 분석한 것은 범위 마법인 토네이도입니다. 코드상에서는 대상 유닛의 타입에 따른 보너스 판정이 가장 먼저 눈에 띕니다.

C
void Tornado(void)
{
    // 대상 유닛이 비병일 경우, 보너스 데미지 플래그 활성화
    if (ARMY2_UNITTYPE == FLYING_UNIT) {
        BonusSpellDamage = 1;
    }

    /* 계산 공식: ((레벨 / 2) + 시전자의 SP) * 2 */
    int damageValue = (((int)FORCE1_LV >> 1) + (int)FORCE1_SP) * 2;

    // 최종 데미지 적용 함수 호출 (마법 방어력 계산 포함)
    ApplySpellDamage_MDF(damageValue);
}

토네이도는 비병에게 치명적이라는 설정답게, BonusSpellDamage를 통해 추가 타격을 줍니다. 흥미로운 점은 기본 데미지가 (레벨 >> 1 + SP) * 2로 계산된다는 것인데, 여기서 SP는 유닛의 티어값(파이터=1, 로드=2 등)을 의미합니다.

2. 마법 방어력을 고려한 최종 데미지 산출

입력된 기초 데미지는 ApplySpellDamage_MDF 함수를 거치며 타겟의 마법 방어력(MDF)에 의해 가공됩니다.

C
void ApplySpellDamage_MDF(int damage)
{
    // 1. 마법 면역 상태 및 마법 방어력 체크
    if (is_magic_immune(FORCE2) || (100 - FORCE1_2_MDF == 0)) return;

    // 2. 최종 데미지 계산식
    // 보너스 데미지 + 아이템 보너스 + (기초 데미지 * 마방 관통률)
    int real_damage = BonusSpellDamage + SpellDamage_Item + 
                      (damage * (100 - (uint)FORCE1_2_MDF)) / 100;

    // 3. 데미지 보정 (데미지 하한선 및 HP 초과 방지)
    if (real_damage <= 0) real_damage = 1;

    int targetHP = (int)FORCE2->Army[ARMY2_NUMBER].HP;
    if (targetHP < real_damage) real_damage = targetHP;

    // 4. 누적 결과 기록 (범위 마법 계산용)
    AccumSpellEffect += real_damage;
    AccumSpellTarget += 1;

    // 5. 실행 플래그 확인 후 실제 데이터 반영
    if (_run_flag_apply == 1) {
        FORCE2->Army[ARMY2_NUMBER].HP -= (char)real_damage;
        
        if (FORCE2->Army[ARMY2_NUMBER].HP == 0) {
            killed_target_logic(); // 유닛 전사 처리
        }
    }
}

3. 분석을 통해 알 수 있는 사실들

분석 결과, 랑그릿사 2의 마법 데미지는 크게 세 단계를 거쳐 적용됩니다.

  1. 최소 데미지의 보장: 마법 방어력이 아무리 높더라도, 공식에 의해 산출된 데미지가 0이라면 강제로 1의 데미지를 가합니다.

  2. 누적 데이터의 활용: AccumSpellEffect와 AccumSpellTarget 변수를 통해 마법 한 번으로 총 얼마의 데미지를 몇 명에게 입혔는지 기록합니다. 이는 주로 범위 마법의 효율을 계산할 때 사용됩니다.

  3. AI 시뮬레이션의 분리: _run_flag_apply라는 플래그가 매우 중요합니다. AI가 마법을 쓸지 말지 결정하기 위해 데미지를 미리 계산해 볼 때는 이 플래그를 끄고 함수를 호출하여, 실제 HP는 깎지 않은 채 예상 결과물만 얻어가는 구조입니다.

맺으며

기드라에서 이 로직을 타고 올라가면, 적군 AI가 마법을 선택하는 판단 근거를 찾을 수 있을 것으로 보입니다. 비병에게 토네이도를 날리는 AI의 영리함은 결국 이런 간결한 if문과 시뮬레이션 플래그에서 시작된 것이었습니다. 리버싱은 단순한 코드 해독을 넘어, 30년 전 개발자의 설계 철학을 엿보는 즐거운 과정입니다.

댓글