오늘의 내용은...특성의 확장?
XML만으로 답답함을 느낄 때가 많을 터인데...때문에 조금만 모딩이라는 것에 빠지면, 도저히 XML만으로는 만족할 수 없게 된다.
그래서 python에 손을 대게 되는데...다행히 참으로 쉬운 언어라서...

XML은 태그에 의존하는데, 이 태그는 순서 및 구성이 특정 식(schema)에 의존하기 때문에,
멋대로 태그를 넣거나 순서를 바꿀 경우, 동작을 하지 않게 된다. 한마디로 그냥 버그가 된다는 것...
때문에, 수정에 있어서 자유도도 상당히 낮은 편이다. 이게 들어가도 되던가? or 이게 여기 들어가는 거던가? 등등등...
게다가 태그가 쓸데없이 많은 경우...그거 일일히 확인해 보느라고 미치는 경우도 왕왕 있지.
파이썬이라고 무규칙인 것은 아니지만...그나마 필요한 것만 손대도 되거든.

모딩에 있어서 가장 먼저 하는 일은...역시 지도자 수정/추가였을 것이다.
자기가 즐겨 하는 세력이 있는데, 그 세력이 가지고 있는 지도자가 마음에 안드는 경우는 항상 있거든.
게임에서 지도자 제한을 풀어둘 수 있는 옵션을 제공하지만, 이러면 나뿐만 아니라 AI들에게도 모두 적용되니까 싫은 경우가 태반.
물론, 등장 AI를 일일히 지정하는 방법을 쓰면 되긴 한데--; 시작도 하기 전에 벌써 진빼기는 귀찮잖아...

그래서 하는 일은, 자기가 좋아하는 지도자를 선호 문명에 옮겨 놓는 것에서 출발하지.
그러다가...아예 지도자나 문명의 성능 자체를 고치고 싶은 욕심이 들거든...

가장 쉬운 단계는 역시, 좋은 특성을 죄다 갖다 붙이는 것...^^;
뭐 본편에서야, 특성이란 무조건 있는게 좋은 거니까 다 붙여도 되지만, FfH2는 절대로 택해서는 안될 특성도 몇개 있기 때문에--;
소위 지도자(문명에 붙이기도 하지만, 하나밖에 못붙이니까)의 먼치킨화...가 되는거지.

그런데 이러면, 어지간히 내공이 쌓였던 사람의 경우(애당초 모드를 만지는 시점에서...) 있던 특성만 가지고는 또 만족 못하는 상태(설상가상)가 된다...
이제는 특성 자체를 손보기 시작하지. 있던 특성들의 기능을 모두 종합한(혹은 뛰어넘는) 슈퍼 트레잇을 만드는 단계...
물론 이쯤 오면, 특성만 손보는 게 아니라 고유/대체 유닛/건물에까지 손을 대지만 말이야--;
결국 이 끝은...게임을 접게 되거나(게임 불감증으로), 게임을 즐기기는 하는데 게임 플레이 시간보다 모드질;;하는 시간이 더 길어지는 단계로 가게 되는 것이지.
바로 나같은!
현 상태는...모드질에 13~14시간에 플레이 1시간 꼴...이군.
모드에 미쳐서 XML, python, SDK, DLL까지...뭐 그쯤 하자.

XML은 검색만 해도 뭐가 어떤 역할을 하는 지 나오기 때문에 그동안 python에 주력해 왔는데,
그 연장선상에서, XML만으로 구현이 불가능하지만 트레잇에서 구현이 가능했으면 싶은 것들을, python을 사용하여 흉내내 보겠다.
잡설이 길었군.

커스텀 트레잇은 만들 줄 안다고 가정하고 시작하겠다. 사실 특성 파일CIV4TraitInfos.xml은 아예 모든 태그에 대해 해석까지 해 준 일이 있었잖아?
거기 있던, 먼치킨 트레잇TRAIT_MUNCHKIN을 그대로 사용해 보겠다.
건드릴 파일은...특별한 언급이 없는 한, 전부 CvEventManager.py만을 사용한다.


