Area editor + sound player + various DBC pickers/editors

This commit is contained in:
T1ti
2022-11-14 23:57:28 +01:00
parent 23c3c65daf
commit c4ae144f32
14 changed files with 2585 additions and 150 deletions

View File

@@ -108,7 +108,7 @@ set(FASTNOISE2_NOISETOOL OFF CACHE BOOL "")
FIND_PACKAGE(FastNoise2 REQUIRED)
FIND_PACKAGE(Sol2 REQUIRED)
FIND_PACKAGE(Qt5 COMPONENTS Widgets OpenGL OpenGLExtensions Network Xml REQUIRED)
FIND_PACKAGE(Qt5 COMPONENTS Widgets OpenGL OpenGLExtensions Network Xml Multimedia REQUIRED)
IF(USE_SQL)
FIND_LIBRARY(MYSQL_LIBRARY NAMES libmysql
@@ -342,6 +342,7 @@ TARGET_LINK_LIBRARIES (noggit
Qt5::OpenGLExtensions
Qt5::Xml
Qt5::Network
Qt5::Multimedia
ColorWidgets-qt5
FramelessHelper
qt_imgui_widgets

View File

@@ -17,6 +17,11 @@ LightFloatBandDB gLightFloatBandDB;
GroundEffectDoodadDB gGroundEffectDoodadDB;
GroundEffectTextureDB gGroundEffectTextureDB;
LiquidTypeDB gLiquidTypeDB;
SoundProviderPreferencesDB gSoundProviderPreferencesDB;
SoundAmbienceDB gSoundAmbienceDB;
ZoneMusicDB gZoneMusicDB;
ZoneIntroMusicTableDB gZoneIntroMusicTableDB;
SoundEntriesDB gSoundEntriesDB;
void OpenDBs(std::shared_ptr<BlizzardArchive::ClientData> clientData)
{
@@ -31,6 +36,11 @@ void OpenDBs(std::shared_ptr<BlizzardArchive::ClientData> clientData)
gGroundEffectDoodadDB.open(clientData);
gGroundEffectTextureDB.open(clientData);
gLiquidTypeDB.open(clientData);
gSoundProviderPreferencesDB.open(clientData);
gSoundAmbienceDB.open(clientData);
gZoneMusicDB.open(clientData);
gZoneIntroMusicTableDB.open(clientData);
gSoundEntriesDB.open(clientData);
}
@@ -89,6 +99,18 @@ std::uint32_t AreaDB::get_area_parent(int area_id)
}
}
std::uint32_t AreaDB::get_new_areabit()
{
unsigned int areabit = 0;
for (Iterator i = gAreaDB.begin(); i != gAreaDB.end(); ++i)
{
areabit = std::max(i->getUInt(AreaDB::AreaBit), areabit);
}
return static_cast<int>(++areabit);
}
std::string MapDB::getMapName(int pMapID)
{
if (pMapID<0) return "Unknown map";

View File

@@ -17,11 +17,24 @@ public:
static const size_t AreaID = 0; // uint
static const size_t Continent = 1; // uint
static const size_t Region = 2; // uint [AreaID]
static const size_t AreaBit = 3; // uint
static const size_t Flags = 4; // bit field
static const size_t SoundProviderPreferences = 5; // uint
static const size_t UnderwaterSoundProviderPreferences = 6; // uint
static const size_t SoundAmbience = 7; // uint
static const size_t ZoneMusic = 8; // uint
static const size_t ZoneIntroMusicTable = 9; // uint
static const size_t ExplorationLevel = 10; // int
static const size_t Name = 11; // localisation string
static const size_t FactionGroup = 28; // uint
static const size_t LiquidType = 29; // uint[4]
static const size_t MinElevation = 33; // float
static const size_t AmbientMultiplier = 34; // float
static const size_t LightId = 35; // int
static std::string getAreaName(int pAreaID);
static std::uint32_t get_area_parent(int area_id);
static std::uint32_t get_new_areabit();
};
class MapDB : public DBCFile
@@ -184,6 +197,87 @@ public:
static std::string getLiquidName(int pID);
};
class SoundProviderPreferencesDB : public DBCFile
{
public:
SoundProviderPreferencesDB() :
DBCFile("DBFilesClient\\SoundProviderPreferences.dbc")
{ }
/// Fields
static const size_t ID = 0; // uint
static const size_t Description = 1; // string
};
class SoundAmbienceDB : public DBCFile
{
public:
SoundAmbienceDB() :
DBCFile("DBFilesClient\\SoundAmbience.dbc")
{ }
/// Fields
static const size_t ID = 0; // uint
static const size_t SoundEntry_day = 1; // uint
static const size_t SoundEntry_night = 2; // uint
};
class ZoneMusicDB : public DBCFile
{
public:
ZoneMusicDB() :
DBCFile("DBFilesClient\\ZoneMusic.dbc")
{ }
/// Fields
static const size_t ID = 0; // uint
static const size_t Name = 1; // string
static const size_t SilenceIntervalMinDay = 2; // uint
static const size_t SilenceIntervalMinNight = 3; // uint
static const size_t SilenceIntervalMaxDay = 4; // uint
static const size_t SilenceIntervalMaxNight = 5; // uint
static const size_t DayMusic = 6; // uint [soundEntries]
static const size_t NightMusic = 7; // uint [soundEntries]
};
class ZoneIntroMusicTableDB : public DBCFile
{
public:
ZoneIntroMusicTableDB() :
DBCFile("DBFilesClient\\ZoneIntroMusicTable.dbc")
{ }
/// Fields
static const size_t ID = 0; // uint
static const size_t Name = 1; // string
static const size_t SoundId = 2; // uint
static const size_t Priority = 3; // uint
static const size_t MinDelayMinutes = 4; // uint
};
class SoundEntriesDB : public DBCFile
{
public:
SoundEntriesDB() :
DBCFile("DBFilesClient\\SoundEntries.dbc")
{ }
/// Fields
static const size_t ID = 0; // uint
static const size_t SoundType = 1; // uint
static const size_t Name = 2; // string
static const size_t Filenames = 3; // string[10]
static const size_t Freq = 13; // uint[10)
static const size_t FilePath = 23; // string[10)
static const size_t Volume = 24; // float
static const size_t Flags = 25; // int
static const size_t minDistance = 26; // float
static const size_t distanceCutoff = 27; // float
static const size_t EAXDef = 28; // int
static const size_t soundEntriesAdvancedID = 29; // int
};
void OpenDBs(std::shared_ptr<BlizzardArchive::ClientData> clientData);
const char * getGroundEffectDoodad(unsigned int effectID, int DoodadNum);
@@ -199,3 +293,8 @@ extern LightFloatBandDB gLightFloatBandDB;
extern GroundEffectDoodadDB gGroundEffectDoodadDB;
extern GroundEffectTextureDB gGroundEffectTextureDB;
extern LiquidTypeDB gLiquidTypeDB;
extern SoundProviderPreferencesDB gSoundProviderPreferencesDB;
extern SoundAmbienceDB gSoundAmbienceDB;
extern ZoneMusicDB gZoneMusicDB;
extern ZoneIntroMusicTableDB gZoneIntroMusicTableDB;
extern SoundEntriesDB gSoundEntriesDB;

View File

@@ -181,6 +181,27 @@ public:
}
throw NotFound();
}
inline bool CheckIfIdExists(unsigned int id, size_t field = 0)
{
for (Iterator i = begin(); i != end(); ++i)
{
if (i->getUInt(field) == id)
return (true);
}
return (false);
}
inline int getRecordRowId(unsigned int id, size_t field = 0)
{
int row_id = 0;
for (Iterator i = begin(); i != end(); ++i)
{
if (i->getUInt(field) == id)
return row_id;
row_id++;
}
throw NotFound();
}
Record addRecord(size_t id, size_t id_field = 0);
Record addRecordCopy(size_t id, size_t id_from, size_t id_field = 0);

View File

