// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "stdpch.h" // #include "group_map.h" #include "interface_manager.h" #include "../continent_manager.h" #include "../continent.h" #include "../zone_util.h" #include "../user_entity.h" #include "ctrl_button.h" #include "group_editbox.h" #include "../string_manager_client.h" #include "group_container.h" #include "action_handler.h" #include "../dummy_progress.h" #include "group_compas.h" #include "../connection.h" #include "../net_manager.h" #include "people_interraction.h" // for MaxNumPeopleInTeam #include "../sheet_manager.h" // for MaxNumPeopleInTeam #include "../global.h" #include "ctrl_quad.h" // #include "game_share/xml_auto_ptr.h" #include "game_share/mission_desc.h" #include "game_share/inventories.h" #include "game_share/animal_type.h" // #include "nel/3d/u_material.h" #include "nel/3d/u_texture.h" #include "nel/3d/u_scene.h" #include "../entities.h" // #include "nel/misc/vector_2f.h" #include "nel/misc/bitmap.h" #include "nel/misc/path.h" #include "nel/misc/file.h" #include "nel/misc/uv.h" #include "nel/misc/i18n.h" #include "../r2/editor.h" // #include "game_share/scenario_entry_points.h" #include extern CContinentManager ContinentMngr; extern NL3D::UDriver *Driver; extern NL3D::UScene *Scene; extern CEntityManager EntitiesMngr; using namespace NLMISC; using NLMISC::CUV; using NLMISC::CI18N; using NLMISC::CRGBA; using NLMISC::CBitMemStream; using namespace STRING_MANAGER; // /////// // // STATICS // // /////// // static CGroupMap *LastClickedMap = NULL; static CCtrlButton *LastSelectedLandMark = NULL; static bool UseUserPositionForLandMark = false; static const char *WIN_LANDMARK_NAME="ui:interface:enter_landmark_name"; //////////// // GLOBAL // //////////// NLMISC::CRGBA CUserLandMark::_LandMarksColor[CUserLandMark::UserLandMarkTypeCount]; const uint32 ISLAND_PIXEL_PER_METER = 2; static void setupFromZoom(CViewBase *pVB, CContLandMark::TContLMType t, float fMeterPerPixel); // popup the landmark name dialog static void popupLandMarkNameDialog() { // pop the rename dialog CInterfaceManager *im = CInterfaceManager::getInstance(); CGroupContainer *gc = dynamic_cast(im->getElementFromId(WIN_LANDMARK_NAME)); if (!gc) return; gc->setActive(true); gc->updateCoords(); gc->center(); im->setTopWindow(gc); gc->enableBlink(1); CGroupEditBox *eb = dynamic_cast(gc->getGroup("eb")); if (!eb) return; if (LastSelectedLandMark) { CGroupMap *map = dynamic_cast(LastSelectedLandMark->getParent()); if (!map) return; const CUserLandMark userLM = map->getUserLandMark(LastSelectedLandMark); im->getDbProp( "UI:TEMP:LANDMARKTYPE" )->setValue8(userLM.Type); eb->setInputString(userLM.Title); } else { im->getDbProp( "UI:TEMP:LANDMARKTYPE" )->setValue8(CUserLandMark::Misc); eb->setInputString(ucstring()); } im->setCaptureKeyboard(eb); eb->setSelectionAll(); } static void closeLandMarkNameDialog() { CInterfaceManager *im = CInterfaceManager::getInstance(); CGroupContainer *gc = dynamic_cast(im->getElementFromId(WIN_LANDMARK_NAME)); if (!gc) return; gc->setActive(false); } //============================================================================================================ // CPolyButton //============================================================================================================ NL3D::UMaterial CGroupMap::CPolyButton::LineMat; //============================================================================================================ CGroupMap::CPolyButton::CPolyButton() : CCtrlBase(TCtorParam()) { if (Driver != NULL) { // create material for displaying the button if (LineMat.empty()) { // create material for the world map LineMat = Driver->createMaterial(); if (!LineMat.empty()) { LineMat.initUnlit(); LineMat.setSrcBlend(NL3D::UMaterial::srcalpha); LineMat.setDstBlend(NL3D::UMaterial::invsrcalpha); LineMat.setBlend(true); LineMat.setZFunc(NL3D::UMaterial::always); LineMat.setZWrite(false); LineMat.setColor(CRGBA::Red); } } } } //============================================================================================================ bool CGroupMap::CPolyButton::handleEvent (const CEventDescriptor &event) { if (CCtrlBase::handleEvent(event)) return true; if (event.getType() == CEventDescriptor::mouse) { CInterfaceManager *im = CInterfaceManager::getInstance(); const CEventDescriptorMouse &eventDesc = (const CEventDescriptorMouse &)event; if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftup) { if (im->getCapturePointerLeft() != this) return false; // Set the map !!! if (contains(CVector2f((float)eventDesc.getX(), (float)eventDesc.getY()))) { bool bFound = false; uint32 i; for (i = 0; i < Map->getCurMap()->Children.size(); ++i) { if (ID == Map->getCurMap()->Children[i].ZoneName) { bFound = true; break; } } im->setCapturePointerLeft(NULL); if (bFound) Map->setMap(Map->getCurMap()->Children[i].Name); return true; } } if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftdown) { if (contains(CVector2f((float)eventDesc.getX(), (float)eventDesc.getY()))) { im->setCapturePointerLeft(this); return true; } } } return false; } //============================================================================================================ void CGroupMap::CPolyButton::updateCoords() { uint32 i, p; PolysReal.resize(Polys.size()); for (p = 0; p < Polys.size(); ++p) { PolysReal[p].Vertices.resize(Polys[p].Vertices.size()); for (i = 0; i < Polys[p].Vertices.size(); ++i) { sint32 x, y; CVector2f mapCoords; Map->worldToMap(mapCoords, Polys[p].Vertices[i]); Map->mapToScreen(x, y, mapCoords); PolysReal[p].Vertices[i] = CVector2f((float)x,(float)y); } } ZoneReal.VPoints.resize(Zone.VPoints.size()); for (i = 0; i < Zone.VPoints.size(); ++i) { sint32 x, y; CVector2f mapCoords; Map->worldToMap(mapCoords, Zone.VPoints[i]); Map->mapToScreen(x, y, mapCoords); ZoneReal.VPoints[i] = NLLIGO::CPrimVector(CVector2f((float)x,(float)y)); } } //============================================================================================================ float CGroupMap::getActualMaxScale() const { return ClientCfg.R2EDEnabled ? _ScaleMaxR2 : _ScaleMax; } //============================================================================================================ void CGroupMap::CPolyButton::drawPolyButton() { CInterfaceManager *pIM = CInterfaceManager::getInstance(); CViewRenderer &rVR = pIM->getViewRenderer(); float oow, ooh; rVR.getScreenOOSize(oow, ooh); bool bOver = false; const std::vector &rCUP = pIM->getCtrlsUnderPointer(); for (uint32 i = 0; i < rCUP.size(); ++i) if (rCUP[i] == this) { bOver = true; break; } /* // Wireframe !!! for (uint32 p = 0; p < PolysReal.size(); ++p) { for (uint32 i = 0; i < PolysReal[p].Vertices.size(); ++i) { NLMISC::CLine l; l.V0 = PolysReal[p].Vertices[i]; if (i != (PolysReal[p].Vertices.size()-1)) l.V1 = PolysReal[p].Vertices[i+1]; else l.V1 = PolysReal[p].Vertices[0]; l.V0.x *= oow; l.V0.y *= ooh; l.V1.x *= oow; l.V1.y *= ooh; Driver->drawLine(l, LineMat); } } */ if (bOver) LineMat.setColor(CRGBA(255,255,255,64)); // LineMat.setColor(CRGBA(165,38,6,128)); else return; // LineMat.setColor(CRGBA(255,255,255,64)); for (uint32 p = 0; p < PolysReal.size(); ++p) { for (uint32 i = 0; i < (PolysReal[p].Vertices.size()-2); ++i) { NLMISC::CTriangle t; t.V0 = PolysReal[p].Vertices[0]; t.V1 = PolysReal[p].Vertices[i+1]; t.V2 = PolysReal[p].Vertices[i+2]; t.V0.x *= oow; t.V0.y *= ooh; t.V1.x *= oow; t.V1.y *= ooh; t.V2.x *= oow; t.V2.y *= ooh; Driver->drawTriangle(t, LineMat); } } } //============================================================================================================ bool CGroupMap::CPolyButton::build(const NLLIGO::CPrimZone &concavePoly, CGroupMap *pMap, const string &sID) { static int gStat = 0; _Id = pMap->getId() + ":polybut" + toString(gStat++); Map = pMap; ID = sID; Zone = concavePoly; CPolygon p; for (uint32 i = 0; i < concavePoly.VPoints.size(); ++i) p.Vertices.push_back(CVector(concavePoly.VPoints[i].x, concavePoly.VPoints[i].y, 0)); std::list outputPolygons; CMatrix id; id.identity(); if (p.toConvexPolygons (outputPolygons, id)) { std::list::iterator it = outputPolygons.begin(); while (it != outputPolygons.end()) { CPolygon2D poly; for (uint32 i = 0; i < it->Vertices.size(); ++i) poly.Vertices.push_back(CVector2f(it->Vertices[i].x, it->Vertices[i].y)); Polys.push_back(poly); it++; } } else { nlwarning("cannot convert to convex poly"); return false; } return true; } //============================================================================================================ bool CGroupMap::CPolyButton::contains(const NLMISC::CVector2f &pos) { /* // Not precise for (uint32 p = 0; p < PolysReal.size(); ++p) { if (PolysReal[p].contains(pos)) return true; } return false; */ return ZoneReal.contains(pos); } //============================================================================================================ // CGroupMap //============================================================================================================ //============================================================================================================ NLMISC_REGISTER_OBJECT(CViewBase, CGroupMap, std::string, "map"); CGroupMap::CGroupMap(const TCtorParam ¶m) : CInterfaceGroup(param) { _Offset.x = 0.f; _Offset.y = 0.f; _WorldOffset.x = 0.f; _WorldOffset.y = 0.f; _Scale = 1.f; _UserScale = 1.f; _MinH = 50; _MaxH = 2000; //_MinW = 50; _MapTF = NULL; _PlayerPosMaterial = NULL; _PlayerPosTF = NULL; _MapTexW = 0; _MapTexH = 0; _PlayerPosTexW = 0; _PlayerPosTexH = 0; _MapLoadFailure = false; _PlayerPosLoadFailure = false; _WorldSheet = dynamic_cast(SheetMngr.get(CSheetId("ryzom.world"))); _CurMap = NULL; _CurContinent = NULL; _Panning = false; _HasMoved = false; _RightClickLastPos.set(0.f, 0.f); // make room for mission targets _MissionLM.resize(2 * MAX_NUM_MISSIONS * MAX_NUM_MISSION_TARGETS, 0); _MissionTargetTextIDs.resize(2 * MAX_NUM_MISSIONS * MAX_NUM_MISSION_TARGETS, 0); _MissionTargetTextReceived.resize(2 * MAX_NUM_MISSIONS * MAX_NUM_MISSION_TARGETS, false); _OldPlayerPos.set(0.f, 0.f); _PlayerPos.set(0.f, 0.f); // _TargetLM = NULL; _HomeLM = NULL; // _ScaleMax = 8.f; _ScaleMaxR2 = 8.f; // _TargetPos = NULL; _HomePos = NULL; // _MapX = 0; _MapY = 0; // _MapMode = MapMode_Normal; _RespawnSelected = 0; _RespawnSelectedBitmap = NULL; // _WorldToMapDeltaX = 0.f; _WorldToMapDeltaY = 0.f; // _VisibleWorldMin.set(0.f, 0.f); _VisibleWorldMax.set(0.f, 0.f); // _MeterPerPixel = 0.f; _FrustumView = NULL; _FrustumViewColor = CRGBA(255, 255, 255, 255); _FrustumViewColorOver = CRGBA(255, 255, 255, 127); _FrustumOverBlendFactor = 0.f; _FrustumViewBlendTimeInMs = 300; _SelectionAxisH = NULL; _SelectionAxisV = NULL; // _IsIsland = false; // _PanStartDateInMs = 0; _DeltaTimeBeforePanInMs = 0; _DeltaPosBeforePan = 0; } //============================================================================================================ CGroupMap::~CGroupMap() { if (Driver) { if (!_MapMaterial.empty()) Driver->deleteMaterial(_MapMaterial); if (!_PlayerPosMaterial.empty()) Driver->deleteMaterial(_PlayerPosMaterial); } for(TDecos::iterator it = _Decos.begin(); it != _Decos.end(); ++it) { (*it)->onRemove(*this); } } //============================================================================================================ void CGroupMap::addDeco(IDeco *deco) { if (!deco) return; if (_Decos.count(deco)) { nlwarning("Deco added twice."); return; } _Decos.insert(deco); deco->onAdd(*this); deco->onUpdate(*this); } //============================================================================================================ void CGroupMap::removeDeco(IDeco *deco) { if (!deco) return; TDecos::iterator it = _Decos.find(deco); if (it != _Decos.end()) { deco->onRemove(*this); _Decos.erase(it); } else { nlwarning("Deco not found"); } } //============================================================================================================ /** Load infos about a landmark */ static void loadLandmarkInfo(xmlNodePtr cur, const std::string &prefix, CLandMarkOptions &dest) { CXMLAutoPtr ptr; ptr = (char*) xmlGetProp( cur, (xmlChar*)(prefix + "_landmark_tex_normal").c_str()); if (ptr) dest.LandMarkTexNormal = (const char *) ptr; ptr = (char*) xmlGetProp( cur, (xmlChar*)(prefix + "_landmark_tex_over").c_str()); if (ptr) dest.LandMarkTexOver = (const char *) ptr; ptr = (char*) xmlGetProp( cur, (xmlChar*)(prefix + "_landmark_tex_pushed").c_str()); if (ptr) dest.LandMarkTexPushed = (const char *) ptr; ptr = (char*) xmlGetProp( cur, (xmlChar*)(prefix + "_landmark_menu").c_str()); if (ptr) dest.LandMarkMenu = (const char *) ptr; ptr = (char*) xmlGetProp( cur, (xmlChar*)(prefix + "_landmark_color_normal").c_str()); if (ptr) dest.ColorNormal = CCtrlBase::convertColor(ptr); ptr = (char*) xmlGetProp( cur, (xmlChar*)(prefix + "_landmark_color_over").c_str()); if (ptr) dest.ColorOver = CCtrlBase::convertColor(ptr); ptr = (char*) xmlGetProp( cur, (xmlChar*)(prefix + "_landmark_color_pushed").c_str()); if (ptr) dest.ColorPushed = CCtrlBase::convertColor(ptr); } //============================================================================================================ CViewBitmap *CGroupMap::newSelectionAxis(NLMISC::CRGBA color) { CViewBitmap *axis = new CViewBitmap(TCtorParam()); axis->setActive(false); axis->setTexture("blank.tga"); axis->setModulateGlobalColor(false); addView(axis); axis->setParent(this); axis->setColor(color); axis->setScale(true); return axis; } //============================================================================================================ bool CGroupMap::parse(xmlNodePtr cur, CInterfaceGroup * parentGroup) { if (!CInterfaceGroup::parse(cur, parentGroup)) return false; CXMLAutoPtr ptr((const char*) xmlGetProp( cur, (xmlChar*)"min_h" )); if (ptr) fromString((const char*) ptr, _MinH); ptr = (char*) xmlGetProp( cur, (xmlChar*)"max_h" ); if (ptr) fromString((const char*)ptr, _MaxH); /*ptr = (char*) xmlGetProp( cur, (xmlChar*)"min_w" ); if (ptr) fromString((const char*)ptr, _MinW);*/ ptr = (char*) xmlGetProp( cur, (xmlChar*)"map_mode" ); if (ptr) { string sTmp = ptr; if (sTmp == "normal") _MapMode = MapMode_Normal; else if (sTmp == "death") _MapMode = MapMode_Death; else if (sTmp == "spawn_squad") _MapMode = MapMode_SpawnSquad; } ptr = (char*) xmlGetProp( cur, (xmlChar*)"frustum_view_color" ); if (ptr) { _FrustumViewColor = convertColor (ptr); } ptr = (char*) xmlGetProp( cur, (xmlChar*)"frustum_view_color_over" ); if (ptr) { _FrustumViewColorOver = convertColor (ptr); } ptr = (char*) xmlGetProp( cur, (xmlChar*)"frustum_view_blend_time_in_ms" ); if (ptr) { fromString((const char*)ptr, _FrustumViewBlendTimeInMs); } if (Driver) { if (_MapMaterial.empty()) { // create material for the world map _MapMaterial = Driver->createMaterial(); if (!_MapMaterial.empty()) { _MapMaterial.initUnlit(); _MapMaterial.setSrcBlend(NL3D::UMaterial::srcalpha); _MapMaterial.setDstBlend(NL3D::UMaterial::invsrcalpha); _MapMaterial.setBlend(true); _MapMaterial.setZFunc(NL3D::UMaterial::always); _MapMaterial.setZWrite(false); // Setup stage 0 _MapMaterial.texEnvOpRGB(0, NL3D::UMaterial::Modulate); _MapMaterial.texEnvArg0RGB(0, NL3D::UMaterial::Texture, NL3D::UMaterial::SrcColor); _MapMaterial.texEnvArg1RGB(0, NL3D::UMaterial::Diffuse, NL3D::UMaterial::SrcColor); _MapMaterial.texEnvOpAlpha(0, NL3D::UMaterial::Modulate); _MapMaterial.texEnvArg0Alpha(0, NL3D::UMaterial::Texture, NL3D::UMaterial::SrcAlpha); _MapMaterial.texEnvArg1Alpha(0, NL3D::UMaterial::Diffuse, NL3D::UMaterial::SrcAlpha); // Setup stage 1 _MapMaterial.texEnvOpRGB(1, NL3D::UMaterial::Modulate); _MapMaterial.texEnvArg0RGB(1, NL3D::UMaterial::Previous, NL3D::UMaterial::SrcColor); _MapMaterial.texEnvArg1RGB(1, NL3D::UMaterial::Texture, NL3D::UMaterial::SrcAlpha); _MapMaterial.texEnvOpAlpha(1, NL3D::UMaterial::Replace); _MapMaterial.texEnvArg0Alpha(1, NL3D::UMaterial::Previous, NL3D::UMaterial::SrcAlpha); } } if (_PlayerPosMaterial.empty()) { // create material for the world map _PlayerPosMaterial = Driver->createMaterial(); if (!_PlayerPosMaterial.empty()) { _PlayerPosMaterial.initUnlit(); _PlayerPosMaterial.setSrcBlend(NL3D::UMaterial::srcalpha); _PlayerPosMaterial.setDstBlend(NL3D::UMaterial::invsrcalpha); _PlayerPosMaterial.setBlend(true); _PlayerPosMaterial.setZFunc(NL3D::UMaterial::always); _PlayerPosMaterial.setZWrite(false); } } } // continent landmarks loadLandmarkInfo(cur, "continent", _ContinentLMOptions); loadLandmarkInfo(cur, "mission", _MissionLMOptions); loadLandmarkInfo(cur, "user", _UserLMOptions); loadLandmarkInfo(cur, "target", _TargetLMOptions); // home aspect depends on race EGSPD::CPeople::TPeople people = EGSPD::CPeople::Fyros; if (PlayerSelectedSlot < CharacterSummaries.size()) { people = CharacterSummaries[people].People; } switch(people) { case EGSPD::CPeople::Fyros: loadLandmarkInfo(cur, "home_fyros", _HomeLMOptions); break; case EGSPD::CPeople::Matis: loadLandmarkInfo(cur, "home_matis", _HomeLMOptions); break; case EGSPD::CPeople::Zorai: loadLandmarkInfo(cur, "home_zorai", _HomeLMOptions); break; case EGSPD::CPeople::Tryker: loadLandmarkInfo(cur, "home_tryker", _HomeLMOptions); break; default: break; } loadLandmarkInfo(cur, "respawn", _RespawnLMOptions); // animal landmark loadLandmarkInfo(cur, "animal", _AnimalLMOptions); // animal(in stable) landmark loadLandmarkInfo(cur, "animal_stable", _AnimalStableLMOptions); // animal(dead) landmark loadLandmarkInfo(cur, "animal_dead", _AnimalDeadLMOptions); // teammate landmark loadLandmarkInfo(cur, "teammate", _TeammateLMOptions); // player pos ptr = (char*) xmlGetProp( cur, (xmlChar*)"player_pos_tex" ); if (ptr) _PlayerPosTexName = (const char *) ptr; // name of compass for targeting ptr = (char*) xmlGetProp( cur, (xmlChar*)"compass" ); if (ptr) _CompassId = (const char *) ptr; if (_MapMode == MapMode_Normal) { // create home, target & respawn landmarks _TargetLM = createLandMarkButton(_TargetLMOptions); if (_TargetLM) { _TargetLM->setParent(this); addCtrl(_TargetLM); } _HomeLM = createLandMarkButton(_HomeLMOptions); if (_HomeLM) { _HomeLM->setParent(this); addCtrl(_HomeLM); _HomeLM->setDefaultContextHelp(NLMISC::CI18N::get("uiHome")); } // create animals Landmark: pack Animals. _AnimalLM.resize(MAX_INVENTORY_ANIMAL); for(uint i=0;i<_AnimalLM.size();i++) { _AnimalLM[i] = createLandMarkButton(_AnimalLMOptions); if(_AnimalLM[i]) { _AnimalLM[i]->setParent(this); addCtrl(_AnimalLM[i]); _AnimalLM[i]->setDefaultContextHelp(NLMISC::CI18N::get(NLMISC::toString("uiPATitleMount%d", i+1))); } } // create teammates Landmark _TeammateLM.resize(MaxNumPeopleInTeam); for(uint i=0; i < MaxNumPeopleInTeam; i++) { _TeammateLM[i] = createLandMarkButton(_TeammateLMOptions); if(_TeammateLM[i]) { _TeammateLM[i]->setParent(this); addCtrl(_TeammateLM[i]); _TeammateLM[i]->setDefaultContextHelp(NLMISC::CI18N::get(NLMISC::toString("uittLMTeam%d",i))); } } } // ptr = (char*) xmlGetProp( cur, (xmlChar*)"scale_max" ); if (ptr) fromString((const char *) ptr, _ScaleMax); // ptr = (char*) xmlGetProp( cur, (xmlChar*)"scale_max_r2" ); if (ptr) fromString((const char *) ptr, _ScaleMaxR2); // if ((_MapMode == MapMode_Death) || (_MapMode == MapMode_SpawnSquad)) { string stmp = "w_answer_16_valid.tga"; ptr = (char*) xmlGetProp( cur, (xmlChar*)"respawn_selected" ); if (ptr) stmp = (const char*)ptr; ptr = (char*) xmlGetProp( cur, (xmlChar*)"respawn_button" ); if (ptr) _RespawnButton = (const char*)ptr; _RespawnSelectedBitmap = new CViewBitmap(CViewBase::TCtorParam()); static int statRP = 0; _RespawnSelectedBitmap->setId(getId()+":rp"+toString(statRP++)); _RespawnSelectedBitmap->setTexture(stmp); _RespawnSelectedBitmap->setParent(this); _RespawnSelectedBitmap->setParentPosRef(Hotspot_MM); _RespawnSelectedBitmap->setPosRef(Hotspot_MM); addView(_RespawnSelectedBitmap); //CCtrlBaseButton *pCB = dynamic_cast(CInterfaceManager::getInstance()->getElementFromId(_RespawnButton)); //if (pCB != NULL) pCB->setActive(false); } nlassert(!_FrustumView); _FrustumView = new CCtrlQuad; _FrustumView->setActive(false); addView(_FrustumView); _FrustumView->setParent(this); ptr = (char*) xmlGetProp( cur, (xmlChar*)"frustum_view_texture" ); const char* value; if (ptr) { value = ptr; } else { value = "r2_frustum.tga"; } _FrustumView->setTexture(value); _FrustumView->setModulateGlobalColor(false); // nlassert(!_SelectionAxisH); nlassert(!_SelectionAxisV); CRGBA axisColor = CRGBA(0, 0, 0, 127); ptr = (char*) xmlGetProp( cur, (xmlChar*)"selection_axis_color" ); if (ptr) { axisColor = convertColor(ptr); } _SelectionAxisH = newSelectionAxis(axisColor); _SelectionAxisV = newSelectionAxis(axisColor); // load all islands R2::CScenarioEntryPoints &sep = R2::CScenarioEntryPoints::getInstance(); try { sep.loadCompleteIslands(); const R2::CScenarioEntryPoints::TCompleteIslands &completeIslands = sep.getCompleteIslands(); _Islands.reserve(completeIslands.size()); for(uint k = 0; k < completeIslands.size(); ++k) { SMap island; island.Name = completeIslands[k].Island; island.ContinentName = ""; // no access to world map for now ... island.MinX = (float) completeIslands[k].XMin; island.MinY = (float) completeIslands[k].YMin; island.MaxX = (float) completeIslands[k].XMax; island.MaxY = (float) completeIslands[k].YMax; // post fix with current season island.BitmapName = completeIslands[k].Island + "_sp.tga"; _Islands.push_back(island); } } catch(const NLMISC::EFile &e) { nlwarning(e.what()); } return true; } //============================================================================================================ void CGroupMap::updateSelectionAxisSize() { if (_SelectionAxisH->getActive()) { _SelectionAxisH->setW(_WReal); _SelectionAxisH->setH(1); _SelectionAxisV->setW(1); _SelectionAxisV->setH(_HReal); } } //============================================================================================================ void CGroupMap::setSelectionAxis(bool active, const NLMISC::CVector2f &pos /*=NLMISC::CVector2f::Null*/) { _SelectionAxisH->setActive(active); _SelectionAxisV->setActive(active); if (active) { sint32 x, y; worldToWindowSnapped(x, y, pos); _SelectionAxisH->setX(0); _SelectionAxisH->setY(y); _SelectionAxisV->setX(x); _SelectionAxisV->setY(0); updateSelectionAxisSize(); _SelectionAxisH->invalidateCoords(); _SelectionAxisV->invalidateCoords(); } } //============================================================================================================ bool CGroupMap::getCtrlsUnder (sint32 x, sint32 y, sint32 clipX, sint32 clipY, sint32 clipW, sint32 clipH, std::vector &vICL) { if (!((x >= _XReal) && (x < (_XReal + _WReal))&& (y > _YReal) && (y <= (_YReal+ _HReal)))) return false; // test against current clip computeCurrentClipContribution(clipX, clipY, clipW, clipH, clipX, clipY, clipW, clipH); if (!((x > clipX) && (x < (clipX + clipW))&& (y > clipY) && (y < (clipY + clipH)))) return false; bool bFound = false; for (uint32 i = 0; i < _PolyButtons.size(); ++i) { if (_PolyButtons[i]->contains(CVector2f((float)x,(float)y))) { vICL.push_back(_PolyButtons[i]); bFound = true; } } return CInterfaceGroup::getCtrlsUnder(x, y, clipX, clipY, clipW, clipH, vICL); } //============================================================================================================ inline void CGroupMap::updateButtonPos(CLandMarkButton &dest) const { sint32 x, y; mapToWindowSnapped(x, y, dest.Pos); dest.setX(x); dest.setY(y); } //============================================================================================================ void CGroupMap::updateCoords() { updateSelectionAxisSize(); // CGroupContainer *enclosingContainer = getEnclosingContainer(); if (!enclosingContainer || !enclosingContainer->getActive()) return; // update position of landmarks updateScale(); // Look if we want to display some details info // Show / Hide details with the ratio indicating the meter per pixel of screen // float denomU = _MapTexW * _Scale; _WorldToMapDeltaX = denomU != 0 ? 1.f / denomU : 0.f; // float denomV = _MapTexH * _Scale; _WorldToMapDeltaY = denomV != 0 ? 1.f / denomV : 0.f; // CInterfaceGroup::updateCoords(); // if (_MapMode == MapMode_Normal) { // float minU, minV, maxU, maxV; computeUVRect(minU, minV, maxU, maxV); mapToWorld(_VisibleWorldMin, CVector2f(minU,maxV)); mapToWorld(_VisibleWorldMax, CVector2f(maxU,minV)); sint32 mapW = std::min(_MapW, _WReal); _MeterPerPixel = (_VisibleWorldMax.x - _VisibleWorldMin.x) / mapW; // bool newLandMarkShown = false; uint i; for (i = 0; i < _ContinentLM.size(); ++i) setupFromZoom(_ContinentLM[i], _ContinentLM[i]->Type, _MeterPerPixel); for (i = 0; i < _ContinentText.size(); ++i) setupFromZoom(_ContinentText[i], _ContinentText[i]->Type, _MeterPerPixel); // updateLandMarkList(_ContinentLM); updateLandMarkTextList(_ContinentText); updateLandMarkList(_UserLM); updateLandMarkList(_MissionLM); // target if (_TargetLM && _TargetLM->getActive()) updateButtonPos(*_TargetLM); // home if (_HomeLM && _HomeLM->getActive()) updateButtonPos(*_HomeLM); // animals updateLandMarkList(_AnimalLM); // teammates updateLandMarkList(_TeammateLM); for (uint32 i = 0; i < _PolyButtons.size(); ++i) _PolyButtons[i]->updateCoords(); } // updateLandMarkList(_RespawnLM); // user decorations for(TDecos::iterator it = _Decos.begin(); it != _Decos.end(); ++it) { (*it)->onUpdate(*this); } // CInterfaceGroup::updateCoords(); // must update coords twice : first is to get map size and meter per pixel -> this allow to know which landmark are visible //second is to update (possibly newly visible) landmarks position } //============================================================================================================ void CGroupMap::worldToMap(NLMISC::CVector2f &dest,const NLMISC::CVector2f &src) const { dest.x = _MapMinCorner.x != _MapMaxCorner.x ? (src.x - _MapMinCorner.x) / (_MapMaxCorner.x - _MapMinCorner.x) : _MapMinCorner.x; dest.y = _MapMinCorner.y != _MapMaxCorner.y ? 1.f - (src.y - _MapMinCorner.y) / (_MapMaxCorner.y - _MapMinCorner.y) : 1.f - _MapMinCorner.y; } //============================================================================================================ void CGroupMap::mapToWorld(NLMISC::CVector2f &dest,const NLMISC::CVector2f &src) const { dest.x = src.x * (_MapMaxCorner.x - _MapMinCorner.x) + _MapMinCorner.x; dest.y = (1.f - src.y) * (_MapMaxCorner.y - _MapMinCorner.y) + _MapMinCorner.y; } /* //============================================================================================================ void CGroupMap::mapToScreen(sint32 &px, sint32 &py, const NLMISC::CVector2f &src) const { px = (sint32) (_XReal + (src.x - (_PlayerPos.x + _Offset.x)) * _MapTexW * _Scale); py = (sint32) (_YReal + _HReal - (src.y - (_PlayerPos.y + _Offset.y)) * _MapTexH * _Scale); } //============================================================================================================ void CGroupMap::mapToWindow(sint32 &px, sint32 &py, const NLMISC::CVector2f &src) const { px = (sint32) ((src.x - (_PlayerPos.x + _Offset.x)) * _MapTexW * _Scale); py = (sint32) (_HReal - (src.y - (_PlayerPos.y + _Offset.y)) * _MapTexH * _Scale); } */ //============================================================================================================ void CGroupMap::worldToWindow(NLMISC::CVector2f &dest, const NLMISC::CVector2f &src) const { worldToMap(dest, src); mapToWindow(dest, dest); } //============================================================================================================ void CGroupMap::worldToWindowSnapped(sint32 &px,sint32 &py, const NLMISC::CVector2f &src) const { NLMISC::CVector2f snappedPos; snappedPos.x = _WorldToMapDeltaX != 0.f ? (src.x - fmodf(src.x, _WorldToMapDeltaX)) : src.x; snappedPos.y = _WorldToMapDeltaY != 0.f ? (src.y - fmodf(src.y, _WorldToMapDeltaY)) : src.y; worldToMap(snappedPos, snappedPos); mapToWindow(px, py, snappedPos); } //============================================================================================================ void CGroupMap::mapToWindowSnapped(sint32 &px,sint32 &py, const NLMISC::CVector2f &src) const { NLMISC::CVector2f snappedPos; snappedPos.x = _WorldToMapDeltaX != 0.f ? (src.x - fmodf(src.x, _WorldToMapDeltaX)) : src.x; snappedPos.y = _WorldToMapDeltaY != 0.f ? (src.y - fmodf(src.y, _WorldToMapDeltaY)) : src.y; mapToWindow(px, py, snappedPos); } //============================================================================================================ void CGroupMap::mapToScreen(sint32 &px, sint32 &py, const NLMISC::CVector2f &src) const { px = (sint32) (_XReal + _MapX + (src.x - (_PlayerPos.x + _Offset.x)) * _MapTexW * _Scale); py = (sint32) (_YReal + _MapY + _HReal - (src.y - (_PlayerPos.y + _Offset.y)) * _MapTexH * _Scale); } //============================================================================================================ void CGroupMap::windowToScreen(sint32 &destX, sint32 &destY, sint32 srcX, sint32 srcY) const { destX = srcX + _XReal; destY = srcY + _YReal; } //============================================================================================================ void CGroupMap::mapToWindow(sint32 &px, sint32 &py, const NLMISC::CVector2f &src) const { px = (sint32) ((src.x - (_PlayerPos.x + _Offset.x)) * _MapTexW * _Scale) + _MapX; py = (sint32) (_HReal - (src.y - (_PlayerPos.y + _Offset.y)) * _MapTexH * _Scale) + _MapY; } //============================================================================================================ void CGroupMap::mapToWindow(NLMISC::CVector2f &dest,const NLMISC::CVector2f &src) const { dest.x = ((src.x - (_PlayerPos.x + _Offset.x)) * _MapTexW * _Scale) + (float) _MapX; dest.y = (sint32) (_HReal - (src.y - (_PlayerPos.y + _Offset.y)) * _MapTexH * _Scale) + (float) _MapY; } //============================================================================================================ void CGroupMap::screenToMap(NLMISC::CVector2f &dest, sint32 px, sint32 py) const { if (_MapTexW == 0 || _MapTexH == 0) { dest.set(0.f, 0.f); return; } dest.x = (px - (_XReal + _MapX)) / (_MapTexW * _Scale) + _PlayerPos.x + _Offset.x; dest.y = (_YReal + _HReal + _MapY - py) / (_MapTexH * _Scale) + _PlayerPos.y + _Offset.y; } //============================================================================================================ void CGroupMap::windowToMap(NLMISC::CVector2f &dest,sint32 px,sint32 py) const { if (_MapTexW == 0 || _MapTexH == 0) { dest.set(0.f, 0.f); return; } dest.x = ((px + 0.5f) - _MapX) / (_MapTexW * _Scale) + _PlayerPos.x + _Offset.x; dest.y = (_HReal + _MapY - (py - 0.5f)) / (_MapTexH * _Scale) + _PlayerPos.y + _Offset.y; } //============================================================================================================ void CGroupMap::updateLMPosFromDBPos(CLandMarkButton *dest ,sint32 px, sint32 py) { nlassert(dest); if (px == 0 && py == 0) { dest->setActive(false); } else { NLMISC::CVector2f worldPos(px * 0.001f, py * 0.001f); NLMISC::CVector2f mapPos; worldToMap(mapPos, worldPos); if (mapPos.x != dest->Pos.x) { dest->Pos.x = mapPos.x; dest->invalidateCoords(); } if (mapPos.y != dest->Pos.y) { dest->Pos.y = mapPos.y; dest->invalidateCoords(); } dest->setActive(true); } } //============================================================================================================ // create mission position state object from base db path static CSmartPtr buildMissionPositionState(CInterfaceManager *im, const std::string &baseDBpath, uint missionIndex, uint targetIndex) { nlassert(im); CCDBNodeLeaf *name = im->getDbProp(baseDBpath + NLMISC::toString(":%d:TARGET%d:TITLE", (int) missionIndex, (int) targetIndex)); CCDBNodeLeaf *x = im->getDbProp(baseDBpath + NLMISC::toString(":%d:TARGET%d:X", (int) missionIndex, (int) targetIndex)); CCDBNodeLeaf *y = im->getDbProp(baseDBpath +NLMISC::toString(":%d:TARGET%d:Y", (int) missionIndex, (int) targetIndex)); CSmartPtr ps = new CNamedEntityPositionState; ps->build(name, x, y); return ps; } //============================================================================================================ void CGroupMap::checkCoords() { if (!_Active) return; updatePlayerPos(); if (!_MapTF && !_MapLoadFailure) { loadMap(); invalidateCoords(); } updateContinentInfo(); CInterfaceManager *pIM = CInterfaceManager::getInstance(); // **** update landmark for missions from the database if (_MissionPosStates.empty()) // pointers on db node initialised ? { _MissionPosStates.resize(2 * MAX_NUM_MISSIONS * MAX_NUM_MISSION_TARGETS); // 2 is because of group missions uint targetIndex = 0; for(uint k = 0; k < MAX_NUM_MISSIONS; ++k) { for(uint l = 0; l getDbProp(COMPASS_DB_PATH ":TARGET"); _HomePos = pIM->getDbProp(COMPASS_DB_PATH ":HOME_POINT"); } // // bool mustInvalidateCoords = false; for(uint k = 0; k < 2 * MAX_NUM_MISSIONS * MAX_NUM_MISSION_TARGETS; ++k) { sint32 nameID = _MissionPosStates[k]->getNameNode()->getValue32(); if (nameID != _MissionTargetTextIDs[k]) { _MissionTargetTextIDs[k] = nameID; if (_MissionTargetTextIDs[k] == 0) { if (_MissionLM[k] != NULL) { delCtrl(_MissionLM[k]); _MissionLM[k] = NULL; } } else { // create a new button if necessary if (_MissionLM[k] == NULL) { _MissionLM[k] = createLandMarkButton(_MissionLMOptions); _MissionLM[k]->setParent(this); addCtrl(_MissionLM[k]); } } // text must be received _MissionTargetTextReceived[k] = false; } if (_MissionLM[k]) { // update text if needed if (!_MissionTargetTextReceived[k]) { ucstring result; if (STRING_MANAGER::CStringManagerClient::instance()->getDynString(_MissionTargetTextIDs[k], result)) { _MissionLM[k]->setDefaultContextHelp(result); _MissionTargetTextReceived[k] = true; } } } } // **** retrieve pos of target and update it, or hide it if there's no target if (_TargetLM) { sint32 px = (sint32) (_TargetPos->getValue64() >> 32); sint32 py = _TargetPos->getValue32(); updateLMPosFromDBPos(_TargetLM, px, py); if (_TargetLM->getActive()) { if (UserEntity) { if (UserEntity->selection() != CLFECOMMON::INVALID_SLOT && UserEntity->selection() != 0) { CEntityCL *sel = EntitiesMngr.entity(UserEntity->selection()); if (sel) { _TargetLM->setDefaultContextHelp(NLMISC::CI18N::get("uiTargetTwoPoint") + sel->removeTitleAndShardFromName(sel->getEntityName())); } } } } } // **** retrieve pos of home and update it, or hide it if there's no target if (_HomeLM) { sint32 px = (sint32) (_HomePos->getValue64() >> 32); sint32 py = _HomePos->getValue32(); updateLMPosFromDBPos(_HomeLM, px, py); } // **** retrieve pos of respawn and update it, or hide it if there's no target uint i; if (_RespawnPos.size() < _RespawnLM.size()) { for (i = (uint)_RespawnPos.size(); i < _RespawnLM.size(); i++) { delCtrl(_RespawnLM[i]); _RespawnLM[i] = NULL; } } _RespawnLM.resize(_RespawnPos.size(), NULL); for(i = 0; i < _RespawnPos.size(); ++i) { if (_RespawnLM[i] == NULL) { _RespawnLM[i] = createLandMarkButton(_RespawnLMOptions); _RespawnLM[i]->setId(this->getId() + ":rplm_" + NLMISC::toString(i)); _RespawnLM[i]->setParent(this); if (_MapMode == MapMode_SpawnSquad) _RespawnLM[i]->setDefaultContextHelp(NLMISC::CI18N::get("uiSquadSpawnPoint") + NLMISC::toString(" %u", i+1)); else { if (isIsland()) { _RespawnLM[i]->setDefaultContextHelp(NLMISC::CI18N::get("uiR2EntryPoint")); } else { _RespawnLM[i]->setDefaultContextHelp(NLMISC::CI18N::get("uiRespawnPoint")); } _RespawnLM[i]->HandleEvents = R2::getEditor().getMode() != R2::CEditor::EditionMode; } addCtrl(_RespawnLM[i]); } if (_RespawnLM[i]) updateLMPosFromDBPos(_RespawnLM[i], _RespawnPos[i].x, _RespawnPos[i].y); } if ((_MapMode == MapMode_Death) || (_MapMode == MapMode_SpawnSquad)) { if (_RespawnPosReseted) { _RespawnPosReseted = false; // Reset selection _RespawnSelected = 0; if (_MapMode == MapMode_Death) pIM->getDbProp("UI:SAVE:RESPAWN_PT")->setValue32(_RespawnSelected); else if (_MapMode == MapMode_SpawnSquad) pIM->getDbProp("UI:TEMP:OUTPOST:SQUAD_RESPAWN_PT")->setValue32(_RespawnSelected); if (_RespawnLM.size() > 0) _RespawnSelectedBitmap->setParentPos(_RespawnLM[_RespawnSelected]); } else { _RespawnSelected = getRespawnSelected(); if (_RespawnLM.size() > 0) _RespawnSelectedBitmap->setParentPos(_RespawnLM[_RespawnSelected]); } } // **** Animal Landmarks // initialize DB if not done if(_AnimalPosStates.empty() && !_AnimalLM.empty()) { _AnimalPosStates.resize(_AnimalLM.size()); // pack animals nlassert(_AnimalPosStates.size()<=MAX_INVENTORY_ANIMAL); for(uint i=0;ibuild(NLMISC::toString("SERVER:PACK_ANIMAL:BEAST%d",i)); } } // update DB pos & tooltip text for(i=0;i<_AnimalLM.size();i++) { if( _AnimalLM[i] ) { if (_IsIsland) { _AnimalLM[i]->setActive(false); } else { _AnimalLM[i]->setActive(true); // update texture from animal status CInterfaceManager *pIM= CInterfaceManager::getInstance(); CCDBNodeLeaf *statusNode = pIM->getDbProp(toString("SERVER:PACK_ANIMAL:BEAST%d", i) + ":STATUS", false); if (statusNode && ANIMAL_STATUS::isInStable((ANIMAL_STATUS::EAnimalStatus)statusNode->getValue32()) ) { _AnimalLM[i]->setTexture(_AnimalStableLMOptions.LandMarkTexNormal); _AnimalLM[i]->setScale(true); // hardcoded because chosen icon is too big (bad...) } else if (statusNode && ANIMAL_STATUS::isDead((ANIMAL_STATUS::EAnimalStatus)statusNode->getValue32()) ) { _AnimalLM[i]->setTexture(_AnimalDeadLMOptions.LandMarkTexNormal); _AnimalLM[i]->setScale(true); // hardcoded because chosen icon is too big (bad...) } else { _AnimalLM[i]->setTexture(_AnimalLMOptions.LandMarkTexNormal); } // update tooltip text ANIMAL_TYPE::EAnimalType at; at = (ANIMAL_TYPE::EAnimalType)pIM->getDbProp("SERVER:PACK_ANIMAL:BEAST"+toString(i)+":TYPE")->getValue32(); string sPrefix; switch(at) { default: case ANIMAL_TYPE::All: sPrefix = "uiPATitleMount"; break; case ANIMAL_TYPE::Mount: sPrefix = "uiPATitleMount"; break; case ANIMAL_TYPE::Packer: sPrefix = "uiPATitlePacker"; break; case ANIMAL_TYPE::Demon: sPrefix = "uiPATitleDemon"; break; } _AnimalLM[i]->setDefaultContextHelp(NLMISC::CI18N::get(sPrefix+toString(i+1))); // update pos sint32 px, py; _AnimalPosStates[i]->getPos(px, py); updateLMPosFromDBPos(_AnimalLM[i], px, py); } } } // **** Teammate Landmarks // initialize DB if not done if(_TeammatePosStates.empty() && !_TeammateLM.empty()) { _TeammatePosStates.resize(MaxNumPeopleInTeam); for(uint i=0; i < MaxNumPeopleInTeam; i++) { _TeammatePosStates[i] = new CTeammatePositionState; _TeammatePosStates[i]->build(NLMISC::toString("SERVER:GROUP:%d",i)); } } // update DB pos. for(i=0; i < _TeammateLM.size(); i++) { if (_TeammateLM[i]) { sint32 px, py; if (_TeammatePosStates[i]->getPos(px, py)) { CInterfaceManager *im = CInterfaceManager::getInstance(); uint32 val = im->getDbProp(NLMISC::toString("SERVER:GROUP:%d:NAME",i))->getValue32(); STRING_MANAGER::CStringManagerClient *pSMC = STRING_MANAGER::CStringManagerClient::instance(); ucstring res; if (pSMC->getString(val,res)) { res = CEntityCL::removeTitleAndShardFromName(res); _TeammateLM[i]->setDefaultContextHelp(res); } } updateLMPosFromDBPos(_TeammateLM[i], px, py); } } // update position for mission landmarks // TODO : try to factor behaviour between anim / treamate / missions (they are all dynamic) // TODO : make just one list of landmark with a CCompassTarget would be better ? for(i=0; i < _MissionPosStates.size(); i++) { if (_MissionLM[i]) { sint32 px, py; if (_MissionPosStates[i]->getPos(px, py)) { updateLMPosFromDBPos(_MissionLM[i], px, py); } } } // **** check if player has moved if (!EntitiesMngr.entities().empty()) { if (EntitiesMngr.entity(0)) { const NLMISC::CVectorD &playerPos = EntitiesMngr.entity(0)->pos(); CVector2f newPlayerPos((float) playerPos.x, (float) playerPos.y); if (newPlayerPos != _OldPlayerPos) { _OldPlayerPos = newPlayerPos; invalidateCoords(); } } } CInterfaceGroup::checkCoords(); } //============================================================================================================ static void setupFromZoom(CViewBase *pVB, CContLandMark::TContLMType t, float fMeterPerPixel) { bool active = false; // Icon if ((t == CContLandMark::Capital) && (fMeterPerPixel <= 5.0f)) active = true; if ((t == CContLandMark::Village) && (fMeterPerPixel <= 4.0f)) active = true; if ((t == CContLandMark::Outpost) && (fMeterPerPixel <= 4.0f)) active = true; if ((t == CContLandMark::Stable) && (fMeterPerPixel <= 3.5f)) active = true; // Just a text if ((t == CContLandMark::Region) && (fMeterPerPixel <= 50.0f)) active = true; if ((t == CContLandMark::Place) && (fMeterPerPixel <= 6.0f)) active = true; if ((t == CContLandMark::Street) && (fMeterPerPixel <= 2.0f)) active = true; if (t == CContLandMark::Unknown) active = true; pVB->setActive(active); } //============================================================================================================ void CGroupMap::computeUVRect(float &minU, float &minV, float &maxU, float &maxV) const { minU = _Offset.x + _PlayerPos.x; minV = _Offset.y + _PlayerPos.y; // delta U & V for a pixel on screen float deltaU = 1.f / favoid0(_MapTexW * _Scale); float deltaV = 1.f / favoid0(_MapTexH * _Scale); // if (_MapX < 0) { minU -= deltaU * _MapX; } // if (_MapY > 0) { minV += deltaV * _MapY; } // 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) minU -= fmodf(minU, deltaU); minV -= fmodf(minV, deltaV); // sint32 mapW = std::min(_MapW, _WReal); sint32 mapH = std::min(_MapH, _HReal); // maxU = minU + ((float) mapW / favoid0(_Scale * (float) _MapTexW)); maxV = minV + ((float) mapH / favoid0(_Scale * (float) _MapTexH)); } //============================================================================================================ void CGroupMap::computeFrustumQuad(CQuad &fruQuad) const { CVector2f winPos; const NLMISC::CVector &camPos = MainCam.getMatrix().getPos(); worldToWindow(winPos, camPos); fruQuad.V0.set(winPos.x, winPos.y, 0.f); CVector projectedFront = MainCam.getMatrix().getJ(); projectedFront.z = 0.f; if (projectedFront.norm() <= 0.01f) { projectedFront = MainCam.getMatrix().getK(); projectedFront.z = 0.f; } CVector front = projectedFront.normed(); CVector right(- front.y, front.x, 0.f); const NL3D::CFrustum &fru = MainCam.getFrustum(); float farRight = fru.Right * (fru.Far / fru.Near); float farLeft = fru.Left * (fru.Far / fru.Near); worldToWindow(winPos, camPos + farRight * right + fru.Far * front);; fruQuad.V1.set(winPos.x, winPos.y, 0.f); worldToWindow(winPos, camPos + farLeft * right + fru.Far * front);; fruQuad.V3.set(winPos.x, winPos.y, 0.f); CVector middle = 0.5f * (fruQuad.V1 + fruQuad.V3); fruQuad.V2 = fruQuad.V0 + 2.f * (middle - fruQuad.V0); } //============================================================================================================ void CGroupMap::draw() { // user decorations for(TDecos::iterator it = _Decos.begin(); it != _Decos.end(); ++it) { (*it)->onPreRender(*this); } // TMP TMP for debug static volatile bool clearAll = false; if (clearAll) { removeLandMarks(_ContinentLM); removeLandMarks(_MissionLM); removeLandMarks(_AnimalLM); removeLandMarks(_TeammateLM); for (uint k = 0; k < _ContinentText.size(); ++k) delView(_ContinentText[k]); _ContinentText.clear(); for (uint k = 0; k < _PolyButtons.size(); ++k) delCtrl(_PolyButtons[k]); _PolyButtons.clear(); } sint32 oldSciX, oldSciY, oldSciW, oldSciH; makeNewClip (oldSciX, oldSciY, oldSciW, oldSciH); CInterfaceManager *im = CInterfaceManager::getInstance(); CViewRenderer &vr = im->getViewRenderer(); uint8 alpha = im->getGlobalColorForContent().A; updateScale(); // No Op if screen minimized if(vr.isMinimized()) return; // compute scissors uint32 sw, sh; vr.getScreenSize(sw, sh); NL3D::CScissor oldScissor; oldScissor = Driver->getScissor(); sint32 sciX, sciY, sciW, sciH; vr.getClipWindow(sciX, sciY, sciW, sciH); NL3D::CScissor newScissor; newScissor.X = sciX / (float) sw; newScissor.Width = sciW / (float) sw; newScissor.Y = sciY / (float) sh; newScissor.Height = sciH / (float) sh; // if (!_PlayerPosTF && !_PlayerPosLoadFailure) { loadPlayerPos(); } if (!_MapLoadFailure) { if (_MapTexW != 0 && _MapTexH != 0) { float minU, minV, maxU, maxV; computeUVRect(minU, minV, maxU, maxV); // draw the map sint32 mapW = std::min(_MapW, _WReal); sint32 mapH = std::min(_MapH, _HReal); // Display fog of war map CVector2f fowMin(0,0), fowMax(0,0); float fowURatio = 0.0f; float fowVRatio = 0.0f; // Convert u,v (from map coords) to world coordinates CVector2f worldMin, worldMax; mapToWorld(worldMin, CVector2f(minU,minV)); mapToWorld(worldMax, CVector2f(maxU,maxV)); if (_CurContinent != NULL) { // Convert world coordinate to map coordinate in the fog of war map CFogOfWar &rFOW = _CurContinent->FoW; if (rFOW.getMaxX() != rFOW.getMinX()) fowMin.x = (worldMin.x - rFOW.getMinX()) / (rFOW.getMaxX() - rFOW.getMinX()); if (rFOW.getMaxY() != rFOW.getMinY()) fowMin.y = (worldMin.y - rFOW.getMinY()) / (rFOW.getMaxY() - rFOW.getMinY()); if (rFOW.getMaxX() != rFOW.getMinX()) fowMax.x = (worldMax.x - rFOW.getMinX()) / (rFOW.getMaxX() - rFOW.getMinX()); if (rFOW.getMaxY() != rFOW.getMinY()) fowMax.y = (worldMax.y - rFOW.getMinY()) / (rFOW.getMaxY() - rFOW.getMinY()); if ((fowMin.x >= 0) && (fowMin.x <= 1) && (fowMin.y >= 0) && (fowMin.y <= 1) && (fowMax.x >= 0) && (fowMax.x <= 1) && (fowMax.y >= 0) && (fowMax.y <= 1)) { fowURatio = (float)rFOW.getMapWidth() / favoid0((float)rFOW.getRealWidth()); fowVRatio = (float)rFOW.getMapHeight() / favoid0((float)rFOW.getRealHeight()); } } vr.drawCustom(_XReal + std::max(_MapX, (sint32) 0), _YReal - std::min(_MapY, (sint32) 0), mapW, mapH, CUV(minU * _URatio, minV * _VRatio), CUV(maxU * _URatio, maxV * _VRatio), CUV(fowMin.x * fowURatio, fowMin.y * fowVRatio), CUV(fowMax.x * fowURatio, fowMax.y * fowVRatio), CRGBA(255, 255, 255, alpha), _MapMaterial ); // Look if we want to display some details info // Show / Hide details with the ratio indicating the meter per pixel of screen /* { float fMeterPerPixel = (worldMax.x - worldMin.x) / mapW; uint32 i; for (i = 0; i < _ContinentLM.size(); ++i) setupFromZoom(_ContinentLM[i], _ContinentLM[i]->Type, fMeterPerPixel); for (i = 0; i < _ContinentText.size(); ++i) setupFromZoom(_ContinentText[i], _ContinentText[i]->Type, fMeterPerPixel); } */ /* if (_MapW < _WReal || _MapH < _HReal) vr.drawWiredQuad(_XReal + _MapX, _YReal - _MapY, _MapW, _MapH, CRGBA(0, 0, 0, alpha));*/ } } // if editor is in edition mode, draw the frustum instead (for better visibility) CQuad fruQuad; CTriangle fruTri; CRGBA fruColor(0, 0, 0); if (_FrustumView) { if (R2::getEditor().getMode() == R2::CEditor::EditionMode) { static volatile bool wantFrustum = true; if (wantFrustum) { computeFrustumQuad(fruQuad); _FrustumView->setActive(true); //_FrustumView->setAdditif(true); _FrustumView->setQuad(fruQuad); _FrustumView->updateCoords(); // handle mouse over if (im->getPointer()) { sint32 originX, originY; getCorner(originX, originY, getPosRef()); CVector delta((float) originX, (float) originY, 0.f); fruTri = CTriangle(fruQuad.V0, fruQuad.V1, fruQuad.V2); CVector mousePos((float) im->getPointer()->getXReal(), (float) im->getPointer()->getYReal(), 0.f); mousePos -= delta; CVector dummyHit; float deltaBlend = DT / (0.001f * (float) _FrustumViewBlendTimeInMs); bool hit = fruTri.intersect(mousePos + CVector::K, mousePos - CVector::K, dummyHit, CPlane(0.f, 0.f, 0.f, 1.f)); NLMISC::incrementalBlend(_FrustumOverBlendFactor, hit ? 1.f : 0.f, deltaBlend); fruColor.blendFromui(_FrustumViewColor, _FrustumViewColorOver, (uint8) (255 * _FrustumOverBlendFactor)); } else { fruColor = _FrustumViewColor; } // _FrustumView->setColorRGBA(fruColor); } } else { _FrustumView->setActive(false); } } //Driver->setScissor(oldScissor); // let parent view draw continent, mission and user locations CInterfaceGroup::draw(); // force the flush vr.flush(); Driver->setScissor(newScissor); if (R2::getEditor().getMode() != R2::CEditor::EditionMode) { // Draw the player TODO : replace with a CViewQuad if (!_PlayerPosLoadFailure) { // draw rotated bitmap for player position const NLMISC::CVector &front3f = UserEntity->front(); NLMISC::CVector2f front; NLMISC::CVector2f right; front.set(front3f.x, front3f.y); right.set(front3f.y, - front3f.x); // compute corners sint32 spx, spy; mapToScreen(spx, spy, _PlayerPos); NLMISC::CVector center; center.set((float) spx, (float) spy, 0.f); NLMISC::CQuadColorUV quv; quv.V0 = center - 0.5f * (float) _PlayerPosTexW * right - 0.5f * (float) _PlayerPosTexH * front; quv.V1 = center + 0.5f * (float) _PlayerPosTexW * right - 0.5f * (float) _PlayerPosTexH * front; quv.V2 = center + 0.5f * (float) _PlayerPosTexW * right + 0.5f * (float) _PlayerPosTexH * front; quv.V3 = center - 0.5f * (float) _PlayerPosTexW * right + 0.5f * (float) _PlayerPosTexH * front; quv.Uv0.set(0.f, 1.f); quv.Uv1.set(1.f, 1.f); quv.Uv2.set(1.f, 0.f); quv.Uv3.set(0.f, 0.f); quv.Color0 = quv.Color1 = quv.Color2 = quv.Color3 = CRGBA(255, 255, 255, alpha); quv.V0.x /= (float) sw; quv.V0.y /= (float) sh; quv.V1.x /= (float) sw; quv.V1.y /= (float) sh; quv.V2.x /= (float) sw; quv.V2.y /= (float) sh; quv.V3.x /= (float) sw; quv.V3.y /= (float) sh; Driver->drawQuads(&quv, 1, _PlayerPosMaterial); } } // draw border of frustum if (_FrustumView) { if (R2::getEditor().getMode() == R2::CEditor::EditionMode) { if (_FrustumMaterial.empty()) { // create material for the world map _FrustumMaterial = Driver->createMaterial(); if (!_FrustumMaterial.empty()) { _FrustumMaterial.initUnlit(); _FrustumMaterial.setZWrite(false); _FrustumMaterial.setZFunc(NL3D::UMaterial::always); _FrustumMaterial.setBlend (true); _FrustumMaterial.setBlendFunc (NL3D::UMaterial::srcalpha, NL3D::UMaterial::invsrcalpha); _FrustumMaterial.setDoubleSided(); } } if (!_FrustumMaterial.empty()) { fruColor.A /= 2; _FrustumMaterial.setColor(fruColor); //Driver->setScissor(newScissor); NL3D::UDriver::TPolygonMode oldPolygonMode = Driver->getPolygonMode(); Driver->setPolygonMode(NL3D::UDriver::Line); // CTriangle fruTri; fruTri.V0.set((fruQuad.V0.x + _XReal) / sw, (fruQuad.V0.y + _YReal) / sh, 0.f); fruTri.V1.set((fruQuad.V1.x + _XReal) / sw, (fruQuad.V1.y + _YReal) / sh, 0.f); fruTri.V2.set((fruQuad.V3.x + _XReal) / sw, (fruQuad.V3.y + _YReal) / sh, 0.f); Driver->drawTriangle(fruTri, _FrustumMaterial); Driver->setPolygonMode(oldPolygonMode); } } } // Draw all poly buttons for (uint32 i = 0; i < _PolyButtons.size(); ++i) { _PolyButtons[i]->drawPolyButton(); } // Restore Old Scissor Driver->setScissor(oldScissor); restoreClip (oldSciX, oldSciY, oldSciW, oldSciH); } //============================================================================================================ bool CGroupMap::handleEvent(const CEventDescriptor &event) { CInterfaceManager *im = CInterfaceManager::getInstance(); // if R2 editor editor is on, give it a chance to handle the event first if (ClientCfg.R2EDEnabled && R2::getEditor().getCurrentTool()) { bool handled = false; bool panEnd = false; // handle standard clicks if (event.getType() == CEventDescriptor::mouse) { const CEventDescriptorMouse &eventDesc = (const CEventDescriptorMouse &)event; panEnd = eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftup && _Panning && _HasMoved; if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftup && !panEnd) { //if (im->getCapturePointerLeft() == this) // NB : don't test capture of mouse here, because // some R2 tool may begin outside of this window // example : clicking in the palette window and doing a drag-and-drop to the // minimap { handled = R2::getEditor().getCurrentTool()->onMouseLeftButtonUp(); if (!handled) { handled = R2::getEditor().getCurrentTool()->onMouseLeftButtonClicked(); } } if (!handled && R2::getEditor().getMode() == R2::CEditor::EditionMode) { if (R2::getEditor().getCurrentTool()) { if (!R2::getEditor().getCurrentTool()->getPreviousToolClickEndFlag()) { if (im->getCapturePointerLeft() == this) { // 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) R2::getEditor().setSelectedInstance(NULL); } } } } } else if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightup) { if (im->getCapturePointerRight() == this) { if (isIn(eventDesc.getX(), eventDesc.getY())) { NLMISC::CVector2f clickPos; screenToMap(clickPos, eventDesc.getX(), eventDesc.getY()); if (clickPos.x >= 0.f && clickPos.y >= 0.f && clickPos.x <= 1.f && clickPos.y <= 1.f ) { handled = R2::getEditor().getCurrentTool()->onMouseRightButtonClicked(); } } } } } if (!panEnd) { handled = handled || R2::getEditor().getCurrentTool()->handleEvent(event); } if (handled) { _Panning = false; _HasMoved = false; return true; } } for (uint32 i = 0; i < _PolyButtons.size(); ++i) if (_PolyButtons[i]->handleEvent(event)) return true; // left button can be used to 'pan' the map // mouse wheel can be used to zoom in/out if (event.getType() == CEventDescriptor::mouse) { if (!_Active) return false; const CEventDescriptorMouse &eventDesc = (const CEventDescriptorMouse &)event; if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftup) { if (im->getCapturePointerLeft() != this) { return false; } _Panning = false; _HasMoved = false; return true; } if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightdown) { im->setCapturePointerRight(this); return true; } if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouseleftdown) { if (isIn(eventDesc.getX(), eventDesc.getY())) { im->setCapturePointerLeft(this); _StartXForPaning = eventDesc.getX(); _StartYForPaning = eventDesc.getY(); _StartWorldOffsetForPaning = _WorldOffset; // Clamp the start WorldOffset on the Move start. NB: not clamped on a scale computeOffsets(); _StartWorldOffsetForPaning.x= _Offset.x * (_MapMaxCorner.x - _MapMinCorner.x); _StartWorldOffsetForPaning.y= _Offset.y * (_MapMaxCorner.y - _MapMinCorner.y); _PanStartDateInMs = T1; /** If in editor, and current tool is a creation tool, only handle panning after a small delta pos / delta time * for better ergonomy */ if (ClientCfg.R2EDEnabled && R2::getEditor().getCurrentTool() && R2::getEditor().getCurrentTool()->isCreationTool() ) { _DeltaPosBeforePan = 2; _DeltaTimeBeforePanInMs = 300; } else { // handle panning immediately _DeltaPosBeforePan = 0; _DeltaTimeBeforePanInMs = 0; } _Panning = true; return true; } } if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mousemove) { if (im->getCapturePointerLeft() != this || !_Panning) return CInterfaceGroup::handleEvent(event); if (_MapTexW != 0 && _MapTexH != 0) { if (_HasMoved || (T1 - _PanStartDateInMs) > _DeltaTimeBeforePanInMs || (uint) abs(eventDesc.getX() - _StartXForPaning) > _DeltaPosBeforePan || (uint) abs(eventDesc.getY() - _StartYForPaning) > _DeltaPosBeforePan) { _HasMoved = true; NLMISC::CVector2f dWorld; dWorld.x= - (_MapMaxCorner.x - _MapMinCorner.x) * (eventDesc.getX() - _StartXForPaning) / (_MapTexW * _Scale); dWorld.y= + (_MapMaxCorner.y - _MapMinCorner.y) * (eventDesc.getY() - _StartYForPaning) / (_MapTexH * _Scale); _WorldOffset= _StartWorldOffsetForPaning + dWorld; // Clamp the WorldOffset on a Move. NB: not clamped on a scale computeOffsets(); _WorldOffset.x= _Offset.x * (_MapMaxCorner.x - _MapMinCorner.x); _WorldOffset.y= _Offset.y * (_MapMaxCorner.y - _MapMinCorner.y); computeOffsets(); invalidateCoords(); } } return true; } if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mousewheel && !_Panning) { sint32 wheel = eventDesc.getWheel(); float newScale = _UserScale; while (wheel != 0) { if (wheel < 0) { newScale *= 0.7f; if (newScale < 1.f) { newScale = 1.f; break; } ++ wheel; } else { newScale *= 1.3f; float realScale = computeRealScaleFromUserScale(newScale); if (realScale > getActualMaxScale()) { newScale = computeUserScaleFromRealScale(getActualMaxScale()); break; } -- wheel; } } NLMISC::CVector2f mapPos; screenToMap(mapPos, eventDesc.getX(), eventDesc.getY()); setScale(newScale, mapPos); return true; } if (eventDesc.getEventTypeExtended() == CEventDescriptorMouse::mouserightup) { // convert click pos into map pos if (_MapTexW == 0 || _MapTexH == 0) { _RightClickLastPos.set(0.f, 0.f); } else { NLMISC::CVector2f clickPos; screenToMap(clickPos, eventDesc.getX(), eventDesc.getY()); if (clickPos.x < 0.f || clickPos.y < 0.f || clickPos.x > 1.f || clickPos.y > 1.f ) { return false; } _RightClickLastPos = clickPos; return CInterfaceGroup::handleEvent(event); } } } if (event.getType() == CEventDescriptor::system) { CEventDescriptorSystem &es = (CEventDescriptorSystem &) event; if (es.getEventTypeExtended() == CEventDescriptorSystem::activecalledonparent) { bool visible = getActive(); if (visible) { CInterfaceElement *curr = this->getParent(); while (curr) { if (!curr->getActive()) { visible = false; break; } curr = curr->getParent(); } } if (visible) { checkCoords(); } else { unloadMap(); } } } return CInterfaceGroup::handleEvent(event); } //============================================================================================================ void CGroupMap::pan(sint32 dx, sint32 dy) { if (_MapTexW * _Scale != 0.f) _WorldOffset.x += dx * (_MapMaxCorner.x - _MapMinCorner.x) / (_MapTexW * _Scale); if (_MapTexH * _Scale != 0.f) _WorldOffset.y -= dy * (_MapMaxCorner.y - _MapMinCorner.y) / (_MapTexH * _Scale); computeOffsets(); _WorldOffset.x= _Offset.x * (_MapMaxCorner.x - _MapMinCorner.x); _WorldOffset.y= _Offset.y * (_MapMaxCorner.y - _MapMinCorner.y); invalidateCoords(); } //============================================================================================================ void CGroupMap::setActive(bool active) { bool visible = active; CInterfaceElement *curr = this->getParent(); while (curr) { if (!curr->getActive()) { visible = false; break; } curr = curr->getParent(); } if (!visible) { unloadMap(); } CInterfaceGroup::setActive(active); if (visible) { checkCoords(); } } //============================================================================================================ void CGroupMap::loadPlayerPos() { if (_PlayerPosLoadFailure) return; _PlayerPosLoadFailure = true; if (_PlayerPosMaterial.empty()) return; std::string fullName = NLMISC::CPath::lookup(_PlayerPosTexName, false, false); if (fullName.empty()) { nlwarning("Can't player pos texture %s", _PlayerPosTexName.c_str()); return; } uint32 w, h; NLMISC::CIFile bm; if (bm.open(fullName)) { try { NLMISC::CBitmap::loadSize(fullName, w, h); } catch(const NLMISC::Exception &e) { nlwarning(e.what()); return; } } else { nlwarning("Can't open player pos texture %s", fullName.c_str()); return; } _PlayerPosTF = Driver->createTextureFile(fullName); if (!_PlayerPosTF) return; _PlayerPosLoadFailure = false; _PlayerPosTF->setWrapS(NL3D::UTexture::Clamp); _PlayerPosTF->setWrapT(NL3D::UTexture::Clamp); _PlayerPosTexW = w; _PlayerPosTexH = h; _PlayerPosMaterial.setTexture(_PlayerPosTF); } //============================================================================================================ void CGroupMap::loadMap() { _MapLoadFailure = true; if (!_CurMap) return; const std::string &mapName = _CurMap->BitmapName; std::string fullName = NLMISC::CPath::lookup(mapName, false, false); if (fullName.empty()) { nlwarning("Can't find map %s", mapName.c_str()); return; } uint32 w, h; NLMISC::CIFile bm; if (bm.open(fullName)) { try { NLMISC::CBitmap::loadSize(fullName, w, h); } catch(const NLMISC::Exception &e) { nlwarning(e.what()); return; } } else { nlwarning("Can't open map %s", mapName.c_str()); return; } _MapTF = Driver->createTextureFile(fullName); if (_MapTF) { _MapMaterial.setTexture(0, _MapTF); _MapTF->setWrapS(NL3D::UTexture::Clamp); _MapTF->setWrapT(NL3D::UTexture::Clamp); _MapTF->setEnlargeCanvasNonPOW2Tex(true); if (_IsIsland) { // island are already pow2 textures // compute the real size // (1 pixel per metter, hardcoded for now) _MapTexW = (uint32) (ISLAND_PIXEL_PER_METER * (_CurMap->MaxX - _CurMap->MinX)); _MapTexH = (uint32) (ISLAND_PIXEL_PER_METER * (_CurMap->MaxY - _CurMap->MinY)); if (_MapTexW > w) { nlwarning("Island real width > texture width, snapshot not up-to-date ? (island = %s)", _CurMap->Name.c_str()); _MapTexW = w; } if (_MapTexH > h) { nlwarning("Island real height > texture height, snapshot not up-to-date ? (island = %s)", _CurMap->Name.c_str()); _MapTexH = h; } _URatio = w != 0 ? (float) _MapTexW / w : 0.f; _VRatio = h != 0 ? (float) _MapTexH / h : 0.f; } else { // must raise to next power of 2 & scale uvs accordingly _MapTexW = w; _MapTexH = h; _URatio = (float) w / (float) NLMISC::raiseToNextPowerOf2(w); _VRatio = (float) h / (float) NLMISC::raiseToNextPowerOf2(h); } _MapLoadFailure = false; } } //============================================================================================================ void CGroupMap::unloadMap() { // remove texture from the material if (_MapTF) Driver->deleteTextureFile(_MapTF); _MapTF = NULL; if (_PlayerPosTF) Driver->deleteTextureFile(_PlayerPosTF); _PlayerPosTF = NULL; _MapMaterial.setTexture(0,NULL); _MapMaterial.setTexture(1,NULL); _MapTexW = 0; _MapTexH = 0; _MapLoadFailure = false; } //============================================================================================================ void CGroupMap::updateContinentInfo() { return; } //============================================================================================================ void CGroupMap::setMap(SMap *map) { nlassert(map); if ((_CurMap != NULL) && (_CurMap->Name == map->Name)) return; // Unload and reset all stuff unloadMap(); _CurMap = map; _CurContinent = ContinentMngr.get(_CurMap->ContinentName); _MapMinCorner.x = _CurMap->MinX; _MapMinCorner.y = _CurMap->MinY; _MapMaxCorner.x = _CurMap->MaxX; _MapMaxCorner.y = _CurMap->MaxY; if (_MapMinCorner.x > _MapMaxCorner.x) std::swap(_MapMinCorner.x, _MapMaxCorner.x); if (_MapMinCorner.y > _MapMaxCorner.y) std::swap(_MapMinCorner.y, _MapMaxCorner.y); loadMap(); centerOnPlayer(); centerOnPlayer(); invalidateCoords(); createContinentLandMarks(); if (_CurContinent != NULL) _MapMaterial.setTexture(1, _CurContinent->FoW.Tx); else _MapMaterial.setTexture(1, NULL); // disable the map_back button for islands (islands can't be seen on the world map) CGroupContainer *gc = getParentContainer(); if (gc) { CCtrlBase *mapBack = gc->getCtrl("map_back"); if (mapBack) mapBack->setActive(!_IsIsland); } centerOnPlayer(); setScale(0); } //============================================================================================================ void CGroupMap::setMap(const string &mapName) { if ((_CurMap != NULL) && (_CurMap->Name == mapName)) return; // Unload and reset all stuff unloadMap(); _IsIsland = false; // Acquire new map uint32 i; for (i = 0; i < _WorldSheet->Maps.size(); ++i) if (_WorldSheet->Maps[i].Name == mapName) break; if (i == _WorldSheet->Maps.size()) { nlwarning("Unknown map to set : %s", mapName.c_str()); return; } setMap(&_WorldSheet->Maps[i]); centerOnPlayer(); setScale(0); } //============================================================================================================ void CGroupMap::centerOnPlayer() { if (_MapTexW == 0 || _MapTexH == 0) return; // Ensure good scale computed updateScale(); // Here, in some case (init, if the map is not displayed), scale is 0. Avoid div by 0. float lx= (_MapTexW * _Scale); float ly= (_MapTexH * _Scale); if(lx==0.f) lx= 0.01f; if(ly==0.f) ly= 0.01f; _WorldOffset.x = (_MapMaxCorner.x - _MapMinCorner.x) * (_MapX - _WReal * 0.5f) / lx; _WorldOffset.y = (_MapMaxCorner.y - _MapMinCorner.y) * (- _MapY - _HReal * 0.5f) / ly; computeOffsets(); invalidateCoords(); } //============================================================================================================ void CGroupMap::setScale(float newUserScale, const NLMISC::CVector2f &/* center */) { NLMISC::clamp(newUserScale, 1.f, computeUserScaleFromRealScale(getActualMaxScale())); _UserScale = newUserScale; computeOffsets(); //fitWindow(); invalidateCoords(); } //============================================================================================================ void CGroupMap::setScale(float newScale) { sint32 centerX = (2 * (_XReal + _MapX) + std::min(_WReal, _MapW)) / 2; sint32 centerY = (2 * (_YReal + _MapY) + std::min(_HReal, _MapH)) / 2; NLMISC::CVector2f mapCoords; screenToMap(mapCoords, centerX, centerY); setScale(newScale, mapCoords); } //============================================================================================================ void CGroupMap::updateLandMarkList(TLandMarkButtonVect &lmVect) { uint numLM = (uint)lmVect.size(); for(uint k = 0; k < numLM; ++k) { CLandMarkButton *lmb = lmVect[k]; if (lmb) { updateButtonPos(*lmb); } } } //============================================================================================================ void CGroupMap::updateLandMarkTextList(TLandMarkTextVect &lmVect) { uint numLM = (uint)lmVect.size(); for(uint k = 0; k < numLM; ++k) { CLandMarkText *lmt = lmVect[k]; if (lmt != NULL) { sint32 x, y; mapToWindowSnapped(x, y, lmt->Pos); lmt->setX(x); lmt->setY(y); } } } //============================================================================================================ void CGroupMap::removeLandMarks(TLandMarkButtonVect &lm) { uint numLM = (uint)lm.size(); for(uint k = 0; k < numLM; ++k) { if (lm[k]) { delCtrl(lm[k]); } } lm.clear(); } //============================================================================================================ void CGroupMap::createLMWidgets(const std::vector &lms) { for (uint32 k = 0; k < lms.size(); ++k) { const CContLandMark &rCLM =lms[k]; NLMISC::CVector2f mapPos; worldToMap(mapPos, rCLM.Pos); const ucstring ucsTmp(CStringManagerClient::getPlaceLocalizedName(rCLM.TitleTextID)); // Add button if not a region nor a place if ((rCLM.Type != CContLandMark::Region) && (rCLM.Type != CContLandMark::Place) && (rCLM.Type != CContLandMark::Street)) { if (rCLM.Type != CContLandMark::Stable) addLandMark(_ContinentLM, mapPos, ucsTmp, _ContinentLMOptions); else addLandMark(_ContinentLM, mapPos, CI18N::get("uiStable"), _ContinentLMOptions); _ContinentLM.back()->Type = rCLM.Type; } else // just add a text { CLandMarkText *pNewText = new CLandMarkText(CViewBase::TCtorParam()); pNewText->setText(ucsTmp); pNewText->Pos = mapPos; pNewText->setParent(this); pNewText->setParentPosRef(Hotspot_BL); pNewText->setPosRef(Hotspot_MM); if (rCLM.Type == CContLandMark::Region) pNewText->setFontSize(16); pNewText->setColor(CRGBA(255,255,255,255)); pNewText->setShadow(true); pNewText->setShadowColor(CRGBA(0,0,0,255)); pNewText->setModulateGlobalColor(false); pNewText->Type = rCLM.Type; _ContinentText.push_back(pNewText); addView(pNewText); } // If the name of the landmark is used as a click zone name of the current map, create a polybutton bool bFound = false; for (uint i = 0; i < _CurMap->Children.size(); ++i) { if (rCLM.TitleTextID == _CurMap->Children[i].ZoneName) { bFound = true; break; } } if (bFound) { CPolyButton *pPB = new CPolyButton; pPB->build(rCLM.Zone, this, rCLM.TitleTextID); _PolyButtons.push_back(pPB); addCtrl(pPB); } } } //============================================================================================================ void CGroupMap::createContinentLandMarks() { uint32 k; if (_MapMode != MapMode_Normal) return; if (_CurMap == NULL) return; // Remove all removeLandMarks(_ContinentLM); for (k = 0; k < _ContinentText.size(); ++k) delView(_ContinentText[k]); _ContinentText.clear(); removeLandMarks(_UserLM); for (k = 0; k < _PolyButtons.size(); ++k) delCtrl(_PolyButtons[k]); _PolyButtons.clear(); // World map special case if (_CurMap->Name == "world") { createLMWidgets(ContinentMngr.WorldMap); invalidateCoords(); return; } if (_CurContinent == NULL) return; // Continent Landmarks createLMWidgets(_CurContinent->ContLandMarks); // User Landmarks for(k = 0; k < _CurContinent->UserLandMarks.size(); ++k) { NLMISC::CVector2f mapPos; worldToMap(mapPos, _CurContinent->UserLandMarks[k].Pos); addLandMark(_UserLM, mapPos, _CurContinent->UserLandMarks[k].Title, getUserLandMarkOptions(k)); } invalidateCoords(); } static void hideTeleportButtonsInPopupMenuIfNotEnoughPriv() { bool showTeleport = (hasPrivilegeDEV() || hasPrivilegeSGM() || hasPrivilegeGM() || hasPrivilegeVG() || hasPrivilegeSG() || hasPrivilegeEM() || hasPrivilegeEG()); CInterfaceManager *im = CInterfaceManager::getInstance(); CInterfaceElement *ie = im->getElementFromId("ui:interface:map_menu:teleport"); if(ie) ie->setActive(showTeleport); ie = im->getElementFromId("ui:interface:land_mark_menu:lmteleport"); if(ie) ie->setActive(showTeleport); ie = im->getElementFromId("ui:interface:user_land_mark_menu:lmteleport"); if(ie) ie->setActive(showTeleport); } //============================================================================================================ void CGroupMap::updateUserLandMarks() { uint32 k; if (_MapMode != MapMode_Normal) return; if (_CurMap == NULL || _CurMap->Name == "world" || _CurContinent == NULL) return; // Remove all removeLandMarks(_UserLM); // Re create User Landmarks for(k = 0; k < _CurContinent->UserLandMarks.size(); ++k) { NLMISC::CVector2f mapPos; worldToMap(mapPos, _CurContinent->UserLandMarks[k].Pos); addLandMark(_UserLM, mapPos, _CurContinent->UserLandMarks[k].Title, getUserLandMarkOptions(k)); } invalidateCoords(); hideTeleportButtonsInPopupMenuIfNotEnoughPriv(); } //============================================================================================================ CGroupMap::CLandMarkButton *CGroupMap::createLandMarkButton(const CLandMarkOptions &options) { CLandMarkButton *lmb = new CLandMarkButton(CViewBase::TCtorParam()); static int statFool = 0; lmb->setId(this->getId()+":lm"+toString(statFool++)); lmb->setTexture(options.LandMarkTexNormal); lmb->setTextureOver(options.LandMarkTexOver); lmb->setTexturePushed(options.LandMarkTexPushed); lmb->setType(CCtrlButton::PushButton); lmb->setActionOnLeftClick("land_mark_selected"); lmb->setColor(options.ColorNormal); lmb->setColorOver(options.ColorOver); lmb->setColorPushed(options.ColorPushed); lmb->setModulateGlobalColorAll(false); if (!options.LandMarkMenu.empty()) { lmb->setActionOnRightClick("active_menu"); lmb->setParamsOnRightClick(NLMISC::toString("menu=%s", options.LandMarkMenu.c_str())); } lmb->setPosRef(Hotspot_MM); return lmb; } //============================================================================================================ void CGroupMap::updateLandMarkButton(CLandMarkButton *lmb, const CLandMarkOptions &options) { lmb->setTexture(options.LandMarkTexNormal); lmb->setTextureOver(options.LandMarkTexOver); lmb->setTexturePushed(options.LandMarkTexPushed); lmb->setColor(options.ColorNormal); lmb->setColorOver(options.ColorOver); lmb->setColorPushed(options.ColorPushed); } //============================================================================================================ void CGroupMap::addLandMark(TLandMarkButtonVect &destList, const NLMISC::CVector2f &pos, const ucstring &title, const CLandMarkOptions &options) { // create a new button and add it to the list CLandMarkButton *lmb = createLandMarkButton(options); lmb->setParent(this); lmb->Pos = pos; lmb->setDefaultContextHelp(title); destList.push_back(lmb); addCtrl(lmb); } //============================================================================================================ CCtrlButton *CGroupMap::addUserLandMark(const NLMISC::CVector2f &pos, const ucstring &title, const CUserLandMark::EUserLandMarkType lmType) { if (_CurContinent == NULL) return NULL; nlassert(_CurContinent->UserLandMarks.size() == _UserLM.size()); // add the landmark in the current continent (for later save) // keep pos in world CUserLandMark ulm; mapToWorld(ulm.Pos, pos); ulm.Title = title; ulm.Type = (uint8)lmType; _CurContinent->UserLandMarks.push_back(ulm); // add a landmark with a menu to remove it addLandMark(_UserLM, pos, title, getUserLandMarkOptions((uint32)_CurContinent->UserLandMarks.size() - 1)); // Save the config file each time a user landmark is created CInterfaceManager *pIM = CInterfaceManager::getInstance(); uint8 currMode = pIM->getMode(); pIM->saveConfig ("save/interface_" + PlayerSelectedFileName + ".icfg"); if (currMode != pIM->getMode()) { pIM->setMode(currMode); } return _UserLM.back(); } //============================================================================================================ void CGroupMap::removeUserLandMark(CCtrlButton *button) { if (_CurContinent == NULL) return; nlassert(_CurContinent->UserLandMarks.size() == _UserLM.size()); for(uint k = 0; k < _UserLM.size(); ++k) { if (_UserLM[k] == button) { delCtrl(_UserLM[k]); _UserLM.erase(_UserLM.begin() + k); _CurContinent->UserLandMarks.erase(_CurContinent->UserLandMarks.begin() + k); return; } } } //============================================================================================================ void CGroupMap::updateUserLandMark(CCtrlButton *button, const ucstring &newTitle, const CUserLandMark::EUserLandMarkType lmType) { if (_CurContinent == NULL) return; nlassert(_CurContinent->UserLandMarks.size() == _UserLM.size()); for(uint k = 0; k < _UserLM.size(); ++k) { if (_UserLM[k] == button) { _CurContinent->UserLandMarks[k].Title = newTitle; _CurContinent->UserLandMarks[k].Type = (uint8)lmType; updateLandMarkButton(_UserLM[k], getUserLandMarkOptions(k)); button->setDefaultContextHelp(newTitle); return; } } } //============================================================================================================ CUserLandMark CGroupMap::getUserLandMark(CCtrlButton *button) const { CUserLandMark ulm; if (_CurContinent == NULL) return ulm; nlassert(_CurContinent->UserLandMarks.size() == _UserLM.size()); for(uint k = 0; k < _UserLM.size(); ++k) { if (_UserLM[k] == button) { return _CurContinent->UserLandMarks[k]; } } return ulm; } //============================================================================================================ void CGroupMap::removeExceedingUserLandMarks(uint maxNumber) { while (_UserLM.size() > maxNumber) { removeUserLandMark(_UserLM.back()); } } //============================================================================================================ uint CGroupMap::getNumUserLandMarks() const { if (_CurContinent == NULL) return 0; return (uint)_CurContinent->UserLandMarks.size(); } //============================================================================================================ CLandMarkOptions CGroupMap::getUserLandMarkOptions(uint32 lmindex) const { if (_CurContinent == NULL || _CurContinent->UserLandMarks.size() < lmindex) return _UserLMOptions; CLandMarkOptions clmo(_UserLMOptions); clmo.ColorNormal = clmo.ColorOver = clmo.ColorPushed = _CurContinent->UserLandMarks[lmindex].getColor(); return clmo; } //============================================================================================================ void CGroupMap::updatePlayerPos() { if (_MapMode != MapMode_SpawnSquad) { if (EntitiesMngr.entities().empty()) return; if (!EntitiesMngr.entity(0)) return; const NLMISC::CVectorD &playerPosD = EntitiesMngr.entity(0)->pos(); NLMISC::CVector pos((float) playerPosD.x, (float) playerPosD.y, (float) playerPosD.z); // convert player pos into pos in map worldToMap(_PlayerPos, pos); // if player isn't in is last map anymore, see if in another island bool isInX = false; bool isInY = false; if(_CurMap) { isInX = (_CurMap->MinX <= pos.x) && (pos.x <= _CurMap->MaxX); isInY = (_CurMap->MinY <= pos.y) && (pos.y <= _CurMap->MaxY); } if(!isInX || !isInY) { _IsIsland = false; for(uint k = 0; k < _Islands.size(); ++k) { if (pos.x >= _Islands[k].MinX && pos.y >= _Islands[k].MinY && pos.x <= _Islands[k].MaxX && pos.y <= _Islands[k].MaxY) { _IsIsland = true; setMap(&_Islands[k]); break; } } } } } //============================================================================================================ /* void CGroupMap::fitWindow() { if (!EntitiesMngr.entity(0)) return; CGroupContainer *parentCont = this->getEnclosingContainer(); if (!parentCont) return; CCtrlBase::updateCoords(); const NLMISC::CVectorD &playerPosD = EntitiesMngr.entity(0)->pos(); NLMISC::CVector pos((float) playerPosD.x, (float) playerPosD.y, (float) playerPosD.z); // convert player pos into pos in map worldToMap(_PlayerPos, pos); // x coord if (_MapTexW != 0) { float mapWidthOnScreen = floorf(_MapTexW * _Scale); sint32 diffWReal = parentCont->getWReal() - _WReal; if ((float)_WReal >= mapWidthOnScreen) { _Offset.x = - _PlayerPos.x; // _W is given by parent, so must update parent W if ((float)_WReal > mapWidthOnScreen) { parentCont->setW((sint32) mapWidthOnScreen + diffWReal); } } else { NLMISC::clamp(_Offset.x, - _PlayerPos.x, - _PlayerPos.x + 1.f - _WReal / ((float) _MapTexW * _Scale)); } sint32 maxW = (sint32) mapWidthOnScreen; sint32 minW = std::min((sint32) mapWidthOnScreen, _MinW); parentCont->setMaxW(maxW + diffWReal); parentCont->setMinW(minW + diffWReal); parentCont->setPopupMaxW(maxW + diffWReal); parentCont->setPopupMinW(minW + diffWReal); if ((float)_WReal < minW) { parentCont->setW((sint32) mapWidthOnScreen + diffWReal); } } // y coord if (_MapTexH != 0) { //sint32 diffHReal = parentCont->getHReal() - _HReal; float mapHeightOnScreen = floorf(_MapTexH * _Scale); // parentCont->setPopupMaxH((sint32) mapHeightOnScreen + diffHReal); // parentCont->setPopupMinH((sint32) std::min(_MinH, (sint32) mapHeightOnScreen) + diffHReal); if ((float)_HReal >= mapHeightOnScreen) { _Offset.y = - _PlayerPos.y; if ((float)_HReal > mapHeightOnScreen) { _H = (sint32) mapHeightOnScreen; } } else { _H = std::max(_H, std::min(_MinH, (sint32) mapHeightOnScreen)); NLMISC::clamp(_Offset.y, - _PlayerPos.y, - _PlayerPos.y + 1.f - _H / ((float) mapHeightOnScreen)); } } } */ //============================================================================================================ void CGroupMap::evalMapOffset(float userScale, float &scale, sint32 &x, sint32 &y) const { if (_MapTexW == 0 || _MapTexH == 0) { x = 0; y = 0; return; } float scaleX = (float) _WReal / (float) _MapTexW; float scaleY = (float) _HReal / (float) _MapTexH; scale = std::min(scaleX, scaleY) * userScale; // center the map if needed sint32 w = (sint32) (scale * _MapTexW); x = (_WReal - w) / 2; sint32 h = (sint32) (scale * _MapTexH); y = (h - _HReal) / 2; } //============================================================================================================ float CGroupMap::computeRealScaleFromUserScale(float userScale) const { float scaleX = (float) _WReal / (float) _MapTexW; float scaleY = (float) _HReal / (float) _MapTexH; return std::min(scaleX, scaleY) * userScale;// } //============================================================================================================ float CGroupMap::computeUserScaleFromRealScale(float realScale) const { float scaleX = (float) _WReal / (float) _MapTexW; float scaleY = (float) _HReal / (float) _MapTexH; if (scaleX <= 0.f || scaleY <= 0.f) return 1.f; return realScale / std::min(scaleX, scaleY); } //============================================================================================================ void CGroupMap::updateScale() { if (_MapTexW == 0 || _MapTexH == 0) { _Scale = _UserScale; return; } else { _Scale = std::min(getActualMaxScale(), computeRealScaleFromUserScale(_UserScale)); // center the map if needed sint32 w = (sint32) (_Scale * _MapTexW); _MapW = w; _MapX = (_WReal - w) / 2; sint32 h = (sint32) (_Scale * _MapTexH); _MapY = (h - _HReal) / 2; _MapH = h; } computeOffsets(); } //========================================================================================================= void CGroupMap::computeMapRectInsideGroup(sint32 &x, sint32 &y, sint32 &w, sint32 &h) const { x = std::max((sint32) 0, _MapX); w = std::min(_WReal, _MapX + _MapW); y = std::max((sint32) 0, _MapY); h = std::min(_HReal, _MapY + _MapH); y = std::max((sint32) 0, (_HReal - _MapY)); } //========================================================================================================= void CGroupMap::computeOffsets() { if (_MapTexW == 0 || _MapTexH == 0) { _WorldOffset.set(0.f, 0.f); _Offset.set(0.f, 0.f); return; } // avoid div by 0 (nb: duno if those values can be negative...) float lx= _MapMaxCorner.x - _MapMinCorner.x; float ly= _MapMaxCorner.y - _MapMinCorner.y; if(lx==0.f) lx= 0.01f; if(ly==0.f) ly= 0.01f; _Offset.x= _WorldOffset.x / lx; _Offset.y= _WorldOffset.y / ly; float startCornerX = _Offset.x + _PlayerPos.x; if (_MapX < 0) startCornerX -= _MapX / (_MapTexW * _Scale); float startCornerY = _Offset.y + _PlayerPos.y; if (_MapY > 0) startCornerY += _MapY / (_MapTexH * _Scale); float endCornerX = startCornerX; float endCornerY = startCornerY; NLMISC::clamp(endCornerX, 0.f, 1.f - std::min(_MapW, _WReal) / ((float) _MapTexW * _Scale)); NLMISC::clamp(endCornerY, 0.f, 1.f - std::min(_MapH, _HReal) / ((float) _MapTexH * _Scale)); _Offset.x += endCornerX - startCornerX; _Offset.y += endCornerY - startCornerY; } //========================================================================================================= void CGroupMap::targetLandmark(CCtrlButton *lm) { if (!lm) return; // continent landmarks CCompassTarget ct; bool found = false; TLandMarkButtonVect::iterator it = std::find(_ContinentLM.begin(), _ContinentLM.end(),lm); { if (it != _ContinentLM.end()) { ct.setType(CCompassTarget::ContinentLandMark); (*it)->getContextHelp(ct.Name); mapToWorld(ct.Pos, (*it)->Pos); found = true; } } if (!found) { // mission landmarks it = std::find(_MissionLM.begin(), _MissionLM.end(),lm); { if (it != _MissionLM.end()) { ct.setPositionState(_MissionPosStates[it - _MissionLM.begin()]); (*it)->getContextHelp(ct.Name); mapToWorld(ct.Pos, (*it)->Pos); found = true; } } } if (!found) { // user landmarks it = std::find(_UserLM.begin(), _UserLM.end(),lm); { if (it != _UserLM.end()) { ct.setType(CCompassTarget::UserLandMark); (*it)->getContextHelp(ct.Name); mapToWorld(ct.Pos, (*it)->Pos); found = true; } } } // home if (!found) { if (lm == _HomeLM) { // pos irrelevant for home, recomputed at each frame ct.setType(CCompassTarget::Home); ct.Name = CI18N::get("uiHome"); found = true; } } // respawn point if (!found) { // if in island -> no effect when choosing entry point for now it = std::find(_RespawnLM.begin(), _RespawnLM.end(),lm); { if (it != _RespawnLM.end()) { if (!isIsland()) { ct.setType(CCompassTarget::Respawn); (*it)->getContextHelp(ct.Name); mapToWorld(ct.Pos, (*it)->Pos); found = true; } // pos irrelevant for respawn point, recomputed at each frame if ((_MapMode == MapMode_Death) || (_MapMode == MapMode_SpawnSquad)) { _RespawnSelectedBitmap->setParentPos(*it); string sTmp = (*it)->getId(); sTmp = sTmp.substr(sTmp.rfind('_')+1, sTmp.size()); fromString(sTmp, _RespawnSelected); CInterfaceManager *pIM = CInterfaceManager::getInstance(); if (_MapMode == MapMode_Death) pIM->getDbProp("UI:SAVE:RESPAWN_PT")->setValue32(_RespawnSelected); else if (_MapMode == MapMode_SpawnSquad) { pIM->getDbProp("UI:TEMP:OUTPOST:SQUAD_RESPAWN_PT")->setValue32(_RespawnSelected); // Close window containing the map CInterfaceGroup *pGrp = pIM->getWindow(this); if (pGrp != NULL) pGrp->setActive(false); } invalidateCoords(); } } } } // target if (!found) { if (lm == _TargetLM) { // pos irrelevant for respwan, recomputed at each frame ct.setType(CCompassTarget::Selection); found = true; } } // animals if (!found) { // animals landmarks if(_AnimalLM.size() == _AnimalPosStates.size()) { for(uint i=0;i<_AnimalLM.size();i++) { if(_AnimalLM[i]==lm) { _AnimalLM[i]->getContextHelp(ct.Name); // copy The Animal Pos retriever into the compass ct.setPositionState(_AnimalPosStates[i]); found = true; } } } } // teammates if (!found) { // teammates landmarks if(_TeammateLM.size() == _TeammatePosStates.size()) { for(uint i=0;i<_TeammateLM.size();i++) { if(_TeammateLM[i]==lm) { _TeammateLM[i]->getContextHelp(ct.Name); // copy The Animal Pos retriever into the compass ct.setPositionState(_TeammatePosStates[i]); found = true; } } } } if (found) { CInterfaceManager *im = CInterfaceManager::getInstance(); CGroupCompas *gc = dynamic_cast(im->getElementFromId(_CompassId)); if (gc) { gc->setActive(true); gc->setTarget(ct); gc->blink(); im->setTopWindow(gc); } } } //========================================================================================================= void CGroupMap::getLandmarkPosition(const CCtrlButton *lm, NLMISC::CVector2f &worldPos) { if (!lm) return; // continent landmarks CCompassTarget ct; TLandMarkButtonVect::iterator it = std::find(_ContinentLM.begin(), _ContinentLM.end(),lm); { if (it != _ContinentLM.end()) { mapToWorld(worldPos, (*it)->Pos); return; } } // mission landmarks it = std::find(_MissionLM.begin(), _MissionLM.end(),lm); { if (it != _MissionLM.end()) { mapToWorld(worldPos, (*it)->Pos); return; } } // user landmarks it = std::find(_UserLM.begin(), _UserLM.end(),lm); { if (it != _UserLM.end()) { mapToWorld(worldPos, (*it)->Pos); return; } } // respawn point // if in island -> no effect when choosing entry point for now it = std::find(_RespawnLM.begin(), _RespawnLM.end(),lm); if (it != _RespawnLM.end()) { if (!isIsland()) { mapToWorld(worldPos, (*it)->Pos); return; } } worldPos = NLMISC::CVector2f::Null; } //========================================================================================================= void CGroupMap::addRespawnPoints(const CRespawnPointsMsg &rpm) { _RespawnPosReseted = false; if (rpm.NeedToReset) { _RespawnPosReseted = true; _RespawnPos.clear(); } for (uint32 i = 0; i < rpm.RespawnPoints.size(); ++i) _RespawnPos.push_back(rpm.RespawnPoints[i]); // Ensure there is at least one respawn point // nlassert(_RespawnPos.size()>0); // Choose the good map ! (select the first respawn point and check for first matching bounding box map if (_MapMode != MapMode_Death) return; if (_RespawnPos.size() == 0) return; CWorldSheet *pWS = dynamic_cast(SheetMngr.get(CSheetId("ryzom.world"))); if (pWS == NULL) return; CInterfaceManager *pIM = CInterfaceManager::getInstance(); if (pIM == NULL) return; NLMISC::CVector2f rpWorldPos(_RespawnPos[0].x * 0.001f, _RespawnPos[0].y * 0.001f); for (uint32 i = 0; i < pWS->Maps.size(); ++i) { SMap &rMap = pWS->Maps[i]; if (rMap.ContinentName.empty()) continue; if ((rpWorldPos.x >= rMap.MinX) && (rpWorldPos.x <= rMap.MaxX) && (rpWorldPos.y >= rMap.MinY) && (rpWorldPos.y <= rMap.MaxY)) { setMap(rMap.Name); break; } } } //========================================================================================================= void CGroupMap::serialConfig(NLMISC::IStream &f) { sint ver = f.serialVersion(3); f.serial(_UserScale); if (ver == 0) { _UserScale = 1.f; } if (ver < 2) { // dummy read the old _Offset, and reset to 0. f.serial(_Offset); _WorldOffset.set(0.f, 0.f); _Offset.set(0.f, 0.f); } else { f.serial(_WorldOffset); } // Avoid bad saved WorldOffset if(f.isReading()) { if(!isValidDouble(_WorldOffset.x) || !isValidDouble(_WorldOffset.y)) _WorldOffset.set(0,0); } // In version 3 we do not read the _H anymore if (ver < 3) { f.serial(_H); // Yoyo: patch to avoid old "respawn map hid at second time" bug if (f.isReading()) if (_H < 10) _H = 10; } } //========================================================================================================= sint32 CGroupMap::getRespawnSelected() const { CInterfaceManager *pIM = CInterfaceManager::getInstance(); CCDBNodeLeaf *pNL = NULL; if (_MapMode == MapMode_Death) pNL = pIM->getDbProp("UI:SAVE:RESPAWN_PT",false); else if (_MapMode == MapMode_SpawnSquad) pNL = pIM->getDbProp("UI:TEMP:OUTPOST:SQUAD_RESPAWN_PT",false); if (pNL != NULL) return pNL->getValue32(); return 0; } //========================================================================================================= void CGroupMap::setRespawnSelected(sint32 nSpawnPointIndex) { if (_RespawnPos.size() == 0) return; if (nSpawnPointIndex < 0) return; if ((uint32)nSpawnPointIndex >= _RespawnPos.size()) return; CInterfaceManager *pIM = CInterfaceManager::getInstance(); CCDBNodeLeaf *pNL = NULL; if (_MapMode == MapMode_Death) pNL = pIM->getDbProp("UI:SAVE:RESPAWN_PT",false); else if (_MapMode == MapMode_SpawnSquad) pNL = pIM->getDbProp("UI:TEMP:OUTPOST:SQUAD_RESPAWN_PT",false); if (pNL != NULL) pNL->setValue32(nSpawnPointIndex); _RespawnSelected = nSpawnPointIndex; _RespawnPosReseted = false; } //========================================================================================================= SMap *CGroupMap::getParentMap(SMap *map) { if (map == NULL) return NULL; for (uint32 i = 0; i < _WorldSheet->Maps.size(); ++i) { bool bFound = false; SMap *pM = &_WorldSheet->Maps[i]; for (uint32 j = 0; j < pM->Children.size(); ++j) { if (pM->Children[j].Name == map->Name) { bFound = true; break; } } if (bFound) return pM; } return NULL; } ///////////////////// // ACTION HANDLERS // ///////////////////// //========================================================================================================= // A land mark button has been pushed class CAHLandMarkSelected : public IActionHandler { virtual void execute (CCtrlBase *pCaller, const string &/* params */) { CCtrlButton *button = dynamic_cast(pCaller); if (!button) return; // Select the landmark as the current target CGroupMap *map = dynamic_cast(button->getParent()); if (!map) return; map->targetLandmark(button); } }; REGISTER_ACTION_HANDLER(CAHLandMarkSelected, "land_mark_selected"); //========================================================================================================= // Remove a user landmark class CAHRemoveUserLandMark : public IActionHandler { virtual void execute (CCtrlBase *pCaller, const string &/* params */) { CCtrlButton *button = dynamic_cast(pCaller); if (!button) return; CGroupMap *map = dynamic_cast(button->getParent()); if (!map) return; map->removeUserLandMark(button); // close the rename window & create window closeLandMarkNameDialog(); LastSelectedLandMark = NULL; } }; REGISTER_ACTION_HANDLER(CAHRemoveUserLandMark, "remove_user_landmark"); //========================================================================================================= // Rename a user land mark class CAHRenameUserLandMark : public IActionHandler { virtual void execute (CCtrlBase *pCaller, const string &/* params */) { LastSelectedLandMark = dynamic_cast(pCaller); if (!LastSelectedLandMark) return; popupLandMarkNameDialog(); } }; REGISTER_ACTION_HANDLER(CAHRenameUserLandMark, "rename_user_landmark"); //========================================================================================================= // Validate user landmark name class CAHValidateUserLandMarkName : public IActionHandler { virtual void execute (CCtrlBase * /* pCaller */, const string &/* params */) { CInterfaceManager *im = CInterfaceManager::getInstance(); CInterfaceGroup *ig = dynamic_cast(im->getElementFromId(WIN_LANDMARK_NAME)); if (!ig) return; CGroupEditBox *eb = dynamic_cast(ig->getGroup("eb")); if (!eb) return; ig->setActive(false); CUserLandMark::EUserLandMarkType landMarkType = CUserLandMark::Misc; sint8 nLandMarkType = im->getDbProp( "UI:TEMP:LANDMARKTYPE" )->getValue8(); if (nLandMarkType>=0 && nLandMarkType<=CUserLandMark::UserLandMarkTypeCount) { landMarkType = (CUserLandMark::EUserLandMarkType)nLandMarkType; } if (LastSelectedLandMark) { CGroupMap *map = dynamic_cast(LastSelectedLandMark->getParent()); if (!map) return; // update existing landmark map->updateUserLandMark(LastSelectedLandMark, eb->getInputString(), landMarkType); } else { // create a new landmark if (!LastClickedMap) return; if( UseUserPositionForLandMark ) { LastClickedMap->addUserLandMark(LastClickedMap->getPlayerPos(), eb->getInputString(), landMarkType); } else { LastClickedMap->addUserLandMark(LastClickedMap->getRightClickLastPos(), eb->getInputString(), landMarkType); } LastClickedMap->invalidateCoords(); } } }; REGISTER_ACTION_HANDLER(CAHValidateUserLandMarkName, "validate_user_landmark_name"); //========================================================================================================= void createUserLandMark(CCtrlBase * /* pCaller */, const string &/* params */) { CInterfaceManager *im = CInterfaceManager::getInstance(); // pop the rename dialog LastClickedMap = dynamic_cast(im->getCtrlLaunchingModal()); if (LastClickedMap->isInDeathMode()) return; if (LastClickedMap->getNumUserLandMarks() >= CContinent::getMaxNbUserLandMarks() ) { // too many landmark, can't create im->displaySystemInfo(CI18N::get("uiNoMoreLandMarks"), "CHK"); return; } LastSelectedLandMark = NULL; popupLandMarkNameDialog(); } // create a new landmark after giving its name class CAHCreateUserLandMark : public IActionHandler { virtual void execute (CCtrlBase *pCaller, const string ¶ms) { UseUserPositionForLandMark = false; createUserLandMark(pCaller,params); } }; REGISTER_ACTION_HANDLER(CAHCreateUserLandMark, "create_user_landmark"); // create a new landmark at user position after giving its name class CAHCreateUserLandMarkAtUserPos: public IActionHandler { virtual void execute (CCtrlBase *pCaller, const string ¶ms) { UseUserPositionForLandMark = true; createUserLandMark(pCaller,params); } }; REGISTER_ACTION_HANDLER(CAHCreateUserLandMarkAtUserPos, "create_user_landmark_at_user_pos"); //========================================================================================================= // zoom in the map class CAHMapZoomIn : public IActionHandler { virtual void execute (CCtrlBase * /* pCaller */, const string ¶ms) { std::string map = getParam(params, "map"); CInterfaceManager *im = CInterfaceManager::getInstance(); CGroupMap *gm = dynamic_cast(im->getElementFromId(map)); if (!gm) return; NLMISC::CVector2f center; gm->windowToMap(center, gm->getWReal() / 2, gm->getHReal() / 2); gm->setScale(gm->getScale() * 1.3f, center); } }; REGISTER_ACTION_HANDLER(CAHMapZoomIn, "map_zoom_in"); //========================================================================================================= // zoom out the map class CAHMapZoomOut : public IActionHandler { virtual void execute (CCtrlBase * /* pCaller */, const string ¶ms) { std::string map = getParam(params, "map"); CInterfaceManager *im = CInterfaceManager::getInstance(); CGroupMap *gm = dynamic_cast(im->getElementFromId(map)); if (!gm) return; NLMISC::CVector2f center; gm->windowToMap(center, gm->getWReal() / 2, gm->getHReal() / 2); gm->setScale(gm->getScale() * 0.7f, center); } }; REGISTER_ACTION_HANDLER(CAHMapZoomOut, "map_zoom_out"); //========================================================================================================= // center map on the player class CAHMapCenter : public IActionHandler { virtual void execute (CCtrlBase * /* pCaller */, const string ¶ms) { std::string map = getParam(params, "map"); CInterfaceManager *im = CInterfaceManager::getInstance(); CGroupMap *gm = dynamic_cast(im->getElementFromId(map)); if (!gm) return; gm->centerOnPlayer(); } }; REGISTER_ACTION_HANDLER(CAHMapCenter, "map_center"); //========================================================================================================= // return to the parent map class CAHMapBack : public IActionHandler { virtual void execute (CCtrlBase * /* pCaller */, const string ¶ms) { std::string map = getParam(params, "map"); CInterfaceManager *im = CInterfaceManager::getInstance(); CGroupMap *pGM = dynamic_cast(im->getElementFromId(map)); if (pGM == NULL) return; SMap *pMap = pGM->getParentMap(pGM->getCurMap()); if (pMap != NULL) pGM->setMap(pMap->Name); } }; REGISTER_ACTION_HANDLER(CAHMapBack, "map_back"); //========================================================================================================= // valid the respawn location selected class CAHRespawnMapValid : public IActionHandler { virtual void execute (CCtrlBase * /* pCaller */, const string ¶ms) { std::string map = getParam(params, "map"); CInterfaceManager *im = CInterfaceManager::getInstance(); CGroupMap *gm = dynamic_cast(im->getElementFromId(map)); if (!gm) return; if (gm->getRespawnSelected() == -1) return; CBitMemStream out; const string msgName = "DEATH:ASK_RESPAWN"; if (!GenericMsgHeaderMngr.pushNameToStream(msgName, out)) { nlwarning ("don't know message name %s", msgName.c_str()); } else { uint16 respawnIndex = (uint16)gm->getRespawnSelected(); out.serial(respawnIndex); NetMngr.push(out); //nlinfo("impulseCallBack : %s %d sent", msgName.c_str(), respawnIndex); } /* Yoyo: NO!!! don't do this!! leave the DB Player MBEHAV Mode drive this (laggy but correct).... Else Errors arise if the client MBEHAV Mode never reset to Normal==1 (for any lag reason) The following scenario else could cause a bug: - the player is dead, the respawn map is activated - the player click "respawn" - in the buggy version we close the window immediatly (no lag) - the server receive the ASK respawn, resapwn the player, and change the mode to NORMAL==1 - the server decide that the PLAYER DIES AUTOMATICALLY in the same server tick (gingo in town for instance! :) ) NB: even if the DIE arise in following frame, lag and packet loss etc... can still cause problems - the server then reset the mode to DEATH - the client never receive the change Mode: 0-->1-->0 (always 0), hence the window is not reopened - the user cannot reswpan.... Instead, I chose to hide the timer text in map.xml */ /*sint64 val = im->getDbProp("UI:VARIABLES:CURRENT_SERVER_TICK")->getValue64(); im->getDbProp("UI:VARIABLES:RESPAWN:END_DATE")->setValue64(val+10*10); im->getDbProp("UI:VARIABLES:OPEN_RESPAWN_AT_TIME")->setValue64(0); // must hide the window which contains this map, not the map itself!! CInterfaceGroup *rootWindow= gm->getRootWindow(); if(rootWindow) rootWindow->setActive(false); */ im->getDbProp("UI:VARIABLES:RESPAWN:MSG_SENT")->setValue64(1); } }; REGISTER_ACTION_HANDLER(CAHRespawnMapValid, "respawn_map_valid"); //========================================================================================================= // right click on the map class CAHWorldMapRightClick : public IActionHandler { virtual void execute (CCtrlBase *pCaller, const string ¶ms) { std::string map = getParam(params, "map"); CInterfaceManager *im = CInterfaceManager::getInstance(); hideTeleportButtonsInPopupMenuIfNotEnoughPriv(); CGroupMap *gm = dynamic_cast(im->getElementFromId(map)); if (!gm) return; if (!gm->isIsland()) { im->runActionHandler("active_menu", pCaller, "menu=ui:interface:map_menu"); } else { im->runActionHandler("active_menu", pCaller, "menu=ui:interface:map_menu_island"); } } }; REGISTER_ACTION_HANDLER(CAHWorldMapRightClick, "world_map_right_click") //========================================================================================================= // A land mark button has been pushed class CAHLandMarkTeleport : public IActionHandler { virtual void execute (CCtrlBase *pCaller, const string &/* params */) { CCtrlButton *button = dynamic_cast(pCaller); if (!button) return; // Select the landmark as the current target CGroupMap *map = dynamic_cast(button->getParent()); if (!map) return; NLMISC::CVector2f pos; map->getLandmarkPosition(button, pos); // Check if the pos is ok if(pos == NLMISC::CVector2f::Null) return; closeLandMarkNameDialog(); // Remove the selection. UserEntity->selection(CLFECOMMON::INVALID_SLOT); // Remove the target. UserEntity->targetSlot(CLFECOMMON::INVALID_SLOT); nlinfo("LM teleport to %f,%f", pos.x, pos.y); ICommand::execute(toString("a Position %f,%f", pos.x, pos.y), *InfoLog); } }; REGISTER_ACTION_HANDLER(CAHLandMarkTeleport, "land_mark_teleport"); //========================================================================================================= // Teleport player to the given location class CAHMapTeleport : public IActionHandler { virtual void execute (CCtrlBase * /* pCaller */, const string &/* params */) { CInterfaceManager *im = CInterfaceManager::getInstance(); CGroupMap *clickedMap = dynamic_cast(im->getCtrlLaunchingModal()); closeLandMarkNameDialog(); NLMISC::CVector2f pos = clickedMap->getRightClickLastPos(); clickedMap->mapToWorld(pos, pos); // Remove the selection. UserEntity->selection(CLFECOMMON::INVALID_SLOT); // Remove the target. UserEntity->targetSlot(CLFECOMMON::INVALID_SLOT); nlinfo("teleport to %f,%f", pos.x, pos.y); ICommand::execute(toString("a Position %f,%f", pos.x, pos.y), *InfoLog); } }; REGISTER_ACTION_HANDLER(CAHMapTeleport, "map_teleport"); //========================================================================================================= // update LandMarks Colors class CUpdateLandMarksColor : public IActionHandler{public: virtual void execute (CCtrlBase * /* pCaller */, const string &/* Params */) { CInterfaceManager *pIM = CInterfaceManager::getInstance(); CUserLandMark::_LandMarksColor[CUserLandMark::Misc] = pIM->getDbProp("UI:SAVE:LANDMARK:COLORS:MISC")->getValueRGBA(); CUserLandMark::_LandMarksColor[CUserLandMark::Tribe] = pIM->getDbProp("UI:SAVE:LANDMARK:COLORS:TRIBE")->getValueRGBA(); CUserLandMark::_LandMarksColor[CUserLandMark::Bandit] = pIM->getDbProp("UI:SAVE:LANDMARK:COLORS:BANDIT")->getValueRGBA(); CUserLandMark::_LandMarksColor[CUserLandMark::Citizen] = pIM->getDbProp("UI:SAVE:LANDMARK:COLORS:CITIZEN")->getValueRGBA(); CUserLandMark::_LandMarksColor[CUserLandMark::Fauna] = pIM->getDbProp("UI:SAVE:LANDMARK:COLORS:FAUNA")->getValueRGBA(); CUserLandMark::_LandMarksColor[CUserLandMark::FaunaExcel] = pIM->getDbProp("UI:SAVE:LANDMARK:COLORS:FAUNAEXCEL")->getValueRGBA(); CUserLandMark::_LandMarksColor[CUserLandMark::FaunaSup] = pIM->getDbProp("UI:SAVE:LANDMARK:COLORS:FAUNASUP")->getValueRGBA(); CUserLandMark::_LandMarksColor[CUserLandMark::Forage] = pIM->getDbProp("UI:SAVE:LANDMARK:COLORS:FORAGE")->getValueRGBA(); CUserLandMark::_LandMarksColor[CUserLandMark::ForageExcel] = pIM->getDbProp("UI:SAVE:LANDMARK:COLORS:FORAGEEXCEL")->getValueRGBA(); CUserLandMark::_LandMarksColor[CUserLandMark::ForageSup] = pIM->getDbProp("UI:SAVE:LANDMARK:COLORS:FORAGESUP")->getValueRGBA(); CUserLandMark::_LandMarksColor[CUserLandMark::Sap] = pIM->getDbProp("UI:SAVE:LANDMARK:COLORS:SAP")->getValueRGBA(); CUserLandMark::_LandMarksColor[CUserLandMark::Amber] = pIM->getDbProp("UI:SAVE:LANDMARK:COLORS:AMBER")->getValueRGBA(); CUserLandMark::_LandMarksColor[CUserLandMark::Node] = pIM->getDbProp("UI:SAVE:LANDMARK:COLORS:NODE")->getValueRGBA(); CUserLandMark::_LandMarksColor[CUserLandMark::Fiber] = pIM->getDbProp("UI:SAVE:LANDMARK:COLORS:FIBER")->getValueRGBA(); CUserLandMark::_LandMarksColor[CUserLandMark::Bark] = pIM->getDbProp("UI:SAVE:LANDMARK:COLORS:BARK")->getValueRGBA(); CUserLandMark::_LandMarksColor[CUserLandMark::Seed] = pIM->getDbProp("UI:SAVE:LANDMARK:COLORS:SEED")->getValueRGBA(); CUserLandMark::_LandMarksColor[CUserLandMark::Shell] = pIM->getDbProp("UI:SAVE:LANDMARK:COLORS:SHELL")->getValueRGBA(); CUserLandMark::_LandMarksColor[CUserLandMark::Resin] = pIM->getDbProp("UI:SAVE:LANDMARK:COLORS:RESIN")->getValueRGBA(); CUserLandMark::_LandMarksColor[CUserLandMark::Wood] = pIM->getDbProp("UI:SAVE:LANDMARK:COLORS:WOOD")->getValueRGBA(); CUserLandMark::_LandMarksColor[CUserLandMark::Oil] = pIM->getDbProp("UI:SAVE:LANDMARK:COLORS:OIL")->getValueRGBA(); CUserLandMark::_LandMarksColor[CUserLandMark::Mission] = pIM->getDbProp("UI:SAVE:LANDMARK:COLORS:MISSION")->getValueRGBA(); CUserLandMark::_LandMarksColor[CUserLandMark::Food] = pIM->getDbProp("UI:SAVE:LANDMARK:COLORS:FOOD")->getValueRGBA(); CUserLandMark::_LandMarksColor[CUserLandMark::Construction] = pIM->getDbProp("UI:SAVE:LANDMARK:COLORS:CONSTRUCTION")->getValueRGBA(); CUserLandMark::_LandMarksColor[CUserLandMark::Goo] = pIM->getDbProp("UI:SAVE:LANDMARK:COLORS:GOO")->getValueRGBA(); CUserLandMark::_LandMarksColor[CUserLandMark::Insect] = pIM->getDbProp("UI:SAVE:LANDMARK:COLORS:INSECT")->getValueRGBA(); CUserLandMark::_LandMarksColor[CUserLandMark::Kitin] = pIM->getDbProp("UI:SAVE:LANDMARK:COLORS:KITIN")->getValueRGBA(); CUserLandMark::_LandMarksColor[CUserLandMark::Nocive] = pIM->getDbProp("UI:SAVE:LANDMARK:COLORS:NOCIVE")->getValueRGBA(); CUserLandMark::_LandMarksColor[CUserLandMark::Preservative] = pIM->getDbProp("UI:SAVE:LANDMARK:COLORS:PRESERVATIVE")->getValueRGBA(); CUserLandMark::_LandMarksColor[CUserLandMark::Passage] = pIM->getDbProp("UI:SAVE:LANDMARK:COLORS:PASSAGE")->getValueRGBA(); CUserLandMark::_LandMarksColor[CUserLandMark::Teleporter] = pIM->getDbProp("UI:SAVE:LANDMARK:COLORS:TELEPORTER")->getValueRGBA(); CGroupMap *pGM = dynamic_cast(pIM->getElementFromId("ui:interface:map:content:map_content:actual_map")); if (pGM == NULL) return; pGM->updateUserLandMarks(); }}; REGISTER_ACTION_HANDLER (CUpdateLandMarksColor, "update_landmarks_color"); //////////////////// // DEBUG COMMANDS // //////////////////// #if !FINAL_VERSION NLMISC_COMMAND( testMapHome, "Debug : test display of home on map", "" ) { if (!args.empty()) return false; CInterfaceManager *im = CInterfaceManager::getInstance(); im->getDbProp(COMPASS_DB_PATH ":HOME_POINT")->setValue64((((sint64) 4787 * 1000) << 32 )| (sint64) (uint32) ((sint64) -3661 * 1000)); return true; } /* NLMISC_COMMAND( testMapRespawn, "Debug : test display of respawn point on map", "" ) { if (!args.empty()) return false; CInterfaceManager *im = CInterfaceManager::getInstance(); im->getDbProp(COMPASS_DB_PATH ":BIND_POINT")->setValue64((((sint64) 4687 * 1000) << 32 )| (sint64) (uint32) ((sint64) -3561 * 1000)); return true; } */ NLMISC_COMMAND( testRespawn, "Debug : test respawn map", "" ) { if (!args.empty()) return false; CRespawnPointsMsg rpm; rpm.NeedToReset = true; rpm.RespawnPoints.push_back(CRespawnPointsMsg::SRespawnPoint(4150*1000,-4350*1000)); rpm.RespawnPoints.push_back(CRespawnPointsMsg::SRespawnPoint(4640*1000,-4320*1000)); rpm.RespawnPoints.push_back(CRespawnPointsMsg::SRespawnPoint(4100*1000,-4120*1000)); rpm.RespawnPoints.push_back(CRespawnPointsMsg::SRespawnPoint(4050*1000,-4200*1000)); rpm.RespawnPoints.push_back(CRespawnPointsMsg::SRespawnPoint(4200*1000,-4150*1000)); CInterfaceManager *pIM = CInterfaceManager::getInstance(); CGroupMap *pMap = dynamic_cast(pIM->getElementFromId("ui:interface:respawn_map:content:map_content:actual_map")); if (pMap == NULL) { nlwarning("problem cannot find ui:interface:respawn_map:content:map_content:actual_map"); return false; } pMap->addRespawnPoints(rpm); pMap = dynamic_cast(pIM->getElementFromId("ui:interface:map:content:map_content:actual_map")); if (pMap == NULL) { nlwarning("problem cannot find ui:interface:map:content:map_content:actual_map"); return false; } pMap->addRespawnPoints(rpm); /* CInterfaceManager *im = CInterfaceManager::getInstance(); im->getDbProp(COMPASS_DB_PATH ":BIND_POINT")->setValue64((((sint64) 4687 * 1000) << 32 )| (sint64) (uint32) ((sint64) -3561 * 1000)); */ return true; } NLMISC_COMMAND( setMap, "Debug : test respawn map", "" ) { if (args.size() != 1) return false; CInterfaceManager *pIM = CInterfaceManager::getInstance(); CGroupMap *pMap = dynamic_cast(pIM->getElementFromId("ui:interface:map:content:map_content:actual_map")); if (pMap != NULL) pMap->setMap(args[0]); return true; } #endif