From 07c24d0437963e62a6f102005a6a0c7bd619107f Mon Sep 17 00:00:00 2001
From: Melinda Green <melinda@lindenlab.com>
Date: Wed, 19 Sep 2007 21:28:44 +0000
Subject: [PATCH] Passed QA, merging minifriends-3:70006 back to release

---
 etc/message.xml                       |   2 +-
 indra/newview/lleventpoll.cpp         |   3 +-
 indra/newview/llnetmap.cpp            |  16 +-
 indra/newview/llpanelavatar.cpp       |  16 +-
 indra/newview/llviewerregion.cpp      |  83 +++++
 indra/newview/llviewerregion.h        |   7 +
 indra/newview/llworldmapview.cpp      | 428 +++++++++-----------------
 indra/newview/llworldmapview.h        |   5 +-
 scripts/messages/message_template.msg |   2 +-
 9 files changed, 271 insertions(+), 291 deletions(-)

diff --git a/etc/message.xml b/etc/message.xml
index 85b1aac99cb..614d2b02717 100644
--- a/etc/message.xml
+++ b/etc/message.xml
@@ -255,7 +255,7 @@
 				<key>CoarseLocationUpdate</key>
 				<map>
 				    <key>flavor</key>
-					<string>template</string>
+					<string>llsd</string>
 					<key>trusted-sender</key>
 					<boolean>true</boolean>
 				</map>
diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp
index 8c362a0ac50..fe595c0920a 100644
--- a/indra/newview/lleventpoll.cpp
+++ b/indra/newview/lleventpoll.cpp
@@ -151,7 +151,8 @@ namespace
 			llwarns << "LLEventPollResponder: id undefined" << llendl;
 		}
 		
-		llinfos  << "LLEventPollResponder::completed <" <<	mCount << "> " << events.size() << "events (id "
+		// was llinfos but now that CoarseRegionUpdate is TCP @ 1/second, it'd be too verbose for viewer logs. -MG
+		lldebugs  << "LLEventPollResponder::completed <" <<	mCount << "> " << events.size() << "events (id "
 				 <<	LLSDXMLStreamer(mAcknowledge) << ")" << llendl;
 		
 		LLSD::array_const_iterator i = events.beginArray();
diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp
index 754c0962969..ffb3bad2aa7 100644
--- a/indra/newview/llnetmap.cpp
+++ b/indra/newview/llnetmap.cpp
@@ -29,11 +29,13 @@
 #include "llstatgraph.h"
 #include "llsurface.h"
 #include "lltextbox.h"
+#include "lluuid.h"
 #include "llviewercamera.h"
 #include "llviewerimage.h"
 #include "llviewerimagelist.h"
 #include "llviewermenu.h"
 #include "llviewerobjectlist.h"
+#include "llviewermenu.h"
 #include "llviewerparceloverlay.h"
 #include "llviewerregion.h"
 #include "llviewerwindow.h"
@@ -381,6 +383,8 @@ void LLNetMap::draw()
 			LLVector3 pos_local;
 			U32 compact_local;
 			U8 bits;
+			// TODO: it'd be very cool to draw these in sorted order from lowest Z to highest.
+			// just be careful to sort the avatar IDs along with the positions. -MG
 			for (i = 0; i < count; i++)
 			{
 				compact_local = regionp->mMapAvatars.get(i);
@@ -400,9 +404,15 @@ void LLNetMap::draw()
 				pos_global += origin_global;
 
 				pos_map = globalPosToView(pos_global);
-				LLWorldMapView::drawAvatar(pos_map.mV[VX], pos_map.mV[VY], 
-												gAvatarMapColor,
-												pos_map.mV[VZ]);
+
+				LLUUID avatar_id = regionp->mMapAvatarIDs.get(i);
+				BOOL show_as_friend = 
+					//is_agent_mappable(avatar_id); // if we're only highlighting mappable friends
+					is_agent_friend(avatar_id); // if we're always highlighting friends
+				LLWorldMapView::drawAvatar(
+					pos_map.mV[VX], pos_map.mV[VY], 
+					show_as_friend ? gFriendMapColor : gAvatarMapColor, 
+					pos_map.mV[VZ]);
 			}
 		}
 
diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp
index e0f19c10d1d..d4ce206b2be 100644
--- a/indra/newview/llpanelavatar.cpp
+++ b/indra/newview/llpanelavatar.cpp
@@ -446,7 +446,7 @@ BOOL LLPanelAvatarSecondLife::postBuild(void)
 	childSetVisible("online_unknown",FALSE);
 	childSetVisible("online_no",FALSE);
 
-	childSetAction("Show on Map", LLPanelAvatar::onClickTrack, getPanelAvatar());
+	childSetAction("Find on Map", LLPanelAvatar::onClickTrack, getPanelAvatar());
 	childSetAction("Instant Message...", LLPanelAvatar::onClickIM, getPanelAvatar());
 	
 	childSetAction("Add Friend...", LLPanelAvatar::onClickAddFriend, getPanelAvatar());
