1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the examples of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:BSD$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** BSD License Usage
18** Alternatively, you may use this file under the terms of the BSD license
19** as follows:
20**
21** "Redistribution and use in source and binary forms, with or without
22** modification, are permitted provided that the following conditions are
23** met:
24** * Redistributions of source code must retain the above copyright
25** notice, this list of conditions and the following disclaimer.
26** * Redistributions in binary form must reproduce the above copyright
27** notice, this list of conditions and the following disclaimer in
28** the documentation and/or other materials provided with the
29** distribution.
30** * Neither the name of The Qt Company Ltd nor the names of its
31** contributors may be used to endorse or promote products derived
32** from this software without specific prior written permission.
33**
34**
35** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46**
47** $QT_END_LICENSE$
48**
49****************************************************************************/
50
51#include "game.h"
52
53#include <QCborMap>
54#include <QCborValue>
55#include <QFile>
56#include <QJsonArray>
57#include <QJsonDocument>
58#include <QRandomGenerator>
59#include <QTextStream>
60
61Character Game::player() const
62{
63 return mPlayer;
64}
65
66QList<Level> Game::levels() const
67{
68 return mLevels;
69}
70
71//! [0]
72void Game::newGame()
73{
74 mPlayer = Character();
75 mPlayer.setName(QStringLiteral("Hero"));
76 mPlayer.setClassType(Character::Archer);
77 mPlayer.setLevel(QRandomGenerator::global()->bounded(15, 21));
78
79 mLevels.clear();
80 mLevels.reserve(2);
81
82 Level village(QStringLiteral("Village"));
83 QList<Character> villageNpcs;
84 villageNpcs.reserve(2);
85 villageNpcs.append(Character(QStringLiteral("Barry the Blacksmith"),
86 QRandomGenerator::global()->bounded(8, 11),
87 Character::Warrior));
88 villageNpcs.append(Character(QStringLiteral("Terry the Trader"),
89 QRandomGenerator::global()->bounded(6, 8),
90 Character::Warrior));
91 village.setNpcs(villageNpcs);
92 mLevels.append(village);
93
94 Level dungeon(QStringLiteral("Dungeon"));
95 QList<Character> dungeonNpcs;
96 dungeonNpcs.reserve(3);
97 dungeonNpcs.append(Character(QStringLiteral("Eric the Evil"),
98 QRandomGenerator::global()->bounded(18, 26),
99 Character::Mage));
100 dungeonNpcs.append(Character(QStringLiteral("Eric's Left Minion"),
101 QRandomGenerator::global()->bounded(5, 7),
102 Character::Warrior));
103 dungeonNpcs.append(Character(QStringLiteral("Eric's Right Minion"),
104 QRandomGenerator::global()->bounded(4, 9),
105 Character::Warrior));
106 dungeon.setNpcs(dungeonNpcs);
107 mLevels.append(dungeon);
108}
109//! [0]
110
111//! [3]
112bool Game::loadGame(Game::SaveFormat saveFormat)
113{
114 QFile loadFile(saveFormat == Json
115 ? QStringLiteral("save.json")
116 : QStringLiteral("save.dat"));
117
118 if (!loadFile.open(QIODevice::ReadOnly)) {
119 qWarning("Couldn't open save file.");
120 return false;
121 }
122
123 QByteArray saveData = loadFile.readAll();
124
125 QJsonDocument loadDoc(saveFormat == Json
126 ? QJsonDocument::fromJson(saveData)
127 : QJsonDocument(QCborValue::fromCbor(saveData).toMap().toJsonObject()));
128
129 read(loadDoc.object());
130
131 QTextStream(stdout) << "Loaded save for "
132 << loadDoc["player"]["name"].toString()
133 << " using "
134 << (saveFormat != Json ? "CBOR" : "JSON") << "...\n";
135 return true;
136}
137//! [3]
138
139//! [4]
140bool Game::saveGame(Game::SaveFormat saveFormat) const
141{
142 QFile saveFile(saveFormat == Json
143 ? QStringLiteral("save.json")
144 : QStringLiteral("save.dat"));
145
146 if (!saveFile.open(QIODevice::WriteOnly)) {
147 qWarning("Couldn't open save file.");
148 return false;
149 }
150
151 QJsonObject gameObject;
152 write(gameObject);
153 saveFile.write(saveFormat == Json
154 ? QJsonDocument(gameObject).toJson()
155 : QCborValue::fromJsonValue(gameObject).toCbor());
156
157 return true;
158}
159//! [4]
160
161//! [1]
162void Game::read(const QJsonObject &json)
163{
164 if (json.contains("player") && json["player"].isObject())
165 mPlayer.read(json["player"].toObject());
166
167 if (json.contains("levels") && json["levels"].isArray()) {
168 QJsonArray levelArray = json["levels"].toArray();
169 mLevels.clear();
170 mLevels.reserve(levelArray.size());
171 for (int levelIndex = 0; levelIndex < levelArray.size(); ++levelIndex) {
172 QJsonObject levelObject = levelArray[levelIndex].toObject();
173 Level level;
174 level.read(levelObject);
175 mLevels.append(level);
176 }
177 }
178}
179//! [1]
180
181//! [2]
182void Game::write(QJsonObject &json) const
183{
184 QJsonObject playerObject;
185 mPlayer.write(playerObject);
186 json["player"] = playerObject;
187
188 QJsonArray levelArray;
189 for (const Level &level : mLevels) {
190 QJsonObject levelObject;
191 level.write(levelObject);
192 levelArray.append(levelObject);
193 }
194 json["levels"] = levelArray;
195}
196//! [2]
197
198void Game::print(int indentation) const
199{
200 const QString indent(indentation * 2, ' ');
201 QTextStream(stdout) << indent << "Player\n";
202 mPlayer.print(indentation + 1);
203
204 QTextStream(stdout) << indent << "Levels\n";
205 for (Level level : mLevels)
206 level.print(indentation + 1);
207}
208