맵 데이터 관련 ============== 맵 전반 관련 ^^^^^^^^^^^^^ * LoadMap(fname) 맵을 읽고 맵 관련 CHK 정보를 다 읽어들입니다. * GetChkTokenized() CHK 데이터를 직접 읽고 쓸 수 있습니다 :: chkt = GetChkTokenized() chkt.getsection('TRIG') # Trig 섹션 읽기 chkt.setsection('TRIG') # Trig 섹션 변형 다만 STR이나 TRIG 단락은 eudplib에서도 쓰니까 웬만하면 변형하지 마세요 * MPQAddFile(fname, content, is_wav) 파일을 맵 MPQ에 넣습니다. content는 파이썬 bytes 오프젝트입니다. * MPQAddWave(fname, content) WAV 파일을 맵 MPQ에 넣습니다. * EUDOnStart(func) 맵이 시작할 때 발동할 함수를 지정 * EUDDoEvents() 트리거 루프를 그 자리에서 잠시 멈춥니다. * SaveMap(fname, rootf) rootf 함수를 메인 함수로 해서 eudplib 맵을 저장합니다. 맵 데이터 ^^^^^^^^ * IsMapdataInitialized() LoadMap 함수로 맵 데이터를 로드했는지를 확인합니다. 아직 맵 데이터가 초기화가 덜 됬으면 아래 함수들이 동작하지 않을 수도 있습니다. * EncodeAIScript(ais) * EncodeAllyStatus(s) * EncodeComparison(s) * EncodeCount(s) * EncodeLocation(loc) * EncodeModifier(s) * EncodeOrder(s) * EncodePlayer(s) * EncodePropState(s) * EncodeProperty(prop) * EncodeResource(s) * EncodeScore(s) * EncodeString(s) * EncodeSwitch(sw) * EncodeSwitchAction(s) * EncodeSwitchState(s) * EncodeUnit(u) 이름을 트리거에서 쓰는 번호로 바꿉니다. EncodeLocation('Location 0') # NOT exist EncodeLocation('Location 1') # 1 EncodeLocation('Anywhere') # 64 EncodeString에 맵에 없는 스트링을 넣으면 알아서 스트링 테이블에 새 데이터를 넣고 새로 만든 스트링의 오프셋을 반환합니다. * GetUnitIndex(u) * GetLocationIndex(l) * GetPropertyIndex(prop) * GetStringIndex(s) * GetSwitchIndex(s) 이름을 인덱스로 바꿉니다. : ** GetLocationIndex는 eudplib 0.63.0 이전 버전에서는 EncodeLocation보다 1 작습니다 ** : GetLocationIndex('Location 0') # NOT exist GetLocationIndex('Location 1') # 1 GetLocationIndex('Anywhere') # 64 * GetPlayerInfo(player) player 플레이어의 정보를 나타냅니다. 자세한건 print해보세요. * UnitProperty(hitpoint, shield, energy, resource, hanger, cloaked, burrowed, intransit, hallucinated, invincible) 굉장히 복잡한 함수입니다만, CreateUnitWithProperties 액션의 프로퍼티에 쓰이는겁니다. EncodeProperty 함수를 이용해 프로퍼티 번호로 만들 수 있습니다. 기초 데이터 ^^^^^^^^^^ * Db(b) 바이너리 데이터를 메모리에 올릴때 씁니다. * EUDArray(initval) 단순 EUD 배열에 씁니다. * EUDGrp(content) GRP에 씁니다. .. ---------------------------------------------------------------------------- 트리거 관련 =================== 조건들 ------------------- 기존 조건 ^^^^^^^^ * Always() * Accumulate(player, comparison, number, resource_type) * Bring(player, comparison, number, unit, Location) * Command(player, comparison, number, unit) * CommandLeast(unit) * CommandLeastAt(unit, Location) * CommandMost(unit) * CommandMostAt(unit, Location) * CountdownTimer(Comparison, Time) * Deaths(player, comparison, number, unit) * ElapsedTime(Comparison, Time) * HighestScore(ScoreType) * LeastKills(unit) * LeastResources(resource_type) * LowestScore(ScoreType) * MostKills(unit) * MostResources(resource_type) * Never() * Opponents(player, comparison, Number) * Score(player, ScoreType, comparison, Number) * Switch(switch, state) 특수조건 ^^^^^^^ * Condition(locid, player, amount, unitid, comparison, condtype, restype, flags) CHK 구조대로 조건을 만들어 쓰고싶을때 쓰세요. scenario.chk를 공부하지 않으신 분은 이걸 쓰실 일이 없을겁니다. * Memory(dest, cmptype, value) 오프셋의 값을 확인합니다. * MemoryEPD(dest, cmptype, value) Memory랑 똑같은데 dest가 오프셋의 EPD값입니다. 액션들 ------------------- 기존 액션 ^^^^^^^^ * CenterView(where) * Comment(text) * CreateUnit(Number, unit, where, for_player) * CreateUnitWithProperties(Count, unit, where, player, Properties) * Defeat() * DisplayText(Text, AlwaysDisplay) * Draw() * GiveUnits(Count, unit, owner, where, new_owner) * KillUnit(unit, Player) * KillUnitAt(Count, unit, where, for_player) * LeaderBoardComputerPlayers(state) * LeaderBoardControl(unit, label) * LeaderBoardControlAt(unit, location, label) * LeaderBoardGoalControl(Goal, unit, label) * LeaderBoardGoalControlAt(Goal, unit, location, label) * LeaderBoardGoalKills(Goal, unit, label) * LeaderBoardGoalResources(Goal, resource_type, label) * LeaderBoardGoalScore(Goal, ScoreType, label) * LeaderBoardGreed(Goal) * LeaderBoardKills(unit, label) * LeaderBoardResources(resource_type, label) * LeaderBoardScore(ScoreType, label) * MinimapPing(where) * ModifyUnitEnergy(Count, unit, owner, where, percent) * ModifyUnitHangarCount(Add, count, unit, owner, where) * ModifyUnitHitPoints(Count, unit, owner, where, percent) * ModifyUnitResourceAmount(Count, owner, where, new_value) * ModifyUnitShields(Count, unit, owner, where, percent) * MoveLocation(location, on_unit, owner, dest_location) * MoveUnit(Count, unit_type, owner, start_location, dest_location) * MuteUnitSpeech() * Order(unit, owner, start_location, order_type, dest_location) * PauseGame() * PauseTimer() * PlayWAV(sound_name) * PreserveTrigger() * RemoveUnit(unit, Player) * RemoveUnitAt(Count, unit, where, for_player) * RunAIScript(script) * RunAIScriptAt(script, where) * SetAllianceStatus(player, Status) * SetCountdownTimer(time_modifier, Time) * SetDeaths(player, modifier, number, unit) * SetDoodadState(state, unit, owner, where) * SetInvincibility(state, unit, owner, where) * SetMissionObjectives(text) * SetNextScenario(scenario_name) * SetResources(player, modifier, amount, resource_type) * SetScore(player, modifier, amount, ScoreType) * SetSwitch(switch, state) * TalkingPortrait(unit, Time) * Transmission(unit, where, sound_name, time_modifier, time, text, AlwaysDisplay) * UnMuteUnitSpeech() * UnpauseGame() * UnpauseTimer() * Victory() * Wait(Time) 특수 액션 ^^^^^^^^ * Action(locid1, strid, wavid, time, player1, player2, unitid, acttype, amount, flags) CHK 구조대로 액션을 만들어 쓰고싶을때 쓰세요. scenario.chk를 공부하지 않으신 분은 이걸 쓸 일이 없을겁니다. * DisplayExtText(text) DisplayText인데 스트링 용량을 잡아먹지 않습니다. 정확히 말하자면 스트링 테이블을 새로 만들어 써가지고 기존 스트링 65536 byte를 쓰지 않는 방식입니다. 어쨌든 스트링 용량을 줄이는덴 좋을겁니다. * SetMemory(dest, modtype, value) 메모리 값을 수정합니다. * SetMemoryEPD(dest, modtype, value) 메모리 값을 수정하는데 EPD를 씁니다. * SetCurrentPlayer(p) Current Player값을 수정합니다. 여러 최적화가 들어가있으니까 6509B0을 직접 수정하기보단 이 액션을 애용해주세요. * SetNextPtr(trg, dest) 트리거의 nextptr값을 수정합니다. 자세한건 뻘강좌를 참고하세요. http://blog.naver.com/whyask37 기타 ------------------- * Trigger(conditions, actions, preserved) 조건과 액션이 있는 트리거입니다. 기본적으로 preserved 상태입니다. 조건/액션 갯수 제한은 없습니다. 조건과 액션에 변수를 넣을수도 있습니다. * DoActions(*actions, preserved) conditions가 Always인 트리거입니다. 기본적으로 preserved 되있고요. * EPD(p) 오프셋을 EPD 플레이어값으로 바꿉니다. * Disabled(arg) 조건/액션을 disable시킵니다. * PTrigger(players, conditions, actions) Current Player가 players중 하나일때만 실행되는 트리거입니다. EUDPlayerLoop랑 궁합이 잘 맞습니다. 무조건 preserved됩니다. 트리거 실행 순서 (고급) --------------------- * PushTriggerScope() * PopTriggerScope() 트리거 실행 구역을 Trigger Scope라고 합니다. 같은 Scope에 있는 트리거끼리는 자동으로 nextptr가 다음에 정의되는 트리거로 설정됩니다. 몰라도 됩니다. * NextTrigger() '바로 다음 트리거'를 나타냅니다. * RawTrigger(prevptr, nextptr, conditions, actions) 조건/액션 갯수 제한이 있는 트리거입니다. Trigger는 RawTrigger 여러개를 조합해서 만든 것입니다. RawTrigger는 주소값을 가지고 있어서 이런 식으로 주소값을 얻을 수 있습니다. :: a = RawTrigger(~) # SetNextPtr(a, ~) 로 nextptr 수정 등을 할 수 있습니다. b = Trigger(~) # Trigger는 주소값이 없기 때문에 이런 활용은 불가능합니다 .. --------------------------------------------------------------------------- 제어문 =================== 기초 제어문 ---------- * EUDIf()(cond) * EUDIfNot()(cond) * EUDElse()() * EUDElseIf()(cond) * EUDElseIfNot()(cond) * EUDEndIf() If~ElseIf~Else 관련입니다. * EUDExecuteOnce() * EUDEndExecuteOnce() 한번만 실행되야하는 코드를 짤 때 씁니다. 단순히 Trigger에서 preserved=False를 하는것만으로는 안 될 경우 유용하게 쓸 수 있을겁니다. * EUDWhile()(cond) * EUDWhileNot()(cond) * EUDEndWhile() While 관련입니다. * EUDLoopN()(count) * EUDEndLoopN() count번 반복 * EUDInfLoop()() * EUDEndInfLoop() 무한반복 * EUDPlayerLoop()() * EUDEndPlayerLoop() 현재 게임에 참여중인 모든 플레이어를 한번씩 Current Player로 하면서 반복 * EUDSwitch(var) * EUDSwitchCase()(case) * EUDSwitchDefault()() * EUDEndSwitch() C언어에서의 switch문과 같습니다. EUDBreak를 하지 않으면 C언어처럼 각 case에서 다음 case로 자동으로 넘어갑니다. * EUDBreak() * EUDBreakIf(conditions) * EUDBreakIfNot(conditions) * EUDContinue() * EUDContinueIf(conditions) * EUDContinueIfNot(conditions) 반복문/switch에서의 break/continue * EUDSetContinuePoint() 반복문에서 continue를 했을 때 갈 곳을 설정하는데 씁니다. EUDWhile를 for문처럼 쓰면서 continue 이후 무조건 실행되야하는 코드를 만들 때 이걸 쓸 수 있습니다. Continue point는 하나만 지정할 수 있습니다. * EUDIsContinuePointSet() 현재 블록에서 이미 Continue point가 지정되었는지 알려줍니다. Jump류 제어문 ------------ * EUDBranch(conditions, ontrue, onfalse) 조건이 만족되는지에 따라 ontrue/onfalse로 점프합니다. ontrue/onfalse는 절대로 EUDVariable이 될 수 없습니다. * EUDJump(nextptr) nextptr로 점프합니다. nextptr는 RawTrigger가 될 수 있고 RawTrigger를 가르키는 Forward나 EUDVariable이 될 수 있습니다. * EUDJumpIf(conditions, ontrue) * EUDJumpIfNot(conditions, onfalse) 조건이 만족하면 EUDJump합니다. EUDJump처럼 ontrue/onfalse가 변수여도 됩니다. 특수 반복문 ---------- 아래 반복문들은 다음과 같이 파이썬 for문이나 epScript의 foreach문으로 ptr, epd를 받아서 사용합니다. 아래 반복문은 내부적으로 EUDWhile을 쓰기 때문에 EUDContinue나 EUDBreak도 문제 없이 사용할 수 있습니다. :: for ptr, epd in EUDLoopBullet(): pass # 내용 foreach(ptr, epd : EUDLoopBullet()) { # 내용 } * EUDLoopList(header_offset, break_offset) 이중 연결 리스트를 순회합니다. header_offset은 첫 리스트 항목을 가르키는 포인터고, next를 따라가다 ptr이 break_offset이 되면 LoopList가 종료됩니다. * EUDLoopBullet() 모든 CBullet를 돕니다. * EUDLoopSprite() 모든 CSprite를 돕니다. * EUDLoopUnit() 모든 CUnit(구조오프셋)을 돕니다. * EUDLoopRange(start, end) [start, end) 범위를 돕니다. EUDLoopN의 상위호환이라 보시면 됩니다. 이 함수는 ptr, epd가 아니라 i를 씁니다. :: for i in EUDLoopRange(0, 5): pass # i가 0, 1, 2, 3, 4가 되면서 돎 조건 연산자 ---------- * EUDAnd(cond1) * EUDOr(cond1) * EUDNot(cond) 두개 조건의 논리곱, 논리합이나 반대조건을 뜻합니다. * EUDTernary(conditions)(ontrue)(onfalse) C언어에서의 삼항 연산자에 해당합니다. conditions에 따라 ontrue와 onfalse의 값을 선택합니다. conditions에 관계 없이 ontrue랑 onfalse의 값이 계산되므로 주의하세요. 커스텀 제어문 (고급) ------------------- 자세한건 EUDWhile이나 EUDPlayerLoop의 코드를 참고하세요. * EUDCreateBlock(name, userdata) 블록을 생성하고 블록 스택에 넣습니다. * EUDGetBlockList() 지금까지 만들어진 블럭들의 목록을 만듭니다. * EUDGetLastBlock() 마지막 블록을 얻습니다. * EUDGetLastBlockOfName(name) 마지막 해당 이름 블록을 얻습니다. * EUDPeekBlock(name) 마지막 블록의 이름이 name이면 그 블록을 리턴합니다. 블록 이름이 다르다면 에러를 띄웁니다. * EUDPopBlock(name) EUDPeekBlock와 동시에 그 블록을 pop합니다. * CtrlStruOpener(f) ()()같은 문법을 쓸 때 필요합니다. EUDWhile을 참고하세요. .. --------------------------------------------------------------------------- 변수/함수 관련 ============= eudplib의 핵심 개념 중 하나가 변수와 함수의 개념입니다. 변수 ------------------- * IsEUDVariable(x) * EUDVariable(initval) eudplib의 변수입니다. 초기값은 initval입니다. .. note:: initval은 초기값을 뜻하는거지 initval로 매번 값이 초기화된다는 뜻이 아닙니다. 예를 들어 아래 상황에서 DisplayText는 한번만 실행됩니다. :: a = EUDVariable(5) # a의 초기값이 5입니다. if EUDIf()(a == 5): # (*) 이후로 a의 값이 5로 다시 돌아가지 않기 때문에 # 이 if문은 한번만 실행됩니다. DoActions(DisplayText('test')) a << 10 # a는 이 이후로 계속 10입니다. (*) EUDEndIf() EUDVariable은 조건/액션에 숫자처럼 그냥 넣을 수 있습니다. EUDLightVariable보다 용량이 조금 더 나가긴 하지만 막 써도 맵 용량이 크게 늘지는 않습니다. .. note:: CHK에서 EUDVariable 하나당 용량이 72byte긴 하지만, MPQ 압축때문에 실재 scx에서 용량은 거의 없다고 봐도 됩니다. .. note:: * EUDLightVariable(initvalue) ** 쓸 일이 없습니다. ** 4byte짜리 변수입니다. 그냥 데스값이랑 대응된다고 보시면 됩니다. v.Exactly(100) 같은 조건이나 v.AddNumber(100)같은 단순 액션을 쓸 수 있습니다. * EUDCreateVariables(varn) EUDVariable을 여러개 만들 때 씁니다. * SeqCompute(assignpairs) 여러 계산을 순서대로 합니다. :: SeqCompute([ (a, Add, 5), # a 변수에 5를 더한다 (*) (EPD(0x6509B0), SetTo, 30), # 0x6509B0 오프셋을 30으로 설정한다 (b, Add, a), # b 변수에 a 변수의 값만큼을 더한다. # 계산을 순서대로 하니까, (*)에서 a에 5를 더해둔만큼 b에도 더 더해지게 되겠죠? ]) * SetVariables(srclist, dstlist, mdtlist) SeqCompute를 쉽게 하는 방법. mdtlist는 SetTo같은 연산의 list이며, 생략하면 mdtlist는 모두 SetTo한걸로 가정 :: # 이것과 SetVariables([a, b], [1, 2]) # 이건 같은 뜻이다. SeqCompute([ (a, SetTo, 1), (b, SetTo, 2) ]) * VProc(v, actions) ** 고급 ** 뻘강의 "Full Variable" 단원 참고. QueueAssignTo같은 액션을 실행하는데 쓴다. 함수 ------------------- * EUDFunc(fdecl_func) @EUDFunc를 씌우면 EUD함수가 됩니다. :: @EUDFunc def f_add(a, b): EUDReturn(a + b) # return a + b도 되긴 하다만 EUDReturn을 애용해주세요. * EUDFuncPtr(argn, retn) EUDFunc에 대한 함수 포인터입니다. argn, retn은 인자 갯수와 리턴값 갯수입니다 :: # 위의 f_add를 그대로 사용 a = EUDFuncPtr(2, 1)(f_add) a(1, 2) # 3을 리턴 a.setFunc(f_mul) # 다른 곱셈함수(있다고 하죠)로 포인터를 설정 a(1, 2) # 2를 리턴 * EUDTypedFunc(argtypes, rettypes) 인자와 리턴값에 타입을 지정할 수 있습니다. :: @EUDTypedFunc([DBString], [None]) def f_dbstr_display(str): # str는 DBString 타입입니다. DoActions(str.GetDisplayActions()) EUDReturn(1) a = f_dbstr_display("test") # DBString("test")가 인자로 넘어감 # a는 EUDVariable(None) 타입입니다. EUDTypedFunc는 EUDFunc의 일종이니까 EUDTypedFunc도 EUDFuncPtr에 넣을 수 있어요. * EUDTypedFuncPtr(argtypes, rettypes) EUDFunc에 대한 함수 포인터입니다. EUDFuncPtr에 추가적으로 타입을 지정할 수 있습니다. * EUDMethod(method) * EUDTypedMethod(argtypes, rettypes) EUDStruct나 EUDObject같이 메서드를 EUDFunc처럼 쓰고 싶을때 쓰면 됩니다. * EUDReturn() 한 함수에 리턴문이 2개 이상 있을 경우에는 그냥 return이 아니라 EUDReturn을 꼭 써야합니다. 아니면 뒤에 함수가 잘려먹힌다던지 하는 문제가 날꺼에요. * EUDFuncN(argn, callerfunc, bodyfunc) ** 고급 ** EUDFunc, EUDMethod 등 모든 EUD함수는 EUDFuncN 타입입니다. EUD 함수 포인터는 포함하지 않습니다. 어떤 함수가 EUD함수인지 판별할때 isinstance로 돌리세요. .. ---------------------------------------------------------------------------- 구조체 관련 ========== * EUDVArray() Full Variable을 이용한 배열입니다. EUDArray에 비해 상수 인덱스 접근이 빠릅니다. 예를 들어, v[a % 2]의 속도는 EUDArray와 EUDVArray와 속도가 비슷하지만 v[2]의 속도는 EUDVArray가 더 빠릅니다. EUDStruct의 구현에 쓰입니다. * EUDStruct(initvar) EUD 구조체를 만드는데 쓸 수 있습니다. 대표적인 EUD 구조체로 EUDStack이 있습니다. :: class EUDStack(EUDStruct): _fields_ = [ ('data', EUDArray), 'pos' ] def __init__(self, size, basetype=None): if isinstance(size, int): super().__init__([ # data EUDArray(size), 0 ]) else: super().__init__(size) self._basetype = basetype def push(self, value): self.data[self.pos] = value self.pos += 1 def pop(self): self.pos -= 1 data = self.data[self.pos] if self._basetype: data = self._basetype(data) return data def empty(self): return self.pos == 0 모든 EUDStruct는 _fields_ 멤버를 갖고 있습니다. _fields_는 (이름, 타입명)의 list 형식입니다. 타입명이 생략되면 해당 필드는 EUDVariable로 취급됩니다. 예를 들어 위 EUDStack이란 구조체에는 EUDArray형의 data와 EUDVariable형의 pos를 갖고 있습니다. 모든 EUDStruct는 _fielddict 멤버를 갖고 있습니다. _fielddict는 상속한 클래스의 필드까지 포함돼있고, {이름: (필드번호, 타입명)}의 dict 형식입니다. EUDStruct의 생성자에 list를 넣으면 해당 데이터를 이용해 EUDStruct의 필드를 초기화해 새로운 EUDStruct를 만들게 되고, ConstExpr나 변수를 넣으면 그 변수에 있는 주소를 가지고 EUDStruct를 만듭니다. 차이점을 유의해두세요. .. note:: 아래 내용은 되게 복잡하니까, 그냥 아래 내용을 고려하기 싫으면 __init__ 함수를 새로 만들지 않으시면 됩니다. 각 EUDStruct는 자체 주소를 갖고 있습니다. 예를 들어 :py:`a = EUDStack()` 라고 쓰면 이 a는 EUDStack의 이름이자 EUDStack를 가르키는 변수이기도 합니다. 실제로 a의 값을 :py:`f_simpleprint(a)` 등으로 출력하면 EUDStack 데이터가 있는 주소가 출력됩니다. a를 EUDStruct의 주소를 값으로 하는 EUDVariable이라 생각하셔도 되겠습니다. 그래서, EUD 함수에 a를 인자로 넘기면 a가 가르키는 EUDStack의 주솟값이 EUD 함수에 넘어가게 됩니다. EUDStruct는 이런 EUDVariable형 주소를 다시 EUDStruct로 해석하는 기능을 제공하고 있습니다. 예를 들어 아래 코드를 보시면 :: a = EUDStack(30) b = EUDVariable() b << a # b에 a의 주소가 대입된다. c = EUDStack(b) # b에 있는 주소를 EUDStack이 들어있는 주소로 해석한다. 처럼, 파이썬에서 쓰던 타입(변수) 와 같은 방식으로 형변환을 할 수 있습니다. 모든 EUDStruct는 위와 같은 형변환을 지원해야 합니다. 예를 들어 EUDStack에서는 :: def __init__(self, size, basetype=None): if isinstance(size, int): super().__init__([ # data EUDArray(size), 0 ]) else: super().__init__(size) 처럼 size가 int인지 아닌지에 따라 생성자를 다르게 적용하고 있습니다. * EUDStack(size, basetype) EUD로 구현한 스택입니다. * ObjPool(size, basetype) malloc/free처럼 EUDStruct를 동적 할당할 수 있는 풀입니다. 미리 정해진 갯수만큼 EUDStruct를 만들어놓고 alloc 요청마다 하나씩 꺼내주는 방식으로 작동합니다. size를 충분히 크게 잡아놔야 alloc가 계속 성공하겠죠? * selftype 가끔 EUDStruct의 필드에 자기 자신의 타입을 넣고싶을 때가 있습니다. 연결 리스트를 구현할 때 등이요. 이 떄 selftype를 쓰시면 됩니다. .. note:: C언어랑 다르게 EUDStruct의 필드에 구조체가 들어가면 EUDStruct에는 실제 그 구조체가 저장되는게 아니라 구조체를 가르키는 포인터만 저장됩니다. 파이썬이나 자바랑 비슷하게 생각하시면 편할것같습니다. * unProxy(x) ** 고급 ** x에 여러가지 타입을 적용할 수 있는데, unProxy는 x에서 이러한 타입을 모두 떼는 연산입니다. 아래와 같이 두 변수를 비교할 때 씁니다. :: a = EUDStack() b = EUDVariable(a) a == b # False c = EUDStack(b) b == c # False unProxy(a) # a unProxy(b) # b unProxy(c) # b unProxy(b) == unProxy(c) .. ---------------------------------------------------------------------------- 잡다한 함수들 ============ 연산자 관련 ------------------- * f_bitand(a, b) * f_bitlshift(a, b) * f_bitnand(a, b) * f_bitnor(a, b) * f_bitnot(a) * f_bitnxor(a, b) * f_bitor(a, b) * f_bitrshift(a, b) * f_bitxor(a, b) * f_div(a, b) * f_mul(a, b) 메모리 IO 관련 ------------------- * f_dwepdread_epd(targetplayer) * f_dwread_epd(targetplayer) * f_epdread_epd(targetplayer) EPD 플레이어에게서 dword/epd값을 읽는 함수입니다. 포인터를 읽을때는 dwepdread 함수를 활용해 dword랑 epd값을 동시에 읽는게 효율적입니다. * f_dwepdread_epd_safe(targetplayer) * f_dwread_epd_safe(targetplayer) * f_epdread_epd_safe(targetplayer) **Deprecated** 위 함수들과 똑같으며 이름만 다릅니다. * f_dwepdread_cp(cpo) * f_dwread_cp(cpo) * f_epdread_cp(cpo) CurrentPlayer를 기준으로 하는 함수입니다. _epd가 붙은 함수들보다 2배 빠릅니다. cpo는 CurrentPlayer를 기준으로 읽을 메모리가 얼마나 떨어져있는지를 나타냅니다. * f_getcurpl() * f_setcurpl(cp) Current Player의 값을 읽고 쓰는 함수입니다. Current Player는 eudplib에서 항상 관리하므로 0x6509B0의 값을 직접 읽는것보다 f_getcurpl 함수를 쓰는게 32배정도 빠릅니다. _cp류 함수들과 조합해서 사용하면 좋습니다. * f_dwbreak(number) * f_dwbreak2(number) dword를 word/byte 단위로 나누는 함수입니다. dwbreak2는 word/byte에 곱해졌던 값을 유지합니다. 예를 들어 f_dwbreak(0x12345678)[2]는 0x12이지만, f_dwbreak2(0x10000000)[2]는 0x12000000입니다. dword의 특정 byte나 word만 바꿔야 할 때 f_dwbreak한 결과에 다시 0x100000같은 값을 곱할 필요가 없습니다. * f_flagread_epd(targetplayer) * f_bitsplit(a) 비트 단위로 dword를 읽고싶거나 dword를 나눌 때 쓰면 됩니다. * f_dwadd_epd(targetplayer, value) * f_dwadd_cp(cpo, value) * f_dwsubtract_epd(targetplayer, value) * f_dwsubtract_cp(cpo, value) * f_dwwrite_epd(targetplayer, value) * f_dwwrite_cp(cpo, value) read 대신 write, add, subtract를 합니다. 당연히 read류 함수보다 32배정도 빠릅니다. 단순 SetMemory랑 속도가 똑같습니다. * f_bread(ptr) * f_bwrite(ptr, b) * f_wread(ptr) * f_wwrite(ptr, w) * f_dwread(ptr) * f_dwwrite(ptr, dw) 포인터에서 byte/word/dword를 읽고 쓰는 함수입니다. * f_blockpatch_epd(dstepd, srcepd, dwn) * f_dwpatch_epd(dstepd, value) * f_unpatchall() 블록 패치/dword 패치용 함수입니다. 위 2개 함수로 패치한 값들은 f_unpatchall로 한번에 원상복귀할 수 있습니다. * f_repmovsd_epd(dstepdp, srcepdp, copydwn) * f_memcpy(dst, src, copylen) 블록 단위로 메모리를 복사할 때 씁니다. 스트링 관련 ------------------- * DBString(content: str | bytes | int) 스트링 테이블을 쓰지 않는 스트링입니다. - GetDisplayActions() : DoActions에 넣을 수 있는 액션입니다. 이걸 쓰면 DBString의 내용물이 출력됩니다. - GetStringMemoryAddr() : 스트링의 시작 주소입니다. f_dbstr류 함수를 부를 때 시작점으로 쓰기 좋아요. 아래 함수들은 DBString 뿐만이 아니라 일반적인 스트링에 적용할 수 있는 함수들입니다. 모두 다 스트링에 내용을 출력하고 난 뒤 스트링의 끝을 나타냅니다. 하나 출력하고 그 끝에 둘 출력하고 그 끝에 셋 출력하면 하나둘셋이 출력되겠죠. 마찬가지로 아래와 같이 스트링을 계속 조합해나갈 수 있습니다. :: t = DBString(1024) k = t.GetStringMemoryAddr() # 스트링 처음부터 쓰기 시작합니다. k = f_dbstr_adddw(k, 100) k = f_dbstr_addstr(k, "원이 남았습니다") DoActions(t.GetDisplayActions()) # f_dbstr_print는 조금 특별해서 t.GetStringMemoryAddr를 쓸 필요가 없습니다. f_dbstr_print(t, 100, "원이 남았습니다") DoActions(t.GetDisplayActions()) * f_dbstr_adddw(dst, number) dst에 number의 10진 표기를 출력합니다. * f_dbstr_addptr(dst, number) dst에 number의 16진법 표기를 출력합니다. 앞에 0을 넣어 8자리를 채웁니다. 예를 들어 0x100을 이 함수로 출력하면 00000100이 됩니다. * f_dbstr_addstr(dst, src) dst에 src 내용을 복붙합니다. f_strcpy와 동일합니다. * f_dbstr_print(dst, args...) dst에 여러가지를 한꺼번에 출력합니다. .. note:: f_dbstr_print에 변수를 넣으면 10진법으로 출력됩니다. f_dbstr_addptr처럼 16진법으로 출력되게 하려면 hptr(숫자)를 넣으세요. * f_simpleprint(args...) 그냥 간단하게 여러개 변수/스트링을 화면에 출력하고 싶을때 쓰면 좋은 함수입니다. 디버깅용으로 좋아요. 아래 함수들은 그냥 스트링 관련 함수입니다. * f_strcmp(s1, s2) 두 스트링을 비교합니다. * f_strcpy(dst, src) 스트링 복사 랜덤 ------------------- * f_dwrand() * f_getseed() * f_rand() * f_randomize() * f_srand(seed) 수학 ------------------- * f_atan2(y, x) * f_lengthdir(length, angle) * f_sqrt(n) * EUDBinaryMax(cond, minv, maxv) * EUDBinaryMin(cond, minv, maxv) 엄밀히 말하면 얘는 EUD함수는 아닌데 그냥 여기 둬봤어요. 각각 cond(x)가 만족하는 [minv, maxv]에서 최대 x와 최소 x를 구하는거에요. 기타 ------------------- * QueueGameCommand(data, size) * QueueGameCommand_RightClick(xy) * QueueGameCommand_Select(n, ptrList) * f_getuserplayerid() 자기 자신의 플레이어 번호를 얻습니다. * f_playerexist(player) UDP/배틀넷 등에서만 작동합니다. 플레이어가 있는지 체크합니다. .. ---------------------------------------------------------------------------- TRIG 트리거 관련 =============== .. note:: eudplib에서 TRIG 단락을 변형하고 STR 트리거를 활성화시키면서 원래 맵에 있던 트리거 앞 뒤로 트리거가 추가될 수 있고, EUDLoopTrigger는 이들 트리거도 순회하게 됩니다. 이러한 트리거중에는 맵 실행 도중 변형되면 안되는 트리거도 있을 수 있습니다. EUDLoopTrigger를 포함해서 아래 함수들을 사용할때는 이런 추가된 트리거들을 조심하세요. * EUDLoopTrigger(player) player의 모든 TRIG Trigger를 돕니다. * GetFirstTrigTrigger(player) * GetLastTrigTrigger(player) 플레이어의 첫/마지막 TRIG 트리거를 나타냅니다. * TrigTriggerBegin(player) * TrigTriggerEnd(player) TrigTriggerBegin은 GetFirstTrigTrigger랑 동일합니다. TrigTriggerEnd는 GetLastTrigTrigger의 nextptr이 가르키는 곳을 말합니다. * EUDRegisterObjectToNamespace(funcname, obj) * EUDRegistered(func) inline_eudplib에서 함수나 클래스, 변수 등을 쓸 수 있도록 합니다. :: @EUDRegistered @EUDFunc def f_add(x, y): return x + y * GetEUDNamespace() EUDRegistered로 등록된 함수들을 얻어옵니다. * EUDClearNamespace() ** 고급 ** 보통 쓸 일이 없을거긴 합니다. EUDRegistered된 함수 목록을 비웁니다. * RunTrigTrigger() 모든 Trig Trigger를 실행합니다. .. ---------------------------------------------------------------------------- 옵션 관련 함수 ============= * CompressPayload(mode) 페이로드의 압축 여부를 설정합니다. 이 옵션을 활성화시키면 맵 용량이 줄어듭니다. euddraft에선 기본적으로 활성화되어있습니다. * EP_SetRValueStrictMode(mode) RValue에 다른 변수를 추가적으로 대입하지 못하게 할지를 설정합니다. 기본적으로 비활성화 상태입니다. 이 모드가 활성화되면 다음과 같은 식에서 컴파일 에러가 납니다. :: a, b = EUDVariable() (a + b) << 5 # a + b는 r-value(수식의 결과)이므로 여기에 다른 값을 대입할 수 없습니다. a = f_dwread_epd(EPD(0x6509B0)) a << 10 # a는 f_dwread_epd의 결과값이므로 a에 10을 대입할 수 없습니다. # 하지만 위와 같이 함수의 결과값을 바로 변수로 쓰는 일은 생각보다 흔하기 때문에 # eudplib에서는 기본적으로 rvalue strict mode가 해제되어있습니다. * PRT_SetInliningRate(rate) 프로텍션에 관련된 함수입니다. 기본 TRIG 트리거를 어느정도 비율로 STR 단락으로 옮길지를 결정합니다. 이 옵션을 쓰면 맵 용량이 늘어납니다. * PRT_SkipPayloadRelocator(enable) ** 쓸 일이 없습니다. ** 프로텍션에 사용될수도 있겠다는 기대로 만들어둔 함수입니다. 복잡한 함수이므로 여러분들이 사용할 일은 아마 없을것같아요. .. note:: 대략적으로 설명하자면, eudplib에서는 3단계에 걸쳐서 STR 단락에 있는 트리거를 실행시킵니다. 1단계에서는 TRIG 트리거에서 STR 단락에 있는 vector relocator를 활성화시키고, 2단계에서는 vector relocator가 STR 단락에 있는 트리거를 활성화시키고, 3단계에서는 STR 단락의 트리거가 후처리를 합니다. PRT_SkipPayloadRelocator 옵션은 2단계를 생략하고 1단계에서 바로 STR 단락의 트리거를 활성화시키는 옵션으로, 이 옵션을 쓰면 맵 용량이 엄청나게 많이 늘어납니다. \ 원래 freeze를 개발하는 과정에서 넣은 옵션입니다만, 이 옵션을 쓴다 해서 딱히 프로텍션이 강해지는것같지도 않아 그냥 관뒀습니다. .. --------------------------------------------------------------------------- Payload/데이터 관련 함수 (초고급) =============================== 아마 볼 사람도 없어보이는데 대충 쓰죠. 대충 써도 이정도 길이와 난이도라는 원래 이 내용이 얼마나 어려운지 대충 감이 잡히시리라 봅니다. 웬만하면 쓰실 일이 없을겁니다. Payload는 트리거, grp와 같이 eudplib로 넣은 데이터들의 집합체입니다. 여기서는 Payload 관련 함수들을 다룹니다. SaveMap에서 맵에 Payload를 넣을 수 있습니다. SaveMap은 3가지 단계로 이루어집니다. - Collection phase : 데이터간 주솟값을 분석해서 맵에 쓰이는 EUDObject들을 모두 모읍니다. - Allocation phase : 각 EUDObject들의 길이(GetDataSize 등)에 따라 EUDObject들의 주소를 결정합니다. - Writing phase : 각 EUDObject들을 주소에 따라 payload에 씁니다. 그래서 Allocation Writing phase 전에는 각 EUDObject의 주소가 정해지지 않았습니다. * EUDObject() Payload에 넣을 수 있는 데이터의 기본 단위를 나타내는 클래스입니다. RawTrigger나 Db같은 모든 데이터 클래스는 다음과 같이 EUDObject에서 상속합니다. :: class Db(EUDObject): """Class for raw data object""" def __init__(self, b): super().__init__() self.content = bytes(b) def GetDataSize(self): return len(self.content) def WritePayload(self, pbuffer): pbuffer.WriteBytes(self.content) 모든 EUDObject는 GetDataSize와 WritePayload, Evaluate 함수를 구현합니다. - GetDataSize : 이 데이터의 크기를 나타냅니다. EUDGrp라면 메모리에서 GRP 크기를, RawTrigger라면 메모리에서 트리거 크기(2408)을 나타내겠죠. 맵에 쓰인 Object 들에 따라 크기가 바뀌는 Object의 경우에는 Allocation Phase에서부터 정확한 값을 리턴해야 합니다. - WritePayload : Payload에 데이터를 쓰는 함수입니다. pbuffer에 WriteBytes, WriteByte, WriteWord, WriteDword같은 함수들로 데이터를 써내려갈 수 있습니다. 예를 들어 EUDGrp에선 아래와 같이 pbuffer에 데이터를 씁니다. :: def WritePayload(self, buf): buf.WriteBytes(b'\0\0') # 2byte padding to align dwords at (*) # fill in grp header b = self._content fn, w, h = struct.unpack(' [a], [a, b] -> [a, b] * List2Assignable(l) [a] -> a, [a, b] -> [a, b] * ExprProxy(initval) ** 고급 ** 사칙연산이 되는 프록시입니다. * b2u(b) * u2b(s) 파이썬3의 bytes와 str 간에 상호변환 * b2i1(b, index) * b2i2(b, index) * b2i4(b, index) * i2b1(i) * i2b2(i) * i2b4(i) int를 Little Endian으로 변환하고 역변환하는 함수입니다. b2i? 함수에서 index를 통해 b의 어느 범위를 int로 변환할지 정할 수 있습니다. * epsCompile(modname, b_code) eps 코드를 .py형식으로 컴파일. * ep_assert(statement, message) assert인데 EPError를 냅니다. * EPError(msg) eudplib 관련 에러 * FlattenList(l) 중첩된 list를 풉니다. * SCMD2Text(s) scmdraft2 형식 텍스트를 해석합니다. * TBL(content) STR단락이나 .tbl파일을 해석할때 쓰면 좋아요. * EUDByteReader() * EUDByteWriter() 바이트 단위로 읽고 씁니다. f_bread 함수를 참고하세요.