@@ -1475,8 +1475,8 @@ void LLPanelAvatar::setAvatarID(const LLUUID &avatar_id, const LLString &name,
 			childSetEnabled("Offer Teleport...",FALSE);
 			childSetVisible("drop target",FALSE);
 			childSetEnabled("drop target",FALSE);
-			childSetVisible("Show on Map",FALSE);
-			childSetEnabled("Show on Map",FALSE);
+			childSetVisible("Find on Map",FALSE);
+			childSetEnabled("Find on Map",FALSE);
 			childSetVisible("Add Friend...",FALSE);
 			childSetEnabled("Add Friend...",FALSE);
 			childSetVisible("Pay...",FALSE);
@@ -1499,21 +1499,21 @@ void LLPanelAvatar::setAvatarID(const LLUUID &avatar_id, const LLString &name,
 			childSetVisible("drop target",TRUE);
 			childSetEnabled("drop target",FALSE);
 
-			childSetVisible("Show on Map",TRUE);
+			childSetVisible("Find on Map",TRUE);
 			// Note: we don't always know online status, so always allow gods to try to track
 			BOOL enable_track = gAgent.isGodlike() || is_agent_mappable(mAvatarID);
-			childSetEnabled("Show on Map",enable_track);
+			childSetEnabled("Find on Map",enable_track);
 			if (!mIsFriend)
 			{
-				childSetToolTip("Show on Map",childGetValue("ShowOnMapNonFriend").asString());
+				childSetToolTip("Find on Map",childGetValue("ShowOnMapNonFriend").asString());
 			}
 			else if (ONLINE_STATUS_YES != online_status)
 			{
-				childSetToolTip("Show on Map",childGetValue("ShowOnMapFriendOffline").asString());
+				childSetToolTip("Find on Map",childGetValue("ShowOnMapFriendOffline").asString());
 			}
 			else
 			{
-				childSetToolTip("Show on Map",childGetValue("ShowOnMapFriendOnline").asString());
+				childSetToolTip("Find on Map",childGetValue("ShowOnMapFriendOnline").asString());
 			}
 			childSetVisible("Add Friend...", true);
 			childSetEnabled("Add Friend...", !avatar_is_friend);
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 8f2362015bb..39c90feca8e 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -31,6 +31,7 @@
 #include "llfloaterregioninfo.h"
 #include "llhttpnode.h"
 #include "llnetmap.h"
+#include "llsdutil.h"
 #include "llstartup.h"
 #include "llviewerobjectlist.h"
 #include "llviewerparceloverlay.h"
@@ -805,6 +806,88 @@ BOOL LLViewerRegion::isOwnedGroup(const LLVector3& pos)
 	}
 }
 
