House::House(uint32_t houseId)
{
guild = pendingTransfer = false;
name = "OTX headquarter (Flat 1, Area 42)";
entry = Position();
id = houseId;
rent = price = townId = paidUntil = owner = rentWarnings = lastWarning = 0;
syncFlags = HOUSE_SYNC_NAME | HOUSE_SYNC_TOWN | HOUSE_SYNC_SIZE | HOUSE_SYNC_PRICE | HOUSE_SYNC_RENT | HOUSE_SYNC_GUILD;
}
bool House::setOwnerEx(uint32_t guid, bool transfer)
{
if(owner == guid)
return true;
if(owner)
{
rentWarnings = paidUntil = 0;
if(transfer)
clean();
setAccessList(SUBOWNER_LIST, "", !transfer);
setAccessList(GUEST_LIST, "", !transfer);
for(HouseDoorList::iterator it = doorList.begin(); it != doorList.end(); ++it)
(*it)->setAccessList("");
}
setOwner(guid);
lastWarning = guid ? time(NULL) : 0;
Database* db = Database::getInstance();
DBTransaction trans(db);
if(!trans.begin())
return false;
IOMapSerialize::getInstance()->saveHouse(db, this);
return trans.commit();
}
Houses::Houses()
{
rentPeriod = RENTPERIOD_NEVER;
std::string strValue = asLowerCaseString(g_config.getString(ConfigManager::HOUSE_RENT_PERIOD));
if(strValue == "yearly")
rentPeriod = RENTPERIOD_YEARLY;
else if(strValue == "monthly")
rentPeriod = RENTPERIOD_MONTHLY;
else if(strValue == "weekly")
rentPeriod = RENTPERIOD_WEEKLY;
else if(strValue == "daily")
rentPeriod = RENTPERIOD_DAILY;
}
int32_t houseId = 0;
if(!readXMLInteger(houseNode, "houseid", houseId))
{
std::clog << "[Error - Houses::loadFromXml] Could not read houseId" << std::endl;
xmlFreeDoc(doc);
return false;
}
House* house = Houses::getInstance()->getHouse(houseId);
if(!house)
{
std::clog << "[Error - Houses::loadFromXml] Unknown house with id: " << houseId << std::endl;
xmlFreeDoc(doc);
return false;
}
Position entry(0, 0, 0);
if(readXMLInteger(houseNode, "entryx", intValue))
entry.x = intValue;
if(readXMLInteger(houseNode, "entryy", intValue))
entry.y = intValue;
if(readXMLInteger(houseNode, "entryz", intValue))
entry.z = intValue;
if(readXMLString(houseNode, "name", strValue))
house->setName(strValue);
else
house->resetSyncFlag(House::HOUSE_SYNC_NAME);
house->setEntry(entry);
if(!entry.x || !entry.y)
{
std::clog << "[Warning - Houses::loadFromXml] House entry not set for: "
<< house->getName() << " (" << houseId << ")" << std::endl;
}
if(readXMLInteger(houseNode, "townid", intValue))
house->setTownId(intValue);
else
house->resetSyncFlag(House::HOUSE_SYNC_TOWN);
if(readXMLInteger(houseNode, "size", intValue))
house->setSize(intValue);
else
house->resetSyncFlag(House::HOUSE_SYNC_SIZE);
if(readXMLString(houseNode, "guildhall", strValue))
house->setGuild(booleanString(strValue));
else
house->resetSyncFlag(House::HOUSE_SYNC_GUILD);
uint32_t rent = 0;
if(readXMLInteger(houseNode, "rent", intValue))
rent = intValue;
uint32_t price = (house->getSize() + house->getBedsCount()) * g_config.getNumber(ConfigManager::HOUSE_PRICE);
// we should let players to pay only for walkable tiles + beds as single units not two items.
if(g_config.getBool(ConfigManager::HOUSE_RENTASPRICE) && rent)
price = rent;
house->setPrice(price);
if(g_config.getBool(ConfigManager::HOUSE_PRICEASRENT))
house->setRent(price);
else
house->setRent(rent);
house->setOwner(0);
houseNode = houseNode->next;
}
xmlFreeDoc(doc);
return true;
}
bool Houses::payRent(Player* player, House* house, uint32_t bid, time_t _time/* = 0*/)
{
if(rentPeriod == RENTPERIOD_NEVER || !house->getOwner() ||
house->getPaidUntil() > _time || !house->getRent() ||
player->hasCustomFlag(PlayerCustomFlag_IgnoreHouseRent))
return true;
Town* town = Towns::getInstance()->getTown(house->getTownId());
if(!town)
return false;
bool paid = false;
uint32_t amount = house->getRent() + bid;
if(g_config.getBool(ConfigManager::BANK_SYSTEM) && player->balance >= amount)
{
player->balance -= amount;
paid = true;
}
else if(Depot* depot = player->getDepot(town->getID(), true))
paid = g_game.removeMoney(depot, amount, FLAG_NOLIMIT);
if(!paid)
return false;
if(!_time)
_time = time(NULL);
uint32_t paidUntil = _time;
switch(rentPeriod)
{
case RENTPERIOD_DAILY:
paidUntil += 86400;
break;
case RENTPERIOD_WEEKLY:
paidUntil += 7 * 86400;
break;
case RENTPERIOD_MONTHLY:
paidUntil += 30 * 86400;
break;
case RENTPERIOD_YEARLY:
paidUntil += 365 * 86400;
break;
default:
break;
}
house->setLastWarning(0);
house->setRentWarnings(0);
house->setPaidUntil(paidUntil);
return true;
}
bool Houses::payHouse(House* house, time_t _time, uint32_t bid)
{
if(rentPeriod == RENTPERIOD_NEVER || !house->getOwner() ||
house->getPaidUntil() > _time || !house->getRent())
return true;
Town* town = Towns::getInstance()->getTown(house->getTownId());
if(!town)
return false;
uint32_t owner = house->getOwner();
if(house->isGuild() && !IOGuild::getInstance()->swapGuildIdToOwner(owner))
{
house->setOwnerEx(0, true);
return false;
}
std::string name;
if(!IOLoginData::getInstance()->getNameByGuid(owner, name))
{
house->setOwnerEx(0, true);
return false;
}
Player* player = g_game.getPlayerByNameEx(name);
if(!player)
return false;
if(!player->isPremium() && g_config.getBool(ConfigManager::HOUSE_NEED_PREMIUM))
{
house->setOwnerEx(0, true);
if(player->isVirtual())
delete player;
return false;
}
int32_t loginClean = g_config.getNumber(ConfigManager::HOUSE_CLEAN_OLD);
if(loginClean && _time >= (player->getLastLogin() + loginClean))
{
house->setOwnerEx(0, true);
if(player->isVirtual())
delete player;
return false;
}
if(payRent(player, house, bid, _time) || _time < (house->getLastWarning() + 86400))
{
if(player->isVirtual())
{
IOLoginData::getInstance()->savePlayer(player);
delete player;
}
return true;
}
uint32_t warningsLimit = 7;
switch(rentPeriod)
{
case RENTPERIOD_DAILY:
warningsLimit = 1;
break;
case RENTPERIOD_WEEKLY:
warningsLimit = 3;
break;
case RENTPERIOD_YEARLY:
warningsLimit = 14;
break;
default:
break;
}
uint32_t warnings = house->getRentWarnings();
if(warnings >= warningsLimit)
{
house->setOwnerEx(0, true);
if(player->isVirtual())
delete player;
return false;
}
if(Depot* depot = player->getDepot(town->getID(), true))
{
if(Item* letter = Item::CreateItem(ITEM_LETTER_STAMPED))
{
if(g_game.internalAddItem(NULL, depot, letter, INDEX_WHEREEVER, FLAG_NOLIMIT) == RET_NOERROR)
{
letter->setWriter(g_config.getString(ConfigManager::SERVER_NAME));
letter->setDate(std::time(NULL));
std::stringstream s;
s << "Warning!\nThe ";
switch(rentPeriod)
{
case RENTPERIOD_DAILY:
s << "daily";
break;
case RENTPERIOD_WEEKLY:
s << "weekly";
break;
case RENTPERIOD_MONTHLY:
s << "monthly";
break;
case RENTPERIOD_YEARLY:
s << "annual";
break;
default:
break;
}
s << " rent of " << house->getRent() << " gold for your "
<< (house->isGuild() ? "guild hall" : "house") << " \"" << house->getName()
<< "\" has to be paid. Have it within " << (warningsLimit - warnings)
<< " days or you will lose your " << (house->isGuild() ? "guild hall" : "house") << ".";
letter->setText(s.str().c_str());
if(player->isVirtual())
IOLoginData::getInstance()->savePlayer(player);
}
else
g_game.freeThing(letter);
}
}
house->setLastWarning(_time);
house->setRentWarnings(++warnings);
if(player->isVirtual())
delete player;
return false;
}