|
发表于 2015-4-28 05:48:16
|
显示全部楼层
简单的做法就是当目标进入到一定距离内就埋地。
复杂的做法是获取周围一定范围内的目标,并根据当前命令预测一段时间后的位置,如果预测埋地时间之后目标在射程内,就埋地。
好吧,代码虽然是cpp仅供参考。。
- #pragma once
- #include "stdafx.h"
- class WidowMineAttack
- {
- std::map<Unit, Unit> UnitLastAcquireTargetMap;
- void OnAcquireTarget()
- {
- Unit u = EventUnit();
- Unit target = EventUnitTarget();
- //Output(u.ToString() + " acquires " + target.ToString());
- UnitLastAcquireTargetMap[u] = target;
- }
- void OnUnitDiedRemoveAcquireTarget()
- {
- Unit u = EventUnit();
- //Output(String("erase acquire ") + u.ToString());
- UnitLastAcquireTargetMap.erase(u);
- }
- //a distance evaluation function. if the unit will attack target, the result is distance between the attacked target and WM.
- //if the unit has move order, the result is the distance after WM burrow time
- bool UnitInRangeOfWMAfterBurrow(Unit u, Unit widowmine)
- {
- Player PlayerWidowMine = widowmine.GetOwner();
- Fixed BurrowTime = PlayerWidowMine.TechTreeUpgradeCount("DrillClaws", ETechTreeCountType::CompleteOnly) > 0 ? 1.0 : 3.0;
- BurrowTime += 0.5;//buffer
- Fixed WMAttackRange = 5.0;
- if (u.OrderCount())
- {
- Order ordCurrent = u.OrderGet(0);
- auto acmd = ordCurrent.GetAbilityCommand();
- auto DetermineByMove = [u, widowmine, ordCurrent, BurrowTime, WMAttackRange]
- {
- Point currPos = u.GetPosition();
- Point target = ordCurrent.GetTargetPosition();
- if (target != none && target != currPos)
- {
- //check if it will get into WM's range
- for (Fixed t = 0; t <= BurrowTime; t += 0.2)
- {
- Point expectPos = currPos.OffsetPolar(t * u.GetPropertyFixed(EUnitProp::MovementSpeed, EUnitPropType::Current), currPos.AngleToPoint(target));
- if (expectPos.DistanceToPoint(widowmine.GetPosition()) <= WMAttackRange)
- {
- return true;
- }
- }
- }
- //otherwise return true only if the unit is already in range
- return u.DistanceTo(widowmine) <= WMAttackRange;
- };
- auto DetermineByAcquireOrMove = [this, WMAttackRange, DetermineByMove](Unit u, Unit widowmine)
- {
- Unit acquireTarget = UnitLastAcquireTargetMap[u];
- //Output(String("AcquireTarget = ") + acquireTarget.ToString() + ", Distance = " + String(acquireTarget.DistanceTo(widowmine)));
- if (acquireTarget != none/* && acquireTarget.IsFriendlyTo(PlayerWidowMine)*/)
- {
- //Output(String("AcquireTarget = ") + acquireTarget.ToString() + ", Distance = " + String(acquireTarget.DistanceTo(widowmine)));
- //TODO: we should also consider the strength of enemy and friendly army near acquired target.
- //For now, just take it as infinite strong so the enemy would be at the target's location after WM is burrowed.
- return acquireTarget.DistanceTo(widowmine) <= WMAttackRange;
- }
- else
- {
- return DetermineByMove();
- }
- };
- if (acmd == AbilCmd::FromStr(Commands::Attack) || acmd == AbilCmd::FromStr(Commands::Patrol))
- {
- //Output("Unit attack move...");
- return DetermineByAcquireOrMove(u, widowmine);
- }
- else if (acmd == AbilCmd::FromStr(Commands::Move) || acmd == AbilCmd::Smart)
- {
- //Output("Unit move...");
- return DetermineByMove();
- }
- }
- else//idle
- {
- //Output("Unit idle...");
- Unit acquireTarget = UnitLastAcquireTargetMap[u];
- if (acquireTarget != none)
- {
- return acquireTarget.DistanceTo(widowmine) <= WMAttackRange;
- }
- else
- {
- return u.DistanceTo(widowmine) <= WMAttackRange;
- }
- }
- return false;
- }
- UnitGroup ActiveWidowMines;
- Array<UnitType> UnitTypeArmyAndWorker;
- void InitUnitTypeArmyAndWorker()
- {
- for (int unitEntryIdx = 0, unitEntryCount = CatalogEntryCount(EGameCatalog::Unit); unitEntryIdx < unitEntryCount; unitEntryIdx++)
- {
- UnitType unitEntry = UnitType(CatalogEntryGet(EGameCatalog::Unit, unitEntryIdx));
- if (UnitTypeArmyAndWorker.Has(unitEntry))
- continue;
- if (unitEntry.TestFlag(EUnitFlag::Worker) || unitEntry.TestFlag(EUnitFlag::ArmySelect))
- {
- UnitTypeArmyAndWorker.Add(unitEntry);
- }
- }
- }
- bool GetWidowMineFlag(Unit widowmine)
- {
- return ActiveWidowMines.HasUnit(widowmine);
- }
- void OnTimer()
- {
- if (!GetFeatureSettingBool("WidowMine"))
- return;
- Fixed searchRange = 18.0;
- UnitGroup g_All = UnitGroup(any, any, any, UnitFilter().Exclude(ETargetFilter::Structure).Exclude(ETargetFilter::Dead).Exclude(ETargetFilter::Missile).Exclude(ETargetFilter::Invulnerable).Exclude(ETargetFilter::Hidden));
- g_All = UnitGroupFilterUnitTypes(g_All, UnitTypeArmyAndWorker);
- UnitGroup deactivated;
- for (Unit widowMine : ActiveWidowMines)
- {
- //get enemies nearby
- UnitGroup enemies = UnitGroupFilterRegion(g_All, RegionCircle(widowMine.GetPosition(), searchRange));
- enemies = UnitGroupFilterAlliance(enemies, widowMine.GetOwner(), EUnitGroupAllianceId_Enemy);
- enemies = UnitGroupFilterVision(enemies, widowMine.GetOwner(), true);
- if (enemies.Count())
- {
- //if the widow mine is activated auto burrow and is not burrowed already, burrow it
- if (widowMine.GetType() == Units::WidowMine && GetWidowMineFlag(widowMine))
- {
- bool IsEnemyNearEnough = false;
- for (Unit enemy : enemies)
- {
- if (UnitInRangeOfWMAfterBurrow(enemy, widowMine))
- {
- IsEnemyNearEnough = true;
- break;
- }
- }
- if (IsEnemyNearEnough)
- {
- widowMine.IssueOrderAsync(Order(AbilCmd::FromStr("WidowMineBurrow,Execute")), EOrderQueueOption::Replace, false, false, "WidowMineAttack");
- deactivated.Add(widowMine);
- }
- }
- }
- }
- SetWidowMineFlag(deactivated, false);//prevent triggering again while burrowing down
- }
- void SetWidowMineFlag(UnitGroup widowmines, bool flag)
- {
- for (Unit mine : widowmines)
- {
- if (flag)
- ActiveWidowMines.Add(mine);
- else
- ActiveWidowMines.Remove(mine);
- }
- }
- void OnUnitDied()
- {
- if (EventUnit().GetType() == Units::WidowMine || EventUnit().GetType() == Units::WidowMineActivated)
- {
- SetWidowMineFlag(EventUnit(), false);
- }
- }
- void OnLocalOrder()
- {
- Order ord = LocalEventOrder();
- UnitGroup SelectingUnits = LocalEventOrderUnits();
- //only unburrowed widow mines
- //TODO: controllable only! implement UnitGroupFilterControllable
- UnitGroup SelectingWidowMines = UnitGroupFilter(Units::WidowMine, any, SelectingUnits, UnitFilter().Exclude(ETargetFilter::Dead));
- if (SelectingWidowMines.Count() == 0)
- return;
- //Attack ground : auto
- if (
- (ord.GetAbilityCommand() == AbilCmd::FromStr(Commands::Attack) || ord.GetAbilityCommand() == AbilCmd::FromStr("move,AcquireMove"))
- && ord.GetTargetType() == EOrderTargetType::Point
- )//TODO + MovePatrol
- {
- SetWidowMineFlag(SelectingWidowMines, true);
- }
- else//any other order
- {
- //order valid test
- if (SelectingWidowMines.UnitAt(1).OrderIsValid(ord))
- SetWidowMineFlag(SelectingWidowMines, false);
- }
- }
- void OnUnitBecomesIdle()//not auto burrow when idle
- {
- Unit IdleUnit = EventUnit();
- //only unburrowed widow mines
- if (IdleUnit.GetType() == Units::WidowMine && IdleUnit.IsControllable(PlayerLocal()))
- {
- SetWidowMineFlag(IdleUnit, true);
- }
- }
- public:
- WidowMineAttack()
- {
- InitUnitTypeArmyAndWorker();
- AbilCmd widowMineAttack = AbilCmd("WidowMineAttack", 0);
- if (widowMineAttack != none)//valid for HotS
- {
- AddLocalEventOrder(TRIG(WidowMineAttack::OnLocalOrder));
- AddEventUnitBecomesIdle(TRIG(WidowMineAttack::OnUnitBecomesIdle), any, true);
- AddEventUnitDied(TRIG(WidowMineAttack::OnUnitDied));
- AddEventTimePeriodic(TRIG(WidowMineAttack::OnTimer), 0, ETimeType::Game);
- AddEventUnitAcquiredTarget(TRIG(WidowMineAttack::OnAcquireTarget));
- AddEventUnitDied(TRIG(WidowMineAttack::OnUnitDiedRemoveAcquireTarget));
- }
- }
- };
复制代码 |
|