@@ -1,17 +1,39 @@
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
#include <noggit/ui/ZoneIDBrowser.h>
#include <noggit/ui/windows/SoundPlayer/SoundEntryPlayer.h>
#include <noggit/ui/windows/EditorWindows/ZoneIntroMusicPickerWindow.h>
#include <noggit/ui/windows/EditorWindows/SoundEntryPickerWindow.h>
#include <noggit/ui/windows/EditorWindows/ZoneMusicPickerWindow.h>
#include <noggit/ui/tools/MapCreationWizard/Ui/MapCreationWizard.hpp>
#include <noggit/DBC.h>
#include <noggit/Log.h>
#include <noggit/Misc.h>
#include <ClientFile.hpp>
#include <noggit/application/NoggitApplication.hpp>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QFormLayout>
#include <QtWidgets/qpushbutton.h>
#include <QtWidgets/qgroupbox.h>
#include <QtWidgets/qcheckbox.h>
#include <QtWidgets/qlineedit.h>
#include <QtWidgets/QTableView>
#include <QStandardItemModel>
#include <QTableWidgetItem>
#include <QSound>
#include <qtemporaryfile>
#include <QMediaPlayer>
#include <QListWidget>
#include <QToolButton>
#include <noggit/ui/tools/UiCommon/expanderwidget.h>
#include <iostream>
#include <sstream>
#include <string>
#include <bitset>
namespace Noggit
{
@@ -22,6 +44,7 @@ namespace Noggit
, _area_tree(new QTreeWidget())
, mapID(-1)
{
auto layout = new QFormLayout(this);
_radius_spin = new QDoubleSpinBox(this);
@@ -35,8 +58,21 @@ namespace Noggit
_radius_slider->setRange(0, 250);
_radius_slider->setSliderPosition(_radius);
QPushButton* edit_area_button = new QPushButton("Edit selected Area", this);
edit_area_button->setIcon(Noggit::Ui::FontAwesomeIcon(Noggit::Ui::FontAwesome::cog));
QPushButton* add_zone_button = new QPushButton("Add a new Zone(parent Area)", this);
add_zone_button->setIcon(Noggit::Ui::FontAwesomeIcon(Noggit::Ui::FontAwesome::plus));
QPushButton* add_subzone_button = new QPushButton("Add a new Subzone(selected as Parent)", this);
add_subzone_button->setIcon(Noggit::Ui::FontAwesomeIcon(Noggit::Ui::FontAwesome::plus));
_area_editor = new AreaEditor(this);
layout->addRow(_radius_slider);
layout->addRow(_area_tree);
layout->addRow(edit_area_button);
layout->addRow(add_zone_button);
layout->addRow(add_subzone_button);
setMinimumWidth(250);
@@ -51,6 +87,12 @@ namespace Noggit
}
);
connect(_area_tree, &QTreeWidget::itemDoubleClicked
, [this]
{
open_area_editor();
});
connect(_radius_spin, qOverload<double>(&QDoubleSpinBox::valueChanged)
, [&](double v)
{
@@ -68,6 +110,18 @@ namespace Noggit
_radius_spin->setValue(v);
}
);
connect(edit_area_button, &QPushButton::clicked, [=]() {
open_area_editor();
});
connect(add_zone_button, &QPushButton::clicked, [=]() {
add_new_zone();
});
connect(add_subzone_button, &QPushButton::clicked, [=]() {
add_new_subzone();
});
}
void zone_id_browser::setMapID(int id)
@@ -132,6 +186,17 @@ namespace Noggit
_radius_spin->setValue(radius);
}
int zone_id_browser::GetSelectedAreaId()
{
auto const& selected_items = _area_tree->selectedItems();
if (selected_items.size())
{
int selected_area_id = selected_items.back()->data(0, 1).toInt();
return selected_area_id;
}
return 0;
}
QTreeWidgetItem* zone_id_browser::create_or_get_tree_widget_item(int area_id)
{
auto it = _items.find(area_id);
@@ -145,7 +210,18 @@ namespace Noggit
QTreeWidgetItem* item = new QTreeWidgetItem();
std::stringstream ss;
ss << area_id << "-" << gAreaDB.getAreaName(area_id);
// ss << area_id << "-" << gAreaDB.getAreaName(area_id);
std::string areaName = "";
try
{
AreaDB::Record rec = gAreaDB.getByID(area_id);
areaName = rec.getLocalizedString(AreaDB::Name);
}
catch (AreaDB::NotFound)
{
areaName = "Unknown location";
}
ss << area_id << "-" << areaName;
item->setData(0, 1, QVariant(area_id));
item->setText(0, QString(ss.str().c_str()));
_items.emplace(area_id, item);
@@ -172,5 +248,553 @@ namespace Noggit
return item;
}
void zone_id_browser::open_area_editor()
{
// opens and loads the area editor with the currently selected item in the tree.
int selected_area_id = GetSelectedAreaId();
if (selected_area_id != 0)
{
_area_editor->load_area(selected_area_id);
_area_editor->show();
}
else
{
// No selected area popup
}
}
void zone_id_browser::add_new_zone()
{
// create new zone area id
auto new_id = gAreaDB.getEmptyRecordID();
auto new_record = gAreaDB.addRecord(new_id);
// init some defaults
new_record.write(AreaDB::Continent, mapID);
// get new areabit
new_record.write(AreaDB::AreaBit, gAreaDB.get_new_areabit());
new_record.write(AreaDB::Flags, 64); // allow dueling, seems to the be the common default for regions
new_record.write(AreaDB::UnderwaterSoundProviderPreferences, 11); // underwater sound pref, usually set
// locale stuff
new_record.writeString(AreaDB::Name, "Unnamed Noggit Zone"); // only write default name for enUS and enGB ? maybe get the client's locale somehow
new_record.writeString(AreaDB::Name + 1, "Unnamed Noggit Zone"); // enGB
new_record.write(AreaDB::Name + 16, 16712190); // loc mask, only verified for enUS
new_record.write(AreaDB::MinElevation, -500.0f); // loc mask, only verified for enUS
// save dbc instantly ?
gAreaDB.save();
// add to tree
auto areawidgetitem = add_area(new_id);
// select the new item
_area_tree->clearSelection();
areawidgetitem->setSelected(true);
open_area_editor();// open the editor
}
void zone_id_browser::add_new_subzone()
{
// create new subzone area id
// set selected as parent
int selected_areaid = GetSelectedAreaId();
if (!selected_areaid) // no valid item selected
return;
// check if it's a valid parent : it shouldn't have a parent
std::uint32_t selected_parent_area_id = gAreaDB.get_area_parent(selected_areaid); // the selected area's parentid
if (selected_parent_area_id)
{
// error, parent must not have a parent
QMessageBox messagebox;
messagebox.setIcon(QMessageBox::Information);
messagebox.setWindowIcon(QIcon(":/icon"));
messagebox.setWindowTitle("Wrong Parent type");
messagebox.setText("The parent must be a Zone, not a Subzone.");
messagebox.exec();
return;
}
auto new_id = gAreaDB.getEmptyRecordID();
auto new_record = gAreaDB.addRecord(new_id);
// init some defaults
new_record.write(AreaDB::Continent, mapID);
new_record.write(AreaDB::Region, selected_areaid); // set selecetd area as parent.
// get new areabit
new_record.write(AreaDB::AreaBit, gAreaDB.get_new_areabit());
new_record.write(AreaDB::Flags, 1073759296); // allow dueling + force area on dynamic transport + enable flight bounds+ subzone flags
new_record.write(AreaDB::UnderwaterSoundProviderPreferences, 11); // underwater sound pref, usually set
// lcoale stuff
new_record.writeString(AreaDB::Name, "Unnamed Noggit Subzone"); // only write default name for enUS and enGB ? maybe get the client's locale somehow
new_record.writeString(AreaDB::Name + 1, "Unnamed Noggit Subzone"); // enGB
new_record.write(AreaDB::Name + 16, 16712190); // loc mask, only verified for enUS
new_record.write(AreaDB::MinElevation, -500.0f); // loc mask, only verified for enUS
// save dbc instantly ?
gAreaDB.save();
// add to tree
auto areawidgetitem = add_area(new_id);
// select the new item
_area_tree->clearSelection();
areawidgetitem->setSelected(true);
open_area_editor();// open the editor
}
AreaEditor::AreaEditor(QWidget* parent)
: QWidget(parent)
{
setWindowTitle("Area Editor");
setWindowFlags(Qt::Dialog);
// setWindowFlags(Qt::Widget);
auto main_layout = new QHBoxLayout(this);
QGroupBox* area_settings_group = new QGroupBox("Area Settings", this);
main_layout->addWidget(area_settings_group);
auto layout = new QFormLayout(area_settings_group);
// main_layout->addLayout(layout);
_area_id_label = new QLabel("0", this);
_area_id_label->setEnabled(false);
_parent_area_label = new QLabel("-NONE-", area_settings_group);
_parent_area_label->setEnabled(false);
// auto parent_set_layout = new QHBoxLayout(this);
_set_parent_button = new QPushButton("Set Selected Zone as Parent", area_settings_group);
// QPushButton* unset_parent_button = new QPushButton("Unset Parent", this);
// parent_set_layout->addWidget(set_parent_button);
// parent_set_layout->addWidget(unset_parent_button);
_area_name = new Tools::MapCreationWizard::Ui::LocaleDBCEntry(area_settings_group);
_exploration_level_spinbox = new QSpinBox(this);
_exploration_level_spinbox->setRange(-1, 255);
_ambiant_multiplier = new QSlider(Qt::Horizontal, this);
_ambiant_multiplier->setRange(0, 100); // 0.0 - 1.0, decimal not supported so *100
_ambiant_multiplier->setTickInterval(5);
_ambiant_multiplier->setSingleStep(5);
// faction group
// read FactionGroup.dbc or just hardcode?
_faction_group_combobox = new QComboBox(this);
_faction_group_combobox->addItem("Contested"); // 0
_faction_group_combobox->addItem("Alliance"); // 2
_faction_group_combobox->addItem("Horde"); // 4
_faction_group_combobox->addItem("Horde & Alliance"); // mask : 2 + 4
// _liquid_type_water_combobox = new QComboBox(this);
// _liquid_type_water_combobox->addItem("None");
// _liquid_type_ocean_combobox = new QComboBox(this);
// _liquid_type_ocean_combobox->addItem("None");
// _liquid_type_magma_combobox = new QComboBox(this);
// _liquid_type_magma_combobox->addItem("None");
// _liquid_type_slime_combobox = new QComboBox(this);
// _liquid_type_slime_combobox->addItem("None");
// for (DBCFile::Iterator i = gLiquidTypeDB.begin(); i != gLiquidTypeDB.end(); ++i)
// {
// std::stringstream ss;
// int liquid_type = i->getInt(LiquidTypeDB::Type);
// ss << i->getInt(LiquidTypeDB::ID) << "-" << i->getString(LiquidTypeDB::Name);
// switch (liquid_type)
// {
// case 0:
// _liquid_type_water_combobox->addItem(i->getString(LiquidTypeDB::Name));
// break;
// case 1:
// _liquid_type_ocean_combobox->addItem(i->getString(LiquidTypeDB::Name));
// break;
// case 2:
// _liquid_type_magma_combobox->addItem(i->getString(LiquidTypeDB::Name));
// break;
// case 3:
// _liquid_type_slime_combobox->addItem(i->getString(LiquidTypeDB::Name));
// }
// }
_sound_provider_preferences_cbbox = new QComboBox(this);
_sound_provider_preferences_cbbox->addItem("None");
_underwater_sound_provider_preferences_cbbox = new QComboBox(this);
_underwater_sound_provider_preferences_cbbox->addItem("None");
for (DBCFile::Iterator i = gSoundProviderPreferencesDB.begin(); i != gSoundProviderPreferencesDB.end(); ++i)
{
std::stringstream ss;
ss << i->getInt(SoundProviderPreferencesDB::ID) << "-" << i->getString(SoundProviderPreferencesDB::Description);
_sound_provider_preferences_cbbox->addItem(ss.str().c_str());
_underwater_sound_provider_preferences_cbbox->addItem(ss.str().c_str());
}
_sound_ambiance_day_button = new QPushButton("-None-", this);
_sound_ambiance_day_button->setProperty("id", 0);
connect(_sound_ambiance_day_button, &QPushButton::clicked, [=]() {
auto window = new SoundEntryPickerWindow(_sound_ambiance_day_button, SoundEntryTypes::ZONE_AMBIENCE, false, this);
window->show();
});
_sound_ambiance_night_button = new QPushButton("-None-", this);
_sound_ambiance_night_button->setProperty("id", 0);
connect(_sound_ambiance_night_button, &QPushButton::clicked, [=]() {
auto window = new SoundEntryPickerWindow(_sound_ambiance_night_button, SoundEntryTypes::ZONE_AMBIENCE, false, this);
window->show();
});
_zone_music_button = new QPushButton("-None-", this);
_zone_music_button->setProperty("id", 0);
connect(_zone_music_button, &QPushButton::clicked, [=]() {
auto window = new ZoneMusicPickerWindow(_zone_music_button, this);
window->show();
});
_zone_intro_music_button = new QPushButton("-None-", this);
_zone_intro_music_button->setProperty("id", 0);
connect(_zone_intro_music_button, &QPushButton::clicked, [=]() {
auto window = new ZoneIntroMusicPickerWindow(_zone_intro_music_button, this);
window->show();
});
// advanced settings group
auto* AdvancedOptionsBox = new ExpanderWidget(this);
AdvancedOptionsBox->setExpanderTitle("Advanced Options");
// selectionOptionsBox->setExpanded(_settings->value("object_editor/movement_options", false).toBool());
auto advancedOptionsBox_content = new QWidget(this);
auto advancedOptions_layout = new QFormLayout(advancedOptionsBox_content);
// advancedOptions_layout->setAlignment(Qt::AlignTop);
AdvancedOptionsBox->addPage(advancedOptionsBox_content);
AdvancedOptionsBox->setExpanded(false);
_min_elevation_spinbox = new QDoubleSpinBox(this);
_min_elevation_spinbox->setRange(-5000, 5000); // only 3 known values : -5000, -500, 1000
_min_elevation_spinbox->setSingleStep(100);
advancedOptions_layout->addRow("Min Elevation:", _min_elevation_spinbox);
advancedOptions_layout->addRow("Ambiant Multiplier:", _ambiant_multiplier);
// advancedOptions_layout->addRow("Water Liquid Type override:", _liquid_type_water_combobox);
// advancedOptions_layout->addRow("Ocean Liquid Type override:", _liquid_type_ocean_combobox);
// advancedOptions_layout->addRow("Magma Liquid Type override:", _liquid_type_magma_combobox);
// advancedOptions_layout->addRow("Slime Liquid Type override:", _liquid_type_slime_combobox);
advancedOptions_layout->addRow("Sound Provider Preference:", _sound_provider_preferences_cbbox);
advancedOptions_layout->addRow("Underwater Sound Provider Preference:", _underwater_sound_provider_preferences_cbbox);
QPushButton* save_area_button = new QPushButton("Save changes (write DBC)", this);
// TODO : unset parent button?
// flags tab **************************//
QGroupBox* area_flags_group = new QGroupBox("Flags", this);
main_layout->addWidget(area_flags_group);
auto flags_layout = new QVBoxLayout(area_flags_group);
_flags_value_spinbox = new QSpinBox(this);
_flags_value_spinbox->setRange(0, INT_MAX); // uint?
flags_layout->addWidget(_flags_value_spinbox);
// TODO : update checkboxes when value is changed, temporarly disable it from edit
_flags_value_spinbox->setEnabled(false);
for (int i = 0; i < 31; ++i)
{
QCheckBox* flag_checkbox = new QCheckBox(QString::fromStdString(area_flags_names.at(i)), this);
flags_checkboxes[i] = flag_checkbox;
flags_layout->addWidget(flag_checkbox);
connect(flag_checkbox, &QCheckBox::stateChanged, [&, i](bool state) {
// connect(flag_checkbox, &QCheckBox::clicked, [=]() {
// int old_value = _flags_value_spinbox->value();
int new_value = _flags_value_spinbox->value();
if (state) // set bit
new_value |= (1ULL << (i));
else // remove bit
new_value &= ~(1ULL << (i));
_flags_value_spinbox->setValue(new_value);
});
}
// hide some useless flags to gain space
flags_checkboxes[30]->setEnabled(false); // user can't set subzone flag.
flags_checkboxes[30]->setHidden(true); // subzone flag
flags_checkboxes[20]->setHidden(true); // tournement realm thingy, useless for pservers
flags_checkboxes[17]->setHidden(true); // "Area not in use", prob some blizz dev stuff
//************************************//
layout->addRow("Area ID:", _area_id_label);
layout->addRow("Area Name:", _area_name);
layout->addWidget(_set_parent_button);
layout->addRow("Parent Area ID:", _parent_area_label);
layout->addRow("Faction Group:", _faction_group_combobox);
layout->addRow("Exploration Level:", _exploration_level_spinbox);
layout->addRow("Zone Music:", _zone_music_button);
layout->addRow("Zone Intro Music:", _zone_intro_music_button);
layout->addRow("Sound Ambience Day:", _sound_ambiance_day_button);
layout->addRow("Sound Ambience Night:", _sound_ambiance_night_button);
layout->addRow(AdvancedOptionsBox);
layout->addRow(save_area_button);
layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding));
// main_layout->addStretch();
connect(_set_parent_button, &QPushButton::clicked, [=]() {
// Current design choice : Cannot change a zone to be a subzone or the opposite, only current subzones can have a parent set.
auto parent = static_cast<zone_id_browser*>(this->parentWidget());
auto tree_selected_id = parent->GetSelectedAreaId();
if (!tree_selected_id)
return;
// can only set a zone as parent, not a subzone.
// a zone must be a top level item, and not have a parent or the subzone flag.
// checks :
// 1 : current area must be a subzone
if (!_parent_area_id)
return;
std::uint32_t selected_parent_area_id = gAreaDB.get_area_parent(tree_selected_id); // the selected area's parentid
if (selected_parent_area_id)
{
// error, parent must not have a parent
QMessageBox messagebox;
messagebox.setIcon(QMessageBox::Information);
messagebox.setWindowIcon(QIcon(":/icon"));
messagebox.setWindowTitle("Wrong Parent type");
messagebox.setText("The parent must be a Zone, not a Subzone.");
messagebox.exec();
return;
}
// can't be self
if (tree_selected_id == _parent_area_id)
return;// same parent, ignore
if (tree_selected_id == _area_id_label->text().toInt())
return; // error, can't select self
// save the change for the session (don't write dbc yet)
_parent_area_id = tree_selected_id;
std::stringstream ss;
ss << _parent_area_id << "-" << gAreaDB.getAreaName(_parent_area_id);
_parent_area_label->setText(ss.str().c_str());
// _parent_area_label->setText(std::to_string( tree_selected_id).c_str());
auto curr_record = gAreaDB.getByID(_area_id_label->text().toInt());
curr_record.write(AreaDB::Region, tree_selected_id);
// update the tree
parent->buildAreaList();
// select the item ?
auto item = parent->create_or_get_tree_widget_item(_area_id_label->text().toInt());
// parent->selected(_area_id_label->text().toInt());
});
connect(save_area_button, &QPushButton::clicked, [=]() {
save_area();// save and write DBC
});
connect(_flags_value_spinbox, qOverload<int>(&QSpinBox::valueChanged), [&](int v) {
// std::bitset<32> IntBits(_flags_value_spinbox->value());
//
// for (int i = 0; i < 31; i++)
// flags_checkboxes[i]->setChecked(IntBits[i]);
});
}
void AreaEditor::load_area(int area_id)
{
DBCFile::Record record = gAreaDB.getByID(area_id);
// record.getString(AreaDB::Name)
_area_id_label->setText(QString(std::to_string(area_id).c_str()));
_areabit = record.getInt(AreaDB::AreaBit);
_parent_area_id = record.getInt(AreaDB::Region);
if (_parent_area_id)
{
std::stringstream ss;
ss << _parent_area_id << "-" << gAreaDB.getAreaName(_parent_area_id);
_parent_area_label->setText(ss.str().c_str());
}
else
_parent_area_label->setText("-NONE-");
// hide some UI if not subzone
_set_parent_button->setHidden(_parent_area_id ? false : true);
// _area_name_ledit->setText(record.getString(AreaDB::Name));
_area_name->fill(record, AreaDB::Name);
_flags_value_spinbox->setValue(record.getInt(AreaDB::Flags));
std::bitset<32> IntBits(_flags_value_spinbox->value());
for (int i = 0; i < 31; i++)
flags_checkboxes[i]->setChecked(IntBits[i]);
_exploration_level_spinbox->setValue(record.getInt(AreaDB::ExplorationLevel));
int faction_group_mask = record.getInt(AreaDB::FactionGroup);
switch (faction_group_mask) // hardcoded but can be read from factiongroup.dbc
{
case 2:
_faction_group_combobox->setCurrentIndex(1);
break;
case 4:
_faction_group_combobox->setCurrentIndex(2);
break;
case 6:
_faction_group_combobox->setCurrentIndex(3);
break;
default:
_faction_group_combobox->setCurrentIndex(0);
}
_min_elevation_spinbox->setValue(record.getFloat(AreaDB::MinElevation)); // only 3 known values : -5000, -500, 1000
_ambiant_multiplier->setValue(record.getFloat(AreaDB::AmbientMultiplier) * 100);
int sound_provider_id = record.getInt(AreaDB::SoundProviderPreferences);
if (sound_provider_id != 0)
{
int row_id = gSoundProviderPreferencesDB.getRecordRowId(sound_provider_id);
_sound_provider_preferences_cbbox->setCurrentIndex(row_id + 1); // index 0 = "None"
}
else
_sound_provider_preferences_cbbox->setCurrentIndex(0);
int underwater_sound_provider_id = record.getInt(AreaDB::UnderwaterSoundProviderPreferences);
if (underwater_sound_provider_id != 0)
{
int row_id = gSoundProviderPreferencesDB.getRecordRowId(underwater_sound_provider_id);
_underwater_sound_provider_preferences_cbbox->setCurrentIndex(row_id + 1); // index 0 = "None"
}
else
_underwater_sound_provider_preferences_cbbox->setCurrentIndex(0);
int zone_music_id = record.getInt(AreaDB::ZoneMusic);
_zone_music_button->setProperty("id", zone_music_id);
if (zone_music_id != 0)
{
auto zone_music_record = gZoneMusicDB.getByID(zone_music_id);
std::stringstream ss;
ss << zone_music_id << "-" << zone_music_record.getString(ZoneMusicDB::Name);
_zone_music_button->setText(ss.str().c_str());
}
else
_zone_music_button->setText("-NONE-");
int zone_intro_music_id = record.getInt(AreaDB::ZoneIntroMusicTable);
_zone_intro_music_button->setProperty("id", zone_intro_music_id);
if (zone_intro_music_id != 0)
{
auto zone_intro_music_record = gZoneIntroMusicTableDB.getByID(zone_intro_music_id);
std::stringstream ss;
ss << zone_intro_music_id << "-" << zone_intro_music_record.getString(ZoneIntroMusicTableDB::Name);
_zone_intro_music_button->setText(ss.str().c_str());
}
else
_zone_intro_music_button->setText("-NONE-");
int sound_ambiance_id = record.getInt(AreaDB::SoundAmbience);
if (sound_ambiance_id != 0)
{
auto sound_ambiance_record = gSoundAmbienceDB.getByID(sound_ambiance_id);
int day_sound_id = sound_ambiance_record.getInt(SoundAmbienceDB::SoundEntry_day);
auto sound_entry_day_record = gSoundEntriesDB.getByID(day_sound_id);
int night_sound_id = sound_ambiance_record.getInt(SoundAmbienceDB::SoundEntry_night);
auto sound_entry_night_record = gSoundEntriesDB.getByID(night_sound_id);
std::stringstream ss_day;
ss_day << day_sound_id << "-" << sound_entry_day_record.getString(SoundEntriesDB::Name);
_sound_ambiance_day_button->setText(ss_day.str().c_str());
_sound_ambiance_day_button->setProperty("id", day_sound_id);
std::stringstream ss_night;
ss_night << night_sound_id << "-" << sound_entry_night_record.getString(SoundEntriesDB::Name);
_sound_ambiance_night_button->setText(ss_night.str().c_str());
_sound_ambiance_night_button->setProperty("id", night_sound_id);
}
else
{
_sound_ambiance_day_button->setProperty("id", 0);
_sound_ambiance_day_button->setText("-NONE-");
_sound_ambiance_night_button->setProperty("id", 0);
_sound_ambiance_night_button->setText("-NONE-");
}
}
void AreaEditor::save_area()
{
DBCFile::Record record = gAreaDB.getByID(_area_id_label->text().toInt()); // is_new_record ? gLightDB.addRecord(Id) : gLightDB.getByID(Id);
// record.write(AreaDB::ID, entry_id);
// rewrite mapid ?
record.write(AreaDB::Region, _parent_area_id);
record.write(AreaDB::AreaBit, _areabit);
record.write(AreaDB::Flags, _flags_value_spinbox->value());
int SoundProviderPreferences_id = 0;
if (_sound_provider_preferences_cbbox->currentIndex() != 0)
{
auto rec = gSoundProviderPreferencesDB.getRecord(_sound_provider_preferences_cbbox->currentIndex() - 1);
SoundProviderPreferences_id = rec.getInt(SoundProviderPreferencesDB::ID);
}
record.write(AreaDB::SoundProviderPreferences, SoundProviderPreferences_id);
int underwaterSoundProviderPreferences_id = 0;
if (_underwater_sound_provider_preferences_cbbox->currentIndex() != 0)
{
auto rec = gSoundProviderPreferencesDB.getRecord(_underwater_sound_provider_preferences_cbbox->currentIndex() - 1);
underwaterSoundProviderPreferences_id = rec.getInt(SoundProviderPreferencesDB::ID);
}
record.write(AreaDB::UnderwaterSoundProviderPreferences, underwaterSoundProviderPreferences_id);
// Ambiance ID. Blizzard stores those as unamed pair
// Just iterate the DBC to see if an entry with our settings already exists, if not create it.
// The reasoning for not having a selector/picker with the existing pairs is that it has less freedom, is harder to use and it's ugly if they don't have a name.
// This doesn't have the option to edit that entry for all its users though.
bool sound_ambiance_exists {false};
for (DBCFile::Iterator i = gSoundAmbienceDB.begin(); i != gSoundAmbienceDB.end(); ++i)
{
int day_id = i->getInt(SoundAmbienceDB::SoundEntry_day);
int night_id = i->getInt(SoundAmbienceDB::SoundEntry_night);
if (day_id == _sound_ambiance_day_button->property("id").toInt() && night_id == _sound_ambiance_night_button->property("id").toInt())
{
record.write(AreaDB::SoundAmbience, i->getInt(SoundAmbienceDB::ID));
sound_ambiance_exists = true;
break;
}
}
if (!sound_ambiance_exists)
{
// create new sond entry record
auto new_id = gSoundAmbienceDB.getEmptyRecordID();
auto new_record = gSoundAmbienceDB.addRecord(new_id);
new_record.write(SoundAmbienceDB::SoundEntry_day, _sound_ambiance_day_button->property("id").toInt());
new_record.write(SoundAmbienceDB::SoundEntry_night, _sound_ambiance_night_button->property("id").toInt());
gSoundAmbienceDB.save();
}
record.write(AreaDB::ZoneMusic, _zone_music_button->property("id").toInt());
record.write(AreaDB::ZoneIntroMusicTable, _zone_intro_music_button->property("id").toInt());
record.write(AreaDB::ExplorationLevel, _exploration_level_spinbox->value());
_area_name->toRecord(record, AreaDB::Name);
record.write(AreaDB::FactionGroup, _faction_group_combobox->currentIndex() * 2);
record.write(AreaDB::MinElevation, static_cast<float>(_min_elevation_spinbox->value()));
record.write(AreaDB::AmbientMultiplier, _ambiant_multiplier->value() / 100.0f);
record.write(AreaDB::LightId, 0); // never used
gAreaDB.save();
}
}
}

