设为首页收藏本站

塞爱维(CIV)文明联盟

 找回密码
 注册
查看: 12560|回复: 43

[原创] [已完成]Civ5DLL解析之小野营地生成及营地生成单位相关规则小考

[复制链接]
发表于 2012-11-4 21:49:57 | 显示全部楼层 |阅读模式
已既然小龟抛砖引玉了一下那我就同样再扔一个砖头好了,因为刚刚开始看DLL对这东西还不是太熟所以有可能有错,仅供参考
0.基本知识
小野营地相关规则分为两部分,一个是营地产生规则,另一个是营地产生的小野规则
DLL中,此部分规则都在CvBarbarians.h和CvBarbarians.cpp中,其中仅包含一个类CvBarbarians,类中有以下三个成员变量:
  1. static short* m_aiPlotBarbCampSpawnCounter;
  2. static short* m_aiPlotBarbCampNumUnitsSpawned;
  3. static FStaticVector<DirectionTypes, 6, true, c_eCiv5GameplayDLL, 0> m_aeValidBarbSpawnDirections;
复制代码
(1)变量m_aiPlotBarbCampSpawnCounter
该变量是一个计数器数组,长度为地图的地块数。当它为负值时表明此地没有野蛮人营地,值为-1时表示此地块可以出现野蛮人营地,值<-1时该值与-1之差的绝对值为允许再次出现野蛮人营地的回合数;在正值的时候意为此地有野蛮人营地,且值直接等于生产下一个单位所剩的回合数。其每回合的行为在BeginTurn()函数中体现。其中,在第156~172行:
  1. if (m_aiPlotBarbCampSpawnCounter[iPlotLoop] > 0)
  2. {
  3.         ...
  4.         m_aiPlotBarbCampSpawnCounter[iPlotLoop]--;
  5.         ...
  6. }else if (m_aiPlotBarbCampSpawnCounter[iPlotLoop] < -1)
  7. {
  8.         m_aiPlotBarbCampSpawnCounter[iPlotLoop]++;
  9. }
复制代码
即在有野蛮人营地时生产下一个单位所剩的回合数减一,无野蛮人营地,且该地区还不允许产生野蛮人营地时,允许再次出现野蛮人营地的回合数同样减一

(2)变量m_aiPlotBarbCampNumUnitsSpawned
某一地块的营地已产生的小野数量

(3)变量m_aeValidBarbSpawnDirections
指明可行的方向,对于解析没有太大意义

[ 本帖最后由 Olemi 于 2012-11-9 10:13 编辑 ]

评分

1

查看全部评分

 楼主| 发表于 2012-11-4 21:51:39 | 显示全部楼层
1、营地被禁止生成单位的时间
这部分代码在CanBarbariansSpawn()函数中,第64~69行
  1. if (kGame.getElapsedGameTurns() < 10)
  2. {
  3.         return false;
  4. }

  5. return true;
复制代码
结论:营地只会在第10回合后生成单位,即如果某个营地在10回合前就达到生成野蛮人单位的条件(条件见4),也会被强制拖到第10回合生成,而且此值和速度无关

[ 本帖最后由 Olemi 于 2012-11-8 21:42 编辑 ]
回复 支持 反对

使用道具 举报

发表于 2012-11-4 21:53:53 | 显示全部楼层
前排占个座
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-11-4 21:56:27 | 显示全部楼层
2、营地每次产生的野蛮人的间隔时间
这部分代码在DoCampActivationNotice()函数中,总第90~125行(已删除注释)
  1. int iNumTurnsToSpawn = 8 + kGame.getJonRandNum(5, "Barb Spawn Rand call");

  2. if (kGame.isOption(GAMEOPTION_RAGING_BARBARIANS))
  3.         iNumTurnsToSpawn /= 2;

  4. int iNumUnitsSpawned = m_aiPlotBarbCampNumUnitsSpawned[pPlot->GetPlotIndex()];

  5. iNumTurnsToSpawn -= min(3, iNumUnitsSpawned);

  6. m_aiPlotBarbCampNumUnitsSpawned[pPlot->GetPlotIndex()]++;

  7. CvHandicapInfo* pHandicapInfo = GC.getHandicapInfo(kGame.getHandicapType());
  8. if (pHandicapInfo)
  9.         NumTurnsToSpawn += pHandicapInfo->getBarbSpawnMod();

  10. CvGameSpeedInfo* pGameSpeedInfo = GC.getGameSpeedInfo(kGame.getGameSpeedType());
  11. if (pGameSpeedInfo)
  12. {
  13.         iNumTurnsToSpawn *= pGameSpeedInfo->getBarbPercent();
  14.         iNumTurnsToSpawn /= 100;
  15. }

  16. m_aiPlotBarbCampSpawnCounter[pPlot->GetPlotIndex()] = iNumTurnsToSpawn;
