找回密码
 点一下
查看: 581|回复: 4

请教下如何让地刺遇到目标后自动下潜攻击?

[复制链接]
发表于 2015-4-27 22:13:36 | 显示全部楼层 |阅读模式
本帖最后由 q535519395 于 2015-4-27 22:32 编辑

我想弄个让  地刺遇到目标后 下潜后攻击目标,当目标消失后潜出的效果。   
发表于 2015-4-28 05:48:16 | 显示全部楼层
简单的做法就是当目标进入到一定距离内就埋地。
复杂的做法是获取周围一定范围内的目标,并根据当前命令预测一段时间后的位置,如果预测埋地时间之后目标在射程内,就埋地。
好吧,代码虽然是cpp仅供参考。。


  1. #pragma once
  2. #include "stdafx.h"

  3. class WidowMineAttack
  4. {
  5.         std::map<Unit, Unit> UnitLastAcquireTargetMap;

  6.         void OnAcquireTarget()
  7.         {
  8.                 Unit u = EventUnit();
  9.                 Unit target = EventUnitTarget();
  10.                 //Output(u.ToString() + " acquires " + target.ToString());
  11.                 UnitLastAcquireTargetMap[u] = target;
  12.         }

  13.         void OnUnitDiedRemoveAcquireTarget()
  14.         {
  15.                 Unit u = EventUnit();
  16.                 //Output(String("erase acquire ") + u.ToString());
  17.                 UnitLastAcquireTargetMap.erase(u);
  18.         }

  19.         //a distance evaluation function. if the unit will attack target, the result is distance between the attacked target and WM.
  20.         //if the unit has move order, the result is the distance after WM burrow time
  21.         bool UnitInRangeOfWMAfterBurrow(Unit u, Unit widowmine)
  22.         {
  23.                 Player PlayerWidowMine = widowmine.GetOwner();
  24.                 Fixed BurrowTime = PlayerWidowMine.TechTreeUpgradeCount("DrillClaws", ETechTreeCountType::CompleteOnly) > 0 ? 1.0 : 3.0;
  25.                 BurrowTime += 0.5;//buffer
  26.                 Fixed WMAttackRange = 5.0;

  27.                 if (u.OrderCount())
  28.                 {
  29.                         Order ordCurrent = u.OrderGet(0);
  30.                         auto acmd = ordCurrent.GetAbilityCommand();

  31.                         auto DetermineByMove = [u, widowmine, ordCurrent, BurrowTime, WMAttackRange]
  32.                         {
  33.                                 Point currPos = u.GetPosition();
  34.                                 Point target = ordCurrent.GetTargetPosition();
  35.                                 if (target != none && target != currPos)
  36.                                 {
  37.                                         //check if it will get into WM's range
  38.                                         for (Fixed t = 0; t <= BurrowTime; t += 0.2)
  39.                                         {
  40.                                                 Point expectPos = currPos.OffsetPolar(t * u.GetPropertyFixed(EUnitProp::MovementSpeed, EUnitPropType::Current), currPos.AngleToPoint(target));
  41.                                                 if (expectPos.DistanceToPoint(widowmine.GetPosition()) <= WMAttackRange)
  42.                                                 {
  43.                                                         return true;
  44.                                                 }
  45.                                         }
  46.                                 }

  47.                                 //otherwise return true only if the unit is already in range
  48.                                 return u.DistanceTo(widowmine) <= WMAttackRange;
  49.                         };

  50.                         auto DetermineByAcquireOrMove = [this, WMAttackRange, DetermineByMove](Unit u, Unit widowmine)
  51.                         {
  52.                                 Unit acquireTarget = UnitLastAcquireTargetMap[u];
  53.                                 //Output(String("AcquireTarget = ") + acquireTarget.ToString() + ", Distance = " + String(acquireTarget.DistanceTo(widowmine)));
  54.                                 if (acquireTarget != none/* && acquireTarget.IsFriendlyTo(PlayerWidowMine)*/)
  55.                                 {
  56.                                         //Output(String("AcquireTarget = ") + acquireTarget.ToString() + ", Distance = " + String(acquireTarget.DistanceTo(widowmine)));
  57.                                         //TODO: we should also consider the strength of enemy and friendly army near acquired target.
  58.                                         //For now, just take it as infinite strong so the enemy would be at the target's location after WM is burrowed.
  59.                                         return acquireTarget.DistanceTo(widowmine) <= WMAttackRange;
  60.                                 }
  61.                                 else
  62.                                 {
  63.                                         return DetermineByMove();
  64.                                 }
  65.                         };

  66.                         if (acmd == AbilCmd::FromStr(Commands::Attack) || acmd == AbilCmd::FromStr(Commands::Patrol))
  67.                         {
  68.                                 //Output("Unit attack move...");
  69.                                 return DetermineByAcquireOrMove(u, widowmine);
  70.                         }
  71.                         else if (acmd == AbilCmd::FromStr(Commands::Move) || acmd == AbilCmd::Smart)
  72.                         {
  73.                                 //Output("Unit move...");
  74.                                 return DetermineByMove();
  75.                         }
  76.                 }
  77.                 else//idle
  78.                 {
  79.                         //Output("Unit idle...");
  80.                         Unit acquireTarget = UnitLastAcquireTargetMap[u];
  81.                         if (acquireTarget != none)
  82.                         {
  83.                                 return acquireTarget.DistanceTo(widowmine) <= WMAttackRange;
  84.                         }
  85.                         else
  86.                         {
  87.                                 return u.DistanceTo(widowmine) <= WMAttackRange;
  88.                         }
  89.                 }
  90.                 return false;
  91.         }

  92.         UnitGroup ActiveWidowMines;

  93.         Array<UnitType> UnitTypeArmyAndWorker;
  94.         void InitUnitTypeArmyAndWorker()
  95.         {
  96.                 for (int unitEntryIdx = 0, unitEntryCount = CatalogEntryCount(EGameCatalog::Unit); unitEntryIdx < unitEntryCount; unitEntryIdx++)
  97.                 {
  98.                         UnitType unitEntry = UnitType(CatalogEntryGet(EGameCatalog::Unit, unitEntryIdx));
  99.                         if (UnitTypeArmyAndWorker.Has(unitEntry))
  100.                                 continue;

  101.                         if (unitEntry.TestFlag(EUnitFlag::Worker) || unitEntry.TestFlag(EUnitFlag::ArmySelect))
  102.                         {
  103.                                 UnitTypeArmyAndWorker.Add(unitEntry);
  104.                         }
  105.                 }
  106.         }

  107.         bool GetWidowMineFlag(Unit widowmine)
  108.         {
  109.                 return ActiveWidowMines.HasUnit(widowmine);
  110.         }

  111.         void OnTimer()
  112.         {
  113.                 if (!GetFeatureSettingBool("WidowMine"))
  114.                         return;

  115.                 Fixed searchRange = 18.0;

  116.                 UnitGroup g_All = UnitGroup(any, any, any, UnitFilter().Exclude(ETargetFilter::Structure).Exclude(ETargetFilter::Dead).Exclude(ETargetFilter::Missile).Exclude(ETargetFilter::Invulnerable).Exclude(ETargetFilter::Hidden));
  117.                 g_All = UnitGroupFilterUnitTypes(g_All, UnitTypeArmyAndWorker);

  118.                 UnitGroup deactivated;
  119.                 for (Unit widowMine : ActiveWidowMines)
  120.                 {
  121.                         //get enemies nearby
  122.                         UnitGroup enemies = UnitGroupFilterRegion(g_All, RegionCircle(widowMine.GetPosition(), searchRange));
  123.                         enemies = UnitGroupFilterAlliance(enemies, widowMine.GetOwner(), EUnitGroupAllianceId_Enemy);
  124.                         enemies = UnitGroupFilterVision(enemies, widowMine.GetOwner(), true);

  125.                         if (enemies.Count())
  126.                         {
  127.                                 //if the widow mine is activated auto burrow and is not burrowed already, burrow it
  128.                                 if (widowMine.GetType() == Units::WidowMine && GetWidowMineFlag(widowMine))
  129.                                 {
  130.                                         bool IsEnemyNearEnough = false;
  131.                                         for (Unit enemy : enemies)
  132.                                         {
  133.                                                 if (UnitInRangeOfWMAfterBurrow(enemy, widowMine))
  134.                                                 {
  135.                                                         IsEnemyNearEnough = true;
  136.                                                         break;
  137.                                                 }
  138.                                         }
  139.                                         if (IsEnemyNearEnough)
  140.                                         {
  141.                                                 widowMine.IssueOrderAsync(Order(AbilCmd::FromStr("WidowMineBurrow,Execute")), EOrderQueueOption::Replace, false, false, "WidowMineAttack");
  142.                                                 deactivated.Add(widowMine);
  143.                                         }
  144.                                 }
  145.                         }
  146.                 }

  147.                 SetWidowMineFlag(deactivated, false);//prevent triggering again while burrowing down
  148.         }

  149.         void SetWidowMineFlag(UnitGroup widowmines, bool flag)
  150.         {
  151.                 for (Unit mine : widowmines)
  152.                 {
  153.                         if (flag)
  154.                                 ActiveWidowMines.Add(mine);
  155.                         else
  156.                                 ActiveWidowMines.Remove(mine);
  157.                 }
  158.         }

  159.         void OnUnitDied()
  160.         {
  161.                 if (EventUnit().GetType() == Units::WidowMine || EventUnit().GetType() == Units::WidowMineActivated)
  162.                 {
  163.                         SetWidowMineFlag(EventUnit(), false);
  164.                 }
  165.         }

  166.         void OnLocalOrder()
  167.         {
  168.                 Order ord = LocalEventOrder();
  169.                 UnitGroup SelectingUnits = LocalEventOrderUnits();

  170.                 //only unburrowed widow mines
  171.                 //TODO: controllable only! implement UnitGroupFilterControllable
  172.                 UnitGroup SelectingWidowMines = UnitGroupFilter(Units::WidowMine, any, SelectingUnits, UnitFilter().Exclude(ETargetFilter::Dead));

  173.                 if (SelectingWidowMines.Count() == 0)
  174.                         return;

  175.                 //Attack ground : auto
  176.                 if (
  177.                         (ord.GetAbilityCommand() == AbilCmd::FromStr(Commands::Attack) || ord.GetAbilityCommand() == AbilCmd::FromStr("move,AcquireMove"))
  178.                         && ord.GetTargetType() == EOrderTargetType::Point
  179.                         )//TODO + MovePatrol
  180.                 {
  181.                         SetWidowMineFlag(SelectingWidowMines, true);
  182.                 }
  183.                 else//any other order
  184.                 {
  185.                         //order valid test
  186.                         if (SelectingWidowMines.UnitAt(1).OrderIsValid(ord))
  187.                                 SetWidowMineFlag(SelectingWidowMines, false);
  188.                 }
  189.         }

  190.         void OnUnitBecomesIdle()//not auto burrow when idle
  191.         {
  192.                 Unit IdleUnit = EventUnit();

  193.                 //only unburrowed widow mines
  194.                 if (IdleUnit.GetType() == Units::WidowMine && IdleUnit.IsControllable(PlayerLocal()))
  195.                 {
  196.                         SetWidowMineFlag(IdleUnit, true);
  197.                 }
  198.         }

  199. public:

  200.         WidowMineAttack()
  201.         {
  202.                 InitUnitTypeArmyAndWorker();
  203.                 AbilCmd widowMineAttack = AbilCmd("WidowMineAttack", 0);
  204.                 if (widowMineAttack != none)//valid for HotS
  205.                 {
  206.                         AddLocalEventOrder(TRIG(WidowMineAttack::OnLocalOrder));
  207.                         AddEventUnitBecomesIdle(TRIG(WidowMineAttack::OnUnitBecomesIdle), any, true);
  208.                         AddEventUnitDied(TRIG(WidowMineAttack::OnUnitDied));
  209.                         AddEventTimePeriodic(TRIG(WidowMineAttack::OnTimer), 0, ETimeType::Game);

  210.                         AddEventUnitAcquiredTarget(TRIG(WidowMineAttack::OnAcquireTarget));
  211.                         AddEventUnitDied(TRIG(WidowMineAttack::OnUnitDiedRemoveAcquireTarget));
  212.                 }
  213.         }
  214. };
复制代码
回复

使用道具 举报

发表于 2015-5-1 18:33:21 | 显示全部楼层
这个可以在技能页面直接定义呀,如果你想更智能些,配合验证器会更好些。
另:这么简单的一个功能,为啥楼上要写那么long的一段代码呀。

点评

因为我写的是地雷自动埋地啊,不是做地图。。。  详情 回复 发表于 2015-5-2 05:55
回复

使用道具 举报

发表于 2015-5-2 05:55:41 | 显示全部楼层
yxxiaobin 发表于 2015-5-1 18:33
这个可以在技能页面直接定义呀,如果你想更智能些,配合验证器会更好些。
另:这么简单的一个功能,为啥楼 ...

因为我写的是地雷自动埋地啊,不是做地图。。。
回复

使用道具 举报

发表于 2015-5-5 08:43:29 | 显示全部楼层
技能的标旗开启自动施法,验证器使用区域枚举,区域内敌对地面单位大于0就潜地,等于0就出地
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 点一下

本版积分规则

Archiver|移动端|小黑屋|地精研究院

GMT+8, 2024-12-25 10:03 , Processed in 0.149682 second(s), 23 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

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