View File

@@ -2,10 +2,21 @@
#pragma once
#include <noggit/DBC.h>
#include <noggit/ui/tools/MapCreationWizard/Ui/MapCreationWizard.hpp>
#include <QtWidgets/QWidget>
#include <QtWidgets/QTreeWidget>
#include <QtWidgets/QDoubleSpinBox>
#include <QtWidgets/QSlider>
#include <QtWidgets/QCheckBox.h>
#include <QtWidgets/QComboBox.h>
#include <QtWidgets/QLabel>
#include <QtWidgets/QListWidget>
#include <QtWidgets/QListView>
#include <QtWidgets/QTableView>
#include <QtWidgets/QPushButton>
#include <QMediaPlayer>
#include <functional>
#include <string>
@@ -14,6 +25,78 @@ namespace Noggit
{
namespace Ui
{
static std::map <int, std::string> area_flags_names = {
{0 , "Emit Breath Particles"},
{1 , "Breath Particles Override Parent"},
{2 , "On Map Dungeon"},
{3 , "Allow Trade Channel"},
{4 , "Enemies PvP Flagged"},
{5 , "Allow Resting"},
{6 , "Allow Dueling"},
{7 , "Free For All PvP"},
{8 , "Linked Chat (Set in cities)"},
{9 , "Linked Chat Special Area"},
{10, "Force this area when on a Dynamic Transport"},
{11, "No PvP"},
{12, "No Ghost on Release"},
{13, "Sub-zone Ambient Multiplier"},
{14, "Enable Flight Bounds on Map"},
{15, "PVP POI"},
{16, "No chat channels"},
{17, "Area not in use"},
{18, "Contested"},
{19, "No Player Summoning"},
{20, "No Dueling if Tournament Realm"},
{21, "Players Call Guards"},
{22, "Horde Resting"},
{23, "Alliance Resting"},
{24, "Combat Zone"},
{25, "Force Indoors"},
{26, "Force Outdoors"},
{27, "Allow Hearth-and-Resurrect from Area"},
{28, "No Local Defense Channel"},
{29, "Only Evaluate Ghost Bind Once"},
{30, "Is Subzone"},
// {31, "Don't Evaluate Graveyard From Client"}
};
class AreaEditor : public QWidget
{
Q_OBJECT
public:
AreaEditor(QWidget* parent = nullptr);
void load_area(int area_id);
private:
QLabel* _area_id_label;
QLabel* _parent_area_label;
int _parent_area_id = 0;
QPushButton* _set_parent_button;
QSpinBox* _flags_value_spinbox;
Tools::MapCreationWizard::Ui::LocaleDBCEntry* _area_name;
QCheckBox* flags_checkboxes[31]{ 0 };
QSpinBox* _exploration_level_spinbox;
QDoubleSpinBox* _min_elevation_spinbox;
QSlider* _ambiant_multiplier;
QComboBox* _faction_group_combobox;
QComboBox* _sound_provider_preferences_cbbox;
QComboBox* _underwater_sound_provider_preferences_cbbox;
// QComboBox* _liquid_type_water_combobox;
// QComboBox* _liquid_type_ocean_combobox;
// QComboBox* _liquid_type_magma_combobox;
// QComboBox* _liquid_type_slime_combobox;
QPushButton* _zone_music_button;
QPushButton* _zone_intro_music_button;
QPushButton* _sound_ambiance_day_button;
QPushButton* _sound_ambiance_night_button;
void save_area();
int _areabit = 0;
};
class zone_id_browser : public QWidget
{
Q_OBJECT
@@ -27,6 +110,10 @@ namespace Noggit
float brushRadius() const { return _radius; }
int GetSelectedAreaId();
void buildAreaList();
QTreeWidgetItem* create_or_get_tree_widget_item(int area_id);
signals:
void selected (int area_id);
@@ -36,13 +123,18 @@ namespace Noggit
QSlider* _radius_slider;
QDoubleSpinBox* _radius_spin;
AreaEditor* _area_editor;
std::map<int, QTreeWidgetItem*> _items;
int mapID;
float _radius = 15.0f;
void buildAreaList();
QTreeWidgetItem* create_or_get_tree_widget_item(int area_id);
QTreeWidgetItem* add_area(int area_id);
void open_area_editor();
void add_new_zone();
void add_new_subzone();
};
}
}

