Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/game/StarQuestDescriptor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/game/StarQuestDescriptor.cpp')
-rw-r--r--source/game/StarQuestDescriptor.cpp444
1 files changed, 444 insertions, 0 deletions
diff --git a/source/game/StarQuestDescriptor.cpp b/source/game/StarQuestDescriptor.cpp
new file mode 100644
index 0000000..7ea986a
--- /dev/null
+++ b/source/game/StarQuestDescriptor.cpp
@@ -0,0 +1,444 @@
+#include "StarQuestDescriptor.hpp"
+#include "StarDataStreamExtra.hpp"
+#include "StarItemDatabase.hpp"
+#include "StarJsonExtra.hpp"
+#include "StarMonster.hpp"
+#include "StarMonsterDatabase.hpp"
+#include "StarObject.hpp"
+#include "StarObjectDatabase.hpp"
+#include "StarVersioningDatabase.hpp"
+
+namespace Star {
+
+bool QuestItem::operator==(QuestItem const& rhs) const {
+ return itemName == rhs.itemName && parameters == rhs.parameters;
+}
+
+ItemDescriptor QuestItem::descriptor() const {
+ return ItemDescriptor(itemName, 1, parameters);
+}
+
+bool QuestEntity::operator==(QuestEntity const& rhs) const {
+ return uniqueId == rhs.uniqueId && species == rhs.species && gender == rhs.gender;
+}
+
+bool QuestLocation::operator==(QuestLocation const& rhs) const {
+ return uniqueId == rhs.uniqueId && region == rhs.region;
+}
+
+bool QuestMonsterType::operator==(QuestMonsterType const& rhs) const {
+ return typeName == rhs.typeName && parameters == rhs.parameters;
+}
+
+bool QuestNpcType::operator==(QuestNpcType const& rhs) const {
+ return species == rhs.species && typeName == rhs.typeName && parameters == rhs.parameters && seed == rhs.seed;
+}
+
+bool QuestCoordinate::operator==(QuestCoordinate const& rhs) const {
+ return coordinate == coordinate;
+}
+
+QuestParamDetail questParamDetailFromJson(Json const& json) {
+ String type = json.getString("type");
+ if (type == "item") {
+ ItemDescriptor itemDescriptor = ItemDescriptor(json.get("item"));
+ return QuestItem{itemDescriptor.name(), itemDescriptor.parameters()};
+
+ } else if (type == "itemTag") {
+ return QuestItemTag(json.getString("tag"));
+
+ } else if (type == "itemList") {
+ return QuestItemList(json.getArray("items").transformed(construct<ItemDescriptor>()));
+
+ } else if (type == "entity") {
+ return QuestEntity{
+ json.optString("uniqueId"),
+ json.optString("species"),
+ json.optString("gender").apply([](String const& gender) { return GenderNames.getLeft(gender); })
+ };
+
+ } else if (type == "location") {
+ return QuestLocation{json.optString("uniqueId"), jsonToRectF(json.get("region"))};
+
+ } else if (type == "monsterType") {
+ return QuestMonsterType{json.getString("typeName"), json.getObject("parameters", JsonObject{})};
+
+ } else if (type == "npcType") {
+ return QuestNpcType{
+ json.getString("species"),
+ json.getString("typeName"),
+ json.getObject("parameters", JsonObject{}),
+ json.optUInt("seed")
+ };
+
+ } else if (type == "coordinate") {
+ return QuestCoordinate{ CelestialCoordinate(json.get("coordinate")) };
+
+ } else if (type == "json") {
+ return json;
+
+ } else if (type == "noDetail") {
+ return {};
+
+ } else {
+ throw StarException::format("Invalid QuestParam type %s", type);
+ }
+}
+
+QuestParam QuestParam::fromJson(Json const& json) {
+ return QuestParam{
+ questParamDetailFromJson(json), json.optString("name"), json.opt("portrait"), json.optString("indicator")};
+}
+
+QuestParamDetail questParamDetailDiskLoad(Json const& json) {
+ String type = json.getString("type");
+ if (type == "item") {
+ ItemDescriptor itemDescriptor = ItemDescriptor::loadStore(json.get("item"));
+ return QuestItem{itemDescriptor.name(), itemDescriptor.parameters()};
+
+ } else if (type == "itemList") {
+ return QuestItemList(json.getArray("items").transformed(&ItemDescriptor::loadStore));
+
+ } else {
+ return questParamDetailFromJson(json);
+ }
+}
+
+QuestParam QuestParam::diskLoad(Json const& json) {
+ return QuestParam{
+ questParamDetailDiskLoad(json), json.optString("name"), json.opt("portrait"), json.optString("indicator")};
+}
+
+Json questParamDetailToJson(QuestParamDetail const& detail) {
+ if (detail.is<QuestItem>()) {
+ QuestItem item = detail.get<QuestItem>();
+ return JsonObject{{"type", "item"}, {"item", item.descriptor().toJson()}};
+
+ } else if (detail.is<QuestItemTag>()) {
+ String tag = detail.get<QuestItemTag>();
+ return JsonObject{{"type", "itemTag"}, {"tag", tag}};
+
+ } else if (detail.is<QuestItemList>()) {
+ List<ItemDescriptor> itemList = detail.get<QuestItemList>();
+ return JsonObject{{"type", "itemList"}, {"items", itemList.transformed(mem_fn(&ItemDescriptor::toJson))}};
+
+ } else if (detail.is<QuestEntity>()) {
+ QuestEntity entity = detail.get<QuestEntity>();
+ return JsonObject{
+ {"type", "entity"},
+ {"uniqueId", jsonFromMaybe(entity.uniqueId)},
+ {"species", jsonFromMaybe(entity.species)},
+ {"gender", jsonFromMaybe(entity.gender.apply([](Gender gender) { return GenderNames.getRight(gender); }))}
+ };
+
+ } else if (detail.is<QuestLocation>()) {
+ QuestLocation location = detail.get<QuestLocation>();
+ return JsonObject{
+ {"type", "location"},
+ {"uniqueId", jsonFromMaybe<String>(location.uniqueId)},
+ {"region", jsonFromRectF(location.region)}
+ };
+
+ } else if (detail.is<QuestMonsterType>()) {
+ QuestMonsterType monsterType = detail.get<QuestMonsterType>();
+ return JsonObject{
+ {"type", "monsterType"}, {"typeName", monsterType.typeName}, {"parameters", monsterType.parameters}};
+
+ }
+ else if (detail.is<QuestNpcType>()) {
+ QuestNpcType npcType = detail.get<QuestNpcType>();
+ return JsonObject{ {"type", "npcType"},
+ {"species", npcType.species},
+ {"typeName", npcType.typeName},
+ {"parameters", npcType.parameters},
+ {"seed", jsonFromMaybe(npcType.seed)}
+ };
+
+ } else if (detail.is<QuestCoordinate>()) {
+ return JsonObject{
+ {"type", "coordinate"},
+ {"coordinate", detail.get<QuestCoordinate>().coordinate.toJson()}
+ };
+
+ } else if (detail.is<QuestJson>()) {
+ return detail.get<QuestJson>().set("type", "json");
+
+ } else {
+ starAssert(detail.empty());
+ return JsonObject{{"type", "noDetail"}};
+ }
+}
+
+Json QuestParam::toJson() const {
+ Json detailJson = questParamDetailToJson(detail);
+ return detailJson.set("name", jsonFromMaybe(name))
+ .set("portrait", jsonFromMaybe(portrait))
+ .set("indicator", jsonFromMaybe(indicator));
+}
+
+Json questParamDetailDiskStore(QuestParamDetail const& detail) {
+ if (detail.is<QuestItem>()) {
+ QuestItem item = detail.get<QuestItem>();
+ return JsonObject{{"type", "item"}, {"item", item.descriptor().diskStore()}};
+
+ } else if (detail.is<QuestItemList>()) {
+ List<ItemDescriptor> itemList = detail.get<QuestItemList>();
+ return JsonObject{{"type", "itemList"}, {"items", itemList.transformed(mem_fn(&ItemDescriptor::diskStore))}};
+ } else {
+ return questParamDetailToJson(detail);
+ }
+}
+
+Json QuestParam::diskStore() const {
+ Json detailJson = questParamDetailDiskStore(detail);
+ return detailJson.set("name", jsonFromMaybe(name))
+ .set("portrait", jsonFromMaybe(portrait))
+ .set("indicator", jsonFromMaybe(indicator));
+}
+
+bool QuestParam::operator==(QuestParam const& rhs) const {
+ return detail == rhs.detail && name == rhs.name && portrait == rhs.portrait && indicator == rhs.indicator;
+}
+
+QuestDescriptor QuestDescriptor::fromJson(Json const& json) {
+ if (json.isType(Json::Type::String)) {
+ return {json.toString(), json.toString(), {}, Random::randu64()};
+ } else {
+ return {json.getString("questId"),
+ json.getString("templateId"),
+ questParamsFromJson(json.get("parameters")),
+ json.getUInt("seed", Random::randu64())};
+ }
+}
+
+QuestDescriptor QuestDescriptor::diskLoad(Json const& spec) {
+ auto versioningDatabase = Root::singleton().versioningDatabase();
+ Json json = versioningDatabase->loadVersionedJson(VersionedJson::fromJson(spec), "QuestDescriptor");
+ return {json.getString("questId"),
+ json.getString("templateId"),
+ questParamsDiskLoad(json.get("parameters")),
+ json.getUInt("seed", Random::randu64())};
+}
+
+Json QuestDescriptor::toJson() const {
+ return JsonObject{
+ {"questId", questId}, {"templateId", templateId}, {"parameters", questParamsToJson(parameters)}, {"seed", seed}};
+}
+
+Json QuestDescriptor::diskStore() const {
+ auto versioningDatabase = Root::singleton().versioningDatabase();
+ auto res = JsonObject{{"questId", questId},
+ {"templateId", templateId},
+ {"parameters", questParamsDiskStore(parameters)},
+ {"seed", seed}};
+ return versioningDatabase->makeCurrentVersionedJson("QuestDescriptor", res).toJson();
+}
+
+bool QuestDescriptor::operator==(QuestDescriptor const& rhs) const {
+ return questId == rhs.questId && templateId == rhs.templateId && parameters == rhs.parameters && seed == rhs.seed;
+}
+
+QuestArcDescriptor QuestArcDescriptor::fromJson(Json const& json) {
+ if (json.isType(Json::Type::Object) && json.contains("quests")) {
+ return QuestArcDescriptor{
+ json.getArray("quests").transformed(&QuestDescriptor::fromJson), json.optString("stagehandUniqueId")};
+ } else {
+ return QuestArcDescriptor{{QuestDescriptor::fromJson(json)}, {}};
+ }
+}
+
+QuestArcDescriptor QuestArcDescriptor::diskLoad(Json const& spec) {
+ auto versioningDatabase = Root::singleton().versioningDatabase();
+ Json json = versioningDatabase->loadVersionedJson(VersionedJson::fromJson(spec), "QuestArcDescriptor");
+ return QuestArcDescriptor{
+ json.getArray("quests").transformed(&QuestDescriptor::diskLoad), json.optString("stagehandUniqueId")};
+}
+
+Json QuestArcDescriptor::toJson() const {
+ return JsonObject{{"quests", quests.transformed(mem_fn(&QuestDescriptor::toJson))},
+ {"stagehandUniqueId", jsonFromMaybe(stagehandUniqueId)}};
+}
+
+Json QuestArcDescriptor::diskStore() const {
+ auto versioningDatabase = Root::singleton().versioningDatabase();
+ auto res = JsonObject{{"quests", quests.transformed(mem_fn(&QuestDescriptor::diskStore))},
+ {"stagehandUniqueId", jsonFromMaybe(stagehandUniqueId)}};
+
+ return versioningDatabase->makeCurrentVersionedJson("QuestArcDescriptor", res).toJson();
+}
+
+bool QuestArcDescriptor::operator==(QuestArcDescriptor const& rhs) const {
+ return quests == rhs.quests && stagehandUniqueId == rhs.stagehandUniqueId;
+}
+
+String questParamText(QuestParam const& parameter) {
+ if (parameter.name)
+ return *parameter.name;
+
+ auto itemDatabase = Root::singleton().itemDatabase();
+
+ if (parameter.detail.is<QuestItem>()) {
+ QuestItem item = parameter.detail.get<QuestItem>();
+ return itemDatabase->item(item.descriptor())->friendlyName();
+
+ } else if (parameter.detail.is<QuestItemList>()) {
+ QuestItemList itemList = parameter.detail.get<QuestItemList>();
+ StringList itemStrings = itemList.transformed([&itemDatabase](ItemDescriptor const& itemDesc) -> String {
+ return strf("%s %s", itemDesc.count(), itemDatabase->item(itemDesc)->friendlyName());
+ });
+ return itemStrings.join(", ");
+
+ } else {
+ return "";
+ }
+}
+
+template <typename Fun,
+ typename ArgType = typename FunctionTraits<Fun>::template Arg<0>,
+ typename RetType = typename FunctionTraits<Fun>::Return>
+StringMap<RetType> transformedMapValues(StringMap<ArgType> const& map, Fun fun) {
+ return StringMap<RetType>::from(map.pairs().transformed(
+ [fun](pair<String, ArgType> entry) { return make_pair(entry.first, fun(entry.second)); }));
+}
+
+StringMap<String> questParamTags(StringMap<QuestParam> const& parameters) {
+ return transformedMapValues(parameters, questParamText);
+}
+
+StringMap<QuestParam> questParamsFromJson(Json const& json) {
+ return transformedMapValues(json.toObject(), &QuestParam::fromJson);
+}
+
+StringMap<QuestParam> questParamsDiskLoad(Json const& json) {
+ return transformedMapValues(json.toObject(), &QuestParam::diskLoad);
+}
+
+Json questParamsToJson(StringMap<QuestParam> const& parameters) {
+ return transformedMapValues(parameters, [](QuestParam const& quest) { return quest.toJson(); });
+}
+
+Json questParamsDiskStore(StringMap<QuestParam> const& parameters) {
+ return transformedMapValues(parameters, [](QuestParam const& quest) { return quest.diskStore(); });
+}
+
+DataStream& operator>>(DataStream& ds, QuestItem& item) {
+ ds.read(item.itemName);
+ ds.read(item.parameters);
+ return ds;
+}
+
+DataStream& operator<<(DataStream& ds, QuestItem const& item) {
+ ds.write(item.itemName);
+ ds.write(item.parameters);
+ return ds;
+}
+
+DataStream& operator>>(DataStream& ds, QuestEntity& entity) {
+ ds.read(entity.uniqueId);
+ ds.read(entity.species);
+ ds.read(entity.gender);
+ return ds;
+}
+
+DataStream& operator<<(DataStream& ds, QuestEntity const& entity) {
+ ds.write(entity.uniqueId);
+ ds.write(entity.species);
+ ds.write(entity.gender);
+ return ds;
+}
+
+DataStream& operator>>(DataStream& ds, QuestLocation& location) {
+ ds.read(location.uniqueId);
+ ds.read(location.region);
+ return ds;
+}
+
+DataStream& operator<<(DataStream& ds, QuestLocation const& location) {
+ ds.write(location.uniqueId);
+ ds.write(location.region);
+ return ds;
+}
+
+DataStream& operator>>(DataStream& ds, QuestMonsterType& monsterType) {
+ ds.read(monsterType.typeName);
+ ds.read(monsterType.parameters);
+ return ds;
+}
+
+DataStream& operator<<(DataStream& ds, QuestMonsterType const& monsterType) {
+ ds.write(monsterType.typeName);
+ ds.write(monsterType.parameters);
+ return ds;
+}
+
+DataStream& operator>>(DataStream& ds, QuestNpcType& npcType) {
+ ds.read(npcType.species);
+ ds.read(npcType.typeName);
+ ds.read(npcType.parameters);
+ ds.read(npcType.seed);
+ return ds;
+}
+
+DataStream& operator<<(DataStream& ds, QuestNpcType const& npcType) {
+ ds.write(npcType.species);
+ ds.write(npcType.typeName);
+ ds.write(npcType.parameters);
+ ds.write(npcType.seed);
+ return ds;
+}
+
+DataStream& operator>>(DataStream& ds, QuestCoordinate& coordinate) {
+ ds.read(coordinate.coordinate);
+ return ds;
+}
+
+DataStream& operator<<(DataStream& ds, QuestCoordinate const& coordinate) {
+ ds.write(coordinate.coordinate);
+ return ds;
+}
+
+DataStream& operator>>(DataStream& ds, QuestParam& param) {
+ ds.read(param.detail);
+ ds.read(param.name);
+ ds.read(param.portrait);
+ ds.read(param.indicator);
+ return ds;
+}
+
+DataStream& operator<<(DataStream& ds, QuestParam const& param) {
+ ds.write(param.detail);
+ ds.write(param.name);
+ ds.write(param.portrait);
+ ds.write(param.indicator);
+ return ds;
+}
+
+DataStream& operator>>(DataStream& ds, QuestDescriptor& quest) {
+ ds.read(quest.questId);
+ ds.read(quest.templateId);
+ ds.read(quest.parameters);
+ ds.read(quest.seed);
+ return ds;
+}
+
+DataStream& operator<<(DataStream& ds, QuestDescriptor const& quest) {
+ ds.write(quest.questId);
+ ds.write(quest.templateId);
+ ds.write(quest.parameters);
+ ds.write(quest.seed);
+ return ds;
+}
+
+DataStream& operator>>(DataStream& ds, QuestArcDescriptor& questArc) {
+ ds.read(questArc.quests);
+ ds.read(questArc.stagehandUniqueId);
+ return ds;
+}
+
+DataStream& operator<<(DataStream& ds, QuestArcDescriptor const& questArc) {
+ ds.write(questArc.quests);
+ ds.write(questArc.stagehandUniqueId);
+ return ds;
+}
+
+}