유닛에게 공짜 승급이나 경험치 주기
 공격적 특성 같은 것들은...전부 특정 계열에 대해서만 공짜 승급을 주지.
 문제는 FfH2에 존재하는 모든 유닛이...전부 어떤 계열에 속해있지는 않다는 것이다. 간단히? 일꾼!
 비전투 유닛이거나 전투 비중이 적은 유닛은 문제가 안되는데...전투용으로 쓸 수밖에 없는 녀석들도 공짜 승급 혜택을 못받는다는 것은...심하게 배아픈 일이지.
 그것에 대해 FfH2가 사용하고 있던 방법 중에...건물을 이용하는 방법이 있어.
 
 건물의 유닛에 대한 이득은...크게 공짜 승급 or 경험치 인데, 이것은 어느정도 XML에서도 처리를 하고 있다. 다만 저인망이지.
 무슨 소리냐면...무차별이거나, 역시나 특정 계열이거나 하는 경우가 많더라...이거야. 조건에 계열 외에는 존재하질 않거든. 아니면 전부 다 되거나.
 그래서 XML로 봐서는 대체 뭐하는 건물이야? 싶지만 사실 그 작동을 온전히 python에 의존하는 것들미 몇몇 있어.(대표적으로? 오크 사육장! 유닛 복제 XML같은거 봤어?)
  예를 들면, 드워프 한정으로 양조장이 있는 도시에서 훈련될 경우 경험치를 2 더 받는다던가, 악마 한정으로 악마의 제단이 지어져 있는 도시에서 훈련되면 역시 경험치 +2...
  골렘의 경우, 발파 작업장/팔렌 엔진/빙장석실이 지어져 있는 도시에서 생산되면 각 건물마다 다른 승급을 더 붙여준다던가...
 이런 것들은 python으로만 구현이 가능하기 때문에 그런 것이지.

 이 방식을 흉내내면, 특성으로 구현되듯 할 수 있겠지. 시리즈 22번째 글 하단을 참고해 보자. 위는 XML얘기니까...뭐 건물 만들긴 해야 할테니 다 보긴 해야겠군.
  특정 사회제도 대신 특정 특성을 가지고 있을 때 공짜 건물을 주도록 하면 되겠지. 그리고 건물의 성능을 바꾸면 되니까...
  건물은 뭐 경험치를 주든, 승급을 주든 마음대로 하면 되겠는데...

 이렇게 하면, 훈련된이라는 한정이 붙는다.
 무슨 소리냐면...보물 찾기 했더니 나온 이벤트로 얻거나, 성전으로 뿅 튀어나왔거나, 주문을 써서 소환했다거나, 돈주고 샀다거나...등등등.
 매우 제한된 조건이 붙는단 말이야. 특성으로 얻는 승급이 그렇던가?
 아니거든. 어쨌든 내 소속이기만 하면 붙는 거였단 말이야.
 따라서 건물이 지어진 도시에서 생산된...이 아니라, 사령의 탑같이 전체에 대해 항상 영향을 끼치는 수단을 써야 한다는 뜻이야.(알겠지만, 모든 언데드에 강한 승급을 붙이지)

 그럼, 사령의 탑을 베끼면 되겠네...싶지?
 ...그것도 아니야. 귀찮거든.
 사령의 탑은 정확히는, 두가지 동작을 한다.
  하나는...지어지는 순간 현재 보유한 모든 언데드 유닛에게 강한 승급을 붙이는 것이고,
  나머지는...이후 생산되는(훈련을 포함한다!) 언데드 유닛에게 강한 승급을 붙이는 일이지.
 결론이야 같지만...동작은 이렇게 구분해서 하게 된다구. 이것은 사령의 탑을 짓기 전에 언데드를 얻을 확률이 매우 높기 때문에 어쩔 수 없는 일이지.
 게다가, 이 방식을 쓰면 건물을 따로 넣어줘야 하잖아......지금 특성 따로 넣는 것만으로도 벌써 질리는 사람 있을 텐데 그짓까지 어떻게 하나?

 그러므로, 그냥 쌩으로, 먼치킨 특성을 가지고 있을 때 얻는 모든 유닛은...이란 식으로 만들어야 한다. 이게 특성이라는 개념에도 맞잖아.
 어디서 이걸 다루고 있을까?
 전에도 다루던 부분(너무 길어서 정말로 부분...만 나왔지)이지만, def onUnitCreated(self, argsList): 구문에서 처리한다.
 이 구문은 def onUnitBuilt(self, argsList): 구문...즉 도시에서 정상적으로 훈련시켜서 나오는 구문을 온전히 포함하는데...
 도시에서 훈련되는 유닛은, 일단 onUnitBuilt 구문의 적용을 받은 후, onUnitCreated 구문의 적용을 또한번 받는다는 뜻이야.
 당연히 후자는 한정적인 용도이고, 전자를 써야 전역 대비가 되겠지.

 자 그럼 답이 나왔으니...거기서 쓰인 구문을 흉내내는 것이 가장 안전하고, 편한 방법이겠지. 그러니까 읽어보자......
 먼저 나오는 것은 몇몇 유닛에 대한 인공지능 설정이고...그 조금 뒤, if unit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_ADEPT'): 구문부터는 현재 사용중인 마나 숫자에 의해 마법 계열 유닛들에게 공짜 속성 승급을 주도록 처리하는 구문이야. 많이 길지--; 마나마다 설정하느라고 그래. 개략적으로만 해석해 보면...
 계열이 마법 계열인가?
  사용중인 에어 마나의 숫자를 세어, 그 수가 1보다 크면,
   에어1 승급을 주고,
   수가 2보다 크고 유닛이 채널링2 승급을 가지고 있다면,
    에어2 승급을 주고,
    수가 3보다 크고 유닛이 채널링3 승급을 가지고 있다면,
     에어3 승급을 준다.
 이후는 속성마다--; 같은 짓을...그래서 길지. 하는 일에 비하면...야튼 밑으로 쭉 내려봐...그래서 마지막 워터 마나 처리까지 보고 나면...
 오, 원소의 탑과 사령의 탑이 각각 정령과 언데드에게 강한 승급을 붙여주는 구문이 있네.
 이게 onUnitBuilt 구문 아래쪽에 있었다면, 소환되거나 하는 유닛들은 적용을 안받는다구. 그래서 필히 onUnitCreated 구문 밑에 있어야 하는 거지.

 우리가 할 일도, 당연히 여기다 해야 된다.
 자 이제야 실질적인 작업이 시작되겠군--; 일단 코드 나간다! 코드 자체는 언데드 다음에 넣자고.
 전부 빨간색이어야 하지만 그대로 둔다.

