You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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 - - -";
}
}