471 lines
14 KiB
C++
471 lines
14 KiB
C++
|
#include <QDebug>
|
||
|
#include "gamefeatures.h"
|
||
|
#include "qw_levelbuilder.h"
|
||
|
#include "qw_eventfactory.h"
|
||
|
#include "qw_dialoguefactory.h"
|
||
|
#include "qw_globalmetadata.h"
|
||
|
#include "view/qw_scene.h"
|
||
|
#include "models/qw_location.h"
|
||
|
#include "models/qw_trigger.h"
|
||
|
|
||
|
QWLevelBuilder::QWLevelBuilder(QObject *parent) :
|
||
|
QObject(parent),
|
||
|
str_current_level(strInitLevel())
|
||
|
{
|
||
|
// Dir for local save files
|
||
|
if (!QDir("save").exists()) {
|
||
|
QDir().mkdir("save");
|
||
|
}
|
||
|
save_dir.setPath("save");
|
||
|
}
|
||
|
|
||
|
template<typename MODEL>
|
||
|
QJsonArray writeEntitesToJsonArray(const QHash<QString, std::shared_ptr<MODEL>> &hash_models)
|
||
|
{
|
||
|
// Writing in active save file all the game elements and their state
|
||
|
QJsonArray json_array;
|
||
|
for (const auto &model : hash_models)
|
||
|
{
|
||
|
QJsonObject model_data;
|
||
|
model->writeToJson(model_data);
|
||
|
|
||
|
json_array.append(model_data);
|
||
|
}
|
||
|
return json_array;
|
||
|
}
|
||
|
|
||
|
void QWLevelBuilder::initMenuLevel()
|
||
|
{
|
||
|
str_current_level = "menu";
|
||
|
|
||
|
QFile file(":/res/menu.json");
|
||
|
|
||
|
Q_ASSERT(file.open(QIODevice::ReadOnly));
|
||
|
const QByteArray json_arr = file.readAll();
|
||
|
file.close();
|
||
|
|
||
|
QJsonObject savefile = QJsonDocument::fromJson(json_arr).object();
|
||
|
init(savefile);
|
||
|
}
|
||
|
|
||
|
void QWLevelBuilder::initSaveProfile(const QString &filename, const QString &profilename)
|
||
|
{
|
||
|
Q_UNUSED(profilename)
|
||
|
|
||
|
// Creating inital save file after beginning the new game:
|
||
|
str_profile_filename = filename;
|
||
|
str_current_level = strInitLevel();
|
||
|
|
||
|
QFile file;
|
||
|
|
||
|
str_profile_filename.remove(".json");
|
||
|
|
||
|
// We move default game description to player's save file
|
||
|
|
||
|
file.setFileName(save_dir.path() + "/" + str_profile_filename + ".json");
|
||
|
|
||
|
qDebug() << save_dir.path() + "/" + str_profile_filename + ".json";
|
||
|
|
||
|
if (!file.exists()) {
|
||
|
qDebug() << "copy file";
|
||
|
QFile::copy(":/res/defaultsave.json", file.fileName());
|
||
|
}
|
||
|
|
||
|
// Now we modify default json file to add the chosen profile name
|
||
|
|
||
|
/*Q_ASSERT(file.open(QIODevice::ReadOnly));
|
||
|
const QByteArray json_arr = file.readAll();
|
||
|
file.close();
|
||
|
|
||
|
QJsonObject savefile = QJsonDocument::fromJson(json_arr).object();
|
||
|
|
||
|
// Pull the saved string from new game dialogue
|
||
|
str_current_profile = profilename;
|
||
|
savefile.insert("save_profile", str_current_profile);
|
||
|
|
||
|
// Write it and resave
|
||
|
Q_ASSERT(file.open(QIODevice::WriteOnly));
|
||
|
file.write(QJsonDocument(savefile).toJson());
|
||
|
file.close();*/
|
||
|
}
|
||
|
|
||
|
void QWLevelBuilder::saveGame(/*QString filename*/)
|
||
|
{
|
||
|
qDebug() << "Save current game!";
|
||
|
|
||
|
QJsonObject savejson;
|
||
|
QJsonArray json_entites;
|
||
|
|
||
|
/* The first Trigger which moves player into its
|
||
|
* needed location where the game starts */
|
||
|
savejson.insert("init", "spawn");
|
||
|
savejson.insert("save_profile", str_current_profile);
|
||
|
|
||
|
qDebug() << "Save triggers!";
|
||
|
json_entites = writeEntitesToJsonArray(hash_triggers);
|
||
|
savejson.insert("triggers", json_entites);
|
||
|
|
||
|
qDebug() << "Save dialogues!";
|
||
|
json_entites = writeEntitesToJsonArray(hash_dialogues);
|
||
|
savejson.insert("dialogues", json_entites);
|
||
|
|
||
|
qDebug() << "Save locations!";
|
||
|
json_entites = writeEntitesToJsonArray(hash_locations);
|
||
|
savejson.insert("locations", json_entites);
|
||
|
|
||
|
qDebug() << "Save events!";
|
||
|
json_entites = writeEntitesToJsonArray(hash_events);
|
||
|
|
||
|
// Creating the inital event where player must appear after game loading
|
||
|
QJsonObject init_spawn_data;
|
||
|
|
||
|
QStringList trs;
|
||
|
for (auto & tr : ptr_scene->currentLocation()->triggers())
|
||
|
trs << tr->tag();
|
||
|
|
||
|
QList<std::shared_ptr<QWTrigger>> list_triggers;
|
||
|
init_spawn_data.insert("id", "spawn");
|
||
|
init_spawn_data.insert("type", 0);
|
||
|
init_spawn_data.insert("trs", QJsonArray::fromStringList(trs));
|
||
|
json_entites.append(init_spawn_data);
|
||
|
|
||
|
savejson.insert("events", json_entites);
|
||
|
// - - - //
|
||
|
|
||
|
QFile file(save_dir.dirName() + "/" + str_profile_filename + ".json");
|
||
|
Q_ASSERT(file.open(QIODevice::ReadOnly));
|
||
|
const QByteArray json_arr = file.readAll();
|
||
|
file.close();
|
||
|
QJsonObject savefile = QJsonDocument::fromJson(json_arr).object();
|
||
|
|
||
|
savefile[str_current_level] = savejson;
|
||
|
|
||
|
Q_ASSERT(file.open(QIODevice::WriteOnly));
|
||
|
file.write(QJsonDocument(savejson).toJson());
|
||
|
file.close();
|
||
|
}
|
||
|
|
||
|
void QWLevelBuilder::loadGame(/*QString filename*/)
|
||
|
{
|
||
|
QFile file;
|
||
|
|
||
|
hash_events.clear();
|
||
|
hash_triggers.clear();
|
||
|
hash_dialogues.clear();
|
||
|
hash_locations.clear();
|
||
|
init_trigger.reset();
|
||
|
|
||
|
file.setFileName(save_dir.dirName() + "/" + str_profile_filename + ".json");
|
||
|
file.open(QIODevice::ReadOnly);
|
||
|
const QByteArray json_arr = file.readAll();
|
||
|
file.close();
|
||
|
QJsonObject savefile = QJsonDocument::fromJson(json_arr).object();
|
||
|
|
||
|
str_current_level = savefile["init_level"].toString();
|
||
|
|
||
|
init(savefile);
|
||
|
}
|
||
|
|
||
|
void QWLevelBuilder::initLevel(const QString &lvlname)
|
||
|
{
|
||
|
str_current_level = lvlname;
|
||
|
|
||
|
QFile file(save_dir.dirName() + "/" + str_profile_filename + ".json");
|
||
|
|
||
|
Q_ASSERT(file.open(QIODevice::ReadOnly));
|
||
|
const QByteArray json_arr = file.readAll();
|
||
|
file.close();
|
||
|
|
||
|
emit ptr_scene->signalLeaveMenu();
|
||
|
|
||
|
QJsonObject savefile = QJsonDocument::fromJson(json_arr).object();
|
||
|
init(savefile);
|
||
|
}
|
||
|
|
||
|
void QWLevelBuilder::init(const QJsonObject & savefile)
|
||
|
{
|
||
|
qDebug() << "Init " << str_current_level << " level!";
|
||
|
|
||
|
hash_events.clear();
|
||
|
hash_triggers.clear();
|
||
|
init_trigger.reset();
|
||
|
|
||
|
level = savefile[str_current_level].toObject();
|
||
|
|
||
|
Q_ASSERT(!level.isEmpty());
|
||
|
|
||
|
// Building level from current json
|
||
|
|
||
|
if (level.contains("triggers"))
|
||
|
setupTriggers(level["triggers"].toArray());
|
||
|
|
||
|
if (level.contains("dialogues"))
|
||
|
setupDialogues(level["dialogues"].toArray());
|
||
|
|
||
|
if (level.contains("locations"))
|
||
|
setupLocations(level["locations"].toArray());
|
||
|
|
||
|
if (level.contains("events"))
|
||
|
setupEvents(level["events"].toArray());
|
||
|
|
||
|
linkEvents(level["triggers"].toArray());
|
||
|
|
||
|
init_trigger = level.contains("init") ? hash_triggers[level["init"].toString()] : nullptr;
|
||
|
|
||
|
// Start the level
|
||
|
Q_ASSERT(init_trigger);
|
||
|
init_trigger->activate();
|
||
|
}
|
||
|
|
||
|
QString QWLevelBuilder::strInitLevel() noexcept
|
||
|
{
|
||
|
return "start";
|
||
|
}
|
||
|
|
||
|
void QWLevelBuilder::setGameFeatures(std::unique_ptr<GameFeatures> &features)
|
||
|
{
|
||
|
ptr_scene = features->ptr_scene;
|
||
|
ptr_inventory = features->ptr_inventory;
|
||
|
ptr_soundplayer = features->ptr_sound_player;
|
||
|
ptr_text_dlg = features->ptr_text_dlg;
|
||
|
ptr_widget_dlg = features->ptr_widget_dlg;
|
||
|
}
|
||
|
|
||
|
void QWLevelBuilder::linkEvents(const QJsonArray &array)
|
||
|
{
|
||
|
qDebug() << "Link the events to triggers!";
|
||
|
|
||
|
for (const QJsonValue &json_value : array)
|
||
|
{
|
||
|
QJsonObject json_object(json_value.toObject());
|
||
|
if (json_object.contains("evs"))
|
||
|
{
|
||
|
qDebug() << " Trigger " << json_object["id"].toString() << " contains events!";
|
||
|
|
||
|
QJsonArray evs = json_object["evs"].toArray();
|
||
|
|
||
|
for (const QJsonValue event : evs)
|
||
|
{
|
||
|
QString obj = event.toString();
|
||
|
qDebug() << " Inserting " << obj << " to its trigger!";
|
||
|
hash_triggers[json_object["id"].toString()]->addEvents(hash_events[obj]);
|
||
|
qDebug() << " Success!";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (json_object.contains("examine_dialogue"))
|
||
|
{
|
||
|
qDebug() << " Trigger " << json_object["id"].toString() << " contains examination dialogue!";
|
||
|
|
||
|
const QString dialogue_tag = json_object["examine_dialogue"].toString();
|
||
|
hash_triggers[json_object["id"].toString()]->setExaminationDialogueEvent(hash_events[dialogue_tag]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// * * * * * * * * * * * * * * SETUP STUFF * * * * * * * * * * * * * *
|
||
|
//
|
||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||
|
|
||
|
void QWLevelBuilder::setupTriggers(const QJsonArray &array)
|
||
|
{
|
||
|
qDebug() << "Setup the triggers!";
|
||
|
|
||
|
QJsonObject json_object;
|
||
|
|
||
|
for (const QJsonValue &json_value : array)
|
||
|
{
|
||
|
json_object = json_value.toObject();
|
||
|
|
||
|
std::shared_ptr<QWTrigger> new_trigger;
|
||
|
|
||
|
// check if the picture exists!
|
||
|
Q_ASSERT(json_object.contains("id"));
|
||
|
QString mask = json_object.contains("mask") ? json_object["mask"].toString() : json_object["id"].toString();
|
||
|
new_trigger = std::make_shared<QWTrigger>(mask);
|
||
|
new_trigger->setTag(json_object["id"].toString());
|
||
|
qDebug() << "! The trigger with id " << json_object["id"].toString() << " was created.";
|
||
|
|
||
|
// setup the position on the scene
|
||
|
if (json_object.contains("x") && json_object.contains("y")) {
|
||
|
new_trigger->setPos(json_object["x"].toDouble(), json_object["y"].toDouble());
|
||
|
qDebug() << " The trigger was moved to "
|
||
|
<< new_trigger->x() << " " << new_trigger->y();
|
||
|
}
|
||
|
|
||
|
hash_triggers.insert(json_object["id"].toString(), new_trigger);
|
||
|
qDebug() << " The trigger was inserted into its map.\n - - -";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void QWLevelBuilder::setupEvents(const QJsonArray &array)
|
||
|
{
|
||
|
qDebug() << "Setup the events!";
|
||
|
|
||
|
std::unique_ptr<QWEventFactory> factory = std::make_unique<QWEventFactory>(this);
|
||
|
|
||
|
QJsonObject json_object;
|
||
|
QList<QJsonObject> list_later_events;
|
||
|
|
||
|
for (const QJsonValue &json_value : array)
|
||
|
{
|
||
|
json_object = json_value.toObject();
|
||
|
|
||
|
std::shared_ptr<QWAbstractEvent> new_event;
|
||
|
|
||
|
// check if the id exists!
|
||
|
Q_ASSERT(json_object.contains("id"));
|
||
|
qDebug() << "! The event with id " << json_object["id"].toString() << " is about to create.";
|
||
|
|
||
|
// independent events
|
||
|
Q_ASSERT(json_object.contains("type"));
|
||
|
int type = json_object["type"].toInt();
|
||
|
|
||
|
switch (type)
|
||
|
{
|
||
|
case (EVENT_TYPE::CHANGE_LOCATION):
|
||
|
new_event = factory->createChangeLocEvent(json_object);
|
||
|
break;
|
||
|
case (EVENT_TYPE::DELETE_FROM_INVENTORY):
|
||
|
new_event = factory->createDeleteItEvent(json_object);
|
||
|
break;
|
||
|
case (EVENT_TYPE::PICKUP_ITEM):
|
||
|
new_event = factory->createPickupItEvent(json_object);
|
||
|
break;
|
||
|
case (EVENT_TYPE::END_LEVEL):
|
||
|
new_event = factory->createEndLevelEvent(json_object);
|
||
|
break;
|
||
|
case (EVENT_TYPE::CHANGE_TRIGGER_PROPERTIES):
|
||
|
new_event = factory->createChangeTrProperts(json_object);
|
||
|
break;
|
||
|
case (EVENT_TYPE::NEW_GAME):
|
||
|
new_event = factory->createNewGameEvent(json_object);
|
||
|
break;
|
||
|
case (EVENT_TYPE::QUIT_GAME):
|
||
|
new_event = factory->createQuitGameEvent(json_object);
|
||
|
break;
|
||
|
case (EVENT_TYPE::START_DIALOGUE):
|
||
|
new_event = factory->createStartDlgEvent(json_object);
|
||
|
break;
|
||
|
case (EVENT_TYPE::ADD_TRIGGER):
|
||
|
new_event = factory->createAddTrEvent(json_object);
|
||
|
break;
|
||
|
case (EVENT_TYPE::REMOVE_TRIGGER):
|
||
|
new_event = factory->createRemoveTrEvent(json_object);
|
||
|
break;
|
||
|
default:
|
||
|
list_later_events.append(json_object);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
new_event->setTag(json_object["id"].toString());
|
||
|
hash_events.insert(json_object["id"].toString(), new_event);
|
||
|
}
|
||
|
|
||
|
// Some events work with other events, so we need to initialize all
|
||
|
// independent events earlier than these
|
||
|
for (const auto &later_event : list_later_events) {
|
||
|
|
||
|
int type = later_event["type"].toInt();
|
||
|
std::shared_ptr<QWAbstractEvent> new_event;
|
||
|
|
||
|
switch (type)
|
||
|
{
|
||
|
case (EVENT_TYPE::SWITCH_EVENTS): // switch events
|
||
|
new_event = factory->createSwitchEventsEvent(later_event);
|
||
|
break;
|
||
|
default:
|
||
|
Q_ASSERT(false);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
new_event->setTag(later_event["id"].toString());
|
||
|
hash_events.insert(later_event["id"].toString(), new_event);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void QWLevelBuilder::setupDialogues(const QJsonArray &array)
|
||
|
{
|
||
|
qDebug() << "Setup the dialogues!";
|
||
|
|
||
|
std::unique_ptr<QWDialogueFactory> factory = std::make_unique<QWDialogueFactory>(this);
|
||
|
|
||
|
QJsonObject json_object;
|
||
|
|
||
|
for (const QJsonValue &json_value : array)
|
||
|
{
|
||
|
json_object = json_value.toObject();
|
||
|
|
||
|
std::shared_ptr<QWAbstractGameDialogue> new_dialogue;
|
||
|
|
||
|
// check if the id exists!
|
||
|
Q_ASSERT(json_object.contains("id"));
|
||
|
qDebug() << "! The dialogue with id " << json_object["id"].toString() << " is about to create.";
|
||
|
|
||
|
Q_ASSERT(json_object.contains("type"));
|
||
|
int type = json_object["type"].toInt();
|
||
|
|
||
|
switch (type)
|
||
|
{
|
||
|
case (DIALOGUE_TYPE::TEXT):
|
||
|
new_dialogue = factory->createTextDialogue(json_object);
|
||
|
break;
|
||
|
case (DIALOGUE_TYPE::WIDGET):
|
||
|
new_dialogue = factory->createWidgetDialogue(json_object);
|
||
|
break;
|
||
|
default:
|
||
|
Q_ASSERT(false);
|
||
|
}
|
||
|
|
||
|
new_dialogue->setTag(json_object["id"].toString());
|
||
|
hash_dialogues.insert(json_object["id"].toString(), new_dialogue);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void QWLevelBuilder::setupLocations(const QJsonArray &array)
|
||
|
{
|
||
|
qDebug() << "Setup the locations!";
|
||
|
|
||
|
QJsonObject json_object;
|
||
|
|
||
|
for (const QJsonValue & json_value : array)
|
||
|
{
|
||
|
json_object = json_value.toObject();
|
||
|
|
||
|
std::shared_ptr<QWLocation> new_location;
|
||
|
|
||
|
Q_ASSERT(json_object.contains("id"));
|
||
|
qDebug() << "! The level with id " << json_object["id"].toString() << " was created.";
|
||
|
new_location = std::make_shared<QWLocation>();
|
||
|
new_location->setTag(json_object["id"].toString());
|
||
|
|
||
|
// check and add the pixmap triggers
|
||
|
Q_ASSERT(json_object.contains("triggers"));
|
||
|
if (json_object.contains("triggers")) {
|
||
|
|
||
|
qDebug() << " Found triggers!";
|
||
|
QJsonArray loc_triggers = json_value["triggers"].toArray();
|
||
|
|
||
|
for (const QJsonValue trg : loc_triggers)
|
||
|
{
|
||
|
qDebug() << " Added the trigger " << trg.toString();
|
||
|
new_location->addTriggers( hash_triggers[trg.toString()] );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (json_object.contains("triggers"))
|
||
|
new_location->setDiscovered(json_object["discovered"].toBool());
|
||
|
|
||
|
// check if it has a background
|
||
|
if (json_object.contains("background")) {
|
||
|
qDebug() << " Here is a background.";
|
||
|
QString b = json_value["background"].toString();
|
||
|
new_location->addTriggers(hash_triggers[b]);
|
||
|
qDebug() << " Background was added.";
|
||
|
}
|
||
|
|
||
|
hash_locations.insert(json_object["id"].toString(), new_location);
|
||
|
qDebug() << " The level was inserted into its map.\n - - -";
|
||
|
}
|
||
|
}
|