if pPlayer.hasTrait(gc.getInfoTypeForString('TRAIT_MUNCHKIN')):
listPromotion = ['STARTING_SETTLER']
iExp = 0
if unit.isAlive():
listPromotion += ['STRONG']
iExp += 2
if unit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_ANIMAL') or unit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_BEAST'):
listPromotion += ['MOBILITY1']
iExp += 5
if unit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_ARCHER'):
listPromotion += ['PRECISION', 'KEEN_SIGHT']
elif unit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_DISCIPLE'):
listPromotion += ['DRAGON_SLAYING']
elif unit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_MELEE'):
listPromotion += ['DEFENSIVE']
elif unit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_MOUNTED'):
listPromotion += ['BLITZ', 'MARKSMAN']
elif unit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_RECON'):
listPromotion += ['PERFECT_SIGHT']
elif unit.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_SIEGE'):
listPromotion += ['ACCURACY']
if unit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_GOLEM')):
listPromotion += ['COMBAT1', 'COMBAT2', 'COMBAT3', 'COMBAT4', 'COMBAT5']
elif unit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_ELF')) or unit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_DARK_ELF')):
listPromotion += ['WOODSMAN1', 'WOODSMAN2']
elif unit.isHasPromotion(gc.getInfoTypeForString('PROMOTION_DWARF')):
listPromotion += ['GUERILLA1', 'GUERILLA2']
for szPromotion in listPromotion:
iPromotion =  gc.getInfoTypeForString('PROMOTION_' + szPromotion)
unit.setHasPromotion(iPromotion, True)
unit.changeExperience(iExp, -1, False, False, False)

 꽤 길지...목적이 여럿이라서 그런건데...
 기존 공짜 승급형 특성들은, 각 계열마다 다른 승급을 줄 수가 없어. 공격적 같으면 지정된 모든 계열에 같은 승급을 모두 줘야 한다.
 그래서 계열마다 개성있는 승급을 주려면...계열 갯수만큼의 승급을 따로 만들어야 하는거지. 그걸 간단히 줄인거라고 보면 된다.
 자 해석을 해야겠지...?

  유닛이 튀어나왔는데, 그 주인이 먼치킨 특성을 가지고 있다면,
   일단 공짜 승급 리스트에 시작 보너스 승급을 설정, 보급경험치량 0.
   유닛이 살아있다면...승급 리스트에 강한 승급 추가, 보급경험치량 2증가.
   동물이나 정찰 계열이면, 승급 리스트에 모빌리티1 추가, 보급경험치량 5증가.
   궁술 계열이면, 승급 리스트에 프리시전, 예리한 시선 추가.
   신앙 계열이면, 승급 리스트에 용 사냥 추가.
   백병 계열이면, 승급 리스트에 방어적 추가.
   기마 계열이면, 승급 리스트에 전격, 저격 추가.
   정찰 계열이면, 승급 리스트에 완벽한 시야 추가.
   공성 계열이면, 승급 리스트에 정확도 추가.
   골렘이면, 승급 리스트에 전투1~5 추가.
   엘프들이면, 승급 리스트에 유격대1,2 추가.
   드워프이면, 승급 리스트에 게릴라1,2 추가.
   승급 리스트에 있는 모든 승급을 유닛에게 부여하고,
   보급경험치량만큼 유닛에게 경험치 추가..

 해석도 기네;; 뭐 내용이 내용이니만큼...
 그러니까 모든 유닛은 기본적으로 시작 보너스(시야+3, 이동력+2)를 가지고...조건에 맞게 추가로 승급을 더 먹을 수 있는 것이지.
 돼지기사를 뽑았다고 치면...경험치 +2에 시작 보너스/강한/전격/저격/게릴라1/게릴라2 승급을 공짜로 받아 나오겠구먼.


이쯤은 돼야 먼치킨이라는 이름이 아깝지 않지!
너무 심했나...뭐 알아서 조절하면 되니까 그거야...
 
죠니 사사키가 작성한 글입니다.
,