Fix css style order when using external css files
[ryzomcore.git] / ryzom / client / src / interface_v3 / group_map.cpp
blob56d00d15e04380d334e4f9b965420d0c7831eb3e
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2019 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 // Copyright (C) 2014-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 //
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "stdpch.h"
25 #include "group_map.h"
26 #include "interface_manager.h"
27 #include "../continent_manager.h"
28 #include "../continent.h"
29 #include "../zone_util.h"
30 #include "../user_entity.h"
31 #include "nel/gui/ctrl_button.h"
32 #include "nel/gui/group_editbox.h"
33 #include "nel/gui/dbgroup_combo_box.h"
34 #include "../string_manager_client.h"
35 #include "nel/gui/group_container.h"
36 #include "nel/gui/action_handler.h"
37 #include "../dummy_progress.h"
38 #include "group_compas.h"
39 #include "group_html_cs.h"
40 #include "../connection.h"
41 #include "../net_manager.h"
42 #include "people_interraction.h" // for MaxNumPeopleInTeam
43 #include "../sheet_manager.h" // for MaxNumPeopleInTeam
44 #include "../global.h"
45 #include "nel/gui/ctrl_quad.h"
46 #include "nel/gui/lua_ihm.h"
48 #include "nel/misc/xml_auto_ptr.h"
49 #include "game_share/mission_desc.h"
50 #include "game_share/inventories.h"
51 #include "game_share/animal_type.h"
53 #include "nel/3d/u_material.h"
54 #include "nel/3d/u_texture.h"
55 #include "nel/3d/u_scene.h"
56 #include "../entities.h"
58 #include "nel/misc/vector_2f.h"
59 #include "nel/misc/bitmap.h"
60 #include "nel/misc/path.h"
61 #include "nel/misc/file.h"
62 #include "nel/misc/uv.h"
63 #include "nel/misc/i18n.h"
64 #include "../r2/editor.h"
66 #include "game_share/scenario_entry_points.h"
68 #include <list>
70 #ifdef DEBUG_NEW
71 #define new DEBUG_NEW
72 #endif
74 extern CContinentManager ContinentMngr;
75 extern NL3D::UDriver *Driver;
76 extern NL3D::UScene *Scene;
77 extern CEntityManager EntitiesMngr;
79 using namespace NLMISC;
80 using NLMISC::CUV;
81 using NLMISC::CI18N;
82 using NLMISC::CRGBA;
83 using NLMISC::CBitMemStream;
84 using namespace STRING_MANAGER;
86 // /////// //
87 // STATICS //
88 // /////// //
89 static CGroupMap *LastClickedMap = NULL;
90 static CCtrlButton *LastSelectedLandMark = NULL;
91 static bool UseUserPositionForLandMark = false;
92 static const char *WIN_LANDMARK_NAME="ui:interface:enter_landmark_name";
94 // Loaded position of user landmark types
95 static std::vector<uint> LoadedPosition;
97 ////////////
98 // GLOBAL //
99 ////////////
100 NLMISC::CRGBA CUserLandMark::_LandMarksColor[CUserLandMark::UserLandMarkTypeCount];
104 const uint32 ISLAND_PIXEL_PER_METER = 2;
106 static void setupFromZoom(CViewBase *pVB, CContLandMark::TContLMType t, float fMeterPerPixel);
108 // calculate distance (squared) between two points
109 static float distsqr(const CVector2f a, const CVector2f b)
111 return pow(a.x - b.x, 2) + pow(a.y - b.y, 2);
114 // popup the landmark name dialog
116 static void popupLandMarkNameDialog()
118 // pop the rename dialog
119 CInterfaceManager *im = CInterfaceManager::getInstance();
120 CGroupContainer *gc = dynamic_cast<CGroupContainer *>(CWidgetManager::getInstance()->getElementFromId(WIN_LANDMARK_NAME));
121 if (!gc) return;
123 gc->setActive(true);
124 gc->updateCoords();
125 gc->center();
126 CWidgetManager::getInstance()->setTopWindow(gc);
127 gc->enableBlink(1);
129 CGroupEditBox *eb = dynamic_cast<CGroupEditBox *>(gc->getGroup("eb"));
130 if (!eb) return;
132 // Load ComboBox for Landmarks & sort entries
133 CDBGroupComboBox *cb = dynamic_cast<CDBGroupComboBox *>(gc->getGroup("landmarktypes"));
134 cb->sortText();
136 if (LastSelectedLandMark)
138 CGroupMap *map = dynamic_cast<CGroupMap *>(LastSelectedLandMark->getParent());
139 if (!map) return;
141 const CUserLandMark userLM = map->getUserLandMark(LastSelectedLandMark);
143 NLGUI::CDBManager::getInstance()->getDbProp( "UI:TEMP:LANDMARKTYPE" )->setValue8(cb->getTextPos(userLM.Type));
144 eb->setInputString(userLM.Title.toUtf8());
146 else
148 NLGUI::CDBManager::getInstance()->getDbProp( "UI:TEMP:LANDMARKTYPE" )->setValue8(cb->getTextPos(CUserLandMark::Misc));
149 eb->setInputString(string());
152 CWidgetManager::getInstance()->setCaptureKeyboard(eb);
153 eb->setSelectionAll();
156 static void closeLandMarkNameDialog()
158 LoadedPosition.clear();
159 CInterfaceManager *im = CInterfaceManager::getInstance();
160 CGroupContainer *gc = dynamic_cast<CGroupContainer *>(CWidgetManager::getInstance()->getElementFromId(WIN_LANDMARK_NAME));
161 if (!gc) return;
162 gc->setActive(false);
165 //============================================================================================================
166 // CPolyButton
167 //============================================================================================================
169 NL3D::UMaterial CGroupMap::CPolyButton::LineMat;
171 //============================================================================================================
172 CGroupMap::CPolyButton::CPolyButton()
173 : CCtrlBase(TCtorParam())
175 if (Driver != NULL)
177 // create material for displaying the button
178 if (LineMat.empty())
180 // create material for the world map
181 LineMat = Driver->createMaterial();
182 if (!LineMat.empty())
184 LineMat.initUnlit();
185 LineMat.setSrcBlend(NL3D::UMaterial::srcalpha);
186 LineMat.setDstBlend(NL3D::UMaterial::invsrcalpha);
187 LineMat.setBlend(true);
188 LineMat.setZFunc(NL3D::UMaterial::always);
189 LineMat.setZWrite(false);
190 LineMat.setColor(CRGBA::Red);
197 //============================================================================================================
198 bool CGroupMap::CPolyButton::handleEvent (const NLGUI::CEventDescriptor &event)
200 if (CCtrlBase::handleEvent(event)) return true;
201 if (event.getType() == NLGUI::CEventDescriptor::mouse)
203 CInterfaceManager *im = CInterfaceManager::getInstance();
204 const NLGUI::CEventDescriptorMouse &eventDesc = (const NLGUI::CEventDescriptorMouse &)event;
206 if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouseleftup)
208 if (CWidgetManager::getInstance()->getCapturePointerLeft() != this)
209 return false;
211 // Set the map !!!
212 if (contains(CVector2f((float)eventDesc.getX(), (float)eventDesc.getY())))
214 bool bFound = false;
215 uint32 i;
216 for (i = 0; i < Map->getCurMap()->Children.size(); ++i)
218 if (ID == Map->getCurMap()->Children[i].ZoneName)
220 bFound = true;
221 break;
225 CWidgetManager::getInstance()->setCapturePointerLeft(NULL);
226 if (bFound)
227 Map->setMap(Map->getCurMap()->Children[i].Name);
228 return true;
232 if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouseleftdown)
234 if (contains(CVector2f((float)eventDesc.getX(), (float)eventDesc.getY())))
236 CWidgetManager::getInstance()->setCapturePointerLeft(this);
237 return true;
242 return false;
245 //============================================================================================================
246 void CGroupMap::CPolyButton::updateCoords()
248 uint32 i, p;
249 PolysReal.resize(Polys.size());
250 for (p = 0; p < Polys.size(); ++p)
252 PolysReal[p].Vertices.resize(Polys[p].Vertices.size());
253 for (i = 0; i < Polys[p].Vertices.size(); ++i)
255 sint32 x, y;
256 CVector2f mapCoords;
257 Map->worldToMap(mapCoords, Polys[p].Vertices[i]);
258 Map->mapToScreen(x, y, mapCoords);
259 PolysReal[p].Vertices[i] = CVector2f((float)x,(float)y);
263 ZoneReal.VPoints.resize(Zone.VPoints.size());
264 for (i = 0; i < Zone.VPoints.size(); ++i)
266 sint32 x, y;
267 CVector2f mapCoords;
268 Map->worldToMap(mapCoords, Zone.VPoints[i]);
269 Map->mapToScreen(x, y, mapCoords);
270 ZoneReal.VPoints[i] = NLLIGO::CPrimVector(CVector2f((float)x,(float)y));
274 //============================================================================================================
275 float CGroupMap::getActualMaxScale() const
277 return ClientCfg.R2EDEnabled ? _ScaleMaxR2 : _ScaleMax;
280 //============================================================================================================
281 void CGroupMap::CPolyButton::drawPolyButton()
283 CInterfaceManager *pIM = CInterfaceManager::getInstance();
284 CViewRenderer &rVR = *CViewRenderer::getInstance();
286 float oow, ooh;
287 rVR.getScreenOOSize(oow, ooh);
289 bool bOver = false;
290 const std::vector<CCtrlBase*> &rCUP = CWidgetManager::getInstance()->getCtrlsUnderPointer();
291 for (uint32 i = 0; i < rCUP.size(); ++i)
292 if (rCUP[i] == this)
294 bOver = true;
295 break;
298 /* // Wireframe !!!
299 for (uint32 p = 0; p < PolysReal.size(); ++p)
301 for (uint32 i = 0; i < PolysReal[p].Vertices.size(); ++i)
303 NLMISC::CLine l;
304 l.V0 = PolysReal[p].Vertices[i];
305 if (i != (PolysReal[p].Vertices.size()-1))
306 l.V1 = PolysReal[p].Vertices[i+1];
307 else
308 l.V1 = PolysReal[p].Vertices[0];
310 l.V0.x *= oow;
311 l.V0.y *= ooh;
312 l.V1.x *= oow;
313 l.V1.y *= ooh;
315 Driver->drawLine(l, LineMat);
320 if (bOver)
321 LineMat.setColor(CRGBA(255,255,255,64)); // LineMat.setColor(CRGBA(165,38,6,128));
322 else
323 return; // LineMat.setColor(CRGBA(255,255,255,64));
325 for (uint32 p = 0; p < PolysReal.size(); ++p)
327 for (uint32 i = 0; i < (PolysReal[p].Vertices.size()-2); ++i)
329 NLMISC::CTriangle t;
330 t.V0 = PolysReal[p].Vertices[0];
331 t.V1 = PolysReal[p].Vertices[i+1];
332 t.V2 = PolysReal[p].Vertices[i+2];
334 t.V0.x *= oow;
335 t.V0.y *= ooh;
336 t.V1.x *= oow;
337 t.V1.y *= ooh;
338 t.V2.x *= oow;
339 t.V2.y *= ooh;
341 Driver->drawTriangle(t, LineMat);
346 //============================================================================================================
347 bool CGroupMap::CPolyButton::build(const NLLIGO::CPrimZone &concavePoly, CGroupMap *pMap, const string &sID)
349 static int gStat = 0;
350 _Id = pMap->getId() + ":polybut" + toString(gStat++);
352 Map = pMap;
353 ID = sID;
354 Zone = concavePoly;
356 CPolygon p;
357 for (uint32 i = 0; i < concavePoly.VPoints.size(); ++i)
358 p.Vertices.push_back(CVector(concavePoly.VPoints[i].x, concavePoly.VPoints[i].y, 0));
360 std::list<CPolygon> outputPolygons;
361 CMatrix id;
362 id.identity();
363 if (p.toConvexPolygons (outputPolygons, id))
365 std::list<CPolygon>::iterator it = outputPolygons.begin();
366 while (it != outputPolygons.end())
368 CPolygon2D poly;
369 for (uint32 i = 0; i < it->Vertices.size(); ++i)
370 poly.Vertices.push_back(CVector2f(it->Vertices[i].x, it->Vertices[i].y));
371 Polys.push_back(poly);
372 it++;
375 else
377 nlwarning("cannot convert to convex poly");
378 return false;
380 return true;
383 //============================================================================================================
384 bool CGroupMap::CPolyButton::contains(const NLMISC::CVector2f &pos)
386 /* // Not precise
387 for (uint32 p = 0; p < PolysReal.size(); ++p)
389 if (PolysReal[p].contains(pos))
390 return true;
392 return false;
394 return ZoneReal.contains(pos);
397 //============================================================================================================
398 // CGroupMap
399 //============================================================================================================
401 //============================================================================================================
403 NLMISC_REGISTER_OBJECT(CViewBase, CGroupMap, std::string, "map");
405 CGroupMap::CGroupMap(const TCtorParam &param)
406 : CInterfaceGroup(param)
408 _Offset.x = 0.f;
409 _Offset.y = 0.f;
410 _WorldOffset.x = 0.f;
411 _WorldOffset.y = 0.f;
412 _Scale = 1.f;
413 _UserScale = 1.f;
414 _MinH = 50;
415 _MaxH = 2000;
416 //_MinW = 50;
417 _MapTF = NULL;
418 _MapTexture.clear();
419 _PlayerPosMaterial = NULL;
420 _PlayerPosTF = NULL;
421 _MapTexW = 0;
422 _MapTexH = 0;
423 _PlayerPosTexW = 0;
424 _PlayerPosTexH = 0;
425 _MapLoadFailure = false;
426 _PlayerPosLoadFailure = false;
427 _WorldSheet = dynamic_cast<CWorldSheet*>(SheetMngr.get(CSheetId("ryzom.world")));
428 _CurMap = NULL;
429 _CurContinent = NULL;
430 _Panning = false;
431 _HasMoved = false;
432 _RightClickLastPos.set(0.f, 0.f);
433 // make room for mission targets
434 _MissionLM.resize(2 * MAX_NUM_MISSIONS * MAX_NUM_MISSION_TARGETS, 0);
435 _MissionTargetTextIDs.resize(2 * MAX_NUM_MISSIONS * MAX_NUM_MISSION_TARGETS, 0);
436 _MissionTargetTextReceived.resize(2 * MAX_NUM_MISSIONS * MAX_NUM_MISSION_TARGETS, false);
437 _OldPlayerPos.set(0.f, 0.f);
438 _PlayerPos.set(0.f, 0.f);
440 _TargetLM = NULL;
441 _HomeLM = NULL;
442 _LandmarkFilter.clear();
443 _MatchedLandmarks.clear();
445 _ScaleMax = 8.f;
446 _ScaleMaxR2 = 8.f;
448 _TargetPos = NULL;
449 _HomePos = NULL;
451 _MapX = 0;
452 _MapY = 0;
454 _MapMode = MapMode_Normal;
455 _RespawnSelected = 0;
456 _RespawnSelectedBitmap = NULL;
458 _WorldToMapDeltaX = 0.f;
459 _WorldToMapDeltaY = 0.f;
461 _VisibleWorldMin.set(0.f, 0.f);
462 _VisibleWorldMax.set(0.f, 0.f);
464 _MeterPerPixel = 0.f;
465 _FrustumView = NULL;
466 _FrustumViewColor = CRGBA(255, 255, 255, 255);
467 _FrustumViewColorOver = CRGBA(255, 255, 255, 127);
468 _FrustumOverBlendFactor = 0.f;
469 _FrustumViewBlendTimeInMs = 300;
470 _SelectionAxisH = NULL;
471 _SelectionAxisV = NULL;
473 _IsIsland = false;
475 _PanStartDateInMs = 0;
476 _DeltaTimeBeforePanInMs = 0;
477 _DeltaPosBeforePan = 0;
479 _LuaLoadMapEntered = false;
482 //============================================================================================================
483 CGroupMap::~CGroupMap()
485 if (Driver)
487 if (!_MapMaterial.empty())
488 Driver->deleteMaterial(_MapMaterial);
489 if (!_PlayerPosMaterial.empty())
490 Driver->deleteMaterial(_PlayerPosMaterial);
492 for(TDecos::iterator it = _Decos.begin(); it != _Decos.end(); ++it)
494 (*it)->onRemove(*this);
499 //============================================================================================================
500 void CGroupMap::addDeco(IDeco *deco)
502 if (!deco) return;
503 if (_Decos.count(deco))
505 nlwarning("Deco added twice.");
506 return;
508 _Decos.insert(deco);
509 deco->onAdd(*this);
510 deco->onUpdate(*this);
513 //============================================================================================================
514 void CGroupMap::removeDeco(IDeco *deco)
516 if (!deco) return;
517 TDecos::iterator it = _Decos.find(deco);
518 if (it != _Decos.end())
520 deco->onRemove(*this);
521 _Decos.erase(it);
523 else
525 nlwarning("Deco not found");
529 //============================================================================================================
530 /** Load infos about a landmark
532 static void loadLandmarkInfo(xmlNodePtr cur, const std::string &prefix, CLandMarkOptions &dest)
534 CXMLAutoPtr ptr;
535 ptr = (char*) xmlGetProp( cur, (xmlChar*)(prefix + "_landmark_tex_normal").c_str());
536 if (ptr) dest.LandMarkTexNormal = (const char *) ptr;
537 ptr = (char*) xmlGetProp( cur, (xmlChar*)(prefix + "_landmark_tex_over").c_str());
538 if (ptr) dest.LandMarkTexOver = (const char *) ptr;
539 ptr = (char*) xmlGetProp( cur, (xmlChar*)(prefix + "_landmark_tex_pushed").c_str());
540 if (ptr) dest.LandMarkTexPushed = (const char *) ptr;
541 ptr = (char*) xmlGetProp( cur, (xmlChar*)(prefix + "_landmark_menu").c_str());
542 if (ptr) dest.LandMarkMenu = (const char *) ptr;
543 ptr = (char*) xmlGetProp( cur, (xmlChar*)(prefix + "_landmark_color_normal").c_str());
544 if (ptr) dest.ColorNormal = CCtrlBase::convertColor(ptr);
545 ptr = (char*) xmlGetProp( cur, (xmlChar*)(prefix + "_landmark_color_over").c_str());
546 if (ptr) dest.ColorOver = CCtrlBase::convertColor(ptr);
547 ptr = (char*) xmlGetProp( cur, (xmlChar*)(prefix + "_landmark_color_pushed").c_str());
548 if (ptr) dest.ColorPushed = CCtrlBase::convertColor(ptr);
552 //============================================================================================================
553 CViewBitmap *CGroupMap::newSelectionAxis(NLMISC::CRGBA color)
555 CViewBitmap *axis = new CViewBitmap(TCtorParam());
556 axis->setActive(false);
557 axis->setTexture("blank.tga");
558 axis->setModulateGlobalColor(false);
559 addView(axis);
560 axis->setParent(this);
561 axis->setColor(color);
562 axis->setScale(true);
563 return axis;
566 //============================================================================================================
567 bool CGroupMap::parse(xmlNodePtr cur, CInterfaceGroup * parentGroup)
569 if (!CInterfaceGroup::parse(cur, parentGroup)) return false;
570 CXMLAutoPtr ptr((const char*) xmlGetProp( cur, (xmlChar*)"min_h" ));
571 if (ptr) fromString((const char*) ptr, _MinH);
572 ptr = (char*) xmlGetProp( cur, (xmlChar*)"max_h" );
573 if (ptr) fromString((const char*)ptr, _MaxH);
574 /*ptr = (char*) xmlGetProp( cur, (xmlChar*)"min_w" );
575 if (ptr) fromString((const char*)ptr, _MinW);*/
577 ptr = (char*) xmlGetProp( cur, (xmlChar*)"map_mode" );
578 if (ptr)
580 string sTmp = ptr.str();
581 if (sTmp == "normal")
582 _MapMode = MapMode_Normal;
583 else if (sTmp == "death")
584 _MapMode = MapMode_Death;
585 else if (sTmp == "spawn_squad")
586 _MapMode = MapMode_SpawnSquad;
589 ptr = (char*) xmlGetProp( cur, (xmlChar*)"frustum_view_color" );
590 if (ptr)
592 _FrustumViewColor = convertColor (ptr);
594 ptr = (char*) xmlGetProp( cur, (xmlChar*)"frustum_view_color_over" );
595 if (ptr)
597 _FrustumViewColorOver = convertColor (ptr);
599 ptr = (char*) xmlGetProp( cur, (xmlChar*)"frustum_view_blend_time_in_ms" );
600 if (ptr)
602 fromString((const char*)ptr, _FrustumViewBlendTimeInMs);
606 if (Driver)
608 if (_MapMaterial.empty())
610 // create material for the world map
611 _MapMaterial = Driver->createMaterial();
612 if (!_MapMaterial.empty())
614 _MapMaterial.initUnlit();
615 _MapMaterial.setSrcBlend(NL3D::UMaterial::srcalpha);
616 _MapMaterial.setDstBlend(NL3D::UMaterial::invsrcalpha);
617 _MapMaterial.setBlend(true);
618 _MapMaterial.setZFunc(NL3D::UMaterial::always);
619 _MapMaterial.setZWrite(false);
620 // Setup stage 0
621 _MapMaterial.texEnvOpRGB(0, NL3D::UMaterial::Modulate);
622 _MapMaterial.texEnvArg0RGB(0, NL3D::UMaterial::Texture, NL3D::UMaterial::SrcColor);
623 _MapMaterial.texEnvArg1RGB(0, NL3D::UMaterial::Diffuse, NL3D::UMaterial::SrcColor);
624 _MapMaterial.texEnvOpAlpha(0, NL3D::UMaterial::Modulate);
625 _MapMaterial.texEnvArg0Alpha(0, NL3D::UMaterial::Texture, NL3D::UMaterial::SrcAlpha);
626 _MapMaterial.texEnvArg1Alpha(0, NL3D::UMaterial::Diffuse, NL3D::UMaterial::SrcAlpha);
627 // Setup stage 1
628 _MapMaterial.texEnvOpRGB(1, NL3D::UMaterial::Modulate);
629 _MapMaterial.texEnvArg0RGB(1, NL3D::UMaterial::Previous, NL3D::UMaterial::SrcColor);
630 _MapMaterial.texEnvArg1RGB(1, NL3D::UMaterial::Texture, NL3D::UMaterial::SrcAlpha);
631 _MapMaterial.texEnvOpAlpha(1, NL3D::UMaterial::Replace);
632 _MapMaterial.texEnvArg0Alpha(1, NL3D::UMaterial::Previous, NL3D::UMaterial::SrcAlpha);
635 if (_PlayerPosMaterial.empty())
637 // create material for the world map
638 _PlayerPosMaterial = Driver->createMaterial();
639 if (!_PlayerPosMaterial.empty())
641 _PlayerPosMaterial.initUnlit();
642 _PlayerPosMaterial.setSrcBlend(NL3D::UMaterial::srcalpha);
643 _PlayerPosMaterial.setDstBlend(NL3D::UMaterial::invsrcalpha);
644 _PlayerPosMaterial.setBlend(true);
645 _PlayerPosMaterial.setZFunc(NL3D::UMaterial::always);
646 _PlayerPosMaterial.setZWrite(false);
650 // continent landmarks
651 loadLandmarkInfo(cur, "continent", _ContinentLMOptions);
652 loadLandmarkInfo(cur, "mission", _MissionLMOptions);
653 loadLandmarkInfo(cur, "user", _UserLMOptions);
654 loadLandmarkInfo(cur, "target", _TargetLMOptions);
655 // home aspect depends on race
656 EGSPD::CPeople::TPeople people = EGSPD::CPeople::Fyros;
657 if (PlayerSelectedSlot < CharacterSummaries.size())
659 people = CharacterSummaries[people].People;
661 switch(people)
663 case EGSPD::CPeople::Fyros: loadLandmarkInfo(cur, "home_fyros", _HomeLMOptions); break;
664 case EGSPD::CPeople::Matis: loadLandmarkInfo(cur, "home_matis", _HomeLMOptions); break;
665 case EGSPD::CPeople::Zorai: loadLandmarkInfo(cur, "home_zorai", _HomeLMOptions); break;
666 case EGSPD::CPeople::Tryker: loadLandmarkInfo(cur, "home_tryker", _HomeLMOptions); break;
667 default: break;
669 loadLandmarkInfo(cur, "respawn", _RespawnLMOptions);
670 // animal landmark
671 loadLandmarkInfo(cur, "animal", _AnimalLMOptions);
672 // animal(in stable) landmark
673 loadLandmarkInfo(cur, "animal_stable", _AnimalStableLMOptions);
674 // animal(dead) landmark
675 loadLandmarkInfo(cur, "animal_dead", _AnimalDeadLMOptions);
676 // teammate landmark
677 loadLandmarkInfo(cur, "teammate", _TeammateLMOptions);
679 // player pos
680 ptr = (char*) xmlGetProp( cur, (xmlChar*)"player_pos_tex" );
681 if (ptr) _PlayerPosTexName = (const char *) ptr;
682 // name of compass for targeting
683 ptr = (char*) xmlGetProp( cur, (xmlChar*)"compass" );
684 if (ptr) _CompassId = (const char *) ptr;
686 if (_MapMode == MapMode_Normal)
688 // create home, target & respawn landmarks
689 _TargetLM = createLandMarkButton(_TargetLMOptions);
690 if (_TargetLM)
692 _TargetLM->setParent(this);
693 addCtrl(_TargetLM);
695 _HomeLM = createLandMarkButton(_HomeLMOptions);
696 if (_HomeLM)
698 _HomeLM->setParent(this);
699 addCtrl(_HomeLM);
700 _HomeLM->setDefaultContextHelp(NLMISC::CI18N::get("uiHome"));
703 // create animals Landmark: pack Animals.
704 _AnimalLM.resize(MAX_INVENTORY_ANIMAL);
705 for(uint i=0;i<_AnimalLM.size();i++)
707 _AnimalLM[i] = createLandMarkButton(_AnimalLMOptions);
708 if(_AnimalLM[i])
710 _AnimalLM[i]->setParent(this);
711 addCtrl(_AnimalLM[i]);
712 _AnimalLM[i]->setDefaultContextHelp(NLMISC::CI18N::get(NLMISC::toString("uiPATitleMount%d", i+1)));
716 // create teammates Landmark
717 _TeammateLM.resize(MaxNumPeopleInTeam);
718 for(uint i=0; i < MaxNumPeopleInTeam; i++)
720 _TeammateLM[i] = createLandMarkButton(_TeammateLMOptions);
721 if(_TeammateLM[i])
723 _TeammateLM[i]->setParent(this);
724 addCtrl(_TeammateLM[i]);
725 _TeammateLM[i]->setDefaultContextHelp(NLMISC::CI18N::get(NLMISC::toString("uittLMTeam%d",i)));
731 _ScaleMax = ClientCfg.MaxMapScale;
732 ptr = (char*) xmlGetProp( cur, (xmlChar*)"scale_max" );
733 if (ptr) fromString((const char *) ptr, _ScaleMax);
735 _ScaleMaxR2 = ClientCfg.R2EDMaxMapScale;
736 ptr = (char*) xmlGetProp( cur, (xmlChar*)"scale_max_r2" );
737 if (ptr) fromString((const char *) ptr, _ScaleMaxR2);
739 if ((_MapMode == MapMode_Death) || (_MapMode == MapMode_SpawnSquad))
741 string stmp = "w_answer_16_valid.tga";
742 ptr = (char*) xmlGetProp( cur, (xmlChar*)"respawn_selected" );
743 if (ptr) stmp = (const char*)ptr;
744 ptr = (char*) xmlGetProp( cur, (xmlChar*)"respawn_button" );
745 if (ptr) _RespawnButton = (const char*)ptr;
746 _RespawnSelectedBitmap = new CViewBitmap(CViewBase::TCtorParam());
747 static int statRP = 0;
748 _RespawnSelectedBitmap->setId(getId()+":rp"+toString(statRP++));
749 _RespawnSelectedBitmap->setTexture(stmp);
750 _RespawnSelectedBitmap->setParent(this);
751 _RespawnSelectedBitmap->setParentPosRef(Hotspot_MM);
752 _RespawnSelectedBitmap->setPosRef(Hotspot_MM);
753 addView(_RespawnSelectedBitmap);
755 //CCtrlBaseButton *pCB = dynamic_cast<CCtrlBaseButton*>(CWidgetManager::getInstance()->getElementFromId(_RespawnButton));
756 //if (pCB != NULL) pCB->setActive(false);
758 nlassert(!_FrustumView);
759 CViewBase::TCtorParam param;
760 _FrustumView = new CCtrlQuad( param );
761 _FrustumView->setActive(false);
762 addView(_FrustumView);
763 _FrustumView->setParent(this);
764 ptr = (char*) xmlGetProp( cur, (xmlChar*)"frustum_view_texture" );
766 const char* value;
767 if (ptr)
769 value = ptr;
771 else
773 value = "r2_frustum.tga";
775 _FrustumView->setTexture(value);
776 _FrustumView->setModulateGlobalColor(false);
778 nlassert(!_SelectionAxisH);
779 nlassert(!_SelectionAxisV);
780 CRGBA axisColor = CRGBA(0, 0, 0, 127);
781 ptr = (char*) xmlGetProp( cur, (xmlChar*)"selection_axis_color" );
782 if (ptr)
784 axisColor = convertColor(ptr);
786 _SelectionAxisH = newSelectionAxis(axisColor);
787 _SelectionAxisV = newSelectionAxis(axisColor);
789 // load all islands
790 R2::CScenarioEntryPoints &sep = R2::CScenarioEntryPoints::getInstance();
793 sep.loadCompleteIslands();
794 const R2::CScenarioEntryPoints::TCompleteIslands &completeIslands = sep.getCompleteIslands();
795 _Islands.reserve(completeIslands.size());
796 for(uint k = 0; k < completeIslands.size(); ++k)
798 SMap island;
799 island.Name = completeIslands[k].Island;
800 island.ContinentName.clear(); // no access to world map for now ...
801 island.MinX = (float) completeIslands[k].XMin;
802 island.MinY = (float) completeIslands[k].YMin;
803 island.MaxX = (float) completeIslands[k].XMax;
804 island.MaxY = (float) completeIslands[k].YMax;
805 // post fix with current season
806 island.BitmapName = completeIslands[k].Island + "_sp.tga";
807 _Islands.push_back(island);
810 catch(const NLMISC::EFile &e)
812 nlwarning(e.what());
814 return true;
817 //============================================================================================================
818 void CGroupMap::updateSelectionAxisSize()
820 if (_SelectionAxisH->getActive())
822 _SelectionAxisH->setW(_WReal);
823 _SelectionAxisH->setH(1);
824 _SelectionAxisV->setW(1);
825 _SelectionAxisV->setH(_HReal);
829 //============================================================================================================
830 void CGroupMap::setSelectionAxis(bool active, const NLMISC::CVector2f &pos /*=NLMISC::CVector2f::Null*/)
832 _SelectionAxisH->setActive(active);
833 _SelectionAxisV->setActive(active);
834 if (active)
836 sint32 x, y;
837 worldToWindowSnapped(x, y, pos);
838 _SelectionAxisH->setX(0);
839 _SelectionAxisH->setY(y);
840 _SelectionAxisV->setX(x);
841 _SelectionAxisV->setY(0);
842 updateSelectionAxisSize();
843 _SelectionAxisH->invalidateCoords();
844 _SelectionAxisV->invalidateCoords();
848 //============================================================================================================
849 bool CGroupMap::getCtrlsUnder (sint32 x, sint32 y, sint32 clipX, sint32 clipY, sint32 clipW, sint32 clipH, std::vector<CCtrlBase*> &vICL)
851 if (!((x >= _XReal) &&
852 (x < (_XReal + _WReal))&&
853 (y > _YReal) &&
854 (y <= (_YReal+ _HReal))))
855 return false;
856 // test against current clip
857 computeCurrentClipContribution(clipX, clipY, clipW, clipH,
858 clipX, clipY, clipW, clipH);
860 if (!((x > clipX) &&
861 (x < (clipX + clipW))&&
862 (y > clipY) &&
863 (y < (clipY + clipH))))
864 return false;
866 // bool bFound = false;
867 for (uint32 i = 0; i < _PolyButtons.size(); ++i)
869 if (_PolyButtons[i]->contains(CVector2f((float)x,(float)y)))
871 vICL.push_back(_PolyButtons[i]);
872 // bFound = true;
875 return CInterfaceGroup::getCtrlsUnder(x, y, clipX, clipY, clipW, clipH, vICL);
878 //============================================================================================================
879 inline void CGroupMap::updateButtonPos(CLandMarkButton &dest) const
881 sint32 x, y;
882 mapToWindowSnapped(x, y, dest.Pos);
883 dest.setX(x);
884 dest.setY(y);
888 //============================================================================================================
889 void CGroupMap::updateCoords()
891 updateSelectionAxisSize();
893 CGroupContainer *enclosingContainer = static_cast< CGroupContainer* >( getEnclosingContainer() );
895 if (!enclosingContainer || !enclosingContainer->getActive()) return;
896 // update position of landmarks
897 updateScale();
898 // Look if we want to display some details info
899 // Show / Hide details with the ratio indicating the meter per pixel of screen
901 float denomU = _MapTexW * _Scale;
902 _WorldToMapDeltaX = denomU != 0 ? 1.f / denomU : 0.f;
905 float denomV = _MapTexH * _Scale;
906 _WorldToMapDeltaY = denomV != 0 ? 1.f / denomV : 0.f;
908 CInterfaceGroup::updateCoords();
910 if (_MapMode == MapMode_Normal)
913 float minU, minV, maxU, maxV;
914 computeUVRect(minU, minV, maxU, maxV);
915 mapToWorld(_VisibleWorldMin, CVector2f(minU,maxV));
916 mapToWorld(_VisibleWorldMax, CVector2f(maxU,minV));
917 sint32 mapW = std::min(_MapW, _WReal);
918 _MeterPerPixel = (_VisibleWorldMax.x - _VisibleWorldMin.x) / mapW;
919 // bool newLandMarkShown = false;
920 uint i;
921 for (i = 0; i < _ContinentLM.size(); ++i)
923 if (_ContinentLM[i]->SearchMatch)
924 _ContinentLM[i]->setActive(true);
925 else
926 setupFromZoom(_ContinentLM[i], _ContinentLM[i]->Type, _MeterPerPixel);
928 for (i = 0; i < _ContinentText.size(); ++i)
930 if (_ContinentText[i]->SearchMatch)
931 _ContinentText[i]->setActive(true);
932 else
933 setupFromZoom(_ContinentText[i], _ContinentText[i]->Type, _MeterPerPixel);
936 updateLandMarkList(_ContinentLM);
937 updateLandMarkTextList(_ContinentText);
938 updateLandMarkList(_UserLM);
939 updateLandMarkList(_MissionLM);
940 // target
941 if (_TargetLM && _TargetLM->getActive()) updateButtonPos(*_TargetLM);
942 // home
943 if (_HomeLM && _HomeLM->getActive()) updateButtonPos(*_HomeLM);
944 // animals
945 updateLandMarkList(_AnimalLM);
946 // teammates
947 updateLandMarkList(_TeammateLM);
949 for (uint32 i = 0; i < _PolyButtons.size(); ++i)
950 _PolyButtons[i]->updateCoords();
953 updateLandMarkList(_RespawnLM);
955 // user decorations
956 for(TDecos::iterator it = _Decos.begin(); it != _Decos.end(); ++it)
958 (*it)->onUpdate(*this);
961 CInterfaceGroup::updateCoords(); // must update coords twice : first is to get map size and meter per pixel -> this allow to know which landmark are visible
962 //second is to update (possibly newly visible) landmarks position
966 //============================================================================================================
967 void CGroupMap::worldToMap(NLMISC::CVector2f &dest,const NLMISC::CVector2f &src) const
969 dest.x = _MapMinCorner.x != _MapMaxCorner.x ? (src.x - _MapMinCorner.x) / (_MapMaxCorner.x - _MapMinCorner.x) : _MapMinCorner.x;
970 dest.y = _MapMinCorner.y != _MapMaxCorner.y ? 1.f - (src.y - _MapMinCorner.y) / (_MapMaxCorner.y - _MapMinCorner.y) : 1.f - _MapMinCorner.y;
973 //============================================================================================================
974 void CGroupMap::mapToWorld(NLMISC::CVector2f &dest,const NLMISC::CVector2f &src) const
976 dest.x = src.x * (_MapMaxCorner.x - _MapMinCorner.x) + _MapMinCorner.x;
977 dest.y = (1.f - src.y) * (_MapMaxCorner.y - _MapMinCorner.y) + _MapMinCorner.y;
982 //============================================================================================================
983 void CGroupMap::mapToScreen(sint32 &px, sint32 &py, const NLMISC::CVector2f &src) const
985 px = (sint32) (_XReal + (src.x - (_PlayerPos.x + _Offset.x)) * _MapTexW * _Scale);
986 py = (sint32) (_YReal + _HReal - (src.y - (_PlayerPos.y + _Offset.y)) * _MapTexH * _Scale);
989 //============================================================================================================
990 void CGroupMap::mapToWindow(sint32 &px, sint32 &py, const NLMISC::CVector2f &src) const
992 px = (sint32) ((src.x - (_PlayerPos.x + _Offset.x)) * _MapTexW * _Scale);
993 py = (sint32) (_HReal - (src.y - (_PlayerPos.y + _Offset.y)) * _MapTexH * _Scale);
997 //============================================================================================================
998 void CGroupMap::worldToWindow(NLMISC::CVector2f &dest, const NLMISC::CVector2f &src) const
1000 worldToMap(dest, src);
1001 mapToWindow(dest, dest);
1004 //============================================================================================================
1005 void CGroupMap::worldToWindowSnapped(sint32 &px,sint32 &py, const NLMISC::CVector2f &src) const
1007 NLMISC::CVector2f snappedPos;
1008 snappedPos.x = _WorldToMapDeltaX != 0.f ? (src.x - fmodf(src.x, _WorldToMapDeltaX)) : src.x;
1009 snappedPos.y = _WorldToMapDeltaY != 0.f ? (src.y - fmodf(src.y, _WorldToMapDeltaY)) : src.y;
1010 worldToMap(snappedPos, snappedPos);
1011 mapToWindow(px, py, snappedPos);
1014 //============================================================================================================
1015 void CGroupMap::mapToWindowSnapped(sint32 &px,sint32 &py, const NLMISC::CVector2f &src) const
1017 NLMISC::CVector2f snappedPos;
1018 snappedPos.x = _WorldToMapDeltaX != 0.f ? (src.x - fmodf(src.x, _WorldToMapDeltaX)) : src.x;
1019 snappedPos.y = _WorldToMapDeltaY != 0.f ? (src.y - fmodf(src.y, _WorldToMapDeltaY)) : src.y;
1020 mapToWindow(px, py, snappedPos);
1023 //============================================================================================================
1024 void CGroupMap::mapToScreen(sint32 &px, sint32 &py, const NLMISC::CVector2f &src) const
1026 px = (sint32) (_XReal + _MapX + (src.x - (_PlayerPos.x + _Offset.x)) * _MapTexW * _Scale);
1027 py = (sint32) (_YReal + _MapY + _HReal - (src.y - (_PlayerPos.y + _Offset.y)) * _MapTexH * _Scale);
1030 //============================================================================================================
1031 void CGroupMap::windowToScreen(sint32 &destX, sint32 &destY, sint32 srcX, sint32 srcY) const
1033 destX = srcX + _XReal;
1034 destY = srcY + _YReal;
1037 //============================================================================================================
1038 void CGroupMap::mapToWindow(sint32 &px, sint32 &py, const NLMISC::CVector2f &src) const
1040 px = (sint32) ((src.x - (_PlayerPos.x + _Offset.x)) * _MapTexW * _Scale) + _MapX;
1041 py = (sint32) (_HReal - (src.y - (_PlayerPos.y + _Offset.y)) * _MapTexH * _Scale) + _MapY;
1044 //============================================================================================================
1045 void CGroupMap::mapToWindow(NLMISC::CVector2f &dest,const NLMISC::CVector2f &src) const
1047 dest.x = ((src.x - (_PlayerPos.x + _Offset.x)) * _MapTexW * _Scale) + (float) _MapX;
1048 dest.y = (sint32) (_HReal - (src.y - (_PlayerPos.y + _Offset.y)) * _MapTexH * _Scale) + (float) _MapY;
1051 //============================================================================================================
1052 void CGroupMap::screenToMap(NLMISC::CVector2f &dest, sint32 px, sint32 py) const
1054 if (_MapTexW == 0 || _MapTexH == 0)
1056 dest.set(0.f, 0.f);
1057 return;
1059 dest.x = (px - (_XReal + _MapX)) / (_MapTexW * _Scale) + _PlayerPos.x + _Offset.x;
1060 dest.y = (_YReal + _HReal + _MapY - py) / (_MapTexH * _Scale) + _PlayerPos.y + _Offset.y;
1063 //============================================================================================================
1064 void CGroupMap::windowToMap(NLMISC::CVector2f &dest,sint32 px,sint32 py) const
1066 if (_MapTexW == 0 || _MapTexH == 0)
1068 dest.set(0.f, 0.f);
1069 return;
1071 dest.x = ((px + 0.5f) - _MapX) / (_MapTexW * _Scale) + _PlayerPos.x + _Offset.x;
1072 dest.y = (_HReal + _MapY - (py - 0.5f)) / (_MapTexH * _Scale) + _PlayerPos.y + _Offset.y;
1075 //============================================================================================================
1076 void CGroupMap::updateLMPosFromDBPos(CLandMarkButton *dest ,sint32 px, sint32 py)
1078 nlassert(dest);
1079 if (px == 0 && py == 0)
1081 dest->setActive(false);
1083 else
1085 NLMISC::CVector2f worldPos(px * 0.001f, py * 0.001f);
1086 NLMISC::CVector2f mapPos;
1087 worldToMap(mapPos, worldPos);
1088 if (mapPos.x != dest->Pos.x)
1090 dest->Pos.x = mapPos.x;
1091 dest->invalidateCoords();
1093 if (mapPos.y != dest->Pos.y)
1095 dest->Pos.y = mapPos.y;
1096 dest->invalidateCoords();
1098 dest->setActive(true);
1101 //============================================================================================================
1102 // create mission position state object from base db path
1103 static CSmartPtr<CNamedEntityPositionState> buildMissionPositionState(CInterfaceManager *im, const std::string &baseDBpath, uint missionIndex, uint targetIndex)
1105 nlassert(im);
1106 CCDBNodeLeaf *name = NLGUI::CDBManager::getInstance()->getDbProp(baseDBpath + NLMISC::toString(":%d:TARGET%d:TITLE", (int) missionIndex, (int) targetIndex));
1107 CCDBNodeLeaf *x = NLGUI::CDBManager::getInstance()->getDbProp(baseDBpath + NLMISC::toString(":%d:TARGET%d:X", (int) missionIndex, (int) targetIndex));
1108 CCDBNodeLeaf *y = NLGUI::CDBManager::getInstance()->getDbProp(baseDBpath +NLMISC::toString(":%d:TARGET%d:Y", (int) missionIndex, (int) targetIndex));
1109 CSmartPtr<CNamedEntityPositionState> ps = new CNamedEntityPositionState;
1110 ps->build(name, x, y);
1111 return ps;
1114 //============================================================================================================
1115 void CGroupMap::checkCoords()
1117 if (!_Active) return;
1118 updatePlayerPos();
1119 if (!_MapTF && !_MapLoadFailure)
1121 loadMap();
1122 invalidateCoords();
1124 updateContinentInfo();
1126 CInterfaceManager *pIM = CInterfaceManager::getInstance();
1128 // **** update landmark for missions from the database
1129 if (_MissionPosStates.empty()) // pointers on db node initialised ?
1131 _MissionPosStates.resize(2 * MAX_NUM_MISSIONS * MAX_NUM_MISSION_TARGETS); // 2 is because of group missions
1132 uint targetIndex = 0;
1133 for(uint k = 0; k < MAX_NUM_MISSIONS; ++k)
1135 for(uint l = 0; l <MAX_NUM_MISSION_TARGETS; ++l)
1137 _MissionPosStates[targetIndex++] = buildMissionPositionState(pIM, MISSIONS_DB_PATH, k, l);
1138 _MissionPosStates[targetIndex++] = buildMissionPositionState(pIM, GROUP_MISSIONS_DB_PATH, k, l);
1141 // also fill ptr for special landmarks (target, home & respawn)
1142 _TargetPos = NLGUI::CDBManager::getInstance()->getDbProp(COMPASS_DB_PATH ":TARGET");
1143 _HomePos = NLGUI::CDBManager::getInstance()->getDbProp(COMPASS_DB_PATH ":HOME_POINT");
1146 // bool mustInvalidateCoords = false;
1147 for(uint k = 0; k < 2 * MAX_NUM_MISSIONS * MAX_NUM_MISSION_TARGETS; ++k)
1149 sint32 nameID = _MissionPosStates[k]->getNameNode()->getValue32();
1150 if (nameID != _MissionTargetTextIDs[k])
1152 _MissionTargetTextIDs[k] = nameID;
1153 if (_MissionTargetTextIDs[k] == 0)
1155 if (_MissionLM[k] != NULL)
1157 delCtrl(_MissionLM[k]);
1158 _MissionLM[k] = NULL;
1161 else
1163 // create a new button if necessary
1164 if (_MissionLM[k] == NULL)
1166 _MissionLM[k] = createLandMarkButton(_MissionLMOptions);
1167 _MissionLM[k]->setParent(this);
1168 addCtrl(_MissionLM[k]);
1171 // text must be received
1172 _MissionTargetTextReceived[k] = false;
1174 if (_MissionLM[k])
1176 // update text if needed
1177 if (!_MissionTargetTextReceived[k])
1179 string result;
1180 if (STRING_MANAGER::CStringManagerClient::instance()->getDynString(_MissionTargetTextIDs[k], result))
1182 _MissionLM[k]->setDefaultContextHelp(result);
1183 _MissionTargetTextReceived[k] = true;
1189 // **** retrieve pos of target and update it, or hide it if there's no target
1190 if (_TargetLM)
1192 sint32 px = (sint32) (_TargetPos->getValue64() >> 32);
1193 sint32 py = _TargetPos->getValue32();
1194 updateLMPosFromDBPos(_TargetLM, px, py);
1195 if (_TargetLM->getActive())
1197 if (UserEntity)
1199 if (UserEntity->selection() != CLFECOMMON::INVALID_SLOT && UserEntity->selection() != 0)
1201 CEntityCL *sel = EntitiesMngr.entity(UserEntity->selection());
1202 if (sel)
1204 _TargetLM->setDefaultContextHelp(NLMISC::CI18N::get("uiTargetTwoPoint") + sel->removeTitleAndShardFromName(sel->getEntityName()));
1211 // **** retrieve pos of home and update it, or hide it if there's no target
1212 if (_HomeLM)
1214 sint32 px = (sint32) (_HomePos->getValue64() >> 32);
1215 sint32 py = _HomePos->getValue32();
1216 updateLMPosFromDBPos(_HomeLM, px, py);
1219 // **** retrieve pos of respawn and update it, or hide it if there's no target
1220 uint i;
1221 uint offset = 0;
1223 if (!_ArkPoints.empty())
1225 offset = _ArkPoints.size();
1226 if (_ArkPoints.size() < _RespawnLM.size())
1228 for (i = (uint)_ArkPoints.size(); i < _RespawnLM.size(); i++)
1230 delCtrl(_RespawnLM[i]);
1231 _RespawnLM[i] = NULL;
1235 _RespawnLM.resize(_ArkPoints.size(), NULL);
1236 for(i = 0; i < _ArkPoints.size(); i++)
1238 if (_RespawnLM[i] == NULL)
1240 _RespawnLM[i] = createArkPointButton(_ArkPoints[i]);
1241 _RespawnLM[i]->setId(this->getId() + ":arklm_" + NLMISC::toString(i));
1242 _RespawnLM[i]->setParent(this);
1243 _RespawnLM[i]->setDefaultContextHelp(_ArkPoints[i].Title);
1244 _RespawnLM[i]->HandleEvents = true;
1245 addCtrl(_RespawnLM[i]);
1246 updateLMPosFromDBPos(_RespawnLM[i], _ArkPoints[i].x, _ArkPoints[i].y);
1252 if (_ArkPoints.empty() || !isIsland())
1254 if (offset + _RespawnPos.size() < _RespawnLM.size())
1256 for (i = offset + _RespawnPos.size(); i < _RespawnLM.size(); i++)
1258 delCtrl(_RespawnLM[i]);
1259 _RespawnLM[i] = NULL;
1263 _RespawnLM.resize(offset + _RespawnPos.size(), NULL);
1264 for(int j = 0; j < _RespawnPos.size(); ++j)
1266 i = offset + j;
1267 if (_RespawnLM[i] == NULL)
1269 _RespawnLM[i] = createLandMarkButton(_RespawnLMOptions);
1270 _RespawnLM[i]->setId(this->getId() + ":rplm_" + NLMISC::toString(i));
1271 _RespawnLM[i]->setParent(this);
1272 if (_MapMode == MapMode_SpawnSquad)
1273 _RespawnLM[i]->setDefaultContextHelp(NLMISC::CI18N::get("uiSquadSpawnPoint") + NLMISC::toString(" %u", i+1));
1274 else
1276 if (isIsland())
1278 _RespawnLM[i]->setDefaultContextHelp(NLMISC::CI18N::get("uiR2EntryPoint"));
1280 else
1282 _RespawnLM[i]->setDefaultContextHelp(NLMISC::CI18N::get("uiRespawnPoint"));
1284 _RespawnLM[i]->HandleEvents = R2::getEditor().getMode() != R2::CEditor::EditionMode;
1286 addCtrl(_RespawnLM[i]);
1288 if (_RespawnLM[i])
1289 updateLMPosFromDBPos(_RespawnLM[i], _RespawnPos[j].x, _RespawnPos[j].y);
1294 if ((_MapMode == MapMode_Death) || (_MapMode == MapMode_SpawnSquad))
1296 if (_RespawnPosReseted)
1298 _RespawnPosReseted = false;
1299 // Reset selection
1300 _RespawnSelected = 0;
1301 if (_MapMode == MapMode_Death)
1302 NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:RESPAWN_PT")->setValue32(_RespawnSelected);
1303 else if (_MapMode == MapMode_SpawnSquad)
1304 NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP:OUTPOST:SQUAD_RESPAWN_PT")->setValue32(_RespawnSelected);
1305 if (!_RespawnLM.empty())
1306 _RespawnSelectedBitmap->setParentPos(_RespawnLM[_RespawnSelected]);
1308 else
1310 _RespawnSelected = getRespawnSelected();
1311 if (!_RespawnLM.empty())
1312 _RespawnSelectedBitmap->setParentPos(_RespawnLM[_RespawnSelected]);
1316 // **** Animal Landmarks
1317 // initialize DB if not done
1318 if(_AnimalPosStates.empty() && !_AnimalLM.empty())
1320 _AnimalPosStates.resize(_AnimalLM.size());
1321 // pack animals
1322 nlassert(_AnimalPosStates.size()<=MAX_INVENTORY_ANIMAL);
1323 for(uint i=0;i<MAX_INVENTORY_ANIMAL;i++)
1325 _AnimalPosStates[i] = new CAnimalPositionState;
1326 _AnimalPosStates[i]->build(NLMISC::toString("SERVER:PACK_ANIMAL:BEAST%d",i));
1329 // update DB pos & tooltip text
1330 for(i=0;i<_AnimalLM.size();i++)
1332 if( _AnimalLM[i] )
1334 // update pos
1335 sint32 px, py;
1336 _AnimalPosStates[i]->getPos(px, py);
1337 updateLMPosFromDBPos(_AnimalLM[i], px, py);
1339 if (_IsIsland)
1341 _AnimalLM[i]->setActive(false);
1343 else if (_AnimalLM[i]->getActive())
1345 // update texture from animal status
1346 CCDBNodeLeaf *statusNode = NLGUI::CDBManager::getInstance()->getDbProp(toString("SERVER:PACK_ANIMAL:BEAST%d", i) + ":STATUS", false);
1347 if (statusNode && ANIMAL_STATUS::isInStable((ANIMAL_STATUS::EAnimalStatus)statusNode->getValue32()) )
1349 _AnimalLM[i]->setTexture(_AnimalStableLMOptions.LandMarkTexNormal);
1350 _AnimalLM[i]->setScale(true); // hardcoded because chosen icon is too big (bad...)
1352 else
1353 if (statusNode && ANIMAL_STATUS::isDead((ANIMAL_STATUS::EAnimalStatus)statusNode->getValue32()) )
1355 _AnimalLM[i]->setTexture(_AnimalDeadLMOptions.LandMarkTexNormal);
1356 _AnimalLM[i]->setScale(true); // hardcoded because chosen icon is too big (bad...)
1358 else
1360 _AnimalLM[i]->setTexture(_AnimalLMOptions.LandMarkTexNormal);
1363 // update tooltip text
1364 ANIMAL_TYPE::EAnimalType at;
1365 at = (ANIMAL_TYPE::EAnimalType)NLGUI::CDBManager::getInstance()->getDbProp("SERVER:PACK_ANIMAL:BEAST"+toString(i)+":TYPE")->getValue32();
1366 string sPrefix;
1367 switch(at)
1369 default:
1370 case ANIMAL_TYPE::All: sPrefix = "uiPATitleMount"; break;
1371 case ANIMAL_TYPE::Mount: sPrefix = "uiPATitleMount"; break;
1372 case ANIMAL_TYPE::Packer: sPrefix = "uiPATitlePacker"; break;
1373 case ANIMAL_TYPE::Demon: sPrefix = "uiPATitleDemon"; break;
1375 _AnimalLM[i]->setDefaultContextHelp(NLMISC::CI18N::get(sPrefix+toString(i+1)));
1380 // **** Teammate Landmarks
1381 // initialize DB if not done
1382 if(_TeammatePosStates.empty() && !_TeammateLM.empty())
1384 _TeammatePosStates.resize(MaxNumPeopleInTeam);
1385 for(uint i=0; i < MaxNumPeopleInTeam; i++)
1387 _TeammatePosStates[i] = new CTeammatePositionState;
1388 _TeammatePosStates[i]->build(NLMISC::toString("SERVER:GROUP:%d",i));
1391 // update DB pos.
1392 for(i=0; i < _TeammateLM.size(); i++)
1395 if (_TeammateLM[i])
1397 sint32 px, py;
1399 if (_TeammatePosStates[i]->getPos(px, py))
1401 CInterfaceManager *im = CInterfaceManager::getInstance();
1402 uint32 val = NLGUI::CDBManager::getInstance()->getDbProp(NLMISC::toString("SERVER:GROUP:%d:NAME",i))->getValue32();
1403 STRING_MANAGER::CStringManagerClient *pSMC = STRING_MANAGER::CStringManagerClient::instance();
1404 string res;
1406 if (pSMC->getString(val, res))
1408 std::string res2 = CEntityCL::removeTitleAndShardFromName(res);
1409 _TeammateLM[i]->setDefaultContextHelp(res2);
1412 updateLMPosFromDBPos(_TeammateLM[i], px, py);
1416 // update position for mission landmarks
1417 // TODO : try to factor behaviour between anim / treamate / missions (they are all dynamic)
1418 // TODO : make just one list of landmark with a CCompassTarget would be better ?
1419 for(i=0; i < _MissionPosStates.size(); i++)
1421 if (_MissionLM[i])
1423 sint32 px, py;
1424 if (_MissionPosStates[i]->getPos(px, py))
1426 updateLMPosFromDBPos(_MissionLM[i], px, py);
1432 // **** check if player has moved
1433 if (!EntitiesMngr.entities().empty())
1435 if (EntitiesMngr.entity(0))
1437 const NLMISC::CVectorD &playerPos = EntitiesMngr.entity(0)->pos();
1438 CVector2f newPlayerPos((float) playerPos.x, (float) playerPos.y);
1439 if (newPlayerPos != _OldPlayerPos)
1441 _OldPlayerPos = newPlayerPos;
1442 invalidateCoords();
1446 CInterfaceGroup::checkCoords();
1449 //============================================================================================================
1450 static void setupFromZoom(CViewBase *pVB, CContLandMark::TContLMType t, float fMeterPerPixel)
1452 bool active = false;
1453 // Icon
1454 if ((t == CContLandMark::Capital) && (fMeterPerPixel <= 5.0f)) active = true;
1455 if ((t == CContLandMark::Village) && (fMeterPerPixel <= 4.0f)) active = true;
1456 if ((t == CContLandMark::Outpost) && (fMeterPerPixel <= 4.0f)) active = true;
1457 if ((t == CContLandMark::Stable) && (fMeterPerPixel <= 3.5f)) active = true;
1458 // Just a text
1459 if ((t == CContLandMark::Region) && (fMeterPerPixel <= 50.0f)) active = true;
1460 if ((t == CContLandMark::Place) && (fMeterPerPixel <= 6.0f)) active = true;
1461 if ((t == CContLandMark::Street) && (fMeterPerPixel <= 2.0f)) active = true;
1462 if (t == CContLandMark::Unknown) active = true;
1463 pVB->setActive(active);
1467 //============================================================================================================
1468 void CGroupMap::computeUVRect(float &minU, float &minV, float &maxU, float &maxV) const
1470 minU = _Offset.x + _PlayerPos.x;
1471 minV = _Offset.y + _PlayerPos.y;
1472 // delta U & V for a pixel on screen
1473 float deltaU = 1.f / favoid0(_MapTexW * _Scale);
1474 float deltaV = 1.f / favoid0(_MapTexH * _Scale);
1476 if (_MapX < 0)
1478 minU -= deltaU * _MapX;
1481 if (_MapY > 0)
1483 minV += deltaV * _MapY;
1485 // ensure that UV displacement results in moves pixel by pixel on screen (landmarks move pixel by pixel, so the map may appear not to follow them because it moves smoothly)
1486 minU -= fmodf(minU, deltaU);
1487 minV -= fmodf(minV, deltaV);
1489 sint32 mapW = std::min(_MapW, _WReal);
1490 sint32 mapH = std::min(_MapH, _HReal);
1492 maxU = minU + ((float) mapW / favoid0(_Scale * (float) _MapTexW));
1493 maxV = minV + ((float) mapH / favoid0(_Scale * (float) _MapTexH));
1497 //============================================================================================================
1498 void CGroupMap::computeFrustumQuad(CQuad &fruQuad) const
1501 CVector2f winPos;
1502 const NLMISC::CVector &camPos = MainCam.getMatrix().getPos();
1503 worldToWindow(winPos, camPos);
1504 fruQuad.V0.set(winPos.x, winPos.y, 0.f);
1505 CVector projectedFront = MainCam.getMatrix().getJ();
1506 projectedFront.z = 0.f;
1507 if (projectedFront.norm() <= 0.01f)
1509 projectedFront = MainCam.getMatrix().getK();
1510 projectedFront.z = 0.f;
1512 CVector front = projectedFront.normed();
1513 CVector right(- front.y, front.x, 0.f);
1514 const NL3D::CFrustum &fru = MainCam.getFrustum();
1515 float farRight = fru.Right * (fru.Far / fru.Near);
1516 float farLeft = fru.Left * (fru.Far / fru.Near);
1517 worldToWindow(winPos, camPos + farRight * right + fru.Far * front);;
1518 fruQuad.V1.set(winPos.x, winPos.y, 0.f);
1519 worldToWindow(winPos, camPos + farLeft * right + fru.Far * front);;
1520 fruQuad.V3.set(winPos.x, winPos.y, 0.f);
1521 CVector middle = 0.5f * (fruQuad.V1 + fruQuad.V3);
1522 fruQuad.V2 = fruQuad.V0 + 2.f * (middle - fruQuad.V0);
1525 //============================================================================================================
1526 void CGroupMap::draw()
1528 // user decorations
1529 for(TDecos::iterator it = _Decos.begin(); it != _Decos.end(); ++it)
1531 (*it)->onPreRender(*this);
1533 // TMP TMP for debug
1534 static volatile bool clearAll = false;
1535 if (clearAll)
1537 removeLandMarks(_ContinentLM);
1538 removeLandMarks(_MissionLM);
1539 removeLandMarks(_AnimalLM);
1540 removeLandMarks(_TeammateLM);
1541 for (uint k = 0; k < _ContinentText.size(); ++k)
1542 delView(_ContinentText[k]);
1543 _ContinentText.clear();
1544 for (uint k = 0; k < _PolyButtons.size(); ++k)
1545 delCtrl(_PolyButtons[k]);
1546 _PolyButtons.clear();
1549 sint32 oldSciX, oldSciY, oldSciW, oldSciH;
1550 makeNewClip (oldSciX, oldSciY, oldSciW, oldSciH);
1551 CInterfaceManager *im = CInterfaceManager::getInstance();
1552 CViewRenderer &vr = *CViewRenderer::getInstance();
1553 uint8 alpha = CWidgetManager::getInstance()->getGlobalColorForContent().A;
1554 updateScale();
1556 // No Op if screen minimized
1557 if(vr.isMinimized())
1558 return;
1560 // compute scissors
1561 uint32 sw, sh;
1562 vr.getScreenSize(sw, sh);
1564 NL3D::CScissor oldScissor;
1565 oldScissor = Driver->getScissor();
1566 sint32 sciX, sciY, sciW, sciH;
1567 vr.getClipWindow(sciX, sciY, sciW, sciH);
1568 NL3D::CScissor newScissor;
1569 newScissor.X = sciX / (float) sw;
1570 newScissor.Width = sciW / (float) sw;
1571 newScissor.Y = sciY / (float) sh;
1572 newScissor.Height = sciH / (float) sh;
1574 if (!_PlayerPosTF && !_PlayerPosLoadFailure)
1576 loadPlayerPos();
1578 if (!_MapLoadFailure)
1580 if (_MapTexW != 0 && _MapTexH != 0)
1582 float minU, minV, maxU, maxV;
1583 computeUVRect(minU, minV, maxU, maxV);
1584 // draw the map
1585 sint32 mapW = std::min(_MapW, _WReal);
1586 sint32 mapH = std::min(_MapH, _HReal);
1587 // Display fog of war map
1588 CVector2f fowMin(0,0), fowMax(0,0);
1589 float fowURatio = 0.0f;
1590 float fowVRatio = 0.0f;
1591 // Convert u,v (from map coords) to world coordinates
1592 CVector2f worldMin, worldMax;
1593 mapToWorld(worldMin, CVector2f(minU,minV));
1594 mapToWorld(worldMax, CVector2f(maxU,maxV));
1596 if (_CurContinent != NULL)
1598 // Convert world coordinate to map coordinate in the fog of war map
1599 CFogOfWar &rFOW = _CurContinent->FoW;
1600 if (rFOW.getMaxX() != rFOW.getMinX()) fowMin.x = (worldMin.x - rFOW.getMinX()) / (rFOW.getMaxX() - rFOW.getMinX());
1601 if (rFOW.getMaxY() != rFOW.getMinY()) fowMin.y = (worldMin.y - rFOW.getMinY()) / (rFOW.getMaxY() - rFOW.getMinY());
1602 if (rFOW.getMaxX() != rFOW.getMinX()) fowMax.x = (worldMax.x - rFOW.getMinX()) / (rFOW.getMaxX() - rFOW.getMinX());
1603 if (rFOW.getMaxY() != rFOW.getMinY()) fowMax.y = (worldMax.y - rFOW.getMinY()) / (rFOW.getMaxY() - rFOW.getMinY());
1604 if ((fowMin.x >= 0) && (fowMin.x <= 1) &&
1605 (fowMin.y >= 0) && (fowMin.y <= 1) &&
1606 (fowMax.x >= 0) && (fowMax.x <= 1) &&
1607 (fowMax.y >= 0) && (fowMax.y <= 1))
1609 fowURatio = (float)rFOW.getMapWidth() / favoid0((float)rFOW.getRealWidth());
1610 fowVRatio = (float)rFOW.getMapHeight() / favoid0((float)rFOW.getRealHeight());
1615 vr.drawCustom(_XReal + std::max(_MapX, (sint32) 0), _YReal - std::min(_MapY, (sint32) 0), mapW, mapH,
1616 CUV(minU * _URatio, minV * _VRatio), CUV(maxU * _URatio, maxV * _VRatio),
1617 CUV(fowMin.x * fowURatio, fowMin.y * fowVRatio), CUV(fowMax.x * fowURatio, fowMax.y * fowVRatio),
1618 CRGBA(255, 255, 255, alpha),
1619 _MapMaterial );
1621 // Look if we want to display some details info
1622 // Show / Hide details with the ratio indicating the meter per pixel of screen
1625 float fMeterPerPixel = (worldMax.x - worldMin.x) / mapW;
1627 uint32 i;
1628 for (i = 0; i < _ContinentLM.size(); ++i)
1629 setupFromZoom(_ContinentLM[i], _ContinentLM[i]->Type, fMeterPerPixel);
1630 for (i = 0; i < _ContinentText.size(); ++i)
1631 setupFromZoom(_ContinentText[i], _ContinentText[i]->Type, fMeterPerPixel);
1636 /* if (_MapW < _WReal || _MapH < _HReal)
1637 vr.drawWiredQuad(_XReal + _MapX, _YReal - _MapY, _MapW, _MapH, CRGBA(0, 0, 0, alpha));*/
1641 // if editor is in edition mode, draw the frustum instead (for better visibility)
1642 CQuad fruQuad;
1643 CTriangle fruTri;
1645 CRGBA fruColor(0, 0, 0);
1647 if (_FrustumView)
1649 if (getArkPowoMode() == "editor" || R2::getEditor().getMode() == R2::CEditor::EditionMode)
1651 static volatile bool wantFrustum = true;
1652 if (wantFrustum)
1654 computeFrustumQuad(fruQuad);
1655 _FrustumView->setActive(true);
1656 //_FrustumView->setAdditif(true);
1657 _FrustumView->setQuad(fruQuad);
1658 _FrustumView->updateCoords();
1659 // handle mouse over
1660 if (CWidgetManager::getInstance()->getPointer())
1662 sint32 originX, originY;
1663 getCorner(originX, originY, getPosRef());
1664 CVector delta((float) originX, (float) originY, 0.f);
1665 fruTri = CTriangle(fruQuad.V0, fruQuad.V1, fruQuad.V2);
1666 CVector mousePos((float) CWidgetManager::getInstance()->getPointer()->getXReal(), (float) CWidgetManager::getInstance()->getPointer()->getYReal(), 0.f);
1667 mousePos -= delta;
1668 CVector dummyHit;
1669 float deltaBlend = DT / (0.001f * (float) _FrustumViewBlendTimeInMs);
1670 bool hit = fruTri.intersect(mousePos + CVector::K, mousePos - CVector::K, dummyHit, CPlane(0.f, 0.f, 0.f, 1.f));
1671 NLMISC::incrementalBlend(_FrustumOverBlendFactor, hit ? 1.f : 0.f, deltaBlend);
1672 fruColor.blendFromui(_FrustumViewColor, _FrustumViewColorOver, (uint8) (255 * _FrustumOverBlendFactor));
1674 else
1676 fruColor = _FrustumViewColor;
1679 _FrustumView->setColorRGBA(fruColor);
1682 else
1684 _FrustumView->setActive(false);
1688 //Driver->setScissor(oldScissor);
1689 // let parent view draw continent, mission and user locations
1690 CInterfaceGroup::draw();
1691 // force the flush
1692 vr.flush();
1695 Driver->setScissor(newScissor);
1697 if (getArkPowoMode() == "editor" || R2::getEditor().getMode() != R2::CEditor::EditionMode)
1699 // Draw the player TODO : replace with a CViewQuad
1700 if (!_PlayerPosLoadFailure)
1702 // draw rotated bitmap for player position
1703 const NLMISC::CVector &front3f = UserEntity->front();
1704 NLMISC::CVector2f front;
1705 NLMISC::CVector2f right;
1706 front.set(front3f.x, front3f.y);
1707 right.set(front3f.y, - front3f.x);
1708 // compute corners
1709 sint32 spx, spy;
1710 mapToScreen(spx, spy, _PlayerPos);
1711 NLMISC::CVector center;
1712 center.set((float) spx, (float) spy, 0.f);
1713 NLMISC::CQuadColorUV quv;
1714 quv.V0 = center - 0.5f * (float) _PlayerPosTexW * right - 0.5f * (float) _PlayerPosTexH * front;
1715 quv.V1 = center + 0.5f * (float) _PlayerPosTexW * right - 0.5f * (float) _PlayerPosTexH * front;
1716 quv.V2 = center + 0.5f * (float) _PlayerPosTexW * right + 0.5f * (float) _PlayerPosTexH * front;
1717 quv.V3 = center - 0.5f * (float) _PlayerPosTexW * right + 0.5f * (float) _PlayerPosTexH * front;
1718 quv.Uv0.set(0.f, 1.f);
1719 quv.Uv1.set(1.f, 1.f);
1720 quv.Uv2.set(1.f, 0.f);
1721 quv.Uv3.set(0.f, 0.f);
1722 quv.Color0 = quv.Color1 = quv.Color2 = quv.Color3 = CRGBA(255, 255, 255, alpha);
1723 quv.V0.x /= (float) sw;
1724 quv.V0.y /= (float) sh;
1725 quv.V1.x /= (float) sw;
1726 quv.V1.y /= (float) sh;
1727 quv.V2.x /= (float) sw;
1728 quv.V2.y /= (float) sh;
1729 quv.V3.x /= (float) sw;
1730 quv.V3.y /= (float) sh;
1731 Driver->drawQuads(&quv, 1, _PlayerPosMaterial);
1735 // draw border of frustum
1736 if (_FrustumView)
1738 if (getArkPowoMode() == "editor" || R2::getEditor().getMode() == R2::CEditor::EditionMode)
1740 if (_FrustumMaterial.empty())
1742 // create material for the world map
1743 _FrustumMaterial = Driver->createMaterial();
1744 if (!_FrustumMaterial.empty())
1746 _FrustumMaterial.initUnlit();
1747 _FrustumMaterial.setZWrite(false);
1748 _FrustumMaterial.setZFunc(NL3D::UMaterial::always);
1749 _FrustumMaterial.setBlend (true);
1750 _FrustumMaterial.setBlendFunc (NL3D::UMaterial::srcalpha, NL3D::UMaterial::invsrcalpha);
1751 _FrustumMaterial.setDoubleSided();
1754 if (!_FrustumMaterial.empty())
1756 fruColor.A /= 2;
1757 _FrustumMaterial.setColor(fruColor);
1758 //Driver->setScissor(newScissor);
1759 NL3D::UDriver::TPolygonMode oldPolygonMode = Driver->getPolygonMode();
1760 Driver->setPolygonMode(NL3D::UDriver::Line);
1762 CTriangle fruTri;
1763 fruTri.V0.set((fruQuad.V0.x + _XReal) / sw, (fruQuad.V0.y + _YReal) / sh, 0.f);
1764 fruTri.V1.set((fruQuad.V1.x + _XReal) / sw, (fruQuad.V1.y + _YReal) / sh, 0.f);
1765 fruTri.V2.set((fruQuad.V3.x + _XReal) / sw, (fruQuad.V3.y + _YReal) / sh, 0.f);
1766 Driver->drawTriangle(fruTri, _FrustumMaterial);
1767 Driver->setPolygonMode(oldPolygonMode);
1772 // Draw all poly buttons
1773 for (uint32 i = 0; i < _PolyButtons.size(); ++i)
1775 _PolyButtons[i]->drawPolyButton();
1778 // Restore Old Scissor
1779 Driver->setScissor(oldScissor);
1781 restoreClip (oldSciX, oldSciY, oldSciW, oldSciH);
1784 //============================================================================================================
1785 bool CGroupMap::handleEvent(const NLGUI::CEventDescriptor &event)
1787 CInterfaceManager *im = CInterfaceManager::getInstance();
1788 // if R2 editor editor is on, give it a chance to handle the event first
1789 if (ClientCfg.R2EDEnabled && R2::getEditor().getCurrentTool())
1791 bool handled = false;
1792 bool panEnd = false;
1793 // handle standard clicks
1794 if (event.getType() == NLGUI::CEventDescriptor::mouse)
1796 const NLGUI::CEventDescriptorMouse &eventDesc = (const NLGUI::CEventDescriptorMouse &)event;
1797 panEnd = eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouseleftup && _Panning && _HasMoved;
1798 if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouseleftup && !panEnd)
1800 //if (CWidgetManager::getInstance()->getCapturePointerLeft() == this)
1801 // NB : don't test capture of mouse here, because
1802 // some R2 tool may begin outside of this window
1803 // example : clicking in the palette window and doing a drag-and-drop to the
1804 // minimap
1806 handled = R2::getEditor().getCurrentTool()->onMouseLeftButtonUp();
1807 if (!handled)
1809 handled = R2::getEditor().getCurrentTool()->onMouseLeftButtonClicked();
1812 if (!handled && R2::getEditor().getMode() == R2::CEditor::EditionMode)
1814 if (R2::getEditor().getCurrentTool())
1816 if (!R2::getEditor().getCurrentTool()->getPreviousToolClickEndFlag())
1818 if (CWidgetManager::getInstance()->getCapturePointerLeft() == this)
1820 // unselected unless tool has been changed before last mouse left up (happens when one's finish a route using double click -> should not unselect then)
1821 R2::getEditor().setSelectedInstance(NULL);
1827 else if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouserightup)
1829 if (CWidgetManager::getInstance()->getCapturePointerRight() == this)
1831 if (isIn(eventDesc.getX(), eventDesc.getY()))
1833 NLMISC::CVector2f clickPos;
1834 screenToMap(clickPos, eventDesc.getX(), eventDesc.getY());
1835 if (clickPos.x >= 0.f &&
1836 clickPos.y >= 0.f &&
1837 clickPos.x <= 1.f &&
1838 clickPos.y <= 1.f
1841 handled = R2::getEditor().getCurrentTool()->onMouseRightButtonClicked();
1847 if (!panEnd)
1849 handled = handled || R2::getEditor().getCurrentTool()->handleEvent(event);
1852 if (handled)
1854 _Panning = false;
1855 _HasMoved = false;
1856 return true;
1860 for (uint32 i = 0; i < _PolyButtons.size(); ++i)
1861 if (_PolyButtons[i]->handleEvent(event))
1862 return true;
1864 // left button can be used to 'pan' the map
1865 // mouse wheel can be used to zoom in/out
1866 if (event.getType() == NLGUI::CEventDescriptor::mouse)
1868 if (!_Active)
1869 return false;
1870 const NLGUI::CEventDescriptorMouse &eventDesc = (const NLGUI::CEventDescriptorMouse &)event;
1872 if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouseleftup)
1874 if (CWidgetManager::getInstance()->getCapturePointerLeft() != this)
1876 return false;
1878 _Panning = false;
1879 _HasMoved = false;
1880 return true;
1883 if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouserightdown)
1885 CWidgetManager::getInstance()->setCapturePointerRight(this);
1886 return true;
1889 if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouseleftdown)
1891 if (isIn(eventDesc.getX(), eventDesc.getY()))
1893 CWidgetManager::getInstance()->setCapturePointerLeft(this);
1894 _StartXForPaning = eventDesc.getX();
1895 _StartYForPaning = eventDesc.getY();
1896 _StartWorldOffsetForPaning = _WorldOffset;
1898 // Clamp the start WorldOffset on the Move start. NB: not clamped on a scale
1899 computeOffsets();
1900 _StartWorldOffsetForPaning.x= _Offset.x * (_MapMaxCorner.x - _MapMinCorner.x);
1901 _StartWorldOffsetForPaning.y= _Offset.y * (_MapMaxCorner.y - _MapMinCorner.y);
1903 _PanStartDateInMs = T1;
1904 /** If in editor, and current tool is a creation tool, only handle panning after a small delta pos / delta time
1905 * for better ergonomy
1907 if (ClientCfg.R2EDEnabled && R2::getEditor().getCurrentTool() &&
1908 R2::getEditor().getCurrentTool()->isCreationTool()
1911 _DeltaPosBeforePan = 2;
1912 _DeltaTimeBeforePanInMs = 300;
1914 else
1916 // handle panning immediately
1917 _DeltaPosBeforePan = 0;
1918 _DeltaTimeBeforePanInMs = 0;
1920 _Panning = true;
1921 return true;
1925 if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mousemove)
1927 if (CWidgetManager::getInstance()->getCapturePointerLeft() != this || !_Panning)
1928 return CInterfaceGroup::handleEvent(event);
1930 if (_MapTexW != 0 && _MapTexH != 0)
1932 if (_HasMoved || (T1 - _PanStartDateInMs) > _DeltaTimeBeforePanInMs ||
1933 (uint) abs(eventDesc.getX() - _StartXForPaning) > _DeltaPosBeforePan ||
1934 (uint) abs(eventDesc.getY() - _StartYForPaning) > _DeltaPosBeforePan)
1936 _HasMoved = true;
1937 NLMISC::CVector2f dWorld;
1938 dWorld.x= - (_MapMaxCorner.x - _MapMinCorner.x) * (eventDesc.getX() - _StartXForPaning) / (_MapTexW * _Scale);
1939 dWorld.y= + (_MapMaxCorner.y - _MapMinCorner.y) * (eventDesc.getY() - _StartYForPaning) / (_MapTexH * _Scale);
1940 _WorldOffset= _StartWorldOffsetForPaning + dWorld;
1942 // Clamp the WorldOffset on a Move. NB: not clamped on a scale
1943 computeOffsets();
1944 _WorldOffset.x= _Offset.x * (_MapMaxCorner.x - _MapMinCorner.x);
1945 _WorldOffset.y= _Offset.y * (_MapMaxCorner.y - _MapMinCorner.y);
1947 computeOffsets();
1948 invalidateCoords();
1951 return true;
1955 if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mousewheel && !_Panning)
1957 sint32 wheel = eventDesc.getWheel();
1958 float newScale = _UserScale;
1959 while (wheel != 0)
1961 if (wheel < 0)
1963 newScale *= 0.7f;
1964 if (newScale < 1.f)
1966 newScale = 1.f;
1967 break;
1969 ++ wheel;
1971 else
1973 newScale *= 1.3f;
1974 float realScale = computeRealScaleFromUserScale(newScale);
1975 if (realScale > getActualMaxScale())
1977 newScale = computeUserScaleFromRealScale(getActualMaxScale());
1978 break;
1980 -- wheel;
1983 NLMISC::CVector2f mapPos;
1984 screenToMap(mapPos, eventDesc.getX(), eventDesc.getY());
1985 setScale(newScale, mapPos);
1986 return true;
1989 if (eventDesc.getEventTypeExtended() == NLGUI::CEventDescriptorMouse::mouserightup)
1991 // convert click pos into map pos
1992 if (_MapTexW == 0 || _MapTexH == 0)
1994 _RightClickLastPos.set(0.f, 0.f);
1996 else
1998 NLMISC::CVector2f clickPos;
1999 screenToMap(clickPos, eventDesc.getX(), eventDesc.getY());
2000 if (clickPos.x < 0.f ||
2001 clickPos.y < 0.f ||
2002 clickPos.x > 1.f ||
2003 clickPos.y > 1.f
2006 return false;
2008 _RightClickLastPos = clickPos;
2009 return CInterfaceGroup::handleEvent(event);
2013 if (event.getType() == NLGUI::CEventDescriptor::system)
2015 NLGUI::CEventDescriptorSystem &es = (NLGUI::CEventDescriptorSystem &) event;
2016 if (es.getEventTypeExtended() == NLGUI::CEventDescriptorSystem::activecalledonparent)
2018 bool visible = getActive();
2019 if (visible)
2021 CInterfaceElement *curr = this->getParent();
2022 while (curr)
2024 if (!curr->getActive())
2026 visible = false;
2027 break;
2029 curr = curr->getParent();
2032 if (visible)
2034 checkCoords();
2036 else
2038 unloadMap();
2043 return CInterfaceGroup::handleEvent(event);
2046 //============================================================================================================
2047 void CGroupMap::pan(sint32 dx, sint32 dy)
2049 if (_MapTexW * _Scale != 0.f) _WorldOffset.x += dx * (_MapMaxCorner.x - _MapMinCorner.x) / (_MapTexW * _Scale);
2050 if (_MapTexH * _Scale != 0.f) _WorldOffset.y -= dy * (_MapMaxCorner.y - _MapMinCorner.y) / (_MapTexH * _Scale);
2051 computeOffsets();
2052 _WorldOffset.x= _Offset.x * (_MapMaxCorner.x - _MapMinCorner.x);
2053 _WorldOffset.y= _Offset.y * (_MapMaxCorner.y - _MapMinCorner.y);
2054 invalidateCoords();
2057 //============================================================================================================
2058 void CGroupMap::setActive(bool active)
2060 bool visible = active;
2061 CInterfaceElement *curr = this->getParent();
2062 while (curr)
2064 if (!curr->getActive())
2066 visible = false;
2067 break;
2069 curr = curr->getParent();
2071 if (!visible)
2073 unloadMap();
2075 CInterfaceGroup::setActive(active);
2076 if (visible)
2078 checkCoords();
2082 //============================================================================================================
2083 void CGroupMap::loadPlayerPos()
2085 if (_PlayerPosLoadFailure) return;
2086 _PlayerPosLoadFailure = true;
2087 if (_PlayerPosMaterial.empty())
2088 return;
2089 std::string fullName = NLMISC::CPath::lookup(_PlayerPosTexName, false, false);
2090 if (fullName.empty())
2092 nlwarning("Can't player pos texture %s", _PlayerPosTexName.c_str());
2093 return;
2095 uint32 w, h;
2096 NLMISC::CIFile bm;
2097 if (bm.open(fullName))
2101 NLMISC::CBitmap::loadSize(fullName, w, h);
2103 catch(const NLMISC::Exception &e)
2105 nlwarning(e.what());
2106 return;
2109 else
2111 nlwarning("Can't open player pos texture %s", fullName.c_str());
2112 return;
2114 _PlayerPosTF = Driver->createTextureFile(fullName);
2115 if (!_PlayerPosTF) return;
2116 _PlayerPosLoadFailure = false;
2117 _PlayerPosTF->setWrapS(NL3D::UTexture::Clamp);
2118 _PlayerPosTF->setWrapT(NL3D::UTexture::Clamp);
2119 _PlayerPosTexW = w;
2120 _PlayerPosTexH = h;
2121 _PlayerPosMaterial.setTexture(_PlayerPosTF);
2124 //============================================================================================================
2125 void CGroupMap::reload()
2127 if (!_CurMap || !getActive()) return;
2129 SMap* current = _CurMap;
2130 _CurMap = NULL;
2132 setMap(current);
2135 //============================================================================================================
2136 void CGroupMap::loadMap()
2138 _MapLoadFailure = true;
2139 if (!_CurMap) return;
2141 _MapTexture = _CurMap->BitmapName;
2143 // call lua game:onLoadMap() function if present
2144 // avoid deadlock if called recursively
2145 if (!_LuaLoadMapEntered)
2147 _LuaLoadMapEntered = true;
2148 CLuaState *ls = CLuaManager::getInstance().getLuaState();
2150 CLuaStackRestorer lsr(ls, ls->getTop());
2151 ls->pushGlobalTable();
2153 CLuaObject game(*ls);
2154 game = game["game"];
2155 if (!game["onLoadMap"].isNil())
2157 uint numArg = 1;
2158 uint numResult = 1;
2160 CLuaIHM::pushReflectableOnStack(*ls, this);
2161 if (game.callMethodByNameNoThrow("onLoadMap", numArg, numResult))
2163 if (ls->isString(1))
2165 if (!NLMISC::CPath::lookup(ls->toString(1), false, false).empty())
2166 _MapTexture = ls->toString(1);
2167 else
2168 nlwarning("Custom map texture not found '%s' for map '%s'", ls->toString(1), _MapTexture.c_str());
2173 _LuaLoadMapEntered = false;
2176 std::string fullName = NLMISC::CPath::lookup(_MapTexture, false, false);
2177 if (fullName.empty())
2179 nlwarning("Can't find map %s", _MapTexture.c_str());
2180 return;
2182 uint32 w, h;
2183 NLMISC::CIFile bm;
2184 if (bm.open(fullName))
2188 NLMISC::CBitmap::loadSize(fullName, w, h);
2190 catch(const NLMISC::Exception &e)
2192 nlwarning(e.what());
2193 return;
2196 else
2198 nlwarning("Can't open map %s", _MapTexture.c_str());
2199 return;
2201 _MapTF = Driver->createTextureFile(fullName);
2202 if (_MapTF)
2204 _MapMaterial.setTexture(0, _MapTF);
2205 _MapTF->setWrapS(NL3D::UTexture::Clamp);
2206 _MapTF->setWrapT(NL3D::UTexture::Clamp);
2207 _MapTF->setEnlargeCanvasNonPOW2Tex(true);
2208 if (_IsIsland)
2210 // island are already pow2 textures
2211 // compute the real size
2212 // (1 pixel per metter, hardcoded for now)
2213 _MapTexW = (uint32) (ISLAND_PIXEL_PER_METER * (_CurMap->MaxX - _CurMap->MinX));
2214 _MapTexH = (uint32) (ISLAND_PIXEL_PER_METER * (_CurMap->MaxY - _CurMap->MinY));
2215 if (_MapTexW > w)
2217 nlwarning("Island real width > texture width, snapshot not up-to-date ? (island = %s)", _CurMap->Name.c_str());
2218 _MapTexW = w;
2220 if (_MapTexH > h)
2222 nlwarning("Island real height > texture height, snapshot not up-to-date ? (island = %s)", _CurMap->Name.c_str());
2223 _MapTexH = h;
2225 _URatio = w != 0 ? (float) _MapTexW / w : 0.f;
2226 _VRatio = h != 0 ? (float) _MapTexH / h : 0.f;
2228 else
2230 // must raise to next power of 2 & scale uvs accordingly
2231 _MapTexW = w;
2232 _MapTexH = h;
2233 _URatio = (float) w / (float) NLMISC::raiseToNextPowerOf2(w);
2234 _VRatio = (float) h / (float) NLMISC::raiseToNextPowerOf2(h);
2236 _MapLoadFailure = false;
2240 //============================================================================================================
2241 void CGroupMap::unloadMap()
2243 // remove texture from the material
2244 if (_MapTF) Driver->deleteTextureFile(_MapTF);
2245 _MapTF = NULL;
2246 if (_PlayerPosTF) Driver->deleteTextureFile(_PlayerPosTF);
2247 _PlayerPosTF = NULL;
2248 _MapMaterial.setTexture(0,NULL);
2249 _MapMaterial.setTexture(1,NULL);
2250 _MapTexW = 0;
2251 _MapTexH = 0;
2252 _MapLoadFailure = false;
2255 //============================================================================================================
2256 void CGroupMap::updateContinentInfo()
2258 return;
2262 //============================================================================================================
2263 void CGroupMap::setMap(SMap *map)
2265 nlassert(map);
2266 if ((_CurMap != NULL) && (_CurMap->Name == map->Name)) return;
2268 // Unload and reset all stuff
2269 unloadMap();
2271 _CurMap = map;
2272 _CurContinent = ContinentMngr.get(_CurMap->ContinentName);
2273 _MapMinCorner.x = _CurMap->MinX;
2274 _MapMinCorner.y = _CurMap->MinY;
2275 _MapMaxCorner.x = _CurMap->MaxX;
2276 _MapMaxCorner.y = _CurMap->MaxY;
2277 if (_MapMinCorner.x > _MapMaxCorner.x) std::swap(_MapMinCorner.x, _MapMaxCorner.x);
2278 if (_MapMinCorner.y > _MapMaxCorner.y) std::swap(_MapMinCorner.y, _MapMaxCorner.y);
2280 loadMap();
2281 centerOnPlayer();
2282 centerOnPlayer();
2283 invalidateCoords();
2284 createContinentLandMarks();
2286 nlinfo("setMap (%f,%f) (%f,%f)", _CurMap->MinX, _CurMap->MinY, _CurMap->MaxX, _CurMap->MaxY);
2288 delArkPoints();
2290 CGroupHTML *groupHtml = dynamic_cast<CGroupHTML*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:map:content:map_content:lm_events:html"));
2292 if (groupHtml)
2294 groupHtml->setHome(groupHtml->Home+toString("&min_x=%f&min_y=%f&max_x=%f&max_y=%f", _CurMap->MinX, _CurMap->MinY, _CurMap->MaxX, _CurMap->MaxY));
2295 groupHtml->browse(groupHtml->Home.c_str());
2299 if (_CurContinent != NULL)
2300 _MapMaterial.setTexture(1, _CurContinent->FoW.Tx);
2301 else
2302 _MapMaterial.setTexture(1, NULL);
2304 // disable the map_back button for islands (islands can't be seen on the world map)
2305 CInterfaceGroup *gc = getParentContainer();
2306 if (gc)
2308 CCtrlBase *mapBack = gc->getCtrl("map_back");
2309 if (mapBack) mapBack->setActive(!_IsIsland);
2312 centerOnPlayer();
2313 setScale(0);
2316 //============================================================================================================
2317 void CGroupMap::setMap(const string &mapName)
2319 if ((_CurMap != NULL) && (_CurMap->Name == mapName)) return;
2321 // Unload and reset all stuff
2322 unloadMap();
2324 _IsIsland = false;
2326 // Acquire new map
2327 uint32 i;
2328 for (i = 0; i < _WorldSheet->Maps.size(); ++i)
2329 if (_WorldSheet->Maps[i].Name == mapName)
2330 break;
2332 if (i == _WorldSheet->Maps.size())
2334 nlwarning("Unknown map to set : %s", mapName.c_str());
2335 return;
2337 setMap(&_WorldSheet->Maps[i]);
2339 centerOnPlayer();
2340 setScale(0);
2343 //============================================================================================================
2344 void CGroupMap::centerOnPlayer()
2346 if (_MapTexW == 0 || _MapTexH == 0) return;
2348 // Ensure good scale computed
2349 updateScale();
2351 // Here, in some case (init, if the map is not displayed), scale is 0. Avoid div by 0.
2352 float lx= (_MapTexW * _Scale);
2353 float ly= (_MapTexH * _Scale);
2354 if(lx==0.f) lx= 0.01f;
2355 if(ly==0.f) ly= 0.01f;
2356 _WorldOffset.x = (_MapMaxCorner.x - _MapMinCorner.x) * (_MapX - _WReal * 0.5f) / lx;
2357 _WorldOffset.y = (_MapMaxCorner.y - _MapMinCorner.y) * (- _MapY - _HReal * 0.5f) / ly;
2359 computeOffsets();
2360 invalidateCoords();
2362 //============================================================================================================
2363 void CGroupMap::centerOnWorldPos(const CVector2f &worldPos)
2365 CVector2f mapPos;
2366 worldToMap(mapPos, worldPos);
2368 sint32 sx, sy;
2369 mapToScreen(sx, sy, mapPos);
2371 sint32 x, y, w, h;
2372 computeMapRectInsideGroup(x, y, w, h);
2374 sint32 dx, dy;
2375 if (sx < getXReal())
2376 dx = -(getXReal() - sx + w/2);
2377 else
2378 dx = sx - getXReal() - w/2;
2380 if (sy < getYReal())
2381 dy = -(getYReal() - sy + h/2);
2382 else
2383 dy = sy - getYReal() - h/2;
2385 pan(dx, dy);
2388 //============================================================================================================
2389 void CGroupMap::setScale(float newUserScale, const NLMISC::CVector2f &/* center */)
2391 NLMISC::clamp(newUserScale, 1.f, computeUserScaleFromRealScale(getActualMaxScale()));
2393 _UserScale = newUserScale;
2394 computeOffsets();
2395 //fitWindow();
2396 invalidateCoords();
2399 //============================================================================================================
2400 void CGroupMap::setScale(float newScale)
2402 sint32 centerX = (2 * (_XReal + _MapX) + std::min(_WReal, _MapW)) / 2;
2403 sint32 centerY = (2 * (_YReal + _MapY) + std::min(_HReal, _MapH)) / 2;
2404 NLMISC::CVector2f mapCoords;
2405 screenToMap(mapCoords, centerX, centerY);
2406 setScale(newScale, mapCoords);
2409 //============================================================================================================
2410 void CGroupMap::updateLandMarkList(TLandMarkButtonVect &lmVect)
2412 uint numLM = (uint)lmVect.size();
2413 for(uint k = 0; k < numLM; ++k)
2415 CLandMarkButton *lmb = lmVect[k];
2416 if (lmb)
2418 updateButtonPos(*lmb);
2423 //============================================================================================================
2424 void CGroupMap::updateLandMarkTextList(TLandMarkTextVect &lmVect)
2426 uint numLM = (uint)lmVect.size();
2427 for(uint k = 0; k < numLM; ++k)
2429 CLandMarkText *lmt = lmVect[k];
2430 if (lmt != NULL)
2432 sint32 x, y;
2433 mapToWindowSnapped(x, y, lmt->Pos);
2434 lmt->setX(x);
2435 lmt->setY(y);
2440 //============================================================================================================
2441 void CGroupMap::updateMatchedLandmarks()
2443 CInterfaceGroup *gc = getParentContainer();
2444 if (!gc) return;
2446 // visible landmark count
2447 CViewText *pVT = dynamic_cast<CViewText *>(gc->getView("lm_count"));
2448 if (pVT)
2450 // show total landmark count if search filter has not been set
2451 uint c = _MatchedLandmarks.size();
2452 if (c == 0 && _LandmarkFilter.size() == 0)
2453 c = _UserLM.size();
2455 pVT->setText(toString(c));
2458 // list of matched landmarks
2459 CGroupList *pL = dynamic_cast<CGroupList *>(gc->getGroup("lm_result"));
2460 if (!pL) return;
2462 pL->clearGroups();
2464 if (_LandmarkFilter.size() == 0) return;
2466 // create result list
2467 for(uint k = 0; k < _MatchedLandmarks.size(); ++k)
2469 std::vector<std::pair<string,string> > params;
2470 params.clear();
2471 params.push_back(std::pair<string,string>("id", toString("lm%d", k)));
2472 // ctrl base expects utf8 string to start with "u:"
2473 params.push_back(std::pair<string,string>("tooltip", "u:" + _MatchedLandmarks[k].Title.toUtf8()));
2474 params.push_back(std::pair<string,string>("index", toString(k)));
2476 CInterfaceGroup *g = CWidgetManager::getInstance()->getParser()->createGroupInstance("lm_search_result", pL->getId(), params);
2477 if (g)
2479 pL->addChild(g);
2481 CViewText* t = dynamic_cast<CViewText *>(g->getView("title"));
2482 if (t)
2484 t->setSingleLineTextFormatTaged(_MatchedLandmarks[k].Title.toUtf8());
2487 CViewBitmap* b = dynamic_cast<CViewBitmap *>(g->getView("icon"));
2488 if (b)
2490 b->setTexture(_MatchedLandmarks[k].Options.LandMarkTexNormal);
2491 b->setColor(_MatchedLandmarks[k].Options.ColorNormal);
2495 pL->invalidateCoords();
2498 //============================================================================================================
2499 void CGroupMap::removeLandMarks(TLandMarkButtonVect &lm)
2501 uint numLM = (uint)lm.size();
2502 for(uint k = 0; k < numLM; ++k)
2504 if (lm[k])
2506 delCtrl(lm[k]);
2509 lm.clear();
2513 //============================================================================================================
2514 void CGroupMap::removeUserLandMarks()
2516 removeLandMarks(_UserLM);
2520 //============================================================================================================
2521 void CGroupMap::createLMWidgets(const std::vector<CContLandMark> &lms)
2523 // disable any match in "world" mode
2524 bool notWorldMode = _CurMap->Name != "world";
2526 for (uint32 k = 0; k < lms.size(); ++k)
2528 const CContLandMark &rCLM =lms[k];
2530 NLMISC::CVector2f mapPos;
2531 worldToMap(mapPos, rCLM.Pos);
2533 const char *ucsTmp = CStringManagerClient::getPlaceLocalizedName(rCLM.TitleTextID);
2534 const std::string lcTitle = toLower(ucsTmp);
2536 bool searchMatch = notWorldMode && _LandmarkFilter.size() > 0 && filterLandmark(lcTitle);
2537 if (searchMatch)
2538 _MatchedLandmarks.push_back(SMatchedLandmark(rCLM.Pos, ucstring::makeFromUtf8(ucsTmp), _ContinentLMOptions));
2540 // Add button if not a region nor a place
2541 if ((rCLM.Type != CContLandMark::Region) && (rCLM.Type != CContLandMark::Place) &&
2542 (rCLM.Type != CContLandMark::Street))
2544 if (rCLM.Type != CContLandMark::Stable)
2545 addLandMark(_ContinentLM, mapPos, ucstring::makeFromUtf8(ucsTmp), _ContinentLMOptions);
2546 else
2547 addLandMark(_ContinentLM, mapPos, CI18N::get("uiStable"), _ContinentLMOptions);
2548 _ContinentLM.back()->Type = rCLM.Type;
2549 _ContinentLM.back()->SearchMatch = searchMatch;
2551 else // just add a text
2553 CLandMarkText *pNewText = new CLandMarkText(CViewBase::TCtorParam());
2554 pNewText->setText(ucsTmp);
2555 pNewText->Pos = mapPos;
2556 pNewText->setParent(this);
2557 pNewText->setParentPosRef(Hotspot_BL);
2558 pNewText->setPosRef(Hotspot_MM);
2559 if (rCLM.Type == CContLandMark::Region)
2560 pNewText->setFontSize(16);
2562 pNewText->setColor(CRGBA(255,255,255,255));
2563 pNewText->setShadow(true);
2564 pNewText->setShadowOutline(false);
2565 pNewText->setShadowColor(CRGBA(0,0,0,255));
2566 pNewText->setModulateGlobalColor(false);
2567 pNewText->Type = rCLM.Type;
2568 pNewText->SearchMatch = searchMatch;
2569 _ContinentText.push_back(pNewText);
2570 addView(pNewText);
2573 // If the name of the landmark is used as a click zone name of the current map, create a polybutton
2574 bool bFound = false;
2575 for (uint i = 0; i < _CurMap->Children.size(); ++i)
2577 if (rCLM.TitleTextID == _CurMap->Children[i].ZoneName)
2579 bFound = true;
2580 break;
2583 if (bFound)
2585 CPolyButton *pPB = new CPolyButton;
2586 pPB->build(rCLM.Zone, this, rCLM.TitleTextID);
2587 _PolyButtons.push_back(pPB);
2588 addCtrl(pPB);
2593 //============================================================================================================
2594 void CGroupMap::createContinentLandMarks()
2596 uint32 k;
2597 _MatchedLandmarks.clear();
2599 if (_MapMode != MapMode_Normal) return;
2600 if (_CurMap == NULL) return;
2602 // Remove all
2603 removeLandMarks(_ContinentLM);
2604 for (k = 0; k < _ContinentText.size(); ++k)
2605 delView(_ContinentText[k]);
2606 _ContinentText.clear();
2607 removeLandMarks(_UserLM);
2608 for (k = 0; k < _PolyButtons.size(); ++k)
2609 delCtrl(_PolyButtons[k]);
2610 _PolyButtons.clear();
2612 // World map special case
2613 if (_CurMap->Name == "world")
2615 createLMWidgets(ContinentMngr.WorldMap);
2617 else if (_CurContinent)
2619 // Continent Landmarks
2620 createLMWidgets(_CurContinent->ContLandMarks);
2621 // User Landmarks
2622 for(k = 0; k < _CurContinent->UserLandMarks.size(); ++k)
2624 NLMISC::CVector2f mapPos;
2625 worldToMap(mapPos, _CurContinent->UserLandMarks[k].Pos);
2627 CLandMarkOptions options = getUserLandMarkOptions(k);
2628 addLandMark(_UserLM, mapPos, _CurContinent->UserLandMarks[k].Title, options);
2630 if (_LandmarkFilter.size() > 0)
2632 if (filterLandmark(_CurContinent->UserLandMarks[k].Title))
2634 _MatchedLandmarks.push_back(SMatchedLandmark(_CurContinent->UserLandMarks[k].Pos, _CurContinent->UserLandMarks[k].Title, options));
2636 else
2638 _UserLM.back()->setActive(false);
2644 updateMatchedLandmarks();
2645 invalidateCoords();
2648 static void hideTeleportButtonsInPopupMenuIfNotEnoughPriv()
2650 bool showTeleport = (hasPrivilegeDEV() || hasPrivilegeSGM() || hasPrivilegeGM() || hasPrivilegeVG() || hasPrivilegeSG() || hasPrivilegeEM() || hasPrivilegeEG());
2651 CInterfaceManager *im = CInterfaceManager::getInstance();
2653 CInterfaceElement *ie = CWidgetManager::getInstance()->getElementFromId("ui:interface:map_menu:teleport");
2654 if(ie) ie->setActive(showTeleport);
2656 ie = CWidgetManager::getInstance()->getElementFromId("ui:interface:map_menu_island:teleport");
2657 if(ie) ie->setActive(showTeleport);
2659 ie = CWidgetManager::getInstance()->getElementFromId("ui:interface:land_mark_menu:lmteleport");
2660 if(ie) ie->setActive(showTeleport);
2662 ie = CWidgetManager::getInstance()->getElementFromId("ui:interface:user_land_mark_menu:lmteleport");
2663 if(ie) ie->setActive(showTeleport);
2665 ie = CWidgetManager::getInstance()->getElementFromId("ui:interface:user_land_mark_menu_base:lmteleport");
2666 if(ie) ie->setActive(showTeleport);
2669 //============================================================================================================
2670 void CGroupMap::setLandmarkFilter(const std::string &s)
2672 _LandmarkFilter.clear();
2674 if (!s.empty()) {
2675 splitUCString(ucstring(toLower(s)), ucstring(" "), _LandmarkFilter);
2678 // recreate landmarks
2679 createContinentLandMarks();
2682 //============================================================================================================
2683 void CGroupMap::updateUserLandMarks()
2685 uint32 k;
2687 if (_MapMode != MapMode_Normal) return;
2688 if (_CurMap == NULL || _CurMap->Name == "world" || _CurContinent == NULL) return;
2690 // Remove all
2691 removeLandMarks(_UserLM);
2693 // Re create User Landmarks
2694 for(k = 0; k < _CurContinent->UserLandMarks.size(); ++k)
2696 NLMISC::CVector2f mapPos;
2697 worldToMap(mapPos, _CurContinent->UserLandMarks[k].Pos);
2699 addLandMark(_UserLM, mapPos, _CurContinent->UserLandMarks[k].Title, getUserLandMarkOptions(k));
2701 // hide landmark if not matching filter
2702 if (!filterLandmark(_CurContinent->UserLandMarks[k].Title))
2703 _UserLM.back()->setActive(false);
2705 invalidateCoords();
2707 hideTeleportButtonsInPopupMenuIfNotEnoughPriv();
2711 //============================================================================================================
2712 CGroupMap::CLandMarkButton *CGroupMap::createLandMarkButton(const CLandMarkOptions &options)
2714 CLandMarkButton *lmb = new CLandMarkButton(CViewBase::TCtorParam());
2715 static int statFool = 0;
2716 lmb->setId(this->getId()+":lm"+toString(statFool++));
2717 lmb->setTexture(options.LandMarkTexNormal);
2718 lmb->setTextureOver(options.LandMarkTexOver);
2719 lmb->setTexturePushed(options.LandMarkTexPushed);
2720 lmb->setType(CCtrlButton::PushButton);
2721 lmb->setActionOnLeftClick("land_mark_selected");
2722 lmb->setColor(options.ColorNormal);
2723 lmb->setColorOver(options.ColorOver);
2724 lmb->setColorPushed(options.ColorPushed);
2725 lmb->setModulateGlobalColorAll(false);
2726 if (!options.LandMarkMenu.empty())
2728 lmb->setActionOnRightClick("world_map_right_click");
2729 lmb->setParamsOnRightClick(NLMISC::toString("map=%s|menu=%s", _Id.c_str(), options.LandMarkMenu.c_str()));
2731 lmb->setPosRef(Hotspot_MM);
2732 return lmb;
2735 //============================================================================================================
2736 CGroupMap::CLandMarkButton *CGroupMap::createArkPointButton(const CArkPoint &point)
2738 CLandMarkButton *lmb = new CLandMarkButton(CViewBase::TCtorParam());
2739 static int statFool = 0;
2740 lmb->setId(this->getId()+":lm"+toString(statFool++));
2741 lmb->setTexture(point.Texture);
2742 lmb->setTextureOver(point.Texture);
2743 lmb->setTexturePushed(point.Texture);
2744 lmb->setType(CCtrlButton::PushButton);
2745 lmb->setActionOnLeftClick(point.LeftClickAction);
2746 lmb->setParamsOnLeftClick(point.LeftClickParam);
2747 lmb->setActionOnRightClick(point.RightClickAction);
2748 lmb->setParamsOnRightClick(point.RightClickParam);
2749 lmb->setColor(point.Color);
2750 lmb->setColorOver(point.Color);
2751 lmb->setColorPushed(point.Color);
2752 lmb->setModulateGlobalColorAll(false);
2754 lmb->setPosRef(Hotspot_MM);
2755 return lmb;
2758 //============================================================================================================
2759 void CGroupMap::updateLandMarkButton(CLandMarkButton *lmb, const CLandMarkOptions &options)
2761 lmb->setTexture(options.LandMarkTexNormal);
2762 lmb->setTextureOver(options.LandMarkTexOver);
2763 lmb->setTexturePushed(options.LandMarkTexPushed);
2765 lmb->setColor(options.ColorNormal);
2766 lmb->setColorOver(options.ColorOver);
2767 lmb->setColorPushed(options.ColorPushed);
2770 //============================================================================================================
2771 bool CGroupMap::filterLandmark(const ucstring &title, const std::vector<ucstring> filter, bool startsWith) const
2773 if (filter.size() > 0)
2775 ucstring lcTitle = toLower(title);
2776 if (startsWith)
2778 if (lcTitle.find(filter[0]) != 0)
2780 return false;
2783 else
2785 for(uint i = 0; i< filter.size(); ++i)
2787 if (lcTitle.find(filter[i]) == ucstring::npos)
2789 return false;
2794 return true;
2797 //============================================================================================================
2798 bool CGroupMap::filterLandmark(const ucstring &title) const
2800 return filterLandmark(title, _LandmarkFilter);
2803 //============================================================================================================
2804 void CGroupMap::addLandMark(TLandMarkButtonVect &destList, const NLMISC::CVector2f &pos, const ucstring &title, const CLandMarkOptions &options)
2806 // create a new button and add it to the list
2807 CLandMarkButton *lmb = createLandMarkButton(options);
2808 lmb->setParent(this);
2809 lmb->Pos = pos;
2810 lmb->setDefaultContextHelp(title.toUtf8());
2811 destList.push_back(lmb);
2812 addCtrl(lmb);
2815 //============================================================================================================
2816 void CGroupMap::addUserLandMark(const NLMISC::CVector2f &pos, const ucstring &title, NLMISC::CRGBA color)
2818 if (_CurContinent == NULL) return;
2820 CUserLandMark ulm;
2821 mapToWorld(ulm.Pos, pos);
2822 ulm.Title = title;
2823 ulm.Type = 5;
2824 _CurContinent->UserLandMarks.push_back(ulm);
2826 CLandMarkOptions options(_UserLMOptions);
2827 options.ColorNormal = options.ColorOver = options.ColorPushed = color;
2828 // create a new button and add it to the list
2829 CLandMarkButton *lmb = createLandMarkButton(options);
2830 lmb->setParent(this);
2831 lmb->Pos = pos;
2832 lmb->setDefaultContextHelp(title.toUtf8());
2833 _UserLM.push_back(lmb);
2834 addCtrl(lmb);
2835 invalidateCoords();
2838 //============================================================================================================
2839 void CGroupMap::delArkPoints()
2841 for (uint i = 0; i < _RespawnLM.size(); i++)
2843 delCtrl(_RespawnLM[i]);
2844 _RespawnLM[i] = NULL;
2846 _ArkPoints.clear();
2849 //============================================================================================================
2850 void CGroupMap::addUserRespawnPoint(const NLMISC::CVector2f &pos)
2852 CRespawnPointsMsg rpm;
2853 rpm.NeedToReset = false;
2854 rpm.RespawnPoints.push_back(CRespawnPointsMsg::SRespawnPoint(pos.x*1000,pos.y*1000));
2855 addRespawnPoints(rpm);
2859 //============================================================================================================
2860 CCtrlButton *CGroupMap::addUserLandMark(const NLMISC::CVector2f &pos, const ucstring &title, const CUserLandMark::EUserLandMarkType lmType)
2862 if (_CurContinent == NULL) return NULL;
2863 nlassert(_CurContinent->UserLandMarks.size() == _UserLM.size());
2864 // add the landmark in the current continent (for later save)
2865 // keep pos in world
2866 CUserLandMark ulm;
2867 mapToWorld(ulm.Pos, pos);
2868 ulm.Title = title;
2869 ulm.Type = (uint8)lmType;
2870 _CurContinent->UserLandMarks.push_back(ulm);
2872 // add a landmark with a menu to remove it
2873 addLandMark(_UserLM, pos, title, getUserLandMarkOptions((uint32)_CurContinent->UserLandMarks.size() - 1));
2875 // Save the config file each time a user landmark is created
2876 CInterfaceManager::getInstance()->saveLandmarks();
2878 return _UserLM.back();
2881 //============================================================================================================
2882 CCtrlButton* CGroupMap::getLandmarkCtrl(const std::string &lmType, uint lmIndex) const
2884 CCtrlButton *ctrl = NULL;
2885 if (lmType == "user")
2887 if (lmIndex < _UserLM.size())
2889 ctrl = _UserLM[lmIndex];
2891 else nlwarning("_UserLM index out of bounds (size:%u, index:%u)", (uint)_UserLM.size(), lmIndex);
2893 else nlwarning("unsupported landmark type '%s'", lmType.c_str());
2895 return ctrl;
2898 //============================================================================================================
2899 void CGroupMap::removeUserLandMark(CCtrlButton *button)
2901 if (_CurContinent == NULL) return;
2902 nlassert(_CurContinent->UserLandMarks.size() >= _UserLM.size());
2903 for(uint k = 0; k < _UserLM.size(); ++k)
2905 if (_UserLM[k] == button)
2907 delCtrl(_UserLM[k]);
2908 _UserLM.erase(_UserLM.begin() + k);
2909 _CurContinent->UserLandMarks.erase(_CurContinent->UserLandMarks.begin() + k);
2911 if (_CurContinent->UserLandMarks.size() > _UserLM.size())
2913 // if user has over the limit landmarks, then rebuild visible markers
2914 updateUserLandMarks();
2917 CInterfaceManager::getInstance()->saveLandmarks();
2918 return;
2923 //============================================================================================================
2924 void CGroupMap::updateUserLandMark(CCtrlButton *button, const ucstring &newTitle, const CUserLandMark::EUserLandMarkType lmType)
2926 if (_CurContinent == NULL) return;
2927 nlassert(_CurContinent->UserLandMarks.size() >= _UserLM.size());
2928 for(uint k = 0; k < _UserLM.size(); ++k)
2930 if (_UserLM[k] == button)
2932 _CurContinent->UserLandMarks[k].Title = newTitle;
2933 _CurContinent->UserLandMarks[k].Type = (uint8)lmType;
2935 updateLandMarkButton(_UserLM[k], getUserLandMarkOptions(k));
2936 button->setDefaultContextHelp(newTitle.toUtf8());
2938 CInterfaceManager::getInstance()->saveLandmarks();
2939 return;
2944 //============================================================================================================
2945 CUserLandMark CGroupMap::getUserLandMark(CCtrlButton *button) const
2947 CUserLandMark ulm;
2948 if (_CurContinent == NULL) return ulm;
2949 nlassert(_CurContinent->UserLandMarks.size() >= _UserLM.size());
2950 for(uint k = 0; k < _UserLM.size(); ++k)
2952 if (_UserLM[k] == button)
2954 return _CurContinent->UserLandMarks[k];
2959 return ulm;
2962 //============================================================================================================
2963 uint CGroupMap::getNumUserLandMarks() const
2965 if (_CurContinent == NULL) return 0;
2966 return (uint)_CurContinent->UserLandMarks.size();
2968 //============================================================================================================
2969 CLandMarkOptions CGroupMap::getUserLandMarkOptions(uint32 lmindex) const
2971 if (_CurContinent == NULL || _CurContinent->UserLandMarks.size() < lmindex)
2972 return _UserLMOptions;
2974 CLandMarkOptions clmo(_UserLMOptions);
2975 clmo.ColorNormal = clmo.ColorOver = clmo.ColorPushed = _CurContinent->UserLandMarks[lmindex].getColor();
2977 return clmo;
2982 //============================================================================================================
2983 void CGroupMap::updatePlayerPos()
2985 if (_MapMode != MapMode_SpawnSquad)
2987 if (EntitiesMngr.entities().empty()) return;
2988 if (!EntitiesMngr.entity(0)) return;
2989 const NLMISC::CVectorD &playerPosD = EntitiesMngr.entity(0)->pos();
2990 NLMISC::CVector pos((float) playerPosD.x, (float) playerPosD.y, (float) playerPosD.z);
2991 // convert player pos into pos in map
2992 worldToMap(_PlayerPos, pos);
2993 // if player isn't in is last map anymore, see if in another island
2994 bool isInX = false;
2995 bool isInY = false;
2996 if(_CurMap)
2998 isInX = (_CurMap->MinX <= pos.x) && (pos.x <= _CurMap->MaxX);
2999 isInY = (_CurMap->MinY <= pos.y) && (pos.y <= _CurMap->MaxY);
3001 if(!isInX || !isInY)
3003 _IsIsland = false;
3004 for(uint k = 0; k < _Islands.size(); ++k)
3006 if (pos.x >= _Islands[k].MinX &&
3007 pos.y >= _Islands[k].MinY &&
3008 pos.x <= _Islands[k].MaxX &&
3009 pos.y <= _Islands[k].MaxY)
3011 _IsIsland = true;
3012 setMap(&_Islands[k]);
3013 break;
3020 //============================================================================================================
3022 void CGroupMap::fitWindow()
3025 if (!EntitiesMngr.entity(0)) return;
3026 CGroupContainer *parentCont = this->getEnclosingContainer();
3027 if (!parentCont) return;
3028 CCtrlBase::updateCoords();
3029 const NLMISC::CVectorD &playerPosD = EntitiesMngr.entity(0)->pos();
3030 NLMISC::CVector pos((float) playerPosD.x, (float) playerPosD.y, (float) playerPosD.z);
3031 // convert player pos into pos in map
3032 worldToMap(_PlayerPos, pos);
3033 // x coord
3034 if (_MapTexW != 0)
3036 float mapWidthOnScreen = floorf(_MapTexW * _Scale);
3037 sint32 diffWReal = parentCont->getWReal() - _WReal;
3038 if ((float)_WReal >= mapWidthOnScreen)
3040 _Offset.x = - _PlayerPos.x;
3041 // _W is given by parent, so must update parent W
3042 if ((float)_WReal > mapWidthOnScreen)
3044 parentCont->setW((sint32) mapWidthOnScreen + diffWReal);
3047 else
3049 NLMISC::clamp(_Offset.x, - _PlayerPos.x, - _PlayerPos.x + 1.f - _WReal / ((float) _MapTexW * _Scale));
3051 sint32 maxW = (sint32) mapWidthOnScreen;
3052 sint32 minW = std::min((sint32) mapWidthOnScreen, _MinW);
3053 parentCont->setMaxW(maxW + diffWReal);
3054 parentCont->setMinW(minW + diffWReal);
3055 parentCont->setPopupMaxW(maxW + diffWReal);
3056 parentCont->setPopupMinW(minW + diffWReal);
3057 if ((float)_WReal < minW)
3059 parentCont->setW((sint32) mapWidthOnScreen + diffWReal);
3062 // y coord
3063 if (_MapTexH != 0)
3065 //sint32 diffHReal = parentCont->getHReal() - _HReal;
3066 float mapHeightOnScreen = floorf(_MapTexH * _Scale);
3067 // parentCont->setPopupMaxH((sint32) mapHeightOnScreen + diffHReal);
3068 // parentCont->setPopupMinH((sint32) std::min(_MinH, (sint32) mapHeightOnScreen) + diffHReal);
3070 if ((float)_HReal >= mapHeightOnScreen)
3072 _Offset.y = - _PlayerPos.y;
3073 if ((float)_HReal > mapHeightOnScreen)
3075 _H = (sint32) mapHeightOnScreen;
3078 else
3080 _H = std::max(_H, std::min(_MinH, (sint32) mapHeightOnScreen));
3081 NLMISC::clamp(_Offset.y, - _PlayerPos.y, - _PlayerPos.y + 1.f - _H / ((float) mapHeightOnScreen));
3087 //============================================================================================================
3088 void CGroupMap::evalMapOffset(float userScale, float &scale, sint32 &x, sint32 &y) const
3090 if (_MapTexW == 0 || _MapTexH == 0)
3092 x = 0;
3093 y = 0;
3094 return;
3096 float scaleX = (float) _WReal / (float) _MapTexW;
3097 float scaleY = (float) _HReal / (float) _MapTexH;
3098 scale = std::min(scaleX, scaleY) * userScale;
3099 // center the map if needed
3100 sint32 w = (sint32) (scale * _MapTexW);
3101 x = (_WReal - w) / 2;
3102 sint32 h = (sint32) (scale * _MapTexH);
3103 y = (h - _HReal) / 2;
3106 //============================================================================================================
3107 float CGroupMap::computeRealScaleFromUserScale(float userScale) const
3109 float scaleX = (float) _WReal / (float) _MapTexW;
3110 float scaleY = (float) _HReal / (float) _MapTexH;
3111 return std::min(scaleX, scaleY) * userScale;//
3114 //============================================================================================================
3115 float CGroupMap::computeUserScaleFromRealScale(float realScale) const
3117 float scaleX = (float) _WReal / (float) _MapTexW;
3118 float scaleY = (float) _HReal / (float) _MapTexH;
3119 if (scaleX <= 0.f || scaleY <= 0.f) return 1.f;
3120 return realScale / std::min(scaleX, scaleY);
3123 //============================================================================================================
3124 void CGroupMap::updateScale()
3126 if (_MapTexW == 0 || _MapTexH == 0)
3128 _Scale = _UserScale;
3129 return;
3131 else
3133 _Scale = std::min(getActualMaxScale(), computeRealScaleFromUserScale(_UserScale));
3135 // center the map if needed
3136 sint32 w = (sint32) (_Scale * _MapTexW);
3137 _MapW = w;
3138 _MapX = (_WReal - w) / 2;
3139 sint32 h = (sint32) (_Scale * _MapTexH);
3140 _MapY = (h - _HReal) / 2;
3141 _MapH = h;
3143 computeOffsets();
3146 //=========================================================================================================
3147 void CGroupMap::computeMapRectInsideGroup(sint32 &x, sint32 &y, sint32 &w, sint32 &h) const
3149 x = std::max((sint32) 0, _MapX);
3150 w = std::min(_WReal, _MapX + _MapW);
3151 y = std::max((sint32) 0, _MapY);
3152 h = std::min(_HReal, _MapY + _MapH);
3153 y = std::max((sint32) 0, (_HReal - _MapY));
3156 //=========================================================================================================
3157 void CGroupMap::computeOffsets()
3159 if (_MapTexW == 0 || _MapTexH == 0)
3161 _WorldOffset.set(0.f, 0.f);
3162 _Offset.set(0.f, 0.f);
3163 return;
3166 // avoid div by 0 (nb: duno if those values can be negative...)
3167 float lx= _MapMaxCorner.x - _MapMinCorner.x;
3168 float ly= _MapMaxCorner.y - _MapMinCorner.y;
3169 if(lx==0.f) lx= 0.01f;
3170 if(ly==0.f) ly= 0.01f;
3171 _Offset.x= _WorldOffset.x / lx;
3172 _Offset.y= _WorldOffset.y / ly;
3174 float startCornerX = _Offset.x + _PlayerPos.x;
3175 if (_MapX < 0) startCornerX -= _MapX / (_MapTexW * _Scale);
3176 float startCornerY = _Offset.y + _PlayerPos.y;
3177 if (_MapY > 0) startCornerY += _MapY / (_MapTexH * _Scale);
3178 float endCornerX = startCornerX;
3179 float endCornerY = startCornerY;
3180 NLMISC::clamp(endCornerX, 0.f, 1.f - std::min(_MapW, _WReal) / ((float) _MapTexW * _Scale));
3181 NLMISC::clamp(endCornerY, 0.f, 1.f - std::min(_MapH, _HReal) / ((float) _MapTexH * _Scale));
3182 _Offset.x += endCornerX - startCornerX;
3183 _Offset.y += endCornerY - startCornerY;
3186 //=========================================================================================================
3187 void CGroupMap::targetLandmark(CCtrlButton *lm)
3189 if (!lm) return;
3190 // continent landmarks
3191 CCompassTarget ct;
3192 bool found = false;
3193 TLandMarkButtonVect::iterator it = std::find(_ContinentLM.begin(), _ContinentLM.end(),lm);
3195 if (it != _ContinentLM.end())
3197 ct.setType(CCompassTarget::ContinentLandMark);
3198 (*it)->getContextHelp(ct.Name);
3199 mapToWorld(ct.Pos, (*it)->Pos);
3200 found = true;
3203 if (!found)
3205 // mission landmarks
3206 it = std::find(_MissionLM.begin(), _MissionLM.end(),lm);
3208 if (it != _MissionLM.end())
3210 ct.setPositionState(_MissionPosStates[it - _MissionLM.begin()]);
3211 (*it)->getContextHelp(ct.Name);
3212 mapToWorld(ct.Pos, (*it)->Pos);
3213 found = true;
3217 if (!found)
3219 // user landmarks
3220 it = std::find(_UserLM.begin(), _UserLM.end(),lm);
3222 if (it != _UserLM.end())
3224 ct.setType(CCompassTarget::UserLandMark);
3225 (*it)->getContextHelp(ct.Name);
3226 mapToWorld(ct.Pos, (*it)->Pos);
3227 found = true;
3231 // home
3232 if (!found)
3234 if (lm == _HomeLM)
3236 // pos irrelevant for home, recomputed at each frame
3237 ct.setType(CCompassTarget::Home);
3238 ct.Name = CI18N::get("uiHome");
3239 found = true;
3242 // respawn point
3243 if (!found)
3245 // if in island -> no effect when choosing entry point for now
3246 it = std::find(_RespawnLM.begin(), _RespawnLM.end(),lm);
3248 if (it != _RespawnLM.end())
3250 if (!isIsland())
3252 ct.setType(CCompassTarget::Respawn);
3253 (*it)->getContextHelp(ct.Name);
3254 mapToWorld(ct.Pos, (*it)->Pos);
3255 found = true;
3257 // pos irrelevant for respawn point, recomputed at each frame
3258 if ((_MapMode == MapMode_Death) || (_MapMode == MapMode_SpawnSquad))
3260 _RespawnSelectedBitmap->setParentPos(*it);
3261 string sTmp = (*it)->getId();
3262 sTmp = sTmp.substr(sTmp.rfind('_')+1, sTmp.size());
3263 fromString(sTmp, _RespawnSelected);
3264 CInterfaceManager *pIM = CInterfaceManager::getInstance();
3265 if (_MapMode == MapMode_Death)
3266 NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:RESPAWN_PT")->setValue32(_RespawnSelected);
3267 else if (_MapMode == MapMode_SpawnSquad)
3269 NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP:OUTPOST:SQUAD_RESPAWN_PT")->setValue32(_RespawnSelected);
3270 // Close window containing the map
3271 CInterfaceGroup *pGrp = CWidgetManager::getInstance()->getWindow(this);
3272 if (pGrp != NULL) pGrp->setActive(false);
3274 invalidateCoords();
3279 // target
3280 if (!found)
3282 if (lm == _TargetLM)
3284 // pos irrelevant for respwan, recomputed at each frame
3285 ct.setType(CCompassTarget::Selection);
3286 found = true;
3289 // animals
3290 if (!found)
3292 // animals landmarks
3293 if(_AnimalLM.size() == _AnimalPosStates.size())
3295 for(uint i=0;i<_AnimalLM.size();i++)
3297 if(_AnimalLM[i]==lm)
3299 _AnimalLM[i]->getContextHelp(ct.Name);
3300 // copy The Animal Pos retriever into the compass
3301 ct.setPositionState(_AnimalPosStates[i]);
3302 found = true;
3307 // teammates
3308 if (!found)
3310 // teammates landmarks
3311 if(_TeammateLM.size() == _TeammatePosStates.size())
3313 for(uint i=0;i<_TeammateLM.size();i++)
3315 if(_TeammateLM[i]==lm)
3317 _TeammateLM[i]->getContextHelp(ct.Name);
3318 // copy The Animal Pos retriever into the compass
3319 ct.setPositionState(_TeammatePosStates[i]);
3320 found = true;
3326 if (found)
3328 CInterfaceManager *im = CInterfaceManager::getInstance();
3329 CGroupCompas *gc = dynamic_cast<CGroupCompas *>(CWidgetManager::getInstance()->getElementFromId(_CompassId));
3330 if (gc)
3332 gc->setActive(true);
3333 gc->setTarget(ct);
3334 gc->blink();
3335 CWidgetManager::getInstance()->setTopWindow(gc);
3340 //=========================================================================================================
3341 void CGroupMap::targetLandmarkResult(uint32 index)
3343 if (index > _MatchedLandmarks.size()) return;
3345 CCompassTarget ct;
3346 ct.Pos = _MatchedLandmarks[index].Pos;
3347 ct.Name = _MatchedLandmarks[index].Title.toUtf8();
3348 // type sets compass arrow color
3349 ct.setType(CCompassTarget::UserLandMark);
3351 centerOnWorldPos(ct.Pos);
3353 CInterfaceManager *im = CInterfaceManager::getInstance();
3354 CGroupCompas *gc = dynamic_cast<CGroupCompas *>(CWidgetManager::getInstance()->getElementFromId(_CompassId));
3355 if (gc)
3357 gc->setActive(true);
3358 gc->setTarget(ct);
3359 gc->blink();
3360 CWidgetManager::getInstance()->setTopWindow(gc);
3364 //=========================================================================================================
3365 CGroupMap::CLandMarkButton* CGroupMap::findClosestLandmark(const CVector2f &center, const ucstring &search, bool startsWith, const TLandMarkButtonVect &landmarks, float &closest) const
3367 CLandMarkButton *ret = NULL;
3369 std::vector<ucstring> keywords;
3370 if (startsWith)
3371 keywords.push_back(search);
3372 else
3373 splitUCString(toLower(search), ucstring(" "), keywords);
3375 closest = std::numeric_limits<float>::max();
3376 for(TLandMarkButtonVect::const_iterator it = landmarks.begin(); it != landmarks.end(); ++it)
3378 std::string lc;
3379 (*it)->getContextHelp(lc);
3380 ucstring ulc = ucstring::makeFromUtf8(lc);
3381 if(filterLandmark(ulc, keywords, startsWith)) {
3382 CVector2f pos;
3383 mapToWorld(pos, (*it)->Pos);
3384 float dist = distsqr(center, pos);
3385 if (dist < closest)
3387 ret = (*it);
3388 closest = dist;
3393 return ret;
3396 //=========================================================================================================
3397 CGroupMap::CLandMarkText* CGroupMap::findClosestLandmark(const CVector2f &center, const ucstring &search, bool startsWith, const TLandMarkTextVect &landmarks, float &closest) const
3399 CLandMarkText *ret = NULL;
3401 std::vector<ucstring> keywords;
3402 if (startsWith)
3403 keywords.push_back(search);
3404 else
3405 splitUCString(toLower(search), ucstring(" "), keywords);
3407 closest = std::numeric_limits<float>::max();
3408 for(TLandMarkTextVect::const_iterator it = landmarks.begin(); it != landmarks.end(); ++it)
3410 ucstring lc;
3411 lc = CUtfStringView((*it)->getText()).toUtf16();
3412 if(filterLandmark(lc, keywords, startsWith)) {
3413 CVector2f pos;
3414 mapToWorld(pos, (*it)->Pos);
3415 float dist = distsqr(center, pos);
3416 if (dist < closest)
3418 ret = (*it);
3419 closest = dist;
3424 return ret;
3427 bool CGroupMap::targetLandmarkByName(const ucstring &search, bool startsWith) const
3429 CCompassTarget ct;
3430 CLandMarkButton* lm;
3431 float dist;
3432 float closest = std::numeric_limits<float>::max();
3433 bool found = false;
3434 CVector2f center;
3435 mapToWorld(center, _PlayerPos);
3437 lm = findClosestLandmark(center, search, startsWith, _UserLM, dist);
3438 if (lm && dist < closest)
3440 ct.setType(CCompassTarget::UserLandMark);
3441 mapToWorld(ct.Pos, lm->Pos);
3442 lm->getContextHelp(ct.Name);
3443 closest = dist;
3444 found = true;
3447 // only check other types if user landmark was not found
3448 if (!found)
3450 lm = findClosestLandmark(center, search, startsWith, _ContinentLM, dist);
3451 if (lm && dist < closest)
3453 ct.setType(CCompassTarget::ContinentLandMark);
3454 mapToWorld(ct.Pos, lm->Pos);
3455 lm->getContextHelp(ct.Name);
3456 closest = dist;
3457 found = true;
3460 CLandMarkText* lmt;
3461 lmt = findClosestLandmark(center, search, startsWith, _ContinentText, dist);
3462 if (lmt && dist < closest)
3464 ct.setType(CCompassTarget::ContinentLandMark);
3465 mapToWorld(ct.Pos, lmt->Pos);
3466 ct.Name = lmt->getText();
3467 closest = dist;
3468 found = true;
3472 if (found)
3474 CInterfaceManager *im = CInterfaceManager::getInstance();
3475 CGroupCompas *gc = dynamic_cast<CGroupCompas *>(CWidgetManager::getInstance()->getElementFromId(_CompassId));
3476 if (gc)
3478 gc->setActive(true);
3479 gc->setTarget(ct);
3480 gc->blink();
3481 CWidgetManager::getInstance()->setTopWindow(gc);
3485 return found;
3488 //=========================================================================================================
3489 void CGroupMap::getLandmarkPosition(const CCtrlButton *lm, NLMISC::CVector2f &worldPos)
3491 if (!lm) return;
3493 // continent landmarks
3494 CCompassTarget ct;
3495 TLandMarkButtonVect::iterator it = std::find(_ContinentLM.begin(), _ContinentLM.end(),lm);
3497 if (it != _ContinentLM.end())
3499 mapToWorld(worldPos, (*it)->Pos);
3500 return;
3504 // mission landmarks
3505 it = std::find(_MissionLM.begin(), _MissionLM.end(),lm);
3507 if (it != _MissionLM.end())
3509 mapToWorld(worldPos, (*it)->Pos);
3510 return;
3514 // user landmarks
3515 it = std::find(_UserLM.begin(), _UserLM.end(),lm);
3517 if (it != _UserLM.end())
3519 mapToWorld(worldPos, (*it)->Pos);
3520 return;
3524 // respawn point
3525 // if in island -> no effect when choosing entry point for now
3526 it = std::find(_RespawnLM.begin(), _RespawnLM.end(),lm);
3527 if (it != _RespawnLM.end())
3529 if (!isIsland())
3531 mapToWorld(worldPos, (*it)->Pos);
3532 return;
3536 worldPos = NLMISC::CVector2f::Null;
3539 //=========================================================================================================
3540 void CGroupMap::addRespawnPoints(const CRespawnPointsMsg &rpm)
3542 _RespawnPosReseted = false;
3543 if (rpm.NeedToReset)
3545 _RespawnPosReseted = true;
3546 _RespawnPos.clear();
3548 for (uint32 i = 0; i < rpm.RespawnPoints.size(); ++i)
3549 _RespawnPos.push_back(rpm.RespawnPoints[i]);
3550 // Ensure there is at least one respawn point
3551 // nlassert(!_RespawnPos.empty());
3553 // Choose the good map ! (select the first respawn point and check for first matching bounding box map
3554 if (_MapMode != MapMode_Death) return;
3555 if (_RespawnPos.empty()) return;
3557 CWorldSheet *pWS = dynamic_cast<CWorldSheet*>(SheetMngr.get(CSheetId("ryzom.world")));
3558 if (pWS == NULL) return;
3560 CInterfaceManager *pIM = CInterfaceManager::getInstance();
3561 if (pIM == NULL) return;
3563 NLMISC::CVector2f rpWorldPos(_RespawnPos[0].x * 0.001f, _RespawnPos[0].y * 0.001f);
3565 for (uint32 i = 0; i < pWS->Maps.size(); ++i)
3567 SMap &rMap = pWS->Maps[i];
3568 if (rMap.ContinentName.empty()) continue;
3570 if ((rpWorldPos.x >= rMap.MinX) &&
3571 (rpWorldPos.x <= rMap.MaxX) &&
3572 (rpWorldPos.y >= rMap.MinY) &&
3573 (rpWorldPos.y <= rMap.MaxY))
3575 setMap(rMap.Name);
3576 break;
3581 //=========================================================================================================
3582 void CGroupMap::addArkPoint(const CArkPoint &point) {
3583 _ArkPoints.push_back(point);
3585 if (_MapMode != MapMode_Death) return;
3586 if (_ArkPoints.empty()) return;
3588 CWorldSheet *pWS = dynamic_cast<CWorldSheet*>(SheetMngr.get(CSheetId("ryzom.world")));
3589 if (pWS == NULL) return;
3591 CInterfaceManager *pIM = CInterfaceManager::getInstance();
3592 if (pIM == NULL) return;
3594 NLMISC::CVector2f rpWorldPos(point.x * 0.001f, point.y * 0.001f);
3596 for (uint32 i = 0; i < pWS->Maps.size(); ++i)
3598 SMap &rMap = pWS->Maps[i];
3599 if (rMap.ContinentName.empty()) continue;
3601 if ((rpWorldPos.x >= rMap.MinX) &&
3602 (rpWorldPos.x <= rMap.MaxX) &&
3603 (rpWorldPos.y >= rMap.MinY) &&
3604 (rpWorldPos.y <= rMap.MaxY))
3606 setMap(rMap.Name);
3607 break;
3613 //=========================================================================================================
3614 void CGroupMap::serialConfig(NLMISC::IStream &f)
3616 sint ver = f.serialVersion(3);
3617 f.serial(_UserScale);
3618 if (ver == 0)
3620 _UserScale = 1.f;
3623 if (ver < 2)
3625 // dummy read the old _Offset, and reset to 0.
3626 f.serial(_Offset);
3627 _WorldOffset.set(0.f, 0.f);
3628 _Offset.set(0.f, 0.f);
3630 else
3632 f.serial(_WorldOffset);
3635 // Avoid bad saved WorldOffset
3636 if(f.isReading())
3638 if(!isValidDouble(_WorldOffset.x) || !isValidDouble(_WorldOffset.y))
3639 _WorldOffset.set(0,0);
3642 // In version 3 we do not read the _H anymore
3643 if (ver < 3)
3645 f.serial(_H);
3646 // Yoyo: patch to avoid old "respawn map hid at second time" bug
3647 if (f.isReading())
3648 if (_H < 10)
3649 _H = 10;
3653 //=========================================================================================================
3654 sint32 CGroupMap::getRespawnSelected() const
3656 CInterfaceManager *pIM = CInterfaceManager::getInstance();
3657 CCDBNodeLeaf *pNL = NULL;
3658 if (_MapMode == MapMode_Death)
3659 pNL = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:RESPAWN_PT",false);
3660 else if (_MapMode == MapMode_SpawnSquad)
3661 pNL = NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP:OUTPOST:SQUAD_RESPAWN_PT",false);
3662 if (pNL != NULL)
3663 return pNL->getValue32();
3664 return 0;
3667 //=========================================================================================================
3668 void CGroupMap::setRespawnSelected(sint32 nSpawnPointIndex)
3670 if (_RespawnPos.empty()) return;
3671 if (nSpawnPointIndex < 0) return;
3672 if ((uint32)nSpawnPointIndex >= _RespawnPos.size()) return;
3673 CInterfaceManager *pIM = CInterfaceManager::getInstance();
3674 CCDBNodeLeaf *pNL = NULL;
3675 if (_MapMode == MapMode_Death)
3676 pNL = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:RESPAWN_PT",false);
3677 else if (_MapMode == MapMode_SpawnSquad)
3678 pNL = NLGUI::CDBManager::getInstance()->getDbProp("UI:TEMP:OUTPOST:SQUAD_RESPAWN_PT",false);
3679 if (pNL != NULL)
3680 pNL->setValue32(nSpawnPointIndex);
3681 _RespawnSelected = nSpawnPointIndex;
3682 _RespawnPosReseted = false;
3686 //=========================================================================================================
3687 SMap *CGroupMap::getParentMap(SMap *map)
3689 if (map == NULL) return NULL;
3691 for (uint32 i = 0; i < _WorldSheet->Maps.size(); ++i)
3693 bool bFound = false;
3694 SMap *pM = &_WorldSheet->Maps[i];
3695 for (uint32 j = 0; j < pM->Children.size(); ++j)
3697 if (pM->Children[j].Name == map->Name)
3699 bFound = true;
3700 break;
3703 if (bFound)
3704 return pM;
3706 return NULL;
3709 //=========================================================================================================
3710 std::string CGroupMap::getContinentName() const
3712 if (_CurMap == NULL) return "";
3714 return toLowerAscii(_CurMap->ContinentName);
3717 //=========================================================================================================
3718 std::string CGroupMap::getMapTexture() const
3720 return toLowerAscii(_MapTexture);
3723 //=========================================================================================================
3724 int CGroupMap::luaReload(CLuaState &ls)
3726 CLuaIHM::checkArgCount(ls, "reload", 0);
3727 reload();
3728 return 0;
3731 //=========================================================================================================
3732 int CGroupMap::luaIsIsland(CLuaState &ls)
3734 CLuaIHM::checkArgCount(ls, "isIsland", 0);
3735 ls.push(_IsIsland);
3736 return 1;
3740 /////////////////////
3741 // ACTION HANDLERS //
3742 /////////////////////
3744 //=========================================================================================================
3745 void CGroupMap::updateClosestLandMarkMenu(const std::string &menu, const NLMISC::CVector2f &pos) const
3747 static uint nbShowLandmarks = 5;
3748 static uint nbShowLandmarksMax = 5;
3750 const CGroupMenu *pMenu = dynamic_cast<CGroupMenu *>(CWidgetManager::getInstance()->getElementFromId(menu));
3751 if (!pMenu) return;
3753 CGroupSubMenu *rootMenu = pMenu->getRootMenu();
3754 if (!rootMenu) return;
3756 // remove previous markers from menu
3757 for(uint i = 0; i < nbShowLandmarksMax; ++i)
3759 std::string lineId = toString("%s:lmcosest%d", menu.c_str(), i);
3760 sint index = rootMenu->getLineFromId(lineId);
3761 if (index < 0) break;
3762 rootMenu->removeLine(index);
3765 // no continent selected (ie world map view)
3766 if (!_CurContinent) return;
3768 // sort landmarks, keep indices
3769 typedef std::pair<uint, float> TSortedDistPair;
3770 std::vector<TSortedDistPair> sortedIndices;
3771 for(uint i = 0; i < _CurContinent->UserLandMarks.size(); ++i)
3773 float dist = distsqr(pos, _CurContinent->UserLandMarks[i].Pos);
3774 if (sortedIndices.empty())
3776 sortedIndices.push_back(TSortedDistPair(i, dist));
3778 else
3780 bool found = false;
3781 for(uint j = 0; j< sortedIndices.size(); j++)
3783 if (dist < sortedIndices[j].second)
3785 sortedIndices.insert(sortedIndices.begin() + j, TSortedDistPair(i, dist));
3786 found = true;
3787 if (sortedIndices.size() > nbShowLandmarks)
3789 sortedIndices.pop_back();
3791 break;
3795 if (!found && sortedIndices.size() < nbShowLandmarks)
3797 sortedIndices.push_back(TSortedDistPair(i, dist));
3802 // add landmarks to menu
3803 uint lineIndex = rootMenu->getNumLines();
3804 for(uint i = 0; i< sortedIndices.size(); ++i)
3806 uint32 index = sortedIndices[i].first;
3807 ucstring name = ucstring(toString("%.2fm ", sqrt(sortedIndices[i].second))) + _CurContinent->UserLandMarks[index].Title;
3808 std::string lineId = toString("%s:lmcosest%d", menu.c_str(), i);
3809 std::string ahParams = toString("type=user|map=%s|index=%d", _Id.c_str(), index);
3811 CViewTextMenu* vt = rootMenu->addLine(std::string(), "map_landmark_by_index", ahParams, lineId.c_str(), "", "", false, false, false);
3812 if (!vt) break;
3814 vt->setSingleLineTextFormatTaged(name.toUtf8());
3815 // TODO: should calculate from mouse pos and client width
3816 vt->setLineMaxW(800);
3818 CLandMarkOptions options = getUserLandMarkOptions(index);
3820 typedef std::pair<std::string, std::string> TTmplParams;
3821 std::vector<TTmplParams> vparams;
3822 vparams.push_back(TTmplParams("id", toString("lmicon%d", i)));
3823 vparams.push_back(TTmplParams("sizeref", ""));
3824 vparams.push_back(TTmplParams("icon_texture", options.LandMarkTexNormal));
3825 vparams.push_back(TTmplParams("icon_color", options.ColorNormal.toString()));
3827 CInterfaceGroup *pUGLeft = CWidgetManager::getInstance()->getParser()->createGroupInstance("landmark_row_icon", lineId, vparams);
3828 if (pUGLeft)
3829 rootMenu->setUserGroupLeft(lineIndex, pUGLeft, true);
3831 rootMenu->setRightClickHandler(lineIndex, "map_landmark_by_index");
3832 rootMenu->setRightClickHandlerParam(lineIndex, toString("%s|menu=%s_base", ahParams.c_str(), options.LandMarkMenu.c_str()));
3833 lineIndex++;
3837 //=========================================================================================================
3838 // remap caller with landmark using index/type and call popup menu or set compass target if no menu is set
3839 class CAHMapLandmarkByIndex : public IActionHandler
3841 virtual void execute (CCtrlBase* pCaller, const string &params )
3843 const std::string mapName = getParam(params, "map");
3844 const std::string lmType = getParam(params, "type");
3845 const std::string menuId = getParam(params, "menu");
3846 uint index;
3847 if (!fromString(getParam(params, "index"), index)) return;
3849 CGroupMap *map = dynamic_cast<CGroupMap *>(CWidgetManager::getInstance()->getElementFromId(mapName));
3850 if (!map) return;
3852 // remap caller to landmark from menu row
3853 CCtrlButton* pButton = map->getLandmarkCtrl(lmType, index);
3854 if (!pButton) return;
3856 if (menuId.empty())
3857 map->targetLandmark(pButton);
3858 else
3859 CAHManager::getInstance()->runActionHandler("active_menu", pButton, toString("pushmodal=true|popmodal=false|menu=%s", menuId.c_str()));
3862 REGISTER_ACTION_HANDLER(CAHMapLandmarkByIndex, "map_landmark_by_index");
3864 //=========================================================================================================
3865 // Set landmark filter
3866 class CAHLandMarkFilter : public IActionHandler
3868 virtual void execute (CCtrlBase * /* pCaller */, const string &params )
3870 string id = getParam(params, "map");
3872 CGroupMap* map = dynamic_cast<CGroupMap*>(CWidgetManager::getInstance()->getElementFromId(id));
3873 if (!map) return;
3875 string text = getParam(params, "text");
3876 if (text.empty() && params.find("text=") == std::string::npos)
3878 string group = getParam(params, "group");
3879 CGroupEditBox* eb = dynamic_cast<CGroupEditBox*>(CWidgetManager::getInstance()->getElementFromId(group));
3880 if (!eb) return;
3882 text = eb->getInputString();
3885 map->setLandmarkFilter(text);
3888 REGISTER_ACTION_HANDLER(CAHLandMarkFilter, "land_mark_filter");
3890 //=========================================================================================================
3891 // Landmark selected from result list
3892 class CAHLandMarkResultSelected : public IActionHandler
3894 virtual void execute (CCtrlBase * /* pCaller */, const string &params)
3896 string id = getParam(params, "map");
3897 CGroupMap* map = dynamic_cast<CGroupMap*>(CWidgetManager::getInstance()->getElementFromId(id));
3898 if (!map) return;
3900 sint index;
3901 string nr = getParam(params, "index");
3902 if (!fromString(nr, index)) return;
3904 map->targetLandmarkResult(index);
3907 REGISTER_ACTION_HANDLER(CAHLandMarkResultSelected, "land_mark_result_selected");
3909 //=========================================================================================================
3910 // A land mark button has been pushed
3911 class CAHLandMarkSelected : public IActionHandler
3913 virtual void execute (CCtrlBase *pCaller, const string &/* params */)
3915 CCtrlButton *button = dynamic_cast<CCtrlButton *>(pCaller);
3916 if (!button) return;
3917 // Select the landmark as the current target
3918 CGroupMap *map = dynamic_cast<CGroupMap *>(button->getParent());
3919 if (!map) return;
3920 map->targetLandmark(button);
3923 REGISTER_ACTION_HANDLER(CAHLandMarkSelected, "land_mark_selected");
3925 //=========================================================================================================
3926 // Remove a user landmark
3927 class CAHRemoveUserLandMark : public IActionHandler
3929 virtual void execute (CCtrlBase *pCaller, const string &/* params */)
3931 CCtrlButton *button = dynamic_cast<CCtrlButton *>(pCaller);
3932 if (!button) return;
3933 CGroupMap *map = dynamic_cast<CGroupMap *>(button->getParent());
3934 if (!map) return;
3935 map->removeUserLandMark(button);
3936 // close the rename window & create window
3937 closeLandMarkNameDialog();
3938 LastSelectedLandMark = NULL;
3941 REGISTER_ACTION_HANDLER(CAHRemoveUserLandMark, "remove_user_landmark");
3943 //=========================================================================================================
3944 // Rename a user land mark
3945 class CAHRenameUserLandMark : public IActionHandler
3947 virtual void execute (CCtrlBase *pCaller, const string &/* params */)
3949 LastSelectedLandMark = dynamic_cast<CCtrlButton *>(pCaller);
3950 if (!LastSelectedLandMark) return;
3952 popupLandMarkNameDialog();
3955 REGISTER_ACTION_HANDLER(CAHRenameUserLandMark, "rename_user_landmark");
3958 //=========================================================================================================
3959 // Validate user landmark name
3960 class CAHValidateUserLandMarkName : public IActionHandler
3962 virtual void execute (CCtrlBase * /* pCaller */, const string &/* params */)
3964 CInterfaceManager *im = CInterfaceManager::getInstance();
3965 CInterfaceGroup *ig = dynamic_cast<CInterfaceGroup *>(CWidgetManager::getInstance()->getElementFromId(WIN_LANDMARK_NAME));
3966 if (!ig) return;
3967 CGroupEditBox *eb = dynamic_cast<CGroupEditBox *>(ig->getGroup("eb"));
3968 if (!eb) return;
3969 ig->setActive(false);
3971 CGroupContainer *gc = dynamic_cast<CGroupContainer *>(CWidgetManager::getInstance()->getElementFromId(WIN_LANDMARK_NAME));
3972 if (!gc) return;
3973 // Retrieve ComboBox to get the position(ordered landmark type) of the selected item
3974 CDBGroupComboBox *cb = dynamic_cast<CDBGroupComboBox *>(gc->getGroup("landmarktypes"));
3976 CUserLandMark::EUserLandMarkType landMarkType = CUserLandMark::Misc;
3977 sint8 nLandMarkType = cb->getTextId( CDBManager::getInstance()->getDbProp( "UI:TEMP:LANDMARKTYPE" )->getValue8());
3978 if (nLandMarkType>=0 && nLandMarkType<=CUserLandMark::UserLandMarkTypeCount)
3980 landMarkType = (CUserLandMark::EUserLandMarkType)nLandMarkType;
3983 if (LastSelectedLandMark)
3985 CGroupMap *map = dynamic_cast<CGroupMap *>(LastSelectedLandMark->getParent());
3986 if (!map) return;
3987 // update existing landmark
3988 map->updateUserLandMark(LastSelectedLandMark, ucstring::makeFromUtf8(eb->getInputString()), landMarkType);
3990 else
3992 // create a new landmark
3993 if (!LastClickedMap) return;
3994 if( UseUserPositionForLandMark )
3996 LastClickedMap->addUserLandMark(LastClickedMap->getPlayerPos(), ucstring::makeFromUtf8(eb->getInputString()), landMarkType);
3998 else
4000 LastClickedMap->addUserLandMark(LastClickedMap->getRightClickLastPos(), ucstring::makeFromUtf8(eb->getInputString()), landMarkType);
4002 LastClickedMap->invalidateCoords();
4006 REGISTER_ACTION_HANDLER(CAHValidateUserLandMarkName, "validate_user_landmark_name");
4008 //=========================================================================================================
4009 void createUserLandMark(CCtrlBase * /* pCaller */, const string &/* params */)
4011 CInterfaceManager *im = CInterfaceManager::getInstance();
4012 // pop the rename dialog
4013 LastClickedMap = dynamic_cast<CGroupMap *>(CWidgetManager::getInstance()->getCtrlLaunchingModal());
4014 if (LastClickedMap->isInDeathMode()) return;
4015 LastSelectedLandMark = NULL;
4016 popupLandMarkNameDialog();
4019 // create a new landmark after giving its name
4020 class CAHCreateUserLandMark : public IActionHandler
4022 virtual void execute (CCtrlBase *pCaller, const string &params)
4024 UseUserPositionForLandMark = false;
4025 createUserLandMark(pCaller,params);
4028 REGISTER_ACTION_HANDLER(CAHCreateUserLandMark, "create_user_landmark");
4030 // create a new landmark at user position after giving its name
4031 class CAHCreateUserLandMarkAtUserPos: public IActionHandler
4033 virtual void execute (CCtrlBase *pCaller, const string &params)
4035 UseUserPositionForLandMark = true;
4036 createUserLandMark(pCaller,params);
4039 REGISTER_ACTION_HANDLER(CAHCreateUserLandMarkAtUserPos, "create_user_landmark_at_user_pos");
4042 //=========================================================================================================
4043 // zoom in the map
4044 class CAHMapZoomIn : public IActionHandler
4046 virtual void execute (CCtrlBase * /* pCaller */, const string &params)
4048 std::string map = getParam(params, "map");
4049 CInterfaceManager *im = CInterfaceManager::getInstance();
4050 CGroupMap *gm = dynamic_cast<CGroupMap *>(CWidgetManager::getInstance()->getElementFromId(map));
4051 if (!gm) return;
4052 NLMISC::CVector2f center;
4053 gm->windowToMap(center, gm->getWReal() / 2, gm->getHReal() / 2);
4054 gm->setScale(gm->getScale() * 1.3f, center);
4057 REGISTER_ACTION_HANDLER(CAHMapZoomIn, "map_zoom_in");
4059 //=========================================================================================================
4060 // zoom out the map
4061 class CAHMapZoomOut : public IActionHandler
4063 virtual void execute (CCtrlBase * /* pCaller */, const string &params)
4065 std::string map = getParam(params, "map");
4066 CInterfaceManager *im = CInterfaceManager::getInstance();
4067 CGroupMap *gm = dynamic_cast<CGroupMap *>(CWidgetManager::getInstance()->getElementFromId(map));
4068 if (!gm) return;
4069 NLMISC::CVector2f center;
4070 gm->windowToMap(center, gm->getWReal() / 2, gm->getHReal() / 2);
4071 gm->setScale(gm->getScale() * 0.7f, center);
4074 REGISTER_ACTION_HANDLER(CAHMapZoomOut, "map_zoom_out");
4076 //=========================================================================================================
4077 // center map on the player
4078 class CAHMapCenter : public IActionHandler
4080 virtual void execute (CCtrlBase * /* pCaller */, const string &params)
4082 std::string map = getParam(params, "map");
4083 CInterfaceManager *im = CInterfaceManager::getInstance();
4084 CGroupMap *gm = dynamic_cast<CGroupMap *>(CWidgetManager::getInstance()->getElementFromId(map));
4085 if (!gm) return;
4086 gm->centerOnPlayer();
4089 REGISTER_ACTION_HANDLER(CAHMapCenter, "map_center");
4091 //=========================================================================================================
4092 // return to the parent map
4093 class CAHMapBack : public IActionHandler
4095 virtual void execute (CCtrlBase * /* pCaller */, const string &params)
4097 std::string map = getParam(params, "map");
4098 CInterfaceManager *im = CInterfaceManager::getInstance();
4099 CGroupMap *pGM = dynamic_cast<CGroupMap *>(CWidgetManager::getInstance()->getElementFromId(map));
4100 if (pGM == NULL) return;
4101 SMap *pMap = pGM->getParentMap(pGM->getCurMap());
4102 if (pMap != NULL)
4103 pGM->setMap(pMap->Name);
4106 REGISTER_ACTION_HANDLER(CAHMapBack, "map_back");
4108 //=========================================================================================================
4109 // valid the respawn location selected
4110 class CAHRespawnMapValid : public IActionHandler
4112 virtual void execute (CCtrlBase * /* pCaller */, const string &params)
4114 std::string map = getParam(params, "map");
4115 CInterfaceManager *im = CInterfaceManager::getInstance();
4116 CGroupMap *gm = dynamic_cast<CGroupMap *>(CWidgetManager::getInstance()->getElementFromId(map));
4117 if (!gm) return;
4118 if (gm->getRespawnSelected() == -1) return;
4120 CBitMemStream out;
4121 const string msgName = "DEATH:ASK_RESPAWN";
4122 if (!GenericMsgHeaderMngr.pushNameToStream(msgName, out))
4124 nlwarning ("don't know message name %s", msgName.c_str());
4126 else
4128 uint16 respawnIndex = (uint16)gm->getRespawnSelected();
4129 out.serial(respawnIndex);
4130 NetMngr.push(out);
4131 //nlinfo("impulseCallBack : %s %d sent", msgName.c_str(), respawnIndex);
4134 Yoyo: NO!!! don't do this!! leave the DB Player MBEHAV Mode drive this (laggy but correct)....
4135 Else Errors arise if the client MBEHAV Mode never reset to Normal==1 (for any lag reason)
4136 The following scenario else could cause a bug:
4137 - the player is dead, the respawn map is activated
4138 - the player click "respawn"
4139 - in the buggy version we close the window immediatly (no lag)
4140 - the server receive the ASK respawn, resapwn the player, and change the mode to NORMAL==1
4141 - the server decide that the PLAYER DIES AUTOMATICALLY in the same server tick (gingo in town for instance! :) )
4142 NB: even if the DIE arise in following frame, lag and packet loss etc... can still cause problems
4143 - the server then reset the mode to DEATH
4144 - the client never receive the change Mode: 0-->1-->0 (always 0), hence the window is not reopened
4145 - the user cannot reswpan....
4146 Instead, I chose to hide the timer text in map.xml
4148 /*sint64 val = NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:CURRENT_SERVER_TICK")->getValue64();
4149 NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:RESPAWN:END_DATE")->setValue64(val+10*10);
4150 NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:OPEN_RESPAWN_AT_TIME")->setValue64(0);
4151 // must hide the window which contains this map, not the map itself!!
4152 CInterfaceGroup *rootWindow= gm->getRootWindow();
4153 if(rootWindow) rootWindow->setActive(false);
4155 NLGUI::CDBManager::getInstance()->getDbProp("UI:VARIABLES:RESPAWN:MSG_SENT")->setValue64(1);
4158 REGISTER_ACTION_HANDLER(CAHRespawnMapValid, "respawn_map_valid");
4161 //=========================================================================================================
4162 // right click on the map
4163 class CAHWorldMapRightClick : public IActionHandler
4165 virtual void execute (CCtrlBase *pCaller, const string &params)
4167 std::string map = getParam(params, "map");
4168 std::string menu = getParam(params, "menu");
4170 hideTeleportButtonsInPopupMenuIfNotEnoughPriv();
4172 CGroupMap *gm = dynamic_cast<CGroupMap *>(CWidgetManager::getInstance()->getElementFromId(map));
4173 if (!gm) return;
4175 if (gm->isIsland())
4177 if (gm->getArkPowoMode() == "editor")
4178 menu = gm->getArkPowoMapMenu();
4179 else
4180 menu = "ui:interface:map_menu_island";
4182 else
4184 if (menu.empty())
4185 menu = "ui:interface:map_menu";
4187 // update menu with closest landmarks
4188 NLMISC::CVector2f pos(NLMISC::CVector2f::Null);
4189 CCtrlButton *button = dynamic_cast<CCtrlButton *>(pCaller);
4190 if (button)
4191 gm->getLandmarkPosition(button, pos);
4193 if(pos == NLMISC::CVector2f::Null)
4195 pos = gm->getRightClickLastPos();
4196 gm->mapToWorld(pos, pos);
4199 gm->updateClosestLandMarkMenu(menu, pos);
4202 CAHManager::getInstance()->runActionHandler("active_menu", pCaller, "menu=" + menu);
4205 REGISTER_ACTION_HANDLER(CAHWorldMapRightClick, "world_map_right_click")
4207 //=========================================================================================================
4208 // A land mark button has been pushed
4209 class CAHLandMarkTeleport : public IActionHandler
4211 virtual void execute (CCtrlBase *pCaller, const string &/* params */)
4213 CCtrlButton *button = dynamic_cast<CCtrlButton *>(pCaller);
4214 if (!button) return;
4215 // Select the landmark as the current target
4216 CGroupMap *map = dynamic_cast<CGroupMap *>(button->getParent());
4217 if (!map) return;
4218 NLMISC::CVector2f pos;
4219 map->getLandmarkPosition(button, pos);
4221 // Check if the pos is ok
4222 if(pos == NLMISC::CVector2f::Null) return;
4224 closeLandMarkNameDialog();
4225 // Remove the selection.
4226 UserEntity->selection(CLFECOMMON::INVALID_SLOT);
4227 // Remove the target.
4228 UserEntity->targetSlot(CLFECOMMON::INVALID_SLOT);
4230 nlinfo("LM teleport to %f,%f", pos.x, pos.y);
4231 ICommand::execute(toString("a Position %f,%f", pos.x, pos.y), *InfoLog);
4234 REGISTER_ACTION_HANDLER(CAHLandMarkTeleport, "land_mark_teleport");
4237 //=========================================================================================================
4238 // Teleport player to the given location
4239 class CAHMapTeleport : public IActionHandler
4241 virtual void execute (CCtrlBase * /* pCaller */, const string &/* params */)
4243 CInterfaceManager *im = CInterfaceManager::getInstance();
4244 CGroupMap *clickedMap = dynamic_cast<CGroupMap *>(CWidgetManager::getInstance()->getCtrlLaunchingModal());
4245 closeLandMarkNameDialog();
4246 NLMISC::CVector2f pos = clickedMap->getRightClickLastPos();
4247 clickedMap->mapToWorld(pos, pos);
4248 // Remove the selection.
4249 UserEntity->selection(CLFECOMMON::INVALID_SLOT);
4250 // Remove the target.
4251 UserEntity->targetSlot(CLFECOMMON::INVALID_SLOT);
4253 nlinfo("teleport to %f,%f", pos.x, pos.y);
4254 ICommand::execute(toString("a Position %f,%f", pos.x, pos.y), *InfoLog);
4258 REGISTER_ACTION_HANDLER(CAHMapTeleport, "map_teleport");
4260 //=========================================================================================================
4261 // update LandMarks Colors
4262 class CUpdateLandMarksColor : public IActionHandler{public: virtual void execute (CCtrlBase * /* pCaller */, const string &/* Params */)
4264 CInterfaceManager *pIM = CInterfaceManager::getInstance();
4266 CUserLandMark::_LandMarksColor[CUserLandMark::Misc] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:LANDMARK:COLORS:MISC")->getValueRGBA();
4267 CUserLandMark::_LandMarksColor[CUserLandMark::Tribe] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:LANDMARK:COLORS:TRIBE")->getValueRGBA();
4268 CUserLandMark::_LandMarksColor[CUserLandMark::Bandit] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:LANDMARK:COLORS:BANDIT")->getValueRGBA();
4269 CUserLandMark::_LandMarksColor[CUserLandMark::Citizen] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:LANDMARK:COLORS:CITIZEN")->getValueRGBA();
4270 CUserLandMark::_LandMarksColor[CUserLandMark::Fauna] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:LANDMARK:COLORS:FAUNA")->getValueRGBA();
4271 CUserLandMark::_LandMarksColor[CUserLandMark::FaunaExcel] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:LANDMARK:COLORS:FAUNAEXCEL")->getValueRGBA();
4272 CUserLandMark::_LandMarksColor[CUserLandMark::FaunaSup] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:LANDMARK:COLORS:FAUNASUP")->getValueRGBA();
4273 CUserLandMark::_LandMarksColor[CUserLandMark::Forage] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:LANDMARK:COLORS:FORAGE")->getValueRGBA();
4274 CUserLandMark::_LandMarksColor[CUserLandMark::ForageExcel] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:LANDMARK:COLORS:FORAGEEXCEL")->getValueRGBA();
4275 CUserLandMark::_LandMarksColor[CUserLandMark::ForageSup] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:LANDMARK:COLORS:FORAGESUP")->getValueRGBA();
4276 CUserLandMark::_LandMarksColor[CUserLandMark::Sap] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:LANDMARK:COLORS:SAP")->getValueRGBA();
4277 CUserLandMark::_LandMarksColor[CUserLandMark::Amber] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:LANDMARK:COLORS:AMBER")->getValueRGBA();
4278 CUserLandMark::_LandMarksColor[CUserLandMark::Node] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:LANDMARK:COLORS:NODE")->getValueRGBA();
4279 CUserLandMark::_LandMarksColor[CUserLandMark::Fiber] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:LANDMARK:COLORS:FIBER")->getValueRGBA();
4280 CUserLandMark::_LandMarksColor[CUserLandMark::Bark] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:LANDMARK:COLORS:BARK")->getValueRGBA();
4281 CUserLandMark::_LandMarksColor[CUserLandMark::Seed] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:LANDMARK:COLORS:SEED")->getValueRGBA();
4282 CUserLandMark::_LandMarksColor[CUserLandMark::Shell] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:LANDMARK:COLORS:SHELL")->getValueRGBA();
4283 CUserLandMark::_LandMarksColor[CUserLandMark::Resin] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:LANDMARK:COLORS:RESIN")->getValueRGBA();
4284 CUserLandMark::_LandMarksColor[CUserLandMark::Wood] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:LANDMARK:COLORS:WOOD")->getValueRGBA();
4285 CUserLandMark::_LandMarksColor[CUserLandMark::Oil] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:LANDMARK:COLORS:OIL")->getValueRGBA();
4286 CUserLandMark::_LandMarksColor[CUserLandMark::Mission] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:LANDMARK:COLORS:MISSION")->getValueRGBA();
4287 CUserLandMark::_LandMarksColor[CUserLandMark::Food] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:LANDMARK:COLORS:FOOD")->getValueRGBA();
4288 CUserLandMark::_LandMarksColor[CUserLandMark::Construction] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:LANDMARK:COLORS:CONSTRUCTION")->getValueRGBA();
4289 CUserLandMark::_LandMarksColor[CUserLandMark::Goo] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:LANDMARK:COLORS:GOO")->getValueRGBA();
4290 CUserLandMark::_LandMarksColor[CUserLandMark::Insect] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:LANDMARK:COLORS:INSECT")->getValueRGBA();
4291 CUserLandMark::_LandMarksColor[CUserLandMark::Kitin] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:LANDMARK:COLORS:KITIN")->getValueRGBA();
4292 CUserLandMark::_LandMarksColor[CUserLandMark::Nocive] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:LANDMARK:COLORS:NOCIVE")->getValueRGBA();
4293 CUserLandMark::_LandMarksColor[CUserLandMark::Preservative] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:LANDMARK:COLORS:PRESERVATIVE")->getValueRGBA();
4294 CUserLandMark::_LandMarksColor[CUserLandMark::Passage] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:LANDMARK:COLORS:PASSAGE")->getValueRGBA();
4295 CUserLandMark::_LandMarksColor[CUserLandMark::Teleporter] = NLGUI::CDBManager::getInstance()->getDbProp("UI:SAVE:LANDMARK:COLORS:TELEPORTER")->getValueRGBA();
4299 CGroupMap *pGM = dynamic_cast<CGroupMap *>(CWidgetManager::getInstance()->getElementFromId("ui:interface:map:content:map_content:actual_map"));
4300 if (pGM == NULL) return;
4301 pGM->updateUserLandMarks();
4304 REGISTER_ACTION_HANDLER (CUpdateLandMarksColor, "update_landmarks_color");
4307 ////////////////////
4308 // DEBUG COMMANDS //
4309 ////////////////////
4312 #if !FINAL_VERSION
4314 NLMISC_COMMAND( testMapHome, "Debug : test display of home on map", "" )
4316 if (!args.empty()) return false;
4317 CInterfaceManager *im = CInterfaceManager::getInstance();
4318 NLGUI::CDBManager::getInstance()->getDbProp(COMPASS_DB_PATH ":HOME_POINT")->setValue64((((sint64) 4787 * 1000) << 32 )| (sint64) (uint32) ((sint64) -3661 * 1000));
4319 return true;
4322 NLMISC_COMMAND( testMapRespawn, "Debug : test display of respawn point on map", "" )
4324 if (!args.empty()) return false;
4325 CInterfaceManager *im = CInterfaceManager::getInstance();
4326 NLGUI::CDBManager::getInstance()->getDbProp(COMPASS_DB_PATH ":BIND_POINT")->setValue64((((sint64) 4687 * 1000) << 32 )| (sint64) (uint32) ((sint64) -3561 * 1000));
4327 return true;
4330 NLMISC_COMMAND( testRespawn, "Debug : test respawn map", "" )
4332 if (!args.empty()) return false;
4334 CRespawnPointsMsg rpm;
4335 rpm.NeedToReset = true;
4336 rpm.RespawnPoints.push_back(CRespawnPointsMsg::SRespawnPoint(4150*1000,-4350*1000));
4337 rpm.RespawnPoints.push_back(CRespawnPointsMsg::SRespawnPoint(4640*1000,-4320*1000));
4338 rpm.RespawnPoints.push_back(CRespawnPointsMsg::SRespawnPoint(4100*1000,-4120*1000));
4339 rpm.RespawnPoints.push_back(CRespawnPointsMsg::SRespawnPoint(4050*1000,-4200*1000));
4340 rpm.RespawnPoints.push_back(CRespawnPointsMsg::SRespawnPoint(4200*1000,-4150*1000));
4341 CInterfaceManager *pIM = CInterfaceManager::getInstance();
4342 CGroupMap *pMap = dynamic_cast<CGroupMap*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:respawn_map:content:map_content:actual_map"));
4343 if (pMap == NULL)
4345 nlwarning("problem cannot find ui:interface:respawn_map:content:map_content:actual_map");
4346 return false;
4348 pMap->addRespawnPoints(rpm);
4351 pMap = dynamic_cast<CGroupMap*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:map:content:map_content:actual_map"));
4352 if (pMap == NULL)
4354 nlwarning("problem cannot find ui:interface:map:content:map_content:actual_map");
4355 return false;
4357 pMap->addRespawnPoints(rpm);
4360 CInterfaceManager *im = CInterfaceManager::getInstance();
4361 NLGUI::CDBManager::getInstance()->getDbProp(COMPASS_DB_PATH ":BIND_POINT")->setValue64((((sint64) 4687 * 1000) << 32 )| (sint64) (uint32) ((sint64) -3561 * 1000));
4363 return true;
4366 NLMISC_COMMAND( setMap, "Debug : test respawn map", "" )
4368 if (args.size() != 1) return false;
4370 CInterfaceManager *pIM = CInterfaceManager::getInstance();
4371 CGroupMap *pMap = dynamic_cast<CGroupMap*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:map:content:map_content:actual_map"));
4372 if (pMap != NULL)
4373 pMap->setMap(args[0]);
4375 return true;
4378 #endif