Navigation

Conventions

파일 위치와 이름, 스크립트 모양. 되는 구문과 함정은 Razor, 머리 위 메시지는 Overheads.

00 한눈에

절내용
01폴더와 파일 이름, config/의 주인
02스크립트 순서와 모양. 헤더, 시작 4줄, 섹션과 블록 배너, 주석, 편집기 하이라이팅
03변수 접두, 세션 값과 영속 값, serial 금지 이유
04타이머 만들기와 읽기
05그 밖의 관용구
06overhead 쓰는 법
07PvP 겸용 스크립트

이 문서에 걸린 질문은 Open items.

저장소

01 저장소 구조

01.A 폴더

폴더 규칙의 정본은 이 표. 루트 README의 폴더 표는 사람용 요약.

폴더내용
script/Razor 스크립트. 모두 공용
module/, recipe/한 벌만 둔 블록, 루프와 루틴마다 레시피 하나. util/build-scripts.mjs가 script/combat/*, script/gather/*와 loadout 같은 루틴으로 조립(Modules)
config/사람마다 클라이언트 설정 원본 하나(config/<이름>/). 링크 방식과 파일별 설명은 config/README.md
content/설계 문서. 공개 문서는 public/ 아래 묶음별 폴더, 홈은 README.md, 공용 자원은 asset/. for-humanity 사이트로 읽음(pnpm docs:dev). 문서 목록은 Workflow 00.A절, 쓰는 법은 Writing
language/README 번역본. 규칙은 Writing 07절
util/저장소 도구. 아래 표

util/ 구성. Node 도구는 Node 22 표준 라이브러리만, 문서 검사만 parse5 사용.

파일역할
setup.sh게임을 저장소에 링크
build-scripts.mjs모듈과 레시피로 루프 조립(pnpm build). --check, --settings, --new-module
check.sh블록 짝, 값 없이 쓴 접두 변수 검사. 인자 없이 돌리면 끝에 조립 결과물 검사(build-scripts.mjs --check)도
check-docs.mjs문서 사이트의 끊긴 링크와 앵커, 번호 제목의 앵커 검사. 테스트는 check-docs.test.mjs
pvp-sim.mjs조건부 전투 모형. 수치 검사는 pvp-sim.test.mjs
razor-syntax/.razor 편집기 하이라이팅(02.F절)

01.B script 분류와 파일명

script/는 언제 돌리는지로 분류. 파일명만으로 무엇인지 알 수 있어야 함.

폴더언제파일명 규칙예
script/combat/사냥 중 계속 도는 메인 루프<템플릿>[-<변형>]bard-necro-enhanced, pvp
script/hotkey/키에 물린 단발 매크로<동작>[-<대상>]. 무기 바꾸기는 weapon-<무기>weapon-katana, cancel-target, regear, moongate
script/debug/진단, 동작 시험용 단발 스크립트. 필요하면 핫키<검사>[-<대상>]dump-label, debug-target-find, debug-target-state, test-telekinesis-var
script/train/스킬 훈련<스킬>magery, carto
script/gather/채집 루프<채집>lumberjack-enhanced, skinning-enhanced
script/loot/주워 온 것 정리, 분해<동사>-<대상>recycle, claim-loot, bank-pouch
script/restock/나가기 전 준비. 로드아웃<동사>-<대상>loadout
script/archive/쓰지 않는 스크립트. 핫키 없음, 수정 없음, util/check.sh 제외. 다시 쓰려면 원래 폴더로 이동원래 이름 그대로bard-mace, hally-mage, lumberjack
script/shelf/outlandsbutler.com이 만든 Storage Shelf 로드아웃<템플릿>bard-dexxer, sailing

01.C 파일 규칙

01.D config는 사람별

모양

02 스크립트 모양

02.A 기준 파일

02.B 구조와 섹션 배너

루프 구성: 헤더(02.C절), 시작 4줄(02.D절), 아래 순서의 섹션(skinning-enhanced.razor, lumberjack-enhanced.razor). 조립한 루프의 시작 4줄은 config__clear_at_start를 읽어야 함 → STATE 뒤 준비 자리(Modules 05절).

배너내용
CONFIG손으로 조정하는 config__ 값
WAIT AND COOLDOWNwait__, interval__, cooldown__ 값. 단위는 모두 ms
TIMERtimer__ 생성과 첫 값(04절)
STATEvar__ 첫 값. Play를 넘어 이어 쓸 값은 if not varexist로 감쌈(03.B절)
INSTRUMENT 같은 준비루프 전 한 번 하는 준비. 예: 악기 찾기, 없으면 고르게 함. 조립한 루프에서는 모듈별 출처 상자 밑
MAIN LOOPwhile not dead부터 endwhile까지 루프 하나. 안의 블록은 - 배너로 구분

배너는 두 종류. 둘 다 폭 90칸, 제목은 대문자 # 제목 한 줄.

# ========================================================================================
# CONFIG
# ========================================================================================
@setvar! config__chatty 1

while not dead
    # ------------------------------------------------------------------------------------
    # BANDAGE
    #
    # Never restarts a running bandage, and full health does not start one. Its target
    # cursor would replace a held precast, so it waits while any cursor is up.
    # ------------------------------------------------------------------------------------
    if not bandaging and not paralyzed
        ...
    endif
endwhile
    # ------------------------------------------------------------------------------------
    # BANDAGE                                               module/recovery/bandage.razor
    # ------------------------------------------------------------------------------------
    if config__use_bandages = 1 and not bandaging and not paralyzed
        ...

02.C 헤더

# Put your share from the distribution chest into your own loot container.
# Needs: global__my_loot_container (asked for on first run), container within 2 tiles

02.D 시작 4줄, 들여쓰기, 빈 줄

clearall
clearsysmsg
cleardragdrop
clearignore

빈 줄은 작업 단위의 경계에 하나씩.

settimer "timer__action" 0

while queued and timer "timer__action" < wait__timeout
    wait wait__poll
endwhile

if queued
    stop
endif

dclick var__tool
waitfortarget wait__target

if targetexists
    target alias__item
endif

02.E 주석

02.F 편집기 하이라이팅

대상scopeWebStorm 색(Language Defaults)Light 기본
명령(@setvar!, hotkey, cast)과 if, while, endifkeywordKeyword남색 굵게
조건식(poisoned, findtype, insysmsg)constant.otherConstant보라 굵게 기울임
and, or, not, stop, breakentity.other.attribute-nameMarkup → Attribute분홍
self, backpack 같은 레이어와 대상constant.character.entityMarkup → Entity파랑 굵게
문자열과 > 메모, # @ hotkeys 목록stringString초록 굵게
문자열 안의 {{…}}constant.character.escapeValid escape sequence남색 굵게
# @ use, # @ config 같은 지시. # @ when과 # @ every 뒤 조건은 코드처럼meta.tagMetadata올리브
모듈 이름, # module/…razor 출처entity.other.attribute-nameMarkup → Attribute분홍
섹션 제목(# CONFIG)markup.headingTextMate → Heading굵게, 밑줄
블록 제목(# BANDAGE)markup.boldTextMate → Bold굵게
상자의 이름 줄(# config__x, # heal_hits (default 35))constant.otherConstant보라 굵게 기울임
접두 변수(config__, var__ 등)variableParameter, Local variable색 없음

scope 선택 기준: WebStorm 기본 Light 구성표에서 색이 있는 항목. Function call, Parameter처럼 Light에서 색 없는 항목은 피함.

WebStorm 설정.

  1. Settings → Editor → File Types → Razor(사용자 정의 형식)에서 *.razor 패턴 삭제. 패턴이 남으면 TextMate 문법 미적용
  2. Settings → Editor → TextMate Bundles → + → 저장소의 util/razor-syntax 폴더 선택
  3. 색: Settings → Editor → Color Scheme → Language Defaults에서 위 표의 이름으로 변경. TextMate 문법은 이 기본 색을 따름
  4. 문법 파일 변경 시: TextMate Bundles 목록에서 번들 체크 끄고 켠 뒤 Apply, 또는 WebStorm 재시작

VS Code: util/razor-syntax 폴더를 확장으로 추가.

03 변수

03.A 접두

접두로 종류 표시. 단어는 snake_case, 접두와 이름 사이는 더블 언더스코어.

접두내용수명
config__손으로 조정하는 설정. 파일 맨 위에 모음세션
wait__쉬는 시간, 타겟 커서 대기 시간세션
interval__timer__와 비교하는 간격. 그 타이머가 다시 돌기까지의 ms(timer "timer__food" >= interval__food)세션
cooldown__Razor 쿨다운 바 길이(cooldown "heal pot" cooldown__heal_potion). 쿨다운 바에만세션
var__스크립트가 든 상태세션
alias__find, findtype의 as로 묶은 결과. 블록 밖에서 쓰려면 var__로 옮김(Razor 03절)묶은 블록 안
label__getlabel 결과. 블록 밖에서는 <not found>(Razor 03절)getlabel을 부른 블록 안
timer__createtimer, settimer 대상세션
list__createlist, pushlist 대상. foreach x in list__y의 루프 변수 x는 접두 없음세션
global__프로필에 저장되는 값영속

03.B 세션 값과 영속 값

03.C serial 리터럴 금지

0x45147618 같은 serial 리터럴 금지. script/는 공용 → 남의 컨테이너 번호가 pull 한 모두의 게임에 들어감. 개인 값은 프로필에 저장, 스크립트에는 이름만(script/loot/claim-loot.razor).

if not varexist global__my_loot_container
    overhead "[ loot chest, pick ]" 255
    setvar global__my_loot_container
endif

setvar 이름 → 타겟 커서, 찍은 대상의 serial을 프로필 script variable로 저장.

03.D varexist는 선언 여부만 확인

if not varexist global__my_supply_box or not find global__my_supply_box ground -1 -1 config__reach
    unsetvar global__my_supply_box
    overhead "[ supply box, pick ]" 255
    setvar global__my_supply_box
endif

그 밖의 곳에는 이 검사 금지. find는 클라이언트가 지금 인식하는 것만 찾음 → 집의 상자를 던전에서 검사하면 멀쩡한 값을 지움.

관용구

04 타이머

skinning-enhanced.razor의 TIMER 섹션 모양. 첫 값을 간격(interval__)으로 주면 첫 패스부터 통과.

if not timerexists "timer__overhead_message"
    createtimer "timer__overhead_message"
endif

settimer "timer__overhead_message" interval__overhead_message

루프 안: timer로 지난 시간 읽기 → 할 일 → settimer로 0부터 다시.

if timer "timer__overhead_message" > interval__overhead_message
    overhead "[ heal pot, out ]" 254
    settimer "timer__overhead_message" 0
endif

05 그 외 관용구

목적모양
시스템 메시지 없이 명령 실행@ 접두
찾은 것 재사용if findtype "name" backpack as alias__x로 alias에 담음
같은 검색을 되풀이하며 하나씩 보기@ignore와 @clearignore(Razor 03절의 findtype 줄)
라벨로 분기getlabel alias__x label__x 뒤 if "문자열" in label__x. in은 대소문자 구분 → 정확한 글자는 debug/dump-label로 확인
검프와 핫바 조작gumpexists, ingump로 확인 후 gumpresponse
디버그 출력{{var}} 보간. 확인 후 삭제

06 overhead

07 PvP 겸용 스크립트