+// the new TCP coarse location handler node
+class CoarseLocationUpdate : public LLHTTPNode
+{
+public:
+	virtual void post(
+		ResponsePtr responder,
+		const LLSD& context,
+		const LLSD& input) const
+	{
+		LLHost host(input["sender"].asString());
+		LLViewerRegion* region = gWorldp->getRegion(host);
+		if( !region )
+		{
+			return;
+		}
+
+		S32 target_index = input["body"]["Index"][0]["Prey"].asInteger();
+		S32 you_index    = input["body"]["Index"][0]["You" ].asInteger();
+
+		LLDynamicArray<U32>* avatar_locs = &region->mMapAvatars;
+		LLDynamicArray<LLUUID>* avatar_ids = &region->mMapAvatarIDs;
+		avatar_locs->reset();
+		avatar_ids->reset();
+
+		//llinfos << "coarse locations agent[0] " << input["body"]["AgentData"][0]["AgentID"].asUUID() << llendl;
+		//llinfos << "my agent id = " << gAgent.getID() << llendl;
+		//llinfos << ll_pretty_print_sd(input) << llendl;
+
+		LLSD 
+			locs   = input["body"]["Location"],
+			agents = input["body"]["AgentData"];
+		LLSD::array_iterator 
+			locs_it = locs.beginArray(), 
+			agents_it = agents.beginArray();
+		BOOL has_agent_data = input["body"].has("AgentData");
+
+		for(int i=0; 
+			locs_it != locs.endArray(); 
+			i++, locs_it++, agents_it++)
+		{
+			U8 
+				x = locs_it->get("X").asInteger(),
+				y = locs_it->get("Y").asInteger(),
+				z = locs_it->get("Z").asInteger();
+			// treat the target specially for the map, and don't add you or the target
+			if(i == target_index)
+			{
+				LLVector3d global_pos(region->getOriginGlobal());
+				global_pos.mdV[VX] += (F64)x;
+				global_pos.mdV[VY] += (F64)y;
+				global_pos.mdV[VZ] += (F64)z * 4.0;
+				LLAvatarTracker::instance().setTrackedCoarseLocation(global_pos);
+			}
+			else if( i != you_index)
+			{
+				U32 loc = x << 16 | y << 8 | z; loc = loc;
+				U32 pos = 0x0;
+				pos |= x;
+				pos <<= 8;
+				pos |= y;
+				pos <<= 8;
+				pos |= z;
+				avatar_locs->put(pos);
+				//llinfos << "next pos: " << x << "," << y << "," << z << ": " << pos << llendl;
+				if(has_agent_data) // for backwards compatibility with old message format
+				{
+					LLUUID agent_id(agents_it->get("AgentID").asUUID());
+					//llinfos << "next agent: " << agent_id.asString() << llendl;
+					avatar_ids->put(agent_id);
+				}
+			}
+		}
+	}
+};
+
+// build the coarse location HTTP node under the "/message" URL
+LLHTTPRegistration<CoarseLocationUpdate>
+   gHTTPRegistrationCoarseLocationUpdate(
+	   "/message/CoarseLocationUpdate");
+
+
+// the deprecated coarse location handler
 void LLViewerRegion::updateCoarseLocations(LLMessageSystem* msg)
 {
 	//llinfos << "CoarseLocationUpdate" << llendl;
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index ec36c0bd0b1..f2883c8f4ed 100644
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -242,7 +242,13 @@ class LLViewerRegion
 	LLStat	mPacketsStat;
 	LLStat	mPacketsLostStat;
 
+	// These arrays are maintained in parallel. Ideally they'd be combined into a
+	// single array of an aggrigate data type but for compatibility with the old
+	// messaging system in which the previous message only sends and parses the 
+	// positions stored in the first array so they're maintained separately until 
+	// we stop supporting the old CoarseLocationUpdate message.
 	LLDynamicArray<U32> mMapAvatars;
+	LLDynamicArray<LLUUID> mMapAvatarIDs;
 
 protected:
 	// The surfaces and other layers
@@ -368,3 +374,4 @@ inline BOOL LLViewerRegion::getRestrictPushObject() const
 
 #endif
 
+
diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp
index ab95b9eda6d..ab96dac5e9d 100644
--- a/indra/newview/llworldmapview.cpp
+++ b/indra/newview/llworldmapview.cpp
@@ -32,6 +32,7 @@
 #include "llviewercamera.h"
 #include "llviewerimage.h"
 #include "llviewerimagelist.h"
+#include "llviewermenu.h"
 #include "llviewerparceloverlay.h"
 #include "llviewerregion.h"
 #include "llviewerwindow.h"
@@ -49,6 +50,8 @@ BOOL LLWorldMapView::sHandledLastClick = FALSE;
 LLPointer<LLViewerImage> LLWorldMapView::sAvatarYouSmallImage = NULL;
 LLPointer<LLViewerImage> LLWorldMapView::sAvatarSmallImage = NULL;
 LLPointer<LLViewerImage> LLWorldMapView::sAvatarLargeImage = NULL;
+LLPointer<LLViewerImage> LLWorldMapView::sAvatarAboveImage = NULL;
+LLPointer<LLViewerImage> LLWorldMapView::sAvatarBelowImage = NULL;
 
 LLPointer<LLViewerImage> LLWorldMapView::sTelehubImage = NULL;
 LLPointer<LLViewerImage> LLWorldMapView::sInfohubImage = NULL;
@@ -87,6 +90,12 @@ void LLWorldMapView::initClass()
 	image_id.set( gViewerArt.getString("map_avatar_16.tga") );
 	sAvatarLargeImage = gImageList.getImage( image_id, MIPMAP_FALSE, TRUE);
 
+	image_id.set( gViewerArt.getString("map_avatar_above_8.tga") );
+	sAvatarAboveImage = gImageList.getImage( image_id, MIPMAP_FALSE, TRUE);
+
+	image_id.set( gViewerArt.getString("map_avatar_below_8.tga") );
+	sAvatarBelowImage = gImageList.getImage( image_id, MIPMAP_FALSE, TRUE);
+
 	image_id.set( gViewerArt.getString("map_home.tga") );
 	sHomeImage = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE);
 
@@ -127,6 +136,8 @@ void LLWorldMapView::cleanupClass()
 	sAvatarYouSmallImage = NULL;
 	sAvatarSmallImage = NULL;
 	sAvatarLargeImage = NULL;
+	sAvatarAboveImage = NULL;
+	sAvatarBelowImage = NULL;
 	sTelehubImage = NULL;
 	sInfohubImage = NULL;
 	sHomeImage = NULL;
@@ -254,18 +265,16 @@ void LLWorldMapView::setPan( S32 x, S32 y, BOOL snap )
 
 
 ///////////////////////////////////////////////////////////////////////////////////
+// HELPERS
 
-// dumb helper function
 BOOL is_agent_in_region(LLViewerRegion* region, LLSimInfo* info)
 {
-	if((region && info)
-	   && (info->mName == region->getName()))
-	{
-		return TRUE;
-	}
-	return FALSE;
+	return ((region && info) && (info->mName == region->getName()));
 }
 
