#define NAVIGATE_NONE 0 #define NAVIGATION_ZONECHANGED 1 #define NAVIGATION_PLOT 2 #define NAVIGATION_FACING 3 #define NAVIGATION_MOTION 4 #define NAVIGATION_ARRIVED 5 #define NAVIGATION_OBJECTSCAN 6 #define NAVIGATION_GROW_LIMIT 50 #define NAVIGATION_PERCISION 5 #define NAVIGATION_TELEPORT_LIMIT 10 objectdef oNavigate inherits oBase { variable string ConfigDir = "c:/program files/innerspace/scripts/bytebot/etc/" variable string ConfigFile = "map.xml" variable int LastObjectScan = 0 variable point3f FinalDestination variable point3f CurrentDestination variable point3f LastPosition variable lnavregionref CurrentZone variable lnavregionref CurrentRegion variable lnavpath CurrentPath variable int CurrentHop member SubZoneText() { return ${WoWScript[GetMinimapZoneText()]} } member ZoneText() { return ${WoWScript[GetRealZoneText()]} } member Continent() { WoWScript SetMapToCurrentZone() if ${WoWScript[GetMapContinents(),${WoWScript[GetCurrentMapContinent()]}](exists)} { return ${WoWScript[GetMapContinents(),${WoWScript[GetCurrentMapContinent()]}]} } return "Unknown" } method InitializeRegions() { variable string Continent variable int IdxContinent variable string Zone variable int IdxZone This:Echo["Generating empty map file."] LavishNav.Tree:AddChild[universe,Azeroth,-unique] LNavRegion[Azeroth]:AddChild[universe,"Unknown",-unique,-coordinatesystem] IdxContinent:Set[1] do { Continent:Set[${WoWScript[GetMapContinents(),${IdxContinent}]}] LNavRegion[Azeroth]:AddChild[universe,${This.Continent},-unique,-coordinatesystem] IdxZone:Set[1] do { Zone:Set[${WoWScript[GetMapZones(${IdxContinent}),${IdxZone}]}] LNavRegion[${This.Continent}]:AddChild[universe,${Zone},-unique] IdxZone:Inc } while ${WoWScript[GetMapZones(${IdxContinent}),${IdxZone}](exists)} IdxContinent:Inc } while ${WoWScript[GetMapContinents(),${IdxContinent}](exists)} } method Save() { LNavRegion[Azeroth]:Export["${ConfigDir}${ConfigFile}"] } method Load() { variable filepath Dir = "${ConfigDir}" LavishNav:Clear if ${Dir.FileExists[${ConfigFile}]} { if ${LNavRegion[Azeroth](exists)} { LNavRegion[Azeroth]:Remove } LavishNav:Import["${ConfigDir}${ConfigFile}"] } if !${LNavRegion[Azeroth](exists)} { This:InitializeRegions This:Save } } method ZoneChanged() { variable string Region This:Debug["Zone changed to ${This.ZoneText}"] if !${LNavRegion[${This.ZoneText}](exists)} { LNavRegion[${This.Continent}]:AddChild[universe,${This.ZoneText},-unique] } CurrentZone:SetRegion[${LNavRegion[${This.ZoneText}].FQN}] Event[NAVIGATION_ZONECHANGED]:Execute } member Facing() { return ${ISXWoW.Facing} } member Container(float X, float Y, float Z) { variable lnavregionref PointContainer PointContainer:SetRegion[${CurrentZone.NearestChild[${X},${Y},${Z}].FQN}] if ${PointContainer.Type.Equal[point]} { PointContainer:SetRegion[${PointContainer.Parent.FQN}] } return ${PointContainer.FQN} } member NeedPlot() { if ${Me.Flying} || !${Me(exists)} { return FALSE } if ${This.CurrentZone.ID} != ${This.CurrentRegion.ID} { return FALSE } return TRUE } method PlotObject(string ObjectGUID, string GroupName="") { variable objectref TargetObject if !${Object[${ObjectGUID}].GUID(exists)} { return } TargetObject:Set[${ObjectGUID}] This:PlotPoint[${TargetObject.Name},${TargetObject.X},${TargetObject.Y},${TargetObject.Z},${GroupName}] } method PlotPoint(string PointName, float X, float Y, float Z, string GroupName="") { This.CurrentZone:AddChild[point, ${PointName}, -unique, ${X}, ${Y}, ${Z}] if ${GroupName.NotEqual[""]} { LNavRegionGroup[${GroupName}]:Add[${PointName}] } This:Debug["Added ${PointName} X: ${X} Y: ${Y} Z: ${Z}"] } method Plot() { variable point3f C1 variable point3f C2 variable string PointName C1.X:Set[${Me.X}] C1.Y:Set[${Me.Y}] C1.Z:Set[${Math.Calc[${Me.Z} + 0.3]}] C2.X:Set[${Me.X}] C2.Y:Set[${Me.Y}] C2.Z:Set[${Math.Calc[${Me.Z} + 1]}] do { C1.X:Dec C2.X:Inc C1.Y:Dec C2.Y:Inc } while !${This.BoxObstructed[${C1.X},${C1.Y},${C1.Z},${C2.X},${C2.Y},${C2.Z},FALSE]} && ${Math.Distance[${C1.X},${C2.X}]} < NAVIGATION_GROW_LIMIT C1.X:Inc C2.X:Dec C1.Y:Inc C2.Y:Dec C1.Z:Set[${Me.Z} - 1] if ${Math.Distance[${C1.X},${C2.X}]} > 0 { PointName:Set["R${Time.Timestamp}${This.CurrentZone.ChildCount}"] This.CurrentZone:AddChild[box, ${PointName}, -unique, ${C1.X}, ${C2.X}, ${C1.Y}, ${C2.Y}, ${C1.Z}, ${C2.Z}] This:Debug["Added ${PointName} X: ${Math.Distance[${C1.X},${C2.X}]} Y: ${Math.Distance[${C1.Y},${C2.Y}]}"] This:ConnectNeighbours[${PointName}] } } member BoxObstructed(float X1, float Y1, float Z1, float X2, float Y2, float Z2, bool Contents = FALSE) { variable float MiddleX variable float MiddleY if ${Contents} { if ${X1} > ${X2} { MiddleX:Set[${Math.Calc[(${X1} - ${X2}) / 2]}] MiddleX:Set[${Math.Calc[${MiddleX} + ${X2}]}] } else { MiddleX:Set[${Math.Calc[(${X2} - ${X1}) / 2]}] MiddleX:Set[${Math.Calc[${MiddleX} + ${X1}]}] } if ${Y1} > ${Y2} { MiddleY:Set[${Math.Calc[(${Y1} - ${Y2}) / 2]}] MiddleY:Set[${Math.Calc[${MiddleY} + ${Y2}]}] } else { MiddleY:Set[${Math.Calc[(${Y2} - ${Y1}) / 2]}] MiddleY:Set[${Math.Calc[${MiddleY} + ${Y1}]}] } if ${This.CollisionTest[${X1},${Y1},${Z1},${X2},${Y2},${Z2}]} { return TRUE } if ${This.CollisionTest[${X1},${Y2},${Z1},${X2},${Y1},${Z2}]} { return TRUE } if ${This.CollisionTest[${MiddleX},${Y1},${Z1},${MiddleX},${Y2},${Z2}]} { return TRUE } if ${This.CollisionTest[${X1},${MiddleY},${Z1},${X2},${MiddleY},${Z2}]} { return TRUE } } if ${This.CollisionTest[${X1},${Y1},${Z1},${X2},${Y1},${Z2}]} { return TRUE } if ${This.CollisionTest[${X1},${Y2},${Z1},${X2},${Y2},${Z2}]} { return TRUE } if ${This.CollisionTest[${X1},${Y1},${Z1},${X1},${Y2},${Z2}]} { return TRUE } if ${This.CollisionTest[${X2},${Y1},${Z1},${X2},${Y2},${Z2}]} { return TRUE } return FALSE } method ConnectNeighbours(string RegionName) { variable index:lnavregionref SurroundingRegions variable lnavregionref Region variable int RegionsFound variable int Index = 1 Region:SetRegion[${RegionName}] RegionsFound:Set[${CurrentZone.DescendantsWithin[SurroundingRegions,${Math.Calc[(NAVIGATION_GROW_LIMIT) + 5]},${Region.CenterPoint.X},${Region.CenterPoint.Y},${Region.CenterPoint.Z}]}] if ${RegionsFound} > 0 { do { if ${This.ShouldConnect[${Region.FQN},${SurroundingRegions.Get[${Index}].FQN}]} { Region:Connect[${SurroundingRegions.Get[${Index}].FQN}] SurroundingRegions.Get[${Index}]:Connect[${Region.FQN}] This:Debug["Connecting ${Region.FQN} to ${SurroundingRegions.Get[${Index}].FQN}"] } } while ${SurroundingRegions.Get[${Index:Inc}](exists)} } } member ShouldConnect(string RegionA, string RegionB) { variable lnavregionref RegionRefA variable lnavregionref RegionRefB if ${RegionA.Equal[${RegionB}]} { return FALSE } RegionRefA:SetRegion[${RegionA}] RegionRefB:SetRegion[${RegionB}] if ${This.CollisionTest[${RegionRefA.CenterPoint.X}, ${RegionRefA.CenterPoint.Y}, ${RegionRefA.CenterPoint.Z}, ${RegionRefB.CenterPoint.X}, ${RegionRefB.CenterPoint.Y}, ${RegionRefB.CenterPoint.Z}]} { return FALSE } if ${This.RegionsIntersect[${RegionA},${RegionB}]} || ${This.RegionsIntersect[${RegionB},${RegionA}]} { return TRUE } return FALSE } member RegionsIntersect(string RegionA, string RegionB) { variable point3f P1 variable point3f P2 variable point3f P3 variable point3f P4 variable point3f P5 variable point3f P6 variable point3f P7 variable point3f P8 variable lnavregionref RA variable lnavregionref RB RA:SetRegion[${RegionA}] RB:SetRegion[${RegionB}] if ${RA.Type.NotEqual["Box"]} || ${RB.Type.NotEqual["Box"]} { return FALSE } P1.X:Set[${RB.X1}] P1.Y:Set[${RB.Y1}] P1.Z:Set[${RB.Z1}] P2.X:Set[${RB.X2}] P2.Y:Set[${RB.Y1}] P2.Z:Set[${RB.Z1}] P3.X:Set[${RB.X2}] P3.Y:Set[${RB.Y2}] P3.Z:Set[${RB.Z1}] P4.X:Set[${RB.X1}] P4.Y:Set[${RB.Y2}] P4.Z:Set[${RB.Z1}] P5.X:Set[${RB.X1}] P5.Y:Set[${RB.Y1}] P5.Z:Set[${RB.Z2}] P6.X:Set[${RB.X2}] P6.Y:Set[${RB.Y1}] P6.Z:Set[${RB.Z2}] P7.X:Set[${RB.X2}] P7.Y:Set[${RB.Y2}] P7.Z:Set[${RB.Z2}] P8.X:Set[${RB.X1}] P8.Y:Set[${RB.Y2}] P8.Z:Set[${RB.Z2}] if ${RA.Contains[${P1.X},${P1.Y},${P1.Z}]} || ${RA.Contains[${P2.X},${P2.Y},${P2.Z}]} || ${RA.Contains[${P3.X},${P3.Y},${P3.Z}]} || ${RA.Contains[${P4.X},${P4.Y},${P4.Z}]} || ${RA.Contains[${P5.X},${P5.Y},${P5.Z}]} || ${RA.Contains[${P6.X},${P6.Y},${P6.Z}]} || ${RA.Contains[${P7.X},${P7.Y},${P7.Z}]} || ${RA.Contains[${P8.X},${P8.Y},${P8.Z}]} { return TRUE } return FALSE } member DirectionObstructed(float Range) { variable point3f DirectionPoint variable float Z Z:Set[${Math.Calc[${Me.Z} + 0.2]}] DirectionPoint.X:Set[${Math.Cos[${Me.Heading}]} * ${Range}] DirectionPoint.Y:Set[${Math.Cos[${Me.Heading}]} * ${Range}] DirectionPoint.Z:Set[${Z}] return ${This.CollisionTest[${Me.X},${Me.Y},${Z},${DirectionPoint.X},${DirectionPoint.Y},${Z}]} } member CollisionTest(float FromX, float FromY, float FromZ, float ToX, float ToY, float ToZ) { return ${Me.IsPathObstructed[${ToX},${ToY},${ToZ},999,${FromX}, ${FromY}, ${FromZ}]} } method PositionCheck() { if ${Math.Distance[${Me.X},${Me.Y},${Me.Z},${This.LastPosition.X},${This.LastPosition.Y},${This.LastPosition.Z}]} > NAVIGATION_TELEPORT_LIMIT { This:Echo["Teleport detected"] Event[NAVIGATION_TELEPORT]:Execute } } method SavePosition() { This.LastPosition.X:Set[${Me.X}] This.LastPosition.Y:Set[${Me.Y}] This.LastPosition.Z:Set[${Me.Z}] } /* * */ member Arrived() { if ${Math.Distance[${Me.X},${Me.Y},${Me.Z},${This.FinalDestination.X},${This.FinalDestination.Y},${This.FinalDestination.Z}]} <= NAVIGATION_PERCISION { return TRUE } return FALSE } member NeedMotion() { if ${This.FinalDestination.X} == 0 && ${This.FinalDestination.Y} == 0 && ${This.FinalDestination.Z} == 0 { return FALSE } if ${Math.Distance[${Me.X},${Me.Y},${This.FinalDestination.X},${This.FinalDestination.Y}]} > NAVIGATION_PERCISION { return TRUE } return FALSE } method FaceXY(float X, float Y) { Face ${X} ${Y} } member Moving() { if (${Movement.Moving} == 0) { return FALSE } return TRUE } method MoveTo(float X, float Y, float Z) { variable dijkstrapathfinder PathFinder This.FinalDestination.X:Set[${X}] This.FinalDestination.Y:Set[${Y}] This.FinalDestination.Z:Set[${Z}] This:Debug["MoveTo: ${X} ${Y} ${Z}"] if !${This.CurrentRegion.FQN(exists)} { This.CurrentRegion:SetRegion[${This.CurrentZone.BestContainer[${Me.X},${Me.Y},${Me.Z}].ID}] } if ${Math.Distance[${Me.X},${Me.Y},${Me.Z},${X},${Y},${Z}]} < 40 && !${This.CollisionTest[${Me.X}, ${Me.Y}, ${Me.Z}, ${X}, ${Y}, ${Z}]} { ; Just a small distance use direct path This.CurrentDestination.X:Set[${X}] This.CurrentDestination.Y:Set[${Y}] This.CurrentDestination.Z:Set[${Z}] } else { This.CurrentHop:Set[1] This.CurrentPath:Clear PathFinder:SelectPath[${This.CurrentRegion.FQN},${This.Container[${X},${Y},${Z}]},This.CurrentPath] if ${This.CurrentPath.Hops} != 0 { ; We found a path This:Debug["Found path!"] This.CurrentDestination.X:Set[${This.CurrentPath.Region[${This.CurrentHop}].CenterPoint.X}] This.CurrentDestination.Y:Set[${This.CurrentPath.Region[${This.CurrentHop}].CenterPoint.Y}] This.CurrentDestination.Z:Set[${This.CurrentPath.Region[${This.CurrentHop}].CenterPoint.Z}] } else { ; We didn't find a path This:Debug["Direct!"] This.CurrentDestination.X:Set[${X}] This.CurrentDestination.Y:Set[${Y}] This.CurrentDestination.Z:Set[${Z}] } } This:FaceXY[${This.CurrentDestination.X}, ${This.CurrentDestination.Y}] } method Stop() { move -stop } method ResetDestination() { This.FinalDestination.X:Set[0] This.FinalDestination.Y:Set[0] This.FinalDestination.Z:Set[0] This.CurrentHop:Set[1] This:Stop } method CheckMotion() { variable int HeadingDiff if !${This.Moving} && !${Math.Distance[${Me.X},${Me.Y},${Me.Z},${This.CurrentDestination.X},${This.CurrentDestination.Y},${This.CurrentDestination.Z}]} <= NAVIGATION_PERCISION { wowpress -hold moveforward } if ${This.DirectionObstructed[5]} { This:Debug["Going to collide!!!"] ;[FIXME] dynamic collision adjusting } if ${Math.Distance[${Me.X},${Me.Y},${Me.Z},${This.CurrentDestination.X},${This.CurrentDestination.Y},${This.CurrentDestination.Z}]} <= NAVIGATION_PERCISION { This.CurrentHop:Inc if ${This.CurrentPath.Region[${This.CurrentHop}](exists)} { This.CurrentDestination.X:Set[${This.CurrentPath.Region[${This.CurrentHop}].CenterPoint.X}] This.CurrentDestination.Y:Set[${This.CurrentPath.Region[${This.CurrentHop}].CenterPoint.Y}] This.CurrentDestination.Z:Set[${This.CurrentPath.Region[${This.CurrentHop}].CenterPoint.Z}] } if ${This.CurrentHop} >= ${This.CurrentPath.Hops} { This.CurrentDestination.X:Set[${This.FinalDestination.X}] This.CurrentDestination.Y:Set[${This.FinalDestination.Y}] This.CurrentDestination.Z:Set[${This.FinalDestination.Z}] } } HeadingDiff:Set[${Math.Abs[${Me.Heading} - ${Me.HeadingTo[${This.CurrentDestination.X},${This.CurrentDestination.Y}]}]}] if ${HeadingDiff} > 30 && ${Math.Distance[${Me.X},${Me.Y},${Me.Z},${This.CurrentDestination.X},${This.CurrentDestination.Y},${This.CurrentDestination.Z}]} > NAVIGATION_PERCISION { This:FaceXY[${CurrentDestination.X},${CurrentDestination.Y}] } } member RegionExists(string RegionName) { return ${LNavRegion[${RegionName}].FQN(exists)} } method PlotGameObject(string ObjectName, string GroupName="") { if !${This.RegionExists["${ObjectName}"]} && ${Object["${ObjectName}"](exists)} { This:PlotObject[${ObjectName}, ${GroupName}] } } method ObjectScan() { This.LastObjectScan:Set[${LavishScript.RunningTime}] This:PlotGameObject["Silverwing Flag","Warsong Flag"] } /* * */ member State() { if (${This.CurrentZone.ID} != ${LNavRegion[${This.ZoneText}].ID}) { return NAVIGATION_ZONECHANGED } if ${This.NeedPlot} { return NAVIGATION_PLOT } if ${Math.Calc[${LavishScript.RunningTime} - ${This.LastObjectScan}]} > 2000 { return NAVIGATION_OBJECTSCAN } if ${This.Arrived} { return NAVIGATION_ARRIVED } if ${ISXWoW.Facing} { return NAVIGATION_FACING } if ${This.NeedMotion} { return NAVIGATION_MOTION } return NAVIGATE_NONE } method Pulse(int Priority) { if !${Me(exists)} { This:ResetDestination return } This:PositionCheck This:SavePosition This.CurrentState:Set[${This.State}] This.CurrentRegion:SetRegion[${This.CurrentZone.BestContainer[${Me.X},${Me.Y},${Me.Z}].ID}] switch ${This.CurrentState} { case NAVIGATION_ZONECHANGED This:ZoneChanged break case NAVIGATION_FACING break case NAVIGATION_PLOT This:Plot break case NAVIGATION_OBJECTSCAN This:ObjectScan break case NAVIGATION_MOTION This:CheckMotion break case NAVIGATION_ARRIVED This:Debug["Arrived at destination"] This:ResetDestination break case NAVIGATE_NONE break } } method Plugin() { Event[CORE_EVENT_PULSE]:AttachAtom[${This.ObjectName}:Pulse] LavishScript:RegisterEvent[NAVIGATION_PLOTPOINT] LavishScript:RegisterEvent[NAVIGATION_ZONECHANGED] LavishScript:RegisterEvent[NAVIGATION_TELEPORT] LavishScript:RegisterEvent[NAVIGATION_MOVETO] Event[NAVIGATION_PLOTPOINT]:AttachAtom[${This.ObjectName}:PlotPoint] Event[NAVIGATION_MOVETO]:AttachAtom[${This.ObjectName}:MoveTo] } method Initialize() { This:Load This:ZoneChanged This:SavePosition This:ObjectScan } method Shutdown() { Event[CORE_EVENT_PULSE]:DetachAtom[${This.ObjectName}:Pulse] Event[NAVIGATION_PLOTPOINT]:DetachAtom[${This.ObjectName}:PlotPoint] Event[NAVIGATION_ZONECHANGED]:Unregister Event[NAVIGATION_PLOTPOINT]:Unregister Event[NAVIGATION_TELEPORT]:Unregister Event[NAVIGATION_MOVETO]:Unregister This:Save } }