//////////////////////////////////////////////////////////////////////// // OpenTibia - an opensource roleplaying game //////////////////////////////////////////////////////////////////////// // 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 3 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, see . //////////////////////////////////////////////////////////////////////// #include "otpch.h" #include "beds.h" #include "house.h" #include "player.h" #include "iologindata.h" #include "game.h" #include "configmanager.h" extern Game g_game; extern ConfigManager g_config; Attr_ReadValue BedItem::readAttr(AttrTypes_t attr, PropStream& propStream) { switch(attr) { case ATTR_SLEEPERGUID: { uint32_t _sleeper; if(!propStream.GET_ULONG(_sleeper)) return ATTR_READ_ERROR; if(_sleeper) { std::string name; if(IOLoginData::getInstance()->getNameByGuid(_sleeper, name)) { setSpecialDescription(name + " is sleeping there."); Beds::getInstance().setBedSleeper(this, _sleeper); } } sleeper = _sleeper; return ATTR_READ_CONTINUE; } case ATTR_SLEEPSTART: { uint32_t _sleepStart; if(!propStream.GET_ULONG(_sleepStart)) return ATTR_READ_ERROR; sleepStart = (time_t)_sleepStart; return ATTR_READ_CONTINUE; } default: break; } return Item::readAttr(attr, propStream); } bool BedItem::serializeAttr(PropWriteStream& propWriteStream) const { if(sleeper) { propWriteStream.ADD_UCHAR(ATTR_SLEEPERGUID); propWriteStream.ADD_ULONG(sleeper); } if(sleepStart) { propWriteStream.ADD_UCHAR(ATTR_SLEEPSTART); propWriteStream.ADD_ULONG((int32_t)sleepStart); } return true; } BedItem* BedItem::getNextBedItem() { if(Tile* tile = g_game.getTile(getNextPosition(Item::items[getID()].bedPartnerDir, getPosition()))) return tile->getBedItem(); return NULL; } bool BedItem::canUse(Player* player) { if(!house || !player || player->isRemoved() || (!player->isPremium() && g_config.getBool( ConfigManager::BED_REQUIRE_PREMIUM)) || player->hasCondition(CONDITION_INFIGHT)) return false; if(!sleeper || house->getHouseAccessLevel(player) == HOUSE_OWNER) return isBed(); Player* _player = g_game.getPlayerByGuidEx(sleeper); if(!_player) return isBed(); bool ret = house->getHouseAccessLevel(_player) <= house->getHouseAccessLevel(player); if(_player->isVirtual()) delete _player; return ret; } void BedItem::sleep(Player* player) { if(!house || !player || player->isRemoved()) return; if(!sleeper) { Beds::getInstance().setBedSleeper(this, player->getGUID()); internalSetSleeper(player); BedItem* nextBedItem = getNextBedItem(); if(nextBedItem) nextBedItem->internalSetSleeper(player); updateAppearance(player); if(nextBedItem) nextBedItem->updateAppearance(player); player->getTile()->moveCreature(NULL, player, getTile()); g_game.addMagicEffect(player->getPosition(), NM_ME_SLEEP); Scheduler::getScheduler().addEvent(createSchedulerTask(SCHEDULER_MINTICKS, boost::bind(&Game::kickPlayer, &g_game, player->getID(), false))); } else if(Item::items[getID()].transformToFree) { wakeUp(); g_game.addMagicEffect(player->getPosition(), NM_ME_POFF); } else player->sendCancelMessage(RET_NOTPOSSIBLE); } void BedItem::wakeUp() { if(!house) return; if(sleeper) { if(Player* player = g_game.getPlayerByGuidEx(sleeper)) { regeneratePlayer(player); if(player->isVirtual()) { IOLoginData::getInstance()->savePlayer(player); delete player; } else g_game.addCreatureHealth(player); } } Beds::getInstance().setBedSleeper(NULL, sleeper); internalRemoveSleeper(); BedItem* nextBedItem = getNextBedItem(); if(nextBedItem) nextBedItem->internalRemoveSleeper(); updateAppearance(NULL); if(nextBedItem) nextBedItem->updateAppearance(NULL); } void BedItem::regeneratePlayer(Player* player) const { int32_t sleptTime = int32_t(time(NULL) - sleepStart); if(Condition* condition = player->getCondition(CONDITION_REGENERATION, CONDITIONID_DEFAULT)) { int32_t amount = sleptTime / 30; if(condition->getTicks() != -1) { amount = std::min((condition->getTicks() / 1000), sleptTime) / 30; int32_t tmp = condition->getTicks() - (amount * 30000); if(tmp <= 0) player->removeCondition(condition); else condition->setTicks(tmp); } player->changeHealth(amount); player->changeMana(amount); } player->changeSoul((int32_t)std::max((float)0, (float)sleptTime / (60 * 15))); } void BedItem::updateAppearance(const Player* player) { const ItemType& it = Item::items[getID()]; if(it.type != ITEM_TYPE_BED) return; if(player && it.transformToOnUse[player->getSex(false)]) { const ItemType& newType = Item::items[it.transformToOnUse[player->getSex(false)]]; if(newType.type == ITEM_TYPE_BED) g_game.transformItem(this, it.transformToOnUse[player->getSex(false)]); } else if(it.transformToFree) { const ItemType& newType = Item::items[it.transformToFree]; if(newType.type == ITEM_TYPE_BED) g_game.transformItem(this, it.transformToFree); } } void BedItem::internalSetSleeper(const Player* player) { setSleeper(player->getGUID()); setSleepStart(time(NULL)); setSpecialDescription(std::string(player->getName() + " is sleeping there.")); } void BedItem::internalRemoveSleeper() { setSleeper(0); setSleepStart(0); setSpecialDescription("Nobody is sleeping there."); } BedItem* Beds::getBedBySleeper(uint32_t guid) { std::map::iterator it = BedSleepersMap.find(guid); if(it != BedSleepersMap.end()) return it->second; return NULL; }