+
+///////////////////////////////////////////////////////////////////////////////////
+
 void LLWorldMapView::draw()
 {
 	if (!getVisible() || !gWorldPointer)
@@ -283,9 +292,6 @@ void LLWorldMapView::draw()
 	sPanX = lerp(sPanX, sTargetPanX, LLCriticalDamp::getInterpolant(0.1f));
 	sPanY = lerp(sPanY, sTargetPanY, LLCriticalDamp::getInterpolant(0.1f));
 
-	LLVector3d pos_global;
-	LLVector3 pos_map;
-
 	const S32 width = mRect.getWidth();
 	const S32 height = mRect.getHeight();
 	const S32 half_width = width / 2;
@@ -665,56 +671,24 @@ void LLWorldMapView::draw()
 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
 	// Infohubs
-	// Draw under avatar so you can find yourself.
 	if (gSavedSettings.getBOOL("MapShowInfohubs"))   //(gMapScale >= sThresholdB)
 	{
-		S32 infohub_icon_size = (S32)sInfohubImage->getWidth();
-		for (U32 infohub=0; infohub<gWorldMap->mInfohubs.size(); ++infohub)
-		{
-			LLItemInfo *infohub_info = &gWorldMap->mInfohubs[infohub];
-
-			pos_map = globalPosToView(infohub_info->mPosGlobal);
-			gl_draw_image(llround(pos_map.mV[VX])-infohub_icon_size/2,
-							llround(pos_map.mV[VY])-infohub_icon_size/2,
-							sInfohubImage,
-							LLColor4::white);
-		}
+		drawGenericItems(gWorldMap->mInfohubs, sInfohubImage);
 	}
 
 	// Telehubs
-	// Draw under avatar so you can find yourself.
 	if (gSavedSettings.getBOOL("MapShowTelehubs"))   //(gMapScale >= sThresholdB)
 	{
-		S32 telehub_icon_size = (S32)sTelehubImage->getWidth();
-		for (U32 telehub=0; telehub<gWorldMap->mTelehubs.size(); ++telehub)
-		{
-			LLItemInfo *telehub_info = &gWorldMap->mTelehubs[telehub];
-
-			pos_map = globalPosToView(telehub_info->mPosGlobal);
-			gl_draw_image(llround(pos_map.mV[VX])-telehub_icon_size/2,
-					llround(pos_map.mV[VY])-telehub_icon_size/2,
-					sTelehubImage,
-					LLColor4::white);
-		}
+		drawGenericItems(gWorldMap->mTelehubs, sTelehubImage);
 	}
 
-	// Home
-	// Always Draw
-	if (1)   //(gMapScale >= sThresholdB)
+	// Home Sweet Home
+	LLVector3d home;
+	if (gAgent.getHomePosGlobal(&home))
 	{
-		S32 home_icon_size = (S32)sHomeImage->getWidth();
-		if (gAgent.getHomePosGlobal(&pos_global))
-		{
-			pos_map = globalPosToView(pos_global);
-			gl_draw_image(llround(pos_map.mV[VX])-home_icon_size/2,
-						  llround(pos_map.mV[VY])-home_icon_size/2,
-						  sHomeImage,
-						  LLColor4::white);
-		}
+		drawImage(home, sHomeImage);
 	}
 
-	// Draw all these under the avatar, so you can find yourself
-
 	if (gSavedSettings.getBOOL("MapShowLandForSale"))
 	{
 		drawGenericItems(gWorldMap->mLandForSale, sForSaleImage);
@@ -735,15 +709,11 @@ void LLWorldMapView::draw()
 		drawEvents();
 	}
 
-	// Your avatar.
-	// Draw avatar position, always, and underneath other avatars
-	pos_global = gAgent.getPositionGlobal();
-	pos_map = globalPosToView(pos_global);
-	gl_draw_image(llround(pos_map.mV[VX])-8,
-				  llround(pos_map.mV[VY])-8,
-				  sAvatarLargeImage,
-				  LLColor4::white);
+	// Now draw your avatar after all that other stuff.
+	LLVector3d pos_global = gAgent.getPositionGlobal();
+	drawImage(pos_global, sAvatarLargeImage);
 
+	LLVector3 pos_map = globalPosToView(pos_global);
 	if (!pointInView(llround(pos_map.mV[VX]), llround(pos_map.mV[VY])))
 	{
 		drawTracking(pos_global, 
@@ -754,17 +724,16 @@ void LLWorldMapView::draw()
 			llround(LLFontGL::sSansSerifSmall->getLineHeight())); // offset vertically by one line, to avoid overlap with target tracking
 	}
 
+	// Show your viewing angle
 	drawFrustum();
 
 	// Draw icons for the avatars in each region.
-	// Draw after avatar so you can see nearby people.
+	// Drawn after your avatar so you can see nearby people.
 	if (gSavedSettings.getBOOL("MapShowPeople"))
 	{
 		drawAgents();
 	}
 
-	//-----------------------------------------------------------------------
-
 	// Always draw tracking information
 	LLTracker::ETrackingStatus tracking_status = LLTracker::getTrackingStatus();
 	if ( LLTracker::TRACKING_AVATAR == tracking_status )
@@ -808,7 +777,8 @@ void LLWorldMapView::draw()
 	LLView::draw();
 
 	updateVisibleBlocks();
-}
+} // end draw()
+
 
 //virtual
 void LLWorldMapView::setVisible(BOOL visible)
@@ -848,29 +818,40 @@ void LLWorldMapView::drawGenericItems(const LLWorldMap::item_info_list_t& items,
 	LLWorldMap::item_info_list_t::const_iterator e;
 	for (e = items.begin(); e != items.end(); ++e)
 	{
-		const LLItemInfo& info = *e;
-
-		drawGenericItem(info, image);
+		drawGenericItem(*e, image);
 	}
 }
 
 void LLWorldMapView::drawGenericItem(const LLItemInfo& item, LLPointer<LLViewerImage> image)
 {
-	S32 half_width  = image->getWidth()/2;
-	S32 half_height = image->getHeight()/2;
-
-	LLVector3 pos_map = globalPosToView( item.mPosGlobal );
-	gl_draw_image(llround(pos_map.mV[VX]) - half_width,
-					llround(pos_map.mV[VY]) - half_height,
-					image,
-					LLColor4::white);				
+	drawImage(item.mPosGlobal, image);
 }
 
-void LLWorldMapView::drawAgents()
+
+void LLWorldMapView::drawImage(const LLVector3d& global_pos, LLPointer<LLViewerImage> image, const LLColor4& color)
+{
+	LLVector3 pos_map = globalPosToView( global_pos );
+	gl_draw_image(llround(pos_map.mV[VX] - image->getWidth() /2.f),
+				  llround(pos_map.mV[VY] - image->getHeight()/2.f),
+				  image,
+				  color);
+}
+
+void LLWorldMapView::drawImageStack(const LLVector3d& global_pos, LLPointer<LLViewerImage> image, U32 count, F32 offset, const LLColor4& color)
 {
-	//S32 half_width  = sPopularImage->getWidth()/2;
-	//S32 half_height = sPopularImage->getHeight()/2;
+	LLVector3 pos_map = globalPosToView( global_pos );
+	for(U32 i=0; i<count; i++)
+	{
+		gl_draw_image(llround(pos_map.mV[VX] - image->getWidth() /2.f),
+					  llround(pos_map.mV[VY] - image->getHeight()/2.f + i*offset),
+					  image,
+					  color);
+	}
+}
+
 
+void LLWorldMapView::drawAgents()
+{
 	F32 agents_scale = (gMapScale * 0.9f) / 256.f;
 
 	for (handle_list_t::iterator iter = mVisibleRegions.begin(); iter != mVisibleRegions.end(); ++iter)
@@ -881,32 +862,20 @@ void LLWorldMapView::drawAgents()
 		{
 			continue;
 		}
-		LLWorldMap::agent_list_map_t::iterator countsiter = gWorldMap->mAgentLocationsMap.find(handle);
-		if (siminfo && siminfo->mShowAgentLocations && countsiter != gWorldMap->mAgentLocationsMap.end())
+		LLWorldMap::agent_list_map_t::iterator counts_iter = gWorldMap->mAgentLocationsMap.find(handle);
+		if (siminfo && siminfo->mShowAgentLocations && counts_iter != gWorldMap->mAgentLocationsMap.end())
 		{
-			// Show Individual agents
-			LLWorldMap::item_info_list_t& agentcounts = countsiter->second;
+			// Show Individual agents (or little stacks where real agents are)
+			LLWorldMap::item_info_list_t& agentcounts = counts_iter->second;
 			S32 sim_agent_count = 0;
 			for (LLWorldMap::item_info_list_t::iterator iter = agentcounts.begin();
 				 iter != agentcounts.end(); ++iter)
 			{
 				const LLItemInfo& info = *iter;
-				LLVector3 pos_map = globalPosToView( info.mPosGlobal );
 				S32 agent_count = info.mExtra;
-				if (agent_count > 0)
-				{
-					sim_agent_count += agent_count;
-					F32 y = 0;
-					for (S32 cur_agent = 0; cur_agent < agent_count; cur_agent++)
-					{
-						gl_draw_image(llround(pos_map.mV[VX]) - 4,
-									  llround(pos_map.mV[VY] + y) - 4,
-									  sAvatarSmallImage,
-									  LLColor4::white );
-						// move up a bit
-						y += 3.f;
-					}
-				}
+				// Here's how we'd choose the color if info.mID were available but it's not being sent:
+				//LLColor4 color = (agent_count == 1 && is_agent_friend(info.mID)) ? gFriendMapColor : gAvatarMapColor;
+				drawImageStack(info.mPosGlobal, sAvatarSmallImage, agent_count, 3.f, gAvatarMapColor);
 			}
 			gWorldMap->mNumAgents[handle] = sim_agent_count; // override mNumAgents for this sim
 		}
@@ -916,24 +885,12 @@ void LLWorldMapView::drawAgents()
 			S32 num_agents = gWorldMap->mNumAgents[handle];
 			if (num_agents > 0)
 			{
-				LLVector3d region_pos = from_region_handle(handle);
-				region_pos[VX] += REGION_WIDTH_METERS * .5f;
-				region_pos[VY] += REGION_WIDTH_METERS * .5f;
-				LLVector3 pos_map = globalPosToView(region_pos);
+				LLVector3d region_center = from_region_handle(handle);
+				region_center[VX] += REGION_WIDTH_METERS / 2;
+				region_center[VY] += REGION_WIDTH_METERS / 2;
 				// Reduce the stack size as you zoom out - always display at lease one agent where there is one or more
 				S32 agent_count = (S32)(((num_agents-1) * agents_scale + (num_agents-1) * 0.1f)+.1f) + 1;
-				S32 y = 0;
-				S32 cur_agent;
-				for (cur_agent = 0; cur_agent < agent_count; cur_agent++)
-				{
-					gl_draw_image(
-						llround(pos_map.mV[VX]) - 4,
-						llround(pos_map.mV[VY]) + y - 4,
-						sAvatarSmallImage,
-						LLColor4::white );
-					// move up a bit
-					y += 3;
-				}
+				drawImageStack(region_center, sAvatarSmallImage, agent_count, 3.f, gAvatarMapColor);
 			}
 		}
 	}
