When a player uses a bed, it converts from playernotsleeping to playersleeping.
onLook ->Dip Set is sleeping.
when a player logs in, it stays visually playersleeping
onLook -> nobody is sleeping.
when a player uses the bed, it reverts to nobody in bed visually but
onLook -> Dip Set is sleeping
So basically when you "use" the bed, it works properly, and transform nobody in bed -> player sleeping in bed
when player is sleeping in bed, it shows properly which character is in the bed
the only problem is on login, it's not triggering bed conversion
TFS 1.3, does anyone have any guidance/direction? I'm not looking for exact answer here, just some direction.
Thank you
my player.cpp wakeup reference
game.cpp
my bed.cpp (sorry for the length)
onLook ->Dip Set is sleeping.
when a player logs in, it stays visually playersleeping
onLook -> nobody is sleeping.
when a player uses the bed, it reverts to nobody in bed visually but
onLook -> Dip Set is sleeping
So basically when you "use" the bed, it works properly, and transform nobody in bed -> player sleeping in bed
when player is sleeping in bed, it shows properly which character is in the bed
the only problem is on login, it's not triggering bed conversion
TFS 1.3, does anyone have any guidance/direction? I'm not looking for exact answer here, just some direction.
Thank you
my player.cpp wakeup reference
C++:
BedItem *bed = g_game.getBedBySleeper(guid);
if (bed)
{
bed->wakeUp(this);
}
game.cpp
C++:
BedItem* Game::getBedBySleeper(uint32_t guid) const
{
auto it = bedSleepersMap.find(guid);
if (it == bedSleepersMap.end()) {
return nullptr;
}
return it->second;
}
void Game::setBedSleeper(BedItem* bed, uint32_t guid)
{
bedSleepersMap[guid] = bed;
}
void Game::removeBedSleeper(uint32_t guid)
{
auto it = bedSleepersMap.find(guid);
if (it != bedSleepersMap.end()) {
bedSleepersMap.erase(it);
}
}
my bed.cpp (sorry for the length)
C++:
BedItem::BedItem(uint16_t id) : Item(id)
{
internalRemoveSleeper();
}
Attr_ReadValue BedItem::readAttr(AttrTypes_t attr, PropStream& propStream)
{
switch (attr) {
case ATTR_SLEEPERGUID: {
uint32_t guid;
if (!propStream.read<uint32_t>(guid)) {
return ATTR_READ_ERROR;
}
if (guid != 0) {
std::string name = IOLoginData::getNameByGuid(guid);
if (!name.empty()) {
setSpecialDescription(name + " is sleeping there.");
g_game.setBedSleeper(this, guid);
sleeperGUID = guid;
}
}
return ATTR_READ_CONTINUE;
}
case ATTR_SLEEPSTART: {
uint32_t sleep_start;
if (!propStream.read<uint32_t>(sleep_start)) {
return ATTR_READ_ERROR;
}
sleepStart = static_cast<uint64_t>(sleep_start);
return ATTR_READ_CONTINUE;
}
default:
break;
}
return Item::readAttr(attr, propStream);
}
void BedItem::serializeAttr(PropWriteStream& propWriteStream) const
{
if (sleeperGUID != 0) {
propWriteStream.write<uint8_t>(ATTR_SLEEPERGUID);
propWriteStream.write<uint32_t>(sleeperGUID);
}
if (sleepStart != 0) {
propWriteStream.write<uint8_t>(ATTR_SLEEPSTART);
// FIXME: should be stored as 64-bit, but we need to retain backwards compatibility
propWriteStream.write<uint32_t>(static_cast<uint32_t>(sleepStart));
}
}
BedItem* BedItem::getNextBedItem() const
{
Direction dir = Item::items[id].bedPartnerDir;
Position targetPos = getNextPosition(dir, getPosition());
Tile* tile = g_game.map.getTile(targetPos);
if (tile == nullptr) {
return nullptr;
}
return tile->getBedItem();
}
bool BedItem::canUse(Player* player)
{
if ((player == nullptr) || (house == nullptr) || !player->isPremium()) {
return false;
}
if (sleeperGUID == 0) {
return true;
}
if (house->getHouseAccessLevel(player) == HOUSE_OWNER) {
return true;
}
Player sleeper(nullptr);
if (!IOLoginData::loadPlayerById(&sleeper, sleeperGUID)) {
return false;
}
if (house->getHouseAccessLevel(&sleeper) > house->getHouseAccessLevel(player)) {
return false;
}
return true;
}
bool BedItem::trySleep(Player* player)
{
if (!house || player->isRemoved()) {
return false;
}
if (sleeperGUID != 0) {
if (Item::items[id].transformToFree != 0 && house->getOwner() == player->getGUID()) {
wakeUp(nullptr);
}
g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
return false;
}
return true;
}
bool BedItem::sleep(Player* player)
{
if (house == nullptr) {
return false;
}
if (sleeperGUID != 0) {
return false;
}
BedItem* nextBedItem = getNextBedItem();
internalSetSleeper(player);
if (nextBedItem != nullptr) {
nextBedItem->internalSetSleeper(player);
}
// update the bedSleepersMap
g_game.setBedSleeper(this, player->getGUID());
// make the player walk onto the bed
g_game.map.moveCreature(*player, *getTile());
// display 'Zzzz'/sleep effect
g_game.addMagicEffect(player->getPosition(), CONST_ME_SLEEP);
// kick player after he sees himself walk onto the bed and it change id
uint32_t playerId = player->getID();
g_scheduler.addEvent(createSchedulerTask(SCHEDULER_MINTICKS, std::bind(&Game::kickPlayer, &g_game, playerId, false)));
// change self and partner's appearance
updateAppearance(player);
if (nextBedItem != nullptr) {
nextBedItem->updateAppearance(player);
}
return true;
}
void BedItem::wakeUp(Player* player)
{
if (house == nullptr) {
return;
}
if (sleeperGUID != 0) {
if (player == nullptr) {
Player regenPlayer(nullptr);
if (IOLoginData::loadPlayerById(®enPlayer, sleeperGUID)) {
regeneratePlayer(®enPlayer);
IOLoginData::savePlayer(®enPlayer);
}
} else {
regeneratePlayer(player);
g_game.addCreatureHealth(player);
}
}
// update the bedSleepersMap
g_game.removeBedSleeper(sleeperGUID);
BedItem* nextBedItem = getNextBedItem();
// unset sleep info
internalRemoveSleeper();
if (nextBedItem != nullptr) {
nextBedItem->internalRemoveSleeper();
}
// change self and partner's appearance
updateAppearance(nullptr);
if (nextBedItem != nullptr) {
nextBedItem->updateAppearance(nullptr);
}
}
void BedItem::regeneratePlayer(Player* player) const
{
const uint32_t sleptTime = time(nullptr) - sleepStart;
Condition* condition = player->getCondition(CONDITION_REGENERATION, CONDITIONID_DEFAULT);
if (condition != nullptr) {
uint32_t regen;
if (condition->getTicks() != -1) {
regen = std::min<int32_t>((condition->getTicks() / 1000), sleptTime) / 30;
const int32_t newRegenTicks = condition->getTicks() - (regen * 30000);
if (newRegenTicks <= 0) {
player->removeCondition(condition);
} else {
condition->setTicks(newRegenTicks);
}
} else {
regen = sleptTime / 30;
}
player->changeHealth(regen, false);
player->changeMana(regen);
}
const int32_t soulRegen = sleptTime / (60 * 15);
player->changeSoul(soulRegen);
}
void BedItem::updateAppearance(const Player* player)
{
const ItemType& it = Item::items[id];
if (it.type == ITEM_TYPE_BED) {
if ((player != nullptr) && it.transformToOnUse[player->getSex()] != 0) {
const ItemType& newType = Item::items[it.transformToOnUse[player->getSex()]];
if (newType.type == ITEM_TYPE_BED) {
g_game.transformItem(this, it.transformToOnUse[player->getSex()]);
}
} else if (it.transformToFree != 0) {
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)
{
std::string desc_str = player->getName() + " is sleeping there.";
sleeperGUID = player->getGUID();
sleepStart = time(nullptr);
setSpecialDescription(desc_str);
}
void BedItem::internalRemoveSleeper()
{
sleeperGUID = 0;
sleepStart = 0;
setSpecialDescription("Nobody is sleeping there.");
}
Last edited: