native UnitAlive takes unit u returns boolean
library PatrolPath
endlibrary
library Patrol requires VectorT, UnitDex, TimerUtils, PatrolPath
struct PatrolPoint
real x
real y
static method create(real x, real y)
method destroy()
local PatrolPath path = PatrolPath.create()
call path.push(PatrolPoint(0,0))
===
struct PatrolType
static constant integer NORMAL
static constant integer BACKWARD
static constant integer LOOP
===
struct PatrolOrder
static constant integer MOVE
static constant integer ATTACK
===
struct PatrolUnit
static method create(unit u, PatrolPath pp, PatrolType pt, PatrolOrder po, real guardDistance, boolean reverse) returns thistype
method destroy()
method operator unit returns unit
method operator pathPosition returns integer
method operator pathPosition= (integer newPos)
method operator order returns PatrolOrder
method operator order= (PatrolOrder p)
method operator guardDistance returns real
method operator guardDistance= (real r)
method operator enabled returns boolean
method operator enabled= (boolean flag)
method operator reverse returns boolean
method operator reverse= (boolean flag)
method operator path returns PatrolPath
method operator path= (PatrolPath p)
method operator patrolType returns PatrolType
method operator patrolType= (PatrolType p)
static method operator enabledAll= (boolean flag)
static method operator[] (unit u) returns thistype
set PatrolUnit[unit].reverse = true
static method register(boolexpr be) returns triggercondition
static method unregister(triggercondition tc)
method registerPatrolUnit(boolexpr be) returns triggercondition
method unregisterPatrolUnit(triggercondition tc)
static method operator currentPatrolUnit returns thistype
===
function PatrolPathHardDestroy(PatrolPath p)
{
private constant boolean DISABLE_ON_DEATH = true;
private constant boolean DESTROY_ON_DEATH = false;
private constant boolean FORMATION_ENABLED = false;
private constant real MAX_RANGE = 20;
public struct PatrolPoint{
real x;
real y;
private boolean p_exists;
static method create(real x, real y) -> thistype{
thistype this = allocate();
this.x = x;
this.y = y;
this.p_exists = true;
return this;
}
method destroy(){
if (p_exists){
deallocate();
p_exists = false;
}
}
method operator exists() -> boolean{
return p_exists;
}
}
public struct PatrolType extends array{
static constant integer NORMAL = 1;
static constant integer BACKWARD = 2;
static constant integer LOOP = 3;
static constant integer MAXIMUM_AMOUNT = 3;
}
public struct PatrolOrder extends array{
static constant integer MOVE = 851986;
static constant integer ATTACK = 851983;
}
private constant real INTERVAL = 0.031250000;
public struct PatrolUnit extends array{
private static group Group = CreateGroup();
private static group Backup = CreateGroup();
private static group Temp;
private static trigger handler = CreateTrigger();
private static thistype p_patrolUnit;
private unit p_u;
private timer clock;
private integer incrementer;
private integer p_pathPosition;
private trigger p_handler;
private boolean p_reverse;
private boolean p_enabled;
private real p_guardDistance;
private trigger guardHandler;
private PatrolType p_patrolType;
private PatrolOrder p_order;
private PatrolPath p_path;
private real xReturn;
private real yReturn;
private boolean isChasing;
method destroy(){
ReleaseTimer(clock);
if(p_handler != null){
DestroyTrigger(p_handler);
p_handler = null;
}
if(guardHandler != null){
DestroyTrigger(guardHandler);
guardHandler = null;
}
p_enabled = false;
GroupRemoveUnit(Group, p_u);
p_u = null;
clock = null;
}
private static method callback(){
thistype this = GetTimerData(GetExpiredTimer());
real distance, x, y;
static if(DESTROY_ON_DEATH){
if (!UnitAlive(p_u)){
destroy();
return;
}
}
static if(DISABLE_ON_DEATH){
if (!UnitAlive(p_u)){
PauseTimer(clock);
p_enabled = false;
return;
}
}
if(p_path.empty()){
debug BJDebugMsg(thistype.callback.name + ": instance " + I2S(this) + " has an invalid or empty PatrolPath.");
return;
}
else if(!p_path[p_pathPosition].exists){
debug BJDebugMsg(thistype.callback.name + ": instance " + I2S(this) + " tries to acces a removed/invalid PatrolPoint.");
return;
}
x = GetUnitX(p_u); y = GetUnitY(p_u);
distance = SquareRoot((p_path[p_pathPosition].x-x)*(p_path[p_pathPosition].x-x) + (p_path[p_pathPosition].y-y)*(p_path[p_pathPosition].y-y));
if (distance <= MAX_RANGE) {
p_patrolUnit = this;
TriggerEvaluate(handler);
if(p_handler != null)
TriggerEvaluate(p_handler);
if (p_patrolType == PatrolType.NORMAL){
if(p_path[p_pathPosition] == p_path.back() && !reverse){
p_pathPosition = 0;
}
else if(reverse && p_path[p_pathPosition] == p_path.front()){
p_pathPosition = p_path.size()-1;
}
else {
p_pathPosition = p_pathPosition + incrementer;
}
}
else if(p_patrolType == PatrolType.BACKWARD){
if(p_path[p_pathPosition] == p_path.back()){
incrementer = -1;
}
else if (p_path[p_pathPosition] == p_path.front()){
incrementer = 1;
}
p_pathPosition = p_pathPosition + incrementer;
}
else if(p_patrolType == PatrolType.LOOP){
if(p_path[p_pathPosition] == p_path.back() && !reverse){
SetUnitX(p_u, p_path.front().x);
SetUnitY(p_u, p_path.front().y);
p_pathPosition = 1;
}
else if(reverse && p_path[p_pathPosition] == p_path.front()){
SetUnitX(p_u, p_path.back().x);
SetUnitY(p_u, p_path.back().y);
p_pathPosition = p_path.size()-2;
}
else {
p_pathPosition = p_pathPosition + incrementer;
}
}
if (FORMATION_ENABLED) {
IssuePointOrderById(p_u, p_order, p_path[p_pathPosition].x + GetRandomReal(0, 0.1), p_path[p_pathPosition].y + GetRandomReal(0, 0.1));
}
else{
IssuePointOrderById(p_u, p_order, p_path[p_pathPosition].x , p_path[p_pathPosition].y);
}
}
if (GetUnitCurrentOrder(p_u) == null){
if (FORMATION_ENABLED) {
IssuePointOrderById(p_u, p_order, p_path[p_pathPosition].x + GetRandomReal(0, 0.1), p_path[p_pathPosition].y + GetRandomReal(0, 0.1));
}
else{
IssuePointOrderById(p_u, p_order, p_path[p_pathPosition].x , p_path[p_pathPosition].y);
}
}
}
private static method callback_2(){
thistype this = GetTimerData(GetExpiredTimer());
real distance, x, y;
static if(DESTROY_ON_DEATH){
if (!UnitAlive(p_u)){
destroy();
return;
}
}
static if(DISABLE_ON_DEATH){
if (!UnitAlive(p_u)){
PauseTimer(clock);
p_enabled = false;
return;
}
}
x = GetUnitX(p_u); y = GetUnitY(p_u);
distance = SquareRoot((xReturn-x)*(xReturn-x) + (yReturn-y)*(yReturn-y));
if(!isChasing && distance <= MAX_RANGE){
TimerStart(clock, INTERVAL, true, function thistype.callback);
}
if(distance > p_guardDistance){
isChasing = false;
IssuePointOrderById(p_u, PatrolOrder.MOVE, xReturn, yReturn);
}
if (GetUnitCurrentOrder(p_u) == null){
isChasing = false;
IssuePointOrderById(p_u, PatrolOrder.MOVE, xReturn, yReturn);
}
}
private static method onTargetAquired() -> boolean{
thistype this = GetUnitId(GetTriggerUnit());
if (!isChasing){
xReturn = GetUnitX(p_u);
yReturn = GetUnitY(p_u);
}
isChasing = true;
TimerStart(clock, INTERVAL, true, function thistype.callback_2);
return false;
}
static method create(unit u, PatrolPath pp, PatrolType pt, PatrolOrder po, real gd, boolean r) -> thistype{
thistype this;
if(integer(pt) < 1 || integer(pt) > 3){
debug BJDebugMsg(thistype.create.name + ": unit with id " + I2S(GetHandleId(u)) + " tries to apply an invalid PatrolType.");
return 0;
}
if(!(po == PatrolOrder.MOVE || po == PatrolOrder.ATTACK)){
debug BJDebugMsg(thistype.create.name + ": unit with id" + I2S(GetHandleId(u)) + " tries to apply an invalid PatrolOrder.");
return 0;
}
if(IsUnitInGroup(u, Group)){
debug BJDebugMsg(thistype.create.name + ": unit with id" + I2S(GetHandleId(u)) + " already is a PatrolUnit.");
return 0;
}
this = GetUnitId(u);
clock = NewTimerEx(this);
p_u = u;
p_order = po;
p_path = pp;
p_patrolType = pt;
p_reverse = r;
p_enabled = true;
p_handler = null;
isChasing = false;
p_guardDistance = gd;
GroupAddUnit(Group, p_u);
if(po == PatrolOrder.ATTACK){
guardHandler = CreateTrigger();
TriggerAddCondition(guardHandler, Condition(function thistype.onTargetAquired));
TriggerRegisterUnitEvent(guardHandler, u, EVENT_UNIT_ACQUIRED_TARGET);
}
if(r){
p_pathPosition = p_path.size()-1;
incrementer = -1;
}
else{
p_pathPosition = 0;
incrementer = 1;
}
TimerStart(clock, INTERVAL, true, function thistype.callback);
return this;
}
method operator patrolType() -> PatrolType{
return p_patrolType;
}
method operator patrolType=(PatrolType p){
if(integer(p) > 0 && integer(p) <= PatrolType.MAXIMUM_AMOUNT){
p_patrolType = p;
}
else{
debug BJDebugMsg("Patrol: operator patrolType=: " + ": instance " + I2S(this) + " tries to apply an invalid PatrolType.");
}
}
method operator reverse() -> boolean{
return p_reverse;
}
method operator reverse=(boolean flag){
if(flag != p_reverse){
incrementer = -incrementer;
p_reverse = flag;
}
}
method operator path() -> PatrolPath{
return p_path;
}
method operator path=(PatrolPath p){
p_path = p;
if(reverse){
p_pathPosition = p_path.size()-1;
incrementer = -1;
}
else{
p_pathPosition = 0;
incrementer = 1;
}
}
method operator unit()-> unit{
return p_u;
}
method operator pathPosition()-> integer{
return p_pathPosition;
}
method operator pathPosition=(integer i){
if (0 <= i && i <= (p_path.size()-1))
p_pathPosition = i;
else
debug BJDebugMsg("Patrol: operator pathPosition=: " + ": instance " + I2S(this) + " tries to apply an invalid pathPosition.");
}
method operator guardDistance() -> real{
return p_guardDistance;
}
method operator guardDistance=(real r){
p_guardDistance = r;
}
method operator order()-> PatrolOrder{
return p_order;
}
method operator order=(PatrolOrder p){
if (p == PatrolOrder.MOVE || p == PatrolOrder.ATTACK){
if(p == PatrolOrder.ATTACK && p_order != p){
guardHandler = CreateTrigger();
TriggerAddCondition(guardHandler, Condition(function thistype.onTargetAquired));
TriggerRegisterUnitEvent(guardHandler, p_u, EVENT_UNIT_ACQUIRED_TARGET);
}
else if(p_order == PatrolOrder.ATTACK && p == PatrolOrder.MOVE){
DestroyTrigger(p_handler);
p_handler = null;
}
p_order = p;
}
else{
debug BJDebugMsg("Patrol: operator order=: " + ": instance " + I2S(this) + " tries to apply an invalid PatrolOrder.");
}
}
method registerPatrolUnit(boolexpr be) -> triggercondition{
if(p_handler == null){
p_handler = CreateTrigger();
}
return TriggerAddCondition(p_handler, be);
}
method unregisterPatrolUnit(triggercondition tc){
TriggerRemoveCondition(p_handler, tc);
}
method operator enabled() -> boolean{
return p_enabled;
}
method operator enabled=(boolean flag){
if(flag && !(p_enabled)){
TimerStart(clock, INTERVAL, true, function thistype.callback);
if(p_order == PatrolOrder.ATTACK){
EnableTrigger(guardHandler);
}
}
else if(!(flag) && p_enabled){
PauseTimer(clock);
if(p_order == PatrolOrder.ATTACK){
DisableTrigger(guardHandler);
}
}
p_enabled = flag;
}
static method operator enabledAll=(boolean flag){
unit fog;
fog = FirstOfGroup(Group);
while(fog != null){
thistype(GetUnitId(fog)).enabled = flag;
GroupAddUnit(Backup,fog);
GroupRemoveUnit(Group,fog);
fog = FirstOfGroup(Group);
}
Temp = Group;
Group = Backup;
Backup = Temp;
}
static method operator[](unit u)-> thistype{
if(!IsUnitInGroup(u, Group)){
debug BJDebugMsg("Patrol: operator []: " + ": unit with id " + I2S(GetHandleId(u)) + " is not a PatrolUnit yet.");
return 0;
}
return GetUnitId(u);
}
static method register(boolexpr be) -> triggercondition{
return TriggerAddCondition(thistype.handler, be);
}
static method unregister(triggercondition tc){
TriggerRemoveCondition(thistype.handler, tc);
}
static method operator currentPatrolUnit()->thistype{
return p_patrolUnit;
}
private static method onDeindex()->boolean{
if (IsUnitInGroup(GetIndexedUnit(), Group)) {
thistype(GetIndexedUnitId()).destroy();
}
return false;
}
private static method onInit(){
OnUnitDeindex(function thistype.onDeindex);
}
}
public function PatrolPathHardDestroy (PatrolPath p){
integer i = p.size() - 1;
while(i >= 0){
p[i].destroy();
i = i - 1;
}
p.destroy();
}
}