View File

@@ -0,0 +1,479 @@
#include "SoundEntryPickerWindow.h"
#include <noggit/ui/windows/SoundPlayer/SoundEntryPlayer.h>
// #include <noggit/ui/ZoneIDBrowser.h>
#include <noggit/DBC.h>
#include <noggit/Log.h>
#include <noggit/Misc.h>
#include <ClientFile.hpp>
#include <noggit/application/NoggitApplication.hpp>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QFormLayout>
#include <QtWidgets/qpushbutton.h>
#include <QtWidgets/qgroupbox.h>
#include <QtWidgets/qcheckbox.h>
#include <QtWidgets/qlineedit.h>
#include <QtWidgets/QTableView>
#include <QStandardItemModel>
#include <QTableWidgetItem>
#include <QSound>
#include <qtemporaryfile>
#include <QMediaPlayer>
#include <QListWidget>
#include <QToolButton>
#include <iostream>
#include <sstream>
#include <string>
namespace Noggit
{
namespace Ui
{
SoundEntryPickerWindow::SoundEntryPickerWindow(QPushButton* button, int sound_type_filter, bool allow_none, QWidget* parent)
: QWidget(parent)
{
setWindowTitle("Sound Entry Picker");
setWindowFlags(Qt::Dialog);
auto layout = new QHBoxLayout(this);
auto list_layout = new QVBoxLayout(this);
auto Editor_layout = new QVBoxLayout(this);
layout->addLayout(list_layout);
layout->addLayout(Editor_layout);
_tree_searchbar = new QLineEdit(this);
list_layout->addWidget(_tree_searchbar);
_tree_filter_cbbox = new QComboBox(this);
_tree_filter_cbbox->addItem("Show All");
for (auto sound_types : sound_types_names)
{
_tree_filter_cbbox->addItem(sound_types.second.c_str());
}
list_layout->addWidget(_tree_filter_cbbox);
_picker_listview = new QListWidget(this);
_picker_listview->setFixedSize(280, 460);
_picker_listview->setSelectionMode(QListWidget::SingleSelection);
// _picker_listview->setSelectionBehavior(QAbstractItemView::SelectionBehavior::SelectRows);
list_layout->addWidget(_picker_listview);
if (sound_type_filter == -1)
{
_tree_filter_cbbox->setCurrentIndex(0);
filter_sound_type(sound_type_filter, true);
}
else
{
int row_id = 0;
for (auto sound_type_pair : sound_types_names)
{
if (sound_type_pair.first == sound_type_filter)
{
_tree_filter_cbbox->setCurrentIndex(row_id + 1);
filter_sound_type(sound_type_filter);
break;
}
row_id++;
}
}
auto select_entry_btn = new QPushButton("Select Entry", this);
auto select_entry_none_btn = new QPushButton("Select -NONE-", this);
auto duplicate_entry_btn = new QPushButton("Duplicate selected Entry (create new)", this);
list_layout->addWidget(duplicate_entry_btn);
list_layout->addWidget(select_entry_btn);
list_layout->addWidget(select_entry_none_btn);
list_layout->addStretch();
// Editor frame
QGroupBox* editor_group = new QGroupBox("Edit Selected Entry", this);
Editor_layout->addWidget(editor_group);
auto editor_form_layout = new QFormLayout(editor_group);
_entry_id_lbl = new QLabel(this);
editor_form_layout->addRow("Id:", _entry_id_lbl);
_entry_id_lbl->setEnabled(false);
_name_ledit = new QLineEdit(this);
editor_form_layout->addRow("Sound Entry Name:", _name_ledit);
_sound_type_cbbox = new QComboBox(this);
for (auto sound_type : sound_types_names)
{
_sound_type_cbbox->addItem(sound_type.second.c_str(), sound_type.first);
}
editor_form_layout->addRow("Sound Type:", _sound_type_cbbox);
_volume_slider = new QSlider(Qt::Horizontal, this);
_volume_slider->setMaximum(100);
// ticks should be 1, should bt QT's default ?
editor_form_layout->addRow("Volume:", _volume_slider);
_min_distance_spinbox = new QSpinBox(this);
_min_distance_spinbox->setMaximum(1000);
editor_form_layout->addRow("Min Distance:", _min_distance_spinbox);
_max_distance_spinbox = new QSpinBox(this);
_max_distance_spinbox->setMaximum(1000);
editor_form_layout->addRow("Distance Cut off:", _max_distance_spinbox);
_eax_type_cbbox = new QComboBox(this);
_eax_type_cbbox->addItem("None");
_eax_type_cbbox->addItem("Effect 1");
_eax_type_cbbox->addItem("Effect 2");
editor_form_layout->addRow("EAX definition:", _eax_type_cbbox);
_flag6_checkbox = new QCheckBox("Use OS sound settings", this);
editor_form_layout->addRow(_flag6_checkbox);
_flag10_checkbox = new QCheckBox("PlaySpellLoopedSound", this);
editor_form_layout->addRow(_flag10_checkbox);
_flag11_checkbox = new QCheckBox("SetFrequencyAndVolume", this);
editor_form_layout->addRow(_flag11_checkbox);
_directory_ledit = new QLineEdit(this);
editor_form_layout->addRow("Directory Path", _directory_ledit);
auto filecount_layout = new QHBoxLayout(this);
Editor_layout->addLayout(filecount_layout);
_filescount_lbl = new QLabel(this);
filecount_layout->addWidget(_filescount_lbl);
auto add_file_button = new QPushButton("Add sound file");
filecount_layout->addWidget(add_file_button);
_files_listview = new QListWidget(this);
_files_listview->setFixedHeight(400);
// _files_listview->setFixedSize(280, 460);
_files_listview->setSelectionMode(QListWidget::SingleSelection);
Editor_layout->addWidget(_files_listview);
auto save_music_entry_btn = new QPushButton("Save changes", this);
Editor_layout->addWidget(save_music_entry_btn, 0, Qt::AlignRight);
Editor_layout->addStretch();
/// check if needed
select_entry(button->property("id").toInt());
connect(_tree_filter_cbbox, qOverload<int>(&QComboBox::currentIndexChanged), [this](int index) {
if (index == 0) // load all
filter_sound_type(0, true);
else
{
int sound_type_id = 0;
int row_id = 0;
for (auto sound_type : sound_types_names)
{
if (row_id == index - 1)
{
sound_type_id = sound_type.first;
break;
}
row_id++;
}
filter_sound_type(sound_type_id);
}
});
connect(_tree_searchbar, &QLineEdit::textChanged, [=](QString obj) {
if (obj.isEmpty())
{
// unhide all
}
// hide all items
for (int i = 0; i < _picker_listview->count(); i++)
{
auto item = _picker_listview->item(i);
item->setHidden(true);
}
// unhide matching items
auto matching_items = _picker_listview->findItems(obj, Qt::MatchContains);
for (auto item : matching_items)
{
item->setHidden(false);
}
});
connect(_picker_listview, &QListWidget::itemClicked, this, [=](QListWidgetItem* item) {
select_entry(item->data(1).toInt());
});
connect(select_entry_btn, &QPushButton::clicked, [=]() {
// auto selection = _picker_listview->selectedItems();
auto selected_item = _picker_listview->currentItem();
if (selected_item == nullptr)
return;
button->setProperty("id", selected_item->data(1).toInt());
button->setText(selected_item->text());
this->close();
});
connect(select_entry_none_btn, &QPushButton::clicked, [=]() {
button->setText("-NONE-");
button->setProperty("id", 0);
this->close();
});
connect(save_music_entry_btn, &QPushButton::clicked, [=]() {
save_entry(_entry_id);
});
connect(add_file_button, &QPushButton::clicked, [=]() {
int new_row_id = _files_listview->count();
if (new_row_id > 9)
return; // can't have more than 10
_filenames_ledits[new_row_id] = new QLineEdit(); // set parent in the widget class
_filenames_ledits[new_row_id]->setText("your_sound_file.mp3");
auto file_widget = new SoundFileWListWidgetItem(_filenames_ledits[new_row_id], _directory_ledit->text().toStdString());
auto item = new QListWidgetItem(_files_listview);
_files_listview->setItemWidget(item, file_widget);
item->setSizeHint(QSize(_files_listview->width(), _files_listview->height() / 10));
_files_listview->addItem(item);
update_files_count();
});
connect(duplicate_entry_btn, &QPushButton::clicked, [=]() {
auto new_id = gSoundEntriesDB.getEmptyRecordID(SoundEntriesDB::ID);
auto new_record = gSoundEntriesDB.addRecord(new_id);
_name_ledit->setText("Noggit Unnamed entry");
save_entry(new_id);
// add new tree item
auto item = new QListWidgetItem();
item->setData(1, new_id);
std::stringstream ss;
_picker_listview->addItem(item);
select_entry(new_id);
ss << new_id << "-" << _name_ledit->text().toStdString();
item->setText(ss.str().c_str());
});
}
void SoundEntryPickerWindow::filter_sound_type(int sound_type, bool load_all)
{
_picker_listview->clear();
for (DBCFile::Iterator i = gSoundEntriesDB.begin(); i != gSoundEntriesDB.end(); ++i)
{
if (!(i->getInt(SoundEntriesDB::SoundType) == sound_type) && !load_all) // it freezes for 2sec if we try to add directly all 13k items
continue;
auto item = new QListWidgetItem();
item->setData(1, i->getInt(SoundEntriesDB::ID));
std::stringstream ss;
ss << i->getInt(SoundEntriesDB::ID) << "-" << i->getString(SoundEntriesDB::Name);
if (load_all)
ss << "(" << sound_types_names.at(i->getInt(SoundEntriesDB::SoundType)) << ')';
item->setText(ss.str().c_str());
_picker_listview->addItem(item);
}
}
void SoundEntryPickerWindow::select_entry(int id)
{
_entry_id = id;
if (id != 0)
{
// _picker_listview->setCurrentRow(0);
// doesn't work because of the type filter ! :(
// _picker_listview->setCurrentRow(gSoundEntriesDB.getRecordRowId(id));
}
else
{
_picker_listview->setCurrentRow(0);
return;
}
_entry_id_lbl->setText(QString(std::to_string(id).c_str()));
DBCFile::Record record = gSoundEntriesDB.getByID(id);
_name_ledit->setText(record.getString(SoundEntriesDB::Name));
int sound_type_id = record.getInt(SoundEntriesDB::SoundType);
int row_id = 0;
for (auto sound_type : sound_types_names)
{
if (sound_type.first == sound_type_id)
{
_sound_type_cbbox->setCurrentIndex(row_id);
break;
}
row_id++;
}
_eax_type_cbbox->setCurrentIndex(record.getInt(SoundEntriesDB::EAXDef));
_min_distance_spinbox->setValue(record.getFloat(SoundEntriesDB::minDistance));
_max_distance_spinbox->setValue(record.getFloat(SoundEntriesDB::distanceCutoff));
_volume_slider->setValue(record.getFloat(SoundEntriesDB::Volume) * 100);
int flags = record.getInt(SoundEntriesDB::Flags);
_flag6_checkbox->setChecked((flags & (1 << (6 - 1))) ? true : false);
_flag10_checkbox->setChecked((flags & (1 << (10 - 1))) ? true : false);
_flag11_checkbox->setChecked((flags & (1 << (11 - 1))) ? true : false);
_flag12 = (flags & (1 << (12 - 1))) ? true : false;
_directory_ledit->setText(record.getString(SoundEntriesDB::FilePath));
_files_listview->clear();
for (int i = 0; i < 10; i++)
{
std::string filename = record.getString(SoundEntriesDB::Filenames + i);
// auto freq = record.getInt(SoundEntriesDB::Freq + i);
if (filename.empty())
continue;
_filenames_ledits[i] = new QLineEdit(); // set parent in the widget class
_filenames_ledits[i]->setText(filename.c_str());
auto file_widget = new SoundFileWListWidgetItem(_filenames_ledits[i], _directory_ledit->text().toStdString());
auto item = new QListWidgetItem(_files_listview);
_files_listview->setItemWidget(item, file_widget);
item->setSizeHint(QSize(_files_listview->width(), _files_listview->height() / 10) );
_files_listview->addItem(item);
}
update_files_count();
_sound_advanced_id = record.getInt(SoundEntriesDB::soundEntriesAdvancedID);
}
void SoundEntryPickerWindow::save_entry(int entry_id)
{
DBCFile::Record record = gSoundEntriesDB.getByID(entry_id);
record.write(SoundEntriesDB::ID, entry_id);
int sound_type_id = 0;
int row_id = 0;
for (auto sound_type : sound_types_names)
{
if (row_id == _sound_type_cbbox->currentIndex())
{
sound_type_id = sound_type.first;
break;
}
row_id++;
}
record.write(SoundEntriesDB::SoundType, sound_type_id);
record.writeString(SoundEntriesDB::Name, _name_ledit->text().toStdString());
// _files_listview->count()
int i = 0;
for (;i < _files_listview->count(); i++)
{
record.writeString(SoundEntriesDB::Filenames + i, _filenames_ledits[i]->text().toStdString());
record.write(SoundEntriesDB::Freq + i, 1); // TODO. but in 99.9% 1 is fine
}
for (;i < 10; i++) // clean up unset entries
{
record.writeString(SoundEntriesDB::Filenames + i, "");
record.write(SoundEntriesDB::Freq + i, 0);
}
record.writeString(SoundEntriesDB::FilePath, _directory_ledit->text().toStdString());
record.write(SoundEntriesDB::Volume, _volume_slider->value() / 100.0f); // should be a float
int flags = 0;
if (_flag6_checkbox->isChecked())
flags |= (1ULL << (5));
if (_flag10_checkbox->isChecked())
flags |= (1ULL << (9));
if (_flag11_checkbox->isChecked())
flags |= (1ULL << (10));
if (_flag12)
flags |= (1ULL << (11));
record.write(SoundEntriesDB::Flags, flags);
record.write(SoundEntriesDB::minDistance, static_cast<float>(_min_distance_spinbox->value()));
record.write(SoundEntriesDB::distanceCutoff, static_cast<float>(_max_distance_spinbox->value()));
record.write(SoundEntriesDB::EAXDef, _eax_type_cbbox->currentIndex());
record.write(SoundEntriesDB::soundEntriesAdvancedID, _sound_advanced_id);
gSoundEntriesDB.save();
}
void SoundEntryPickerWindow::update_files_count()
{
int file_count = _files_listview->count();
std::stringstream ss;
ss << "Files: " << std::to_string(file_count) << "/10";
_filescount_lbl->setText(ss.str().c_str());
}
SoundFileWListWidgetItem::SoundFileWListWidgetItem(QLineEdit* filename_ledit, std::string dirpath, QWidget* parent) // std::string filename
: QWidget(parent)
{
auto layout = new QHBoxLayout(this);
layout->addWidget(new QLabel("File:", this));
// auto lol = _filenames_ledits[i];
// auto _filename_ledit = new QLineEdit(filename.c_str(), this);
filename_ledit->setParent(this);
filename_ledit->setFixedHeight(30);
layout->addWidget(filename_ledit);
auto play_sound_button = new QToolButton(this);
play_sound_button->setIcon(Noggit::Ui::FontAwesomeIcon(FontAwesome::play));
//play_sound_button->setFixedSize(play_sound_button->size() * 0.5);
play_sound_button->setFixedSize(20, 20);
layout->addWidget(play_sound_button);
// auto removefile_button = new QToolButton(this);
// removefile_button->setIcon(Noggit::Ui::FontAwesomeIcon(FontAwesome::windowclose));
//removefile_button->setFixedSize(removefile_button->size() * 0.5);
// removefile_button->setFixedSize(20, 20);
// layout->addWidget(removefile_button);
connect(play_sound_button, &QPushButton::clicked, [=]() {
if (!filename_ledit->text().toStdString().empty() && !dirpath.empty())
{
auto sound_player = new SoundEntryPlayer(this);
sound_player->PlaySingleSoundFile(filename_ledit->text().toStdString(), dirpath);
sound_player->show();
}
});
}
}
}

View File

@@ -0,0 +1,156 @@
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
#pragma once
#include <noggit/DBC.h>
#include <QtWidgets/QWidget>
#include <QtWidgets/QTreeWidget>
#include <QtWidgets/QDoubleSpinBox>
#include <QtWidgets/QSlider>
#include <QtWidgets/QCheckBox.h>
#include <QtWidgets/QComboBox.h>
#include <QtWidgets/QLabel>
#include <QtWidgets/QListWidget>
#include <QtWidgets/QListView>
#include <QtWidgets/QPushButton>
#include <QMediaPlayer>
#include <string>
namespace Noggit
{
namespace Ui
{
// struct SoundEntryFilename
// {
// SoundEntryFilename(std::string f, int freq);
//
// std::string filename;
// int freq;
// };
// };
class SoundFileWListWidgetItem : public QWidget
{
Q_OBJECT
public:
SoundFileWListWidgetItem(QLineEdit* filename_ledit, std::string dirpath, QWidget* parent = nullptr);
// QLineEdit* _filename_ledit;
private:
};
class SoundEntryPickerWindow : public QWidget
{
Q_OBJECT
public:
SoundEntryPickerWindow(QPushButton* button, int sound_type_filter = -1, bool allow_none = true, QWidget* parent = nullptr);
private:
QComboBox* _tree_filter_cbbox;
QLineEdit* _tree_searchbar;
QListWidget* _picker_listview;
int _entry_id = 0;
QLabel* _entry_id_lbl;
QLineEdit* _name_ledit;
QComboBox* _sound_type_cbbox;
QComboBox* _eax_type_cbbox;
QSpinBox* _min_distance_spinbox;
QSpinBox* _max_distance_spinbox;
QSlider* _volume_slider;
QCheckBox* _flag6_checkbox;
QCheckBox* _flag10_checkbox;
QCheckBox* _flag11_checkbox;
QLineEdit* _directory_ledit;
QLabel* _filescount_lbl;
QListWidget* _files_listview;
QLineEdit* _filenames_ledits[10]{ 0 };
QSpinBox* _freqs_spinboxes[10]{ 0 };
bool _flag12; // 7 users and unknown definition, not adding it to the UI.
// TODO sound advanced. shouldn't use a picker as it is unique for each sound, just add an optional advanced layout without maybe a checkbox. maybe it is in a separate tab ?
int _sound_advanced_id = 0;
void filter_sound_type(int sound_type, bool load_all = false);
void select_entry(int id);
void save_entry(int entry_id);
void update_files_count();
// void duplicate_entry();
};
enum SoundEntryTypes
{
SPELLS = 1,
UI,
FOOTSTEPS,
COMBAT_IMPACTS,
COMBAT_SWINGS = 6,
GREETINGS,
CASTING,
ITEM_USE_SOUNDS,
MONSTER_SOUNDS,
VOCAL_UI_SOUNDS = 12,
POINT_SOUND_EMITTERS,
DOODAD_SOUNDS,
DEATH = 16,
NPC_SOUNDS,
FOLEY_SOUNDS = 19,
FOOTSTEPS_SPLASHES,
CHARACTER_SPLASH_SOUNDS,
WATERVOLUME_SOUNDS,
TRADESKILL,
TERRAIN_EMITER,
GAME_OBJECTS,
SPELL_FIZZLES,
CREATURE_LOOPS,
ZONE_MUSIC_FILES,
EMOTES,
CINEMATIC_MUSIC,
CINEMATIC_VOICE,
ZONE_AMBIENCE = 50,
SOUND_EMITTERS = 52,
VEHICLE_STATES
};
static std::map <int, std::string> sound_types_names = {
{SPELLS , "Spells"},
{UI , "UI"},
{FOOTSTEPS , "Footsteps"},
{COMBAT_IMPACTS , "Combat Impacts"},
{COMBAT_SWINGS , "Combat Swings"},
{GREETINGS, "Greetings"},
{CASTING, "Casting"},
{ITEM_USE_SOUNDS, "Item Use Sound"},
{MONSTER_SOUNDS, "Monster Sound"},
{VOCAL_UI_SOUNDS, "VocalUISound"},
{POINT_SOUND_EMITTERS, "Point Sound Emitter"},
{DOODAD_SOUNDS, "Doodad Sounds"},
{DEATH, "Death Thud Sounds"},
{NPC_SOUNDS, "NPC Sounds"},
{FOLEY_SOUNDS, "Foley Sound"},
{FOOTSTEPS_SPLASHES, "Footsteps(Splashes)"},
{CHARACTER_SPLASH_SOUNDS, "CharacterSplashSounds"},
{WATERVOLUME_SOUNDS, "WaterVolume Sounds"},
{TRADESKILL, "Tradeskill Sounds"},
{TERRAIN_EMITER, "Terrain Emitter Sounds"},
{GAME_OBJECTS, "Game Object Sounds"},
{SPELL_FIZZLES, "SpellFizzles"},
{CREATURE_LOOPS, "CreatureLoops"},
{ZONE_MUSIC_FILES, "Zone Music Files"},
{EMOTES, "Character Macro Line"},
{CINEMATIC_MUSIC, "Cinematic Music"},
{CINEMATIC_VOICE, "Cinematic Voice"},
{ZONE_AMBIENCE, "Zone Ambience"},
{SOUND_EMITTERS, "Sound Emitters"},
{VEHICLE_STATES, "Vehicle States"}
};
}
}

View File

@@ -0,0 +1,250 @@
#include <noggit/ui/windows/SoundPlayer/SoundEntryPlayer.h>
#include "ZoneIntroMusicPickerWindow.h"
// #include <noggit/ui/ZoneIDBrowser.h>
#include "SoundEntryPickerWindow.h"
#include <noggit/DBC.h>
#include <noggit/Log.h>
#include <noggit/Misc.h>
#include <ClientFile.hpp>
#include <noggit/application/NoggitApplication.hpp>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QFormLayout>
#include <QtWidgets/qpushbutton.h>
#include <QtWidgets/qgroupbox.h>
#include <QtWidgets/qcheckbox.h>
#include <QtWidgets/qlineedit.h>
#include <QtWidgets/QTableView>
#include <QStandardItemModel>
#include <QTableWidgetItem>
#include <QSound>
#include <qtemporaryfile>
#include <QMediaPlayer>
#include <QListWidget>
#include <QToolButton>
#include <iostream>
#include <sstream>
#include <string>
namespace Noggit
{
namespace Ui
{
ZoneIntroMusicPickerWindow::ZoneIntroMusicPickerWindow(QPushButton* button, QWidget* parent)
: QWidget(parent)
{
setWindowTitle("Zone Intro Music Picker");
setWindowFlags(Qt::Dialog);
auto layout = new QHBoxLayout(this);
auto list_layout = new QVBoxLayout(this);
auto Editor_layout = new QVBoxLayout(this);
layout->addLayout(list_layout);
layout->addLayout(Editor_layout);
_tree_searchbar = new QLineEdit(this);
list_layout->addWidget(_tree_searchbar);
_picker_listview = new QListWidget(this);
_picker_listview->setFixedSize(280, 460);
_picker_listview->setSelectionMode(QListWidget::SingleSelection);
list_layout->addWidget(_picker_listview);
for (DBCFile::Iterator i = gZoneIntroMusicTableDB.begin(); i != gZoneIntroMusicTableDB.end(); ++i)
{
auto item = new QListWidgetItem();
item->setData(1, i->getInt(ZoneIntroMusicTableDB::ID));
std::stringstream ss;
ss << i->getInt(ZoneIntroMusicTableDB::ID) << "-" << i->getString(ZoneIntroMusicTableDB::Name);
item->setText(ss.str().c_str());
_picker_listview->addItem(item);
}
auto select_entry_btn = new QPushButton("Select Entry", this);
auto select_entry_none_btn = new QPushButton("Select -NONE-", this);
auto duplicate_entry_btn = new QPushButton("Duplicate selected Entry (create new)", this);
list_layout->addWidget(duplicate_entry_btn);
list_layout->addWidget(select_entry_btn);
list_layout->addWidget(select_entry_none_btn);
// Editor frame
QGroupBox* editor_group = new QGroupBox("Edit Selected Entry", this);
Editor_layout->addWidget(editor_group);
auto editor_form_layout = new QFormLayout(editor_group);
_entry_id_lbl = new QLabel(this);
editor_form_layout->addRow("Id:", _entry_id_lbl);
_entry_id_lbl->setEnabled(false);
_name_ledit = new QLineEdit(this);
editor_form_layout->addRow("Intro Music Name:", _name_ledit);
_sound_button = new QPushButton("-NONE-", this);
_sound_button->setProperty("id", 0);
connect(_sound_button, &QPushButton::clicked, [=]() {
auto window = new SoundEntryPickerWindow(_sound_button, SoundEntryTypes::ZONE_MUSIC_FILES, false, this);
window->show();
});
auto music_layout = new QHBoxLayout(this);
auto play_music_button = new QToolButton(this);
play_music_button->setIcon(Noggit::Ui::FontAwesomeIcon(FontAwesome::play));
music_layout->addWidget(new QLabel("Music sound entry:"));
music_layout->addWidget(_sound_button);
music_layout->addWidget(play_music_button);
editor_form_layout->addRow(music_layout);
_min_delay_spinbox = new QSpinBox(this);
_min_delay_spinbox->setMaximum(300);
editor_form_layout->addRow("Min Delay (minutes):", _min_delay_spinbox);
auto save_music_entry_btn = new QPushButton("Save changes", this);
Editor_layout->addWidget(save_music_entry_btn, 0, Qt::AlignRight);
Editor_layout->addStretch();
/// check if needed
select_entry(button->property("id").toInt());
connect(_tree_searchbar, &QLineEdit::textChanged, [=](QString obj) {
if (obj.isEmpty())
{
// unhide all
}
// hide all items
for (int i = 0; i < _picker_listview->count(); i++)
{
auto item = _picker_listview->item(i);
item->setHidden(true);
}
// unhide matching items
auto matching_items = _picker_listview->findItems(obj, Qt::MatchContains);
for (auto item : matching_items)
{
item->setHidden(false);
}
});
connect(_picker_listview, &QListWidget::itemClicked, this, [=](QListWidgetItem* item) {
select_entry(item->data(1).toInt());
});
connect(select_entry_btn, &QPushButton::clicked, [=]() {
// auto selection = _picker_listview->selectedItems();
auto selected_item = _picker_listview->currentItem();
if (selected_item == nullptr)
return;
button->setProperty("id", selected_item->data(1).toInt());
button->setText(selected_item->text());
this->close();
});
connect(select_entry_none_btn, &QPushButton::clicked, [=]() {
button->setText("-NONE-");
button->setProperty("id", 0);
this->close();
});
connect(play_music_button, &QPushButton::clicked, [=]() {
auto sound_entry = _sound_button->property("id").toInt();
if (sound_entry)
{
auto sound_player = new SoundEntryPlayer(this);
sound_player->LoadSoundsFromSoundEntry(sound_entry);
sound_player->show();
}
});
connect(save_music_entry_btn, &QPushButton::clicked, [=]() {
save_entry(_entry_id);
});
connect(duplicate_entry_btn, &QPushButton::clicked, [=]() {
auto new_id = gZoneIntroMusicTableDB.getEmptyRecordID(ZoneIntroMusicTableDB::ID);
auto new_record = gZoneIntroMusicTableDB.addRecord(new_id);
_name_ledit->setText("Noggit Unnamed entry");
save_entry(new_id);
// add new tree item
auto item = new QListWidgetItem();
item->setData(1, new_id);
std::stringstream ss;
_picker_listview->addItem(item);
select_entry(new_id);
ss << new_id << "-" << _name_ledit->text().toStdString();
item->setText(ss.str().c_str());
});
}
void ZoneIntroMusicPickerWindow::select_entry(int id)
{
_entry_id = id;
if (id != 0)
_picker_listview->setCurrentRow(gZoneIntroMusicTableDB.getRecordRowId(id));
else
{
_picker_listview->setCurrentRow(0);
return;
}
_entry_id_lbl->setText(QString(std::to_string(id).c_str()));
DBCFile::Record record = gZoneIntroMusicTableDB.getByID(id);
_name_ledit->setText(record.getString(ZoneIntroMusicTableDB::Name));
int sound_entry = record.getInt(ZoneIntroMusicTableDB::SoundId);
if (sound_entry != 0 && gSoundEntriesDB.CheckIfIdExists(sound_entry))
{
DBCFile::Record sound_record = gSoundEntriesDB.getByID(sound_entry);
std::stringstream ss;
ss << sound_entry << "-" << sound_record.getString(SoundEntriesDB::Name);
_sound_button->setText(ss.str().c_str());
_sound_button->setProperty("id", sound_entry);
}
else
{
_sound_button->setText("-NONE-");
_sound_button->setProperty("id", 0);
}
_priority = record.getInt(ZoneIntroMusicTableDB::Priority); // always 1 except for 1 test entry
_min_delay_spinbox->setValue(record.getInt(ZoneIntroMusicTableDB::MinDelayMinutes));
}
void ZoneIntroMusicPickerWindow::save_entry(int entry_id)
{
DBCFile::Record record = gZoneIntroMusicTableDB.getByID(entry_id); // is_new_record ? gLightDB.addRecord(Id) : gLightDB.getByID(Id);
record.write(ZoneIntroMusicTableDB::ID, entry_id);
record.writeString(ZoneIntroMusicTableDB::Name, _name_ledit->text().toStdString());
record.write(ZoneIntroMusicTableDB::SoundId, _sound_button->property("id").toInt());
record.write(ZoneIntroMusicTableDB::Priority, _priority);
record.write(ZoneIntroMusicTableDB::MinDelayMinutes, _min_delay_spinbox->value());
gZoneIntroMusicTableDB.save();
}
}
}

View File

@@ -0,0 +1,50 @@
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
#pragma once
#include <noggit/DBC.h>
#include <QtWidgets/QWidget>
#include <QtWidgets/QTreeWidget>
#include <QtWidgets/QDoubleSpinBox>
#include <QtWidgets/QSlider>
#include <QtWidgets/QCheckBox.h>
#include <QtWidgets/QComboBox.h>
#include <QtWidgets/QLabel>
#include <QtWidgets/QListWidget>
#include <QtWidgets/QListView>
#include <QtWidgets/QPushButton>
#include <QMediaPlayer>
#include <string>
namespace Noggit
{
namespace Ui
{
class ZoneIntroMusicPickerWindow : public QWidget
{
Q_OBJECT
public:
ZoneIntroMusicPickerWindow(QPushButton* button, QWidget* parent = nullptr);
private:
QLineEdit* _tree_searchbar;
QListWidget* _picker_listview;
int _entry_id = 0;
int _priority = 1;
QLabel* _entry_id_lbl;
QLineEdit* _name_ledit;
QSpinBox* _min_delay_spinbox;
QPushButton* _sound_button;
void select_entry(int id);
void save_entry(int entry_id);
// void duplicate_entry();
};
}
}

View File

@@ -0,0 +1,326 @@
#include "ZoneMusicPickerWindow.h"
#include <noggit/ui/windows/SoundPlayer/SoundEntryPlayer.h>
#include "SoundEntryPickerWindow.h"
#include <noggit/DBC.h>
#include <noggit/Log.h>
#include <noggit/Misc.h>
#include <ClientFile.hpp>
#include <noggit/application/NoggitApplication.hpp>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QFormLayout>
#include <QtWidgets/qpushbutton.h>
#include <QtWidgets/qgroupbox.h>
#include <QtWidgets/qcheckbox.h>
#include <QtWidgets/qlineedit.h>
#include <QtWidgets/QTableView>
#include <QStandardItemModel>
#include <QTableWidgetItem>
#include <QSound>
#include <qtemporaryfile>
#include <QMediaPlayer>
#include <QListWidget>
#include <QToolButton>
#include <iostream>
#include <sstream>
#include <string>
namespace Noggit
{
namespace Ui
{
ZoneMusicPickerWindow::ZoneMusicPickerWindow(QPushButton* button, QWidget* parent)
: QWidget(parent)
{
setWindowTitle("Zone Music Picker");
setWindowFlags(Qt::Dialog);
auto layout = new QHBoxLayout(this);
auto list_layout = new QVBoxLayout(this);
auto Editor_layout = new QVBoxLayout(this);
layout->addLayout(list_layout);
layout->addLayout(Editor_layout);
_tree_searchbar = new QLineEdit(this);
list_layout->addWidget(_tree_searchbar);
_picker_listview = new QListWidget(this);
_picker_listview->setFixedSize(280, 460);
_picker_listview->setSelectionMode(QListWidget::SingleSelection);
list_layout->addWidget(_picker_listview);
for (DBCFile::Iterator i = gZoneMusicDB.begin(); i != gZoneMusicDB.end(); ++i)
{
auto item = new QListWidgetItem();
item->setData(1, i->getInt(ZoneMusicDB::ID));
std::stringstream ss;
ss << i->getInt(ZoneMusicDB::ID) << "-" << i->getString(ZoneMusicDB::Name);
item->setText(ss.str().c_str());
// _picker_listview->addItem(ss.str().c_str());
_picker_listview->addItem(item);
}
auto select_entry_btn = new QPushButton("Select Entry", this);
select_entry_btn->setIcon(Noggit::Ui::FontAwesomeIcon(Noggit::Ui::FontAwesome::check));
auto select_entry_none_btn = new QPushButton("Select -NONE-", this);
select_entry_none_btn->setIcon(Noggit::Ui::FontAwesomeIcon(Noggit::Ui::FontAwesome::check));
auto duplicate_entry_btn = new QPushButton("Duplicate selected Entry (create new)", this);
duplicate_entry_btn->setIcon(Noggit::Ui::FontAwesomeIcon(Noggit::Ui::FontAwesome::plus));
list_layout->addWidget(duplicate_entry_btn);
list_layout->addWidget(select_entry_btn);
list_layout->addWidget(select_entry_none_btn);
// Editor frame
QGroupBox* editor_group = new QGroupBox("Edit Selected Entry", this);
Editor_layout->addWidget(editor_group);
auto editor_form_layout = new QFormLayout(editor_group);
_entry_id_lbl = new QLabel(this);
editor_form_layout->addRow("Id:", _entry_id_lbl);
_entry_id_lbl->setEnabled(false);
_name_ledit = new QLineEdit(this);
editor_form_layout->addRow("Music Set Name:", _name_ledit);
_day_music_button = new QPushButton("-NONE-", this);
_day_music_button->setProperty("id", 0);
connect(_day_music_button, &QPushButton::clicked, [=]() {
auto window = new SoundEntryPickerWindow(_day_music_button, SoundEntryTypes::ZONE_MUSIC_FILES, true, this);
window->show();
});
auto day_music_layout = new QHBoxLayout(this);
auto play_day_music_button = new QToolButton(this);
play_day_music_button->setIcon(Noggit::Ui::FontAwesomeIcon(FontAwesome::play));
day_music_layout->addWidget(new QLabel("Day Music:"));
day_music_layout->addWidget(_day_music_button);
day_music_layout->addWidget(play_day_music_button);
editor_form_layout->addRow(day_music_layout);
_night_music_button = new QPushButton("-NONE-", this);
_night_music_button->setProperty("id", 0);
connect(_night_music_button, &QPushButton::clicked, [=]() {
auto window = new SoundEntryPickerWindow(_night_music_button, SoundEntryTypes::ZONE_MUSIC_FILES, true, this);
window->show();
});
auto night_music_layout = new QHBoxLayout(this);
auto play_night_music_button = new QToolButton(this);
play_night_music_button->setIcon(Noggit::Ui::FontAwesomeIcon(FontAwesome::play));
night_music_layout->addWidget(new QLabel("Night Music:"));
night_music_layout->addWidget(_night_music_button);
night_music_layout->addWidget(play_night_music_button);
editor_form_layout->addRow(night_music_layout);
// editor_form_layout->addRow("Night Music:", _night_music_button);
QGroupBox* silence_intervals_group = new QGroupBox("Silence Intervals", this);
Editor_layout->addWidget(silence_intervals_group);
auto silence_interval_layout = new QVBoxLayout(silence_intervals_group);
silence_interval_layout->addWidget(new QLabel("Day:"));
auto day_silence_intervals_layout = new QHBoxLayout(this);
silence_interval_layout->addLayout(day_silence_intervals_layout);
day_silence_intervals_layout->addWidget(new QLabel("Min:"));
_day_min_interval_spinbox = new QSpinBox(this);
_day_min_interval_spinbox->setMaximum(600000);
day_silence_intervals_layout->addWidget(_day_min_interval_spinbox);
day_silence_intervals_layout->addWidget(new QLabel("Max:"));
_day_max_interval_spinbox = new QSpinBox(this);
_day_max_interval_spinbox->setMaximum(600000);
day_silence_intervals_layout->addWidget(_day_max_interval_spinbox);
silence_interval_layout->addWidget(new QLabel("Night:"));
auto night_silence_intervals_layout = new QHBoxLayout(this);
silence_interval_layout->addLayout(night_silence_intervals_layout);
night_silence_intervals_layout->addWidget(new QLabel("Min:"));
_night_min_interval_spinbox = new QSpinBox(this);
_night_min_interval_spinbox->setMaximum(600000);
night_silence_intervals_layout->addWidget(_night_min_interval_spinbox);
night_silence_intervals_layout->addWidget(new QLabel("Max:"));
_night_max_interval_spinbox = new QSpinBox(this);
_night_max_interval_spinbox->setMaximum(600000);
night_silence_intervals_layout->addWidget(_night_max_interval_spinbox);
auto save_music_entry_btn = new QPushButton("Save changes", this);
Editor_layout->addWidget(save_music_entry_btn, 0, Qt::AlignRight);
Editor_layout->addStretch();
/// check if needed
select_entry(button->property("id").toInt());
connect(_tree_searchbar, &QLineEdit::textChanged, [=](QString obj) {
if (obj.isEmpty())
{
// unhide all
}
// hide all items
for (int i = 0; i < _picker_listview->count(); i++)
{
auto item = _picker_listview->item(i);
item->setHidden(true);
}
// unhide matching items
auto matching_items = _picker_listview->findItems(obj, Qt::MatchContains);
for (auto item : matching_items)
{
item->setHidden(false);
}
});
connect(_picker_listview, &QListWidget::itemClicked, this, [=](QListWidgetItem* item) {
select_entry(item->data(1).toInt());
});
connect(select_entry_btn, &QPushButton::clicked, [=]() {
// auto selection = _picker_listview->selectedItems();
auto selected_item = _picker_listview->currentItem();
if (selected_item == nullptr)
return;
button->setProperty("id", selected_item->data(1).toInt());
button->setText(selected_item->text());
this->close();
});
connect(select_entry_none_btn, &QPushButton::clicked, [=]() {
button->setText("-NONE-");
button->setProperty("id", 0);
this->close();
});
connect(play_day_music_button, &QPushButton::clicked, [=]() {
auto sound_entry = _day_music_button->property("id").toInt();
if (sound_entry)
{
auto sound_player = new SoundEntryPlayer(this);
sound_player->LoadSoundsFromSoundEntry(sound_entry);
sound_player->show();
}
});
connect(play_night_music_button, &QPushButton::clicked, [=]() {
auto sound_entry = _night_music_button->property("id").toInt();
if (sound_entry)
{
auto sound_player = new SoundEntryPlayer(this);
sound_player->LoadSoundsFromSoundEntry(sound_entry);
sound_player->show();
}
});
connect(save_music_entry_btn, &QPushButton::clicked, [=]() {
save_entry(_entry_id);
});
connect(duplicate_entry_btn, &QPushButton::clicked, [=]() {
auto new_id = gZoneMusicDB.getEmptyRecordID(ZoneMusicDB::ID);
auto new_record = gZoneMusicDB.addRecord(new_id);
_name_ledit->setText("Noggit Unnamed entry");
save_entry(new_id);
// add new tree item
auto item = new QListWidgetItem();
item->setData(1, new_id);
std::stringstream ss;
_picker_listview->addItem(item);
select_entry(new_id);
ss << new_id << "-" << _name_ledit->text().toStdString();
item->setText(ss.str().c_str());
});
}
void ZoneMusicPickerWindow::select_entry(int id)
{
_entry_id = id;
if (id != 0)
_picker_listview->setCurrentRow(gZoneMusicDB.getRecordRowId(id));
else
{
_picker_listview->setCurrentRow(0);
return;
}
_entry_id_lbl->setText(QString(std::to_string(id).c_str()));
DBCFile::Record record = gZoneMusicDB.getByID(id);
_name_ledit->setText(record.getString(ZoneMusicDB::Name));
int day_sound_entry = record.getInt(ZoneMusicDB::DayMusic);
int night_sound_entry = record.getInt(ZoneMusicDB::NightMusic);
if (day_sound_entry != 0 && gSoundEntriesDB.CheckIfIdExists(day_sound_entry)) // some entries reference sound entries that don't exist
{
DBCFile::Record day_sound_record = gSoundEntriesDB.getByID(day_sound_entry);
std::stringstream ss_day;
ss_day << day_sound_entry << "-" << day_sound_record.getString(SoundEntriesDB::Name);
_day_music_button->setText(ss_day.str().c_str());
_day_music_button->setProperty("id", day_sound_entry);
}
else
{
_day_music_button->setText("-NONE-");
_day_music_button->setProperty("id", 0);
}
if (night_sound_entry != 0 && gSoundEntriesDB.CheckIfIdExists(night_sound_entry))
{
DBCFile::Record night_sound_record = gSoundEntriesDB.getByID(night_sound_entry);
std::stringstream ss_night;
ss_night << night_sound_entry << "-" << night_sound_record.getString(SoundEntriesDB::Name);
_night_music_button->setText(ss_night.str().c_str());
_night_music_button->setProperty("id", night_sound_entry);
}
else
{
_night_music_button->setText("-NONE-");
_night_music_button->setProperty("id", 0);
}
_day_min_interval_spinbox->setValue(record.getInt(ZoneMusicDB::SilenceIntervalMinDay));
_day_max_interval_spinbox->setValue(record.getInt(ZoneMusicDB::SilenceIntervalMaxDay));
_night_min_interval_spinbox->setValue(record.getInt(ZoneMusicDB::SilenceIntervalMinNight));
_night_max_interval_spinbox->setValue(record.getInt(ZoneMusicDB::SilenceIntervalMaxNight));
}
void ZoneMusicPickerWindow::save_entry(int entry_id)
{
DBCFile::Record record = gZoneMusicDB.getByID(entry_id); // is_new_record ? gLightDB.addRecord(Id) : gLightDB.getByID(Id);
record.write(ZoneMusicDB::ID, entry_id);
record.writeString(ZoneMusicDB::Name, _name_ledit->text().toStdString());
record.write(ZoneMusicDB::SilenceIntervalMinDay, _day_min_interval_spinbox->value());
record.write(ZoneMusicDB::SilenceIntervalMaxDay, _day_max_interval_spinbox->value());
record.write(ZoneMusicDB::SilenceIntervalMinNight, _night_min_interval_spinbox->value());
record.write(ZoneMusicDB::SilenceIntervalMaxNight, _night_max_interval_spinbox->value());
record.write(ZoneMusicDB::DayMusic, _day_music_button->property("id").toInt());
record.write(ZoneMusicDB::NightMusic, _night_music_button->property("id").toInt());
gZoneMusicDB.save();
}
}
}