@@ -942,95 +899,46 @@ void LLWorldMapView::drawAgents()
 
 void LLWorldMapView::drawEvents()
 {
-	BOOL show_mature = gSavedSettings.getBOOL("ShowMatureEvents");
-
-	// Non-selected events
-	// Draw under avatar so you can find yourself.
-	LLWorldMap::item_info_list_t::const_iterator e;
-	for (e = gWorldMap->mPGEvents.begin(); e != gWorldMap->mPGEvents.end(); ++e)
-	{
-		const LLItemInfo& event = *e;
-
-		// Draw, but without relative-Z icons
-		if (!event.mSelected)
-		{
-			LLVector3 pos_map = globalPosToView( event.mPosGlobal );
-			gl_draw_image(llround(pos_map.mV[VX]) - sEventImage->getWidth()/2,
-							llround(pos_map.mV[VY]) - sEventImage->getHeight()/2,
-							sEventImage,
-							LLColor4::white);				
-		}
-	}
-	if (show_mature)
-	{
-		for (e = gWorldMap->mMatureEvents.begin(); e != gWorldMap->mMatureEvents.end(); ++e)
-		{
-			const LLItemInfo& event = *e;
-
-			// Draw, but without relative-Z icons
-			if (!event.mSelected)
-			{
-				LLVector3 pos_map = globalPosToView( event.mPosGlobal );
-				gl_draw_image(llround(pos_map.mV[VX]) - sEventMatureImage->getWidth()/2,
-								llround(pos_map.mV[VY]) - sEventMatureImage->getHeight()/2,
-								sEventMatureImage,
-								LLColor4::white);				
-			}
-		}
-	}
-
-	// Selected events
-	// Draw under avatar so you can find yourself.
-	for (e = gWorldMap->mPGEvents.begin(); e != gWorldMap->mPGEvents.end(); ++e)
-	{
-		const LLItemInfo& event = *e;
-
-		// Draw, but without relative-Z icons
-		if (event.mSelected)
-		{
-			LLVector3 pos_map = globalPosToView( event.mPosGlobal );
-			gl_draw_image(llround(pos_map.mV[VX]) - sEventImage->getWidth()/2,
-							llround(pos_map.mV[VY]) - sEventImage->getHeight()/2,
-							sEventImage,
-							LLColor4::white);				
-
-			//drawIconName(
-			//	pos_map.mV[VX], 
-			//	pos_map.mV[VY], 
-			//	gEventColor,
-			//	event.mToolTip.c_str(), 
-			//	event.mName.c_str() );
-		}
-	}
-	if (show_mature)
-	{
-		for (e = gWorldMap->mMatureEvents.begin(); e != gWorldMap->mMatureEvents.end(); ++e)
-		{
-			const LLItemInfo& event = *e;
-
-			// Draw, but without relative-Z icons
-			if (event.mSelected)
-			{
-				LLVector3 pos_map = globalPosToView( event.mPosGlobal );
-				gl_draw_image(llround(pos_map.mV[VX]) - sEventMatureImage->getWidth()/2,
-								llround(pos_map.mV[VY]) - sEventMatureImage->getHeight()/2,
-								sEventMatureImage,
-								LLColor4::white);				
-
-				//drawIconName(
-				//	pos_map.mV[VX], 
-				//	pos_map.mV[VY], 
-				//	gEventColor,
-				//	event.mToolTip.c_str(), 
-				//	event.mName.c_str() );
-			}
-		}
-	}
-}
-
-void LLWorldMapView::drawDots()
-{
-
+    BOOL show_mature = gSavedSettings.getBOOL("ShowMatureEvents");
+
+    // First the non-selected events
+    LLWorldMap::item_info_list_t::const_iterator e;
+    for (e = gWorldMap->mPGEvents.begin(); e != gWorldMap->mPGEvents.end(); ++e)
+    {
+        if (!e->mSelected)
+        {
+            drawGenericItem(*e, sEventImage);   
+        }
+    }
+    if (show_mature)
+    {
+        for (e = gWorldMap->mMatureEvents.begin(); e != gWorldMap->mMatureEvents.end(); ++e)
+        {
+            if (!e->mSelected)
+            {
+                drawGenericItem(*e, sEventMatureImage);       
+            }
+        }
+    }
+
+    // Then the selected events
+    for (e = gWorldMap->mPGEvents.begin(); e != gWorldMap->mPGEvents.end(); ++e)
+    {
+        if (e->mSelected)
+        {
+            drawGenericItem(*e, sEventImage);
+        }
+    }
+    if (show_mature)
+    {
+        for (e = gWorldMap->mMatureEvents.begin(); e != gWorldMap->mMatureEvents.end(); ++e)
+        {
+            if (e->mSelected)
+            {
+                drawGenericItem(*e, sEventMatureImage);       
+            }
+        }
+    }
 }
 
 
