diff options
Diffstat (limited to 'src/player_relations.cpp')
-rw-r--r-- | src/player_relations.cpp | 406 |
1 files changed, 406 insertions, 0 deletions
diff --git a/src/player_relations.cpp b/src/player_relations.cpp new file mode 100644 index 00000000..fe71191c --- /dev/null +++ b/src/player_relations.cpp @@ -0,0 +1,406 @@ +/* + * The Mana World + * Copyright 2008 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World 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 + * any later version. + * + * The Mana World 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 The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "beingmanager.h" +#include "player_relations.h" +#include "graphics.h" +#include "gui/gui.h" + +#include <algorithm> + +#define PLAYER_IGNORE_STRATEGY_NOP "nop" +#define PLAYER_IGNORE_STRATEGY_EMOTE0 "emote0" +#define DEFAULT_IGNORE_STRATEGY PLAYER_IGNORE_STRATEGY_EMOTE0 + +#define NAME "name" // constant for xml serialisation +#define RELATION "relation" // constant for xml serialisation + +#define IGNORE_EMOTE_TIME 100 + + +// (De)serialisation class +class PlayerConfSerialiser : public ConfigurationListManager<std::pair<std::string, PlayerRelation *>, + std::map<std::string, PlayerRelation *> *> +{ + virtual ConfigurationObject *writeConfigItem(std::pair<std::string, PlayerRelation *> value, + ConfigurationObject *cobj) + { + if (!value.second) + return NULL; + cobj->setValue(NAME, value.first); + cobj->setValue(RELATION, value.second->mRelation); + + return cobj; + } + + virtual std::map<std::string, PlayerRelation *> * + readConfigItem(ConfigurationObject *cobj, + std::map<std::string, PlayerRelation *> *container) + { + std::string name = cobj->getValue(NAME, ""); + if (name == "") + return container; + + if (!(*container)[name]) { + int v = cobj->getValue(RELATION, PlayerRelation::NEUTRAL); + (*container)[name] = new PlayerRelation(static_cast<PlayerRelation::relation>(v)); + } + // otherwise ignore the duplicate entry + + return container; + } +}; + +static PlayerConfSerialiser player_conf_serialiser; // stateless singleton + +const unsigned int PlayerRelation::RELATION_PERMISSIONS[RELATIONS_NR] = { + /* NEUTRAL */ 0, // we always fall back to the defaults anyway + /* FRIEND */ EMOTE | SPEECH_FLOAT | SPEECH_LOG | WHISPER | TRADE, + /* DISREGARDED*/ EMOTE | SPEECH_FLOAT, + /* IGNORED */ 0 +}; + +PlayerRelation::PlayerRelation(relation relation) +{ + mRelation = relation; +} + +PlayerRelationsManager::PlayerRelationsManager(void) : + mPersistIgnores(false), + mDefaultPermissions(PlayerRelation::DEFAULT), + mIgnoreStrategy(NULL) +{ +} + +void +PlayerRelationsManager::clear(void) +{ + std::vector<std::string> *names = getPlayers(); + for (std::vector<std::string>::const_iterator + it = names->begin(); it != names->end(); it++) + removePlayer(*it); + delete names; +} + +#define PERSIST_IGNORE_LIST "persist-player-list" +#define PLAYER_IGNORE_STRATEGY "player-ignore-strategy" +#define DEFAULT_PERMISSIONS "default-player-permissions" + +int +PlayerRelationsManager::getPlayerIgnoreStrategyIndex(const std::string &name) +{ + std::vector<PlayerIgnoreStrategy *> *strategies = getPlayerIgnoreStrategies(); + for (unsigned int i = 0; i < strategies->size(); i++) + if ((*strategies)[i]->mShortName == name) + return i; + + return -1; +} + +void +PlayerRelationsManager::load(void) +{ + clear(); + + mPersistIgnores = config.getValue(PERSIST_IGNORE_LIST, 0); + mDefaultPermissions = config.getValue(DEFAULT_PERMISSIONS, mDefaultPermissions); + std::string ignore_strategy_name = config.getValue(PLAYER_IGNORE_STRATEGY, DEFAULT_IGNORE_STRATEGY); + int ignore_strategy_index = getPlayerIgnoreStrategyIndex(ignore_strategy_name); + if (ignore_strategy_index >= 0) + setPlayerIgnoreStrategy((*getPlayerIgnoreStrategies())[ignore_strategy_index]); + + config.getList<std::pair<std::string, PlayerRelation *>, + std::map<std::string, PlayerRelation *> *> + ("player", &(mRelations), &player_conf_serialiser); +} + + +void +PlayerRelationsManager::init(void) +{ + load(); + + if (!mPersistIgnores) + clear(); // Yes, we still keep them around in the config file until the next update. +} + +void +PlayerRelationsManager::store(void) +{ + config.setList<std::map<std::string, PlayerRelation *>::const_iterator, + std::pair<std::string, PlayerRelation *>, + std::map<std::string, PlayerRelation *> *> + ("player", + mRelations.begin(), mRelations.end(), + &player_conf_serialiser); + + config.setValue(DEFAULT_PERMISSIONS, mDefaultPermissions); + config.setValue(PERSIST_IGNORE_LIST, mPersistIgnores); + config.setValue(PLAYER_IGNORE_STRATEGY, + (mIgnoreStrategy)? mIgnoreStrategy->mShortName : DEFAULT_IGNORE_STRATEGY); + + config.write(); +} + +void +PlayerRelationsManager::signalUpdate(const std::string &name) +{ + store(); + + for (std::list<PlayerRelationsListener *>::const_iterator it = mListeners.begin(); it != mListeners.end(); it++) + (*it)->updatedPlayer(name); +} + +unsigned int +PlayerRelationsManager::checkPermissionSilently(const std::string &player_name, unsigned int flags) +{ + PlayerRelation *r = mRelations[player_name]; + if (!r) + return mDefaultPermissions & flags; + else { + unsigned int permissions = PlayerRelation::RELATION_PERMISSIONS[r->mRelation]; + + switch (r->mRelation) { + case PlayerRelation::NEUTRAL: + permissions = mDefaultPermissions; + break; + + case PlayerRelation::FRIEND: + permissions |= mDefaultPermissions; // widen + break; + + default: + permissions &= mDefaultPermissions; // narrow + } + + return permissions & flags; + } +} + +bool +PlayerRelationsManager::hasPermission(Being *being, unsigned int flags) +{ + if (being->getType() == Being::PLAYER) + return hasPermission(being->getName(), flags) == flags; + return true; +} + +bool +PlayerRelationsManager::hasPermission(const std::string &name, unsigned int flags) +{ + unsigned int rejections = flags & ~checkPermissionSilently(name, flags); + bool permitted = rejections == 0; + + if (!permitted) { + // execute `ignore' strategy, if possible + if (mIgnoreStrategy) + mIgnoreStrategy->ignore(dynamic_cast<Player *>(beingManager->findBeingByName(name, Being::PLAYER)), + rejections); + } + + return permitted; +} + +void +PlayerRelationsManager::setRelation(const std::string &player_name, PlayerRelation::relation relation) +{ + PlayerRelation *r = mRelations[player_name]; + if (r == NULL) + mRelations[player_name] = new PlayerRelation(relation); + else + r->mRelation = relation; + + signalUpdate(player_name); +} + +std::vector<std::string> * +PlayerRelationsManager::getPlayers(void) +{ + std::vector<std::string> *retval = new std::vector<std::string>(); + + for (std::map<std::string, PlayerRelation *>::const_iterator it = mRelations.begin(); it != mRelations.end(); it++) + if (it->second) + retval->push_back(it->first); + + sort(retval->begin(), retval->end()); + + return retval; +} + +void +PlayerRelationsManager::removePlayer(const std::string &name) +{ + if (mRelations[name]) + delete mRelations[name]; + + mRelations.erase(name); + + signalUpdate(name); +} + + +PlayerRelation::relation +PlayerRelationsManager::getRelation(const std::string &name) +{ + if (mRelations[name]) + return mRelations[name]->mRelation; + + return PlayerRelation::NEUTRAL; +} + +//////////////////////////////////////// +// defaults + +unsigned int +PlayerRelationsManager::getDefault(void) const +{ + return mDefaultPermissions; +} + +void +PlayerRelationsManager::setDefault(unsigned int permissions) +{ + mDefaultPermissions = permissions; + + store(); + signalUpdate(""); +} + + +//////////////////////////////////////// +// ignore strategies + + +class PIS_nothing : public PlayerIgnoreStrategy +{ +public: + PIS_nothing() + { + mDescription = "completely ignore"; + mShortName = PLAYER_IGNORE_STRATEGY_NOP; + } + + virtual void + ignore(Player *player, unsigned int flags) + { + } +}; + +class PIS_dotdotdot : public PlayerIgnoreStrategy +{ +public: + PIS_dotdotdot() + { + mDescription = "print '...'"; + mShortName = "dotdotdot"; + } + + virtual void + ignore(Player *player, unsigned int flags) + { + player->setSpeech("...", 5); + } +}; + + +class +BlinkPlayerNameDrawStrategy : public PlayerNameDrawStrategy +{ +public: + BlinkPlayerNameDrawStrategy(int count) : + mCount(count) + { + } + + virtual void draw(Player *player, Graphics *graphics, int px, int py) + { + graphics->setFont(speechFont); + if (mCount & 4) + graphics->drawText(player->getName(), px + 15, py + 30, gcn::Graphics::CENTER); + + if (mCount-- <= 0) + player->setNameDrawStrategy(NULL); + } +private: + int mCount; // Number of steps to blink +}; + + +class PIS_blinkname : public PlayerIgnoreStrategy +{ +public: + PIS_blinkname() + { + mDescription = "blink name"; + mShortName = "blinkname"; + } + + virtual void + ignore(Player *player, unsigned int flags) + { + player->setNameDrawStrategy(new BlinkPlayerNameDrawStrategy(200)); + } +}; + +class PIS_emote : public PlayerIgnoreStrategy +{ +public: + PIS_emote(int emote_nr, const std::string &description, const std::string &shortname) : + mEmotion(emote_nr) + { + mDescription = description; + mShortName = shortname; + } + + virtual void + ignore(Player *player, unsigned int flags) + { + player->setEmote(mEmotion, IGNORE_EMOTE_TIME); + } +private: + int mEmotion; +}; + + + +static std::vector<PlayerIgnoreStrategy *> player_ignore_strategies; + +std::vector<PlayerIgnoreStrategy *> * +PlayerRelationsManager::getPlayerIgnoreStrategies(void) +{ + if (player_ignore_strategies.size() == 0) { + // not initialised yet? + player_ignore_strategies.push_back(new PIS_emote(FIRST_IGNORE_EMOTE, + "floating '...' bubble", + PLAYER_IGNORE_STRATEGY_EMOTE0)); + player_ignore_strategies.push_back(new PIS_emote(FIRST_IGNORE_EMOTE + 1, + "floating bubble", + "emote1")); + player_ignore_strategies.push_back(new PIS_nothing()); + player_ignore_strategies.push_back(new PIS_dotdotdot()); + player_ignore_strategies.push_back(new PIS_blinkname()); + } + return &player_ignore_strategies; +} + + +PlayerRelationsManager player_relations; + |