View File

@@ -0,0 +1,53 @@
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
#pragma once
#include <noggit/DBC.h>
#include <QtWidgets/QWidget>
#include <QtWidgets/QTreeWidget>
#include <QtWidgets/QDoubleSpinBox>
#include <QtWidgets/QSlider>
#include <QtWidgets/QCheckBox.h>
#include <QtWidgets/QComboBox.h>
#include <QtWidgets/QLabel>
#include <QtWidgets/QListWidget>
#include <QtWidgets/QListView>
#include <QtWidgets/QPushButton>
#include <QMediaPlayer>
#include <string>
namespace Noggit
{
namespace Ui
{
class ZoneMusicPickerWindow : public QWidget
{
Q_OBJECT
public:
ZoneMusicPickerWindow(QPushButton* button, QWidget* parent = nullptr);
private:
QLineEdit* _tree_searchbar;
QListWidget* _picker_listview;
int _entry_id = 0;
QLabel* _entry_id_lbl;
QLineEdit* _name_ledit;
QSpinBox* _day_min_interval_spinbox;
QSpinBox* _day_max_interval_spinbox;
QSpinBox* _night_min_interval_spinbox;
QSpinBox* _night_max_interval_spinbox;
QPushButton* _day_music_button;
QPushButton* _night_music_button;
void select_entry(int id);
void save_entry(int entry_id);
// void duplicate_entry();
};
}
}

View File

@@ -0,0 +1,213 @@
#include "SoundEntryPlayer.h"
#include <noggit/DBC.h>
#include <noggit/Log.h>
#include <noggit/Misc.h>
#include <ClientFile.hpp>
#include <noggit/application/NoggitApplication.hpp>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QFormLayout>
#include <QtWidgets/qpushbutton.h>
#include <QtWidgets/qgroupbox.h>
#include <QtWidgets/qcheckbox.h>
#include <QtWidgets/qlineedit.h>
#include <QtWidgets/QTableView>
#include <QStandardItemModel>
#include <QTableWidgetItem>
#include <QSound>
#include <qtemporaryfile>
#include <QMediaPlayer>
#include <QListWidget>
#include <QToolButton>
#include <iostream>
#include <sstream>
#include <string>
namespace Noggit
{
namespace Ui
{
SoundEntryPlayer::SoundEntryPlayer(QWidget* parent)
: QWidget(parent)
{
setWindowTitle("Sound entry player");
setWindowFlags(Qt::Tool);
auto layout = new QVBoxLayout(this);
// auto sound_id_lbl = new QLabel(this);
// sound_id_lbl->setText("Sound Entry : " + sound_entry_id);
// layout->addWidget(sound_id_lbl);
auto dir_layout = new QHBoxLayout(this);
layout->addLayout(dir_layout);
dir_layout->addWidget(new QLabel("Directory:"));
_directory_lbl = new QLabel(this);
dir_layout->addWidget(_directory_lbl);
auto controls_layout = new QHBoxLayout(this);
layout->addLayout(controls_layout);
_media_player = new QMediaPlayer(this);
auto btn_play = new QToolButton(this);
controls_layout->addWidget(btn_play);
connect(btn_play, &QToolButton::clicked, _media_player, &QMediaPlayer::play);
btn_play->setIcon(Noggit::Ui::FontAwesomeIcon(FontAwesome::play));
auto btn_pause = new QToolButton(this);
controls_layout->addWidget(btn_pause);
connect(btn_pause, &QToolButton::clicked, _media_player, &QMediaPlayer::pause);
btn_pause->setIcon(Noggit::Ui::FontAwesomeIcon(FontAwesome::pause));
auto btn_stop = new QToolButton(this);
controls_layout->addWidget(btn_stop);
connect(btn_stop, &QToolButton::clicked, _media_player, &QMediaPlayer::stop);
btn_stop->setIcon(Noggit::Ui::FontAwesomeIcon(FontAwesome::stop));
_position_slider = new QSlider(Qt::Horizontal, this);
_position_slider->setTickInterval(100);
_position_slider->setSingleStep(100);
controls_layout->addWidget(_position_slider);
_volume_slider = new QSlider(Qt::Horizontal, this);
_volume_slider->setRange(0, 100);
_volume_slider->setValue(80);
_media_player->setVolume(80);
// controls_layout->addWidget(new QLabel("Volume:"));
auto btn_volume = new QToolButton(this);
controls_layout->addWidget(btn_volume);
// connect(btn_volume, &QToolButton::clicked, _media_player, &QMediaPlayer::stop);
btn_volume->setIcon(Noggit::Ui::FontAwesomeIcon(FontAwesome::volumeup));
controls_layout->addWidget(btn_volume);
controls_layout->addWidget(_volume_slider);
_files_listview = new QListWidget();
_files_listview->setSelectionMode(QListWidget::SingleSelection);
layout->addWidget(_files_listview);
connect(_files_listview, &QListWidget::itemClicked, this, [=](QListWidgetItem* item) {
play_selected_sound();
});
// connect volume
connect(_volume_slider, &QSlider::valueChanged, [&](int v) {
_media_player->setVolume(v);
});
// media doesn't start playnig imemdiatly when called, need to use this signal
connect(_media_player, &QMediaPlayer::durationChanged, this, [&](qint64 dur) {
_position_slider->setMaximum(dur);
});
// connect(_media_player, SIGNAL(positionChanged(qint64)), this, SLOT(positionChanged(qint64)));
connect(_media_player, &QMediaPlayer::positionChanged, [&](qint64 v) {
auto testmax = _position_slider->maximum();
QSignalBlocker const blocker(_position_slider);
_position_slider->setSliderPosition(v);
});
// position bar
connect(_position_slider, &QSlider::valueChanged, [&](int v) {
// _media_player->currentMedia().canonicalResource().dataSize();
_media_player->setPosition(v);
});
// _media_player->setPosition();
}
void SoundEntryPlayer::LoadSoundsFromSoundEntry(int sound_entry_id)
{
if (sound_entry_id == 0)
{
this->close();
this->destroy();
return;
}
// get files list
DBCFile::Record sound_entry_record = gSoundEntriesDB.getByID(sound_entry_id);
_directory_lbl->setText(sound_entry_record.getString(SoundEntriesDB::FilePath));
_volume_slider->setValue(sound_entry_record.getFloat(SoundEntriesDB::Volume) * 100);
_media_player->setVolume(sound_entry_record.getFloat(SoundEntriesDB::Volume) * 100);
for (int fileid = 0; fileid < 10; fileid++)
{
std::string filename = sound_entry_record.getString(SoundEntriesDB::Filenames + fileid);
if (!filename.empty())
{
// std::stringstream ss_filepah;
// ss_filepath << directory << "\\" << filename;
// music_files.push_back(ss_filepah.str());
// music_files.push_back(filename);
_files_listview->addItem(filename.c_str());
}
}
_files_listview->setCurrentRow(0);
play_selected_sound();
}
void SoundEntryPlayer::PlaySingleSoundFile(std::string filepath, std::string dir_path)
{
_directory_lbl->setText(dir_path.c_str());
_files_listview->clear();
_files_listview->addItem(filepath.c_str());
_files_listview->setCurrentRow(0);
play_selected_sound();
}
void SoundEntryPlayer::play_selected_sound()
{
std::stringstream filename;
auto item = _files_listview->selectedItems().back();
filename << _directory_lbl->text().toStdString() << "\\" << item->text().toStdString();
if (!Noggit::Application::NoggitApplication::instance()->clientData()->exists(filename.str()))
{
LogError << "The requested sound file \"" << filename.str() << "\" does not exist! Oo" << std::endl;
QMessageBox not_found_messagebox;
not_found_messagebox.setIcon(QMessageBox::Warning);
not_found_messagebox.setWindowIcon(QIcon(":/icon"));
not_found_messagebox.setWindowTitle("File not found");
std::stringstream ss;
ss << "The requested sound file \"" << filename.str() << "\" was not found in the client." << std::endl;
not_found_messagebox.setText(ss.str().c_str());
not_found_messagebox.exec();
return;
}
BlizzardArchive::ClientFile file(filename.str(), Noggit::Application::NoggitApplication::instance()->clientData());
auto temp_file = new QTemporaryFile(this); // must parent for the object to be destroyed properly(and file deleted)
temp_file->open();
temp_file->write(file.getBuffer(), file.getSize());
temp_file->close();
// default tempname is like User\AppData\Local\Temp\Noggit.qrRfsy ...We need to add back the file extension or it won't be read by the player!
// must rename after closing or it doesn't write correctly
temp_file->rename(temp_file->fileName() + item->text());
// file.save(); // saves file to project folder
// auto save_path = file.getPath().string();
auto testlol = temp_file->fileName().toStdString();
_media_player->setMedia(QUrl::fromLocalFile(temp_file->fileName())); // QUrl::fromLocalFile("/Users/me/Music/coolsong.mp3")
_media_player->play();
}
void SoundEntryPlayer::closeEvent(QCloseEvent* event)
{
// makes the music stop when closing
_media_player->stop();
event->accept();
}
}
}

View File

@@ -0,0 +1,49 @@
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
#pragma once
#include <noggit/DBC.h>
#include <QtWidgets/QWidget>
#include <QtWidgets/QTreeWidget>
#include <QtWidgets/QDoubleSpinBox>
#include <QtWidgets/QSlider>
#include <QtWidgets/QCheckBox.h>
#include <QtWidgets/QComboBox.h>
#include <QtWidgets/QLabel>
#include <QtWidgets/QListWidget>
#include <QtWidgets/QListView>
#include <QtWidgets/QPushButton>
#include <QMediaPlayer>
#include <string>
namespace Noggit
{
namespace Ui
{
class SoundEntryPlayer : public QWidget
{
Q_OBJECT
public:
SoundEntryPlayer(QWidget* parent = nullptr);
void LoadSoundsFromSoundEntry(int sound_entry_id);
void PlaySingleSoundFile(std::string filepath, std::string dir_path);
private:
QMediaPlayer* _media_player;
// QLabel* sound_id_lbl;
QLabel* _directory_lbl;
QListWidget* _files_listview;
QSlider* _volume_slider;
QSlider* _position_slider;
void play_selected_sound();
protected:
void closeEvent(QCloseEvent* event) override;
};
}
}