From 9c6c735fc1044f3d4e043658b6416d0941ebc6d4 Mon Sep 17 00:00:00 2001 From: sfb Date: Sun, 8 May 2011 14:59:27 -0500 Subject: [PATCH 01/46] Changed: Started fixing up the menus. --- .../zone_painter/zone_painter_model.cpp | 40 ++++++++++++++++++ .../plugins/zone_painter/zone_painter_model.h | 42 +++++++++++++++++++ .../zone_painter/zone_painter_plugin.cpp | 32 ++++++++------ .../zone_painter/zone_painter_plugin.h | 5 +++ 4 files changed, 107 insertions(+), 12 deletions(-) create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/zone_painter/zone_painter_model.cpp create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/zone_painter/zone_painter_model.h diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/zone_painter/zone_painter_model.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/zone_painter/zone_painter_model.cpp new file mode 100644 index 000000000..4ab93d62d --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/zone_painter/zone_painter_model.cpp @@ -0,0 +1,40 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// Copyright (C) 2011 Dzmitry Kamiahin +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#include "zone_painter_model.h" + +// STL includes + +// Qt includes + +// NeL includes + +namespace Plugin +{ + +CZonePainterModel::CZonePainterModel() +{ + +} + +CZonePainterModel::~CZonePainterModel() +{ + +} + +} /* namespace Plugin */ + diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/zone_painter/zone_painter_model.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/zone_painter/zone_painter_model.h new file mode 100644 index 000000000..259634b63 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/zone_painter/zone_painter_model.h @@ -0,0 +1,42 @@ +// Object Viewer Qt - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// Copyright (C) 2011 Dzmitry Kamiahin +// +// 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 . + +#ifndef ZONE_PAINTER_MODEL_H +#define ZONE_PAINTER_MODEL_H + +// NeL includes +#include +#include +#include + +// Qt includes + +namespace Plugin +{ + +class CZonePainterModel +{ +public: + CZonePainterModel(); + virtual ~CZonePainterModel(); + +}; /* class CZonePainterModel */ + +} /* namespace Plugin */ + + +#endif // ZONE_PAINTER_MODEL_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/zone_painter/zone_painter_plugin.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/zone_painter/zone_painter_plugin.cpp index 7b8237ccb..bfd310e95 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/zone_painter/zone_painter_plugin.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/zone_painter/zone_painter_plugin.cpp @@ -16,6 +16,7 @@ #include #include #include +#include namespace Plugin { @@ -37,6 +38,7 @@ bool ZonePainterPlugin::initialize(ExtensionSystem::IPluginManager *pluginManage addAutoReleasedObject(new CZonePainterSettingsPage(this)); addAutoReleasedObject(new CZonePainterContext(this)); //addAutoReleasedObject(new CCoreListener(this)); + return true; } @@ -44,20 +46,26 @@ void ZonePainterPlugin::extensionsInitialized() { Core::ICore *core = Core::ICore::instance(); Core::IMenuManager *menuManager = core->menuManager(); - //menuManager = _plugMan->getObject(); - QAction *exampleAction1 = new QAction("Zone1", this); - QAction *exampleAction2 = new QAction("Zone2", this); - QAction *aboutQtAction = menuManager->action(Core::Constants::ABOUT_QT); - QMenu *helpMenu = menuManager->menu(Core::Constants::M_HELP); - helpMenu->insertAction(aboutQtAction, exampleAction1); - helpMenu->addSeparator(); - helpMenu->addAction(exampleAction2); - QMenu *zoneMenu = menuManager->menuBar()->addMenu("ZoneMenu"); - zoneMenu->insertAction(aboutQtAction, exampleAction1); - zoneMenu->addSeparator(); - zoneMenu->addAction(exampleAction2); + QAction *loadZoneAction = new QAction("Load Zone", this); + QAction *saveZoneAction = new QAction("Save Zone", this); + + QMenu *toolsMenu = menuManager->menu(Core::Constants::M_TOOLS); + QMenu *zoneMenu = toolsMenu->addMenu("Zone Painter"); + zoneMenu->addAction(loadZoneAction); + connect(loadZoneAction, SIGNAL(triggered()), this, SLOT(clickLoadZoneAction())); + zoneMenu->addAction(saveZoneAction); } +/****** SLOTS ******/ +void ZonePainterPlugin::clickLoadZoneAction() { + QString zoneFile = QFileDialog::getOpenFileName(NULL, tr("Open Zone File"), ".", tr("Zone Files (*.zone);;")); +} + +void ZonePainterPlugin::clickSaveZoneAction() { + +} +/****** END SLOTS ******/ + void ZonePainterPlugin::setNelContext(NLMISC::INelContext *nelContext) { #ifdef NL_OS_WINDOWS diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/zone_painter/zone_painter_plugin.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/zone_painter/zone_painter_plugin.h index aeae39ba6..2731637ed 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/zone_painter/zone_painter_plugin.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/zone_painter/zone_painter_plugin.h @@ -65,7 +65,10 @@ public: QObject *objectByName(const QString &name) const; ExtensionSystem::IPluginSpec *pluginByName(const QString &name) const; +public Q_SLOTS: + void clickLoadZoneAction(); + void clickSaveZoneAction(); protected: NLMISC::CLibraryContext *_LibContext; @@ -73,6 +76,8 @@ protected: private: ExtensionSystem::IPluginManager *_plugMan; QList _autoReleaseObjects; + + NL3D::CLandscapeModel *m_Landscape; }; class CZonePainterContext: public Core::IContext From 81df57ac0f4a2d0f9dfcbf544149e3d4f74272d6 Mon Sep 17 00:00:00 2001 From: kervala Date: Sat, 29 Oct 2011 15:34:04 +0200 Subject: [PATCH 02/46] Changed: #1328 Map time and weather Issue (patch provided by Sywindt) --- code/nel/src/misc/noise_value.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/code/nel/src/misc/noise_value.cpp b/code/nel/src/misc/noise_value.cpp index 89b9a8ad4..4b7cade1f 100644 --- a/code/nel/src/misc/noise_value.cpp +++ b/code/nel/src/misc/noise_value.cpp @@ -18,7 +18,7 @@ #include "nel/misc/noise_value.h" #include "nel/misc/fast_floor.h" - +#include "nel/misc/random.h" namespace NLMISC @@ -45,7 +45,8 @@ public: CRandomGrid3D() { //seed - srand(0); + CRandom Random; + Random.srand(0); // init the grid for(uint z=0; z> 5; + uint v= Random.rand() >> 5; _Texture3d[id]= v&255; } } @@ -80,9 +81,9 @@ public: // init LevelPhases. for(i=0; i Date: Mon, 31 Oct 2011 13:48:43 +0100 Subject: [PATCH 03/46] Fixed: Errors when using the database xslt using msxsl. --- code/ryzom/common/src/game_share/generate_client_db.xslt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/ryzom/common/src/game_share/generate_client_db.xslt b/code/ryzom/common/src/game_share/generate_client_db.xslt index d14903519..0680a3e39 100644 --- a/code/ryzom/common/src/game_share/generate_client_db.xslt +++ b/code/ryzom/common/src/game_share/generate_client_db.xslt @@ -297,13 +297,13 @@ inline void _getProp(const CCDBSynchronised &db, ICDBStructNode *node, NLMISC::C - + class { public: - + private: ICDBStructNode *_BranchNode; From 43b0cf8ad163728498bb056a0a21e2e5bd44645c Mon Sep 17 00:00:00 2001 From: kaetemi Date: Mon, 31 Oct 2011 13:54:22 +0100 Subject: [PATCH 04/46] Changed: #1093 Handle leveldesign and primitives directories seperately for the server upload script. --- code/nel/tools/build_gamedata/8_upload.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/code/nel/tools/build_gamedata/8_upload.py b/code/nel/tools/build_gamedata/8_upload.py index 3cfbd77ef..0b51a3683 100644 --- a/code/nel/tools/build_gamedata/8_upload.py +++ b/code/nel/tools/build_gamedata/8_upload.py @@ -166,10 +166,14 @@ printLog(log, ">>> Upload data_common <<<") for target in UploadCommon: uploadSftp(target[0], target[1], target[3], DataCommonDirectory, [ ]) -printLog(log, ">>> Upload data_leveldesign <<<") +printLog(log, ">>> Upload data_leveldesign/leveldesign <<<") for target in UploadLeveldesign: uploadSftp(target[0], target[1], target[3], LeveldesignDirectory, [ ]) +printLog(log, ">>> Upload data_leveldesign/primitives <<<") +for target in UploadPrimitives: + uploadSftp(target[0], target[1], target[3], PrimitivesDirectory, [ ]) + log.close() if os.path.isfile("8_upload.log"): os.remove("8_upload.log") From 2234eae556c2a4f05f5bc25c351dd660c13a4ba4 Mon Sep 17 00:00:00 2001 From: dnk-88 Date: Tue, 8 Nov 2011 00:22:32 +0200 Subject: [PATCH 05/46] Fixed: #1193 Correct deleting particle system from workspace --- .../src/plugins/object_viewer/particle_editor.cpp | 2 ++ .../src/plugins/object_viewer/particle_node.cpp | 1 + .../plugins/object_viewer/particle_workspace_dialog.cpp | 7 +++++-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/particle_editor.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/particle_editor.cpp index d03cdab3d..768576755 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/particle_editor.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/particle_editor.cpp @@ -78,6 +78,8 @@ void CParticleEditor::release() void CParticleEditor::setActiveNode(CWorkspaceNode *node) { if (node == _ActiveNode) return; + if (node == 0) + _ActiveNode->getPSModel()->hide(); _ActiveNode = node; bool wasRunning = _State == State::RunningSingle; diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/particle_node.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/particle_node.cpp index 3dfc1ce2c..15761c505 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/particle_node.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/particle_node.cpp @@ -378,6 +378,7 @@ void CParticleWorkspace::removeNode(uint index) { nlassert(index < _Nodes.size()); _Nodes[index] = NULL; // delete the smart-ptr target + delete _Nodes[index]; _Nodes.erase(_Nodes.begin() + index); touch(); } diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/particle_workspace_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/particle_workspace_dialog.cpp index cb49def05..74182120c 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/particle_workspace_dialog.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/particle_workspace_dialog.cpp @@ -305,6 +305,8 @@ void CParticleWorkspaceDialog::customContextMenu() _instanciateAction->setEnabled(stopped); _savePSAction->setEnabled(stopped); _saveAsPSAction->setEnabled(stopped); + _removeFromWSAction->setEnabled(stopped); + _clearContentAction->setEnabled(stopped); popurMenu->exec(QCursor::pos()); delete popurMenu; @@ -369,13 +371,14 @@ void CParticleWorkspaceDialog::clearContent() void CParticleWorkspaceDialog::removePS() { - if (_treeModel->getOwnerNode(_currentItem) == Modules::psEdit().getActiveNode()) + CWorkspaceNode *node = _currentItem->getNode(); + if (node == Modules::psEdit().getActiveNode()) Modules::psEdit().setActiveNode(NULL); QModelIndex index = _ui.treeView->currentIndex(); _ui.treeView->setCurrentIndex(index.parent()); clickedItem(index.parent()); - Modules::psEdit().getParticleWorkspace()->removeNode(static_cast(index.internalPointer())->getNode()); + Modules::psEdit().getParticleWorkspace()->removeNode(node); _treeModel->removeRows(index.row(), index.parent()); } From bf9c2885833aec85572525893c8145dc31e2b0b4 Mon Sep 17 00:00:00 2001 From: kaetemi Date: Sat, 12 Nov 2011 13:40:44 +0100 Subject: [PATCH 06/46] Added: Default cfg values for textures interfaces. --- code/ryzom/client/client_default.cfg | 3 +++ 1 file changed, 3 insertions(+) diff --git a/code/ryzom/client/client_default.cfg b/code/ryzom/client/client_default.cfg index c29ca9b93..14885fa01 100644 --- a/code/ryzom/client/client_default.cfg +++ b/code/ryzom/client/client_default.cfg @@ -80,6 +80,9 @@ XMLOutGameInterfaceFiles = { "out_v2_keys.xml", }; +TexturesInterface = "texture_interfaces_v3"; +TexturesInterfaceDXTC = "texture_interfaces_dxtc"; + // The ligo primitive class file LigoPrimitiveClass = "world_editor_classes.xml"; From 72b8643d54597562adde4646fa9aa356dd7bee6a Mon Sep 17 00:00:00 2001 From: kaetemi Date: Tue, 15 Nov 2011 14:55:57 +0100 Subject: [PATCH 07/46] Added: Use ssh key for 8_upload script. --- code/nel/tools/build_gamedata/8_upload.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/code/nel/tools/build_gamedata/8_upload.py b/code/nel/tools/build_gamedata/8_upload.py index 0b51a3683..1b60aad68 100644 --- a/code/nel/tools/build_gamedata/8_upload.py +++ b/code/nel/tools/build_gamedata/8_upload.py @@ -57,7 +57,7 @@ printLog(log, "") Psftp = findFileMultiDir(log, ToolDirectories + WindowsExeDllCfgDirectories, UploadPsftpTool) printLog(log, "PSFTP " + Psftp) -def downloadVersionTag(server, user, dir): +def downloadVersionTag(server, user, sshkey, dir): if os.path.isfile("upload.tag"): os.remove("upload.tag") if os.path.isfile("upload.batch"): @@ -67,7 +67,7 @@ def downloadVersionTag(server, user, dir): ub.write("get upload.tag upload.tag\n") ub.write("quit\n") ub.close() - subprocess.call([ Psftp, "-b", "upload.batch", user + "@" + server ]) + subprocess.call([ Psftp, "-b", "upload.batch", "-i", sshkey, user + "@" + server ]) os.remove("upload.batch") if os.path.isfile("upload.tag"): ft = open("upload.tag") @@ -122,8 +122,8 @@ def listDirectoryUpload(ft, ub, udb, dir): printLog(log, "listDirectoryUpload: file not dir or file?!" + fileFull) return nft -def uploadSftp(server, user, dir_to, dir_from, addcmd): - ft = downloadVersionTag(server, user, dir_to) +def uploadSftp(server, user, sshkey, dir_to, dir_from, addcmd): + ft = downloadVersionTag(server, user, sshkey, dir_to) if isDirectoryNeeded(ft, dir_from): if os.path.isfile("upload_dir.batch"): os.remove("upload_dir.batch") @@ -146,8 +146,8 @@ def uploadSftp(server, user, dir_to, dir_from, addcmd): ub.close() udb.write("quit\n") udb.close() - subprocess.call([ Psftp, "-be", "-b", "upload_dir.batch", user + "@" + server ]) - subprocess.call([ Psftp, "-b", "upload.batch", user + "@" + server ]) + subprocess.call([ Psftp, "-be", "-b", "upload_dir.batch", "-i", sshkey, user + "@" + server ]) + subprocess.call([ Psftp, "-b", "upload.batch", "-i", sshkey, user + "@" + server ]) os.remove("upload_dir.batch") os.remove("upload.batch") os.remove("upload.tag") @@ -156,23 +156,23 @@ def uploadSftp(server, user, dir_to, dir_from, addcmd): printLog(log, ">>> Upload patch <<<") for target in UploadPatch: - uploadSftp(target[0], target[1], target[3], ClientPatchDirectory + "/patch", [ ]) + uploadSftp(target[0], target[1], target[2], target[3], ClientPatchDirectory + "/patch", [ ]) printLog(log, ">>> Upload data_shard <<<") for target in UploadShard: - uploadSftp(target[0], target[1], target[3], DataShardDirectory, [ "rm *.packed_sheets", "rm primitive_cache/*.binprim" ]) + uploadSftp(target[0], target[1], target[2], target[3], DataShardDirectory, [ "rm *.packed_sheets", "rm primitive_cache/*.binprim" ]) printLog(log, ">>> Upload data_common <<<") for target in UploadCommon: - uploadSftp(target[0], target[1], target[3], DataCommonDirectory, [ ]) + uploadSftp(target[0], target[1], target[2], target[3], DataCommonDirectory, [ ]) printLog(log, ">>> Upload data_leveldesign/leveldesign <<<") for target in UploadLeveldesign: - uploadSftp(target[0], target[1], target[3], LeveldesignDirectory, [ ]) + uploadSftp(target[0], target[1], target[2], target[3], LeveldesignDirectory, [ ]) printLog(log, ">>> Upload data_leveldesign/primitives <<<") for target in UploadPrimitives: - uploadSftp(target[0], target[1], target[3], PrimitivesDirectory, [ ]) + uploadSftp(target[0], target[1], target[2], target[3], PrimitivesDirectory, [ ]) log.close() if os.path.isfile("8_upload.log"): From 506e214e389a221d033cad5eb6b82bfa0d84451d Mon Sep 17 00:00:00 2001 From: sfb Date: Wed, 7 Dec 2011 07:16:37 -0600 Subject: [PATCH 08/46] Fixed: #1367 Added ifdef for OSX 10.7 GL API changes. Thanks GelluleX. --- code/nel/src/3d/driver/opengl/mac/glext.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/nel/src/3d/driver/opengl/mac/glext.h b/code/nel/src/3d/driver/opengl/mac/glext.h index 7d222aa19..6bcd8c238 100644 --- a/code/nel/src/3d/driver/opengl/mac/glext.h +++ b/code/nel/src/3d/driver/opengl/mac/glext.h @@ -4851,8 +4851,10 @@ typedef ptrdiff_t GLsizeiptrARB; #ifndef GL_ARB_shader_objects /* GL types for program/shader text and shader object handles */ typedef char GLcharARB; +#if !defined(MAC_OS_X_VERSION_10_7) typedef unsigned int GLhandleARB; #endif +#endif /* GL type for "half" precision (s10e5) float data in host memory */ #ifndef GL_ARB_half_float_pixel From c8467d9b51fbffe4d1102750c05c7daa3858e755 Mon Sep 17 00:00:00 2001 From: sfb Date: Wed, 7 Dec 2011 07:20:05 -0600 Subject: [PATCH 09/46] Fixed: #1359 Applied patch from GelluleX adding cut/paste functionality to Ryzom for OSX. --- .../driver/opengl/mac/cocoa_event_emitter.cpp | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/code/nel/src/3d/driver/opengl/mac/cocoa_event_emitter.cpp b/code/nel/src/3d/driver/opengl/mac/cocoa_event_emitter.cpp index 95c713021..15bb40d28 100644 --- a/code/nel/src/3d/driver/opengl/mac/cocoa_event_emitter.cpp +++ b/code/nel/src/3d/driver/opengl/mac/cocoa_event_emitter.cpp @@ -149,14 +149,28 @@ static NLMISC::TKey virtualKeycodeToNelKey(unsigned short keycode) bool CCocoaEventEmitter::pasteTextFromClipboard(ucstring &text) { -#warning "OpenGL Driver: Missing Mac Implementation for pasteTextFromClipboard" + NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; + NSArray *classArray = [NSArray arrayWithObject:[NSString class]]; + NSDictionary *options = [NSDictionary dictionary]; + + BOOL ok = [pasteboard canReadObjectForClasses:classArray options:options]; + if (ok) + { + NSArray *objectsToPaste = [pasteboard readObjectsForClasses:classArray options:options]; + NSString *nstext = [objectsToPaste objectAtIndex:0]; + text.fromUtf8([nstext UTF8String]); + return true; + } return false; } bool CCocoaEventEmitter::copyTextToClipboard(const ucstring &text) { -#warning "OpenGL Driver: Missing Mac Implementation for copyTextToClipboard" - return false; + NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; + [pasteboard clearContents]; + NSArray *copiedObjects = [NSArray arrayWithObject:[NSString stringWithUTF8String:text.toUtf8().c_str()]]; + [pasteboard writeObjects:copiedObjects]; + return true; } /// convert modifier key state to nel internal modifier key state From 8d9e04262210373bf680cf417ddcae6336f20a19 Mon Sep 17 00:00:00 2001 From: sfb Date: Wed, 7 Dec 2011 07:30:30 -0600 Subject: [PATCH 10/46] Changed: #1323 Applied patch for Snowballs finding its config file on Windows. Thanks Molator. --- code/snowballs2/CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/code/snowballs2/CMakeLists.txt b/code/snowballs2/CMakeLists.txt index 0007259ee..3107726e0 100644 --- a/code/snowballs2/CMakeLists.txt +++ b/code/snowballs2/CMakeLists.txt @@ -1,4 +1,8 @@ -SET(SNOWBALLS_CONFIG_FILE "${NL_ETC_PREFIX}/snowballs" CACHE FILEPATH "Snowballs config file location") +IF(WIN32) + SET(SNOWBALLS_CONFIG_FILE "." CACHE FILEPATH "Snowballs config file location") +ELSE(WIN32) + SET(SNOWBALLS_CONFIG_FILE "${NL_ETC_PREFIX}/snowballs" CACHE FILEPATH "Snowballs config file location") +ENDIF(WIN32) SET(SNOWBALLS_DATA_FILE "${NL_SHARE_PREFIX}/games/snowballs" CACHE FILEPATH "Snowballs data file location") SET(SNOWBALLS_LOG_FILE "${NL_LOG_PREFIX}/snowballs" CACHE FILEPATH "Snowballs log file location") From b7ffe497541bd99c054b31a15b36028980979f23 Mon Sep 17 00:00:00 2001 From: sfb Date: Mon, 12 Dec 2011 14:38:41 -0600 Subject: [PATCH 11/46] Fixed: #1385 patch_gen uses tmpnam function instead of 'nul' for files with no pre-existing version. Note - used tmpnam instead of mkstemp due to cross-platform compatibility. --- code/ryzom/tools/patch_gen/patch_gen_common.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/code/ryzom/tools/patch_gen/patch_gen_common.cpp b/code/ryzom/tools/patch_gen/patch_gen_common.cpp index fc39e9fcf..c746fcd00 100644 --- a/code/ryzom/tools/patch_gen/patch_gen_common.cpp +++ b/code/ryzom/tools/patch_gen/patch_gen_common.cpp @@ -18,8 +18,11 @@ // includes //----------------------------------------------------------------------------- +#include + #include "game_share/bnp_patch.h" #include "nel/misc/path.h" +#include "nel/misc/file.h" #include "nel/misc/command.h" #include "nel/misc/sstring.h" #include "game_share/singleton_registry.h" @@ -320,7 +323,6 @@ void CPackageDescription::generatePatches(CBNPFileSet& packageIndex) const for (uint32 i=packageIndex.fileCount();i--;) { - bool deleteRefAfterDelta= true; // generate file name root std::string bnpFileName= _BnpDirectory+packageIndex.getFile(i).getFileName(); std::string refNameRoot= _RefDirectory+NLMISC::CFile::getFilenameWithoutExtension(bnpFileName); @@ -340,8 +342,9 @@ void CPackageDescription::generatePatches(CBNPFileSet& packageIndex) const std::string prevVersionFileName; if (packageIndex.getFile(i).versionCount()==1) { - prevVersionFileName= "nul"; - deleteRefAfterDelta= false; + prevVersionFileName= tmpnam(NULL); + NLMISC::COFile tmpFile(prevVersionFileName); + tmpFile.close(); } else { @@ -400,7 +403,7 @@ void CPackageDescription::generatePatches(CBNPFileSet& packageIndex) const } // if we have a ref file still hanging about from the previous patch then delete it - if (prevVersionFileName!= "nul" && NLMISC::CFile::fileExists(prevVersionFileName)) + if (NLMISC::CFile::fileExists(prevVersionFileName)) { NLMISC::CFile::deleteFile(prevVersionFileName); } From c0c75e442ddf9434e03f9075df90798aaaaab0fc Mon Sep 17 00:00:00 2001 From: sfb Date: Wed, 14 Dec 2011 14:51:29 -0600 Subject: [PATCH 12/46] Fixed: #1412 Added build_sound, build_samplebank and build_soundbank to CMake. --- code/nel/tools/sound/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/code/nel/tools/sound/CMakeLists.txt b/code/nel/tools/sound/CMakeLists.txt index d3f5a12fa..a5d44bb50 100644 --- a/code/nel/tools/sound/CMakeLists.txt +++ b/code/nel/tools/sound/CMakeLists.txt @@ -1 +1,6 @@ +ADD_SUBDIRECTORY(build_samplebank) +ADD_SUBDIRECTORY(build_sound) +ADD_SUBDIRECTORY(build_soundbank) +# Deprecated tool - no longer useful, valid or buildable. +#ADD_SUBDIRECTORY(source_sounds_builder) From e87ed2460852684a2f4f70dc0062ddf04842b3eb Mon Sep 17 00:00:00 2001 From: sfb Date: Wed, 14 Dec 2011 14:51:42 -0600 Subject: [PATCH 13/46] Fixed: #1412 Added build_sound, build_samplebank and build_soundbank to CMake. --- .../nel/tools/sound/build_samplebank/CMakeLists.txt | 13 +++++++++++++ code/nel/tools/sound/build_sound/CMakeLists.txt | 13 +++++++++++++ code/nel/tools/sound/build_soundbank/CMakeLists.txt | 13 +++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 code/nel/tools/sound/build_samplebank/CMakeLists.txt create mode 100644 code/nel/tools/sound/build_sound/CMakeLists.txt create mode 100644 code/nel/tools/sound/build_soundbank/CMakeLists.txt diff --git a/code/nel/tools/sound/build_samplebank/CMakeLists.txt b/code/nel/tools/sound/build_samplebank/CMakeLists.txt new file mode 100644 index 000000000..b94d4d1bf --- /dev/null +++ b/code/nel/tools/sound/build_samplebank/CMakeLists.txt @@ -0,0 +1,13 @@ +FILE(GLOB SRC *.cpp *.h) + +ADD_EXECUTABLE(build_samplebank ${SRC}) + +ADD_DEFINITIONS( ${LIBXML2_DEFINITIONS}) + +INCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIR}) + +TARGET_LINK_LIBRARIES(build_samplebank nelmisc nelsound) +NL_DEFAULT_PROPS(build_samplebank "NeL, Tools, Sound: build_samplebank") +NL_ADD_RUNTIME_FLAGS(build_samplebank) + +INSTALL(TARGETS build_samplebank RUNTIME DESTINATION bin COMPONENT toolssound) diff --git a/code/nel/tools/sound/build_sound/CMakeLists.txt b/code/nel/tools/sound/build_sound/CMakeLists.txt new file mode 100644 index 000000000..5cf651e42 --- /dev/null +++ b/code/nel/tools/sound/build_sound/CMakeLists.txt @@ -0,0 +1,13 @@ +FILE(GLOB SRC *.cpp *.h) + +ADD_EXECUTABLE(build_sound ${SRC}) + +ADD_DEFINITIONS( ${LIBXML2_DEFINITIONS}) + +INCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIR}) + +TARGET_LINK_LIBRARIES(build_sound nelmisc nelsound) +NL_DEFAULT_PROPS(build_sound "NeL, Tools, Sound: build_sound") +NL_ADD_RUNTIME_FLAGS(build_sound) + +INSTALL(TARGETS build_sound RUNTIME DESTINATION bin COMPONENT toolssound) diff --git a/code/nel/tools/sound/build_soundbank/CMakeLists.txt b/code/nel/tools/sound/build_soundbank/CMakeLists.txt new file mode 100644 index 000000000..a9f556280 --- /dev/null +++ b/code/nel/tools/sound/build_soundbank/CMakeLists.txt @@ -0,0 +1,13 @@ +FILE(GLOB SRC *.cpp *.h) + +ADD_EXECUTABLE(build_soundbank ${SRC}) + +ADD_DEFINITIONS( ${LIBXML2_DEFINITIONS}) + +INCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIR}) + +TARGET_LINK_LIBRARIES(build_soundbank nelmisc nelsound) +NL_DEFAULT_PROPS(build_soundbank "NeL, Tools, Sound: build_soundbank") +NL_ADD_RUNTIME_FLAGS(build_soundbank) + +INSTALL(TARGETS build_soundbank RUNTIME DESTINATION bin COMPONENT toolssound) From 03b4c8db28aa9b0db1792fa83c3b4b7b81f5b094 Mon Sep 17 00:00:00 2001 From: sfb Date: Wed, 21 Dec 2011 09:49:30 -0600 Subject: [PATCH 14/46] Fixed: #1334 Applied Ulukyn's patch. Adds two new config variables - WebIgMainDomain and WebIgTrustedDomains. --- code/ryzom/client/src/client_cfg.cpp | 13 +++++- code/ryzom/client/src/client_cfg.h | 4 ++ .../src/interface_v3/action_handler_ui.cpp | 2 +- .../client/src/interface_v3/group_html.cpp | 44 ++++++++++++------- .../client/src/interface_v3/group_html.h | 4 ++ .../src/interface_v3/group_html_webig.cpp | 3 +- code/ryzom/client/src/libwww.cpp | 3 +- code/ryzom/client/src/libwww.h | 2 +- code/ryzom/client/src/net_manager.cpp | 2 +- 9 files changed, 54 insertions(+), 23 deletions(-) diff --git a/code/ryzom/client/src/client_cfg.cpp b/code/ryzom/client/src/client_cfg.cpp index 9b60a4c5f..ff270ad1a 100644 --- a/code/ryzom/client/src/client_cfg.cpp +++ b/code/ryzom/client/src/client_cfg.cpp @@ -426,8 +426,12 @@ CClientConfig::CClientConfig() PatchUrl = ""; PatchVersion = ""; PatchServer = ""; - RingReleaseNotePath = "http://atys.ryzom.com/releasenotes_ring/index.php"; - ReleaseNotePath = "http://atys.ryzom.com/releasenotes/index.php"; + + WebIgMainDomain = "atys.ryzom.com"; + WebIgTrustedDomains.push_back(WebIgMainDomain); + + RingReleaseNotePath = "http://"+WebIgMainDomain+"/releasenotes_ring/index.php"; + ReleaseNotePath = "http://"+WebIgMainDomain+"/releasenotes/index.php"; /////////////// // ANIMATION // @@ -1040,6 +1044,11 @@ void CClientConfig::setValues() READ_STRING_DEV(ReleaseNotePath) READ_STRING_FV(PatchServer) + //////////////////////// + // WEBIG // + READ_STRING_DEV(WebIgMainDomain); + READ_STRINGVECTOR_FV(WebIgTrustedDomains); + /////////////// // ANIMATION // // AnimatedAngleThreshold diff --git a/code/ryzom/client/src/client_cfg.h b/code/ryzom/client/src/client_cfg.h index 7b7c3f8ab..667606814 100644 --- a/code/ryzom/client/src/client_cfg.h +++ b/code/ryzom/client/src/client_cfg.h @@ -292,6 +292,10 @@ struct CClientConfig std::string RingReleaseNotePath; std::string ReleaseNotePath; + //////////////////////// + // WEBIG // + std::string WebIgMainDomain; + std::vector WebIgTrustedDomains; /////////////// // ANIMATION // diff --git a/code/ryzom/client/src/interface_v3/action_handler_ui.cpp b/code/ryzom/client/src/interface_v3/action_handler_ui.cpp index 58ab060d5..8503f2738 100644 --- a/code/ryzom/client/src/interface_v3/action_handler_ui.cpp +++ b/code/ryzom/client/src/interface_v3/action_handler_ui.cpp @@ -416,7 +416,7 @@ class CAHUIShowHide : public IActionHandler nlwarning("%s is not a group html", window.c_str()); return; } - pGH->setURL("http://atys.ryzom.com/start/index.php?app="+webapp); + pGH->setURL("http://"+ClientCfg.WebIgMainDomain+"/start/index.php?app="+webapp); } } else diff --git a/code/ryzom/client/src/interface_v3/group_html.cpp b/code/ryzom/client/src/interface_v3/group_html.cpp index 487344508..8ce18fb77 100644 --- a/code/ryzom/client/src/interface_v3/group_html.cpp +++ b/code/ryzom/client/src/interface_v3/group_html.cpp @@ -63,6 +63,13 @@ using namespace NLMISC; CGroupHTML *CGroupHTML::_ConnectingLock = NULL; extern CActionsContext ActionsContext; +// Check if domain is on TrustedDomain +bool CGroupHTML::isTrustedDomain(const string &domain) { + vector::iterator it; + it = find (ClientCfg.WebIgTrustedDomains.begin(), ClientCfg.WebIgTrustedDomains.end(), domain); + return it != ClientCfg.WebIgTrustedDomains.end(); +} + // Get an url and return the local filename with the path where the url image should be string CGroupHTML::localImageName(const string &url) { @@ -215,6 +222,9 @@ bool CGroupHTML::addBnpDownload(const string &url, const string &action, const s void CGroupHTML::initBnpDownload() { + if (!_TrustedDomain) + return; + #ifdef LOG_DL nlwarning("Init Bnp Download"); #endif @@ -452,7 +462,7 @@ void CGroupHTML::addText (const char * buf, int len) // for (i=0; i<(uint)len; i++) // inputString[i] = buf[i]; - if (_ParsingLua) + if (_ParsingLua && _TrustedDomain) { // we are parsing a lua script _LuaScript += inputString; @@ -523,12 +533,12 @@ void CGroupHTML::addLink (uint element_number, uint /* attribute_number */, HTCh if (present[MY_HTML_A_HREF] && value[MY_HTML_A_HREF]) { string suri = value[MY_HTML_A_HREF]; - if(suri.find("ah:") == 0) + if(_TrustedDomain && suri.find("ah:") == 0) { // in ah: command we don't respect the uri standard so the HTAnchor_address doesn't work correctly _Link.push_back (suri); } - else if (suri[0] == '#') + else if (_TrustedDomain && suri[0] == '#') { // Direct url (hack for lua beginElement) _Link.push_back (suri.substr(1)); @@ -822,7 +832,7 @@ void CGroupHTML::beginElement (uint element_number, const BOOL *present, const c _A.push_back(true); // Quick help - if (present[MY_HTML_A_Z_ACTION_SHORTCUT] && value[MY_HTML_A_Z_ACTION_SHORTCUT]) + if (_TrustedDomain && present[MY_HTML_A_Z_ACTION_SHORTCUT] && value[MY_HTML_A_Z_ACTION_SHORTCUT]) { // Get the action category string category; @@ -1532,19 +1542,23 @@ void CGroupHTML::endElement (uint element_number) _IgnoreText = false; break; case HTML_OBJECT: - if (_ObjectType=="application/ryzom-data") + if (_TrustedDomain) { - if (!_ObjectData.empty()) + if (_ObjectType=="application/ryzom-data") { - if (addBnpDownload(_ObjectData, _ObjectAction, _ObjectScript, _ObjectMD5Sum)) + if (!_ObjectData.empty()) { - CInterfaceManager *pIM = CInterfaceManager::getInstance(); - pIM->executeLuaScript(_ObjectScript, true); + if (addBnpDownload(_ObjectData, _ObjectAction, _ObjectScript, _ObjectMD5Sum)) + { + CInterfaceManager *pIM = CInterfaceManager::getInstance(); + pIM->executeLuaScript(_ObjectScript, true); + } + _ObjectScript = ""; } - _ObjectScript = ""; } + _Object = false; } - _Object = false; + break; } } } @@ -1556,7 +1570,7 @@ void CGroupHTML::beginUnparsedElement(const char *buffer, int length) if (stricmp(str.c_str(), "lua") == 0) { // we receive an embeded lua script - _ParsingLua = true; + _ParsingLua = _TrustedDomain; // Only parse lua if TrustedDomain _LuaScript = ""; } } @@ -1567,7 +1581,7 @@ void CGroupHTML::endUnparsedElement(const char *buffer, int length) string str(buffer, buffer+length); if (stricmp(str.c_str(), "lua") == 0) { - if (_ParsingLua) + if (_ParsingLua && _TrustedDomain) { _ParsingLua = false; // execute the embeded lua script @@ -2894,7 +2908,7 @@ void CGroupHTML::handle () // Init LibWWW initLibWWW(); - setCurrentDomain(finalUrl); + _TrustedDomain = isTrustedDomain(setCurrentDomain(finalUrl)); // Get the final URL C3WSmartPtr uri = HTParse(finalUrl.c_str(), NULL, PARSE_ALL); @@ -3045,7 +3059,7 @@ void CGroupHTML::handle () // Init LibWWW initLibWWW(); - setCurrentDomain(_URL); + _TrustedDomain = isTrustedDomain(setCurrentDomain(_URL)); // Get the final URL C3WSmartPtr uri = HTParse(_URL.c_str(), NULL, PARSE_ALL); diff --git a/code/ryzom/client/src/interface_v3/group_html.h b/code/ryzom/client/src/interface_v3/group_html.h index 92cb81e6e..d155c6d3f 100644 --- a/code/ryzom/client/src/interface_v3/group_html.h +++ b/code/ryzom/client/src/interface_v3/group_html.h @@ -281,6 +281,9 @@ protected : // Current URL std::string _URL; + // Current DOMAIN + bool _TrustedDomain; + // Title prefix ucstring _TitlePrefix; @@ -579,6 +582,7 @@ private: void checkImageDownload(); void addImageDownload(const std::string &url, CViewBase *img); std::string localImageName(const std::string &url); + bool isTrustedDomain(const std::string &domain); diff --git a/code/ryzom/client/src/interface_v3/group_html_webig.cpp b/code/ryzom/client/src/interface_v3/group_html_webig.cpp index 7e1781289..4a13d9806 100644 --- a/code/ryzom/client/src/interface_v3/group_html_webig.cpp +++ b/code/ryzom/client/src/interface_v3/group_html_webig.cpp @@ -203,8 +203,7 @@ struct CWebigNotificationThread : public NLMISC::IRunnable nlSleep(1*60*1000); while (true) { - string url = "http://atys.ryzom.com/start/index.php?app=notif&rnd="+randomString(); - //string url = "http://ryapp.bmsite.net/app_mail.php?page=ajax/inbox/unread&rnd="+randomString(); + string url = "http://"+ClientCfg.WebIgMainDomain+"/start/index.php?app=notif&rnd="+randomString(); addWebIGParams(url); get(url); nlSleep(10*60*1000); diff --git a/code/ryzom/client/src/libwww.cpp b/code/ryzom/client/src/libwww.cpp index c4695840d..966aeffa6 100644 --- a/code/ryzom/client/src/libwww.cpp +++ b/code/ryzom/client/src/libwww.cpp @@ -520,7 +520,7 @@ int HTMIME_location_custom (HTRequest * request, HTResponse * response, char * t // *************************************************************************** -void setCurrentDomain(const std::string &url) +const std::string &setCurrentDomain(const std::string &url) { if(url.find("http://") == 0) { @@ -532,6 +532,7 @@ void setCurrentDomain(const std::string &url) HTTPCurrentDomain.clear(); // nlinfo("****cd: clear the domain"); } + return HTTPCurrentDomain; } void initLibWWW() diff --git a/code/ryzom/client/src/libwww.h b/code/ryzom/client/src/libwww.h index 5c686e39b..41db90a6c 100644 --- a/code/ryzom/client/src/libwww.h +++ b/code/ryzom/client/src/libwww.h @@ -35,7 +35,7 @@ class CCtrlBaseButton; void initLibWWW(); // Get an url and setup a local domain -void setCurrentDomain(const std::string &url); +const std::string &setCurrentDomain(const std::string &url); extern std::string CurrentCookie; diff --git a/code/ryzom/client/src/net_manager.cpp b/code/ryzom/client/src/net_manager.cpp index 29a5a0e37..568081c81 100644 --- a/code/ryzom/client/src/net_manager.cpp +++ b/code/ryzom/client/src/net_manager.cpp @@ -3253,7 +3253,7 @@ private: if(i != digitMaxEnd) { ucstring web_app = contentStr.substr(digitStart, i-digitStart); - contentStr = ucstring("http://atys.ryzom.com/start/")+web_app+ucstring(".php?")+contentStr.substr(i+1); + contentStr = ucstring("http://"+ClientCfg.WebIgMainDomain+"/start/")+web_app+ucstring(".php?")+contentStr.substr(i+1); } else { From d0d7f37432515efae8ea2ab4ffee73c8d2d16149 Mon Sep 17 00:00:00 2001 From: dnk-88 Date: Thu, 22 Dec 2011 02:41:39 +0300 Subject: [PATCH 15/46] Fixed: #1307 Clean up code. --- .../translation_manager/CMakeLists.txt | 26 +- .../translation_manager/editor_phrase.cpp | 100 +- .../translation_manager/editor_phrase.h | 185 ++-- .../translation_manager/editor_worksheet.cpp | 734 +++++++-------- .../translation_manager/editor_worksheet.h | 93 +- .../translation_manager/extract_bot_names.cpp | 181 ++-- .../translation_manager/extract_bot_names.h | 64 +- .../extract_new_sheet_names.cpp | 206 ++--- .../extract_new_sheet_names.h | 29 +- .../translation_manager/ftp_selection.cpp | 373 ++++---- .../translation_manager/ftp_selection.h | 57 +- .../translation_manager/source_selection.cpp | 51 +- .../translation_manager/source_selection.h | 39 +- .../translation_manager_constants.h | 47 +- .../translation_manager_editor.h | 50 +- .../translation_manager_main_window.cpp | 869 +++++++++--------- .../translation_manager_main_window.h | 130 ++- .../translation_manager_plugin.cpp | 27 +- .../translation_manager_plugin.h | 16 +- .../translation_manager_settings_page.cpp | 114 ++- .../translation_manager_settings_page.h | 28 +- .../translation_manager_settings_page.ui | 308 +++---- 22 files changed, 1858 insertions(+), 1869 deletions(-) diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/CMakeLists.txt b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/CMakeLists.txt index 0f520c9d8..272c7b962 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/CMakeLists.txt +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/CMakeLists.txt @@ -10,25 +10,23 @@ SET(OVQT_EXT_SYS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/../../extension_system/iplugin. ${CMAKE_CURRENT_SOURCE_DIR}/../../extension_system/iplugin_spec.h) SET(OVQT_PLUG_TRANSLATION_MANAGER_HDR translation_manager_plugin.h - translation_manager_main_window.h - translation_manager_settings_page.h - translation_manager_editor.h - source_selection.h - ftp_selection.h - editor_worksheet.h - editor_phrase.h - extract_new_sheet_names.h - extract_bot_names.h) + translation_manager_main_window.h + translation_manager_settings_page.h + translation_manager_editor.h + source_selection.h + ftp_selection.h + editor_worksheet.h + editor_phrase.h +) SET(OVQT_PLUG_TRANSLATION_MANAGER_UIS translation_manager_settings_page.ui - translation_manager_main_window.ui - source_selection.ui - ftp_selection.ui) + translation_manager_main_window.ui + source_selection.ui + ftp_selection.ui) SET(OVQT_PLUG_TRANSLATION_MANAGER_RCS ftp_selection.qrc) SET(QT_USE_QTGUI TRUE) -SET(QT_USE_QTOPENGL TRUE) SET(QT_USE_QTNETWORK TRUE) QT4_WRAP_CPP(OVQT_PLUG_TRANSLATION_MANAGER_MOC_SRC ${OVQT_PLUG_TRANSLATION_MANAGER_HDR}) @@ -42,7 +40,7 @@ SOURCE_GROUP("OVQT Extension System" FILES ${OVQT_EXT_SYS_SRC}) ADD_LIBRARY(ovqt_plugin_translation_manager MODULE ${SRC} ${OVQT_PLUG_TRANSLATION_MANAGER_MOC_SRC} ${OVQT_EXT_SYS_SRC} ${OVQT_PLUG_TRANSLATION_MANAGER_UI_HDRS}) -TARGET_LINK_LIBRARIES(ovqt_plugin_translation_manager ovqt_plugin_core nelmisc nel3d nelligo nelgeorges ${QT_LIBRARIES} ${QT_QTOPENGL_LIBRARY} ${QT_QTNETWORK_LIBRARY} ) +TARGET_LINK_LIBRARIES(ovqt_plugin_translation_manager ovqt_plugin_core nelmisc nelligo nelgeorges ${QT_LIBRARIES} ${QT_QTOPENGL_LIBRARY} ${QT_QTNETWORK_LIBRARY} ) NL_DEFAULT_PROPS(ovqt_plugin_translation_manager "NeL, Tools, 3D: Object Viewer Qt Plugin: Translation Manager") NL_ADD_RUNTIME_FLAGS(ovqt_plugin_translation_manager) diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/editor_phrase.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/editor_phrase.cpp index c1633c3be..a1c59a11f 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/editor_phrase.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/editor_phrase.cpp @@ -1,5 +1,4 @@ // Translation Manager Plugin - OVQT Plugin -// Copyright (C) 2010 Winch Gate Property Limited // Copyright (C) 2011 Emanuel Costea // // This program is free software: you can redistribute it and/or modify @@ -15,32 +14,32 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . +// Project includes +#include "editor_phrase.h" +#include "translation_manager_constants.h" + // Nel includes #include "nel/misc/path.h" #include "nel/misc/diff_tool.h" // Qt includes +#include +#include +#include +#include +#include #include -#include #include #include -#include -#include -#include -#include -#include - -// Project includes -#include "editor_phrase.h" -#include "translation_manager_constants.h" using namespace std; -namespace TranslationManager { +namespace TranslationManager +{ void CEditorPhrase::open(QString filename) { - vector phrases; + std::vector phrases; if(readPhraseFile(filename.toStdString(), phrases, false)) { text_edit = new CTextEdit(this); @@ -53,26 +52,28 @@ void CEditorPhrase::open(QString filename) QFile file(filename); file.open(QIODevice::ReadOnly | QIODevice::Text); QTextStream in(&file); - // set the file content to the text edit + // set the file content to the text edit QString data = in.readAll(); text_edit->append(data); // window settings setCurrentFile(filename); - setAttribute(Qt::WA_DeleteOnClose); + setAttribute(Qt::WA_DeleteOnClose); editor_type = Constants::ED_PHRASE; current_file = filename; connect(text_edit->document(), SIGNAL(contentsChanged()), this, SLOT(docContentsChanged())); connect(text_edit->document(), SIGNAL(undoCommandAdded()), this, SLOT(newUndoCommandAdded())); - } else { - QErrorMessage error; - error.showMessage("This file is not a phrase file."); - error.exec(); - } + } + else + { + QErrorMessage error; + error.showMessage("This file is not a phrase file."); + error.exec(); + } } void CEditorPhrase::newUndoCommandAdded() { - current_stack->push(new CUndoPhraseNewCommand(text_edit)); + current_stack->push(new CUndoPhraseNewCommand(text_edit)); } void CEditorPhrase::docContentsChanged() @@ -97,44 +98,37 @@ void CEditorPhrase::saveAs(QString filename) QTextStream out(&file); out.setCodec("UTF-8"); out.setGenerateByteOrderMark(true); - out<toPlainText(); + out << text_edit->toPlainText(); current_file = filename; setCurrentFile(current_file); } - - void CEditorPhrase::closeEvent(QCloseEvent *event) { - if(isWindowModified()) - { - QMessageBox msgBox; - msgBox.setText("The document has been modified."); - msgBox.setInformativeText("Do you want to save your changes?"); - msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); - msgBox.setDefaultButton(QMessageBox::Save); - int ret = msgBox.exec(); - switch (ret) - { - case QMessageBox::Save: - save(); - event->accept(); - close(); - break; - case QMessageBox::Discard: - event->accept(); - close(); - break; - case QMessageBox::Cancel: - event->ignore(); - break; - default: - break; - } - } else { - event->accept(); - close(); - } + if(isWindowModified()) + { + QMessageBox msgBox; + msgBox.setIcon(QMessageBox::Question); + msgBox.setText(tr("The document has been modified.")); + msgBox.setInformativeText(tr("Do you want to save your changes?")); + msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); + msgBox.setDefaultButton(QMessageBox::Save); + + int ret = msgBox.exec(); + switch (ret) + { + case QMessageBox::Save: + save(); + break; + case QMessageBox::Discard: + break; + case QMessageBox::Cancel: + event->ignore(); + return; + } + } + event->accept(); + close(); } } \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/editor_phrase.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/editor_phrase.h index f26dec73e..b9955fa48 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/editor_phrase.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/editor_phrase.h @@ -18,6 +18,9 @@ #ifndef EDITOR_PHRASE_H #define EDITOR_PHRASE_H +// Project includes +#include "translation_manager_editor.h" + // Qt includes #include #include @@ -32,23 +35,23 @@ #include #include -// Project includes -#include "translation_manager_editor.h" - -namespace TranslationManager { +namespace TranslationManager +{ class CTextEdit : public QTextEdit { Q_OBJECT + private: - QUndoStack* m_undoStack; + QUndoStack *m_undoStack; + public: - CTextEdit(QWidget* parent = 0) : QTextEdit(parent) - { + CTextEdit(QWidget *parent = 0) : QTextEdit(parent) + { setUndoRedoEnabled(true); } //void keyPressEvent(QKeyEvent *event); - void setUndoStack(QUndoStack* undoStack) + void setUndoStack(QUndoStack *undoStack) { m_undoStack = undoStack; } @@ -57,20 +60,22 @@ public: class CEditorPhrase : public CEditor { Q_OBJECT + public: - CTextEdit *text_edit; -public: - CEditorPhrase(QMdiArea* parent) : CEditor(parent) {} - CEditorPhrase() : CEditor() {} - void open(QString filename); - void save(); - void saveAs(QString filename); - void activateWindow(); + CEditorPhrase(QMdiArea *parent) : CEditor(parent) {} + CEditorPhrase() : CEditor() {} + void open(QString filename); + void save(); + void saveAs(QString filename); + void activateWindow(); void closeEvent(QCloseEvent *event); + public Q_SLOTS: void docContentsChanged(); void newUndoCommandAdded(); +private: + CTextEdit *text_edit; }; class CUndoPhraseNewCommand : public QUndoCommand @@ -79,7 +84,7 @@ public: CUndoPhraseNewCommand(CTextEdit *textEdit, QUndoCommand *parent = 0) : QUndoCommand("Inserting/Removing characters", parent), m_textEdit(textEdit) - { } + {} ~CUndoPhraseNewCommand() {} @@ -92,96 +97,102 @@ public: { m_textEdit->redo(); } + private: - CTextEdit* m_textEdit; + CTextEdit *m_textEdit; }; class SyntaxHighlighter : public QSyntaxHighlighter { public: SyntaxHighlighter(QTextEdit *parent) : QSyntaxHighlighter(parent) - { - HighlightingRule rule; + { + HighlightingRule rule; - translateStringFormat.setFontWeight(QFont::Bold); - translateStringFormat.setForeground(Qt::darkMagenta); - rule.pattern = QRegExp("\\[.+\\]"); - rule.format = translateStringFormat; - highlightingRules.append(rule); + translateStringFormat.setFontWeight(QFont::Bold); + translateStringFormat.setForeground(Qt::darkMagenta); + rule.pattern = QRegExp("\\[.+\\]"); + rule.format = translateStringFormat; + highlightingRules.append(rule); + singleLineCommentFormat.setForeground(Qt::red); + rule.pattern = QRegExp("//[^\n]*"); + rule.format = singleLineCommentFormat; + highlightingRules.append(rule); - singleLineCommentFormat.setForeground(Qt::red); - rule.pattern = QRegExp("//[^\n]*"); - rule.format = singleLineCommentFormat; - highlightingRules.append(rule); + multiLineCommentFormat.setForeground(Qt::red); - multiLineCommentFormat.setForeground(Qt::red); + quotationFormat.setForeground(Qt::darkGreen); + rule.pattern = QRegExp("\".*\""); + rule.format = quotationFormat; + highlightingRules.append(rule); - quotationFormat.setForeground(Qt::darkGreen); - rule.pattern = QRegExp("\".*\""); - rule.format = quotationFormat; - highlightingRules.append(rule); + functionFormat.setFontItalic(true); + functionFormat.setForeground(Qt::blue); + rule.pattern = QRegExp("\\(.+\\)"); + rule.format = functionFormat; + highlightingRules.append(rule); - functionFormat.setFontItalic(true); - functionFormat.setForeground(Qt::blue); - rule.pattern = QRegExp("\\(.+\\)"); - rule.format = functionFormat; - highlightingRules.append(rule); - - commentStartExpression = QRegExp("/\\*"); - commentEndExpression = QRegExp("\\*/"); + commentStartExpression = QRegExp("/\\*"); + commentEndExpression = QRegExp("\\*/"); } - void highlightBlock(const QString &text) - { - Q_FOREACH(const HighlightingRule &rule, highlightingRules) { - QRegExp expression(rule.pattern); - int index = expression.indexIn(text); - while (index >= 0) { - int length = expression.matchedLength(); - setFormat(index, length, rule.format); - index = expression.indexIn(text, index + length); - } - } - setCurrentBlockState(0); + void highlightBlock(const QString &text) + { + Q_FOREACH(const HighlightingRule &rule, highlightingRules) + { + QRegExp expression(rule.pattern); + int index = expression.indexIn(text); + while (index >= 0) + { + int length = expression.matchedLength(); + setFormat(index, length, rule.format); + index = expression.indexIn(text, index + length); + } + } + setCurrentBlockState(0); - int startIndex = 0; - if (previousBlockState() != 1) - startIndex = commentStartExpression.indexIn(text); + int startIndex = 0; + if (previousBlockState() != 1) + startIndex = commentStartExpression.indexIn(text); - while (startIndex >= 0) { - int endIndex = commentEndExpression.indexIn(text, startIndex); - int commentLength; - if (endIndex == -1) { - setCurrentBlockState(1); - commentLength = text.length() - startIndex; - } else { - commentLength = endIndex - startIndex - + commentEndExpression.matchedLength(); - } - setFormat(startIndex, commentLength, multiLineCommentFormat); - startIndex = commentStartExpression.indexIn(text, startIndex + commentLength); - } - } + while (startIndex >= 0) + { + int endIndex = commentEndExpression.indexIn(text, startIndex); + int commentLength; + if (endIndex == -1) + { + setCurrentBlockState(1); + commentLength = text.length() - startIndex; + } + else + { + commentLength = endIndex - startIndex + + commentEndExpression.matchedLength(); + } + setFormat(startIndex, commentLength, multiLineCommentFormat); + startIndex = commentStartExpression.indexIn(text, startIndex + commentLength); + } + } - private: - struct HighlightingRule - { - QRegExp pattern; - QTextCharFormat format; - }; - QVector highlightingRules; +private: + struct HighlightingRule + { + QRegExp pattern; + QTextCharFormat format; + }; + QVector highlightingRules; - QRegExp commentStartExpression; - QRegExp commentEndExpression; + QRegExp commentStartExpression; + QRegExp commentEndExpression; - QTextCharFormat keywordFormat; - QTextCharFormat classFormat; - QTextCharFormat singleLineCommentFormat; - QTextCharFormat multiLineCommentFormat; - QTextCharFormat quotationFormat; - QTextCharFormat functionFormat; - QTextCharFormat translateStringFormat; + QTextCharFormat keywordFormat; + QTextCharFormat classFormat; + QTextCharFormat singleLineCommentFormat; + QTextCharFormat multiLineCommentFormat; + QTextCharFormat quotationFormat; + QTextCharFormat functionFormat; + QTextCharFormat translateStringFormat; }; } diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/editor_worksheet.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/editor_worksheet.cpp index c8a101e0f..7041a5178 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/editor_worksheet.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/editor_worksheet.cpp @@ -15,6 +15,11 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . +// Project includes +#include "editor_worksheet.h" +#include "extract_bot_names.h" +#include "translation_manager_constants.h" + // Qt includes #include #include @@ -24,97 +29,103 @@ #include #include -// Project includes -#include "editor_worksheet.h" -#include "extract_bot_names.h" -#include "translation_manager_constants.h" -#include - using namespace std; -namespace TranslationManager { +namespace TranslationManager +{ void CEditorWorksheet::open(QString filename) { - STRING_MANAGER::TWorksheet wk_file; - if(loadExcelSheet(filename.toStdString(), wk_file, true) == true) - { - bool hasHashValue = false; - table_editor = new QTableWidget(); - if(wk_file.getData(0, 0) == ucstring("*HASH_VALUE")) - { - table_editor->setColumnCount(wk_file.ColCount - 1); - hasHashValue = true; - } else { - table_editor->setColumnCount(wk_file.ColCount); - } - table_editor->setRowCount(wk_file.size() - 1); - - // read columns name - for(unsigned int i = 0; i < wk_file.ColCount; i++) - { - if(hasHashValue && i == 0) - { - // we don't show the column with hash value - } else { - QTableWidgetItem *col = new QTableWidgetItem(); - ucstring col_name = wk_file.getData(0, i); - col->setText(QString(col_name.toString().c_str())); - if(hasHashValue) - { - table_editor->setHorizontalHeaderItem(i - 1, col); - } else { - table_editor->setHorizontalHeaderItem(i, col); - } - } - } - - // read rows - for(unsigned int i = 1; i < wk_file.size(); i++) - { - for(unsigned int j = 0; j < wk_file.ColCount; j++) - { - if(hasHashValue && j == 0) - { - // we don't show the column with hash value - } else { - QTableWidgetItem *row = new QTableWidgetItem(); - ucstring row_value = wk_file.getData(i, j); - row->setText(QString::fromUtf8(row_value.toUtf8().c_str())); - if(hasHashValue) - { - table_editor->setItem(i - 1, j - 1, row); - } else { - table_editor->setItem(i - 1, j, row); - } - } - } - } - setCurrentFile(filename); - setAttribute(Qt::WA_DeleteOnClose); - setWidget(table_editor); - editor_type = Constants::ED_SHEET; - table_editor->resizeColumnsToContents(); - table_editor->resizeRowsToContents(); - // set editor signals - connect(table_editor, SIGNAL(itemChanged(QTableWidgetItem*) ), this, SLOT(worksheetEditorChanged(QTableWidgetItem*))); - connect(table_editor, SIGNAL(itemDoubleClicked(QTableWidgetItem*) ), this, SLOT(worksheetEditorCellEntered(QTableWidgetItem*))); - connect (table_editor,SIGNAL(customContextMenuRequested(const QPoint &)), this,SLOT(contextMenuEvent(QContextMenuEvent*))); - } else { - QErrorMessage error; - error.showMessage("This file is not a worksheet file."); - error.exec(); - } - + STRING_MANAGER::TWorksheet wk_file; + if(loadExcelSheet(filename.toStdString(), wk_file, true) == true) + { + bool hasHashValue = false; + table_editor = new QTableWidget(); + if(wk_file.getData(0, 0) == ucstring("*HASH_VALUE")) + { + table_editor->setColumnCount(wk_file.ColCount - 1); + hasHashValue = true; + } + else + { + table_editor->setColumnCount(wk_file.ColCount); + } + table_editor->setRowCount(wk_file.size() - 1); + + // read columns name + for(uint i = 0; i < wk_file.ColCount; i++) + { + if(hasHashValue && i == 0) + { + // we don't show the column with hash value + } + else + { + QTableWidgetItem *col = new QTableWidgetItem(); + ucstring col_name = wk_file.getData(0, i); + col->setText(QString(col_name.toString().c_str())); + if(hasHashValue) + { + table_editor->setHorizontalHeaderItem(i - 1, col); + } + else + { + table_editor->setHorizontalHeaderItem(i, col); + } + } + } + + // read rows + for(unsigned int i = 1; i < wk_file.size(); i++) + { + for(unsigned int j = 0; j < wk_file.ColCount; j++) + { + if(hasHashValue && j == 0) + { + // we don't show the column with hash value + } + else + { + QTableWidgetItem *row = new QTableWidgetItem(); + ucstring row_value = wk_file.getData(i, j); + row->setText(QString::fromUtf8(row_value.toUtf8().c_str())); + if(hasHashValue) + { + table_editor->setItem(i - 1, j - 1, row); + } + else + { + table_editor->setItem(i - 1, j, row); + } + } + } + } + setCurrentFile(filename); + setAttribute(Qt::WA_DeleteOnClose); + setWidget(table_editor); + editor_type = Constants::ED_SHEET; + table_editor->resizeColumnsToContents(); + table_editor->resizeRowsToContents(); + // set editor signals + connect(table_editor, SIGNAL(itemChanged(QTableWidgetItem *) ), this, SLOT(worksheetEditorChanged(QTableWidgetItem *))); + connect(table_editor, SIGNAL(itemDoubleClicked(QTableWidgetItem *) ), this, SLOT(worksheetEditorCellEntered(QTableWidgetItem *))); + connect(table_editor,SIGNAL(customContextMenuRequested(const QPoint &)), this,SLOT(contextMenuEvent(QContextMenuEvent *))); + } + else + { + QErrorMessage error; + error.showMessage(tr("This file is not a worksheet file.")); + error.exec(); + } } void CEditorWorksheet::contextMenuEvent(QContextMenuEvent *e) { - QAction *insertRowAct = new QAction("Insert new row", this); - connect(insertRowAct, SIGNAL(triggered()), this, SLOT(insertRow())); - QAction *deleteRowAct = new QAction("Delete row", this); - connect(deleteRowAct, SIGNAL(triggered()), this, SLOT(deleteRow())); + QAction *insertRowAct = new QAction(tr("Insert new row"), this); + connect(insertRowAct, SIGNAL(triggered()), this, SLOT(insertRow())); + QAction *deleteRowAct = new QAction(tr("Delete row"), this); + connect(deleteRowAct, SIGNAL(triggered()), this, SLOT(deleteRow())); QMenu *contextMenu = new QMenu(this); contextMenu->addAction(insertRowAct); @@ -127,7 +138,7 @@ void CEditorWorksheet::contextMenuEvent(QContextMenuEvent *e) void CEditorWorksheet::activateWindow() { - showMaximized(); + showMaximized(); } void CEditorWorksheet::save() @@ -137,372 +148,377 @@ void CEditorWorksheet::save() void CEditorWorksheet::saveAs(QString filename) { - STRING_MANAGER::TWorksheet new_file, wk_file; - loadExcelSheet(current_file.toStdString(), wk_file, true); - // set columns - new_file.resize(new_file.size() + 1); - for(unsigned int i = 0; i < wk_file.ColCount; i++) - { - ucstring col_name = wk_file.getData(0, i); - new_file.insertColumn(new_file.ColCount); - new_file.setData(0, new_file.ColCount - 1, col_name); - } - // read all the rows from table - uint rowIdx; - uint colIdx = 0; - bool hasHashValue = false; - if(wk_file.getData(0, 0) == ucstring("*HASH_VALUE")) - { - hasHashValue = true; - colIdx = 1; - } - for(int i = 0; i < table_editor->rowCount(); i++) - { - rowIdx = new_file.size(); - new_file.resize(new_file.size() + 1); - ucstring tvalue; - for(int j = 0; j < table_editor->columnCount(); j++) - { - QTableWidgetItem* item = table_editor->item(i, j); - tvalue.fromUtf8(std::string(item->text().toUtf8())); - new_file.setData(rowIdx, j + colIdx, tvalue); - } - } - if(hasHashValue) - { - // rewrite the hash codes - makeHashCode(wk_file, true); - } - ucstring s = prepareExcelSheet(new_file); - NLMISC::CI18N::writeTextFile(filename.toStdString(), s, false); - current_file = filename; - setCurrentFile(filename); + STRING_MANAGER::TWorksheet new_file, wk_file; + loadExcelSheet(current_file.toStdString(), wk_file, true); + // set columns + new_file.resize(new_file.size() + 1); + for(unsigned int i = 0; i < wk_file.ColCount; i++) + { + ucstring col_name = wk_file.getData(0, i); + new_file.insertColumn(new_file.ColCount); + new_file.setData(0, new_file.ColCount - 1, col_name); + } + // read all the rows from table + uint rowIdx; + uint colIdx = 0; + bool hasHashValue = false; + if(wk_file.getData(0, 0) == ucstring("*HASH_VALUE")) + { + hasHashValue = true; + colIdx = 1; + } + for(int i = 0; i < table_editor->rowCount(); i++) + { + rowIdx = new_file.size(); + new_file.resize(new_file.size() + 1); + ucstring tvalue; + for(int j = 0; j < table_editor->columnCount(); j++) + { + QTableWidgetItem *item = table_editor->item(i, j); + tvalue.fromUtf8(std::string(item->text().toUtf8())); + new_file.setData(rowIdx, j + colIdx, tvalue); + } + } + if(hasHashValue) + { + // rewrite the hash codes + makeHashCode(wk_file, true); + } + ucstring s = prepareExcelSheet(new_file); + NLMISC::CI18N::writeTextFile(filename.toStdString(), s, false); + current_file = filename; + setCurrentFile(filename); } void CEditorWorksheet::insertRow() { - int last_row = table_editor->rowCount(); + int last_row = table_editor->rowCount(); current_stack->push(new CUndoWorksheetNewCommand(table_editor, last_row)); } void CEditorWorksheet::deleteRow() { - int selected_row = table_editor->currentRow(); - QMessageBox msgBox; - msgBox.setText(tr("The row will be deleted.")); - msgBox.setInformativeText(tr("Do you want to delete the selected row ?")); - msgBox.setStandardButtons(QMessageBox::No | QMessageBox::Yes); - msgBox.setDefaultButton(QMessageBox::No); - int ret = msgBox.exec(); - if(ret == QMessageBox::Yes) - { - current_stack->push(new CUndoWorksheetDeleteCommand(table_editor, selected_row)); - } + int selected_row = table_editor->currentRow(); + QMessageBox msgBox; + msgBox.setIcon(QMessageBox::Question); + msgBox.setText(tr("The row will be deleted.")); + msgBox.setInformativeText(tr("Do you want to delete the selected row ?")); + msgBox.setStandardButtons(QMessageBox::No | QMessageBox::Yes); + msgBox.setDefaultButton(QMessageBox::No); - table_editor->clearFocus(); - table_editor->clearSelection(); - return; + int ret = msgBox.exec(); + if(ret == QMessageBox::Yes) + { + current_stack->push(new CUndoWorksheetDeleteCommand(table_editor, selected_row)); + } + table_editor->clearFocus(); + table_editor->clearSelection(); + return; } -void CEditorWorksheet::worksheetEditorCellEntered(QTableWidgetItem * item) +void CEditorWorksheet::worksheetEditorCellEntered(QTableWidgetItem *item) { temp_content = item->text(); current_stack->push(new CUndoWorksheetCommand(table_editor, item, temp_content)); } -void CEditorWorksheet::worksheetEditorChanged(QTableWidgetItem * item) +void CEditorWorksheet::worksheetEditorChanged(QTableWidgetItem *item) { if(temp_content != item->text()) { //current_stack->push(new CUndoWorksheetCommand(table_editor, item, temp_content)); } - if(!isWindowModified()) - setWindowModified(true); + if(!isWindowModified()) + setWindowModified(true); } void CEditorWorksheet::extractBotNames(list filters, string level_design_path, NLLIGO::CLigoConfig ligoConfig) { - bool modified = false; + bool modified = false; QList new_items; - ExtractBotNames ebn; - ebn.setRequiredSettings(filters, level_design_path); - ebn.extractBotNamesFromPrimitives(ligoConfig); - // get SimpleNames - { - map SimpleNames = ebn.getSimpleNames(); - map::iterator it(SimpleNames.begin()), last(SimpleNames.end()); + ExtractBotNames ebn; + ebn.setRequiredSettings(filters, level_design_path); + ebn.extractBotNamesFromPrimitives(ligoConfig); + // get SimpleNames + { + map SimpleNames = ebn.getSimpleNames(); + map::iterator it(SimpleNames.begin()), last(SimpleNames.end()); + + for (; it != last; ++it) + { + QList search_results = table_editor->findItems(QString(it->first.c_str()), Qt::MatchExactly); + if(search_results.size() == 0) + { + QList records; + records.push_back(QString(it->first.c_str())); + records.push_back(QString(it->first.c_str())); + records.push_back(QString(it->second.SheetName.c_str())); + insertTableRecords(records, new_items); + if(!modified) modified = true; + } + } + ebn.cleanSimpleNames(); + } + // get GenericNames + { + set GenericNames = ebn.getGenericNames(); + set::iterator it(GenericNames.begin()), last(GenericNames.end()); + for (; it != last; ++it) + { + string gnName = "gn_" + ebn.cleanupName(*it); + QList search_results = table_editor->findItems(QString((*it).c_str()), Qt::MatchExactly); + if(search_results.size() == 0) + { + QList records; + records.push_back(QString((*it).c_str())); + records.push_back(QString(gnName.c_str())); + records.push_back(" "); + insertTableRecords(records, new_items); + if(!modified) modified = true; + } + } + ebn.cleanGenericNames(); + } + + current_stack->push(new CUndoWorksheetExtraction(new_items, table_editor)); + if(modified) + { + setWindowModified(true); + table_editor->scrollToBottom(); + } - for (; it != last; ++it) - { - QList search_results = table_editor->findItems(QString(it->first.c_str()), Qt::MatchExactly); - if(search_results.size() == 0) - { - QList records; - records.push_back(QString(it->first.c_str())); - records.push_back(QString(it->first.c_str())); - records.push_back(QString(it->second.SheetName.c_str())); - insertTableRecords(records, new_items); - if(!modified) modified = true; - } - } - ebn.cleanSimpleNames(); - } - // get GenericNames - { - set GenericNames = ebn.getGenericNames(); - set::iterator it(GenericNames.begin()), last(GenericNames.end()); - for (; it != last; ++it) - { - string gnName = "gn_" + ebn.cleanupName(*it); - QList search_results = table_editor->findItems(QString((*it).c_str()), Qt::MatchExactly); - if(search_results.size() == 0) - { - QList records; - records.push_back(QString((*it).c_str())); - records.push_back(QString(gnName.c_str())); - records.push_back(" "); - insertTableRecords(records, new_items); - if(!modified) modified = true; - } - } - ebn.cleanGenericNames(); - } - - current_stack->push(new CUndoWorksheetExtraction(new_items, table_editor)); - if(modified) - { - setWindowModified(true); - table_editor->scrollToBottom(); - } - } -void CEditorWorksheet::extractWords(QString filename, QString columnId, IWordListBuilder& wordListBuilder) +void CEditorWorksheet::extractWords(QString filename, QString columnId, IWordListBuilder &wordListBuilder) { - uint i; + uint i; // **** Load the excel sheet // load - TWorksheet workSheet; + STRING_MANAGER::TWorksheet workSheet; if(!loadExcelSheet(filename.toStdString(), workSheet, true)) { nlwarning("Error reading '%s'. Aborted", filename.toStdString().c_str()); return; } // get the key column index - uint keyColIndex = 0; + uint keyColIndex = 0; if(!workSheet.findCol(columnId.toStdString(), keyColIndex)) { nlwarning("Error: Don't find the column '%s'. '%s' Aborted", columnId.toStdString().c_str(), filename.toStdString().c_str()); return; } // get the name column index - uint nameColIndex; + uint nameColIndex; if(!workSheet.findCol(ucstring("name"), nameColIndex)) { nlwarning("Error: Don't find the column 'name'. '%s' Aborted", filename.toStdString().c_str()); return; - } - - // **** List all words with the builder given - std::vector allWords; - if(!wordListBuilder.buildWordList(allWords, filename.toStdString())) - { - return; - } - bool modified = false; - QList new_items; - for(i = 0; i < allWords.size(); i++) - { - string keyName = allWords[i]; - QList search_results = table_editor->findItems(QString(keyName.c_str()), Qt::MatchExactly); - if(search_results.size() == 0) - { - int knPos = 0, nPos = 0; - if(workSheet.getData(0, 0) == ucstring("*HASH_VALUE")) - { - knPos = keyColIndex - 1; - nPos = nameColIndex - 1; - } else { - knPos = keyColIndex; - nPos = nameColIndex; - } + } - QList records; - records.push_back(QString(keyName.c_str())); - records.push_back(QString("") + QString(keyName.c_str())); - insertTableRecords(records, new_items); - if(!modified) modified = true; - } - } - current_stack->push(new CUndoWorksheetExtraction(new_items, table_editor)); - if(modified) - { - setWindowModified(true); - table_editor->scrollToBottom(); - } + // **** List all words with the builder given + std::vector allWords; + if(!wordListBuilder.buildWordList(allWords, filename.toStdString())) + { + return; + } + bool modified = false; + QList new_items; + for(i = 0; i < allWords.size(); i++) + { + string keyName = allWords[i]; + QList search_results = table_editor->findItems(QString(keyName.c_str()), Qt::MatchExactly); + if(search_results.size() == 0) + { + int knPos = 0, nPos = 0; + if(workSheet.getData(0, 0) == ucstring("*HASH_VALUE")) + { + knPos = keyColIndex - 1; + nPos = nameColIndex - 1; + } + else + { + knPos = keyColIndex; + nPos = nameColIndex; + } + + QList records; + records.push_back(QString(keyName.c_str())); + records.push_back(QString("") + QString(keyName.c_str())); + insertTableRecords(records, new_items); + if(!modified) modified = true; + } + } + current_stack->push(new CUndoWorksheetExtraction(new_items, table_editor)); + if(modified) + { + setWindowModified(true); + table_editor->scrollToBottom(); + } } void CEditorWorksheet::insertTableRecords(QList records, QList new_items) { - const int currentRow = table_editor->rowCount(); + const int currentRow = table_editor->rowCount(); table_editor->setRowCount(currentRow + 1); int n = 0; Q_FOREACH(QString record, records) { QTableWidgetItem *rec = new QTableWidgetItem(); rec->setBackgroundColor(QColor("#F75D59")); - table_editor ->setItem(currentRow, n, rec); + table_editor ->setItem(currentRow, n, rec); CTableWidgetItemStore rec_s(rec, currentRow, n); new_items.push_back(rec_s); n++; } - } bool CEditorWorksheet::compareWorksheetFile(QString filename) { - STRING_MANAGER::TWorksheet wk_file; - int colIndex = 0; - if(loadExcelSheet(filename.toStdString(), wk_file, true) == true) - { - if(wk_file.getData(0, 0) == ucstring("*HASH_VALUE")) - { - colIndex = 1; - } - if(wk_file.ColCount - colIndex != table_editor->columnCount()) - { - return false; - } - for(int i = 0; i < table_editor->columnCount(); i++) - { - QString item = table_editor->horizontalHeaderItem(i)->text(); - ucstring itemC = wk_file.getData(0, i+ colIndex); - if(item.toStdString() != itemC.toString()) - { - nlwarning(item.toStdString().c_str()); - nlwarning(itemC.toString().c_str()); - return false; - } - } - } else { - return false; - } - - return true; + STRING_MANAGER::TWorksheet wk_file; + int colIndex = 0; + if(loadExcelSheet(filename.toStdString(), wk_file, true) == true) + { + if(wk_file.getData(0, 0) == ucstring("*HASH_VALUE")) + { + colIndex = 1; + } + if(wk_file.ColCount - colIndex != table_editor->columnCount()) + { + return false; + } + for(int i = 0; i < table_editor->columnCount(); i++) + { + QString item = table_editor->horizontalHeaderItem(i)->text(); + ucstring itemC = wk_file.getData(0, i+ colIndex); + if(item.toStdString() != itemC.toString()) + { + nlwarning(item.toStdString().c_str()); + nlwarning(itemC.toString().c_str()); + return false; + } + } + } + else + { + return false; + } + return true; } void CEditorWorksheet::mergeWorksheetFile(QString filename) { - STRING_MANAGER::TWorksheet wk_file; - if(loadExcelSheet(filename.toStdString(), wk_file, true) == true) - { - bool hasHashValue = false; - int colIndex = 0; - if(wk_file.getData(0, 0) == ucstring("*HASH_VALUE")) - { - hasHashValue = true; - colIndex = 1; - } - // read rows - for(unsigned int i = 1; i < wk_file.size(); i++) - { - // search with the first column - ucstring rowId = wk_file.getData(i,colIndex); - QList search_results = table_editor->findItems(QString(rowId.toString().c_str()), Qt::MatchExactly); - if(search_results.size() == 0) - { - const int lastRow = table_editor->rowCount(); - table_editor->setRowCount(lastRow + 1); - for(unsigned int j = 0; j < table_editor->columnCount(); j++) - { - ucstring rowValue = wk_file.getData(i, j + colIndex); // get the value - QTableWidgetItem *row = new QTableWidgetItem(); - row->setText(QString(rowValue.toString().c_str())); // set the value in table item - table_editor->setItem(lastRow, j, row); - } - } - } - } else { - QErrorMessage error; - error.showMessage(tr("This file is not a worksheet file.")); - error.exec(); - } + STRING_MANAGER::TWorksheet wk_file; + if(loadExcelSheet(filename.toStdString(), wk_file, true) == true) + { + bool hasHashValue = false; + int colIndex = 0; + if(wk_file.getData(0, 0) == ucstring("*HASH_VALUE")) + { + hasHashValue = true; + colIndex = 1; + } + // read rows + for(unsigned int i = 1; i < wk_file.size(); i++) + { + // search with the first column + ucstring rowId = wk_file.getData(i,colIndex); + QList search_results = table_editor->findItems(QString(rowId.toString().c_str()), Qt::MatchExactly); + if(search_results.size() == 0) + { + const int lastRow = table_editor->rowCount(); + table_editor->setRowCount(lastRow + 1); + for(int j = 0; j < table_editor->columnCount(); j++) + { + ucstring rowValue = wk_file.getData(i, j + colIndex); // get the value + QTableWidgetItem *row = new QTableWidgetItem(); + row->setText(QString(rowValue.toString().c_str())); // set the value in table item + table_editor->setItem(lastRow, j, row); + } + } + } + } + else + { + QErrorMessage error; + error.showMessage(tr("This file is not a worksheet file.")); + error.exec(); + } } void CEditorWorksheet::closeEvent(QCloseEvent *event) { - if(isWindowModified()) - { - QMessageBox msgBox; - msgBox.setText(tr("The document has been modified.")); - msgBox.setInformativeText(tr("Do you want to save your changes?")); - msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); - msgBox.setDefaultButton(QMessageBox::Save); - int ret = msgBox.exec(); - switch (ret) - { - case QMessageBox::Save: - save(); - event->accept(); - close(); - break; - case QMessageBox::Discard: - event->accept(); - close(); - break; - case QMessageBox::Cancel: - event->ignore(); - break; - default: - break; - } - } else { - event->accept(); - close(); - } + if(isWindowModified()) + { + QMessageBox msgBox; + msgBox.setIcon(QMessageBox::Question); + msgBox.setText(tr("The document has been modified.")); + msgBox.setInformativeText(tr("Do you want to save your changes?")); + msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); + msgBox.setDefaultButton(QMessageBox::Save); + int ret = msgBox.exec(); + switch (ret) + { + case QMessageBox::Save: + save(); + break; + case QMessageBox::Discard: + break; + case QMessageBox::Cancel: + event->ignore(); + return; + } + } + event->accept(); + close(); } bool CEditorWorksheet::isBotNamesTable() { - bool status = true; - if(table_editor->horizontalHeaderItem(0)->text() != "bot name" - || table_editor->horizontalHeaderItem(1)->text() != "translated name" - || table_editor->horizontalHeaderItem(2)->text() != "sheet_name") - { - status = false; - } - - return status; + bool status = true; + if(table_editor->horizontalHeaderItem(0)->text() != "bot name" + || table_editor->horizontalHeaderItem(1)->text() != "translated name" + || table_editor->horizontalHeaderItem(2)->text() != "sheet_name") + { + status = false; + } + return status; } bool CEditorWorksheet::isSheetTable(QString type) { - QString column_name; - if(type.toAscii() == Constants::WK_ITEM) - { - column_name = "item ID"; - } else if(type.toAscii() == Constants::WK_CREATURE) { - column_name = "creature ID"; - } else if(type.toAscii() == Constants::WK_SBRICK) { - column_name = "sbrick ID"; - } else if(type.toAscii() == Constants::WK_SPHRASE) { - column_name = "sphrase ID"; - } else if(type.toAscii() == Constants::WK_PLACE) { - column_name = "placeId"; - } - bool status = true; - if(table_editor->horizontalHeaderItem(0)->text() != column_name - || table_editor->horizontalHeaderItem(1)->text() != "name") - { - status = false; - } - - return status; + QString column_name; + if(type.toAscii() == Constants::WK_ITEM) + { + column_name = "item ID"; + } + else if(type.toAscii() == Constants::WK_CREATURE) + { + column_name = "creature ID"; + } + else if(type.toAscii() == Constants::WK_SBRICK) + { + column_name = "sbrick ID"; + } + else if(type.toAscii() == Constants::WK_SPHRASE) + { + column_name = "sphrase ID"; + } + else if(type.toAscii() == Constants::WK_PLACE) + { + column_name = "placeId"; + } + bool status = true; + if(table_editor->horizontalHeaderItem(0)->text() != column_name + || table_editor->horizontalHeaderItem(1)->text() != "name") + { + status = false; + } + return status; } } diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/editor_worksheet.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/editor_worksheet.h index 487a9eea8..b60c7a534 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/editor_worksheet.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/editor_worksheet.h @@ -18,6 +18,10 @@ #ifndef EDITOR_WORKSHEET_H #define EDITOR_WORKSHEET_H +// Project includes +#include "translation_manager_editor.h" +#include "extract_new_sheet_names.h" + // Nel includes #include "nel/misc/types_nl.h" #include "nel/misc/sheet_id.h" @@ -34,11 +38,9 @@ #include #include -// Project includes -#include "translation_manager_editor.h" -#include "extract_new_sheet_names.h" -namespace TranslationManager { +namespace TranslationManager +{ struct CTableWidgetItemStore { @@ -47,6 +49,7 @@ public: m_item(item), m_row(row), m_column(column) { } + QTableWidgetItem *m_item; int m_row; int m_column; @@ -54,39 +57,41 @@ public: class CEditorWorksheet : public CEditor { - Q_OBJECT -private: - QString temp_content; + Q_OBJECT + public: - CEditorWorksheet(QMdiArea* parent) : CEditor(parent) {} - CEditorWorksheet() : CEditor() {} - QTableWidget* table_editor; - void open(QString filename); - void save(); - void saveAs(QString filename); - void activateWindow(); - void mergeWorksheetFile(QString filename); - bool compareWorksheetFile(QString filename); - void extractBotNames(list filters, string level_design_path, NLLIGO::CLigoConfig ligoConfig); - void extractWords(QString filename, QString columnId, IWordListBuilder &wordListBuilder); + CEditorWorksheet(QMdiArea *parent) : CEditor(parent) {} + CEditorWorksheet() : CEditor() {} + QTableWidget *table_editor; + void open(QString filename); + void save(); + void saveAs(QString filename); + void activateWindow(); + void mergeWorksheetFile(QString filename); + bool compareWorksheetFile(QString filename); + void extractBotNames(std::list filters, std::string level_design_path, NLLIGO::CLigoConfig ligoConfig); + void extractWords(QString filename, QString columnId, IWordListBuilder &wordListBuilder); void insertTableRecords(QList records, QList new_items); - bool isBotNamesTable(); - bool isSheetTable(QString type); - void closeEvent(QCloseEvent *event); + bool isBotNamesTable(); + bool isSheetTable(QString type); + void closeEvent(QCloseEvent *event); + private Q_SLOTS: - void worksheetEditorCellEntered(QTableWidgetItem * item); - void worksheetEditorChanged(QTableWidgetItem * item); - void insertRow(); - void deleteRow(); + void worksheetEditorCellEntered(QTableWidgetItem *item); + void worksheetEditorChanged(QTableWidgetItem *item); + void insertRow(); + void deleteRow(); void contextMenuEvent(QContextMenuEvent *e); - + +private: + QString temp_content; }; class CUndoWorksheetCommand : public QUndoCommand { public: - CUndoWorksheetCommand(QTableWidget *table, QTableWidgetItem* item, const QString &ocontent, QUndoCommand *parent = 0) : QUndoCommand("Insert characters in cells", parent), m_table(table), m_item(item), m_ocontent(ocontent) - { + CUndoWorksheetCommand(QTableWidget *table, QTableWidgetItem *item, const QString &ocontent, QUndoCommand *parent = 0) : QUndoCommand("Insert characters in cells", parent), m_table(table), m_item(item), m_ocontent(ocontent) + { m_ccontent = m_ocontent; } @@ -98,16 +103,16 @@ public: } } void undo() - { + { if(m_item->text() != m_ocontent) { m_ccontent = m_item->text(); } m_item->setText(m_ocontent); - } + } private: - QTableWidget* m_table; - QTableWidgetItem* m_item; + QTableWidget *m_table; + QTableWidgetItem *m_item; QString m_ocontent; QString m_ccontent; }; @@ -123,7 +128,7 @@ public: m_table->setRowCount(m_rowID + 1); for(int j = 0; j < m_table->columnCount(); j++) { - QTableWidgetItem* item = new QTableWidgetItem(); + QTableWidgetItem *item = new QTableWidgetItem(); m_table->setItem(m_rowID, j, item); m_table->scrollToBottom(); } @@ -133,16 +138,16 @@ public: { m_table->removeRow(m_rowID); } -private: - QTableWidget* m_table; - int m_rowID; +private: + QTableWidget *m_table; + int m_rowID; }; class CUndoWorksheetExtraction : public QUndoCommand { public: - CUndoWorksheetExtraction(QList items, QTableWidget *table, QUndoCommand *parent = 0) : QUndoCommand("Word extraction", parent), + CUndoWorksheetExtraction(QList items, QTableWidget *table, QUndoCommand *parent = 0) : QUndoCommand("Word extraction", parent), m_items(items), m_table(table) { } @@ -153,7 +158,6 @@ public: { m_table->setItem(is.m_row, is.m_column, is.m_item); } - } void undo() @@ -161,14 +165,13 @@ public: Q_FOREACH(CTableWidgetItemStore is, m_items) { m_table->setItem(is.m_row, is.m_column, is.m_item); - m_table->takeItem(is.m_row, is.m_column); + m_table->takeItem(is.m_row, is.m_column); } - } private: QList m_items; - QTableWidget* m_table; + QTableWidget *m_table; }; class CUndoWorksheetDeleteCommand : public QUndoCommand @@ -181,8 +184,8 @@ public: { for(int i = 0; i < m_table->columnCount(); i++) { - QTableWidgetItem* item = new QTableWidgetItem(); - QTableWidgetItem* table_item = m_table->item(m_rowID, i); + QTableWidgetItem *item = new QTableWidgetItem(); + QTableWidgetItem *table_item = m_table->item(m_rowID, i); item->setText(table_item->text()); m_deletedItems.push_back(item); } @@ -203,8 +206,8 @@ public: } private: - QList m_deletedItems; - QTableWidget* m_table; + QList m_deletedItems; + QTableWidget *m_table; int m_rowID; }; diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/extract_bot_names.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/extract_bot_names.cpp index e8ed68bbf..ee65ca73c 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/extract_bot_names.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/extract_bot_names.cpp @@ -17,18 +17,14 @@ #include "extract_bot_names.h" - static bool RemoveOlds = false; - - - namespace TranslationManager { TCreatureInfo *ExtractBotNames::getCreature(const std::string &sheetName) { - CSheetId id(sheetName+".creature"); + NLMISC::CSheetId id(sheetName+".creature"); if (Creatures.find(id) != Creatures.end()) return &(Creatures.find(id)->second); @@ -36,18 +32,17 @@ TCreatureInfo *ExtractBotNames::getCreature(const std::string &sheetName) return NULL; } -string ExtractBotNames::cleanupName(const std::string &name) +std::string ExtractBotNames::cleanupName(const std::string &name) { - string ret; + std::string ret; - for (uint i=0; i= 2) { - if ( *ret.begin() == ucchar('$')) + if (*ret.begin() == ucchar('$')) { ret=ret.substr(1); } - if ( *ret.rbegin() == ucchar('$')) + if (*ret.rbegin() == ucchar('$')) { - ret = ret.substr(0, ret.size()-1); + ret = ret.substr(0, ret.size() - 1); } } ret = cleanupUcName(ret); - return ret; + return ret; } - - - - -set ExtractBotNames::getGenericNames() +std::set ExtractBotNames::getGenericNames() { - return GenericNames; + return GenericNames; } -map ExtractBotNames::getSimpleNames() +std::map ExtractBotNames::getSimpleNames() { - return SimpleNames; + return SimpleNames; } void ExtractBotNames::cleanSimpleNames() -{ - SimpleNames.clear(); +{ + SimpleNames.clear(); } void ExtractBotNames::cleanGenericNames() { - GenericNames.clear(); + GenericNames.clear(); } -string ExtractBotNames::removeAndStoreFunction(const std::string &fullName) +std::string ExtractBotNames::removeAndStoreFunction(const std::string &fullName) { - string::size_type pos = fullName.find("$"); - if (pos == string::npos) + std::string::size_type pos = fullName.find("$"); + if (pos == std::string::npos) + { return fullName; + } else { // extract and store the function name - string ret; + std::string ret; ret = fullName.substr(0, pos); - string::size_type pos2 = fullName.find("$", pos+1); + std::string::size_type pos2 = fullName.find("$", pos+1); - string fct = fullName.substr(pos+1, pos2-(pos+1)); + std::string fct = fullName.substr(pos + 1, pos2 - (pos + 1)); - ret += fullName.substr(pos2+1); + ret += fullName.substr(pos2 + 1); if (Functions.find(fct) == Functions.end()) { nldebug("Adding function '%s'", fct.c_str()); Functions.insert(fct); } - return ret; } } - void ExtractBotNames::addGenericName(const std::string &name, const std::string &sheetName) { TCreatureInfo *c = getCreature(sheetName); if (!c || c->ForceSheetName || !c->DisplayName) return; - + if (SimpleNames.find(name) != SimpleNames.end()) { nldebug("Name '%s' is now a generic name", name.c_str()); @@ -177,7 +167,7 @@ void ExtractBotNames::addSimpleName(const std::string &name, const std::string & else { nldebug("Adding simple name '%s'", name.c_str()); - + TEntryInfo ei; ei.SheetName = sheetName; @@ -185,75 +175,72 @@ void ExtractBotNames::addSimpleName(const std::string &name, const std::string & } } -void ExtractBotNames::setRequiredSettings(list filters, string level_design_path) +void ExtractBotNames::setRequiredSettings(std::list filters, std::string level_design_path) { - for (std::list::iterator it = filters.begin(); it != filters.end(); ++it) + for (std::list::iterator it = filters.begin(); it != filters.end(); ++it) { Filters.push_back(*it); } //------------------------------------------------------------------- // init the sheets - CSheetId::init(false); - const string PACKED_SHEETS_NAME = "bin/translation_tools_creature.packed_sheets"; + NLMISC::CSheetId::init(false); + const std::string PACKED_SHEETS_NAME = "bin/translation_tools_creature.packed_sheets"; loadForm("creature", PACKED_SHEETS_NAME, Creatures, false, false); if (Creatures.empty()) { - loadForm("creature", PACKED_SHEETS_NAME, Creatures, true); + loadForm("creature", PACKED_SHEETS_NAME, Creatures, true); } - } -void ExtractBotNames::extractBotNamesFromPrimitives(CLigoConfig ligoConfig) +void ExtractBotNames::extractBotNamesFromPrimitives(NLLIGO::CLigoConfig ligoConfig) { - //------------------------------------------------------------------- // ok, ready for the real work, // first, read the primitives files and parse the primitives - vector files; - CPath::getFileList("primitive", files); - + std::vector files; + NLMISC::CPath::getFileList("primitive", files); for (uint i=0; i ps; + NLLIGO::CPrimitiveSet ps; ps.buildSet(primDoc.RootNode, pred, result); - for (uint i=0; igetPropertyByName("name", name); result[i]->getPropertyByName("count", countStr); result[i]->getPropertyByName("bot_sheet_look", sheetStr); @@ -276,16 +263,16 @@ void ExtractBotNames::extractBotNamesFromPrimitives(CLigoConfig ligoConfig) } // look for bot template { - TPrimitiveClassPredicate pred("bot_template_npc"); - TPrimitiveSet result; + NLLIGO::TPrimitiveClassPredicate pred("bot_template_npc"); + NLLIGO::TPrimitiveSet result; - CPrimitiveSet ps; + NLLIGO::CPrimitiveSet ps; ps.buildSet(primDoc.RootNode, pred, result); - for (uint i=0; igetPropertyByName("name", name); result[i]->getPropertyByName("sheet_look", sheetStr); @@ -305,19 +292,19 @@ void ExtractBotNames::extractBotNamesFromPrimitives(CLigoConfig ligoConfig) } } } - // look for npc_group + // look for npc_group { - TPrimitiveClassPredicate pred("npc_group"); - TPrimitiveSet result; + NLLIGO::TPrimitiveClassPredicate pred("npc_group"); + NLLIGO::TPrimitiveSet result; - CPrimitiveSet ps; + NLLIGO::CPrimitiveSet ps; ps.buildSet(primDoc.RootNode, pred, result); - for (uint i=0; igetPropertyByName("name", name); result[i]->getPropertyByName("count", countStr); result[i]->getPropertyByName("bot_sheet_client", sheetStr); @@ -342,18 +329,18 @@ void ExtractBotNames::extractBotNamesFromPrimitives(CLigoConfig ligoConfig) } } } - // look for bot + // look for bot { - TPrimitiveClassPredicate pred("npc_bot"); - TPrimitiveSet result; + NLLIGO::TPrimitiveClassPredicate pred("npc_bot"); + NLLIGO::TPrimitiveSet result; - CPrimitiveSet ps; + NLLIGO::CPrimitiveSet ps; ps.buildSet(primDoc.RootNode, pred, result); - for (uint i=0; igetPropertyByName("name", name); result[i]->getPropertyByName("sheet_client", sheetStr); @@ -373,7 +360,7 @@ void ExtractBotNames::extractBotNamesFromPrimitives(CLigoConfig ligoConfig) } } } - } + } } - + } \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/extract_bot_names.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/extract_bot_names.h index df1cb39ca..208b4db5c 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/extract_bot_names.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/extract_bot_names.h @@ -30,22 +30,16 @@ #include "nel/ligo/primitive.h" #include "nel/ligo/primitive_utils.h" -using namespace std; -using namespace NLMISC; -using namespace NLLIGO; -using namespace STRING_MANAGER; - namespace TranslationManager { struct TCreatureInfo { - CSheetId SheetId; - bool ForceSheetName; - bool DisplayName; + NLMISC::CSheetId SheetId; + bool ForceSheetName; + bool DisplayName; - - void readGeorges (const NLMISC::CSmartPtr &form, const NLMISC::CSheetId &sheetId) + void readGeorges(const NLMISC::CSmartPtr &form, const NLMISC::CSheetId &sheetId) { const NLGEORGES::UFormElm &item=form->getRootNode(); @@ -61,51 +55,45 @@ struct TCreatureInfo f.serial(DisplayName); } - - static uint getVersion () - { + static uint getVersion () + { return 1; } void removed() { } - }; struct TEntryInfo { - string SheetName; + std::string SheetName; }; struct ExtractBotNames { private: - vector Filters; - std::map Creatures; - set GenericNames; - map SimpleNames; - set Functions; + std::vector Filters; + std::map Creatures; + std::set GenericNames; + std::map SimpleNames; + std::set Functions; private: - TCreatureInfo *getCreature(const std::string &sheetName); - ucstring makeGroupName(const ucstring & translationName); - string removeAndStoreFunction(const std::string &fullName); - void addGenericName(const std::string &name, const std::string &sheetName); - void addSimpleName(const std::string &name, const std::string &sheetName); + TCreatureInfo *getCreature(const std::string &sheetName); + ucstring makeGroupName(const ucstring &translationName); + std::string removeAndStoreFunction(const std::string &fullName); + void addGenericName(const std::string &name, const std::string &sheetName); + void addSimpleName(const std::string &name, const std::string &sheetName); public: - void extractBotNamesFromPrimitives(CLigoConfig ligoConfig); - void setRequiredSettings(list filters, string level_design_path); - set getGenericNames(); - map getSimpleNames(); - string cleanupName(const std::string &name); - ucstring cleanupUcName(const ucstring &name); - void cleanSimpleNames(); - void cleanGenericNames(); - + void extractBotNamesFromPrimitives(NLLIGO::CLigoConfig ligoConfig); + void setRequiredSettings(std::list filters, std::string level_design_path); + std::set getGenericNames(); + std::map getSimpleNames(); + std::string cleanupName(const std::string &name); + ucstring cleanupUcName(const ucstring &name); + void cleanSimpleNames(); + void cleanGenericNames(); }; - } - -#endif /* EXTRACT_BOT_NAMES_H */ - +#endif /* EXTRACT_BOT_NAMES_H */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/extract_new_sheet_names.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/extract_new_sheet_names.cpp index 5d0b9b455..984f86d17 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/extract_new_sheet_names.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/extract_new_sheet_names.cpp @@ -16,139 +16,135 @@ #include "extract_new_sheet_names.h" -using namespace std; -using namespace NLMISC; -using namespace NLLIGO; -using namespace STRING_MANAGER; - -namespace TranslationManager +namespace TranslationManager { - - // *************************************************************************** /* * Specialisation of IWordListBuilder to list sheets in a directory */ - -bool CSheetWordListBuilder::buildWordList(std::vector &allWords, string workSheetFileName) +bool CSheetWordListBuilder::buildWordList(std::vector &allWords, std::string workSheetFileName) +{ + SheetExt = NLMISC::toLower(SheetExt); + // verify the directory is correct + if(!NLMISC::CFile::isDirectory(SheetPath)) { - SheetExt= toLower(SheetExt); - // verify the directory is correct - if(!CFile::isDirectory(SheetPath)) - { - nlwarning("Error: Directory '%s' not found. '%s' Aborted", SheetPath.c_str(), workSheetFileName.c_str()); - return false; - } - - // list all files. - std::vector allFiles; - allFiles.reserve(100000); - CPath::getPathContent(SheetPath, true, false, true, allFiles, NULL); - - // Keep only the extension we want, and remove "_" (parent) - allWords.clear(); - allWords.reserve(allFiles.size()); - for(uint i=0;i allFiles; + allFiles.reserve(100000); + NLMISC::CPath::getPathContent(SheetPath, true, false, true, allFiles, NULL); + // Keep only the extension we want, and remove "_" (parent) + allWords.clear(); + allWords.reserve(allFiles.size()); + for(size_t i = 0; i < allFiles.size(); i++) + { + std::string fileNameWithoutExt = NLMISC::CFile::getFilenameWithoutExtension(allFiles[i]); + std::string extension = NLMISC::toLower(NLMISC::CFile::getExtension(allFiles[i])); + + // bad extension? + if(extension!=SheetExt) + continue; + + // parent? + if(fileNameWithoutExt.empty() || fileNameWithoutExt[0] == '_') + continue; + + // ok, add + allWords.push_back(NLMISC::toLower(fileNameWithoutExt)); + } + return true; +} // *************************************************************************** /* * Specialisation of IWordListBuilder to list new region/place name from .primitive */ -bool CRegionPrimWordListBuilder::buildWordList(std::vector &allWords, string workSheetFileName) +bool CRegionPrimWordListBuilder::buildWordList(std::vector &allWords, std::string workSheetFileName) +{ + // verify the directory is correct + if(!NLMISC::CFile::isDirectory(PrimPath)) { - // verify the directory is correct - if(!CFile::isDirectory(PrimPath)) + nlwarning("Error: Directory '%s' not found. '%s' Aborted", PrimPath.c_str(), workSheetFileName.c_str()); + return false; + } + + // list all files. + std::vector allFiles; + allFiles.reserve(100000); + NLMISC::CPath::getPathContent(PrimPath, true, false, true, allFiles, NULL); + + // parse all primitive that match the filter + allWords.clear(); + allWords.reserve(100000); + // to avoid duplicate + std::set allWordSet; + for(size_t i = 0; i < allFiles.size(); i++) + { + std::string fileName = NLMISC::CFile::getFilename(allFiles[i]); + // filter don't match? + bool oneMatch= false; + for(size_t filter = 0; filter < PrimFilter.size(); filter++) { - nlwarning("Error: Directory '%s' not found. '%s' Aborted", PrimPath.c_str(), workSheetFileName.c_str()); + if(NLMISC::testWildCard(fileName, PrimFilter[filter])) + oneMatch= true; + } + if(!oneMatch) + continue; + + // ok, read the file + NLLIGO::CPrimitives PrimDoc; + NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = &PrimDoc; + if (!NLLIGO::loadXmlPrimitiveFile(PrimDoc, allFiles[i], LigoConfig)) + { + nlwarning("Error: cannot open file '%s'. '%s' Aborted", allFiles[i].c_str(), workSheetFileName.c_str()); + NLLIGO::CPrimitiveContext::instance().CurrentPrimitive = NULL; return false; } - - // list all files. - std::vector allFiles; - allFiles.reserve(100000); - CPath::getPathContent(PrimPath, true, false, true, allFiles, NULL); - - // parse all primitive that match the filter - allWords.clear(); - allWords.reserve(100000); - // to avoid duplicate - set allWordSet; - for(uint i=0;i setPlace; + NLLIGO::TPrimitiveSet placeRes; + setPlace.buildSet(PrimDoc.RootNode, predCont, placeRes); + + // for all found + for (size_t placeId = 0; placeId < placeRes.size(); ++placeId) { - nlwarning("Error: cannot open file '%s'. '%s' Aborted", allFiles[i].c_str(), workSheetFileName.c_str()); - CPrimitiveContext::instance().CurrentPrimitive = NULL; - return false; - } - CPrimitiveContext::instance().CurrentPrimitive = NULL; - - // For all primitives of interest - const char *listClass[]= {"continent", "region", "place", "stable", - "teleport_destination", "room_template"}; - const char *listProp[]= {"name", "name", "name", "name", - "place_name", "place_name"}; - const uint numListClass= sizeof(listClass)/sizeof(listClass[0]); - const uint numListProp= sizeof(listProp)/sizeof(listProp[0]); - nlctassert(numListProp==numListClass); - for(uint cid=0;cid setPlace; - TPrimitiveSet placeRes; - setPlace.buildSet(PrimDoc.RootNode, predCont, placeRes); - // for all found - for (uint placeId= 0; placeId < placeRes.size(); ++placeId) + std::string primName; + if(placeRes[placeId]->getPropertyByName(listProp[cid], primName) && !primName.empty()) { - string primName; - if(placeRes[placeId]->getPropertyByName(listProp[cid], primName) && !primName.empty()) + primName = NLMISC::toLower(primName); + // avoid duplicate + if(allWordSet.insert(primName).second) { - primName= toLower(primName); - // avoid duplicate - if(allWordSet.insert(primName).second) - { - allWords.push_back(primName); - } + allWords.push_back(primName); } } } } - - return true; } + return true; +} } \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/extract_new_sheet_names.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/extract_new_sheet_names.h index ca7295f91..01d0f1a0a 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/extract_new_sheet_names.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/extract_new_sheet_names.h @@ -30,43 +30,34 @@ #include "nel/ligo/primitive.h" #include "nel/ligo/primitive_utils.h" -using namespace std; -using namespace NLMISC; -using namespace NLLIGO; -using namespace STRING_MANAGER; - -namespace TranslationManager +namespace TranslationManager { - // *************************************************************************** /* * Interface to build the whole list of words (key id) for a specific worksheet */ struct IWordListBuilder { - virtual bool buildWordList(std::vector &allWords, string workSheetFileName) =0; - + virtual bool buildWordList(std::vector &allWords, std::string workSheetFileName) =0; }; struct CSheetWordListBuilder : public IWordListBuilder { - string SheetExt; - string SheetPath; + std::string SheetExt; + std::string SheetPath; - virtual bool buildWordList(std::vector &allWords, string workSheetFileName); + virtual bool buildWordList(std::vector &allWords, std::string workSheetFileName); }; struct CRegionPrimWordListBuilder : public IWordListBuilder { - string PrimPath; - vector PrimFilter; - NLLIGO::CLigoConfig LigoConfig; - virtual bool buildWordList(std::vector &allWords, string workSheetFileName); + std::string PrimPath; + std::vector PrimFilter; + NLLIGO::CLigoConfig LigoConfig; + virtual bool buildWordList(std::vector &allWords, std::string workSheetFileName); }; } - -#endif /* EXTRACT_NEW_SHEET_NAMES_H */ - +#endif /* EXTRACT_NEW_SHEET_NAMES_H */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/ftp_selection.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/ftp_selection.cpp index 41a8072e2..876599b61 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/ftp_selection.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/ftp_selection.cpp @@ -1,191 +1,216 @@ +// Translation Manager Plugin - OVQT Plugin +// Copyright (C) 2011 Emanuel Costea +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . #include "ftp_selection.h" #include #include + namespace TranslationManager { - CFtpSelection::CFtpSelection(QWidget *parent): QDialog(parent) - { - _ui.setupUi(this); - connect(_ui.connectButton, SIGNAL(clicked()), this, SLOT(ConnectButtonClicked())); - connect(_ui.doneButton, SIGNAL(clicked()), this, SLOT(DoneButtonClicked())); - connect(_ui.cdToParrent, SIGNAL(clicked()), this, SLOT(cdToParent())); - connect(_ui.cancelButton, SIGNAL(clicked()), this, SLOT(reject())); - - // file list - connect(_ui.fileList, SIGNAL(itemActivated(QTreeWidgetItem*,int)),this, SLOT(processItem(QTreeWidgetItem*,int))); - _ui.fileList->setEnabled(false); - _ui.fileList->setRootIsDecorated(false); - _ui.fileList->setHeaderLabels(QStringList() << tr("Name") << tr("Size") << tr("Owner") << tr("Group") << tr("Time")); - _ui.fileList->header()->setStretchLastSection(false); +CFtpSelection::CFtpSelection(QWidget *parent): QDialog(parent) +{ + _ui.setupUi(this); + connect(_ui.connectButton, SIGNAL(clicked()), this, SLOT(ConnectButtonClicked())); + connect(_ui.doneButton, SIGNAL(clicked()), this, SLOT(DoneButtonClicked())); + connect(_ui.cdToParrent, SIGNAL(clicked()), this, SLOT(cdToParent())); + connect(_ui.cancelButton, SIGNAL(clicked()), this, SLOT(reject())); - // buttons - _ui.cdToParrent->setEnabled(false); - _ui.doneButton->setEnabled(false); + // file list + connect(_ui.fileList, SIGNAL(itemActivated(QTreeWidgetItem *,int)),this, SLOT(processItem(QTreeWidgetItem *,int))); + _ui.fileList->setEnabled(false); + _ui.fileList->setRootIsDecorated(false); + _ui.fileList->setHeaderLabels(QStringList() << tr("Name") << tr("Size") << tr("Owner") << tr("Group") << tr("Time")); + _ui.fileList->header()->setStretchLastSection(false); - status = false; - } - - // Connection with the FTP Server. We retrieve the file list. - void CFtpSelection::ConnectButtonClicked() - { - conn = new QFtp(this); - connect(conn, SIGNAL(commandFinished(int,bool)), this, SLOT(FtpCommandFinished(int,bool))); - connect(conn, SIGNAL(listInfo(QUrlInfo)), this, SLOT(AddToList(QUrlInfo))); - #ifndef QT_NO_CURSOR - setCursor(Qt::WaitCursor); - #endif - QUrl url(_ui.url->text()); - if (!url.isValid() || url.scheme().toLower() != QLatin1String("ftp")) { - conn->connectToHost(_ui.url->text(), 21); - conn->login(); - } else { - conn->connectToHost(url.host(), url.port(21)); + // buttons + _ui.cdToParrent->setEnabled(false); + _ui.doneButton->setEnabled(false); - if (!url.userName().isEmpty()) - conn->login(QUrl::fromPercentEncoding(url.userName().toLatin1()), url.password()); - else - conn->login(); - if (!url.path().isEmpty()) - conn->cd(url.path()); - } - } - - // Get the user action. - void CFtpSelection::FtpCommandFinished(int, bool error) - { - #ifndef QT_NO_CURSOR - setCursor(Qt::ArrowCursor); - #endif - if (conn->currentCommand() == QFtp::ConnectToHost) - { - if (error) - { - QMessageBox::information(this, tr("FTP"), - tr("Unable to connect to the FTP server " - "at %1. Please check that the host " - "name is correct.") - .arg(_ui.url->text())); - return; - } + status = false; +} - return; - } - - if (conn->currentCommand() == QFtp::Login) - { - conn->list(); - } - - if (conn->currentCommand() == QFtp::Get) - { - if(error) - { - status = false; - file->close(); - file->remove(); - } else { - file->close(); - status = true; - } - _ui.cancelButton->setEnabled(true); - } +// Connection with the FTP Server. We retrieve the file list. +void CFtpSelection::ConnectButtonClicked() +{ + conn = new QFtp(this); + connect(conn, SIGNAL(commandFinished(int,bool)), this, SLOT(FtpCommandFinished(int,bool))); + connect(conn, SIGNAL(listInfo(QUrlInfo)), this, SLOT(AddToList(QUrlInfo))); - if (conn->currentCommand() == QFtp::List) - { - if (isDirectory.isEmpty()) { - _ui.fileList->addTopLevelItem(new QTreeWidgetItem(QStringList() << tr(""))); - _ui.fileList->setEnabled(false); - } - } - } - // Make the file list with directories and files - void CFtpSelection::AddToList(const QUrlInfo &urlInfo) - { - QTreeWidgetItem *item = new QTreeWidgetItem; - item->setText(0, urlInfo.name()); - item->setText(1, QString::number(urlInfo.size())); - item->setText(2, urlInfo.owner()); - item->setText(3, urlInfo.group()); - item->setText(4, urlInfo.lastModified().toString("MMM dd yyyy")); + setCursor(Qt::WaitCursor); - QPixmap pixmap(urlInfo.isDir() ? ":/translationManager/images/dir.png" : ":/translationManager/images/file.png"); - item->setIcon(0, pixmap); - - isDirectory[urlInfo.name()] = urlInfo.isDir(); - _ui.fileList->addTopLevelItem(item); - if (!_ui.fileList->currentItem()) { - _ui.fileList->setCurrentItem(_ui.fileList->topLevelItem(0)); - _ui.fileList->setEnabled(true); - } - } - - void CFtpSelection::processItem(QTreeWidgetItem* item, int) - { - QString name = item->text(0); - if (isDirectory.value(name)) - { - _ui.fileList->clear(); - isDirectory.clear(); - currentPath += '/'; - currentPath += name; - conn->cd(name); - conn->list(); - #ifndef QT_NO_CURSOR - setCursor(Qt::WaitCursor); - #endif - return; - } - _ui.doneButton->setEnabled(true); - } - - // Exit from a directory - void CFtpSelection::cdToParent() + QUrl url(_ui.url->text()); + if (!url.isValid() || url.scheme().toLower() != QLatin1String("ftp")) { - #ifndef QT_NO_CURSOR - setCursor(Qt::WaitCursor); - #endif - _ui.fileList->clear(); - isDirectory.clear(); - currentPath = currentPath.left(currentPath.lastIndexOf('/')); - if (currentPath.isEmpty()) { - _ui.cdToParrent->setEnabled(false); - conn->cd("/"); - } else { - conn->cd(currentPath); - } - conn->list(); + conn->connectToHost(_ui.url->text(), 21); + conn->login(); + } + else + { + conn->connectToHost(url.host(), url.port(21)); + + if (!url.userName().isEmpty()) + conn->login(QUrl::fromPercentEncoding(url.userName().toLatin1()), url.password()); + else + conn->login(); + if (!url.path().isEmpty()) + conn->cd(url.path()); + } +} + +// Get the user action. +void CFtpSelection::FtpCommandFinished(int, bool error) +{ + setCursor(Qt::ArrowCursor); + + if (conn->currentCommand() == QFtp::ConnectToHost) + { + if (error) + { + QMessageBox::information(this, tr("FTP"), + tr("Unable to connect to the FTP server " + "at %1. Please check that the host " + "name is correct.") + .arg(_ui.url->text())); + return; + } + + return; } - // Done action - void CFtpSelection::DoneButtonClicked() - { - QString fileName = _ui.fileList->currentItem()->text(0); - - if (QFile::exists(fileName)) { - QMessageBox::information(this, tr("FTP"), - tr("There already exists a file called %1 in " - "the current directory.") - .arg(fileName)); - return; - } - - file = new QFile(fileName); - #ifndef QT_NO_CURSOR - setCursor(Qt::WaitCursor); - #endif - if (!file->open(QIODevice::WriteOnly)) { - QMessageBox::information(this, tr("FTP"), - tr("Unable to save the file %1: %2.") - .arg(fileName).arg(file->errorString())); - delete file; - return; - } - _ui.cancelButton->setEnabled(false); - conn->get(_ui.fileList->currentItem()->text(0), file); - - reject(); - } - + if (conn->currentCommand() == QFtp::Login) + { + conn->list(); + } + + if (conn->currentCommand() == QFtp::Get) + { + if(error) + { + status = false; + file->close(); + file->remove(); + } + else + { + file->close(); + status = true; + } + _ui.cancelButton->setEnabled(true); + } + + if (conn->currentCommand() == QFtp::List) + { + if (isDirectory.isEmpty()) + { + _ui.fileList->addTopLevelItem(new QTreeWidgetItem(QStringList() << tr(""))); + _ui.fileList->setEnabled(false); + } + } +} +// Make the file list with directories and files +void CFtpSelection::AddToList(const QUrlInfo &urlInfo) +{ + QTreeWidgetItem *item = new QTreeWidgetItem; + item->setText(0, urlInfo.name()); + item->setText(1, QString::number(urlInfo.size())); + item->setText(2, urlInfo.owner()); + item->setText(3, urlInfo.group()); + item->setText(4, urlInfo.lastModified().toString("MMM dd yyyy")); + + QPixmap pixmap(urlInfo.isDir() ? ":/translationManager/images/dir.png" : ":/translationManager/images/file.png"); + item->setIcon(0, pixmap); + + isDirectory[urlInfo.name()] = urlInfo.isDir(); + _ui.fileList->addTopLevelItem(item); + if (!_ui.fileList->currentItem()) + { + _ui.fileList->setCurrentItem(_ui.fileList->topLevelItem(0)); + _ui.fileList->setEnabled(true); + } +} + +void CFtpSelection::processItem(QTreeWidgetItem *item, int) +{ + QString name = item->text(0); + if (isDirectory.value(name)) + { + _ui.fileList->clear(); + isDirectory.clear(); + currentPath += '/'; + currentPath += name; + conn->cd(name); + conn->list(); + + setCursor(Qt::WaitCursor); + return; + } + _ui.doneButton->setEnabled(true); +} + +// Exit from a directory +void CFtpSelection::cdToParent() +{ + setCursor(Qt::WaitCursor); + + _ui.fileList->clear(); + isDirectory.clear(); + currentPath = currentPath.left(currentPath.lastIndexOf('/')); + if (currentPath.isEmpty()) + { + _ui.cdToParrent->setEnabled(false); + conn->cd("/"); + } + else + { + conn->cd(currentPath); + } + conn->list(); +} + +// Done action +void CFtpSelection::DoneButtonClicked() +{ + QString fileName = _ui.fileList->currentItem()->text(0); + + if (QFile::exists(fileName)) + { + QMessageBox::information(this, tr("FTP"), + tr("There already exists a file called %1 in " + "the current directory.") + .arg(fileName)); + return; + } + + file = new QFile(fileName); + + setCursor(Qt::WaitCursor); + + if (!file->open(QIODevice::WriteOnly)) + { + QMessageBox::information(this, tr("FTP"), + tr("Unable to save the file %1: %2.") + .arg(fileName).arg(file->errorString())); + delete file; + return; + } + _ui.cancelButton->setEnabled(false); + conn->get(_ui.fileList->currentItem()->text(0), file); + + reject(); +} + } diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/ftp_selection.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/ftp_selection.h index 47dcfdb57..9f8af85dd 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/ftp_selection.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/ftp_selection.h @@ -1,4 +1,4 @@ -/* +/* * File: ftp_selection.h * Author: cemycc * @@ -8,6 +8,8 @@ #ifndef FTP_SELECTION_H #define FTP_SELECTION_H +#include "ui_ftp_selection.h" + #include #include #include @@ -16,34 +18,33 @@ #include #include -#include "ui_ftp_selection.h" +namespace TranslationManager +{ -using namespace std; +class CFtpSelection : public QDialog +{ + Q_OBJECT -namespace TranslationManager { - - class CFtpSelection : public QDialog - { - Q_OBJECT - private: - Ui::FtpSelectionDialog _ui; - QFtp *conn; - QHash isDirectory; - QString currentPath; - private Q_SLOTS: - void cdToParent(); - void processItem(QTreeWidgetItem*,int); - void ConnectButtonClicked(); - void DoneButtonClicked(); - void FtpCommandFinished(int, bool error); - void AddToList(const QUrlInfo &urlInfo); - public: - bool status; - QFile *file; - CFtpSelection(QWidget* parent = 0); - ~CFtpSelection() {} - }; +public: + CFtpSelection(QWidget *parent = 0); + ~CFtpSelection() {} + bool status; + QFile *file; + +private Q_SLOTS: + void cdToParent(); + void processItem(QTreeWidgetItem *,int); + void ConnectButtonClicked(); + void DoneButtonClicked(); + void FtpCommandFinished(int, bool error); + void AddToList(const QUrlInfo &urlInfo); + +private: + Ui::FtpSelectionDialog _ui; + QFtp *conn; + QHash isDirectory; + QString currentPath; +}; } -#endif /* FTP_SELECTION_H */ - +#endif /* FTP_SELECTION_H */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/source_selection.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/source_selection.cpp index 3015b447d..518906db0 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/source_selection.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/source_selection.cpp @@ -1,39 +1,54 @@ - -#include +// Translation Manager Plugin - OVQT Plugin +// Copyright (C) 2010 Winch Gate Property Limited +// Copyright (C) 2011 Emanuel Costea +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . #include "source_selection.h" +#include + namespace TranslationManager { - CSourceDialog::CSourceDialog(QWidget *parent): QDialog(parent) { _ui.setupUi(this); - // Set signal and slot for "OK Button" + connect(_ui.ok_button, SIGNAL(clicked()), this, SLOT(OkButtonClicked())); - // Set signal and slot for "Cancel Button" - connect(_ui.cancel_button, SIGNAL(clicked()), this, SLOT(reject())); - _ui.sourceSelectionListWidget->setSortingEnabled(false); + connect(_ui.cancel_button, SIGNAL(clicked()), this, SLOT(reject())); + + _ui.sourceSelectionListWidget->setSortingEnabled(false); connect(_ui.sourceSelectionListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem *)), - this, SLOT(itemDoubleClicked(QListWidgetItem *))); + this, SLOT(itemDoubleClicked(QListWidgetItem *))); } // Insert options in the source dialog. Options like: from FTP Server, from Local directory etc. -void CSourceDialog::setSourceOptions(map options) +void CSourceDialog::setSourceOptions(std::map &options) { - map::iterator it; - - for(it = options.begin(); it != options.end(); ++it) - { - _ui.sourceSelectionListWidget->addItem((*it).first); - } + std::map::iterator it; + + for(it = options.begin(); it != options.end(); ++it) + { + _ui.sourceSelectionListWidget->addItem((*it).first); + } } void CSourceDialog::OkButtonClicked() { - selected_item = _ui.sourceSelectionListWidget->currentItem(); - accept(); + selected_item = _ui.sourceSelectionListWidget->currentItem(); + accept(); } void CSourceDialog::itemDoubleClicked(QListWidgetItem *item) @@ -42,4 +57,4 @@ void CSourceDialog::itemDoubleClicked(QListWidgetItem *item) accept(); } -} +} \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/source_selection.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/source_selection.h index d32bfcb02..7b6fc2cb9 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/source_selection.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/source_selection.h @@ -1,16 +1,30 @@ - +// Translation Manager Plugin - OVQT Plugin +// Copyright (C) 2011 Emanuel Costea +// +// 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 . #ifndef SOURCE_SELECTION_H #define SOURCE_SELECTION_H +#include "ui_source_selection.h" + #include #include #include #include -#include "ui_source_selection.h" -#include -using namespace std; +#include namespace TranslationManager { @@ -18,16 +32,19 @@ namespace TranslationManager class CSourceDialog : public QDialog { Q_OBJECT -private: - Ui::SourceSelectionDialog _ui; + +public: + CSourceDialog(QWidget *parent = 0); + ~CSourceDialog() {} + void setSourceOptions(std::map &options); + QListWidgetItem *selected_item; + private Q_SLOTS: void OkButtonClicked(); void itemDoubleClicked(QListWidgetItem *item); -public: - CSourceDialog(QWidget *parent = 0); - ~CSourceDialog(){} - void setSourceOptions(map options); - QListWidgetItem *selected_item; + +private: + Ui::SourceSelectionDialog _ui; }; } diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_constants.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_constants.h index dcb91676b..d72a2b223 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_constants.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_constants.h @@ -1,29 +1,38 @@ -/* - * File: translation_manager_constants.h - * Author: cemycc - * - * Created on July 5, 2011, 9:15 PM - */ +// Translation Manager Plugin - OVQT Plugin +// Copyright (C) 2011 Emanuel Costea +// +// 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 . #ifndef TRANSLATION_MANAGER_CONSTANTS_H #define TRANSLATION_MANAGER_CONSTANTS_H namespace TranslationManager { - namespace Constants - { - const int ED_SHEET = 1; - const int ED_PHRASE = 2; +namespace Constants +{ +const int ED_SHEET = 1; +const int ED_PHRASE = 2; - const char * const WK_BOTNAMES = "bot_names_wk.txt"; - const char * const WK_ITEM = "item_words_wk.txt"; - const char * const WK_CREATURE = "creature_words_wk.txt"; - const char * const WK_SBRICK = "sbrick_words_wk.txt"; - const char * const WK_SPHRASE = "sphrase_words_wk.txt"; - const char * const WK_PLACE = "place_words_wk.txt"; - const char * const WK_CONTINENT = "place_words_wk.txt"; - const char * const WK_STABLE = "place_words_wk.txt"; - } +const char *const WK_BOTNAMES = "bot_names_wk.txt"; +const char *const WK_ITEM = "item_words_wk.txt"; +const char *const WK_CREATURE = "creature_words_wk.txt"; +const char *const WK_SBRICK = "sbrick_words_wk.txt"; +const char *const WK_SPHRASE = "sphrase_words_wk.txt"; +const char *const WK_PLACE = "place_words_wk.txt"; +const char *const WK_CONTINENT = "place_words_wk.txt"; +const char *const WK_STABLE = "place_words_wk.txt"; +} } #endif /* TRANSLATION_MANAGER_CONSTANTS_H */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_editor.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_editor.h index bc46769c1..fd53ba863 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_editor.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_editor.h @@ -1,5 +1,4 @@ // Translation Manager Plugin - OVQT Plugin -// Copyright (C) 2010 Winch Gate Property Limited // Copyright (C) 2011 Emanuel Costea // // This program is free software: you can redistribute it and/or modify @@ -25,31 +24,30 @@ #include #include -namespace TranslationManager { - -class CEditor : public QMdiSubWindow { -Q_OBJECT -protected: - QUndoStack* current_stack; - QString current_file; - int editor_type; -public: - CEditor(QMdiArea* parent) : QMdiSubWindow(parent) {} - CEditor() : QMdiSubWindow() {} - virtual void open(QString filename) =0; - virtual void save() =0; - virtual void saveAs(QString filename) =0; - virtual void activateWindow() =0; +namespace TranslationManager +{ + +class CEditor : public QMdiSubWindow +{ + Q_OBJECT + public: + CEditor(QMdiArea *parent) : QMdiSubWindow(parent) {} + CEditor() : QMdiSubWindow() {} + virtual void open(QString filename) =0; + virtual void save() =0; + virtual void saveAs(QString filename) =0; + virtual void activateWindow() =0; + int eType() { return editor_type; } - QString subWindowFilePath() - { - return current_file; - } - void setUndoStack(QUndoStack* stack) + QString subWindowFilePath() + { + return current_file; + } + void setUndoStack(QUndoStack *stack) { current_stack = stack; } @@ -58,14 +56,16 @@ public: QFileInfo *file = new QFileInfo(filename); current_file = file->canonicalFilePath(); setWindowModified(false); - setWindowTitle(file->fileName() + "[*]"); + setWindowTitle(file->fileName() + "[*]"); setWindowFilePath(current_file); } +protected: + QUndoStack *current_stack; + QString current_file; + int editor_type; }; } - -#endif /* TRANSLATION_MANAGER_EDITOR_H */ - +#endif /* TRANSLATION_MANAGER_EDITOR_H */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_main_window.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_main_window.cpp index 23509bd20..46a0dd99f 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_main_window.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_main_window.cpp @@ -1,4 +1,3 @@ - // Translation Manager Plugin - OVQT Plugin // Copyright (C) 2010 Winch Gate Property Limited // Copyright (C) 2011 Emanuel Costea @@ -16,32 +15,31 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -// Project system includes +// Plugin includes +#include "translation_manager_main_window.h" +#include "translation_manager_constants.h" +#include "ftp_selection.h" + +// Core includes #include "../core/icore.h" #include "../core/core_constants.h" #include "../core/menu_manager.h" #include "../../extension_system/iplugin_spec.h" // Qt includes -#include -#include +#include +#include #include -#include #include +#include +#include +#include #include #include #include #include -#include #include -#include -#include #include -// Plugin includes -#include "translation_manager_main_window.h" -#include "translation_manager_constants.h" -#include "ftp_selection.h" - namespace TranslationManager { @@ -49,122 +47,126 @@ namespace TranslationManager CMainWindow::CMainWindow(QWidget *parent) : QMainWindow(parent) { - _ui.setupUi(this); - - _ui.mdiArea->closeAllSubWindows(); - windowMapper = new QSignalMapper(this); - connect(windowMapper, SIGNAL(mapped(QWidget*)), this, SLOT(setActiveSubWindow(QWidget*))); - - initialize_settings["georges"] = false; - initialize_settings["ligo"] = false; + _ui.setupUi(this); - connect(Core::ICore::instance(), SIGNAL(changeSettings()), this, SLOT(readSettings())); - readSettings(); - createToolbar(); - m_undoStack = new QUndoStack(this); + _ui.mdiArea->closeAllSubWindows(); + windowMapper = new QSignalMapper(this); + connect(windowMapper, SIGNAL(mapped(QWidget *)), this, SLOT(setActiveSubWindow(QWidget *))); + + initialize_settings["georges"] = false; + initialize_settings["ligo"] = false; + + connect(Core::ICore::instance(), SIGNAL(changeSettings()), this, SLOT(readSettings())); + readSettings(); + createToolbar(); + m_undoStack = new QUndoStack(this); } // Functions that will insert the plugin buttons void CMainWindow::createToolbar() -{ - // File menu - openAct = new QAction(QIcon(Core::Constants::ICON_OPEN), "&Open file(s)...", this); - _ui.toolBar->addAction(openAct); - connect(openAct, SIGNAL(triggered()), this, SLOT(open())); - saveAct = new QAction(QIcon(Core::Constants::ICON_SAVE), "&Save...", this); - _ui.toolBar->addAction(saveAct); - connect(saveAct, SIGNAL(triggered()), this, SLOT(save())); - saveAsAct = new QAction(QIcon(Core::Constants::ICON_SAVE_AS), "&Save as...", this); - _ui.toolBar->addAction(saveAsAct); - connect(saveAsAct, SIGNAL(triggered()), this, SLOT(saveAs())); +{ + // File menu + openAct = new QAction(QIcon(Core::Constants::ICON_OPEN), "&Open file(s)...", this); + _ui.toolBar->addAction(openAct); + connect(openAct, SIGNAL(triggered()), this, SLOT(open())); + saveAct = new QAction(QIcon(Core::Constants::ICON_SAVE), "&Save...", this); + _ui.toolBar->addAction(saveAct); + connect(saveAct, SIGNAL(triggered()), this, SLOT(save())); + saveAsAct = new QAction(QIcon(Core::Constants::ICON_SAVE_AS), "&Save as...", this); + _ui.toolBar->addAction(saveAsAct); + connect(saveAsAct, SIGNAL(triggered()), this, SLOT(saveAs())); - // Tools menu - QMenu *wordsExtractionMenu = new QMenu("&Words extraction..."); - wordsExtractionMenu->setIcon(QIcon(Core::Constants::ICON_SETTINGS)); - _ui.toolBar->addAction(wordsExtractionMenu->menuAction()); - // extract bot names - QAction *extractBotNamesAct = wordsExtractionMenu->addAction("&Extract bot names..."); - extractBotNamesAct->setStatusTip(tr("Extract bot names from primitives.")); - connect(extractBotNamesAct, SIGNAL(triggered()), this, SLOT(extractBotNames())); - // Words extraction - // ----------------------------- - // signal mapper for extraction words - QSignalMapper *wordsExtractionMapper = new QSignalMapper(this); - connect(wordsExtractionMapper, SIGNAL(mapped(QString)), this, SLOT(extractWords(QString))); - // extract item words - QAction *extractItemWordsAct = wordsExtractionMenu->addAction("&Extract item words..."); - extractItemWordsAct->setStatusTip(tr("Extract item words")); - connect(extractItemWordsAct, SIGNAL(triggered()), wordsExtractionMapper, SLOT(map())); - wordsExtractionMapper->setMapping(extractItemWordsAct, QString(Constants::WK_ITEM)); - // extract creature words - QAction *extractCreatureWordsAct = wordsExtractionMenu->addAction("&Extract creature words..."); - extractCreatureWordsAct->setStatusTip(tr("Extract creature words")); - connect(extractCreatureWordsAct, SIGNAL(triggered()), wordsExtractionMapper, SLOT(map())); - wordsExtractionMapper->setMapping(extractCreatureWordsAct, QString(Constants::WK_CREATURE)); - // extract sbrick words - QAction *extractSbrickWordsAct = wordsExtractionMenu->addAction("&Extract sbrick words..."); - extractSbrickWordsAct->setStatusTip(tr("Extract sbrick words")); - connect(extractSbrickWordsAct, SIGNAL(triggered()), wordsExtractionMapper, SLOT(map())); - wordsExtractionMapper->setMapping(extractSbrickWordsAct, QString(Constants::WK_SBRICK)); - // extract sphrase words - QAction *extractSphraseWordsAct = wordsExtractionMenu->addAction("&Extract sphrase words..."); - extractSphraseWordsAct->setStatusTip(tr("Extract sphrase words")); - connect(extractSphraseWordsAct, SIGNAL(triggered()), wordsExtractionMapper, SLOT(map())); - wordsExtractionMapper->setMapping(extractSphraseWordsAct, QString(Constants::WK_SPHRASE)); - // extract place and region names - QAction *extractPlaceNamesAct = wordsExtractionMenu->addAction("&Extract place names..."); - extractPlaceNamesAct->setStatusTip(tr("Extract place names from primitives")); - connect(extractPlaceNamesAct, SIGNAL(triggered()), wordsExtractionMapper, SLOT(map())); - wordsExtractionMapper->setMapping(extractPlaceNamesAct, QString(Constants::WK_PLACE)); - // Merge options - // ----------------------------- - QAction *mergeSingleFileAct = wordsExtractionMenu->addAction("&Merge worksheet file..."); - mergeSingleFileAct->setStatusTip(tr("Merge worksheet file from local or remote directory")); - connect(mergeSingleFileAct, SIGNAL(triggered()), this, SLOT(mergeSingleFile())); - // Windows menu - Core::ICore *core = Core::ICore::instance(); - Core::MenuManager *menuManager = core->menuManager(); - windowMenu = menuManager->menuBar()->addMenu("Window"); - updateWindowsList(); - connect(windowMenu, SIGNAL(aboutToShow()), this, SLOT(updateWindowsList())); + // Tools menu + QMenu *wordsExtractionMenu = new QMenu("&Words extraction..."); + wordsExtractionMenu->setIcon(QIcon(Core::Constants::ICON_SETTINGS)); + _ui.toolBar->addAction(wordsExtractionMenu->menuAction()); - // Undo, Redo actions - // ----------------------------- - QAction* undoAction = menuManager->action(Core::Constants::UNDO); - if (undoAction != 0) - _ui.toolBar->addAction(undoAction); - - QAction* redoAction = menuManager->action(Core::Constants::REDO); - if (redoAction != 0) - _ui.toolBar->addAction(redoAction); + // extract bot names + QAction *extractBotNamesAct = wordsExtractionMenu->addAction("&Extract bot names..."); + extractBotNamesAct->setStatusTip(tr("Extract bot names from primitives.")); + connect(extractBotNamesAct, SIGNAL(triggered()), this, SLOT(extractBotNames())); + + // Words extraction + QSignalMapper *wordsExtractionMapper = new QSignalMapper(this); + connect(wordsExtractionMapper, SIGNAL(mapped(QString)), this, SLOT(extractWords(QString))); + // extract item words + + QAction *extractItemWordsAct = wordsExtractionMenu->addAction("&Extract item words..."); + extractItemWordsAct->setStatusTip(tr("Extract item words")); + connect(extractItemWordsAct, SIGNAL(triggered()), wordsExtractionMapper, SLOT(map())); + wordsExtractionMapper->setMapping(extractItemWordsAct, QString(Constants::WK_ITEM)); + + // extract creature words + QAction *extractCreatureWordsAct = wordsExtractionMenu->addAction(tr("&Extract creature words...")); + extractCreatureWordsAct->setStatusTip(tr("Extract creature words")); + connect(extractCreatureWordsAct, SIGNAL(triggered()), wordsExtractionMapper, SLOT(map())); + wordsExtractionMapper->setMapping(extractCreatureWordsAct, QString(Constants::WK_CREATURE)); + + // extract sbrick words + QAction *extractSbrickWordsAct = wordsExtractionMenu->addAction("&Extract sbrick words..."); + extractSbrickWordsAct->setStatusTip(tr("Extract sbrick words")); + connect(extractSbrickWordsAct, SIGNAL(triggered()), wordsExtractionMapper, SLOT(map())); + wordsExtractionMapper->setMapping(extractSbrickWordsAct, QString(Constants::WK_SBRICK)); + + // extract sphrase words + QAction *extractSphraseWordsAct = wordsExtractionMenu->addAction("&Extract sphrase words..."); + extractSphraseWordsAct->setStatusTip(tr("Extract sphrase words")); + connect(extractSphraseWordsAct, SIGNAL(triggered()), wordsExtractionMapper, SLOT(map())); + wordsExtractionMapper->setMapping(extractSphraseWordsAct, QString(Constants::WK_SPHRASE)); + + // extract place and region names + QAction *extractPlaceNamesAct = wordsExtractionMenu->addAction("&Extract place names..."); + extractPlaceNamesAct->setStatusTip(tr("Extract place names from primitives")); + connect(extractPlaceNamesAct, SIGNAL(triggered()), wordsExtractionMapper, SLOT(map())); + wordsExtractionMapper->setMapping(extractPlaceNamesAct, QString(Constants::WK_PLACE)); + + // Merge options + QAction *mergeSingleFileAct = wordsExtractionMenu->addAction("&Merge worksheet file..."); + mergeSingleFileAct->setStatusTip(tr("Merge worksheet file from local or remote directory")); + connect(mergeSingleFileAct, SIGNAL(triggered()), this, SLOT(mergeSingleFile())); + + // Windows menu + Core::ICore *core = Core::ICore::instance(); + Core::MenuManager *menuManager = core->menuManager(); + windowMenu = menuManager->menuBar()->addMenu("Window"); + updateWindowsList(); + connect(windowMenu, SIGNAL(aboutToShow()), this, SLOT(updateWindowsList())); + + // Undo, Redo actions + QAction *undoAction = menuManager->action(Core::Constants::UNDO); + if (undoAction != 0) + _ui.toolBar->addAction(undoAction); + + QAction *redoAction = menuManager->action(Core::Constants::REDO); + if (redoAction != 0) + _ui.toolBar->addAction(redoAction); } // Update the toolbar if the editor is worksheet void CMainWindow::updateToolbar(QMdiSubWindow *window) { - if(_ui.mdiArea->subWindowList().size() > 0) - if(QString(window->widget()->metaObject()->className()) == "QTableWidget") // Sheet Editor - { - QAction *insertRowAct = new QAction(tr("Insert new row"), this); - connect(insertRowAct, SIGNAL(triggered()), window, SLOT(insertRow())); - windowMenu->addAction(insertRowAct); - QAction *deleteRowAct = new QAction(tr("Delete row"), this); - connect(deleteRowAct, SIGNAL(triggered()), window, SLOT(deleteRow())); - windowMenu->addAction(deleteRowAct); - - } + if(_ui.mdiArea->subWindowList().size() > 0) + if(QString(window->widget()->metaObject()->className()) == "QTableWidget") // Sheet Editor + { + QAction *insertRowAct = new QAction(tr("Insert new row"), this); + connect(insertRowAct, SIGNAL(triggered()), window, SLOT(insertRow())); + windowMenu->addAction(insertRowAct); + QAction *deleteRowAct = new QAction(tr("Delete row"), this); + connect(deleteRowAct, SIGNAL(triggered()), window, SLOT(deleteRow())); + windowMenu->addAction(deleteRowAct); + } } // Set the active subwindow -void CMainWindow::setActiveSubWindow(QWidget* window) +void CMainWindow::setActiveSubWindow(QWidget *window) { - if (!window) - { - return; - } - QMdiSubWindow *cwindow = qobject_cast(window); - _ui.mdiArea->setActiveSubWindow(cwindow); + if (!window) + return; + + QMdiSubWindow *mdiWindow = qobject_cast(window); + if (mdiWindow != 0) + _ui.mdiArea->setActiveSubWindow(mdiWindow); } // Functions for updating the windows list @@ -172,148 +174,139 @@ void CMainWindow::updateWindowsList() { if(_ui.mdiArea->activeSubWindow()) { - windowMenu->clear(); - QMdiSubWindow *current_window = _ui.mdiArea->activeSubWindow(); - QList subWindows = _ui.mdiArea->subWindowList(); - - updateToolbar(current_window); - - for(int i = 0; i < subWindows.size(); ++i) - { - QString window_file = QFileInfo(subWindows.at(i)->windowFilePath()).fileName(); - QString action_text; - if (i < 9) { - action_text = QString("&%1 %2").arg(i + 1).arg(window_file); - } else { - action_text = QString("%1 %2").arg(i + 1).arg(window_file); - } - QAction *action = new QAction(action_text, this); - action->setCheckable(true); - action->setChecked(subWindows.at(i) == current_window); - connect(action, SIGNAL(triggered()), windowMapper, SLOT(map())); - windowMenu->addAction(action); - windowMapper->setMapping(action, subWindows.at(i)); - } - } else { - windowMenu->clear(); - } + windowMenu->clear(); + QMdiSubWindow *current_window = _ui.mdiArea->activeSubWindow(); + QList subWindows = _ui.mdiArea->subWindowList(); + + updateToolbar(current_window); + + for(int i = 0; i < subWindows.size(); ++i) + { + QString window_file = QFileInfo(subWindows.at(i)->windowFilePath()).fileName(); + QString action_text; + if (i < 9) + { + action_text = QString("&%1 %2").arg(i + 1).arg(window_file); + } + else + { + action_text = QString("%1 %2").arg(i + 1).arg(window_file); + } + QAction *action = new QAction(action_text, this); + action->setCheckable(true); + action->setChecked(subWindows.at(i) == current_window); + connect(action, SIGNAL(triggered()), windowMapper, SLOT(map())); + windowMenu->addAction(action); + windowMapper->setMapping(action, subWindows.at(i)); + } + } + else + { + windowMenu->clear(); + } } // Open signal void CMainWindow::open() { - QSettings *settings = Core::ICore::instance()->settings(); - settings->beginGroup("translationmanager"); - QString lastOpenLocation = settings->value("lastOpenLocation").toString(); - QString file_name = QFileDialog::getOpenFileName(this, tr("Open translation file"), lastOpenLocation, tr("Translation files (*txt)")); - QFileInfo* file_info = new QFileInfo(file_name); - settings->setValue("lastOpenLocation", file_info->absolutePath()); - settings->endGroup(); + QSettings *settings = Core::ICore::instance()->settings(); + settings->beginGroup("translationmanager"); + QString lastOpenLocation = settings->value("lastOpenLocation").toString(); + QString file_name = QFileDialog::getOpenFileName(this, tr("Open translation file"), lastOpenLocation, tr("Translation files (*txt)")); + QFileInfo *file_info = new QFileInfo(file_name); + settings->setValue("lastOpenLocation", file_info->absolutePath()); + settings->endGroup(); - if(!file_name.isEmpty()) - { - CEditor *editor = getEditorByWindowFilePath(file_name); - if(editor != NULL) - { - editor->activateWindow(); - return; - } - #ifndef QT_NO_CURSOR - QApplication::setOverrideCursor(Qt::WaitCursor); - #endif - // sheet editor - if(isWorksheetEditor(file_name)) - { - CEditorWorksheet *new_window = new CEditorWorksheet(_ui.mdiArea); - new_window->setUndoStack(m_undoStack); - new_window->open(file_name); - new_window->activateWindow(); - } - // phrase editor - if(isPhraseEditor(file_name)) - { - CEditorPhrase *new_window = new CEditorPhrase(_ui.mdiArea); - new_window->setUndoStack(m_undoStack); - new_window->open(file_name); - new_window->activateWindow(); - } - #ifndef QT_NO_CURSOR - QApplication::restoreOverrideCursor(); - #endif - } - + if(!file_name.isEmpty()) + { + CEditor *editor = getEditorByWindowFilePath(file_name); + if(editor != NULL) + { + editor->activateWindow(); + return; + } + QApplication::setOverrideCursor(Qt::WaitCursor); + + // sheet editor + if(isWorksheetEditor(file_name)) + { + CEditorWorksheet *new_window = new CEditorWorksheet(_ui.mdiArea); + new_window->setUndoStack(m_undoStack); + new_window->open(file_name); + new_window->activateWindow(); + } + // phrase editor + if(isPhraseEditor(file_name)) + { + CEditorPhrase *new_window = new CEditorPhrase(_ui.mdiArea); + new_window->setUndoStack(m_undoStack); + new_window->open(file_name); + new_window->activateWindow(); + } + QApplication::restoreOverrideCursor(); + } } // Open a work file. You can set the directory for work file in the settings dialog void CMainWindow::openWorkFile(QString file) { - QFileInfo* file_path = new QFileInfo(QString("%1/%2").arg(work_path).arg(file)); - if(file_path->exists()) - { - if(isWorksheetEditor(file_path->filePath())) - { - CEditorWorksheet *new_window = new CEditorWorksheet(_ui.mdiArea); - new_window->open(file_path->filePath()); - new_window->activateWindow(); - } - } else { - QErrorMessage error; - error.showMessage(QString("The %1 file don't exists.").arg(file_path->fileName())); - error.exec(); - } - + QFileInfo *file_path = new QFileInfo(QString("%1/%2").arg(work_path).arg(file)); + if(file_path->exists()) + { + if(isWorksheetEditor(file_path->filePath())) + { + CEditorWorksheet *new_window = new CEditorWorksheet(_ui.mdiArea); + new_window->open(file_path->filePath()); + new_window->activateWindow(); + } + } + else + { + QErrorMessage error; + error.showMessage(tr("The %1 file don't exists.").arg(file_path->fileName())); + error.exec(); + } } -// Save signal void CMainWindow::save() { - if(_ui.mdiArea->subWindowList().size() > 0) - { - CEditor* current_window = qobject_cast(_ui.mdiArea->currentSubWindow()); - #ifndef QT_NO_CURSOR - QApplication::setOverrideCursor(Qt::WaitCursor); - #endif + if(_ui.mdiArea->subWindowList().size() > 0) + { + CEditor *current_window = qobject_cast(_ui.mdiArea->currentSubWindow()); + QApplication::setOverrideCursor(Qt::WaitCursor); current_window->save(); - #ifndef QT_NO_CURSOR - QApplication::restoreOverrideCursor(); - #endif - } + QApplication::restoreOverrideCursor(); + } } -// Save as signal void CMainWindow::saveAs() { - QString file_name; - if (_ui.mdiArea->isActiveWindow()) - { - file_name = QFileDialog::getSaveFileName(this); - } - - if (!file_name.isEmpty()) - { - CEditor* current_window = qobject_cast(_ui.mdiArea->currentSubWindow()); - #ifndef QT_NO_CURSOR - QApplication::setOverrideCursor(Qt::WaitCursor); - #endif - current_window->saveAs(file_name); - #ifndef QT_NO_CURSOR - QApplication::restoreOverrideCursor(); - #endif - } + QString file_name; + if (_ui.mdiArea->isActiveWindow()) + { + file_name = QFileDialog::getSaveFileName(this); + } + if (!file_name.isEmpty()) + { + CEditor *current_window = qobject_cast(_ui.mdiArea->currentSubWindow()); + QApplication::setOverrideCursor(Qt::WaitCursor); + current_window->saveAs(file_name); + QApplication::restoreOverrideCursor(); + } } // This function is needed by extraction. void CMainWindow::initializeSettings(bool georges = false) -{ - if(georges == true && initialize_settings["georges"] == false) - { - CPath::addSearchPath(level_design_path.toStdString() + "/DFN", true, false); - CPath::addSearchPath(level_design_path.toStdString() + "/Game_elem/Creature", true, false); - initialize_settings["georges"] = true; - } +{ + if(georges == true && initialize_settings["georges"] == false) + { + NLMISC::CPath::addSearchPath(level_design_path.toStdString() + "/DFN", true, false); + NLMISC::CPath::addSearchPath(level_design_path.toStdString() + "/Game_elem/Creature", true, false); + initialize_settings["georges"] = true; + } - if(initialize_settings["ligo"] == false) - { + if(initialize_settings["ligo"] == false) + { try { // Search path of file world_editor_classes.xml @@ -328,252 +321,263 @@ void CMainWindow::initializeSettings(bool georges = false) { nlerror("Can't found path to world_editor_classes.xml"); } - } - + } } // Extracting words void CMainWindow::extractWords(QString typeq) { - if(verifySettings() == true) - { - CEditorWorksheet* editor_window = getEditorByWorksheetType(typeq); + if(verifySettings() == true) + { + CEditorWorksheet *editor_window = getEditorByWorksheetType(typeq); + if(editor_window != NULL) + { + editor_window->activateWindow(); + QString file_path = editor_window->windowFilePath(); + } + else + { + openWorkFile(typeq); + editor_window = getEditorByWorksheetType(typeq); if(editor_window != NULL) { - editor_window->activateWindow(); - QString file_path = editor_window->windowFilePath(); - } else { - openWorkFile(typeq); - editor_window = getEditorByWorksheetType(typeq); - if(editor_window != NULL) - { - editor_window->activateWindow(); - QString file_path = editor_window->windowFilePath(); - } else return; + editor_window->activateWindow(); + QString file_path = editor_window->windowFilePath(); } + else return; + } - QString column_name; - // Sheet extraction - CSheetWordListBuilder builderS; - // Primitives extraction - CRegionPrimWordListBuilder builderP; - bool isSheet = false; - if(typeq.toAscii() == Constants::WK_ITEM) { - column_name = "item ID"; - builderS.SheetExt = "sitem"; - builderS.SheetPath = level_design_path.append("/game_element/sitem").toStdString(); - isSheet = true; - } else if(typeq.toAscii() == Constants::WK_CREATURE) { - column_name = "creature ID"; - builderS.SheetExt = "creature"; - builderS.SheetPath = level_design_path.append("/Game_elem/Creature/fauna").toStdString(); - isSheet = true; - } else if(typeq.toAscii() == Constants::WK_SBRICK) { - column_name = "sbrick ID"; - builderS.SheetExt = "sbrick"; - builderS.SheetPath = level_design_path.append("/game_element/sbrick").toStdString(); - isSheet = true; - } else if(typeq.toAscii() == Constants::WK_SPHRASE) { - column_name = "sphrase ID"; - builderS.SheetExt = "sphrase"; - builderS.SheetPath = level_design_path.append("/game_element/sphrase").toStdString(); - isSheet = true; - } else if(typeq.toAscii() == Constants::WK_PLACE) { - column_name = "placeId"; - builderP.PrimPath = primitives_path.toStdString(); - builderP.PrimFilter.push_back("region_*.primitive"); - builderP.PrimFilter.push_back("indoors_*.primitive"); - isSheet = false; - } - #ifndef QT_NO_CURSOR - QApplication::setOverrideCursor(Qt::WaitCursor); - #endif - if(isSheet) - { - editor_window->extractWords(editor_window->windowFilePath(), column_name, builderS); - } else { - initializeSettings(false); - editor_window->extractWords(editor_window->windowFilePath(), column_name, builderP); - } - #ifndef QT_NO_CURSOR - QApplication::restoreOverrideCursor(); - #endif - } - + QString column_name; + // Sheet extraction + CSheetWordListBuilder builderS; + // Primitives extraction + CRegionPrimWordListBuilder builderP; + bool isSheet = false; + if(typeq.toAscii() == Constants::WK_ITEM) + { + column_name = "item ID"; + builderS.SheetExt = "sitem"; + builderS.SheetPath = level_design_path.append("/game_element/sitem").toStdString(); + isSheet = true; + } + else if(typeq.toAscii() == Constants::WK_CREATURE) + { + column_name = "creature ID"; + builderS.SheetExt = "creature"; + builderS.SheetPath = level_design_path.append("/Game_elem/Creature/fauna").toStdString(); + isSheet = true; + } + else if(typeq.toAscii() == Constants::WK_SBRICK) + { + column_name = "sbrick ID"; + builderS.SheetExt = "sbrick"; + builderS.SheetPath = level_design_path.append("/game_element/sbrick").toStdString(); + isSheet = true; + } + else if(typeq.toAscii() == Constants::WK_SPHRASE) + { + column_name = "sphrase ID"; + builderS.SheetExt = "sphrase"; + builderS.SheetPath = level_design_path.append("/game_element/sphrase").toStdString(); + isSheet = true; + } + else if(typeq.toAscii() == Constants::WK_PLACE) + { + column_name = "placeId"; + builderP.PrimPath = primitives_path.toStdString(); + builderP.PrimFilter.push_back("region_*.primitive"); + builderP.PrimFilter.push_back("indoors_*.primitive"); + isSheet = false; + } + QApplication::setOverrideCursor(Qt::WaitCursor); + if(isSheet) + { + editor_window->extractWords(editor_window->windowFilePath(), column_name, builderS); + } + else + { + initializeSettings(false); + editor_window->extractWords(editor_window->windowFilePath(), column_name, builderP); + } + QApplication::restoreOverrideCursor(); + } } // Extract bot names from primitives void CMainWindow::extractBotNames() { - if(verifySettings() == true) - { - CEditorWorksheet* editor_window = getEditorByWorksheetType(NULL); + if(verifySettings() == true) + { + CEditorWorksheet *editor_window = getEditorByWorksheetType(NULL); + if(editor_window != NULL) + { + editor_window->activateWindow(); + QString file_path = editor_window->windowFilePath(); + } + else + { + openWorkFile(Constants::WK_BOTNAMES); + editor_window = getEditorByWorksheetType(NULL); if(editor_window != NULL) { - editor_window->activateWindow(); - QString file_path = editor_window->windowFilePath(); - } else { - openWorkFile(Constants::WK_BOTNAMES); - editor_window = getEditorByWorksheetType(NULL); - if(editor_window != NULL) - { - editor_window->activateWindow(); - QString file_path = editor_window->windowFilePath(); - } else return; + editor_window->activateWindow(); + QString file_path = editor_window->windowFilePath(); } - #ifndef QT_NO_CURSOR - QApplication::setOverrideCursor(Qt::WaitCursor); - #endif - initializeSettings(true); - editor_window->extractBotNames(convertQStringList(filters), level_design_path.toStdString(), ligoConfig); - #ifndef QT_NO_CURSOR - QApplication::restoreOverrideCursor(); - #endif - } + else return; + } + + QApplication::setOverrideCursor(Qt::WaitCursor); + initializeSettings(true); + editor_window->extractBotNames(convertQStringList(filters), level_design_path.toStdString(), ligoConfig); + QApplication::restoreOverrideCursor(); + } } // Merge the content for 2 worksheet files void CMainWindow::mergeSingleFile() { - CEditor* editor_window = qobject_cast(_ui.mdiArea->currentSubWindow()); - CSourceDialog *dialog = new CSourceDialog(this); - CFtpSelection* ftp_dialog; - map methods; + CEditor *editor_window = qobject_cast(_ui.mdiArea->currentSubWindow()); + CSourceDialog *dialog = new CSourceDialog(this); + CFtpSelection *ftp_dialog; + map methods; QString file_name; - if (_ui.mdiArea->subWindowList().size() == 0) - { + if (_ui.mdiArea->subWindowList().size() == 0) + { QErrorMessage error; - error.showMessage(QString("Open a work file in editor for merge operation.")); - error.exec(); + error.showMessage(tr("Open a work file in editor for merge operation.")); + error.exec(); return; } - if(editor_window->eType() != Constants::ED_SHEET) // Sheet Editor - { + if(editor_window->eType() != Constants::ED_SHEET) // Sheet Editor + { QErrorMessage error; - error.showMessage(QString("Please open or activate the window with a sheet file.")); - error.exec(); + error.showMessage(tr("Please open or activate the window with a sheet file.")); + error.exec(); return; } - // create items - QListWidgetItem* local_item = new QListWidgetItem(); - local_item->setText("Local directory"); - methods[local_item] = 0; - QListWidgetItem* ftp_item = new QListWidgetItem(); - ftp_item->setText("From a FTP server"); - methods[ftp_item] = 1; - - dialog->setSourceOptions(methods); - dialog->show(); - dialog->exec(); + // create items + QListWidgetItem *local_item = new QListWidgetItem(); + local_item->setText("Local directory"); + methods[local_item] = 0; + QListWidgetItem *ftp_item = new QListWidgetItem(); + ftp_item->setText("From a FTP server"); + methods[ftp_item] = 1; + + dialog->setSourceOptions(methods); + dialog->show(); + dialog->exec(); // get the file for merge - if(dialog->selected_item == local_item) // Local directory - { - file_name = QFileDialog::getOpenFileName(this); - } + if(dialog->selected_item == local_item) // Local directory + { + file_name = QFileDialog::getOpenFileName(this); + } else if(dialog->selected_item == ftp_item) // Ftp directory { - CFtpSelection* ftp_dialog = new CFtpSelection(this); - ftp_dialog->show(); + CFtpSelection *ftp_dialog = new CFtpSelection(this); + ftp_dialog->show(); if(ftp_dialog->exec() && ftp_dialog->status == true) - file_name = ftp_dialog->file->fileName(); + file_name = ftp_dialog->file->fileName(); delete ftp_dialog; - } + } else - return; - + return; + // Make sure we retrieved a file name if(file_name.isEmpty()) return; - editor_window->activateWindow(); - CEditorWorksheet* current_window = qobject_cast(editor_window); - if(current_window->windowFilePath() == file_name) + editor_window->activateWindow(); + CEditorWorksheet *current_window = qobject_cast(editor_window); + if(current_window->windowFilePath() == file_name) return; - if(current_window->compareWorksheetFile(file_name)) - { - current_window->mergeWorksheetFile(file_name); - } else { - QErrorMessage error; - error.showMessage(tr("The file: %1 has different columns from the current file in editor.").arg(file_name)); - error.exec(); - } - if(dialog->selected_item == ftp_item) + if(current_window->compareWorksheetFile(file_name)) { + current_window->mergeWorksheetFile(file_name); + } + else + { + QErrorMessage error; + error.showMessage(tr("The file: %1 has different columns from the current file in editor.").arg(file_name)); + error.exec(); + } + if(dialog->selected_item == ftp_item) + { + /* + // TODO: uninit ftp_dialog????? if(!ftp_dialog->file->remove()) { QErrorMessage error; error.showMessage(tr("Please remove the file from ftp server manually. The file is located on the same directory with OVQT application.")); - error.exec(); + error.exec(); } - + */ } } // Read the settings from QSettings void CMainWindow::readSettings() { - QSettings *settings = Core::ICore::instance()->settings(); - // translation manager settings - settings->beginGroup("translationmanager"); - filters = settings->value("filters").toStringList(); - languages = settings->value("trlanguages").toStringList(); - translation_path = settings->value("translation").toString(); - work_path = settings->value("work").toString(); - settings->endGroup(); - // core settings - settings->beginGroup(Core::Constants::DATA_PATH_SECTION); - level_design_path = settings->value(Core::Constants::LEVELDESIGN_PATH).toString(); - primitives_path = QString(Core::Constants::PRIMITIVES_PATH); //TODO - settings->endGroup(); + QSettings *settings = Core::ICore::instance()->settings(); + // translation manager settings + settings->beginGroup("translationmanager"); + filters = settings->value("filters").toStringList(); + languages = settings->value("trlanguages").toStringList(); + translation_path = settings->value("translation").toString(); + work_path = settings->value("work").toString(); + settings->endGroup(); + // core settings + settings->beginGroup(Core::Constants::DATA_PATH_SECTION); + level_design_path = settings->value(Core::Constants::LEVELDESIGN_PATH).toString(); + primitives_path = QString(Core::Constants::PRIMITIVES_PATH); //TODO + settings->endGroup(); } // Verify the settings bool CMainWindow::verifySettings() { - bool count_errors = false; - - if(level_design_path.isNull() || primitives_path.isNull() || work_path.isNull()) - { - QErrorMessage error_settings; - error_settings.showMessage(tr("Please write all the paths on the settings dialog.")); - error_settings.exec(); - count_errors = true; - } - - return !count_errors; - + bool count_errors = false; + + if(level_design_path.isNull() || primitives_path.isNull() || work_path.isNull()) + { + QErrorMessage error_settings; + error_settings.showMessage(tr("Please write all the paths on the settings dialog.")); + error_settings.exec(); + count_errors = true; + } + return !count_errors; } bool CCoreListener::closeMainWindow() const { bool okToClose = true; - Q_FOREACH(QMdiSubWindow *subWindow, m_MainWindow->_ui.mdiArea->subWindowList()) - { - CEditor *currentEditor = qobject_cast(subWindow); + Q_FOREACH(QMdiSubWindow *subWindow, m_MainWindow->_ui.mdiArea->subWindowList()) + { + CEditor *currentEditor = qobject_cast(subWindow); if(subWindow->isWindowModified()) { QMessageBox msgBox; + msgBox.setIcon(QMessageBox::Question); msgBox.setText(tr("The document has been modified ( %1 ).").arg(currentEditor->windowFilePath())); - msgBox.setInformativeText("Do you want to save your changes?"); + msgBox.setInformativeText(tr("Do you want to save your changes?")); msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); msgBox.setDefaultButton(QMessageBox::Save); int ret = msgBox.exec(); - if(ret == QMessageBox::Save) - { - currentEditor->save(); - } - else if(ret == QMessageBox::Cancel) - { - okToClose = false; - break; - } + if(ret == QMessageBox::Save) + { + currentEditor->save(); + } + else if(ret == QMessageBox::Cancel) + { + okToClose = false; + break; + } } - } + } return okToClose; } @@ -581,73 +585,68 @@ bool CCoreListener::closeMainWindow() const // Helper functions CEditor *CMainWindow::getEditorByWindowFilePath(const QString &fileName) { - Q_FOREACH(QMdiSubWindow *subWindow, _ui.mdiArea->subWindowList()) - { - CEditor *currentEditor = qobject_cast(subWindow); - if(currentEditor->subWindowFilePath() == fileName) - return currentEditor; - } - return NULL; + Q_FOREACH(QMdiSubWindow *subWindow, _ui.mdiArea->subWindowList()) + { + CEditor *currentEditor = qobject_cast(subWindow); + if(currentEditor->subWindowFilePath() == fileName) + return currentEditor; + } + return NULL; } CEditorWorksheet *CMainWindow::getEditorByWorksheetType(const QString &type) { - Q_FOREACH(QMdiSubWindow *subWindow, _ui.mdiArea->subWindowList()) - { - CEditor *currentEditor = qobject_cast(subWindow); + Q_FOREACH(QMdiSubWindow *subWindow, _ui.mdiArea->subWindowList()) + { + CEditor *currentEditor = qobject_cast(subWindow); if(currentEditor->eType() == Constants::ED_SHEET) { CEditorWorksheet *editor = qobject_cast(currentEditor); - if(type != NULL) { + if(type != NULL) + { if(editor->isSheetTable(type)) { return editor; } - } else { + } + else + { if(editor->isBotNamesTable()) { return editor; } } } - } - return NULL; + } + return NULL; } +std::list CMainWindow::convertQStringList(QStringList listq) +{ + std::list stdlist; -list CMainWindow::convertQStringList(QStringList listq) -{ - std::list stdlist; - - Q_FOREACH(QString text, listq) - { - stdlist.push_back(text.toStdString()); - } - - return stdlist; + Q_FOREACH(QString text, listq) + { + stdlist.push_back(text.toStdString()); + } + return stdlist; } bool CMainWindow::isWorksheetEditor(QString filename) { - STRING_MANAGER::TWorksheet wk_file; - if(loadExcelSheet(filename.toStdString(), wk_file, true) == true) - { + STRING_MANAGER::TWorksheet wk_file; + if(loadExcelSheet(filename.toStdString(), wk_file, true) == true) + { if(wk_file.ColCount > 1) return true; - } - + } return false; } bool CMainWindow::isPhraseEditor(QString filename) { vector phrases; - if(readPhraseFile(filename.toStdString(), phrases, false)) - { - return true; - } else { - return false; - } + return readPhraseFile(filename.toStdString(), phrases, false); } } /* namespace TranslationManager */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_main_window.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_main_window.h index 19c3c1976..c67f282e0 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_main_window.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_main_window.h @@ -1,5 +1,4 @@ // Translation Manager Plugin - OVQT Plugin -// Copyright (C) 2010 Winch Gate Property Limited // Copyright (C) 2011 Emanuel Costea // // This program is free software: you can redistribute it and/or modify @@ -15,20 +14,19 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . - #ifndef MAIN_WINDOW_H #define MAIN_WINDOW_H +// Project includes +#include "ui_translation_manager_main_window.h" +#include "translation_manager_editor.h" +#include "source_selection.h" +#include "editor_worksheet.h" +#include "editor_phrase.h" + // Project system includes #include "../core/icore_listener.h" -// Nel includes -#include "nel/misc/types_nl.h" -#include "nel/misc/sheet_id.h" -#include "nel/misc/path.h" -#include "nel/misc/diff_tool.h" -#include "nel/ligo/ligo_config.h" - // Qt includes #include #include @@ -39,80 +37,82 @@ #include #include -// Plugin includes -#include "translation_manager_editor.h" -#include "source_selection.h" -#include "ui_translation_manager_main_window.h" +// STL includes #include -#include "editor_worksheet.h" -#include "editor_phrase.h" - -class QWidget; +// Nel includes +#include "nel/misc/types_nl.h" +#include "nel/misc/sheet_id.h" +#include "nel/misc/path.h" +#include "nel/misc/diff_tool.h" +#include "nel/ligo/ligo_config.h" using namespace std; namespace TranslationManager { - + class CMainWindow : public QMainWindow { Q_OBJECT + public: - CMainWindow(QWidget *parent = 0); - virtual ~CMainWindow() {} - QUndoStack *m_undoStack; + CMainWindow(QWidget *parent = 0); + virtual ~CMainWindow() {} + QUndoStack *m_undoStack; + public: - Ui::CMainWindow _ui; -private: - // actions - QAction *openAct; - QAction *saveAct; - QAction *saveAsAct; - QMenu *windowMenu; - QSignalMapper *windowMapper; - // config - QMap initialize_settings; - QList filters; - QList languages; - QString level_design_path; - QString primitives_path; - QString translation_path; - QString work_path; - NLLIGO::CLigoConfig ligoConfig; -private Q_SLOTS: - void extractBotNames(); - void extractWords(QString typeq); - void open(); - void save(); - void saveAs(); - void setActiveSubWindow(QWidget *window); - void updateWindowsList(); - void mergeSingleFile(); + Ui::CMainWindow _ui; + private: - void openWorkFile(QString file); - void updateToolbar(QMdiSubWindow *window); - bool verifySettings(); - void readSettings(); - void createMenus(); - void createToolbar(); - void initializeSettings(bool georges); - list convertQStringList(QStringList listq); - CEditor* getEditorByWindowFilePath(const QString &fileName); + // actions + QAction *openAct; + QAction *saveAct; + QAction *saveAsAct; + QMenu *windowMenu; + QSignalMapper *windowMapper; + // config + QMap initialize_settings; + QList filters; + QList languages; + QString level_design_path; + QString primitives_path; + QString translation_path; + QString work_path; + NLLIGO::CLigoConfig ligoConfig; + +private Q_SLOTS: + void extractBotNames(); + void extractWords(QString typeq); + void open(); + void save(); + void saveAs(); + void setActiveSubWindow(QWidget *window); + void updateWindowsList(); + void mergeSingleFile(); + +private: + void openWorkFile(QString file); + void updateToolbar(QMdiSubWindow *window); + bool verifySettings(); + void readSettings(); + void createMenus(); + void createToolbar(); + void initializeSettings(bool georges); + std::list convertQStringList(QStringList listq); + CEditor *getEditorByWindowFilePath(const QString &fileName); // Worksheet specific functions - CEditorWorksheet* getEditorByWorksheetType(const QString &type); - bool isWorksheetEditor(QString filename); + CEditorWorksheet *getEditorByWorksheetType(const QString &type); + bool isWorksheetEditor(QString filename); bool isPhraseEditor(QString filename); - - - }; class CCoreListener : public Core::ICoreListener { Q_OBJECT + public: - CCoreListener(CMainWindow* mainWindow, QObject *parent = 0): ICoreListener(parent) + CCoreListener(CMainWindow *mainWindow, QObject *parent = 0): ICoreListener(parent) { m_MainWindow = mainWindow; } @@ -124,10 +124,6 @@ public: CMainWindow *m_MainWindow; }; - - } // namespace TranslationManager - - -#endif // SIMPLE_VIEWER_H +#endif diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_plugin.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_plugin.cpp index a43311506..03aa06c87 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_plugin.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_plugin.cpp @@ -19,7 +19,8 @@ #include "translation_manager_plugin.h" #include "translation_manager_settings_page.h" #include "translation_manager_main_window.h" -// Project system includes + +// Core includes #include "../core/icore.h" #include "../core/core_constants.h" #include "../core/menu_manager.h" @@ -59,17 +60,14 @@ bool TranslationManagerPlugin::initialize(ExtensionSystem::IPluginManager *plugi addAutoReleasedObject(new CTranslationManagerSettingsPage(this)); addAutoReleasedObject(new CTranslationManagerContext(mainWindow, this)); addAutoReleasedObject(new CCoreListener(mainWindow, this)); - + return true; } void TranslationManagerPlugin::extensionsInitialized() { - } - - void TranslationManagerPlugin::setNelContext(NLMISC::INelContext *nelContext) { #ifdef NL_OS_WINDOWS @@ -86,23 +84,6 @@ void TranslationManagerPlugin::addAutoReleasedObject(QObject *obj) _autoReleaseObjects.prepend(obj); } -QObject* TranslationManagerPlugin::objectByName(const QString &name) const -{ - Q_FOREACH (QObject *qobj, _plugMan->allObjects()) - if (qobj->objectName() == name) - return qobj; - return 0; } -ExtensionSystem::IPluginSpec *TranslationManagerPlugin::pluginByName(const QString &name) const -{ - Q_FOREACH (ExtensionSystem::IPluginSpec *spec, _plugMan->plugins()) - if (spec->name() == name) - return spec; - return 0; - -} - -} - -Q_EXPORT_PLUGIN(TranslationManager::TranslationManagerPlugin) +Q_EXPORT_PLUGIN(TranslationManager::TranslationManagerPlugin) \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_plugin.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_plugin.h index f9cb6798c..fb03a49f1 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_plugin.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_plugin.h @@ -45,8 +45,8 @@ class IPluginSpec; namespace TranslationManager { - class CTranslationManagerContext; - +class CTranslationManagerContext; + class TranslationManagerPlugin : public QObject, public ExtensionSystem::IPlugin { Q_OBJECT @@ -58,12 +58,8 @@ public: void extensionsInitialized(); void setNelContext(NLMISC::INelContext *nelContext); - void addAutoReleasedObject(QObject *obj); - QObject *objectByName(const QString &name) const; - ExtensionSystem::IPluginSpec *pluginByName(const QString &name) const; - protected: NLMISC::CLibraryContext *_LibContext; @@ -75,8 +71,9 @@ private: class CTranslationManagerContext: public Core::IContext { Q_OBJECT + public: - CTranslationManagerContext(CMainWindow* mainWindow, QObject *parent = 0): IContext(parent) + CTranslationManagerContext(CMainWindow *mainWindow, QObject *parent = 0): IContext(parent) { m_MainWindow = mainWindow; } @@ -109,9 +106,8 @@ public: } CMainWindow *m_MainWindow; - }; -} // namespace Plugin +} -#endif // TRANSLATION_MANAGER_PLUGIN_H +#endif // TRANSLATION_MANAGER_PLUGIN_H \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_settings_page.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_settings_page.cpp index 09588da7d..e3dbd92df 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_settings_page.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_settings_page.cpp @@ -1,5 +1,4 @@ // Translation Manager Plugin - OVQT Plugin -// Copyright (C) 2010 Winch Gate Property Limited // Copyright (C) 2011 Emanuel Costea // // This program is free software: you can redistribute it and/or modify @@ -17,17 +16,15 @@ #include "translation_manager_settings_page.h" +// Core includes +#include "../core/icore.h" + // Qt includes #include #include #include #include -// NeL includes - -// Project includes -#include "../core/icore.h" - namespace TranslationManager { @@ -68,20 +65,20 @@ QWidget *CTranslationManagerSettingsPage::createPage(QWidget *parent) { _currentPage = new QWidget(parent); _ui.setupUi(_currentPage); - readSettings(); + readSettings(); connect(_ui.filter_add, SIGNAL(clicked()), this, SLOT(filterAdd())); connect(_ui.filter_del, SIGNAL(clicked()), this, SLOT(filterDel())); connect(_ui.lang_add, SIGNAL(clicked()), this, SLOT(languageAdd())); connect(_ui.lang_del, SIGNAL(clicked()), this, SLOT(languageDel())); - connect(_ui.translation_add, SIGNAL(clicked()), this, SLOT(translationAdd())); - connect(_ui.work_add, SIGNAL(clicked()), this, SLOT(workAdd())); - + connect(_ui.translation_add, SIGNAL(clicked()), this, SLOT(translationAdd())); + connect(_ui.work_add, SIGNAL(clicked()), this, SLOT(workAdd())); + return _currentPage; } void CTranslationManagerSettingsPage::filterAdd() -{ - QString newValue = _ui.filter_edit->text(); +{ + QString newValue = _ui.filter_edit->text(); if (!newValue.isEmpty()) { QListWidgetItem *newItem = new QListWidgetItem; @@ -95,113 +92,112 @@ void CTranslationManagerSettingsPage::filterDel() { QListWidgetItem *removeItem = _ui.filter_list->takeItem(_ui.filter_list->currentRow()); if (!removeItem) - delete removeItem; + delete removeItem; } void CTranslationManagerSettingsPage::languageAdd() { - QString newValue = _ui.lang_edit->text(); + QString newValue = _ui.lang_edit->text(); if (!newValue.isEmpty()) { QListWidgetItem *newItem = new QListWidgetItem; newItem->setText(newValue); newItem->setFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable); _ui.lang_list->addItem(newItem); - } + } } void CTranslationManagerSettingsPage::languageDel() { QListWidgetItem *removeItem = _ui.lang_list->takeItem(_ui.lang_list->currentRow()); if (!removeItem) - delete removeItem; + delete removeItem; } void CTranslationManagerSettingsPage::translationAdd() { - QString newPath = QFileDialog::getExistingDirectory(_currentPage, ""); - if (!newPath.isEmpty()) + QString newPath = QFileDialog::getExistingDirectory(_currentPage, ""); + if (!newPath.isEmpty()) { - _ui.translation_edit->setText(newPath); - } + _ui.translation_edit->setText(newPath); + } } void CTranslationManagerSettingsPage::workAdd() { - QString newPath = QFileDialog::getExistingDirectory(_currentPage, ""); - if (!newPath.isEmpty()) + QString newPath = QFileDialog::getExistingDirectory(_currentPage, ""); + if (!newPath.isEmpty()) { - _ui.work_edit->setText(newPath); - } + _ui.work_edit->setText(newPath); + } } void CTranslationManagerSettingsPage::apply() { - writeSettings(); + writeSettings(); } void CTranslationManagerSettingsPage::readSettings() { QStringList filters, languages; - QString ligo, translation, work; - + QString ligo, translation, work; + QSettings *settings = Core::ICore::instance()->settings(); settings->beginGroup("translationmanager"); - - filters = settings->value("filters").toStringList(); /* filters */ - languages = settings->value("trlanguages").toStringList(); /* languages */ - ligo = settings->value("ligo").toString(); - translation = settings->value("translation").toString(); - work = settings->value("work").toString(); - + + filters = settings->value("filters").toStringList(); /* filters */ + languages = settings->value("trlanguages").toStringList(); /* languages */ + ligo = settings->value("ligo").toString(); + translation = settings->value("translation").toString(); + work = settings->value("work").toString(); + settings->endGroup(); - // filter + // filter Q_FOREACH(QString filter, filters) { QListWidgetItem *newItem = new QListWidgetItem; newItem->setText(filter); newItem->setFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable); _ui.filter_list->addItem(newItem); - } - // languages + } + // languages Q_FOREACH(QString lang, languages) { QListWidgetItem *newItem = new QListWidgetItem; newItem->setText(lang); newItem->setFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable); _ui.lang_list->addItem(newItem); - } - // translation - _ui.translation_edit->setText(translation); - // work - _ui.work_edit->setText(work); - + } + // translation + _ui.translation_edit->setText(translation); + // work + _ui.work_edit->setText(work); + } void CTranslationManagerSettingsPage::writeSettings() { QStringList filters, languages; - QString ligo, translation, work; - // filters + QString ligo, translation, work; + // filters for (int i = 0; i < _ui.filter_list->count(); ++i) filters << _ui.filter_list->item(i)->text(); - // languages + // languages for (int i = 0; i < _ui.lang_list->count(); ++i) - languages << _ui.lang_list->item(i)->text(); - // translations path - translation = _ui.translation_edit->text(); - // work path - work = _ui.work_edit->text(); - + languages << _ui.lang_list->item(i)->text(); + // translations path + translation = _ui.translation_edit->text(); + // work path + work = _ui.work_edit->text(); + QSettings *settings = Core::ICore::instance()->settings(); settings->beginGroup("translationmanager"); - settings->setValue("filters", filters); - settings->setValue("trlanguages", languages); - settings->setValue("translation", translation); - settings->setValue("work", work); + settings->setValue("filters", filters); + settings->setValue("trlanguages", languages); + settings->setValue("translation", translation); + settings->setValue("work", work); settings->endGroup(); - settings->sync(); + settings->sync(); } - -} /* namespace Plugin */ +} \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_settings_page.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_settings_page.h index 34caea5e1..9b34d87ba 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_settings_page.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_settings_page.h @@ -24,13 +24,9 @@ #include "ui_translation_manager_settings_page.h" -class QWidget; - namespace TranslationManager { -/** -@class CTranslationManagerSettingsPage -*/ + class CTranslationManagerSettingsPage : public Core::IOptionsPage { Q_OBJECT @@ -44,23 +40,23 @@ public: virtual QString trCategory() const; virtual QIcon categoryIcon() const; virtual QWidget *createPage(QWidget *parent); - + virtual void apply(); virtual void finish() {} private Q_SLOTS: - void filterAdd(); - void filterDel(); - void languageAdd(); - void languageDel(); - void translationAdd(); - void workAdd(); + void filterAdd(); + void filterDel(); + void languageAdd(); + void languageDel(); + void translationAdd(); + void workAdd(); private: QWidget *_currentPage; Ui::CTranslationManagerSettingsPage _ui; - void writeSettings(); - void readSettings(); + void writeSettings(); + void readSettings(); }; -} // namespace Plugin +} -#endif // TRANSLATION_MANAGER_SETTINGS_H +#endif // TRANSLATION_MANAGER_SETTINGS_H \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_settings_page.ui b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_settings_page.ui index aaa4337f4..bd377b6b9 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_settings_page.ui +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/translation_manager/translation_manager_settings_page.ui @@ -6,178 +6,152 @@ 0 0 - 533 - 478 + 589 + 490 Form - - - - 0 - 10 - 531 - 421 - - - - Translation Manager Plugin - - - - - 0 - 30 - 521 - 232 - - - - - - - Filters - - - - - - - - - - - - - - :/core/icons/ic_nel_add_item.png:/core/icons/ic_nel_add_item.png - - - true - - - - - - - - - - - :/core/icons/ic_nel_delete_item.png:/core/icons/ic_nel_delete_item.png - - - true - - - - - - - Languages - - - - - - - - - - - - - - :/core/icons/ic_nel_add_item.png:/core/icons/ic_nel_add_item.png - - - true - - - - - - - - - - - :/core/icons/ic_nel_delete_item.png:/core/icons/ic_nel_delete_item.png - - - true - - - - - - - - - - - - - - - 0 - 340 - 521 - 60 - - - - - - - Translation directory - - - - - - - - - - ... - - - - - - - - - 0 - 270 - 521 - 60 - - - - - - - Work directory - - - - - - - - - - ... - - - - - - + + + + + Translation Manager Plugin + + + + + + + + Filters + + + + + + + + + + + + + + :/core/icons/ic_nel_add_item.png:/core/icons/ic_nel_add_item.png + + + true + + + + + + + + + + + :/core/icons/ic_nel_delete_item.png:/core/icons/ic_nel_delete_item.png + + + true + + + + + + + Languages + + + + + + + + + + + + + + :/core/icons/ic_nel_add_item.png:/core/icons/ic_nel_add_item.png + + + true + + + + + + + + + + + :/core/icons/ic_nel_delete_item.png:/core/icons/ic_nel_delete_item.png + + + true + + + + + + + + + + + + + + + + + Work directory + + + + + + + + + + ... + + + + + + + + + + + Translation directory + + + + + + + + + + ... + + + + + + + + + From 3e32c1b037233776ceccaa870c649c15f266253b Mon Sep 17 00:00:00 2001 From: dnk-88 Date: Sat, 31 Dec 2011 12:24:23 +0300 Subject: [PATCH 16/46] Added #1193 Added scheme bank dialog in particles editor. --- .../src/plugins/object_viewer/attrib_form.ui | 2 +- .../plugins/object_viewer/attrib_widget.cpp | 11 +- .../plugins/object_viewer/particle_editor.cpp | 1 + .../object_viewer/scheme_bank_dialog.cpp | 149 ++++++++++++++++-- .../object_viewer/scheme_bank_dialog.h | 57 +++++-- .../plugins/object_viewer/scheme_bank_form.ui | 36 +++-- .../plugins/object_viewer/scheme_manager.cpp | 26 +-- 7 files changed, 217 insertions(+), 65 deletions(-) diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/attrib_form.ui b/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/attrib_form.ui index 77c4b895f..404444fc0 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/attrib_form.ui +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/attrib_form.ui @@ -91,7 +91,7 @@ - false + true diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/attrib_widget.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/attrib_widget.cpp index 648e0e1a5..e00d07cec 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/attrib_widget.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/attrib_widget.cpp @@ -186,12 +186,11 @@ void CAttribWidget::changeUseScheme(int index) void CAttribWidget::openSchemeBankDialog() { - CSchemeBankDialog *dialog = new CSchemeBankDialog(this); - dialog->setModal(true); - dialog->show(); - dialog->exec(); - delete dialog; - //updateUi(); + CSchemeBankDialog dialog(this); + dialog.setModal(true); + dialog.show(); + dialog.exec(); + updateUi(); } void CAttribWidget::inputValueUpdate(void) diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/particle_editor.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/particle_editor.cpp index 768576755..12ea96c8a 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/particle_editor.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/particle_editor.cpp @@ -73,6 +73,7 @@ void CParticleEditor::release() { stop(); closeWorkspace(); + delete _SchemeManager; } void CParticleEditor::setActiveNode(CWorkspaceNode *node) diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/scheme_bank_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/scheme_bank_dialog.cpp index 66deb2a17..bca0f4879 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/scheme_bank_dialog.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/scheme_bank_dialog.cpp @@ -1,24 +1,33 @@ -// NeL - MMORPG Framework -// Copyright (C) 2010 Winch Gate Property Limited -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License +// NeL - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . // Project includes #include "stdpch.h" #include "scheme_bank_dialog.h" +#include "scheme_manager.h" #include "modules.h" +// NeL includes +#include + +// Qt includes +#include +#include +#include + namespace NLQT { @@ -27,6 +36,16 @@ CSchemeBankDialog::CSchemeBankDialog(CAttribWidget *attribWidget, QWidget *paren { _ui.setupUi(this); _attribWidget = attribWidget; + + connect(_ui.createButton, SIGNAL(clicked()), this, SLOT(createScheme())); + connect(_ui.currentButton, SIGNAL(clicked()), this, SLOT(setCurrentScheme())); + connect(_ui.removeButton, SIGNAL(clicked()), this, SLOT(removeScheme())); + connect(_ui.loadButton, SIGNAL(clicked()), this, SLOT(loadBank())); + connect(_ui.saveButton, SIGNAL(clicked()), this, SLOT(saveBank())); + connect(_ui.listWidget, SIGNAL(itemSelectionChanged()), this, SLOT(enableButtons())); + connect(_ui.listWidget, SIGNAL(itemChanged(QListWidgetItem *)), this, SLOT(changeNameScheme(QListWidgetItem *))); + + buildList(); } CSchemeBankDialog::~CSchemeBankDialog() @@ -35,27 +54,125 @@ CSchemeBankDialog::~CSchemeBankDialog() void CSchemeBankDialog::createScheme() { + bool ok; + QString text = QInputDialog::getText(this, tr("Insert new scheme"), + tr("Set name:"), QLineEdit::Normal, + "new scheme", &ok); + if (ok && !text.isEmpty()) + { + NL3D::CPSAttribMakerBase *attribMakerBase = _attribWidget->getCurrentSchemePtr()->clone(); + Modules::psEdit().getSchemeManager()->insertScheme(text.toStdString(), attribMakerBase); + + CSchemeItem *item = new CSchemeItem(text, _ui.listWidget); + item->setUserData(attribMakerBase); + item->setFlags(Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsEnabled); + } } void CSchemeBankDialog::setCurrentScheme() { - //SchemeManager.insertScheme(cn.getName(), getCurrentSchemePtr()->clone()); + CSchemeItem *item = dynamic_cast(_ui.listWidget->currentItem()); + + NL3D::CPSAttribMakerBase *attrib = item->getUserData(); + nlassert(attrib); + + _attribWidget->setCurrentSchemePtr(attrib->clone()); + _attribWidget->updateUi(); } void CSchemeBankDialog::removeScheme() { + CSchemeItem *item = dynamic_cast(_ui.listWidget->currentItem()); + + NL3D::CPSAttribMakerBase *attrib = item->getUserData(); + nlassert(attrib); + Modules::psEdit().getSchemeManager()->remove(attrib); + _ui.listWidget->removeItemWidget(item); + delete item; + + if (_ui.listWidget->count() == 0) + { + _ui.currentButton->setEnabled(false); + _ui.removeButton->setEnabled(false); + } } void CSchemeBankDialog::saveBank() { + QString fileName = QFileDialog::getSaveFileName(this, + tr("Save scheme bank file"), ".", + tr("Scheme bank files (*.scb)")); + + if (!fileName.isEmpty()) + { + try + { + NLMISC::COFile iF; + iF.open(fileName.toStdString()); + NLQT::CSchemeManager *schemeManager = Modules::psEdit().getSchemeManager(); + iF.serial(*schemeManager); + } + catch (std::exception &e) + { + QMessageBox::critical(this, "Scheme manager", tr("Error saving scheme bank : %1").arg(e.what())); + return; + } + } } void CSchemeBankDialog::loadBank() { + QString fileName = QFileDialog::getOpenFileName(this, + tr("Open scheme bank file"), ".", + tr("Scheme bank files (*.scb)")); + + if (!fileName.isEmpty()) + { + NLQT::CSchemeManager sm; + try + { + NLMISC::CIFile iF; + iF.open(fileName.toStdString()); + iF.serial(sm); + Modules::psEdit().getSchemeManager()->swap(sm); + } + catch (std::exception &e) + { + QMessageBox::critical(this, "Scheme manager", tr("Error loading scheme bank : %1").arg(e.what())); + return; + } + buildList(); + } } -void CSchemeBankDialog::buildList() +void CSchemeBankDialog::changeNameScheme(QListWidgetItem *item) { + CSchemeItem *schemeItem = dynamic_cast(item); + + NL3D::CPSAttribMakerBase *attrib = schemeItem->getUserData(); + nlassert(attrib); + + Modules::psEdit().getSchemeManager()->rename(attrib, item->text().toStdString()); +} + +void CSchemeBankDialog::enableButtons() +{ + _ui.currentButton->setEnabled(true); + _ui.removeButton->setEnabled(true); +} + +void CSchemeBankDialog::buildList() +{ + _ui.listWidget->clear(); + typedef std::vector TSchemeVect; + static TSchemeVect schemes; + Modules::psEdit().getSchemeManager()->getSchemes(_attribWidget->getCurrentSchemePtr()->getType(), schemes); + for (TSchemeVect::const_iterator it = schemes.begin(); it != schemes.end(); ++it) + { + CSchemeItem *item = new CSchemeItem(it->first.c_str(), _ui.listWidget); + item->setUserData(it->second); + item->setFlags(Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsEnabled); + } } } /* namespace NLQT */ \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/scheme_bank_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/scheme_bank_dialog.h index a02406468..8f9f300b8 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/scheme_bank_dialog.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/scheme_bank_dialog.h @@ -1,17 +1,17 @@ -// NeL - MMORPG Framework -// Copyright (C) 2010 Winch Gate Property Limited -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License +// NeL - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef SCHEME_BANK_DIALOG_H @@ -27,12 +27,37 @@ #include "nel/3d/particle_system.h" // Project includes +#include "attrib_widget.h" #include "ps_wrapper.h" namespace NLQT { class CAttribWidget; +/** +@class CSchemeItem +@brief Contain pointer to NL3D::CPSAttribMakerBase. +*/ +class CSchemeItem: public QListWidgetItem +{ +public: + CSchemeItem(const QString &text, QListWidget *parent = 0, int type = UserType ): + QListWidgetItem(text, parent, type), _attrib(NULL) {} + + void setUserData(NL3D::CPSAttribMakerBase *attrib) + { + _attrib = attrib; + } + NL3D::CPSAttribMakerBase *getUserData() const + { + return _attrib; + } + +private: + + NL3D::CPSAttribMakerBase *_attrib; +}; /* class CSchemeItem */ + class CSchemeBankDialog: public QDialog { Q_OBJECT @@ -47,9 +72,11 @@ private Q_SLOTS: void removeScheme(); void saveBank(); void loadBank(); + void enableButtons(); + void changeNameScheme(QListWidgetItem *item); private: - void buildList(); + void buildList(); CAttribWidget *_attribWidget; Ui::CSchemeBankDialog _ui; diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/scheme_bank_form.ui b/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/scheme_bank_form.ui index e7dd281f8..f8fa10865 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/scheme_bank_form.ui +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/scheme_bank_form.ui @@ -14,31 +14,27 @@ Sceme bank - + - Create + Put current - - - Rename - - - - + + false + Remove - + Qt::Vertical @@ -51,24 +47,33 @@ - + + + true + Load bank - + + + true + Save bank - + + + false + 0 @@ -105,7 +110,10 @@ - + + + false + Set current diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/scheme_manager.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/scheme_manager.cpp index 62e847a73..c00422af5 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/scheme_manager.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/scheme_manager.cpp @@ -18,7 +18,7 @@ #include "scheme_manager.h" #include "nel/3d/ps_attrib_maker.h" -namespace NLQT +namespace NLQT { CSchemeManager::~CSchemeManager() @@ -34,7 +34,7 @@ void CSchemeManager::insertScheme(const std::string &name, NL3D::CPSAttribMakerB { nlassert(scheme); TSchemeInfo si(std::string(name), scheme); - _SchemeMap.insert(TSchemeMap::value_type(std::string(scheme->getType()), si)); + _SchemeMap.insert(TSchemeMap::value_type(std::string(scheme->getType()), si)); } void CSchemeManager::getSchemes(const std::string &type, std::vector &dest) @@ -49,30 +49,30 @@ void CSchemeManager::getSchemes(const std::string &type, std::vectorsecond.first); // name f.serialPolyPtr(smIt->second.second); // scheme - } + } } else { _SchemeMap.clear(); - + std::string name; NL3D::CPSAttribMakerBase *scheme = NULL; sint32 size; f.serial(size); for (sint32 k = 0; k < size; ++k) - { + { f.serial(name); f.serialPolyPtr(scheme); insertScheme(name, scheme); @@ -80,12 +80,12 @@ void CSchemeManager::serial(NLMISC::IStream &f) throw(NLMISC::EStream) } } -void CSchemeManager::swap(CSchemeManager &other) +void CSchemeManager::swap(CSchemeManager &other) { this->_SchemeMap.swap(other._SchemeMap); } -void CSchemeManager::remove(NL3D::CPSAttribMakerBase *am) +void CSchemeManager::remove(NL3D::CPSAttribMakerBase *am) { TSchemeMap::iterator smIt; for (smIt = _SchemeMap.begin(); smIt != _SchemeMap.end(); ++smIt) @@ -101,7 +101,7 @@ void CSchemeManager::remove(NL3D::CPSAttribMakerBase *am) } // rename a scheme, given a pointer on it -void CSchemeManager::rename(NL3D::CPSAttribMakerBase *am, const std::string &newName) +void CSchemeManager::rename(NL3D::CPSAttribMakerBase *am, const std::string &newName) { TSchemeMap::iterator smIt; for (smIt = _SchemeMap.begin(); smIt != _SchemeMap.end(); ++smIt) @@ -110,7 +110,7 @@ void CSchemeManager::rename(NL3D::CPSAttribMakerBase *am, const std::string &ne } if (smIt != _SchemeMap.end()) { - smIt->second.first = newName; + smIt->second.first = newName; } } From 6994f7374ef77adfb30b568e7af1967dce3c5721 Mon Sep 17 00:00:00 2001 From: kervala Date: Mon, 2 Jan 2012 15:41:22 +0100 Subject: [PATCH 17/46] Changed: #825 Remove all warnings when compiling Ryzom --- code/nel/src/3d/patchdlm_context.cpp | 4 ++-- code/nel/src/ligo/primitive.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/code/nel/src/3d/patchdlm_context.cpp b/code/nel/src/3d/patchdlm_context.cpp index f5a5b578d..e50f1befe 100644 --- a/code/nel/src/3d/patchdlm_context.cpp +++ b/code/nel/src/3d/patchdlm_context.cpp @@ -1018,8 +1018,8 @@ void CPatchDLMContext::computeTextureFar() // compute src pixel const CRGBA *srcPixel= pTile->getPixels(CTileFarBank::diffuse, CTileFarBank::order1); // compute src info, for this tile rot and 256x256 context. - sint srcDeltaX; - sint srcDeltaY; + sint srcDeltaX = 0; + sint srcDeltaY = 0; srcPixel= computeTileFarSrcDeltas(nRot, is256x256, uvOff, srcPixel, srcDeltaX, srcDeltaY); // compute dst coordinate. start writing at pixel (1,1) diff --git a/code/nel/src/ligo/primitive.cpp b/code/nel/src/ligo/primitive.cpp index ff8c71c18..62c4ab9d6 100644 --- a/code/nel/src/ligo/primitive.cpp +++ b/code/nel/src/ligo/primitive.cpp @@ -2118,7 +2118,7 @@ bool CPrimAlias::read (xmlNodePtr xmlNode, const char *filename, uint version, C xmlNodePtr ptNode = CIXml::getFirstChildNode (xmlNode, "ALIAS"); if (ptNode) { - int val; + sint val = 0; if (ReadInt ("VALUE", val, filename, ptNode)) { _Alias = uint32(val); From 08c853b9dc5577d1e62d4422d2baaa97bf7725af Mon Sep 17 00:00:00 2001 From: kervala Date: Mon, 2 Jan 2012 15:53:21 +0100 Subject: [PATCH 18/46] Fixed: Missing "stdpch.h" include --- code/ryzom/client/src/app_bundle_utils.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/code/ryzom/client/src/app_bundle_utils.cpp b/code/ryzom/client/src/app_bundle_utils.cpp index 214d278b2..b6321ad20 100644 --- a/code/ryzom/client/src/app_bundle_utils.cpp +++ b/code/ryzom/client/src/app_bundle_utils.cpp @@ -14,6 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . +#include "stdpch.h" #include "app_bundle_utils.h" #if defined(NL_OS_MAC) From be53b772b5880bad576131ab7e9172d557104fae Mon Sep 17 00:00:00 2001 From: Krolock Date: Wed, 4 Jan 2012 09:45:25 +0100 Subject: [PATCH 19/46] Changed: added thumbs.db to hgignore --- .hgignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.hgignore b/.hgignore index 4a0311dcc..fcc548cd0 100644 --- a/.hgignore +++ b/.hgignore @@ -144,6 +144,8 @@ external external_stlport 3rdParty .svn +thumbs.db +Thumbs.db # build code/nel/build/* From 34bfcc1af8548ca39841c7731eef1179a078f6e8 Mon Sep 17 00:00:00 2001 From: Krolock Date: Wed, 4 Jan 2012 09:51:10 +0100 Subject: [PATCH 20/46] Added: Added bnp manager plugin basic layout, list and unpack for ovqt --- .../src/plugins/CMakeLists.txt | 1 + .../src/plugins/bnp_manager/CMakeLists.txt | 46 ++++ .../bnp_manager/bnp_dirtree_dialog.cpp | 87 +++++++ .../plugins/bnp_manager/bnp_dirtree_dialog.h | 80 +++++++ .../plugins/bnp_manager/bnp_dirtree_form.ui | 58 +++++ .../src/plugins/bnp_manager/bnp_file.cpp | 204 ++++++++++++++++ .../src/plugins/bnp_manager/bnp_file.h | 103 ++++++++ .../bnp_manager/bnp_filelist_dialog.cpp | 122 ++++++++++ .../plugins/bnp_manager/bnp_filelist_dialog.h | 81 +++++++ .../bnp_manager/bnp_filelist_dialog.ui | 70 ++++++ .../bnp_manager/bnp_filesystem_model.cpp | 52 ++++ .../bnp_manager/bnp_filesystem_model.h | 49 ++++ .../src/plugins/bnp_manager/bnp_manager.qrc | 9 + .../bnp_manager/bnp_manager_constants.h | 37 +++ .../bnp_manager/bnp_manager_plugin.cpp | 89 +++++++ .../plugins/bnp_manager/bnp_manager_plugin.h | 130 ++++++++++ .../bnp_manager/bnp_manager_window.cpp | 223 ++++++++++++++++++ .../plugins/bnp_manager/bnp_manager_window.h | 146 ++++++++++++ .../plugins/bnp_manager/bnp_manager_window.ui | 50 ++++ .../bnp_manager/images/ic_nel_add_item.png | Bin 0 -> 3270 bytes .../bnp_manager/images/ic_nel_bnp_make.png | Bin 0 -> 25705 bytes .../bnp_manager/images/ic_nel_delete_item.png | Bin 0 -> 1496 bytes .../bnp_manager/images/ic_nel_export.png | Bin 0 -> 27878 bytes .../bnp_manager/images/ic_nel_reset_all.png | Bin 0 -> 30281 bytes .../bnp_manager/ovqt_plugin_bnp_manager.xml | 10 + 25 files changed, 1647 insertions(+) create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/CMakeLists.txt create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_dirtree_dialog.cpp create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_dirtree_dialog.h create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_dirtree_form.ui create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_file.cpp create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_file.h create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_filelist_dialog.cpp create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_filelist_dialog.h create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_filelist_dialog.ui create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_filesystem_model.cpp create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_filesystem_model.h create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager.qrc create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_constants.h create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_plugin.cpp create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_plugin.h create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_window.cpp create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_window.h create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_window.ui create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/images/ic_nel_add_item.png create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/images/ic_nel_bnp_make.png create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/images/ic_nel_delete_item.png create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/images/ic_nel_export.png create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/images/ic_nel_reset_all.png create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/ovqt_plugin_bnp_manager.xml diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/CMakeLists.txt b/code/nel/tools/3d/object_viewer_qt/src/plugins/CMakeLists.txt index 426d3aa61..467b00876 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/CMakeLists.txt +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/CMakeLists.txt @@ -7,6 +7,7 @@ ADD_SUBDIRECTORY(disp_sheet_id) ADD_SUBDIRECTORY(object_viewer) ADD_SUBDIRECTORY(georges_editor) ADD_SUBDIRECTORY(translation_manager) +ADD_SUBDIRECTORY(bnp_manager) # Note: Temporarily disabled until development continues. #ADD_SUBDIRECTORY(zone_painter) # Ryzom Specific Plugins diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/CMakeLists.txt b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/CMakeLists.txt new file mode 100644 index 000000000..e06c82c94 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/CMakeLists.txt @@ -0,0 +1,46 @@ +INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + ${LIBXML2_INCLUDE_DIR} + ${QT_INCLUDES}) + +FILE(GLOB SRC *.cpp *.h) +SET(OVQT_EXT_SYS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/../../extension_system/iplugin.h + ${CMAKE_CURRENT_SOURCE_DIR}/../../extension_system/iplugin_manager.h + ${CMAKE_CURRENT_SOURCE_DIR}/../../extension_system/iplugin_spec.h) + +SET(OVQT_PLUG_BNP_MANAGER_HDR bnp_manager_plugin.h + bnp_manager_window.h + bnp_dirtree_dialog.h + bnp_filesystem_model.h + bnp_file.h + bnp_filelist_dialog.h + ) +SET(OVQT_PLUG_BNP_MANAGER_UIS bnp_dirtree_form.ui + bnp_filelist_dialog.ui + ) + +SET(OVQT_PLUGIN_BNP_MANAGER_RCS bnp_manager.qrc) + +SET(QT_USE_QTGUI TRUE) + +QT4_ADD_RESOURCES(OVQT_PLUGIN_BNP_MANAGER_RC_SRCS ${OVQT_PLUGIN_BNP_MANAGER_RCS}) +QT4_WRAP_CPP(OVQT_PLUG_BNP_MANAGER_MOC_SRC ${OVQT_PLUG_BNP_MANAGER_HDR}) +QT4_WRAP_UI(OVQT_PLUG_BNP_MANAGER_UI_HDRS ${OVQT_PLUG_BNP_MANAGER_UIS}) + +SOURCE_GROUP(QtResources FILES ${OVQT_PLUG_BNP_MANAGER_UIS} ${OVQT_PLUGIN_BNP_MANAGER_RCS}) +SOURCE_GROUP(QtGeneratedUiHdr FILES ${OVQT_PLUG_BNP_MANAGER_UI_HDRS}) +SOURCE_GROUP(QtGeneratedMocSrc FILES ${OVQT_PLUG_BNP_MANAGER_MOC_SRC}) +SOURCE_GROUP("BNP Manager Plugin" FILES ${SRC}) +SOURCE_GROUP("OVQT Extension System" FILES ${OVQT_EXT_SYS_SRC}) + +ADD_LIBRARY(ovqt_plugin_bnp_manager MODULE ${SRC} ${OVQT_PLUG_BNP_MANAGER_MOC_SRC} ${OVQT_EXT_SYS_SRC} ${OVQT_PLUGIN_BNP_MANAGER_RC_SRCS} ${OVQT_PLUG_BNP_MANAGER_UI_HDRS}) + +TARGET_LINK_LIBRARIES(ovqt_plugin_bnp_manager ovqt_plugin_core nelmisc nelgeorges ${QT_LIBRARIES}) + +NL_DEFAULT_PROPS(ovqt_plugin_bnp_manager "NeL, Tools, 3D: Object Viewer Qt Plugin: BNP Manager") +NL_ADD_RUNTIME_FLAGS(ovqt_plugin_bnp_manager) +NL_ADD_LIB_SUFFIX(ovqt_plugin_bnp_manager) + +ADD_DEFINITIONS(${LIBXML2_DEFINITIONS} -DQT_PLUGIN -DQT_SHARED ${QT_DEFINITIONS}) + +INSTALL(TARGETS ovqt_plugin_bnp_manager LIBRARY DESTINATION lib RUNTIME DESTINATION bin ARCHIVE DESTINATION lib COMPONENT tools3d) diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_dirtree_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_dirtree_dialog.cpp new file mode 100644 index 000000000..9487f66ae --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_dirtree_dialog.cpp @@ -0,0 +1,87 @@ +// Object Viewer Qt - BNP Manager Plugin - MMORPG Framework +// Copyright (C) 2011 Roland Winklmeier +// +// 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 . + +// Project includes +#include "bnp_dirtree_dialog.h" +#include "bnp_filesystem_model.h" + +// Qt includes +#include + +// NeL includes +#include + +namespace BNPManager +{ + +CBnpDirTreeDialog::CBnpDirTreeDialog(QString bnpPath, QWidget *parent) + : QDockWidget(parent), + m_DataPath(bnpPath) +{ + // Setup the dialog + m_ui.setupUi(this); + + // Filter settings to only display files with bnp extension. + // Could be changed to display all files and react according to the extension: + // Bnp file: opened and displayed + // all other files: added to the currently opened bnp file + QStringList filter; + filter << tr("*.bnp"); + + // Setup the directory tree model + m_dirModel= new BNPFileSystemModel; + m_dirModel->setRootPath(m_DataPath); + m_dirModel->setFilter(QDir::AllDirs | QDir::NoDotAndDotDot | QDir::AllEntries); + m_dirModel->setNameFilters(filter); + m_dirModel->setNameFilterDisables(0); + + m_ui.dirTree->setModel(m_dirModel); + + m_ui.dirTree->setRootIndex(m_dirModel->index(m_DataPath)); + + // Trigger if one filename is activated + // In future drag&drop should be also possible + connect(m_ui.dirTree, SIGNAL(activated(QModelIndex)), + this, SLOT(fileSelected(QModelIndex))); +} +// *************************************************************************** +CBnpDirTreeDialog::~CBnpDirTreeDialog() +{ + +} +// *************************************************************************** +void CBnpDirTreeDialog::fileSelected(QModelIndex index) +{ + if (index.isValid() && !m_dirModel->isDir(index)) + { + // emit the according signal to BNPManagerWindow class + Q_EMIT selectedForm(m_dirModel->fileInfo(index).filePath()); + } +} +// *************************************************************************** +void CBnpDirTreeDialog::changeFile(QString file) +{ + +} +// *************************************************************************** +void CBnpDirTreeDialog::BnpPathChanged(QString path) +{ + +} +// *************************************************************************** +} + + diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_dirtree_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_dirtree_dialog.h new file mode 100644 index 000000000..33b221a4d --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_dirtree_dialog.h @@ -0,0 +1,80 @@ +// Object Viewer Qt - BNP Manager Plugin - MMORPG Framework +// Copyright (C) 2011 Roland Winklmeier +// +// 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 . + +#ifndef BNP_DIRTREE_DIALOG_H +#define BNP_DIRTREE_DIALOG_H + +// Qt includes +#include + +// STL includes + +// NeL includes + +// Project includes +#include "ui_bnp_dirtree_form.h" + +namespace BNPManager +{ + +class BNPFileSystemModel; + +class CBnpDirTreeDialog : public QDockWidget +{ + Q_OBJECT +public: + + /** + * Constructor + * \param path to root directory, which should be displayed + */ + CBnpDirTreeDialog(QString bnpPath, QWidget *parent = 0); + + /** + * Destructor + */ + ~CBnpDirTreeDialog(); + + /** + * Change the root path for the dir tree view + * \param data path to the new directory + */ + void BnpPathChanged(QString); + +private: + + Ui::CBnpDirTreeDialog m_ui; + + // path ro data root directory + QString m_DataPath; + + BNPFileSystemModel *m_dirModel; + +Q_SIGNALS: + void selectedForm(const QString); + +private Q_SLOTS: + /** + * Triggered if the user activates (double klick on windows) + * a file name in the dir tree view + * \param selected ModelIndex (filename) + */ + void fileSelected(QModelIndex index); + + void changeFile(QString file); +}; +} +#endif \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_dirtree_form.ui b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_dirtree_form.ui new file mode 100644 index 000000000..751c4f055 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_dirtree_form.ui @@ -0,0 +1,58 @@ + + + CBnpDirTreeDialog + + + + 0 + 0 + 400 + 300 + + + + + 0 + 0 + + + + + 200 + 141 + + + + QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable + + + BNP Datapath + + + + + 50 + 0 + + + + + + + + 0 + 0 + + + + + + + + + + + + + + diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_file.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_file.cpp new file mode 100644 index 000000000..d6782a9a7 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_file.cpp @@ -0,0 +1,204 @@ +// Object Viewer Qt - BNP Manager Plugin - MMORPG Framework +// Copyright (C) 2011 Roland Winklmeier +// +// 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 . + +// Project includes +#include "bnp_file.h" + +// Nel includes +#include +#include +#include +#include +#include + +// Qt includes + +using namespace NLMISC; +using namespace std; + + +namespace BNPManager +{ + +NLMISC_SAFE_SINGLETON_IMPL(BNPFileHandle); + +BNPFileHandle::BNPFileHandle() +{ + m_offsetFromBeginning = 0; +} +// *************************************************************************** +BNPFileHandle::~BNPFileHandle() +{ + // Erase the list + m_packedFiles.clear(); +} +// *************************************************************************** +void BNPFileHandle::releaseInstance() +{ + if (_Instance) + { + NLMISC::INelContext::getInstance().releaseSingletonPointer("BNPFileHandle", _Instance); + delete _Instance; + _Instance = NULL; + } +} +// *************************************************************************** +bool BNPFileHandle::unpack(const string &dirName, const vector& fileList) +{ + FILE *bnp = fopen (m_activeBNPFile.c_str(), "rb"); + FILE *out; + if (bnp == NULL) + return false; + + TPackedFilesList::iterator it_files = m_packedFiles.begin(); + + for (it_files; it_files != m_packedFiles.end(); it_files++) + { + // Check if the file should be unpacked or not + if (find(fileList.begin(), fileList.end(), it_files->m_name) != fileList.end()) + { + string filename = dirName + "/" + it_files->m_name; + + out = fopen (filename.c_str(), "wb"); + if (out != NULL) + { + nlfseek64 (bnp, it_files->m_pos, SEEK_SET); + uint8 *ptr = new uint8[it_files->m_size]; + if (fread (ptr, it_files->m_size, 1, bnp) != 1) + { + nlwarning("%s read error", filename.c_str()); + return false; + } + if (fwrite (ptr, it_files->m_size, 1, out) != 1) + { + nlwarning("%s write error", filename.c_str()); + return false; + } + fclose (out); + delete [] ptr; + } + } + } + fclose (bnp); + return true; +} +// *************************************************************************** +// Read the header from a big file +bool BNPFileHandle::readHeader(const std::string &filename) +{ + m_packedFiles.clear(); + + m_activeBNPFile = filename; + + FILE *f = fopen (filename.c_str(), "rb"); + if (f == NULL) + { + nlwarning("Could not open file!"); + return false; + } + + nlfseek64 (f, 0, SEEK_END); + uint32 nFileSize=CFile::getFileSize (filename ); + nlfseek64 (f, nFileSize-sizeof(uint32), SEEK_SET); + + uint32 nOffsetFromBegining; + + if (fread (&nOffsetFromBegining, sizeof(uint32), 1, f) != 1) + { + fclose (f); + return false; + } +#ifdef NL_BIG_ENDIAN + NLMISC_BSWAP32(nOffsetFromBegining); +#endif + + if (nlfseek64 (f, nOffsetFromBegining, SEEK_SET) != 0) + { + nlwarning("Could not read offset from begining"); + fclose (f); + return false; + } + + uint32 nNbFile; + if (fread (&nNbFile, sizeof(uint32), 1, f) != 1) + { + nlwarning("Could not read number of files!"); + fclose (f); + return false; + } + +#ifdef NL_BIG_ENDIAN + NLMISC_BSWAP32(nNbFile); +#endif + + for (uint32 i = 0; i < nNbFile; ++i) + { + uint8 nStringSize; + char sName[256]; + if (fread (&nStringSize, 1, 1, f) != 1) + { + nlwarning("Error reading packed filename!"); + fclose (f); + return false; + } + if (fread (sName, 1, nStringSize, f) != nStringSize) + { + fclose (f); + return false; + } + sName[nStringSize] = 0; + PackedFile tmpPackedFile; + tmpPackedFile.m_name = sName; + if (fread (&tmpPackedFile.m_size, sizeof(uint32), 1, f) != 1) + { + nlwarning("Error reading packed file size!"); + fclose (f); + return false; + } +#ifdef NL_BIG_ENDIAN + NLMISC_BSWAP32(tmpBNPFile.Size); +#endif + if (fread (&tmpPackedFile.m_pos, sizeof(uint32), 1, f) != 1) + { + nlwarning("Error reading packed file position!"); + fclose (f); + return false; + } +#ifdef NL_BIG_ENDIAN + NLMISC_BSWAP32(tmpBNPFile.Pos); +#endif + m_packedFiles.push_back (tmpPackedFile); + } + + fclose (f); + return true; +} +// *************************************************************************** +void BNPFileHandle::list(TPackedFilesList& FileList) +{ + PackedFile tmpFile; + TPackedFilesList::iterator it = m_packedFiles.begin(); + while (it != m_packedFiles.end() ) + { + tmpFile.m_name = it->m_name; + tmpFile.m_pos = it->m_pos; + tmpFile.m_size = it->m_size; + FileList.push_back(tmpFile); + it++; + } +} +// *************************************************************************** +} // namespace BNPManager \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_file.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_file.h new file mode 100644 index 000000000..d1c642e3d --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_file.h @@ -0,0 +1,103 @@ +// Object Viewer Qt - BNP Manager Plugin - MMORPG Framework +// Copyright (C) 2011 Roland Winklmeier +// +// 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 . + +#ifndef BNP_FILE_H +#define BNP_FILE_H + +// Project includes + +// Nel includes +#include "nel/misc/types_nl.h" +#include + +// Qt includes +#include + + +namespace BNPManager +{ + +struct PackedFile +{ + std::string m_name; + uint32 m_size; + uint32 m_pos; +}; + +typedef std::vector TPackedFilesList; + +class BNPFileHandle +{ + NLMISC_SAFE_SINGLETON_DECL(BNPFileHandle) + + /** + * Private constructor + */ + BNPFileHandle(); + + /** + * Private destructor + */ + ~BNPFileHandle(); + +public: + // release memory + static void releaseInstance(); + + /*void append (const QString destFilename, const QString origFilename, uint32 sizeToRead); + void packRecurse();*/ + + /** + * Read the header from the bnp file and create a filelist + * \param filename (consisting the whole path) + */ + bool readHeader (const std::string &filename); + + /** + * Append the header to a created bnp file + * \param filename (consisting the whole path) + */ + void appendHeader (const std::string &filename) {}; + + /** + * Create a list of all packed files inside the bnp file + * \param reference to the list, which has to be filled + */ + void list (TPackedFilesList& FileList); + + /** + * Unpack the selected packed files into user defined dir + * \param directory path, where the files should be unpacked + * \param list of files, which has to be unpacked + */ + bool unpack (const std::string &dirName, const std::vector& fileList); + +private: + + TPackedFilesList m_packedFiles; + + // currently opened and displayed bnp file + std::string m_activeBNPFile; + + // offset where the header of the bnp file begins + uint32 m_offsetFromBeginning; + +}; + + +} + +#endif \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_filelist_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_filelist_dialog.cpp new file mode 100644 index 000000000..b78e6c0bf --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_filelist_dialog.cpp @@ -0,0 +1,122 @@ +// Object Viewer Qt - BNP Manager Plugin - MMORPG Framework +// Copyright (C) 2011 Roland Winklmeier +// +// 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 . + +// Project includes +#include "bnp_filelist_dialog.h" +#include "bnp_file.h" + +// Qt includes +#include + +// NeL includes +#include + +using namespace std; + +namespace BNPManager +{ + +BnpFileListDialog::BnpFileListDialog(QString bnpPath, QWidget *parent) + : QDockWidget(parent), + m_DataPath(bnpPath) +{ + m_ui.setupUi(this); +} +// *************************************************************************** +BnpFileListDialog::~BnpFileListDialog() +{ + +} +// *************************************************************************** +void BnpFileListDialog::setupTable(int nbrows) +{ + // delete all old entries + m_ui.tableWidget->clear(); + + // set 2 colums: filename and size + m_ui.tableWidget->setColumnCount(2); + + // set number of rows according to the number of files in the bnp file + m_ui.tableWidget->setRowCount(nbrows); + + // only entire rows can be selected + m_ui.tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows); + + // set the horizontal headers + QStringList labels; + labels << tr("Filename") << tr("Size"); + m_ui.tableWidget->setHorizontalHeaderLabels(labels); + + m_ui.tableWidget->horizontalHeader()->setResizeMode(0, QHeaderView::Interactive); + m_ui.tableWidget->horizontalHeader()->setResizeMode(1, QHeaderView::Stretch ); + m_ui.tableWidget->verticalHeader()->hide(); + + // set vertical size a little bit smaller + m_ui.tableWidget->verticalHeader()->setDefaultSectionSize(15); + m_ui.tableWidget->setShowGrid(false); + m_ui.tableWidget->setObjectName("tablewidget"); +} +// *************************************************************************** +bool BnpFileListDialog::loadTable(const QString fileName) +{ + // reference to the BNPFileHandle singletone instance + BNPFileHandle& myBNPFileHandle = BNPFileHandle::getInstance(); + // string vector of all packed files inside a bnp + TPackedFilesList filelist; + int row = 0; + + // read the header from the bnp file + if (!myBNPFileHandle.readHeader( fileName.toStdString()) ) + { + return false; + } + myBNPFileHandle.list( filelist ); + + // create table with number of rows + setupTable(filelist.size()); + + // fill the table items + TPackedFilesList::iterator it = filelist.begin(); + while (it != filelist.end() ) + { + QTableWidgetItem *nameItem = new QTableWidgetItem (it->m_name.c_str() ); + QTableWidgetItem *sizeItem = new QTableWidgetItem (tr("%1 KB").arg(it->m_size)); + m_ui.tableWidget->setItem(row, 0, nameItem); + m_ui.tableWidget->setItem(row, 1, sizeItem); + it++; + row++; + } + + return true; +} +// *************************************************************************** +void BnpFileListDialog::getSelections(TSelectionList& SelectionList) +{ + QModelIndex index; + QAbstractItemModel *model = m_ui.tableWidget->model(); + QItemSelectionModel *selection = m_ui.tableWidget->selectionModel(); + QModelIndexList indexes = selection->selectedRows(); + + Q_FOREACH(index, indexes) + { + QVariant data = model->data(index); + QString filename = data.toString(); + SelectionList.push_back( filename.toStdString() ); + } +} +// *************************************************************************** + +} // namespace BNPManager \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_filelist_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_filelist_dialog.h new file mode 100644 index 000000000..f2cc021a9 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_filelist_dialog.h @@ -0,0 +1,81 @@ +// Object Viewer Qt - BNP Manager Plugin - MMORPG Framework +// Copyright (C) 2011 Roland Winklmeier +// +// 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 . + +#ifndef BNP_FILELIST_DIALOG_H +#define BNP_FILELIST_DIALOG_H + +// Qt includes +#include + +// STL includes +#include +#include + +// NeL includes + +// Project includes +#include "ui_bnp_filelist_dialog.h" + +namespace BNPManager +{ + +typedef std::vector TSelectionList; + +class BnpFileListDialog : public QDockWidget +{ + Q_OBJECT + +public: + + // Constructor + BnpFileListDialog(QString bnpPath, QWidget *parent = 0); + + // Destructor + ~BnpFileListDialog(); + + /** + * Load the bnp file and setup the table view + * \param Filename + * \return true if everything went well + */ + bool loadTable(const QString filename); + + /** + * Set the dimension of the table + * \param number of rows + */ + void setupTable(int nbrows); + + /** + * Fill the files selected in the table view to + * unpack them. + * \param reference to a vector of filenames. + * \return true if everything went well + */ + void getSelections(TSelectionList& SelectionList); + +private: + + Ui::BnpFileListDialog m_ui; + + // common data path as root folder for the dirtree view + QString m_DataPath; + +}; + +} + +#endif diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_filelist_dialog.ui b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_filelist_dialog.ui new file mode 100644 index 000000000..9f62ff7c0 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_filelist_dialog.ui @@ -0,0 +1,70 @@ + + + BnpFileListDialog + + + + 0 + 0 + 400 + 300 + + + + + 0 + 0 + + + + + 200 + 141 + + + + true + + + QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable + + + BNP File List + + + + + 50 + 0 + + + + + + + true + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::SelectRows + + + false + + + 15 + + + + + + + + + + + + + diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_filesystem_model.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_filesystem_model.cpp new file mode 100644 index 000000000..eaf6389f5 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_filesystem_model.cpp @@ -0,0 +1,52 @@ +// Object Viewer Qt - BNP Manager Plugin - MMORPG Framework +// Copyright (C) 2011 Roland Winklmeier +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see + +#include "bnp_filesystem_model.h" + +#include +#include + +namespace BNPManager +{ + +BNPFileSystemModel::BNPFileSystemModel(QObject *parent) + : QFileSystemModel(parent) +{ + +} +// *************************************************************************** +BNPFileSystemModel::~BNPFileSystemModel() +{ + +} +// *************************************************************************** +int BNPFileSystemModel::columnCount(const QModelIndex &) const +{ + return 1; +} +// *************************************************************************** +QVariant BNPFileSystemModel::data(const QModelIndex& index, int role) const +{ + + if (role == Qt::DecorationRole) + { + if (isDir(index)) + return QApplication::style()->standardIcon(QStyle::SP_DirIcon); + } + return QFileSystemModel::data(index, role); +} +// *************************************************************************** +} // namespace BNPManager diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_filesystem_model.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_filesystem_model.h new file mode 100644 index 000000000..2ca086b39 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_filesystem_model.h @@ -0,0 +1,49 @@ +// Object Viewer Qt - BNP Manager Plugin - MMORPG Framework +// Copyright (C) 2011 Roland Winklmeier +// +// 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 + +#ifndef BNP_FILESYSTEM_MODEL_H +#define BNP_FILESYSTEM_MODEL_H + +#include + +namespace BNPManager +{ + +class BNPFileSystemModel : public QFileSystemModel +{ + Q_OBJECT + +public: + + /** + * Constructor + */ + BNPFileSystemModel(QObject *parent = 0); + + /** + * Destructor + */ + ~BNPFileSystemModel(); + + int columnCount(const QModelIndex &) const; + + QVariant data(const QModelIndex& index, int role) const ; + +}; + +} + +#endif \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager.qrc b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager.qrc new file mode 100644 index 000000000..bf32595d6 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager.qrc @@ -0,0 +1,9 @@ + + + images/ic_nel_bnp_make.png + images/ic_nel_delete_item.png + images/ic_nel_add_item.png + images/ic_nel_export.png + images/ic_nel_reset_all.png + + diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_constants.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_constants.h new file mode 100644 index 000000000..7ec5eecd0 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_constants.h @@ -0,0 +1,37 @@ +// Object Viewer Qt - BNP Manager Plugin - MMORPG Framework +// Copyright (C) 2011 Roland Winklmeier +// +// 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 . + +#ifndef BNP_MANAGER_CONSTANTS_H +#define BNP_MANAGER_CONSTANTS_H + +namespace BNPManager +{ +namespace Constants +{ +//settings +const char * const BNP_MANAGER_SECTION = "BNPManager"; + +//resources +const char *const ICON_ADD = ":/images/ic_nel_add_item.png"; +const char *const ICON_DELETE = ":/images/ic_nel_delete_item.png"; +const char *const ICON_UNPACK = ":/images/ic_nel_export.png"; +const char *const ICON_CLOSE = ":/images/ic_nel_reset_all.png"; + + +} // namespace Constants +} // namespace Plugin + +#endif diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_plugin.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_plugin.cpp new file mode 100644 index 000000000..70015773b --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_plugin.cpp @@ -0,0 +1,89 @@ +// Object Viewer Qt - BNP Manager Plugin - MMORPG Framework +// Copyright (C) 2011 Roland Winklmeier +// +// 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 . + +// Project includes +#include "bnp_manager_plugin.h" +#include "bnp_manager_window.h" + +#include "../core/icore.h" +#include "../core/core_constants.h" +#include "../core/menu_manager.h" + +// NeL includes +#include "nel/misc/debug.h" + +// Qt includes +#include +#include + +namespace BNPManager +{ + + BNPManagerPlugin::BNPManagerPlugin() + { + } + + BNPManagerPlugin::~BNPManagerPlugin() + { + Q_FOREACH(QObject *obj, m_autoReleaseObjects) + { + m_plugMan->removeObject(obj); + } + qDeleteAll(m_autoReleaseObjects); + m_autoReleaseObjects.clear(); + } + +bool BNPManagerPlugin::initialize(ExtensionSystem::IPluginManager *pluginManager, QString *errorString) +{ + Q_UNUSED(errorString); + m_plugMan = pluginManager; + + addAutoReleasedObject(new BNPManagerContext(this)); + return true; +} + +void BNPManagerPlugin::extensionsInitialized() +{ +} + +void BNPManagerPlugin::shutdown() +{ + +} + +void BNPManagerPlugin::setNelContext(NLMISC::INelContext *nelContext) +{ +#ifdef NL_OS_WINDOWS + // Ensure that a context doesn't exist yet. + // This only applies to platforms without PIC, e.g. Windows. + nlassert(!NLMISC::INelContext::isContextInitialised()); +#endif // NL_OS_WINDOWS + m_libContext = new NLMISC::CLibraryContext(*nelContext); +} + +void BNPManagerPlugin::addAutoReleasedObject(QObject *obj) +{ + m_plugMan->addObject(obj); + m_autoReleaseObjects.prepend(obj); +} + +/*void BNPManagerContext::open() +{ + m_BnpManagerWindow->open(); +}*/ +} + +Q_EXPORT_PLUGIN(BNPManager::BNPManagerPlugin) diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_plugin.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_plugin.h new file mode 100644 index 000000000..55e2e8444 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_plugin.h @@ -0,0 +1,130 @@ +// Object Viewer Qt - BNP Manager Plugin - MMORPG Framework +// Copyright (C) 2011 Roland Winklmeier +// +// 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 . + +#ifndef BNP_MANAGER_PLUGIN_H +#define BNP_MANAGER_PLUGIN_H + +// Project includes +#include "../../extension_system/iplugin.h" +#include "../core/icontext.h" +#include "bnp_manager_window.h" + +// NeL includes +#include "nel/misc/app_context.h" +#include + +// Qt includes +#include +#include + +namespace NLMISC +{ +class CLibraryContext; +} + +namespace ExtensionSystem +{ +class IPluginSpec; +} + +namespace BNPManager +{ +class m_BnpManagerWindow; + +class BNPManagerPlugin : public QObject, public ExtensionSystem::IPlugin +{ + Q_OBJECT + Q_INTERFACES(ExtensionSystem::IPlugin) + +public: + BNPManagerPlugin(); + virtual ~BNPManagerPlugin(); + + virtual bool initialize(ExtensionSystem::IPluginManager *pluginManager, QString *errorString); + virtual void extensionsInitialized(); + virtual void shutdown(); + virtual void setNelContext(NLMISC::INelContext *nelContext); + + void addAutoReleasedObject(QObject *obj); + +protected: + + NLMISC::CLibraryContext *m_libContext; + +private: + + ExtensionSystem::IPluginManager *m_plugMan; + QList m_autoReleaseObjects; +}; + +/** + * Implementation of the IContext interface + * + * \date 2011 + */ + +class BNPManagerContext : public Core::IContext +{ + Q_OBJECT + +public: + // Constructor + BNPManagerContext(QObject *parent = 0) : IContext(parent) + { + // run new manager window app + m_BnpManagerWindow = new BNPManagerWindow(); + } + + // Destructor + virtual ~BNPManagerContext() {} + + virtual QString id() const + { + return QLatin1String("BNPManagerContext"); + } + virtual QString trName() const + { + return tr("BNP Manager"); + } + virtual QIcon icon() const + { + return QIcon(":/images/ic_nel_bnp_make.png"); + } + + virtual void open() + { + m_BnpManagerWindow->open(); + } + + virtual QUndoStack *undoStack() + { + return m_BnpManagerWindow->m_undoStack; + } + + virtual QWidget *widget() + { + return m_BnpManagerWindow; + } + + BNPManagerWindow *m_BnpManagerWindow; + +}; + +} // namespace Plugin + + + +#endif // BNP_MANAGER_PLUGIN_H diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_window.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_window.cpp new file mode 100644 index 000000000..3ed36d181 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_window.cpp @@ -0,0 +1,223 @@ +// Object Viewer Qt - BNP Manager Plugin - MMORPG Framework +// Copyright (C) 2011 Roland Winklmeier +// +// 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 . + +// Project includes +#include "bnp_manager_window.h" +#include "bnp_manager_constants.h" +#include "bnp_dirtree_dialog.h" +#include "bnp_filelist_dialog.h" +#include "bnp_file.h" + +#include "../core/icore.h" +#include "../core/menu_manager.h" +#include "../core/core_constants.h" +#include "../../extension_system/iplugin_spec.h" + +// NeL includes +#include + +// Qt includes +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace NLMISC; + + +namespace BNPManager +{ + +BNPManagerWindow::BNPManagerWindow(QWidget *parent) + : QMainWindow(parent) +{ + // add new mainwindow for sheet dockwidgets + QTableWidget* hideWidget = new QTableWidget(0,0,this); + setCentralWidget(hideWidget); + hideWidget->hide(); + + // Read the settings + readSettings(); + + // create main dialogs and display them + createDialogs(); + + // create actions like open, close, add etc. + createActions(); + + // create a toolbar with icons + createToolBars(); + + // this SLOT is triggered if the user activates a bnp files in the + // dirtree view + connect(m_BnpDirTreeDialog, SIGNAL(selectedForm(const QString)), + this, SLOT(loadFile(const QString))); + + // not used + m_undoStack = new QUndoStack(this); +} +// *************************************************************************** +BNPManagerWindow::~BNPManagerWindow() +{ + writeSettings(); +} +// *************************************************************************** +void BNPManagerWindow::createDialogs() +{ + // create dialog to list the contents of the specified + // bnp data file directory + m_BnpDirTreeDialog = new CBnpDirTreeDialog(tr(m_DataPath.toStdString().c_str()),this); + addDockWidget(Qt::LeftDockWidgetArea, m_BnpDirTreeDialog); + m_BnpDirTreeDialog->setVisible(true); + restoreDockWidget(m_BnpDirTreeDialog); + + // create dialog to list the packed file contents of bnp files on + // the right hand side + m_BnpFileListDialog = new BnpFileListDialog(m_DataPath,this); + addDockWidget(Qt::RightDockWidgetArea, m_BnpFileListDialog); + m_BnpFileListDialog->setVisible(true); + restoreDockWidget(m_BnpFileListDialog); +} +// *************************************************************************** +void BNPManagerWindow::createActions() +{ + // open action + m_openAction = new QAction(tr("&Open..."), this); + m_openAction->setIcon(QIcon(Core::Constants::ICON_OPEN)); + m_openAction->setStatusTip(tr("Open file")); + connect(m_openAction, SIGNAL(triggered()), this, SLOT( open() )); + + // close action + m_closeAction = new QAction(tr("&Close..."), this); + m_closeAction->setIcon(QIcon(Constants::ICON_CLOSE)); + m_closeAction->setStatusTip(tr("Close the BNP File")); + connect(m_closeAction, SIGNAL(triggered()), this, SLOT( close() )); + + // add files into the bnp file + m_addFilesAction = new QAction(tr("&Add..."), this); + m_addFilesAction->setIcon(QIcon(Constants::ICON_ADD)); + m_addFilesAction->setStatusTip(tr("Add Files to BNP")); + connect(m_addFilesAction, SIGNAL(triggered()), this, SLOT( addFiles() )); + + // delete files from the bnp file + m_deleteFilesAction = new QAction(tr("&Delete..."), this); + m_deleteFilesAction->setIcon(QIcon(Constants::ICON_DELETE)); + m_deleteFilesAction->setStatusTip(tr("Delete Files")); + connect(m_deleteFilesAction, SIGNAL(triggered()), this, SLOT( deleteFiles() )); + + // unpack selected files into user defined dir + m_unpackFilesAction = new QAction(tr("&Unpack..."), this); + m_unpackFilesAction->setIcon(QIcon(Constants::ICON_UNPACK)); + m_unpackFilesAction->setStatusTip(tr("Unpack Files")); + connect(m_unpackFilesAction, SIGNAL(triggered()), this, SLOT( unpackFiles() )); +} +// *************************************************************************** +void BNPManagerWindow::createToolBars() +{ + m_fileToolBar = addToolBar(tr("&File")); + m_fileToolBar->addAction(m_openAction); + m_fileToolBar->addAction(m_closeAction); + + m_toolsBar = addToolBar(tr("&Tools")); + m_toolsBar->addAction(m_addFilesAction); + m_toolsBar->addAction(m_deleteFilesAction); + m_toolsBar->addAction(m_unpackFilesAction); +} +// *************************************************************************** +bool BNPManagerWindow::loadFile(const QString fileName) +{ + m_BnpFileListDialog->loadTable(fileName); + return true; +} +// *************************************************************************** +void BNPManagerWindow::open() +{ + QString fileName; + // file dialog to select with file should be opened + fileName = QFileDialog::getOpenFileName(this, + tr("Open BNP file"), tr(m_DataPath.toStdString().c_str()), tr("BNP Files (*.bnp)")); + + // check if there is a filename + if (fileName.isNull()) + return; + loadFile(fileName); +} +// *************************************************************************** +void BNPManagerWindow::close() +{ + //TODO +} +// *************************************************************************** +void BNPManagerWindow::addFiles() +{ + //TODO +} +// *************************************************************************** +void BNPManagerWindow::deleteFiles() +{ + //TODO +} +// *************************************************************************** +void BNPManagerWindow::unpackFiles() +{ + QFileDialog filedialog(this); + BNPFileHandle& myBNPFileHandle = BNPFileHandle::getInstance(); + vector selectedrows; + + m_BnpFileListDialog->getSelections(selectedrows); + + // Check if files were selected. If not, inform the user. + // TODO: Ask the user if nothing was selected, if he wants to unpack all + // files. This is more like Winzip. + if (selectedrows.empty()) + { + QMessageBox::information(this, tr("BNP Manager"), + tr("No files were selected to unpack!"), + QMessageBox::Ok, + QMessageBox::Ok); + return; + } + + QString dir = QFileDialog::getExistingDirectory(this, tr("Open Directory"), + tr(m_DataPath.toStdString().c_str()), + QFileDialog::ShowDirsOnly + | QFileDialog::DontResolveSymlinks); + + if (myBNPFileHandle.unpack(dir.toStdString(),selectedrows)) + { + QMessageBox::information(this, tr("BNP Manager"), + tr("All files has been exported successfully."), + QMessageBox::Ok, + QMessageBox::Ok); + } +} +// *************************************************************************** +void BNPManagerWindow::readSettings() +{ + QSettings *settings = Core::ICore::instance()->settings(); + + settings->beginGroup(Core::Constants::DATA_PATH_SECTION); + m_DataPath = settings->value(Core::Constants::ASSETS_PATH, "w:/database").toString(); + settings->endGroup(); +} +// *************************************************************************** +void BNPManagerWindow::writeSettings() +{ +} +} // namespace BNPManager diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_window.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_window.h new file mode 100644 index 000000000..b38e2b7be --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_window.h @@ -0,0 +1,146 @@ +// Object Viewer Qt - BNP Manager Plugin - MMORPG Framework +// Copyright (C) 2011 Roland Winklmeier +// +// 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 . + +#ifndef BNP_MANAGER_WINDOW_H +#define BNP_MANAGER_WINDOW_H + +// Project includes +//#include "ui_bnp_manager_window.h" + +// Qt includes +#include +#include +#include +#include + + +namespace BNPManager +{ + +class CBnpDirTreeDialog; +class BnpFileListDialog; +class BNPFileHandle; + +/** + * Main window class. Derived from QMainWindow and implements + * the basic layout like menue, toolbars and dialogs. + * + * \date 2011 + */ + +class BNPManagerWindow : public QMainWindow +{ + Q_OBJECT + +public: + + // Constructor + BNPManagerWindow(QWidget *parent = 0); + + //Destructor + ~BNPManagerWindow(); + + + QUndoStack *m_undoStack; + +public Q_SLOTS: + + /** + * Open a file dialog to choose which file should be opened. + * \return Filename string + */ + void open(); + + /** + * Load a certain bnp file into the manager + * \param Filename + * \return true if everything went well + */ + bool loadFile(const QString fileName); + + /** + * close an opened bnp file and reset all views + */ + void close(); + + /** + * Add files into an opened bnp file. + * \param Filelist + */ + void addFiles(); + + /** + * Unpack the files marked in the filelist dialog into user defined + * directory. + * \param TBD + * \return true if everything went well + */ + void unpackFiles(); + + /** + * Delete marked files from the bnp file + * \param TBD + */ + void deleteFiles(); + +private: + + /** + * Read plugin settings and set the window accordingly + */ + void readSettings(); + + /** + * Write plugin settings + */ + void writeSettings(); + + /** + * Create all plugin dialogs + */ + void createDialogs(); + + /** + * Create all plugin actions + */ + void createActions(); + + /** + * Create the plugin toolbar + */ + void createToolBars(); + + QToolBar *m_fileToolBar; + QToolBar *m_toolsBar; + + QAction *m_openAction; + QAction *m_closeAction; + QAction *m_addFilesAction; + QAction *m_unpackFilesAction; + QAction *m_deleteFilesAction; + + CBnpDirTreeDialog *m_BnpDirTreeDialog; + BnpFileListDialog *m_BnpFileListDialog; + + QString m_DataPath; + + BNPFileHandle *m_BNPFileHandle; + +}; /* class BNPManagerWindow */ + +} /* namespace Plugin */ + +#endif diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_window.ui b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_window.ui new file mode 100644 index 000000000..4e695f72c --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_window.ui @@ -0,0 +1,50 @@ + + + BNPManagerWindow + + + + 0 + 0 + 800 + 600 + + + + BNP Manager + + + + + + + QWidget#centralwidget { + image: url(:/images/ic_nel_georges_editor.png); + } + + + + + + + + + + + + + toolBar + + + TopToolBarArea + + + false + + + + + + + + diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/images/ic_nel_add_item.png b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/images/ic_nel_add_item.png new file mode 100644 index 0000000000000000000000000000000000000000..bde338f7851d2675b29272c7dcf9471196a8f6cc GIT binary patch literal 3270 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 Eg5p97)c^nh literal 0 HcmV?d00001 diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/images/ic_nel_bnp_make.png b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/images/ic_nel_bnp_make.png new file mode 100644 index 0000000000000000000000000000000000000000..19b749b1da76ec5ae8a7f063c7127f5672915ef6 GIT binary patch literal 25705 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 literal 0 HcmV?d00001 diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/images/ic_nel_delete_item.png b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/images/ic_nel_delete_item.png new file mode 100644 index 0000000000000000000000000000000000000000..a5a1787d593591f855be9a7eb8da271cc8d8f214 GIT binary patch literal 1496 zcmaKs{XY{30LC|C-c2!W(h#B2QhA@kOt{brn;~tK$;-mn#DM?-zdb>=i zu*@RTd8@_pvUxpuxyoG1>Bsxw?uX}jKHujL_-0@|T~w8{l>h*Ms+%k3&``sHb<81=-~(e+|N^9C&_KHVw5X^3IM3J{S1(sAHJ}8!egC%W4+FY#L`JIX8~B! zIZ7C+< z6bcMhk7Jz$z zt<~^Npzeyeat^;b(tkMW#bRkwb5S`|-P(cZ{!1geIKC7Tzpi^Q9XhN7r*| zh)Tmw?h}4)r(e%EPx*~jbiDn>W9k_F^gyx#1J1b!&uZuD!J$Duh_I|$-B|3)pjcABT`DZr@@$gnJ?g*7niqC zPg~-q=_uM61|+bWZC}wlE4;C-L;LVrU6J(R@D0Z4=p`kt`4==LnW(d8wXiBZND)3NugXyk}j`B>QSp`rx>7I47#1U z_C?Zqn_!w_iq*Q=7#33$KOO+R;CW!bcdn#k;~tqqg>*o8s|#;{%M1@^2B=`1X*QOW z`~~EL<8YMd;Wk~hP%ln9+T{3weTCGPC>#3IdbbgtfSL(^;<-$(&+()%CWY(ZY}rUs zYZ^=Sws7E+dDpj6e_>>!qz;jFg;SMzWx6GvaM=_CJv#h+^qF(IggsR{8BYMQlBT|c zLR(J;=NJUkn>YRLcdDtY?zXt@zIEUuTe=1hEndEU6|7%)i#=`5cs5S}P9Mh=PcJfo z{ZbSwueq|yZyG~GMGk&1;XI&33fgfyu~6eIQgk!Fkv4<^W8F=|9U5oXINb+#fCen_ z{sB?u3Xfi@SxqMAC%ZI%1BJIf0uMiCx!yXz62rndMv z$=6toP8$LinV$s7C|ZjMS5+@W1rn4NxN=o7bmp|tGx-1vXy7V6(LK7Owl1b<1|o_O z>bY9rcsZ;+(mT(U8Vqy|@K*SC7Xeg!@WG?ntw{ZC`G3Vh1-90Bf1vJ=9f)jI$P4Q6YBQ@Z8;^^H#>9pe+1$q6DXU$-5VbBeJ(3kUiuh943T}3C$!G=4Zw&rX zIZx;etQ%$b10W;H`0fD|-g&n~Eq? zJZ zC}pc4u@0qD`7mQX=zMD+8o3Hi#&31p7{mxJ*6-KkigeYIgt}@Xn1a05YyE6U8VHU~ z8PL=CTn*0W$(#-|89Sz`9P!(hY?pOfm^ZQVXfjUeBhD+B#yUg0vkok?_%`$Xq0`=> g{}tB1bjDO$2a)_&SEAML{IoE@&Dj&vfF`E?18{b*hyVZp literal 0 HcmV?d00001 diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/images/ic_nel_export.png b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/images/ic_nel_export.png new file mode 100644 index 0000000000000000000000000000000000000000..9fc71c09dab0615021bb5c813d47e3f5b2a72623 GIT binary patch literal 27878 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 literal 0 HcmV?d00001 diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/images/ic_nel_reset_all.png b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/images/ic_nel_reset_all.png new file mode 100644 index 0000000000000000000000000000000000000000..c6728740865db94a38a7d740accd930a9c8326d5 GIT binary patch literal 30281 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 + ovqt_plugin_bnp_manager + BNPManager + 0.1 + Krolock + Edit BNP Files + + + + \ No newline at end of file From 9f0e1482dd6db0b90aeca6872cb8c69a0eaba94c Mon Sep 17 00:00:00 2001 From: kervala Date: Sat, 7 Jan 2012 19:14:24 +0100 Subject: [PATCH 21/46] Fixed: ryzom_client_patcher missing file --- code/ryzom/tools/client/client_patcher/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/code/ryzom/tools/client/client_patcher/CMakeLists.txt b/code/ryzom/tools/client/client_patcher/CMakeLists.txt index 5ea9b320d..afe2cbc31 100644 --- a/code/ryzom/tools/client/client_patcher/CMakeLists.txt +++ b/code/ryzom/tools/client/client_patcher/CMakeLists.txt @@ -1,4 +1,5 @@ FILE(GLOB SRC main.cpp + ${CMAKE_SOURCE_DIR}/ryzom/client/src/app_bundle_utils.cpp ${CMAKE_SOURCE_DIR}/ryzom/client/src/client_cfg.cpp ${CMAKE_SOURCE_DIR}/ryzom/client/src/login_patch.cpp ${CMAKE_SOURCE_DIR}/ryzom/client/src/login_xdelta.cpp From 3bf819651e79ccacb9878479fd948c4a593beb0c Mon Sep 17 00:00:00 2001 From: kervala Date: Tue, 10 Jan 2012 10:19:52 +0100 Subject: [PATCH 22/46] Fixed: #1420 Client patcher compilation under Mac OS X --- code/ryzom/tools/client/client_patcher/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/code/ryzom/tools/client/client_patcher/CMakeLists.txt b/code/ryzom/tools/client/client_patcher/CMakeLists.txt index afe2cbc31..4a8b47bdf 100644 --- a/code/ryzom/tools/client/client_patcher/CMakeLists.txt +++ b/code/ryzom/tools/client/client_patcher/CMakeLists.txt @@ -22,6 +22,11 @@ TARGET_LINK_LIBRARIES(ryzom_client_patcher ryzom_sevenzip ${CURL_LIBRARIES}) +IF(APPLE) + FIND_LIBRARY(FOUNDATION_LIBRARY Foundation) + TARGET_LINK_LIBRARIES(ryzom_client_patcher ${FOUNDATION_LIBRARY}) +ENDIF(APPLE) + ADD_DEFINITIONS(${LIBXML2_DEFINITIONS} ${CURL_DEFINITIONS} -DRZ_NO_CLIENT -DNL_USE_SEVENZIP) NL_DEFAULT_PROPS(ryzom_client_patcher "Ryzom, Tools: Ryzom Client Patcher") From b112ec5f91af28068d51906a47ff735f5c2b6b15 Mon Sep 17 00:00:00 2001 From: Krolock Date: Wed, 11 Jan 2012 20:54:54 +0100 Subject: [PATCH 23/46] Added: Implemented bnp_manager_plugin add and delete files --- .../src/plugins/bnp_manager/bnp_file.cpp | 194 +++++++++++++++++- .../src/plugins/bnp_manager/bnp_file.h | 46 ++++- .../bnp_manager/bnp_manager_window.cpp | 76 ++++++- .../plugins/bnp_manager/bnp_manager_window.h | 9 +- 4 files changed, 306 insertions(+), 19 deletions(-) diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_file.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_file.cpp index d6782a9a7..370b6e3a9 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_file.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_file.cpp @@ -33,6 +33,12 @@ using namespace std; namespace BNPManager { +PackedFile::PackedFile() +{ + m_size = 0; + m_pos = 0; +} + NLMISC_SAFE_SINGLETON_IMPL(BNPFileHandle); BNPFileHandle::BNPFileHandle() @@ -58,7 +64,7 @@ void BNPFileHandle::releaseInstance() // *************************************************************************** bool BNPFileHandle::unpack(const string &dirName, const vector& fileList) { - FILE *bnp = fopen (m_activeBNPFile.c_str(), "rb"); + FILE *bnp = fopen (m_openedBNPFile.c_str(), "rb"); FILE *out; if (bnp == NULL) return false; @@ -97,13 +103,13 @@ bool BNPFileHandle::unpack(const string &dirName, const vector& fileList } // *************************************************************************** // Read the header from a big file -bool BNPFileHandle::readHeader(const std::string &filename) +bool BNPFileHandle::readHeader(const std::string &filePath) { m_packedFiles.clear(); - m_activeBNPFile = filename; + m_openedBNPFile = filePath; - FILE *f = fopen (filename.c_str(), "rb"); + FILE *f = fopen (filePath.c_str(), "rb"); if (f == NULL) { nlwarning("Could not open file!"); @@ -111,7 +117,7 @@ bool BNPFileHandle::readHeader(const std::string &filename) } nlfseek64 (f, 0, SEEK_END); - uint32 nFileSize=CFile::getFileSize (filename ); + uint32 nFileSize=CFile::getFileSize (filePath ); nlfseek64 (f, nFileSize-sizeof(uint32), SEEK_SET); uint32 nOffsetFromBegining; @@ -162,6 +168,7 @@ bool BNPFileHandle::readHeader(const std::string &filename) sName[nStringSize] = 0; PackedFile tmpPackedFile; tmpPackedFile.m_name = sName; + tmpPackedFile.m_path = m_openedBNPFile; if (fread (&tmpPackedFile.m_size, sizeof(uint32), 1, f) != 1) { nlwarning("Error reading packed file size!"); @@ -196,9 +203,186 @@ void BNPFileHandle::list(TPackedFilesList& FileList) tmpFile.m_name = it->m_name; tmpFile.m_pos = it->m_pos; tmpFile.m_size = it->m_size; + tmpFile.m_path = it->m_path; FileList.push_back(tmpFile); it++; } } // *************************************************************************** +bool BNPFileHandle::writeHeader( const std::string &filePath, uint32 offset ) +{ + FILE *f = fopen (filePath.c_str(), "ab"); + if (f == NULL) return false; + + uint32 nNbFile = (uint32)m_packedFiles.size(); + if (fwrite (&nNbFile, sizeof(uint32), 1, f) != 1) + { + fclose(f); + return false; + } + + for (uint32 i = 0; i < nNbFile; ++i) + { + uint8 nStringSize = (uint8)m_packedFiles[i].m_name.size(); + if (fwrite (&nStringSize, 1, 1, f) != 1) + { + fclose(f); + return false; + } + + if (fwrite (m_packedFiles[i].m_name.c_str(), 1, nStringSize, f) != nStringSize) + { + fclose(f); + return false; + } + + if (fwrite (&m_packedFiles[i].m_size, sizeof(uint32), 1, f) != 1) + { + fclose(f); + return false; + } + + if (fwrite (&m_packedFiles[i].m_pos, sizeof(uint32), 1, f) != 1) + { + fclose(f); + return false; + } + } + + if (fwrite (&offset, sizeof(uint32), 1, f) != 1) + { + fclose(f); + return false; + } + + fclose (f); + return true; +} +// *************************************************************************** +void BNPFileHandle::fileNames(std::vector &fileNames) +{ + TPackedFilesList::iterator it = m_packedFiles.begin(); + while (it != m_packedFiles.end() ) + { + fileNames.push_back(it->m_name); + it++; + } +} +// *************************************************************************** +void BNPFileHandle::addFiles( const vector &filePathes) +{ + uint32 OffsetFromBegining = 0; + + // create packed files and add them to the private vector + vector::const_iterator it_vec = filePathes.begin(); + while (it_vec != filePathes.end() ) + { + PackedFile tmpFile; + tmpFile.m_name = CFile::getFilename (*it_vec); + // Leave position to 0 and set the value during the new bnp file is creating + // We need the position only for the header at the end + tmpFile.m_pos = 0; + tmpFile.m_size = CFile::getFileSize(*it_vec); + tmpFile.m_path = *it_vec; + m_packedFiles.push_back( tmpFile ); + + it_vec++; + } + + // sort packed files alphabetic + std::sort ( m_packedFiles.begin(), m_packedFiles.end(), compare ); + + // create a new temporary bnp file with extension *.tmp + TPackedFilesList::iterator it_packed = m_packedFiles.begin(); + while (it_packed != m_packedFiles.end() ) + { + append(m_openedBNPFile + ".tmp", *it_packed); + // Set now the new offset for the new header + it_packed->m_pos = OffsetFromBegining; + OffsetFromBegining += it_packed->m_size; + + it_packed++; + } + + writeHeader(m_openedBNPFile + ".tmp", OffsetFromBegining); + + CFile::deleteFile( m_openedBNPFile ); + string src = m_openedBNPFile + ".tmp"; + CFile::moveFile( m_openedBNPFile.c_str(), src.c_str() ); +} +// *************************************************************************** +void BNPFileHandle::deleteFiles( const vector& fileNames) +{ + vector::const_iterator it_vec; + TPackedFilesList::iterator it_packed; + uint32 OffsetFromBegining = 0; + string tmpFile = m_openedBNPFile + ".tmp"; + + // create a new temporary bnp file with extension *.tmp + it_packed = m_packedFiles.begin(); + while (it_packed != m_packedFiles.end() ) + { + // check each packed file if it should be deleted + it_vec = find (fileNames.begin(), fileNames.end(), it_packed->m_name ); + if ( it_vec != fileNames.end() ) + { + nlinfo("Deleting file %s.", it_packed->m_name.c_str() ); + it_packed = m_packedFiles.erase(it_packed); + } + else + { + append(tmpFile, *it_packed); + // Set now the new offset for the new header + it_packed->m_pos = OffsetFromBegining; + OffsetFromBegining += it_packed->m_size; + + it_packed++; + } + } + nldebug("Writing header..."); + + writeHeader(tmpFile, OffsetFromBegining); + + CFile::deleteFile( m_openedBNPFile ); + string src = m_openedBNPFile + ".tmp"; + CFile::moveFile( m_openedBNPFile.c_str(), src.c_str() ); +} +// *************************************************************************** +void BNPFileHandle::append(const string &destination, const PackedFile &source) +{ + // check if the file exists and create one if not + if ( !CFile::fileExists(destination) ) + CFile::createEmptyFile( destination ); + + FILE *bnpfile = fopen(destination.c_str(), "ab"); + FILE *packedfile = fopen(source.m_path.c_str(), "rb"); + if (bnpfile == NULL) return; + if (packedfile == NULL) { fclose(bnpfile); return; } + + uint8 *ptr = new uint8[source.m_size]; + + // check if the source is a bnp file. + if ( nlstricmp( CFile::getExtension(source.m_path), "bnp" ) == 0 ) + { + // Jump to the file position inside the bnp + nlfseek64(packedfile, source.m_pos, SEEK_SET); + } + // Read the source + if (fread (ptr, source.m_size, 1, packedfile) != 1) + nlwarning("%s read error", source.m_path.c_str()); + + // Append the data to the destination + if (fwrite (ptr, source.m_size, 1, bnpfile) != 1) + nlwarning("%s write error", destination.c_str()); + + delete [] ptr; + + fclose(packedfile); + fclose(bnpfile); +} +// *************************************************************************** +bool BNPFileHandle::compare(const PackedFile &left, const PackedFile &right) +{ + return nlstricmp (left.m_name.c_str(), right.m_name.c_str()) < 0; +} } // namespace BNPManager \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_file.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_file.h index d1c642e3d..e03d0e664 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_file.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_file.h @@ -32,9 +32,11 @@ namespace BNPManager struct PackedFile { + PackedFile(); std::string m_name; uint32 m_size; uint32 m_pos; + std::string m_path; }; typedef std::vector TPackedFilesList; @@ -64,7 +66,9 @@ public: * Read the header from the bnp file and create a filelist * \param filename (consisting the whole path) */ - bool readHeader (const std::string &filename); + bool readHeader (const std::string &filePath); + + bool writeHeader (const std::string &filePath, uint32 offset); /** * Append the header to a created bnp file @@ -73,10 +77,28 @@ public: void appendHeader (const std::string &filename) {}; /** - * Create a list of all packed files inside the bnp file - * \param reference to the list, which has to be filled + * Create a vector of all packed files inside the bnp file + * \param reference to the vector, which has to be filled */ void list (TPackedFilesList& FileList); + + /** + * Create a vector of all file names inside the bnp file + * \param reference to the vector, which has to be filled + */ + void fileNames( std::vector& fileNames ); + + /** + * Add files to the current aktive bnp file + * \param vector of file pathes to add + */ + void addFiles( const std::vector& filePathes ); + + /** + * Delete files from the current aktive bnp file + * \param vector of files names + */ + void deleteFiles (const std::vector& fileNames); /** * Unpack the selected packed files into user defined dir @@ -85,19 +107,33 @@ public: */ bool unpack (const std::string &dirName, const std::vector& fileList); + /** + * Compares two filenames + * \param left: left packed file + * \param right: right packed file + * \return: TODO + */ + static bool compare(const PackedFile &left, const PackedFile &right); + private: + /** + * Append one file to an existing bnp file + * \param destination: the active bnp file to append the file + * \param source: the source file to pack + */ + void append( const std::string& destination, const PackedFile& source ); + TPackedFilesList m_packedFiles; // currently opened and displayed bnp file - std::string m_activeBNPFile; + std::string m_openedBNPFile; // offset where the header of the bnp file begins uint32 m_offsetFromBeginning; }; - } #endif \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_window.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_window.cpp index 3ed36d181..33157733e 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_window.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_window.cpp @@ -28,6 +28,7 @@ // NeL includes #include +#include // Qt includes #include @@ -153,9 +154,11 @@ void BNPManagerWindow::open() fileName = QFileDialog::getOpenFileName(this, tr("Open BNP file"), tr(m_DataPath.toStdString().c_str()), tr("BNP Files (*.bnp)")); - // check if there is a filename + // Check if filename is empty if (fileName.isNull()) return; + + m_openedBNPFile = fileName; loadFile(fileName); } // *************************************************************************** @@ -166,12 +169,73 @@ void BNPManagerWindow::close() // *************************************************************************** void BNPManagerWindow::addFiles() { - //TODO + // reference to the BNPFileHandle singletone instance + BNPFileHandle& myBNPFileHandle = BNPFileHandle::getInstance(); + + // vector of all current packed filenames + vector currentFiles; + + // vector of files to add + vector addFiles; + + // open a file dialog and to add files + QStringList FileList; + + FileList = QFileDialog::getOpenFileNames(this,tr("Add Files..."), + QDir::currentPath(), tr("All Files (*.*)") ); + + // get all current filenames from the opened bnp file + myBNPFileHandle.fileNames(currentFiles); + + QStringList::iterator it_list = FileList.begin(); + while (it_list != FileList.end() ) + { + string fileName = CFile::getFilename (it_list->toStdString() ); + if ( std::find(currentFiles.begin(), currentFiles.end(), fileName ) != currentFiles.end() ) + { + // Ask the user if he wants to override the existing file + // atm only warn the user and do not override + QMessageBox::warning(this, tr("BNP Manager"), + tr("File is already in the list!"), + QMessageBox::Ok, + QMessageBox::Ok); + } + else + { + addFiles.push_back( it_list->toStdString() ); + // log it + nlinfo("Add file %s", fileName.c_str() ); + } + it_list++; + } + + if ( !addFiles.empty() ) + { + myBNPFileHandle.addFiles( addFiles ); + } + loadFile(m_openedBNPFile); } // *************************************************************************** void BNPManagerWindow::deleteFiles() { - //TODO + QFileDialog filedialog(this); + BNPFileHandle& myBNPFileHandle = BNPFileHandle::getInstance(); + vector selectedRows; + + m_BnpFileListDialog->getSelections(selectedRows); + + // Check if files were selected. If not, inform the user. + if (selectedRows.empty()) + { + QMessageBox::information(this, tr("BNP Manager"), + tr("No files selected!"), + QMessageBox::Ok, + QMessageBox::Ok); + return; + } + + myBNPFileHandle.deleteFiles(selectedRows); + loadFile(m_openedBNPFile); } // *************************************************************************** void BNPManagerWindow::unpackFiles() @@ -188,7 +252,7 @@ void BNPManagerWindow::unpackFiles() if (selectedrows.empty()) { QMessageBox::information(this, tr("BNP Manager"), - tr("No files were selected to unpack!"), + tr("No files selected!"), QMessageBox::Ok, QMessageBox::Ok); return; @@ -198,6 +262,10 @@ void BNPManagerWindow::unpackFiles() tr(m_DataPath.toStdString().c_str()), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + + // If anything went wrong or the user pressed "cancel" + if ( dir.isEmpty() ) + return; if (myBNPFileHandle.unpack(dir.toStdString(),selectedrows)) { diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_window.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_window.h index b38e2b7be..b31d17a09 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_window.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_window.h @@ -101,11 +101,11 @@ private: /** * Read plugin settings and set the window accordingly */ - void readSettings(); - + void readSettings(); + /** * Write plugin settings - */ + */ void writeSettings(); /** @@ -136,8 +136,7 @@ private: BnpFileListDialog *m_BnpFileListDialog; QString m_DataPath; - - BNPFileHandle *m_BNPFileHandle; + QString m_openedBNPFile; }; /* class BNPManagerWindow */ From 390dd139dd5b4d4db130de7607959bce1c69480d Mon Sep 17 00:00:00 2001 From: Krolock Date: Wed, 11 Jan 2012 23:52:18 +0100 Subject: [PATCH 24/46] Changed: bnp_manager_plugin file handles to CIFile/COFile to use serial system --- .../src/plugins/bnp_manager/bnp_file.cpp | 139 +++++------------- 1 file changed, 37 insertions(+), 102 deletions(-) diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_file.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_file.cpp index 370b6e3a9..7c404b347 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_file.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_file.cpp @@ -64,9 +64,8 @@ void BNPFileHandle::releaseInstance() // *************************************************************************** bool BNPFileHandle::unpack(const string &dirName, const vector& fileList) { - FILE *bnp = fopen (m_openedBNPFile.c_str(), "rb"); - FILE *out; - if (bnp == NULL) + CIFile bnp; + if ( !bnp.open(m_openedBNPFile) ) return false; TPackedFilesList::iterator it_files = m_packedFiles.begin(); @@ -78,27 +77,17 @@ bool BNPFileHandle::unpack(const string &dirName, const vector& fileList { string filename = dirName + "/" + it_files->m_name; - out = fopen (filename.c_str(), "wb"); - if (out != NULL) + COFile out; + if ( out.open(filename) ) { - nlfseek64 (bnp, it_files->m_pos, SEEK_SET); + bnp.seek(it_files->m_pos, IStream::begin); uint8 *ptr = new uint8[it_files->m_size]; - if (fread (ptr, it_files->m_size, 1, bnp) != 1) - { - nlwarning("%s read error", filename.c_str()); - return false; - } - if (fwrite (ptr, it_files->m_size, 1, out) != 1) - { - nlwarning("%s write error", filename.c_str()); - return false; - } - fclose (out); + bnp.serialBuffer(ptr,it_files->m_size); + out.serialBuffer(ptr,it_files->m_size); delete [] ptr; } } } - fclose (bnp); return true; } // *************************************************************************** @@ -109,42 +98,32 @@ bool BNPFileHandle::readHeader(const std::string &filePath) m_openedBNPFile = filePath; - FILE *f = fopen (filePath.c_str(), "rb"); - if (f == NULL) + CIFile bnp; + if ( !bnp.open (filePath) ) { nlwarning("Could not open file!"); return false; } - nlfseek64 (f, 0, SEEK_END); + bnp.seek(0, IStream::end); uint32 nFileSize=CFile::getFileSize (filePath ); - nlfseek64 (f, nFileSize-sizeof(uint32), SEEK_SET); + bnp.seek(nFileSize-sizeof(uint32), IStream::begin); uint32 nOffsetFromBegining; - if (fread (&nOffsetFromBegining, sizeof(uint32), 1, f) != 1) - { - fclose (f); - return false; - } + bnp.serial(nOffsetFromBegining); #ifdef NL_BIG_ENDIAN NLMISC_BSWAP32(nOffsetFromBegining); #endif - if (nlfseek64 (f, nOffsetFromBegining, SEEK_SET) != 0) + if ( !bnp.seek (nOffsetFromBegining, IStream::begin) ) { nlwarning("Could not read offset from begining"); - fclose (f); return false; } uint32 nNbFile; - if (fread (&nNbFile, sizeof(uint32), 1, f) != 1) - { - nlwarning("Could not read number of files!"); - fclose (f); - return false; - } + bnp.serial(nNbFile); #ifdef NL_BIG_ENDIAN NLMISC_BSWAP32(nNbFile); @@ -153,44 +132,28 @@ bool BNPFileHandle::readHeader(const std::string &filePath) for (uint32 i = 0; i < nNbFile; ++i) { uint8 nStringSize; + uint32 fileSize; + uint32 filePos; char sName[256]; - if (fread (&nStringSize, 1, 1, f) != 1) - { - nlwarning("Error reading packed filename!"); - fclose (f); - return false; - } - if (fread (sName, 1, nStringSize, f) != nStringSize) - { - fclose (f); - return false; - } + bnp.serial(nStringSize); + bnp.serialBuffer( (uint8*)sName, nStringSize); sName[nStringSize] = 0; PackedFile tmpPackedFile; tmpPackedFile.m_name = sName; tmpPackedFile.m_path = m_openedBNPFile; - if (fread (&tmpPackedFile.m_size, sizeof(uint32), 1, f) != 1) - { - nlwarning("Error reading packed file size!"); - fclose (f); - return false; - } + + bnp.serial(fileSize); + tmpPackedFile.m_size = fileSize; #ifdef NL_BIG_ENDIAN NLMISC_BSWAP32(tmpBNPFile.Size); #endif - if (fread (&tmpPackedFile.m_pos, sizeof(uint32), 1, f) != 1) - { - nlwarning("Error reading packed file position!"); - fclose (f); - return false; - } + bnp.serial(filePos); + tmpPackedFile.m_pos = filePos; #ifdef NL_BIG_ENDIAN NLMISC_BSWAP32(tmpBNPFile.Pos); #endif m_packedFiles.push_back (tmpPackedFile); } - - fclose (f); return true; } // *************************************************************************** @@ -211,52 +174,24 @@ void BNPFileHandle::list(TPackedFilesList& FileList) // *************************************************************************** bool BNPFileHandle::writeHeader( const std::string &filePath, uint32 offset ) { - FILE *f = fopen (filePath.c_str(), "ab"); - if (f == NULL) return false; + COFile bnp; + if ( !bnp.open(filePath, true) ) return false; - uint32 nNbFile = (uint32)m_packedFiles.size(); - if (fwrite (&nNbFile, sizeof(uint32), 1, f) != 1) - { - fclose(f); - return false; - } + uint32 nNbFile = (uint32)m_packedFiles.size(); + bnp.serial(nNbFile); - for (uint32 i = 0; i < nNbFile; ++i) - { - uint8 nStringSize = (uint8)m_packedFiles[i].m_name.size(); - if (fwrite (&nStringSize, 1, 1, f) != 1) - { - fclose(f); - return false; - } + for (uint32 i = 0; i < nNbFile; ++i) + { + uint8 nStringSize = (uint8)m_packedFiles[i].m_name.size(); + bnp.serial( nStringSize ); + bnp.serialBuffer( (uint8*)m_packedFiles[i].m_name.c_str(), nStringSize ); + bnp.serial(m_packedFiles[i].m_size); + bnp.serial(m_packedFiles[i].m_pos); + } - if (fwrite (m_packedFiles[i].m_name.c_str(), 1, nStringSize, f) != nStringSize) - { - fclose(f); - return false; - } + bnp.serial(offset); - if (fwrite (&m_packedFiles[i].m_size, sizeof(uint32), 1, f) != 1) - { - fclose(f); - return false; - } - - if (fwrite (&m_packedFiles[i].m_pos, sizeof(uint32), 1, f) != 1) - { - fclose(f); - return false; - } - } - - if (fwrite (&offset, sizeof(uint32), 1, f) != 1) - { - fclose(f); - return false; - } - - fclose (f); - return true; + return true; } // *************************************************************************** void BNPFileHandle::fileNames(std::vector &fileNames) From 874db0ccea05f3a90c0118e25fba180f2bc5be92 Mon Sep 17 00:00:00 2001 From: Krolock Date: Thu, 12 Jan 2012 00:00:09 +0100 Subject: [PATCH 25/46] Changed: BIG_ENDIAN check is no longer needed --- .../src/plugins/bnp_manager/bnp_file.cpp | 33 ++++--------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_file.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_file.cpp index 7c404b347..cce2a022a 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_file.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_file.cpp @@ -65,8 +65,7 @@ void BNPFileHandle::releaseInstance() bool BNPFileHandle::unpack(const string &dirName, const vector& fileList) { CIFile bnp; - if ( !bnp.open(m_openedBNPFile) ) - return false; + bnp.open(m_openedBNPFile); TPackedFilesList::iterator it_files = m_packedFiles.begin(); @@ -99,11 +98,7 @@ bool BNPFileHandle::readHeader(const std::string &filePath) m_openedBNPFile = filePath; CIFile bnp; - if ( !bnp.open (filePath) ) - { - nlwarning("Could not open file!"); - return false; - } + bnp.open (filePath); bnp.seek(0, IStream::end); uint32 nFileSize=CFile::getFileSize (filePath ); @@ -112,9 +107,6 @@ bool BNPFileHandle::readHeader(const std::string &filePath) uint32 nOffsetFromBegining; bnp.serial(nOffsetFromBegining); -#ifdef NL_BIG_ENDIAN - NLMISC_BSWAP32(nOffsetFromBegining); -#endif if ( !bnp.seek (nOffsetFromBegining, IStream::begin) ) { @@ -125,33 +117,22 @@ bool BNPFileHandle::readHeader(const std::string &filePath) uint32 nNbFile; bnp.serial(nNbFile); -#ifdef NL_BIG_ENDIAN - NLMISC_BSWAP32(nNbFile); -#endif - for (uint32 i = 0; i < nNbFile; ++i) { uint8 nStringSize; - uint32 fileSize; - uint32 filePos; char sName[256]; + bnp.serial(nStringSize); bnp.serialBuffer( (uint8*)sName, nStringSize); sName[nStringSize] = 0; + PackedFile tmpPackedFile; tmpPackedFile.m_name = sName; tmpPackedFile.m_path = m_openedBNPFile; - bnp.serial(fileSize); - tmpPackedFile.m_size = fileSize; -#ifdef NL_BIG_ENDIAN - NLMISC_BSWAP32(tmpBNPFile.Size); -#endif - bnp.serial(filePos); - tmpPackedFile.m_pos = filePos; -#ifdef NL_BIG_ENDIAN - NLMISC_BSWAP32(tmpBNPFile.Pos); -#endif + bnp.serial(tmpPackedFile.m_size); + bnp.serial(tmpPackedFile.m_pos); + m_packedFiles.push_back (tmpPackedFile); } return true; From ae946437d7eeb7d8c1d73d3bf60942f400cd8311 Mon Sep 17 00:00:00 2001 From: Krolock Date: Thu, 12 Jan 2012 00:18:09 +0100 Subject: [PATCH 26/46] Changed: Finished serial system --- .../src/plugins/bnp_manager/bnp_file.cpp | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_file.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_file.cpp index cce2a022a..d9b2f45c1 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_file.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_file.cpp @@ -85,8 +85,11 @@ bool BNPFileHandle::unpack(const string &dirName, const vector& fileList out.serialBuffer(ptr,it_files->m_size); delete [] ptr; } + out.close(); } } + + bnp.close(); return true; } // *************************************************************************** @@ -101,7 +104,7 @@ bool BNPFileHandle::readHeader(const std::string &filePath) bnp.open (filePath); bnp.seek(0, IStream::end); - uint32 nFileSize=CFile::getFileSize (filePath ); + uint32 nFileSize = bnp.getFileSize(); bnp.seek(nFileSize-sizeof(uint32), IStream::begin); uint32 nOffsetFromBegining; @@ -111,6 +114,7 @@ bool BNPFileHandle::readHeader(const std::string &filePath) if ( !bnp.seek (nOffsetFromBegining, IStream::begin) ) { nlwarning("Could not read offset from begining"); + bnp.close(); return false; } @@ -135,6 +139,8 @@ bool BNPFileHandle::readHeader(const std::string &filePath) m_packedFiles.push_back (tmpPackedFile); } + + bnp.close(); return true; } // *************************************************************************** @@ -156,7 +162,9 @@ void BNPFileHandle::list(TPackedFilesList& FileList) bool BNPFileHandle::writeHeader( const std::string &filePath, uint32 offset ) { COFile bnp; - if ( !bnp.open(filePath, true) ) return false; + bnp.open(filePath, true); + if ( !bnp.isOpen() ) + return false; uint32 nNbFile = (uint32)m_packedFiles.size(); bnp.serial(nNbFile); @@ -172,6 +180,8 @@ bool BNPFileHandle::writeHeader( const std::string &filePath, uint32 offset ) bnp.serial(offset); + bnp.close(); + return true; } // *************************************************************************** @@ -255,7 +265,6 @@ void BNPFileHandle::deleteFiles( const vector& fileNames) it_packed++; } } - nldebug("Writing header..."); writeHeader(tmpFile, OffsetFromBegining); @@ -270,10 +279,12 @@ void BNPFileHandle::append(const string &destination, const PackedFile &source) if ( !CFile::fileExists(destination) ) CFile::createEmptyFile( destination ); - FILE *bnpfile = fopen(destination.c_str(), "ab"); - FILE *packedfile = fopen(source.m_path.c_str(), "rb"); - if (bnpfile == NULL) return; - if (packedfile == NULL) { fclose(bnpfile); return; } + COFile bnpfile; + CIFile packedfile; + bnpfile.open(destination, true); + packedfile.open(source.m_path); + if ( !bnpfile.isOpen() ) return; + uint8 *ptr = new uint8[source.m_size]; @@ -281,20 +292,18 @@ void BNPFileHandle::append(const string &destination, const PackedFile &source) if ( nlstricmp( CFile::getExtension(source.m_path), "bnp" ) == 0 ) { // Jump to the file position inside the bnp - nlfseek64(packedfile, source.m_pos, SEEK_SET); + packedfile.seek(source.m_pos, IStream::begin); } // Read the source - if (fread (ptr, source.m_size, 1, packedfile) != 1) - nlwarning("%s read error", source.m_path.c_str()); + packedfile.serialBuffer(ptr, source.m_size); // Append the data to the destination - if (fwrite (ptr, source.m_size, 1, bnpfile) != 1) - nlwarning("%s write error", destination.c_str()); + bnpfile.serialBuffer(ptr, source.m_size); delete [] ptr; - fclose(packedfile); - fclose(bnpfile); + packedfile.close(); + bnpfile.close(); } // *************************************************************************** bool BNPFileHandle::compare(const PackedFile &left, const PackedFile &right) From 0dea27251690fc7f51d2ec4c31b983c6518998df Mon Sep 17 00:00:00 2001 From: dnk-88 Date: Sun, 15 Jan 2012 20:52:33 +0300 Subject: [PATCH 27/46] Fixed: #1375 Fixed compilation error. --- .../object_viewer_qt/src/plugins/object_viewer/attrib_widget.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/attrib_widget.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/attrib_widget.h index 7bd929d72..da308aba7 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/attrib_widget.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/object_viewer/attrib_widget.h @@ -58,7 +58,7 @@ public: /// Force to update dialog content void updateUi(); - /// Сonnects all the slots with signals + /// Connects all the slots with signals void init(); /// Sets the pointer CWorkspaceNode* in the wrappers. @@ -192,6 +192,7 @@ protected: QDialog *_SchemeWidget; Ui::CAttribWidget _ui; + friend class CSchemeBankDialog; }; /* class CAttribWidget */ /** From 130b43104357927922f2ca728c67750e5a2e2907 Mon Sep 17 00:00:00 2001 From: kervala Date: Mon, 13 Feb 2012 11:31:28 +0100 Subject: [PATCH 28/46] Fixed: Bad check in emote tokens --- code/ryzom/client/src/interface_v3/interface_manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/ryzom/client/src/interface_v3/interface_manager.cpp b/code/ryzom/client/src/interface_v3/interface_manager.cpp index 180a25763..27b8f9197 100644 --- a/code/ryzom/client/src/interface_v3/interface_manager.cpp +++ b/code/ryzom/client/src/interface_v3/interface_manager.cpp @@ -6374,7 +6374,7 @@ bool CInterfaceManager::parseTokens(ucstring& ucstr) // Get everything between the two "$" size_t token_start_pos = start_pos + start_token.length(); size_t token_end_pos = end_pos - end_token.length(); - if (token_start_pos < token_end_pos) + if (token_start_pos > token_end_pos) { // Wrong formatting; give up on this one. start_pos = end_pos; From b3730e18ceb1184cbc2954ba7eb0c1cd7c200290 Mon Sep 17 00:00:00 2001 From: Krolock Date: Tue, 21 Feb 2012 17:45:47 +0100 Subject: [PATCH 29/46] Added: Sortproxymodel in order to sort DirTreeView (folders on top) --- .../src/plugins/bnp_manager/CMakeLists.txt | 1 + .../plugins/bnp_manager/bnp_dirtree_dialog.cpp | 18 ++++++++++++------ .../plugins/bnp_manager/bnp_dirtree_dialog.h | 5 ++++- .../bnp_manager/bnp_filesystem_model.cpp | 1 - .../plugins/bnp_manager/bnp_manager_window.cpp | 2 +- 5 files changed, 18 insertions(+), 9 deletions(-) diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/CMakeLists.txt b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/CMakeLists.txt index e06c82c94..7ecfd7396 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/CMakeLists.txt +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/CMakeLists.txt @@ -14,6 +14,7 @@ SET(OVQT_PLUG_BNP_MANAGER_HDR bnp_manager_plugin.h bnp_filesystem_model.h bnp_file.h bnp_filelist_dialog.h + bnp_proxy_model.h ) SET(OVQT_PLUG_BNP_MANAGER_UIS bnp_dirtree_form.ui bnp_filelist_dialog.ui diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_dirtree_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_dirtree_dialog.cpp index 9487f66ae..78cc2f3cd 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_dirtree_dialog.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_dirtree_dialog.cpp @@ -17,6 +17,7 @@ // Project includes #include "bnp_dirtree_dialog.h" #include "bnp_filesystem_model.h" +#include "bnp_proxy_model.h" // Qt includes #include @@ -39,18 +40,22 @@ CBnpDirTreeDialog::CBnpDirTreeDialog(QString bnpPath, QWidget *parent) // Bnp file: opened and displayed // all other files: added to the currently opened bnp file QStringList filter; - filter << tr("*.bnp"); + //filter << tr("*.bnp"); // Setup the directory tree model - m_dirModel= new BNPFileSystemModel; + m_dirModel= new BNPFileSystemModel(); + m_proxyModel = new BNPSortProxyModel(); m_dirModel->setRootPath(m_DataPath); m_dirModel->setFilter(QDir::AllDirs | QDir::NoDotAndDotDot | QDir::AllEntries); m_dirModel->setNameFilters(filter); m_dirModel->setNameFilterDisables(0); - m_ui.dirTree->setModel(m_dirModel); + m_proxyModel->setSourceModel(m_dirModel); - m_ui.dirTree->setRootIndex(m_dirModel->index(m_DataPath)); + m_ui.dirTree->setModel(m_proxyModel); + + m_ui.dirTree->setRootIndex( m_proxyModel->mapFromSource (m_dirModel->index(m_DataPath) ) ); + m_ui.dirTree->setSortingEnabled(true); // Trigger if one filename is activated // In future drag&drop should be also possible @@ -65,10 +70,11 @@ CBnpDirTreeDialog::~CBnpDirTreeDialog() // *************************************************************************** void CBnpDirTreeDialog::fileSelected(QModelIndex index) { - if (index.isValid() && !m_dirModel->isDir(index)) + QModelIndex source = m_proxyModel->mapToSource(index); + if (source.isValid() && !m_dirModel->isDir(source)) { // emit the according signal to BNPManagerWindow class - Q_EMIT selectedForm(m_dirModel->fileInfo(index).filePath()); + Q_EMIT selectedFile(m_dirModel->fileInfo(source).filePath()); } } // *************************************************************************** diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_dirtree_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_dirtree_dialog.h index 33b221a4d..737085185 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_dirtree_dialog.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_dirtree_dialog.h @@ -31,6 +31,7 @@ namespace BNPManager { class BNPFileSystemModel; +class BNPSortProxyModel; class CBnpDirTreeDialog : public QDockWidget { @@ -63,8 +64,10 @@ private: BNPFileSystemModel *m_dirModel; + BNPSortProxyModel *m_proxyModel; + Q_SIGNALS: - void selectedForm(const QString); + void selectedFile(const QString); private Q_SLOTS: /** diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_filesystem_model.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_filesystem_model.cpp index eaf6389f5..75ef031ff 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_filesystem_model.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_filesystem_model.cpp @@ -25,7 +25,6 @@ namespace BNPManager BNPFileSystemModel::BNPFileSystemModel(QObject *parent) : QFileSystemModel(parent) { - } // *************************************************************************** BNPFileSystemModel::~BNPFileSystemModel() diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_window.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_window.cpp index 33157733e..4022931d1 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_window.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_manager_window.cpp @@ -67,7 +67,7 @@ BNPManagerWindow::BNPManagerWindow(QWidget *parent) // this SLOT is triggered if the user activates a bnp files in the // dirtree view - connect(m_BnpDirTreeDialog, SIGNAL(selectedForm(const QString)), + connect(m_BnpDirTreeDialog, SIGNAL(selectedFile(const QString)), this, SLOT(loadFile(const QString))); // not used From 874b39b05a3f5778709baf9364dd778e0252b3c8 Mon Sep 17 00:00:00 2001 From: kervala Date: Tue, 21 Feb 2012 17:47:16 +0100 Subject: [PATCH 30/46] Changed: Search in default paths if DXSDK_DIR is not defined --- code/CMakeModules/FindDirectXSDK.cmake | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/code/CMakeModules/FindDirectXSDK.cmake b/code/CMakeModules/FindDirectXSDK.cmake index 1f832cf95..9947778db 100644 --- a/code/CMakeModules/FindDirectXSDK.cmake +++ b/code/CMakeModules/FindDirectXSDK.cmake @@ -14,17 +14,22 @@ FIND_PATH(DXSDK_DIR "Include/dxsdkver.h" PATHS "$ENV{DXSDK_DIR}" + "C:/Program Files (x86)/Microsoft DirectX SDK (June 2010)" + "C:/Program Files/Microsoft DirectX SDK (June 2010)" + "C:/Program Files (x86)/Microsoft DirectX SDK (February 2010)" + "C:/Program Files/Microsoft DirectX SDK (February 2010)" + "C:/Program Files (x86)/Microsoft DirectX SDK (November 2007)" + "C:/Program Files/Microsoft DirectX SDK (November 2007)" + "C:/Program Files (x86)/Microsoft DirectX SDK" + "C:/Program Files/Microsoft DirectX SDK" ) MACRO(FIND_DXSDK_LIBRARY MYLIBRARY MYLIBRARYNAME) FIND_LIBRARY(${MYLIBRARY} NAMES ${MYLIBRARYNAME} PATHS - "${DXSDK_LIBRARY_DIR}" - "$ENV{DXSDK_DIR}" - "$ENV{DXSDK_DIR}/Lib" - "$ENV{DXSDK_DIR}/Lib/x86" - ) + "${DXSDK_LIBRARY_DIR}" + ) ENDMACRO(FIND_DXSDK_LIBRARY MYLIBRARY MYLIBRARYNAME) IF(DXSDK_DIR) From 3f1d11568eac655722bde70633f348ae3d647183 Mon Sep 17 00:00:00 2001 From: Krolock Date: Tue, 21 Feb 2012 17:47:26 +0100 Subject: [PATCH 31/46] Added: Sortproxymodel class --- .../plugins/bnp_manager/bnp_proxy_model.cpp | 56 +++++++++++++++++++ .../src/plugins/bnp_manager/bnp_proxy_model.h | 44 +++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_proxy_model.cpp create mode 100644 code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_proxy_model.h diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_proxy_model.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_proxy_model.cpp new file mode 100644 index 000000000..d3657d13b --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_proxy_model.cpp @@ -0,0 +1,56 @@ +// Object Viewer Qt - BNP Manager Plugin - MMORPG Framework +// Copyright (C) 2011 Roland Winklmeier +// +// 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 + +// NeL includes +#include + +// project includes +#include "bnp_proxy_model.h" + +namespace BNPManager +{ + +bool BNPSortProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const +{ + if ( sourceModel()->hasChildren(left) ) + { + if ( !sourceModel()->hasChildren(right) ) + { + return true; + } + else + { + QString leftString = sourceModel()->data( left ).toString(); + QString rightString = sourceModel()->data( right ).toString(); + return QString::localeAwareCompare(leftString, rightString) < 0; + } + } + else + { + if ( sourceModel()->hasChildren(right) ) + return false; + else + { + QString leftString = sourceModel()->data( left ).toString(); + QString rightString = sourceModel()->data( right ).toString(); + return QString::localeAwareCompare(leftString, rightString) < 0; + } + } +} + +} /* namespace Plugin */ + +/* end of file */ diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_proxy_model.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_proxy_model.h new file mode 100644 index 000000000..ed2da5966 --- /dev/null +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_proxy_model.h @@ -0,0 +1,44 @@ +// Object Viewer Qt - BNP Manager Plugin - MMORPG Framework +// Copyright (C) 2011 Roland Winklmeier +// +// 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 + +#ifndef BNP_PROXY_MODEL_H +#define BNP_PROXY_MODEL_H + +// Qt includes +#include + +namespace BNPManager +{ + + class BNPSortProxyModel : public QSortFilterProxyModel + { + + public: + BNPSortProxyModel(QObject *parent = 0): QSortFilterProxyModel(parent) + { + } + ~BNPSortProxyModel() + { + } + + protected: + virtual bool lessThan ( const QModelIndex & left, const QModelIndex & right ) const; + + };/* class BNPSortProxyModel */ + +} // BNPManager + +#endif // BNP_PROXY_MODEL_H From bfb06efd8e3f4765e19b0b4016d83bf021ace6fb Mon Sep 17 00:00:00 2001 From: Krolock Date: Tue, 21 Feb 2012 18:00:05 +0100 Subject: [PATCH 32/46] Added: Drop handling from outside into FileListDialog --- .../bnp_manager/bnp_filelist_dialog.cpp | 27 +++++++++++++++++-- .../plugins/bnp_manager/bnp_filelist_dialog.h | 6 +++-- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_filelist_dialog.cpp b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_filelist_dialog.cpp index b78e6c0bf..418d7fa04 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_filelist_dialog.cpp +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_filelist_dialog.cpp @@ -20,6 +20,10 @@ // Qt includes #include +#include +#include +#include +#include // NeL includes #include @@ -34,6 +38,7 @@ BnpFileListDialog::BnpFileListDialog(QString bnpPath, QWidget *parent) m_DataPath(bnpPath) { m_ui.setupUi(this); + setAcceptDrops(true); } // *************************************************************************** BnpFileListDialog::~BnpFileListDialog() @@ -70,7 +75,7 @@ void BnpFileListDialog::setupTable(int nbrows) m_ui.tableWidget->setObjectName("tablewidget"); } // *************************************************************************** -bool BnpFileListDialog::loadTable(const QString fileName) +bool BnpFileListDialog::loadTable(const QString filePath) { // reference to the BNPFileHandle singletone instance BNPFileHandle& myBNPFileHandle = BNPFileHandle::getInstance(); @@ -79,7 +84,7 @@ bool BnpFileListDialog::loadTable(const QString fileName) int row = 0; // read the header from the bnp file - if (!myBNPFileHandle.readHeader( fileName.toStdString()) ) + if (!myBNPFileHandle.readHeader( filePath.toStdString()) ) { return false; } @@ -100,6 +105,9 @@ bool BnpFileListDialog::loadTable(const QString fileName) row++; } + // Set the file path as the widgets title + setWindowTitle(filePath); + return true; } // *************************************************************************** @@ -118,5 +126,20 @@ void BnpFileListDialog::getSelections(TSelectionList& SelectionList) } } // *************************************************************************** +void BnpFileListDialog::dragEnterEvent(QDragEnterEvent *event) +{ + // Accept only one file + // In the future a tabbed FileListDialog would accept more + if ( event->mimeData()->hasUrls() && event->mimeData()->urls().count() == 1) + event->acceptProposedAction(); +} +// *************************************************************************** +void BnpFileListDialog::dropEvent(QDropEvent *event) + { + // Excraft the local file url from the drop object and fill the table + const QMimeData *mimeData = event->mimeData(); + QList urlList = mimeData->urls(); + loadTable( urlList.first().toLocalFile() ); + } } // namespace BNPManager \ No newline at end of file diff --git a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_filelist_dialog.h b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_filelist_dialog.h index f2cc021a9..5b5491d8f 100644 --- a/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_filelist_dialog.h +++ b/code/nel/tools/3d/object_viewer_qt/src/plugins/bnp_manager/bnp_filelist_dialog.h @@ -51,7 +51,7 @@ public: * \param Filename * \return true if everything went well */ - bool loadTable(const QString filename); + bool loadTable(const QString filePath); /** * Set the dimension of the table @@ -67,8 +67,10 @@ public: */ void getSelections(TSelectionList& SelectionList); +protected: + void dragEnterEvent (QDragEnterEvent *event); + void dropEvent(QDropEvent *event); private: - Ui::BnpFileListDialog m_ui; // common data path as root folder for the dirtree view From 639b7f228568d45b15946962b6034d8cc36b8b85 Mon Sep 17 00:00:00 2001 From: kervala Date: Tue, 21 Feb 2012 21:11:04 +0100 Subject: [PATCH 33/46] Changed: #1219 Bad color when rgba.cpp is compiled with GCC 4.2.4 --- code/nel/src/misc/rgba.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/code/nel/src/misc/rgba.cpp b/code/nel/src/misc/rgba.cpp index 844a100cf..598d8eb53 100644 --- a/code/nel/src/misc/rgba.cpp +++ b/code/nel/src/misc/rgba.cpp @@ -643,6 +643,8 @@ bool CRGBA::convertToHLS(float &h, float &l, float &s) const { h = 2.f + (b - r) / diff; } +#if defined(GCC_VERSION) && (GCC_VERSION == 40204) + // use the fix only if using the specific GCC version else if (maxV == b) { h = 4.f + (r - g) / diff; @@ -652,6 +654,12 @@ bool CRGBA::convertToHLS(float &h, float &l, float &s) const // this case is to fix a compiler bug h = (g - b) / diff; } +#else + else + { + h = 4.f + (r - g) / diff; + } +#endif h *= 60.f; // scale to [0..360] From 48d8e331a65831d92c23abc802410e789d6db3f8 Mon Sep 17 00:00:00 2001 From: kervala Date: Wed, 22 Feb 2012 22:17:09 +0100 Subject: [PATCH 34/46] Changed: Fix again bad MSVC10 CMake generator... --- code/CMakeModules/nel.cmake | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/code/CMakeModules/nel.cmake b/code/CMakeModules/nel.cmake index 5c5efc4a9..eb2bc24ac 100644 --- a/code/CMakeModules/nel.cmake +++ b/code/CMakeModules/nel.cmake @@ -37,7 +37,9 @@ ENDMACRO(NL_TARGET_DRIVER) # Argument: ### MACRO(NL_DEFAULT_PROPS name label) - SET_TARGET_PROPERTIES(${name} PROPERTIES PROJECT_LABEL ${label}) + IF(NOT MSVC10) + SET_TARGET_PROPERTIES(${name} PROPERTIES PROJECT_LABEL ${label}) + ENDIF(NOT MSVC10) GET_TARGET_PROPERTY(type ${name} TYPE) IF(${type} STREQUAL SHARED_LIBRARY) # Set versions only if target is a shared library From ea55ed6cd0072720f49146ab10233709c70d3a4d Mon Sep 17 00:00:00 2001 From: kervala Date: Mon, 27 Feb 2012 09:59:27 +0100 Subject: [PATCH 35/46] Changed: #1433 Merge changes from patch 1.13 --- code/nel/include/nel/misc/common.h | 2 ++ code/nel/include/nel/misc/eid_translator.h | 2 ++ code/nel/include/nel/net/transport_class.h | 3 ++- code/nel/src/misc/common.cpp | 26 ++++++++++++++++++++++ code/nel/src/misc/eid_translator.cpp | 11 +++++++++ code/nel/src/misc/win_event_emitter.cpp | 7 ++++++ code/nel/src/net/transport_class.cpp | 3 ++- 7 files changed, 52 insertions(+), 2 deletions(-) diff --git a/code/nel/include/nel/misc/common.h b/code/nel/include/nel/misc/common.h index 42bf56d3b..fa9272386 100644 --- a/code/nel/include/nel/misc/common.h +++ b/code/nel/include/nel/misc/common.h @@ -342,6 +342,8 @@ std::string secondsToHumanReadable (uint32 time); /// Get a bytes or time in string format and convert it in seconds or bytes uint32 fromHumanReadable (const std::string &str); +/// Add digit grouping seperator to if value >= 10 000. Assumes input is numerical string. +std::string formatThousands(const std::string& s); /// This function executes a program in the background and returns instantly (used for example to launch services in AES). /// The program will be launched in the current directory diff --git a/code/nel/include/nel/misc/eid_translator.h b/code/nel/include/nel/misc/eid_translator.h index 695f7724e..9937b72fd 100644 --- a/code/nel/include/nel/misc/eid_translator.h +++ b/code/nel/include/nel/misc/eid_translator.h @@ -146,6 +146,8 @@ public: TAdditionalInfoCb EntityInfoCallback; + static void removeShardFromName(ucstring& name); + private: // get all eid for a user using the user name or the user id void getByUser (uint32 uid, std::vector &res); diff --git a/code/nel/include/nel/net/transport_class.h b/code/nel/include/nel/net/transport_class.h index 11161d7cd..2517da64b 100644 --- a/code/nel/include/nel/net/transport_class.h +++ b/code/nel/include/nel/net/transport_class.h @@ -75,7 +75,7 @@ public: enum TProp { PropUInt8, PropUInt16, PropUInt32, PropUInt64, PropSInt8, PropSInt16, PropSInt32, PropSInt64, - PropBool, PropFloat, PropDouble, PropString, PropDataSetRow, PropSheetId, PropUKN }; + PropBool, PropFloat, PropDouble, PropString, PropDataSetRow, PropSheetId, PropUCString, PropUKN }; // PropBool, PropFloat, PropDouble, PropString, PropDataSetRow, PropEntityId, PropSheetId, PropUKN }; @@ -160,6 +160,7 @@ public: case PropString: nlassert(sizeof(T) == sizeof (std::string)); break; // case PropEntityId: nlassert(sizeof(T) == sizeof (NLMISC::CEntityId)); break; case PropSheetId: nlassert(sizeof(T) == sizeof (NLMISC::CSheetId)); break; + case PropUCString: nlassert(sizeof(T) == sizeof (ucstring)); break; default: nlerror ("property %s have unknown type %d", name.c_str(), type); } diff --git a/code/nel/src/misc/common.cpp b/code/nel/src/misc/common.cpp index fb9a9c6f5..19be95367 100644 --- a/code/nel/src/misc/common.cpp +++ b/code/nel/src/misc/common.cpp @@ -30,6 +30,7 @@ #include "nel/misc/command.h" #include "nel/misc/path.h" +#include "nel/misc/i18n.h" using namespace std; @@ -526,6 +527,31 @@ void toUpper(char *str) } } +std::string formatThousands(const std::string& s) +{ + int i, k; + int remaining = s.length() - 1; + static std::string separator = NLMISC::CI18N::get("uiThousandsSeparator").toUtf8(); + + // Don't add separator if the number is < 10k + if (remaining < 4) return s; + + std::string ns; + + do + { + for (i = remaining, k = 0; i >= 0 && k < 3; --i, ++k ) + { + ns = s[i] + ns; // New char is added to front of ns + if ( i > 0 && k == 2) ns = separator + ns; // j > 0 means still more digits + } + + remaining -= 3; + } + while (remaining >= 0); + + return ns; +} // // Exceptions diff --git a/code/nel/src/misc/eid_translator.cpp b/code/nel/src/misc/eid_translator.cpp index 36ea84247..e254831c4 100644 --- a/code/nel/src/misc/eid_translator.cpp +++ b/code/nel/src/misc/eid_translator.cpp @@ -417,6 +417,17 @@ void CEntityIdTranslator::checkEntity (const CEntityId &eid, const ucstring &ent } } +void CEntityIdTranslator::removeShardFromName(ucstring& name) +{ + // The string must contain a '(' and a ')' + ucstring::size_type p0= name.find('('); + ucstring::size_type p1= name.find(')'); + if (p0 == ucstring::npos || p1 == ucstring::npos || p1 <= p0) + return; + + name = name.substr(0, p0) + name.substr(p1 + 1); +} + // this callback is call when the file is changed void cbInvalidEntityNamesFilename(const std::string &invalidEntityNamesFilename) { diff --git a/code/nel/src/misc/win_event_emitter.cpp b/code/nel/src/misc/win_event_emitter.cpp index 2c46a7530..c216e3e1a 100644 --- a/code/nel/src/misc/win_event_emitter.cpp +++ b/code/nel/src/misc/win_event_emitter.cpp @@ -153,6 +153,13 @@ bool CWinEventEmitter::processMessage (HWND hWnd, uint32 msg, WPARAM wParam, LPA if ((int)wParam==VK_SHIFT) _ShiftButton=false; + // As Print Screen button does not trigger a WM_KEYDOWN msg, simulate it here + if ((int)wParam==VK_SNAPSHOT) + { + if (wParam < KeyCount) + server->postEvent (new CEventKeyDown ((NLMISC::TKey)wParam, getKeyButton(_AltButton, _ShiftButton, _CtrlButton), true, this)); + } + // Post the message if (wParam < KeyCount) server->postEvent (new CEventKeyUp ((NLMISC::TKey)wParam, getKeyButton(_AltButton, _ShiftButton, _CtrlButton), this)); diff --git a/code/nel/src/net/transport_class.cpp b/code/nel/src/net/transport_class.cpp index a5f826728..dca866916 100644 --- a/code/nel/src/net/transport_class.cpp +++ b/code/nel/src/net/transport_class.cpp @@ -77,7 +77,7 @@ string typeToString (CTransportClass::TProp type) string conv[] = { "PropUInt8", "PropUInt16", "PropUInt32", "PropUInt64", "PropSInt8", "PropSInt16", "PropSInt32", "PropSInt64", - "PropBool", "PropFloat", "PropDouble", "PropString", "PropDataSetRow", "PropSheetId", "PropUKN" }; + "PropBool", "PropFloat", "PropDouble", "PropString", "PropDataSetRow", "PropSheetId", "PropUCString", "PropUKN" }; // "PropBool", "PropFloat", "PropDouble", "PropString", "PropDataSetRow", "PropEntityId", "PropSheetId", "PropUKN" }; if (type > CTransportClass::PropUKN) @@ -352,6 +352,7 @@ void CTransportClass::init () // nlassert (PropDataSetRow < PropUKN); DummyProp[PropDataSetRow] = new CTransportClass::CRegisteredProp; // nlassert (PropEntityId < PropUKN); DummyProp[PropEntityId] = new CTransportClass::CRegisteredProp; nlassert (PropSheetId < PropUKN); DummyProp[PropSheetId] = new CTransportClass::CRegisteredProp; + nlassert (PropUCString < PropUKN); DummyProp[PropUCString] = new CTransportClass::CRegisteredProp; // we have to know when a service comes, so add callback (put the callback before all other one because we have to send this message first) CUnifiedNetwork::getInstance()->setServiceUpCallback("*", cbTCUpService, NULL, false); From 6865470c035e03f9607185ced79a7f96353a54d5 Mon Sep 17 00:00:00 2001 From: kervala Date: Mon, 27 Feb 2012 10:01:45 +0100 Subject: [PATCH 36/46] Changed: #878 Fix typos in comments/code --- code/nel/include/nel/misc/event_emitter.h | 2 +- code/nel/src/3d/driver/direct3d/driver_direct3d.cpp | 2 +- code/nel/src/3d/driver/opengl/driver_opengl_light.cpp | 2 +- code/nel/src/3d/driver/opengl/driver_opengl_vertex.cpp | 2 +- code/nel/src/3d/nelu.cpp | 3 ++- code/nel/src/misc/events.cpp | 2 +- 6 files changed, 7 insertions(+), 6 deletions(-) diff --git a/code/nel/include/nel/misc/event_emitter.h b/code/nel/include/nel/misc/event_emitter.h index e678c2674..5c547d07f 100644 --- a/code/nel/include/nel/misc/event_emitter.h +++ b/code/nel/include/nel/misc/event_emitter.h @@ -49,7 +49,7 @@ public: * \param server */ virtual void submitEvents(CEventServer & server, bool allWindows) = 0; - + /** * Instruct the event emitter to send CGDMouseMove instead of CEventMouseMove. * diff --git a/code/nel/src/3d/driver/direct3d/driver_direct3d.cpp b/code/nel/src/3d/driver/direct3d/driver_direct3d.cpp index 5ac1d2906..bfbd3fdb7 100644 --- a/code/nel/src/3d/driver/direct3d/driver_direct3d.cpp +++ b/code/nel/src/3d/driver/direct3d/driver_direct3d.cpp @@ -1228,7 +1228,7 @@ bool CDriverD3D::init (uint windowIcon, emptyProc exitFunc) ExitFunc = exitFunc; createCursors(); - + // Register a window class WNDCLASSW wc; diff --git a/code/nel/src/3d/driver/opengl/driver_opengl_light.cpp b/code/nel/src/3d/driver/opengl/driver_opengl_light.cpp index e5c3cff6e..2fc25f94a 100644 --- a/code/nel/src/3d/driver/opengl/driver_opengl_light.cpp +++ b/code/nel/src/3d/driver/opengl/driver_opengl_light.cpp @@ -138,7 +138,7 @@ void CDriverGL::setLightInternal(uint8 num, const CLight& light) } else { - // Deactivate spot properties + // Disable spot properties #ifdef USE_OPENGLES glLightf (lightNum, GL_SPOT_CUTOFF, 180.f); glLightf (lightNum, GL_SPOT_EXPONENT, 0.f); diff --git a/code/nel/src/3d/driver/opengl/driver_opengl_vertex.cpp b/code/nel/src/3d/driver/opengl/driver_opengl_vertex.cpp index 502c971f1..7241d499b 100644 --- a/code/nel/src/3d/driver/opengl/driver_opengl_vertex.cpp +++ b/code/nel/src/3d/driver/opengl/driver_opengl_vertex.cpp @@ -978,7 +978,7 @@ void CDriverGL::setupGlArraysStd(CVertexBufferInfo &vb) // Check type nlassert (vb.Type[CVertexBuffer::Normal]==CVertexBuffer::Float3); _DriverGLStates.enableNormalArray(true); - nglArrayObjectATI(GL_NORMAL_ARRAY, 3, GL_FLOAT, vb.VertexSize, vb.VertexObjectId, (ptrdiff_t) vb.ValuePtr[CVertexBuffer::Normal]); + nglArrayObjectATI(GL_NORMAL_ARRAY, 3, GL_FLOAT, vb.VertexSize, vb.VertexObjectId, (ptrdiff_t) vb.ValuePtr[CVertexBuffer::Normal]); } else { diff --git a/code/nel/src/3d/nelu.cpp b/code/nel/src/3d/nelu.cpp index 80ef89ec4..3d143bce1 100644 --- a/code/nel/src/3d/nelu.cpp +++ b/code/nel/src/3d/nelu.cpp @@ -58,7 +58,7 @@ bool CNELU::initDriver (uint w, uint h, uint bpp, bool windowed, nlWindow syst CNELU::Driver = NULL; // Init driver. -#if defined(NL_OS_WINDOWS) +#ifdef NL_OS_WINDOWS if (direct3d) { CNELU::Driver= CDRU::createD3DDriver(); @@ -75,6 +75,7 @@ bool CNELU::initDriver (uint w, uint h, uint bpp, bool windowed, nlWindow syst nlwarning ("CNELU::initDriver: no driver found"); return false; } + if (!CNELU::Driver->init()) { nlwarning ("CNELU::initDriver: init() failed"); diff --git a/code/nel/src/misc/events.cpp b/code/nel/src/misc/events.cpp index 4d3979416..4d0f996d5 100644 --- a/code/nel/src/misc/events.cpp +++ b/code/nel/src/misc/events.cpp @@ -179,7 +179,7 @@ static const CStringConversion::CPair stringTable [] = { "KeyNONAME", KeyNONAME }, { "KeyPA1", KeyPA1 }, { "KeyOEM_CLEAR", KeyOEM_CLEAR }, -}; +} static CStringConversion KeyConversion(stringTable, sizeof(stringTable) / sizeof(stringTable[0]), KeyCount); From 87e6c19981fb8e65b99ca29ebea4ab73711af558 Mon Sep 17 00:00:00 2001 From: kervala Date: Mon, 27 Feb 2012 15:04:33 +0100 Subject: [PATCH 37/46] Changed: #1433 Merge changes from patch 1.13 --- code/ryzom/common/src/game_share/bot_chat_types.h | 2 ++ code/ryzom/common/src/game_share/entity_types.h | 2 +- code/ryzom/common/src/game_share/item_infos.cpp | 2 ++ code/ryzom/common/src/game_share/item_infos.h | 1 + .../common/src/game_share/persistent_data_template.h | 12 ++++++++---- code/ryzom/common/src/game_share/pvp_mode.cpp | 2 ++ code/ryzom/common/src/game_share/pvp_mode.h | 4 +++- .../common/src/game_share/ryzom_mirror_properties.h | 2 +- code/ryzom/common/src/game_share/send_chat.h | 2 +- 9 files changed, 21 insertions(+), 8 deletions(-) diff --git a/code/ryzom/common/src/game_share/bot_chat_types.h b/code/ryzom/common/src/game_share/bot_chat_types.h index 779bc8ba3..19982f106 100644 --- a/code/ryzom/common/src/game_share/bot_chat_types.h +++ b/code/ryzom/common/src/game_share/bot_chat_types.h @@ -82,6 +82,8 @@ namespace BOTCHATTYPE ResaleKOBroken, // this item can't be sold because its Resold time has expired ResaleKONoTimeLeft, + // this item can't be sold because the owner has locked it (temporary hack to get around modifying database.xml) + ResaleKOLockedByOwner, NumBotChatResaleFlag }; diff --git a/code/ryzom/common/src/game_share/entity_types.h b/code/ryzom/common/src/game_share/entity_types.h index 3841f9a17..68b42e954 100644 --- a/code/ryzom/common/src/game_share/entity_types.h +++ b/code/ryzom/common/src/game_share/entity_types.h @@ -130,7 +130,7 @@ const TCoord THRESHOLD_BEHAVIOUR = 60000; // Name const TPropIndex PROPERTY_NAME_STRING_ID = 6; -const TCoord THRESHOLD_NAME_STRING_ID = 25000; +const TCoord THRESHOLD_NAME_STRING_ID = 100000; // Main target const TPropIndex PROPERTY_TARGET_ID = 7; diff --git a/code/ryzom/common/src/game_share/item_infos.cpp b/code/ryzom/common/src/game_share/item_infos.cpp index a968ff8a4..af84c5d6c 100644 --- a/code/ryzom/common/src/game_share/item_infos.cpp +++ b/code/ryzom/common/src/game_share/item_infos.cpp @@ -73,6 +73,7 @@ CItemInfos::CItemInfos() LacustreMagicResistance = 0; JungleMagicResistance = 0; PrimaryRootMagicResistance = 0; + PetNumber = 0; // 1 based! } void CItemInfos::serial(NLMISC::IStream & s) @@ -130,5 +131,6 @@ void CItemInfos::serial(NLMISC::IStream & s) s.serial( CustomText ); s.serial( R2ItemDescription ); s.serial( R2ItemComment ); + s.serial( PetNumber ); } diff --git a/code/ryzom/common/src/game_share/item_infos.h b/code/ryzom/common/src/game_share/item_infos.h index ff34bfddc..3fd94444e 100644 --- a/code/ryzom/common/src/game_share/item_infos.h +++ b/code/ryzom/common/src/game_share/item_infos.h @@ -139,6 +139,7 @@ public: ucstring CustomText; ucstring R2ItemDescription; ucstring R2ItemComment; + uint8 PetNumber; // 1 based pet index //@} }; diff --git a/code/ryzom/common/src/game_share/persistent_data_template.h b/code/ryzom/common/src/game_share/persistent_data_template.h index ef76101cd..08211687a 100644 --- a/code/ryzom/common/src/game_share/persistent_data_template.h +++ b/code/ryzom/common/src/game_share/persistent_data_template.h @@ -176,16 +176,20 @@ inline uint32 saveGameCycleToSecond(NLMISC::TGameCycle tick) { // Evaluate the UTC of this event (with the current date of save). Suppose that 1 second==10 tick - return sint32(NLMISC::CTime::getSecondsSince1970()) + (sint32(tick) - sint32(CTickEventHandler::getGameCycle()))/10; + if (tick < CTickEventHandler::getGameCycle()) + return NLMISC::CTime::getSecondsSince1970(); + else + return NLMISC::CTime::getSecondsSince1970() + (tick - CTickEventHandler::getGameCycle())/10; // NB: result should be positive since no event should have been launched before 1970! } inline NLMISC::TGameCycle loadSecondToGameCycle(uint32 second) { + if (second < NLMISC::CTime::getSecondsSince1970()) + return 0; + // Convert UTC of the event to game cycle. Suppose that 1 second==10 tick - sint32 newTick= CTickEventHandler::getGameCycle() + (sint32(second) - sint32(NLMISC::CTime::getSecondsSince1970()))*10; - // If game cycle is loaded on a server where current game cycle is too young, we can have here negative values => avoid them - return std::max(newTick, sint32(0)); + return CTickEventHandler::getGameCycle() + (second - NLMISC::CTime::getSecondsSince1970())*10; } #endif diff --git a/code/ryzom/common/src/game_share/pvp_mode.cpp b/code/ryzom/common/src/game_share/pvp_mode.cpp index aa3ac1496..3e13fd428 100644 --- a/code/ryzom/common/src/game_share/pvp_mode.cpp +++ b/code/ryzom/common/src/game_share/pvp_mode.cpp @@ -35,6 +35,8 @@ namespace PVP_MODE NL_STRING_CONVERSION_TABLE_ENTRY(PvpZoneOutpost) NL_STRING_CONVERSION_TABLE_ENTRY(PvpFaction) NL_STRING_CONVERSION_TABLE_ENTRY(PvpFactionFlagged) + NL_STRING_CONVERSION_TABLE_ENTRY(PvpZoneSafe) + NL_STRING_CONVERSION_TABLE_ENTRY(PvpSafe) NL_END_STRING_CONVERSION_TABLE(TPVPMode, PVPModeConversion, Unknown) TPVPMode fromString(const std::string & str) diff --git a/code/ryzom/common/src/game_share/pvp_mode.h b/code/ryzom/common/src/game_share/pvp_mode.h index dd52f1fd6..0e654752f 100644 --- a/code/ryzom/common/src/game_share/pvp_mode.h +++ b/code/ryzom/common/src/game_share/pvp_mode.h @@ -32,10 +32,12 @@ namespace PVP_MODE PvpZoneOutpost = 32, PvpFaction = 64, PvpFactionFlagged = 128, + PvpZoneSafe = 256, + PvpSafe = 512, Unknown, NbModes = Unknown, - NbBits = 8 // number of bits needed to store all valid values + NbBits = 10 // number of bits needed to store all valid values }; diff --git a/code/ryzom/common/src/game_share/ryzom_mirror_properties.h b/code/ryzom/common/src/game_share/ryzom_mirror_properties.h index 0aab0b870..afd0ac892 100644 --- a/code/ryzom/common/src/game_share/ryzom_mirror_properties.h +++ b/code/ryzom/common/src/game_share/ryzom_mirror_properties.h @@ -138,7 +138,7 @@ void initRyzomVisualPropertyIndices( CMirroredDataSet& dataset ); #define TYPE_BOT_TRADE_SELECTOR2 uint64 #define TYPE_EVENT_FACTION_ID uint32 -#define TYPE_PVP_MODE uint8 +#define TYPE_PVP_MODE uint32 #define TYPE_PVP_CLAN uint32 #define TYPE_FUEL bool diff --git a/code/ryzom/common/src/game_share/send_chat.h b/code/ryzom/common/src/game_share/send_chat.h index cefb8bba0..1efa7acee 100644 --- a/code/ryzom/common/src/game_share/send_chat.h +++ b/code/ryzom/common/src/game_share/send_chat.h @@ -115,7 +115,7 @@ inline void npcChatToChannelEx(const TDataSetRow &senderId, CChatGroup::TGroupTy * Chat group can be constructed from CChatGroup class. * sentence is the sentence to be sent. */ -inline void npcChatToChannelSentence(const TDataSetRow &senderId, CChatGroup::TGroupType groupType, std::string& sentence) +inline void npcChatToChannelSentence(const TDataSetRow &senderId, CChatGroup::TGroupType groupType, ucstring& sentence) { NLNET::CMessage msgout("NPC_CHAT_SENTENCE"); msgout.serial(const_cast(senderId)); From 232493249100e7bdd53db6c18c85f1e7007dcae4 Mon Sep 17 00:00:00 2001 From: kervala Date: Mon, 27 Feb 2012 15:19:53 +0100 Subject: [PATCH 38/46] Changed: Support for Debian/Ubuntu multiarch (use -DCMAKE_LIBRARY_ARCHITECTURE=) --- code/CMakeModules/nel.cmake | 98 +++++++++++++++++++++++++++++-------- 1 file changed, 77 insertions(+), 21 deletions(-) diff --git a/code/CMakeModules/nel.cmake b/code/CMakeModules/nel.cmake index eb2bc24ac..9314a7a85 100644 --- a/code/CMakeModules/nel.cmake +++ b/code/CMakeModules/nel.cmake @@ -304,27 +304,66 @@ MACRO(NL_SETUP_BUILD) ENDIF(CMAKE_BUILD_TYPE MATCHES "Release") ENDIF(CMAKE_BUILD_TYPE MATCHES "Debug") + SET(HOST_CPU ${CMAKE_SYSTEM_PROCESSOR}) + # Determine target CPU -# IF(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86") - IF(NOT CMAKE_SIZEOF_VOID_P) - INCLUDE (CheckTypeSize) - CHECK_TYPE_SIZE("void*" CMAKE_SIZEOF_VOID_P) - ENDIF(NOT CMAKE_SIZEOF_VOID_P) + IF(NOT TARGET_CPU) + SET(TARGET_CPU $ENV{DEB_HOST_GNU_CPU}) + ENDIF(NOT TARGET_CPU) - # Using 32 or 64 bits libraries + # If not specified, use the same CPU as host + IF(NOT TARGET_CPU) + SET(TARGET_CPU ${CMAKE_SYSTEM_PROCESSOR}) + ENDIF(NOT TARGET_CPU) + + IF(TARGET_CPU MATCHES "amd64") + SET(TARGET_CPU "x86_64") + ELSEIF(TARGET_CPU MATCHES "i.86") + SET(TARGET_CPU "x86") + ENDIF(TARGET_CPU MATCHES "amd64") + + # DEB_HOST_ARCH_ENDIAN is 'little' or 'big' + # DEB_HOST_ARCH_BITS is '32' or '64' + + # If target and host CPU are the same + IF("${HOST_CPU}" STREQUAL "${TARGET_CPU}") + # x86-compatible CPU + IF(HOST_CPU MATCHES "x86") + IF(NOT CMAKE_SIZEOF_VOID_P) + INCLUDE (CheckTypeSize) + CHECK_TYPE_SIZE("void*" CMAKE_SIZEOF_VOID_P) + ENDIF(NOT CMAKE_SIZEOF_VOID_P) + + # Using 32 or 64 bits libraries + IF(CMAKE_SIZEOF_VOID_P EQUAL 8) + SET(TARGET_CPU "x86_64") + ELSE(CMAKE_SIZEOF_VOID_P EQUAL 8) + SET(TARGET_CPU "x86") + ENDIF(CMAKE_SIZEOF_VOID_P EQUAL 8) + ENDIF(HOST_CPU MATCHES "x86") + # TODO: add checks for ARM and PPC + ELSE("${HOST_CPU}" STREQUAL "${TARGET_CPU}") + MESSAGE(STATUS "Compiling on ${HOST_CPU} for ${TARGET_CPU}") + ENDIF("${HOST_CPU}" STREQUAL "${TARGET_CPU}") + + IF(TARGET_CPU STREQUAL "x86_64") + SET(TARGET_X64 1) + SET(PLATFORM_CFLAGS "-DHAVE_X86_64") + ELSEIF(TARGET_CPU STREQUAL "x86") SET(TARGET_X86 1) - IF(CMAKE_SIZEOF_VOID_P EQUAL 8) - SET(ARCH "x86_64") - SET(TARGET_X64 1) - ADD_DEFINITIONS(-DHAVE_X86_64) - ELSE(CMAKE_SIZEOF_VOID_P EQUAL 8) - SET(ARCH "x86") - ADD_DEFINITIONS(-DHAVE_X86) - ENDIF(CMAKE_SIZEOF_VOID_P EQUAL 8) -# ADD_DEFINITIONS(-DHAVE_IA64) -# ENDIF(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86") + SET(PLATFORM_CFLAGS "-DHAVE_X86") + ENDIF(TARGET_CPU STREQUAL "x86_64") - IF(WIN32) + # Fix library paths suffixes for Debian MultiArch + IF(NOT CMAKE_LIBRARY_ARCHITECTURE) + SET(CMAKE_LIBRARY_ARCHITECTURE $ENV{DEB_HOST_MULTIARCH}) + ENDIF(NOT CMAKE_LIBRARY_ARCHITECTURE) + + IF(CMAKE_LIBRARY_ARCHITECTURE) + SET(CMAKE_LIBRARY_PATH "/lib/${CMAKE_LIBRARY_ARCHITECTURE};/usr/lib/${CMAKE_LIBRARY_ARCHITECTURE};${CMAKE_LIBRARY_PATH}") + ENDIF(CMAKE_LIBRARY_ARCHITECTURE) + + IF(MSVC) IF(MSVC10) # /Ox is working with VC++ 2010, but custom optimizations don't exist SET(SPEED_OPTIMIZATIONS "/Ox /GF /GS-") @@ -367,7 +406,16 @@ MACRO(NL_SETUP_BUILD) SET(NL_DEBUG_LINKFLAGS "/NODEFAULTLIB:msvcrt /INCREMENTAL:YES") SET(NL_RELEASE_LINKFLAGS "/OPT:REF /OPT:ICF /INCREMENTAL:NO") ELSE(WIN32) - SET(PLATFORM_CFLAGS "-g -pipe -ftemplate-depth-48 -D_REENTRANT -Wall -ansi -W -Wpointer-arith -Wsign-compare -Wno-deprecated-declarations -Wno-multichar -Wno-unused -fno-strict-aliasing") + IF(HOST_CPU STREQUAL "x86_64" AND TARGET_CPU STREQUAL "x86") + SET(PLATFORM_CFLAGS "${PLATFORM_CFLAGS} -m32 -march=i686") + ENDIF(HOST_CPU STREQUAL "x86_64" AND TARGET_CPU STREQUAL "x86") + + IF(HOST_CPU STREQUAL "x86" AND TARGET_CPU STREQUAL "x86_64") + SET(PLATFORM_CFLAGS "${PLATFORM_CFLAGS} -m64") + ENDIF(HOST_CPU STREQUAL "x86" AND TARGET_CPU STREQUAL "x86_64") + + SET(PLATFORM_CFLAGS "{PLATFORM_CFLAGS} -g -D_REENTRANT -pipe -ftemplate-depth-48 -Wall -ansi -W -Wpointer-arith -Wsign-compare -Wno-deprecated-declarations -Wno-multichar -Wno-unused -fno-strict-aliasing") + IF(WITH_COVERAGE) SET(PLATFORM_CFLAGS "-fprofile-arcs -ftest-coverage ${PLATFORM_CFLAGS}") ENDIF(WITH_COVERAGE) @@ -384,7 +432,7 @@ MACRO(NL_SETUP_BUILD) SET(PLATFORM_CXXFLAGS ${PLATFORM_CFLAGS}) IF(NOT APPLE) - SET(PLATFORM_LINKFLAGS "-Wl,--no-undefined -Wl,--as-needed") + SET(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} -Wl,--no-undefined -Wl,--as-needed") ENDIF(NOT APPLE) SET(NL_DEBUG_CFLAGS "-DNL_DEBUG -D_DEBUG") @@ -453,7 +501,11 @@ MACRO(NL_SETUP_PREFIX_PATHS) IF(WIN32) SET(NL_LIB_PREFIX "../lib" CACHE PATH "Installation path for libraries.") ELSE(WIN32) - SET(NL_LIB_PREFIX "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Installation path for libraries.") + IF(CMAKE_LIBRARY_ARCHITECTURE) + SET(NL_LIB_PREFIX "${CMAKE_INSTALL_PREFIX}/lib/${CMAKE_LIBRARY_ARCHITECTURE}" CACHE PATH "Installation path for libraries.") + ELSE(CMAKE_LIBRARY_ARCHITECTURE) + SET(NL_LIB_PREFIX "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Installation path for libraries.") + ENDIF(CMAKE_LIBRARY_ARCHITECTURE) ENDIF(WIN32) ENDIF(NOT NL_LIB_PREFIX) @@ -462,7 +514,11 @@ MACRO(NL_SETUP_PREFIX_PATHS) IF(WIN32) SET(NL_DRIVER_PREFIX "../lib" CACHE PATH "Installation path for drivers.") ELSE(WIN32) - SET(NL_DRIVER_PREFIX "${CMAKE_INSTALL_PREFIX}/lib/nel" CACHE PATH "Installation path for drivers.") + IF(CMAKE_LIBRARY_ARCHITECTURE) + SET(NL_DRIVER_PREFIX "${CMAKE_INSTALL_PREFIX}/lib/${CMAKE_LIBRARY_ARCHITECTURE}/nel" CACHE PATH "Installation path for drivers.") + ELSE(CMAKE_LIBRARY_ARCHITECTURE) + SET(NL_DRIVER_PREFIX "${CMAKE_INSTALL_PREFIX}/lib/nel" CACHE PATH "Installation path for drivers.") + ENDIF(CMAKE_LIBRARY_ARCHITECTURE) ENDIF(WIN32) ENDIF(NOT NL_DRIVER_PREFIX) From a272d956c242b6b74f645020fbeb5231fccc780f Mon Sep 17 00:00:00 2001 From: kervala Date: Mon, 27 Feb 2012 16:10:47 +0100 Subject: [PATCH 39/46] Changed: #1433 Merge changes from patch 1.13 --- code/ryzom/client/src/character_cl.cpp | 89 ++-- code/ryzom/client/src/character_cl.h | 55 +- code/ryzom/client/src/client.cpp | 15 +- code/ryzom/client/src/client_cfg.cpp | 8 +- code/ryzom/client/src/client_cfg.h | 4 +- code/ryzom/client/src/client_chat_manager.cpp | 59 +-- code/ryzom/client/src/commands.cpp | 39 +- code/ryzom/client/src/connection.cpp | 35 +- code/ryzom/client/src/cursor_functions.cpp | 3 + code/ryzom/client/src/entity_cl.cpp | 76 ++- code/ryzom/client/src/entity_cl.h | 27 +- .../src/interface_v3/action_handler_help.cpp | 49 +- .../src/interface_v3/action_handler_help.h | 9 + .../src/interface_v3/action_handler_item.cpp | 140 ++++- .../src/interface_v3/action_phrase_faber.cpp | 103 +++- .../src/interface_v3/action_phrase_faber.h | 5 +- .../src/interface_v3/bot_chat_page_trade.cpp | 17 +- .../client/src/interface_v3/chat_filter.cpp | 2 +- .../src/interface_v3/chat_text_manager.cpp | 27 +- .../client/src/interface_v3/chat_window.cpp | 26 +- .../src/interface_v3/ctrl_base_button.h | 2 + .../client/src/interface_v3/ctrl_button.cpp | 9 +- .../client/src/interface_v3/dbctrl_sheet.cpp | 171 +++++- .../client/src/interface_v3/dbctrl_sheet.h | 29 +- .../interface_v3/dbgroup_list_sheet_trade.cpp | 25 +- .../client/src/interface_v3/dbview_number.cpp | 28 +- .../client/src/interface_v3/group_html.cpp | 493 ++++++++++++++---- .../client/src/interface_v3/group_html.h | 46 +- .../client/src/interface_v3/group_html_cs.cpp | 14 +- .../client/src/interface_v3/group_html_cs.h | 4 +- .../src/interface_v3/group_html_forum.cpp | 11 +- .../src/interface_v3/group_html_forum.h | 4 +- .../src/interface_v3/group_html_mail.cpp | 11 +- .../client/src/interface_v3/group_html_mail.h | 4 +- .../src/interface_v3/group_html_webig.cpp | 150 +++++- .../src/interface_v3/group_html_webig.h | 30 +- .../interface_v3/group_in_scene_bubble.cpp | 126 +++++ .../src/interface_v3/group_in_scene_bubble.h | 3 + .../interface_v3/group_in_scene_user_info.cpp | 209 ++++---- .../client/src/interface_v3/group_table.cpp | 97 +++- .../client/src/interface_v3/group_table.h | 11 + .../client/src/interface_v3/guild_manager.cpp | 61 ++- .../client/src/interface_v3/interface_group.h | 18 +- .../src/interface_v3/interface_manager.cpp | 41 +- .../src/interface_v3/interface_manager.h | 1 + .../src/interface_v3/interface_parser.cpp | 22 +- .../src/interface_v3/inventory_manager.cpp | 80 ++- .../src/interface_v3/inventory_manager.h | 17 +- .../ryzom/client/src/interface_v3/lua_ihm.cpp | 404 +++++++++++++- code/ryzom/client/src/interface_v3/lua_ihm.h | 53 +- .../src/interface_v3/people_interraction.cpp | 82 ++- .../client/src/interface_v3/people_list.cpp | 28 +- .../client/src/interface_v3/player_trade.cpp | 1 + .../client/src/interface_v3/skill_manager.cpp | 2 +- .../ryzom/client/src/interface_v3/view_base.h | 4 + .../client/src/interface_v3/view_bitmap.h | 2 + .../client/src/interface_v3/view_link.cpp | 18 + .../ryzom/client/src/interface_v3/view_link.h | 3 + .../client/src/interface_v3/view_pointer.cpp | 82 ++- .../client/src/interface_v3/view_pointer.h | 1 + .../client/src/interface_v3/view_renderer.cpp | 9 +- .../client/src/interface_v3/view_renderer.h | 1 + code/ryzom/client/src/libwww.cpp | 6 +- code/ryzom/client/src/libwww.h | 5 +- code/ryzom/client/src/login.cpp | 21 +- code/ryzom/client/src/main_loop.cpp | 3 + code/ryzom/client/src/net_manager.cpp | 14 +- code/ryzom/client/src/player_cl.cpp | 189 +++---- .../client/src/string_manager_client.cpp | 41 +- code/ryzom/client/src/string_manager_client.h | 7 +- code/ryzom/client/src/user_entity.cpp | 47 +- code/ryzom/client/src/user_entity.h | 10 + 72 files changed, 2719 insertions(+), 819 deletions(-) diff --git a/code/ryzom/client/src/character_cl.cpp b/code/ryzom/client/src/character_cl.cpp index 1d7c87c2a..694ed9b16 100644 --- a/code/ryzom/client/src/character_cl.cpp +++ b/code/ryzom/client/src/character_cl.cpp @@ -358,17 +358,8 @@ CCharacterCL::CCharacterCL() _EventFactionId = 0; _PvpMode = PVP_MODE::None; - _PvpClan = PVP_CLAN::None; - - for (uint8 i = 0; i < PVP_CLAN::NbClans; i++) - { - _PvpAllies[i] = false; - _PvpEnemies[i] = false; - } - - _ClanCivMaxFame = PVP_CLAN::None; - _ClanCultMaxFame = PVP_CLAN::None; + _LeagueId = 0; _OutpostId = 0; _OutpostSide = OUTPOSTENUMS::UnknownPVPSide; @@ -1842,9 +1833,30 @@ void CCharacterCL::updateVisualPropertyGuildNameID(const NLMISC::TGameCycle &/* //----------------------------------------------- void CCharacterCL::updateVisualPropertyEventFactionID(const NLMISC::TGameCycle &/* gameCycle */, const sint64 &prop) { - _EventFactionId = uint32(prop); + // ODD Hack by Ulukyn + //_EventFactionId = uint32(prop); + _PvpMode = uint32(prop); + buildInSceneInterface(); + if (isUser()) + { + uint i; + uint numEntity = (uint)EntitiesMngr.entities().size(); + for (i=0; i(entity); + if (character) + { + if( character->getPvpMode() != 0 && !character->isUser()) + character->buildInSceneInterface (); + } + } + } + } } // updateVisualPropertyEventFactionID // //----------------------------------------------- @@ -1853,8 +1865,8 @@ void CCharacterCL::updateVisualPropertyEventFactionID(const NLMISC::TGameCycle & //----------------------------------------------- void CCharacterCL::updateVisualPropertyPvpMode(const NLMISC::TGameCycle &/* gameCycle */, const sint64 &prop) { - _PvpMode = (uint8)prop; - buildInSceneInterface(); + //_PvpMode = uint32(prop); + //buildInSceneInterface(); } // updateVisualPropertyPvpMode // @@ -1864,18 +1876,27 @@ void CCharacterCL::updateVisualPropertyPvpMode(const NLMISC::TGameCycle &/* game //----------------------------------------------- void CCharacterCL::updateVisualPropertyPvpClan(const NLMISC::TGameCycle &/* gameCycle */, const sint64 &prop) { - // get fames signs from prop - for (uint8 fameIdx = 0; fameIdx < 7; fameIdx++) - { - _PvpAllies[fameIdx] = (prop & (SINT64_CONSTANT(1) << (2*fameIdx))) != 0; - _PvpEnemies[fameIdx] = (prop & (SINT64_CONSTANT(1) << (2*fameIdx+1))) != 0; - } - - _ClanCivMaxFame = PVP_CLAN::TPVPClan((prop & (0x03 << 2*7)) >> 2*7); - _ClanCultMaxFame = PVP_CLAN::TPVPClan(4 + ((prop & (0x03 << 2*8)) >> 2*8)); - + _LeagueId = uint32(prop); buildInSceneInterface(); + if (isUser()) + { + uint i; + uint numEntity = (uint)EntitiesMngr.entities().size(); + for (i=0; i(entity); + if (character) + { + if( character->getPvpMode() != 0 && !character->isUser()) + character->buildInSceneInterface (); + } + } + } + } } // updateVisualPropertyPvpClan // //----------------------------------------------- @@ -4522,10 +4543,6 @@ void CCharacterCL::applyBehaviourFlyingHPs(const CBehaviourContext &bc, const MB else deltaHPColor = ClientCfg.SystemInfoParams["dg"].Color; } - else - { - deltaHPColor = CRGBA(127,127,127); - } } else { @@ -10252,7 +10269,7 @@ NLMISC_COMMAND(pvpMode, "modify pvp mode", "[ ]") if( args.size() == 0 ) { - uint8 pvpMode = playerTarget->getPvpMode(); + uint16 pvpMode = playerTarget->getPvpMode(); string str; if( pvpMode&PVP_MODE::PvpDuel ) str+="duel "; @@ -10270,6 +10287,10 @@ NLMISC_COMMAND(pvpMode, "modify pvp mode", "[ ]") str+="faction "; if( pvpMode&PVP_MODE::PvpFactionFlagged) str+="faction_flagged "; + if( pvpMode&PVP_MODE::PvpZoneSafe) + str+="in_safe_zone "; + if( pvpMode&PVP_MODE::PvpSafe) + str+="safe "; IM->displaySystemInfo(ucstring(str)); nlinfo(" %s",str.c_str()); } @@ -10280,14 +10301,14 @@ NLMISC_COMMAND(pvpMode, "modify pvp mode", "[ ]") fromString(args[1], state); if( state ) { - uint8 currentPVPMode = playerTarget->getPvpMode(); + uint16 currentPVPMode = playerTarget->getPvpMode(); currentPVPMode |= pvpMode; playerTarget->setPvpMode(currentPVPMode); IM->displaySystemInfo(toString(" adding pvp mode %s",args[0].c_str())); } else { - uint8 currentPVPMode = playerTarget->getPvpMode(); + uint16 currentPVPMode = playerTarget->getPvpMode(); currentPVPMode &= ~pvpMode; playerTarget->setPvpMode(currentPVPMode); IM->displaySystemInfo(toString(" removing pvp mode %s",args[0].c_str())); @@ -10297,7 +10318,7 @@ NLMISC_COMMAND(pvpMode, "modify pvp mode", "[ ]") return true; } - +/* NLMISC_COMMAND(pvpClan, "modify pvp clan", "") { if (args.size() != 1) return false; @@ -10319,13 +10340,13 @@ NLMISC_COMMAND(pvpClan, "modify pvp clan", "") if (!playerTarget) return false; - PVP_CLAN::TPVPClan clan = PVP_CLAN::fromString(args[0]); - playerTarget->setPvpClan(clan); +// PVP_CLAN::TPVPClan clan = PVP_CLAN::fromString(args[0]); +// playerTarget->setPvpClan(clan); playerTarget->buildInSceneInterface(); return true; } - +*/ #endif // !FINAL_VERSION #include "r2/editor.h" diff --git a/code/ryzom/client/src/character_cl.h b/code/ryzom/client/src/character_cl.h index a5d7ba880..6c87692d3 100644 --- a/code/ryzom/client/src/character_cl.h +++ b/code/ryzom/client/src/character_cl.h @@ -84,7 +84,7 @@ public: enum { MaxNumAura = 2 }; enum TAtkHeight { - AtkUnknownHeight = 0, + AtkUnkownHeight = 0, AtkLow, AtkMiddle, AtkHigh @@ -368,48 +368,10 @@ public: virtual uint64 getGuildSymbol () const { return _GuildSymbol; } virtual uint32 getEventFactionID() const { return _EventFactionId; } - virtual uint8 getPvpMode() const { return _PvpMode; } - void setPvpMode(uint8 mode) { _PvpMode=mode; } - virtual PVP_CLAN::TPVPClan getPvpClan() const { return _PvpClan; } - void setPvpClan(PVP_CLAN::TPVPClan clan) { _PvpClan=clan; } - - virtual PVP_CLAN::TPVPClan getClanCivMaxFame() const { return _ClanCivMaxFame; } - void setClanCivMaxFame(PVP_CLAN::TPVPClan clan) { _ClanCivMaxFame=clan; } - virtual PVP_CLAN::TPVPClan getClanCultMaxFame() const { return _ClanCultMaxFame; } - void setClanCultMaxFame(PVP_CLAN::TPVPClan clan) { _ClanCultMaxFame=clan; } - - virtual bool isPvpAlly(uint8 faction) const { if (faction < PVP_CLAN::NbClans) return _PvpAllies[faction]; else return false; } - virtual bool isPvpEnnemy(uint8 faction) const { if (faction < PVP_CLAN::NbClans) return _PvpEnemies[faction]; else return false; } - - virtual bool isPvpMarauder() const - { - for (uint8 i = 0; i < 4; i++) - if (!_PvpEnemies[i]) - return false; - return true; - } - - virtual bool isPvpTrytonist() const - { - if (_PvpEnemies[4] && _PvpEnemies[6]) - return true; - return false; - } - - virtual bool isPvpPrimas() const - { - if (_PvpAllies[4] && _PvpAllies[6]) - return true; - return false; - } - - virtual bool isPvpRanger() const - { - for (uint8 i = 0; i < 4; i++) - if (!_PvpAllies[i]) - return false; - return true; - } + virtual uint16 getPvpMode() const { return _PvpMode; } + void setPvpMode(uint16 mode) { _PvpMode=mode; } + virtual uint32 getLeagueID() const { return _LeagueId; } + void setLeagueID(uint32 league) { _LeagueId=league; } virtual uint16 getOutpostId() const { return _OutpostId; } virtual OUTPOSTENUMS::TPVPSide getOutpostSide() const { return _OutpostSide; } @@ -727,12 +689,9 @@ protected: uint32 _GuildNameId; uint64 _GuildSymbol; uint32 _EventFactionId; - uint8 _PvpMode; + uint16 _PvpMode; PVP_CLAN::TPVPClan _PvpClan; - PVP_CLAN::TPVPClan _ClanCivMaxFame; - PVP_CLAN::TPVPClan _ClanCultMaxFame; - bool _PvpAllies[PVP_CLAN::NbClans]; - bool _PvpEnemies[PVP_CLAN::NbClans]; + uint32 _LeagueId; uint16 _OutpostId; OUTPOSTENUMS::TPVPSide _OutpostSide; diff --git a/code/ryzom/client/src/client.cpp b/code/ryzom/client/src/client.cpp index 72fe1c0b1..49cc6e328 100644 --- a/code/ryzom/client/src/client.cpp +++ b/code/ryzom/client/src/client.cpp @@ -422,15 +422,12 @@ int main(int argc, char **argv) string sCmdLine = cmdline; #if FINAL_VERSION - if (sCmdLine.find("/multi") == string::npos) // If '/multi' not found - { - HANDLE mutex = CreateMutex (NULL, false, "RyzomClient"); - if (mutex && GetLastError() == ERROR_ALREADY_EXISTS) - { - delete appContext; - return 0; - } - } + //if (sCmdLine.find("/multi") == string::npos) // If '/multi' not found + //{ + // HANDLE mutex = CreateMutex (NULL, false, "RyzomClient"); + // if (mutex && GetLastError() == ERROR_ALREADY_EXISTS) + // exit (0); + //} initCrashReport (); #endif // FINAL_VERSION diff --git a/code/ryzom/client/src/client_cfg.cpp b/code/ryzom/client/src/client_cfg.cpp index ff270ad1a..54a3d9b45 100644 --- a/code/ryzom/client/src/client_cfg.cpp +++ b/code/ryzom/client/src/client_cfg.cpp @@ -424,6 +424,7 @@ CClientConfig::CClientConfig() PatchWanted = false; #endif PatchUrl = ""; + PatchletUrl = ""; PatchVersion = ""; PatchServer = ""; @@ -433,6 +434,7 @@ CClientConfig::CClientConfig() RingReleaseNotePath = "http://"+WebIgMainDomain+"/releasenotes_ring/index.php"; ReleaseNotePath = "http://"+WebIgMainDomain+"/releasenotes/index.php"; + /////////////// // ANIMATION // // With a bigger angle, rotation is animated. @@ -1044,9 +1046,13 @@ void CClientConfig::setValues() READ_STRING_DEV(ReleaseNotePath) READ_STRING_FV(PatchServer) + ///////////////////////// + // NEW PATCHLET SYSTEM // + READ_STRING_FV(PatchletUrl) + //////////////////////// // WEBIG // - READ_STRING_DEV(WebIgMainDomain); + READ_STRING_FV(WebIgMainDomain); READ_STRINGVECTOR_FV(WebIgTrustedDomains); /////////////// diff --git a/code/ryzom/client/src/client_cfg.h b/code/ryzom/client/src/client_cfg.h index 667606814..86e70c1b8 100644 --- a/code/ryzom/client/src/client_cfg.h +++ b/code/ryzom/client/src/client_cfg.h @@ -286,17 +286,17 @@ struct CClientConfig // NEW PATCHING SYSTEM // bool PatchWanted; std::string PatchUrl; + std::string PatchletUrl; std::string PatchVersion; std::string PatchServer; std::string RingReleaseNotePath; std::string ReleaseNotePath; - //////////////////////// - // WEBIG // std::string WebIgMainDomain; std::vector WebIgTrustedDomains; + /////////////// // ANIMATION // // With a bigger angle, rotation is animated. diff --git a/code/ryzom/client/src/client_chat_manager.cpp b/code/ryzom/client/src/client_chat_manager.cpp index fa4159b1f..e7ef54d02 100644 --- a/code/ryzom/client/src/client_chat_manager.cpp +++ b/code/ryzom/client/src/client_chat_manager.cpp @@ -963,16 +963,10 @@ void CClientChatManager::buildTellSentence(const ucstring &sender, const ucstrin else { // Does the char have a CSR title? - if (CHARACTER_TITLE::isCsrTitle(CEntityCL::getTitleFromName(sender))) csr = ucstring("(CSR) "); + csr = CHARACTER_TITLE::isCsrTitle(CEntityCL::getTitleFromName(sender)) ? ucstring("(CSR) ") : ucstring(""); } - ucstring cur_time; - CCDBNodeLeaf *pNL = CInterfaceManager::getInstance()->getDbProp("UI:SAVE:CHAT:SHOW_TIMES_IN_CHAT_CB", false); - if (pNL && pNL->getValueBool()) - { - cur_time = CInterfaceManager::getTimestampHuman(); - } - result = cur_time + csr + name + ucstring(" ") + CI18N::get("tellsYou") + ucstring(": ") + msg; + result = csr + name + ucstring(" ") + CI18N::get("tellsYou") + ucstring(": ") + msg; } } @@ -1002,23 +996,18 @@ void CClientChatManager::buildChatSentence(TDataSetIndex /* compressedSenderInde if (!catStr.empty()) cat = string("&")+catStr+"&"; + if ( ! cat.empty()) + { + result = msg; + return; + } + // Format the sentence with the provided sender name ucstring senderName = CEntityCL::removeTitleAndShardFromName(sender); - // Add time if not a &bbl& - ucstring cur_time; - if (cat.toString() != "&bbl&") - { - CCDBNodeLeaf *pNL = CInterfaceManager::getInstance()->getDbProp("UI:SAVE:CHAT:SHOW_TIMES_IN_CHAT_CB", false); - if (pNL && pNL->getValueBool()) - { - cur_time = CInterfaceManager::getTimestampHuman(); - } - } - ucstring csr; // Does the char have a CSR title? - if (CHARACTER_TITLE::isCsrTitle(CEntityCL::getTitleFromName(sender))) csr = ucstring("(CSR) "); + csr = CHARACTER_TITLE::isCsrTitle(CEntityCL::getTitleFromName(sender)) ? ucstring("(CSR) ") : ucstring(""); if (UserEntity && senderName == UserEntity->getDisplayName()) { @@ -1026,10 +1015,10 @@ void CClientChatManager::buildChatSentence(TDataSetIndex /* compressedSenderInde switch(type) { case CChatGroup::shout: - result = cat + cur_time + csr + CI18N::get("youShout") + ucstring(": ") + finalMsg; + result = cat + csr + CI18N::get("youShout") + ucstring(": ") + finalMsg; break; default: - result = cat + cur_time + csr + CI18N::get("youSay") + ucstring(": ") + finalMsg; + result = cat + csr + CI18N::get("youSay") + ucstring(": ") + finalMsg; break; } } @@ -1048,10 +1037,10 @@ void CClientChatManager::buildChatSentence(TDataSetIndex /* compressedSenderInde switch(type) { case CChatGroup::shout: - result = cat + cur_time + csr + senderName + ucstring(" ") + CI18N::get("heShout") + ucstring(": ") + finalMsg; + result = cat + csr + senderName + ucstring(" ") + CI18N::get("heShout") + ucstring(": ") + finalMsg; break; default: - result = cat + cur_time + csr + senderName + ucstring(" ") + CI18N::get("heSays") + ucstring(": ") + finalMsg; + result = cat + csr + senderName + ucstring(" ") + CI18N::get("heSays") + ucstring(": ") + finalMsg; break; } } @@ -1185,14 +1174,8 @@ class CHandlerTell : public IActionHandler ucstring finalMsg; CChatWindow::encodeColorTag(prop.getRGBA(), finalMsg, false); - ucstring cur_time; - CCDBNodeLeaf *pNL = CInterfaceManager::getInstance()->getDbProp("UI:SAVE:CHAT:SHOW_TIMES_IN_CHAT_CB", false); - if (pNL && pNL->getValueBool()) - cur_time = CInterfaceManager::getTimestampHuman(); - - ucstring csr; - if (CHARACTER_TITLE::isCsrTitle(UserEntity->getTitleRaw())) csr += ucstring("(CSR) "); - finalMsg += cur_time + csr + CI18N::get("youTell") + ": "; + ucstring csr = CHARACTER_TITLE::isCsrTitle(UserEntity->getTitleRaw()) ? "(CSR) " : ""; + finalMsg += csr + CI18N::get("youTell") + ": "; prop.readRGBA("UI:SAVE:CHAT:COLORS:TELL"," "); CChatWindow::encodeColorTag(prop.getRGBA(), finalMsg, true); finalMsg += message; @@ -1351,8 +1334,18 @@ class CHandlerTalk : public IActionHandler { string str = text.toUtf8(); string cmdWithArgs = str.substr(1); - /* In the chat context, only ' ' is a possible separator */ + + // Get the command name from the string, can contain spaces string cmd = cmdWithArgs.substr(0, cmdWithArgs.find(' ')); + if (cmdWithArgs.find('"') == 0) + { + string::size_type pos = cmdWithArgs.find('"', 1); + if (string::npos != pos) + { + cmd = cmdWithArgs.substr(1, pos - 1); + } + } + if ( NLMISC::ICommand::exists( cmd ) ) { NLMISC::ICommand::execute( cmdWithArgs, g_log ); diff --git a/code/ryzom/client/src/commands.cpp b/code/ryzom/client/src/commands.cpp index 877f80429..f62d8f245 100644 --- a/code/ryzom/client/src/commands.cpp +++ b/code/ryzom/client/src/commands.cpp @@ -192,7 +192,7 @@ NLMISC_COMMAND(where, "Ask information on the position", "") return false; } -NLMISC_COMMAND(who, "Display all players currently in game","[]") +NLMISC_COMMAND(who, "Display all players currently in region","[]") { // Check parameters. if(args.size() > 1) @@ -1177,7 +1177,7 @@ NLMISC_COMMAND(db, "Modify Database"," ") if(node) node->setValue64(value); else - pIM->displaySystemInfo(toString("DB %s don't exist.", args[0].c_str())); + pIM->displaySystemInfo(toString("DB '%s' does not exist.", args[0].c_str())); #else pIM->displaySystemInfo(ucstring("Can't write to DB when in Final Version.")); #endif @@ -1193,7 +1193,7 @@ NLMISC_COMMAND(db, "Modify Database"," ") nlinfo("%s", str.c_str()); } else - pIM->displaySystemInfo(toString("DB %s don't exist.", args[0].c_str())); + pIM->displaySystemInfo(toString("DB '%s' does not exist.", args[0].c_str())); return true; } else @@ -1295,6 +1295,24 @@ NLMISC_COMMAND(setItemName, "set name of items, sbrick, etc.."," ") +{ + if (args.size() < 2) return false; + ucstring name; + name.fromUtf8(args[0]); + ucstring text; + text.fromUtf8(args[1]); + + STRING_MANAGER::CStringManagerClient *pSMC = STRING_MANAGER::CStringManagerClient::instance(); + if (pSMC) + pSMC->replaceDynString(name, text); + else + return false; + return true; +} + + + ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// @@ -5243,7 +5261,7 @@ bool CUserCommand::execute(const std::string &/* rawCommandString */, const std: { if ((uint)index >= args.size()) { - // Not enough argument + // Not enough arguments pIM->displaySystemInfo (ucstring(CommandName+" : ")+CI18N::get ("uiCommandWrongArgumentCount")); return false; } @@ -5253,11 +5271,18 @@ bool CUserCommand::execute(const std::string &/* rawCommandString */, const std: finalArgs += /*ucstring(*/args[index++]/*).toUtf8()*/; else { - finalArgs += /*ucstring(*/args[index++]/*).toUtf8()*/; while (index 0) ? " " : ""; + // If arg contains spaces then put it in quotes + if (string::npos != args[index].find(" ")) + { + finalArgs += "\"" + args[index++] + "\""; + } + else + { + finalArgs += args[index++]; + } } } } diff --git a/code/ryzom/client/src/connection.cpp b/code/ryzom/client/src/connection.cpp index 1750d253b..32962cd93 100644 --- a/code/ryzom/client/src/connection.cpp +++ b/code/ryzom/client/src/connection.cpp @@ -244,20 +244,20 @@ class CAHOnReloadTestPage: public IActionHandler REGISTER_ACTION_HANDLER (CAHOnReloadTestPage, "on_reload_test_page"); -//void initWebBrowser() -//{ -// CInterfaceManager *pIM = CInterfaceManager::getInstance(); -// pIM->getDbProp("UI:VARIABLES:SCREEN")->setValue32(UI_VARIABLES_SCREEN_WEBSTART); -// -// // start the browser -// CGroupHTML *pGH = dynamic_cast(pIM->getElementFromId(GROUP_BROWSER)); -// -// if (pGH) -// { -// pGH->setActive(true); -// pGH->browse(MainPageURL.c_str()); -// } -//} +void initWebBrowser() +{ + CInterfaceManager *pIM = CInterfaceManager::getInstance(); + //pIM->getDbProp("UI:VARIABLES:SCREEN")->setValue32(UI_VARIABLES_SCREEN_WEBSTART); + + // start the browser + CGroupHTML *pGH = dynamic_cast(pIM->getElementFromId(GROUP_BROWSER)); + + if (pGH) + { + pGH->setActive(true); + pGH->browse(ClientCfg.PatchletUrl.c_str()); + } +} // ------------------------------------------------------------------------------------------------ @@ -392,9 +392,6 @@ bool connection (const string &cookie, const string &fsaddr) pIM->getDbProp ("UI:CURRENT_SCREEN")->setValue32(ClientCfg.Local ? 6 : -1); // TMP TMP CCDBNodeBranch::flushObserversCalls(); - // Init web box - //initWebBrowser(); - // Active inputs Actions.enable(true); EditActions.enable(true); @@ -422,6 +419,10 @@ bool connection (const string &cookie, const string &fsaddr) nlinfo ("PROFILE: %d seconds for connection", (uint32)(ryzomGetLocalTime ()-connStart)/1000); + // Init web box + nlinfo("ok"); + initWebBrowser(); + // TMP TMP if (ClientCfg.Local) { diff --git a/code/ryzom/client/src/cursor_functions.cpp b/code/ryzom/client/src/cursor_functions.cpp index c212dbb0d..2ced655c9 100644 --- a/code/ryzom/client/src/cursor_functions.cpp +++ b/code/ryzom/client/src/cursor_functions.cpp @@ -484,6 +484,9 @@ void checkUnderCursor() if(ContextCur.context("ATTACK")) return; } + + if(testMissionOption(0)) + return; } // Dead else diff --git a/code/ryzom/client/src/entity_cl.cpp b/code/ryzom/client/src/entity_cl.cpp index fbbe0c041..421faad47 100644 --- a/code/ryzom/client/src/entity_cl.cpp +++ b/code/ryzom/client/src/entity_cl.cpp @@ -115,7 +115,7 @@ NLMISC::CRGBA CEntityCL::_UserPackAnimalColor; NLMISC::CRGBA CEntityCL::_PvpEnemyColor; NLMISC::CRGBA CEntityCL::_PvpNeutralColor; NLMISC::CRGBA CEntityCL::_PvpAllyInTeamColor; -NLMISC::CRGBA CEntityCL::_PvpAllyInGuildColor; +NLMISC::CRGBA CEntityCL::_PvpAllyInLeagueColor; NLMISC::CRGBA CEntityCL::_PvpAllyColor; NLMISC::CRGBA CEntityCL::_GMTitleColor[CHARACTER_TITLE::EndGmTitle - CHARACTER_TITLE::BeginGmTitle + 1]; uint8 CEntityCL::_InvalidGMTitleCode = 0xFF; @@ -2295,6 +2295,7 @@ void CEntityCL::onStringAvailable(uint /* stringId */, const ucstring &value) womenTitle = true; } const ucstring replacement(STRING_MANAGER::CStringManagerClient::getTitleLocalizedName(_TitleRaw,womenTitle)); + _Tags = STRING_MANAGER::CStringManagerClient::getTitleInfos(_TitleRaw,womenTitle); if (!replacement.empty() || !ClientCfg.DebugStringManager) { // build the final name @@ -2436,7 +2437,6 @@ public: CEntityCL::_PvpEnemyColor = pIM->getDbProp("UI:SAVE:ENTITY:COLORS:PVPENEMY")->getValueRGBA(); CEntityCL::_PvpAllyColor = pIM->getDbProp("UI:SAVE:ENTITY:COLORS:PVPALLY")->getValueRGBA(); CEntityCL::_PvpAllyInTeamColor = pIM->getDbProp("UI:SAVE:ENTITY:COLORS:PVPALLYINTEAM")->getValueRGBA(); - CEntityCL::_PvpAllyInGuildColor = pIM->getDbProp("UI:SAVE:ENTITY:COLORS:PVPALLYINGUILD")->getValueRGBA(); CEntityCL::_PvpNeutralColor = pIM->getDbProp("UI:SAVE:ENTITY:COLORS:PVPNEUTRAL")->getValueRGBA(); // don't save these colors in .icfg because players can't change them @@ -2463,7 +2463,7 @@ bool CEntityCL::isTarget () const //----------------------------------------------- -bool CEntityCL::isInGuild () const +bool CEntityCL::isInSameGuild () const { if (Type != Player && Type != User) return false; @@ -2477,6 +2477,33 @@ bool CEntityCL::isInGuild () const //----------------------------------------------- +bool CEntityCL::oneInLeague () const +{ + if (Type != Player && Type != User) + return false; + + const uint32 leagueID = getLeagueID(); + if ((UserEntity && (UserEntity->getLeagueID() != 0)) || leagueID != 0) + return true; + + return false; +} + +//----------------------------------------------- + +bool CEntityCL::isInSameLeague () const +{ + if (Type != Player && Type != User) + return false; + + const uint32 leagueID = getLeagueID(); + if ((leagueID != 0) && UserEntity && (leagueID == UserEntity->getLeagueID())) + return true; + + return false; +} +//----------------------------------------------- + NLMISC::CRGBA CEntityCL::getColor () const { // target @@ -2511,46 +2538,43 @@ NLMISC::CRGBA CEntityCL::getColor () const { if (isEnemy()) { - if (getPvpMode()&PVP_MODE::PvpFactionFlagged || getPvpMode()&PVP_MODE::PvpChallenge) - return _PvpEnemyColor; + if (getPvpMode()&PVP_MODE::PvpFaction) + return CRGBA::CRGBA(min(255, _PvpEnemyColor.R+150), min(255, _PvpEnemyColor.G+150), min(255, _PvpEnemyColor.B+150),_PvpEnemyColor.A); else - return CRGBA(min(255, _PvpEnemyColor.R+150), min(255, _PvpEnemyColor.G+150), min(255, _PvpEnemyColor.B+150),_PvpEnemyColor.A); + return _PvpEnemyColor; } } - // neutral pvp - if (isNeutralPVP()) - { - if (isInTeam()) - return _PvpAllyInTeamColor; - if (isInGuild()) - return _PvpAllyInGuildColor; - return _PvpNeutralColor; - } // ally if (isAlly()) { if (getPvpMode() & PVP_MODE::PvpFactionFlagged) { - if (isInTeam()) - return _PvpAllyInTeamColor; - if(isInGuild()) - return _PvpAllyInGuildColor; - return _PvpAllyColor; + if(isInSameLeague()) + return CRGBA::CRGBA(max(0, _PvpAllyColor.R-100), max(0, _PvpAllyColor.G-100), max(0, _PvpAllyColor.B-100),_PvpAllyColor.A); + return CRGBA::CRGBA(max(0, _PvpAllyInTeamColor.R-100), max(0, _PvpAllyInTeamColor.G-100), max(0, _PvpAllyInTeamColor.B-100),_PvpAllyInTeamColor.A); } else { - if (isInTeam()) - return CRGBA(min(255, _PvpAllyInTeamColor.R+150), min(255, _PvpAllyInTeamColor.G+150), min(255, _PvpAllyInTeamColor.B+150),_PvpAllyInTeamColor.A); - if(isInGuild()) - return CRGBA(min(255, _PvpAllyInGuildColor.R+150), min(255, _PvpAllyInGuildColor.G+150), min(255, _PvpAllyInGuildColor.B+150),_PvpAllyInGuildColor.A); - return CRGBA(min(255, _PvpAllyColor.R+150), min(255, _PvpAllyColor.G+150), min(255, _PvpAllyColor.B+150),_PvpAllyColor.A); + if(isInSameLeague()) + return _PvpAllyColor; + return _PvpAllyInTeamColor; } } + + // neutral pvp + if (isNeutralPVP()) + return _PvpNeutralColor; + // neutral if (isInTeam()) return _GroupColor; - if (isInGuild()) + + // neutral + if (isInSameLeague()) + return CRGBA::CRGBA(min(255, _GroupColor.R+50), min(255, _GroupColor.G+50), min(255, _GroupColor.B+50),_GroupColor.A); + + if (isInSameGuild()) return _GuildColor; } return _EntitiesColor[Type]; diff --git a/code/ryzom/client/src/entity_cl.h b/code/ryzom/client/src/entity_cl.h index 1c79161ea..bb508dd42 100644 --- a/code/ryzom/client/src/entity_cl.h +++ b/code/ryzom/client/src/entity_cl.h @@ -686,7 +686,7 @@ public: virtual bool isNeutralPVP() const { return false; } /// Return true if this player has the viewing properties of a friend (inscene bars...) - virtual bool isViewedAsFriend() const { return isNeutral() || isFriend() || isInTeam() || isInGuild(); } + virtual bool isViewedAsFriend() const { return isNeutral() || isFriend() || isInTeam() || isInSameGuild() || isInSameLeague(); } /// Return the People for the entity (unknown by default) virtual EGSPD::CPeople::TPeople people() const; @@ -733,7 +733,13 @@ public: bool isInTeam () const { return _IsInTeam; } // Return true if this entity is in the user guild - bool isInGuild () const; + bool isInSameGuild () const; + + // Return true if this entity is in the user league + bool isInSameLeague () const; + + // Return true if this entity or the user is in a league + bool oneInLeague () const; // Return true if this entity is a Mount owned by the User bool isUserMount () const {return _IsUserMount;} @@ -746,8 +752,9 @@ public: virtual uint64 getGuildSymbol () const { return 0; } virtual uint32 getEventFactionID() const { return 0; } - virtual uint8 getPvpMode() const { return PVP_MODE::None; } + virtual uint16 getPvpMode() const { return PVP_MODE::None; } virtual PVP_CLAN::TPVPClan getPvpClan() const { return PVP_CLAN::None; } + virtual uint32 getLeagueID() const { return 0; } virtual uint16 getOutpostId() const { return 0; } virtual OUTPOSTENUMS::TPVPSide getOutpostSide() const { return OUTPOSTENUMS::UnknownPVPSide; } @@ -760,6 +767,16 @@ public: return _Title; } + /// Return the entity tags + const ucstring &getTag(uint8 id) const + { + if (_Tags.size() > id) { + return _Tags[id]; + } + static ucstring empty; + return empty; + } + /// Return the raw unparsed entity title const ucstring getTitleRaw() const { @@ -910,6 +927,8 @@ protected: ucstring _EntityName; // Current entity title ucstring _Title; + // Current entity tags + std::vector _Tags; // Current entity title string id std::string _TitleRaw; // Current permanent content symbol for the entity @@ -1006,7 +1025,7 @@ protected: static NLMISC::CRGBA _PvpEnemyColor; static NLMISC::CRGBA _PvpNeutralColor; static NLMISC::CRGBA _PvpAllyInTeamColor; - static NLMISC::CRGBA _PvpAllyInGuildColor; + static NLMISC::CRGBA _PvpAllyInLeagueColor; static NLMISC::CRGBA _PvpAllyColor; // colors for GM players static NLMISC::CRGBA _GMTitleColor[CHARACTER_TITLE::EndGmTitle - CHARACTER_TITLE::BeginGmTitle + 1]; diff --git a/code/ryzom/client/src/interface_v3/action_handler_help.cpp b/code/ryzom/client/src/interface_v3/action_handler_help.cpp index 4c92fe6e0..ddcb324d7 100644 --- a/code/ryzom/client/src/interface_v3/action_handler_help.cpp +++ b/code/ryzom/client/src/interface_v3/action_handler_help.cpp @@ -57,6 +57,9 @@ #include "sbrick_manager.h" #include "sphrase_manager.h" #include "action_handler_help.h" +#include "nel/misc/i18n.h" +#include "nel/misc/algo.h" +#include "nel/net/email.h" #include "game_share/mission_desc.h" #include "game_share/inventories.h" #include "game_share/visual_slot_manager.h" @@ -378,7 +381,7 @@ CInterfaceGroup *CInterfaceHelp::activateNextWindow(CDBCtrlSheet *elt, sint forc setup.setupDefaultIDs(); setup.SrcSheet = elt; setup.HelpWindow = group; - setupCreatorName(setup); + //setupCreatorName(setup); // Hide elements by defaults resetSheetHelp(setup); @@ -2064,6 +2067,12 @@ void getItemText (CDBCtrlSheet *item, ucstring &itemText, const CItemSheet*pIS) strFindReplace(itemText, "%r2_comment_text", toString(itemInfo.R2ItemComment)); } break; + case ITEMFAMILY::PET_ANIMAL_TICKET: + { + string nr = (itemInfo.PetNumber > 0) ? toString(itemInfo.PetNumber) : "(slot)" + toString(item->getIndexInDB()); + strFindReplace(itemText, "%petnumber", nr); + } + break; default: { strFindReplace(itemText, "%no_rent", pIS->IsItemNoRent ? CI18N::get("uihelpItemNoRent") : string("")); @@ -2745,8 +2754,15 @@ void setupCreatorName(CSheetHelpSetup &setup) CViewText *vthd = dynamic_cast(setup.HelpWindow->getView("creator_header")); if (vtid != NULL) { - // if not an item, disable the view - if(!setup.SrcSheet || setup.SrcSheet->getType()!=CCtrlSheetInfo::SheetType_Item ) + bool bIsRM = false; + if (setup.SrcSheet) + { + const CItemSheet *pIS= dynamic_cast(SheetMngr.get(CSheetId(setup.SrcSheet->getSheetId()))); + bIsRM = (pIS && pIS->Family == ITEMFAMILY::RAW_MATERIAL); + } + + // if a RM or not an item, disable the view + if(!setup.SrcSheet || bIsRM || setup.SrcSheet->getType()!=CCtrlSheetInfo::SheetType_Item ) { // important else a brick could display a creator name.... vtid->setActive(false); @@ -3569,6 +3585,31 @@ public: }; REGISTER_ACTION_HANDLER( CHandlerAuraModifierTooltip, "aura_modifier_tooltip"); +// *************************************************************************** +class CHandlerUserPaToolTip : public IActionHandler +{ +public: + virtual void execute(CCtrlBase *pCaller, const string &Params) + { + CInterfaceManager *pIM= CInterfaceManager::getInstance(); + + uint8 index; + fromString(Params, index); + --index; // Param is 1-based so subtract 1 + if (index < 0 || index >= MAX_INVENTORY_ANIMAL) + { + return; + } + + ucstring txt; + CCDBNodeLeaf *node = pIM->getDbProp(toString("SERVER:PACK_ANIMAL:BEAST%d:NAME", index)); + if (node && CStringManagerClient::instance()->getDynString(node->getValue32(), txt)) + { + pIM->setContextHelpText(CEntityCL::removeTitleFromName(txt)); + } + } +}; +REGISTER_ACTION_HANDLER( CHandlerUserPaToolTip, "userpa_name_tooltip"); // *************************************************************************** class CHandlerAnimalDeadPopupTooltip : public IActionHandler @@ -3922,7 +3963,7 @@ public: #ifdef NL_OS_WINDOWS if (Driver) { - HWND wnd = Driver->getDisplay(); + HWND wnd = (HWND) Driver->getDisplay(); ShowWindow(wnd, SW_MINIMIZE); } #endif diff --git a/code/ryzom/client/src/interface_v3/action_handler_help.h b/code/ryzom/client/src/interface_v3/action_handler_help.h index 7430ee8cf..48253ea96 100644 --- a/code/ryzom/client/src/interface_v3/action_handler_help.h +++ b/code/ryzom/client/src/interface_v3/action_handler_help.h @@ -64,6 +64,15 @@ void refreshItemHelp(CSheetHelpSetup &setup); // refresh help for a mission void refreshMissionHelp(CSheetHelpSetup &setup, const CPrerequisitInfos &infos); +class CPetAnimalItemInfoWaiter : public IItemInfoWaiter +{ + void infoReceived() + { + //ItemSheet + //ItemSlotId + CClientItemInfo info = getInventory().getItemInfo(ItemSlotId); + } +}; // *************************************************************************** diff --git a/code/ryzom/client/src/interface_v3/action_handler_item.cpp b/code/ryzom/client/src/interface_v3/action_handler_item.cpp index 819b8c0d4..ce5e49307 100644 --- a/code/ryzom/client/src/interface_v3/action_handler_item.cpp +++ b/code/ryzom/client/src/interface_v3/action_handler_item.cpp @@ -31,9 +31,11 @@ #include "../net_manager.h" #include "group_menu.h" #include "../global.h" +#include "group_html.h" // #include "game_share/inventories.h" +#include "game_share/bot_chat_types.h" #include "macrocmd_manager.h" #include "inventory_manager.h" @@ -43,6 +45,7 @@ #include "view_bitmap.h" extern CSheetManager SheetMngr; +extern NLMISC::CLog g_log; using namespace std; using namespace NLMISC; @@ -80,8 +83,6 @@ void CInterfaceItemEdition::setCurrWindow(CDBCtrlSheet* ctrlSheet, const std::st _CurrWindow.IsInEditionMode = isInEditionMode; _CurrWindow.begin(); } - - } // ******************************************************************************************** @@ -153,13 +154,26 @@ void CInterfaceItemEdition::CItemEditionWindow::infoReceived() if (itemInfo.CustomText.empty()) display->setTextFormatTaged(ucstring(STRING_MANAGER::CStringManagerClient::getItemLocalizedDescription(pIS->Id))); else - display->setTextFormatTaged(itemInfo.CustomText); + { + ucstring text = itemInfo.CustomText; + string::size_type delimiter = text.find(' '); + if(text.size() > 3 && text[0]=='@' && text[1]=='W' && text[2]=='E' && text[3]=='B') + { + CGroupHTML *pGH = dynamic_cast(pIM->getElementFromId("ui:interface:web_transactions:content:html")); + if (pGH) + pGH->browse(ucstring(text.substr(4, delimiter-4)).toString().c_str()); + if (delimiter == string::npos) + group->setActive(false); + else + text = text.substr(delimiter, text.size()-delimiter); + } + + display->setTextFormatTaged(text); + } } - } } } - } @@ -278,7 +292,21 @@ void CInterfaceItemEdition::CItemEditionWindow::begin() if (itemInfo.CustomText.empty()) display->setTextFormatTaged(ucstring(STRING_MANAGER::CStringManagerClient::getItemLocalizedDescription(pIS->Id))); else - display->setTextFormatTaged(itemInfo.CustomText); + { + ucstring text = itemInfo.CustomText; + string::size_type delimiter = text.find(' '); + if(text.size() > 3 && text[0]=='@' && text[1]=='W' && text[2]=='E' && text[3]=='B') + { + CGroupHTML *pGH = dynamic_cast(pIM->getElementFromId("ui:interface:web_transactions:content:html")); + if (pGH) + pGH->browse(ucstring(text.substr(4, delimiter-4)).toString().c_str()); + if (delimiter == string::npos) + group->setActive(false); + else + text = text.substr(delimiter, text.size()-delimiter); + } + display->setTextFormatTaged(text); + } } else { @@ -287,7 +315,6 @@ void CInterfaceItemEdition::CItemEditionWindow::begin() } } } - } } } @@ -366,7 +393,6 @@ void CInterfaceItemEdition::CItemEditionWindow::validate() text = editBoxLarge->getInputString(); } - if (textValid) { CBitMemStream out; @@ -972,6 +998,12 @@ bool checkCanExchangeItem(CDBCtrlSheet *pCSSrc) bDropOrSell = pIS->canExchangeOrGive(PlayerTrade.BotChatGiftContext); } + // Locked by owner; cannot trade + if (pCSSrc->getLockedByOwner()) + { + return false; + } + // Special case if this is an animal ticket if ((pIS != NULL) && (pIS->Family == ITEMFAMILY::PET_ANIMAL_TICKET)) { @@ -1209,6 +1241,13 @@ class CHandlerDestroyItem : public IActionHandler nlwarning(" no caller sheet found"); return; } + + // Don't destroy locked items + if (item->getLockedByOwner()) + { + return; + } + // if the item is currently selected, removes the selection if (item == CDBCtrlSheet::getCurrSelection()) { @@ -1712,11 +1751,15 @@ class CHandlerItemMenuCheck : public IActionHandler CViewTextMenu *pXpCatalyserUse = dynamic_cast(pMenu->getView("xp_catalyser_use")); CViewTextMenu *pDrop = dynamic_cast(pMenu->getView("drop")); CViewTextMenu *pDestroy = dynamic_cast(pMenu->getView("destroy")); + CViewTextMenu *pLockUnlock = dynamic_cast(pMenu->getView("lockunlock")); CViewTextMenu *pMoveSubMenu = dynamic_cast(pMenu->getView("move")); CViewTextMenu *pMoveToBag = dynamic_cast(pMenu->getView("bag")); CViewTextMenu *pMoveToGuild = dynamic_cast(pMenu->getView("guild")); CViewTextMenu *pMoveToRoom = dynamic_cast(pMenu->getView("room")); CViewTextMenu *pMoveToPa[MAX_INVENTORY_ANIMAL]; + + bool bIsLockedByOwner = pCS->getLockedByOwner(); + for(i=0;i(pMenu->getView(toString("pa%d", i))); @@ -1735,24 +1778,27 @@ class CHandlerItemMenuCheck : public IActionHandler if(pXpCatalyserUse) pXpCatalyserUse->setActive(false); if(pItemTextDisplay) pItemTextDisplay->setActive(false); if(pItemTextEdition) pItemTextEdition->setActive(false); + + if(pLockUnlock) pLockUnlock->setActive(true); + const CItemSheet *pIS = pCS->asItemSheet(); if (invId != INVENTORIES::guild) if (pIS != NULL) { - if (pCrisEnchant && pIS->Family == ITEMFAMILY::CRYSTALLIZED_SPELL) + if (pCrisEnchant && pIS->Family == ITEMFAMILY::CRYSTALLIZED_SPELL && !bIsLockedByOwner) pCrisEnchant->setActive(true); - if (pCrisReload && pIS->Family == ITEMFAMILY::ITEM_SAP_RECHARGE) + if (pCrisReload && pIS->Family == ITEMFAMILY::ITEM_SAP_RECHARGE && !bIsLockedByOwner) pCrisReload->setActive(true); // teleport can be used only from bag (NB: should not exist in mektoub....) - if (pTeleportUse && pIS->Family == ITEMFAMILY::TELEPORT && pCS->getInventoryIndex()==INVENTORIES::bag) + if (pTeleportUse && pIS->Family == ITEMFAMILY::TELEPORT && pCS->getInventoryIndex()==INVENTORIES::bag && !bIsLockedByOwner) { pTeleportUse->setActive(true); } - if (pItemConsume && pIS->IsConsumable == true && pCS->getInventoryIndex()==INVENTORIES::bag) + if (pItemConsume && pIS->IsConsumable == true && pCS->getInventoryIndex()==INVENTORIES::bag && !bIsLockedByOwner) { pItemConsume->setActive(true); } - if (pXpCatalyserUse && pIS->Family == ITEMFAMILY::XP_CATALYSER && pCS->getInventoryIndex()==INVENTORIES::bag) + if (pXpCatalyserUse && pIS->Family == ITEMFAMILY::XP_CATALYSER && pCS->getInventoryIndex()==INVENTORIES::bag && !bIsLockedByOwner) { pXpCatalyserUse->setActive(true); } @@ -1815,9 +1861,10 @@ class CHandlerItemMenuCheck : public IActionHandler for(i=0;isetActive(false); - // additionnaly, cannot drop/destroy an animal item. + // additionnaly, cannot drop/destroy/lock an animal item. if(pDrop) pDrop->setActive(false); if(pDestroy) pDestroy->setActive(false); + if(pLockUnlock) pLockUnlock->setActive(false); } else { @@ -1845,6 +1892,7 @@ class CHandlerItemMenuCheck : public IActionHandler // std case: can drop / destroy if(pDrop) pDrop->setActive(invId!=INVENTORIES::guild); if(pDestroy) pDestroy->setActive(invId!=INVENTORIES::guild); + if(pLockUnlock) pLockUnlock->setActive(invId!=INVENTORIES::guild); } // hide the move entry completely? @@ -1899,6 +1947,29 @@ class CHandlerItemMenuCheck : public IActionHandler pItemTextDisplay->setGrayed(pIM->getDbProp("UI:VARIABLES:ISACTIVE:PHRASE_EDIT_CUSTOM")->getValueBool()); } + if (pCS->getGrayed()) + { + if (pEquip) pEquip->setActive(false); + if (pDestroy) pDestroy->setActive(false); + if (pLockUnlock) pLockUnlock->setActive(false); + if (pMoveSubMenu) pMoveSubMenu->setActive(false); + } + + if (bIsLockedByOwner) + { + if (pLockUnlock) pLockUnlock->setHardText("uimUnlockItem"); + // Cannot drop/destroy if locked by owner + if (pDrop) pDrop->setActive(false); + if (pDestroy) pDestroy->setActive(false); + } + else + { + if (pLockUnlock) pLockUnlock->setHardText("uimLockItem"); + } + + // Only show lock menu item if inventory contains the info + if (pLockUnlock) pLockUnlock->setActive(pCS->canOwnerLock()); + // **** Gray Entries // If ourselves are not available, then gray all @@ -1911,6 +1982,7 @@ class CHandlerItemMenuCheck : public IActionHandler if(pXpCatalyserUse) pXpCatalyserUse->setGrayed(true); if(pDrop) pDrop->setGrayed(true); if(pDestroy) pDestroy->setGrayed(true); + if(pLockUnlock) pLockUnlock->setGrayed(true); if(pMoveSubMenu) pMoveSubMenu->setGrayed(true); if(pMoveToBag) pMoveToBag->setGrayed(true); for(i=0;isetGrayed(false); if(pDrop) pDrop->setGrayed(false); if(pDestroy) pDestroy->setGrayed(false); + if(pLockUnlock) pLockUnlock->setGrayed(false); if(pMoveSubMenu) pMoveSubMenu->setGrayed(false); // check each inventory dest if available @@ -1956,6 +2029,45 @@ class CHandlerItemMenuDeactivate : public IActionHandler }; REGISTER_ACTION_HANDLER( CHandlerItemMenuDeactivate, "item_menu_deactivate" ); + +// *************************************************************************** + +class CHandlerItemMenuBaseCheck : public IActionHandler +{ + void execute (CCtrlBase *pCaller, const std::string &/* sParams */) + { + CInterfaceManager *pIM = CInterfaceManager::getInstance(); + + // Get the ctrl sheet that launched this menu + CDBCtrlSheet *pCS = dynamic_cast(pIM->getCtrlLaunchingModal()); + if (pCS == NULL) return; + INVENTORIES::TInventory invId= (INVENTORIES::TInventory)pCS->getInventoryIndex(); + + // Get the menu launched + CInterfaceGroup *pMenu= dynamic_cast(pCaller); + if(!pMenu) return; + + // Get all needed text entries + CViewTextMenu *pDestroy = dynamic_cast(pMenu->getView("destroy")); + CViewTextMenu *pLockUnlock = dynamic_cast(pMenu->getView("lockunlock")); + + if (pCS->getLockedByOwner()) + { + pLockUnlock->setHardText("uimUnlockItem"); + // Cannot destroy if locked by owner + if (pDestroy) pDestroy->setActive(false); + } + else + { + pLockUnlock->setHardText("uimLockItem"); + if (pDestroy) pDestroy->setActive(true); + } + + } +}; +REGISTER_ACTION_HANDLER( CHandlerItemMenuBaseCheck, "item_menu_base_check" ); + + // *************************************************************************** static void sendMsgUseItem(uint16 slot) { diff --git a/code/ryzom/client/src/interface_v3/action_phrase_faber.cpp b/code/ryzom/client/src/interface_v3/action_phrase_faber.cpp index 53a1258bc..097247f6f 100644 --- a/code/ryzom/client/src/interface_v3/action_phrase_faber.cpp +++ b/code/ryzom/client/src/interface_v3/action_phrase_faber.cpp @@ -33,7 +33,7 @@ #include "group_editbox.h" #include "dbview_bar.h" #include "skill_manager.h" - +#include "game_share/bot_chat_types.h" using namespace std; using namespace NLMISC; @@ -69,7 +69,9 @@ const std::string FaberPhraseItemResultGroup= FaberPhraseWindow + ":header_opene // *************************************************************************** CActionPhraseFaber::CActionPhraseFaber() { - _InventoryMirror.resize(INVENTORIES::NUM_INVENTORY * MAX_PLAYER_INV_ENTRIES); + uint size = MAX_PLAYER_INV_ENTRIES + (MAX_ANIMALINV_ENTRIES * MAX_INVENTORY_ANIMAL) + + MAX_GUILDINV_ENTRIES + MAX_ROOMINV_ENTRIES; + _InventoryMirror.resize(size); _InventoryObsSetup= false; _ExecuteFromItemPlanBrick= NULL; } @@ -275,25 +277,64 @@ void CActionPhraseFaber::fillFaberPlanSelection(const std::string &brickDB, ui } // *************************************************************************** -CItemImage *CActionPhraseFaber::getInvMirrorItemImage(uint slotIndex) +CItemImage *CActionPhraseFaber::getInvMirrorItemImage(uint slotIndex, uint& invId, uint& indexInInv) { - uint invId= slotIndex/MAX_PLAYER_INV_ENTRIES; - uint indexInInv= slotIndex%MAX_PLAYER_INV_ENTRIES; + if (slotIndex < MAX_PLAYER_INV_ENTRIES) + { + invId = INVENTORIES::bag; + indexInInv = slotIndex; + return &getInventory().getBagItem(slotIndex); + } + slotIndex -= MAX_PLAYER_INV_ENTRIES; - // get the item image from bag, steed, pack animal... - if(invId==INVENTORIES::bag && indexInInv=INVENTORIES::pet_animal && invIdgetDbBranch(SERVER_INVENTORY ":GUILD:" + toString(slotIndex)); + static CItemImage image; + image.build(itemBranch); + invId = INVENTORIES::guild; + indexInInv = slotIndex; + return ℑ + } + return NULL; + } + slotIndex -= MAX_GUILDINV_ENTRIES; + + if (slotIndex < MAX_ROOMINV_ENTRIES) + { + if (getInventory().isInventoryAvailable(INVENTORIES::player_room)) + { + CInterfaceManager *im = CInterfaceManager::getInstance(); + CCDBNodeBranch *itemBranch = im->getDbBranch(SERVER_INVENTORY ":ROOM:" + toString(slotIndex)); + static CItemImage image; + image.build(itemBranch); + invId = INVENTORIES::player_room; + indexInInv = slotIndex; + return ℑ + } + return NULL; + } return NULL; } // *************************************************************************** -bool CActionPhraseFaber::isMpAvailable(CItemSheet *mpSheet, uint slotIndex) const +bool CActionPhraseFaber::isMpAvailable(CItemSheet *mpSheet, uint invId, uint slotIndex) const { - uint invId= slotIndex / MAX_PLAYER_INV_ENTRIES; return mpSheet && mpSheet->Family==ITEMFAMILY::RAW_MATERIAL && getInventory().isInventoryAvailable((INVENTORIES::TInventory)invId); } @@ -396,14 +437,14 @@ void CActionPhraseFaber::validateFaberPlanSelection(CSBrickSheet *itemPlanBrick _InventoryMirror[i].reset(); } + uint invId = 0; + uint indexInInv = 0; // Run all the inventories. for(i=0;i<_InventoryMirror.size();i++) { - uint invId= i/MAX_PLAYER_INV_ENTRIES; - uint indexInInv= i%MAX_PLAYER_INV_ENTRIES; - CItemImage *itemImage= getInvMirrorItemImage(i); - - // item found? + CItemImage *itemImage= getInvMirrorItemImage(i, invId, indexInInv); + bool bLockedByOwner = itemImage && itemImage->getLockedByOwner(); + // item found and not locked? if(itemImage) { // setup the origin @@ -413,7 +454,7 @@ void CActionPhraseFaber::validateFaberPlanSelection(CSBrickSheet *itemPlanBrick // The item must be a mp CSheetId sheetId= CSheetId(itemImage->getSheetID()); CItemSheet *mpSheet= dynamic_cast(SheetMngr.get(sheetId)); - if( isMpAvailable(mpSheet, i) ) + if( isMpAvailable(mpSheet, invId, i) && !bLockedByOwner) { _InventoryMirror[i].Sheet= sheetId; _InventoryMirror[i].Quality= itemImage->getQuality(); @@ -422,6 +463,7 @@ void CActionPhraseFaber::validateFaberPlanSelection(CSBrickSheet *itemPlanBrick _InventoryMirror[i].Weight= itemImage->getWeight(); // Bkup original quantity from inventory _InventoryMirror[i].OriginalQuantity= _InventoryMirror[i].Quantity; + _InventoryMirror[i].LockedByOwner= bLockedByOwner; } } } @@ -1311,17 +1353,22 @@ void CActionPhraseFaber::onInventoryChange() return; // Run all the Bag + uint invId = 0; + uint indexInInv = 0; for(i=0;i<_InventoryMirror.size();i++) { - CItemImage *itemImage= getInvMirrorItemImage(i); + CItemImage *itemImage= getInvMirrorItemImage(i, invId, indexInInv); + if(itemImage) { CSheetId sheetId= CSheetId(itemImage->getSheetID()); CItemSheet *mpSheet= dynamic_cast(SheetMngr.get(sheetId)); CItem newInvItem; - // The item must be a mp, and the item must be available - if( isMpAvailable(mpSheet, i) ) + bool bLockedByOwner = itemImage->getLockedByOwner(); + + // The item must be a mp, and the item must be available and unlocked + if( isMpAvailable(mpSheet, invId, i) && !bLockedByOwner) { newInvItem.Sheet= sheetId; newInvItem.Quality= itemImage->getQuality(); @@ -1329,12 +1376,13 @@ void CActionPhraseFaber::onInventoryChange() newInvItem.UserColor= itemImage->getUserColor(); newInvItem.Weight= itemImage->getWeight(); newInvItem.OriginalQuantity= newInvItem.Quantity; + newInvItem.LockedByOwner = bLockedByOwner; } - /* There is 4 cases: + /* There is 5 cases: - no changes => no op. - - new Mp on a empty or non Mp slot. Easy, just add. - - old Mp removed (not same sheetId/quality/userColor) + - new/unlocked Mp on a empty or non Mp slot. Easy, just add. + - old Mp removed (not same sheetId/quality/userColor/locked) - old Mp with quantity changed to be greater - old Mp with quantity changed to be smaller */ @@ -1348,8 +1396,8 @@ void CActionPhraseFaber::onInventoryChange() // If the item was not a mp if(_InventoryMirror[i].Sheet==CSheetId::Unknown) { - // if now it is, easy, just add - if(newInvItem.Sheet!=CSheetId::Unknown) + // if now it is, easy, just add if not locked + if(newInvItem.Sheet!=CSheetId::Unknown && !newInvItem.LockedByOwner) curInvItem= newInvItem; } // else must test change or remove @@ -1358,7 +1406,8 @@ void CActionPhraseFaber::onInventoryChange() bool sameMp; sameMp= curInvItem.Sheet == newInvItem.Sheet && curInvItem.Quality == newInvItem.Quality && - curInvItem.UserColor == newInvItem.UserColor ; + curInvItem.UserColor == newInvItem.UserColor && + curInvItem.LockedByOwner == newInvItem.LockedByOwner; // if the Mp was deleted from this slot, delete it from all faber execution if(!sameMp) diff --git a/code/ryzom/client/src/interface_v3/action_phrase_faber.h b/code/ryzom/client/src/interface_v3/action_phrase_faber.h index 8b792089b..517b25210 100644 --- a/code/ryzom/client/src/interface_v3/action_phrase_faber.h +++ b/code/ryzom/client/src/interface_v3/action_phrase_faber.h @@ -92,6 +92,7 @@ private: uint Selected; // This is the original quantity in inventory sint32 OriginalQuantity; + bool LockedByOwner; CItem() : Sheet(0) { @@ -233,8 +234,8 @@ private: void removeMpSlotThatUseInvSlot(uint invSlot, uint quantityToRemove); // from an index in _InventoryMirror, get the ItemImage - CItemImage *getInvMirrorItemImage(uint slotIndex); - bool isMpAvailable(CItemSheet *mpSheet, uint slotIndex) const; + CItemImage *getInvMirrorItemImage(uint slotIndex, uint& invId, uint& indexInInv); + bool isMpAvailable(CItemSheet *mpSheet, uint invId, uint slotIndex) const; void updateItemResult(); }; diff --git a/code/ryzom/client/src/interface_v3/bot_chat_page_trade.cpp b/code/ryzom/client/src/interface_v3/bot_chat_page_trade.cpp index dcebe792d..1cd5644d4 100644 --- a/code/ryzom/client/src/interface_v3/bot_chat_page_trade.cpp +++ b/code/ryzom/client/src/interface_v3/bot_chat_page_trade.cpp @@ -48,6 +48,7 @@ #include "../sheet_manager.h" #include "../user_entity.h" #include "view_bitmap.h" +#include "nel/misc/common.h" using namespace std::rel_ops; @@ -996,7 +997,7 @@ void CBotChatPageTrade::startSellDialog(CDBCtrlSheet *sheet, CCtrlBase * /* pCal CCtrlTextButton *confirmButton = dynamic_cast(ig->getCtrl("ok")); if (confirmButton) { - confirmButton->setActive( true ); + confirmButton->setActive( sheet->getLockedByOwner() ); confirmButton->setText(CI18N::get("uiSellImmediately")); confirmButton->setDefaultContextHelp(CI18N::get("uittDirectSellButton")); } @@ -1538,10 +1539,12 @@ void CBotChatPageTrade::setupResellGroup(bool sellMode, uint defaultQuantity, CI CViewText *vt= dynamic_cast(cantResellGroup->getView("reason")); if(vt) { - if(resaleFlag==BOTCHATTYPE::ResaleKOBroken) + if(resaleFlag == BOTCHATTYPE::ResaleKOBroken) vt->setHardText("uiCantResaleCauseDamaged"); - else + else if (resaleFlag == BOTCHATTYPE::ResaleKONoTimeLeft) vt->setHardText("uiCantResaleCauseTooLate"); + else + vt->setHardText("uiCantResaleLockedByOwner"); } } // else setup "can_resell:choose_resell group" @@ -2575,9 +2578,9 @@ static DECLARE_INTERFACE_USER_FCT(getPriceWithFame) if(value==-1) result.setUCString(CI18N::get("uiBadPrice")); else if(value==valueFame) - result.setUCString(toString(value)); + result.setUCString(NLMISC::formatThousands(toString(value))); else - result.setUCString(toString("%d (%d)", valueFame, value)); + result.setUCString(NLMISC::formatThousands(toString(valueFame)) + " (" + NLMISC::formatThousands(toString(value)) + ")"); return true; } @@ -2592,8 +2595,8 @@ static DECLARE_INTERFACE_USER_FCT(getBonusOnResale) sint valueHigh= (sint)args[0].getInteger(); sint valueLow= (sint)args[1].getInteger(); - sint diff = valueHigh - valueLow; - result.setUCString(toString("+%d", diff)); + sint diff = valueHigh - valueLow; + result.setUCString("+" + NLMISC::formatThousands(toString(diff))); return true; } diff --git a/code/ryzom/client/src/interface_v3/chat_filter.cpp b/code/ryzom/client/src/interface_v3/chat_filter.cpp index fc2e6c9c3..9609fc1af 100644 --- a/code/ryzom/client/src/interface_v3/chat_filter.cpp +++ b/code/ryzom/client/src/interface_v3/chat_filter.cpp @@ -378,7 +378,7 @@ void CChatTargetFilter::setTargetGroup(CChatGroup::TGroupType groupType, uint32 const bool guildActive = pIM->getDbProp("SERVER:GUILD:NAME")->getValueBool(); switch(groupType) { - case CChatGroup::dyn_chat: entry+="DYN"; break; + case CChatGroup::dyn_chat: entry+="DYN:" + NLMISC::toString(dynamicChannelDbIndex); break; case CChatGroup::say: entry+="SAY"; break; case CChatGroup::shout: entry+="SHOUT"; break; case CChatGroup::team: if(!teamActive) return; entry+="GROUP"; break; diff --git a/code/ryzom/client/src/interface_v3/chat_text_manager.cpp b/code/ryzom/client/src/interface_v3/chat_text_manager.cpp index 391898563..d1488b4dd 100644 --- a/code/ryzom/client/src/interface_v3/chat_text_manager.cpp +++ b/code/ryzom/client/src/interface_v3/chat_text_manager.cpp @@ -148,18 +148,43 @@ CViewBase *CChatTextManager::createMsgText(const ucstring &cstMsg, NLMISC::CRGBA vt->setMultiLineSpace(getTextMultiLineSpace()); vt->setModulateGlobalColor(false); + ucstring cur_time = ""; + static CCDBNodeLeaf* node = CInterfaceManager::getInstance()->getDbProp("UI:SAVE:CHAT:SHOW_TIMES_IN_CHAT_CB", false); + if (node) + { + if (node->getValueBool()) + { + cur_time = CInterfaceManager::getTimestampHuman(); + } + } + // if text contain any color code, set the text formated and white, // otherwise, set text normal and apply global color - if (msg.find(ucstring("@{")) != ucstring::npos) + size_t codePos = msg.find(ucstring("@{")); + if (codePos != ucstring::npos) { + // Prepend the current time (do it after the color if the color at first position. + if (codePos == 0) + { + codePos = msg.find(ucstring("}")); + msg = msg.substr(0, codePos + 1) + cur_time + msg.substr(codePos + 1, msg.length() - codePos); + } + else + { + msg = cur_time + msg; + } + + vt->setTextFormatTaged(msg); vt->setColor(NLMISC::CRGBA::White); } else { + msg = cur_time + msg; vt->setText(msg); vt->setColor(col); } + if (!commandGroup) { return vt; diff --git a/code/ryzom/client/src/interface_v3/chat_window.cpp b/code/ryzom/client/src/interface_v3/chat_window.cpp index 6f13b1bed..773992fc3 100644 --- a/code/ryzom/client/src/interface_v3/chat_window.cpp +++ b/code/ryzom/client/src/interface_v3/chat_window.cpp @@ -472,15 +472,9 @@ void CChatWindow::displayLocalPlayerTell(const ucstring &receiver, const ucstrin CInterfaceProperty prop; prop.readRGBA("UI:SAVE:CHAT:COLORS:SPEAKER"," "); encodeColorTag(prop.getRGBA(), finalMsg, false); - ucstring cur_time; - CCDBNodeLeaf *pNL = CInterfaceManager::getInstance()->getDbProp("UI:SAVE:CHAT:SHOW_TIMES_IN_CHAT_CB", false); - if (pNL && pNL->getValueBool()) - { - cur_time = CInterfaceManager::getTimestampHuman(); - } - ucstring csr; - if (CHARACTER_TITLE::isCsrTitle(UserEntity->getTitleRaw())) csr += ucstring("(CSR) "); - finalMsg += cur_time + csr + CI18N::get("youTell") + ": "; + + ucstring csr = CHARACTER_TITLE::isCsrTitle(UserEntity->getTitleRaw()) ? "(CSR) " : ""; + finalMsg += csr + CI18N::get("youTell") + ": "; prop.readRGBA("UI:SAVE:CHAT:COLORS:TELL"," "); encodeColorTag(prop.getRGBA(), finalMsg, true); finalMsg += msg; @@ -1294,8 +1288,18 @@ public: CChatWindow::_ChatWindowLaunchingCommand = chat; string str = text.toUtf8(); string cmdWithArgs = str.substr(1); - /* In the chat context, only ' ' is a possible separator */ + + // Get the command name from the string, can contain spaces string cmd = cmdWithArgs.substr(0, cmdWithArgs.find(' ')); + if (cmdWithArgs.find('"') == 0) + { + string::size_type pos = cmdWithArgs.find('"', 1); + if (string::npos != pos) + { + cmd = cmdWithArgs.substr(1, pos - 1); + } + } + if ( NLMISC::ICommand::exists( cmd ) ) { NLMISC::ICommand::execute( cmdWithArgs, g_log ); @@ -1314,7 +1318,7 @@ public: } } // Clear input string - pEB->setInputString (string("")); + pEB->setInputString (ucstring("")); CGroupContainer *gc = pEB->getEnclosingContainer(); if (gc) { diff --git a/code/ryzom/client/src/interface_v3/ctrl_base_button.h b/code/ryzom/client/src/interface_v3/ctrl_base_button.h index 06a27b276..c33f0c63e 100644 --- a/code/ryzom/client/src/interface_v3/ctrl_base_button.h +++ b/code/ryzom/client/src/interface_v3/ctrl_base_button.h @@ -115,6 +115,7 @@ public: // @{ // Event part void setActionOnLeftClick (const std::string &actionHandlerName) { _AHOnLeftClickString = actionHandlerName; _AHOnLeftClick = getAH(actionHandlerName, _AHLeftClickParams); } + void setActionOnLeftClickParams(const std::string ¶ms) { _AHOnLeftClickStringParams = params; } void setActionOnRightClick (const std::string &actionHandlerName) { _AHOnRightClick = getAH(actionHandlerName, _AHRightClickParams); } void setActionOnClockTick (const std::string &ahName) { _AHOnClockTick = getAH(ahName, _AHClockTickParams); } void setParamsOnLeftClick (const std::string ¶msHandlerName) { _AHLeftClickParams = paramsHandlerName; } @@ -204,6 +205,7 @@ protected: IActionHandler *_AHOnOver; CStringShared _AHOverParams; std::string _AHOnLeftClickString; + std::string _AHOnLeftClickStringParams; IActionHandler *_AHOnLeftClick; CStringShared _AHLeftClickParams; IActionHandler *_AHOnLeftDblClick; diff --git a/code/ryzom/client/src/interface_v3/ctrl_button.cpp b/code/ryzom/client/src/interface_v3/ctrl_button.cpp index fd1ba049b..0f77fc6fe 100644 --- a/code/ryzom/client/src/interface_v3/ctrl_button.cpp +++ b/code/ryzom/client/src/interface_v3/ctrl_button.cpp @@ -338,7 +338,14 @@ bool CCtrlButton::getMouseOverShape(string &texName, uint8 &rot, CRGBA &col) { if (_AHOnLeftClickString == "browse") { - texName = "curs_pick.tga"; + if (!_AHOnLeftClickStringParams.empty()) + { + texName = "@curs_pick.tga@"+_AHOnLeftClickStringParams; + } + else + { + texName = "curs_pick.tga"; + } rot= 0; col = CRGBA::White; return true; diff --git a/code/ryzom/client/src/interface_v3/dbctrl_sheet.cpp b/code/ryzom/client/src/interface_v3/dbctrl_sheet.cpp index ce551a0b7..c7afcaf92 100644 --- a/code/ryzom/client/src/interface_v3/dbctrl_sheet.cpp +++ b/code/ryzom/client/src/interface_v3/dbctrl_sheet.cpp @@ -45,6 +45,7 @@ #include "../client_sheets/sphrase_sheet.h" #include "game_share/xml_auto_ptr.h" #include "lua_ihm.h" +#include "game_share/bot_chat_types.h" #include "../r2/editor.h" @@ -123,6 +124,14 @@ ucstring CControlSheetTooltipInfoWaiter::infoValidated(CDBCtrlSheet* ctrlSheet, return help; } + +// *************************************************************************** +int CDBCtrlSheet::luaGetDraggedSheet(CLuaState &ls) +{ + CLuaIHM::pushUIOnStack(ls, dynamic_cast(_LastDraggedSheet)); + return 1; +} + // *************************************************************************** int CDBCtrlSheet::luaGetHpBuff(CLuaState &ls) { @@ -179,6 +188,62 @@ int CDBCtrlSheet::luaGetName(CLuaState &ls) return 1; } +// ********************************************************************************************************** +class LuaInfoWaiter : public IItemInfoWaiter +{ +public: + volatile bool done; + +public: + virtual void infoReceived(); +}; + + +void LuaInfoWaiter::infoReceived() +{ + getInventory().removeItemInfoWaiter(this); + this->done = true; +} + +static LuaInfoWaiter luaInfoWaiter; + +// *************************************************************************** +int CDBCtrlSheet::luaGetCreatorName(CLuaState &ls) +{ + uint32 itemSlotId = getInventory().getItemSlotId(this); + CClientItemInfo itemInfo = getInventory().getItemInfo(itemSlotId); + ucstring creatorName; + STRING_MANAGER::CStringManagerClient::instance()->getString(itemInfo.CreatorName, creatorName); + CLuaIHM::push(ls, creatorName); + + return 1; +} + +// *************************************************************************** +int CDBCtrlSheet::luaWaitInfo(CLuaState &ls) +{ + static bool sent = false; + CDBCtrlSheet *ctrlSheet = const_cast(this); + uint32 itemSlotId= getInventory().getItemSlotId(ctrlSheet); + CClientItemInfo itemInfo = getInventory().getItemInfo(itemSlotId); + + if (sent || itemInfo.versionInfo != 0) + { + ls.push((bool)(luaInfoWaiter.done)); + if (luaInfoWaiter.done) + sent = false; + return luaInfoWaiter.done ? 1 : 0; + } + else + { + luaInfoWaiter.ItemSlotId = itemSlotId; + luaInfoWaiter.ItemSheet = this->getSheetId(); + luaInfoWaiter.done = false; + getInventory().addItemInfoWaiter(&luaInfoWaiter); + sent = true; + } + return 0; +} // *************************************************************************** int CDBCtrlSheet::luaBuildCrystallizedSpellListBrick(CLuaState &ls) @@ -1797,8 +1862,16 @@ void CDBCtrlSheet::draw() string params = string("src=") + pCSSrc->getId(); if (!_AHCanDropParams.empty()) { - string sTmp = _AHCanDropParams; - params = sTmp + "|" + params; + if (getAHName(_AHOnCanDrop) == "lua") + { + params = _AHCanDropParams; + strFindReplace(params, "%src", pCSSrc->getId()); + } + else + { + string sTmp = _AHCanDropParams; + params = sTmp + "|" + params; + } } pIM->runActionHandler (_AHOnCanDrop, this, params); } @@ -2138,6 +2211,12 @@ void CDBCtrlSheet::drawSheet (sint32 x, sint32 y, bool draging, bool showSelecti // if a raw material for example, must add special icon text. displayCharBitmaps(_RenderLayer+2, x, y, curSheetColor); + + // Add the lock overlay if needed + if (getLockedByOwner()) + { + rVR.draw11RotFlipBitmap (_RenderLayer+1, x - 2, y + 8, 0, false, rVR.getSystemTextureId(CViewRenderer::ItemLockedByOwnerTexture), curSheetColor); + } } break; // Action @@ -2600,8 +2679,16 @@ bool CDBCtrlSheet::handleEvent (const CEventDescriptor &event) string params = string("src=") + _Id; if (!pCSdest->_AHCanDropParams.empty()) { - string sTmp = pCSdest->_AHCanDropParams; - params = sTmp + "|" + params; + if (getAHName(pCSdest->_AHOnCanDrop) == "lua") + { + params = pCSdest->_AHCanDropParams; + strFindReplace(params, "%src", _Id); + } + else + { + string sTmp = pCSdest->_AHCanDropParams; + params = sTmp + "|" + params; + } } pIM->runActionHandler (pCSdest->_AHOnCanDrop, pCSdest, params); @@ -2612,8 +2699,16 @@ bool CDBCtrlSheet::handleEvent (const CEventDescriptor &event) string params = string("src=") + _Id; if (!pCSdest->_AHDropParams.empty()) { - string sTmp = pCSdest->_AHDropParams; - params = sTmp + "|" + params; // must copy 'drop' params at start because it could be the name of a procedure + if (getAHName(pCSdest->_AHOnDrop) == "lua") + { + params = pCSdest->_AHDropParams; + strFindReplace(params, "%src", _Id); + } + else + { + string sTmp = pCSdest->_AHDropParams; + params = sTmp + "|" + params;// must copy 'drop' params at start because it could be the name of a procedure + } } // call action pIM->runActionHandler (pCSdest->_AHOnDrop, pCSdest, params); @@ -2649,8 +2744,16 @@ bool CDBCtrlSheet::handleEvent (const CEventDescriptor &event) string params = string("src=") + _Id; if (!pList->getCtrlSheetInfo()._AHCanDropParams.empty()) { - string sTmp = pList->getCtrlSheetInfo()._AHCanDropParams; - params = sTmp + "|" + params; + if (getAHName(pList->getCtrlSheetInfo()._AHOnCanDrop) == "lua") + { + params = pList->getCtrlSheetInfo()._AHCanDropParams; + strFindReplace(params, "%src", _Id); + } + else + { + string sTmp = pList->getCtrlSheetInfo()._AHCanDropParams; + params = sTmp + "|" + params; + } } pIM->runActionHandler (pList->getCtrlSheetInfo()._AHOnCanDrop, pList, params); @@ -2661,8 +2764,16 @@ bool CDBCtrlSheet::handleEvent (const CEventDescriptor &event) string params = string("src=") + _Id; if (!pList->getCtrlSheetInfo()._AHDropParams.empty()) { - string sTmp = pList->getCtrlSheetInfo()._AHDropParams; - params = sTmp + "|" + params; // must copy 'drop' params at start because it could be the name of a procedure + if (getAHName(pList->getCtrlSheetInfo()._AHOnDrop) == "lua") + { + params = pList->getCtrlSheetInfo()._AHDropParams; + strFindReplace(params, "%src", _Id); + } + else + { + string sTmp = pList->getCtrlSheetInfo()._AHDropParams; + params = sTmp + "|" + params; // must copy 'drop' params at start because it could be the name of a procedure + } } // call action pIM->runActionHandler (pList->getCtrlSheetInfo()._AHOnDrop, pList, params); @@ -2975,9 +3086,32 @@ void CDBCtrlSheet::getContextHelp(ucstring &help) const } else if(getType() == CCtrlSheetInfo::SheetType_Item) { - const CItemSheet *item = asItemSheet(); - if (item) - help = getItemActualName(); + const CItemSheet *item= asItemSheet(); + if(item) + { + if (item->Family == ITEMFAMILY::CRYSTALLIZED_SPELL || item->Family == ITEMFAMILY::JEWELRY || item->Family == ITEMFAMILY::ARMOR) + { + string luaMethodName = ( (item->Family == ITEMFAMILY::CRYSTALLIZED_SPELL) ? "updateCrystallizedSpellTooltip" : "updateBuffItemTooltip"); + CDBCtrlSheet *ctrlSheet = const_cast(this); + if ( ! getInventory().isItemInfoUpToDate(getInventory().getItemSlotId(ctrlSheet))) + { + // Prepare the waiter + ControlSheetTooltipUpdater.ItemSheet= ctrlSheet->getSheetId(); + ControlSheetTooltipUpdater.LuaMethodName = luaMethodName; + ControlSheetTooltipUpdater.ItemSlotId= getInventory().getItemSlotId(ctrlSheet); + ControlSheetTooltipUpdater.CtrlSheet = ctrlSheet; + + // Add the waiter + getInventory().addItemInfoWaiter(&ControlSheetTooltipUpdater); + } + + help = ControlSheetTooltipUpdater.infoValidated(ctrlSheet, luaMethodName); + + } + else + help= getItemActualName(); + + } else help= _ContextHelp; } @@ -3936,6 +4070,17 @@ void CDBCtrlSheet::setItemResaleFlag(sint32 rf) node->setValue32(rf); } +// *************************************************************************** +bool CDBCtrlSheet::getLockedByOwner() const +{ + return (getItemResaleFlag() == BOTCHATTYPE::ResaleKOLockedByOwner); +} + +// *************************************************************************** +bool CDBCtrlSheet::canOwnerLock() const +{ + return (NULL != getItemResaleFlagPtr()); +} // *************************************************************************** sint32 CDBCtrlSheet::getItemSellerType() const diff --git a/code/ryzom/client/src/interface_v3/dbctrl_sheet.h b/code/ryzom/client/src/interface_v3/dbctrl_sheet.h index 2cf34e722..6bd7706fb 100644 --- a/code/ryzom/client/src/interface_v3/dbctrl_sheet.h +++ b/code/ryzom/client/src/interface_v3/dbctrl_sheet.h @@ -194,16 +194,20 @@ public: void setActionOnLeftClick (const std::string &ActionHandlerName) { _AHOnLeftClick = getAH(ActionHandlerName, _AHLeftClickParams); } void setActionOnRightClick (const std::string &ActionHandlerName) { _AHOnRightClick = getAH(ActionHandlerName, _AHRightClickParams); } void setActionOnDrop (const std::string &ActionHandlerName) { _AHOnDrop = getAH(ActionHandlerName, _AHDropParams); } + void setActionOnCanDrop (const std::string &ActionHandlerName) { _AHOnCanDrop = getAH(ActionHandlerName, _AHCanDropParams); } void setParamsOnLeftClick (const std::string &ParamsHandlerName) { _AHLeftClickParams = ParamsHandlerName; } void setParamsOnRightClick (const std::string &ParamsHandlerName) { _AHRightClickParams = ParamsHandlerName; } void setParamsOnDrop (const std::string &ParamsHandlerName) { _AHDropParams = ParamsHandlerName; } + void setParamsOnCanDrop (const std::string &ParamsHandlerName) { _AHCanDropParams = ParamsHandlerName; } const std::string &getActionOnLeftClick () const { return getAHName(_AHOnLeftClick); } const std::string &getActionOnRightClick () const { return getAHName(_AHOnRightClick); } const std::string &getActionOnDrop () const { return getAHName(_AHOnDrop); } + const std::string &getActionOnCanDrop () const { return getAHName(_AHOnCanDrop); } const std::string &getParamsOnLeftClick () const { return _AHLeftClickParams; } const std::string &getParamsOnRightClick () const { return _AHRightClickParams; } const std::string &getParamsOnDrop () const { return _AHDropParams; } + const std::string &getParamsOnCanDrop () const { return _AHCanDropParams; } void setListMenuLeft (const std::string &cm) { CCtrlSheetInfo::setListMenuLeft(cm); } void setListMenuRight (const std::string &cm) { CCtrlSheetInfo::setListMenuRight(cm); } @@ -215,6 +219,7 @@ public: void setCanDrop (bool cd) { _CanDrop = cd; } bool getCanDrop () const { return _CanDrop; } bool isDragable() { return _Dragable; } + void setDragable(bool dragable) { _Dragable = dragable; } bool isDraging() { return _Draging; } sint32 getDeltaDragX() {return _DeltaDragX;} sint32 getDeltaDragY() {return _DeltaDragY;} @@ -265,19 +270,35 @@ public: REFLECT_SINT32("back", getGuildBack, setGuildBack); REFLECT_SINT32("symbol", getGuildSymbol, setGuildSymbol); REFLECT_BOOL("invert_symbol", getInvertGuildSymbol, setInvertGuildSymbol); + REFLECT_BOOL("dragable", isDragable, setDragable); + REFLECT_BOOL("can_drop", getCanDrop, setCanDrop); + REFLECT_STRING ("left_click", getActionOnLeftClick, setActionOnLeftClick); + REFLECT_STRING ("right_click", getActionOnRightClick, setActionOnRightClick); + REFLECT_STRING ("left_click_params", getParamsOnLeftClick, setParamsOnLeftClick); + REFLECT_STRING ("right_click_params", getParamsOnRightClick, setParamsOnRightClick); + REFLECT_STRING ("on_drop", getActionOnDrop, setActionOnDrop); + REFLECT_STRING ("on_drop_params", getParamsOnDrop, setParamsOnDrop); + REFLECT_STRING ("on_can_drop", getActionOnCanDrop, setActionOnCanDrop); + REFLECT_STRING ("on_can_drop_params", getParamsOnCanDrop, setParamsOnCanDrop); + REFLECT_LUA_METHOD("getDraggedSheet", luaGetDraggedSheet) REFLECT_LUA_METHOD("getHpBuff", luaGetHpBuff) REFLECT_LUA_METHOD("getSapBuff", luaGetSapBuff) REFLECT_LUA_METHOD("getFocusBuff", luaGetFocusBuff) REFLECT_LUA_METHOD("getStaBuff", luaGetStaBuff) REFLECT_LUA_METHOD("getName", luaGetName) + REFLECT_LUA_METHOD("getCreatorName", luaGetCreatorName) + REFLECT_LUA_METHOD("waitInfo", luaWaitInfo) REFLECT_LUA_METHOD("buildCrystallizedSpellListBrick", luaBuildCrystallizedSpellListBrick) REFLECT_EXPORT_END + int luaGetDraggedSheet(CLuaState &ls); int luaGetHpBuff(CLuaState &ls); int luaGetSapBuff(CLuaState &ls); int luaGetFocusBuff(CLuaState &ls); int luaGetStaBuff(CLuaState &ls); int luaGetName(CLuaState &ls); + int luaGetCreatorName(CLuaState &ls); + int luaWaitInfo(CLuaState &ls); int luaBuildCrystallizedSpellListBrick(CLuaState &ls); // hardcode creation. User must setup other CtrlBase value (parent etc...) @@ -355,9 +376,9 @@ public: /// Special ContextHelp for ctrl sheet. virtual void getContextHelp(ucstring &help) const; - /// Special ContextHelp for ctrl sheet. virtual void getContextHelpToolTip(ucstring &help) const; + /** true if an item of another ctrlSheet can be dropped on this slot. * also return true if src is 0, or if _ItemSlot==UNDEFINED */ @@ -494,6 +515,12 @@ public: // set item RESALE_FLAG void setItemResaleFlag(sint32 rf); + // get item locked by owner + bool getLockedByOwner() const; + + // true if the inventory supports owner locking + bool canOwnerLock() const; + // get item SELLER_TYPE. 0 if no DB sint32 getItemSellerType() const; CCDBNodeLeaf *getItemSellerTypePtr() const; diff --git a/code/ryzom/client/src/interface_v3/dbgroup_list_sheet_trade.cpp b/code/ryzom/client/src/interface_v3/dbgroup_list_sheet_trade.cpp index 7511ee8ef..bd30d61f6 100644 --- a/code/ryzom/client/src/interface_v3/dbgroup_list_sheet_trade.cpp +++ b/code/ryzom/client/src/interface_v3/dbgroup_list_sheet_trade.cpp @@ -30,6 +30,7 @@ #include "game_share/pvp_clan.h" #include "../string_manager_client.h" #include "../entity_cl.h" +#include "nel/misc/common.h" using namespace NLMISC; @@ -264,7 +265,7 @@ void CDBGroupListSheetTrade::CSheetChildTrade::updateViewText(CDBGroupListSheetT { STRING_MANAGER::CStringManagerClient *pSMC = STRING_MANAGER::CStringManagerClient::instance(); text += string("\n") + pSMC->getOutpostBuildingLocalizedDescription(CSheetId(Ctrl->getSheetId())); - text += "\n" + CI18N::get("uiBotChatPrice") + toString(pOBS->CostDapper); + text += "\n" + CI18N::get("uiBotChatPrice") + NLMISC::formatThousands(toString(pOBS->CostDapper)); text += CI18N::get("uiBotChatTime") + toString(pOBS->CostTime/60) + CI18N::get("uiBotChatTimeMinute"); if ((pOBS->CostTime % 60) != 0) text += toString(pOBS->CostTime%60) + CI18N::get("uiBotChatTimeSecond"); @@ -341,7 +342,7 @@ void CDBGroupListSheetTrade::CSheetChildTrade::updateViewText(CDBGroupListSheetT if (pIS && pIS->Family == ITEMFAMILY::GUILD_OPTION) { text+= "\n" + CI18N::get("uiBotChatSkillPointCost") + toString(pIS->GuildOption.XPCost); - text+= "\n" + CI18N::get("uiBotChatPrice") + toString(pIS->GuildOption.MoneyCost); + text+= "\n" + CI18N::get("uiBotChatPrice") + NLMISC::formatThousands(toString(pIS->GuildOption.MoneyCost)); guildOption= true; } } @@ -376,10 +377,10 @@ void CDBGroupListSheetTrade::CSheetChildTrade::updateViewText(CDBGroupListSheetT if (LastPrice > 0) { if(displayMulPrice) - text+= "\n" + CI18N::get("uiBotChatPrice") + toString(sint32(LastPrice * priceFactor)) + " (" - + toString( sint32(factor) * sint32(LastPrice * priceFactor) ) + ")"; + text+= "\n" + CI18N::get("uiBotChatPrice") + NLMISC::formatThousands(toString(sint32(LastPrice * priceFactor))) + " (" + + NLMISC::formatThousands(toString( sint32(factor) * sint32(LastPrice * priceFactor) )) + ")"; else - text+= "\n" + CI18N::get("uiBotChatPrice") + toString( sint32(factor * LastPrice * priceFactor) ); + text+= "\n" + CI18N::get("uiBotChatPrice") + NLMISC::formatThousands(toString( sint32(factor * LastPrice * priceFactor) )); } if ((LastFactionPointPrice != 0) && (LastFactionType >= PVP_CLAN::BeginClans) && (LastFactionType <= PVP_CLAN::EndClans)) @@ -390,7 +391,7 @@ void CDBGroupListSheetTrade::CSheetChildTrade::updateViewText(CDBGroupListSheetT text+= "\n"; text+= CI18N::get("uiBotChatFactionType") + PVP_CLAN::toString((PVP_CLAN::TPVPClan)LastFactionType) - + CI18N::get("uiBotChatFactionPointPrice") + toString(LastFactionPointPrice); + + CI18N::get("uiBotChatFactionPointPrice") + NLMISC::formatThousands(toString(LastFactionPointPrice)); } // some additional info for resale @@ -402,10 +403,10 @@ void CDBGroupListSheetTrade::CSheetChildTrade::updateViewText(CDBGroupListSheetT { // append price if(pIS && pIS->Stackable>1 && zeFather->getMultiplyPriceByQuantityFlag()) - text+= CI18N::get("uiBotChatRetirePrice") + toString(LastPriceRetire) + " (" - + toString(factor * LastPriceRetire) + ")"; + text+= CI18N::get("uiBotChatRetirePrice") + NLMISC::formatThousands(toString(LastPriceRetire)) + " (" + + NLMISC::formatThousands(toString(factor * LastPriceRetire)) + ")"; else - text+= CI18N::get("uiBotChatRetirePrice") + toString(factor * LastPriceRetire); + text+= CI18N::get("uiBotChatRetirePrice") + NLMISC::formatThousands(toString(factor * LastPriceRetire)); // set resale time left ucstring fmt= CI18N::get("uiBotChatResaleTimeLeft"); strFindReplace(fmt, "%d", toString(LastResaleTimeLeft/RYZOM_DAY_IN_HOUR)); @@ -482,6 +483,12 @@ bool CDBGroupListSheetTrade::CSheetChildTrade::isSheetValid(CDBGroupListSheetTex return false; } + // Locked by owner; cannot trade + if (Ctrl->getLockedByOwner()) + { + return false; + } + // Check seller type? TSellerTypeFilter stf= father->getSellerTypeFilter(); if( stf != None) diff --git a/code/ryzom/client/src/interface_v3/dbview_number.cpp b/code/ryzom/client/src/interface_v3/dbview_number.cpp index 8ca6e7c94..5ac955659 100644 --- a/code/ryzom/client/src/interface_v3/dbview_number.cpp +++ b/code/ryzom/client/src/interface_v3/dbview_number.cpp @@ -21,6 +21,7 @@ #include "dbview_number.h" #include "interface_manager.h" #include "game_share/xml_auto_ptr.h" +#include "nel/misc/common.h" using namespace std; using namespace NL3D; @@ -102,30 +103,6 @@ bool CDBViewNumber::parse (xmlNodePtr cur, CInterfaceGroup * parentGroup) return true; } -// *************************************************************************** -// Helper function -ucstring formatThousands(const ucstring& s, const ucstring& separator) -{ - int j; - int k; - int topI = s.length() - 1; - - if (topI < 4) return s; - - ucstring ns; - do - { - for (j = topI, k = 0; j >= 0 && k < 3; --j, ++k ) - { - ns = s[j] + ns; // new char is added to front of ns - if( j > 0 && k == 2) ns = separator + ns; // j > 0 means still more digits - } - topI -= 3; - - } while(topI >= 0); - return ns; -} - // *************************************************************************** void CDBViewNumber::checkCoords() { @@ -134,8 +111,7 @@ void CDBViewNumber::checkCoords() if (_Cache != val) { _Cache= val; - static ucstring separator = NLMISC::CI18N::get("uiThousandsSeparator"); - ucstring value = _Format ? formatThousands(toString(val), separator) : toString(val); + ucstring value = _Format ? NLMISC::formatThousands(toString(val)) : toString(val); if (_Positive) setText(val >= 0 ? ( ucstring(_Prefix) + value + ucstring(_Suffix) ) : ucstring("?")); else setText( ucstring(_Prefix) + value + ucstring(_Suffix) ); } diff --git a/code/ryzom/client/src/interface_v3/group_html.cpp b/code/ryzom/client/src/interface_v3/group_html.cpp index 8ce18fb77..388064131 100644 --- a/code/ryzom/client/src/interface_v3/group_html.cpp +++ b/code/ryzom/client/src/interface_v3/group_html.cpp @@ -34,6 +34,7 @@ extern "C" #include "view_link.h" #include "ctrl_scroll.h" #include "ctrl_button.h" +#include "dbctrl_sheet.h" #include "ctrl_text_button.h" #include "action_handler.h" #include "group_paragraph.h" @@ -63,13 +64,55 @@ using namespace NLMISC; CGroupHTML *CGroupHTML::_ConnectingLock = NULL; extern CActionsContext ActionsContext; -// Check if domain is on TrustedDomain -bool CGroupHTML::isTrustedDomain(const string &domain) { +// Check if domain is on TrustedDomain +bool CGroupHTML::isTrustedDomain(const string &domain) +{ vector::iterator it; it = find (ClientCfg.WebIgTrustedDomains.begin(), ClientCfg.WebIgTrustedDomains.end(), domain); return it != ClientCfg.WebIgTrustedDomains.end(); } +void CGroupHTML::setImage(CViewBase * view, const string &file) +{ + CCtrlButton *btn = dynamic_cast(view); + if(btn) + { + btn->setTexture (file); + btn->setTexturePushed(file); + btn->invalidateCoords(); + btn->invalidateContent(); + btn->resetInvalidCoords(); + btn->updateCoords(); + paragraphChange(); + } + else + { + CViewBitmap *btm = dynamic_cast(view); + if(btm) + { + btm->setTexture (file); + btm->invalidateCoords(); + btm->invalidateContent(); + btm->resetInvalidCoords(); + btm->updateCoords(); + paragraphChange(); + } + else + { + CGroupCell *btgc = dynamic_cast(view); + if(btgc) + { + btgc->setTexture (file); + btgc->invalidateCoords(); + btgc->invalidateContent(); + btgc->resetInvalidCoords(); + btgc->updateCoords(); + paragraphChange(); + } + } + } +} + // Get an url and return the local filename with the path where the url image should be string CGroupHTML::localImageName(const string &url) { @@ -99,30 +142,38 @@ void CGroupHTML::addImageDownload(const string &url, CViewBase *img) curl_easy_setopt(curl, CURLOPT_NOPROGRESS, true); curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); - string dest = localImageName(url)+".tmp"; + string dest = localImageName(url); + string tmpdest = localImageName(url)+".tmp"; #ifdef LOG_DL nlwarning("add to download '%s' dest '%s' img %p", url.c_str(), dest.c_str(), img); #endif - // create the local file - if (NLMISC::CFile::fileExists(dest)) - { - CFile::setRWAccess(dest); - NLMISC::CFile::deleteFile(dest); - } - FILE *fp = fopen (dest.c_str(), "wb"); - if (fp == NULL) - { - nlwarning("Can't open file '%s' for writing: code=%d '%s'", dest.c_str (), errno, strerror(errno)); - return; - } - curl_easy_setopt(curl, CURLOPT_FILE, fp); - curl_multi_add_handle(MultiCurl, curl); - Curls.push_back(CDataDownload(curl, url, fp, ImgType, img, "", "")); -#ifdef LOG_DL - nlwarning("adding handle %x, %d curls", curl, Curls.size()); -#endif - RunningCurls++; + // erase the tmp file if exists + if (NLMISC::CFile::fileExists(tmpdest)) + NLMISC::CFile::deleteFile(tmpdest); + + if (!NLMISC::CFile::fileExists(dest)) + { + + FILE *fp = fopen (tmpdest.c_str(), "wb"); + if (fp == NULL) + { + nlwarning("Can't open file '%s' for writing: code=%d '%s'", tmpdest.c_str (), errno, strerror(errno)); + return; + } + curl_easy_setopt(curl, CURLOPT_FILE, fp); + + curl_multi_add_handle(MultiCurl, curl); + Curls.push_back(CDataDownload(curl, url, fp, ImgType, img, "", "")); + #ifdef LOG_DL + nlwarning("adding handle %x, %d curls", curl, Curls.size()); + #endif + RunningCurls++; + } + else + { + setImage(img, dest); + } } void CGroupHTML::initImageDownload() @@ -297,41 +348,11 @@ void CGroupHTML::checkDownloads() for(uint i = 0; i < it->imgs.size(); i++) { // don't display image that are not power of 2 - uint32 w, h; - CBitmap::loadSize (file, w, h); - if (w == 0 || h == 0 || ((!NLMISC::isPowerOf2(w) || !NLMISC::isPowerOf2(h)) && !NL3D::CTextureFile::supportNonPowerOfTwoTextures())) - file.clear(); - - CCtrlButton *btn = dynamic_cast(it->imgs[i]); - if(btn) - { - #ifdef LOG_DL - nlwarning("refresh new downloading image %d button %p", i, it->imgs[i]); - #endif - btn->setTexture (file); - btn->setTexturePushed(file); - btn->invalidateCoords(); - btn->invalidateContent(); - btn->resetInvalidCoords(); - btn->updateCoords(); - paragraphChange(); - } - else - { - CViewBitmap *btm = dynamic_cast(it->imgs[i]); - if(btm) - { - #ifdef LOG_DL - nlwarning("refresh new downloading image %d image %p", i, it->imgs[i]); - #endif - btm->setTexture (file); - btm->invalidateCoords(); - btm->invalidateContent(); - btm->resetInvalidCoords(); - btm->updateCoords(); - paragraphChange(); - } - } + //uint32 w, h; + //CBitmap::loadSize (file, w, h); + //if (w == 0 || h == 0 || ((!NLMISC::isPowerOf2(w) || !NLMISC::isPowerOf2(h)) && !NL3D::CTextureFile::supportNonPowerOfTwoTextures())) + // file.clear(); + setImage(it->imgs[i], file); } } } @@ -446,6 +467,28 @@ void CGroupHTML::beginBuild () } +TStyle CGroupHTML::parseStyle (const string &str_styles) +{ + TStyle styles; + vector elements; + NLMISC::splitString(str_styles, ";", elements); + + for(uint i = 0; i < elements.size(); ++i) + { + vector style; + NLMISC::splitString(elements[i], ":", style); + if (style.size() >= 2) + { + string fullstyle = style[1]; + for (uint j=2; j < style.size(); j++) + fullstyle += ":"+style[j]; + styles[trim(style[0])] = fullstyle; + } + } + + return styles; +} + // *************************************************************************** void CGroupHTML::addText (const char * buf, int len) @@ -556,9 +599,31 @@ void CGroupHTML::addLink (uint element_number, uint /* attribute_number */, HTCh _Link.push_back(""); } } + + for(uint8 i = MY_HTML_A_ACCESSKEY; i < MY_HTML_A_Z_ACTION_SHORTCUT; i++) + { + if (present[i] && value[i]) + { + string title = value[i]; + // nlinfo("key %d = %s", i, title.c_str()); + } + } + //nlinfo("key of TITLE is : %d", MY_HTML_A_Z_ACTION_PARAMS); + if (present[MY_HTML_A_Z_ACTION_PARAMS] && value[MY_HTML_A_Z_ACTION_PARAMS]) + { + string title = value[MY_HTML_A_Z_ACTION_PARAMS]; + _LinkTitle.push_back(title); + } + else + _LinkTitle.push_back(""); } else + { _Link.push_back(""); + _LinkTitle.push_back(""); + } + + } } } @@ -626,7 +691,6 @@ static const char *scanColorComponent(const char *src, uint8 &intensity) return src; } - class CNameToCol { public: @@ -831,6 +895,11 @@ void CGroupHTML::beginElement (uint element_number, const BOOL *present, const c _GlobalColor.push_back(LinkColorGlobalColor); _A.push_back(true); + if (present[MY_HTML_A_TITLE] && value[MY_HTML_A_TITLE]) + _LinkTitle.push_back(value[MY_HTML_A_TITLE]); + if (present[MY_HTML_A_CLASS] && value[MY_HTML_A_CLASS]) + _LinkClass.push_back(value[MY_HTML_A_CLASS]); + // Quick help if (_TrustedDomain && present[MY_HTML_A_Z_ACTION_SHORTCUT] && value[MY_HTML_A_Z_ACTION_SHORTCUT]) { @@ -856,15 +925,87 @@ void CGroupHTML::beginElement (uint element_number, const BOOL *present, const c } } } + break; case HTML_DIV: { if (present[MY_HTML_DIV_NAME] && value[MY_HTML_DIV_NAME]) - { _DivName = value[MY_HTML_DIV_NAME]; + + string instClass; + if (present[MY_HTML_DIV_CLASS] && value[MY_HTML_DIV_CLASS]) + instClass = value[MY_HTML_DIV_CLASS]; + + // use generic template system + if (_TrustedDomain && !instClass.empty() && instClass == "ryzom-ui-grouptemplate") + { + string id; + if (present[MY_HTML_DIV_ID] && value[MY_HTML_DIV_ID]) + id = value[MY_HTML_DIV_ID]; + + string style; + if (present[MY_HTML_DIV_STYLE] && value[MY_HTML_DIV_STYLE]) + style = value[MY_HTML_DIV_STYLE]; + + typedef pair TTmplParam; + vector tmplParams; + + string templateName; + if (!style.empty()) + { + TStyle styles = parseStyle(style); + TStyle::iterator it; + for (it=styles.begin(); it != styles.end(); it++) + { + if ((*it).first == "template") + templateName = (*it).second; + else + tmplParams.push_back(TTmplParam((*it).first, (*it).second)); + } + } + + if (!templateName.empty()) + { + string parentId; + bool haveParentDiv = getDiv() != NULL; + if (haveParentDiv) + parentId = getDiv()->getId(); + else + parentId = _Paragraph->getId(); + + CInterfaceManager *im = CInterfaceManager::getInstance(); + CInterfaceGroup *inst = im->createGroupInstance(templateName, parentId+":"+id, tmplParams); + if (inst) + { + inst->setId(parentId+":"+id); + inst->updateCoords(); + if (haveParentDiv) + { + inst->setParent(getDiv()); + inst->setParentSize(getDiv()); + inst->setParentPos(getDiv()); + inst->setPosRef(Hotspot_TL); + inst->setParentPosRef(Hotspot_TL); + getDiv()->addGroup(inst); + } + else + { + if (!_Paragraph) + { + newParagraph (0); + paragraphChange (); + } + + getParagraph()->addChild(inst); + paragraphChange(); + } + _Divs.push_back(inst); + } + } } } break; + case HTML_FONT: { bool found = false; @@ -898,11 +1039,42 @@ void CGroupHTML::beginElement (uint element_number, const BOOL *present, const c addString(ucstring ("\n")); break; case HTML_BODY: - if (present[HTML_BODY_BGCOLOR] && value[HTML_BODY_BGCOLOR]) { - // Get the color - CRGBA bgColor = getColor (value[HTML_BODY_BGCOLOR]); - setBackgroundColor (bgColor); + if (present[HTML_BODY_BGCOLOR] && value[HTML_BODY_BGCOLOR]) + { + CRGBA bgColor = getColor (value[HTML_BODY_BGCOLOR]); + setBackgroundColor (bgColor); + } + + string style; + if (present[HTML_BODY_STYLE] && value[HTML_BODY_STYLE]) + style = value[HTML_BODY_STYLE]; + + + if (!style.empty()) + { + TStyle styles = parseStyle(style); + TStyle::iterator it; + + it = styles.find("background-repeat"); + bool repeat = (it != styles.end() && it->second == "1"); + + // Webig only + it = styles.find("background-scale"); + bool scale = (it != styles.end() && it->second == "1"); + + it = styles.find("background-image"); + if (it != styles.end()) + { + string image = it->second; + string::size_type texExt = strlwr(image).find("url("); + // Url image + if (texExt != string::npos) + // Remove url() + image = image.substr(4, image.size()-5); + setBackground (image, scale, repeat); + } + } } break; case HTML_FORM: @@ -1000,7 +1172,24 @@ void CGroupHTML::beginElement (uint element_number, const BOOL *present, const c } else { - addImage (value[MY_HTML_IMG_SRC], globalColor); + // Get the option to reload (class==reload) + bool reloadImg = false; + + string style; + if (present[MY_HTML_IMG_STYLE] && value[MY_HTML_IMG_STYLE]) + style = value[MY_HTML_IMG_STYLE]; + + if (!style.empty()) + { + TStyle styles = parseStyle(style); + TStyle::iterator it; + + it = styles.find("reload"); + if (it != styles.end() && (*it).second == "1") + reloadImg = true; + } + + addImage (value[MY_HTML_IMG_SRC], globalColor, reloadImg); } } } @@ -1312,8 +1501,43 @@ void CGroupHTML::beginElement (uint element_number, const BOOL *present, const c if (!_Cells.empty()) { _Cells.back() = new CGroupCell(CViewBase::TCtorParam()); + string style; + if (present[MY_HTML_TD_STYLE] && value[MY_HTML_TD_STYLE]) + style = value[MY_HTML_TD_STYLE]; // Set the cell parameters + if (!style.empty()) + { + TStyle styles = parseStyle(style); + TStyle::iterator it; + + it = styles.find("background-repeat"); + _Cells.back()->setTextureTile(it != styles.end()); + + // Webig only + it = styles.find("background-scale"); + _Cells.back()->setTextureScale(it != styles.end()); + + it = styles.find("background-image"); + if (it != styles.end()) + { + nlinfo("found background-image %s", it->second.c_str()); + string image = (*it).second; + string::size_type texExt = strlwr(image).find("url("); + // Url image + if (texExt != string::npos) + { + // Remove url() + image = image.substr(4, image.size()-5); + addImageDownload(image, _Cells.back()); + // Image in BNP + } + else + { + _Cells.back()->setTexture(image); + } + } + } _Cells.back()->BgColor = _CellParams.back().BgColor; _Cells.back()->Align = _CellParams.back().Align; _Cells.back()->VAlign = _CellParams.back().VAlign; @@ -1435,6 +1659,8 @@ void CGroupHTML::endElement (uint element_number) popIfNotEmpty (_GlobalColor); popIfNotEmpty (_A); popIfNotEmpty (_Link); + popIfNotEmpty (_LinkTitle); + popIfNotEmpty (_LinkClass); break; case HTML_H1: case HTML_H2: @@ -1452,6 +1678,7 @@ void CGroupHTML::endElement (uint element_number) break; case HTML_DIV: _DivName = ""; + popIfNotEmpty (_Divs); break; case HTML_TABLE: @@ -1551,7 +1778,7 @@ void CGroupHTML::endElement (uint element_number) if (addBnpDownload(_ObjectData, _ObjectAction, _ObjectScript, _ObjectMD5Sum)) { CInterfaceManager *pIM = CInterfaceManager::getInstance(); - pIM->executeLuaScript(_ObjectScript, true); + pIM->executeLuaScript("\nlocal __ALLREADYDL__=true\n"+_ObjectScript, true); } _ObjectScript = ""; } @@ -1586,6 +1813,7 @@ void CGroupHTML::endUnparsedElement(const char *buffer, int length) _ParsingLua = false; // execute the embeded lua script CInterfaceManager *pIM = CInterfaceManager::getInstance(); + _LuaScript = "\nlocal __CURRENT_WINDOW__=\""+this->_Id+"\" \n"+_LuaScript; pIM->executeLuaScript(_LuaScript, true); } } @@ -2211,40 +2439,77 @@ void CGroupHTML::addString(const ucstring &str) // Not added ? if (!added) { - CViewLink *newLink = new CViewLink(CViewBase::TCtorParam()); - if (getA()) + if (getA() && string(getLinkClass()) == "ryzom-ui-button") { - newLink->Link = getLink(); - if (!newLink->Link.empty()) - { - newLink->setHTMLView (this); - newLink->setUnderlined (true); - } - } - newLink->setText(tmpStr); - newLink->setColor(getTextColor()); - newLink->setFontSize(getFontSize()); - newLink->setMultiLineSpace((uint)((float)getFontSize()*LineSpaceFontFactor)); - newLink->setMultiLine(true); - newLink->setModulateGlobalColor(getGlobalColor()); - // newLink->setLineAtBottom (true); + string buttonTemplate = DefaultButtonGroup; + // Action handler parameters : "name=group_html_id|form=id_of_the_form|submit_button=button_name" + string param = "name=" + this->_Id + "|url=" + getLink(); - if (getA() && !newLink->Link.empty()) - { - getParagraph()->addChildLink(newLink); + CInterfaceManager *im = CInterfaceManager::getInstance(); + typedef pair TTmplParam; + vector tmplParams; + tmplParams.push_back(TTmplParam("id", "")); + tmplParams.push_back(TTmplParam("onclick", "browse")); + tmplParams.push_back(TTmplParam("onclick_param", param)); + tmplParams.push_back(TTmplParam("active", "true")); + CInterfaceGroup *buttonGroup = im->createGroupInstance(buttonTemplate, _Paragraph->getId(), tmplParams); + if (buttonGroup) + { + + // Add the ctrl button + CCtrlTextButton *ctrlButton = dynamic_cast(buttonGroup->getCtrl("button")); + if (!ctrlButton) ctrlButton = dynamic_cast(buttonGroup->getCtrl("b")); + if (ctrlButton) + { + ctrlButton->setModulateGlobalColorAll (false); + + // Translate the tooltip + ctrlButton->setDefaultContextHelp(ucstring::makeFromUtf8(getLinkTitle())); + ctrlButton->setText(tmpStr); + } + getParagraph()->addChild (buttonGroup); + paragraphChange (); + } + } else { - getParagraph()->addChild(newLink); + CViewLink *newLink = new CViewLink(CViewBase::TCtorParam()); + if (getA()) + { + newLink->Link = getLink(); + newLink->LinkTitle = getLinkTitle(); + if (!newLink->Link.empty()) + { + newLink->setHTMLView (this); + newLink->setUnderlined (true); + } + } + newLink->setText(tmpStr); + newLink->setColor(getTextColor()); + newLink->setFontSize(getFontSize()); + newLink->setMultiLineSpace((uint)((float)getFontSize()*LineSpaceFontFactor)); + newLink->setMultiLine(true); + newLink->setModulateGlobalColor(getGlobalColor()); + // newLink->setLineAtBottom (true); + + if (getA() && !newLink->Link.empty()) + { + getParagraph()->addChildLink(newLink); + } + else + { + getParagraph()->addChild(newLink); + } + paragraphChange (); } - paragraphChange (); } } } // *************************************************************************** -void CGroupHTML::addImage(const char *img, bool globalColor) +void CGroupHTML::addImage(const char *img, bool globalColor, bool reloadImg) { // In a paragraph ? if (_Paragraph) @@ -2268,6 +2533,7 @@ void CGroupHTML::addImage(const char *img, bool globalColor) newImage->Link = getLink(); newImage->setHTMLView (this); }*/ + newImage->setRenderLayer(getRenderLayer()+1); newImage->setTexture (finalUrl); newImage->setModulateGlobalColor(globalColor); @@ -2284,7 +2550,7 @@ void CGroupHTML::addImage(const char *img, bool globalColor) // 2/ if it doesn't work, try to load the image in cache // image = localImageName(img); - if (lookupLocalFile (finalUrl, image.c_str(), false)) + if (!reloadImg && lookupLocalFile (finalUrl, image.c_str(), false)) { // No more text in this text view _CurrentViewLink = NULL; @@ -2314,7 +2580,9 @@ void CGroupHTML::addImage(const char *img, bool globalColor) else*/ getParagraph()->addChild(newImage); paragraphChange (); - } else { + } + else + { // // 3/ if it doesn't work, display a placeholder and ask to dl the image into the cache @@ -2527,6 +2795,9 @@ CCtrlButton *CGroupHTML::addButton(CCtrlButton::EType type, const std::string &/ ctrlButton->setInstantContextHelp(true); ctrlButton->setToolTipParent(TTMouse); + ctrlButton->setToolTipParentPosRef(Hotspot_TTAuto); + ctrlButton->setToolTipPosRef(Hotspot_TTAuto); + ctrlButton->setActionOnLeftClickParams(tooltip); } getParagraph()->addChild (ctrlButton); @@ -2556,6 +2827,7 @@ void CGroupHTML::clearContext() _UL.clear(); _A.clear(); _Link.clear(); + _LinkTitle.clear(); _Tables.clear(); _Cells.clear(); _TR.clear(); @@ -2632,6 +2904,9 @@ CInterfaceGroup *CGroupHTML::getCurrentGroup() void CGroupHTML::addGroup (CInterfaceGroup *group, uint beginSpace) { + if (!group) + return; + // Remove previous paragraph if empty if (_Paragraph && (_Paragraph->getNumChildren() == 0)) { @@ -2796,7 +3071,30 @@ void CGroupHTML::setBackgroundColor (const CRGBA &bgcolor) { // Change the background color bitmap->setColor (bgcolor); - bitmap->setModulateGlobalColor(true); + bitmap->setModulateGlobalColor(false); + } + } +} + +// *************************************************************************** + +void CGroupHTML::setBackground (const string &bgtex, bool scale, bool tile) +{ + // Should have a child named bg + CViewBase *view = getView (DefaultBackgroundBitmapView); + if (view) + { + CViewBitmap *bitmap = dynamic_cast (view); + if (bitmap) + { + bitmap->setParentPosRef(Hotspot_TL); + bitmap->setPosRef(Hotspot_TL); + bitmap->setX(0); + bitmap->setY(0); + bitmap->setRenderLayer(-2); + bitmap->setScale(scale); + bitmap->setTile(tile); + addImageDownload(bgtex, view); } } } @@ -2897,9 +3195,6 @@ void CGroupHTML::handle () _Browsing = true; updateRefreshButton(); - // Add custom get params - addHTTPGetParams (finalUrl); - // Save new url _URL = finalUrl; @@ -2910,6 +3205,10 @@ void CGroupHTML::handle () initLibWWW(); _TrustedDomain = isTrustedDomain(setCurrentDomain(finalUrl)); + // Add custom get params + addHTTPGetParams (finalUrl, _TrustedDomain); + + // Get the final URL C3WSmartPtr uri = HTParse(finalUrl.c_str(), NULL, PARSE_ALL); @@ -3030,7 +3329,7 @@ void CGroupHTML::handle () HTParseFormInput(formfields, (_PostFormSubmitButton + "_y=0").c_str()); // Add custom params - addHTTPPostParams (formfields); + addHTTPPostParams(formfields, _TrustedDomain); // Reset the title if(_TitlePrefix.empty()) @@ -3146,13 +3445,13 @@ void CGroupHTML::endBuild () // *************************************************************************** -void CGroupHTML::addHTTPGetParams (string &/* url */) +void CGroupHTML::addHTTPGetParams (string &/* url */, bool /*trustedDomain*/) { } // *************************************************************************** -void CGroupHTML::addHTTPPostParams (HTAssocList * /* formfields */) +void CGroupHTML::addHTTPPostParams (HTAssocList * /* formfields */, bool /*trustedDomain*/) { } @@ -3401,7 +3700,7 @@ int CGroupHTML::luaRefresh(CLuaState &ls) // *************************************************************************** int CGroupHTML::luaRemoveContent(CLuaState &ls) { - const char *funcName = "refresh"; + const char *funcName = "removeContent"; CLuaIHM::checkArgCount(ls, funcName, 0); removeContent(); return 0; diff --git a/code/ryzom/client/src/interface_v3/group_html.h b/code/ryzom/client/src/interface_v3/group_html.h index d155c6d3f..098fbb4ff 100644 --- a/code/ryzom/client/src/interface_v3/group_html.h +++ b/code/ryzom/client/src/interface_v3/group_html.h @@ -30,6 +30,8 @@ #include "ctrl_button.h" #include "group_table.h" +typedef std::map TStyle; + extern "C" { #include "WWWInit.h" @@ -147,6 +149,7 @@ public: std::string DefaultCheckBoxBitmapPushed; std::string DefaultCheckBoxBitmapOver; std::string DefaultBackgroundBitmapView; + std::string CurrentLinkTitle; // Browser home std::string Home; @@ -216,10 +219,10 @@ protected : virtual void endUnparsedElement(const char *buffer, int length); // Add GET params to the url - virtual void addHTTPGetParams (std::string &url); + virtual void addHTTPGetParams (std::string &url, bool trustedDomain); // Add POST params to the libwww list - virtual void addHTTPPostParams (HTAssocList *formfields); + virtual void addHTTPPostParams (HTAssocList *formfields, bool trustedDomain); // the current request is terminated virtual void requestTerminated(HTRequest *request); @@ -227,6 +230,9 @@ protected : // Get Home URL virtual std::string home(); + // Parse style html tag + TStyle parseStyle(const std::string &str_styles); + // Handle some work at each pass virtual void handle (); @@ -251,7 +257,7 @@ protected : void addString(const ucstring &str); // Add an image in the current paragraph - void addImage(const char *image, bool globalColor); + void addImage(const char *image, bool globalColor, bool reloadImg=false); // Add a text area in the current paragraph CInterfaceGroup *addTextArea (const std::string &templateName, const char *name, uint rows, uint cols, bool multiLine, const ucstring &content); @@ -266,6 +272,9 @@ protected : // Set the background color void setBackgroundColor (const NLMISC::CRGBA &bgcolor); + // Set the background + void setBackground (const std::string &bgtex, bool scale, bool tile); + // Force the current string to be in a single string void flushString(); @@ -281,7 +290,7 @@ protected : // Current URL std::string _URL; - // Current DOMAIN + // Current DOMAIN bool _TrustedDomain; // Title prefix @@ -397,6 +406,30 @@ protected : return _Link.back().c_str(); } + std::vector _LinkTitle; + inline const char *getLinkTitle() const + { + if (_LinkTitle.empty()) + return ""; + return _LinkTitle.back().c_str(); + } + std::vector _LinkClass; + inline const char *getLinkClass() const + { + if (_LinkClass.empty()) + return ""; + return _LinkClass.back().c_str(); + } + + // Divs (i.e. interface group) + std::vector _Divs; + inline CInterfaceGroup *getDiv() const + { + if (_Divs.empty()) + return NULL; + return _Divs.back(); + } + // Tables std::vector _Tables; inline CGroupTable *getTable() const @@ -475,6 +508,7 @@ protected : NoWrap = false; } NLMISC::CRGBA BgColor; + std::string Style; CGroupCell::TAlign Align; CGroupCell::TVAlign VAlign; sint32 LeftMargin; @@ -582,9 +616,9 @@ private: void checkImageDownload(); void addImageDownload(const std::string &url, CViewBase *img); std::string localImageName(const std::string &url); + bool isTrustedDomain(const std::string &domain); - - + void setImage(CViewBase *view, const std::string &file); // BnpDownload system void initBnpDownload(); diff --git a/code/ryzom/client/src/interface_v3/group_html_cs.cpp b/code/ryzom/client/src/interface_v3/group_html_cs.cpp index 66d884437..13d7dda24 100644 --- a/code/ryzom/client/src/interface_v3/group_html_cs.cpp +++ b/code/ryzom/client/src/interface_v3/group_html_cs.cpp @@ -24,6 +24,7 @@ #include "group_html_cs.h" #include "game_share/xml_auto_ptr.h" #include "../client_cfg.h" +#include "interface_manager.h" // used for login cookie to be sent to the web server #include "../net_manager.h" @@ -49,7 +50,7 @@ CGroupHTMLCS::~CGroupHTMLCS() // *************************************************************************** -void CGroupHTMLCS::addHTTPGetParams (string &url) +void CGroupHTMLCS::addHTTPGetParams (string &url, bool /*trustedDomain*/) { url += ((url.find('?') != string::npos) ? "&" : "?"); @@ -69,7 +70,7 @@ void CGroupHTMLCS::addHTTPGetParams (string &url) // *************************************************************************** -void CGroupHTMLCS::addHTTPPostParams (HTAssocList *formfields) +void CGroupHTMLCS::addHTTPPostParams (HTAssocList *formfields, bool /*trustedDomain*/) { std::vector parameters; getParameters (parameters, false); @@ -120,6 +121,15 @@ void CGroupHTMLCS::getParameters (std::vector ¶meters, bool enco string s = getDebugInformation(); s += getSystemInformation(); + static bool webIgReady = false; + + if (!webIgReady) // Webig is ready when getParameters of CGroupHTMLCS is called + { + webIgReady = true; + CInterfaceManager *pIM = CInterfaceManager::getInstance(); + pIM->executeLuaScript("game:onWebIgReady()"); + } + // For each line string::size_type startOfLine = 0; string::size_type endOfLine; diff --git a/code/ryzom/client/src/interface_v3/group_html_cs.h b/code/ryzom/client/src/interface_v3/group_html_cs.h index a37b2b50c..e3c8a765e 100644 --- a/code/ryzom/client/src/interface_v3/group_html_cs.h +++ b/code/ryzom/client/src/interface_v3/group_html_cs.h @@ -39,8 +39,8 @@ public: ~CGroupHTMLCS(); // From CGroupHTML - virtual void addHTTPGetParams (std::string &url); - virtual void addHTTPPostParams (HTAssocList *formfields); + virtual void addHTTPGetParams (std::string &url, bool trustedDomain); + virtual void addHTTPPostParams (HTAssocList *formfields, bool trustedDomain); virtual std::string home(); private: diff --git a/code/ryzom/client/src/interface_v3/group_html_forum.cpp b/code/ryzom/client/src/interface_v3/group_html_forum.cpp index b0fd96642..53d1058d9 100644 --- a/code/ryzom/client/src/interface_v3/group_html_forum.cpp +++ b/code/ryzom/client/src/interface_v3/group_html_forum.cpp @@ -51,9 +51,9 @@ CGroupHTMLForum::~CGroupHTMLForum() // *************************************************************************** -void CGroupHTMLForum::addHTTPGetParams (string &url) +void CGroupHTMLForum::addHTTPGetParams (string &url, bool /*trustedDomain*/) { - ucstring user_name = UserEntity->getDisplayName (); + ucstring user_name = UserEntity->getLoginName (); const SGuild &guild = CGuildManager::getInstance()->getGuild(); string gname = guild.Name.toUtf8(); @@ -83,9 +83,9 @@ void CGroupHTMLForum::addHTTPGetParams (string &url) // *************************************************************************** -void CGroupHTMLForum::addHTTPPostParams (HTAssocList *formfields) +void CGroupHTMLForum::addHTTPPostParams (HTAssocList *formfields, bool /*trustedDomain*/) { - ucstring user_name = UserEntity->getDisplayName (); + ucstring user_name = UserEntity->getLoginName (); const SGuild &guild = CGuildManager::getInstance()->getGuild(); string gname = guild.Name.toUtf8(); @@ -115,12 +115,13 @@ string CGroupHTMLForum::home () void CGroupHTMLForum::handle () { - // Do nothing if WebServer is not initialized +/* // Do nothing if WebServer is not initialized if (!WebServer.empty()) { Home = WebServer+"forum.php"; CGroupHTML::handle (); } +*/ } // *************************************************************************** diff --git a/code/ryzom/client/src/interface_v3/group_html_forum.h b/code/ryzom/client/src/interface_v3/group_html_forum.h index 8458609c6..fe233fecc 100644 --- a/code/ryzom/client/src/interface_v3/group_html_forum.h +++ b/code/ryzom/client/src/interface_v3/group_html_forum.h @@ -39,8 +39,8 @@ public: ~CGroupHTMLForum(); // From CGroupHTML - virtual void addHTTPGetParams (std::string &url); - virtual void addHTTPPostParams (HTAssocList *formfields); + virtual void addHTTPGetParams (std::string &url, bool trustedDomain); + virtual void addHTTPPostParams (HTAssocList *formfields, bool trustedDomain); virtual std::string home(); virtual void handle (); diff --git a/code/ryzom/client/src/interface_v3/group_html_mail.cpp b/code/ryzom/client/src/interface_v3/group_html_mail.cpp index 2c0d9d225..9c723d45b 100644 --- a/code/ryzom/client/src/interface_v3/group_html_mail.cpp +++ b/code/ryzom/client/src/interface_v3/group_html_mail.cpp @@ -50,9 +50,9 @@ CGroupHTMLMail::~CGroupHTMLMail() // *************************************************************************** -void CGroupHTMLMail::addHTTPGetParams (string &url) +void CGroupHTMLMail::addHTTPGetParams (string &url, bool /*trustedDomain*/) { - ucstring user_name = UserEntity->getDisplayName (); + ucstring user_name = UserEntity->getLoginName (); url += ((url.find('?') != string::npos) ? "&" : "?") + string("shard=") + toString(CharacterHomeSessionId) + string("&user_login=") + user_name.toString() + @@ -62,9 +62,9 @@ void CGroupHTMLMail::addHTTPGetParams (string &url) // *************************************************************************** -void CGroupHTMLMail::addHTTPPostParams (HTAssocList *formfields) +void CGroupHTMLMail::addHTTPPostParams (HTAssocList *formfields, bool /*trustedDomain*/) { - ucstring user_name = UserEntity->getDisplayName (); + ucstring user_name = UserEntity->getLoginName (); HTParseFormInput(formfields, ("shard="+toString(CharacterHomeSessionId)).c_str()); HTParseFormInput(formfields, ("user_login="+user_name.toString()).c_str()); HTParseFormInput(formfields, ("session_cookie="+NetMngr.getLoginCookie().toString()).c_str()); @@ -85,11 +85,12 @@ string CGroupHTMLMail::home () void CGroupHTMLMail::handle () { // Do nothing if WebServer is not initialized - if (!WebServer.empty()) +/* if (!WebServer.empty()) { Home = WebServer+"mailbox.php"; CGroupHTML::handle (); } +*/ } // *************************************************************************** diff --git a/code/ryzom/client/src/interface_v3/group_html_mail.h b/code/ryzom/client/src/interface_v3/group_html_mail.h index bb72a3b78..51f363c3c 100644 --- a/code/ryzom/client/src/interface_v3/group_html_mail.h +++ b/code/ryzom/client/src/interface_v3/group_html_mail.h @@ -39,8 +39,8 @@ public: ~CGroupHTMLMail(); // From CGroupHTML - virtual void addHTTPGetParams (std::string &url); - virtual void addHTTPPostParams (HTAssocList *formfields); + virtual void addHTTPGetParams (std::string &url, bool trustedDomain); + virtual void addHTTPPostParams (HTAssocList *formfields, bool trustedDomain); virtual std::string home(); virtual void handle (); diff --git a/code/ryzom/client/src/interface_v3/group_html_webig.cpp b/code/ryzom/client/src/interface_v3/group_html_webig.cpp index 4a13d9806..e4a55ab48 100644 --- a/code/ryzom/client/src/interface_v3/group_html_webig.cpp +++ b/code/ryzom/client/src/interface_v3/group_html_webig.cpp @@ -20,6 +20,7 @@ #include "game_share/xml_auto_ptr.h" #include "../client_cfg.h" #include "../user_entity.h" +#include "../entities.h" #include "interface_manager.h" // used for login cookie to be sent to the web server @@ -55,7 +56,7 @@ static string getWebAuthKey() // authkey = uint32 cid = NetMngr.getLoginCookie().getUserId() * 16 + PlayerSelectedSlot; string rawKey = toString(CharacterHomeSessionId) + - UserEntity->getDisplayName().toString() + + UserEntity->getLoginName().toString() + toString(cid) + NetMngr.getLoginCookie().toString(); string key = getMD5((const uint8*)rawKey.c_str(), (uint32)rawKey.size()).toString(); @@ -64,18 +65,72 @@ static string getWebAuthKey() return key; } -void addWebIGParams (string &url) +void addWebIGParams (string &url, bool trustedDomain) { if(!UserEntity || !NetMngr.getLoginCookie().isValid()) return; uint32 cid = NetMngr.getLoginCookie().getUserId() * 16 + PlayerSelectedSlot; url += ((url.find('?') != string::npos) ? "&" : "?") + string("shardid=") + toString(CharacterHomeSessionId) + - string("&name=") + UserEntity->getDisplayName().toUtf8() + - string("&cid=") + toString(cid) + - string("&authkey=") + getWebAuthKey() + - string("&ig=1") + - string("&lang=") + CI18N::getCurrentLanguageCode(); + string("&name=") + UserEntity->getLoginName().toUtf8() + + string("&lang=") + CI18N::getCurrentLanguageCode() + + string("&ig=1"); + if (trustedDomain) + { + url += string("&cid=") + toString(cid) + + string("&authkey=") + getWebAuthKey(); + + if (url.find('$') != string::npos) + { + strFindReplace(url, "$datasetid$", toString(UserEntity->dataSetId())); + strFindReplace(url, "$gender$", GSGENDER::toString(UserEntity->getGender())); + strFindReplace(url, "$displayName$", UserEntity->getDisplayName().toString()); + strFindReplace(url, "$posx$", toString(UserEntity->pos().x)); + strFindReplace(url, "$posy$", toString(UserEntity->pos().y)); + strFindReplace(url, "$posz$", toString(UserEntity->pos().z)); + strFindReplace(url, "$post$", toString(atan2(UserEntity->front().y, UserEntity->front().x))); + + // Target fields + const char *dbPath = "UI:VARIABLES:TARGET:SLOT"; + CInterfaceManager *im = CInterfaceManager::getInstance(); + CCDBNodeLeaf *node = im->getDbProp(dbPath, false); + if (node && (uint8)node->getValue32() != (uint8) CLFECOMMON::INVALID_SLOT) + { + CEntityCL *target = EntitiesMngr.entity((uint) node->getValue32()); + if (target) + { + strFindReplace(url, "$tdatasetid$", toString(target->dataSetId())); + strFindReplace(url, "$tdisplayName$", target->getDisplayName().toString()); + strFindReplace(url, "$tposx$", toString(target->pos().x)); + strFindReplace(url, "$tposy$", toString(target->pos().y)); + strFindReplace(url, "$tposz$", toString(target->pos().z)); + strFindReplace(url, "$tpost$", toString(atan2(target->front().y, target->front().x))); + strFindReplace(url, "$tsheet$", target->sheetId().toString()); + string type; + if (target->isFauna()) + type = "fauna"; + else if (target->isNPC()) + type = "npc"; + else if (target->isPlayer()) + type = "player"; + else if (target->isUser()) + type = "user"; + strFindReplace(url, "$ttype$", target->sheetId().toString()); + } + else + { + strFindReplace(url, "$tdatasetid$", ""); + strFindReplace(url, "$tdisplayName$", ""); + strFindReplace(url, "$tposx$", ""); + strFindReplace(url, "$tposy$", ""); + strFindReplace(url, "$tposz$", ""); + strFindReplace(url, "$tpost$", ""); + strFindReplace(url, "$tsheet$", ""); + strFindReplace(url, "$ttype$", ""); + } + } + } + } } // *************************************************************************** @@ -204,7 +259,7 @@ struct CWebigNotificationThread : public NLMISC::IRunnable while (true) { string url = "http://"+ClientCfg.WebIgMainDomain+"/start/index.php?app=notif&rnd="+randomString(); - addWebIGParams(url); + addWebIGParams(url, true); get(url); nlSleep(10*60*1000); } @@ -230,11 +285,66 @@ void startWebigNotificationThread() // *************************************************************************** +// *************************************************************************** +NLMISC_REGISTER_OBJECT(CViewBase, CGroupHTMLAuth, std::string, "auth_html"); + +CGroupHTMLAuth::CGroupHTMLAuth(const TCtorParam ¶m) +: CGroupHTML(param) +{ +} + +// *************************************************************************** + +CGroupHTMLAuth::~CGroupHTMLAuth() +{ +} + +void CGroupHTMLAuth::addHTTPGetParams (string &url, bool trustedDomain) +{ + addWebIGParams(url, trustedDomain); +} + +// *************************************************************************** + +void CGroupHTMLAuth::addHTTPPostParams (HTAssocList *formfields, bool trustedDomain) +{ + if(!UserEntity) return; + + uint32 cid = NetMngr.getLoginCookie().getUserId() * 16 + PlayerSelectedSlot; + HTParseFormInput(formfields, ("shardid="+toString(CharacterHomeSessionId)).c_str()); + HTParseFormInput(formfields, ("name="+UserEntity->getLoginName().toUtf8()).c_str()); + HTParseFormInput(formfields, ("lang="+CI18N::getCurrentLanguageCode()).c_str()); + HTParseFormInput(formfields, "ig=1"); + if (trustedDomain) + { + HTParseFormInput(formfields, ("cid="+toString(cid)).c_str()); + HTParseFormInput(formfields, ("authkey="+getWebAuthKey()).c_str()); + } +} + +// *************************************************************************** + +string CGroupHTMLAuth::home () +{ + return Home; +} + +// *************************************************************************** + +void CGroupHTMLAuth::handle () +{ + CGroupHTML::handle (); +} + +// *************************************************************************** +// *************************************************************************** + + // *************************************************************************** NLMISC_REGISTER_OBJECT(CViewBase, CGroupHTMLWebIG, std::string, "webig_html"); CGroupHTMLWebIG::CGroupHTMLWebIG(const TCtorParam ¶m) -: CGroupHTML(param) +: CGroupHTMLAuth(param) { startWebigNotificationThread(); } @@ -245,24 +355,18 @@ CGroupHTMLWebIG::~CGroupHTMLWebIG() { } -void CGroupHTMLWebIG::addHTTPGetParams (string &url) +// *************************************************************************** + +void CGroupHTMLWebIG::addHTTPGetParams (string &url, bool trustedDomain) { - addWebIGParams(url); + CGroupHTMLAuth::addHTTPGetParams(url, trustedDomain); } // *************************************************************************** -void CGroupHTMLWebIG::addHTTPPostParams (HTAssocList *formfields) +void CGroupHTMLWebIG::addHTTPPostParams (HTAssocList *formfields, bool trustedDomain) { - if(!UserEntity) return; - - uint32 cid = NetMngr.getLoginCookie().getUserId() * 16 + PlayerSelectedSlot; - HTParseFormInput(formfields, ("shardid="+toString(CharacterHomeSessionId)).c_str()); - HTParseFormInput(formfields, ("name="+UserEntity->getDisplayName().toUtf8()).c_str()); - HTParseFormInput(formfields, ("cid="+toString(cid)).c_str()); - HTParseFormInput(formfields, ("authkey="+getWebAuthKey()).c_str()); - HTParseFormInput(formfields, "ig=1"); - HTParseFormInput(formfields, ("lang="+CI18N::getCurrentLanguageCode()).c_str()); + CGroupHTMLAuth::addHTTPPostParams(formfields, trustedDomain); } // *************************************************************************** @@ -276,8 +380,6 @@ string CGroupHTMLWebIG::home () void CGroupHTMLWebIG::handle () { -// Home = "http://atys.ryzom.com/start/index.php"; - CGroupHTML::handle (); + CGroupHTMLAuth::handle (); } -// *************************************************************************** diff --git a/code/ryzom/client/src/interface_v3/group_html_webig.h b/code/ryzom/client/src/interface_v3/group_html_webig.h index 15485d7dc..5967f671d 100644 --- a/code/ryzom/client/src/interface_v3/group_html_webig.h +++ b/code/ryzom/client/src/interface_v3/group_html_webig.h @@ -20,10 +20,32 @@ #include "nel/misc/types_nl.h" #include "group_html.h" +/** +* Auth HTML group +*/ +class CGroupHTMLAuth : public CGroupHTML +{ +public: + + // Constructor + CGroupHTMLAuth(const TCtorParam ¶m); + ~CGroupHTMLAuth(); + + // From CGroupHTML + virtual void addHTTPGetParams (std::string &url, bool trustedDomain); + virtual void addHTTPPostParams (HTAssocList *formfields, bool trustedDomain); + virtual std::string home(); + virtual void handle (); + +private: + +}; + + /** * WebIG HTML group */ -class CGroupHTMLWebIG : public CGroupHTML +class CGroupHTMLWebIG : public CGroupHTMLAuth { public: @@ -31,9 +53,9 @@ public: CGroupHTMLWebIG(const TCtorParam ¶m); ~CGroupHTMLWebIG(); - // From CGroupHTML - virtual void addHTTPGetParams (std::string &url); - virtual void addHTTPPostParams (HTAssocList *formfields); + /// From CGroupHTMLAuth + virtual void addHTTPGetParams (std::string &url, bool trustedDomain); + virtual void addHTTPPostParams (HTAssocList *formfields, bool trustedDomain); virtual std::string home(); virtual void handle (); diff --git a/code/ryzom/client/src/interface_v3/group_in_scene_bubble.cpp b/code/ryzom/client/src/interface_v3/group_in_scene_bubble.cpp index 85238ad7d..cc0d3e82f 100644 --- a/code/ryzom/client/src/interface_v3/group_in_scene_bubble.cpp +++ b/code/ryzom/client/src/interface_v3/group_in_scene_bubble.cpp @@ -973,6 +973,132 @@ void CGroupInSceneBubbleManager::dynChatOpen (uint32 nBotUID, uint32 nBotName, c UserEntity->interlocutor( pChar->slot() ); } +// *************************************************************************** + +void CGroupInSceneBubbleManager::webIgChatOpen (uint32 nBotUID, string text, const vector &strs, const vector &links) +{ + CInterfaceManager *pIM = CInterfaceManager::getInstance(); + // If the character doesn't exist in view field -> do not display the bubble + + CEntityCL *pEntity = EntitiesMngr.getEntityByCompressedIndex(nBotUID); + CCharacterCL *pChar = dynamic_cast(pEntity); + if (pChar == NULL) + { + nlwarning("character probably too far"); + return; + } + + // Look if we get a bubble with this nBotUID ? + uint32 pos, j; + for (pos = 0; pos < _DynBubbles.size(); ++pos) + { + if (_DynBubbles[pos].BotUID == nBotUID) + break; + } + + // If the bubble doesn't exist -> create + CGroupInSceneBubble *bubble = NULL; + string id; + if (pos == _DynBubbles.size()) + { + uint32 i = 0; + while (getDynBubble(i) != NULL) i++; + id = "in_scene_webig_bubble_" + toString(i); + // Create the instance + std::vector > templateParams; + templateParams.push_back (std::pair("id", id)); + + CInterfaceGroup *group = pIM->createGroupInstance ("webig_3dbulle_L", "ui:interface", templateParams); + if (group == NULL) + { + nlwarning("cannot create webig_3dbulle_L"); + return; + } + // Link to the interface + pIM->addWindowToMasterGroup("ui:interface", group); + CInterfaceGroup *pRoot = dynamic_cast(pIM->getElementFromId("ui:interface")); + group->setParent(pRoot); + if (pRoot) + pRoot->addGroup (group); + group->setActive(false); + + bubble = dynamic_cast(group); + if (bubble == NULL) + { + nlwarning("cannot cast to CGroupInSceneBubble"); + return; + } + CDynBubble dynBubble; + dynBubble.BotName = 0; + dynBubble.BotUID = nBotUID; + dynBubble.Bubble = bubble; + _DynBubbles.push_back(dynBubble); + } + else + { + bubble = _DynBubbles[pos].Bubble; + // Remove from group to delete if in the same frame + for (j=0; j<_GroupToDelete.size(); j++) + if (_GroupToDelete[j] == bubble) + { + _GroupToDelete.erase(_GroupToDelete.begin()+j); + break; + } + } + + // Update the bubble's texts + + ucstring ucText; + ucText.fromUtf8(text); + bubble->setText(ucText); + id = bubble->getId() + ":header_opened:window:"; + CViewText *pVT; + CCtrlLink *pCL; + + _DynBubbles[pos].DescWaiting = 0; + + for (j = 0; j < 8; ++j) + { + pVT = dynamic_cast(bubble->getElement(id+"opt"+toString(j))); + if (pVT != NULL) + { + pVT->setActive(false); + pVT->setText(ucstring("")); + } + pCL = dynamic_cast(bubble->getElement(id+"optb"+toString(j))); + if (pCL != NULL) pCL->setActive(false); + } + + for (j = 0; j < strs.size(); ++j) + { + string fullid = id+"opt"+toString(j); + pVT = dynamic_cast(bubble->getElement(id+"opt"+toString(j))); + if (pVT != NULL) + { + pVT->setActive(true); + ucstring optionText; + optionText.fromUtf8(strs[j]); + pVT->setText(optionText); + pCL = dynamic_cast(bubble->getElement(id+"optb"+toString(j))); + if (pCL != NULL) + { + pCL->setActionOnLeftClick("browse"); + pCL->setParamsOnLeftClick("name=ui:interface:web_transactions:content:html|show=0|url="+links[j]); + //pCL->setActionOnLeftClickParams("name=ui:interface:web_transactions:content:html|url="+links[j]); + pCL->setActive(true); + + } + } + } + + // Link bubble to the character + pChar->setBubble(bubble); + + // Make the npc face the character + UserEntity->interlocutor( pChar->slot() ); +} + + uint32 CGroupInSceneBubbleManager::CDynBubble::getOptionStringId(uint option) { if (!Bubble) return 0; diff --git a/code/ryzom/client/src/interface_v3/group_in_scene_bubble.h b/code/ryzom/client/src/interface_v3/group_in_scene_bubble.h index 5e7cd4546..635e8c47e 100644 --- a/code/ryzom/client/src/interface_v3/group_in_scene_bubble.h +++ b/code/ryzom/client/src/interface_v3/group_in_scene_bubble.h @@ -64,6 +64,9 @@ public: // Open a Dynamic Chat void dynChatOpen (uint32 nBotUID, uint32 nBotName, const std::vector &DynStrs); + // Open a Dynamic Chat from webig + void webIgChatOpen (uint32 nBotUID, std::string sBotName, const std::vector &strs, const std::vector &links); + // Close a Dynamic Chat void dynChatClose (uint32 nBotUID); diff --git a/code/ryzom/client/src/interface_v3/group_in_scene_user_info.cpp b/code/ryzom/client/src/interface_v3/group_in_scene_user_info.cpp index dcc3895f7..d9fa10707 100644 --- a/code/ryzom/client/src/interface_v3/group_in_scene_user_info.cpp +++ b/code/ryzom/client/src/interface_v3/group_in_scene_user_info.cpp @@ -97,7 +97,7 @@ CRGBA CGroupInSceneUserInfo::BarColorHPNegative = CRGBA(127, 32, 0); #define nlfsinfo2 if ( _Entity->isForageSource() ) nlinfo -CGroupInSceneUserInfo *CGroupInSceneUserInfo::build (class CEntityCL *entity) +CGroupInSceneUserInfo *CGroupInSceneUserInfo::build (CEntityCL *entity) { // Get the interface manager CInterfaceManager *pIM = CInterfaceManager::getInstance(); @@ -129,6 +129,7 @@ CGroupInSceneUserInfo *CGroupInSceneUserInfo::build (class CEntityCL *entity) bool forageSourceBarDisplayed= false; bool needPvPLogo= false; bool permanentContent = false; + bool rpTags = false; bool displayMissionIcons = pIM->getDbProp("UI:SAVE:INSCENE:FRIEND:MISSION_ICON")->getValueBool(); // Names @@ -136,6 +137,12 @@ CGroupInSceneUserInfo *CGroupInSceneUserInfo::build (class CEntityCL *entity) ucstring theTribeName; ucstring entityName = entity->getDisplayName(); ucstring entityTitle = entity->getTitle(); + + ucstring entityTag1 = entity->getTag(1); + ucstring entityTag2 = entity->getTag(2); + ucstring entityTag3 = entity->getTag(3); + ucstring entityTag4 = entity->getTag(4); + string entityPermanentContent = entity->getPermanentStatutIcon(); // Active fields and bars @@ -160,6 +167,8 @@ CGroupInSceneUserInfo *CGroupInSceneUserInfo::build (class CEntityCL *entity) } else if(npcFriendAndNeutral) { + string dbEntry; + getBarSettings( pIM, user, entity->isPlayer(), _friend, dbEntry, bars ); // For RoleMasters, merchants etc... must display name and function, and nothing else for(uint i=0;igetDbProp(dbEntry+"RPTAGS")->getValueBool(); } else { @@ -176,6 +186,7 @@ CGroupInSceneUserInfo *CGroupInSceneUserInfo::build (class CEntityCL *entity) getBarSettings( pIM, user, entity->isPlayer(), _friend, dbEntry, bars ); name = !entityName.empty() && pIM->getDbProp(dbEntry+"NAME")->getValueBool(); title = !entityTitle.empty() && pIM->getDbProp(dbEntry+"TITLE")->getValueBool(); + rpTags = (!entityTag1.empty() || !entityTag2.empty() || !entityTag3.empty() || !entityTag4.empty() ) && pIM->getDbProp(dbEntry+"RPTAGS")->getValueBool(); // if name is empty but not title, title is displayed as name if (!title && entityName.empty() && !entityTitle.empty() && pIM->getDbProp(dbEntry+"NAME")->getValueBool()) title = true; @@ -369,6 +380,26 @@ CGroupInSceneUserInfo *CGroupInSceneUserInfo::build (class CEntityCL *entity) else stringSpace += textH; + if (rpTags) + { + CPlayerCL * pPlayer = dynamic_cast(entity); + CViewBitmap *bitmap; + if (pPlayer == NULL || (pPlayer != NULL && pPlayer->getPvpMode() & PVP_MODE::PvpFaction)) + { + bitmap = dynamic_cast(leftGroup->getView ("rp_logo_1")); + if (bitmap) + bitmap->setTexture(entityTag1.toString()); + bitmap = dynamic_cast(leftGroup->getView ("rp_logo_2")); + if (bitmap) + bitmap->setTexture(entityTag2.toString()); + } + bitmap = dynamic_cast(leftGroup->getView ("rp_logo_3")); + if (bitmap) + bitmap->setTexture(entityTag3.toString()); + bitmap = dynamic_cast(leftGroup->getView ("rp_logo_4")); + if (bitmap) + bitmap->setTexture(entityTag4.toString()); + } // Get the permanent content bitmap if(permanentContent) @@ -539,162 +570,96 @@ CGroupInSceneUserInfo *CGroupInSceneUserInfo::build (class CEntityCL *entity) info->_MissionTarget = bitmap; } - CViewBase * pvpCivLogo = info->getView ("pvp_faction_civ_logo"); - CViewBase * pvpCultLogo = info->getView ("pvp_faction_cult_logo"); + CViewBase * pvpFactionLogo = info->getView ("pvp_faction_logo"); + CViewBase * pvpOutpostLogo = info->getView ("pvp_outpost_logo"); + CViewBase * pvpDuelLogo = info->getView ("pvp_duel_logo"); CPlayerCL * pPlayer = dynamic_cast(entity); if (pPlayer == NULL) needPvPLogo = false; - // set or inactive pvp logos - bool needCivPvpLogo = needPvPLogo; - bool needCultPvpLogo = needPvPLogo; - if (pPlayer != NULL && needPvPLogo && pvpCivLogo && pvpCultLogo) + if (pPlayer != NULL && needPvPLogo) { - uint8 civToDisplay = (uint8)(pPlayer->getClanCivMaxFame() & 0xFF); - uint8 cultToDisplay = (uint8)(pPlayer->getClanCultMaxFame() & 0xFF); - - if (!entity->isUser()) + if (pvpFactionLogo) { - bool civEnnemies = false; - for (uint8 i = 0; i < 4; i++) + pvpFactionLogo->setActive(true); + CViewBitmap * pvpFactionBitmap = dynamic_cast(pvpFactionLogo); + if( pvpFactionBitmap ) { - if ( (pPlayer->isPvpAlly(i) && UserEntity->isPvpEnnemy(i)) || - (pPlayer->isPvpEnnemy(i) && UserEntity->isPvpAlly(i)) ) + if (user) { - civEnnemies = true; - if ( civToDisplay == i) - break; - else - civToDisplay = i; - } - - if (!civEnnemies) - { - if ( (pPlayer->isPvpAlly(i) && UserEntity->isPvpAlly(i)) || - (pPlayer->isPvpEnnemy(i) && UserEntity->isPvpEnnemy(i)) ) + if (pPlayer->getPvpMode() & PVP_MODE::PvpChallenge) { - if ( civToDisplay == i) - break; - else - civToDisplay = i; + pvpFactionBitmap->setTexture("ico_curse.tga"); + } + else if (pPlayer->getPvpMode() & PVP_MODE::PvpFaction) + { + if (pPlayer->getPvpMode() & PVP_MODE::PvpZoneSafe) + pvpFactionBitmap->setTexture("pvp_neutral.tga"); + else + pvpFactionBitmap->setTexture("pvp_enemy_tag.tga"); + } + else if (pPlayer->getPvpMode() & PVP_MODE::PvpFactionFlagged) + { + if (pPlayer->getPvpMode() & PVP_MODE::PvpSafe) + pvpFactionBitmap->setTexture("pvp_neutral.tga"); + else + pvpFactionBitmap->setTexture("pvp_enemy_flag.tga"); } - } - } - - - for (uint8 i = 4; i < 7; i++) - { - if ( (pPlayer->isPvpAlly(i) && UserEntity->isPvpEnnemy(i)) || - (pPlayer->isPvpEnnemy(i) && UserEntity->isPvpAlly(i)) ) - { - if ( cultToDisplay == i) - break; else - cultToDisplay = i; - } - - if ( (pPlayer->isPvpAlly(i) && UserEntity->isPvpAlly(i)) || - (pPlayer->isPvpEnnemy(i) && UserEntity->isPvpEnnemy(i)) ) - { - if ( cultToDisplay == i) - break; - else - cultToDisplay = i; - } - } - } - - if ((pPlayer->getPvpMode() & PVP_MODE::PvpFaction) || (pPlayer->getPvpMode() & PVP_MODE::PvpFactionFlagged)) - { - CViewBitmap * pvpCivLogoBmp = dynamic_cast(pvpCivLogo); - if( pvpCivLogoBmp ) - { - if (pPlayer->isPvpAlly(civToDisplay)) - { - if (pPlayer->isPvpRanger()) - pvpCivLogoBmp->setTexture("pvp_ally_ranger.tga"); - else - pvpCivLogoBmp->setTexture("pvp_ally_"+toString(civToDisplay)+".tga"); - } - else if (pPlayer->isPvpEnnemy(civToDisplay)) - { - if (pPlayer->isPvpMarauder()) - pvpCivLogoBmp->setTexture("pvp_enemy_marauder.tga"); - else - pvpCivLogoBmp->setTexture("pvp_enemy_"+toString(civToDisplay)+".tga"); + pvpFactionLogo->setActive(false); } else { - needCivPvpLogo = false; - } - } - - CViewBitmap * pvpCultLogoBmp = dynamic_cast(pvpCultLogo); - if( pvpCultLogoBmp ) - { - if (pPlayer->isPvpAlly(cultToDisplay)) - { - if (pPlayer->isPvpPrimas()) - pvpCultLogoBmp->setTexture("pvp_ally_primas.tga"); + if (pPlayer->getPvpMode() & PVP_MODE::PvpChallenge) + pvpFactionBitmap->setTexture("ico_curse.tga"); + else if (pPlayer->isNeutralPVP()) + pvpFactionBitmap->setTexture("pvp_neutral.tga"); + else if (pPlayer->isAlly() && (pPlayer->getPvpMode() & PVP_MODE::PvpFactionFlagged)) + pvpFactionBitmap->setTexture("pvp_ally_flag.tga"); + else if (pPlayer->isAlly() && (pPlayer->getPvpMode() & PVP_MODE::PvpFaction)) + pvpFactionBitmap->setTexture("pvp_ally_tag.tga"); + else if (pPlayer->isEnemy() && (pPlayer->getPvpMode() & PVP_MODE::PvpFactionFlagged)) + pvpFactionBitmap->setTexture("pvp_enemy_flag.tga"); + else if (pPlayer->isEnemy() && (pPlayer->getPvpMode() & PVP_MODE::PvpFaction)) + pvpFactionBitmap->setTexture("pvp_enemy_tag.tga"); + else if (pPlayer->getPvpMode() & PVP_MODE::PvpFactionFlagged) + pvpFactionBitmap->setTexture("pvp_enemy_flag.tga"); + else if (pPlayer->getPvpMode() & PVP_MODE::PvpFaction) + pvpFactionBitmap->setTexture("pvp_enemy_tag.tga"); else - pvpCultLogoBmp->setTexture("pvp_ally_"+toString(cultToDisplay)+".tga"); - } - else if (pPlayer->isPvpEnnemy(cultToDisplay)) - { - if (pPlayer->isPvpTrytonist()) - pvpCultLogoBmp->setTexture("pvp_enemy_trytonist.tga"); - else - pvpCultLogoBmp->setTexture("pvp_enemy_"+toString(cultToDisplay)+".tga"); - } - else - { - needCultPvpLogo = false; + pvpFactionLogo->setActive(false); } } } - else - { - needCivPvpLogo = false; - needCultPvpLogo = false; - } - - CViewBase * pvpOutpostLogo = info->getView ("pvp_outpost_logo"); + if (pvpOutpostLogo) { - if( pPlayer->getOutpostId() == 0 ) - { + if( pPlayer->getOutpostId() != 0 ) + pvpOutpostLogo->setActive(true); + else pvpOutpostLogo->setActive(false); - } } - - CViewBase * pvpDuelLogo = info->getView ("pvp_duel_logo"); + if (pvpDuelLogo) { - if( !(pPlayer->getPvpMode()&PVP_MODE::PvpDuel || pPlayer->getPvpMode()&PVP_MODE::PvpChallenge) ) - { + if( pPlayer->getPvpMode()&PVP_MODE::PvpDuel ) + pvpDuelLogo->setActive(true); + else pvpDuelLogo->setActive(false); - } } + } else { - CViewBase * pvpOutpostLogo = info->getView ("pvp_outpost_logo"); + if (pvpFactionLogo) + pvpFactionLogo->setActive(false); if (pvpOutpostLogo) pvpOutpostLogo->setActive(false); - - CViewBase * pvpDuelLogo = info->getView ("pvp_duel_logo"); if (pvpDuelLogo) - pvpDuelLogo->setActive(false); + pvpDuelLogo->setActive(false); } - - if (pvpCivLogo) - pvpCivLogo->setActive(needCivPvpLogo); - - if (pvpCultLogo) - pvpCultLogo->setActive(needCultPvpLogo); - } // No bar and no string ? diff --git a/code/ryzom/client/src/interface_v3/group_table.cpp b/code/ryzom/client/src/interface_v3/group_table.cpp index 48ec926a4..890a8b0fe 100644 --- a/code/ryzom/client/src/interface_v3/group_table.cpp +++ b/code/ryzom/client/src/interface_v3/group_table.cpp @@ -55,6 +55,9 @@ CGroupCell::CGroupCell(const TCtorParam ¶m) IgnoreMaxWidth = false; IgnoreMinWidth = false; AddChildW = false; + _UserTexture = false; + _TextureTiled = false; + _TextureScaled = false; setEnclosedGroupDefaultParams(); addGroup (Group); } @@ -200,20 +203,62 @@ void CGroupCell::draw () } // Draw the background - if (BgColor.A != 0) + if (_UserTexture || BgColor.A != 0) { CViewRenderer &rVR = pIM->getViewRenderer(); - CRGBA finalColor; - finalColor.modulateFromColor (BgColor, pIM->getGlobalColor()); - - // Get the parent table - if (getParent ()) + if (_UserTexture) { - CGroupTable *table = static_cast (getParent ()); - finalColor.A = (uint8) (((uint16) table->CurrentAlpha * (uint16) finalColor.A) >> 8); + CRGBA col; + if (BgColor.A == 0 ) + col = CRGBA(255,255,255,255); + else + col = BgColor; + + + if (_TextureScaled && !_TextureTiled) + { + rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, + _WReal, _HReal, + 0, false, + _TextureId, + col ); + } + else + { + if (!_TextureTiled) + { + rVR.draw11RotFlipBitmap (_RenderLayer, _XReal, _YReal, + 0, false, + _TextureId, + col); + } + else + { + rVR.drawRotFlipBitmapTiled(_RenderLayer, _XReal, _YReal, + _WReal, _HReal, + 0, false, + _TextureId, + 0, + col); + } + } + } + else + { + CRGBA finalColor; + finalColor.modulateFromColor (BgColor, pIM->getGlobalColor()); - rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, _WReal, _HReal, 0, false, rVR.getBlankTextureId(), finalColor); + // Get the parent table + if (getParent ()) + { + CGroupTable *table = static_cast (getParent ()); + finalColor.A = (uint8) (((uint16) table->CurrentAlpha * (uint16) finalColor.A) >> 8); + } + + //nlinfo("Blank Texture"); + rVR.drawRotFlipBitmap (_RenderLayer, _XReal, _YReal, _WReal, _HReal, 0, false, rVR.getBlankTextureId(), finalColor); + } } CInterfaceGroup::draw (); @@ -231,6 +276,40 @@ sint32 CGroupCell::getMinUsedW() const return Group->getMinUsedW(); } + +// ---------------------------------------------------------------------------- +void CGroupCell::setTexture(const std::string & TxName) +{ + if (TxName.empty() || TxName == "none") + { + _UserTexture = false; + nlinfo("Set no texture"); + } + else + { + nlinfo("Set texture to cell : %s", TxName.c_str()); + _UserTexture = true; + _TextureId.setTexture (TxName.c_str (), 0, 0, -1, -1, false); + } +} + +// ---------------------------------------------------------------------------- +void CGroupCell::setTextureTile(bool tiled) +{ + if (tiled) + nlinfo("Set texture is Tiled"); + _TextureTiled = tiled; +} + +// ---------------------------------------------------------------------------- +void CGroupCell::setTextureScale(bool scaled) +{ + if (scaled) + nlinfo("Set texture is Scaled : %s"); + _TextureScaled = scaled; +} + + // ---------------------------------------------------------------------------- NLMISC_REGISTER_OBJECT(CViewBase, CGroupTable, std::string, "table"); diff --git a/code/ryzom/client/src/interface_v3/group_table.h b/code/ryzom/client/src/interface_v3/group_table.h index 08cdad11e..888d6dbe3 100644 --- a/code/ryzom/client/src/interface_v3/group_table.h +++ b/code/ryzom/client/src/interface_v3/group_table.h @@ -80,6 +80,12 @@ public: // The cell color NLMISC::CRGBA BgColor; + // Texture + CViewRenderer::CTextureId _TextureId; /// Accelerator + bool _UserTexture; + bool _TextureTiled; + bool _TextureScaled; + // Alignment TAlign Align; TVAlign VAlign; @@ -90,6 +96,11 @@ public: // The cell is nowrap bool NoWrap; + + void setTexture(const std::string & TxName); + void setTextureTile(bool tiled); + void setTextureScale(bool scaled); + private: void setEnclosedGroupDefaultParams(); }; diff --git a/code/ryzom/client/src/interface_v3/guild_manager.cpp b/code/ryzom/client/src/interface_v3/guild_manager.cpp index c9bb4ec01..8d0066816 100644 --- a/code/ryzom/client/src/interface_v3/guild_manager.cpp +++ b/code/ryzom/client/src/interface_v3/guild_manager.cpp @@ -358,15 +358,54 @@ void CGuildManager::update() // If all is valid no more need update and if guild is opened update the interface if (bAllValid) { + CCDBNodeLeaf* node = CInterfaceManager::getInstance()->getDbProp("UI:SAVE:CHAT:SHOW_ONLINE_OFFLINE_NOTIFICATIONS_CB", false); + if (node && node->getValueBool()) + { + // See if we need to show any online/offline messages + static vector CachedGuildMembers; + ucstring onlineMessage = CI18N::get("uiPlayerOnline"); + ucstring offlineMessage = CI18N::get("uiPlayerOffline"); + + for (uint i = 0; i < _GuildMembers.size(); ++i) + { + for (uint j = 0; j < CachedGuildMembers.size(); ++j) + { + if ((CachedGuildMembers[j].Name == _GuildMembers[i].Name) && + (CachedGuildMembers[j].Online != _GuildMembers[i].Online)) + { + ucstring msg = (_GuildMembers[i].Online != ccs_offline) ? onlineMessage : offlineMessage; + strFindReplace(msg, "%s", _GuildMembers[i].Name); + string cat = getStringCategory(msg, msg); + map::const_iterator it; + NLMISC::CRGBA col = CRGBA::Yellow; + it = ClientCfg.SystemInfoParams.find(toLower(cat)); + if (it != ClientCfg.SystemInfoParams.end()) + { + col = it->second.Color; + } + bool dummy; + PeopleInterraction.ChatInput.Guild.displayMessage(msg, col, 2, &dummy); + break; + } + } + } + + CachedGuildMembers.clear(); + for (uint i = 0; i < _GuildMembers.size(); ++i) + { + CachedGuildMembers.push_back(_GuildMembers[i]); + } + } + // Search for UserEntity to find our own grade if ((UserEntity != NULL) && (_GuildMembers.size() > 0)) { uint i; _Grade = EGSPD::CGuildGrade::Member; - string sUserName = strlwr(UserEntity->getEntityName().toString()); + ucstring sUserName = toLower(UserEntity->getEntityName()); for (i = 0; i < _GuildMembers.size(); ++i) { - if (strlwr(_GuildMembers[i].Name.toString()) == sUserName) + if (toLower(_GuildMembers[i].Name) == sUserName) { _Grade = _GuildMembers[i].Grade; break; @@ -1048,10 +1087,26 @@ class CAHGuildSheetSetLeader : public IActionHandler { virtual void execute (CCtrlBase * /* pCaller */, const string &/* Params */) { - sendMsgSetGrade(EGSPD::CGuildGrade::Leader); + CInterfaceManager *pIM = CInterfaceManager::getInstance(); + + // Ask if they are sure + pIM->validMessageBox(CInterfaceManager::QuestionIconMsg, CI18N::get("uiQSetLeader"), "guild_member_do_change_leader"); } }; REGISTER_ACTION_HANDLER (CAHGuildSheetSetLeader, "guild_member_chg_to_leader"); + +// *************************************************************************** +class CAHGuildSheetSetLeaderConfirm : public IActionHandler +{ + virtual void execute (CCtrlBase * /* pCaller */, const string &/* Params */) + { + // Leadership change confirmed + sendMsgSetGrade(EGSPD::CGuildGrade::Leader); + } +}; +REGISTER_ACTION_HANDLER (CAHGuildSheetSetLeaderConfirm, "guild_member_do_change_leader"); + + // *************************************************************************** class CAHGuildSheetSetHighOfficer : public IActionHandler diff --git a/code/ryzom/client/src/interface_v3/interface_group.h b/code/ryzom/client/src/interface_v3/interface_group.h index 5079c1899..432176704 100644 --- a/code/ryzom/client/src/interface_v3/interface_group.h +++ b/code/ryzom/client/src/interface_v3/interface_group.h @@ -176,13 +176,17 @@ public: void setRightClickHandlerParams(const std::string ¶ms) { _AHOnRightClickParams = params; } void setOnActiveHandler(const std::string &h) { _AHOnActive = getAH(h,_AHOnActiveParams); } void setOnActiveParams(const std::string &p) { _AHOnActiveParams = p; } - std::string getOnActiveParams() const { return _AHOnActiveParams; } void setOnDeactiveHandler(const std::string &h) { _AHOnDeactive = getAH(h,_AHOnDeactiveParams); } void setOnDeactiveParams(const std::string &p) { _AHOnDeactiveParams = p; } - std::string getOnDeactiveParams() const { return _AHOnDeactiveParams; } const std::string &getLeftClickHandler() const { return getAHName(_AHOnLeftClick); } const std::string &getLeftClickHandlerParams() const { return _AHOnLeftClickParams; } + const std::string &getRightClickHandler() const { return getAHName(_AHOnRightClick); } + const std::string &getRightClickHandlerParams() const { return _AHOnRightClickParams; } + const std::string &getOnActiveHandler() const { return getAHName(_AHOnActive); } + const std::string &getOnActiveParams() const { return _AHOnActiveParams; } + const std::string &getOnDeactiveHandler() const { return getAHName(_AHOnDeactive); } + const std::string &getOnDeactiveParams() const { return _AHOnDeactiveParams; } // find a sub view/ctrl/group in this group from its id int luaFind(CLuaState &ls); @@ -205,8 +209,18 @@ public: REFLECT_LUA_METHOD("delGroup", luaDelGroup); REFLECT_LUA_METHOD("getNumGroups", luaGetNumGroups); REFLECT_LUA_METHOD("getGroup", luaGetGroup); + REFLECT_STRING ("left_click", getLeftClickHandler, setLeftClickHandler); + REFLECT_STRING ("right_click", getRightClickHandler, setRightClickHandler); + REFLECT_STRING ("left_click_params", getLeftClickHandlerParams, setLeftClickHandlerParams); + REFLECT_STRING ("right_click_params", getRightClickHandlerParams, setRightClickHandlerParams); + REFLECT_STRING ("on_active", getOnActiveHandler, setOnActiveHandler); REFLECT_STRING ("on_active_params", getOnActiveParams, setOnActiveParams); + REFLECT_STRING ("on_deactive", getOnDeactiveHandler, setOnDeactiveHandler); REFLECT_STRING ("on_deactive_params", getOnDeactiveParams, setOnDeactiveParams); + REFLECT_STRING ("on_enter", getAHOnEnter, setAHOnEnter); + REFLECT_STRING ("on_enter_params", getAHOnEnterParams, setAHOnEnterParams); + REFLECT_STRING ("on_escape", getAHOnEscape, setAHOnEscape); + REFLECT_STRING ("on_escape_params", getAHOnEscapeParams, setAHOnEscapeParams); REFLECT_SINT32 ("ofsx", getOfsX, setOfsX); REFLECT_SINT32 ("ofsy", getOfsY, setOfsY); REFLECT_BOOL("child_resize_w", getResizeFromChildW, setResizeFromChildW); diff --git a/code/ryzom/client/src/interface_v3/interface_manager.cpp b/code/ryzom/client/src/interface_v3/interface_manager.cpp index 27b8f9197..8e0851cf6 100644 --- a/code/ryzom/client/src/interface_v3/interface_manager.cpp +++ b/code/ryzom/client/src/interface_v3/interface_manager.cpp @@ -824,6 +824,21 @@ void CInterfaceManager::initInGame() { gc->setTarget(gc->getSavedTarget()); } + + CCDBNodeLeaf *node = getDbProp("UI:SAVE:CHATLOG_STATE", false); + if (node) + { + _LogState = (node->getValue32() != 0); + } + + if (_LogState) + { + displaySystemInfo(CI18N::get("uiLogTurnedOn")); + } + else + { + displaySystemInfo(CI18N::get("uiLogTurnedOff")); + } } // ------------------------------------------------------------------------------------------------ @@ -2372,7 +2387,8 @@ void CInterfaceManager::drawContextHelp () if(newCtrl) { // get the text - newCtrl->getContextHelpToolTip(_ContextHelpText); + //newCtrl->getContextHelpToolTip(_ContextHelpText); + newCtrl->getContextHelp(_ContextHelpText); // UserDefined context help if( !newCtrl->getContextHelpActionHandler().empty() ) { @@ -3408,6 +3424,13 @@ CCDBNodeLeaf* CInterfaceManager::getDbProp(const std::string & name, bool bCreat return pDBNL; } +// ------------------------------------------------------------------------------------------------ +void CInterfaceManager::delDbProp(const std::string & name) +{ + if (name.empty()) return; + _DbRootNode->removeNode( ICDBNode::CTextId(name) ); +} + // ------------------------------------------------------------------------------------------------ CCDBNodeBranch *CInterfaceManager::getDbBranch(const std::string &name) { @@ -5759,7 +5782,7 @@ bool CInterfaceManager::executeLuaScript(const std::string &luaScript, bool smal std::string msg = e.luaWhat(); char filename[MAX_PATH]; char exceptionName[MAX_PATH]; - int line; + uint32 line; // Hamster: quick fix on AJM code but sscanf is still awfull if (sscanf(msg.c_str(), "%s: %s.lua:%d:",exceptionName, filename, &line) == 3) // NB: test not exact here, but should work in 99,9 % of cases { @@ -5770,6 +5793,20 @@ bool CInterfaceManager::executeLuaScript(const std::string &luaScript, bool smal else // AJM: handle the other 0.1% of cases { // Yoyo: seems that previous test doesn't work.... btw, must still print the message please... + std::vector error; + splitString(msg.c_str(), ":", error); + if (error.size() > 3) + { + std::vector contextList; + explode(luaScript, string("\n"), contextList); + fromString(error[2], line); + if (line >= 3 && contextList.size() >= line) + msg = error[0]+": \n>>> "+contextList[line-3]+"\n>>> "+contextList[line-2]+"\n>>> "+contextList[line-1]+"\nError:"+error[2]+": "+error[3]; + else if (line >= 2 && contextList.size() >= line) + msg = error[0]+": \n>>>"+contextList[line-2]+"\n>>>"+contextList[line-1]+"\nError:"+error[2]+": "+error[3]; + else if (line >= 1 && contextList.size() >= line) + msg = error[0]+": \n>>>"+contextList[line-1]+"\nError:"+error[2]+": "+error[3]; + } nlwarning(formatLuaErrorNlWarn(msg).c_str()); displaySystemInfo(formatLuaErrorSysInfo(msg)); } diff --git a/code/ryzom/client/src/interface_v3/interface_manager.h b/code/ryzom/client/src/interface_v3/interface_manager.h index ced23130f..7ee6d1951 100644 --- a/code/ryzom/client/src/interface_v3/interface_manager.h +++ b/code/ryzom/client/src/interface_v3/interface_manager.h @@ -232,6 +232,7 @@ public: CCDBNodeBranch *getDB() const { return _DbRootNode; } // yoyo: should avoid to try creating DbPropr with this system... very dangerous CCDBNodeLeaf* getDbProp (const std::string & name, bool bCreate=true); + void delDbProp(const std::string & name); // get a Db Branch by its name. NULL if don't exist or not a branch (never try to create it) CCDBNodeBranch *getDbBranch(const std::string &name); // return the DB as an int32. return 0 if the DB does not exist (never create) diff --git a/code/ryzom/client/src/interface_v3/interface_parser.cpp b/code/ryzom/client/src/interface_v3/interface_parser.cpp index 56b95be88..109b3d5cd 100644 --- a/code/ryzom/client/src/interface_v3/interface_parser.cpp +++ b/code/ryzom/client/src/interface_v3/interface_parser.cpp @@ -517,7 +517,7 @@ bool CInterfaceParser::parseInterface (const std::vector & strings, { bool ok; - bool needCheck = checkInData; + bool needCheck = false; #if !FINAL_VERSION needCheck = false; @@ -554,10 +554,12 @@ bool CInterfaceParser::parseInterface (const std::vector & strings, string::size_type pos = filename.find ("@"); if (pos != string::npos) { - std::string bigFilename = CBigFile::getInstance().getBigFileName(filename.substr(0, pos)); - std::string path = "data/"+filename.substr(0, pos); - - isInData = bigFilename.find(path) != std::string::npos; + vector bigFilePaths; + CBigFile::getInstance().getBigFilePaths(bigFilePaths); + if (CBigFile::getInstance().getBigFileName(filename.substr(0, pos)) != "data/"+filename.substr(0, pos)) + isInData = false; + else + isInData = true; } if ((needCheck && !isInData) || !file.open (CPath::lookup(firstFileName))) @@ -4685,7 +4687,7 @@ bool CInterfaceParser::loadLUA(const std::string &fileName, std::string &error) { // get file - bool needCheck = true; + bool needCheck = false; #if !FINAL_VERSION needCheck = false; @@ -4702,10 +4704,10 @@ bool CInterfaceParser::loadLUA(const std::string &fileName, std::string &error) std::string::size_type pos = pathName.find("@"); if (pos != string::npos) { - std::string bigFilename = CBigFile::getInstance().getBigFileName(pathName.substr(0, pos)); - std::string path = "data/"+pathName.substr(0, pos); - - isInData = bigFilename.find(path) != std::string::npos; + if (CBigFile::getInstance().getBigFileName(pathName.substr(0, pos)) != "data/"+pathName.substr(0, pos)) + isInData = false; + else + isInData = true; } if (needCheck && !isInData) diff --git a/code/ryzom/client/src/interface_v3/inventory_manager.cpp b/code/ryzom/client/src/interface_v3/inventory_manager.cpp index 9d20c0661..421076364 100644 --- a/code/ryzom/client/src/interface_v3/inventory_manager.cpp +++ b/code/ryzom/client/src/interface_v3/inventory_manager.cpp @@ -44,12 +44,14 @@ #include "../sheet_manager.h" #include "game_share/slot_equipment.h" #include "game_share/animal_status.h" +#include "game_share/bot_chat_types.h" #include "../client_cfg.h" using namespace std; using namespace NLMISC; +extern NLMISC::CLog g_log; // Context help extern void contextHelp (const std::string &help); @@ -131,6 +133,7 @@ void CItemImage::build(CCDBNodeBranch *branch) Weight = dynamic_cast(branch->getNode(ICDBNode::CTextId("WEIGHT"), false)); NameId = dynamic_cast(branch->getNode(ICDBNode::CTextId("NAMEID"), false)); InfoVersion= dynamic_cast(branch->getNode(ICDBNode::CTextId("INFO_VERSION"), false)); + ResaleFlag = dynamic_cast(branch->getNode(ICDBNode::CTextId("RESALE_FLAG"), false)); // Should always have at least those one:(ie all but Price) nlassert(Sheet && Quality && Quantity && UserColor && Weight && NameId && InfoVersion); @@ -1998,6 +2001,9 @@ bool SBagOptions::parse(xmlNodePtr cur, CInterfaceGroup * /* parentGroup */) prop = xmlGetProp (cur, (xmlChar*)"filter_missmp"); if (prop) DbFilterMissMP = pIM->getDbProp(prop); + prop = xmlGetProp (cur, (xmlChar*)"filter_tp"); + if (prop) DbFilterTP = pIM->getDbProp(prop); + return true; } @@ -2041,6 +2047,13 @@ bool SBagOptions::isSomethingChanged() LastDbFilterMissMP = (DbFilterMissMP->getValue8() != 0); } + if (DbFilterTP != NULL) + if ((DbFilterTP->getValue8() != 0) != LastDbFilterTP) + { + bRet = true; + LastDbFilterTP = (DbFilterTP->getValue8() != 0); + } + return bRet; } @@ -2054,25 +2067,33 @@ bool SBagOptions::canDisplay(CDBCtrlSheet *pCS) const bool bFilterTool = getFilterTool(); bool bFilterMP = getFilterMP(); bool bFilterMissMP = getFilterMissMP(); + bool bFilterTP = getFilterTP(); const CItemSheet *pIS = pCS->asItemSheet(); if (pIS != NULL) { // Armor - if ((pIS->Family == ITEMFAMILY::ARMOR) || (pIS->Family == ITEMFAMILY::JEWELRY)) + if ((pIS->Family == ITEMFAMILY::ARMOR) || + (pIS->Family == ITEMFAMILY::JEWELRY)) if (!bFilterArmor) bDisplay = false; // Weapon - if ((pIS->Family == ITEMFAMILY::SHIELD) || (pIS->Family == ITEMFAMILY::MELEE_WEAPON) || - (pIS->Family == ITEMFAMILY::RANGE_WEAPON) || (pIS->Family == ITEMFAMILY::AMMO) || - (pIS->Family == ITEMFAMILY::CRYSTALLIZED_SPELL) || (pIS->Family == ITEMFAMILY::ITEM_SAP_RECHARGE) || + if ((pIS->Family == ITEMFAMILY::SHIELD) || + (pIS->Family == ITEMFAMILY::MELEE_WEAPON) || + (pIS->Family == ITEMFAMILY::RANGE_WEAPON) || + (pIS->Family == ITEMFAMILY::AMMO) || + (pIS->Family == ITEMFAMILY::CRYSTALLIZED_SPELL) || + (pIS->Family == ITEMFAMILY::ITEM_SAP_RECHARGE) || (pIS->Family == ITEMFAMILY::BRICK) ) if (!bFilterWeapon) bDisplay = false; // Tool - if ((pIS->Family == ITEMFAMILY::CRAFTING_TOOL) || (pIS->Family == ITEMFAMILY::HARVEST_TOOL) || - (pIS->Family == ITEMFAMILY::TAMING_TOOL) || (pIS->Family == ITEMFAMILY::TRAINING_TOOL) || - (pIS->Family == ITEMFAMILY::BAG) || (pIS->Family == ITEMFAMILY::PET_ANIMAL_TICKET) ) + if ((pIS->Family == ITEMFAMILY::CRAFTING_TOOL) || + (pIS->Family == ITEMFAMILY::HARVEST_TOOL) || + (pIS->Family == ITEMFAMILY::TAMING_TOOL) || + (pIS->Family == ITEMFAMILY::TRAINING_TOOL) || + (pIS->Family == ITEMFAMILY::BAG) || + (pIS->Family == ITEMFAMILY::PET_ANIMAL_TICKET) ) if (!bFilterTool) bDisplay = false; // MP @@ -2081,9 +2102,15 @@ bool SBagOptions::canDisplay(CDBCtrlSheet *pCS) const // Mission MP if ((pIS->Family == ITEMFAMILY::MISSION_ITEM) || + (pIS->Family == ITEMFAMILY::XP_CATALYSER) || + (pIS->Family == ITEMFAMILY::CONSUMABLE) || ((pIS->Family == ITEMFAMILY::RAW_MATERIAL) && !pIS->canBuildSomeItemPart())) if (!bFilterMissMP) bDisplay = false; - + + // Teleporter Pacts + if ((pIS->Family == ITEMFAMILY::TELEPORT)) + if (!bFilterTP) bDisplay = false; + // Jobs Items if (pIS->Id.toString().substr(0, 6) == "rpjob_") bDisplay = false; @@ -2776,6 +2803,37 @@ public: REGISTER_ACTION_HANDLER( CHandlerInvAutoEquip, "inv_auto_equip" ); +// ********************************************************************************************************** +class CHandlerLockInvItem : public IActionHandler +{ + void execute (CCtrlBase *pCaller, const std::string &sParams) + { + // get the calling item + CDBCtrlSheet *item = CDBCtrlSheet::getCurrSelSheet(); + if ( ! item) + { + nlwarning(" no caller sheet found"); + return; + } + + string lock = "1"; + if (item->getLockedByOwner()) + { + lock = "0"; + } + + uint32 slot = item->getIndexInDB(); + uint32 inv = item->getInventoryIndex(); + INVENTORIES::TInventory inventory = INVENTORIES::UNDEFINED; + inventory = (INVENTORIES::TInventory)(inv); + if (inventory == INVENTORIES::UNDEFINED) + { + return; + } + NLMISC::ICommand::execute("a lockItem " + INVENTORIES::toString(inventory) + " " + toString(slot) + " " + lock, g_log); + } +}; +REGISTER_ACTION_HANDLER( CHandlerLockInvItem, "lock_inv_item" ); // *************************************************************************** // Inventory Temporary @@ -2844,11 +2902,11 @@ class CHandlerInvTempAll : public IActionHandler nlctassert(MAX_INVENTORY_ANIMAL==4); if (pInv->isInventoryAvailable(INVENTORIES::pet_animal1)) - BagsBulk.push_back(pair (pInv->getBagBulk(2), pInv->getMaxBagBulk(2))); + BagsBulk.push_back(pair (pInv->getBagBulk(1), pInv->getMaxBagBulk(1))); if (pInv->isInventoryAvailable(INVENTORIES::pet_animal2)) - BagsBulk.push_back(pair (pInv->getBagBulk(3), pInv->getMaxBagBulk(3))); + BagsBulk.push_back(pair (pInv->getBagBulk(2), pInv->getMaxBagBulk(2))); if (pInv->isInventoryAvailable(INVENTORIES::pet_animal3)) - BagsBulk.push_back(pair (pInv->getBagBulk(4), pInv->getMaxBagBulk(4))); + BagsBulk.push_back(pair (pInv->getBagBulk(3), pInv->getMaxBagBulk(3))); if (pInv->isInventoryAvailable(INVENTORIES::pet_animal4)) BagsBulk.push_back(pair (pInv->getBagBulk(4), pInv->getMaxBagBulk(4))); diff --git a/code/ryzom/client/src/interface_v3/inventory_manager.h b/code/ryzom/client/src/interface_v3/inventory_manager.h index a5c332ba7..12de9ad98 100644 --- a/code/ryzom/client/src/interface_v3/inventory_manager.h +++ b/code/ryzom/client/src/interface_v3/inventory_manager.h @@ -25,6 +25,7 @@ #include "game_share/item_infos.h" #include "game_share/temp_inventory_mode.h" #include "game_share/inventories.h" +#include "game_share/bot_chat_types.h" class CCDBNodeBranch; class CDBCtrlSheet; @@ -62,6 +63,7 @@ public: CCDBNodeLeaf *Weight; CCDBNodeLeaf *NameId; CCDBNodeLeaf *InfoVersion; + CCDBNodeLeaf *ResaleFlag; public: // ctor @@ -77,6 +79,8 @@ public: uint32 getWeight() const { return (uint32) (Weight ? Weight->getValue32() : 0); } uint32 getNameId() const { return (uint32) (NameId ? NameId->getValue32() : 0); } uint8 getInfoVersion() const { return (uint8) (InfoVersion ? (uint8) InfoVersion->getValue8() : 0); } + uint8 getResaleFlag() const { return (uint8) (ResaleFlag ? (uint8) ResaleFlag->getValue8() : 0); } + bool getLockedByOwner() const { return (bool) (ResaleFlag ? (ResaleFlag->getValue8() == BOTCHATTYPE::ResaleKOLockedByOwner) : false); } // void setSheetID(uint32 si) { if (Sheet) Sheet->setValue32((sint32) si); } void setQuality(uint16 quality) { if (Quality) Quality->setValue16((sint16) quality); } @@ -86,6 +90,7 @@ public: void setWeight(uint32 wgt) { if (Weight) Weight->setValue32((sint32) wgt); } void setNameId(uint32 nid) { if (NameId) NameId->setValue32((sint32) nid); } void setInfoVersion(uint8 iv) { if (InfoVersion) InfoVersion->setValue8((sint8) iv); } + void setResaleFlag(uint8 resale) { if (ResaleFlag) ResaleFlag->setValue8(resale); } }; @@ -504,18 +509,20 @@ struct SBagOptions CCDBNodeLeaf *DbFilterTool; CCDBNodeLeaf *DbFilterMP; CCDBNodeLeaf *DbFilterMissMP; + CCDBNodeLeaf *DbFilterTP; bool LastDbFilterArmor; bool LastDbFilterWeapon; bool LastDbFilterTool; bool LastDbFilterMP; bool LastDbFilterMissMP; + bool LastDbFilterTP; // ----------------------- SBagOptions() { InvType = CInventoryManager::InvUnknown; - DbFilterArmor = DbFilterWeapon = DbFilterTool = DbFilterMP = DbFilterMissMP = NULL; - LastDbFilterArmor = LastDbFilterWeapon = LastDbFilterTool = LastDbFilterMP = LastDbFilterMissMP = false; + DbFilterArmor = DbFilterWeapon = DbFilterTool = DbFilterMP = DbFilterMissMP = DbFilterTP = NULL; + LastDbFilterArmor = LastDbFilterWeapon = LastDbFilterTool = LastDbFilterMP = LastDbFilterMissMP = LastDbFilterTP = false; } bool parse (xmlNodePtr cur, CInterfaceGroup *parentGroup); @@ -552,6 +559,12 @@ struct SBagOptions return (DbFilterMissMP->getValue8()!=0); } + bool getFilterTP() const + { + if (DbFilterTP == NULL) return true; + return (DbFilterTP->getValue8() != 0); + } + // Return true if the sheet can be displayed due to filters bool canDisplay(CDBCtrlSheet *pCS) const; }; diff --git a/code/ryzom/client/src/interface_v3/lua_ihm.cpp b/code/ryzom/client/src/interface_v3/lua_ihm.cpp index 15dd9872a..44e9a3ba7 100644 --- a/code/ryzom/client/src/interface_v3/lua_ihm.cpp +++ b/code/ryzom/client/src/interface_v3/lua_ihm.cpp @@ -143,7 +143,7 @@ extern NLMISC::CLog g_log; extern CContinentManager ContinentMngr; extern uint8 PlayerSelectedSlot; extern CClientChatManager ChatMngr; -extern void addWebIGParams (string &url); +extern void addWebIGParams (string &url, bool trustedDomain); // declare ostream << operator for ucstring -> registration of ucstring iin luabind will build a 'tostring' function from it std::ostream &operator<<(std::ostream &str, const ucstring &value) @@ -1323,6 +1323,7 @@ void CLuaIHM::registerIHM(CLuaState &ls) ls.registerFunc("getIndexInDB", getIndexInDB); ls.registerFunc("getUIId", getUIId); ls.registerFunc("createGroupInstance", createGroupInstance); + ls.registerFunc("createRootGroupInstance", createRootGroupInstance); ls.registerFunc("createUIElement", createUIElement); ls.registerFunc("launchContextMenuInGame", launchContextMenuInGame); ls.registerFunc("parseInterfaceFromString", parseInterfaceFromString); @@ -1356,6 +1357,19 @@ void CLuaIHM::registerIHM(CLuaState &ls) ls.registerFunc("enableModalWindow", enableModalWindow); ls.registerFunc("disableModalWindow", disableModalWindow); ls.registerFunc("getPlayerPos", getPlayerPos); + ls.registerFunc("getPlayerFront", getPlayerFront); + ls.registerFunc("getPlayerDirection", getPlayerDirection); + ls.registerFunc("getPlayerGender", getPlayerGender); + ls.registerFunc("getPlayerName", getPlayerName); + ls.registerFunc("getPlayerTitleRaw", getPlayerTitleRaw); + ls.registerFunc("getPlayerTitle", getPlayerTitle); + ls.registerFunc("getTargetPos", getTargetPos); + ls.registerFunc("getTargetFront", getTargetFront); + ls.registerFunc("getTargetDirection", getTargetDirection); + ls.registerFunc("getTargetGender", getTargetGender); + ls.registerFunc("getTargetName", getTargetName); + ls.registerFunc("getTargetTitleRaw", getTargetTitleRaw); + ls.registerFunc("getTargetTitle", getTargetTitle); ls.registerFunc("addSearchPathUser", addSearchPathUser); ls.registerFunc("displaySystemInfo", displaySystemInfo); ls.registerFunc("disableContextHelpForControl", disableContextHelpForControl); @@ -1363,6 +1377,7 @@ void CLuaIHM::registerIHM(CLuaState &ls) ls.registerFunc("setWeatherValue", setWeatherValue); ls.registerFunc("getWeatherValue", getWeatherValue); ls.registerFunc("getCompleteIslands", getCompleteIslands); + ls.registerFunc("displayBubble", displayBubble); ls.registerFunc("getIslandId", getIslandId); ls.registerFunc("getClientCfgVar", getClientCfgVar); ls.registerFunc("isPlayerFreeTrial", isPlayerFreeTrial); @@ -1370,14 +1385,18 @@ void CLuaIHM::registerIHM(CLuaState &ls) ls.registerFunc("isInRingMode", isInRingMode); ls.registerFunc("getUserRace", getUserRace); ls.registerFunc("getSheet2idx", getSheet2idx); + ls.registerFunc("getTargetSlot", getTargetSlot); + ls.registerFunc("getSlotDataSetId", getSlotDataSetId); // Through LUABind API lua_State *L= ls.getStatePointer(); luabind::module(L) [ + LUABIND_FUNC(addDbProp), LUABIND_FUNC(getDbProp), LUABIND_FUNC(setDbProp), + LUABIND_FUNC(delDbProp), LUABIND_FUNC(debugInfo), LUABIND_FUNC(rawDebugInfo), LUABIND_FUNC(dumpCallStack), @@ -1456,9 +1475,16 @@ void CLuaIHM::registerIHM(CLuaState &ls) luabind::def("shellExecute", CMiscFunctions::shellExecute), LUABIND_FUNC(getPlayerLevel), + LUABIND_FUNC(getPlayerVpa), + LUABIND_FUNC(getPlayerVpb), + LUABIND_FUNC(getPlayerVpc), LUABIND_FUNC(getTargetLevel), LUABIND_FUNC(getTargetForceRegion), LUABIND_FUNC(getTargetLevelForce), + LUABIND_FUNC(getTargetSheet), + LUABIND_FUNC(getTargetVpa), + LUABIND_FUNC(getTargetVpb), + LUABIND_FUNC(getTargetVpc), LUABIND_FUNC(isTargetNPC), LUABIND_FUNC(isTargetPlayer), // return 'true' if the target is an npc LUABIND_FUNC(isTargetUser), @@ -1686,12 +1712,60 @@ void CLuaIHM::setDbProp(const std::string &dbProp, sint32 value) // Write to the DB if found CInterfaceManager *pIM= CInterfaceManager::getInstance(); CCDBNodeLeaf *node= pIM->getDbProp(dbProp, false); + if(node) node->setValue32(value); else debugInfo(toString("setDbProp(): '%s' dbProp Not found", dbProp.c_str())); } +void CLuaIHM::delDbProp(const string &dbProp) +{ + //H_AUTO(Lua_CLuaIHM_setDbProp) + // Do not allow Write on SERVER: or LOCAL: + static const string dbServer= "SERVER:"; + static const string dbLocal= "LOCAL:"; + static const string dbLocalR2= "LOCAL:R2"; + if( (0==dbProp.compare(0, dbServer.size(), dbServer)) || + (0==dbProp.compare(0, dbLocal.size(), dbLocal)) + ) + { + if (0!=dbProp.compare(0, dbLocalR2.size(), dbLocalR2)) + { + nlstop; + throw ELuaIHMException("setDbProp(): You are not allowed to write on 'SERVER:...' or 'LOCAL:...' database"); + } + } + + // Write to the DB if found + CInterfaceManager *pIM= CInterfaceManager::getInstance(); + pIM->delDbProp(dbProp); +} + +void CLuaIHM::addDbProp(const std::string &dbProp, sint32 value) +{ + //H_AUTO(Lua_CLuaIHM_setDbProp) + // Do not allow Write on SERVER: or LOCAL: + static const std::string dbServer= "SERVER:"; + static const std::string dbLocal= "LOCAL:"; + static const std::string dbLocalR2= "LOCAL:R2"; + if( (0==dbProp.compare(0, dbServer.size(), dbServer)) || + (0==dbProp.compare(0, dbLocal.size(), dbLocal)) + ) + { + if (0!=dbProp.compare(0, dbLocalR2.size(), dbLocalR2)) + { + nlstop; + throw ELuaIHMException("setDbProp(): You are not allowed to write on 'SERVER:...' or 'LOCAL:...' database"); + } + } + + // Write to the DB if found + CInterfaceManager *pIM= CInterfaceManager::getInstance(); + CCDBNodeLeaf *node= pIM->getDbProp(dbProp, true); + if(node) + node->setValue32(value); +} // *************************************************************************** void CLuaIHM::debugInfo(const std::string &cstDbg) @@ -1865,7 +1939,21 @@ std::string CLuaIHM::getDefine(const std::string &def) // *************************************************************************** -static CEntityCL *getTargetSlot() +static sint32 getTargetSlotNr() +{ + const char *dbPath = "UI:VARIABLES:TARGET:SLOT"; + CInterfaceManager *im = CInterfaceManager::getInstance(); + CCDBNodeLeaf *node = im->getDbProp(dbPath, false); + if (!node) return NULL; + if ((uint8) node->getValue32() == (uint8) CLFECOMMON::INVALID_SLOT) + { + return NULL; + } + return node->getValue32(); +} + +// *************************************************************************** +static CEntityCL *getTargetEntity() { const char *dbPath = "UI:VARIABLES:TARGET:SLOT"; CInterfaceManager *im = CInterfaceManager::getInstance(); @@ -1878,6 +1966,12 @@ static CEntityCL *getTargetSlot() return EntitiesMngr.entity((uint) node->getValue32()); } +// *************************************************************************** +static CEntityCL *getSlotEntity(uint slot) +{ + return EntitiesMngr.entity(slot); +} + // *************************************************************************** sint32 CLuaIHM::getPlayerLevel() { @@ -1890,10 +1984,31 @@ sint32 CLuaIHM::getPlayerLevel() return sint32(maxskill); } +// *************************************************************************** +sint64 CLuaIHM::getPlayerVpa() +{ + sint64 prop = CInterfaceManager::getInstance()->getDbProp("SERVER:Entities:E0:P"+toString("%d", CLFECOMMON::PROPERTY_VPA))->getValue64(); + return prop; +} + +// *************************************************************************** +sint64 CLuaIHM::getPlayerVpb() +{ + sint64 prop = CInterfaceManager::getInstance()->getDbProp("SERVER:Entities:E0:P"+toString("%d", CLFECOMMON::PROPERTY_VPB))->getValue64(); + return prop; +} + +// *************************************************************************** +sint64 CLuaIHM::getPlayerVpc() +{ + sint64 prop = CInterfaceManager::getInstance()->getDbProp("SERVER:Entities:E0:P"+toString("%d", CLFECOMMON::PROPERTY_VPB))->getValue64(); + return prop; +} + // *************************************************************************** sint32 CLuaIHM::getTargetLevel() { - CEntityCL *target = getTargetSlot(); + CEntityCL *target = getTargetEntity(); if (!target) return -1; if ( target->isPlayer() ) { @@ -1913,10 +2028,52 @@ sint32 CLuaIHM::getTargetLevel() return -1; } +// *************************************************************************** +ucstring CLuaIHM::getTargetSheet() +{ + CEntityCL *target = getTargetEntity(); + if (!target) return ""; + + return target->sheetId().toString(); +} + +// *************************************************************************** +sint64 CLuaIHM::getTargetVpa() +{ + CEntityCL *target = getTargetEntity(); + if (!target) return 0; + + sint64 prop = CInterfaceManager::getInstance()->getDbProp("SERVER:Entities:E"+toString("%d", getTargetSlotNr())+":P"+toString("%d", CLFECOMMON::PROPERTY_VPA))->getValue64(); + + return prop; +} + +// *************************************************************************** +sint64 CLuaIHM::getTargetVpb() +{ + CEntityCL *target = getTargetEntity(); + if (!target) return 0; + + sint64 prop = CInterfaceManager::getInstance()->getDbProp("SERVER:Entities:E"+toString("%d", getTargetSlotNr())+":P"+toString("%d", CLFECOMMON::PROPERTY_VPB))->getValue64(); + + return prop; +} + +// *************************************************************************** +sint64 CLuaIHM::getTargetVpc() +{ + CEntityCL *target = getTargetEntity(); + if (!target) return 0; + + sint64 prop = CInterfaceManager::getInstance()->getDbProp("SERVER:Entities:E"+toString("%d", getTargetSlotNr())+":P"+toString("%d", CLFECOMMON::PROPERTY_VPB))->getValue64(); + + return prop; +} + // *************************************************************************** sint32 CLuaIHM::getTargetForceRegion() { - CEntityCL *target = getTargetSlot(); + CEntityCL *target = getTargetEntity(); if (!target) return -1; if ( target->isPlayer() ) { @@ -1944,7 +2101,7 @@ sint32 CLuaIHM::getTargetForceRegion() // *************************************************************************** sint32 CLuaIHM::getTargetLevelForce() { - CEntityCL *target = getTargetSlot(); + CEntityCL *target = getTargetEntity(); if (!target) return -1; if ( target->isPlayer() ) { @@ -1972,7 +2129,7 @@ sint32 CLuaIHM::getTargetLevelForce() // *************************************************************************** bool CLuaIHM::isTargetNPC() { - CEntityCL *target = getTargetSlot(); + CEntityCL *target = getTargetEntity(); if (!target) return false; return target->isNPC(); } @@ -1980,7 +2137,7 @@ bool CLuaIHM::isTargetNPC() // *************************************************************************** bool CLuaIHM::isTargetPlayer() { - CEntityCL *target = getTargetSlot(); + CEntityCL *target = getTargetEntity(); if (!target) return false; return target->isPlayer(); } @@ -1989,7 +2146,7 @@ bool CLuaIHM::isTargetPlayer() // *************************************************************************** bool CLuaIHM::isTargetUser() { - CEntityCL *target = getTargetSlot(); + CEntityCL *target = getTargetEntity(); if (!target) return false; return target->isUser(); } @@ -1998,15 +2155,15 @@ bool CLuaIHM::isTargetUser() bool CLuaIHM::isPlayerInPVPMode() { if (!UserEntity) return false; - return (UserEntity->getPvpMode() & PVP_MODE::PvpFaction || UserEntity->getPvpMode() & PVP_MODE::PvpFactionFlagged || UserEntity->getPvpMode() & PVP_MODE::PvpZoneFaction); + return (UserEntity->getPvpMode() & PVP_MODE::PvpFaction || UserEntity->getPvpMode() & PVP_MODE::PvpFactionFlagged || UserEntity->getPvpMode() & PVP_MODE::PvpZoneFaction) != 0; } // *************************************************************************** bool CLuaIHM::isTargetInPVPMode() { - CEntityCL *target = getTargetSlot(); + CEntityCL *target = getTargetEntity(); if (!target) return false; - return (target->getPvpMode() & PVP_MODE::PvpFaction || target->getPvpMode() & PVP_MODE::PvpFactionFlagged || target->getPvpMode() & PVP_MODE::PvpZoneFaction); + return (target->getPvpMode() & PVP_MODE::PvpFaction || target->getPvpMode() & PVP_MODE::PvpFactionFlagged || target->getPvpMode() & PVP_MODE::PvpZoneFaction) != 0; } // *************************************************************************** @@ -2368,6 +2525,53 @@ int CLuaIHM::createGroupInstance(CLuaState &ls) return 1; } +// *************************************************************************** +int CLuaIHM::createRootGroupInstance(CLuaState &ls) +{ + //H_AUTO(Lua_CLuaIHM_createGroupInstance) + const char *funcName = "createRootGroupInstance"; + CLuaIHM::checkArgCount(ls, funcName, 3); + CLuaIHM::checkArgType(ls, funcName, 1, LUA_TSTRING); + CLuaIHM::checkArgType(ls, funcName, 2, LUA_TSTRING); + CLuaIHM::checkArgType(ls, funcName, 3, LUA_TTABLE); + std::vector > templateParams; + CLuaObject params; + params.pop(ls); + ENUM_LUA_TABLE(params, it) + { + if (!it.nextKey().isString()) + { + nlwarning("%s : bad key encountered with type %s, string expected.", funcName, it.nextKey().getTypename()); + continue; + } + if (!it.nextValue().isString()) + { + nlwarning("%s : bad value encountered with type %s for key %s, string expected.", funcName, it.nextValue().getTypename(), it.nextKey().toString().c_str()); + continue; + } + templateParams.push_back(std::pair(it.nextKey().toString(), it.nextValue().toString())); // strange compilation bug here when I use std::make_pair ... :( + } + CInterfaceManager *im = CInterfaceManager::getInstance(); + CInterfaceGroup *result = im->createGroupInstance(ls.toString(1), "ui:interface:"+string(ls.toString(2)), templateParams); + if (!result) + { + ls.pushNil(); + } + else + { + result->setId("ui:interface:"+string(ls.toString(2))); + result->updateCoords(); + im->addWindowToMasterGroup("ui:interface", result); + CInterfaceGroup *pRoot = dynamic_cast(im->getElementFromId("ui:interface")); + result->setParent(pRoot); + if (pRoot) + pRoot->addGroup(result); + result->setActive(true); + CLuaIHM::pushUIOnStack(ls, result); + } + return 1; +} + // *************************************************************************** int CLuaIHM::createUIElement(CLuaState &ls) { @@ -2407,6 +2611,42 @@ int CLuaIHM::createUIElement(CLuaState &ls) return 1; } + +// *************************************************************************** +int CLuaIHM::displayBubble(CLuaState &ls) +{ + //H_AUTO(Lua_CLuaIHM_createUIElement) + const char *funcName = "displayBubble"; + CLuaIHM::checkArgCount(ls, funcName, 3); + CLuaIHM::checkArgType(ls, funcName, 1, LUA_TNUMBER); + CLuaIHM::checkArgType(ls, funcName, 2, LUA_TSTRING); + CLuaIHM::checkArgType(ls, funcName, 3, LUA_TTABLE); + std::vector strs; + std::vector links; + CLuaObject params; + params.pop(ls); + ENUM_LUA_TABLE(params, it) + { + if (!it.nextKey().isString()) + { + nlwarning("%s : bad key encountered with type %s, string expected.", funcName, it.nextKey().getTypename()); + continue; + } + if (!it.nextValue().isString()) + { + nlwarning("%s : bad value encountered with type %s for key %s, string expected.", funcName, it.nextValue().getTypename(), it.nextKey().toString().c_str()); + continue; + } + links.push_back(it.nextValue().toString()); + strs.push_back(it.nextKey().toString()); + } + + InSceneBubbleManager.webIgChatOpen((uint32)ls.toNumber(1), ls.toString(2), strs, links); + + return 1; +} + + // *************************************************************************** int CLuaIHM::getCompleteIslands(CLuaState &ls) { @@ -3523,7 +3763,7 @@ void CLuaIHM::browseNpcWebPage(const std::string &htmlId, const std::string &url string("&lang=") + ClientCfg.getHtmlLanguageCode() + string("&guild_name=") + guildName; } -/* +/* Already added by GroupHtml if(webig) { // append special webig auth params @@ -4242,6 +4482,126 @@ int CLuaIHM::getPlayerPos(CLuaState &ls) return 3; } +// *************************************************************************** +int CLuaIHM::getPlayerFront(CLuaState &ls) +{ + checkArgCount(ls, "getPlayerFront", 0); + ls.push(atan2(UserEntity->front().y, UserEntity->front().x)); + return 1; +} + +// *************************************************************************** +int CLuaIHM::getPlayerDirection(CLuaState &ls) +{ + checkArgCount(ls, "getPlayerDirection", 0); + ls.push(atan2(UserEntity->dir().y, UserEntity->dir().x)); + return 1; +} + +// *************************************************************************** +int CLuaIHM::getPlayerGender(CLuaState &ls) +{ + checkArgCount(ls, "getPlayerGender", 0); + ls.push((lua_Number)(UserEntity->getGender())); + return 1; +} + +// *************************************************************************** +int CLuaIHM::getPlayerName(CLuaState &ls) +{ + checkArgCount(ls, "getPlayerName", 0); + ls.push(UserEntity->getEntityName().toUtf8()); + return 1; +} + +// *************************************************************************** +int CLuaIHM::getPlayerTitleRaw(CLuaState &ls) +{ + checkArgCount(ls, "getPlayerTitleRaw", 0); + ls.push(UserEntity->getTitleRaw().toUtf8()); + return 1; +} + +// *************************************************************************** +int CLuaIHM::getPlayerTitle(CLuaState &ls) +{ + checkArgCount(ls, "getPlayerTitle", 0); + ls.push(UserEntity->getTitle().toUtf8()); + return 1; +} + +// *************************************************************************** +int CLuaIHM::getTargetPos(CLuaState &ls) +{ + checkArgCount(ls, "getTargetPos", 0); + CEntityCL *target = getTargetEntity(); + if (!target) return 0; + ls.push(target->pos().x); + ls.push(target->pos().y); + ls.push(target->pos().z); + return 3; +} + +// *************************************************************************** +int CLuaIHM::getTargetFront(CLuaState &ls) +{ + checkArgCount(ls, "getTargetFront", 0); + CEntityCL *target = getTargetEntity(); + if (!target) return 0; + ls.push(atan2(target->front().y, target->front().x)); + return 1; +} + +// *************************************************************************** +int CLuaIHM::getTargetDirection(CLuaState &ls) +{ + checkArgCount(ls, "getTargetDirection", 0); + CEntityCL *target = getTargetEntity(); + if (!target) return 0; + ls.push(atan2(target->dir().y, target->dir().x)); + return 1; +} + +// *************************************************************************** +int CLuaIHM::getTargetGender(CLuaState &ls) +{ + checkArgCount(ls, "getTargetGender", 0); + CCharacterCL* target = (CCharacterCL*)getTargetEntity(); + if (!target) return (int)GSGENDER::unknown; + ls.push((lua_Number)(target->getGender())); + return 1; +} + +// *************************************************************************** +int CLuaIHM::getTargetName(CLuaState &ls) +{ + checkArgCount(ls, "getTargetName", 0); + CEntityCL *target = getTargetEntity(); + if (!target) return 0; + ls.push(target->getEntityName().toUtf8()); + return 1; +} + +// *************************************************************************** +int CLuaIHM::getTargetTitleRaw(CLuaState &ls) +{ + checkArgCount(ls, "getTargetTitleRaw", 0); + CEntityCL *target = getTargetEntity(); + if (!target) return 0; + ls.push(target->getTitleRaw().toUtf8()); + return 1; +} + +// *************************************************************************** +int CLuaIHM::getTargetTitle(CLuaState &ls) +{ + checkArgCount(ls, "getTargetTitle", 0); + CEntityCL *target = getTargetEntity(); + if (!target) return 0; + ls.push(target->getTitle().toUtf8()); + return 1; +} + // *************************************************************************** int CLuaIHM::addSearchPathUser(CLuaState &ls) { @@ -4437,3 +4797,23 @@ int CLuaIHM::getSheet2idx(CLuaState &ls) return 1; } +// *************************************************************************** +int CLuaIHM::getTargetSlot(CLuaState &ls) +{ + uint32 slot = (uint32)getTargetSlotNr(); + ls.push((lua_Number)slot); + return 1; +} + +// *************************************************************************** +int CLuaIHM::getSlotDataSetId(CLuaState &ls) +{ + CLuaIHM::checkArgCount(ls, "getSlotDataSetId", 1); + CLuaIHM::checkArgType(ls, "getSlotDataSetId", 1, LUA_TNUMBER); + + uint32 slot = (uint32)ls.toNumber(1); + CEntityCL *e = getSlotEntity(slot); + string id = toString(e->dataSetId()); + ls.push(id); + return 1; +} diff --git a/code/ryzom/client/src/interface_v3/lua_ihm.h b/code/ryzom/client/src/interface_v3/lua_ihm.h index 6a11a5c91..12d8b5459 100644 --- a/code/ryzom/client/src/interface_v3/lua_ihm.h +++ b/code/ryzom/client/src/interface_v3/lua_ihm.h @@ -185,9 +185,16 @@ private: // LUA exported Functions with luabind static sint32 getPlayerLevel(); // get max level among player skills (magi, combat, crafting ,foraging) + static sint64 getPlayerVpa(); + static sint64 getPlayerVpb(); + static sint64 getPlayerVpc(); static sint32 getTargetLevel(); // get current, precise level of the selected target, or -1 if there's no such selected target static sint32 getTargetForceRegion(); // get 'force region' for current target, or -1 if there's no selected target - static sint32 getTargetLevelForce(); // get 'level force' for current target, or -1 if there's no selected target + static sint32 getTargetLevelForce(); // get 'level force' for current target, or -1 if there's no selected target + static ucstring getTargetSheet(); // get the name of the target sheet (like 'zoha2old.creature') + static sint64 getTargetVpa(); + static sint64 getTargetVpb(); + static sint64 getTargetVpc(); static bool isTargetNPC(); // return 'true' if the target is an npc static bool isTargetPlayer(); // return 'true' if the target is a player static bool isTargetUser(); // return 'true' if the target is the user @@ -202,10 +209,12 @@ private: static bool isInGame(); static uint32 getPlayerSelectedSlot(); static bool isPlayerSlotNewbieLand(uint32 slot); // test if one of the player slot is a newbieland one, if not so, client must be patched in order to continue - static uint32 getLocalTime(); + static uint32 getLocalTime(); static double getPreciseLocalTime(); static sint32 getDbProp(const std::string &dbProp); // return 0 if not found. static void setDbProp(const std::string &dbProp, sint32 value); // Nb: the db prop is not created if not present. + static void addDbProp(const std::string &dbProp, sint32 value); // Nb: the db prop is created if not present. + static void delDbProp(const std::string &dbProp); static std::string getDefine(const std::string &def); static void messageBox(const ucstring &text); static void messageBox(const ucstring &text, const std::string &masterGroup); @@ -286,17 +295,24 @@ private: static int getUICaller(CLuaState &ls); // params: none. return: CInterfaceElement* (nil if error) static int getCurrentWindowUnder(CLuaState &ls); // params: none. return: CInterfaceElement* (nil if none) static int getUI(CLuaState &ls); // params: "ui:interface:...". return: CInterfaceElement* (nil if error), an additionnal boolean parameter - // can specify verbose display when the element is note found (default is true) + // can specify verbose display when the element is note found (default is true) static int createGroupInstance(CLuaState &ls); // params : param 1 = template name, - // param 2 = id of parent where the instance will be inserted - // param 3 = table with ("template_param", "template_param_value") key/value pairs + // param 2 = id of parent where the instance will be inserted + // param 3 = table with ("template_param", "template_param_value") key/value pairs // such as { id="foo", x="10" } etc. -> returns a new instance of the template, or nil on fail + static int createRootGroupInstance(CLuaState &ls); // params : param 1 = template name, + // param 2 = id of parent where the instance will be inserted + // param 3 = table with ("template_param", "template_param_value") key/value pairs + // such as { id="foo", x="10" } etc. -> returns a new instance of the template, or nil on fail static int createUIElement(CLuaState &ls); // params : param 1 = template name, - // param 2 = id of parent where the instance will be inserted - // param 3 = table with ("template_param", "template_param_value") key/value pairs + // param 2 = id of parent where the instance will be inserted + // param 3 = table with ("template_param", "template_param_value") key/value pairs // such as { id="foo", x="10" } etc. -> returns a new instance of the template, or nil on fail - + static int displayBubble(CLuaState &ls); // params : param 1 = bot id + // param 2 = text + // param 3 = table with all strings and urls + // {"main text"="http:///", "text option 1"="http:///", "text option 2"="http:///") etc... static int getIndexInDB(CLuaState &ls); // params: CDBCtrlSheet*.... return: index, or 0 if error static int getUIId(CLuaState &ls); // params: CInterfaceElement*. return: ui id (empty if error) static int runAH(CLuaState &ls); // params: CInterfaceElement *, "ah", "params". return: none @@ -334,9 +350,9 @@ private: static int getServerSeason(CLuaState &ls); // get the last season sent by the server // 0->auto, computed locally from the current day (or not received from server yet) // 1->server force spring - // 2->' ' ' summer - // 3->' ' ' autumn - // 4->' ' ' winter + // 2->' ' ' summer + // 3->' ' ' autumn + // 4->' ' ' winter static int computeCurrSeason(CLuaState &ls); // compute current displayed season (1->spring, etc .) static int getAutoSeason(CLuaState &ls); // compute automatic season that would be at this time (1->spring, etc .) @@ -345,6 +361,19 @@ private: static int enableModalWindow(CLuaState &ls); static int disableModalWindow(CLuaState &ls); static int getPlayerPos(CLuaState &ls); + static int getPlayerFront(CLuaState &ls); + static int getPlayerDirection(CLuaState &ls); + static int getPlayerGender(CLuaState &ls); + static int getPlayerName(CLuaState &ls); + static int getPlayerTitleRaw(CLuaState &ls); + static int getPlayerTitle(CLuaState &ls); + static int getTargetPos(CLuaState &ls); + static int getTargetFront(CLuaState &ls); + static int getTargetDirection(CLuaState &ls); + static int getTargetGender(CLuaState &ls); + static int getTargetName(CLuaState &ls); + static int getTargetTitleRaw(CLuaState &ls); + static int getTargetTitle(CLuaState &ls); static int addSearchPathUser(CLuaState &ls); static int getClientCfgVar(CLuaState &ls); static int isPlayerFreeTrial(CLuaState &ls); @@ -352,6 +381,8 @@ private: static int isInRingMode(CLuaState &ls); static int getUserRace(CLuaState &ls); static int getSheet2idx(CLuaState &ls); + static int getTargetSlot(CLuaState &ls); + static int getSlotDataSetId(CLuaState &ls); // LUA functions exported for Dev only (debug) diff --git a/code/ryzom/client/src/interface_v3/people_interraction.cpp b/code/ryzom/client/src/interface_v3/people_interraction.cpp index e98013f9a..a92d73ce3 100644 --- a/code/ryzom/client/src/interface_v3/people_interraction.cpp +++ b/code/ryzom/client/src/interface_v3/people_interraction.cpp @@ -40,6 +40,7 @@ #include "../net_manager.h" #include "../connection.h" #include "group_tab.h" +#include "guild_manager.h" // Game share #include "game_share/entity_types.h" // NeL @@ -1418,7 +1419,47 @@ void CPeopleInterraction::updateContactInList(uint32 contactId, TCharConnectionS { sint index = FriendList.getIndexFromContactId(contactId); if (index != -1) - FriendList.setOnline(index, online); + { + if (FriendList.getOnline(index) != online) + { + // Only do work if online status has changed + FriendList.setOnline(index, online); + + CCDBNodeLeaf* node = CInterfaceManager::getInstance()->getDbProp("UI:SAVE:CHAT:SHOW_ONLINE_OFFLINE_NOTIFICATIONS_CB", false); + if (node && node->getValueBool()) + { + // Only show the message if this player is not in my guild (because then the guild manager will show a message) + std::vector GuildMembers = CGuildManager::getInstance()->getGuildMembers(); + bool bOnlyFriend = true; + ucstring name = toLower(FriendList.getName(index)); + for (uint i = 0; i < GuildMembers.size(); ++i) + { + if (toLower(GuildMembers[i].Name) == name) + { + bOnlyFriend = false; + break; + } + } + + // Player is not in my guild + if (bOnlyFriend) + { + ucstring msg = (online != ccs_offline) ? CI18N::get("uiPlayerOnline") : CI18N::get("uiPlayerOffline"); + strFindReplace(msg, "%s", FriendList.getName(index)); + string cat = getStringCategory(msg, msg); + map::const_iterator it; + NLMISC::CRGBA col = CRGBA::Yellow; + it = ClientCfg.SystemInfoParams.find(toLower(cat)); + if (it != ClientCfg.SystemInfoParams.end()) + { + col = it->second.Color; + } + bool dummy; + PeopleInterraction.ChatInput.AroundMe.displayMessage(msg, col, 2, &dummy); + } + } + } + } } else { @@ -1988,6 +2029,39 @@ public: }; REGISTER_ACTION_HANDLER( CHandlerDismissMember, "dismiss_member"); +//================================================================================================================= +// Set the leader of the team +class CHandlerSetTeamLeader : public IActionHandler +{ +public: + void execute (CCtrlBase * /* pCaller */, const std::string &/* sParams */) + { + // retrieve the index of the people + CPeopleList *list; + uint peopleIndex; + if (PeopleInterraction.getPeopleFromCurrentMenu(list, peopleIndex)) + { + if (list == &PeopleInterraction.TeamList) // check for good list + { + /* + const string msgName = "TEAM:SET_LEADER"; + CBitMemStream out; + if(GenericMsgHeaderMngr.pushNameToStream(msgName, out)) + { + uint8 teamMember = (uint8)(peopleIndex); + out.serial(teamMember); + NetMngr.push(out); + //nlinfo("impulseCallBack : %s %d sent", msgName.c_str(), teamMember); + } + else + nlwarning("command 'set_leader': unknown message named '%s'.", msgName.c_str()); + */ + NLMISC::ICommand::execute("a setTeamLeader " + toString(peopleIndex), g_log); + } + } + } +}; +REGISTER_ACTION_HANDLER( CHandlerSetTeamLeader, "set_team_leader"); //================================================================================================================= // Set a successor for the team @@ -3236,6 +3310,12 @@ NLMISC_COMMAND(chatLog, "", "") if (pIM->getLogState()) pIM->displaySystemInfo(CI18N::get("uiLogTurnedOn")); + CCDBNodeLeaf *node = pIM->getDbProp("UI:SAVE:CHATLOG_STATE", false); + if (node) + { + node->setValue32(pIM->getLogState() ? 1 : 0); + } + return true; }; diff --git a/code/ryzom/client/src/interface_v3/people_list.cpp b/code/ryzom/client/src/interface_v3/people_list.cpp index ac4764e15..c9b95a14a 100644 --- a/code/ryzom/client/src/interface_v3/people_list.cpp +++ b/code/ryzom/client/src/interface_v3/people_list.cpp @@ -211,7 +211,8 @@ bool CPeopleList::sortExByOnline(const CPeople& a, const CPeople& b) { return (name_a < name_b); } - else { + else + { // Compare online status switch (a.Online) { @@ -467,14 +468,8 @@ void CPeopleList::displayLocalPlayerTell(const ucstring &receiver, uint index, c return; } - ucstring cur_time; - CCDBNodeLeaf *pNL = CInterfaceManager::getInstance()->getDbProp("UI:SAVE:CHAT:SHOW_TIMES_IN_CHAT_CB", false); - if (pNL && pNL->getValueBool()) - cur_time = CInterfaceManager::getTimestampHuman(); - - ucstring csr; - if (CHARACTER_TITLE::isCsrTitle(UserEntity->getTitleRaw())) csr += ucstring("(CSR) "); - ucstring finalMsg = cur_time + csr + CI18N::get("youTell") + ": " + msg; + ucstring csr = CHARACTER_TITLE::isCsrTitle(UserEntity->getTitleRaw()) ? "(CSR) " : ""; + ucstring finalMsg = csr + CI18N::get("youTell") + ": " + msg; // display msg with good color CInterfaceProperty prop; prop.readRGBA("UI:SAVE:CHAT:COLORS:TELL"," "); @@ -783,10 +778,6 @@ void CPeopleList::setOnline(uint index, TCharConnectionState online) _Peoples[index].Online = online; - // If the people goes offline remove eventually opened chat - if (online == ccs_offline) - openCloseChat(index, false); - updatePeopleMenu(index); } @@ -944,14 +935,8 @@ class CHandlerContactEntry : public IActionHandler ucstring final; CChatWindow::encodeColorTag(prop.getRGBA(), final, false); - ucstring cur_time; - CCDBNodeLeaf *pNL = CInterfaceManager::getInstance()->getDbProp("UI:SAVE:CHAT:SHOW_TIMES_IN_CHAT_CB", false); - if (pNL && pNL->getValueBool()) - cur_time = CInterfaceManager::getTimestampHuman(); - - ucstring csr; - if (CHARACTER_TITLE::isCsrTitle(UserEntity->getTitleRaw())) csr += ucstring("(CSR) "); - final += cur_time + csr + CI18N::get("youTell")+": "; + ucstring csr = CHARACTER_TITLE::isCsrTitle(UserEntity->getTitleRaw()) ? "(CSR) " : ""; + final += csr + CI18N::get("youTell")+": "; prop.readRGBA("UI:SAVE:CHAT:COLORS:TELL"," "); CChatWindow::encodeColorTag(prop.getRGBA(), final, true); final += text; @@ -962,7 +947,6 @@ class CHandlerContactEntry : public IActionHandler strFindReplace(final, CI18N::get("youTell"), s); CInterfaceManager::getInstance()->log(final); } - } } }; diff --git a/code/ryzom/client/src/interface_v3/player_trade.cpp b/code/ryzom/client/src/interface_v3/player_trade.cpp index 7307110d9..ebc618ec7 100644 --- a/code/ryzom/client/src/interface_v3/player_trade.cpp +++ b/code/ryzom/client/src/interface_v3/player_trade.cpp @@ -139,6 +139,7 @@ void CPlayerTrade::restoreItem(CDBCtrlSheet *exchangeSlot) im.getBagItem(emptySlot).setWeight((uint32) exchangeSlot->getItemWeight()); im.getBagItem(emptySlot).setNameId(exchangeSlot->getItemNameId()); im.getBagItem(emptySlot).setInfoVersion(exchangeSlot->getItemInfoVersion()); + im.getBagItem(emptySlot).setResaleFlag(exchangeSlot->getItemResaleFlag()); } diff --git a/code/ryzom/client/src/interface_v3/skill_manager.cpp b/code/ryzom/client/src/interface_v3/skill_manager.cpp index 9d59c5bcb..c5fec7eb8 100644 --- a/code/ryzom/client/src/interface_v3/skill_manager.cpp +++ b/code/ryzom/client/src/interface_v3/skill_manager.cpp @@ -1042,7 +1042,7 @@ void CSkillManager::setPlayerTitle(const std::string &name) // *************************************************************************** // *************************************************************************** -#define GROUP_TITLE_COMBO "ui:interface:info_player_skills:content:basics_skills:title:player_title" +#define GROUP_TITLE_COMBO "ui:interface:info_player_skills:content:webinfos:title:player_title" // *************************************************************************** class CHandlerTitleInit: public IActionHandler diff --git a/code/ryzom/client/src/interface_v3/view_base.h b/code/ryzom/client/src/interface_v3/view_base.h index b568014a6..f4faaa204 100644 --- a/code/ryzom/client/src/interface_v3/view_base.h +++ b/code/ryzom/client/src/interface_v3/view_base.h @@ -70,6 +70,10 @@ public: // from CInterfaceElement virtual void visit(CInterfaceElementVisitor *visitor); + + // special for mouse over : return true and fill the name of the cursor to display + virtual bool getMouseOverShape(std::string &/* texName */, uint8 &/* rot */, NLMISC::CRGBA &/* col */) { return false; } + }; diff --git a/code/ryzom/client/src/interface_v3/view_bitmap.h b/code/ryzom/client/src/interface_v3/view_bitmap.h index 9cfd9de09..670c6fdf7 100644 --- a/code/ryzom/client/src/interface_v3/view_bitmap.h +++ b/code/ryzom/client/src/interface_v3/view_bitmap.h @@ -72,6 +72,8 @@ public: bool getScale() const { return _Scale; } void setScale (bool s) { _Scale = s; } + bool getTile() const { return _Tile; } + void setTile (bool s) { _Tile = s; } void setColor (const NLMISC::CRGBA &r) { _Color = r; } // Reflected diff --git a/code/ryzom/client/src/interface_v3/view_link.cpp b/code/ryzom/client/src/interface_v3/view_link.cpp index 4b0426006..61421133e 100644 --- a/code/ryzom/client/src/interface_v3/view_link.cpp +++ b/code/ryzom/client/src/interface_v3/view_link.cpp @@ -42,5 +42,23 @@ void CViewLink::setHTMLView(CGroupHTML *html) HTML = html; } +// *************************************************************************** +bool CViewLink::getMouseOverShape(string &texName, uint8 &rot, CRGBA &col) +{ + if (HTML != NULL) + { + if (!LinkTitle.empty()) + { + texName = LinkTitle; + rot= 0; + col = CRGBA::White; + return true; + } + } + + return false; +} + + // *************************************************************************** diff --git a/code/ryzom/client/src/interface_v3/view_link.h b/code/ryzom/client/src/interface_v3/view_link.h index 7a77f2b81..ba30fafd2 100644 --- a/code/ryzom/client/src/interface_v3/view_link.h +++ b/code/ryzom/client/src/interface_v3/view_link.h @@ -38,8 +38,11 @@ public: // The URI std::string Link; + std::string LinkTitle; + // Set the main group void setHTMLView(class CGroupHTML *html); + bool getMouseOverShape(std::string &texName, uint8 &rot, NLMISC::CRGBA &col); protected: diff --git a/code/ryzom/client/src/interface_v3/view_pointer.cpp b/code/ryzom/client/src/interface_v3/view_pointer.cpp index e6e6dcaa2..27d3dae86 100644 --- a/code/ryzom/client/src/interface_v3/view_pointer.cpp +++ b/code/ryzom/client/src/interface_v3/view_pointer.cpp @@ -70,6 +70,7 @@ CViewPointer::CViewPointer (const TCtorParam ¶m) _Color = CRGBA(255,255,255,255); _LastHightLight = NULL; _StringMode = false; + _ForceStringMode = false; _StringCursor = NULL; } @@ -255,6 +256,41 @@ void CViewPointer::draw () return; } + const vector &vUP = pIM->getViewsUnderPointer (); + + for(uint i=0;i(vUP[i]); + if (vLink != NULL) + { + string tooltip; + uint8 rot; + + if (vLink->getMouseOverShape(tooltip, rot, col)) + { + setString(ucstring(tooltip)); + sint32 texId = rVR.getTextureIdFromName ("curs_pick.tga"); + + CInterfaceGroup *stringCursor = IsMouseCursorHardware() ? _StringCursorHardware : _StringCursor; + if (stringCursor) + { + stringCursor->setX(_PointerX); + stringCursor->setY(_PointerY); + stringCursor->updateCoords(); + stringCursor->draw(); + // if in hardware mode, force to draw the default cursor no matter what.. + if (IsMouseCursorHardware()) + drawCursor(texId, col, 0); + } + else + { + drawCursor(texId, col, 0); + } + return; + } + } + } + // Draw if capture right pCB = pIM->getCapturePointerRight(); if (pCB != NULL) @@ -521,16 +557,50 @@ bool CViewPointer::drawPan(CCtrlBase* pCB, NLMISC::CRGBA col) // -------------------------------------------------------------------------------------------------------------------- bool CViewPointer::drawCustom(CCtrlBase* pCB) { - std::string texName; + string texName; uint8 rot; NLMISC::CRGBA col; if (pCB->getMouseOverShape(texName, rot, col)) { - CInterfaceManager *pIM = CInterfaceManager::getInstance(); - CViewRenderer &rVR = pIM->getViewRenderer(); - sint32 texId = rVR.getTextureIdFromName (texName); - drawCursor(texId, col, 0); - return true; + if (texName[0] == '@') + { + const string &tooltipInfos = texName.substr(1); + string tooltip; + vector tooltipInfosList; + splitString(tooltipInfos, "@", tooltipInfosList); + texName = tooltipInfosList[0]; + tooltip = tooltipInfosList[1]; + nlinfo(tooltip.c_str()); + setString(ucstring(tooltip)); + CInterfaceManager *pIM = CInterfaceManager::getInstance(); + CViewRenderer &rVR = pIM->getViewRenderer(); + sint32 texId = rVR.getTextureIdFromName (texName); + + CInterfaceGroup *stringCursor = IsMouseCursorHardware() ? _StringCursorHardware : _StringCursor; + if (stringCursor) + { + stringCursor->setX(_PointerX); + stringCursor->setY(_PointerY); + stringCursor->updateCoords(); + stringCursor->draw(); + // if in hardware mode, force to draw the default cursor no matter what.. + if (IsMouseCursorHardware()) + drawCursor(texId, col, 0); + } + else + { + drawCursor(texId, col, 0); + } + return true; + } + else + { + CInterfaceManager *pIM = CInterfaceManager::getInstance(); + CViewRenderer &rVR = pIM->getViewRenderer(); + sint32 texId = rVR.getTextureIdFromName (texName); + drawCursor(texId, col, 0); + return true; + } } return false; } diff --git a/code/ryzom/client/src/interface_v3/view_pointer.h b/code/ryzom/client/src/interface_v3/view_pointer.h index 0ade8b2c7..42a20b0a0 100644 --- a/code/ryzom/client/src/interface_v3/view_pointer.h +++ b/code/ryzom/client/src/interface_v3/view_pointer.h @@ -153,6 +153,7 @@ private: // Cursor mode bool _StringMode; + bool _ForceStringMode; CInterfaceGroup *_StringCursor; CInterfaceGroup *_StringCursorHardware; ucstring _ContextString; diff --git a/code/ryzom/client/src/interface_v3/view_renderer.cpp b/code/ryzom/client/src/interface_v3/view_renderer.cpp index 6a300275e..b3e419e5c 100644 --- a/code/ryzom/client/src/interface_v3/view_renderer.cpp +++ b/code/ryzom/client/src/interface_v3/view_renderer.cpp @@ -743,8 +743,8 @@ void CViewRenderer::loadTextures (const std::string &textureFileName, const std: image.UVMin.V = uvMinV; image.UVMax.U = uvMaxU; image.UVMax.V = uvMaxV; - sTGAname = tgaName; - sTGAname = toLower(sTGAname); + sTGAname = toLower(string(tgaName)); + string::size_type stripPng = sTGAname.find(".png"); if (stripPng != string::npos) { @@ -752,6 +752,7 @@ void CViewRenderer::loadTextures (const std::string &textureFileName, const std: sTGAname[stripPng + 2] = 'g'; sTGAname[stripPng + 3] = 'a'; } + image.Name = sTGAname; image.GlobalTexturePtr = &(_GlobalTextures.back()); if (getTextureIdFromName(sTGAname) != -1) @@ -1029,6 +1030,7 @@ sint32 CViewRenderer::getTextureIdFromName (const string &sName) const // convert to lowCase string nameLwr = toLower(sName); + string::size_type stripPng = nameLwr.find(".png"); if (stripPng != string::npos) { @@ -1036,7 +1038,7 @@ sint32 CViewRenderer::getTextureIdFromName (const string &sName) const nameLwr[stripPng + 2] = 'g'; nameLwr[stripPng + 3] = 'a'; } - + // Search in map TTextureMap::const_iterator it= _TextureMap.find(nameLwr); if( it==_TextureMap.end() ) @@ -1531,6 +1533,7 @@ void CViewRenderer::initSystemTextures() addSystemTexture(RegenTexture, "regen.tga"); addSystemTexture(RegenBackTexture, "regen_back.tga"); addSystemTexture(GlowStarTexture, "glow_star_24.tga"); + addSystemTexture(ItemLockedByOwnerTexture, "r2ed_toolbar_lock_small.tga"); } diff --git a/code/ryzom/client/src/interface_v3/view_renderer.h b/code/ryzom/client/src/interface_v3/view_renderer.h index ea7583dfa..cea807a23 100644 --- a/code/ryzom/client/src/interface_v3/view_renderer.h +++ b/code/ryzom/client/src/interface_v3/view_renderer.h @@ -75,6 +75,7 @@ public: RegenTexture, RegenBackTexture, GlowStarTexture, + ItemLockedByOwnerTexture, NumSystemTextures, }; diff --git a/code/ryzom/client/src/libwww.cpp b/code/ryzom/client/src/libwww.cpp index 966aeffa6..a1c0ce826 100644 --- a/code/ryzom/client/src/libwww.cpp +++ b/code/ryzom/client/src/libwww.cpp @@ -225,7 +225,10 @@ HTAttr p_attr[] = HTAttr div_attr[] = { - HTML_ATTR(DIV,NAME), + HTML_ATTR(DIV,CLASS), + HTML_ATTR(DIV,ID), + HTML_ATTR(DIV,NAME), + HTML_ATTR(DIV,STYLE), { 0 } }; @@ -535,6 +538,7 @@ const std::string &setCurrentDomain(const std::string &url) return HTTPCurrentDomain; } + void initLibWWW() { static bool initialized = false; diff --git a/code/ryzom/client/src/libwww.h b/code/ryzom/client/src/libwww.h index 41db90a6c..2c6ed2ae0 100644 --- a/code/ryzom/client/src/libwww.h +++ b/code/ryzom/client/src/libwww.h @@ -206,7 +206,10 @@ enum enum { - HTML_ATTR(DIV,NAME) = 0, + HTML_ATTR(DIV,CLASS) = 0, + HTML_ATTR(DIV,ID), + HTML_ATTR(DIV,NAME), + HTML_ATTR(DIV,STYLE), }; diff --git a/code/ryzom/client/src/login.cpp b/code/ryzom/client/src/login.cpp index d1dee738d..e43d6c8f5 100644 --- a/code/ryzom/client/src/login.cpp +++ b/code/ryzom/client/src/login.cpp @@ -738,8 +738,10 @@ void initLoginScreen() if(!l.empty()) { CGroupEditBox *pGEB = dynamic_cast(pIM->getElementFromId(CTRL_EDITBOX_LOGIN)); - if (pGEB != NULL) + if (pGEB != NULL && (pGEB->getInputString().empty())) + { pGEB->setInputString(l); + } pIM->runActionHandler("set_keyboard_focus", NULL, "target=" CTRL_EDITBOX_PASSWORD "|select_all=false"); } else @@ -1792,7 +1794,6 @@ class CAHOpenURL : public IActionHandler } else { - DWORD ret = 0; LPVOID lpMsgBuf; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | @@ -1922,21 +1923,21 @@ class CAHInitResLod : public IActionHandler // first indicates the preset-able cfg-variable // second indicates if its a double variable (else it's an int) CfgPresetList.clear(); - CfgPresetList.push_back(pair("LandscapeTileNear", true)); - CfgPresetList.push_back(pair("LandscapeThreshold", true)); - CfgPresetList.push_back(pair("Vision", true)); - CfgPresetList.push_back(pair("MicroVeget", false)); - CfgPresetList.push_back(pair("MicroVegetDensity", true)); + CfgPresetList.push_back(pair("LandscapeTileNear", true)); + CfgPresetList.push_back(pair("LandscapeThreshold", true)); + CfgPresetList.push_back(pair("Vision", true)); + CfgPresetList.push_back(pair("MicroVeget", false)); + CfgPresetList.push_back(pair("MicroVegetDensity", true)); CfgPresetList.push_back(pair("FxNbMaxPoly", false)); - CfgPresetList.push_back(pair("Cloud", false)); + CfgPresetList.push_back(pair("Cloud", false)); CfgPresetList.push_back(pair("CloudQuality", true)); CfgPresetList.push_back(pair("CloudUpdate", false)); CfgPresetList.push_back(pair("Shadows", false)); - CfgPresetList.push_back(pair("SkinNbMaxPoly", false)); + CfgPresetList.push_back(pair("SkinNbMaxPoly", false)); CfgPresetList.push_back(pair("NbMaxSkeletonNotCLod", false)); CfgPresetList.push_back(pair("CharacterFarClip", true)); - CfgPresetList.push_back(pair("Bloom", false)); + CfgPresetList.push_back(pair("Bloom", false)); CfgPresetList.push_back(pair("SquareBloom", false)); CfgPresetList.push_back(pair("DensityBloom", true)); diff --git a/code/ryzom/client/src/main_loop.cpp b/code/ryzom/client/src/main_loop.cpp index 81a63ae60..15a525f58 100644 --- a/code/ryzom/client/src/main_loop.cpp +++ b/code/ryzom/client/src/main_loop.cpp @@ -2889,6 +2889,7 @@ bool mainLoop() // This code must remain at the very end of the main loop. if(LoginSM.getCurrentState() == CLoginStateMachine::st_enter_far_tp_main_loop) { + CInterfaceManager::getInstance()->executeLuaScript("game:onFarTpStart()"); // Will loop the network until the end of the relogging process FarTP.farTPmainLoop(); @@ -2965,6 +2966,8 @@ bool mainLoop() // Get the Connection State (must be done after any Far TP to prevent the uiDisconnected box to be displayed) lastConnectionState = CNetworkConnection::Connected; connectionState = NetMngr.getConnectionState(); + + CInterfaceManager::getInstance()->executeLuaScript("game:onFarTpEnd()"); } } // end of main loop diff --git a/code/ryzom/client/src/net_manager.cpp b/code/ryzom/client/src/net_manager.cpp index 568081c81..55df0585d 100644 --- a/code/ryzom/client/src/net_manager.cpp +++ b/code/ryzom/client/src/net_manager.cpp @@ -664,10 +664,12 @@ void CInterfaceChatDisplayer::displayChat(TDataSetIndex compressedSenderIndex, c } // select DB + sint32 dbIndex = ChatMngr.getDynamicChannelDbIndexFromId(dynChatId); + clamp(dbIndex,0 , CChatGroup::MaxDynChanPerPlayer); string entry="UI:SAVE:CHAT:COLORS:"; switch(mode) { - case CChatGroup::dyn_chat: entry+="DYN"; break; + case CChatGroup::dyn_chat: entry+="DYN:" + NLMISC::toString(dbIndex); break; case CChatGroup::say: entry+="SAY"; break; case CChatGroup::shout: entry+="SHOUT"; break; case CChatGroup::team: entry+="GROUP"; break; @@ -697,6 +699,11 @@ void CInterfaceChatDisplayer::displayChat(TDataSetIndex compressedSenderIndex, c } } + if (stringCategory == "emt") + { + bubbleWanted = false; + } + if (mode != CChatGroup::system) { // find the sender/text separator to put color tags @@ -3206,7 +3213,7 @@ void impulseOutpostDeclareWarAck(NLMISC::CBitMemStream &impulse) node->setValue32(timeStartAttack); } -extern void addWebIGParams (string &url); +extern void addWebIGParams(string &url, bool trustedDomain); //----------------------------------------------- //----------------------------------------------- @@ -3290,7 +3297,6 @@ private: string group = titleStr.toString(); // group = group.substr(9, group.size()-10); - nlinfo("group = %s", group.c_str()); groupHtml = dynamic_cast(pIM->getElementFromId("ui:interface:"+group+":content:html")); if (!groupHtml) { @@ -3312,7 +3318,7 @@ private: if (group == "webig") pGC->setActive(true); string url = contentStr.toString(); - addWebIGParams(url); + addWebIGParams(url, true); groupHtml->browse(url.c_str()); pIM->setTopWindow(pGC); } diff --git a/code/ryzom/client/src/player_cl.cpp b/code/ryzom/client/src/player_cl.cpp index 9dfe6e12f..d74cf6ae1 100644 --- a/code/ryzom/client/src/player_cl.cpp +++ b/code/ryzom/client/src/player_cl.cpp @@ -164,7 +164,7 @@ bool CPlayerCL::isNeutral() const //----------------------------------------------- bool CPlayerCL::isFriend () const { - return isNeutral() || isNeutralPVP() || isAlly(); + return isNeutral() || isAlly(); } @@ -174,12 +174,44 @@ bool CPlayerCL::isFriend () const //----------------------------------------------- bool CPlayerCL::isEnemy () const { + // Challenge i.e. SOLO FULL PVP + if( getPvpMode()&PVP_MODE::PvpChallenge || + UserEntity->getPvpMode()&PVP_MODE::PvpChallenge ) + { + return true; + } + + // if one of 2 players is not in pvp they can't be enemies if( UserEntity->getPvpMode() == PVP_MODE::None || getPvpMode() == PVP_MODE::None ) { return false; } + + // if one of 2 players is safe they can't be enemies + if( UserEntity->getPvpMode()&PVP_MODE::PvpSafe || + getPvpMode()&PVP_MODE::PvpSafe ) + { + return false; + } + + // if one of 2 players are in safe zone and not flagged they can't be enemies + if ((UserEntity->getPvpMode()&PVP_MODE::PvpZoneSafe && + ((UserEntity->getPvpMode()&PVP_MODE::PvpFactionFlagged) == 0)) + || + (getPvpMode()&PVP_MODE::PvpZoneSafe && + ((getPvpMode()&PVP_MODE::PvpFactionFlagged) == 0))) + { + return false; + } + + // Duel + if( getPvpMode()&PVP_MODE::PvpDuel && + UserEntity->getPvpMode()&PVP_MODE::PvpDuel ) + { + return true; // TODO + } // Outpost if ( isAnOutpostEnemy() ) @@ -187,19 +219,12 @@ bool CPlayerCL::isEnemy () const return true; } - // Challenge - if( getPvpMode()&PVP_MODE::PvpChallenge && - UserEntity->getPvpMode()&PVP_MODE::PvpChallenge ) - { - if( !isInTeam() ) - return true; - } - // Zone Free if( getPvpMode()&PVP_MODE::PvpZoneFree && UserEntity->getPvpMode()&PVP_MODE::PvpZoneFree ) { - if( !isInTeam() && !isInGuild() ) + // If not in same Team and not in same League => ennemy + if( !isInTeam() && !isInSameLeague() ) return true; } @@ -207,7 +232,11 @@ bool CPlayerCL::isEnemy () const if( getPvpMode()&PVP_MODE::PvpZoneGuild && UserEntity->getPvpMode()&PVP_MODE::PvpZoneGuild ) { - if( !isInTeam() && !isInGuild() ) + // If in same Guild but different Leagues => ennemy + if ( isInSameGuild() && oneInLeague() && !isInSameLeague() ) + return true; + + if( !isInTeam() && !isInSameLeague() ) return true; } @@ -219,29 +248,18 @@ bool CPlayerCL::isEnemy () const return true; } - // Duel - if( getPvpMode()&PVP_MODE::PvpDuel && - UserEntity->getPvpMode()&PVP_MODE::PvpDuel ) - { - return true; // TODO - } - - // Faction + // Free PVP : Ennemis are not in team AND not in league if ((getPvpMode()&PVP_MODE::PvpFaction || getPvpMode()&PVP_MODE::PvpFactionFlagged) && (UserEntity->getPvpMode()&PVP_MODE::PvpFaction || UserEntity->getPvpMode()&PVP_MODE::PvpFactionFlagged)) { - // Check if is not ally - if (!isInTeam() && !isInGuild()) - { - // Check for each Clan if is in opposition - for (uint8 i = 0; i < PVP_CLAN::NbClans; i++) - { - if ((isPvpEnnemy(i) && UserEntity->isPvpAlly(i)) || (isPvpAlly(i) && UserEntity->isPvpEnnemy(i))) - return true; - } - } - + // If in same Guild but different Leagues => ennemy + if ( isInSameGuild() && oneInLeague() && !isInSameLeague() ) + return true; + + if (!isInTeam() && !isInSameLeague()) + return true; } + return false; } // isEnemy // @@ -253,32 +271,38 @@ bool CPlayerCL::isEnemy () const //----------------------------------------------- bool CPlayerCL::isAlly() const { - // if one of 2 players is not in pvp they can't be enemies + + // Challenge i.e. SOLO FULL PVP + if( getPvpMode()&PVP_MODE::PvpChallenge || + UserEntity->getPvpMode()&PVP_MODE::PvpChallenge ) + { + return false; + } + + // if one of 2 players is not in pvp they can't be allies if( UserEntity->getPvpMode() == PVP_MODE::None || getPvpMode() == PVP_MODE::None ) { return false; } + // if one of 2 players is in safe zone and not other they can't be allies + if ((UserEntity->getPvpMode()&PVP_MODE::PvpSafe) != (getPvpMode()&PVP_MODE::PvpSafe)) + { + return false; + } + // Outpost if ( isAnOutpostAlly() ) { return true; } - // Challenge - if( getPvpMode()&PVP_MODE::PvpChallenge && - UserEntity->getPvpMode()&PVP_MODE::PvpChallenge ) - { - if( isInTeam() ) - return true; - } - // Zone Free if( getPvpMode()&PVP_MODE::PvpZoneFree && UserEntity->getPvpMode()&PVP_MODE::PvpZoneFree ) { - if( isInTeam() || isInGuild() ) + if( isInTeam() || isInSameLeague() ) return true; } @@ -286,8 +310,12 @@ bool CPlayerCL::isAlly() const if( getPvpMode()&PVP_MODE::PvpZoneGuild && UserEntity->getPvpMode()&PVP_MODE::PvpZoneGuild ) { - if( isInTeam() || isInGuild() ) + if( isInTeam() || isInSameLeague() ) return true; + + if ( isInSameGuild() && !oneInLeague() ) + return true; + } // Zone Faction @@ -298,26 +326,15 @@ bool CPlayerCL::isAlly() const return true; } - // Faction + // Free PVP : Allies are in team OR in league if ((getPvpMode()&PVP_MODE::PvpFaction || getPvpMode()&PVP_MODE::PvpFactionFlagged) && (UserEntity->getPvpMode()&PVP_MODE::PvpFaction || UserEntity->getPvpMode()&PVP_MODE::PvpFactionFlagged)) { - if (isInTeam() && isInGuild()) + if (isInTeam() || isInSameLeague()) return true; - - // Check for each Clan if is in opposition - for (uint8 i = 0; i < PVP_CLAN::NbClans; i++) - { - if ((isPvpEnnemy(i) && UserEntity->isPvpAlly(i)) || (isPvpAlly(i) && UserEntity->isPvpEnnemy(i))) - return false; - } - // Check for each Clan if is in same clan - for (uint8 i = 0; i < PVP_CLAN::NbClans; i++) - { - if ((isPvpEnnemy(i) && UserEntity->isPvpEnnemy(i)) || (isPvpAlly(i) && UserEntity->isPvpAlly(i))) - return true; - } + if ( isInSameGuild() && !oneInLeague() ) + return true; } return false; @@ -336,66 +353,12 @@ bool CPlayerCL::isNeutralPVP() const return false; } - // Outpost - if ( getOutpostId() != 0 ) + if( UserEntity->getPvpMode() == PVP_MODE::None ) { - if( UserEntity->getOutpostId() != getOutpostId() ) - { - return true; - } + return false; } - // Challenge - if( getPvpMode()&PVP_MODE::PvpChallenge && - !(UserEntity->getPvpMode()&PVP_MODE::PvpChallenge) ) - { - return true; - } - - // Zone Free - if( getPvpMode()&PVP_MODE::PvpZoneFree && - !(UserEntity->getPvpMode()&PVP_MODE::PvpZoneFree) ) - { - return true; - } - - // Zone Guild - if( getPvpMode()&PVP_MODE::PvpZoneGuild && - !(UserEntity->getPvpMode()&PVP_MODE::PvpZoneGuild) ) - { - return true; - } - - // Zone Faction - if( getPvpMode()&PVP_MODE::PvpZoneFaction && - !(UserEntity->getPvpMode()&PVP_MODE::PvpZoneFaction) ) - { - return true; - } - - // Duel - if( getPvpMode()&PVP_MODE::PvpDuel && - !(UserEntity->getPvpMode()&PVP_MODE::PvpDuel) ) - { - return true; - } - - if ((getPvpMode()&PVP_MODE::PvpFaction || getPvpMode()&PVP_MODE::PvpFactionFlagged) && - (UserEntity->getPvpMode()&PVP_MODE::PvpFaction || UserEntity->getPvpMode()&PVP_MODE::PvpFactionFlagged)) - { - // Check for each Clan if is in opposition or same - for (uint8 i = 0; i < PVP_CLAN::NbClans; i++) - { - if ((isPvpEnnemy(i) && UserEntity->isPvpAlly(i)) || - (isPvpAlly(i) && UserEntity->isPvpEnnemy(i)) || - (isPvpEnnemy(i) && UserEntity->isPvpEnnemy(i)) || - (isPvpAlly(i) && UserEntity->isPvpAlly(i))) - return false; - } - return true; - } - - return false; + return (!isEnemy() && !isAlly()); } diff --git a/code/ryzom/client/src/string_manager_client.cpp b/code/ryzom/client/src/string_manager_client.cpp index 40886d518..dd79da45e 100644 --- a/code/ryzom/client/src/string_manager_client.cpp +++ b/code/ryzom/client/src/string_manager_client.cpp @@ -34,6 +34,8 @@ namespace STRING_MANAGER // *************************************************************************** map CStringManagerClient::_SpecItem_TempMap; + map CStringManagerClient::_DynStrings; + vector CStringManagerClient::_TitleWords; bool CStringManagerClient::_SpecItem_MemoryCompressed = false; char *CStringManagerClient::_SpecItem_Labels = NULL; ucchar *CStringManagerClient::_SpecItem_NameDesc = NULL; @@ -381,7 +383,15 @@ restartLoop4: result = ucstring(tmp) + it->second; } else + { result = it->second; + if (result.size() > 9 && result.substr(0, 9) == ucstring("::iterator itds = _DynStrings.find(result.substr(9, result.size()-10)); + if (itds != _DynStrings.end()) + result = itds->second; + } + } } return true; @@ -1595,9 +1605,29 @@ const ucchar *CStringManagerClient::getSPhraseLocalizedDescription(NLMISC::CShee // *************************************************************************** const ucchar *CStringManagerClient::getTitleLocalizedName(const std::string &titleId, bool women) { - return getSpecialWord(titleId,women); + const ucchar * infos = getSpecialWord(titleId, women); + ucstring infosUC(infos); + + vector listInfos; + splitUCString(infosUC, ucstring("#"), listInfos); + if (listInfos.empty()) + return infos; + + _TitleWords.push_back(listInfos[0]); + return _TitleWords.back().c_str(); } +vector CStringManagerClient::getTitleInfos(const std::string &titleId, bool women) +{ + const ucchar * infos = getSpecialWord(titleId, women); + ucstring infosUC(infos); + + vector listInfos; + splitUCString(infosUC, ucstring("#"), listInfos); + return listInfos; +} + + // *************************************************************************** const ucchar *CStringManagerClient::getClassificationTypeLocalizedName(EGSPD::CClassificationType::TClassificationType type) { @@ -1641,7 +1671,14 @@ const ucchar *CStringManagerClient::getSquadLocalizedDescription(NLMISC::CSheetI } // *************************************************************************** -void CStringManagerClient::replaceSBrickName(NLMISC::CSheetId id, const ucstring &name, const ucstring &desc, const ucstring &desc2) +void CStringManagerClient::replaceDynString(const ucstring &name, const ucstring &text) +{ + _DynStrings[name] = text; +} + + +// *************************************************************************** +void CStringManagerClient::replaceSBrickName(NLMISC::CSheetId id, const ucstring &name, const ucstring &desc, const ucstring &desc2) { std::string label= id.toString(); if (label.empty()) diff --git a/code/ryzom/client/src/string_manager_client.h b/code/ryzom/client/src/string_manager_client.h index 511986407..e5842a9f6 100644 --- a/code/ryzom/client/src/string_manager_client.h +++ b/code/ryzom/client/src/string_manager_client.h @@ -77,6 +77,7 @@ public: static void specialWordsMemoryCompress(); // Yoyo: Replace the Brick Name with Filled stats (CSBrickManager work). No-Op if not found static void replaceSBrickName(NLMISC::CSheetId id, const ucstring &name, const ucstring &desc, const ucstring &desc2); + static void replaceDynString(const ucstring &name, const ucstring &text); // Get the Localized Name of the Places. static const ucchar *getPlaceLocalizedName(const std::string &placeNameID); @@ -106,6 +107,7 @@ public: // Get the Localized Title name static const ucchar *getTitleLocalizedName(const std::string &titleId, bool women); + static std::vector CStringManagerClient::getTitleInfos(const std::string &titleId, bool women); // Get the Localized name of a classification type static const ucchar *getClassificationTypeLocalizedName(EGSPD::CClassificationType::TClassificationType type); @@ -215,8 +217,6 @@ private: // Callback for dyn string value from the server TStringCallbacksContainer _DynStringsCallbacks; - - // Return value for waiting string.. static ucstring _WaitString; @@ -273,6 +273,9 @@ private: static bool _SpecItem_MemoryCompressed; static std::map _SpecItem_TempMap; + static std::vector _TitleWords; + static std::map _DynStrings; + static char *_SpecItem_Labels; static ucchar *_SpecItem_NameDesc; diff --git a/code/ryzom/client/src/user_entity.cpp b/code/ryzom/client/src/user_entity.cpp index 64a493d2e..f1e4aeff2 100644 --- a/code/ryzom/client/src/user_entity.cpp +++ b/code/ryzom/client/src/user_entity.cpp @@ -507,7 +507,7 @@ void CUserEntity::updateVisualPropertyName(const NLMISC::TGameCycle &gameCycle, CPlayerCL::updateVisualPropertyName(gameCycle, prop); // Name changed ? - if (oldNameId != _NameId) +/* if (oldNameId != _NameId) { CInterfaceManager *pIM = CInterfaceManager::getInstance(); CInterfaceElement *element = pIM->getElementFromId("ui:interface:mailbox:content:html"); @@ -518,7 +518,7 @@ void CUserEntity::updateVisualPropertyName(const NLMISC::TGameCycle &gameCycle, html->browse("home"); } } - +*/ }// updateVisualPropertyName // //----------------------------------------------- @@ -2657,36 +2657,39 @@ void CUserEntity::selection(const CLFECOMMON::TCLEntityId &slot) // virtual playerGiftNeeded->setValue32(0); } } +/* TODO ULU : Add RP tags */ // update pvp tags - CViewBase * tagView = dynamic_cast(pIM->getElementFromId("ui:interface:target:pvp_tags")); - CViewBase * contentView = dynamic_cast(pIM->getElementFromId("ui:interface:target:content")); - if ((tgtSlot!=CLFECOMMON::INVALID_SLOT) && entity) { CPlayerCL *pPlayer = dynamic_cast(entity); if (pPlayer) { - for (uint8 i = 0; i < 7; i++) + /*// Pvp Mode + CViewBitmap * tagMode = dynamic_cast(pIM->getElementFromId("ui:interface:target:pvp_tags:mode")); + if (tagMode) { - CViewBitmap * tag = dynamic_cast(pIM->getElementFromId("ui:interface:target:pvp_tags:tag_"+toString(i))); - if (tag) - { - if ((pPlayer->getPvpMode()&PVP_MODE::PvpFaction || pPlayer->getPvpMode()&PVP_MODE::PvpFactionFlagged) && pPlayer->isPvpAlly(i)) - { - tag->setTexture("pvp_ally_"+toString(i)+".tga"); - } - else if ((pPlayer->getPvpMode()&PVP_MODE::PvpFaction || pPlayer->getPvpMode()&PVP_MODE::PvpFactionFlagged) && pPlayer->isPvpEnnemy(i)) - { - tag->setTexture("pvp_enemy_"+toString(i)+".tga"); - } - else - { - tag->setTexture("alpha_10.tga"); - } - } + if (pPlayer->getPvpMode()&PVP_MODE::PvpFaction) + tagMode->setTexture("pvp_orange.tga"); + else if (pPlayer->getPvpMode()&PVP_MODE::PvpFactionFlagged) + tagMode->setTexture("pvp_red.tga"); + else + tagMode->setTexture("alpha_10.tga"); } +*/ + /*// Pvp available actions (attack, heal, both) + CViewBitmap * tagMode = dynamic_cast(pIM->getElementFromId("ui:interface:target:pvp_tags:actions")); + if (tagMode) + { + if (pPlayer->getPvpMode()&PVP_MODE::PvpFaction) + tag->setTexture("pvp_orange.tga"); + else if (pPlayer->getPvpMode()&PVP_MODE::PvpFactionFlagged) + tag->setTexture("pvp_red.tga"); + else + tag->setTexture("alpha_10.tga"); + }*/ + } } diff --git a/code/ryzom/client/src/user_entity.h b/code/ryzom/client/src/user_entity.h index 0d39f2967..30c9fed41 100644 --- a/code/ryzom/client/src/user_entity.h +++ b/code/ryzom/client/src/user_entity.h @@ -477,6 +477,14 @@ public: /// true if current behaviour allows to change front bool canChangeFront(); + ucstring getLoginName() + { + if (_LoginName == ucstring("")) + _LoginName = getDisplayName(); + + return _LoginName; + } + protected: class CSpeedFactor : public ICDBNode::IPropertyObserver { @@ -741,6 +749,8 @@ private: /// previous items in hand before they have been changed by an auto-equip due to an action (ex: forage) CItemSnapshot _PreviousRightHandItem; CItemSnapshot _PreviousLeftHandItem; + + ucstring _LoginName; }; /// Out game received position From ad9b680e9182a1d1d14221ae8d452c2e3dcce062 Mon Sep 17 00:00:00 2001 From: kervala Date: Mon, 27 Feb 2012 22:42:30 +0100 Subject: [PATCH 40/46] Changed: #1433 Merge changes from patch 1.13 --- code/ryzom/client/src/cdb_branch.cpp | 2 +- code/ryzom/client/src/cdb_branch.h | 2 +- code/ryzom/client/src/character_cl.cpp | 1 - code/ryzom/client/src/client_chat_manager.cpp | 4 ++-- code/ryzom/client/src/entity_cl.cpp | 8 ++++---- .../client/src/interface_v3/chat_text_manager.cpp | 2 +- code/ryzom/client/src/interface_v3/chat_window.cpp | 2 +- code/ryzom/client/src/interface_v3/group_compas.cpp | 10 ++++++++++ .../client/src/interface_v3/group_html_webig.cpp | 2 +- code/ryzom/client/src/interface_v3/lua_ihm.cpp | 12 ++++++------ code/ryzom/client/src/interface_v3/people_list.cpp | 6 +++--- code/ryzom/client/src/string_manager_client.h | 2 +- 12 files changed, 31 insertions(+), 22 deletions(-) diff --git a/code/ryzom/client/src/cdb_branch.cpp b/code/ryzom/client/src/cdb_branch.cpp index 60c6b63f4..351203493 100644 --- a/code/ryzom/client/src/cdb_branch.cpp +++ b/code/ryzom/client/src/cdb_branch.cpp @@ -628,7 +628,7 @@ void CCDBNodeBranch::display (const std::string &prefix) } } -void CCDBNodeBranch::removeNode (CTextId& id) +void CCDBNodeBranch::removeNode (const CTextId& id) { // Look for the node CCDBNodeBranch *pNode = dynamic_cast(getNode(id,false)); diff --git a/code/ryzom/client/src/cdb_branch.h b/code/ryzom/client/src/cdb_branch.h index 405c7c479..74e085ca4 100644 --- a/code/ryzom/client/src/cdb_branch.h +++ b/code/ryzom/client/src/cdb_branch.h @@ -165,7 +165,7 @@ public: virtual void display (const std::string &prefix); - void removeNode (CTextId& id); + void removeNode (const CTextId& id); /** * add an observer to a property diff --git a/code/ryzom/client/src/character_cl.cpp b/code/ryzom/client/src/character_cl.cpp index 694ed9b16..c0e6d1104 100644 --- a/code/ryzom/client/src/character_cl.cpp +++ b/code/ryzom/client/src/character_cl.cpp @@ -1877,7 +1877,6 @@ void CCharacterCL::updateVisualPropertyPvpMode(const NLMISC::TGameCycle &/* game void CCharacterCL::updateVisualPropertyPvpClan(const NLMISC::TGameCycle &/* gameCycle */, const sint64 &prop) { _LeagueId = uint32(prop); - buildInSceneInterface(); if (isUser()) { diff --git a/code/ryzom/client/src/client_chat_manager.cpp b/code/ryzom/client/src/client_chat_manager.cpp index e7ef54d02..59b72cedb 100644 --- a/code/ryzom/client/src/client_chat_manager.cpp +++ b/code/ryzom/client/src/client_chat_manager.cpp @@ -1174,7 +1174,7 @@ class CHandlerTell : public IActionHandler ucstring finalMsg; CChatWindow::encodeColorTag(prop.getRGBA(), finalMsg, false); - ucstring csr = CHARACTER_TITLE::isCsrTitle(UserEntity->getTitleRaw()) ? "(CSR) " : ""; + ucstring csr(CHARACTER_TITLE::isCsrTitle(UserEntity->getTitleRaw()) ? "(CSR) " : ""); finalMsg += csr + CI18N::get("youTell") + ": "; prop.readRGBA("UI:SAVE:CHAT:COLORS:TELL"," "); CChatWindow::encodeColorTag(prop.getRGBA(), finalMsg, true); @@ -1182,7 +1182,7 @@ class CHandlerTell : public IActionHandler // display msg with good color // TDataSetIndex dsi; // not used .... PeopleInterraction.ChatInput.Tell.displayTellMessage(/*dsi, */finalMsg, receiver, prop.getRGBA()); - + ucstring s = CI18N::get("youTellPlayer"); strFindReplace(s, "%name", receiver); strFindReplace(finalMsg, CI18N::get("youTell"), s); diff --git a/code/ryzom/client/src/entity_cl.cpp b/code/ryzom/client/src/entity_cl.cpp index 421faad47..7cefa69d7 100644 --- a/code/ryzom/client/src/entity_cl.cpp +++ b/code/ryzom/client/src/entity_cl.cpp @@ -2539,7 +2539,7 @@ NLMISC::CRGBA CEntityCL::getColor () const if (isEnemy()) { if (getPvpMode()&PVP_MODE::PvpFaction) - return CRGBA::CRGBA(min(255, _PvpEnemyColor.R+150), min(255, _PvpEnemyColor.G+150), min(255, _PvpEnemyColor.B+150),_PvpEnemyColor.A); + return CRGBA(min(255, _PvpEnemyColor.R+150), min(255, _PvpEnemyColor.G+150), min(255, _PvpEnemyColor.B+150),_PvpEnemyColor.A); else return _PvpEnemyColor; } @@ -2551,8 +2551,8 @@ NLMISC::CRGBA CEntityCL::getColor () const if (getPvpMode() & PVP_MODE::PvpFactionFlagged) { if(isInSameLeague()) - return CRGBA::CRGBA(max(0, _PvpAllyColor.R-100), max(0, _PvpAllyColor.G-100), max(0, _PvpAllyColor.B-100),_PvpAllyColor.A); - return CRGBA::CRGBA(max(0, _PvpAllyInTeamColor.R-100), max(0, _PvpAllyInTeamColor.G-100), max(0, _PvpAllyInTeamColor.B-100),_PvpAllyInTeamColor.A); + return CRGBA(max(0, _PvpAllyColor.R-100), max(0, _PvpAllyColor.G-100), max(0, _PvpAllyColor.B-100),_PvpAllyColor.A); + return CRGBA(max(0, _PvpAllyInTeamColor.R-100), max(0, _PvpAllyInTeamColor.G-100), max(0, _PvpAllyInTeamColor.B-100),_PvpAllyInTeamColor.A); } else { @@ -2572,7 +2572,7 @@ NLMISC::CRGBA CEntityCL::getColor () const // neutral if (isInSameLeague()) - return CRGBA::CRGBA(min(255, _GroupColor.R+50), min(255, _GroupColor.G+50), min(255, _GroupColor.B+50),_GroupColor.A); + return CRGBA(min(255, _GroupColor.R+50), min(255, _GroupColor.G+50), min(255, _GroupColor.B+50),_GroupColor.A); if (isInSameGuild()) return _GuildColor; diff --git a/code/ryzom/client/src/interface_v3/chat_text_manager.cpp b/code/ryzom/client/src/interface_v3/chat_text_manager.cpp index d1488b4dd..9b5113a55 100644 --- a/code/ryzom/client/src/interface_v3/chat_text_manager.cpp +++ b/code/ryzom/client/src/interface_v3/chat_text_manager.cpp @@ -148,7 +148,7 @@ CViewBase *CChatTextManager::createMsgText(const ucstring &cstMsg, NLMISC::CRGBA vt->setMultiLineSpace(getTextMultiLineSpace()); vt->setModulateGlobalColor(false); - ucstring cur_time = ""; + ucstring cur_time; static CCDBNodeLeaf* node = CInterfaceManager::getInstance()->getDbProp("UI:SAVE:CHAT:SHOW_TIMES_IN_CHAT_CB", false); if (node) { diff --git a/code/ryzom/client/src/interface_v3/chat_window.cpp b/code/ryzom/client/src/interface_v3/chat_window.cpp index 773992fc3..18be552e9 100644 --- a/code/ryzom/client/src/interface_v3/chat_window.cpp +++ b/code/ryzom/client/src/interface_v3/chat_window.cpp @@ -473,7 +473,7 @@ void CChatWindow::displayLocalPlayerTell(const ucstring &receiver, const ucstrin prop.readRGBA("UI:SAVE:CHAT:COLORS:SPEAKER"," "); encodeColorTag(prop.getRGBA(), finalMsg, false); - ucstring csr = CHARACTER_TITLE::isCsrTitle(UserEntity->getTitleRaw()) ? "(CSR) " : ""; + ucstring csr(CHARACTER_TITLE::isCsrTitle(UserEntity->getTitleRaw()) ? "(CSR) " : ""); finalMsg += csr + CI18N::get("youTell") + ": "; prop.readRGBA("UI:SAVE:CHAT:COLORS:TELL"," "); encodeColorTag(prop.getRGBA(), finalMsg, true); diff --git a/code/ryzom/client/src/interface_v3/group_compas.cpp b/code/ryzom/client/src/interface_v3/group_compas.cpp index 0fa2b30e7..fa7655591 100644 --- a/code/ryzom/client/src/interface_v3/group_compas.cpp +++ b/code/ryzom/client/src/interface_v3/group_compas.cpp @@ -587,6 +587,12 @@ bool CGroupCompasMenu::parse(xmlNodePtr cur, CInterfaceGroup *parent /*=NULL*/) return true; } +// Helper for sorting landmarks +static inline bool UserLandMarksSortPredicate(const CUserLandMark& lm1, const CUserLandMark& lm2) +{ + return toLower(lm1.Title) < toLower(lm2.Title); +} + // *************************************************************************** // Called when we activate the compass menu void CGroupCompasMenu::setActive (bool state) @@ -803,6 +809,10 @@ void CGroupCompasMenu::setActive (bool state) } // User landmarks uint nbUserLandMarks = std::min( uint(currCont->UserLandMarks.size()), CContinent::getMaxNbUserLandMarks() ); + + // Sort the landmarks + std::sort(currCont->UserLandMarks.begin(), currCont->UserLandMarks.end(), UserLandMarksSortPredicate); + for(k = 0; k < nbUserLandMarks; ++k) { if (currCont->UserLandMarks[k].Type < CUserLandMark::UserLandMarkTypeCount) diff --git a/code/ryzom/client/src/interface_v3/group_html_webig.cpp b/code/ryzom/client/src/interface_v3/group_html_webig.cpp index e4a55ab48..0e17c47d3 100644 --- a/code/ryzom/client/src/interface_v3/group_html_webig.cpp +++ b/code/ryzom/client/src/interface_v3/group_html_webig.cpp @@ -74,6 +74,7 @@ void addWebIGParams (string &url, bool trustedDomain) string("shardid=") + toString(CharacterHomeSessionId) + string("&name=") + UserEntity->getLoginName().toUtf8() + string("&lang=") + CI18N::getCurrentLanguageCode() + + string("&datasetid=") + toString(UserEntity->dataSetId()) + string("&ig=1"); if (trustedDomain) { @@ -82,7 +83,6 @@ void addWebIGParams (string &url, bool trustedDomain) if (url.find('$') != string::npos) { - strFindReplace(url, "$datasetid$", toString(UserEntity->dataSetId())); strFindReplace(url, "$gender$", GSGENDER::toString(UserEntity->getGender())); strFindReplace(url, "$displayName$", UserEntity->getDisplayName().toString()); strFindReplace(url, "$posx$", toString(UserEntity->pos().x)); diff --git a/code/ryzom/client/src/interface_v3/lua_ihm.cpp b/code/ryzom/client/src/interface_v3/lua_ihm.cpp index 44e9a3ba7..08b128b66 100644 --- a/code/ryzom/client/src/interface_v3/lua_ihm.cpp +++ b/code/ryzom/client/src/interface_v3/lua_ihm.cpp @@ -1944,12 +1944,12 @@ static sint32 getTargetSlotNr() const char *dbPath = "UI:VARIABLES:TARGET:SLOT"; CInterfaceManager *im = CInterfaceManager::getInstance(); CCDBNodeLeaf *node = im->getDbProp(dbPath, false); - if (!node) return NULL; + if (!node) return 0; if ((uint8) node->getValue32() == (uint8) CLFECOMMON::INVALID_SLOT) { - return NULL; + return 0; } - return node->getValue32(); + return node->getValue32(); } // *************************************************************************** @@ -1963,13 +1963,13 @@ static CEntityCL *getTargetEntity() { return NULL; } - return EntitiesMngr.entity((uint) node->getValue32()); + return EntitiesMngr.entity((uint) node->getValue32()); } // *************************************************************************** static CEntityCL *getSlotEntity(uint slot) { - return EntitiesMngr.entity(slot); + return EntitiesMngr.entity(slot); } // *************************************************************************** @@ -2032,7 +2032,7 @@ sint32 CLuaIHM::getTargetLevel() ucstring CLuaIHM::getTargetSheet() { CEntityCL *target = getTargetEntity(); - if (!target) return ""; + if (!target) return ucstring(); return target->sheetId().toString(); } diff --git a/code/ryzom/client/src/interface_v3/people_list.cpp b/code/ryzom/client/src/interface_v3/people_list.cpp index c9b95a14a..395935aab 100644 --- a/code/ryzom/client/src/interface_v3/people_list.cpp +++ b/code/ryzom/client/src/interface_v3/people_list.cpp @@ -468,12 +468,12 @@ void CPeopleList::displayLocalPlayerTell(const ucstring &receiver, uint index, c return; } - ucstring csr = CHARACTER_TITLE::isCsrTitle(UserEntity->getTitleRaw()) ? "(CSR) " : ""; + ucstring csr(CHARACTER_TITLE::isCsrTitle(UserEntity->getTitleRaw()) ? "(CSR) " : ""); ucstring finalMsg = csr + CI18N::get("youTell") + ": " + msg; // display msg with good color CInterfaceProperty prop; prop.readRGBA("UI:SAVE:CHAT:COLORS:TELL"," "); - + ucstring s = CI18N::get("youTellPlayer"); strFindReplace(s, "%name", receiver); strFindReplace(finalMsg, CI18N::get("youTell"), s); @@ -935,7 +935,7 @@ class CHandlerContactEntry : public IActionHandler ucstring final; CChatWindow::encodeColorTag(prop.getRGBA(), final, false); - ucstring csr = CHARACTER_TITLE::isCsrTitle(UserEntity->getTitleRaw()) ? "(CSR) " : ""; + ucstring csr(CHARACTER_TITLE::isCsrTitle(UserEntity->getTitleRaw()) ? "(CSR) " : ""); final += csr + CI18N::get("youTell")+": "; prop.readRGBA("UI:SAVE:CHAT:COLORS:TELL"," "); CChatWindow::encodeColorTag(prop.getRGBA(), final, true); diff --git a/code/ryzom/client/src/string_manager_client.h b/code/ryzom/client/src/string_manager_client.h index e5842a9f6..13f8188bb 100644 --- a/code/ryzom/client/src/string_manager_client.h +++ b/code/ryzom/client/src/string_manager_client.h @@ -107,7 +107,7 @@ public: // Get the Localized Title name static const ucchar *getTitleLocalizedName(const std::string &titleId, bool women); - static std::vector CStringManagerClient::getTitleInfos(const std::string &titleId, bool women); + static std::vector getTitleInfos(const std::string &titleId, bool women); // Get the Localized name of a classification type static const ucchar *getClassificationTypeLocalizedName(EGSPD::CClassificationType::TClassificationType type); From 89e0ca326042348429ff8b30f6cfe9d71000ab3c Mon Sep 17 00:00:00 2001 From: kervala Date: Mon, 27 Feb 2012 23:48:36 +0100 Subject: [PATCH 41/46] Changed: #1433 Merge changes from patch 1.13 --- code/CMakeModules/nel.cmake | 6 +- code/nel/src/misc/events.cpp | 4 +- code/ryzom/client/client_default.cfg | 20 +- code/ryzom/client/client_default.cfg.in | 23 +- .../new_texture_interfaces_dxtc.tga | Bin 4194322 -> 4194322 bytes .../new_texture_interfaces_dxtc.txt | 1282 +++++++++-------- .../data/gamedev/interfaces_v3/commands.xml | 11 +- .../data/gamedev/interfaces_v3/config.xml | 65 +- .../gamedev/interfaces_v3/encyclopedia.xml | 2 +- .../gamedev/interfaces_v3/game_config.xml | 178 ++- .../data/gamedev/interfaces_v3/guild.xml | 53 +- .../gamedev/interfaces_v3/info_player.lua | 134 +- .../gamedev/interfaces_v3/info_player.xml | 278 +++- .../gamedev/interfaces_v3/interaction.xml | 28 +- .../data/gamedev/interfaces_v3/interface.txt | 1 + .../gamedev/interfaces_v3/out_v2_select.xml | 16 +- .../gamedev/interfaces_v3/out_v2_widgets.xml | 2 +- .../data/gamedev/interfaces_v3/player.lua | 41 +- .../data/gamedev/interfaces_v3/player.xml | 14 +- .../gamedev/interfaces_v3/player_trade.xml | 58 +- .../data/gamedev/interfaces_v3/reset.xml | 6 + .../interfaces_v3/texture_interfaces_v3.tga | Bin 2117952 -> 4194322 bytes .../data/gamedev/interfaces_v3/widgets.xml | 129 +- 23 files changed, 1478 insertions(+), 873 deletions(-) diff --git a/code/CMakeModules/nel.cmake b/code/CMakeModules/nel.cmake index 9314a7a85..7dd43e8b4 100644 --- a/code/CMakeModules/nel.cmake +++ b/code/CMakeModules/nel.cmake @@ -405,7 +405,7 @@ MACRO(NL_SETUP_BUILD) SET(NL_RELEASE_CFLAGS "/MD /D NDEBUG ${SPEED_OPTIMIZATIONS}") SET(NL_DEBUG_LINKFLAGS "/NODEFAULTLIB:msvcrt /INCREMENTAL:YES") SET(NL_RELEASE_LINKFLAGS "/OPT:REF /OPT:ICF /INCREMENTAL:NO") - ELSE(WIN32) + ELSE(MSVC) IF(HOST_CPU STREQUAL "x86_64" AND TARGET_CPU STREQUAL "x86") SET(PLATFORM_CFLAGS "${PLATFORM_CFLAGS} -m32 -march=i686") ENDIF(HOST_CPU STREQUAL "x86_64" AND TARGET_CPU STREQUAL "x86") @@ -414,7 +414,7 @@ MACRO(NL_SETUP_BUILD) SET(PLATFORM_CFLAGS "${PLATFORM_CFLAGS} -m64") ENDIF(HOST_CPU STREQUAL "x86" AND TARGET_CPU STREQUAL "x86_64") - SET(PLATFORM_CFLAGS "{PLATFORM_CFLAGS} -g -D_REENTRANT -pipe -ftemplate-depth-48 -Wall -ansi -W -Wpointer-arith -Wsign-compare -Wno-deprecated-declarations -Wno-multichar -Wno-unused -fno-strict-aliasing") + SET(PLATFORM_CFLAGS "${PLATFORM_CFLAGS} -g -D_REENTRANT -pipe -ftemplate-depth-48 -Wall -ansi -W -Wpointer-arith -Wsign-compare -Wno-deprecated-declarations -Wno-multichar -Wno-unused -fno-strict-aliasing") IF(WITH_COVERAGE) SET(PLATFORM_CFLAGS "-fprofile-arcs -ftest-coverage ${PLATFORM_CFLAGS}") @@ -437,7 +437,7 @@ MACRO(NL_SETUP_BUILD) SET(NL_DEBUG_CFLAGS "-DNL_DEBUG -D_DEBUG") SET(NL_RELEASE_CFLAGS "-DNL_RELEASE -DNDEBUG -O6") - ENDIF(WIN32) + ENDIF(MSVC) ENDMACRO(NL_SETUP_BUILD) MACRO(NL_SETUP_BUILD_FLAGS) diff --git a/code/nel/src/misc/events.cpp b/code/nel/src/misc/events.cpp index 4d0f996d5..7cef02f44 100644 --- a/code/nel/src/misc/events.cpp +++ b/code/nel/src/misc/events.cpp @@ -178,8 +178,8 @@ static const CStringConversion::CPair stringTable [] = { "KeyZOOM", KeyZOOM }, { "KeyNONAME", KeyNONAME }, { "KeyPA1", KeyPA1 }, - { "KeyOEM_CLEAR", KeyOEM_CLEAR }, -} + { "KeyOEM_CLEAR", KeyOEM_CLEAR } +}; static CStringConversion KeyConversion(stringTable, sizeof(stringTable) / sizeof(stringTable[0]), KeyCount); diff --git a/code/ryzom/client/client_default.cfg b/code/ryzom/client/client_default.cfg index 14885fa01..997699ca8 100644 --- a/code/ryzom/client/client_default.cfg +++ b/code/ryzom/client/client_default.cfg @@ -354,8 +354,8 @@ SystemInfoColors = // NEW System Info Categories "SYS", "255 255 255 255 normal", // Default system messages -"BC", "255 255 255 255 center", // Broadcast messages -"TAGBC", "255 255 255 255 center", // Taged broadcast messages : color should remain white as some word are tagged +"BC", "255 255 255 255 centeraround", // Broadcast messages +"TAGBC", "255 255 255 255 centeraround", // Taged broadcast messages : color should remain white as some word are tagged "XP", "255 255 64 255 over", // XP Gain "SP", "255 255 64 255 over", // SP Gain "TTL", "255 255 64 255 over", // Title @@ -443,23 +443,24 @@ R2EDReloadFiles = { XMLInterfaceFiles = { "config.xml", "widgets.xml", + "webig_widgets.xml", "player.xml", "inventory.xml", "interaction.xml", - "phrase.xml", + "phrase.xml", "harvest.xml", "macros.xml", "info_player.xml", "outpost.xml", "guild.xml", "taskbar.xml", - "game_config.xml", + "game_config.xml", "game_context_menu.xml", "player_trade.xml", "bot_chat_v4.xml", "compass.xml", "map.xml", - "hierarchy.xml", + "hierarchy.xml", "reset.xml", "actions.xml", "help.xml", @@ -559,6 +560,15 @@ HelpPages = "de=http://forums.ryzom.com/forum/showthread.php?t=29131" }; +WebIgMainDomain = "atys.ryzom.com"; + +WebIgTrustedDomains = +{ + "atys.ryzom.com" +}; + +PatchletUrl = "http://atys.ryzom.com/start/app_patchlet.php?patch=preload"; + SelectedSlot = 0; BuildName = "RELEASE_HEAD"; diff --git a/code/ryzom/client/client_default.cfg.in b/code/ryzom/client/client_default.cfg.in index 8ae0117a5..41c3dd1de 100644 --- a/code/ryzom/client/client_default.cfg.in +++ b/code/ryzom/client/client_default.cfg.in @@ -80,6 +80,9 @@ XMLOutGameInterfaceFiles = { "out_v2_keys.xml", }; +TexturesInterface = "texture_interfaces_v3"; +TexturesInterfaceDXTC = "texture_interfaces_dxtc"; + // The ligo primitive class file LigoPrimitiveClass = "world_editor_classes.xml"; @@ -352,8 +355,8 @@ SystemInfoColors = // NEW System Info Categories "SYS", "255 255 255 255 normal", // Default system messages -"BC", "255 255 255 255 center", // Broadcast messages -"TAGBC", "255 255 255 255 center", // Taged broadcast messages : color should remain white as some word are tagged +"BC", "255 255 255 255 centeraround", // Broadcast messages +"TAGBC", "255 255 255 255 centeraround", // Taged broadcast messages : color should remain white as some word are tagged "XP", "255 255 64 255 over", // XP Gain "SP", "255 255 64 255 over", // SP Gain "TTL", "255 255 64 255 over", // Title @@ -441,23 +444,24 @@ R2EDReloadFiles = { XMLInterfaceFiles = { "config.xml", "widgets.xml", + "webig_widgets.xml", "player.xml", "inventory.xml", "interaction.xml", - "phrase.xml", + "phrase.xml", "harvest.xml", "macros.xml", "info_player.xml", "outpost.xml", "guild.xml", "taskbar.xml", - "game_config.xml", + "game_config.xml", "game_context_menu.xml", "player_trade.xml", "bot_chat_v4.xml", "compass.xml", "map.xml", - "hierarchy.xml", + "hierarchy.xml", "reset.xml", "actions.xml", "help.xml", @@ -557,6 +561,15 @@ HelpPages = "de=http://forums.ryzom.com/forum/showthread.php?t=29131" }; +WebIgMainDomain = "atys.ryzom.com"; + +WebIgTrustedDomains = +{ + "atys.ryzom.com" +}; + +PatchletUrl = "http://atys.ryzom.com/start/app_patchlet.php?patch=preload"; + SelectedSlot = 0; BuildName = "RELEASE_HEAD"; diff --git a/code/ryzom/client/data/gamedev/adds/interfaces/new_texture_interfaces_dxtc.tga b/code/ryzom/client/data/gamedev/adds/interfaces/new_texture_interfaces_dxtc.tga index bbeeab27b137f23de2ef17354622069d33f7c77c..91e87e2e7ca33bf8fcad0846b7f2d90a0849095f 100644 GIT binary patch delta 75237 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 wOzxN4!CoHX0h+d&k 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
{Fb24wo2>~lVm~rbn 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 Jr8B}>{6B`FHJ$(f delta 55962 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 diff --git a/code/ryzom/client/data/gamedev/adds/interfaces/new_texture_interfaces_dxtc.txt b/code/ryzom/client/data/gamedev/adds/interfaces/new_texture_interfaces_dxtc.txt index ec1afb449..f35989e33 100644 --- a/code/ryzom/client/data/gamedev/adds/interfaces/new_texture_interfaces_dxtc.txt +++ b/code/ryzom/client/data/gamedev/adds/interfaces/new_texture_interfaces_dxtc.txt @@ -18,305 +18,305 @@ BK_goo.tga 0.156250000000 0.078125000000 0.195312500000 0.117187500000 bk_guild.tga 0.195312500000 0.078125000000 0.234375000000 0.117187500000 bk_horde.tga 0.000000000000 0.117187500000 0.039062500000 0.156250000000 bk_kami.tga 0.039062500000 0.117187500000 0.078125000000 0.156250000000 -bk_karavan.tga 0.078125000000 0.117187500000 0.117187500000 0.156250000000 -BK_matis.tga 0.117187500000 0.117187500000 0.156250000000 0.156250000000 -bk_mission.tga 0.156250000000 0.117187500000 0.195312500000 0.156250000000 -bk_mission2.tga 0.195312500000 0.117187500000 0.234375000000 0.156250000000 -BK_outpost.tga 0.000000000000 0.156250000000 0.039062500000 0.195312500000 -BK_primes.tga 0.039062500000 0.156250000000 0.078125000000 0.195312500000 -bk_service.tga 0.078125000000 0.156250000000 0.117187500000 0.195312500000 -bk_training.tga 0.117187500000 0.156250000000 0.156250000000 0.195312500000 -BK_tryker.tga 0.156250000000 0.156250000000 0.195312500000 0.195312500000 -BK_zorai.tga 0.195312500000 0.156250000000 0.234375000000 0.195312500000 -charge.tga 0.000000000000 0.195312500000 0.039062500000 0.234375000000 -clef.tga 0.039062500000 0.195312500000 0.078125000000 0.234375000000 -conso_branche.tga 0.078125000000 0.195312500000 0.117187500000 0.234375000000 -conso_branche_mask.tga 0.117187500000 0.195312500000 0.156250000000 0.234375000000 -conso_fleur.tga 0.156250000000 0.195312500000 0.195312500000 0.234375000000 -conso_fleur_mask.tga 0.195312500000 0.195312500000 0.234375000000 0.234375000000 -conso_grappe.tga 0.242187500000 0.000000000000 0.281250000000 0.039062500000 -conso_grappe_mask.tga 0.281250000000 0.000000000000 0.320312500000 0.039062500000 -conso_nectar.tga 0.320312500000 0.000000000000 0.359375000000 0.039062500000 -conso_nectar_mask.tga 0.359375000000 0.000000000000 0.398437500000 0.039062500000 -construction.tga 0.398437500000 0.000000000000 0.437500000000 0.039062500000 -cristal_ammo.tga 0.437500000000 0.000000000000 0.476562500000 0.039062500000 -cristal_spell.tga 0.238281250000 0.039062500000 0.277343750000 0.078125000000 -ge_mission_outpost_townhall.tga 0.277343750000 0.039062500000 0.316406250000 0.078125000000 -ico_amande.tga 0.316406250000 0.039062500000 0.355468750000 0.078125000000 -ico_cataliseur_xp.tga 0.355468750000 0.039062500000 0.394531250000 0.078125000000 -ico_consommable_over.tga 0.394531250000 0.039062500000 0.433593750000 0.078125000000 -ico_fleur_carac_1.tga 0.433593750000 0.039062500000 0.472656250000 0.078125000000 -ico_fleur_carac_1_mask.tga 0.234375000000 0.078125000000 0.273437500000 0.117187500000 -ico_fleur_carac_2.tga 0.273437500000 0.078125000000 0.312500000000 0.117187500000 -ico_fleur_carac_2_mask.tga 0.312500000000 0.078125000000 0.351562500000 0.117187500000 -ico_fleur_carac_3.tga 0.351562500000 0.078125000000 0.390625000000 0.117187500000 -ico_fleur_carac_3_mask.tga 0.390625000000 0.078125000000 0.429687500000 0.117187500000 -ico_foreuse.tga 0.429687500000 0.078125000000 0.468750000000 0.117187500000 -ico_haircolor.tga 0.234375000000 0.117187500000 0.273437500000 0.156250000000 -ico_haircut.tga 0.273437500000 0.117187500000 0.312500000000 0.156250000000 -ico_mission_art_fyros.tga 0.312500000000 0.117187500000 0.351562500000 0.156250000000 -ico_mission_art_matis.tga 0.351562500000 0.117187500000 0.390625000000 0.156250000000 -ico_mission_art_tryker.tga 0.390625000000 0.117187500000 0.429687500000 0.156250000000 -ico_mission_art_zorai.tga 0.429687500000 0.117187500000 0.468750000000 0.156250000000 -ico_mission_barrel.tga 0.234375000000 0.156250000000 0.273437500000 0.195312500000 -ico_mission_bottle.tga 0.273437500000 0.156250000000 0.312500000000 0.195312500000 -ico_mission_casket.tga 0.312500000000 0.156250000000 0.351562500000 0.195312500000 -ico_mission_medicine.tga 0.351562500000 0.156250000000 0.390625000000 0.195312500000 -ico_mission_message.tga 0.390625000000 0.156250000000 0.429687500000 0.195312500000 -ico_mission_package.tga 0.429687500000 0.156250000000 0.468750000000 0.195312500000 -ico_mission_pot.tga 0.234375000000 0.195312500000 0.273437500000 0.234375000000 -ico_mission_purse.tga 0.273437500000 0.195312500000 0.312500000000 0.234375000000 -ico_noix.tga 0.312500000000 0.195312500000 0.351562500000 0.234375000000 -ico_racine.tga 0.351562500000 0.195312500000 0.390625000000 0.234375000000 -ico_spores.tga 0.390625000000 0.195312500000 0.429687500000 0.234375000000 -ico_task_craft.tga 0.429687500000 0.195312500000 0.468750000000 0.234375000000 -ico_task_done.tga 0.000000000000 0.234375000000 0.039062500000 0.273437500000 -ico_task_failed.tga 0.039062500000 0.234375000000 0.078125000000 0.273437500000 -ico_task_fight.tga 0.078125000000 0.234375000000 0.117187500000 0.273437500000 -ico_task_forage.tga 0.117187500000 0.234375000000 0.156250000000 0.273437500000 -ico_task_generic.tga 0.156250000000 0.234375000000 0.195312500000 0.273437500000 -ico_task_generic_quart.tga 0.195312500000 0.234375000000 0.234375000000 0.273437500000 -ico_task_guild.tga 0.234375000000 0.234375000000 0.273437500000 0.273437500000 -ico_task_rite.tga 0.273437500000 0.234375000000 0.312500000000 0.273437500000 -ico_task_travel.tga 0.312500000000 0.234375000000 0.351562500000 0.273437500000 -ico_tatoo.tga 0.351562500000 0.234375000000 0.390625000000 0.273437500000 -ico_tourbe.tga 0.390625000000 0.234375000000 0.429687500000 0.273437500000 -improved_tool.tga 0.429687500000 0.234375000000 0.468750000000 0.273437500000 -item_default.tga 0.000000000000 0.273437500000 0.039062500000 0.312500000000 -item_plan_over.tga 0.039062500000 0.273437500000 0.078125000000 0.312500000000 -lucky_flower.tga 0.078125000000 0.273437500000 0.117187500000 0.312500000000 -mektoub_pack.tga 0.117187500000 0.273437500000 0.156250000000 0.312500000000 -mektoub_steed.tga 0.156250000000 0.273437500000 0.195312500000 0.312500000000 -mg_glove.tga 0.195312500000 0.273437500000 0.234375000000 0.312500000000 -mission_icon_0.tga 0.234375000000 0.273437500000 0.273437500000 0.312500000000 -mission_icon_1.tga 0.273437500000 0.273437500000 0.312500000000 0.312500000000 -mission_icon_2.tga 0.312500000000 0.273437500000 0.351562500000 0.312500000000 -mission_icon_3.tga 0.351562500000 0.273437500000 0.390625000000 0.312500000000 -mp_amber.tga 0.390625000000 0.273437500000 0.429687500000 0.312500000000 -mp_bark.tga 0.429687500000 0.273437500000 0.468750000000 0.312500000000 -mp_batiment_brique.tga 0.000000000000 0.312500000000 0.039062500000 0.351562500000 -mp_batiment_colonne.tga 0.039062500000 0.312500000000 0.078125000000 0.351562500000 -mp_batiment_colonne_justice.tga 0.078125000000 0.312500000000 0.117187500000 0.351562500000 -mp_batiment_comble.tga 0.117187500000 0.312500000000 0.156250000000 0.351562500000 -mp_batiment_noyau_maduk.tga 0.156250000000 0.312500000000 0.195312500000 0.351562500000 -mp_batiment_ornement.tga 0.195312500000 0.312500000000 0.234375000000 0.351562500000 -mp_batiment_revetement.tga 0.234375000000 0.312500000000 0.273437500000 0.351562500000 -mp_batiment_socle.tga 0.273437500000 0.312500000000 0.312500000000 0.351562500000 -mp_batiment_statue.tga 0.312500000000 0.312500000000 0.351562500000 0.351562500000 -mp_beak.tga 0.351562500000 0.312500000000 0.390625000000 0.351562500000 -mp_blood.tga 0.390625000000 0.312500000000 0.429687500000 0.351562500000 -mp_bone.tga 0.429687500000 0.312500000000 0.468750000000 0.351562500000 -mp_bud.tga 0.000000000000 0.351562500000 0.039062500000 0.390625000000 -mp_buterfly_blue.tga 0.039062500000 0.351562500000 0.078125000000 0.390625000000 -mp_buterfly_cocoon.tga 0.078125000000 0.351562500000 0.117187500000 0.390625000000 -mp_cereal.tga 0.117187500000 0.351562500000 0.156250000000 0.390625000000 -mp_claw.tga 0.156250000000 0.351562500000 0.195312500000 0.390625000000 -mp_dandelion.tga 0.195312500000 0.351562500000 0.234375000000 0.390625000000 -mp_dust.tga 0.234375000000 0.351562500000 0.273437500000 0.390625000000 -mp_egg.tga 0.273437500000 0.351562500000 0.312500000000 0.390625000000 -mp_eyes.tga 0.312500000000 0.351562500000 0.351562500000 0.390625000000 -mp_fang.tga 0.351562500000 0.351562500000 0.390625000000 0.390625000000 -mp_fiber.tga 0.390625000000 0.351562500000 0.429687500000 0.390625000000 -mp_filament.tga 0.429687500000 0.351562500000 0.468750000000 0.390625000000 -mp_firefly_abdomen.tga 0.000000000000 0.390625000000 0.039062500000 0.429687500000 -mp_fish_scale.tga 0.039062500000 0.390625000000 0.078125000000 0.429687500000 -mp_flowers.tga 0.078125000000 0.390625000000 0.117187500000 0.429687500000 -mp_fresh_loose_soil.tga 0.117187500000 0.390625000000 0.156250000000 0.429687500000 -mp_fruit.tga 0.156250000000 0.390625000000 0.195312500000 0.429687500000 -mp_generic.tga 0.195312500000 0.390625000000 0.234375000000 0.429687500000 -mp_generic_colorize.tga 0.234375000000 0.390625000000 0.273437500000 0.429687500000 -mp_gomme.tga 0.273437500000 0.390625000000 0.312500000000 0.429687500000 -mp_goo_residue.tga 0.312500000000 0.390625000000 0.351562500000 0.429687500000 -mp_hairs.tga 0.351562500000 0.390625000000 0.390625000000 0.429687500000 -mp_hoof.tga 0.390625000000 0.390625000000 0.429687500000 0.429687500000 -mp_horn.tga 0.429687500000 0.390625000000 0.468750000000 0.429687500000 -mp_horney.tga 0.000000000000 0.429687500000 0.039062500000 0.468750000000 -mp_insect_fossil.tga 0.039062500000 0.429687500000 0.078125000000 0.468750000000 -mp_kitinshell.tga 0.078125000000 0.429687500000 0.117187500000 0.468750000000 -mp_kitin_flesh.tga 0.117187500000 0.429687500000 0.156250000000 0.468750000000 -mp_kitin_secretion.tga 0.156250000000 0.429687500000 0.195312500000 0.468750000000 -mp_larva.tga 0.195312500000 0.429687500000 0.234375000000 0.468750000000 -mp_leaf.tga 0.234375000000 0.429687500000 0.273437500000 0.468750000000 -mp_leather.tga 0.273437500000 0.429687500000 0.312500000000 0.468750000000 -mp_liane.tga 0.312500000000 0.429687500000 0.351562500000 0.468750000000 -mp_lichen.tga 0.351562500000 0.429687500000 0.390625000000 0.468750000000 -mp_ligament.tga 0.390625000000 0.429687500000 0.429687500000 0.468750000000 -mp_mandible.tga 0.429687500000 0.429687500000 0.468750000000 0.468750000000 -mp_meat.tga 0.476562500000 0.000000000000 0.515625000000 0.039062500000 -mp_moss.tga 0.515625000000 0.000000000000 0.554687500000 0.039062500000 -mp_mushroom.tga 0.554687500000 0.000000000000 0.593750000000 0.039062500000 -mp_nail.tga 0.593750000000 0.000000000000 0.632812500000 0.039062500000 -mp_oil.tga 0.632812500000 0.000000000000 0.671875000000 0.039062500000 -mp_parasite.tga 0.671875000000 0.000000000000 0.710937500000 0.039062500000 -mp_pearl.tga 0.710937500000 0.000000000000 0.750000000000 0.039062500000 -mp_pelvis.tga 0.750000000000 0.000000000000 0.789062500000 0.039062500000 -mp_pigment.tga 0.789062500000 0.000000000000 0.828125000000 0.039062500000 -mp_pistil.tga 0.828125000000 0.000000000000 0.867187500000 0.039062500000 -mp_plant_fossil.tga 0.867187500000 0.000000000000 0.906250000000 0.039062500000 -mp_pollen.tga 0.906250000000 0.000000000000 0.945312500000 0.039062500000 -mp_resin.tga 0.945312500000 0.000000000000 0.984375000000 0.039062500000 -mp_ronce.tga 0.472656250000 0.039062500000 0.511718750000 0.078125000000 -mp_rostrum.tga 0.511718750000 0.039062500000 0.550781250000 0.078125000000 -mp_sap.tga 0.550781250000 0.039062500000 0.589843750000 0.078125000000 -mp_sawdust.tga 0.589843750000 0.039062500000 0.628906250000 0.078125000000 -mp_seed.tga 0.628906250000 0.039062500000 0.667968750000 0.078125000000 -mp_shell.tga 0.667968750000 0.039062500000 0.707031250000 0.078125000000 -mp_silk_worm.tga 0.707031250000 0.039062500000 0.746093750000 0.078125000000 -mp_skin.tga 0.746093750000 0.039062500000 0.785156250000 0.078125000000 -mp_skull.tga 0.785156250000 0.039062500000 0.824218750000 0.078125000000 -mp_spiders_web.tga 0.824218750000 0.039062500000 0.863281250000 0.078125000000 -mp_spine.tga 0.863281250000 0.039062500000 0.902343750000 0.078125000000 -mp_stem.tga 0.902343750000 0.039062500000 0.941406250000 0.078125000000 -mp_sting.tga 0.941406250000 0.039062500000 0.980468750000 0.078125000000 -mp_straw.tga 0.468750000000 0.078125000000 0.507812500000 0.117187500000 -mp_suc.tga 0.507812500000 0.078125000000 0.546875000000 0.117187500000 -mp_tail.tga 0.546875000000 0.078125000000 0.585937500000 0.117187500000 -mp_tooth.tga 0.585937500000 0.078125000000 0.625000000000 0.117187500000 -mp_trunk.tga 0.625000000000 0.078125000000 0.664062500000 0.117187500000 -mp_whiskers.tga 0.664062500000 0.078125000000 0.703125000000 0.117187500000 -mp_wing.tga 0.703125000000 0.078125000000 0.742187500000 0.117187500000 -mp_wood.tga 0.742187500000 0.078125000000 0.781250000000 0.117187500000 -mp_wood_node.tga 0.781250000000 0.078125000000 0.820312500000 0.117187500000 -MW_2h_axe.tga 0.820312500000 0.078125000000 0.859375000000 0.117187500000 -MW_2h_lance.tga 0.859375000000 0.078125000000 0.898437500000 0.117187500000 -MW_2h_mace.tga 0.898437500000 0.078125000000 0.937500000000 0.117187500000 -MW_2h_sword.tga 0.937500000000 0.078125000000 0.976562500000 0.117187500000 -MW_axe.tga 0.468750000000 0.117187500000 0.507812500000 0.156250000000 -MW_dagger.tga 0.507812500000 0.117187500000 0.546875000000 0.156250000000 -MW_lance.tga 0.546875000000 0.117187500000 0.585937500000 0.156250000000 -MW_mace.tga 0.585937500000 0.117187500000 0.625000000000 0.156250000000 -MW_staff.tga 0.625000000000 0.117187500000 0.664062500000 0.156250000000 -MW_sword.tga 0.664062500000 0.117187500000 0.703125000000 0.156250000000 -PA_anklet.tga 0.703125000000 0.117187500000 0.742187500000 0.156250000000 -PA_bracelet.tga 0.742187500000 0.117187500000 0.781250000000 0.156250000000 -PA_diadem.tga 0.781250000000 0.117187500000 0.820312500000 0.156250000000 -PA_earring.tga 0.820312500000 0.117187500000 0.859375000000 0.156250000000 -PA_pendant.tga 0.859375000000 0.117187500000 0.898437500000 0.156250000000 -PA_ring.tga 0.898437500000 0.117187500000 0.937500000000 0.156250000000 -protect_amber.tga 0.937500000000 0.117187500000 0.976562500000 0.156250000000 -pvp_aura.tga 0.468750000000 0.156250000000 0.507812500000 0.195312500000 -pvp_aura_mask.tga 0.507812500000 0.156250000000 0.546875000000 0.195312500000 -pvp_boost.tga 0.546875000000 0.156250000000 0.585937500000 0.195312500000 -pvp_boost_mask.tga 0.585937500000 0.156250000000 0.625000000000 0.195312500000 -pw_4.tga 0.625000000000 0.156250000000 0.664062500000 0.195312500000 -pw_5.tga 0.664062500000 0.156250000000 0.703125000000 0.195312500000 -pw_6.tga 0.703125000000 0.156250000000 0.742187500000 0.195312500000 -pw_7.tga 0.742187500000 0.156250000000 0.781250000000 0.195312500000 -PW_heavy.tga 0.781250000000 0.156250000000 0.820312500000 0.195312500000 -PW_light.tga 0.820312500000 0.156250000000 0.859375000000 0.195312500000 -PW_medium.tga 0.859375000000 0.156250000000 0.898437500000 0.195312500000 -quest_coeur.tga 0.898437500000 0.156250000000 0.937500000000 0.195312500000 -quest_foie.tga 0.937500000000 0.156250000000 0.976562500000 0.195312500000 -quest_jeton.tga 0.468750000000 0.195312500000 0.507812500000 0.234375000000 -quest_langue.tga 0.507812500000 0.195312500000 0.546875000000 0.234375000000 -quest_louche.tga 0.546875000000 0.195312500000 0.585937500000 0.234375000000 -quest_oreille.tga 0.585937500000 0.195312500000 0.625000000000 0.234375000000 -quest_patte.tga 0.625000000000 0.195312500000 0.664062500000 0.234375000000 -quest_poils.tga 0.664062500000 0.195312500000 0.703125000000 0.234375000000 -quest_queue.tga 0.703125000000 0.195312500000 0.742187500000 0.234375000000 -quest_ticket.tga 0.742187500000 0.195312500000 0.781250000000 0.234375000000 -AM_logo.tga 0.781250000000 0.195312500000 0.820312500000 0.234375000000 -AR_armpad.tga 0.820312500000 0.195312500000 0.859375000000 0.234375000000 -ar_armpad_mask.tga 0.859375000000 0.195312500000 0.898437500000 0.234375000000 -requirement.tga 0.898437500000 0.195312500000 0.937500000000 0.234375000000 -rm_f.tga 0.937500000000 0.195312500000 0.976562500000 0.234375000000 -rm_f_upgrade.tga 0.468750000000 0.234375000000 0.507812500000 0.273437500000 -rm_h.tga 0.507812500000 0.234375000000 0.546875000000 0.273437500000 -rm_h_upgrade.tga 0.546875000000 0.234375000000 0.585937500000 0.273437500000 -rm_m.tga 0.585937500000 0.234375000000 0.625000000000 0.273437500000 -rm_m_upgrade.tga 0.625000000000 0.234375000000 0.664062500000 0.273437500000 -rm_r.tga 0.664062500000 0.234375000000 0.703125000000 0.273437500000 -rm_r_upgrade.tga 0.703125000000 0.234375000000 0.742187500000 0.273437500000 -rpjobitem_200_a.tga 0.742187500000 0.234375000000 0.781250000000 0.273437500000 -rpjobitem_200_b.tga 0.781250000000 0.234375000000 0.820312500000 0.273437500000 -rpjobitem_200_c.tga 0.820312500000 0.234375000000 0.859375000000 0.273437500000 -rpjobitem_201_a.tga 0.859375000000 0.234375000000 0.898437500000 0.273437500000 -rpjobitem_201_b.tga 0.898437500000 0.234375000000 0.937500000000 0.273437500000 -rpjobitem_201_c.tga 0.937500000000 0.234375000000 0.976562500000 0.273437500000 -rpjobitem_202_a.tga 0.468750000000 0.273437500000 0.507812500000 0.312500000000 -rpjobitem_202_b.tga 0.507812500000 0.273437500000 0.546875000000 0.312500000000 -rpjobitem_202_c.tga 0.546875000000 0.273437500000 0.585937500000 0.312500000000 -rpjobitem_203_a.tga 0.585937500000 0.273437500000 0.625000000000 0.312500000000 -rpjobitem_203_b.tga 0.625000000000 0.273437500000 0.664062500000 0.312500000000 -rpjobitem_203_c.tga 0.664062500000 0.273437500000 0.703125000000 0.312500000000 -rpjobitem_204_a.tga 0.703125000000 0.273437500000 0.742187500000 0.312500000000 -rpjobitem_204_b.tga 0.742187500000 0.273437500000 0.781250000000 0.312500000000 -rpjobitem_204_c.tga 0.781250000000 0.273437500000 0.820312500000 0.312500000000 -rpjobitem_205_a.tga 0.820312500000 0.273437500000 0.859375000000 0.312500000000 -rpjobitem_205_b.tga 0.859375000000 0.273437500000 0.898437500000 0.312500000000 -rpjobitem_205_c.tga 0.898437500000 0.273437500000 0.937500000000 0.312500000000 -rpjobitem_206_a.tga 0.937500000000 0.273437500000 0.976562500000 0.312500000000 -rpjobitem_206_b.tga 0.468750000000 0.312500000000 0.507812500000 0.351562500000 -rpjobitem_206_c.tga 0.507812500000 0.312500000000 0.546875000000 0.351562500000 -rpjobitem_207_a.tga 0.546875000000 0.312500000000 0.585937500000 0.351562500000 -rpjobitem_207_b.tga 0.585937500000 0.312500000000 0.625000000000 0.351562500000 -rpjobitem_207_c.tga 0.625000000000 0.312500000000 0.664062500000 0.351562500000 -rpjobitem_certifications.tga 0.664062500000 0.312500000000 0.703125000000 0.351562500000 -rpjob_200.tga 0.703125000000 0.312500000000 0.742187500000 0.351562500000 -rpjob_201.tga 0.742187500000 0.312500000000 0.781250000000 0.351562500000 -rpjob_202.tga 0.781250000000 0.312500000000 0.820312500000 0.351562500000 -rpjob_203.tga 0.820312500000 0.312500000000 0.859375000000 0.351562500000 -rpjob_204.tga 0.859375000000 0.312500000000 0.898437500000 0.351562500000 -rpjob_205.tga 0.898437500000 0.312500000000 0.937500000000 0.351562500000 -rpjob_206.tga 0.937500000000 0.312500000000 0.976562500000 0.351562500000 -rpjob_207.tga 0.468750000000 0.351562500000 0.507812500000 0.390625000000 -rpjob_advanced.tga 0.507812500000 0.351562500000 0.546875000000 0.390625000000 -rpjob_elementary.tga 0.546875000000 0.351562500000 0.585937500000 0.390625000000 -rpjob_roleplay.tga 0.585937500000 0.351562500000 0.625000000000 0.390625000000 -rpjob_task.tga 0.625000000000 0.351562500000 0.664062500000 0.390625000000 -rpjob_task_certificats.tga 0.664062500000 0.351562500000 0.703125000000 0.390625000000 -rpjob_task_convert.tga 0.703125000000 0.351562500000 0.742187500000 0.390625000000 -rpjob_task_elementary.tga 0.742187500000 0.351562500000 0.781250000000 0.390625000000 -rpjob_task_generic.tga 0.781250000000 0.351562500000 0.820312500000 0.390625000000 -rpjob_task_upgrade.tga 0.820312500000 0.351562500000 0.859375000000 0.390625000000 -RW_autolaunch.tga 0.859375000000 0.351562500000 0.898437500000 0.390625000000 -RW_bowgun.tga 0.898437500000 0.351562500000 0.937500000000 0.390625000000 -RW_grenade.tga 0.937500000000 0.351562500000 0.976562500000 0.390625000000 -RW_harpoongun.tga 0.468750000000 0.390625000000 0.507812500000 0.429687500000 -RW_launcher.tga 0.507812500000 0.390625000000 0.546875000000 0.429687500000 -RW_pistol.tga 0.546875000000 0.390625000000 0.585937500000 0.429687500000 -RW_pistolarc.tga 0.585937500000 0.390625000000 0.625000000000 0.429687500000 -RW_rifle.tga 0.625000000000 0.390625000000 0.664062500000 0.429687500000 -SH_buckler.tga 0.664062500000 0.390625000000 0.703125000000 0.429687500000 -SH_large_shield.tga 0.703125000000 0.390625000000 0.742187500000 0.429687500000 -spe_beast.tga 0.742187500000 0.390625000000 0.781250000000 0.429687500000 -spe_com.tga 0.781250000000 0.390625000000 0.820312500000 0.429687500000 -spe_inventory.tga 0.820312500000 0.390625000000 0.859375000000 0.429687500000 -spe_labs.tga 0.859375000000 0.390625000000 0.898437500000 0.429687500000 -spe_memory.tga 0.898437500000 0.390625000000 0.937500000000 0.429687500000 -spe_options.tga 0.937500000000 0.390625000000 0.976562500000 0.429687500000 -spe_status.tga 0.468750000000 0.429687500000 0.507812500000 0.468750000000 -stimulating_water.tga 0.507812500000 0.429687500000 0.546875000000 0.468750000000 -tetekitin.tga 0.546875000000 0.429687500000 0.585937500000 0.468750000000 -to_ammo.tga 0.585937500000 0.429687500000 0.625000000000 0.468750000000 -to_armor.tga 0.625000000000 0.429687500000 0.664062500000 0.468750000000 -to_cooking_pot.tga 0.664062500000 0.429687500000 0.703125000000 0.468750000000 -to_fishing_rod.tga 0.703125000000 0.429687500000 0.742187500000 0.468750000000 -to_forage.tga 0.742187500000 0.429687500000 0.781250000000 0.468750000000 -to_hammer.tga 0.781250000000 0.429687500000 0.820312500000 0.468750000000 -to_jewelry_hammer.tga 0.820312500000 0.429687500000 0.859375000000 0.468750000000 -to_jewels.tga 0.859375000000 0.429687500000 0.898437500000 0.468750000000 -to_leathercutter.tga 0.898437500000 0.429687500000 0.937500000000 0.468750000000 -to_melee.tga 0.937500000000 0.429687500000 0.976562500000 0.468750000000 -to_needle.tga 0.000000000000 0.468750000000 0.039062500000 0.507812500000 -to_pestle.tga 0.039062500000 0.468750000000 0.078125000000 0.507812500000 -to_range.tga 0.078125000000 0.468750000000 0.117187500000 0.507812500000 -to_searake.tga 0.117187500000 0.468750000000 0.156250000000 0.507812500000 -to_spade.tga 0.156250000000 0.468750000000 0.195312500000 0.507812500000 -to_stick.tga 0.195312500000 0.468750000000 0.234375000000 0.507812500000 -to_tunneling_knife.tga 0.234375000000 0.468750000000 0.273437500000 0.507812500000 -to_whip.tga 0.273437500000 0.468750000000 0.312500000000 0.507812500000 -to_wrench.tga 0.312500000000 0.468750000000 0.351562500000 0.507812500000 -TP_caravane.tga 0.351562500000 0.468750000000 0.390625000000 0.507812500000 -TP_kami.tga 0.390625000000 0.468750000000 0.429687500000 0.507812500000 -W_AM_logo.tga 0.429687500000 0.468750000000 0.468750000000 0.507812500000 -w_pa_anklet.tga 0.468750000000 0.468750000000 0.507812500000 0.507812500000 -w_pa_bracelet.tga 0.507812500000 0.468750000000 0.546875000000 0.507812500000 -w_pa_diadem.tga 0.546875000000 0.468750000000 0.585937500000 0.507812500000 -w_pa_earring.tga 0.585937500000 0.468750000000 0.625000000000 0.507812500000 -w_pa_pendant.tga 0.625000000000 0.468750000000 0.664062500000 0.507812500000 -w_pa_ring.tga 0.664062500000 0.468750000000 0.703125000000 0.507812500000 -xp_cat_green.tga 0.703125000000 0.468750000000 0.742187500000 0.507812500000 +BK_matis.tga 0.078125000000 0.117187500000 0.117187500000 0.156250000000 +bk_mission.tga 0.117187500000 0.117187500000 0.156250000000 0.156250000000 +bk_mission2.tga 0.156250000000 0.117187500000 0.195312500000 0.156250000000 +BK_outpost.tga 0.195312500000 0.117187500000 0.234375000000 0.156250000000 +BK_primes.tga 0.000000000000 0.156250000000 0.039062500000 0.195312500000 +bk_service.tga 0.039062500000 0.156250000000 0.078125000000 0.195312500000 +bk_training.tga 0.078125000000 0.156250000000 0.117187500000 0.195312500000 +BK_tryker.tga 0.117187500000 0.156250000000 0.156250000000 0.195312500000 +BK_zorai.tga 0.156250000000 0.156250000000 0.195312500000 0.195312500000 +charge.tga 0.195312500000 0.156250000000 0.234375000000 0.195312500000 +clef.tga 0.000000000000 0.195312500000 0.039062500000 0.234375000000 +conso_branche.tga 0.039062500000 0.195312500000 0.078125000000 0.234375000000 +conso_branche_mask.tga 0.078125000000 0.195312500000 0.117187500000 0.234375000000 +conso_fleur.tga 0.117187500000 0.195312500000 0.156250000000 0.234375000000 +conso_fleur_mask.tga 0.156250000000 0.195312500000 0.195312500000 0.234375000000 +conso_grappe.tga 0.195312500000 0.195312500000 0.234375000000 0.234375000000 +conso_nectar.tga 0.242187500000 0.000000000000 0.281250000000 0.039062500000 +conso_nectar_mask.tga 0.281250000000 0.000000000000 0.320312500000 0.039062500000 +construction.tga 0.320312500000 0.000000000000 0.359375000000 0.039062500000 +cristal_ammo.tga 0.359375000000 0.000000000000 0.398437500000 0.039062500000 +cristal_spell.tga 0.398437500000 0.000000000000 0.437500000000 0.039062500000 +ico_haircolor.tga 0.437500000000 0.000000000000 0.476562500000 0.039062500000 +ico_haircut.tga 0.238281250000 0.039062500000 0.277343750000 0.078125000000 +bk_karavan.tga 0.277343750000 0.039062500000 0.316406250000 0.078125000000 +conso_grappe_mask.tga 0.316406250000 0.039062500000 0.355468750000 0.078125000000 +ico_foreuse.tga 0.355468750000 0.039062500000 0.394531250000 0.078125000000 +ico_noix.tga 0.394531250000 0.039062500000 0.433593750000 0.078125000000 +ico_spores.tga 0.433593750000 0.039062500000 0.472656250000 0.078125000000 +mektoub_pack.tga 0.234375000000 0.078125000000 0.273437500000 0.117187500000 +mp_beak.tga 0.273437500000 0.078125000000 0.312500000000 0.117187500000 +mp_fresh_loose_soil.tga 0.312500000000 0.078125000000 0.351562500000 0.117187500000 +mp_lichen.tga 0.351562500000 0.078125000000 0.390625000000 0.117187500000 +mp_sawdust.tga 0.390625000000 0.078125000000 0.429687500000 0.117187500000 +MW_2h_axe.tga 0.429687500000 0.078125000000 0.468750000000 0.117187500000 +PA_bracelet.tga 0.234375000000 0.117187500000 0.273437500000 0.156250000000 +pvp_aura_mask.tga 0.273437500000 0.117187500000 0.312500000000 0.156250000000 +quest_queue.tga 0.312500000000 0.117187500000 0.351562500000 0.156250000000 +rpjobitem_201_b.tga 0.351562500000 0.117187500000 0.390625000000 0.156250000000 +rpjobitem_207_a.tga 0.390625000000 0.117187500000 0.429687500000 0.156250000000 +rpjob_task_elementary.tga 0.429687500000 0.117187500000 0.468750000000 0.156250000000 +spe_options.tga 0.234375000000 0.156250000000 0.273437500000 0.195312500000 +to_range.tga 0.273437500000 0.156250000000 0.312500000000 0.195312500000 +w_pa_anklet.tga 0.312500000000 0.156250000000 0.351562500000 0.195312500000 +ico_task_craft.tga 0.351562500000 0.156250000000 0.390625000000 0.195312500000 +ico_task_done.tga 0.390625000000 0.156250000000 0.429687500000 0.195312500000 +ico_task_failed.tga 0.429687500000 0.156250000000 0.468750000000 0.195312500000 +ico_task_fight.tga 0.234375000000 0.195312500000 0.273437500000 0.234375000000 +ico_task_forage.tga 0.273437500000 0.195312500000 0.312500000000 0.234375000000 +ico_task_generic.tga 0.312500000000 0.195312500000 0.351562500000 0.234375000000 +ico_task_generic_quart.tga 0.351562500000 0.195312500000 0.390625000000 0.234375000000 +ico_task_guild.tga 0.390625000000 0.195312500000 0.429687500000 0.234375000000 +ico_task_rite.tga 0.429687500000 0.195312500000 0.468750000000 0.234375000000 +ico_task_travel.tga 0.000000000000 0.234375000000 0.039062500000 0.273437500000 +ico_tatoo.tga 0.039062500000 0.234375000000 0.078125000000 0.273437500000 +mektoub_steed.tga 0.078125000000 0.234375000000 0.117187500000 0.273437500000 +mg_glove.tga 0.117187500000 0.234375000000 0.156250000000 0.273437500000 +mission_icon_0.tga 0.156250000000 0.234375000000 0.195312500000 0.273437500000 +mission_icon_1.tga 0.195312500000 0.234375000000 0.234375000000 0.273437500000 +mission_icon_2.tga 0.234375000000 0.234375000000 0.273437500000 0.273437500000 +mission_icon_3.tga 0.273437500000 0.234375000000 0.312500000000 0.273437500000 +mp_amber.tga 0.312500000000 0.234375000000 0.351562500000 0.273437500000 +mp_bark.tga 0.351562500000 0.234375000000 0.390625000000 0.273437500000 +mp_batiment_brique.tga 0.390625000000 0.234375000000 0.429687500000 0.273437500000 +mp_batiment_colonne.tga 0.429687500000 0.234375000000 0.468750000000 0.273437500000 +mp_batiment_colonne_justice.tga 0.000000000000 0.273437500000 0.039062500000 0.312500000000 +mp_batiment_comble.tga 0.039062500000 0.273437500000 0.078125000000 0.312500000000 +mp_batiment_noyau_maduk.tga 0.078125000000 0.273437500000 0.117187500000 0.312500000000 +mp_batiment_ornement.tga 0.117187500000 0.273437500000 0.156250000000 0.312500000000 +mp_batiment_revetement.tga 0.156250000000 0.273437500000 0.195312500000 0.312500000000 +mp_batiment_socle.tga 0.195312500000 0.273437500000 0.234375000000 0.312500000000 +mp_batiment_statue.tga 0.234375000000 0.273437500000 0.273437500000 0.312500000000 +mp_blood.tga 0.273437500000 0.273437500000 0.312500000000 0.312500000000 +mp_bone.tga 0.312500000000 0.273437500000 0.351562500000 0.312500000000 +mp_bud.tga 0.351562500000 0.273437500000 0.390625000000 0.312500000000 +mp_buterfly_blue.tga 0.390625000000 0.273437500000 0.429687500000 0.312500000000 +mp_buterfly_cocoon.tga 0.429687500000 0.273437500000 0.468750000000 0.312500000000 +mp_cereal.tga 0.000000000000 0.312500000000 0.039062500000 0.351562500000 +mp_claw.tga 0.039062500000 0.312500000000 0.078125000000 0.351562500000 +mp_dandelion.tga 0.078125000000 0.312500000000 0.117187500000 0.351562500000 +mp_dust.tga 0.117187500000 0.312500000000 0.156250000000 0.351562500000 +mp_egg.tga 0.156250000000 0.312500000000 0.195312500000 0.351562500000 +mp_eyes.tga 0.195312500000 0.312500000000 0.234375000000 0.351562500000 +mp_fang.tga 0.234375000000 0.312500000000 0.273437500000 0.351562500000 +mp_fiber.tga 0.273437500000 0.312500000000 0.312500000000 0.351562500000 +mp_filament.tga 0.312500000000 0.312500000000 0.351562500000 0.351562500000 +mp_firefly_abdomen.tga 0.351562500000 0.312500000000 0.390625000000 0.351562500000 +mp_fish_scale.tga 0.390625000000 0.312500000000 0.429687500000 0.351562500000 +mp_flowers.tga 0.429687500000 0.312500000000 0.468750000000 0.351562500000 +mp_fruit.tga 0.000000000000 0.351562500000 0.039062500000 0.390625000000 +mp_generic.tga 0.039062500000 0.351562500000 0.078125000000 0.390625000000 +mp_generic_colorize.tga 0.078125000000 0.351562500000 0.117187500000 0.390625000000 +mp_gomme.tga 0.117187500000 0.351562500000 0.156250000000 0.390625000000 +mp_goo_residue.tga 0.156250000000 0.351562500000 0.195312500000 0.390625000000 +mp_hairs.tga 0.195312500000 0.351562500000 0.234375000000 0.390625000000 +mp_hoof.tga 0.234375000000 0.351562500000 0.273437500000 0.390625000000 +mp_horn.tga 0.273437500000 0.351562500000 0.312500000000 0.390625000000 +mp_horney.tga 0.312500000000 0.351562500000 0.351562500000 0.390625000000 +mp_insect_fossil.tga 0.351562500000 0.351562500000 0.390625000000 0.390625000000 +mp_kitinshell.tga 0.390625000000 0.351562500000 0.429687500000 0.390625000000 +mp_kitin_flesh.tga 0.429687500000 0.351562500000 0.468750000000 0.390625000000 +mp_kitin_secretion.tga 0.000000000000 0.390625000000 0.039062500000 0.429687500000 +mp_larva.tga 0.039062500000 0.390625000000 0.078125000000 0.429687500000 +mp_leaf.tga 0.078125000000 0.390625000000 0.117187500000 0.429687500000 +mp_leather.tga 0.117187500000 0.390625000000 0.156250000000 0.429687500000 +mp_liane.tga 0.156250000000 0.390625000000 0.195312500000 0.429687500000 +mp_ligament.tga 0.195312500000 0.390625000000 0.234375000000 0.429687500000 +mp_mandible.tga 0.234375000000 0.390625000000 0.273437500000 0.429687500000 +mp_meat.tga 0.273437500000 0.390625000000 0.312500000000 0.429687500000 +mp_moss.tga 0.312500000000 0.390625000000 0.351562500000 0.429687500000 +mp_mushroom.tga 0.351562500000 0.390625000000 0.390625000000 0.429687500000 +mp_nail.tga 0.390625000000 0.390625000000 0.429687500000 0.429687500000 +mp_oil.tga 0.429687500000 0.390625000000 0.468750000000 0.429687500000 +mp_parasite.tga 0.000000000000 0.429687500000 0.039062500000 0.468750000000 +mp_pearl.tga 0.039062500000 0.429687500000 0.078125000000 0.468750000000 +mp_pelvis.tga 0.078125000000 0.429687500000 0.117187500000 0.468750000000 +mp_pigment.tga 0.117187500000 0.429687500000 0.156250000000 0.468750000000 +mp_pistil.tga 0.156250000000 0.429687500000 0.195312500000 0.468750000000 +mp_plant_fossil.tga 0.195312500000 0.429687500000 0.234375000000 0.468750000000 +mp_pollen.tga 0.234375000000 0.429687500000 0.273437500000 0.468750000000 +mp_resin.tga 0.273437500000 0.429687500000 0.312500000000 0.468750000000 +mp_ronce.tga 0.312500000000 0.429687500000 0.351562500000 0.468750000000 +mp_rostrum.tga 0.351562500000 0.429687500000 0.390625000000 0.468750000000 +mp_sap.tga 0.390625000000 0.429687500000 0.429687500000 0.468750000000 +mp_seed.tga 0.429687500000 0.429687500000 0.468750000000 0.468750000000 +mp_shell.tga 0.476562500000 0.000000000000 0.515625000000 0.039062500000 +mp_silk_worm.tga 0.515625000000 0.000000000000 0.554687500000 0.039062500000 +mp_skin.tga 0.554687500000 0.000000000000 0.593750000000 0.039062500000 +mp_skull.tga 0.593750000000 0.000000000000 0.632812500000 0.039062500000 +mp_spiders_web.tga 0.632812500000 0.000000000000 0.671875000000 0.039062500000 +mp_spine.tga 0.671875000000 0.000000000000 0.710937500000 0.039062500000 +mp_stem.tga 0.710937500000 0.000000000000 0.750000000000 0.039062500000 +mp_sting.tga 0.750000000000 0.000000000000 0.789062500000 0.039062500000 +mp_straw.tga 0.789062500000 0.000000000000 0.828125000000 0.039062500000 +mp_suc.tga 0.828125000000 0.000000000000 0.867187500000 0.039062500000 +mp_tail.tga 0.867187500000 0.000000000000 0.906250000000 0.039062500000 +mp_tooth.tga 0.906250000000 0.000000000000 0.945312500000 0.039062500000 +mp_trunk.tga 0.945312500000 0.000000000000 0.984375000000 0.039062500000 +mp_whiskers.tga 0.472656250000 0.039062500000 0.511718750000 0.078125000000 +mp_wing.tga 0.511718750000 0.039062500000 0.550781250000 0.078125000000 +mp_wood.tga 0.550781250000 0.039062500000 0.589843750000 0.078125000000 +mp_wood_node.tga 0.589843750000 0.039062500000 0.628906250000 0.078125000000 +MW_2h_lance.tga 0.628906250000 0.039062500000 0.667968750000 0.078125000000 +MW_2h_mace.tga 0.667968750000 0.039062500000 0.707031250000 0.078125000000 +MW_2h_sword.tga 0.707031250000 0.039062500000 0.746093750000 0.078125000000 +MW_axe.tga 0.746093750000 0.039062500000 0.785156250000 0.078125000000 +MW_dagger.tga 0.785156250000 0.039062500000 0.824218750000 0.078125000000 +MW_lance.tga 0.824218750000 0.039062500000 0.863281250000 0.078125000000 +MW_mace.tga 0.863281250000 0.039062500000 0.902343750000 0.078125000000 +MW_staff.tga 0.902343750000 0.039062500000 0.941406250000 0.078125000000 +MW_sword.tga 0.941406250000 0.039062500000 0.980468750000 0.078125000000 +PA_anklet.tga 0.468750000000 0.078125000000 0.507812500000 0.117187500000 +pvp_boost.tga 0.507812500000 0.078125000000 0.546875000000 0.117187500000 +pvp_boost_mask.tga 0.546875000000 0.078125000000 0.585937500000 0.117187500000 +pw_4.tga 0.585937500000 0.078125000000 0.625000000000 0.117187500000 +pw_5.tga 0.625000000000 0.078125000000 0.664062500000 0.117187500000 +pw_6.tga 0.664062500000 0.078125000000 0.703125000000 0.117187500000 +pw_7.tga 0.703125000000 0.078125000000 0.742187500000 0.117187500000 +PW_heavy.tga 0.742187500000 0.078125000000 0.781250000000 0.117187500000 +PW_light.tga 0.781250000000 0.078125000000 0.820312500000 0.117187500000 +PW_medium.tga 0.820312500000 0.078125000000 0.859375000000 0.117187500000 +quest_coeur.tga 0.859375000000 0.078125000000 0.898437500000 0.117187500000 +quest_foie.tga 0.898437500000 0.078125000000 0.937500000000 0.117187500000 +quest_jeton.tga 0.937500000000 0.078125000000 0.976562500000 0.117187500000 +quest_langue.tga 0.468750000000 0.117187500000 0.507812500000 0.156250000000 +quest_louche.tga 0.507812500000 0.117187500000 0.546875000000 0.156250000000 +quest_oreille.tga 0.546875000000 0.117187500000 0.585937500000 0.156250000000 +quest_patte.tga 0.585937500000 0.117187500000 0.625000000000 0.156250000000 +quest_poils.tga 0.625000000000 0.117187500000 0.664062500000 0.156250000000 +quest_ticket.tga 0.664062500000 0.117187500000 0.703125000000 0.156250000000 +AM_logo.tga 0.703125000000 0.117187500000 0.742187500000 0.156250000000 +AR_armpad.tga 0.742187500000 0.117187500000 0.781250000000 0.156250000000 +ar_armpad_mask.tga 0.781250000000 0.117187500000 0.820312500000 0.156250000000 +requirement.tga 0.820312500000 0.117187500000 0.859375000000 0.156250000000 +rm_f.tga 0.859375000000 0.117187500000 0.898437500000 0.156250000000 +rm_f_upgrade.tga 0.898437500000 0.117187500000 0.937500000000 0.156250000000 +rm_h.tga 0.937500000000 0.117187500000 0.976562500000 0.156250000000 +rm_h_upgrade.tga 0.468750000000 0.156250000000 0.507812500000 0.195312500000 +rm_m.tga 0.507812500000 0.156250000000 0.546875000000 0.195312500000 +rm_m_upgrade.tga 0.546875000000 0.156250000000 0.585937500000 0.195312500000 +rm_r.tga 0.585937500000 0.156250000000 0.625000000000 0.195312500000 +rm_r_upgrade.tga 0.625000000000 0.156250000000 0.664062500000 0.195312500000 +rpjobitem_200_a.tga 0.664062500000 0.156250000000 0.703125000000 0.195312500000 +rpjobitem_200_b.tga 0.703125000000 0.156250000000 0.742187500000 0.195312500000 +rpjobitem_200_c.tga 0.742187500000 0.156250000000 0.781250000000 0.195312500000 +rpjobitem_201_a.tga 0.781250000000 0.156250000000 0.820312500000 0.195312500000 +rpjobitem_201_c.tga 0.820312500000 0.156250000000 0.859375000000 0.195312500000 +rpjobitem_202_a.tga 0.859375000000 0.156250000000 0.898437500000 0.195312500000 +rpjobitem_202_b.tga 0.898437500000 0.156250000000 0.937500000000 0.195312500000 +rpjobitem_202_c.tga 0.937500000000 0.156250000000 0.976562500000 0.195312500000 +rpjobitem_203_a.tga 0.468750000000 0.195312500000 0.507812500000 0.234375000000 +rpjobitem_203_b.tga 0.507812500000 0.195312500000 0.546875000000 0.234375000000 +rpjobitem_203_c.tga 0.546875000000 0.195312500000 0.585937500000 0.234375000000 +rpjobitem_204_a.tga 0.585937500000 0.195312500000 0.625000000000 0.234375000000 +rpjobitem_204_b.tga 0.625000000000 0.195312500000 0.664062500000 0.234375000000 +rpjobitem_204_c.tga 0.664062500000 0.195312500000 0.703125000000 0.234375000000 +rpjobitem_205_a.tga 0.703125000000 0.195312500000 0.742187500000 0.234375000000 +rpjobitem_205_b.tga 0.742187500000 0.195312500000 0.781250000000 0.234375000000 +rpjobitem_205_c.tga 0.781250000000 0.195312500000 0.820312500000 0.234375000000 +rpjobitem_206_a.tga 0.820312500000 0.195312500000 0.859375000000 0.234375000000 +rpjobitem_206_b.tga 0.859375000000 0.195312500000 0.898437500000 0.234375000000 +rpjobitem_206_c.tga 0.898437500000 0.195312500000 0.937500000000 0.234375000000 +rpjobitem_207_b.tga 0.937500000000 0.195312500000 0.976562500000 0.234375000000 +rpjobitem_207_c.tga 0.468750000000 0.234375000000 0.507812500000 0.273437500000 +rpjobitem_certifications.tga 0.507812500000 0.234375000000 0.546875000000 0.273437500000 +rpjob_200.tga 0.546875000000 0.234375000000 0.585937500000 0.273437500000 +rpjob_201.tga 0.585937500000 0.234375000000 0.625000000000 0.273437500000 +rpjob_202.tga 0.625000000000 0.234375000000 0.664062500000 0.273437500000 +rpjob_203.tga 0.664062500000 0.234375000000 0.703125000000 0.273437500000 +rpjob_204.tga 0.703125000000 0.234375000000 0.742187500000 0.273437500000 +rpjob_205.tga 0.742187500000 0.234375000000 0.781250000000 0.273437500000 +rpjob_206.tga 0.781250000000 0.234375000000 0.820312500000 0.273437500000 +rpjob_207.tga 0.820312500000 0.234375000000 0.859375000000 0.273437500000 +rpjob_advanced.tga 0.859375000000 0.234375000000 0.898437500000 0.273437500000 +rpjob_elementary.tga 0.898437500000 0.234375000000 0.937500000000 0.273437500000 +rpjob_roleplay.tga 0.937500000000 0.234375000000 0.976562500000 0.273437500000 +rpjob_task.tga 0.468750000000 0.273437500000 0.507812500000 0.312500000000 +rpjob_task_certificats.tga 0.507812500000 0.273437500000 0.546875000000 0.312500000000 +rpjob_task_convert.tga 0.546875000000 0.273437500000 0.585937500000 0.312500000000 +rpjob_task_generic.tga 0.585937500000 0.273437500000 0.625000000000 0.312500000000 +rpjob_task_upgrade.tga 0.625000000000 0.273437500000 0.664062500000 0.312500000000 +RW_autolaunch.tga 0.664062500000 0.273437500000 0.703125000000 0.312500000000 +RW_bowgun.tga 0.703125000000 0.273437500000 0.742187500000 0.312500000000 +RW_grenade.tga 0.742187500000 0.273437500000 0.781250000000 0.312500000000 +RW_harpoongun.tga 0.781250000000 0.273437500000 0.820312500000 0.312500000000 +RW_launcher.tga 0.820312500000 0.273437500000 0.859375000000 0.312500000000 +RW_pistol.tga 0.859375000000 0.273437500000 0.898437500000 0.312500000000 +RW_pistolarc.tga 0.898437500000 0.273437500000 0.937500000000 0.312500000000 +RW_rifle.tga 0.937500000000 0.273437500000 0.976562500000 0.312500000000 +SH_buckler.tga 0.468750000000 0.312500000000 0.507812500000 0.351562500000 +SH_large_shield.tga 0.507812500000 0.312500000000 0.546875000000 0.351562500000 +spe_beast.tga 0.546875000000 0.312500000000 0.585937500000 0.351562500000 +spe_com.tga 0.585937500000 0.312500000000 0.625000000000 0.351562500000 +spe_inventory.tga 0.625000000000 0.312500000000 0.664062500000 0.351562500000 +spe_labs.tga 0.664062500000 0.312500000000 0.703125000000 0.351562500000 +spe_memory.tga 0.703125000000 0.312500000000 0.742187500000 0.351562500000 +spe_status.tga 0.742187500000 0.312500000000 0.781250000000 0.351562500000 +stimulating_water.tga 0.781250000000 0.312500000000 0.820312500000 0.351562500000 +ico_cataliseur_xp.tga 0.820312500000 0.312500000000 0.859375000000 0.351562500000 +ico_consommable_over.tga 0.859375000000 0.312500000000 0.898437500000 0.351562500000 +ico_fleur_carac_1.tga 0.898437500000 0.312500000000 0.937500000000 0.351562500000 +ico_fleur_carac_1_mask.tga 0.937500000000 0.312500000000 0.976562500000 0.351562500000 +ico_fleur_carac_2.tga 0.468750000000 0.351562500000 0.507812500000 0.390625000000 +ico_fleur_carac_2_mask.tga 0.507812500000 0.351562500000 0.546875000000 0.390625000000 +ico_fleur_carac_3.tga 0.546875000000 0.351562500000 0.585937500000 0.390625000000 +ico_fleur_carac_3_mask.tga 0.585937500000 0.351562500000 0.625000000000 0.390625000000 +ico_mission_art_fyros.tga 0.625000000000 0.351562500000 0.664062500000 0.390625000000 +ico_mission_art_matis.tga 0.664062500000 0.351562500000 0.703125000000 0.390625000000 +ico_mission_art_tryker.tga 0.703125000000 0.351562500000 0.742187500000 0.390625000000 +ico_mission_art_zorai.tga 0.742187500000 0.351562500000 0.781250000000 0.390625000000 +ico_mission_barrel.tga 0.781250000000 0.351562500000 0.820312500000 0.390625000000 +ico_mission_bottle.tga 0.820312500000 0.351562500000 0.859375000000 0.390625000000 +ico_mission_casket.tga 0.859375000000 0.351562500000 0.898437500000 0.390625000000 +ico_mission_medicine.tga 0.898437500000 0.351562500000 0.937500000000 0.390625000000 +ico_mission_message.tga 0.937500000000 0.351562500000 0.976562500000 0.390625000000 +ico_mission_package.tga 0.468750000000 0.390625000000 0.507812500000 0.429687500000 +ico_mission_pot.tga 0.507812500000 0.390625000000 0.546875000000 0.429687500000 +ico_mission_purse.tga 0.546875000000 0.390625000000 0.585937500000 0.429687500000 +ico_racine.tga 0.585937500000 0.390625000000 0.625000000000 0.429687500000 +ge_mission_outpost_townhall.tga 0.625000000000 0.390625000000 0.664062500000 0.429687500000 +ico_amande.tga 0.664062500000 0.390625000000 0.703125000000 0.429687500000 +to_searake.tga 0.703125000000 0.390625000000 0.742187500000 0.429687500000 +to_spade.tga 0.742187500000 0.390625000000 0.781250000000 0.429687500000 +to_stick.tga 0.781250000000 0.390625000000 0.820312500000 0.429687500000 +to_tunneling_knife.tga 0.820312500000 0.390625000000 0.859375000000 0.429687500000 +to_whip.tga 0.859375000000 0.390625000000 0.898437500000 0.429687500000 +to_wrench.tga 0.898437500000 0.390625000000 0.937500000000 0.429687500000 +TP_caravane.tga 0.937500000000 0.390625000000 0.976562500000 0.429687500000 +TP_kami.tga 0.468750000000 0.429687500000 0.507812500000 0.468750000000 +tetekitin.tga 0.507812500000 0.429687500000 0.546875000000 0.468750000000 +to_ammo.tga 0.546875000000 0.429687500000 0.585937500000 0.468750000000 +to_armor.tga 0.585937500000 0.429687500000 0.625000000000 0.468750000000 +to_cooking_pot.tga 0.625000000000 0.429687500000 0.664062500000 0.468750000000 +to_fishing_rod.tga 0.664062500000 0.429687500000 0.703125000000 0.468750000000 +to_forage.tga 0.703125000000 0.429687500000 0.742187500000 0.468750000000 +to_hammer.tga 0.742187500000 0.429687500000 0.781250000000 0.468750000000 +to_jewelry_hammer.tga 0.781250000000 0.429687500000 0.820312500000 0.468750000000 +to_jewels.tga 0.820312500000 0.429687500000 0.859375000000 0.468750000000 +to_leathercutter.tga 0.859375000000 0.429687500000 0.898437500000 0.468750000000 +to_melee.tga 0.898437500000 0.429687500000 0.937500000000 0.468750000000 +to_needle.tga 0.937500000000 0.429687500000 0.976562500000 0.468750000000 +to_pestle.tga 0.000000000000 0.468750000000 0.039062500000 0.507812500000 +ico_tourbe.tga 0.039062500000 0.468750000000 0.078125000000 0.507812500000 +improved_tool.tga 0.078125000000 0.468750000000 0.117187500000 0.507812500000 +item_default.tga 0.117187500000 0.468750000000 0.156250000000 0.507812500000 +item_plan_over.tga 0.156250000000 0.468750000000 0.195312500000 0.507812500000 +lucky_flower.tga 0.195312500000 0.468750000000 0.234375000000 0.507812500000 +W_AM_logo.tga 0.234375000000 0.468750000000 0.273437500000 0.507812500000 +w_pa_bracelet.tga 0.273437500000 0.468750000000 0.312500000000 0.507812500000 +w_pa_diadem.tga 0.312500000000 0.468750000000 0.351562500000 0.507812500000 +w_pa_earring.tga 0.351562500000 0.468750000000 0.390625000000 0.507812500000 +w_pa_pendant.tga 0.390625000000 0.468750000000 0.429687500000 0.507812500000 +w_pa_ring.tga 0.429687500000 0.468750000000 0.468750000000 0.507812500000 +xp_cat_green.tga 0.468750000000 0.468750000000 0.507812500000 0.507812500000 +PA_diadem.tga 0.507812500000 0.468750000000 0.546875000000 0.507812500000 +PA_earring.tga 0.546875000000 0.468750000000 0.585937500000 0.507812500000 +PA_pendant.tga 0.585937500000 0.468750000000 0.625000000000 0.507812500000 +PA_ring.tga 0.625000000000 0.468750000000 0.664062500000 0.507812500000 +protect_amber.tga 0.664062500000 0.468750000000 0.703125000000 0.507812500000 +pvp_aura.tga 0.703125000000 0.468750000000 0.742187500000 0.507812500000 asc_exit.tga 0.742187500000 0.468750000000 0.773437500000 0.500000000000 asc_rolemastercraft.tga 0.773437500000 0.468750000000 0.804687500000 0.500000000000 asc_rolemasterfight.tga 0.804687500000 0.468750000000 0.835937500000 0.500000000000 @@ -324,340 +324,350 @@ asc_rolemasterharvest.tga 0.835937500000 0.468750000000 0.867187500000 0.5000000 asc_rolemastermagic.tga 0.867187500000 0.468750000000 0.898437500000 0.500000000000 asc_unknown.tga 0.898437500000 0.468750000000 0.929687500000 0.500000000000 mail.tga 0.929687500000 0.468750000000 0.960937500000 0.492187500000 -mp_back_curative.tga 0.976562500000 0.078125000000 1.000000000000 0.101562500000 -mp_back_offensive.tga 0.976562500000 0.101562500000 1.000000000000 0.125000000000 -mp_back_selfonly.tga 0.976562500000 0.125000000000 1.000000000000 0.148437500000 -building_state_24x24.tga 0.976562500000 0.148437500000 1.000000000000 0.171875000000 -ico_ammo_bullet.tga 0.976562500000 0.171875000000 1.000000000000 0.195312500000 -ico_ammo_jacket.tga 0.976562500000 0.195312500000 1.000000000000 0.218750000000 -ico_angle.tga 0.976562500000 0.218750000000 1.000000000000 0.242187500000 -ico_anti_magic_shield.tga 0.976562500000 0.242187500000 1.000000000000 0.265625000000 -ico_armor.tga 0.976562500000 0.265625000000 1.000000000000 0.289062500000 -ico_armor_clip.tga 0.976562500000 0.289062500000 1.000000000000 0.312500000000 -ico_armor_heavy.tga 0.976562500000 0.312500000000 1.000000000000 0.335937500000 -ico_armor_kitin.tga 0.976562500000 0.335937500000 1.000000000000 0.359375000000 -ico_armor_light.tga 0.976562500000 0.359375000000 1.000000000000 0.382812500000 -ico_armor_medium.tga 0.976562500000 0.382812500000 1.000000000000 0.406250000000 -ico_armor_penalty.tga 0.976562500000 0.406250000000 1.000000000000 0.429687500000 -ico_armor_shell.tga 0.976562500000 0.429687500000 1.000000000000 0.453125000000 -ico_atys.tga 0.976562500000 0.453125000000 1.000000000000 0.476562500000 -ico_atysian.tga 0.960937500000 0.476562500000 0.984375000000 0.500000000000 -ico_balance_hp.tga 0.929687500000 0.492187500000 0.953125000000 0.515625000000 -ico_barrel.tga 0.742187500000 0.500000000000 0.765625000000 0.523437500000 -ico_bash.tga 0.765625000000 0.500000000000 0.789062500000 0.523437500000 -ico_berserk.tga 0.789062500000 0.500000000000 0.812500000000 0.523437500000 -ico_blade.tga 0.812500000000 0.500000000000 0.835937500000 0.523437500000 -ico_bleeding.tga 0.835937500000 0.500000000000 0.859375000000 0.523437500000 -ico_blind.tga 0.859375000000 0.500000000000 0.882812500000 0.523437500000 -ico_blunt.tga 0.882812500000 0.500000000000 0.906250000000 0.523437500000 -ico_bomb.tga 0.906250000000 0.500000000000 0.929687500000 0.523437500000 -cb_main_nue.tga 0.953125000000 0.500000000000 0.976562500000 0.523437500000 -ico_celestial.tga 0.976562500000 0.500000000000 1.000000000000 0.523437500000 -ico_circular_attack.tga 0.000000000000 0.507812500000 0.023437500000 0.531250000000 -ico_clothes.tga 0.023437500000 0.507812500000 0.046875000000 0.531250000000 -ico_cold.tga 0.046875000000 0.507812500000 0.070312500000 0.531250000000 -ico_concentration.tga 0.070312500000 0.507812500000 0.093750000000 0.531250000000 -BK_matis_brick.tga 0.093750000000 0.507812500000 0.117187500000 0.531250000000 -ico_constitution.tga 0.117187500000 0.507812500000 0.140625000000 0.531250000000 -ico_counterweight.tga 0.140625000000 0.507812500000 0.164062500000 0.531250000000 -ico_craft_buff.tga 0.164062500000 0.507812500000 0.187500000000 0.531250000000 -ico_create_sapload.tga 0.187500000000 0.507812500000 0.210937500000 0.531250000000 -ico_curse.tga 0.210937500000 0.507812500000 0.234375000000 0.531250000000 -ico_debuff.tga 0.234375000000 0.507812500000 0.257812500000 0.531250000000 -ico_debuff_resist.tga 0.257812500000 0.507812500000 0.281250000000 0.531250000000 -ico_debuff_skill.tga 0.281250000000 0.507812500000 0.304687500000 0.531250000000 -ico_desert.tga 0.304687500000 0.507812500000 0.328125000000 0.531250000000 -ico_dexterity.tga 0.328125000000 0.507812500000 0.351562500000 0.531250000000 -ico_disarm.tga 0.351562500000 0.507812500000 0.375000000000 0.531250000000 -ico_dodge.tga 0.375000000000 0.507812500000 0.398437500000 0.531250000000 -ico_dot.tga 0.398437500000 0.507812500000 0.421875000000 0.531250000000 -ico_durability.tga 0.421875000000 0.507812500000 0.445312500000 0.531250000000 -ico_electric.tga 0.445312500000 0.507812500000 0.468750000000 0.531250000000 -ico_explosif.tga 0.468750000000 0.507812500000 0.492187500000 0.531250000000 -ico_extracting.tga 0.492187500000 0.507812500000 0.515625000000 0.531250000000 -ico_fear.tga 0.515625000000 0.507812500000 0.539062500000 0.531250000000 -ico_feint.tga 0.539062500000 0.507812500000 0.562500000000 0.531250000000 -ico_fire.tga 0.562500000000 0.507812500000 0.585937500000 0.531250000000 -ico_firing_pin.tga 0.585937500000 0.507812500000 0.609375000000 0.531250000000 -ch_back.tga 0.609375000000 0.507812500000 0.632812500000 0.531250000000 -BK_generic_brick.tga 0.632812500000 0.507812500000 0.656250000000 0.531250000000 -mp_over_link.tga 0.656250000000 0.507812500000 0.679687500000 0.531250000000 -bk_aura.tga 0.679687500000 0.507812500000 0.703125000000 0.531250000000 -bk_conso.tga 0.703125000000 0.507812500000 0.726562500000 0.531250000000 -bk_outpost_brick.tga 0.929687500000 0.515625000000 0.953125000000 0.539062500000 -bk_power.tga 0.726562500000 0.523437500000 0.750000000000 0.546875000000 -ico_focus.tga 0.750000000000 0.523437500000 0.773437500000 0.546875000000 -ico_forage_buff.tga 0.773437500000 0.523437500000 0.796875000000 0.546875000000 -ico_forbid_item.tga 0.796875000000 0.523437500000 0.820312500000 0.546875000000 -ico_forest.tga 0.820312500000 0.523437500000 0.843750000000 0.546875000000 -2h_over.tga 0.843750000000 0.523437500000 0.867187500000 0.546875000000 -ico_gardening.tga 0.867187500000 0.523437500000 0.890625000000 0.546875000000 -ico_gentle.tga 0.890625000000 0.523437500000 0.914062500000 0.546875000000 -ico_goo.tga 0.953125000000 0.523437500000 0.976562500000 0.546875000000 -ico_gripp.tga 0.976562500000 0.523437500000 1.000000000000 0.546875000000 -1h_over.tga 0.000000000000 0.531250000000 0.023437500000 0.554687500000 -BK_fyros_brick.tga 0.023437500000 0.531250000000 0.046875000000 0.554687500000 -ico_hammer.tga 0.046875000000 0.531250000000 0.070312500000 0.554687500000 -ico_harmful.tga 0.070312500000 0.531250000000 0.093750000000 0.554687500000 -ico_hatred.tga 0.093750000000 0.531250000000 0.117187500000 0.554687500000 -ico_heal.tga 0.117187500000 0.531250000000 0.140625000000 0.554687500000 -ico_hit_rate.tga 0.140625000000 0.531250000000 0.164062500000 0.554687500000 -ico_incapacity.tga 0.164062500000 0.531250000000 0.187500000000 0.554687500000 -ico_intelligence.tga 0.187500000000 0.531250000000 0.210937500000 0.554687500000 -ico_interrupt.tga 0.210937500000 0.531250000000 0.234375000000 0.554687500000 -ico_invulnerability.tga 0.234375000000 0.531250000000 0.257812500000 0.554687500000 -ico_jewel_stone.tga 0.257812500000 0.531250000000 0.281250000000 0.554687500000 -ico_jewel_stone_support.tga 0.281250000000 0.531250000000 0.304687500000 0.554687500000 -ico_jungle.tga 0.304687500000 0.531250000000 0.328125000000 0.554687500000 -ico_lacustre.tga 0.328125000000 0.531250000000 0.351562500000 0.554687500000 -ico_landmark_bonus.tga 0.351562500000 0.531250000000 0.375000000000 0.554687500000 -ico_level.tga 0.375000000000 0.531250000000 0.398437500000 0.554687500000 -ico_lining.tga 0.398437500000 0.531250000000 0.421875000000 0.554687500000 -ico_location.tga 0.421875000000 0.531250000000 0.445312500000 0.554687500000 -ico_madness.tga 0.445312500000 0.531250000000 0.468750000000 0.554687500000 -ico_magic.tga 0.468750000000 0.531250000000 0.492187500000 0.554687500000 -ico_magic_action_buff.tga 0.492187500000 0.531250000000 0.515625000000 0.554687500000 -ico_magic_focus.tga 0.515625000000 0.531250000000 0.539062500000 0.554687500000 -ico_magic_target_buff.tga 0.539062500000 0.531250000000 0.562500000000 0.554687500000 -ico_melee_action_buff.tga 0.562500000000 0.531250000000 0.585937500000 0.554687500000 -ico_melee_target_buff.tga 0.585937500000 0.531250000000 0.609375000000 0.554687500000 -ico_mental.tga 0.609375000000 0.531250000000 0.632812500000 0.554687500000 -no_action.tga 0.632812500000 0.531250000000 0.656250000000 0.554687500000 -op_back.tga 0.656250000000 0.531250000000 0.679687500000 0.554687500000 -op_over_break.tga 0.679687500000 0.531250000000 0.703125000000 0.554687500000 -op_over_less.tga 0.703125000000 0.531250000000 0.726562500000 0.554687500000 -op_over_more.tga 0.914062500000 0.539062500000 0.937500000000 0.562500000000 -ico_metabolism.tga 0.726562500000 0.546875000000 0.750000000000 0.570312500000 -pa_back.tga 0.750000000000 0.546875000000 0.773437500000 0.570312500000 -ico_mezz.tga 0.773437500000 0.546875000000 0.796875000000 0.570312500000 -ico_misfortune.tga 0.796875000000 0.546875000000 0.820312500000 0.570312500000 -BK_magie_noire_brick.tga 0.820312500000 0.546875000000 0.843750000000 0.570312500000 -pa_over_break.tga 0.843750000000 0.546875000000 0.867187500000 0.570312500000 -pa_over_less.tga 0.867187500000 0.546875000000 0.890625000000 0.570312500000 -pa_over_more.tga 0.890625000000 0.546875000000 0.914062500000 0.570312500000 -BK_tryker_brick.tga 0.937500000000 0.546875000000 0.960937500000 0.570312500000 -cp_back.tga 0.960937500000 0.546875000000 0.984375000000 0.570312500000 -cp_over_break.tga 0.000000000000 0.554687500000 0.023437500000 0.578125000000 -pvp_ally_0.tga 0.023437500000 0.554687500000 0.046875000000 0.578125000000 -pvp_ally_1.tga 0.046875000000 0.554687500000 0.070312500000 0.578125000000 -pvp_ally_2.tga 0.070312500000 0.554687500000 0.093750000000 0.578125000000 -pvp_ally_3.tga 0.093750000000 0.554687500000 0.117187500000 0.578125000000 -pvp_ally_4.tga 0.117187500000 0.554687500000 0.140625000000 0.578125000000 -pvp_ally_6.tga 0.140625000000 0.554687500000 0.164062500000 0.578125000000 -pvp_ally_primas.tga 0.164062500000 0.554687500000 0.187500000000 0.578125000000 -pvp_ally_ranger.tga 0.187500000000 0.554687500000 0.210937500000 0.578125000000 -cp_over_less.tga 0.210937500000 0.554687500000 0.234375000000 0.578125000000 -cp_over_more.tga 0.234375000000 0.554687500000 0.257812500000 0.578125000000 -cp_over_opening.tga 0.257812500000 0.554687500000 0.281250000000 0.578125000000 -cp_over_opening_2.tga 0.281250000000 0.554687500000 0.304687500000 0.578125000000 -pvp_enemy_0.tga 0.304687500000 0.554687500000 0.328125000000 0.578125000000 -pvp_enemy_1.tga 0.328125000000 0.554687500000 0.351562500000 0.578125000000 -pvp_enemy_2.tga 0.351562500000 0.554687500000 0.375000000000 0.578125000000 -pvp_enemy_3.tga 0.375000000000 0.554687500000 0.398437500000 0.578125000000 -pvp_enemy_4.tga 0.398437500000 0.554687500000 0.421875000000 0.578125000000 -pvp_enemy_6.tga 0.421875000000 0.554687500000 0.445312500000 0.578125000000 -pvp_enemy_marauder.tga 0.445312500000 0.554687500000 0.468750000000 0.578125000000 -pvp_enemy_trytonist.tga 0.468750000000 0.554687500000 0.492187500000 0.578125000000 -bg_downloader.tga 0.492187500000 0.554687500000 0.515625000000 0.578125000000 -BK_zorai_brick.tga 0.515625000000 0.554687500000 0.539062500000 0.578125000000 -ef_back.tga 0.539062500000 0.554687500000 0.562500000000 0.578125000000 -ef_over_break.tga 0.562500000000 0.554687500000 0.585937500000 0.578125000000 -ico_move.tga 0.585937500000 0.554687500000 0.609375000000 0.578125000000 -ico_multiple_spots.tga 0.609375000000 0.554687500000 0.632812500000 0.578125000000 -ico_multi_fight.tga 0.632812500000 0.554687500000 0.656250000000 0.578125000000 -ef_over_less.tga 0.656250000000 0.554687500000 0.679687500000 0.578125000000 -ico_opening_hit.tga 0.679687500000 0.554687500000 0.703125000000 0.578125000000 -ico_over_autumn.tga 0.703125000000 0.554687500000 0.726562500000 0.578125000000 -ico_over_degenerated.tga 0.914062500000 0.562500000000 0.937500000000 0.585937500000 -ico_over_fauna.tga 0.726562500000 0.570312500000 0.750000000000 0.593750000000 -ico_over_flora.tga 0.750000000000 0.570312500000 0.773437500000 0.593750000000 -ico_over_hit_arms.tga 0.773437500000 0.570312500000 0.796875000000 0.593750000000 -ico_over_hit_chest.tga 0.796875000000 0.570312500000 0.820312500000 0.593750000000 -ico_over_hit_feet.tga 0.820312500000 0.570312500000 0.843750000000 0.593750000000 -ico_over_hit_feet_hands.tga 0.843750000000 0.570312500000 0.867187500000 0.593750000000 -ico_over_hit_feet_head.tga 0.867187500000 0.570312500000 0.890625000000 0.593750000000 -ico_over_hit_feet_x2.tga 0.890625000000 0.570312500000 0.914062500000 0.593750000000 -ico_over_hit_feint_x3.tga 0.937500000000 0.570312500000 0.960937500000 0.593750000000 -ico_over_hit_hands.tga 0.960937500000 0.570312500000 0.984375000000 0.593750000000 -ico_over_hit_hands_chest.tga 0.000000000000 0.578125000000 0.023437500000 0.601562500000 -ico_over_hit_hands_head.tga 0.023437500000 0.578125000000 0.046875000000 0.601562500000 -ico_over_hit_head.tga 0.046875000000 0.578125000000 0.070312500000 0.601562500000 -ico_over_hit_head_x3.tga 0.070312500000 0.578125000000 0.093750000000 0.601562500000 -ico_over_hit_legs.tga 0.093750000000 0.578125000000 0.117187500000 0.601562500000 -ico_over_homin.tga 0.117187500000 0.578125000000 0.140625000000 0.601562500000 -ico_over_kitin.tga 0.140625000000 0.578125000000 0.164062500000 0.601562500000 -ico_over_magic.tga 0.164062500000 0.578125000000 0.187500000000 0.601562500000 -ico_over_melee.tga 0.187500000000 0.578125000000 0.210937500000 0.601562500000 -ico_over_racial.tga 0.210937500000 0.578125000000 0.234375000000 0.601562500000 -ico_over_range.tga 0.234375000000 0.578125000000 0.257812500000 0.601562500000 -ico_over_special.tga 0.257812500000 0.578125000000 0.281250000000 0.601562500000 -ico_over_spring.tga 0.281250000000 0.578125000000 0.304687500000 0.601562500000 -ico_over_summer.tga 0.304687500000 0.578125000000 0.328125000000 0.601562500000 -ico_over_winter.tga 0.328125000000 0.578125000000 0.351562500000 0.601562500000 -ico_parry.tga 0.351562500000 0.578125000000 0.375000000000 0.601562500000 -ico_piercing.tga 0.375000000000 0.578125000000 0.398437500000 0.601562500000 -ico_pointe.tga 0.398437500000 0.578125000000 0.421875000000 0.601562500000 -ico_poison.tga 0.421875000000 0.578125000000 0.445312500000 0.601562500000 -ico_power.tga 0.445312500000 0.578125000000 0.468750000000 0.601562500000 -ico_preservation.tga 0.468750000000 0.578125000000 0.492187500000 0.601562500000 -ico_primal.tga 0.492187500000 0.578125000000 0.515625000000 0.601562500000 -ico_prime_roots.tga 0.515625000000 0.578125000000 0.539062500000 0.601562500000 -ico_private.tga 0.539062500000 0.578125000000 0.562500000000 0.601562500000 -ico_prospecting.tga 0.562500000000 0.578125000000 0.585937500000 0.601562500000 -ico_quality.tga 0.585937500000 0.578125000000 0.609375000000 0.601562500000 -ef_over_more.tga 0.609375000000 0.578125000000 0.632812500000 0.601562500000 -ico_range.tga 0.632812500000 0.578125000000 0.656250000000 0.601562500000 -ico_range_action_buff.tga 0.656250000000 0.578125000000 0.679687500000 0.601562500000 -ico_range_target_buff.tga 0.679687500000 0.578125000000 0.703125000000 0.601562500000 -ico_ricochet.tga 0.703125000000 0.578125000000 0.726562500000 0.601562500000 -ico_root.tga 0.914062500000 0.585937500000 0.937500000000 0.609375000000 -ico_rot.tga 0.726562500000 0.593750000000 0.750000000000 0.617187500000 -ico_safe.tga 0.750000000000 0.593750000000 0.773437500000 0.617187500000 -ico_sap.tga 0.773437500000 0.593750000000 0.796875000000 0.617187500000 -ico_self_damage.tga 0.796875000000 0.593750000000 0.820312500000 0.617187500000 -ico_shaft.tga 0.820312500000 0.593750000000 0.843750000000 0.617187500000 -ico_shielding.tga 0.843750000000 0.593750000000 0.867187500000 0.617187500000 -ico_shield_buff.tga 0.867187500000 0.593750000000 0.890625000000 0.617187500000 -ico_shield_up.tga 0.890625000000 0.593750000000 0.914062500000 0.617187500000 -ico_shockwave.tga 0.937500000000 0.593750000000 0.960937500000 0.617187500000 -ico_sickness.tga 0.960937500000 0.593750000000 0.984375000000 0.617187500000 -ico_slashing.tga 0.000000000000 0.601562500000 0.023437500000 0.625000000000 -ico_slow.tga 0.023437500000 0.601562500000 0.046875000000 0.625000000000 -ico_soft_spot.tga 0.046875000000 0.601562500000 0.070312500000 0.625000000000 -ico_source_time.tga 0.070312500000 0.601562500000 0.093750000000 0.625000000000 -ico_speed.tga 0.093750000000 0.601562500000 0.117187500000 0.625000000000 -ico_speeding_up.tga 0.117187500000 0.601562500000 0.140625000000 0.625000000000 -ico_spell_break.tga 0.140625000000 0.601562500000 0.164062500000 0.625000000000 -fo_back.tga 0.164062500000 0.601562500000 0.187500000000 0.625000000000 -ico_spray.tga 0.187500000000 0.601562500000 0.210937500000 0.625000000000 -ico_spying.tga 0.210937500000 0.601562500000 0.234375000000 0.625000000000 -ico_stamina.tga 0.234375000000 0.601562500000 0.257812500000 0.625000000000 -ico_strength.tga 0.257812500000 0.601562500000 0.281250000000 0.625000000000 -ico_stuffing.tga 0.281250000000 0.601562500000 0.304687500000 0.625000000000 -ico_stunn.tga 0.304687500000 0.601562500000 0.328125000000 0.625000000000 -fo_over.tga 0.328125000000 0.601562500000 0.351562500000 0.625000000000 -fp_ammo.tga 0.351562500000 0.601562500000 0.375000000000 0.625000000000 -fp_armor.tga 0.375000000000 0.601562500000 0.398437500000 0.625000000000 -fp_building.tga 0.398437500000 0.601562500000 0.421875000000 0.625000000000 -fp_jewel.tga 0.421875000000 0.601562500000 0.445312500000 0.625000000000 -fp_melee.tga 0.445312500000 0.601562500000 0.468750000000 0.625000000000 -fp_over.tga 0.468750000000 0.601562500000 0.492187500000 0.625000000000 -fp_range.tga 0.492187500000 0.601562500000 0.515625000000 0.625000000000 -fp_shield.tga 0.515625000000 0.601562500000 0.539062500000 0.625000000000 -fp_tools.tga 0.539062500000 0.601562500000 0.562500000000 0.625000000000 -brick_default.tga 0.562500000000 0.601562500000 0.585937500000 0.625000000000 -ico_taunt.tga 0.585937500000 0.601562500000 0.609375000000 0.625000000000 -tb_action_attack.tga 0.609375000000 0.601562500000 0.632812500000 0.625000000000 -tb_action_config.tga 0.632812500000 0.601562500000 0.656250000000 0.625000000000 -tb_action_disband.tga 0.656250000000 0.601562500000 0.679687500000 0.625000000000 -tb_action_disengage.tga 0.679687500000 0.601562500000 0.703125000000 0.625000000000 -tb_action_extract.tga 0.703125000000 0.601562500000 0.726562500000 0.625000000000 -tb_action_invite.tga 0.914062500000 0.609375000000 0.937500000000 0.632812500000 -tb_action_kick.tga 0.726562500000 0.617187500000 0.750000000000 0.640625000000 -tb_action_move.tga 0.750000000000 0.617187500000 0.773437500000 0.640625000000 -tb_action_run.tga 0.773437500000 0.617187500000 0.796875000000 0.640625000000 -tb_action_sit.tga 0.796875000000 0.617187500000 0.820312500000 0.640625000000 -tb_action_stand.tga 0.820312500000 0.617187500000 0.843750000000 0.640625000000 -tb_action_stop.tga 0.843750000000 0.617187500000 0.867187500000 0.640625000000 -tb_action_talk.tga 0.867187500000 0.617187500000 0.890625000000 0.640625000000 -tb_action_walk.tga 0.890625000000 0.617187500000 0.914062500000 0.640625000000 -tb_animals.tga 0.937500000000 0.617187500000 0.960937500000 0.640625000000 -tb_config.tga 0.960937500000 0.617187500000 0.984375000000 0.640625000000 -tb_connection.tga 0.000000000000 0.625000000000 0.023437500000 0.648437500000 -tb_contacts.tga 0.023437500000 0.625000000000 0.046875000000 0.648437500000 -tb_desk_1.tga 0.046875000000 0.625000000000 0.070312500000 0.648437500000 -tb_desk_2.tga 0.070312500000 0.625000000000 0.093750000000 0.648437500000 -tb_desk_3.tga 0.093750000000 0.625000000000 0.117187500000 0.648437500000 -tb_desk_4.tga 0.117187500000 0.625000000000 0.140625000000 0.648437500000 -tb_faction.tga 0.140625000000 0.625000000000 0.164062500000 0.648437500000 -tb_forum.tga 0.164062500000 0.625000000000 0.187500000000 0.648437500000 -tb_guild.tga 0.187500000000 0.625000000000 0.210937500000 0.648437500000 -TB_help2.tga 0.210937500000 0.625000000000 0.234375000000 0.648437500000 -tb_keys.tga 0.234375000000 0.625000000000 0.257812500000 0.648437500000 -tb_macros.tga 0.257812500000 0.625000000000 0.281250000000 0.648437500000 -tb_mail.tga 0.281250000000 0.625000000000 0.304687500000 0.648437500000 -tb_mode_dodge.tga 0.304687500000 0.625000000000 0.328125000000 0.648437500000 -tb_mode_parry.tga 0.328125000000 0.625000000000 0.351562500000 0.648437500000 -tb_over.tga 0.351562500000 0.625000000000 0.375000000000 0.648437500000 -tb_support.tga 0.375000000000 0.625000000000 0.398437500000 0.648437500000 -tb_team.tga 0.398437500000 0.625000000000 0.421875000000 0.648437500000 -tb_windows.tga 0.421875000000 0.625000000000 0.445312500000 0.648437500000 -ico_time.tga 0.445312500000 0.625000000000 0.468750000000 0.648437500000 -ico_time_bonus.tga 0.468750000000 0.625000000000 0.492187500000 0.648437500000 -ico_absorb_damage.tga 0.492187500000 0.625000000000 0.515625000000 0.648437500000 -ico_trigger.tga 0.515625000000 0.625000000000 0.539062500000 0.648437500000 -ico_umbrella.tga 0.539062500000 0.625000000000 0.562500000000 0.648437500000 -ico_use_enchantement.tga 0.562500000000 0.625000000000 0.585937500000 0.648437500000 -ico_vampire.tga 0.585937500000 0.625000000000 0.609375000000 0.648437500000 -ico_visibility.tga 0.609375000000 0.625000000000 0.632812500000 0.648437500000 -ico_war_cry.tga 0.632812500000 0.625000000000 0.656250000000 0.648437500000 -ico_weight.tga 0.656250000000 0.625000000000 0.679687500000 0.648437500000 -ico_wellbalanced.tga 0.679687500000 0.625000000000 0.703125000000 0.648437500000 -ico_will.tga 0.703125000000 0.625000000000 0.726562500000 0.648437500000 -ico_windding.tga 0.914062500000 0.632812500000 0.937500000000 0.656250000000 -ico_wisdom.tga 0.726562500000 0.640625000000 0.750000000000 0.664062500000 -ico_accurate.tga 0.750000000000 0.640625000000 0.773437500000 0.664062500000 -ico_acid.tga 0.773437500000 0.640625000000 0.796875000000 0.664062500000 -ico_aim.tga 0.796875000000 0.640625000000 0.820312500000 0.664062500000 -ico_aim_bird_wings.tga 0.820312500000 0.640625000000 0.843750000000 0.664062500000 -ico_aim_flying_kitin_abdomen.tga 0.843750000000 0.640625000000 0.867187500000 0.664062500000 -ico_aim_homin_arms.tga 0.867187500000 0.640625000000 0.890625000000 0.664062500000 -ico_aim_homin_chest.tga 0.890625000000 0.640625000000 0.914062500000 0.664062500000 -mf_back.tga 0.937500000000 0.640625000000 0.960937500000 0.664062500000 -us_back_0.tga 0.960937500000 0.640625000000 0.984375000000 0.664062500000 -us_back_1.tga 0.000000000000 0.648437500000 0.023437500000 0.671875000000 -us_back_2.tga 0.023437500000 0.648437500000 0.046875000000 0.671875000000 -us_back_3.tga 0.046875000000 0.648437500000 0.070312500000 0.671875000000 -us_back_4.tga 0.070312500000 0.648437500000 0.093750000000 0.671875000000 -us_back_5.tga 0.093750000000 0.648437500000 0.117187500000 0.671875000000 -us_back_6.tga 0.117187500000 0.648437500000 0.140625000000 0.671875000000 -us_back_7.tga 0.140625000000 0.648437500000 0.164062500000 0.671875000000 -us_back_8.tga 0.164062500000 0.648437500000 0.187500000000 0.671875000000 -us_back_9.tga 0.187500000000 0.648437500000 0.210937500000 0.671875000000 -us_ico_0.tga 0.210937500000 0.648437500000 0.234375000000 0.671875000000 -us_ico_1.tga 0.234375000000 0.648437500000 0.257812500000 0.671875000000 -us_ico_2.tga 0.257812500000 0.648437500000 0.281250000000 0.671875000000 -us_ico_3.tga 0.281250000000 0.648437500000 0.304687500000 0.671875000000 -us_ico_4.tga 0.304687500000 0.648437500000 0.328125000000 0.671875000000 -us_ico_5.tga 0.328125000000 0.648437500000 0.351562500000 0.671875000000 -us_ico_6.tga 0.351562500000 0.648437500000 0.375000000000 0.671875000000 -us_ico_7.tga 0.375000000000 0.648437500000 0.398437500000 0.671875000000 -us_ico_8.tga 0.398437500000 0.648437500000 0.421875000000 0.671875000000 -us_ico_9.tga 0.421875000000 0.648437500000 0.445312500000 0.671875000000 -us_over_0.tga 0.445312500000 0.648437500000 0.468750000000 0.671875000000 -us_over_1.tga 0.468750000000 0.648437500000 0.492187500000 0.671875000000 -us_over_2.tga 0.492187500000 0.648437500000 0.515625000000 0.671875000000 -us_over_3.tga 0.515625000000 0.648437500000 0.539062500000 0.671875000000 -us_over_4.tga 0.539062500000 0.648437500000 0.562500000000 0.671875000000 -mf_over.tga 0.562500000000 0.648437500000 0.585937500000 0.671875000000 -ico_aim_homin_feet.tga 0.585937500000 0.648437500000 0.609375000000 0.671875000000 -ico_aim_homin_feint.tga 0.609375000000 0.648437500000 0.632812500000 0.671875000000 -ico_aim_homin_hands.tga 0.632812500000 0.648437500000 0.656250000000 0.671875000000 -ico_aim_homin_head.tga 0.656250000000 0.648437500000 0.679687500000 0.671875000000 -ico_aim_homin_legs.tga 0.679687500000 0.648437500000 0.703125000000 0.671875000000 -mp3.tga 0.703125000000 0.648437500000 0.726562500000 0.671875000000 -W_slot_shortcut_id0.tga 0.914062500000 0.656250000000 0.937500000000 0.679687500000 -W_slot_shortcut_id1.tga 0.726562500000 0.664062500000 0.750000000000 0.687500000000 -W_slot_shortcut_id2.tga 0.750000000000 0.664062500000 0.773437500000 0.687500000000 -W_slot_shortcut_id3.tga 0.773437500000 0.664062500000 0.796875000000 0.687500000000 -W_slot_shortcut_id4.tga 0.796875000000 0.664062500000 0.820312500000 0.687500000000 -W_slot_shortcut_id5.tga 0.820312500000 0.664062500000 0.843750000000 0.687500000000 -W_slot_shortcut_id6.tga 0.843750000000 0.664062500000 0.867187500000 0.687500000000 -W_slot_shortcut_id7.tga 0.867187500000 0.664062500000 0.890625000000 0.687500000000 -W_slot_shortcut_id8.tga 0.890625000000 0.664062500000 0.914062500000 0.687500000000 -W_slot_shortcut_id9.tga 0.937500000000 0.664062500000 0.960937500000 0.687500000000 -w_slot_shortcut_shift_id0.tga 0.960937500000 0.664062500000 0.984375000000 0.687500000000 -w_slot_shortcut_shift_id1.tga 0.000000000000 0.671875000000 0.023437500000 0.695312500000 -w_slot_shortcut_shift_id2.tga 0.023437500000 0.671875000000 0.046875000000 0.695312500000 -w_slot_shortcut_shift_id3.tga 0.046875000000 0.671875000000 0.070312500000 0.695312500000 -w_slot_shortcut_shift_id4.tga 0.070312500000 0.671875000000 0.093750000000 0.695312500000 -w_slot_shortcut_shift_id5.tga 0.093750000000 0.671875000000 0.117187500000 0.695312500000 -w_slot_shortcut_shift_id6.tga 0.117187500000 0.671875000000 0.140625000000 0.695312500000 -w_slot_shortcut_shift_id7.tga 0.140625000000 0.671875000000 0.164062500000 0.695312500000 -w_slot_shortcut_shift_id8.tga 0.164062500000 0.671875000000 0.187500000000 0.695312500000 -w_slot_shortcut_shift_id9.tga 0.187500000000 0.671875000000 0.210937500000 0.695312500000 -ico_aim_kitin_head.tga 0.210937500000 0.671875000000 0.234375000000 0.695312500000 -ico_source_knowledge.tga 0.234375000000 0.671875000000 0.255859375000 0.695312500000 +ico_taunt.tga 0.976562500000 0.078125000000 1.000000000000 0.101562500000 +BK_generic_brick.tga 0.976562500000 0.101562500000 1.000000000000 0.125000000000 +bk_aura.tga 0.976562500000 0.125000000000 1.000000000000 0.148437500000 +bk_outpost_brick.tga 0.976562500000 0.148437500000 1.000000000000 0.171875000000 +bk_power.tga 0.976562500000 0.171875000000 1.000000000000 0.195312500000 +no_action.tga 0.976562500000 0.195312500000 1.000000000000 0.218750000000 +no_pvp.tga 0.976562500000 0.218750000000 1.000000000000 0.242187500000 +op_back.tga 0.976562500000 0.242187500000 1.000000000000 0.265625000000 +op_over_break.tga 0.976562500000 0.265625000000 1.000000000000 0.289062500000 +op_over_less.tga 0.976562500000 0.289062500000 1.000000000000 0.312500000000 +op_over_more.tga 0.976562500000 0.312500000000 1.000000000000 0.335937500000 +bk_conso.tga 0.976562500000 0.335937500000 1.000000000000 0.359375000000 +pa_back.tga 0.976562500000 0.359375000000 1.000000000000 0.382812500000 +2h_over.tga 0.976562500000 0.382812500000 1.000000000000 0.406250000000 +1h_over.tga 0.976562500000 0.406250000000 1.000000000000 0.429687500000 +pvp_duel.tga 0.976562500000 0.429687500000 1.000000000000 0.453125000000 +pvp_enemy_0.tga 0.976562500000 0.453125000000 1.000000000000 0.476562500000 +pvp_enemy_1.tga 0.960937500000 0.476562500000 0.984375000000 0.500000000000 +pvp_enemy_2.tga 0.929687500000 0.492187500000 0.953125000000 0.515625000000 +pvp_enemy_3.tga 0.742187500000 0.500000000000 0.765625000000 0.523437500000 +pvp_enemy_4.tga 0.765625000000 0.500000000000 0.789062500000 0.523437500000 +pvp_enemy_6.tga 0.789062500000 0.500000000000 0.812500000000 0.523437500000 +pvp_enemy_flag.tga 0.812500000000 0.500000000000 0.835937500000 0.523437500000 +pvp_enemy_marauder.tga 0.835937500000 0.500000000000 0.859375000000 0.523437500000 +pvp_enemy_tag.tga 0.859375000000 0.500000000000 0.882812500000 0.523437500000 +tb_action_attack.tga 0.882812500000 0.500000000000 0.906250000000 0.523437500000 +tb_action_config.tga 0.906250000000 0.500000000000 0.929687500000 0.523437500000 +tb_action_disband.tga 0.953125000000 0.500000000000 0.976562500000 0.523437500000 +tb_action_disengage.tga 0.976562500000 0.500000000000 1.000000000000 0.523437500000 +tb_action_extract.tga 0.000000000000 0.507812500000 0.023437500000 0.531250000000 +tb_action_invite.tga 0.023437500000 0.507812500000 0.046875000000 0.531250000000 +tb_action_kick.tga 0.046875000000 0.507812500000 0.070312500000 0.531250000000 +tb_action_move.tga 0.070312500000 0.507812500000 0.093750000000 0.531250000000 +tb_action_run.tga 0.093750000000 0.507812500000 0.117187500000 0.531250000000 +tb_action_sit.tga 0.117187500000 0.507812500000 0.140625000000 0.531250000000 +tb_action_stand.tga 0.140625000000 0.507812500000 0.164062500000 0.531250000000 +tb_action_stop.tga 0.164062500000 0.507812500000 0.187500000000 0.531250000000 +tb_action_talk.tga 0.187500000000 0.507812500000 0.210937500000 0.531250000000 +tb_action_walk.tga 0.210937500000 0.507812500000 0.234375000000 0.531250000000 +ico_armor_penalty.tga 0.234375000000 0.507812500000 0.257812500000 0.531250000000 +ico_armor_shell.tga 0.257812500000 0.507812500000 0.281250000000 0.531250000000 +ico_atys.tga 0.281250000000 0.507812500000 0.304687500000 0.531250000000 +ico_atysian.tga 0.304687500000 0.507812500000 0.328125000000 0.531250000000 +ico_balance_hp.tga 0.328125000000 0.507812500000 0.351562500000 0.531250000000 +ico_barrel.tga 0.351562500000 0.507812500000 0.375000000000 0.531250000000 +ico_bash.tga 0.375000000000 0.507812500000 0.398437500000 0.531250000000 +ico_berserk.tga 0.398437500000 0.507812500000 0.421875000000 0.531250000000 +ico_blade.tga 0.421875000000 0.507812500000 0.445312500000 0.531250000000 +ico_bleeding.tga 0.445312500000 0.507812500000 0.468750000000 0.531250000000 +ico_blind.tga 0.468750000000 0.507812500000 0.492187500000 0.531250000000 +ico_blunt.tga 0.492187500000 0.507812500000 0.515625000000 0.531250000000 +ico_bomb.tga 0.515625000000 0.507812500000 0.539062500000 0.531250000000 +pvp_enemy_trytonist.tga 0.539062500000 0.507812500000 0.562500000000 0.531250000000 +ico_celestial.tga 0.562500000000 0.507812500000 0.585937500000 0.531250000000 +ico_circular_attack.tga 0.585937500000 0.507812500000 0.609375000000 0.531250000000 +ico_cold.tga 0.609375000000 0.507812500000 0.632812500000 0.531250000000 +ico_concentration.tga 0.632812500000 0.507812500000 0.656250000000 0.531250000000 +pvp_flag.tga 0.656250000000 0.507812500000 0.679687500000 0.531250000000 +ico_constitution.tga 0.679687500000 0.507812500000 0.703125000000 0.531250000000 +ico_counterweight.tga 0.703125000000 0.507812500000 0.726562500000 0.531250000000 +ico_craft_buff.tga 0.929687500000 0.515625000000 0.953125000000 0.539062500000 +ico_create_sapload.tga 0.726562500000 0.523437500000 0.750000000000 0.546875000000 +ico_curse.tga 0.750000000000 0.523437500000 0.773437500000 0.546875000000 +ico_debuff.tga 0.773437500000 0.523437500000 0.796875000000 0.546875000000 +ico_debuff_resist.tga 0.796875000000 0.523437500000 0.820312500000 0.546875000000 +ico_debuff_skill.tga 0.820312500000 0.523437500000 0.843750000000 0.546875000000 +ico_desert.tga 0.843750000000 0.523437500000 0.867187500000 0.546875000000 +ico_dexterity.tga 0.867187500000 0.523437500000 0.890625000000 0.546875000000 +ico_disarm.tga 0.890625000000 0.523437500000 0.914062500000 0.546875000000 +ico_dodge.tga 0.953125000000 0.523437500000 0.976562500000 0.546875000000 +ico_dot.tga 0.976562500000 0.523437500000 1.000000000000 0.546875000000 +ico_electric.tga 0.000000000000 0.531250000000 0.023437500000 0.554687500000 +ico_explosif.tga 0.023437500000 0.531250000000 0.046875000000 0.554687500000 +ico_extracting.tga 0.046875000000 0.531250000000 0.070312500000 0.554687500000 +ico_fear.tga 0.070312500000 0.531250000000 0.093750000000 0.554687500000 +ico_feint.tga 0.093750000000 0.531250000000 0.117187500000 0.554687500000 +ico_fire.tga 0.117187500000 0.531250000000 0.140625000000 0.554687500000 +ico_firing_pin.tga 0.140625000000 0.531250000000 0.164062500000 0.554687500000 +pvp_neutral.tga 0.164062500000 0.531250000000 0.187500000000 0.554687500000 +pvp_tag.tga 0.187500000000 0.531250000000 0.210937500000 0.554687500000 +BK_magie_noire_brick.tga 0.210937500000 0.531250000000 0.234375000000 0.554687500000 +cp_back.tga 0.234375000000 0.531250000000 0.257812500000 0.554687500000 +cp_over_break.tga 0.257812500000 0.531250000000 0.281250000000 0.554687500000 +cp_over_less.tga 0.281250000000 0.531250000000 0.304687500000 0.554687500000 +ico_focus.tga 0.304687500000 0.531250000000 0.328125000000 0.554687500000 +ico_forage_buff.tga 0.328125000000 0.531250000000 0.351562500000 0.554687500000 +ico_forbid_item.tga 0.351562500000 0.531250000000 0.375000000000 0.554687500000 +ico_forest.tga 0.375000000000 0.531250000000 0.398437500000 0.554687500000 +ico_jungle.tga 0.398437500000 0.531250000000 0.421875000000 0.554687500000 +ico_lacustre.tga 0.421875000000 0.531250000000 0.445312500000 0.554687500000 +ico_landmark_bonus.tga 0.445312500000 0.531250000000 0.468750000000 0.554687500000 +ico_level.tga 0.468750000000 0.531250000000 0.492187500000 0.554687500000 +ico_lining.tga 0.492187500000 0.531250000000 0.515625000000 0.554687500000 +ico_location.tga 0.515625000000 0.531250000000 0.539062500000 0.554687500000 +ico_madness.tga 0.539062500000 0.531250000000 0.562500000000 0.554687500000 +ico_magic.tga 0.562500000000 0.531250000000 0.585937500000 0.554687500000 +ico_magic_action_buff.tga 0.585937500000 0.531250000000 0.609375000000 0.554687500000 +ico_magic_focus.tga 0.609375000000 0.531250000000 0.632812500000 0.554687500000 +ico_magic_target_buff.tga 0.632812500000 0.531250000000 0.656250000000 0.554687500000 +ico_melee_action_buff.tga 0.656250000000 0.531250000000 0.679687500000 0.554687500000 +ico_melee_target_buff.tga 0.679687500000 0.531250000000 0.703125000000 0.554687500000 +ico_mental.tga 0.703125000000 0.531250000000 0.726562500000 0.554687500000 +ico_metabolism.tga 0.914062500000 0.539062500000 0.937500000000 0.562500000000 +ico_mezz.tga 0.726562500000 0.546875000000 0.750000000000 0.570312500000 +cp_over_more.tga 0.750000000000 0.546875000000 0.773437500000 0.570312500000 +cp_over_opening.tga 0.773437500000 0.546875000000 0.796875000000 0.570312500000 +tb_animals.tga 0.796875000000 0.546875000000 0.820312500000 0.570312500000 +cp_over_opening_2.tga 0.820312500000 0.546875000000 0.843750000000 0.570312500000 +us_back_9.tga 0.843750000000 0.546875000000 0.867187500000 0.570312500000 +BK_tryker_brick.tga 0.867187500000 0.546875000000 0.890625000000 0.570312500000 +ico_spray.tga 0.890625000000 0.546875000000 0.914062500000 0.570312500000 +ico_spying.tga 0.937500000000 0.546875000000 0.960937500000 0.570312500000 +ico_stamina.tga 0.960937500000 0.546875000000 0.984375000000 0.570312500000 +ico_strength.tga 0.000000000000 0.554687500000 0.023437500000 0.578125000000 +ico_stuffing.tga 0.023437500000 0.554687500000 0.046875000000 0.578125000000 +ico_stunn.tga 0.046875000000 0.554687500000 0.070312500000 0.578125000000 +ico_move.tga 0.070312500000 0.554687500000 0.093750000000 0.578125000000 +ico_multiple_spots.tga 0.093750000000 0.554687500000 0.117187500000 0.578125000000 +ico_multi_fight.tga 0.117187500000 0.554687500000 0.140625000000 0.578125000000 +ico_opening_hit.tga 0.140625000000 0.554687500000 0.164062500000 0.578125000000 +ico_over_autumn.tga 0.164062500000 0.554687500000 0.187500000000 0.578125000000 +ico_over_degenerated.tga 0.187500000000 0.554687500000 0.210937500000 0.578125000000 +ico_over_fauna.tga 0.210937500000 0.554687500000 0.234375000000 0.578125000000 +ico_over_flora.tga 0.234375000000 0.554687500000 0.257812500000 0.578125000000 +ico_over_hit_arms.tga 0.257812500000 0.554687500000 0.281250000000 0.578125000000 +ico_over_hit_chest.tga 0.281250000000 0.554687500000 0.304687500000 0.578125000000 +ico_over_hit_feet.tga 0.304687500000 0.554687500000 0.328125000000 0.578125000000 +ico_over_hit_feet_hands.tga 0.328125000000 0.554687500000 0.351562500000 0.578125000000 +ico_over_hit_feet_head.tga 0.351562500000 0.554687500000 0.375000000000 0.578125000000 +ico_over_hit_feet_x2.tga 0.375000000000 0.554687500000 0.398437500000 0.578125000000 +ico_over_hit_feint_x3.tga 0.398437500000 0.554687500000 0.421875000000 0.578125000000 +ico_over_hit_hands.tga 0.421875000000 0.554687500000 0.445312500000 0.578125000000 +ico_over_hit_hands_chest.tga 0.445312500000 0.554687500000 0.468750000000 0.578125000000 +ico_over_hit_hands_head.tga 0.468750000000 0.554687500000 0.492187500000 0.578125000000 +ico_over_hit_head.tga 0.492187500000 0.554687500000 0.515625000000 0.578125000000 +ico_over_hit_legs.tga 0.515625000000 0.554687500000 0.539062500000 0.578125000000 +ico_over_homin.tga 0.539062500000 0.554687500000 0.562500000000 0.578125000000 +ico_over_kitin.tga 0.562500000000 0.554687500000 0.585937500000 0.578125000000 +ico_over_magic.tga 0.585937500000 0.554687500000 0.609375000000 0.578125000000 +ico_over_melee.tga 0.609375000000 0.554687500000 0.632812500000 0.578125000000 +ico_over_racial.tga 0.632812500000 0.554687500000 0.656250000000 0.578125000000 +ico_over_range.tga 0.656250000000 0.554687500000 0.679687500000 0.578125000000 +ico_over_special.tga 0.679687500000 0.554687500000 0.703125000000 0.578125000000 +ico_over_spring.tga 0.703125000000 0.554687500000 0.726562500000 0.578125000000 +ico_over_summer.tga 0.914062500000 0.562500000000 0.937500000000 0.585937500000 +ico_over_winter.tga 0.726562500000 0.570312500000 0.750000000000 0.593750000000 +ico_parry.tga 0.750000000000 0.570312500000 0.773437500000 0.593750000000 +ico_piercing.tga 0.773437500000 0.570312500000 0.796875000000 0.593750000000 +ico_pointe.tga 0.796875000000 0.570312500000 0.820312500000 0.593750000000 +ico_poison.tga 0.820312500000 0.570312500000 0.843750000000 0.593750000000 +ico_power.tga 0.843750000000 0.570312500000 0.867187500000 0.593750000000 +ico_preservation.tga 0.867187500000 0.570312500000 0.890625000000 0.593750000000 +ico_prime_roots.tga 0.890625000000 0.570312500000 0.914062500000 0.593750000000 +ico_private.tga 0.937500000000 0.570312500000 0.960937500000 0.593750000000 +ico_prospecting.tga 0.960937500000 0.570312500000 0.984375000000 0.593750000000 +ico_quality.tga 0.000000000000 0.578125000000 0.023437500000 0.601562500000 +BK_fyros_brick.tga 0.023437500000 0.578125000000 0.046875000000 0.601562500000 +ico_range.tga 0.046875000000 0.578125000000 0.070312500000 0.601562500000 +ico_range_action_buff.tga 0.070312500000 0.578125000000 0.093750000000 0.601562500000 +ico_range_target_buff.tga 0.093750000000 0.578125000000 0.117187500000 0.601562500000 +ico_ricochet.tga 0.117187500000 0.578125000000 0.140625000000 0.601562500000 +ico_root.tga 0.140625000000 0.578125000000 0.164062500000 0.601562500000 +ico_rot.tga 0.164062500000 0.578125000000 0.187500000000 0.601562500000 +ico_safe.tga 0.187500000000 0.578125000000 0.210937500000 0.601562500000 +ico_sap.tga 0.210937500000 0.578125000000 0.234375000000 0.601562500000 +ico_self_damage.tga 0.234375000000 0.578125000000 0.257812500000 0.601562500000 +ico_shaft.tga 0.257812500000 0.578125000000 0.281250000000 0.601562500000 +ico_shielding.tga 0.281250000000 0.578125000000 0.304687500000 0.601562500000 +ico_shield_buff.tga 0.304687500000 0.578125000000 0.328125000000 0.601562500000 +ico_shield_up.tga 0.328125000000 0.578125000000 0.351562500000 0.601562500000 +ico_shockwave.tga 0.351562500000 0.578125000000 0.375000000000 0.601562500000 +ico_sickness.tga 0.375000000000 0.578125000000 0.398437500000 0.601562500000 +ico_slashing.tga 0.398437500000 0.578125000000 0.421875000000 0.601562500000 +ico_slow.tga 0.421875000000 0.578125000000 0.445312500000 0.601562500000 +ico_soft_spot.tga 0.445312500000 0.578125000000 0.468750000000 0.601562500000 +ico_source_time.tga 0.468750000000 0.578125000000 0.492187500000 0.601562500000 +ico_speed.tga 0.492187500000 0.578125000000 0.515625000000 0.601562500000 +ico_speeding_up.tga 0.515625000000 0.578125000000 0.539062500000 0.601562500000 +ico_spell_break.tga 0.539062500000 0.578125000000 0.562500000000 0.601562500000 +fp_armor.tga 0.562500000000 0.578125000000 0.585937500000 0.601562500000 +fp_building.tga 0.585937500000 0.578125000000 0.609375000000 0.601562500000 +fp_jewel.tga 0.609375000000 0.578125000000 0.632812500000 0.601562500000 +fp_melee.tga 0.632812500000 0.578125000000 0.656250000000 0.601562500000 +fp_over.tga 0.656250000000 0.578125000000 0.679687500000 0.601562500000 +fp_range.tga 0.679687500000 0.578125000000 0.703125000000 0.601562500000 +fp_shield.tga 0.703125000000 0.578125000000 0.726562500000 0.601562500000 +fp_tools.tga 0.914062500000 0.585937500000 0.937500000000 0.609375000000 +ef_back.tga 0.726562500000 0.593750000000 0.750000000000 0.617187500000 +ico_absorb_damage.tga 0.750000000000 0.593750000000 0.773437500000 0.617187500000 +ico_accurate.tga 0.773437500000 0.593750000000 0.796875000000 0.617187500000 +ico_acid.tga 0.796875000000 0.593750000000 0.820312500000 0.617187500000 +ico_aim.tga 0.820312500000 0.593750000000 0.843750000000 0.617187500000 +ico_aim_bird_wings.tga 0.843750000000 0.593750000000 0.867187500000 0.617187500000 +ico_aim_flying_kitin_abdomen.tga 0.867187500000 0.593750000000 0.890625000000 0.617187500000 +ico_aim_homin_arms.tga 0.890625000000 0.593750000000 0.914062500000 0.617187500000 +ico_aim_homin_chest.tga 0.937500000000 0.593750000000 0.960937500000 0.617187500000 +ico_aim_homin_feet.tga 0.960937500000 0.593750000000 0.984375000000 0.617187500000 +ico_aim_homin_feint.tga 0.000000000000 0.601562500000 0.023437500000 0.625000000000 +ico_aim_homin_hands.tga 0.023437500000 0.601562500000 0.046875000000 0.625000000000 +ico_aim_homin_head.tga 0.046875000000 0.601562500000 0.070312500000 0.625000000000 +ico_aim_homin_legs.tga 0.070312500000 0.601562500000 0.093750000000 0.625000000000 +ico_aim_kitin_head.tga 0.093750000000 0.601562500000 0.117187500000 0.625000000000 +ef_over_break.tga 0.117187500000 0.601562500000 0.140625000000 0.625000000000 +ico_ammo_bullet.tga 0.140625000000 0.601562500000 0.164062500000 0.625000000000 +ico_ammo_jacket.tga 0.164062500000 0.601562500000 0.187500000000 0.625000000000 +ico_angle.tga 0.187500000000 0.601562500000 0.210937500000 0.625000000000 +ico_anti_magic_shield.tga 0.210937500000 0.601562500000 0.234375000000 0.625000000000 +ico_armor.tga 0.234375000000 0.601562500000 0.257812500000 0.625000000000 +ico_armor_clip.tga 0.257812500000 0.601562500000 0.281250000000 0.625000000000 +ico_armor_heavy.tga 0.281250000000 0.601562500000 0.304687500000 0.625000000000 +ico_armor_kitin.tga 0.304687500000 0.601562500000 0.328125000000 0.625000000000 +ico_armor_light.tga 0.328125000000 0.601562500000 0.351562500000 0.625000000000 +ef_over_less.tga 0.351562500000 0.601562500000 0.375000000000 0.625000000000 +ef_over_more.tga 0.375000000000 0.601562500000 0.398437500000 0.625000000000 +fo_back.tga 0.398437500000 0.601562500000 0.421875000000 0.625000000000 +fo_over.tga 0.421875000000 0.601562500000 0.445312500000 0.625000000000 +ico_gardening.tga 0.445312500000 0.601562500000 0.468750000000 0.625000000000 +ico_gentle.tga 0.468750000000 0.601562500000 0.492187500000 0.625000000000 +mp_over_link.tga 0.492187500000 0.601562500000 0.515625000000 0.625000000000 +ico_goo.tga 0.515625000000 0.601562500000 0.539062500000 0.625000000000 +us_back_0.tga 0.539062500000 0.601562500000 0.562500000000 0.625000000000 +us_back_1.tga 0.562500000000 0.601562500000 0.585937500000 0.625000000000 +us_back_2.tga 0.585937500000 0.601562500000 0.609375000000 0.625000000000 +us_back_3.tga 0.609375000000 0.601562500000 0.632812500000 0.625000000000 +us_back_4.tga 0.632812500000 0.601562500000 0.656250000000 0.625000000000 +us_back_5.tga 0.656250000000 0.601562500000 0.679687500000 0.625000000000 +us_back_6.tga 0.679687500000 0.601562500000 0.703125000000 0.625000000000 +us_back_7.tga 0.703125000000 0.601562500000 0.726562500000 0.625000000000 +us_back_8.tga 0.914062500000 0.609375000000 0.937500000000 0.632812500000 +tb_config.tga 0.726562500000 0.617187500000 0.750000000000 0.640625000000 +tb_connection.tga 0.750000000000 0.617187500000 0.773437500000 0.640625000000 +tb_contacts.tga 0.773437500000 0.617187500000 0.796875000000 0.640625000000 +tb_desk_1.tga 0.796875000000 0.617187500000 0.820312500000 0.640625000000 +tb_desk_2.tga 0.820312500000 0.617187500000 0.843750000000 0.640625000000 +tb_desk_3.tga 0.843750000000 0.617187500000 0.867187500000 0.640625000000 +tb_desk_4.tga 0.867187500000 0.617187500000 0.890625000000 0.640625000000 +tb_faction.tga 0.890625000000 0.617187500000 0.914062500000 0.640625000000 +tb_forum.tga 0.937500000000 0.617187500000 0.960937500000 0.640625000000 +tb_guild.tga 0.960937500000 0.617187500000 0.984375000000 0.640625000000 +TB_help2.tga 0.000000000000 0.625000000000 0.023437500000 0.648437500000 +tb_keys.tga 0.023437500000 0.625000000000 0.046875000000 0.648437500000 +tb_macros.tga 0.046875000000 0.625000000000 0.070312500000 0.648437500000 +tb_mail.tga 0.070312500000 0.625000000000 0.093750000000 0.648437500000 +tb_mode_dodge.tga 0.093750000000 0.625000000000 0.117187500000 0.648437500000 +tb_mode_parry.tga 0.117187500000 0.625000000000 0.140625000000 0.648437500000 +tb_over.tga 0.140625000000 0.625000000000 0.164062500000 0.648437500000 +tb_support.tga 0.164062500000 0.625000000000 0.187500000000 0.648437500000 +tb_team.tga 0.187500000000 0.625000000000 0.210937500000 0.648437500000 +tb_windows.tga 0.210937500000 0.625000000000 0.234375000000 0.648437500000 +ico_gripp.tga 0.234375000000 0.625000000000 0.257812500000 0.648437500000 +BK_zorai_brick.tga 0.257812500000 0.625000000000 0.281250000000 0.648437500000 +mf_back.tga 0.281250000000 0.625000000000 0.304687500000 0.648437500000 +mf_over.tga 0.304687500000 0.625000000000 0.328125000000 0.648437500000 +brick_default.tga 0.328125000000 0.625000000000 0.351562500000 0.648437500000 +ico_hammer.tga 0.351562500000 0.625000000000 0.375000000000 0.648437500000 +ico_harmful.tga 0.375000000000 0.625000000000 0.398437500000 0.648437500000 +ico_hatred.tga 0.398437500000 0.625000000000 0.421875000000 0.648437500000 +ico_heal.tga 0.421875000000 0.625000000000 0.445312500000 0.648437500000 +mp3.tga 0.445312500000 0.625000000000 0.468750000000 0.648437500000 +ico_hit_rate.tga 0.468750000000 0.625000000000 0.492187500000 0.648437500000 +mp_back_curative.tga 0.492187500000 0.625000000000 0.515625000000 0.648437500000 +mp_back_offensive.tga 0.515625000000 0.625000000000 0.539062500000 0.648437500000 +ico_time.tga 0.539062500000 0.625000000000 0.562500000000 0.648437500000 +ico_time_bonus.tga 0.562500000000 0.625000000000 0.585937500000 0.648437500000 +mp_back_selfonly.tga 0.585937500000 0.625000000000 0.609375000000 0.648437500000 +ico_trigger.tga 0.609375000000 0.625000000000 0.632812500000 0.648437500000 +ico_umbrella.tga 0.632812500000 0.625000000000 0.656250000000 0.648437500000 +ico_use_enchantement.tga 0.656250000000 0.625000000000 0.679687500000 0.648437500000 +ico_vampire.tga 0.679687500000 0.625000000000 0.703125000000 0.648437500000 +ico_visibility.tga 0.703125000000 0.625000000000 0.726562500000 0.648437500000 +ico_war_cry.tga 0.914062500000 0.632812500000 0.937500000000 0.656250000000 +ico_weight.tga 0.726562500000 0.640625000000 0.750000000000 0.664062500000 +ico_wellbalanced.tga 0.750000000000 0.640625000000 0.773437500000 0.664062500000 +ico_will.tga 0.773437500000 0.640625000000 0.796875000000 0.664062500000 +ico_windding.tga 0.796875000000 0.640625000000 0.820312500000 0.664062500000 +ico_wisdom.tga 0.820312500000 0.640625000000 0.843750000000 0.664062500000 +ico_incapacity.tga 0.843750000000 0.640625000000 0.867187500000 0.664062500000 +ico_intelligence.tga 0.867187500000 0.640625000000 0.890625000000 0.664062500000 +ico_interrupt.tga 0.890625000000 0.640625000000 0.914062500000 0.664062500000 +ico_invulnerability.tga 0.937500000000 0.640625000000 0.960937500000 0.664062500000 +ico_jewel_stone.tga 0.960937500000 0.640625000000 0.984375000000 0.664062500000 +us_ico_0.tga 0.000000000000 0.648437500000 0.023437500000 0.671875000000 +us_ico_1.tga 0.023437500000 0.648437500000 0.046875000000 0.671875000000 +us_ico_2.tga 0.046875000000 0.648437500000 0.070312500000 0.671875000000 +us_ico_3.tga 0.070312500000 0.648437500000 0.093750000000 0.671875000000 +us_ico_4.tga 0.093750000000 0.648437500000 0.117187500000 0.671875000000 +us_ico_5.tga 0.117187500000 0.648437500000 0.140625000000 0.671875000000 +us_ico_6.tga 0.140625000000 0.648437500000 0.164062500000 0.671875000000 +us_ico_7.tga 0.164062500000 0.648437500000 0.187500000000 0.671875000000 +us_ico_8.tga 0.187500000000 0.648437500000 0.210937500000 0.671875000000 +us_ico_9.tga 0.210937500000 0.648437500000 0.234375000000 0.671875000000 +us_over_0.tga 0.234375000000 0.648437500000 0.257812500000 0.671875000000 +us_over_1.tga 0.257812500000 0.648437500000 0.281250000000 0.671875000000 +us_over_2.tga 0.281250000000 0.648437500000 0.304687500000 0.671875000000 +us_over_3.tga 0.304687500000 0.648437500000 0.328125000000 0.671875000000 +us_over_4.tga 0.328125000000 0.648437500000 0.351562500000 0.671875000000 +building_state_24x24.tga 0.351562500000 0.648437500000 0.375000000000 0.671875000000 +cb_main_nue.tga 0.375000000000 0.648437500000 0.398437500000 0.671875000000 +fp_ammo.tga 0.398437500000 0.648437500000 0.421875000000 0.671875000000 +ico_armor_medium.tga 0.421875000000 0.648437500000 0.445312500000 0.671875000000 +ico_clothes.tga 0.445312500000 0.648437500000 0.468750000000 0.671875000000 +ico_durability.tga 0.468750000000 0.648437500000 0.492187500000 0.671875000000 +W_slot_shortcut_id0.tga 0.492187500000 0.648437500000 0.515625000000 0.671875000000 +W_slot_shortcut_id1.tga 0.515625000000 0.648437500000 0.539062500000 0.671875000000 +W_slot_shortcut_id2.tga 0.539062500000 0.648437500000 0.562500000000 0.671875000000 +W_slot_shortcut_id3.tga 0.562500000000 0.648437500000 0.585937500000 0.671875000000 +W_slot_shortcut_id4.tga 0.585937500000 0.648437500000 0.609375000000 0.671875000000 +W_slot_shortcut_id5.tga 0.609375000000 0.648437500000 0.632812500000 0.671875000000 +W_slot_shortcut_id6.tga 0.632812500000 0.648437500000 0.656250000000 0.671875000000 +W_slot_shortcut_id7.tga 0.656250000000 0.648437500000 0.679687500000 0.671875000000 +W_slot_shortcut_id8.tga 0.679687500000 0.648437500000 0.703125000000 0.671875000000 +W_slot_shortcut_id9.tga 0.703125000000 0.648437500000 0.726562500000 0.671875000000 +w_slot_shortcut_shift_id0.tga 0.914062500000 0.656250000000 0.937500000000 0.679687500000 +w_slot_shortcut_shift_id1.tga 0.726562500000 0.664062500000 0.750000000000 0.687500000000 +w_slot_shortcut_shift_id2.tga 0.750000000000 0.664062500000 0.773437500000 0.687500000000 +w_slot_shortcut_shift_id3.tga 0.773437500000 0.664062500000 0.796875000000 0.687500000000 +w_slot_shortcut_shift_id4.tga 0.796875000000 0.664062500000 0.820312500000 0.687500000000 +w_slot_shortcut_shift_id5.tga 0.820312500000 0.664062500000 0.843750000000 0.687500000000 +w_slot_shortcut_shift_id6.tga 0.843750000000 0.664062500000 0.867187500000 0.687500000000 +w_slot_shortcut_shift_id7.tga 0.867187500000 0.664062500000 0.890625000000 0.687500000000 +w_slot_shortcut_shift_id8.tga 0.890625000000 0.664062500000 0.914062500000 0.687500000000 +w_slot_shortcut_shift_id9.tga 0.937500000000 0.664062500000 0.960937500000 0.687500000000 +BK_matis_brick.tga 0.960937500000 0.664062500000 0.984375000000 0.687500000000 +ico_jewel_stone_support.tga 0.000000000000 0.671875000000 0.023437500000 0.695312500000 +ico_misfortune.tga 0.023437500000 0.671875000000 0.046875000000 0.695312500000 +pa_over_break.tga 0.046875000000 0.671875000000 0.070312500000 0.695312500000 +pa_over_less.tga 0.070312500000 0.671875000000 0.093750000000 0.695312500000 +pa_over_more.tga 0.093750000000 0.671875000000 0.117187500000 0.695312500000 +ch_back.tga 0.117187500000 0.671875000000 0.140625000000 0.695312500000 +ico_over_hit_head_x3.tga 0.140625000000 0.671875000000 0.164062500000 0.695312500000 +ico_primal.tga 0.164062500000 0.671875000000 0.187500000000 0.695312500000 +pvp_ally_0.tga 0.187500000000 0.671875000000 0.210937500000 0.695312500000 +pvp_ally_1.tga 0.210937500000 0.671875000000 0.234375000000 0.695312500000 +pvp_ally_2.tga 0.234375000000 0.671875000000 0.257812500000 0.695312500000 +pvp_ally_3.tga 0.257812500000 0.671875000000 0.281250000000 0.695312500000 +pvp_ally_4.tga 0.281250000000 0.671875000000 0.304687500000 0.695312500000 +pvp_ally_6.tga 0.304687500000 0.671875000000 0.328125000000 0.695312500000 +pvp_ally_flag.tga 0.328125000000 0.671875000000 0.351562500000 0.695312500000 +pvp_ally_primas.tga 0.351562500000 0.671875000000 0.375000000000 0.695312500000 +pvp_ally_ranger.tga 0.375000000000 0.671875000000 0.398437500000 0.695312500000 +pvp_ally_tag.tga 0.398437500000 0.671875000000 0.421875000000 0.695312500000 +bg_downloader.tga 0.421875000000 0.671875000000 0.445312500000 0.695312500000 +ico_source_knowledge.tga 0.445312500000 0.671875000000 0.466796875000 0.695312500000 +filter_tp.tga 0.468750000000 0.671875000000 0.492187500000 0.687500000000 small_task_done.tga 0.984375000000 0.000000000000 1.000000000000 0.015625000000 small_task_failed.tga 0.984375000000 0.015625000000 1.000000000000 0.031250000000 small_task_fight.tga 0.984375000000 0.031250000000 1.000000000000 0.046875000000 @@ -669,6 +679,6 @@ small_task_travel.tga 0.914062500000 0.523437500000 0.929687500000 0.53906250000 small_task_craft.tga 0.984375000000 0.546875000000 1.000000000000 0.562500000000 num_slash.tga 0.984375000000 0.562500000000 0.996093750000 0.576171875000 W_leader.tga 0.984375000000 0.578125000000 0.997070312500 0.589843750000 -tb_mode.tga 0.984375000000 0.589843750000 0.996093750000 0.601562500000 -profile.tga 0.984375000000 0.601562500000 0.996093750000 0.613281250000 -w_major.tga 0.984375000000 0.613281250000 0.996093750000 0.625000000000 +w_major.tga 0.984375000000 0.589843750000 0.996093750000 0.601562500000 +tb_mode.tga 0.984375000000 0.601562500000 0.996093750000 0.613281250000 +profile.tga 0.984375000000 0.613281250000 0.996093750000 0.625000000000 diff --git a/code/ryzom/client/data/gamedev/interfaces_v3/commands.xml b/code/ryzom/client/data/gamedev/interfaces_v3/commands.xml index ca013f242..f0455028a 100644 --- a/code/ryzom/client/data/gamedev/interfaces_v3/commands.xml +++ b/code/ryzom/client/data/gamedev/interfaces_v3/commands.xml @@ -78,9 +78,18 @@ - + + + + + + + + + + diff --git a/code/ryzom/client/data/gamedev/interfaces_v3/config.xml b/code/ryzom/client/data/gamedev/interfaces_v3/config.xml index 1d593ef06..9fb0dd958 100644 --- a/code/ryzom/client/data/gamedev/interfaces_v3/config.xml +++ b/code/ryzom/client/data/gamedev/interfaces_v3/config.xml @@ -258,6 +258,9 @@ + @@ -291,6 +294,9 @@ + @@ -327,6 +333,9 @@ + @@ -2797,6 +2806,9 @@ This MUST follow the Enum MISSION_DESC::TIconId + - + + + + + + + + @@ -3045,6 +3081,9 @@ This MUST follow the Enum MISSION_DESC::TIconId + @@ -3066,6 +3105,9 @@ This MUST follow the Enum MISSION_DESC::TIconId + @@ -3087,6 +3129,9 @@ This MUST follow the Enum MISSION_DESC::TIconId + @@ -3108,6 +3153,9 @@ This MUST follow the Enum MISSION_DESC::TIconId + @@ -3129,6 +3177,9 @@ This MUST follow the Enum MISSION_DESC::TIconId + @@ -3151,6 +3202,9 @@ This MUST follow the Enum MISSION_DESC::TIconId + @@ -3173,6 +3227,9 @@ This MUST follow the Enum MISSION_DESC::TIconId + + + diff --git a/code/ryzom/client/data/gamedev/interfaces_v3/encyclopedia.xml b/code/ryzom/client/data/gamedev/interfaces_v3/encyclopedia.xml index b2db7ab26..30f2c34a0 100644 --- a/code/ryzom/client/data/gamedev/interfaces_v3/encyclopedia.xml +++ b/code/ryzom/client/data/gamedev/interfaces_v3/encyclopedia.xml @@ -11,7 +11,7 @@ -