@@ -1123,11 +1031,7 @@ void LLWorldMapView::drawTracking(const LLVector3d& pos_global, const LLColor4&
 	}
 	else
 	{
-		// Draw, but without relative Z
-		gl_draw_image(x - sTrackCircleImage->getWidth()/2, 
-					  y - sTrackCircleImage->getHeight()/2, 
-					  sTrackCircleImage, 
-					  color);
+		drawImage(pos_global, sTrackCircleImage, color);
 	}
 
 	// clamp text position to on-screen
@@ -1251,55 +1155,67 @@ BOOL LLWorldMapView::handleToolTip( S32 x, S32 y, LLString& msg, LLRect* sticky_
 
 // Pass relative Z of 0 to draw at same level.
 // static
-void LLWorldMapView::drawAvatar(F32 x_pixels, 
-								F32 y_pixels,
-								const LLColor4& color,
-								F32 relative_z,
-								F32 dot_radius)
-{	
-	F32 left =		x_pixels - dot_radius;
-	F32 right =		x_pixels + dot_radius;
-	F32 center = (left + right) * 0.5f;
-	F32 top =		y_pixels + dot_radius;
-	F32 bottom =	y_pixels - dot_radius;
-
+static void drawDot(F32 x_pixels, F32 y_pixels,
+			 const LLColor4& color,
+			 F32 relative_z,
+			 F32 dot_radius,
+			 LLPointer<LLViewerImage> dot_image)
+{
 	const F32 HEIGHT_THRESHOLD = 7.f;
 
-	if (relative_z > HEIGHT_THRESHOLD)
-	{
-		LLGLSNoTexture gls_no_texture;
-		glColor4fv( color.mV );
-		LLUI::setLineWidth(1.5f);
-		glBegin( GL_LINES );
-			glVertex2f(left, top);
-			glVertex2f(right, top);
-			glVertex2f(center, top);
-			glVertex2f(center, bottom);
-		glEnd();
-		LLUI::setLineWidth(1.0f);
-	}
-	else if (relative_z > -HEIGHT_THRESHOLD)
+	if(-HEIGHT_THRESHOLD <= relative_z && relative_z <= HEIGHT_THRESHOLD)
 	{
-		gl_draw_image(	llround(x_pixels) - sAvatarSmallImage->getWidth()/2, 
-						llround(y_pixels) - sAvatarSmallImage->getHeight()/2, 
-						sAvatarSmallImage, 
+		gl_draw_image(	llround(x_pixels) - dot_image->getWidth()/2,
+						llround(y_pixels) - dot_image->getHeight()/2, 
+						dot_image, 
 						color);
 	}
 	else
 	{
+		F32 left =		x_pixels - dot_radius;
+		F32 right =		x_pixels + dot_radius;
+		F32 center = (left + right) * 0.5f;
+		F32 top =		y_pixels + dot_radius;
+		F32 bottom =	y_pixels - dot_radius;
+
 		LLGLSNoTexture gls_no_texture;
 		glColor4fv( color.mV );
 		LLUI::setLineWidth(1.5f);
+		F32 h_bar = relative_z > HEIGHT_THRESHOLD ? top : bottom; // horizontal bar Y
 		glBegin( GL_LINES );
+			glVertex2f(left, h_bar);
+			glVertex2f(right, h_bar);
 			glVertex2f(center, top);
 			glVertex2f(center, bottom);
-			glVertex2f(left, bottom);
-			glVertex2f(right, bottom);
 		glEnd();
 		LLUI::setLineWidth(1.0f);
 	}
 }
 
+// Pass relative Z of 0 to draw at same level.
+// static
+void LLWorldMapView::drawAvatar(F32 x_pixels, 
+								F32 y_pixels,
+								const LLColor4& color,
+								F32 relative_z,
+								F32 dot_radius)
+{
+	const F32 HEIGHT_THRESHOLD = 7.f;
+	LLViewerImage* dot_image = sAvatarSmallImage;
+	if(relative_z < -HEIGHT_THRESHOLD) 
+	{
+		dot_image = sAvatarBelowImage; 
+	}
+	else if(relative_z > HEIGHT_THRESHOLD) 
+	{ 
+		dot_image = sAvatarAboveImage;
+	}
+	gl_draw_image(
+		llround(x_pixels) - dot_image->getWidth()/2,
+		llround(y_pixels) - dot_image->getHeight()/2, 
+		dot_image, color);
+}
+
 // Pass relative Z of 0 to draw at same level.
 // static
 void LLWorldMapView::drawTrackingDot( F32 x_pixels, 
@@ -1307,48 +1223,8 @@ void LLWorldMapView::drawTrackingDot( F32 x_pixels,
 									  const LLColor4& color,
 									  F32 relative_z,
 									  F32 dot_radius)
-{	
-	F32 left =		x_pixels - dot_radius;
-	F32 right =		x_pixels + dot_radius;
-	F32 center = (left + right) * 0.5f;
-	F32 top =		y_pixels + dot_radius;
-	F32 bottom =	y_pixels - dot_radius;
-
-	const F32 HEIGHT_THRESHOLD = 7.f;
-
-	if (relative_z > HEIGHT_THRESHOLD)
-	{
-		LLGLSNoTexture gls_no_texture;
-		glColor4fv( color.mV );
-		LLUI::setLineWidth(1.5f);
-		glBegin( GL_LINES );
-			glVertex2f(left, top);
-			glVertex2f(right, top);
-			glVertex2f(center, top);
-			glVertex2f(center, bottom);
-		glEnd();
-		LLUI::setLineWidth(1.0f);
-	}
-	else if (relative_z > -HEIGHT_THRESHOLD)
-	{
-		gl_draw_image(	llround(x_pixels) - sAvatarSmallImage->getWidth()/2, 
-						llround(y_pixels) - sAvatarSmallImage->getHeight()/2, 
-						sTrackCircleImage, 
-						color);
-	}
-	else
-	{
-		LLGLSNoTexture gls_no_texture;
-		glColor4fv( color.mV );
-		LLUI::setLineWidth(1.5f);
-		glBegin( GL_LINES );
-			glVertex2f(center, top);
-			glVertex2f(center, bottom);
-			glVertex2f(left, bottom);
-			glVertex2f(right, bottom);
-		glEnd();
-		LLUI::setLineWidth(1.0f);
-	}
+{
+	drawDot(x_pixels, y_pixels, color, relative_z, dot_radius, sTrackCircleImage);
 }
 
 
diff --git a/indra/newview/llworldmapview.h b/indra/newview/llworldmapview.h
index 9b353efc72c..74e2bc2978c 100644
--- a/indra/newview/llworldmapview.h
+++ b/indra/newview/llworldmapview.h
@@ -69,9 +69,10 @@ class LLWorldMapView : public LLPanel
 	virtual void	draw();
 	void			drawGenericItems(const LLWorldMap::item_info_list_t& items, LLPointer<LLViewerImage> image);
 	void			drawGenericItem(const LLItemInfo& item, LLPointer<LLViewerImage> image);
+	void			drawImage(const LLVector3d& global_pos, LLPointer<LLViewerImage> image, const LLColor4& color = LLColor4::white);
+	void			drawImageStack(const LLVector3d& global_pos, LLPointer<LLViewerImage> image, U32 count, F32 offset, const LLColor4& color);
 	void			drawAgents();
 	void			drawEvents();
-	void			drawDots();
 	void			drawFrustum();
 
 	static void		cleanupTextures();
@@ -122,6 +123,8 @@ class LLWorldMapView : public LLPanel
 	static LLPointer<LLViewerImage>	sAvatarYouSmallImage;
 	static LLPointer<LLViewerImage>	sAvatarSmallImage;
 	static LLPointer<LLViewerImage>	sAvatarLargeImage;
+	static LLPointer<LLViewerImage>	sAvatarAboveImage;
+	static LLPointer<LLViewerImage>	sAvatarBelowImage;
 	static LLPointer<LLViewerImage>	sTelehubImage;
 	static LLPointer<LLViewerImage>	sInfohubImage;
 	static LLPointer<LLViewerImage>	sHomeImage;
diff --git a/scripts/messages/message_template.msg b/scripts/messages/message_template.msg
index 983be8a11d0..7aabb780307 100644
--- a/scripts/messages/message_template.msg
+++ b/scripts/messages/message_template.msg
@@ -3038,7 +3038,7 @@ version 2.0
 // and where someone you are tracking is located. They are -1 if not
 // applicable.
 {
-	CoarseLocationUpdate Medium 6 Trusted Unencoded
+	CoarseLocationUpdate Medium 6 Trusted Unencoded UDPDeprecated
 	{
 		Location	Variable
 		{	X		U8	}
-- 
GitLab