#define NAVIGATION_NONE 0 #define NAVIGATION_ZONE_CHANGED 1 #define NAVIGATION_PLOT 2 #define NAVIGATION_HOP 3 #define NAVIGATION_ARRIVED 4 #define NAVIGATION_DIRECT 0 #define NAVIGATION_MAP 1 #define NAVIGATION_GROW_LIMIT 50 #define NAVIGATION_GROW_Z_LIMIT 2 /* * Events: * REGION_ADDED [regionname] */ objectdef oNavigation inherits oBase { variable string ConfigDir = "c:/program files/innerspace/scripts/etc/" variable string ConfigFile = "map.xml" variable int CurrentState = 0 variable int PreviousState = 0 variable int NavigationStart variable int CurrentMethod variable int CurrentHop variable lnavpath CurrentPath variable lnavregionref CurrentZone variable lnavregionref CurrentRegion variable point3f CurrentDestination variable lnavregionref PreviousRegion 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 "Instance" } method InitializeRegions() { variable string Continent variable int IdxContinent variable string Zone variable int IdxZone LavishNav.Tree:AddChild[universe,Azeroth,-unique] LNavRegion[Azeroth]:AddChild[universe,"Instance",-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}] } /* * */ member Arrived() { switch ${This.CurrentMethod} { case NAVIGATION_MAP if ${This.CurrentHop} < ${This.CurrentPath.Hops} { return FALSE } break case NAVIGATION_DIRECT if ${Math.Distance[${Me.X},${Me.Y},${Me.Z},${This.CurrentDestination.X},${This.CurrentDestination.Y},${This.CurrentDestination.Z}]} < 5 { return FALSE } break } return TRUE } member State() { if (${This.CurrentZone.ID} != ${LNavRegion[${This.ZoneText}].ID}) { return NAVIGATION_ZONE_CHANGED } if (${This.CurrentZone.ID} == ${This.CurrentRegion.ID}) { return NAVIGATION_PLOT } if !${This.Arrived} && !${Motion.NeedMotion} { return NAVIGATION_HOP } else { return NAVIGATION_ARRIVED } return NAVIGATION_NONE } method Pulse() { This.PreviousRegion:SetRegion[${This.CurrentRegion.ID}] This.CurrentRegion:SetRegion[${This.CurrentZone.BestContainer[${Me.X},${Me.Y},${Me.Z}].ID}] This.CurrentState:Set[${This.State}] if ${This.CurrentState} != ${This.PreviousState} { This.PreviousState:Set[${CurrentState}] This:OnStateChange } switch ${This.CurrentState} { case NAVIGATION_ZONE_CHANGED This:ZoneChanged break case NAVIGATION_PLOT This:PlotBox break case NAVIGATION_HOP This:MakeHop break case NAVIGATION_ARRIVED This:OnArrived break case NAVIGATION_NONE break } This:MapObjects } method OnStateChange() { } method OnArrived() { } /* * Mapping stuff */ member IsMapped(float X, float Y, float Z) { variable lnavregionref Container Container:SetRegion[${This.CurrentZone.BestContainer[${X},${Y},${Z}].FQN}] if !${Container.Contains[${X},${Y},${Z}]} { return FALSE } return TRUE } method MapObject(string ObjectName, string GroupName) { variable objectref Obj if !${Object[${ObjectName}](exists)} { return } Obj:Set[${Object[${ObjectName}].GUID}] if !${LNavRegion[${ObjectName}].FQN(exists)} { if !${This.IsMapped[${Obj.X},${Obj.Y},${Obj.Z}]} { This:Debug["Found ${ObjectName} but could not map it since ground has not been discovered yet."] return } This:PlotPoint["${ObjectName}",${Obj.X},${Obj.Y},${Obj.Z}] LNavRegionGroup[${GroupName}]:Add[${ObjectName}] } } method MapObjects() { This:MapObject[Silverwing Flag,"Warsong Gulch Flag"] This:MapObject[Warsong Flag,"Warsong Gulch Flag"] } method PlotPoint(string PointName, float X, float Y, float Z) { CurrentZone:AddChild[point,${PointName},-unique,${X},${Y},${Z}] Event["REGION_ADDED"]:Execute[${PointName}] This:Debug["Region added (${PointName}@${CurrentZone.FQN}) (X: ${X} Y: ${Y} Z: ${Z})"] } method PlotBox() { variable float X1 variable float X2 variable float Y1 variable float Y2 variable float Z1 variable float Z2 variable string RegionName X1:Set[${Me.X}] X2:Set[${Me.X}] Y1:Set[${Me.Y}] Y2:Set[${Me.Y}] Z1:Set[${Math.Calc[${Me.Z} + 0.2]}] Z2:Set[${Math.Calc[${Me.Z} + 0.4]}] do { X1:Dec X2:Inc Y1:Dec Y2:Inc } while ${This.IsCollisionFree[${X1},${Y1},${X2},${Y2},${Z1},FALSE]} && ${Math.Distance[${Me.X},${X1}]} < NAVIGATION_GROW_LIMIT do { Z1:Dec } while ${This.IsCollisionFree[${X1},${Y1},${X2},${Y2},${Z1},FALSE]} && ${Math.Distance[${Me.Z},${Z1}]} < NAVIGATION_GROW_Z_LIMIT do { Z2:Inc } while ${This.IsCollisionFree[${X1},${Y1},${X2},${Y2},${Z2},FALSE]} && ${Math.Distance[${Me.Z},${Z2}]} < NAVIGATION_GROW_Z_LIMIT Z1:Set[${Math.Calc[${Z1} - 0.5]}] Z2:Set[${Math.Calc[${Z2} + 0.5]}] RegionName:Set["R${Time.Timestamp}${CurrentZone.ChildCount}"] CurrentZone:AddChild[box,${RegionName},-unique,${X1},${X2},${Y1},${Y2},${Z1},${Z2}] This:Debug["Region added (${RegionName}@${CurrentZone.FQN}) (X: ${Math.Distance[${X1}, ${X2}]}, Y: ${Math.Distance[${Y1},${Y2}]}, Z: ${Math.Distance[${Z1},${Z2}]})"] Event["REGION_ADDED"]:Execute[${RegionName}] This:ConnectNeighbours[${RegionName}] } 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 * 2) + 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 IsCollisionFree(float X1, float Y1, float X2, float Y2, float Z, bool Contents=TRUE) { 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},${Z},${X2},${Y2},${Z}]} { return FALSE } if ${This.CollisionTest[${X1},${Y2},${Z},${X2},${Y1},${Z}]} { return FALSE } if ${This.CollisionTest[${MiddleX},${Y1},${Z},${MiddleX},${Y2},${Z}]} { return FALSE } if ${This.CollisionTest[${X1},${MiddleY},${Z},${X2},${MiddleY},${Z}]} { return FALSE } } if ${This.CollisionTest[${X1},${Y1},${Z},${X2},${Y1},${Z}]} { return FALSE } if ${This.CollisionTest[${X1},${Y2},${Z},${X2},${Y2},${Z}]} { return FALSE } if ${This.CollisionTest[${X1},${Y1},${Z},${X1},${Y2},${Z}]} { return FALSE } if ${This.CollisionTest[${X2},${Y1},${Z},${X2},${Y2},${Z}]} { return FALSE } return TRUE } member CollisionTest(float FromX, float FromY, float FromZ, float ToX, float ToY, float ToZ) { return ${Me.IsPathObstructed[${ToX},${ToY},${ToZ},999,${FromX}, ${FromY}, ${FromZ}]} } /* * Pathfinding */ member NearestRegion(float X, float Y, float Z) { return ${This.CurrentZone.NearestChild[${X},${Y},${Z}].FQN} } member FindPath(float X, float Y, float Z) { variable lnavregionref DestinationRegion variable dijkstrapathfinder PathFinder This.CurrentHop:Set[1] This.CurrentDestination.X:Set[${X}] This.CurrentDestination.Y:Set[${Y}] This.CurrentDestination.Z:Set[${Z}] This.CurrentPath:Clear DestinationRegion:SetRegion[${This.NearestRegion[${X},${Y},${Z}]}] PathFinder:SelectPath[${This.CurrentRegion.FQN},${DestinationRegion.FQN},This.CurrentPath] if (${This.CurrentPath.Hops} == 0) { return FALSE } return TRUE } method NavigateTo(float X, float Y, float Z) { This.NavigationStart:Set[${LavishScript.RunningTime}] if !${This.FindPath[${X},${Y},${Z}]} { This.CurrentMethod:Set[NAVIGATION_DIRECT] This:Debug["Navigating to ${X} ${Y} ${Z} using direct path."] } else { This.CurrentMethod:Set[NAVIGATION_MAP] This:Debug["Navigating to ${X} ${Y} ${Z} using navigation map."] } Motion:MoveTo[${CurrentDestination.X},${CurrentDestination.Y},${CurrentDestination.Z}] } method MakeHop() { variable point3f DestinationPoint switch ${This.CurrentMethod} { case NAVIGATION_MAP ;FIXME! Randomize region movement since we use ffm region DestinationPoint.X:Set[${This.CurrentPath.Region[${This.CurrentHop}].CenterPoint.X}] DestinationPoint.Y:Set[${This.CurrentPath.Region[${This.CurrentHop}].CenterPoint.Y}] DestinationPoint.Z:Set[${This.CurrentPath.Region[${This.CurrentHop}].CenterPoint.Z}] This.CurrentHop:Inc break case NAVIGATION_DIRECT DestinationPoint.X:Set[${This.CurrentDestination.X}] DestinationPoint.Y:Set[${This.CurrentDestination.Y}] DestinationPoint.Z:Set[${This.CurrentDestination.Z}] break } ;FIXME! Moveto DestinationPoint Motion:MoveTo[${DestinationPoint.X},${DestinationPoint.Y},${DestinationPoint.Z}] } /* * */ method Initialize() { LavishScript:RegisterEvent["REGION_ADDED"] This:Load This:ZoneChanged } method Shutdown() { Event["REGION_ADDED"]:Unregister This:Save } }