复制代码
因此营地出现野蛮人的间隔时间由以下规则(按顺序)确定
在产生过野蛮人之后:
(1)取8~12间的随机数,设为X
(2)如果开狂暴小野,X值减半
(3)X再减去此营地已产生野蛮人的数量-1之差和3之间的最小值,即X=X-min{(此营地已产生野蛮人的数量-1),3}
(4)X再加上难度所带来的影响,即X=X+BarbSpawnMod,BarbSpawnMod在各难度下的具体值为(从易到难):8/5/3/0/0/0/0/0
(5)X再乘以速度所带来的影响,即X=X*(BarbPercent/100),BarbPercent在各速度下的具体值为(从慢到快):400/150/100/67
另外这个时间会在某些情况下变动,请参见3


结论:
1.在满足生成条件(条件见4)的情况下,标准速度亲王难度下5~13回合营地就会产生一个野蛮人;
2.亲王以上不存在营地生成野蛮人的惩罚。


[ 本帖最后由 Olemi 于 2012-11-8 21:45 编辑 ]
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-11-4 21:59:32 | 显示全部楼层
3、营地受攻击后的动作
这部分代码在DoCampAttacked()函数中,总第132~137行
  1. int iCounter = m_aiPlotBarbCampSpawnCounter[pPlot->GetPlotIndex()];

  2. int iNewValue = iCounter / 2;

  3. m_aiPlotBarbCampSpawnCounter[pPlot->GetPlotIndex()] = iNewValue;
复制代码
结论:在野蛮人营地受到攻击后,此营地产生野蛮人所剩的回合数减半(向下取整)

