// Cyphesis Online RPG Server and AI Engine // Copyright (C) 2006 Alistair Riddoch // // 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 // $Id: OutfitProperty.cpp,v 1.11 2007-01-13 13:54:24 alriddoch Exp $ #include "OutfitProperty.h" #include "Entity.h" #include "common/log.h" #include "common/debug.h" #include "common/Update.h" #include #include #include using Atlas::Message::Element; using Atlas::Message::MapType; using Atlas::Objects::Operation::Update; using Atlas::Objects::Entity::Anonymous; static const bool debug_flag = false; /// \brief OutfitProperty constructor OutfitProperty::OutfitProperty() : PropertyBase(0) { } OutfitProperty::~OutfitProperty() { } bool OutfitProperty::get(Atlas::Message::Element & val) const { val = MapType(); MapType & val_map = val.Map(); EntityRefMap::const_iterator I = m_data.begin(); EntityRefMap::const_iterator Iend = m_data.end(); for (; I != Iend; ++I) { const EntityRef & item = I->second; if (item.get() == 0) { val_map[I->first] = ""; } else { val_map[I->first] = item->getId(); } } return true; } void OutfitProperty::set(const Atlas::Message::Element & val) { // INT id? if (!val.isMap()) { debug(std::cout << "Value of outfit is not a map" << std::endl << std::flush;); return; } const MapType & val_map = val.Map(); MapType::const_iterator I = val_map.begin(); MapType::const_iterator Iend = val_map.end(); for (; I != Iend; ++I) { const std::string & key = I->first; const Atlas::Message::Element & item = I->second; if (item.isString()) { const std::string & id = item.String(); Entity * e = BaseWorld::instance().getEntity(id); if (e != 0) { m_data[key] = EntityRef(e); } } else if (item.isPtr()) { Entity * e = (Entity*)item.Ptr(); assert(e != 0); m_data[key] = EntityRef(e); } else { debug(std::cout << "Key " << key << " is of type " << item.getType() << " when setting outfit" << std::endl << std::flush;); } } } void OutfitProperty::add(const std::string & key, Atlas::Message::MapType & map) const { if (m_data.empty()) { return; } MapType & val_map = (map[key] = MapType()).Map(); // FIXME This code is essentially shared with the add function below // Move it into a protected function EntityRefMap::const_iterator I = m_data.begin(); EntityRefMap::const_iterator Iend = m_data.end(); for (; I != Iend; ++I) { const EntityRef & item = I->second; if (item.get() != 0) { val_map[I->first] = item->getId(); } else { val_map[I->first] = ""; } } } void OutfitProperty::add(const std::string & key, const Atlas::Objects::Entity::RootEntity & ent) const { if (m_data.empty()) { return; } MapType val_map; EntityRefMap::const_iterator I = m_data.begin(); EntityRefMap::const_iterator Iend = m_data.end(); for (; I != Iend; ++I) { const EntityRef & item = I->second; if (item.get() != 0) { val_map[I->first] = item->getId(); } else { val_map[I->first] = ""; } } ent->setAttr(key, val_map); } void OutfitProperty::cleanUp() { std::set empty_locations; EntityRefMap::const_iterator I = m_data.begin(); EntityRefMap::const_iterator Iend = m_data.end(); for (; I != Iend; ++I) { if (I->second == 0) { empty_locations.insert(I->first); } } std::set::const_iterator J = empty_locations.begin(); std::set::const_iterator Jend = empty_locations.end(); for (; J != Jend; ++J) { m_data.erase(*J); } } void OutfitProperty::wear(Entity * wearer, const std::string & location, Entity * garment) { m_data[location] = EntityRef(garment); // FIXME #10 We need to disconnect the containered signal when re // get triggered, thus removing it, otherwise the calls accumulate. garment->containered_oneshots.push_back( garment->containered.connect(sigc::bind(sigc::mem_fun(this, &OutfitProperty::itemRemoved), garment, wearer)) ); garment->containered_oneshots.push_back( garment->destroyed.connect(sigc::bind(sigc::mem_fun(this, &OutfitProperty::itemRemoved), garment, wearer)) ); } void OutfitProperty::itemRemoved(Entity * garment, Entity * wearer) { Element worn_attr; std::string key; if (garment->getAttr("worn", worn_attr)) { if (worn_attr.isString()) { key = worn_attr.String(); assert(!key.empty()); } else { log(ERROR, "WORN property of garment is not a string"); } } else { EntityRefMap::const_iterator I = m_data.begin(); EntityRefMap::const_iterator Iend = m_data.end(); for (; I != Iend; ++I) { if (I->second == garment) { key = I->first; assert(!key.empty()); } } } if (key.empty()) { log(ERROR, "Outfit trying to remove garment with empty key"); return; } m_data[key] = EntityRef(0); Anonymous update_arg; update_arg->setId(wearer->getId()); update_arg->setAttr("outfit", MapType()); Update update; update->setTo(wearer->getId()); update->setArgs1(update_arg); wearer->sendWorld(update); }