mirror of
https://github.com/ErikasKontenis/SabrehavenServer.git
synced 2025-04-29 17:19:20 +02:00
first implementation of quest log need to review everything
This commit is contained in:
parent
abed251a30
commit
871013018e
@ -37,7 +37,7 @@ replaceKickOnLogin = true
|
|||||||
maxPacketsPerSecond = -1
|
maxPacketsPerSecond = -1
|
||||||
autoStackCumulatives = false
|
autoStackCumulatives = false
|
||||||
moneyRate = 1
|
moneyRate = 1
|
||||||
clientVersion = 780
|
clientVersion = 792
|
||||||
|
|
||||||
-- Deaths
|
-- Deaths
|
||||||
-- NOTE: Leave deathLosePercent as -1 if you want to use the default
|
-- NOTE: Leave deathLosePercent as -1 if you want to use the default
|
||||||
|
1167
data/XML/quests.xml
Normal file
1167
data/XML/quests.xml
Normal file
File diff suppressed because it is too large
Load Diff
@ -32,7 +32,10 @@ local reloadTypes = {
|
|||||||
|
|
||||||
["npc"] = { targetType = RELOAD_TYPE_NPCS, name = "npcs" },
|
["npc"] = { targetType = RELOAD_TYPE_NPCS, name = "npcs" },
|
||||||
["npcs"] = { targetType = RELOAD_TYPE_NPCS, name = "npcs" },
|
["npcs"] = { targetType = RELOAD_TYPE_NPCS, name = "npcs" },
|
||||||
|
|
||||||
|
["quest"] = { targetType = RELOAD_TYPE_QUESTS, name = "quests" },
|
||||||
|
["quests"] = { targetType = RELOAD_TYPE_QUESTS, name = "quests" },
|
||||||
|
|
||||||
["raid"] = { targetType = RELOAD_TYPE_RAIDS, name = "raids" },
|
["raid"] = { targetType = RELOAD_TYPE_RAIDS, name = "raids" },
|
||||||
["raids"] = { targetType = RELOAD_TYPE_RAIDS, name = "raids" },
|
["raids"] = { targetType = RELOAD_TYPE_RAIDS, name = "raids" },
|
||||||
|
|
||||||
|
30
src/game.cpp
30
src/game.cpp
@ -104,6 +104,8 @@ void Game::setGameState(GameState_t newState)
|
|||||||
raids.loadFromXml();
|
raids.loadFromXml();
|
||||||
raids.startup();
|
raids.startup();
|
||||||
|
|
||||||
|
quests.loadFromXml();
|
||||||
|
|
||||||
loadMotdNum();
|
loadMotdNum();
|
||||||
loadPlayersRecord();
|
loadPlayersRecord();
|
||||||
|
|
||||||
@ -2914,6 +2916,31 @@ void Game::playerChangeOutfit(uint32_t playerId, Outfit_t outfit)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Game::playerShowQuestLog(uint32_t playerId)
|
||||||
|
{
|
||||||
|
Player* player = getPlayerByID(playerId);
|
||||||
|
if (!player) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
player->sendQuestLog();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::playerShowQuestLine(uint32_t playerId, uint16_t questId)
|
||||||
|
{
|
||||||
|
Player* player = getPlayerByID(playerId);
|
||||||
|
if (!player) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Quest* quest = quests.getQuestByID(questId);
|
||||||
|
if (!quest) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
player->sendQuestLine(quest);
|
||||||
|
}
|
||||||
|
|
||||||
void Game::playerSay(uint32_t playerId, uint16_t channelId, SpeakClasses type,
|
void Game::playerSay(uint32_t playerId, uint16_t channelId, SpeakClasses type,
|
||||||
const std::string& receiver, const std::string& text)
|
const std::string& receiver, const std::string& text)
|
||||||
{
|
{
|
||||||
@ -4599,6 +4626,8 @@ bool Game::reload(ReloadTypes_t reloadType)
|
|||||||
Npcs::reload();
|
Npcs::reload();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case RELOAD_TYPE_QUESTS: return quests.reload();
|
||||||
case RELOAD_TYPE_RAIDS: return raids.reload() && raids.startup();
|
case RELOAD_TYPE_RAIDS: return raids.reload() && raids.startup();
|
||||||
|
|
||||||
case RELOAD_TYPE_SPELLS: {
|
case RELOAD_TYPE_SPELLS: {
|
||||||
@ -4636,6 +4665,7 @@ bool Game::reload(ReloadTypes_t reloadType)
|
|||||||
raids.reload() && raids.startup();
|
raids.reload() && raids.startup();
|
||||||
g_talkActions->reload();
|
g_talkActions->reload();
|
||||||
Item::items.reload();
|
Item::items.reload();
|
||||||
|
quests.reload();
|
||||||
g_globalEvents->reload();
|
g_globalEvents->reload();
|
||||||
g_events->load();
|
g_events->load();
|
||||||
g_chat->load();
|
g_chat->load();
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include "raids.h"
|
#include "raids.h"
|
||||||
#include "npc.h"
|
#include "npc.h"
|
||||||
#include "wildcardtree.h"
|
#include "wildcardtree.h"
|
||||||
|
#include "quests.h"
|
||||||
|
|
||||||
class ServiceManager;
|
class ServiceManager;
|
||||||
class Creature;
|
class Creature;
|
||||||
@ -387,6 +388,8 @@ class Game
|
|||||||
void playerRequestRemoveVip(uint32_t playerId, uint32_t guid);
|
void playerRequestRemoveVip(uint32_t playerId, uint32_t guid);
|
||||||
void playerTurn(uint32_t playerId, Direction dir);
|
void playerTurn(uint32_t playerId, Direction dir);
|
||||||
void playerRequestOutfit(uint32_t playerId);
|
void playerRequestOutfit(uint32_t playerId);
|
||||||
|
void playerShowQuestLog(uint32_t playerId);
|
||||||
|
void playerShowQuestLine(uint32_t playerId, uint16_t questId);
|
||||||
void playerSay(uint32_t playerId, uint16_t channelId, SpeakClasses type,
|
void playerSay(uint32_t playerId, uint16_t channelId, SpeakClasses type,
|
||||||
const std::string& receiver, const std::string& text);
|
const std::string& receiver, const std::string& text);
|
||||||
void playerChangeOutfit(uint32_t playerId, Outfit_t outfit);
|
void playerChangeOutfit(uint32_t playerId, Outfit_t outfit);
|
||||||
@ -493,6 +496,7 @@ class Game
|
|||||||
Groups groups;
|
Groups groups;
|
||||||
Map map;
|
Map map;
|
||||||
Raids raids;
|
Raids raids;
|
||||||
|
Quests quests;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool playerSaySpell(Player* player, SpeakClasses type, const std::string& text);
|
bool playerSaySpell(Player* player, SpeakClasses type, const std::string& text);
|
||||||
|
@ -495,7 +495,7 @@ bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result)
|
|||||||
query << "SELECT `key`, `value` FROM `player_storage` WHERE `player_id` = " << player->getGUID();
|
query << "SELECT `key`, `value` FROM `player_storage` WHERE `player_id` = " << player->getGUID();
|
||||||
if ((result = db->storeQuery(query.str()))) {
|
if ((result = db->storeQuery(query.str()))) {
|
||||||
do {
|
do {
|
||||||
player->addStorageValue(result->getNumber<uint32_t>("key"), result->getNumber<int32_t>("value"));
|
player->addStorageValue(result->getNumber<uint32_t>("key"), result->getNumber<int32_t>("value"), true);
|
||||||
} while (result->next());
|
} while (result->next());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -507,7 +507,7 @@ uint16_t Player::getLookCorpse() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::addStorageValue(const uint32_t key, const int32_t value)
|
void Player::addStorageValue(const uint32_t key, const int32_t value, const bool isLogin/* = false*/)
|
||||||
{
|
{
|
||||||
if (IS_IN_KEYRANGE(key, RESERVED_RANGE)) {
|
if (IS_IN_KEYRANGE(key, RESERVED_RANGE)) {
|
||||||
if (IS_IN_KEYRANGE(key, OUTFITS_RANGE)) {
|
if (IS_IN_KEYRANGE(key, OUTFITS_RANGE)) {
|
||||||
@ -524,8 +524,20 @@ void Player::addStorageValue(const uint32_t key, const int32_t value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (value != -1) {
|
if (value != -1) {
|
||||||
|
int32_t oldValue;
|
||||||
|
getStorageValue(key, oldValue);
|
||||||
|
|
||||||
storageMap[key] = value;
|
storageMap[key] = value;
|
||||||
} else {
|
|
||||||
|
if (!isLogin && g_game.getClientVersion() >= CLIENT_VERSION_790) {
|
||||||
|
auto currentFrameTime = g_dispatcher.getDispatcherCycle();
|
||||||
|
if (lastQuestlogUpdate != currentFrameTime && g_game.quests.isQuestStorage(key, value, oldValue)) {
|
||||||
|
lastQuestlogUpdate = currentFrameTime;
|
||||||
|
sendTextMessage(MESSAGE_EVENT_ADVANCE, "Your questlog has been updated.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
storageMap.erase(key);
|
storageMap.erase(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
13
src/player.h
13
src/player.h
@ -273,7 +273,7 @@ class Player final : public Creature, public Cylinder
|
|||||||
|
|
||||||
bool canOpenCorpse(uint32_t ownerId) const;
|
bool canOpenCorpse(uint32_t ownerId) const;
|
||||||
|
|
||||||
void addStorageValue(const uint32_t key, const int32_t value);
|
void addStorageValue(const uint32_t key, const int32_t value, const bool isLogin = false);
|
||||||
bool getStorageValue(const uint32_t key, int32_t& value) const;
|
bool getStorageValue(const uint32_t key, int32_t& value) const;
|
||||||
void genReservedStorageRange();
|
void genReservedStorageRange();
|
||||||
|
|
||||||
@ -854,6 +854,16 @@ class Player final : public Creature, public Cylinder
|
|||||||
client->sendOpenPrivateChannel(receiver);
|
client->sendOpenPrivateChannel(receiver);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void sendQuestLog() {
|
||||||
|
if (client) {
|
||||||
|
client->sendQuestLog();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void sendQuestLine(const Quest* quest) {
|
||||||
|
if (client) {
|
||||||
|
client->sendQuestLine(quest);
|
||||||
|
}
|
||||||
|
}
|
||||||
void sendOutfitWindow() {
|
void sendOutfitWindow() {
|
||||||
if (client) {
|
if (client) {
|
||||||
client->sendOutfitWindow();
|
client->sendOutfitWindow();
|
||||||
@ -1012,6 +1022,7 @@ class Player final : public Creature, public Cylinder
|
|||||||
uint64_t experience = 0;
|
uint64_t experience = 0;
|
||||||
uint64_t manaSpent = 0;
|
uint64_t manaSpent = 0;
|
||||||
uint64_t bankBalance = 0;
|
uint64_t bankBalance = 0;
|
||||||
|
uint64_t lastQuestlogUpdate = 0;
|
||||||
int64_t lastAttack = 0;
|
int64_t lastAttack = 0;
|
||||||
int64_t lastFailedFollow = 0;
|
int64_t lastFailedFollow = 0;
|
||||||
int64_t lastPing;
|
int64_t lastPing;
|
||||||
|
@ -429,6 +429,8 @@ void ProtocolGame::parsePacket(NetworkMessage& msg)
|
|||||||
case 0xE6: parseBugReport(msg); break;
|
case 0xE6: parseBugReport(msg); break;
|
||||||
case 0xE7: /* violation window */ break;
|
case 0xE7: /* violation window */ break;
|
||||||
case 0xE8: parseDebugAssert(msg); break;
|
case 0xE8: parseDebugAssert(msg); break;
|
||||||
|
case 0xF0: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerShowQuestLog, player->getID()); break;
|
||||||
|
case 0xF1: parseQuestLine(msg); break;
|
||||||
default:
|
default:
|
||||||
std::cout << "Player: " << player->getName() << " sent an unknown packet header: 0x" << std::hex << static_cast<uint16_t>(recvbyte) << std::dec << "!" << std::endl;
|
std::cout << "Player: " << player->getName() << " sent an unknown packet header: 0x" << std::hex << static_cast<uint16_t>(recvbyte) << std::dec << "!" << std::endl;
|
||||||
break;
|
break;
|
||||||
@ -963,6 +965,12 @@ void ProtocolGame::parsePassPartyLeadership(NetworkMessage& msg)
|
|||||||
addGameTask(&Game::playerPassPartyLeadership, player->getID(), targetId);
|
addGameTask(&Game::playerPassPartyLeadership, player->getID(), targetId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProtocolGame::parseQuestLine(NetworkMessage& msg)
|
||||||
|
{
|
||||||
|
uint16_t questId = msg.get<uint16_t>();
|
||||||
|
addGameTask(&Game::playerShowQuestLine, player->getID(), questId);
|
||||||
|
}
|
||||||
|
|
||||||
void ProtocolGame::parseSeekInContainer(NetworkMessage& msg)
|
void ProtocolGame::parseSeekInContainer(NetworkMessage& msg)
|
||||||
{
|
{
|
||||||
uint8_t containerId = msg.getByte();
|
uint8_t containerId = msg.getByte();
|
||||||
@ -1205,7 +1213,39 @@ void ProtocolGame::sendContainer(uint8_t cid, const Container* container, bool h
|
|||||||
writeToOutputBuffer(msg);
|
writeToOutputBuffer(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProtocolGame::sendQuestLog()
|
||||||
|
{
|
||||||
|
NetworkMessage msg;
|
||||||
|
msg.addByte(0xF0);
|
||||||
|
msg.add<uint16_t>(g_game.quests.getQuestsCount(player));
|
||||||
|
|
||||||
|
for (const Quest& quest : g_game.quests.getQuests()) {
|
||||||
|
if (quest.isStarted(player)) {
|
||||||
|
msg.add<uint16_t>(quest.getID());
|
||||||
|
msg.addString(quest.getName());
|
||||||
|
msg.addByte(quest.isCompleted(player));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writeToOutputBuffer(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProtocolGame::sendQuestLine(const Quest* quest)
|
||||||
|
{
|
||||||
|
NetworkMessage msg;
|
||||||
|
msg.addByte(0xF1);
|
||||||
|
msg.add<uint16_t>(quest->getID());
|
||||||
|
msg.addByte(quest->getMissionsCount(player));
|
||||||
|
|
||||||
|
for (const Mission& mission : quest->getMissions()) {
|
||||||
|
if (mission.isStarted(player)) {
|
||||||
|
msg.addString(mission.getName(player));
|
||||||
|
msg.addString(mission.getDescription(player));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writeToOutputBuffer(msg);
|
||||||
|
}
|
||||||
|
|
||||||
void ProtocolGame::sendTradeItemRequest(const std::string& traderName, const Item* item, bool ack)
|
void ProtocolGame::sendTradeItemRequest(const std::string& traderName, const Item* item, bool ack)
|
||||||
{
|
{
|
||||||
|
@ -113,6 +113,8 @@ class ProtocolGame final : public Protocol
|
|||||||
void parseTextWindow(NetworkMessage& msg);
|
void parseTextWindow(NetworkMessage& msg);
|
||||||
void parseHouseWindow(NetworkMessage& msg);
|
void parseHouseWindow(NetworkMessage& msg);
|
||||||
|
|
||||||
|
void parseQuestLine(NetworkMessage& msg);
|
||||||
|
|
||||||
void parseInviteToParty(NetworkMessage& msg);
|
void parseInviteToParty(NetworkMessage& msg);
|
||||||
void parseJoinParty(NetworkMessage& msg);
|
void parseJoinParty(NetworkMessage& msg);
|
||||||
void parseRevokePartyInvite(NetworkMessage& msg);
|
void parseRevokePartyInvite(NetworkMessage& msg);
|
||||||
@ -156,6 +158,9 @@ class ProtocolGame final : public Protocol
|
|||||||
void sendCreatureTurn(const Creature* creature, uint32_t stackpos);
|
void sendCreatureTurn(const Creature* creature, uint32_t stackpos);
|
||||||
void sendCreatureSay(const Creature* creature, SpeakClasses type, const std::string& text, const Position* pos = nullptr);
|
void sendCreatureSay(const Creature* creature, SpeakClasses type, const std::string& text, const Position* pos = nullptr);
|
||||||
|
|
||||||
|
void sendQuestLog();
|
||||||
|
void sendQuestLine(const Quest* quest);
|
||||||
|
|
||||||
void sendCancelWalk();
|
void sendCancelWalk();
|
||||||
void sendChangeSpeed(const Creature* creature, uint32_t speed);
|
void sendChangeSpeed(const Creature* creature, uint32_t speed);
|
||||||
void sendCancelTarget();
|
void sendCancelTarget();
|
||||||
|
230
src/quests.cpp
Normal file
230
src/quests.cpp
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
/**
|
||||||
|
* The Forgotten Server - a free and open-source MMORPG server emulator
|
||||||
|
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "otpch.h"
|
||||||
|
|
||||||
|
#include "quests.h"
|
||||||
|
|
||||||
|
#include "pugicast.h"
|
||||||
|
|
||||||
|
std::string Mission::getDescription(Player* player) const
|
||||||
|
{
|
||||||
|
int32_t value;
|
||||||
|
player->getStorageValue(storageID, value);
|
||||||
|
|
||||||
|
if (!mainDescription.empty()) {
|
||||||
|
std::string desc = mainDescription;
|
||||||
|
replaceString(desc, "|STATE|", std::to_string(value));
|
||||||
|
replaceString(desc, "\\n", "\n");
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ignoreEndValue) {
|
||||||
|
for (int32_t current = endValue; current >= startValue; current--) {
|
||||||
|
if (value >= current) {
|
||||||
|
auto sit = descriptions.find(current);
|
||||||
|
if (sit != descriptions.end()) {
|
||||||
|
return sit->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (int32_t current = endValue; current >= startValue; current--) {
|
||||||
|
if (value == current) {
|
||||||
|
auto sit = descriptions.find(current);
|
||||||
|
if (sit != descriptions.end()) {
|
||||||
|
return sit->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "An error has occurred, please contact a gamemaster.";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Mission::isStarted(Player* player) const
|
||||||
|
{
|
||||||
|
if (!player) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t value;
|
||||||
|
if (!player->getStorageValue(storageID, value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value < startValue) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ignoreEndValue && value > endValue) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Mission::isCompleted(Player* player) const
|
||||||
|
{
|
||||||
|
if (!player) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t value;
|
||||||
|
if (!player->getStorageValue(storageID, value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ignoreEndValue) {
|
||||||
|
return value >= endValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value == endValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Mission::getName(Player* player) const
|
||||||
|
{
|
||||||
|
if (isCompleted(player)) {
|
||||||
|
return name + " (completed)";
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t Quest::getMissionsCount(Player* player) const
|
||||||
|
{
|
||||||
|
uint16_t count = 0;
|
||||||
|
for (const Mission& mission : missions) {
|
||||||
|
if (mission.isStarted(player)) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Quest::isCompleted(Player* player) const
|
||||||
|
{
|
||||||
|
for (const Mission& mission : missions) {
|
||||||
|
if (!mission.isCompleted(player)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Quest::isStarted(Player* player) const
|
||||||
|
{
|
||||||
|
if (!player) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t value;
|
||||||
|
if (!player->getStorageValue(startStorageID, value) || value < startStorageValue) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Quests::reload()
|
||||||
|
{
|
||||||
|
quests.clear();
|
||||||
|
return loadFromXml();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Quests::loadFromXml()
|
||||||
|
{
|
||||||
|
pugi::xml_document doc;
|
||||||
|
pugi::xml_parse_result result = doc.load_file("data/XML/quests.xml");
|
||||||
|
if (!result) {
|
||||||
|
printXMLError("Error - Quests::loadFromXml", "data/XML/quests.xml", result);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t id = 0;
|
||||||
|
for (auto questNode : doc.child("quests").children()) {
|
||||||
|
quests.emplace_back(
|
||||||
|
questNode.attribute("name").as_string(),
|
||||||
|
++id,
|
||||||
|
pugi::cast<int32_t>(questNode.attribute("startstorageid").value()),
|
||||||
|
pugi::cast<int32_t>(questNode.attribute("startstoragevalue").value())
|
||||||
|
);
|
||||||
|
Quest& quest = quests.back();
|
||||||
|
|
||||||
|
for (auto missionNode : questNode.children()) {
|
||||||
|
std::string mainDescription = missionNode.attribute("description").as_string();
|
||||||
|
|
||||||
|
quest.missions.emplace_back(
|
||||||
|
missionNode.attribute("name").as_string(),
|
||||||
|
pugi::cast<int32_t>(missionNode.attribute("storageid").value()),
|
||||||
|
pugi::cast<int32_t>(missionNode.attribute("startvalue").value()),
|
||||||
|
pugi::cast<int32_t>(missionNode.attribute("endvalue").value()),
|
||||||
|
missionNode.attribute("ignoreendvalue").as_bool()
|
||||||
|
);
|
||||||
|
Mission& mission = quest.missions.back();
|
||||||
|
|
||||||
|
if (mainDescription.empty()) {
|
||||||
|
for (auto missionStateNode : missionNode.children()) {
|
||||||
|
int32_t missionId = pugi::cast<int32_t>(missionStateNode.attribute("id").value());
|
||||||
|
mission.descriptions.emplace(missionId, missionStateNode.attribute("description").as_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mission.mainDescription = mainDescription;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Quest* Quests::getQuestByID(uint16_t id)
|
||||||
|
{
|
||||||
|
for (Quest& quest : quests) {
|
||||||
|
if (quest.id == id) {
|
||||||
|
return ?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t Quests::getQuestsCount(Player* player) const
|
||||||
|
{
|
||||||
|
uint16_t count = 0;
|
||||||
|
for (const Quest& quest : quests) {
|
||||||
|
if (quest.isStarted(player)) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Quests::isQuestStorage(const uint32_t key, const int32_t value, const int32_t oldValue) const
|
||||||
|
{
|
||||||
|
for (const Quest& quest : quests) {
|
||||||
|
if (quest.getStartStorageId() == key && quest.getStartStorageValue() == value) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const Mission& mission : quest.getMissions()) {
|
||||||
|
if (mission.getStorageId() == key && value >= mission.getStartStorageValue() && value <= mission.getEndStorageValue()) {
|
||||||
|
return mission.mainDescription.empty() || oldValue < mission.getStartStorageValue() || oldValue > mission.getEndStorageValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
119
src/quests.h
Normal file
119
src/quests.h
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
/**
|
||||||
|
* The Forgotten Server - a free and open-source MMORPG server emulator
|
||||||
|
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FS_QUESTS_H_16E44051F23547BE8097F8EA9FCAACA0
|
||||||
|
#define FS_QUESTS_H_16E44051F23547BE8097F8EA9FCAACA0
|
||||||
|
|
||||||
|
#include "player.h"
|
||||||
|
#include "networkmessage.h"
|
||||||
|
|
||||||
|
class Mission;
|
||||||
|
class Quest;
|
||||||
|
|
||||||
|
using MissionsList = std::list<Mission>;
|
||||||
|
using QuestsList = std::list<Quest>;
|
||||||
|
|
||||||
|
class Mission
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Mission(std::string name, int32_t storageID, int32_t startValue, int32_t endValue, bool ignoreEndValue) :
|
||||||
|
name(std::move(name)), storageID(storageID), startValue(startValue), endValue(endValue), ignoreEndValue(ignoreEndValue) {}
|
||||||
|
|
||||||
|
bool isCompleted(Player* player) const;
|
||||||
|
bool isStarted(Player* player) const;
|
||||||
|
std::string getName(Player* player) const;
|
||||||
|
std::string getDescription(Player* player) const;
|
||||||
|
|
||||||
|
uint32_t getStorageId() const {
|
||||||
|
return storageID;
|
||||||
|
}
|
||||||
|
int32_t getStartStorageValue() const {
|
||||||
|
return startValue;
|
||||||
|
}
|
||||||
|
int32_t getEndStorageValue() const {
|
||||||
|
return endValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<int32_t, std::string> descriptions;
|
||||||
|
std::string mainDescription;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string name;
|
||||||
|
uint32_t storageID;
|
||||||
|
int32_t startValue, endValue;
|
||||||
|
bool ignoreEndValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Quest
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Quest(std::string name, uint16_t id, int32_t startStorageID, int32_t startStorageValue) :
|
||||||
|
name(std::move(name)), startStorageID(startStorageID), startStorageValue(startStorageValue), id(id) {}
|
||||||
|
|
||||||
|
bool isCompleted(Player* player) const;
|
||||||
|
bool isStarted(Player* player) const;
|
||||||
|
uint16_t getID() const {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
std::string getName() const {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
uint16_t getMissionsCount(Player* player) const;
|
||||||
|
|
||||||
|
uint32_t getStartStorageId() const {
|
||||||
|
return startStorageID;
|
||||||
|
}
|
||||||
|
int32_t getStartStorageValue() const {
|
||||||
|
return startStorageValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MissionsList& getMissions() const {
|
||||||
|
return missions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string name;
|
||||||
|
|
||||||
|
uint32_t startStorageID;
|
||||||
|
int32_t startStorageValue;
|
||||||
|
uint16_t id;
|
||||||
|
|
||||||
|
MissionsList missions;
|
||||||
|
|
||||||
|
friend class Quests;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Quests
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
const QuestsList& getQuests() const {
|
||||||
|
return quests;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool loadFromXml();
|
||||||
|
Quest* getQuestByID(uint16_t id);
|
||||||
|
bool isQuestStorage(const uint32_t key, const int32_t value, const int32_t oldValue) const;
|
||||||
|
uint16_t getQuestsCount(Player* player) const;
|
||||||
|
bool reload();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QuestsList quests;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -217,6 +217,7 @@
|
|||||||
<ClCompile Include="..\src\waitlist.cpp" />
|
<ClCompile Include="..\src\waitlist.cpp" />
|
||||||
<ClCompile Include="..\src\wildcardtree.cpp" />
|
<ClCompile Include="..\src\wildcardtree.cpp" />
|
||||||
<ClCompile Include="..\src\xtea.cpp" />
|
<ClCompile Include="..\src\xtea.cpp" />
|
||||||
|
<ClCompile Include="..\src\quests.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\src\account.h" />
|
<ClInclude Include="..\src\account.h" />
|
||||||
@ -295,6 +296,7 @@
|
|||||||
<ClInclude Include="..\src\waitlist.h" />
|
<ClInclude Include="..\src\waitlist.h" />
|
||||||
<ClInclude Include="..\src\wildcardtree.h" />
|
<ClInclude Include="..\src\wildcardtree.h" />
|
||||||
<ClInclude Include="..\src\xtea.h" />
|
<ClInclude Include="..\src\xtea.h" />
|
||||||
|
<ClInclude Include="..\src\quests.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user