[ 本帖最后由 Olemi 于 2012-11-5 00:01 编辑 ]
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-11-4 23:16:49 | 显示全部楼层
4、营地产生的野蛮人单位的条件及类型、位置
这段代码在DoSpawnBarbarianUnit()函数中,总第659~777行,调用条件是某地块的m_aiPlotBarbCampSpawnCounter为0(m_aiPlotBarbCampSpawnCounter解释见0):
  1. int iNumNearbyUnits;
  2. int iNearbyUnitLoop;
  3. int iRange = GC.getMAX_BARBARIANS_FROM_CAMP_NEARBY_RANGE();
  4. int iX;
  5. int iY;
  6. CvPlot* pNearbyPlot;
  7. DirectionTypes eDirection;

  8. CvGame& kGame = GC.getGame();

  9. if (pPlot == 0)
  10.     return;

  11. // is this camp empty - first priority is to fill it
  12. if (pPlot && pPlot->GetNumCombatUnits() == 0)
  13. {
  14.     UnitTypes eUnit;
  15.     eUnit = GetRandomBarbarianUnitType(GC.getMap().getArea(pPlot->getArea()), UNITAI_FAST_ATTACK);

  16.     if (eUnit != NO_UNIT)
  17.     {
  18.         CvUnit* pUnit = GET_PLAYER(BARBARIAN_PLAYER).initUnit(eUnit, pPlot->getX(), pPlot->getY(), UNITAI_FAST_ATTACK);
  19.         pUnit->finishMoves();
  20.         return;
  21.     }
  22. }

  23. m_aeValidBarbSpawnDirections.clear();

  24. // Look at nearby Plots to see if there are already too many Barbs nearby
  25. iNumNearbyUnits = 0;

  26. for(iX = -iRange; iX <= iRange; iX++)
  27. {
  28.     for(iY = -iRange; iY <= iRange; iY++)
  29.     {
  30.         // Cut off the corners of the area we're looking at that we don't want
  31.         pNearbyPlot = plotXYWithRangeCheck(pPlot->getX(), pPlot->getY(), iX, iY, iRange);

  32.         if(pNearbyPlot != NULL)
  33.         {
  34.             if(pNearbyPlot->getNumUnits() > 0)
  35.             {
  36.                 for(iNearbyUnitLoop = 0; iNearbyUnitLoop < pNearbyPlot->getNumUnits(); iNearbyUnitLoop++)
  37.                 {
  38.                     const CvUnit* const unit = pNearbyPlot->getUnitByIndex(iNearbyUnitLoop);
  39.                     if(unit && pNearbyPlot->getUnitByIndex(iNearbyUnitLoop)->isBarbarian())
  40.                     {
  41.                         iNumNearbyUnits++;
  42.                     }
  43.                 }
  44.             }
  45.         }
  46.     }
  47. }

  48. if(iNumNearbyUnits <= /*2*/ GC.getMAX_BARBARIANS_FROM_CAMP_NEARBY())
  49. {
  50.     CvPlot* pLoopPlot;

  51.     // Barbs only get boats after some period of time has passed
  52.     bool bCanSpawnBoats = kGame.getElapsedGameTurns() > /*30*/ GC.getBARBARIAN_NAVAL_UNIT_START_TURN_SPAWN();

  53.     // Look to see if adjacent Tiles are valid locations to spawn a Unit
  54.     for(int iDirectionLoop = 0; iDirectionLoop < NUM_DIRECTION_TYPES; iDirectionLoop++)
  55.     {
  56.         eDirection = (DirectionTypes) iDirectionLoop;
  57.         pLoopPlot = plotDirection(pPlot->getX(), pPlot->getY(), eDirection);

  58.         if(pLoopPlot != NULL)
  59.         {
  60.             if(pLoopPlot->getNumUnits() == 0)
  61.             {
  62.                 if(!pLoopPlot->isImpassable() && !pLoopPlot->isMountain())
  63.                 {
  64.                     if(!pLoopPlot->isCity())
  65.                     {
  66.                         if(!pLoopPlot->isLake())
  67.                         {
  68.                             // Water Tiles are only valid when the Barbs have the proper Tech
  69.                             if(!pLoopPlot->isWater() || bCanSpawnBoats)
  70.                             {
  71.                                 m_aeValidBarbSpawnDirections.push_back(eDirection);
  72.                             }
  73.                         }
  74.                     }
  75.                 }
  76.             }
  77.         }
  78.     }

  79.     // Any valid locations?
  80.     if(m_aeValidBarbSpawnDirections.size() > 0)
  81.     {
  82.         int iIndex = kGame.getJonRandNum(m_aeValidBarbSpawnDirections.size(), "Barb Unit Location Spawn Roll");
  83.         eDirection = (DirectionTypes) m_aeValidBarbSpawnDirections[iIndex];
  84.         CvPlot* pSpawnPlot = plotDirection(pPlot->getX(), pPlot->getY(), eDirection);
  85.         UnitAITypes eUnitAI;
  86.         UnitTypes eUnit;

  87.         // Naval Barbs
  88.         if(pSpawnPlot->isWater())
  89.         {
  90.             eUnitAI = UNITAI_ATTACK_SEA;
  91.         }
  92.         // Land Barbs
  93.         else
  94.         {
  95.             eUnitAI = UNITAI_FAST_ATTACK;
  96.         }

  97.         eUnit = GetRandomBarbarianUnitType(GC.getMap().getArea(pSpawnPlot->getArea()), eUnitAI);

  98.         if(eUnit != NO_UNIT)
  99.         {
  100.             CvUnit* pUnit = GET_PLAYER(BARBARIAN_PLAYER).initUnit(eUnit, pSpawnPlot->getX(), pSpawnPlot->getY(), eUnitAI);
  101.         }
  102.     }
  103. }
复制代码
其中,iRange=MAX_BARBARIANS_FROM_CAMP_NEARBY_RANGE=4;BARBARIAN_NAVAL_UNIT_START_TURN_SPAWN=2;BARBARIAN_NAVAL_UNIT_START_TURN_SPAWN=30


1.当前地块是否有野蛮人单位?
  (1).没有,在当前地块产生UNITAI_FAST_ATTACK类型的单位,函数返回
  (2).有,继续执行
2.检查附近4(MAX_BARBARIANS_FROM_CAMP_NEARBY_RANGE)格范围内的野蛮人单位的数量,如果小于2(MAX_BARBARIANS_FROM_CAMP_NEARBY)个
  (1).逐个检查临近地块,若符合以下条件:
    a.无单位
    b.可通行
    c.非山峰
    d.非城市
    e.非湖泊
    f.非水域和可产生船只之间满足一项(可产生船只的条件是已经过的回合数大于30)
  则将该地块加入可产生单位地块队列中
