mirror of
https://port.numenaute.org/aleajactaest/khanat-opennel-code.git
synced 2024-12-13 05:14:49 +00:00
3595 lines
116 KiB
C++
3595 lines
116 KiB
C++
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
|
// 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 <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
#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 <list>
|
|
|
|
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<CGroupContainer *>(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<CGroupEditBox *>(gc->getGroup("eb"));
|
|
if (!eb) return;
|
|
|
|
if (LastSelectedLandMark)
|
|
{
|
|
CGroupMap *map = dynamic_cast<CGroupMap *>(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<CGroupContainer *>(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<CCtrlBase*> &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<CPolygon> outputPolygons;
|
|
CMatrix id;
|
|
id.identity();
|
|
if (p.toConvexPolygons (outputPolygons, id))
|
|
{
|
|
std::list<CPolygon>::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<CWorldSheet*>(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<CCtrlBaseButton*>(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(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<CCtrlBase*> &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<CNamedEntityPositionState> 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<CNamedEntityPositionState> 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 <MAX_NUM_MISSION_TARGETS; ++l)
|
|
{
|
|
_MissionPosStates[targetIndex++] = buildMissionPositionState(pIM, MISSIONS_DB_PATH, k, l);
|
|
_MissionPosStates[targetIndex++] = buildMissionPositionState(pIM, GROUP_MISSIONS_DB_PATH, k, l);
|
|
}
|
|
}
|
|
// also fill ptr for special landmarks (target, home & respawn)
|
|
_TargetPos = pIM->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;i<MAX_INVENTORY_ANIMAL;i++)
|
|
{
|
|
_AnimalPosStates[i] = new CAnimalPositionState;
|
|
_AnimalPosStates[i]->build(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;
|
|
|
|
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<CContLandMark> &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() || 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<CGroupCompas *>(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<CWorldSheet*>(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<CCtrlButton *>(pCaller);
|
|
if (!button) return;
|
|
// Select the landmark as the current target
|
|
CGroupMap *map = dynamic_cast<CGroupMap *>(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<CCtrlButton *>(pCaller);
|
|
if (!button) return;
|
|
CGroupMap *map = dynamic_cast<CGroupMap *>(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<CCtrlButton *>(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<CInterfaceGroup *>(im->getElementFromId(WIN_LANDMARK_NAME));
|
|
if (!ig) return;
|
|
CGroupEditBox *eb = dynamic_cast<CGroupEditBox *>(ig->getGroup("eb"));
|
|
if (!eb) return;
|
|
ig->setActive(false);
|
|
|
|
|
|
CUserLandMark::EUserLandMarkType landMarkType;
|
|
sint8 nLandMarkType = im->getDbProp( "UI:TEMP:LANDMARKTYPE" )->getValue8();
|
|
if (nLandMarkType>=0 && nLandMarkType<=CUserLandMark::UserLandMarkTypeCount)
|
|
{
|
|
landMarkType = (CUserLandMark::EUserLandMarkType)nLandMarkType;
|
|
}
|
|
|
|
if (LastSelectedLandMark)
|
|
{
|
|
CGroupMap *map = dynamic_cast<CGroupMap *>(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<CGroupMap *>(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<CGroupMap *>(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<CGroupMap *>(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<CGroupMap *>(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<CGroupMap *>(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<CGroupMap *>(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<CGroupMap *>(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<CCtrlButton *>(pCaller);
|
|
if (!button) return;
|
|
// Select the landmark as the current target
|
|
CGroupMap *map = dynamic_cast<CGroupMap *>(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<CGroupMap *>(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<CGroupMap *>(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<CGroupMap*>(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<CGroupMap*>(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<CGroupMap*>(pIM->getElementFromId("ui:interface:map:content:map_content:actual_map"));
|
|
if (pMap != NULL)
|
|
pMap->setMap(args[0]);
|
|
|
|
return true;
|
|
}
|
|
|
|
#endif
|
|
|