スポンサーサイト

--.--.-- *--
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

戦闘力を動的に変更する

2009.11.11 *Wed
タイトル通り、Civ4のMODを製作する上で、
戦闘力を動的に変更する方法を書きます。
完全に技術情報のみなので、興味無い方はスルー推奨。

MODの製作者or製作してみたいという人で、
SDKをいじれるだけの気力がある人向け。


以前の記事にもちらっと書いたので、さらっとまずは結論を書きますね。
SDKのうち、CvUnit.cppの以下の箇所を変更すれば思いのままに戦闘力を変動させられます。
(タブが上手く入れられなかったので全角スペースでインデントとってます
そのうえ<は全角になっちゃってしまっていたり)

int CvUnit::baseCombatStr() const
{
  return m_iBaseCombat;
}

および

int CvUnit::getExtraCombatPercent() const
{
  return m_iExtraCombatPercent;
}

どちらもユニットのインスタンスから素の戦闘力や、
戦闘力に対する補正値を参照するときに呼び出される、参照元です。

例えば以下のようにコードを書いた場合、全てのユニットの素の戦闘力は10になります。

int CvUnit::baseCombatStr() const
{
  return 10;
}


仮にここで、「戦闘術6の昇進を持っていたら戦闘力を+2にしたい」となれば、
以下のように書くことで解決できます。

int CvUnit::getExtraCombatPercent() const
{
  int temp = 0;
  if ( this->isHasPromotion((PromotionTypes)GC.getInfoTypeForString("PROMOTION_COMBAT6")) )
    temp += 2

  return m_iBaseCombat + temp;
}

改行されて見づらいですが、特に難しくはないはず。

東方叙事詩なんかでは、「基本操作1をもっているユニットが居れば、
同スタックの見方ユニット全員にボーナスがつく」
なんていうのもあり、そういうのは以下のように書けばOKです。

int CvUnit::baseCombatStr() const
{
  int temp = 0;
  CvPlot* pPlot = this->plot();
  for(int i=0;i<pPlot->getNumUnits();i++){
    CvUnit* pUnit = pPlot->getUnitByIndex(i);
    if (this->getTeam() == pUnit->getTeam()){
      if ( pUnit->isHasPromotion((PromotionTypes)GC.getInfoTypeForString("PROMOTION_COMBAT6")) )
        temp += 1;

  return m_iBaseCombat + temp;
}

同じplotに居るユニットを走査して、昇進もってればボーナス付与、
やってることは至極単純です。
とりあえずこれだけ書けば望みどおりの結果は得られます。




実はここに大きな落とし穴があります。
以前はこれに気づかずひどい目に会いましたが…



実は、この関数はものすごく頻繁に呼び出されるんですね。
ちょっとでも複雑なコードを書くとフリーズしたかと思うくらい
凄まじく何度も呼び出され、CPUリソースを食い荒らします。
(人柱3のverがやたら重かったのはこれが原因です)

特にひどいのが大スタック同士で戦闘をさせたときで、
勝率を見ようと移動先に敵スタックを合わせただけで固まります。

ですので、これらの関数には極力処理コストを下げてやる必要があり、
以下のようなコードにするのが一番良いです。

int CvUnit::baseCombatStr() const
{
  return m_iBaseCombat + m_itemp;
}

ハンガリアン記法については解説をしませんが、
要は専用のメンバ変数を持たせ、それとの合算を返すだけにするわけです。

なので、当然このメンバ変数は別の場所で計算してやる必要があります。
計算用の関数を追加して、適宜呼び出してやればよい、
というのはすぐにわかるかと思いますが、問題は何時呼び出すか。

戦闘力が変動するタイミングというのは、大抵の場合はCvEventManeger.pyに
記述されているようなイベントの発生したときでしょう。
例えばユニットが生まれたときとか、戦闘終了後などなど。

ですので、それらのイベントを適宜捕まえてやり、Pythonから呼び出すなり
SDKにコード埋め込むなりして、このメンバ変数の再計算を行えば良いわけです。

ここらへんの捕まえてやるべきイベントは、どういった条件で戦闘力を変動させたいかにもよるので、一概に「ここだ」と言うことはできませんが、参考までに上記の東方叙事詩における基本操作1でのボーナスを実装するときに捕まえたイベント一覧を書いておきます。

・onUnitMove
・onUnitSetXY
・onUnitCreated
・onUnitLost
・onUnitPromoted
・onUnitGifted

以上6箇所です。
ユニットが移動したり、生まれたり、死んだり、昇進とったり、贈られたとき、ですね。

あと、GC.getInfoTypeForString()も割と重い関数らしく、
ループの中で何度も呼び出すような場合にはループの外で一回だけ取得して、
ループの中ではその値を使いまわすようにした方が良いでしょう。




スポンサーサイト
CATEGORY : Civ4のMOD開発
COMMENT (0)  TRACKBACK (0) 

COMMENT

Comment Form


秘密にする
 

TRACKBACK

TrackBack List


Copyright © フリップフロップ All Rights Reserved.
テンプレート配布者:サリイ (素材:ふるるか) ・・・ 
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。