3.如果可产生单位地块队列长度不为0
  1.产生一个0~队列长度-1的随机数
  2.此地块是否为水域?
    a.是,产生UNITAI_ATTACK_SEA类型的单位
    b.否,产生UNITAI_FAST_ATTACK类型的单位

UNITAI_FAST_ATTACK和UNITAI_ATTACK_SEA是AI所使用的单位类型,具体有哪些请参阅相关帖子(虽然貌似目前还没有- -)
另外注意一点如果到时间没有产生野蛮人计数器会一直保持在0,也就是说,只要在之后的某个回合满足条件,就会生成野蛮人
结论:
1.营地野蛮人生成的条件:达到生成的回合数,且4格内有少于或等于2个的蛮族单位,且临近地块或当前地块有可以放置野蛮人单位的地块;
2.别过度吸引野蛮人的注意,如果他们远离营地会使营地继续产生野蛮人;
3.30回合后小心野蛮人的战船。


[ 本帖最后由 Olemi 于 2012-11-8 23:36 编辑 ]
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-11-4 23:18:14 | 显示全部楼层
我勒个去,有人看没人回……

有一些参数是XML里的,没有装文明V也不方便去查,具体数据等我以后查一下再补充……

[ 本帖最后由 Olemi 于 2012-11-4 23:24 编辑 ]
回复 支持 反对

使用道具 举报

发表于 2012-11-4 23:27:26 | 显示全部楼层
好吧 虽然想潜水
不过LZ既然发话了 就冒出来支持下技术贴
回复 支持 反对

使用道具 举报

发表于 2012-11-4 23:34:53 | 显示全部楼层
怎么得到代码的啊?
回复 支持 反对

使用道具 举报

发表于 2012-11-4 23:38:19 | 显示全部楼层
我非常非常好奇你怎么拿到source code的,这是商业机密呀。
回复 支持 反对

使用道具 举报

发表于 2012-11-4 23:46:34 | 显示全部楼层
犀利啊
回复 支持 反对

使用道具 举报

发表于 2012-11-4 23:47:13 | 显示全部楼层
代码里带注释,应该不是反编译出来的,楼主快给大家讲讲代码怎么来的,我也想去读读。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-11-4 23:58:37 | 显示全部楼层
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-11-5 00:11:10 | 显示全部楼层
5、摧毁上一个野蛮人营地后允许此地块产生下一个营地的间隔时间
这段代码在DoBarbCampCleared()函数中,总第56行:
  1. m_aiPlotBarbCampSpawnCounter[pPlot->GetPlotIndex()] = -16;
复制代码
由于代码块0的执行顺序比建立营地的代码块早,所以
结论:摧毁上一个野蛮人营地后15回合此地块才有产生下一个营地的可能。事实上,根据6的结果,4格以内在15回合中都不会产生下一个营地

[ 本帖最后由 Olemi 于 2012-11-8 22:54 编辑 ]
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-11-5 00:15:07 | 显示全部楼层
今天先到这里,有时间再研究……
回复 支持 反对

使用道具 举报

发表于 2012-11-5 00:16:22 | 显示全部楼层

回复 13# 的帖子

多谢哈,原来C5这么大方
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-11-5 00:18:04 | 显示全部楼层

回复 16# 的帖子

C4更大方,直接就在游戏文件夹下
回复 支持 反对

使用道具 举报

发表于 2012-11-5 00:29:58 | 显示全部楼层
看了一下这些code都是游戏规则相关的数据处理,跟UI无关,就是让玩家自己编译个dll替换着玩的,真是欢乐无限~
回复 支持 反对

使用道具 举报

发表于 2012-11-5 00:46:54 | 显示全部楼层
lz说10回合后才有野蛮人。。。我棒子走一步就看到野蛮人怎么破 = = 你这是在是坑爹
回复 支持 反对

使用道具 举报

发表于 2012-11-5 00:53:12 | 显示全部楼层
这是神马语言编写的。。。。。 只学过python + pascal的伤不起
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|Archiver|塞爱维(CIV)文明联盟    

GMT+8, 2024-4-29 04:25

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表