diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp
index 65cf0717e..05c4cdef8 100644
--- a/Telegram/SourceFiles/apiwrap.cpp
+++ b/Telegram/SourceFiles/apiwrap.cpp
@@ -1046,26 +1046,25 @@ void ApiWrap::clearWebPageRequests() {
 
 void ApiWrap::resolveWebPages() {
 	MessageIds ids; // temp_req_id = -1
-	typedef QPair<int32, MessageIds> IndexAndMessageIds;
-	typedef QMap<ChannelData*, IndexAndMessageIds> MessageIdsByChannel;
+	using IndexAndMessageIds = QPair<int32, MessageIds>;
+	using MessageIdsByChannel = QMap<ChannelData*, IndexAndMessageIds>;
 	MessageIdsByChannel idsByChannel; // temp_req_id = -index - 2
 
-	const WebPageItems &items(App::webPageItems());
+	auto &items = App::webPageItems();
 	ids.reserve(_webPagesPending.size());
 	int32 t = unixtime(), m = INT_MAX;
-	for (WebPagesPending::iterator i = _webPagesPending.begin(); i != _webPagesPending.cend(); ++i) {
+	for (auto i = _webPagesPending.begin(); i != _webPagesPending.cend(); ++i) {
 		if (i.value() > 0) continue;
 		if (i.key()->pendingTill <= t) {
-			WebPageItems::const_iterator j = items.constFind(i.key());
+			auto j = items.constFind(i.key());
 			if (j != items.cend() && !j.value().isEmpty()) {
-				for (HistoryItemsMap::const_iterator it = j.value().cbegin(); it != j.value().cend(); ++it) {
-					HistoryItem *item = j.value().begin().key();
+				for_const (auto item, j.value()) {
 					if (item->id > 0) {
 						if (item->channelId() == NoChannel) {
 							ids.push_back(MTP_int(item->id));
 							i.value() = -1;
 						} else {
-							ChannelData *channel = item->history()->peer->asChannel();
+							auto channel = item->history()->peer->asChannel();
 							MessageIdsByChannel::iterator channelMap = idsByChannel.find(channel);
 							if (channelMap == idsByChannel.cend()) {
 								channelMap = idsByChannel.insert(channel, IndexAndMessageIds(idsByChannel.size(), MessageIds(1, MTP_int(item->id))));
@@ -1083,20 +1082,20 @@ void ApiWrap::resolveWebPages() {
 		}
 	}
 
-	mtpRequestId req = ids.isEmpty() ? 0 : MTP::send(MTPmessages_GetMessages(MTP_vector<MTPint>(ids)), rpcDone(&ApiWrap::gotWebPages, (ChannelData*)0), RPCFailHandlerPtr(), 0, 5);
-	typedef QVector<mtpRequestId> RequestIds;
+	mtpRequestId req = ids.isEmpty() ? 0 : MTP::send(MTPmessages_GetMessages(MTP_vector<MTPint>(ids)), rpcDone(&ApiWrap::gotWebPages, (ChannelData*)nullptr), RPCFailHandlerPtr(), 0, 5);
+	using RequestIds = QVector<mtpRequestId>;
 	RequestIds reqsByIndex(idsByChannel.size(), 0);
-	for (MessageIdsByChannel::const_iterator i = idsByChannel.cbegin(), e = idsByChannel.cend(); i != e; ++i) {
+	for (auto i = idsByChannel.cbegin(), e = idsByChannel.cend(); i != e; ++i) {
 		reqsByIndex[i.value().first] = MTP::send(MTPchannels_GetMessages(i.key()->inputChannel, MTP_vector<MTPint>(i.value().second)), rpcDone(&ApiWrap::gotWebPages, i.key()), RPCFailHandlerPtr(), 0, 5);
 	}
 	if (req || !reqsByIndex.isEmpty()) {
-		for (WebPagesPending::iterator i = _webPagesPending.begin(); i != _webPagesPending.cend(); ++i) {
-			if (i.value() > 0) continue;
-			if (i.value() < 0) {
-				if (i.value() == -1) {
-					i.value() = req;
+		for (auto &requestId : _webPagesPending) {
+			if (requestId > 0) continue;
+			if (requestId < 0) {
+				if (requestId == -1) {
+					requestId = req;
 				} else {
-					i.value() = reqsByIndex[-i.value() - 2];
+					requestId = reqsByIndex[-requestId - 2];
 				}
 			}
 		}
@@ -1115,21 +1114,21 @@ void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &msgs
 	const QVector<MTPMessage> *v = 0;
 	switch (msgs.type()) {
 	case mtpc_messages_messages: {
-		const auto &d(msgs.c_messages_messages());
+		auto &d = msgs.c_messages_messages();
 		App::feedUsers(d.vusers);
 		App::feedChats(d.vchats);
 		v = &d.vmessages.c_vector().v;
 	} break;
 
 	case mtpc_messages_messagesSlice: {
-		const auto &d(msgs.c_messages_messagesSlice());
+		auto &d = msgs.c_messages_messagesSlice();
 		App::feedUsers(d.vusers);
 		App::feedChats(d.vchats);
 		v = &d.vmessages.c_vector().v;
 	} break;
 
 	case mtpc_messages_channelMessages: {
-		auto &d(msgs.c_messages_channelMessages());
+		auto &d = msgs.c_messages_channelMessages();
 		if (channel) {
 			channel->ptsReceived(d.vpts.v);
 		} else {
@@ -1152,21 +1151,21 @@ void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &msgs
 		}
 	}
 
-	for (QMap<uint64, int32>::const_iterator i = msgsIds.cbegin(), e = msgsIds.cend(); i != e; ++i) {
-		if (HistoryItem *item = App::histories().addNewMessage(v->at(i.value()), NewMessageExisting)) {
+	for_const (auto msgId, msgsIds) {
+		if (auto item = App::histories().addNewMessage(v->at(msgId), NewMessageExisting)) {
 			item->setPendingInitDimensions();
 		}
 	}
 
-	const WebPageItems &items(App::webPageItems());
-	for (WebPagesPending::iterator i = _webPagesPending.begin(); i != _webPagesPending.cend();) {
+	auto &items = App::webPageItems();
+	for (auto i = _webPagesPending.begin(); i != _webPagesPending.cend();) {
 		if (i.value() == req) {
 			if (i.key()->pendingTill > 0) {
 				i.key()->pendingTill = -1;
-				WebPageItems::const_iterator j = items.constFind(i.key());
+				auto j = items.constFind(i.key());
 				if (j != items.cend()) {
-					for (HistoryItemsMap::const_iterator k = j.value().cbegin(), e = j.value().cend(); k != e; ++k) {
-						k.key()->setPendingInitDimensions();
+					for_const (auto item, j.value()) {
+						item->setPendingInitDimensions();
 					}
 				}
 			}
diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp
index e8d763647..fcdfe3dcf 100644
--- a/Telegram/SourceFiles/app.cpp
+++ b/Telegram/SourceFiles/app.cpp
@@ -30,6 +30,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
 #include "lang.h"
 #include "data/data_abstract_structure.h"
 #include "history/history_service_layout.h"
+#include "history/history_location_manager.h"
 #include "media/media_audio.h"
 #include "inline_bots/inline_bot_layout_item.h"
 #include "application.h"
@@ -44,47 +45,51 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
 namespace {
 	App::LaunchState _launchState = App::Launched;
 
-	UserData *self = 0;
+	UserData *self = nullptr;
 
-	typedef QHash<PeerId, PeerData*> PeersData;
+	using PeersData = QHash<PeerId, PeerData*>;
 	PeersData peersData;
 
-	typedef QMap<PeerData*, bool> MutedPeers;
+	using MutedPeers = QMap<PeerData*, bool>;
 	MutedPeers mutedPeers;
 
-	typedef QMap<PeerData*, bool> UpdatedPeers;
+	using UpdatedPeers = QMap<PeerData*, bool>;
 	UpdatedPeers updatedPeers;
 
 	PhotosData photosData;
 	DocumentsData documentsData;
 
-	typedef QHash<LocationCoords, LocationData*> LocationsData;
+	using LocationsData = QHash<LocationCoords, LocationData*>;
 	LocationsData locationsData;
 
-	typedef QHash<WebPageId, WebPageData*> WebPagesData;
+	using WebPagesData = QHash<WebPageId, WebPageData*>;
 	WebPagesData webPagesData;
 
+	using GamesData = QHash<GameId, GameData*>;
+	GamesData gamesData;
+
 	PhotoItems photoItems;
 	DocumentItems documentItems;
 	WebPageItems webPageItems;
+	GameItems gameItems;
 	SharedContactItems sharedContactItems;
 	GifItems gifItems;
 
-	typedef OrderedSet<HistoryItem*> DependentItemsSet;
-	typedef QMap<HistoryItem*, DependentItemsSet> DependentItems;
+	using DependentItemsSet = OrderedSet<HistoryItem*>;
+	using DependentItems = QMap<HistoryItem*, DependentItemsSet>;
 	DependentItems dependentItems;
 
 	Histories histories;
 
-	typedef QHash<MsgId, HistoryItem*> MsgsData;
+	using MsgsData = QHash<MsgId, HistoryItem*>;
 	MsgsData msgsData;
-	typedef QMap<ChannelId, MsgsData> ChannelMsgsData;
+	using ChannelMsgsData = QMap<ChannelId, MsgsData>;
 	ChannelMsgsData channelMsgsData;
 
-	typedef QMap<uint64, FullMsgId> RandomData;
+	using RandomData = QMap<uint64, FullMsgId>;
 	RandomData randomData;
 
-	typedef QMap<uint64, QPair<PeerId, QString> > SentData;
+	using SentData = QMap<uint64, QPair<PeerId, QString>>;
 	SentData sentData;
 
 	HistoryItem *hoveredItem = nullptr,
@@ -94,7 +99,7 @@ namespace {
 		*contextItem = nullptr,
 		*mousedItem = nullptr;
 
-	QPixmap *emoji = 0, *emojiLarge = 0;
+	QPixmap *emoji = nullptr, *emojiLarge = nullptr;
 	style::font monofont;
 
 	struct CornersPixmaps {
@@ -104,19 +109,19 @@ namespace {
 		QPixmap *p[4];
 	};
 	CornersPixmaps corners[RoundCornersCount];
-	typedef QMap<uint32, CornersPixmaps> CornersMap;
+	using CornersMap = QMap<uint32, CornersPixmaps>;
 	CornersMap cornersMap;
-	QImage *cornersMaskLarge[4] = { 0 }, *cornersMaskSmall[4] = { 0 };
+	QImage *cornersMaskLarge[4] = { nullptr }, *cornersMaskSmall[4] = { nullptr };
 
-	typedef QMap<uint64, QPixmap> EmojiMap;
+	using EmojiMap = QMap<uint64, QPixmap>;
 	EmojiMap mainEmojiMap;
 	QMap<int32, EmojiMap> otherEmojiMap;
 
 	int32 serviceImageCacheSize = 0;
 
-	typedef QLinkedList<PhotoData*> LastPhotosList;
+	using LastPhotosList = QLinkedList<PhotoData*>;
 	LastPhotosList lastPhotos;
-	typedef QHash<PhotoData*, LastPhotosList::iterator> LastPhotosMap;
+	using LastPhotosMap = QHash<PhotoData*, LastPhotosList::iterator>;
 	LastPhotosMap lastPhotosMap;
 
 	style::color _msgServiceBg;
@@ -1472,7 +1477,7 @@ namespace {
 	DocumentData *feedDocument(const MTPdocument &document, const QPixmap &thumb) {
 		switch (document.type()) {
 		case mtpc_document: {
-			const auto &d(document.c_document());
+			auto &d = document.c_document();
 			return App::documentSet(d.vid.v, 0, d.vaccess_hash.v, d.vversion.v, d.vdate.v, d.vattributes.c_vector().v, qs(d.vmime_type), ImagePtr(thumb, "JPG"), d.vdc_id.v, d.vsize.v, StorageImageLocation());
 		} break;
 		case mtpc_documentEmpty: return App::document(document.c_documentEmpty().vid.v);
@@ -1514,7 +1519,11 @@ namespace {
 		} break;
 		case mtpc_webPagePending: return App::feedWebPage(webpage.c_webPagePending());
 		}
-		return 0;
+		return nullptr;
+	}
+
+	GameData *feedGame(const MTPDgame &game, GameData *convert) {
+		return App::gameSet(game.vid.v, convert, game.vaccess_hash.v, qs(game.vshort_name), qs(game.vtitle), qs(game.vdescription), qs(game.vurl), App::feedPhoto(game.vphoto), game.has_document() ? App::feedDocument(game.vdocument) : nullptr);
 	}
 
 	UserData *curUser() {
@@ -1754,8 +1763,8 @@ namespace {
 			auto &items = App::documentItems();
 			auto i = items.constFind(result);
 			if (i != items.cend()) {
-				for (auto j = i->cbegin(), e = i->cend(); j != e; ++j) {
-					j.key()->setPendingInitDimensions();
+				for_const (auto item, i.value()) {
+					item->setPendingInitDimensions();
 				}
 			}
 		}
@@ -1763,7 +1772,7 @@ namespace {
 	}
 
 	WebPageData *webPage(const WebPageId &webPage) {
-		WebPagesData::const_iterator i = webPagesData.constFind(webPage);
+		auto i = webPagesData.constFind(webPage);
 		if (i == webPagesData.cend()) {
 			i = webPagesData.insert(webPage, new WebPageData(webPage));
 		}
@@ -1773,7 +1782,7 @@ namespace {
 	WebPageData *webPageSet(const WebPageId &webPage, WebPageData *convert, const QString &type, const QString &url, const QString &displayUrl, const QString &siteName, const QString &title, const QString &description, PhotoData *photo, DocumentData *document, int32 duration, const QString &author, int32 pendingTill) {
 		if (convert) {
 			if (convert->id != webPage) {
-				WebPagesData::iterator i = webPagesData.find(convert->id);
+				auto i = webPagesData.find(convert->id);
 				if (i != webPagesData.cend() && i.value() == convert) {
 					webPagesData.erase(i);
 				}
@@ -1795,7 +1804,7 @@ namespace {
 				if (App::main()) App::main()->webPageUpdated(convert);
 			}
 		}
-		WebPagesData::const_iterator i = webPagesData.constFind(webPage);
+		auto i = webPagesData.constFind(webPage);
 		WebPageData *result;
 		if (i == webPagesData.cend()) {
 			if (convert) {
@@ -1830,8 +1839,63 @@ namespace {
 		return result;
 	}
 
+	GameData *game(const GameId &game) {
+		auto i = gamesData.constFind(game);
+		if (i == gamesData.cend()) {
+			i = gamesData.insert(game, new GameData(game));
+		}
+		return i.value();
+	}
+
+	GameData *gameSet(const GameId &game, GameData *convert, const uint64 &accessHash, const QString &shortName, const QString &title, const QString &description, const QString &url, PhotoData *photo, DocumentData *document) {
+		if (convert) {
+			if (convert->id != game) {
+				auto i = gamesData.find(convert->id);
+				if (i != gamesData.cend() && i.value() == convert) {
+					gamesData.erase(i);
+				}
+				convert->id = game;
+			}
+			if (convert->url.isEmpty() && !url.isEmpty()) {
+				convert->accessHash = accessHash;
+				convert->shortName = shortName;
+				convert->title = title;
+				convert->description = description;
+				convert->url = url;
+				convert->photo = photo;
+				convert->document = document;
+				if (App::main()) App::main()->gameUpdated(convert);
+			}
+		}
+		auto i = gamesData.constFind(game);
+		GameData *result;
+		if (i == gamesData.cend()) {
+			if (convert) {
+				result = convert;
+			} else {
+				result = new GameData(game, accessHash, shortName, title, description, url, photo, document);
+			}
+			gamesData.insert(game, result);
+		} else {
+			result = i.value();
+			if (result != convert) {
+				if (result->url.isEmpty() && !url.isEmpty()) {
+					result->accessHash = accessHash;
+					result->shortName = shortName;
+					result->title = title;
+					result->description = description;
+					result->url = url;
+					result->photo = photo;
+					result->document = document;
+					if (App::main()) App::main()->gameUpdated(result);
+				}
+			}
+		}
+		return result;
+	}
+
 	LocationData *location(const LocationCoords &coords) {
-		LocationsData::const_iterator i = locationsData.constFind(coords);
+		auto i = locationsData.constFind(coords);
 		if (i == locationsData.cend()) {
 			i = locationsData.insert(coords, new LocationData(coords));
 		}
@@ -1841,14 +1905,14 @@ namespace {
 	void forgetMedia() {
 		lastPhotos.clear();
 		lastPhotosMap.clear();
-		for (PhotosData::const_iterator i = ::photosData.cbegin(), e = ::photosData.cend(); i != e; ++i) {
-			i.value()->forget();
+		for_const (auto photo, ::photosData) {
+			photo->forget();
 		}
-		for (DocumentsData::const_iterator i = ::documentsData.cbegin(), e = ::documentsData.cend(); i != e; ++i) {
-			i.value()->forget();
+		for_const (auto document, ::documentsData) {
+			document->forget();
 		}
-		for (LocationsData::const_iterator i = ::locationsData.cbegin(), e = ::locationsData.cend(); i != e; ++i) {
-			i.value()->thumb->forget();
+		for_const (auto location, ::locationsData) {
+			location->thumb->forget();
 		}
 	}
 
@@ -2041,6 +2105,7 @@ namespace {
 		::photoItems.clear();
 		::documentItems.clear();
 		::webPageItems.clear();
+		::gameItems.clear();
 		::sharedContactItems.clear();
 		::gifItems.clear();
 		lastPhotos.clear();
@@ -2464,7 +2529,7 @@ namespace {
 	}
 
 	void regPhotoItem(PhotoData *data, HistoryItem *item) {
-		::photoItems[data].insert(item, NullType());
+		::photoItems[data].insert(item);
 	}
 
 	void unregPhotoItem(PhotoData *data, HistoryItem *item) {
@@ -2480,7 +2545,7 @@ namespace {
 	}
 
 	void regDocumentItem(DocumentData *data, HistoryItem *item) {
-		::documentItems[data].insert(item, NullType());
+		::documentItems[data].insert(item);
 	}
 
 	void unregDocumentItem(DocumentData *data, HistoryItem *item) {
@@ -2496,7 +2561,7 @@ namespace {
 	}
 
 	void regWebPageItem(WebPageData *data, HistoryItem *item) {
-		::webPageItems[data].insert(item, NullType());
+		::webPageItems[data].insert(item);
 	}
 
 	void unregWebPageItem(WebPageData *data, HistoryItem *item) {
@@ -2507,10 +2572,22 @@ namespace {
 		return ::webPageItems;
 	}
 
+	void regGameItem(GameData *data, HistoryItem *item) {
+		::gameItems[data].insert(item);
+	}
+
+	void unregGameItem(GameData *data, HistoryItem *item) {
+		::gameItems[data].remove(item);
+	}
+
+	const GameItems &gameItems() {
+		return ::gameItems;
+	}
+
 	void regSharedContactItem(int32 userId, HistoryItem *item) {
 		auto user = App::userLoaded(userId);
 		auto canShareThisContact = user ? user->canShareThisContact() : false;
-		::sharedContactItems[userId].insert(item, NullType());
+		::sharedContactItems[userId].insert(item);
 		if (canShareThisContact != (user ? user->canShareThisContact() : false)) {
 			Notify::peerUpdatedDelayed(user, Notify::PeerUpdate::Flag::UserCanShareContact);
 		}
@@ -2549,11 +2626,12 @@ namespace {
 	}
 
 	QString phoneFromSharedContact(int32 userId) {
-		SharedContactItems::const_iterator i = ::sharedContactItems.constFind(userId);
+		auto i = ::sharedContactItems.constFind(userId);
 		if (i != ::sharedContactItems.cend() && !i->isEmpty()) {
-			HistoryMedia *media = i->cbegin().key()->getMedia();
-			if (media && media->type() == MediaTypeContact) {
-				return static_cast<HistoryContact*>(media)->phone();
+			if (auto media = (*i->cbegin())->getMedia()) {
+				if (media->type() == MediaTypeContact) {
+					return static_cast<HistoryContact*>(media)->phone();
+				}
 			}
 		}
 		return QString();
diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h
index 299caaf90..1f4951232 100644
--- a/Telegram/SourceFiles/app.h
+++ b/Telegram/SourceFiles/app.h
@@ -31,15 +31,16 @@ class FileUploader;
 #include "history.h"
 #include "layout.h"
 
-typedef QMap<HistoryItem*, NullType> HistoryItemsMap;
-typedef QHash<PhotoData*, HistoryItemsMap> PhotoItems;
-typedef QHash<DocumentData*, HistoryItemsMap> DocumentItems;
-typedef QHash<WebPageData*, HistoryItemsMap> WebPageItems;
-typedef QHash<int32, HistoryItemsMap> SharedContactItems;
-typedef QHash<Media::Clip::Reader*, HistoryItem*> GifItems;
+using HistoryItemsMap = OrderedSet<HistoryItem*>;
+using PhotoItems = QHash<PhotoData*, HistoryItemsMap>;
+using DocumentItems = QHash<DocumentData*, HistoryItemsMap>;
+using WebPageItems = QHash<WebPageData*, HistoryItemsMap>;
+using GameItems = QHash<GameData*, HistoryItemsMap>;
+using SharedContactItems = QHash<int32, HistoryItemsMap>;
+using GifItems = QHash<Media::Clip::Reader*, HistoryItem*>;
 
-typedef QHash<PhotoId, PhotoData*> PhotosData;
-typedef QHash<DocumentId, DocumentData*> DocumentsData;
+using PhotosData = QHash<PhotoId, PhotoData*>;
+using DocumentsData = QHash<DocumentId, DocumentData*>;
 
 namespace App {
 	AppClass *app();
@@ -90,14 +91,15 @@ namespace App {
 	StorageImageLocation imageLocation(const MTPPhotoSize &size);
 
 	PhotoData *feedPhoto(const MTPPhoto &photo, const PreparedPhotoThumbs &thumbs);
-	PhotoData *feedPhoto(const MTPPhoto &photo, PhotoData *convert = 0);
-	PhotoData *feedPhoto(const MTPDphoto &photo, PhotoData *convert = 0);
+	PhotoData *feedPhoto(const MTPPhoto &photo, PhotoData *convert = nullptr);
+	PhotoData *feedPhoto(const MTPDphoto &photo, PhotoData *convert = nullptr);
 	DocumentData *feedDocument(const MTPdocument &document, const QPixmap &thumb);
-	DocumentData *feedDocument(const MTPdocument &document, DocumentData *convert = 0);
-	DocumentData *feedDocument(const MTPDdocument &document, DocumentData *convert = 0);
-	WebPageData *feedWebPage(const MTPDwebPage &webpage, WebPageData *convert = 0);
-	WebPageData *feedWebPage(const MTPDwebPagePending &webpage, WebPageData *convert = 0);
+	DocumentData *feedDocument(const MTPdocument &document, DocumentData *convert = nullptr);
+	DocumentData *feedDocument(const MTPDdocument &document, DocumentData *convert = nullptr);
+	WebPageData *feedWebPage(const MTPDwebPage &webpage, WebPageData *convert = nullptr);
+	WebPageData *feedWebPage(const MTPDwebPagePending &webpage, WebPageData *convert = nullptr);
 	WebPageData *feedWebPage(const MTPWebPage &webpage);
+	GameData *feedGame(const MTPDgame &game, GameData *convert = nullptr);
 
 	PeerData *peer(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded);
 	inline UserData *user(const PeerId &id, PeerData::LoadedStatus restriction = PeerData::NotLoaded) {
@@ -148,7 +150,9 @@ namespace App {
 	DocumentData *document(const DocumentId &document);
 	DocumentData *documentSet(const DocumentId &document, DocumentData *convert, const uint64 &access, int32 version, int32 date, const QVector<MTPDocumentAttribute> &attributes, const QString &mime, const ImagePtr &thumb, int32 dc, int32 size, const StorageImageLocation &thumbLocation);
 	WebPageData *webPage(const WebPageId &webPage);
-	WebPageData *webPageSet(const WebPageId &webPage, WebPageData *convert, const QString &, const QString &url, const QString &displayUrl, const QString &siteName, const QString &title, const QString &description, PhotoData *photo, DocumentData *doc, int32 duration, const QString &author, int32 pendingTill);
+	WebPageData *webPageSet(const WebPageId &webPage, WebPageData *convert, const QString &type, const QString &url, const QString &displayUrl, const QString &siteName, const QString &title, const QString &description, PhotoData *photo, DocumentData *doc, int32 duration, const QString &author, int32 pendingTill);
+	GameData *game(const GameId &game);
+	GameData *gameSet(const GameId &game, GameData *convert, const uint64 &accessHash, const QString &shortName, const QString &title, const QString &description, const QString &url, PhotoData *photo, DocumentData *doc);
 	LocationData *location(const LocationCoords &coords);
 	void forgetMedia();
 
@@ -247,6 +251,10 @@ namespace App {
 	void unregWebPageItem(WebPageData *data, HistoryItem *item);
 	const WebPageItems &webPageItems();
 
+	void regGameItem(GameData *data, HistoryItem *item);
+	void unregGameItem(GameData *data, HistoryItem *item);
+	const GameItems &gameItems();
+
 	void regSharedContactItem(int32 userId, HistoryItem *item);
 	void unregSharedContactItem(int32 userId, HistoryItem *item);
 	const SharedContactItems &sharedContactItems();
diff --git a/Telegram/SourceFiles/application.cpp b/Telegram/SourceFiles/application.cpp
index 247aef93a..8a44c4c45 100644
--- a/Telegram/SourceFiles/application.cpp
+++ b/Telegram/SourceFiles/application.cpp
@@ -33,8 +33,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
 #include "autoupdater.h"
 #include "core/observer.h"
 #include "observer_peer.h"
-#include "core/observer.h"
 #include "window/chat_background.h"
+#include "history/history_location_manager.h"
 
 namespace {
 	void mtpStateChanged(int32 dc, int32 state) {
@@ -744,7 +744,7 @@ AppClass::AppClass() : QObject()
 
 	Shortcuts::start();
 
-	initImageLinkManager();
+	initLocationManager();
 	App::initMedia();
 
 	Local::ReadMapState state = Local::readMap(QByteArray());
@@ -1095,7 +1095,7 @@ AppClass::~AppClass() {
 
 	stopWebLoadManager();
 	App::deinitMedia();
-	deinitImageLinkManager();
+	deinitLocationManager();
 
 	MTP::finish();
 
diff --git a/Telegram/SourceFiles/boxes/connectionbox.cpp b/Telegram/SourceFiles/boxes/connectionbox.cpp
index 8075d8b57..755221c49 100644
--- a/Telegram/SourceFiles/boxes/connectionbox.cpp
+++ b/Telegram/SourceFiles/boxes/connectionbox.cpp
@@ -26,6 +26,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
 #include "connectionbox.h"
 #include "mainwidget.h"
 #include "mainwindow.h"
+#include "history/history_location_manager.h"
 
 ConnectionBox::ConnectionBox() : AbstractBox(st::boxWidth)
 , _hostInput(this, st::connectionHostInputField, lang(lng_connection_host_ph), Global::ConnectionProxy().host)
@@ -207,7 +208,7 @@ void ConnectionBox::onSave() {
 		Global::RefConnectionTypeChanged().notify();
 
 		MTP::restart();
-		reinitImageLinkManager();
+		reinitLocationManager();
 		reinitWebLoadManager();
 		onClose();
 	}
diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp
index 59281428e..2259c1e09 100644
--- a/Telegram/SourceFiles/history.cpp
+++ b/Telegram/SourceFiles/history.cpp
@@ -25,6 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
 #include "dialogs/dialogs_indexed_list.h"
 #include "styles/style_dialogs.h"
 #include "history/history_service_layout.h"
+#include "history/history_location_manager.h"
 #include "data/data_drafts.h"
 #include "media/media_clip_reader.h"
 #include "lang.h"
@@ -786,6 +787,12 @@ HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction,
 			default: badMedia = 1; break;
 			}
 			break;
+		case mtpc_messageMediaGame:
+		switch (m.vmedia.c_messageMediaGame().vgame.type()) {
+			case mtpc_game: break;
+			default: badMedia = 1; break;
+			}
+			break;
 		case mtpc_messageMediaUnsupported:
 		default: badMedia = 1; break;
 		}
@@ -2590,18 +2597,7 @@ void HistoryMessageReplyMarkup::createFromButtonRows(const QVector<MTPKeyboardBu
 					} break;
 					case mtpc_keyboardButtonGame: {
 						auto &buttonData = button.c_keyboardButtonGame();
-						auto title = qs(buttonData.vgame_title);
-						auto start = qs(buttonData.vstart_param);
-						auto charIsGoodForStartParam = [](QChar ch) {
-							return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') || (ch == '_') || (ch == '-');
-						};
-						for (auto &ch : start) {
-							if (!charIsGoodForStartParam(ch)) {
-								ch = '_';
-							}
-						}
-						auto strData = QString::number(buttonData.vgame_id.v) + ',' + start + ',' + title;
-						buttonRow.push_back({ Button::Type::Game, qs(buttonData.vtext), strData.toUtf8(), 0 });
+						buttonRow.push_back({ Button::Type::Game, qs(buttonData.vtext), QByteArray(), 0 });
 					} break;
 					}
 				}
@@ -2889,7 +2885,7 @@ bool HistoryItem::canEdit(const QDateTime &cur) const {
 	if (auto msg = toHistoryMessage()) {
 		if (msg->Has<HistoryMessageVia>() || msg->Has<HistoryMessageForwarded>()) return false;
 
-		if (HistoryMedia *media = msg->getMedia()) {
+		if (auto media = msg->getMedia()) {
 			auto type = media->type();
 			if (type != MediaTypePhoto &&
 				type != MediaTypeVideo &&
@@ -3428,6 +3424,7 @@ int HistoryPhoto::resizeGetHeight(int width) {
 
 void HistoryPhoto::draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const {
 	if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return;
+	p.fillRect(QRect(0, 0, _width, _height), QColor(128, 255, 128));
 
 	_data->automaticLoad(_parent);
 	bool selected = (selection == FullSelection);
@@ -3579,11 +3576,11 @@ HistoryTextState HistoryPhoto::getState(int x, int y, HistoryStateRequest reques
 
 void HistoryPhoto::updateSentMedia(const MTPMessageMedia &media) {
 	if (media.type() == mtpc_messageMediaPhoto) {
-		const auto &photo(media.c_messageMediaPhoto().vphoto);
+		auto &photo = media.c_messageMediaPhoto().vphoto;
 		App::feedPhoto(photo, _data);
 
 		if (photo.type() == mtpc_photo) {
-			const auto &sizes(photo.c_photo().vsizes.c_vector().v);
+			auto &sizes = photo.c_photo().vsizes.c_vector().v;
 			int32 max = 0;
 			const MTPDfileLocation *maxLocation = 0;
 			for (int32 i = 0, l = sizes.size(); i < l; ++i) {
@@ -5428,24 +5425,16 @@ namespace {
 	}
 
 	int32 _lineHeight = 0;
-}
+} // namespace
 
 HistoryWebPage::HistoryWebPage(HistoryItem *parent, WebPageData *data) : HistoryMedia(parent)
 , _data(data)
-, _openl(0)
-, _attach(nullptr)
-, _asArticle(false)
 , _title(st::msgMinWidth - st::webPageLeft)
-, _description(st::msgMinWidth - st::webPageLeft)
-, _siteNameWidth(0)
-, _durationWidth(0)
-, _pixw(0)
-, _pixh(0) {
+, _description(st::msgMinWidth - st::webPageLeft) {
 }
 
 HistoryWebPage::HistoryWebPage(HistoryItem *parent, const HistoryWebPage &other) : HistoryMedia(parent)
 , _data(other._data)
-, _openl(0)
 , _attach(other._attach ? other._attach->clone(parent) : nullptr)
 , _asArticle(other._asArticle)
 , _title(other._title)
@@ -5489,16 +5478,16 @@ void HistoryWebPage::initDimensions() {
 	if (!_asArticle && !_attach) {
 		if (_data->document) {
 			if (_data->document->sticker()) {
-				_attach = new HistorySticker(_parent, _data->document);
+				_attach = std_::make_unique<HistorySticker>(_parent, _data->document);
 			} else if (_data->document->isAnimation()) {
-				_attach = new HistoryGif(_parent, _data->document, QString());
+				_attach = std_::make_unique<HistoryGif>(_parent, _data->document, QString());
 			} else if (_data->document->isVideo()) {
-				_attach = new HistoryVideo(_parent, _data->document, QString());
+				_attach = std_::make_unique<HistoryVideo>(_parent, _data->document, QString());
 			} else {
-				_attach = new HistoryDocument(_parent, _data->document, QString());
+				_attach = std_::make_unique<HistoryDocument>(_parent, _data->document, QString());
 			}
 		} else if (_data->photo) {
-			_attach = new HistoryPhoto(_parent, _data->photo, QString());
+			_attach = std_::make_unique<HistoryPhoto>(_parent, _data->photo, QString());
 		}
 	}
 
@@ -5911,218 +5900,280 @@ ImagePtr HistoryWebPage::replyPreview() {
 	return _attach ? _attach->replyPreview() : (_data->photo ? _data->photo->makeReplyPreview() : ImagePtr());
 }
 
-HistoryWebPage::~HistoryWebPage() {
-	deleteAndMark(_attach);
+HistoryGame::HistoryGame(HistoryItem *parent, GameData *data) : HistoryMedia(parent)
+, _data(data)
+, _title(st::msgMinWidth - st::webPageLeft)
+, _description(st::msgMinWidth - st::webPageLeft) {
 }
 
-namespace {
-	LocationManager *locationManager = nullptr;
+HistoryGame::HistoryGame(HistoryItem *parent, const HistoryGame &other) : HistoryMedia(parent)
+, _data(other._data)
+, _attach(other._attach ? other._attach->clone(parent) : nullptr)
+, _title(other._title)
+, _description(other._description) {
 }
 
-void LocationManager::init() {
-	if (manager) delete manager;
-	manager = new QNetworkAccessManager();
-	App::setProxySettings(*manager);
+void HistoryGame::initDimensions() {
+	if (!_lineHeight) _lineHeight = qMax(st::webPageTitleFont->height, st::webPageDescriptionFont->height);
 
-	connect(manager, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)), this, SLOT(onFailed(QNetworkReply*)));
-#ifndef OS_MAC_OLD
-	connect(manager, SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError>&)), this, SLOT(onFailed(QNetworkReply*)));
-#endif // OS_MAC_OLD
-	connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(onFinished(QNetworkReply*)));
+	if (!_openl && !_data->url.isEmpty()) _openl.reset(new UrlClickHandler(_data->url, true));
 
-	if (black) {
-		delete black->v();
-		delete black;
-	}
-	QImage b(cIntRetinaFactor(), cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
-	{
-		QPainter p(&b);
-		p.fillRect(QRect(0, 0, cIntRetinaFactor(), cIntRetinaFactor()), st::white->b);
-	}
-	QPixmap p = App::pixmapFromImageInPlace(std_::move(b));
-	p.setDevicePixelRatio(cRetinaFactor());
-	black = new ImagePtr(p, "PNG");
-}
+	auto title = _data->title;
 
-void LocationManager::reinit() {
-	if (manager) App::setProxySettings(*manager);
-}
-
-void LocationManager::deinit() {
-	if (manager) {
-		delete manager;
-		manager = nullptr;
-	}
-	if (black) {
-		delete black->v();
-		delete black;
-		black = nullptr;
-	}
-	dataLoadings.clear();
-	imageLoadings.clear();
-}
-
-void initImageLinkManager() {
-	if (!locationManager) {
-		locationManager = new LocationManager();
-		locationManager->init();
-	}
-}
-
-void reinitImageLinkManager() {
-	if (locationManager) {
-		locationManager->reinit();
-	}
-}
-
-void deinitImageLinkManager() {
-	if (locationManager) {
-		locationManager->deinit();
-		delete locationManager;
-		locationManager = nullptr;
-	}
-}
-
-void LocationManager::getData(LocationData *data) {
-	if (!manager) {
-		DEBUG_LOG(("App Error: getting image link data without manager init!"));
-		return failed(data);
-	}
-
-	int32 w = st::locationSize.width(), h = st::locationSize.height();
-	int32 zoom = 13, scale = 1;
-	if (cScale() == dbisTwo || cRetina()) {
-		scale = 2;
-	} else {
-		w = convertScale(w);
-		h = convertScale(h);
-	}
-	QString coords = qsl("%1,%2").arg(data->coords.lat).arg(data->coords.lon);
-	QString url = qsl("https://maps.googleapis.com/maps/api/staticmap?center=") + coords + qsl("&zoom=%1&size=%2x%3&maptype=roadmap&scale=%4&markers=color:red|size:big|").arg(zoom).arg(w).arg(h).arg(scale) + coords + qsl("&sensor=false");
-	QNetworkReply *reply = manager->get(QNetworkRequest(QUrl(url)));
-	imageLoadings[reply] = data;
-}
-
-void LocationManager::onFinished(QNetworkReply *reply) {
-	if (!manager) return;
-	if (reply->error() != QNetworkReply::NoError) return onFailed(reply);
-
-	QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
-	if (statusCode.isValid()) {
-		int status = statusCode.toInt();
-		if (status == 301 || status == 302) {
-			QString loc = reply->header(QNetworkRequest::LocationHeader).toString();
-			if (!loc.isEmpty()) {
-				QMap<QNetworkReply*, LocationData*>::iterator i = dataLoadings.find(reply);
-				if (i != dataLoadings.cend()) {
-					LocationData *d = i.value();
-					if (serverRedirects.constFind(d) == serverRedirects.cend()) {
-						serverRedirects.insert(d, 1);
-					} else if (++serverRedirects[d] > MaxHttpRedirects) {
-						DEBUG_LOG(("Network Error: Too many HTTP redirects in onFinished() for image link: %1").arg(loc));
-						return onFailed(reply);
-					}
-					dataLoadings.erase(i);
-					dataLoadings.insert(manager->get(QNetworkRequest(loc)), d);
-					return;
-				} else if ((i = imageLoadings.find(reply)) != imageLoadings.cend()) {
-					LocationData *d = i.value();
-					if (serverRedirects.constFind(d) == serverRedirects.cend()) {
-						serverRedirects.insert(d, 1);
-					} else if (++serverRedirects[d] > MaxHttpRedirects) {
-						DEBUG_LOG(("Network Error: Too many HTTP redirects in onFinished() for image link: %1").arg(loc));
-						return onFailed(reply);
-					}
-					imageLoadings.erase(i);
-					imageLoadings.insert(manager->get(QNetworkRequest(loc)), d);
-					return;
-				}
+	// init attach
+	if (!_attach) {
+		if (_data->document) {
+			if (_data->document->sticker()) {
+				_attach = std_::make_unique<HistorySticker>(_parent, _data->document);
+			} else if (_data->document->isAnimation()) {
+				_attach = std_::make_unique<HistoryGif>(_parent, _data->document, QString());
+			} else if (_data->document->isVideo()) {
+				_attach = std_::make_unique<HistoryVideo>(_parent, _data->document, QString());
+			} else {
+				_attach = std_::make_unique<HistoryDocument>(_parent, _data->document, QString());
 			}
-		}
-		if (status != 200) {
-			DEBUG_LOG(("Network Error: Bad HTTP status received in onFinished() for image link: %1").arg(status));
-			return onFailed(reply);
+		} else if (_data->photo) {
+			_attach = std_::make_unique<HistoryPhoto>(_parent, _data->photo, QString());
 		}
 	}
 
-	LocationData *d = 0;
-	QMap<QNetworkReply*, LocationData*>::iterator i = dataLoadings.find(reply);
-	if (i != dataLoadings.cend()) {
-		d = i.value();
-		dataLoadings.erase(i);
-
-		QJsonParseError e;
-		QJsonDocument doc = QJsonDocument::fromJson(reply->readAll(), &e);
-		if (e.error != QJsonParseError::NoError) {
-			DEBUG_LOG(("JSON Error: Bad json received in onFinished() for image link"));
-			return onFailed(reply);
+	// init strings
+	if (_description.isEmpty() && !_data->description.isEmpty()) {
+		auto text = textClean(_data->description);
+		if (text.isEmpty()) {
+			_data->description = QString();
+		} else {
+			_description.setText(st::webPageDescriptionFont, text, _webpageDescriptionOptions);
 		}
-		failed(d);
+	}
+	if (_title.isEmpty() && !title.isEmpty()) {
+		title = textOneLine(textClean(title));
+		if (title.isEmpty()) {
+			_data->title = QString();
+		} else {
+			_title.setText(st::webPageTitleFont, title, _webpageTitleOptions);
+		}
+	}
 
-		if (App::main()) App::main()->update();
+	// init dimensions
+	int32 l = st::msgPadding.left() + st::webPageLeft, r = st::msgPadding.right();
+	int32 skipBlockWidth = _parent->skipBlockWidth();
+	_maxw = skipBlockWidth;
+	_minh = st::msgPadding.top();
+
+	int32 titleMinHeight = _title.isEmpty() ? 0 : _lineHeight;
+	int32 descMaxLines = (4 + (titleMinHeight ? 0 : 1));
+	int32 descriptionMinHeight = _description.isEmpty() ? 0 : qMin(_description.minHeight(), descMaxLines * _lineHeight);
+
+	if (!_title.isEmpty()) {
+		_maxw = qMax(_maxw, int32(_title.maxWidth()));
+		_minh += titleMinHeight;
+	}
+	if (!_description.isEmpty()) {
+		_maxw = qMax(_maxw, int32(_description.maxWidth()));
+		_minh += descriptionMinHeight;
+	}
+	if (_attach) {
+		if (_minh) _minh += st::webPagePhotoSkip;
+		_attach->initDimensions();
+		QMargins bubble(_attach->bubbleMargins());
+		_maxw = qMax(_maxw, int32(_attach->maxWidth() - bubble.left() - bubble.top()));
+		_minh += _attach->minHeight() - bubble.top() - bubble.bottom();
+	}
+	_maxw += st::msgPadding.left() + st::webPageLeft + st::msgPadding.right();
+}
+
+int HistoryGame::resizeGetHeight(int width) {
+	_width = qMin(width, _maxw);
+	width -= st::msgPadding.left() + st::webPageLeft + st::msgPadding.right();
+
+	int32 linesMax = 5;
+	_height = st::msgPadding.top();
+	if (_title.isEmpty()) {
+		_titleLines = 0;
 	} else {
-		i = imageLoadings.find(reply);
-		if (i != imageLoadings.cend()) {
-			d = i.value();
-			imageLoadings.erase(i);
-
-			QPixmap thumb;
-			QByteArray format;
-			QByteArray data(reply->readAll());
-			{
-				QBuffer buffer(&data);
-				QImageReader reader(&buffer);
-#ifndef OS_MAC_OLD
-				reader.setAutoTransform(true);
-#endif // OS_MAC_OLD
-				thumb = QPixmap::fromImageReader(&reader, Qt::ColorOnly);
-				format = reader.format();
-				thumb.setDevicePixelRatio(cRetinaFactor());
-				if (format.isEmpty()) format = QByteArray("JPG");
-			}
-			d->loading = false;
-			d->thumb = thumb.isNull() ? (*black) : ImagePtr(thumb, format);
-			serverRedirects.remove(d);
-			if (App::main()) App::main()->update();
+		if (_title.countHeight(width) < 2 * st::webPageTitleFont->height) {
+			_titleLines = 1;
+		} else {
+			_titleLines = 2;
 		}
+		_height += _titleLines * _lineHeight;
 	}
-}
 
-void LocationManager::onFailed(QNetworkReply *reply) {
-	if (!manager) return;
-
-	LocationData *d = 0;
-	QMap<QNetworkReply*, LocationData*>::iterator i = dataLoadings.find(reply);
-	if (i != dataLoadings.cend()) {
-		d = i.value();
-		dataLoadings.erase(i);
+	if (_description.isEmpty()) {
+		_descriptionLines = 0;
 	} else {
-		i = imageLoadings.find(reply);
-		if (i != imageLoadings.cend()) {
-			d = i.value();
-			imageLoadings.erase(i);
+		int32 descriptionHeight = _description.countHeight(width);
+		if (descriptionHeight < (linesMax - _titleLines) * st::webPageDescriptionFont->height) {
+			_descriptionLines = (descriptionHeight / st::webPageDescriptionFont->height);
+		} else {
+			_descriptionLines = (linesMax - _titleLines);
+		}
+		_height += _descriptionLines * _lineHeight;
+	}
+
+	if (_attach) {
+		if (_height) _height += st::webPagePhotoSkip;
+
+		QMargins bubble(_attach->bubbleMargins());
+
+		_attach->resizeGetHeight(width + bubble.left() + bubble.right());
+		_height += _attach->height() - bubble.top() - bubble.bottom();
+	}
+
+	return _height;
+}
+
+void HistoryGame::draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const {
+	if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return;
+	int32 width = _width, height = _height;
+
+	bool out = _parent->out(), isPost = _parent->isPost(), outbg = out && !isPost;
+	bool selected = (selection == FullSelection);
+
+	style::color barfg = (selected ? (outbg ? st::msgOutReplyBarSelColor : st::msgInReplyBarSelColor) : (outbg ? st::msgOutReplyBarColor : st::msgInReplyBarColor));
+	style::color semibold = (selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg));
+	style::color regular = (selected ? (outbg ? st::msgOutDateFgSelected : st::msgInDateFgSelected) : (outbg ? st::msgOutDateFg : st::msgInDateFg));
+
+	int32 lshift = st::msgPadding.left() + st::webPageLeft, rshift = st::msgPadding.right(), bshift = 0;
+	width -= lshift + rshift;
+	QMargins bubble(_attach ? _attach->bubbleMargins() : QMargins());
+
+	QRect bar(rtlrect(st::msgPadding.left(), st::msgPadding.top(), st::webPageBar, _height - bshift, _width));
+	p.fillRect(bar, barfg);
+
+	int32 tshift = st::msgPadding.top();
+	if (_titleLines) {
+		p.setPen(st::black);
+		int32 endskip = 0;
+		if (_title.hasSkipBlock()) {
+			endskip = _parent->skipBlockWidth();
+		}
+		_title.drawLeftElided(p, lshift, tshift, width, _width, _titleLines, style::al_left, 0, -1, endskip, false, selection);
+		tshift += _titleLines * _lineHeight;
+	}
+	if (_descriptionLines) {
+		p.setPen(st::black);
+		int32 endskip = 0;
+		if (_description.hasSkipBlock()) {
+			endskip = _parent->skipBlockWidth();
+		}
+		_description.drawLeftElided(p, lshift, tshift, width, _width, _descriptionLines, style::al_left, 0, -1, endskip, false, toDescriptionSelection(selection));
+		tshift += _descriptionLines * _lineHeight;
+	}
+	if (_attach) {
+		if (tshift) tshift += st::webPagePhotoSkip;
+
+		int32 attachLeft = lshift - bubble.left(), attachTop = tshift - bubble.top();
+		if (rtl()) attachLeft = _width - attachLeft - _attach->currentWidth();
+
+		auto attachSelection = selected ? FullSelection : TextSelection { 0, 0 };
+
+		p.translate(attachLeft, attachTop);
+		_attach->draw(p, r.translated(-attachLeft, -attachTop), attachSelection, ms);
+		p.translate(-attachLeft, -attachTop);
+	}
+}
+
+HistoryTextState HistoryGame::getState(int x, int y, HistoryStateRequest request) const {
+	HistoryTextState result;
+
+	if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return result;
+	int32 width = _width, height = _height;
+
+	int32 lshift = st::msgPadding.left() + st::webPageLeft, rshift = st::msgPadding.right(), bshift = 0;
+	width -= lshift + rshift;
+	QMargins bubble(_attach ? _attach->bubbleMargins() : QMargins());
+
+	bool inThumb = false;
+	int tshift = st::msgPadding.top(), symbolAdd = 0;
+	if (_titleLines) {
+		if (y >= tshift && y < tshift + _titleLines * _lineHeight) {
+			Text::StateRequestElided titleRequest = request.forText();
+			titleRequest.lines = _titleLines;
+			result = _title.getStateElidedLeft(x - lshift, y - tshift, width, _width, titleRequest);
+		} else if (y >= tshift + _titleLines * _lineHeight) {
+			symbolAdd += _title.length();
+		}
+		tshift += _titleLines * _lineHeight;
+	}
+	if (_descriptionLines) {
+		if (y >= tshift && y < tshift + _descriptionLines * _lineHeight) {
+			Text::StateRequestElided descriptionRequest = request.forText();
+			descriptionRequest.lines = _descriptionLines;
+			result = _description.getStateElidedLeft(x - lshift, y - tshift, width, _width, descriptionRequest);
+		} else if (y >= tshift + _descriptionLines * _lineHeight) {
+			symbolAdd += _description.length();
+		}
+		tshift += _descriptionLines * _lineHeight;
+	}
+	if (inThumb) {
+		result.link = _openl;
+	} else if (_attach) {
+		if (tshift) tshift += st::webPagePhotoSkip;
+
+		if (x >= lshift && x < lshift + width && y >= tshift && y < _height) {
+			result.link = _openl;
 		}
 	}
-	DEBUG_LOG(("Network Error: failed to get data for image link %1,%2 error %3").arg(d ? d->coords.lat : 0).arg(d ? d->coords.lon : 0).arg(reply->errorString()));
-	if (d) {
-		failed(d);
+
+	result.symbol += symbolAdd;
+	return result;
+}
+
+TextSelection HistoryGame::adjustSelection(TextSelection selection, TextSelectType type) const {
+	if (!_descriptionLines || selection.to <= _title.length()) {
+		return _title.adjustSelection(selection, type);
+	}
+	auto descriptionSelection = _description.adjustSelection(toDescriptionSelection(selection), type);
+	if (selection.from >= _title.length()) {
+		return fromDescriptionSelection(descriptionSelection);
+	}
+	auto titleSelection = _title.adjustSelection(selection, type);
+	return { titleSelection.from, fromDescriptionSelection(descriptionSelection).to };
+}
+
+void HistoryGame::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
+	if (_attach) {
+		_attach->clickHandlerActiveChanged(p, active);
 	}
 }
 
-void LocationManager::failed(LocationData *data) {
-	data->loading = false;
-	data->thumb = *black;
-	serverRedirects.remove(data);
+void HistoryGame::clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) {
+	if (_attach) {
+		_attach->clickHandlerPressedChanged(p, pressed);
+	}
 }
 
-void LocationData::load() {
-	if (!thumb->isNull()) return thumb->load(false, false);
-	if (loading) return;
+void HistoryGame::attachToParent() {
+	App::regGameItem(_data, _parent);
+	if (_attach) _attach->attachToParent();
+}
 
-	loading = true;
-	if (locationManager) {
-		locationManager->getData(this);
+void HistoryGame::detachFromParent() {
+	App::unregGameItem(_data, _parent);
+	if (_attach) _attach->detachFromParent();
+}
+
+TextWithEntities HistoryGame::selectedText(TextSelection selection) const {
+	if (selection == FullSelection) {
+		return TextWithEntities();
 	}
+	auto titleResult = _title.originalTextWithEntities(selection, ExpandLinksAll);
+	auto descriptionResult = _description.originalTextWithEntities(toDescriptionSelection(selection), ExpandLinksAll);
+	if (titleResult.text.isEmpty()) {
+		return descriptionResult;
+	} else if (descriptionResult.text.isEmpty()) {
+		return titleResult;
+	}
+
+	titleResult.text += '\n';
+	appendTextWithEntities(titleResult, std_::move(descriptionResult));
+	return titleResult;
+}
+
+ImagePtr HistoryGame::replyPreview() {
+	return _attach ? _attach->replyPreview() : (_data->photo ? _data->photo->makeReplyPreview() : ImagePtr());
 }
 
 HistoryLocation::HistoryLocation(HistoryItem *parent, const LocationCoords &coords, const QString &title, const QString &description) : HistoryMedia(parent)
@@ -6907,35 +6958,35 @@ void HistoryMessage::initTime() {
 void HistoryMessage::initMedia(const MTPMessageMedia *media, QString &currentText) {
 	switch (media ? media->type() : mtpc_messageMediaEmpty) {
 	case mtpc_messageMediaContact: {
-		const auto &d(media->c_messageMediaContact());
+		auto &d = media->c_messageMediaContact();
 		_media.reset(new HistoryContact(this, d.vuser_id.v, qs(d.vfirst_name), qs(d.vlast_name), qs(d.vphone_number)));
 	} break;
 	case mtpc_messageMediaGeo: {
-		const auto &point(media->c_messageMediaGeo().vgeo);
+		auto &point = media->c_messageMediaGeo().vgeo;
 		if (point.type() == mtpc_geoPoint) {
 			_media.reset(new HistoryLocation(this, LocationCoords(point.c_geoPoint())));
 		}
 	} break;
 	case mtpc_messageMediaVenue: {
-		const auto &d(media->c_messageMediaVenue());
+		auto &d = media->c_messageMediaVenue();
 		if (d.vgeo.type() == mtpc_geoPoint) {
 			_media.reset(new HistoryLocation(this, LocationCoords(d.vgeo.c_geoPoint()), qs(d.vtitle), qs(d.vaddress)));
 		}
 	} break;
 	case mtpc_messageMediaPhoto: {
-		const auto &photo(media->c_messageMediaPhoto());
+		auto &photo = media->c_messageMediaPhoto();
 		if (photo.vphoto.type() == mtpc_photo) {
 			_media.reset(new HistoryPhoto(this, App::feedPhoto(photo.vphoto.c_photo()), qs(photo.vcaption)));
 		}
 	} break;
 	case mtpc_messageMediaDocument: {
-		const auto &document(media->c_messageMediaDocument().vdocument);
+		auto &document = media->c_messageMediaDocument().vdocument;
 		if (document.type() == mtpc_document) {
 			return initMediaFromDocument(App::feedDocument(document), qs(media->c_messageMediaDocument().vcaption));
 		}
 	} break;
 	case mtpc_messageMediaWebPage: {
-		const auto &d(media->c_messageMediaWebPage().vwebpage);
+		auto &d = media->c_messageMediaWebPage().vwebpage;
 		switch (d.type()) {
 		case mtpc_webPageEmpty: break;
 		case mtpc_webPagePending: {
@@ -6946,6 +6997,12 @@ void HistoryMessage::initMedia(const MTPMessageMedia *media, QString &currentTex
 		} break;
 		}
 	} break;
+	case mtpc_messageMediaGame: {
+		auto &d = media->c_messageMediaGame().vgame;
+		if (d.type() == mtpc_game) {
+			_media.reset(new HistoryGame(this, App::feedGame(d.c_game())));
+		}
+	} break;
 	};
 }
 
@@ -6979,7 +7036,7 @@ void HistoryMessage::initDimensions() {
 
 		if (_media) {
 			_media->initDimensions();
-			if (_media->isDisplayed()) {
+			if (_media->isDisplayed() && !_media->isAboveMessage()) {
 				if (_text.hasSkipBlock()) {
 					_text.removeSkipBlock();
 					_textWidth = -1;
@@ -6993,7 +7050,7 @@ void HistoryMessage::initDimensions() {
 		}
 
 		_maxw = plainMaxWidth();
-		if (_text.isEmpty()) {
+		if (emptyText()) {
 			_minh = 0;
 		} else {
 			_minh = st::msgPadding.top() + _text.minHeight() + st::msgPadding.bottom();
@@ -7031,7 +7088,7 @@ void HistoryMessage::initDimensions() {
 		_maxw = st::msgMinWidth;
 		_minh = 0;
 	}
-	if (reply && !_text.isEmpty()) {
+	if (reply && !emptyText()) {
 		int replyw = st::msgPadding.left() + reply->_maxReplyWidth - st::msgReplyPadding.left() - st::msgReplyPadding.right() + st::msgPadding.right();
 		if (reply->_replyToVia) {
 			replyw += st::msgServiceFont->spacew + reply->_replyToVia->_maxWidth;
@@ -7045,7 +7102,7 @@ void HistoryMessage::initDimensions() {
 
 		// if we have a text bubble we can resize it to fit the keyboard
 		// but if we have only media we don't do that
-		if (!_text.isEmpty()) {
+		if (!emptyText()) {
 			_maxw = qMax(_maxw, markup->inlineKeyboard->naturalWidth());
 		}
 	}
@@ -7132,6 +7189,9 @@ void HistoryMessage::applyEditionToEmpty() {
 }
 
 void HistoryMessage::updateMedia(const MTPMessageMedia *media) {
+	auto setMediaAllowed = [](HistoryMediaType type) {
+		return (type == MediaTypeWebPage || type == MediaTypeGame || type == MediaTypeLocation);
+	};
 	if (_flags & MTPDmessage_ClientFlag::f_from_inline_bot) {
 		bool needReSet = true;
 		if (media && _media) {
@@ -7141,7 +7201,7 @@ void HistoryMessage::updateMedia(const MTPMessageMedia *media) {
 			setMedia(media);
 		}
 		_flags &= ~MTPDmessage_ClientFlag::f_from_inline_bot;
-	} else if (media && _media && _media->type() != MediaTypeWebPage) {
+	} else if (media && _media && !setMediaAllowed(_media->type())) {
 		_media->updateSentMedia(*media);
 	} else {
 		setMedia(media);
@@ -7228,18 +7288,18 @@ TextWithEntities HistoryMessage::selectedText(TextSelection selection) const {
 void HistoryMessage::setMedia(const MTPMessageMedia *media) {
 	if (!_media && (!media || media->type() == mtpc_messageMediaEmpty)) return;
 
-	bool mediaWasDisplayed = false;
+	bool mediaRemovedSkipBlock = false;
 	if (_media) {
-		mediaWasDisplayed = _media->isDisplayed();
+		mediaRemovedSkipBlock = _media->isDisplayed() && !_media->isAboveMessage();
 		_media.clear();
 	}
 	QString t;
 	initMedia(media, t);
-	if (_media && _media->isDisplayed() && !mediaWasDisplayed) {
+	if (_media && _media->isDisplayed() && !_media->isAboveMessage() && !mediaRemovedSkipBlock) {
 		_text.removeSkipBlock();
 		_textWidth = -1;
 		_textHeight = 0;
-	} else if (mediaWasDisplayed && (!_media || !_media->isDisplayed())) {
+	} else if (mediaRemovedSkipBlock && (!_media || !_media->isDisplayed() || _media->isAboveMessage())) {
 		_text.setSkipBlock(skipBlockWidth(), skipBlockHeight());
 		_textWidth = -1;
 		_textHeight = 0;
@@ -7248,7 +7308,7 @@ void HistoryMessage::setMedia(const MTPMessageMedia *media) {
 
 void HistoryMessage::setText(const TextWithEntities &textWithEntities) {
 	textstyleSet(&((out() && !isPost()) ? st::outTextStyle : st::inTextStyle));
-	if (_media && _media->isDisplayed()) {
+	if (_media && _media->isDisplayed() && !_media->isAboveMessage()) {
 		_text.setMarkedText(st::msgFont, textWithEntities, itemTextOptions(this));
 	} else {
 		_text.setMarkedText(st::msgFont, { textWithEntities.text + skipBlock(), textWithEntities.entities }, itemTextOptions(this));
@@ -7492,7 +7552,7 @@ void HistoryMessage::draw(Painter &p, const QRect &r, TextSelection selection, u
 
 	textstyleSet(&(outbg ? st::outTextStyle : st::inTextStyle));
 
-	if (const ReplyKeyboard *keyboard = inlineReplyKeyboard()) {
+	if (auto keyboard = inlineReplyKeyboard()) {
 		int h = st::msgBotKbButton.margin + keyboard->naturalHeight();
 		height -= h;
 		int top = height + st::msgBotKbButton.margin - marginBottom();
@@ -7502,8 +7562,6 @@ void HistoryMessage::draw(Painter &p, const QRect &r, TextSelection selection, u
 	}
 
 	if (bubble) {
-		auto fwd = Get<HistoryMessageForwarded>();
-		auto via = Get<HistoryMessageVia>();
 		if (displayFromName() && author()->nameVersion > _authorNameVersion) {
 			fromNameUpdated(width);
 		}
@@ -7516,40 +7574,35 @@ void HistoryMessage::draw(Painter &p, const QRect &r, TextSelection selection, u
 		RoundCorners cors(selected ? (outbg ? MessageOutSelectedCorners : MessageInSelectedCorners) : (outbg ? MessageOutCorners : MessageInCorners));
 		App::roundRect(p, r, bg, cors, &sh);
 
-		if (displayFromName()) {
-			p.setFont(st::msgNameFont);
-			if (isPost()) {
-				p.setPen(selected ? st::msgInServiceFgSelected : st::msgInServiceFg);
-			} else {
-				p.setPen(author()->color);
-			}
-			author()->nameText.drawElided(p, r.left() + st::msgPadding.left(), r.top() + st::msgPadding.top(), width - st::msgPadding.left() - st::msgPadding.right());
-			if (via && !fwd && width > st::msgPadding.left() + st::msgPadding.right() + author()->nameText.maxWidth() + st::msgServiceFont->spacew) {
-				p.setPen(selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg));
-				p.drawText(r.left() + st::msgPadding.left() + author()->nameText.maxWidth() + st::msgServiceFont->spacew, r.top() + st::msgPadding.top() + st::msgServiceFont->ascent, via->_text);
-			}
-			r.setTop(r.top() + st::msgNameFont->height);
-		}
-
 		QRect trect(r.marginsAdded(-st::msgPadding));
-
+		paintFromName(p, trect, selected);
 		paintForwardedInfo(p, trect, selected);
 		paintReplyInfo(p, trect, selected);
 		paintViaBotIdInfo(p, trect, selected);
 
-		p.setPen(st::msgColor);
-		p.setFont(st::msgFont);
-		_text.draw(p, trect.x(), trect.y(), trect.width(), style::al_left, 0, -1, selection);
-
+		auto needDrawInfo = true;
 		if (_media && _media->isDisplayed()) {
-			int32 top = height - marginBottom() - _media->height();
-			p.translate(left, top);
-			_media->draw(p, r.translated(-left, -top), toMediaSelection(selection), ms);
-			p.translate(-left, -top);
-			if (!_media->customInfoLayout()) {
-				HistoryMessage::drawInfo(p, r.x() + r.width(), r.y() + r.height(), 2 * r.x() + r.width(), selected, InfoDisplayDefault);
+			auto mediaAboveText = _media->isAboveMessage();
+			auto mediaHeight = _media->height();
+			auto mediaLeft = trect.x() - st::msgPadding.left();
+			auto mediaTop = mediaAboveText ? (trect.y() - st::msgPadding.top()) : (r.y() + r.height() - mediaHeight);
+			if (!mediaAboveText) {
+				paintText(p, trect, selection);
 			}
+			p.translate(mediaLeft, mediaTop);
+			_media->draw(p, r.translated(-mediaLeft, -mediaTop), toMediaSelection(selection), ms);
+			p.translate(-mediaLeft, -mediaTop);
+
+			if (mediaAboveText) {
+				trect.setY(trect.y() + mediaHeight);
+				paintText(p, trect, selection);
+			}
+
+			needDrawInfo = !_media->customInfoLayout();
 		} else {
+			paintText(p, trect, selection);
+		}
+		if (needDrawInfo) {
 			HistoryMessage::drawInfo(p, r.x() + r.width(), r.y() + r.height(), 2 * r.x() + r.width(), selected, InfoDisplayDefault);
 		}
 	} else if (_media) {
@@ -7567,6 +7620,27 @@ void HistoryMessage::draw(Painter &p, const QRect &r, TextSelection selection, u
 	}
 }
 
+void HistoryMessage::paintFromName(Painter &p, QRect &trect, bool selected) const {
+	if (displayFromName()) {
+		p.setFont(st::msgNameFont);
+		if (isPost()) {
+			p.setPen(selected ? st::msgInServiceFgSelected : st::msgInServiceFg);
+		} else {
+			p.setPen(author()->color);
+		}
+		author()->nameText.drawElided(p, trect.left(), trect.top(), trect.width());
+
+		auto fwd = Get<HistoryMessageForwarded>();
+		auto via = Get<HistoryMessageVia>();
+		if (via && !fwd && trect.width() > author()->nameText.maxWidth() + st::msgServiceFont->spacew) {
+			bool outbg = out() && !isPost();
+			p.setPen(selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg));
+			p.drawText(trect.left() + author()->nameText.maxWidth() + st::msgServiceFont->spacew, trect.top() + st::msgServiceFont->ascent, via->_text);
+		}
+		trect.setY(trect.y() + st::msgNameFont->height);
+	}
+}
+
 void HistoryMessage::paintForwardedInfo(Painter &p, QRect &trect, bool selected) const {
 	if (displayForwardedFrom()) {
 		style::font serviceFont(st::msgServiceFont), serviceName(st::msgServiceNameFont);
@@ -7609,6 +7683,12 @@ void HistoryMessage::paintViaBotIdInfo(Painter &p, QRect &trect, bool selected)
 	}
 }
 
+void HistoryMessage::paintText(Painter &p, QRect &trect, TextSelection selection) const {
+	p.setPen(st::msgColor);
+	p.setFont(st::msgFont);
+	_text.draw(p, trect.x(), trect.y(), trect.width(), style::al_left, 0, -1, selection);
+}
+
 void HistoryMessage::dependencyItemRemoved(HistoryItem *dependency) {
 	if (auto reply = Get<HistoryMessageReply>()) {
 		reply->itemRemoved(this, dependency);
@@ -7655,7 +7735,7 @@ int HistoryMessage::performResizeGetHeight(int width) {
 			_height = _minh;
 			if (media) _media->resizeGetHeight(_maxw);
 		} else {
-			if (_text.isEmpty()) {
+			if (emptyText()) {
 				_height = 0;
 			} else {
 				int32 textWidth = qMax(width - st::msgPadding.left() - st::msgPadding.right(), 1);
@@ -7670,24 +7750,27 @@ int HistoryMessage::performResizeGetHeight(int width) {
 			if (media) _height += _media->resizeGetHeight(width);
 		}
 
+		auto mediaTopPaddingAdded = !emptyText();
 		if (displayFromName()) {
-			if (emptyText()) {
-				_height += st::msgPadding.top() + st::msgNameFont->height + st::mediaHeaderSkip;
-			} else {
-				_height += st::msgNameFont->height;
-			}
 			int32 l = 0, w = 0;
 			countPositionAndSize(l, w);
 			fromNameUpdated(w);
+
+			if (!mediaTopPaddingAdded) {
+				_height += st::msgPadding.top() + st::mediaHeaderSkip;
+				mediaTopPaddingAdded = true;
+			}
+			_height += st::msgNameFont->height;
 		} else if (via && !fwd) {
 			int32 l = 0, w = 0;
 			countPositionAndSize(l, w);
 			via->resize(w - st::msgPadding.left() - st::msgPadding.right());
-			if (emptyText() && !displayFromName()) {
-				_height += st::msgPadding.top() + st::msgNameFont->height + st::mediaHeaderSkip;
-			} else {
-				_height += st::msgNameFont->height;
+
+			if (!mediaTopPaddingAdded) {
+				_height += st::msgPadding.top() + st::mediaHeaderSkip;
+				mediaTopPaddingAdded = true;
 			}
+			_height += st::msgNameFont->height;
 		}
 
 		if (displayForwardedFrom()) {
@@ -7695,23 +7778,23 @@ int HistoryMessage::performResizeGetHeight(int width) {
 			countPositionAndSize(l, w);
 			int32 fwdheight = ((fwd->_text.maxWidth() > (w - st::msgPadding.left() - st::msgPadding.right())) ? 2 : 1) * st::semiboldFont->height;
 
-			if (emptyText() && !displayFromName()) {
-				_height += st::msgPadding.top() + fwdheight + st::mediaHeaderSkip;
-			} else {
-				_height += fwdheight;
+			if (!mediaTopPaddingAdded) {
+				_height += st::msgPadding.top() + st::mediaHeaderSkip;
+				mediaTopPaddingAdded = true;
 			}
+			_height += fwdheight;
 		}
 
 		if (reply) {
 			int32 l = 0, w = 0;
 			countPositionAndSize(l, w);
-
-			if (emptyText() && !displayFromName() && !Has<HistoryMessageVia>()) {
-				_height += st::msgPadding.top() + st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom() + st::mediaHeaderSkip;
-			} else {
-				_height += st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom();
-			}
 			reply->resize(w - st::msgPadding.left() - st::msgPadding.right());
+
+			if (!mediaTopPaddingAdded) {
+				_height += st::msgPadding.top() + st::mediaHeaderSkip;
+				mediaTopPaddingAdded = true;
+			}
+			_height += st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom();
 		}
 	} else if (_media) {
 		_height = _media->resizeGetHeight(width);
@@ -8154,25 +8237,9 @@ bool HistoryService::prepareGameScoreText(const QString &from, QString *outText,
 	auto gamescore = Get<HistoryServiceGameScore>();
 	if (gamescore && gamescore->msg) {
 		auto getGameTitle = [item = gamescore->msg, &second]() -> QString {
-			if (auto markup = item->Get<HistoryMessageReplyMarkup>()) {
-				for (int i = 0, rowsCount = markup->rows.size(); i != rowsCount; ++i) {
-					auto &row = markup->rows[i];
-					for (int j = 0, buttonsCount = row.size(); j != buttonsCount; ++j) {
-						auto &button = row[j];
-						if (button.type == HistoryMessageReplyMarkup::Button::Type::Game) {
-							auto strData = QString::fromUtf8(button.data);
-							second = MakeShared<ReplyMarkupClickHandler>(item, i, j);
-							auto parts = strData.split(',');
-							t_assert(parts.size() > 2);
-							QString gameTitle;
-							gameTitle.reserve(strData.size() - 2);
-							gameTitle.append(parts[2]);
-							for (int i = 3, count = parts.size(); i != count; ++i) {
-								gameTitle.append(',').append(parts[i]);
-							}
-							return textcmdLink(2, gameTitle);
-						}
-					}
+			if (auto media = item->getMedia()) {
+				if (media->type() == MediaTypeGame) {
+					return static_cast<HistoryGame*>(media)->game()->title;
 				}
 			}
 			return lang(lng_deleted_message);
diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h
index ecba44ef3..91d1d263e 100644
--- a/Telegram/SourceFiles/history.h
+++ b/Telegram/SourceFiles/history.h
@@ -100,6 +100,7 @@ enum HistoryMediaType {
 	MediaTypeWebPage,
 	MediaTypeMusicFile,
 	MediaTypeVoiceFile,
+	MediaTypeGame,
 
 	MediaTypeCount
 };
@@ -1617,6 +1618,9 @@ public:
 	virtual bool isDisplayed() const {
 		return true;
 	}
+	virtual bool isAboveMessage() const {
+		return false;
+	}
 	virtual bool hasTextForCopy() const {
 		return false;
 	}
@@ -2408,11 +2412,9 @@ public:
 	}
 
 	HistoryMedia *attach() const {
-		return _attach;
+		return _attach.get();
 	}
 
-	~HistoryWebPage();
-
 private:
 	TextSelection toDescriptionSelection(TextSelection selection) const {
 		return internal::unshiftSelection(selection, _title);
@@ -2423,51 +2425,114 @@ private:
 
 	WebPageData *_data;
 	ClickHandlerPtr _openl;
-	HistoryMedia *_attach;
+	std_::unique_ptr<HistoryMedia> _attach;
 
-	bool _asArticle;
+	bool _asArticle = false;
 	int32 _titleLines, _descriptionLines;
 
 	Text _title, _description;
-	int32 _siteNameWidth;
+	int32 _siteNameWidth = 0;
 
 	QString _duration;
-	int32 _durationWidth;
+	int32 _durationWidth = 0;
 
-	int16 _pixw, _pixh;
+	int16 _pixw = 0;
+	int16 _pixh = 0;
 };
 
-void initImageLinkManager();
-void reinitImageLinkManager();
-void deinitImageLinkManager();
+class HistoryGame : public HistoryMedia {
+public:
+	HistoryGame(HistoryItem *parent, GameData *data);
+	HistoryGame(HistoryItem *parent, const HistoryGame &other);
+	HistoryMediaType type() const override {
+		return MediaTypeGame;
+	}
+	HistoryGame *clone(HistoryItem *newParent) const override {
+		return new HistoryGame(newParent, *this);
+	}
+
+	void initDimensions() override;
+	int resizeGetHeight(int width) override;
+
+	void draw(Painter &p, const QRect &r, TextSelection selection, uint64 ms) const override;
+	HistoryTextState getState(int x, int y, HistoryStateRequest request) const override;
+
+	TextSelection adjustSelection(TextSelection selection, TextSelectType type) const override;
+	bool isAboveMessage() const override {
+		return true;
+	}
+	bool hasTextForCopy() const override {
+		return false; // we do not add _title and _description in FullSelection text copy.
+	}
+
+	bool toggleSelectionByHandlerClick(const ClickHandlerPtr &p) const override {
+		return _attach && _attach->toggleSelectionByHandlerClick(p);
+	}
+	bool dragItemByHandler(const ClickHandlerPtr &p) const override {
+		return _attach && _attach->dragItemByHandler(p);
+	}
+
+	TextWithEntities selectedText(TextSelection selection) const override;
+
+	void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
+	void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override;
+
+	DocumentData *getDocument() override {
+		return _attach ? _attach->getDocument() : nullptr;
+	}
+	Media::Clip::Reader *getClipReader() override {
+		return _attach ? _attach->getClipReader() : nullptr;
+	}
+	bool playInline(bool autoplay) override {
+		return _attach ? _attach->playInline(autoplay) : false;
+	}
+	void stopInline() override {
+		if (_attach) _attach->stopInline();
+	}
+
+	void attachToParent() override;
+	void detachFromParent() override;
+
+	bool hasReplyPreview() const override {
+		return (_data->photo && !_data->photo->thumb->isNull()) || (_data->document && !_data->document->thumb->isNull());
+	}
+	ImagePtr replyPreview() override;
+
+	GameData *game() {
+		return _data;
+	}
+
+	bool needsBubble() const override {
+		return true;
+	}
+	bool customInfoLayout() const override {
+		return false;
+	}
+
+	HistoryMedia *attach() const {
+		return _attach.get();
+	}
+
+private:
+	TextSelection toDescriptionSelection(TextSelection selection) const {
+		return internal::unshiftSelection(selection, _title);
+	}
+	TextSelection fromDescriptionSelection(TextSelection selection) const {
+		return internal::shiftSelection(selection, _title);
+	}
+
+	GameData *_data;
+	ClickHandlerPtr _openl;
+	std_::unique_ptr<HistoryMedia> _attach;
+
+	int32 _titleLines, _descriptionLines;
+
+	Text _title, _description;
+
+};
 
 struct LocationCoords;
 struct LocationData;
-class LocationManager : public QObject {
-	Q_OBJECT
-public:
-	void init();
-	void reinit();
-	void deinit();
-
-	void getData(LocationData *data);
-
-	~LocationManager() {
-		deinit();
-	}
-
-public slots:
-	void onFinished(QNetworkReply *reply);
-	void onFailed(QNetworkReply *reply);
-
-private:
-	void failed(LocationData *data);
-
-	QNetworkAccessManager *manager = nullptr;
-	QMap<QNetworkReply*, LocationData*> dataLoadings, imageLoadings;
-	QMap<LocationData*, int32> serverRedirects;
-	ImagePtr *black = nullptr;
-};
 
 class HistoryLocation : public HistoryMedia {
 public:
@@ -2703,13 +2768,15 @@ private:
 		}
 		return false;
 	}
-
+	void paintFromName(Painter &p, QRect &trect, bool selected) const;
 	void paintForwardedInfo(Painter &p, QRect &trect, bool selected) const;
 	void paintReplyInfo(Painter &p, QRect &trect, bool selected) const;
 
 	// this method draws "via @bot" if it is not painted in forwarded info or in from name
 	void paintViaBotIdInfo(Painter &p, QRect &trect, bool selected) const;
 
+	void paintText(Painter &p, QRect &trect, TextSelection selection) const;
+
 	void setMedia(const MTPMessageMedia *media);
 	void setReplyMarkup(const MTPReplyMarkup *markup);
 
diff --git a/Telegram/SourceFiles/history/history_location_manager.cpp b/Telegram/SourceFiles/history/history_location_manager.cpp
new file mode 100644
index 000000000..ee90d6734
--- /dev/null
+++ b/Telegram/SourceFiles/history/history_location_manager.cpp
@@ -0,0 +1,251 @@
+/*
+This file is part of Telegram Desktop,
+the official desktop version of Telegram messaging app, see https://telegram.org
+
+Telegram Desktop 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.
+
+It 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.
+
+In addition, as a special exception, the copyright holders give permission
+to link the code of portions of this program with the OpenSSL library.
+
+Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
+Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
+*/
+#include "stdafx.h"
+#include "history/history_location_manager.h"
+
+#include "mainwidget.h"
+#include "lang.h"
+#include "pspecific.h"
+
+QString LocationClickHandler::copyToClipboardContextItemText() const {
+	return lang(lng_context_copy_link);
+}
+
+void LocationClickHandler::onClick(Qt::MouseButton button) const {
+	if (!psLaunchMaps(_coords)) {
+		QDesktopServices::openUrl(_text);
+	}
+}
+
+void LocationClickHandler::setup() {
+	QString latlon(qsl("%1,%2").arg(_coords.lat).arg(_coords.lon));
+	_text = qsl("https://maps.google.com/maps?q=") + latlon + qsl("&ll=") + latlon + qsl("&z=16");
+}
+
+namespace {
+LocationManager *locationManager = nullptr;
+} // namespace
+
+void initLocationManager() {
+	if (!locationManager) {
+		locationManager = new LocationManager();
+		locationManager->init();
+	}
+}
+
+void reinitLocationManager() {
+	if (locationManager) {
+		locationManager->reinit();
+	}
+}
+
+void deinitLocationManager() {
+	if (locationManager) {
+		locationManager->deinit();
+		delete locationManager;
+		locationManager = nullptr;
+	}
+}
+
+void LocationManager::init() {
+	if (manager) delete manager;
+	manager = new QNetworkAccessManager();
+	App::setProxySettings(*manager);
+
+	connect(manager, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)), this, SLOT(onFailed(QNetworkReply*)));
+#ifndef OS_MAC_OLD
+	connect(manager, SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError>&)), this, SLOT(onFailed(QNetworkReply*)));
+#endif // OS_MAC_OLD
+	connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(onFinished(QNetworkReply*)));
+
+	if (black) {
+		delete black->v();
+		delete black;
+	}
+	QImage b(cIntRetinaFactor(), cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
+	{
+		QPainter p(&b);
+		p.fillRect(QRect(0, 0, cIntRetinaFactor(), cIntRetinaFactor()), st::white->b);
+	}
+	QPixmap p = App::pixmapFromImageInPlace(std_::move(b));
+	p.setDevicePixelRatio(cRetinaFactor());
+	black = new ImagePtr(p, "PNG");
+}
+
+void LocationManager::reinit() {
+	if (manager) App::setProxySettings(*manager);
+}
+
+void LocationManager::deinit() {
+	if (manager) {
+		delete manager;
+		manager = nullptr;
+	}
+	if (black) {
+		delete black->v();
+		delete black;
+		black = nullptr;
+	}
+	dataLoadings.clear();
+	imageLoadings.clear();
+}
+
+void LocationManager::getData(LocationData *data) {
+	if (!manager) {
+		DEBUG_LOG(("App Error: getting image link data without manager init!"));
+		return failed(data);
+	}
+
+	int32 w = st::locationSize.width(), h = st::locationSize.height();
+	int32 zoom = 13, scale = 1;
+	if (cScale() == dbisTwo || cRetina()) {
+		scale = 2;
+	} else {
+		w = convertScale(w);
+		h = convertScale(h);
+	}
+	QString coords = qsl("%1,%2").arg(data->coords.lat).arg(data->coords.lon);
+	QString url = qsl("https://maps.googleapis.com/maps/api/staticmap?center=") + coords + qsl("&zoom=%1&size=%2x%3&maptype=roadmap&scale=%4&markers=color:red|size:big|").arg(zoom).arg(w).arg(h).arg(scale) + coords + qsl("&sensor=false");
+	QNetworkReply *reply = manager->get(QNetworkRequest(QUrl(url)));
+	imageLoadings[reply] = data;
+}
+
+void LocationManager::onFinished(QNetworkReply *reply) {
+	if (!manager) return;
+	if (reply->error() != QNetworkReply::NoError) return onFailed(reply);
+
+	QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
+	if (statusCode.isValid()) {
+		int status = statusCode.toInt();
+		if (status == 301 || status == 302) {
+			QString loc = reply->header(QNetworkRequest::LocationHeader).toString();
+			if (!loc.isEmpty()) {
+				QMap<QNetworkReply*, LocationData*>::iterator i = dataLoadings.find(reply);
+				if (i != dataLoadings.cend()) {
+					LocationData *d = i.value();
+					if (serverRedirects.constFind(d) == serverRedirects.cend()) {
+						serverRedirects.insert(d, 1);
+					} else if (++serverRedirects[d] > MaxHttpRedirects) {
+						DEBUG_LOG(("Network Error: Too many HTTP redirects in onFinished() for image link: %1").arg(loc));
+						return onFailed(reply);
+					}
+					dataLoadings.erase(i);
+					dataLoadings.insert(manager->get(QNetworkRequest(loc)), d);
+					return;
+				} else if ((i = imageLoadings.find(reply)) != imageLoadings.cend()) {
+					LocationData *d = i.value();
+					if (serverRedirects.constFind(d) == serverRedirects.cend()) {
+						serverRedirects.insert(d, 1);
+					} else if (++serverRedirects[d] > MaxHttpRedirects) {
+						DEBUG_LOG(("Network Error: Too many HTTP redirects in onFinished() for image link: %1").arg(loc));
+						return onFailed(reply);
+					}
+					imageLoadings.erase(i);
+					imageLoadings.insert(manager->get(QNetworkRequest(loc)), d);
+					return;
+				}
+			}
+		}
+		if (status != 200) {
+			DEBUG_LOG(("Network Error: Bad HTTP status received in onFinished() for image link: %1").arg(status));
+			return onFailed(reply);
+		}
+	}
+
+	LocationData *d = 0;
+	QMap<QNetworkReply*, LocationData*>::iterator i = dataLoadings.find(reply);
+	if (i != dataLoadings.cend()) {
+		d = i.value();
+		dataLoadings.erase(i);
+
+		QJsonParseError e;
+		QJsonDocument doc = QJsonDocument::fromJson(reply->readAll(), &e);
+		if (e.error != QJsonParseError::NoError) {
+			DEBUG_LOG(("JSON Error: Bad json received in onFinished() for image link"));
+			return onFailed(reply);
+		}
+		failed(d);
+
+		if (App::main()) App::main()->update();
+	} else {
+		i = imageLoadings.find(reply);
+		if (i != imageLoadings.cend()) {
+			d = i.value();
+			imageLoadings.erase(i);
+
+			QPixmap thumb;
+			QByteArray format;
+			QByteArray data(reply->readAll());
+			{
+				QBuffer buffer(&data);
+				QImageReader reader(&buffer);
+#ifndef OS_MAC_OLD
+				reader.setAutoTransform(true);
+#endif // OS_MAC_OLD
+				thumb = QPixmap::fromImageReader(&reader, Qt::ColorOnly);
+				format = reader.format();
+				thumb.setDevicePixelRatio(cRetinaFactor());
+				if (format.isEmpty()) format = QByteArray("JPG");
+			}
+			d->loading = false;
+			d->thumb = thumb.isNull() ? (*black) : ImagePtr(thumb, format);
+			serverRedirects.remove(d);
+			if (App::main()) App::main()->update();
+		}
+	}
+}
+
+void LocationManager::onFailed(QNetworkReply *reply) {
+	if (!manager) return;
+
+	LocationData *d = 0;
+	QMap<QNetworkReply*, LocationData*>::iterator i = dataLoadings.find(reply);
+	if (i != dataLoadings.cend()) {
+		d = i.value();
+		dataLoadings.erase(i);
+	} else {
+		i = imageLoadings.find(reply);
+		if (i != imageLoadings.cend()) {
+			d = i.value();
+			imageLoadings.erase(i);
+		}
+	}
+	DEBUG_LOG(("Network Error: failed to get data for image link %1,%2 error %3").arg(d ? d->coords.lat : 0).arg(d ? d->coords.lon : 0).arg(reply->errorString()));
+	if (d) {
+		failed(d);
+	}
+}
+
+void LocationManager::failed(LocationData *data) {
+	data->loading = false;
+	data->thumb = *black;
+	serverRedirects.remove(data);
+}
+
+void LocationData::load() {
+	if (!thumb->isNull()) return thumb->load(false, false);
+	if (loading) return;
+
+	loading = true;
+	if (locationManager) {
+		locationManager->getData(this);
+	}
+}
diff --git a/Telegram/SourceFiles/history/history_location_manager.h b/Telegram/SourceFiles/history/history_location_manager.h
new file mode 100644
index 000000000..bf422e4bb
--- /dev/null
+++ b/Telegram/SourceFiles/history/history_location_manager.h
@@ -0,0 +1,120 @@
+/*
+This file is part of Telegram Desktop,
+the official desktop version of Telegram messaging app, see https://telegram.org
+
+Telegram Desktop 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.
+
+It 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.
+
+In addition, as a special exception, the copyright holders give permission
+to link the code of portions of this program with the OpenSSL library.
+
+Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
+Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
+*/
+#pragma once
+
+void initLocationManager();
+void reinitLocationManager();
+void deinitLocationManager();
+
+struct LocationCoords {
+	LocationCoords() : lat(0), lon(0) {
+	}
+	LocationCoords(float64 lat, float64 lon) : lat(lat), lon(lon) {
+	}
+	LocationCoords(const MTPDgeoPoint &point) : lat(point.vlat.v), lon(point.vlong.v) {
+	}
+	float64 lat, lon;
+};
+inline bool operator==(const LocationCoords &a, const LocationCoords &b) {
+	return (a.lat == b.lat) && (a.lon == b.lon);
+}
+inline bool operator<(const LocationCoords &a, const LocationCoords &b) {
+	return (a.lat < b.lat) || ((a.lat == b.lat) && (a.lon < b.lon));
+}
+inline uint qHash(const LocationCoords &t, uint seed = 0) {
+#ifndef OS_MAC_OLD
+	return qHash(QtPrivate::QHashCombine().operator()(qHash(t.lat), t.lon), seed);
+#else // OS_MAC_OLD
+	uint h1 = qHash(t.lat, seed);
+	uint h2 = qHash(t.lon, seed);
+	return ((h1 << 16) | (h1 >> 16)) ^ h2 ^ seed;
+#endif // OS_MAC_OLD
+}
+
+struct LocationData {
+	LocationData(const LocationCoords &coords) : coords(coords), loading(false) {
+	}
+
+	LocationCoords coords;
+	ImagePtr thumb;
+	bool loading;
+
+	void load();
+};
+
+class LocationClickHandler : public ClickHandler {
+public:
+	LocationClickHandler(const LocationCoords &coords) : _coords(coords) {
+		setup();
+	}
+
+	void onClick(Qt::MouseButton button) const override;
+
+	QString tooltip() const override {
+		return QString();
+	}
+
+	QString dragText() const override {
+		return _text;
+	}
+
+	void copyToClipboard() const override {
+		if (!_text.isEmpty()) {
+			QApplication::clipboard()->setText(_text);
+		}
+	}
+	QString copyToClipboardContextItemText() const override;
+
+private:
+
+	void setup();
+	LocationCoords _coords;
+	QString _text;
+
+};
+
+class LocationManager : public QObject {
+	Q_OBJECT
+
+public:
+	void init();
+	void reinit();
+	void deinit();
+
+	void getData(LocationData *data);
+
+	~LocationManager() {
+		deinit();
+	}
+
+public slots:
+	void onFinished(QNetworkReply *reply);
+	void onFailed(QNetworkReply *reply);
+
+private:
+	void failed(LocationData *data);
+
+	QNetworkAccessManager *manager = nullptr;
+	QMap<QNetworkReply*, LocationData*> dataLoadings, imageLoadings;
+	QMap<LocationData*, int32> serverRedirects;
+	ImagePtr *black = nullptr;
+
+};
diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp
index 198a634b1..b4dc8eb68 100644
--- a/Telegram/SourceFiles/historywidget.cpp
+++ b/Telegram/SourceFiles/historywidget.cpp
@@ -5797,16 +5797,13 @@ void HistoryWidget::app_sendBotCallback(const HistoryMessageReplyMarkup::Button
 	BotCallbackInfo info = { bot, msg->fullId(), row, col, (button->type == ButtonType::Game) };
 	MTPmessages_GetBotCallbackAnswer::Flags flags = 0;
 	QByteArray sendData;
-	int32 sendGameId = 0;
 	if (info.game) {
-		flags = MTPmessages_GetBotCallbackAnswer::Flag::f_game_id;
-		auto strData = QString::fromUtf8(button->data);
-		sendGameId = strData.midRef(0, strData.indexOf(',')).toInt();
+		flags = MTPmessages_GetBotCallbackAnswer::Flag::f_game;
 	} else if (button->type == ButtonType::Callback) {
 		flags = MTPmessages_GetBotCallbackAnswer::Flag::f_data;
 		sendData = button->data;
 	}
-	button->requestId = MTP::send(MTPmessages_GetBotCallbackAnswer(MTP_flags(flags), _peer->input, MTP_int(msg->id), MTP_bytes(sendData), MTP_int(sendGameId)), rpcDone(&HistoryWidget::botCallbackDone, info), rpcFail(&HistoryWidget::botCallbackFail, info));
+	button->requestId = MTP::send(MTPmessages_GetBotCallbackAnswer(MTP_flags(flags), _peer->input, MTP_int(msg->id), MTP_bytes(sendData)), rpcDone(&HistoryWidget::botCallbackDone, info), rpcFail(&HistoryWidget::botCallbackFail, info));
 	Ui::repaintHistoryItem(msg);
 
 	if (_replyToId == msg->id) {
@@ -8138,7 +8135,7 @@ void HistoryWidget::gotPreview(QString links, const MTPMessageMedia &result, mtp
 		_previewRequest = 0;
 	}
 	if (result.type() == mtpc_messageMediaWebPage) {
-		WebPageData *data = App::feedWebPage(result.c_messageMediaWebPage().vwebpage);
+		auto data = App::feedWebPage(result.c_messageMediaWebPage().vwebpage);
 		_previewCache.insert(links, data->id);
 		if (data->pendingTill > 0 && data->pendingTill <= unixtime()) {
 			data->pendingTill = -1;
@@ -8147,7 +8144,7 @@ void HistoryWidget::gotPreview(QString links, const MTPMessageMedia &result, mtp
 			_previewData = (data->id && data->pendingTill >= 0) ? data : 0;
 			updatePreview();
 		}
-		if (App::main()) App::main()->webPagesUpdate();
+		if (App::main()) App::main()->webPagesOrGamesUpdate();
 	} else if (result.type() == mtpc_messageMediaEmpty) {
 		_previewCache.insert(links, 0);
 		if (links == _previewLinks && !_previewCancelled) {
diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp
index 49a70a392..63385e707 100644
--- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp
+++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp
@@ -24,6 +24,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
 #include "styles/style_overview.h"
 #include "inline_bots/inline_bot_result.h"
 #include "media/media_clip_reader.h"
+#include "history/history_location_manager.h"
 #include "localstorage.h"
 #include "mainwidget.h"
 #include "lang.h"
diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_send_data.h b/Telegram/SourceFiles/inline_bots/inline_bot_send_data.h
index 031ee992e..3c2e8fbf4 100644
--- a/Telegram/SourceFiles/inline_bots/inline_bot_send_data.h
+++ b/Telegram/SourceFiles/inline_bots/inline_bot_send_data.h
@@ -23,6 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
 #include "core/basic_types.h"
 #include "structs.h"
 #include "mtproto/core_types.h"
+#include "history/history_location_manager.h"
 
 namespace InlineBots {
 
@@ -62,7 +63,6 @@ public:
 // Only SendFile and SendPhoto work by their own.
 class SendDataCommon : public SendData {
 public:
-
 	struct SentMTPMessageFields {
 		MTPString text = MTP_string("");
 		MTPVector<MTPMessageEntity> entities = MTPnullEntities;
@@ -99,7 +99,7 @@ private:
 // Message with geo location point media.
 class SendGeo : public SendDataCommon {
 public:
-	SendGeo(const MTPDgeoPoint &point) : _location(point) {
+	explicit SendGeo(const MTPDgeoPoint &point) : _location(point) {
 	}
 
 	bool isValid() const override {
diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp
index 28d1bece6..5027ec7dc 100644
--- a/Telegram/SourceFiles/localstorage.cpp
+++ b/Telegram/SourceFiles/localstorage.cpp
@@ -2978,11 +2978,11 @@ public:
 				voice->waveform[0] = -2;
 				voice->wavemax = 0;
 			}
-			const DocumentItems &items(App::documentItems());
-			DocumentItems::const_iterator i = items.constFind(_doc);
+			auto &items = App::documentItems();
+			auto i = items.constFind(_doc);
 			if (i != items.cend()) {
-				for (HistoryItemsMap::const_iterator j = i->cbegin(), e = i->cend(); j != e; ++j) {
-					Ui::repaintHistoryItem(j.key());
+				for_const (auto item, i.value()) {
+					Ui::repaintHistoryItem(item);
 				}
 			}
 		}
diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp
index d96db84ee..cb6b37fe9 100644
--- a/Telegram/SourceFiles/mainwidget.cpp
+++ b/Telegram/SourceFiles/mainwidget.cpp
@@ -102,8 +102,8 @@ MainWidget::MainWidget(MainWindow *window) : TWidget(window)
 	connect(&_updateMutedTimer, SIGNAL(timeout()), this, SLOT(onUpdateMuted()));
 	connect(&_viewsIncrementTimer, SIGNAL(timeout()), this, SLOT(onViewsIncrement()));
 
-	_webPageUpdater.setSingleShot(true);
-	connect(&_webPageUpdater, SIGNAL(timeout()), this, SLOT(webPagesUpdate()));
+	_webPageOrGameUpdater.setSingleShot(true);
+	connect(&_webPageOrGameUpdater, SIGNAL(timeout()), this, SLOT(webPagesOrGamesUpdate()));
 
 	subscribe(Window::chatBackground(), [this](const Window::ChatBackgroundUpdate &update) {
 		using Update = Window::ChatBackgroundUpdate;
@@ -341,24 +341,41 @@ void MainWidget::finishForwarding(History *history, bool silent) {
 }
 
 void MainWidget::webPageUpdated(WebPageData *data) {
-	_webPagesUpdated.insert(data->id, true);
-	_webPageUpdater.start(0);
+	_webPagesUpdated.insert(data->id);
+	_webPageOrGameUpdater.start(0);
 }
 
-void MainWidget::webPagesUpdate() {
-	if (_webPagesUpdated.isEmpty()) return;
+void MainWidget::gameUpdated(GameData *data) {
+	_gamesUpdated.insert(data->id);
+	_webPageOrGameUpdater.start(0);
+}
 
-	_webPageUpdater.stop();
-	const WebPageItems &items(App::webPageItems());
-	for (QMap<WebPageId, bool>::const_iterator i = _webPagesUpdated.cbegin(), e = _webPagesUpdated.cend(); i != e; ++i) {
-		WebPageItems::const_iterator j = items.constFind(App::webPage(i.key()));
-		if (j != items.cend()) {
-			for (HistoryItemsMap::const_iterator k = j.value().cbegin(), e = j.value().cend(); k != e; ++k) {
-				k.key()->setPendingInitDimensions();
+void MainWidget::webPagesOrGamesUpdate() {
+	_webPageOrGameUpdater.stop();
+	if (!_webPagesUpdated.isEmpty()) {
+		auto &items = App::webPageItems();
+		for_const (auto webPageId, _webPagesUpdated) {
+			auto j = items.constFind(App::webPage(webPageId));
+			if (j != items.cend()) {
+				for_const (auto item, j.value()) {
+					item->setPendingInitDimensions();
+				}
 			}
 		}
+		_webPagesUpdated.clear();
+	}
+	if (!_gamesUpdated.isEmpty()) {
+		auto &items = App::gameItems();
+		for_const (auto gameId, _gamesUpdated) {
+			auto j = items.constFind(App::game(gameId));
+			if (j != items.cend()) {
+				for_const (auto item, j.value()) {
+					item->setPendingInitDimensions();
+				}
+			}
+		}
+		_gamesUpdated.clear();
 	}
-	_webPagesUpdated.clear();
 }
 
 void MainWidget::updateMutedIn(int32 seconds) {
@@ -470,8 +487,8 @@ void MainWidget::notify_userIsContactChanged(UserData *user, bool fromThisApp) {
 	const SharedContactItems &items(App::sharedContactItems());
 	SharedContactItems::const_iterator i = items.constFind(peerToUser(user->id));
 	if (i != items.cend()) {
-		for (HistoryItemsMap::const_iterator j = i->cbegin(), e = i->cend(); j != e; ++j) {
-			j.key()->setPendingInitDimensions();
+		for_const (auto item, i.value()) {
+			item->setPendingInitDimensions();
 		}
 	}
 
@@ -1151,7 +1168,7 @@ void MainWidget::sendMessage(const MessageToSend &message) {
 		if (message.webPageId == CancelledWebPageId) {
 			sendFlags |= MTPmessages_SendMessage::Flag::f_no_webpage;
 		} else if (message.webPageId) {
-			WebPageData *page = App::webPage(message.webPageId);
+			auto page = App::webPage(message.webPageId);
 			media = MTP_messageMediaWebPage(MTP_webPagePending(MTP_long(page->id), MTP_int(page->pendingTill)));
 			flags |= MTPDmessage::Flag::f_media;
 		}
@@ -1612,8 +1629,8 @@ void MainWidget::documentLoadProgress(FileLoader *loader) {
 	const DocumentItems &items(App::documentItems());
 	DocumentItems::const_iterator i = items.constFind(document);
 	if (i != items.cend()) {
-		for (HistoryItemsMap::const_iterator j = i->cbegin(), e = i->cend(); j != e; ++j) {
-			Ui::repaintHistoryItem(j.key());
+		for_const (auto item, i.value()) {
+			Ui::repaintHistoryItem(item);
 		}
 	}
 	App::wnd()->documentUpdated(document);
@@ -1674,11 +1691,11 @@ void MainWidget::mediaMarkRead(DocumentData *data) {
 void MainWidget::mediaMarkRead(const HistoryItemsMap &items) {
 	QVector<MTPint> markedIds;
 	markedIds.reserve(items.size());
-	for (HistoryItemsMap::const_iterator j = items.cbegin(), e = items.cend(); j != e; ++j) {
-		if (!j.key()->out() && j.key()->isMediaUnread()) {
-			j.key()->markMediaRead();
-			if (j.key()->id > 0) {
-				markedIds.push_back(MTP_int(j.key()->id));
+	for_const (auto item, items) {
+		if (!item->out() && item->isMediaUnread()) {
+			item->markMediaRead();
+			if (item->id > 0) {
+				markedIds.push_back(MTP_int(item->id));
 			}
 		}
 	}
@@ -4179,8 +4196,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 			}
 		}
 		if (needToAdd) {
-			HistoryItem *item = App::histories().addNewMessage(d.vmessage, NewMessageUnread);
-			if (item) {
+			if (auto item = App::histories().addNewMessage(d.vmessage, NewMessageUnread)) {
 				_history->peerMessagesUpdated(item->history()->peer->id);
 			}
 		}
@@ -4188,11 +4204,10 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 	} break;
 
 	case mtpc_updateMessageID: {
-		const auto &d(update.c_updateMessageID());
-		FullMsgId msg = App::histItemByRandom(d.vrandom_id.v);
+		auto &d = update.c_updateMessageID();
+		auto msg = App::histItemByRandom(d.vrandom_id.v);
 		if (msg.msg) {
-			HistoryItem *msgRow = App::histItemById(msg);
-			if (msgRow) {
+			if (auto msgRow = App::histItemById(msg)) {
 				if (App::histItemById(msg.channel, d.vid.v)) {
 					History *h = msgRow->history();
 					bool wasLast = (h->lastMsg == msgRow);
@@ -4218,14 +4233,14 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 	} break;
 
 	case mtpc_updateReadMessagesContents: {
-		const auto &d(update.c_updateReadMessagesContents());
+		auto &d = update.c_updateReadMessagesContents();
 
 		if (!ptsUpdated(d.vpts.v, d.vpts_count.v, update)) {
 			return;
 		}
 
 		// update before applying skipped
-		const auto &v(d.vmessages.c_vector().v);
+		auto &v = d.vmessages.c_vector().v;
 		for (int32 i = 0, l = v.size(); i < l; ++i) {
 			if (HistoryItem *item = App::histItemById(NoChannel, v.at(i).v)) {
 				if (item->isMediaUnread()) {
@@ -4244,7 +4259,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 	} break;
 
 	case mtpc_updateReadHistoryInbox: {
-		const auto &d(update.c_updateReadHistoryInbox());
+		auto &d = update.c_updateReadHistoryInbox();
 
 		if (!ptsUpdated(d.vpts.v, d.vpts_count.v, update)) {
 			return;
@@ -4257,7 +4272,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 	} break;
 
 	case mtpc_updateReadHistoryOutbox: {
-		const auto &d(update.c_updateReadHistoryOutbox());
+		auto &d = update.c_updateReadHistoryOutbox();
 
 		if (!ptsUpdated(d.vpts.v, d.vpts_count.v, update)) {
 			return;
@@ -4275,7 +4290,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 	} break;
 
 	case mtpc_updateWebPage: {
-		const auto &d(update.c_updateWebPage());
+		auto &d = update.c_updateWebPage();
 
 		if (!ptsUpdated(d.vpts.v, d.vpts_count.v, update)) {
 			return;
@@ -4284,13 +4299,13 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 		// update before applying skipped
 		App::feedWebPage(d.vwebpage);
 		_history->updatePreview();
-		webPagesUpdate();
+		webPagesOrGamesUpdate();
 
 		ptsApplySkippedUpdates();
 	} break;
 
 	case mtpc_updateDeleteMessages: {
-		const auto &d(update.c_updateDeleteMessages());
+		auto &d = update.c_updateDeleteMessages();
 
 		if (!ptsUpdated(d.vpts.v, d.vpts_count.v, update)) {
 			return;
@@ -4304,9 +4319,9 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 	} break;
 
 	case mtpc_updateUserTyping: {
-		const auto &d(update.c_updateUserTyping());
-		History *history = App::historyLoaded(peerFromUser(d.vuser_id));
-		UserData *user = App::userLoaded(d.vuser_id.v);
+		auto &d = update.c_updateUserTyping();
+		auto history = App::historyLoaded(peerFromUser(d.vuser_id));
+		auto user = App::userLoaded(d.vuser_id.v);
 		if (history && user) {
 			auto when = requestingDifference() ? 0 : unixtime();
 			App::histories().regSendAction(history, user, d.vaction, when);
@@ -4314,14 +4329,14 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 	} break;
 
 	case mtpc_updateChatUserTyping: {
-		const auto &d(update.c_updateChatUserTyping());
+		auto &d = update.c_updateChatUserTyping();
 		History *history = 0;
-		if (PeerData *chat = App::chatLoaded(d.vchat_id.v)) {
+		if (auto chat = App::chatLoaded(d.vchat_id.v)) {
 			history = App::historyLoaded(chat->id);
-		} else if (PeerData *channel = App::channelLoaded(d.vchat_id.v)) {
+		} else if (auto channel = App::channelLoaded(d.vchat_id.v)) {
 			history = App::historyLoaded(channel->id);
 		}
-		UserData *user = (d.vuser_id.v == MTP::authedId()) ? 0 : App::userLoaded(d.vuser_id.v);
+		auto user = (d.vuser_id.v == MTP::authedId()) ? nullptr : App::userLoaded(d.vuser_id.v);
 		if (history && user) {
 			auto when = requestingDifference() ? 0 : unixtime();
 			App::histories().regSendAction(history, user, d.vaction, when);
@@ -4349,9 +4364,8 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 	} break;
 
 	case mtpc_updateUserStatus: {
-		const auto &d(update.c_updateUserStatus());
-		UserData *user = App::userLoaded(d.vuser_id.v);
-		if (user) {
+		auto &d = update.c_updateUserStatus();
+		if (auto user = App::userLoaded(d.vuser_id.v)) {
 			switch (d.vstatus.type()) {
 			case mtpc_userStatusEmpty: user->onlineTill = 0; break;
 			case mtpc_userStatusRecently:
@@ -4380,7 +4394,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 	} break;
 
 	case mtpc_updateUserName: {
-		auto &d(update.c_updateUserName());
+		auto &d = update.c_updateUserName();
 		if (auto user = App::userLoaded(d.vuser_id.v)) {
 			if (user->contact <= 0) {
 				user->setName(textOneLine(qs(d.vfirst_name)), textOneLine(qs(d.vlast_name)), user->nameOrPhone, textOneLine(qs(d.vusername)));
@@ -4392,9 +4406,8 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 	} break;
 
 	case mtpc_updateUserPhoto: {
-		const auto &d(update.c_updateUserPhoto());
-		UserData *user = App::userLoaded(d.vuser_id.v);
-		if (user) {
+		auto &d = update.c_updateUserPhoto();
+		if (auto user = App::userLoaded(d.vuser_id.v)) {
 			user->setPhoto(d.vphoto);
 			user->loadUserpic();
 			if (mtpIsTrue(d.vprevious)) {
@@ -4415,9 +4428,8 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 	} break;
 
 	case mtpc_updateContactRegistered: {
-		const auto &d(update.c_updateContactRegistered());
-		UserData *user = App::userLoaded(d.vuser_id.v);
-		if (user) {
+		auto &d = update.c_updateContactRegistered();
+		if (auto user = App::userLoaded(d.vuser_id.v)) {
 			if (App::history(user->id)->loadedAtBottom()) {
 				App::history(user->id)->addNewService(clientMsgId(), date(d.vdate), lng_action_user_registered(lt_from, user->name), 0);
 			}
@@ -4425,22 +4437,22 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 	} break;
 
 	case mtpc_updateContactLink: {
-		const auto &d(update.c_updateContactLink());
+		auto &d = update.c_updateContactLink();
 		App::feedUserLink(d.vuser_id, d.vmy_link, d.vforeign_link);
 	} break;
 
 	case mtpc_updateNotifySettings: {
-		const auto &d(update.c_updateNotifySettings());
+		auto &d = update.c_updateNotifySettings();
 		applyNotifySetting(d.vpeer, d.vnotify_settings);
 	} break;
 
 	case mtpc_updateDcOptions: {
-		const auto &d(update.c_updateDcOptions());
+		auto &d = update.c_updateDcOptions();
 		MTP::updateDcOptions(d.vdc_options.c_vector().v);
 	} break;
 
 	case mtpc_updateUserPhone: {
-		auto &d(update.c_updateUserPhone());
+		auto &d = update.c_updateUserPhone();
 		if (auto user = App::userLoaded(d.vuser_id.v)) {
 			auto newPhone = qs(d.vphone);
 			if (newPhone != user->phone()) {
@@ -4454,31 +4466,31 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 	} break;
 
 	case mtpc_updateNewEncryptedMessage: {
-		const auto &d(update.c_updateNewEncryptedMessage());
+		auto &d = update.c_updateNewEncryptedMessage();
 	} break;
 
 	case mtpc_updateEncryptedChatTyping: {
-		const auto &d(update.c_updateEncryptedChatTyping());
+		auto &d = update.c_updateEncryptedChatTyping();
 	} break;
 
 	case mtpc_updateEncryption: {
-		const auto &d(update.c_updateEncryption());
+		auto &d = update.c_updateEncryption();
 	} break;
 
 	case mtpc_updateEncryptedMessagesRead: {
-		const auto &d(update.c_updateEncryptedMessagesRead());
+		auto &d = update.c_updateEncryptedMessagesRead();
 	} break;
 
 	case mtpc_updateUserBlocked: {
-		const auto &d(update.c_updateUserBlocked());
-		if (UserData *user = App::userLoaded(d.vuser_id.v)) {
+		auto &d = update.c_updateUserBlocked();
+		if (auto user = App::userLoaded(d.vuser_id.v)) {
 			user->setBlockStatus(mtpIsTrue(d.vblocked) ? UserData::BlockStatus::Blocked : UserData::BlockStatus::NotBlocked);
 			App::markPeerUpdated(user);
 		}
 	} break;
 
 	case mtpc_updateNewAuthorization: {
-		const auto &d(update.c_updateNewAuthorization());
+		auto &d = update.c_updateNewAuthorization();
 		QDateTime datetime = date(d.vdate);
 
 		QString name = App::self()->firstName;
@@ -4491,7 +4503,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 	} break;
 
 	case mtpc_updateServiceNotification: {
-		const auto &d(update.c_updateServiceNotification());
+		auto &d = update.c_updateServiceNotification();
 		if (mtpIsTrue(d.vpopup)) {
 			Ui::showLayer(new InformBox(qs(d.vmessage)));
 		} else {
diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h
index 939494967..84fb26380 100644
--- a/Telegram/SourceFiles/mainwidget.h
+++ b/Telegram/SourceFiles/mainwidget.h
@@ -344,6 +344,7 @@ public:
 	void mediaMarkRead(const HistoryItemsMap &items);
 
 	void webPageUpdated(WebPageData *page);
+	void gameUpdated(GameData *game);
 	void updateMutedIn(int32 seconds);
 
 	void updateStickers();
@@ -407,7 +408,6 @@ public:
 	~MainWidget();
 
 signals:
-
 	void peerUpdated(PeerData *peer);
 	void peerNameChanged(PeerData *peer, const PeerData::Names &oldNames, const PeerData::NameFirstChars &oldChars);
 	void peerPhotoChanged(PeerData *peer);
@@ -417,8 +417,7 @@ signals:
 	void savedGifsUpdated();
 
 public slots:
-
-	void webPagesUpdate();
+	void webPagesOrGamesUpdate();
 
 	void audioPlayProgress(const AudioMsgId &audioId);
 	void documentLoadProgress(FileLoader *loader);
@@ -511,8 +510,9 @@ private:
 	Text _toForwardFrom, _toForwardText;
 	int32 _toForwardNameVersion = 0;
 
-	QMap<WebPageId, bool> _webPagesUpdated;
-	QTimer _webPageUpdater;
+	OrderedSet<WebPageId> _webPagesUpdated;
+	OrderedSet<GameId> _gamesUpdated;
+	QTimer _webPageOrGameUpdater;
 
 	SingleTimer _updateMutedTimer;
 
diff --git a/Telegram/SourceFiles/mtproto/scheme.tl b/Telegram/SourceFiles/mtproto/scheme.tl
index ba2100cb3..286280dd9 100644
--- a/Telegram/SourceFiles/mtproto/scheme.tl
+++ b/Telegram/SourceFiles/mtproto/scheme.tl
@@ -157,6 +157,7 @@ inputMediaVenue#2827a81a geo_point:InputGeoPoint title:string address:string pro
 inputMediaGifExternal#4843b0fd url:string q:string = InputMedia;
 inputMediaPhotoExternal#b55f4f18 url:string caption:string = InputMedia;
 inputMediaDocumentExternal#e5e9607c url:string caption:string = InputMedia;
+inputMediaGame#d33f43f3 id:InputGame = InputMedia;
 
 inputChatPhotoEmpty#1ca48f57 = InputChatPhoto;
 inputChatUploadedPhoto#927c55b4 file:InputFile = InputChatPhoto;
@@ -236,6 +237,7 @@ messageMediaUnsupported#9f84f49e = MessageMedia;
 messageMediaDocument#f3e02ea8 document:Document caption:string = MessageMedia;
 messageMediaWebPage#a32dd600 webpage:WebPage = MessageMedia;
 messageMediaVenue#7912b71f geo:GeoPoint title:string address:string provider:string venue_id:string = MessageMedia;
+messageMediaGame#fdb19008 game:Game = MessageMedia;
 
 messageActionEmpty#b6aef7b0 = MessageAction;
 messageActionChatCreate#a6638b9a title:string users:Vector<int> = MessageAction;
@@ -250,7 +252,7 @@ messageActionChatMigrateTo#51bdb021 channel_id:int = MessageAction;
 messageActionChannelMigrateFrom#b055eaee title:string chat_id:int = MessageAction;
 messageActionPinMessage#94bd38ed = MessageAction;
 messageActionHistoryClear#9fbab604 = MessageAction;
-messageActionGameScore#3a14cfa5 game_id:int score:int = MessageAction;
+messageActionGameScore#92a72876 game_id:long score:int = MessageAction;
 
 dialog#66ffba14 flags:# peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog;
 
@@ -387,9 +389,9 @@ updateBotInlineQuery#54826690 flags:# query_id:long user_id:int query:string geo
 updateBotInlineSend#e48f964 flags:# user_id:int query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update;
 updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update;
 updateChannelPinnedMessage#98592475 channel_id:int id:int = Update;
-updateBotCallbackQuery#4bf9a8a0 flags:# query_id:long user_id:int peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_id:flags.1?int = Update;
+updateBotCallbackQuery#e73547e1 flags:# query_id:long user_id:int peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update;
 updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update;
-updateInlineBotCallbackQuery#4f2f45d1 flags:# query_id:long user_id:int msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_id:flags.1?int = Update;
+updateInlineBotCallbackQuery#f9d27a5a flags:# query_id:long user_id:int msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update;
 updateReadChannelOutbox#25d6c9c7 channel_id:int max_id:int = Update;
 updateDraftMessage#ee2bb969 peer:Peer draft:DraftMessage = Update;
 updateReadFeaturedStickers#571d2742 = Update;
@@ -572,7 +574,7 @@ keyboardButtonCallback#683a5e46 text:string data:bytes = KeyboardButton;
 keyboardButtonRequestPhone#b16a6c29 text:string = KeyboardButton;
 keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton;
 keyboardButtonSwitchInline#568a748 flags:# same_peer:flags.0?true text:string query:string = KeyboardButton;
-keyboardButtonGame#28fc3164 text:string game_title:string game_id:int start_param:string = KeyboardButton;
+keyboardButtonGame#50f41ccf text:string = KeyboardButton;
 
 keyboardButtonRow#77608b83 buttons:Vector<KeyboardButton> = KeyboardButtonRow;
 
@@ -647,10 +649,12 @@ inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true message:strin
 inputBotInlineMessageMediaGeo#f4a59de1 flags:# geo_point:InputGeoPoint reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
 inputBotInlineMessageMediaVenue#aaafadc8 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
 inputBotInlineMessageMediaContact#2daf01a7 flags:# phone_number:string first_name:string last_name:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
+inputBotInlineMessageGame#3c00f8aa reply_markup:ReplyMarkup = InputBotInlineMessage;
 
 inputBotInlineResult#2cbbe15a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb_url:flags.4?string content_url:flags.5?string content_type:flags.5?string w:flags.6?int h:flags.6?int duration:flags.7?int send_message:InputBotInlineMessage = InputBotInlineResult;
 inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult;
 inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult;
+inputBotInlineResultGame#efff34f9 flags:# id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult;
 
 botInlineMessageMediaAuto#a74b15b flags:# caption:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
 botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true message:string entities:flags.1?Vector<MessageEntity> reply_markup:flags.2?ReplyMarkup = BotInlineMessage;
@@ -721,6 +725,15 @@ maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords;
 inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia;
 inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia;
 
+game#b351c590 flags:# id:long access_hash:long short_name:string title:string description:string url:string photo:Photo document:flags.0?Document = Game;
+
+inputGameID#32c3e77 id:long access_hash:long = InputGame;
+inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame;
+
+highScore#58fffcd0 pos:int user_id:int score:int = HighScore;
+
+messages.highScores#9a3bfd99 scores:Vector<HighScore> users:Vector<User> = messages.HighScores;
+
 ---functions---
 
 invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
@@ -851,7 +864,7 @@ messages.sendInlineBotResult#b16e06fe flags:# silent:flags.5?true background:fla
 messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData;
 messages.editMessage#ce91e4ca flags:# no_webpage:flags.1?true peer:InputPeer id:int message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Updates;
 messages.editInlineBotMessage#130c2c85 flags:# no_webpage:flags.1?true id:InputBotInlineMessageID message:flags.11?string reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Bool;
-messages.getBotCallbackAnswer#6c996518 flags:# peer:InputPeer msg_id:int data:flags.0?bytes game_id:flags.1?int = messages.BotCallbackAnswer;
+messages.getBotCallbackAnswer#810a9fec flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes = messages.BotCallbackAnswer;
 messages.setBotCallbackAnswer#c927d44b flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string = Bool;
 messages.getPeerDialogs#2d9776b9 peers:Vector<InputPeer> = messages.PeerDialogs;
 messages.saveDraft#bc39e14b flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int peer:InputPeer message:string entities:flags.3?Vector<MessageEntity> = Bool;
@@ -862,10 +875,12 @@ messages.getRecentStickers#5ea192c9 flags:# attached:flags.0?true hash:int = mes
 messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool;
 messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool;
 messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true offset_id:long limit:int = messages.ArchivedStickers;
-messages.setGameScore#dfbc7c1f flags:# edit_message:flags.0?true peer:InputPeer id:int user_id:InputUser game_id:int score:int = Updates;
-messages.setInlineGameScore#54f882f1 flags:# edit_message:flags.0?true id:InputBotInlineMessageID user_id:InputUser game_id:int score:int = Bool;
 messages.getMaskStickers#65b8c79f hash:int = messages.AllStickers;
 messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector<StickerSetCovered>;
+messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true peer:InputPeer id:int user_id:InputUser score:int = Updates;
+messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true id:InputBotInlineMessageID user_id:InputUser score:int = Bool;
+messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores;
+messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores;
 
 updates.getState#edd4882a = updates.State;
 updates.getDifference#a041495 pts:int date:int qts:int = updates.Difference;
@@ -917,4 +932,4 @@ channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates;
 channels.updatePinnedMessage#a72ded52 flags:# silent:flags.0?true channel:InputChannel id:int = Updates;
 channels.getAdminedPublicChannels#8d8d82d7 = messages.Chats;
 
-// LAYER 56
+// LAYER 57
diff --git a/Telegram/SourceFiles/mtproto/scheme_auto.cpp b/Telegram/SourceFiles/mtproto/scheme_auto.cpp
index 58618e4b8..a716a5f30 100644
--- a/Telegram/SourceFiles/mtproto/scheme_auto.cpp
+++ b/Telegram/SourceFiles/mtproto/scheme_auto.cpp
@@ -761,6 +761,19 @@ void _serialize_inputMediaDocumentExternal(MTPStringLogger &to, int32 stage, int
 	}
 }
 
+void _serialize_inputMediaGame(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
+	if (stage) {
+		to.add(",\n").addSpaces(lev);
+	} else {
+		to.add("{ inputMediaGame");
+		to.add("\n").addSpaces(lev);
+	}
+	switch (stage) {
+	case 0: to.add("  id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
+	}
+}
+
 void _serialize_inputChatPhotoEmpty(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
 	to.add("{ inputChatPhotoEmpty }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
 }
@@ -1528,6 +1541,19 @@ void _serialize_messageMediaVenue(MTPStringLogger &to, int32 stage, int32 lev, T
 	}
 }
 
+void _serialize_messageMediaGame(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
+	if (stage) {
+		to.add(",\n").addSpaces(lev);
+	} else {
+		to.add("{ messageMediaGame");
+		to.add("\n").addSpaces(lev);
+	}
+	switch (stage) {
+	case 0: to.add("  game: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
+	}
+}
+
 void _serialize_messageActionEmpty(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
 	to.add("{ messageActionEmpty }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
 }
@@ -1671,7 +1697,7 @@ void _serialize_messageActionGameScore(MTPStringLogger &to, int32 stage, int32 l
 		to.add("\n").addSpaces(lev);
 	}
 	switch (stage) {
-	case 0: to.add("  game_id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 0: to.add("  game_id: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
 	case 1: to.add("  score: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
 	default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
 	}
@@ -2999,7 +3025,7 @@ void _serialize_updateBotCallbackQuery(MTPStringLogger &to, int32 stage, int32 l
 	case 4: to.add("  msg_id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
 	case 5: to.add("  chat_instance: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
 	case 6: to.add("  data: "); ++stages.back(); if (flag & MTPDupdateBotCallbackQuery::Flag::f_data) { types.push_back(mtpc_bytes+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
-	case 7: to.add("  game_id: "); ++stages.back(); if (flag & MTPDupdateBotCallbackQuery::Flag::f_game_id) { types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break;
+	case 7: to.add("  game_short_name: "); ++stages.back(); if (flag & MTPDupdateBotCallbackQuery::Flag::f_game_short_name) { types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break;
 	default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
 	}
 }
@@ -3035,7 +3061,7 @@ void _serialize_updateInlineBotCallbackQuery(MTPStringLogger &to, int32 stage, i
 	case 3: to.add("  msg_id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
 	case 4: to.add("  chat_instance: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
 	case 5: to.add("  data: "); ++stages.back(); if (flag & MTPDupdateInlineBotCallbackQuery::Flag::f_data) { types.push_back(mtpc_bytes+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
-	case 6: to.add("  game_id: "); ++stages.back(); if (flag & MTPDupdateInlineBotCallbackQuery::Flag::f_game_id) { types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break;
+	case 6: to.add("  game_short_name: "); ++stages.back(); if (flag & MTPDupdateInlineBotCallbackQuery::Flag::f_game_short_name) { types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break;
 	default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
 	}
 }
@@ -4627,9 +4653,6 @@ void _serialize_keyboardButtonGame(MTPStringLogger &to, int32 stage, int32 lev,
 	}
 	switch (stage) {
 	case 0: to.add("  text: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
-	case 1: to.add("  game_title: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
-	case 2: to.add("  game_id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
-	case 3: to.add("  start_param: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
 	default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
 	}
 }
@@ -5363,6 +5386,19 @@ void _serialize_inputBotInlineMessageMediaContact(MTPStringLogger &to, int32 sta
 	}
 }
 
+void _serialize_inputBotInlineMessageGame(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
+	if (stage) {
+		to.add(",\n").addSpaces(lev);
+	} else {
+		to.add("{ inputBotInlineMessageGame");
+		to.add("\n").addSpaces(lev);
+	}
+	switch (stage) {
+	case 0: to.add("  reply_markup: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
+	}
+}
+
 void _serialize_inputBotInlineResult(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
 	MTPDinputBotInlineResult::Flags flag(iflag);
 
@@ -5427,6 +5463,22 @@ void _serialize_inputBotInlineResultDocument(MTPStringLogger &to, int32 stage, i
 	}
 }
 
+void _serialize_inputBotInlineResultGame(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
+	if (stage) {
+		to.add(",\n").addSpaces(lev);
+	} else {
+		to.add("{ inputBotInlineResultGame");
+		to.add("\n").addSpaces(lev);
+	}
+	switch (stage) {
+	case 0: to.add("  flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_flags); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 1: to.add("  id: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 2: to.add("  short_name: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 3: to.add("  send_message: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
+	}
+}
+
 void _serialize_botInlineMessageMediaAuto(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
 	MTPDbotInlineMessageMediaAuto::Flags flag(iflag);
 
@@ -5996,6 +6048,86 @@ void _serialize_inputStickeredMediaDocument(MTPStringLogger &to, int32 stage, in
 	}
 }
 
+void _serialize_game(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
+	MTPDgame::Flags flag(iflag);
+
+	if (stage) {
+		to.add(",\n").addSpaces(lev);
+	} else {
+		to.add("{ game");
+		to.add("\n").addSpaces(lev);
+	}
+	switch (stage) {
+	case 0: to.add("  flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_flags); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 1: to.add("  id: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 2: to.add("  access_hash: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 3: to.add("  short_name: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 4: to.add("  title: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 5: to.add("  description: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 6: to.add("  url: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 7: to.add("  photo: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 8: to.add("  document: "); ++stages.back(); if (flag & MTPDgame::Flag::f_document) { types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
+	default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
+	}
+}
+
+void _serialize_inputGameID(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
+	if (stage) {
+		to.add(",\n").addSpaces(lev);
+	} else {
+		to.add("{ inputGameID");
+		to.add("\n").addSpaces(lev);
+	}
+	switch (stage) {
+	case 0: to.add("  id: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 1: to.add("  access_hash: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
+	}
+}
+
+void _serialize_inputGameShortName(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
+	if (stage) {
+		to.add(",\n").addSpaces(lev);
+	} else {
+		to.add("{ inputGameShortName");
+		to.add("\n").addSpaces(lev);
+	}
+	switch (stage) {
+	case 0: to.add("  bot_id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 1: to.add("  short_name: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
+	}
+}
+
+void _serialize_highScore(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
+	if (stage) {
+		to.add(",\n").addSpaces(lev);
+	} else {
+		to.add("{ highScore");
+		to.add("\n").addSpaces(lev);
+	}
+	switch (stage) {
+	case 0: to.add("  pos: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 1: to.add("  user_id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 2: to.add("  score: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
+	}
+}
+
+void _serialize_messages_highScores(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
+	if (stage) {
+		to.add(",\n").addSpaces(lev);
+	} else {
+		to.add("{ messages_highScores");
+		to.add("\n").addSpaces(lev);
+	}
+	switch (stage) {
+	case 0: to.add("  scores: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 1: to.add("  users: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
+	}
+}
+
 void _serialize_req_pq(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
 	if (stage) {
 		to.add(",\n").addSpaces(lev);
@@ -6691,8 +6823,7 @@ void _serialize_messages_setInlineGameScore(MTPStringLogger &to, int32 stage, in
 	case 1: to.add("  edit_message: "); ++stages.back(); if (flag & MTPmessages_setInlineGameScore::Flag::f_edit_message) { to.add("YES [ BY BIT 0 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
 	case 2: to.add("  id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
 	case 3: to.add("  user_id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
-	case 4: to.add("  game_id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
-	case 5: to.add("  score: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 4: to.add("  score: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
 	default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
 	}
 }
@@ -7828,8 +7959,7 @@ void _serialize_messages_setGameScore(MTPStringLogger &to, int32 stage, int32 le
 	case 2: to.add("  peer: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
 	case 3: to.add("  id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
 	case 4: to.add("  user_id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
-	case 5: to.add("  game_id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
-	case 6: to.add("  score: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 5: to.add("  score: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
 	default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
 	}
 }
@@ -8387,10 +8517,10 @@ void _serialize_messages_getBotCallbackAnswer(MTPStringLogger &to, int32 stage,
 	}
 	switch (stage) {
 	case 0: to.add("  flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_flags); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
-	case 1: to.add("  peer: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
-	case 2: to.add("  msg_id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
-	case 3: to.add("  data: "); ++stages.back(); if (flag & MTPmessages_getBotCallbackAnswer::Flag::f_data) { types.push_back(mtpc_bytes+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
-	case 4: to.add("  game_id: "); ++stages.back(); if (flag & MTPmessages_getBotCallbackAnswer::Flag::f_game_id) { types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break;
+	case 1: to.add("  game: "); ++stages.back(); if (flag & MTPmessages_getBotCallbackAnswer::Flag::f_game) { to.add("YES [ BY BIT 1 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break;
+	case 2: to.add("  peer: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 3: to.add("  msg_id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 4: to.add("  data: "); ++stages.back(); if (flag & MTPmessages_getBotCallbackAnswer::Flag::f_data) { types.push_back(mtpc_bytes+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
 	default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
 	}
 }
@@ -8469,6 +8599,35 @@ void _serialize_messages_getAttachedStickers(MTPStringLogger &to, int32 stage, i
 	}
 }
 
+void _serialize_messages_getGameHighScores(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
+	if (stage) {
+		to.add(",\n").addSpaces(lev);
+	} else {
+		to.add("{ messages_getGameHighScores");
+		to.add("\n").addSpaces(lev);
+	}
+	switch (stage) {
+	case 0: to.add("  peer: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 1: to.add("  id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 2: to.add("  user_id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
+	}
+}
+
+void _serialize_messages_getInlineGameHighScores(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
+	if (stage) {
+		to.add(",\n").addSpaces(lev);
+	} else {
+		to.add("{ messages_getInlineGameHighScores");
+		to.add("\n").addSpaces(lev);
+	}
+	switch (stage) {
+	case 0: to.add("  id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 1: to.add("  user_id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
+	}
+}
+
 void _serialize_updates_getState(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
 	to.add("{ updates_getState }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
 }
@@ -8739,6 +8898,7 @@ namespace {
 		_serializers.insert(mtpc_inputMediaGifExternal, _serialize_inputMediaGifExternal);
 		_serializers.insert(mtpc_inputMediaPhotoExternal, _serialize_inputMediaPhotoExternal);
 		_serializers.insert(mtpc_inputMediaDocumentExternal, _serialize_inputMediaDocumentExternal);
+		_serializers.insert(mtpc_inputMediaGame, _serialize_inputMediaGame);
 		_serializers.insert(mtpc_inputChatPhotoEmpty, _serialize_inputChatPhotoEmpty);
 		_serializers.insert(mtpc_inputChatUploadedPhoto, _serialize_inputChatUploadedPhoto);
 		_serializers.insert(mtpc_inputChatPhoto, _serialize_inputChatPhoto);
@@ -8800,6 +8960,7 @@ namespace {
 		_serializers.insert(mtpc_messageMediaDocument, _serialize_messageMediaDocument);
 		_serializers.insert(mtpc_messageMediaWebPage, _serialize_messageMediaWebPage);
 		_serializers.insert(mtpc_messageMediaVenue, _serialize_messageMediaVenue);
+		_serializers.insert(mtpc_messageMediaGame, _serialize_messageMediaGame);
 		_serializers.insert(mtpc_messageActionEmpty, _serialize_messageActionEmpty);
 		_serializers.insert(mtpc_messageActionChatCreate, _serialize_messageActionChatCreate);
 		_serializers.insert(mtpc_messageActionChatEditTitle, _serialize_messageActionChatEditTitle);
@@ -9106,9 +9267,11 @@ namespace {
 		_serializers.insert(mtpc_inputBotInlineMessageMediaGeo, _serialize_inputBotInlineMessageMediaGeo);
 		_serializers.insert(mtpc_inputBotInlineMessageMediaVenue, _serialize_inputBotInlineMessageMediaVenue);
 		_serializers.insert(mtpc_inputBotInlineMessageMediaContact, _serialize_inputBotInlineMessageMediaContact);
+		_serializers.insert(mtpc_inputBotInlineMessageGame, _serialize_inputBotInlineMessageGame);
 		_serializers.insert(mtpc_inputBotInlineResult, _serialize_inputBotInlineResult);
 		_serializers.insert(mtpc_inputBotInlineResultPhoto, _serialize_inputBotInlineResultPhoto);
 		_serializers.insert(mtpc_inputBotInlineResultDocument, _serialize_inputBotInlineResultDocument);
+		_serializers.insert(mtpc_inputBotInlineResultGame, _serialize_inputBotInlineResultGame);
 		_serializers.insert(mtpc_botInlineMessageMediaAuto, _serialize_botInlineMessageMediaAuto);
 		_serializers.insert(mtpc_botInlineMessageText, _serialize_botInlineMessageText);
 		_serializers.insert(mtpc_botInlineMessageMediaGeo, _serialize_botInlineMessageMediaGeo);
@@ -9154,6 +9317,11 @@ namespace {
 		_serializers.insert(mtpc_maskCoords, _serialize_maskCoords);
 		_serializers.insert(mtpc_inputStickeredMediaPhoto, _serialize_inputStickeredMediaPhoto);
 		_serializers.insert(mtpc_inputStickeredMediaDocument, _serialize_inputStickeredMediaDocument);
+		_serializers.insert(mtpc_game, _serialize_game);
+		_serializers.insert(mtpc_inputGameID, _serialize_inputGameID);
+		_serializers.insert(mtpc_inputGameShortName, _serialize_inputGameShortName);
+		_serializers.insert(mtpc_highScore, _serialize_highScore);
+		_serializers.insert(mtpc_messages_highScores, _serialize_messages_highScores);
 
 		_serializers.insert(mtpc_req_pq, _serialize_req_pq);
 		_serializers.insert(mtpc_req_DH_params, _serialize_req_DH_params);
@@ -9330,6 +9498,8 @@ namespace {
 		_serializers.insert(mtpc_messages_getRecentStickers, _serialize_messages_getRecentStickers);
 		_serializers.insert(mtpc_messages_getArchivedStickers, _serialize_messages_getArchivedStickers);
 		_serializers.insert(mtpc_messages_getAttachedStickers, _serialize_messages_getAttachedStickers);
+		_serializers.insert(mtpc_messages_getGameHighScores, _serialize_messages_getGameHighScores);
+		_serializers.insert(mtpc_messages_getInlineGameHighScores, _serialize_messages_getInlineGameHighScores);
 		_serializers.insert(mtpc_updates_getState, _serialize_updates_getState);
 		_serializers.insert(mtpc_updates_getDifference, _serialize_updates_getDifference);
 		_serializers.insert(mtpc_updates_getChannelDifference, _serialize_updates_getChannelDifference);
diff --git a/Telegram/SourceFiles/mtproto/scheme_auto.h b/Telegram/SourceFiles/mtproto/scheme_auto.h
index 9f9813388..5767a2ad8 100644
--- a/Telegram/SourceFiles/mtproto/scheme_auto.h
+++ b/Telegram/SourceFiles/mtproto/scheme_auto.h
@@ -30,7 +30,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
 namespace MTP {
 namespace internal {
 
-static constexpr mtpPrime CurrentLayer = 56;
+static constexpr mtpPrime CurrentLayer = 57;
 
 class TypeCreator;
 
@@ -105,6 +105,7 @@ enum {
 	mtpc_inputMediaGifExternal = 0x4843b0fd,
 	mtpc_inputMediaPhotoExternal = 0xb55f4f18,
 	mtpc_inputMediaDocumentExternal = 0xe5e9607c,
+	mtpc_inputMediaGame = 0xd33f43f3,
 	mtpc_inputChatPhotoEmpty = 0x1ca48f57,
 	mtpc_inputChatUploadedPhoto = 0x927c55b4,
 	mtpc_inputChatPhoto = 0x8953ad37,
@@ -166,6 +167,7 @@ enum {
 	mtpc_messageMediaDocument = 0xf3e02ea8,
 	mtpc_messageMediaWebPage = 0xa32dd600,
 	mtpc_messageMediaVenue = 0x7912b71f,
+	mtpc_messageMediaGame = 0xfdb19008,
 	mtpc_messageActionEmpty = 0xb6aef7b0,
 	mtpc_messageActionChatCreate = 0xa6638b9a,
 	mtpc_messageActionChatEditTitle = 0xb5a1ce5a,
@@ -179,7 +181,7 @@ enum {
 	mtpc_messageActionChannelMigrateFrom = 0xb055eaee,
 	mtpc_messageActionPinMessage = 0x94bd38ed,
 	mtpc_messageActionHistoryClear = 0x9fbab604,
-	mtpc_messageActionGameScore = 0x3a14cfa5,
+	mtpc_messageActionGameScore = 0x92a72876,
 	mtpc_dialog = 0x66ffba14,
 	mtpc_photoEmpty = 0x2331b22d,
 	mtpc_photo = 0x9288dd29,
@@ -284,9 +286,9 @@ enum {
 	mtpc_updateBotInlineSend = 0xe48f964,
 	mtpc_updateEditChannelMessage = 0x1b3f4df7,
 	mtpc_updateChannelPinnedMessage = 0x98592475,
-	mtpc_updateBotCallbackQuery = 0x4bf9a8a0,
+	mtpc_updateBotCallbackQuery = 0xe73547e1,
 	mtpc_updateEditMessage = 0xe40370a3,
-	mtpc_updateInlineBotCallbackQuery = 0x4f2f45d1,
+	mtpc_updateInlineBotCallbackQuery = 0xf9d27a5a,
 	mtpc_updateReadChannelOutbox = 0x25d6c9c7,
 	mtpc_updateDraftMessage = 0xee2bb969,
 	mtpc_updateReadFeaturedStickers = 0x571d2742,
@@ -416,7 +418,7 @@ enum {
 	mtpc_keyboardButtonRequestPhone = 0xb16a6c29,
 	mtpc_keyboardButtonRequestGeoLocation = 0xfc796b3f,
 	mtpc_keyboardButtonSwitchInline = 0x568a748,
-	mtpc_keyboardButtonGame = 0x28fc3164,
+	mtpc_keyboardButtonGame = 0x50f41ccf,
 	mtpc_keyboardButtonRow = 0x77608b83,
 	mtpc_replyKeyboardHide = 0xa03e5b85,
 	mtpc_replyKeyboardForceReply = 0xf4108aa0,
@@ -472,9 +474,11 @@ enum {
 	mtpc_inputBotInlineMessageMediaGeo = 0xf4a59de1,
 	mtpc_inputBotInlineMessageMediaVenue = 0xaaafadc8,
 	mtpc_inputBotInlineMessageMediaContact = 0x2daf01a7,
+	mtpc_inputBotInlineMessageGame = 0x3c00f8aa,
 	mtpc_inputBotInlineResult = 0x2cbbe15a,
 	mtpc_inputBotInlineResultPhoto = 0xa8d864a7,
 	mtpc_inputBotInlineResultDocument = 0xfff8fdc4,
+	mtpc_inputBotInlineResultGame = 0xefff34f9,
 	mtpc_botInlineMessageMediaAuto = 0xa74b15b,
 	mtpc_botInlineMessageText = 0x8c7f65e2,
 	mtpc_botInlineMessageMediaGeo = 0x3a8fd8b8,
@@ -520,6 +524,11 @@ enum {
 	mtpc_maskCoords = 0xaed6dbb2,
 	mtpc_inputStickeredMediaPhoto = 0x4a992157,
 	mtpc_inputStickeredMediaDocument = 0x438865b,
+	mtpc_game = 0xb351c590,
+	mtpc_inputGameID = 0x32c3e77,
+	mtpc_inputGameShortName = 0xc331e80a,
+	mtpc_highScore = 0x58fffcd0,
+	mtpc_messages_highScores = 0x9a3bfd99,
 	mtpc_invokeAfterMsg = 0xcb9f372d,
 	mtpc_invokeAfterMsgs = 0x3dc4b4f0,
 	mtpc_initConnection = 0x69796de9,
@@ -643,7 +652,7 @@ enum {
 	mtpc_messages_getMessageEditData = 0xfda68d36,
 	mtpc_messages_editMessage = 0xce91e4ca,
 	mtpc_messages_editInlineBotMessage = 0x130c2c85,
-	mtpc_messages_getBotCallbackAnswer = 0x6c996518,
+	mtpc_messages_getBotCallbackAnswer = 0x810a9fec,
 	mtpc_messages_setBotCallbackAnswer = 0xc927d44b,
 	mtpc_messages_getPeerDialogs = 0x2d9776b9,
 	mtpc_messages_saveDraft = 0xbc39e14b,
@@ -654,10 +663,12 @@ enum {
 	mtpc_messages_saveRecentSticker = 0x392718f8,
 	mtpc_messages_clearRecentStickers = 0x8999602d,
 	mtpc_messages_getArchivedStickers = 0x57f17692,
-	mtpc_messages_setGameScore = 0xdfbc7c1f,
-	mtpc_messages_setInlineGameScore = 0x54f882f1,
 	mtpc_messages_getMaskStickers = 0x65b8c79f,
 	mtpc_messages_getAttachedStickers = 0xcc5b67cc,
+	mtpc_messages_setGameScore = 0x8ef8ecc0,
+	mtpc_messages_setInlineGameScore = 0x15ad9f64,
+	mtpc_messages_getGameHighScores = 0xe822649d,
+	mtpc_messages_getInlineGameHighScores = 0xf635e1b,
 	mtpc_updates_getState = 0xedd4882a,
 	mtpc_updates_getDifference = 0xa041495,
 	mtpc_updates_getChannelDifference = 0xbb32d7c0,
@@ -811,6 +822,7 @@ class MTPDinputMediaVenue;
 class MTPDinputMediaGifExternal;
 class MTPDinputMediaPhotoExternal;
 class MTPDinputMediaDocumentExternal;
+class MTPDinputMediaGame;
 
 class MTPinputChatPhoto;
 class MTPDinputChatUploadedPhoto;
@@ -887,6 +899,7 @@ class MTPDmessageMediaContact;
 class MTPDmessageMediaDocument;
 class MTPDmessageMediaWebPage;
 class MTPDmessageMediaVenue;
+class MTPDmessageMediaGame;
 
 class MTPmessageAction;
 class MTPDmessageActionChatCreate;
@@ -1322,11 +1335,13 @@ class MTPDinputBotInlineMessageText;
 class MTPDinputBotInlineMessageMediaGeo;
 class MTPDinputBotInlineMessageMediaVenue;
 class MTPDinputBotInlineMessageMediaContact;
+class MTPDinputBotInlineMessageGame;
 
 class MTPinputBotInlineResult;
 class MTPDinputBotInlineResult;
 class MTPDinputBotInlineResultPhoto;
 class MTPDinputBotInlineResultDocument;
+class MTPDinputBotInlineResultGame;
 
 class MTPbotInlineMessage;
 class MTPDbotInlineMessageMediaAuto;
@@ -1408,6 +1423,19 @@ class MTPinputStickeredMedia;
 class MTPDinputStickeredMediaPhoto;
 class MTPDinputStickeredMediaDocument;
 
+class MTPgame;
+class MTPDgame;
+
+class MTPinputGame;
+class MTPDinputGameID;
+class MTPDinputGameShortName;
+
+class MTPhighScore;
+class MTPDhighScore;
+
+class MTPmessages_highScores;
+class MTPDmessages_highScores;
+
 
 // Boxed types definitions
 typedef MTPBoxed<MTPresPQ> MTPResPQ;
@@ -1588,6 +1616,10 @@ typedef MTPBoxed<MTPmessages_stickerSetInstallResult> MTPmessages_StickerSetInst
 typedef MTPBoxed<MTPstickerSetCovered> MTPStickerSetCovered;
 typedef MTPBoxed<MTPmaskCoords> MTPMaskCoords;
 typedef MTPBoxed<MTPinputStickeredMedia> MTPInputStickeredMedia;
+typedef MTPBoxed<MTPgame> MTPGame;
+typedef MTPBoxed<MTPinputGame> MTPInputGame;
+typedef MTPBoxed<MTPhighScore> MTPHighScore;
+typedef MTPBoxed<MTPmessages_highScores> MTPmessages_HighScores;
 
 // Type classes definitions
 
@@ -2774,6 +2806,18 @@ public:
 		return *(const MTPDinputMediaDocumentExternal*)data;
 	}
 
+	MTPDinputMediaGame &_inputMediaGame() {
+		if (!data) throw mtpErrorUninitialized();
+		if (_type != mtpc_inputMediaGame) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaGame);
+		split();
+		return *(MTPDinputMediaGame*)data;
+	}
+	const MTPDinputMediaGame &c_inputMediaGame() const {
+		if (!data) throw mtpErrorUninitialized();
+		if (_type != mtpc_inputMediaGame) throw mtpErrorWrongTypeId(_type, mtpc_inputMediaGame);
+		return *(const MTPDinputMediaGame*)data;
+	}
+
 	uint32 innerLength() const;
 	mtpTypeId type() const;
 	void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons);
@@ -2794,6 +2838,7 @@ private:
 	explicit MTPinputMedia(MTPDinputMediaGifExternal *_data);
 	explicit MTPinputMedia(MTPDinputMediaPhotoExternal *_data);
 	explicit MTPinputMedia(MTPDinputMediaDocumentExternal *_data);
+	explicit MTPinputMedia(MTPDinputMediaGame *_data);
 
 	friend class MTP::internal::TypeCreator;
 
@@ -3725,6 +3770,18 @@ public:
 		return *(const MTPDmessageMediaVenue*)data;
 	}
 
+	MTPDmessageMediaGame &_messageMediaGame() {
+		if (!data) throw mtpErrorUninitialized();
+		if (_type != mtpc_messageMediaGame) throw mtpErrorWrongTypeId(_type, mtpc_messageMediaGame);
+		split();
+		return *(MTPDmessageMediaGame*)data;
+	}
+	const MTPDmessageMediaGame &c_messageMediaGame() const {
+		if (!data) throw mtpErrorUninitialized();
+		if (_type != mtpc_messageMediaGame) throw mtpErrorWrongTypeId(_type, mtpc_messageMediaGame);
+		return *(const MTPDmessageMediaGame*)data;
+	}
+
 	uint32 innerLength() const;
 	mtpTypeId type() const;
 	void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons);
@@ -3740,6 +3797,7 @@ private:
 	explicit MTPmessageMedia(MTPDmessageMediaDocument *_data);
 	explicit MTPmessageMedia(MTPDmessageMediaWebPage *_data);
 	explicit MTPmessageMedia(MTPDmessageMediaVenue *_data);
+	explicit MTPmessageMedia(MTPDmessageMediaGame *_data);
 
 	friend class MTP::internal::TypeCreator;
 
@@ -8877,6 +8935,18 @@ public:
 		return *(const MTPDinputBotInlineMessageMediaContact*)data;
 	}
 
+	MTPDinputBotInlineMessageGame &_inputBotInlineMessageGame() {
+		if (!data) throw mtpErrorUninitialized();
+		if (_type != mtpc_inputBotInlineMessageGame) throw mtpErrorWrongTypeId(_type, mtpc_inputBotInlineMessageGame);
+		split();
+		return *(MTPDinputBotInlineMessageGame*)data;
+	}
+	const MTPDinputBotInlineMessageGame &c_inputBotInlineMessageGame() const {
+		if (!data) throw mtpErrorUninitialized();
+		if (_type != mtpc_inputBotInlineMessageGame) throw mtpErrorWrongTypeId(_type, mtpc_inputBotInlineMessageGame);
+		return *(const MTPDinputBotInlineMessageGame*)data;
+	}
+
 	uint32 innerLength() const;
 	mtpTypeId type() const;
 	void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons);
@@ -8891,6 +8961,7 @@ private:
 	explicit MTPinputBotInlineMessage(MTPDinputBotInlineMessageMediaGeo *_data);
 	explicit MTPinputBotInlineMessage(MTPDinputBotInlineMessageMediaVenue *_data);
 	explicit MTPinputBotInlineMessage(MTPDinputBotInlineMessageMediaContact *_data);
+	explicit MTPinputBotInlineMessage(MTPDinputBotInlineMessageGame *_data);
 
 	friend class MTP::internal::TypeCreator;
 
@@ -8942,6 +9013,18 @@ public:
 		return *(const MTPDinputBotInlineResultDocument*)data;
 	}
 
+	MTPDinputBotInlineResultGame &_inputBotInlineResultGame() {
+		if (!data) throw mtpErrorUninitialized();
+		if (_type != mtpc_inputBotInlineResultGame) throw mtpErrorWrongTypeId(_type, mtpc_inputBotInlineResultGame);
+		split();
+		return *(MTPDinputBotInlineResultGame*)data;
+	}
+	const MTPDinputBotInlineResultGame &c_inputBotInlineResultGame() const {
+		if (!data) throw mtpErrorUninitialized();
+		if (_type != mtpc_inputBotInlineResultGame) throw mtpErrorWrongTypeId(_type, mtpc_inputBotInlineResultGame);
+		return *(const MTPDinputBotInlineResultGame*)data;
+	}
+
 	uint32 innerLength() const;
 	mtpTypeId type() const;
 	void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons);
@@ -8954,6 +9037,7 @@ private:
 	explicit MTPinputBotInlineResult(MTPDinputBotInlineResult *_data);
 	explicit MTPinputBotInlineResult(MTPDinputBotInlineResultPhoto *_data);
 	explicit MTPinputBotInlineResult(MTPDinputBotInlineResultDocument *_data);
+	explicit MTPinputBotInlineResult(MTPDinputBotInlineResultGame *_data);
 
 	friend class MTP::internal::TypeCreator;
 
@@ -9881,6 +9965,149 @@ private:
 };
 typedef MTPBoxed<MTPinputStickeredMedia> MTPInputStickeredMedia;
 
+class MTPgame : private mtpDataOwner {
+public:
+	MTPgame();
+	MTPgame(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_game) : mtpDataOwner(0) {
+		read(from, end, cons);
+	}
+
+	MTPDgame &_game() {
+		if (!data) throw mtpErrorUninitialized();
+		split();
+		return *(MTPDgame*)data;
+	}
+	const MTPDgame &c_game() const {
+		if (!data) throw mtpErrorUninitialized();
+		return *(const MTPDgame*)data;
+	}
+
+	uint32 innerLength() const;
+	mtpTypeId type() const;
+	void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_game);
+	void write(mtpBuffer &to) const;
+
+	typedef void ResponseType;
+
+private:
+	explicit MTPgame(MTPDgame *_data);
+
+	friend class MTP::internal::TypeCreator;
+};
+typedef MTPBoxed<MTPgame> MTPGame;
+
+class MTPinputGame : private mtpDataOwner {
+public:
+	MTPinputGame() : mtpDataOwner(0), _type(0) {
+	}
+	MTPinputGame(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) {
+		read(from, end, cons);
+	}
+
+	MTPDinputGameID &_inputGameID() {
+		if (!data) throw mtpErrorUninitialized();
+		if (_type != mtpc_inputGameID) throw mtpErrorWrongTypeId(_type, mtpc_inputGameID);
+		split();
+		return *(MTPDinputGameID*)data;
+	}
+	const MTPDinputGameID &c_inputGameID() const {
+		if (!data) throw mtpErrorUninitialized();
+		if (_type != mtpc_inputGameID) throw mtpErrorWrongTypeId(_type, mtpc_inputGameID);
+		return *(const MTPDinputGameID*)data;
+	}
+
+	MTPDinputGameShortName &_inputGameShortName() {
+		if (!data) throw mtpErrorUninitialized();
+		if (_type != mtpc_inputGameShortName) throw mtpErrorWrongTypeId(_type, mtpc_inputGameShortName);
+		split();
+		return *(MTPDinputGameShortName*)data;
+	}
+	const MTPDinputGameShortName &c_inputGameShortName() const {
+		if (!data) throw mtpErrorUninitialized();
+		if (_type != mtpc_inputGameShortName) throw mtpErrorWrongTypeId(_type, mtpc_inputGameShortName);
+		return *(const MTPDinputGameShortName*)data;
+	}
+
+	uint32 innerLength() const;
+	mtpTypeId type() const;
+	void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons);
+	void write(mtpBuffer &to) const;
+
+	typedef void ResponseType;
+
+private:
+	explicit MTPinputGame(mtpTypeId type);
+	explicit MTPinputGame(MTPDinputGameID *_data);
+	explicit MTPinputGame(MTPDinputGameShortName *_data);
+
+	friend class MTP::internal::TypeCreator;
+
+	mtpTypeId _type;
+};
+typedef MTPBoxed<MTPinputGame> MTPInputGame;
+
+class MTPhighScore : private mtpDataOwner {
+public:
+	MTPhighScore();
+	MTPhighScore(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_highScore) : mtpDataOwner(0) {
+		read(from, end, cons);
+	}
+
+	MTPDhighScore &_highScore() {
+		if (!data) throw mtpErrorUninitialized();
+		split();
+		return *(MTPDhighScore*)data;
+	}
+	const MTPDhighScore &c_highScore() const {
+		if (!data) throw mtpErrorUninitialized();
+		return *(const MTPDhighScore*)data;
+	}
+
+	uint32 innerLength() const;
+	mtpTypeId type() const;
+	void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_highScore);
+	void write(mtpBuffer &to) const;
+
+	typedef void ResponseType;
+
+private:
+	explicit MTPhighScore(MTPDhighScore *_data);
+
+	friend class MTP::internal::TypeCreator;
+};
+typedef MTPBoxed<MTPhighScore> MTPHighScore;
+
+class MTPmessages_highScores : private mtpDataOwner {
+public:
+	MTPmessages_highScores();
+	MTPmessages_highScores(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_highScores) : mtpDataOwner(0) {
+		read(from, end, cons);
+	}
+
+	MTPDmessages_highScores &_messages_highScores() {
+		if (!data) throw mtpErrorUninitialized();
+		split();
+		return *(MTPDmessages_highScores*)data;
+	}
+	const MTPDmessages_highScores &c_messages_highScores() const {
+		if (!data) throw mtpErrorUninitialized();
+		return *(const MTPDmessages_highScores*)data;
+	}
+
+	uint32 innerLength() const;
+	mtpTypeId type() const;
+	void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_highScores);
+	void write(mtpBuffer &to) const;
+
+	typedef void ResponseType;
+
+private:
+	explicit MTPmessages_highScores(MTPDmessages_highScores *_data);
+
+	friend class MTP::internal::TypeCreator;
+};
+typedef MTPBoxed<MTPmessages_highScores> MTPmessages_HighScores;
+
 // Type constructors with data
 
 class MTPDresPQ : public mtpDataImpl<MTPDresPQ> {
@@ -10457,6 +10684,16 @@ public:
 	MTPstring vcaption;
 };
 
+class MTPDinputMediaGame : public mtpDataImpl<MTPDinputMediaGame> {
+public:
+	MTPDinputMediaGame() {
+	}
+	MTPDinputMediaGame(const MTPInputGame &_id) : vid(_id) {
+	}
+
+	MTPInputGame vid;
+};
+
 class MTPDinputChatUploadedPhoto : public mtpDataImpl<MTPDinputChatUploadedPhoto> {
 public:
 	MTPDinputChatUploadedPhoto() {
@@ -11174,6 +11411,16 @@ public:
 	MTPstring vvenue_id;
 };
 
+class MTPDmessageMediaGame : public mtpDataImpl<MTPDmessageMediaGame> {
+public:
+	MTPDmessageMediaGame() {
+	}
+	MTPDmessageMediaGame(const MTPGame &_game) : vgame(_game) {
+	}
+
+	MTPGame vgame;
+};
+
 class MTPDmessageActionChatCreate : public mtpDataImpl<MTPDmessageActionChatCreate> {
 public:
 	MTPDmessageActionChatCreate() {
@@ -11270,10 +11517,10 @@ class MTPDmessageActionGameScore : public mtpDataImpl<MTPDmessageActionGameScore
 public:
 	MTPDmessageActionGameScore() {
 	}
-	MTPDmessageActionGameScore(MTPint _game_id, MTPint _score) : vgame_id(_game_id), vscore(_score) {
+	MTPDmessageActionGameScore(const MTPlong &_game_id, MTPint _score) : vgame_id(_game_id), vscore(_score) {
 	}
 
-	MTPint vgame_id;
+	MTPlong vgame_id;
 	MTPint vscore;
 };
 
@@ -12353,7 +12600,7 @@ class MTPDupdateBotCallbackQuery : public mtpDataImpl<MTPDupdateBotCallbackQuery
 public:
 	enum class Flag : int32 {
 		f_data = (1 << 0),
-		f_game_id = (1 << 1),
+		f_game_short_name = (1 << 1),
 
 		MAX_FIELD = (1 << 1),
 	};
@@ -12361,11 +12608,11 @@ public:
 	friend inline Flags operator~(Flag v) { return QFlag(~static_cast<int32>(v)); }
 
 	bool has_data() const { return vflags.v & Flag::f_data; }
-	bool has_game_id() const { return vflags.v & Flag::f_game_id; }
+	bool has_game_short_name() const { return vflags.v & Flag::f_game_short_name; }
 
 	MTPDupdateBotCallbackQuery() {
 	}
-	MTPDupdateBotCallbackQuery(const MTPflags<MTPDupdateBotCallbackQuery::Flags> &_flags, const MTPlong &_query_id, MTPint _user_id, const MTPPeer &_peer, MTPint _msg_id, const MTPlong &_chat_instance, const MTPbytes &_data, MTPint _game_id) : vflags(_flags), vquery_id(_query_id), vuser_id(_user_id), vpeer(_peer), vmsg_id(_msg_id), vchat_instance(_chat_instance), vdata(_data), vgame_id(_game_id) {
+	MTPDupdateBotCallbackQuery(const MTPflags<MTPDupdateBotCallbackQuery::Flags> &_flags, const MTPlong &_query_id, MTPint _user_id, const MTPPeer &_peer, MTPint _msg_id, const MTPlong &_chat_instance, const MTPbytes &_data, const MTPstring &_game_short_name) : vflags(_flags), vquery_id(_query_id), vuser_id(_user_id), vpeer(_peer), vmsg_id(_msg_id), vchat_instance(_chat_instance), vdata(_data), vgame_short_name(_game_short_name) {
 	}
 
 	MTPflags<MTPDupdateBotCallbackQuery::Flags> vflags;
@@ -12375,7 +12622,7 @@ public:
 	MTPint vmsg_id;
 	MTPlong vchat_instance;
 	MTPbytes vdata;
-	MTPint vgame_id;
+	MTPstring vgame_short_name;
 };
 
 class MTPDupdateEditMessage : public mtpDataImpl<MTPDupdateEditMessage> {
@@ -12394,7 +12641,7 @@ class MTPDupdateInlineBotCallbackQuery : public mtpDataImpl<MTPDupdateInlineBotC
 public:
 	enum class Flag : int32 {
 		f_data = (1 << 0),
-		f_game_id = (1 << 1),
+		f_game_short_name = (1 << 1),
 
 		MAX_FIELD = (1 << 1),
 	};
@@ -12402,11 +12649,11 @@ public:
 	friend inline Flags operator~(Flag v) { return QFlag(~static_cast<int32>(v)); }
 
 	bool has_data() const { return vflags.v & Flag::f_data; }
-	bool has_game_id() const { return vflags.v & Flag::f_game_id; }
+	bool has_game_short_name() const { return vflags.v & Flag::f_game_short_name; }
 
 	MTPDupdateInlineBotCallbackQuery() {
 	}
-	MTPDupdateInlineBotCallbackQuery(const MTPflags<MTPDupdateInlineBotCallbackQuery::Flags> &_flags, const MTPlong &_query_id, MTPint _user_id, const MTPInputBotInlineMessageID &_msg_id, const MTPlong &_chat_instance, const MTPbytes &_data, MTPint _game_id) : vflags(_flags), vquery_id(_query_id), vuser_id(_user_id), vmsg_id(_msg_id), vchat_instance(_chat_instance), vdata(_data), vgame_id(_game_id) {
+	MTPDupdateInlineBotCallbackQuery(const MTPflags<MTPDupdateInlineBotCallbackQuery::Flags> &_flags, const MTPlong &_query_id, MTPint _user_id, const MTPInputBotInlineMessageID &_msg_id, const MTPlong &_chat_instance, const MTPbytes &_data, const MTPstring &_game_short_name) : vflags(_flags), vquery_id(_query_id), vuser_id(_user_id), vmsg_id(_msg_id), vchat_instance(_chat_instance), vdata(_data), vgame_short_name(_game_short_name) {
 	}
 
 	MTPflags<MTPDupdateInlineBotCallbackQuery::Flags> vflags;
@@ -12415,7 +12662,7 @@ public:
 	MTPInputBotInlineMessageID vmsg_id;
 	MTPlong vchat_instance;
 	MTPbytes vdata;
-	MTPint vgame_id;
+	MTPstring vgame_short_name;
 };
 
 class MTPDupdateReadChannelOutbox : public mtpDataImpl<MTPDupdateReadChannelOutbox> {
@@ -13730,13 +13977,10 @@ class MTPDkeyboardButtonGame : public mtpDataImpl<MTPDkeyboardButtonGame> {
 public:
 	MTPDkeyboardButtonGame() {
 	}
-	MTPDkeyboardButtonGame(const MTPstring &_text, const MTPstring &_game_title, MTPint _game_id, const MTPstring &_start_param) : vtext(_text), vgame_title(_game_title), vgame_id(_game_id), vstart_param(_start_param) {
+	MTPDkeyboardButtonGame(const MTPstring &_text) : vtext(_text) {
 	}
 
 	MTPstring vtext;
-	MTPstring vgame_title;
-	MTPint vgame_id;
-	MTPstring vstart_param;
 };
 
 class MTPDkeyboardButtonRow : public mtpDataImpl<MTPDkeyboardButtonRow> {
@@ -14393,6 +14637,16 @@ public:
 	MTPReplyMarkup vreply_markup;
 };
 
+class MTPDinputBotInlineMessageGame : public mtpDataImpl<MTPDinputBotInlineMessageGame> {
+public:
+	MTPDinputBotInlineMessageGame() {
+	}
+	MTPDinputBotInlineMessageGame(const MTPReplyMarkup &_reply_markup) : vreply_markup(_reply_markup) {
+	}
+
+	MTPReplyMarkup vreply_markup;
+};
+
 class MTPDinputBotInlineResult : public mtpDataImpl<MTPDinputBotInlineResult> {
 public:
 	enum class Flag : int32 {
@@ -14482,6 +14736,25 @@ public:
 	MTPInputBotInlineMessage vsend_message;
 };
 
+class MTPDinputBotInlineResultGame : public mtpDataImpl<MTPDinputBotInlineResultGame> {
+public:
+	enum class Flag : int32 {
+		MAX_FIELD = (1 << 0),
+	};
+	Q_DECLARE_FLAGS(Flags, Flag);
+	friend inline Flags operator~(Flag v) { return QFlag(~static_cast<int32>(v)); }
+
+	MTPDinputBotInlineResultGame() {
+	}
+	MTPDinputBotInlineResultGame(const MTPflags<MTPDinputBotInlineResultGame::Flags> &_flags, const MTPstring &_id, const MTPstring &_short_name, const MTPInputBotInlineMessage &_send_message) : vflags(_flags), vid(_id), vshort_name(_short_name), vsend_message(_send_message) {
+	}
+
+	MTPflags<MTPDinputBotInlineResultGame::Flags> vflags;
+	MTPstring vid;
+	MTPstring vshort_name;
+	MTPInputBotInlineMessage vsend_message;
+};
+
 class MTPDbotInlineMessageMediaAuto : public mtpDataImpl<MTPDbotInlineMessageMediaAuto> {
 public:
 	enum class Flag : int32 {
@@ -15036,6 +15309,78 @@ public:
 	MTPInputDocument vid;
 };
 
+class MTPDgame : public mtpDataImpl<MTPDgame> {
+public:
+	enum class Flag : int32 {
+		f_document = (1 << 0),
+		MAX_FIELD = (1 << 0),
+	};
+	Q_DECLARE_FLAGS(Flags, Flag);
+	friend inline Flags operator~(Flag v) { return QFlag(~static_cast<int32>(v)); }
+
+	bool has_document() const { return vflags.v & Flag::f_document; }
+
+	MTPDgame() {
+	}
+	MTPDgame(const MTPflags<MTPDgame::Flags> &_flags, const MTPlong &_id, const MTPlong &_access_hash, const MTPstring &_short_name, const MTPstring &_title, const MTPstring &_description, const MTPstring &_url, const MTPPhoto &_photo, const MTPDocument &_document) : vflags(_flags), vid(_id), vaccess_hash(_access_hash), vshort_name(_short_name), vtitle(_title), vdescription(_description), vurl(_url), vphoto(_photo), vdocument(_document) {
+	}
+
+	MTPflags<MTPDgame::Flags> vflags;
+	MTPlong vid;
+	MTPlong vaccess_hash;
+	MTPstring vshort_name;
+	MTPstring vtitle;
+	MTPstring vdescription;
+	MTPstring vurl;
+	MTPPhoto vphoto;
+	MTPDocument vdocument;
+};
+
+class MTPDinputGameID : public mtpDataImpl<MTPDinputGameID> {
+public:
+	MTPDinputGameID() {
+	}
+	MTPDinputGameID(const MTPlong &_id, const MTPlong &_access_hash) : vid(_id), vaccess_hash(_access_hash) {
+	}
+
+	MTPlong vid;
+	MTPlong vaccess_hash;
+};
+
+class MTPDinputGameShortName : public mtpDataImpl<MTPDinputGameShortName> {
+public:
+	MTPDinputGameShortName() {
+	}
+	MTPDinputGameShortName(const MTPInputUser &_bot_id, const MTPstring &_short_name) : vbot_id(_bot_id), vshort_name(_short_name) {
+	}
+
+	MTPInputUser vbot_id;
+	MTPstring vshort_name;
+};
+
+class MTPDhighScore : public mtpDataImpl<MTPDhighScore> {
+public:
+	MTPDhighScore() {
+	}
+	MTPDhighScore(MTPint _pos, MTPint _user_id, MTPint _score) : vpos(_pos), vuser_id(_user_id), vscore(_score) {
+	}
+
+	MTPint vpos;
+	MTPint vuser_id;
+	MTPint vscore;
+};
+
+class MTPDmessages_highScores : public mtpDataImpl<MTPDmessages_highScores> {
+public:
+	MTPDmessages_highScores() {
+	}
+	MTPDmessages_highScores(const MTPVector<MTPHighScore> &_scores, const MTPVector<MTPUser> &_users) : vscores(_scores), vusers(_users) {
+	}
+
+	MTPVector<MTPHighScore> vscores;
+	MTPVector<MTPUser> vusers;
+};
+
 // RPC methods
 
 class MTPreq_pq { // RPC method 'req_pq'
@@ -20847,33 +21192,32 @@ public:
 class MTPmessages_getBotCallbackAnswer { // RPC method 'messages.getBotCallbackAnswer'
 public:
 	enum class Flag : int32 {
+		f_game = (1 << 1),
 		f_data = (1 << 0),
-		f_game_id = (1 << 1),
 
 		MAX_FIELD = (1 << 1),
 	};
 	Q_DECLARE_FLAGS(Flags, Flag);
 	friend inline Flags operator~(Flag v) { return QFlag(~static_cast<int32>(v)); }
 
+	bool is_game() const { return vflags.v & Flag::f_game; }
 	bool has_data() const { return vflags.v & Flag::f_data; }
-	bool has_game_id() const { return vflags.v & Flag::f_game_id; }
 
 	MTPflags<MTPmessages_getBotCallbackAnswer::Flags> vflags;
 	MTPInputPeer vpeer;
 	MTPint vmsg_id;
 	MTPbytes vdata;
-	MTPint vgame_id;
 
 	MTPmessages_getBotCallbackAnswer() {
 	}
 	MTPmessages_getBotCallbackAnswer(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getBotCallbackAnswer) {
 		read(from, end, cons);
 	}
-	MTPmessages_getBotCallbackAnswer(const MTPflags<MTPmessages_getBotCallbackAnswer::Flags> &_flags, const MTPInputPeer &_peer, MTPint _msg_id, const MTPbytes &_data, MTPint _game_id) : vflags(_flags), vpeer(_peer), vmsg_id(_msg_id), vdata(_data), vgame_id(_game_id) {
+	MTPmessages_getBotCallbackAnswer(const MTPflags<MTPmessages_getBotCallbackAnswer::Flags> &_flags, const MTPInputPeer &_peer, MTPint _msg_id, const MTPbytes &_data) : vflags(_flags), vpeer(_peer), vmsg_id(_msg_id), vdata(_data) {
 	}
 
 	uint32 innerLength() const {
-		return vflags.innerLength() + vpeer.innerLength() + vmsg_id.innerLength() + (has_data() ? vdata.innerLength() : 0) + (has_game_id() ? vgame_id.innerLength() : 0);
+		return vflags.innerLength() + vpeer.innerLength() + vmsg_id.innerLength() + (has_data() ? vdata.innerLength() : 0);
 	}
 	mtpTypeId type() const {
 		return mtpc_messages_getBotCallbackAnswer;
@@ -20883,14 +21227,12 @@ public:
 		vpeer.read(from, end);
 		vmsg_id.read(from, end);
 		if (has_data()) { vdata.read(from, end); } else { vdata = MTPbytes(); }
-		if (has_game_id()) { vgame_id.read(from, end); } else { vgame_id = MTPint(); }
 	}
 	void write(mtpBuffer &to) const {
 		vflags.write(to);
 		vpeer.write(to);
 		vmsg_id.write(to);
 		if (has_data()) vdata.write(to);
-		if (has_game_id()) vgame_id.write(to);
 	}
 
 	typedef MTPmessages_BotCallbackAnswer ResponseType;
@@ -20905,7 +21247,7 @@ public:
 	}
 	MTPmessages_GetBotCallbackAnswer(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed<MTPmessages_getBotCallbackAnswer>(from, end, cons) {
 	}
-	MTPmessages_GetBotCallbackAnswer(const MTPflags<MTPmessages_getBotCallbackAnswer::Flags> &_flags, const MTPInputPeer &_peer, MTPint _msg_id, const MTPbytes &_data, MTPint _game_id) : MTPBoxed<MTPmessages_getBotCallbackAnswer>(MTPmessages_getBotCallbackAnswer(_flags, _peer, _msg_id, _data, _game_id)) {
+	MTPmessages_GetBotCallbackAnswer(const MTPflags<MTPmessages_getBotCallbackAnswer::Flags> &_flags, const MTPInputPeer &_peer, MTPint _msg_id, const MTPbytes &_data) : MTPBoxed<MTPmessages_getBotCallbackAnswer>(MTPmessages_getBotCallbackAnswer(_flags, _peer, _msg_id, _data)) {
 	}
 };
 
@@ -21403,133 +21745,6 @@ public:
 	}
 };
 
-class MTPmessages_setGameScore { // RPC method 'messages.setGameScore'
-public:
-	enum class Flag : int32 {
-		f_edit_message = (1 << 0),
-		MAX_FIELD = (1 << 0),
-	};
-	Q_DECLARE_FLAGS(Flags, Flag);
-	friend inline Flags operator~(Flag v) { return QFlag(~static_cast<int32>(v)); }
-
-	bool is_edit_message() const { return vflags.v & Flag::f_edit_message; }
-
-	MTPflags<MTPmessages_setGameScore::Flags> vflags;
-	MTPInputPeer vpeer;
-	MTPint vid;
-	MTPInputUser vuser_id;
-	MTPint vgame_id;
-	MTPint vscore;
-
-	MTPmessages_setGameScore() {
-	}
-	MTPmessages_setGameScore(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_setGameScore) {
-		read(from, end, cons);
-	}
-	MTPmessages_setGameScore(const MTPflags<MTPmessages_setGameScore::Flags> &_flags, const MTPInputPeer &_peer, MTPint _id, const MTPInputUser &_user_id, MTPint _game_id, MTPint _score) : vflags(_flags), vpeer(_peer), vid(_id), vuser_id(_user_id), vgame_id(_game_id), vscore(_score) {
-	}
-
-	uint32 innerLength() const {
-		return vflags.innerLength() + vpeer.innerLength() + vid.innerLength() + vuser_id.innerLength() + vgame_id.innerLength() + vscore.innerLength();
-	}
-	mtpTypeId type() const {
-		return mtpc_messages_setGameScore;
-	}
-	void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_setGameScore) {
-		vflags.read(from, end);
-		vpeer.read(from, end);
-		vid.read(from, end);
-		vuser_id.read(from, end);
-		vgame_id.read(from, end);
-		vscore.read(from, end);
-	}
-	void write(mtpBuffer &to) const {
-		vflags.write(to);
-		vpeer.write(to);
-		vid.write(to);
-		vuser_id.write(to);
-		vgame_id.write(to);
-		vscore.write(to);
-	}
-
-	typedef MTPUpdates ResponseType;
-};
-Q_DECLARE_OPERATORS_FOR_FLAGS(MTPmessages_setGameScore::Flags)
-
-class MTPmessages_SetGameScore : public MTPBoxed<MTPmessages_setGameScore> {
-public:
-	MTPmessages_SetGameScore() {
-	}
-	MTPmessages_SetGameScore(const MTPmessages_setGameScore &v) : MTPBoxed<MTPmessages_setGameScore>(v) {
-	}
-	MTPmessages_SetGameScore(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed<MTPmessages_setGameScore>(from, end, cons) {
-	}
-	MTPmessages_SetGameScore(const MTPflags<MTPmessages_setGameScore::Flags> &_flags, const MTPInputPeer &_peer, MTPint _id, const MTPInputUser &_user_id, MTPint _game_id, MTPint _score) : MTPBoxed<MTPmessages_setGameScore>(MTPmessages_setGameScore(_flags, _peer, _id, _user_id, _game_id, _score)) {
-	}
-};
-
-class MTPmessages_setInlineGameScore { // RPC method 'messages.setInlineGameScore'
-public:
-	enum class Flag : int32 {
-		f_edit_message = (1 << 0),
-		MAX_FIELD = (1 << 0),
-	};
-	Q_DECLARE_FLAGS(Flags, Flag);
-	friend inline Flags operator~(Flag v) { return QFlag(~static_cast<int32>(v)); }
-
-	bool is_edit_message() const { return vflags.v & Flag::f_edit_message; }
-
-	MTPflags<MTPmessages_setInlineGameScore::Flags> vflags;
-	MTPInputBotInlineMessageID vid;
-	MTPInputUser vuser_id;
-	MTPint vgame_id;
-	MTPint vscore;
-
-	MTPmessages_setInlineGameScore() {
-	}
-	MTPmessages_setInlineGameScore(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_setInlineGameScore) {
-		read(from, end, cons);
-	}
-	MTPmessages_setInlineGameScore(const MTPflags<MTPmessages_setInlineGameScore::Flags> &_flags, const MTPInputBotInlineMessageID &_id, const MTPInputUser &_user_id, MTPint _game_id, MTPint _score) : vflags(_flags), vid(_id), vuser_id(_user_id), vgame_id(_game_id), vscore(_score) {
-	}
-
-	uint32 innerLength() const {
-		return vflags.innerLength() + vid.innerLength() + vuser_id.innerLength() + vgame_id.innerLength() + vscore.innerLength();
-	}
-	mtpTypeId type() const {
-		return mtpc_messages_setInlineGameScore;
-	}
-	void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_setInlineGameScore) {
-		vflags.read(from, end);
-		vid.read(from, end);
-		vuser_id.read(from, end);
-		vgame_id.read(from, end);
-		vscore.read(from, end);
-	}
-	void write(mtpBuffer &to) const {
-		vflags.write(to);
-		vid.write(to);
-		vuser_id.write(to);
-		vgame_id.write(to);
-		vscore.write(to);
-	}
-
-	typedef MTPBool ResponseType;
-};
-Q_DECLARE_OPERATORS_FOR_FLAGS(MTPmessages_setInlineGameScore::Flags)
-
-class MTPmessages_SetInlineGameScore : public MTPBoxed<MTPmessages_setInlineGameScore> {
-public:
-	MTPmessages_SetInlineGameScore() {
-	}
-	MTPmessages_SetInlineGameScore(const MTPmessages_setInlineGameScore &v) : MTPBoxed<MTPmessages_setInlineGameScore>(v) {
-	}
-	MTPmessages_SetInlineGameScore(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed<MTPmessages_setInlineGameScore>(from, end, cons) {
-	}
-	MTPmessages_SetInlineGameScore(const MTPflags<MTPmessages_setInlineGameScore::Flags> &_flags, const MTPInputBotInlineMessageID &_id, const MTPInputUser &_user_id, MTPint _game_id, MTPint _score) : MTPBoxed<MTPmessages_setInlineGameScore>(MTPmessages_setInlineGameScore(_flags, _id, _user_id, _game_id, _score)) {
-	}
-};
-
 class MTPmessages_getMaskStickers { // RPC method 'messages.getMaskStickers'
 public:
 	MTPint vhash;
@@ -21608,6 +21823,214 @@ public:
 	}
 };
 
+class MTPmessages_setGameScore { // RPC method 'messages.setGameScore'
+public:
+	enum class Flag : int32 {
+		f_edit_message = (1 << 0),
+		MAX_FIELD = (1 << 0),
+	};
+	Q_DECLARE_FLAGS(Flags, Flag);
+	friend inline Flags operator~(Flag v) { return QFlag(~static_cast<int32>(v)); }
+
+	bool is_edit_message() const { return vflags.v & Flag::f_edit_message; }
+
+	MTPflags<MTPmessages_setGameScore::Flags> vflags;
+	MTPInputPeer vpeer;
+	MTPint vid;
+	MTPInputUser vuser_id;
+	MTPint vscore;
+
+	MTPmessages_setGameScore() {
+	}
+	MTPmessages_setGameScore(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_setGameScore) {
+		read(from, end, cons);
+	}
+	MTPmessages_setGameScore(const MTPflags<MTPmessages_setGameScore::Flags> &_flags, const MTPInputPeer &_peer, MTPint _id, const MTPInputUser &_user_id, MTPint _score) : vflags(_flags), vpeer(_peer), vid(_id), vuser_id(_user_id), vscore(_score) {
+	}
+
+	uint32 innerLength() const {
+		return vflags.innerLength() + vpeer.innerLength() + vid.innerLength() + vuser_id.innerLength() + vscore.innerLength();
+	}
+	mtpTypeId type() const {
+		return mtpc_messages_setGameScore;
+	}
+	void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_setGameScore) {
+		vflags.read(from, end);
+		vpeer.read(from, end);
+		vid.read(from, end);
+		vuser_id.read(from, end);
+		vscore.read(from, end);
+	}
+	void write(mtpBuffer &to) const {
+		vflags.write(to);
+		vpeer.write(to);
+		vid.write(to);
+		vuser_id.write(to);
+		vscore.write(to);
+	}
+
+	typedef MTPUpdates ResponseType;
+};
+Q_DECLARE_OPERATORS_FOR_FLAGS(MTPmessages_setGameScore::Flags)
+
+class MTPmessages_SetGameScore : public MTPBoxed<MTPmessages_setGameScore> {
+public:
+	MTPmessages_SetGameScore() {
+	}
+	MTPmessages_SetGameScore(const MTPmessages_setGameScore &v) : MTPBoxed<MTPmessages_setGameScore>(v) {
+	}
+	MTPmessages_SetGameScore(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed<MTPmessages_setGameScore>(from, end, cons) {
+	}
+	MTPmessages_SetGameScore(const MTPflags<MTPmessages_setGameScore::Flags> &_flags, const MTPInputPeer &_peer, MTPint _id, const MTPInputUser &_user_id, MTPint _score) : MTPBoxed<MTPmessages_setGameScore>(MTPmessages_setGameScore(_flags, _peer, _id, _user_id, _score)) {
+	}
+};
+
+class MTPmessages_setInlineGameScore { // RPC method 'messages.setInlineGameScore'
+public:
+	enum class Flag : int32 {
+		f_edit_message = (1 << 0),
+		MAX_FIELD = (1 << 0),
+	};
+	Q_DECLARE_FLAGS(Flags, Flag);
+	friend inline Flags operator~(Flag v) { return QFlag(~static_cast<int32>(v)); }
+
+	bool is_edit_message() const { return vflags.v & Flag::f_edit_message; }
+
+	MTPflags<MTPmessages_setInlineGameScore::Flags> vflags;
+	MTPInputBotInlineMessageID vid;
+	MTPInputUser vuser_id;
+	MTPint vscore;
+
+	MTPmessages_setInlineGameScore() {
+	}
+	MTPmessages_setInlineGameScore(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_setInlineGameScore) {
+		read(from, end, cons);
+	}
+	MTPmessages_setInlineGameScore(const MTPflags<MTPmessages_setInlineGameScore::Flags> &_flags, const MTPInputBotInlineMessageID &_id, const MTPInputUser &_user_id, MTPint _score) : vflags(_flags), vid(_id), vuser_id(_user_id), vscore(_score) {
+	}
+
+	uint32 innerLength() const {
+		return vflags.innerLength() + vid.innerLength() + vuser_id.innerLength() + vscore.innerLength();
+	}
+	mtpTypeId type() const {
+		return mtpc_messages_setInlineGameScore;
+	}
+	void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_setInlineGameScore) {
+		vflags.read(from, end);
+		vid.read(from, end);
+		vuser_id.read(from, end);
+		vscore.read(from, end);
+	}
+	void write(mtpBuffer &to) const {
+		vflags.write(to);
+		vid.write(to);
+		vuser_id.write(to);
+		vscore.write(to);
+	}
+
+	typedef MTPBool ResponseType;
+};
+Q_DECLARE_OPERATORS_FOR_FLAGS(MTPmessages_setInlineGameScore::Flags)
+
+class MTPmessages_SetInlineGameScore : public MTPBoxed<MTPmessages_setInlineGameScore> {
+public:
+	MTPmessages_SetInlineGameScore() {
+	}
+	MTPmessages_SetInlineGameScore(const MTPmessages_setInlineGameScore &v) : MTPBoxed<MTPmessages_setInlineGameScore>(v) {
+	}
+	MTPmessages_SetInlineGameScore(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed<MTPmessages_setInlineGameScore>(from, end, cons) {
+	}
+	MTPmessages_SetInlineGameScore(const MTPflags<MTPmessages_setInlineGameScore::Flags> &_flags, const MTPInputBotInlineMessageID &_id, const MTPInputUser &_user_id, MTPint _score) : MTPBoxed<MTPmessages_setInlineGameScore>(MTPmessages_setInlineGameScore(_flags, _id, _user_id, _score)) {
+	}
+};
+
+class MTPmessages_getGameHighScores { // RPC method 'messages.getGameHighScores'
+public:
+	MTPInputPeer vpeer;
+	MTPint vid;
+	MTPInputUser vuser_id;
+
+	MTPmessages_getGameHighScores() {
+	}
+	MTPmessages_getGameHighScores(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getGameHighScores) {
+		read(from, end, cons);
+	}
+	MTPmessages_getGameHighScores(const MTPInputPeer &_peer, MTPint _id, const MTPInputUser &_user_id) : vpeer(_peer), vid(_id), vuser_id(_user_id) {
+	}
+
+	uint32 innerLength() const {
+		return vpeer.innerLength() + vid.innerLength() + vuser_id.innerLength();
+	}
+	mtpTypeId type() const {
+		return mtpc_messages_getGameHighScores;
+	}
+	void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getGameHighScores) {
+		vpeer.read(from, end);
+		vid.read(from, end);
+		vuser_id.read(from, end);
+	}
+	void write(mtpBuffer &to) const {
+		vpeer.write(to);
+		vid.write(to);
+		vuser_id.write(to);
+	}
+
+	typedef MTPmessages_HighScores ResponseType;
+};
+class MTPmessages_GetGameHighScores : public MTPBoxed<MTPmessages_getGameHighScores> {
+public:
+	MTPmessages_GetGameHighScores() {
+	}
+	MTPmessages_GetGameHighScores(const MTPmessages_getGameHighScores &v) : MTPBoxed<MTPmessages_getGameHighScores>(v) {
+	}
+	MTPmessages_GetGameHighScores(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed<MTPmessages_getGameHighScores>(from, end, cons) {
+	}
+	MTPmessages_GetGameHighScores(const MTPInputPeer &_peer, MTPint _id, const MTPInputUser &_user_id) : MTPBoxed<MTPmessages_getGameHighScores>(MTPmessages_getGameHighScores(_peer, _id, _user_id)) {
+	}
+};
+
+class MTPmessages_getInlineGameHighScores { // RPC method 'messages.getInlineGameHighScores'
+public:
+	MTPInputBotInlineMessageID vid;
+	MTPInputUser vuser_id;
+
+	MTPmessages_getInlineGameHighScores() {
+	}
+	MTPmessages_getInlineGameHighScores(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getInlineGameHighScores) {
+		read(from, end, cons);
+	}
+	MTPmessages_getInlineGameHighScores(const MTPInputBotInlineMessageID &_id, const MTPInputUser &_user_id) : vid(_id), vuser_id(_user_id) {
+	}
+
+	uint32 innerLength() const {
+		return vid.innerLength() + vuser_id.innerLength();
+	}
+	mtpTypeId type() const {
+		return mtpc_messages_getInlineGameHighScores;
+	}
+	void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getInlineGameHighScores) {
+		vid.read(from, end);
+		vuser_id.read(from, end);
+	}
+	void write(mtpBuffer &to) const {
+		vid.write(to);
+		vuser_id.write(to);
+	}
+
+	typedef MTPmessages_HighScores ResponseType;
+};
+class MTPmessages_GetInlineGameHighScores : public MTPBoxed<MTPmessages_getInlineGameHighScores> {
+public:
+	MTPmessages_GetInlineGameHighScores() {
+	}
+	MTPmessages_GetInlineGameHighScores(const MTPmessages_getInlineGameHighScores &v) : MTPBoxed<MTPmessages_getInlineGameHighScores>(v) {
+	}
+	MTPmessages_GetInlineGameHighScores(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed<MTPmessages_getInlineGameHighScores>(from, end, cons) {
+	}
+	MTPmessages_GetInlineGameHighScores(const MTPInputBotInlineMessageID &_id, const MTPInputUser &_user_id) : MTPBoxed<MTPmessages_getInlineGameHighScores>(MTPmessages_getInlineGameHighScores(_id, _user_id)) {
+	}
+};
+
 class MTPupdates_getState { // RPC method 'updates.getState'
 public:
 	MTPupdates_getState() {
@@ -23619,6 +24042,9 @@ public:
 	inline static MTPinputMedia new_inputMediaDocumentExternal(const MTPstring &_url, const MTPstring &_caption) {
 		return MTPinputMedia(new MTPDinputMediaDocumentExternal(_url, _caption));
 	}
+	inline static MTPinputMedia new_inputMediaGame(const MTPInputGame &_id) {
+		return MTPinputMedia(new MTPDinputMediaGame(_id));
+	}
 	inline static MTPinputChatPhoto new_inputChatPhotoEmpty() {
 		return MTPinputChatPhoto(mtpc_inputChatPhotoEmpty);
 	}
@@ -23802,6 +24228,9 @@ public:
 	inline static MTPmessageMedia new_messageMediaVenue(const MTPGeoPoint &_geo, const MTPstring &_title, const MTPstring &_address, const MTPstring &_provider, const MTPstring &_venue_id) {
 		return MTPmessageMedia(new MTPDmessageMediaVenue(_geo, _title, _address, _provider, _venue_id));
 	}
+	inline static MTPmessageMedia new_messageMediaGame(const MTPGame &_game) {
+		return MTPmessageMedia(new MTPDmessageMediaGame(_game));
+	}
 	inline static MTPmessageAction new_messageActionEmpty() {
 		return MTPmessageAction(mtpc_messageActionEmpty);
 	}
@@ -23841,7 +24270,7 @@ public:
 	inline static MTPmessageAction new_messageActionHistoryClear() {
 		return MTPmessageAction(mtpc_messageActionHistoryClear);
 	}
-	inline static MTPmessageAction new_messageActionGameScore(MTPint _game_id, MTPint _score) {
+	inline static MTPmessageAction new_messageActionGameScore(const MTPlong &_game_id, MTPint _score) {
 		return MTPmessageAction(new MTPDmessageActionGameScore(_game_id, _score));
 	}
 	inline static MTPdialog new_dialog(const MTPflags<MTPDdialog::Flags> &_flags, const MTPPeer &_peer, MTPint _top_message, MTPint _read_inbox_max_id, MTPint _read_outbox_max_id, MTPint _unread_count, const MTPPeerNotifySettings &_notify_settings, MTPint _pts, const MTPDraftMessage &_draft) {
@@ -24156,14 +24585,14 @@ public:
 	inline static MTPupdate new_updateChannelPinnedMessage(MTPint _channel_id, MTPint _id) {
 		return MTPupdate(new MTPDupdateChannelPinnedMessage(_channel_id, _id));
 	}
-	inline static MTPupdate new_updateBotCallbackQuery(const MTPflags<MTPDupdateBotCallbackQuery::Flags> &_flags, const MTPlong &_query_id, MTPint _user_id, const MTPPeer &_peer, MTPint _msg_id, const MTPlong &_chat_instance, const MTPbytes &_data, MTPint _game_id) {
-		return MTPupdate(new MTPDupdateBotCallbackQuery(_flags, _query_id, _user_id, _peer, _msg_id, _chat_instance, _data, _game_id));
+	inline static MTPupdate new_updateBotCallbackQuery(const MTPflags<MTPDupdateBotCallbackQuery::Flags> &_flags, const MTPlong &_query_id, MTPint _user_id, const MTPPeer &_peer, MTPint _msg_id, const MTPlong &_chat_instance, const MTPbytes &_data, const MTPstring &_game_short_name) {
+		return MTPupdate(new MTPDupdateBotCallbackQuery(_flags, _query_id, _user_id, _peer, _msg_id, _chat_instance, _data, _game_short_name));
 	}
 	inline static MTPupdate new_updateEditMessage(const MTPMessage &_message, MTPint _pts, MTPint _pts_count) {
 		return MTPupdate(new MTPDupdateEditMessage(_message, _pts, _pts_count));
 	}
-	inline static MTPupdate new_updateInlineBotCallbackQuery(const MTPflags<MTPDupdateInlineBotCallbackQuery::Flags> &_flags, const MTPlong &_query_id, MTPint _user_id, const MTPInputBotInlineMessageID &_msg_id, const MTPlong &_chat_instance, const MTPbytes &_data, MTPint _game_id) {
-		return MTPupdate(new MTPDupdateInlineBotCallbackQuery(_flags, _query_id, _user_id, _msg_id, _chat_instance, _data, _game_id));
+	inline static MTPupdate new_updateInlineBotCallbackQuery(const MTPflags<MTPDupdateInlineBotCallbackQuery::Flags> &_flags, const MTPlong &_query_id, MTPint _user_id, const MTPInputBotInlineMessageID &_msg_id, const MTPlong &_chat_instance, const MTPbytes &_data, const MTPstring &_game_short_name) {
+		return MTPupdate(new MTPDupdateInlineBotCallbackQuery(_flags, _query_id, _user_id, _msg_id, _chat_instance, _data, _game_short_name));
 	}
 	inline static MTPupdate new_updateReadChannelOutbox(MTPint _channel_id, MTPint _max_id) {
 		return MTPupdate(new MTPDupdateReadChannelOutbox(_channel_id, _max_id));
@@ -24552,8 +24981,8 @@ public:
 	inline static MTPkeyboardButton new_keyboardButtonSwitchInline(const MTPflags<MTPDkeyboardButtonSwitchInline::Flags> &_flags, const MTPstring &_text, const MTPstring &_query) {
 		return MTPkeyboardButton(new MTPDkeyboardButtonSwitchInline(_flags, _text, _query));
 	}
-	inline static MTPkeyboardButton new_keyboardButtonGame(const MTPstring &_text, const MTPstring &_game_title, MTPint _game_id, const MTPstring &_start_param) {
-		return MTPkeyboardButton(new MTPDkeyboardButtonGame(_text, _game_title, _game_id, _start_param));
+	inline static MTPkeyboardButton new_keyboardButtonGame(const MTPstring &_text) {
+		return MTPkeyboardButton(new MTPDkeyboardButtonGame(_text));
 	}
 	inline static MTPkeyboardButtonRow new_keyboardButtonRow(const MTPVector<MTPKeyboardButton> &_buttons) {
 		return MTPkeyboardButtonRow(new MTPDkeyboardButtonRow(_buttons));
@@ -24720,6 +25149,9 @@ public:
 	inline static MTPinputBotInlineMessage new_inputBotInlineMessageMediaContact(const MTPflags<MTPDinputBotInlineMessageMediaContact::Flags> &_flags, const MTPstring &_phone_number, const MTPstring &_first_name, const MTPstring &_last_name, const MTPReplyMarkup &_reply_markup) {
 		return MTPinputBotInlineMessage(new MTPDinputBotInlineMessageMediaContact(_flags, _phone_number, _first_name, _last_name, _reply_markup));
 	}
+	inline static MTPinputBotInlineMessage new_inputBotInlineMessageGame(const MTPReplyMarkup &_reply_markup) {
+		return MTPinputBotInlineMessage(new MTPDinputBotInlineMessageGame(_reply_markup));
+	}
 	inline static MTPinputBotInlineResult new_inputBotInlineResult(const MTPflags<MTPDinputBotInlineResult::Flags> &_flags, const MTPstring &_id, const MTPstring &_type, const MTPstring &_title, const MTPstring &_description, const MTPstring &_url, const MTPstring &_thumb_url, const MTPstring &_content_url, const MTPstring &_content_type, MTPint _w, MTPint _h, MTPint _duration, const MTPInputBotInlineMessage &_send_message) {
 		return MTPinputBotInlineResult(new MTPDinputBotInlineResult(_flags, _id, _type, _title, _description, _url, _thumb_url, _content_url, _content_type, _w, _h, _duration, _send_message));
 	}
@@ -24729,6 +25161,9 @@ public:
 	inline static MTPinputBotInlineResult new_inputBotInlineResultDocument(const MTPflags<MTPDinputBotInlineResultDocument::Flags> &_flags, const MTPstring &_id, const MTPstring &_type, const MTPstring &_title, const MTPstring &_description, const MTPInputDocument &_document, const MTPInputBotInlineMessage &_send_message) {
 		return MTPinputBotInlineResult(new MTPDinputBotInlineResultDocument(_flags, _id, _type, _title, _description, _document, _send_message));
 	}
+	inline static MTPinputBotInlineResult new_inputBotInlineResultGame(const MTPflags<MTPDinputBotInlineResultGame::Flags> &_flags, const MTPstring &_id, const MTPstring &_short_name, const MTPInputBotInlineMessage &_send_message) {
+		return MTPinputBotInlineResult(new MTPDinputBotInlineResultGame(_flags, _id, _short_name, _send_message));
+	}
 	inline static MTPbotInlineMessage new_botInlineMessageMediaAuto(const MTPflags<MTPDbotInlineMessageMediaAuto::Flags> &_flags, const MTPstring &_caption, const MTPReplyMarkup &_reply_markup) {
 		return MTPbotInlineMessage(new MTPDbotInlineMessageMediaAuto(_flags, _caption, _reply_markup));
 	}
@@ -24864,6 +25299,21 @@ public:
 	inline static MTPinputStickeredMedia new_inputStickeredMediaDocument(const MTPInputDocument &_id) {
 		return MTPinputStickeredMedia(new MTPDinputStickeredMediaDocument(_id));
 	}
+	inline static MTPgame new_game(const MTPflags<MTPDgame::Flags> &_flags, const MTPlong &_id, const MTPlong &_access_hash, const MTPstring &_short_name, const MTPstring &_title, const MTPstring &_description, const MTPstring &_url, const MTPPhoto &_photo, const MTPDocument &_document) {
+		return MTPgame(new MTPDgame(_flags, _id, _access_hash, _short_name, _title, _description, _url, _photo, _document));
+	}
+	inline static MTPinputGame new_inputGameID(const MTPlong &_id, const MTPlong &_access_hash) {
+		return MTPinputGame(new MTPDinputGameID(_id, _access_hash));
+	}
+	inline static MTPinputGame new_inputGameShortName(const MTPInputUser &_bot_id, const MTPstring &_short_name) {
+		return MTPinputGame(new MTPDinputGameShortName(_bot_id, _short_name));
+	}
+	inline static MTPhighScore new_highScore(MTPint _pos, MTPint _user_id, MTPint _score) {
+		return MTPhighScore(new MTPDhighScore(_pos, _user_id, _score));
+	}
+	inline static MTPmessages_highScores new_messages_highScores(const MTPVector<MTPHighScore> &_scores, const MTPVector<MTPUser> &_users) {
+		return MTPmessages_highScores(new MTPDmessages_highScores(_scores, _users));
+	}
 	};
 
 } // namespace internal
@@ -26155,6 +26605,10 @@ inline uint32 MTPinputMedia::innerLength() const {
 			const MTPDinputMediaDocumentExternal &v(c_inputMediaDocumentExternal());
 			return v.vurl.innerLength() + v.vcaption.innerLength();
 		}
+		case mtpc_inputMediaGame: {
+			const MTPDinputMediaGame &v(c_inputMediaGame());
+			return v.vid.innerLength();
+		}
 	}
 	return 0;
 }
@@ -26246,6 +26700,11 @@ inline void MTPinputMedia::read(const mtpPrime *&from, const mtpPrime *end, mtpT
 			v.vurl.read(from, end);
 			v.vcaption.read(from, end);
 		} break;
+		case mtpc_inputMediaGame: _type = cons; {
+			if (!data) setData(new MTPDinputMediaGame());
+			MTPDinputMediaGame &v(_inputMediaGame());
+			v.vid.read(from, end);
+		} break;
 		default: throw mtpErrorUnexpected(cons, "MTPinputMedia");
 	}
 }
@@ -26320,6 +26779,10 @@ inline void MTPinputMedia::write(mtpBuffer &to) const {
 			v.vurl.write(to);
 			v.vcaption.write(to);
 		} break;
+		case mtpc_inputMediaGame: {
+			const MTPDinputMediaGame &v(c_inputMediaGame());
+			v.vid.write(to);
+		} break;
 	}
 }
 inline MTPinputMedia::MTPinputMedia(mtpTypeId type) : mtpDataOwner(0), _type(type) {
@@ -26336,6 +26799,7 @@ inline MTPinputMedia::MTPinputMedia(mtpTypeId type) : mtpDataOwner(0), _type(typ
 		case mtpc_inputMediaGifExternal: setData(new MTPDinputMediaGifExternal()); break;
 		case mtpc_inputMediaPhotoExternal: setData(new MTPDinputMediaPhotoExternal()); break;
 		case mtpc_inputMediaDocumentExternal: setData(new MTPDinputMediaDocumentExternal()); break;
+		case mtpc_inputMediaGame: setData(new MTPDinputMediaGame()); break;
 		default: throw mtpErrorBadTypeId(type, "MTPinputMedia");
 	}
 }
@@ -26361,6 +26825,8 @@ inline MTPinputMedia::MTPinputMedia(MTPDinputMediaPhotoExternal *_data) : mtpDat
 }
 inline MTPinputMedia::MTPinputMedia(MTPDinputMediaDocumentExternal *_data) : mtpDataOwner(_data), _type(mtpc_inputMediaDocumentExternal) {
 }
+inline MTPinputMedia::MTPinputMedia(MTPDinputMediaGame *_data) : mtpDataOwner(_data), _type(mtpc_inputMediaGame) {
+}
 inline MTPinputMedia MTP_inputMediaEmpty() {
 	return MTP::internal::TypeCreator::new_inputMediaEmpty();
 }
@@ -26400,6 +26866,9 @@ inline MTPinputMedia MTP_inputMediaPhotoExternal(const MTPstring &_url, const MT
 inline MTPinputMedia MTP_inputMediaDocumentExternal(const MTPstring &_url, const MTPstring &_caption) {
 	return MTP::internal::TypeCreator::new_inputMediaDocumentExternal(_url, _caption);
 }
+inline MTPinputMedia MTP_inputMediaGame(const MTPInputGame &_id) {
+	return MTP::internal::TypeCreator::new_inputMediaGame(_id);
+}
 
 inline uint32 MTPinputChatPhoto::innerLength() const {
 	switch (_type) {
@@ -27769,6 +28238,10 @@ inline uint32 MTPmessageMedia::innerLength() const {
 			const MTPDmessageMediaVenue &v(c_messageMediaVenue());
 			return v.vgeo.innerLength() + v.vtitle.innerLength() + v.vaddress.innerLength() + v.vprovider.innerLength() + v.vvenue_id.innerLength();
 		}
+		case mtpc_messageMediaGame: {
+			const MTPDmessageMediaGame &v(c_messageMediaGame());
+			return v.vgame.innerLength();
+		}
 	}
 	return 0;
 }
@@ -27820,6 +28293,11 @@ inline void MTPmessageMedia::read(const mtpPrime *&from, const mtpPrime *end, mt
 			v.vprovider.read(from, end);
 			v.vvenue_id.read(from, end);
 		} break;
+		case mtpc_messageMediaGame: _type = cons; {
+			if (!data) setData(new MTPDmessageMediaGame());
+			MTPDmessageMediaGame &v(_messageMediaGame());
+			v.vgame.read(from, end);
+		} break;
 		default: throw mtpErrorUnexpected(cons, "MTPmessageMedia");
 	}
 }
@@ -27858,6 +28336,10 @@ inline void MTPmessageMedia::write(mtpBuffer &to) const {
 			v.vprovider.write(to);
 			v.vvenue_id.write(to);
 		} break;
+		case mtpc_messageMediaGame: {
+			const MTPDmessageMediaGame &v(c_messageMediaGame());
+			v.vgame.write(to);
+		} break;
 	}
 }
 inline MTPmessageMedia::MTPmessageMedia(mtpTypeId type) : mtpDataOwner(0), _type(type) {
@@ -27870,6 +28352,7 @@ inline MTPmessageMedia::MTPmessageMedia(mtpTypeId type) : mtpDataOwner(0), _type
 		case mtpc_messageMediaDocument: setData(new MTPDmessageMediaDocument()); break;
 		case mtpc_messageMediaWebPage: setData(new MTPDmessageMediaWebPage()); break;
 		case mtpc_messageMediaVenue: setData(new MTPDmessageMediaVenue()); break;
+		case mtpc_messageMediaGame: setData(new MTPDmessageMediaGame()); break;
 		default: throw mtpErrorBadTypeId(type, "MTPmessageMedia");
 	}
 }
@@ -27885,6 +28368,8 @@ inline MTPmessageMedia::MTPmessageMedia(MTPDmessageMediaWebPage *_data) : mtpDat
 }
 inline MTPmessageMedia::MTPmessageMedia(MTPDmessageMediaVenue *_data) : mtpDataOwner(_data), _type(mtpc_messageMediaVenue) {
 }
+inline MTPmessageMedia::MTPmessageMedia(MTPDmessageMediaGame *_data) : mtpDataOwner(_data), _type(mtpc_messageMediaGame) {
+}
 inline MTPmessageMedia MTP_messageMediaEmpty() {
 	return MTP::internal::TypeCreator::new_messageMediaEmpty();
 }
@@ -27909,6 +28394,9 @@ inline MTPmessageMedia MTP_messageMediaWebPage(const MTPWebPage &_webpage) {
 inline MTPmessageMedia MTP_messageMediaVenue(const MTPGeoPoint &_geo, const MTPstring &_title, const MTPstring &_address, const MTPstring &_provider, const MTPstring &_venue_id) {
 	return MTP::internal::TypeCreator::new_messageMediaVenue(_geo, _title, _address, _provider, _venue_id);
 }
+inline MTPmessageMedia MTP_messageMediaGame(const MTPGame &_game) {
+	return MTP::internal::TypeCreator::new_messageMediaGame(_game);
+}
 
 inline uint32 MTPmessageAction::innerLength() const {
 	switch (_type) {
@@ -28147,7 +28635,7 @@ inline MTPmessageAction MTP_messageActionPinMessage() {
 inline MTPmessageAction MTP_messageActionHistoryClear() {
 	return MTP::internal::TypeCreator::new_messageActionHistoryClear();
 }
-inline MTPmessageAction MTP_messageActionGameScore(MTPint _game_id, MTPint _score) {
+inline MTPmessageAction MTP_messageActionGameScore(const MTPlong &_game_id, MTPint _score) {
 	return MTP::internal::TypeCreator::new_messageActionGameScore(_game_id, _score);
 }
 
@@ -29760,7 +30248,7 @@ inline uint32 MTPupdate::innerLength() const {
 		}
 		case mtpc_updateBotCallbackQuery: {
 			const MTPDupdateBotCallbackQuery &v(c_updateBotCallbackQuery());
-			return v.vflags.innerLength() + v.vquery_id.innerLength() + v.vuser_id.innerLength() + v.vpeer.innerLength() + v.vmsg_id.innerLength() + v.vchat_instance.innerLength() + (v.has_data() ? v.vdata.innerLength() : 0) + (v.has_game_id() ? v.vgame_id.innerLength() : 0);
+			return v.vflags.innerLength() + v.vquery_id.innerLength() + v.vuser_id.innerLength() + v.vpeer.innerLength() + v.vmsg_id.innerLength() + v.vchat_instance.innerLength() + (v.has_data() ? v.vdata.innerLength() : 0) + (v.has_game_short_name() ? v.vgame_short_name.innerLength() : 0);
 		}
 		case mtpc_updateEditMessage: {
 			const MTPDupdateEditMessage &v(c_updateEditMessage());
@@ -29768,7 +30256,7 @@ inline uint32 MTPupdate::innerLength() const {
 		}
 		case mtpc_updateInlineBotCallbackQuery: {
 			const MTPDupdateInlineBotCallbackQuery &v(c_updateInlineBotCallbackQuery());
-			return v.vflags.innerLength() + v.vquery_id.innerLength() + v.vuser_id.innerLength() + v.vmsg_id.innerLength() + v.vchat_instance.innerLength() + (v.has_data() ? v.vdata.innerLength() : 0) + (v.has_game_id() ? v.vgame_id.innerLength() : 0);
+			return v.vflags.innerLength() + v.vquery_id.innerLength() + v.vuser_id.innerLength() + v.vmsg_id.innerLength() + v.vchat_instance.innerLength() + (v.has_data() ? v.vdata.innerLength() : 0) + (v.has_game_short_name() ? v.vgame_short_name.innerLength() : 0);
 		}
 		case mtpc_updateReadChannelOutbox: {
 			const MTPDupdateReadChannelOutbox &v(c_updateReadChannelOutbox());
@@ -30087,7 +30575,7 @@ inline void MTPupdate::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeI
 			v.vmsg_id.read(from, end);
 			v.vchat_instance.read(from, end);
 			if (v.has_data()) { v.vdata.read(from, end); } else { v.vdata = MTPbytes(); }
-			if (v.has_game_id()) { v.vgame_id.read(from, end); } else { v.vgame_id = MTPint(); }
+			if (v.has_game_short_name()) { v.vgame_short_name.read(from, end); } else { v.vgame_short_name = MTPstring(); }
 		} break;
 		case mtpc_updateEditMessage: _type = cons; {
 			if (!data) setData(new MTPDupdateEditMessage());
@@ -30105,7 +30593,7 @@ inline void MTPupdate::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeI
 			v.vmsg_id.read(from, end);
 			v.vchat_instance.read(from, end);
 			if (v.has_data()) { v.vdata.read(from, end); } else { v.vdata = MTPbytes(); }
-			if (v.has_game_id()) { v.vgame_id.read(from, end); } else { v.vgame_id = MTPint(); }
+			if (v.has_game_short_name()) { v.vgame_short_name.read(from, end); } else { v.vgame_short_name = MTPstring(); }
 		} break;
 		case mtpc_updateReadChannelOutbox: _type = cons; {
 			if (!data) setData(new MTPDupdateReadChannelOutbox());
@@ -30382,7 +30870,7 @@ inline void MTPupdate::write(mtpBuffer &to) const {
 			v.vmsg_id.write(to);
 			v.vchat_instance.write(to);
 			if (v.has_data()) v.vdata.write(to);
-			if (v.has_game_id()) v.vgame_id.write(to);
+			if (v.has_game_short_name()) v.vgame_short_name.write(to);
 		} break;
 		case mtpc_updateEditMessage: {
 			const MTPDupdateEditMessage &v(c_updateEditMessage());
@@ -30398,7 +30886,7 @@ inline void MTPupdate::write(mtpBuffer &to) const {
 			v.vmsg_id.write(to);
 			v.vchat_instance.write(to);
 			if (v.has_data()) v.vdata.write(to);
-			if (v.has_game_id()) v.vgame_id.write(to);
+			if (v.has_game_short_name()) v.vgame_short_name.write(to);
 		} break;
 		case mtpc_updateReadChannelOutbox: {
 			const MTPDupdateReadChannelOutbox &v(c_updateReadChannelOutbox());
@@ -30701,15 +31189,15 @@ inline MTPupdate MTP_updateChannelPinnedMessage(MTPint _channel_id, MTPint _id)
 	return MTP::internal::TypeCreator::new_updateChannelPinnedMessage(_channel_id, _id);
 }
 Q_DECLARE_OPERATORS_FOR_FLAGS(MTPDupdateBotCallbackQuery::Flags)
-inline MTPupdate MTP_updateBotCallbackQuery(const MTPflags<MTPDupdateBotCallbackQuery::Flags> &_flags, const MTPlong &_query_id, MTPint _user_id, const MTPPeer &_peer, MTPint _msg_id, const MTPlong &_chat_instance, const MTPbytes &_data, MTPint _game_id) {
-	return MTP::internal::TypeCreator::new_updateBotCallbackQuery(_flags, _query_id, _user_id, _peer, _msg_id, _chat_instance, _data, _game_id);
+inline MTPupdate MTP_updateBotCallbackQuery(const MTPflags<MTPDupdateBotCallbackQuery::Flags> &_flags, const MTPlong &_query_id, MTPint _user_id, const MTPPeer &_peer, MTPint _msg_id, const MTPlong &_chat_instance, const MTPbytes &_data, const MTPstring &_game_short_name) {
+	return MTP::internal::TypeCreator::new_updateBotCallbackQuery(_flags, _query_id, _user_id, _peer, _msg_id, _chat_instance, _data, _game_short_name);
 }
 inline MTPupdate MTP_updateEditMessage(const MTPMessage &_message, MTPint _pts, MTPint _pts_count) {
 	return MTP::internal::TypeCreator::new_updateEditMessage(_message, _pts, _pts_count);
 }
 Q_DECLARE_OPERATORS_FOR_FLAGS(MTPDupdateInlineBotCallbackQuery::Flags)
-inline MTPupdate MTP_updateInlineBotCallbackQuery(const MTPflags<MTPDupdateInlineBotCallbackQuery::Flags> &_flags, const MTPlong &_query_id, MTPint _user_id, const MTPInputBotInlineMessageID &_msg_id, const MTPlong &_chat_instance, const MTPbytes &_data, MTPint _game_id) {
-	return MTP::internal::TypeCreator::new_updateInlineBotCallbackQuery(_flags, _query_id, _user_id, _msg_id, _chat_instance, _data, _game_id);
+inline MTPupdate MTP_updateInlineBotCallbackQuery(const MTPflags<MTPDupdateInlineBotCallbackQuery::Flags> &_flags, const MTPlong &_query_id, MTPint _user_id, const MTPInputBotInlineMessageID &_msg_id, const MTPlong &_chat_instance, const MTPbytes &_data, const MTPstring &_game_short_name) {
+	return MTP::internal::TypeCreator::new_updateInlineBotCallbackQuery(_flags, _query_id, _user_id, _msg_id, _chat_instance, _data, _game_short_name);
 }
 inline MTPupdate MTP_updateReadChannelOutbox(MTPint _channel_id, MTPint _max_id) {
 	return MTP::internal::TypeCreator::new_updateReadChannelOutbox(_channel_id, _max_id);
@@ -33764,7 +34252,7 @@ inline uint32 MTPkeyboardButton::innerLength() const {
 		}
 		case mtpc_keyboardButtonGame: {
 			const MTPDkeyboardButtonGame &v(c_keyboardButtonGame());
-			return v.vtext.innerLength() + v.vgame_title.innerLength() + v.vgame_id.innerLength() + v.vstart_param.innerLength();
+			return v.vtext.innerLength();
 		}
 	}
 	return 0;
@@ -33814,9 +34302,6 @@ inline void MTPkeyboardButton::read(const mtpPrime *&from, const mtpPrime *end,
 			if (!data) setData(new MTPDkeyboardButtonGame());
 			MTPDkeyboardButtonGame &v(_keyboardButtonGame());
 			v.vtext.read(from, end);
-			v.vgame_title.read(from, end);
-			v.vgame_id.read(from, end);
-			v.vstart_param.read(from, end);
 		} break;
 		default: throw mtpErrorUnexpected(cons, "MTPkeyboardButton");
 	}
@@ -33854,9 +34339,6 @@ inline void MTPkeyboardButton::write(mtpBuffer &to) const {
 		case mtpc_keyboardButtonGame: {
 			const MTPDkeyboardButtonGame &v(c_keyboardButtonGame());
 			v.vtext.write(to);
-			v.vgame_title.write(to);
-			v.vgame_id.write(to);
-			v.vstart_param.write(to);
 		} break;
 	}
 }
@@ -33905,8 +34387,8 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(MTPDkeyboardButtonSwitchInline::Flags)
 inline MTPkeyboardButton MTP_keyboardButtonSwitchInline(const MTPflags<MTPDkeyboardButtonSwitchInline::Flags> &_flags, const MTPstring &_text, const MTPstring &_query) {
 	return MTP::internal::TypeCreator::new_keyboardButtonSwitchInline(_flags, _text, _query);
 }
-inline MTPkeyboardButton MTP_keyboardButtonGame(const MTPstring &_text, const MTPstring &_game_title, MTPint _game_id, const MTPstring &_start_param) {
-	return MTP::internal::TypeCreator::new_keyboardButtonGame(_text, _game_title, _game_id, _start_param);
+inline MTPkeyboardButton MTP_keyboardButtonGame(const MTPstring &_text) {
+	return MTP::internal::TypeCreator::new_keyboardButtonGame(_text);
 }
 
 inline MTPkeyboardButtonRow::MTPkeyboardButtonRow() : mtpDataOwner(new MTPDkeyboardButtonRow()) {
@@ -35177,6 +35659,10 @@ inline uint32 MTPinputBotInlineMessage::innerLength() const {
 			const MTPDinputBotInlineMessageMediaContact &v(c_inputBotInlineMessageMediaContact());
 			return v.vflags.innerLength() + v.vphone_number.innerLength() + v.vfirst_name.innerLength() + v.vlast_name.innerLength() + (v.has_reply_markup() ? v.vreply_markup.innerLength() : 0);
 		}
+		case mtpc_inputBotInlineMessageGame: {
+			const MTPDinputBotInlineMessageGame &v(c_inputBotInlineMessageGame());
+			return v.vreply_markup.innerLength();
+		}
 	}
 	return 0;
 }
@@ -35229,6 +35715,11 @@ inline void MTPinputBotInlineMessage::read(const mtpPrime *&from, const mtpPrime
 			v.vlast_name.read(from, end);
 			if (v.has_reply_markup()) { v.vreply_markup.read(from, end); } else { v.vreply_markup = MTPReplyMarkup(); }
 		} break;
+		case mtpc_inputBotInlineMessageGame: _type = cons; {
+			if (!data) setData(new MTPDinputBotInlineMessageGame());
+			MTPDinputBotInlineMessageGame &v(_inputBotInlineMessageGame());
+			v.vreply_markup.read(from, end);
+		} break;
 		default: throw mtpErrorUnexpected(cons, "MTPinputBotInlineMessage");
 	}
 }
@@ -35271,6 +35762,10 @@ inline void MTPinputBotInlineMessage::write(mtpBuffer &to) const {
 			v.vlast_name.write(to);
 			if (v.has_reply_markup()) v.vreply_markup.write(to);
 		} break;
+		case mtpc_inputBotInlineMessageGame: {
+			const MTPDinputBotInlineMessageGame &v(c_inputBotInlineMessageGame());
+			v.vreply_markup.write(to);
+		} break;
 	}
 }
 inline MTPinputBotInlineMessage::MTPinputBotInlineMessage(mtpTypeId type) : mtpDataOwner(0), _type(type) {
@@ -35280,6 +35775,7 @@ inline MTPinputBotInlineMessage::MTPinputBotInlineMessage(mtpTypeId type) : mtpD
 		case mtpc_inputBotInlineMessageMediaGeo: setData(new MTPDinputBotInlineMessageMediaGeo()); break;
 		case mtpc_inputBotInlineMessageMediaVenue: setData(new MTPDinputBotInlineMessageMediaVenue()); break;
 		case mtpc_inputBotInlineMessageMediaContact: setData(new MTPDinputBotInlineMessageMediaContact()); break;
+		case mtpc_inputBotInlineMessageGame: setData(new MTPDinputBotInlineMessageGame()); break;
 		default: throw mtpErrorBadTypeId(type, "MTPinputBotInlineMessage");
 	}
 }
@@ -35293,6 +35789,8 @@ inline MTPinputBotInlineMessage::MTPinputBotInlineMessage(MTPDinputBotInlineMess
 }
 inline MTPinputBotInlineMessage::MTPinputBotInlineMessage(MTPDinputBotInlineMessageMediaContact *_data) : mtpDataOwner(_data), _type(mtpc_inputBotInlineMessageMediaContact) {
 }
+inline MTPinputBotInlineMessage::MTPinputBotInlineMessage(MTPDinputBotInlineMessageGame *_data) : mtpDataOwner(_data), _type(mtpc_inputBotInlineMessageGame) {
+}
 Q_DECLARE_OPERATORS_FOR_FLAGS(MTPDinputBotInlineMessageMediaAuto::Flags)
 inline MTPinputBotInlineMessage MTP_inputBotInlineMessageMediaAuto(const MTPflags<MTPDinputBotInlineMessageMediaAuto::Flags> &_flags, const MTPstring &_caption, const MTPReplyMarkup &_reply_markup) {
 	return MTP::internal::TypeCreator::new_inputBotInlineMessageMediaAuto(_flags, _caption, _reply_markup);
@@ -35313,6 +35811,9 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(MTPDinputBotInlineMessageMediaContact::Flags)
 inline MTPinputBotInlineMessage MTP_inputBotInlineMessageMediaContact(const MTPflags<MTPDinputBotInlineMessageMediaContact::Flags> &_flags, const MTPstring &_phone_number, const MTPstring &_first_name, const MTPstring &_last_name, const MTPReplyMarkup &_reply_markup) {
 	return MTP::internal::TypeCreator::new_inputBotInlineMessageMediaContact(_flags, _phone_number, _first_name, _last_name, _reply_markup);
 }
+inline MTPinputBotInlineMessage MTP_inputBotInlineMessageGame(const MTPReplyMarkup &_reply_markup) {
+	return MTP::internal::TypeCreator::new_inputBotInlineMessageGame(_reply_markup);
+}
 
 inline uint32 MTPinputBotInlineResult::innerLength() const {
 	switch (_type) {
@@ -35328,6 +35829,10 @@ inline uint32 MTPinputBotInlineResult::innerLength() const {
 			const MTPDinputBotInlineResultDocument &v(c_inputBotInlineResultDocument());
 			return v.vflags.innerLength() + v.vid.innerLength() + v.vtype.innerLength() + (v.has_title() ? v.vtitle.innerLength() : 0) + (v.has_description() ? v.vdescription.innerLength() : 0) + v.vdocument.innerLength() + v.vsend_message.innerLength();
 		}
+		case mtpc_inputBotInlineResultGame: {
+			const MTPDinputBotInlineResultGame &v(c_inputBotInlineResultGame());
+			return v.vflags.innerLength() + v.vid.innerLength() + v.vshort_name.innerLength() + v.vsend_message.innerLength();
+		}
 	}
 	return 0;
 }
@@ -35374,6 +35879,14 @@ inline void MTPinputBotInlineResult::read(const mtpPrime *&from, const mtpPrime
 			v.vdocument.read(from, end);
 			v.vsend_message.read(from, end);
 		} break;
+		case mtpc_inputBotInlineResultGame: _type = cons; {
+			if (!data) setData(new MTPDinputBotInlineResultGame());
+			MTPDinputBotInlineResultGame &v(_inputBotInlineResultGame());
+			v.vflags.read(from, end);
+			v.vid.read(from, end);
+			v.vshort_name.read(from, end);
+			v.vsend_message.read(from, end);
+		} break;
 		default: throw mtpErrorUnexpected(cons, "MTPinputBotInlineResult");
 	}
 }
@@ -35412,6 +35925,13 @@ inline void MTPinputBotInlineResult::write(mtpBuffer &to) const {
 			v.vdocument.write(to);
 			v.vsend_message.write(to);
 		} break;
+		case mtpc_inputBotInlineResultGame: {
+			const MTPDinputBotInlineResultGame &v(c_inputBotInlineResultGame());
+			v.vflags.write(to);
+			v.vid.write(to);
+			v.vshort_name.write(to);
+			v.vsend_message.write(to);
+		} break;
 	}
 }
 inline MTPinputBotInlineResult::MTPinputBotInlineResult(mtpTypeId type) : mtpDataOwner(0), _type(type) {
@@ -35419,6 +35939,7 @@ inline MTPinputBotInlineResult::MTPinputBotInlineResult(mtpTypeId type) : mtpDat
 		case mtpc_inputBotInlineResult: setData(new MTPDinputBotInlineResult()); break;
 		case mtpc_inputBotInlineResultPhoto: setData(new MTPDinputBotInlineResultPhoto()); break;
 		case mtpc_inputBotInlineResultDocument: setData(new MTPDinputBotInlineResultDocument()); break;
+		case mtpc_inputBotInlineResultGame: setData(new MTPDinputBotInlineResultGame()); break;
 		default: throw mtpErrorBadTypeId(type, "MTPinputBotInlineResult");
 	}
 }
@@ -35428,6 +35949,8 @@ inline MTPinputBotInlineResult::MTPinputBotInlineResult(MTPDinputBotInlineResult
 }
 inline MTPinputBotInlineResult::MTPinputBotInlineResult(MTPDinputBotInlineResultDocument *_data) : mtpDataOwner(_data), _type(mtpc_inputBotInlineResultDocument) {
 }
+inline MTPinputBotInlineResult::MTPinputBotInlineResult(MTPDinputBotInlineResultGame *_data) : mtpDataOwner(_data), _type(mtpc_inputBotInlineResultGame) {
+}
 Q_DECLARE_OPERATORS_FOR_FLAGS(MTPDinputBotInlineResult::Flags)
 inline MTPinputBotInlineResult MTP_inputBotInlineResult(const MTPflags<MTPDinputBotInlineResult::Flags> &_flags, const MTPstring &_id, const MTPstring &_type, const MTPstring &_title, const MTPstring &_description, const MTPstring &_url, const MTPstring &_thumb_url, const MTPstring &_content_url, const MTPstring &_content_type, MTPint _w, MTPint _h, MTPint _duration, const MTPInputBotInlineMessage &_send_message) {
 	return MTP::internal::TypeCreator::new_inputBotInlineResult(_flags, _id, _type, _title, _description, _url, _thumb_url, _content_url, _content_type, _w, _h, _duration, _send_message);
@@ -35439,6 +35962,9 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(MTPDinputBotInlineResultDocument::Flags)
 inline MTPinputBotInlineResult MTP_inputBotInlineResultDocument(const MTPflags<MTPDinputBotInlineResultDocument::Flags> &_flags, const MTPstring &_id, const MTPstring &_type, const MTPstring &_title, const MTPstring &_description, const MTPInputDocument &_document, const MTPInputBotInlineMessage &_send_message) {
 	return MTP::internal::TypeCreator::new_inputBotInlineResultDocument(_flags, _id, _type, _title, _description, _document, _send_message);
 }
+inline MTPinputBotInlineResult MTP_inputBotInlineResultGame(const MTPflags<MTPDinputBotInlineResultGame::Flags> &_flags, const MTPstring &_id, const MTPstring &_short_name, const MTPInputBotInlineMessage &_send_message) {
+	return MTP::internal::TypeCreator::new_inputBotInlineResultGame(_flags, _id, _short_name, _send_message);
+}
 
 inline uint32 MTPbotInlineMessage::innerLength() const {
 	switch (_type) {
@@ -36652,6 +37178,177 @@ inline MTPinputStickeredMedia MTP_inputStickeredMediaPhoto(const MTPInputPhoto &
 inline MTPinputStickeredMedia MTP_inputStickeredMediaDocument(const MTPInputDocument &_id) {
 	return MTP::internal::TypeCreator::new_inputStickeredMediaDocument(_id);
 }
+
+inline MTPgame::MTPgame() : mtpDataOwner(new MTPDgame()) {
+}
+
+inline uint32 MTPgame::innerLength() const {
+	const MTPDgame &v(c_game());
+	return v.vflags.innerLength() + v.vid.innerLength() + v.vaccess_hash.innerLength() + v.vshort_name.innerLength() + v.vtitle.innerLength() + v.vdescription.innerLength() + v.vurl.innerLength() + v.vphoto.innerLength() + (v.has_document() ? v.vdocument.innerLength() : 0);
+}
+inline mtpTypeId MTPgame::type() const {
+	return mtpc_game;
+}
+inline void MTPgame::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) {
+	if (cons != mtpc_game) throw mtpErrorUnexpected(cons, "MTPgame");
+
+	if (!data) setData(new MTPDgame());
+	MTPDgame &v(_game());
+	v.vflags.read(from, end);
+	v.vid.read(from, end);
+	v.vaccess_hash.read(from, end);
+	v.vshort_name.read(from, end);
+	v.vtitle.read(from, end);
+	v.vdescription.read(from, end);
+	v.vurl.read(from, end);
+	v.vphoto.read(from, end);
+	if (v.has_document()) { v.vdocument.read(from, end); } else { v.vdocument = MTPDocument(); }
+}
+inline void MTPgame::write(mtpBuffer &to) const {
+	const MTPDgame &v(c_game());
+	v.vflags.write(to);
+	v.vid.write(to);
+	v.vaccess_hash.write(to);
+	v.vshort_name.write(to);
+	v.vtitle.write(to);
+	v.vdescription.write(to);
+	v.vurl.write(to);
+	v.vphoto.write(to);
+	if (v.has_document()) v.vdocument.write(to);
+}
+inline MTPgame::MTPgame(MTPDgame *_data) : mtpDataOwner(_data) {
+}
+Q_DECLARE_OPERATORS_FOR_FLAGS(MTPDgame::Flags)
+inline MTPgame MTP_game(const MTPflags<MTPDgame::Flags> &_flags, const MTPlong &_id, const MTPlong &_access_hash, const MTPstring &_short_name, const MTPstring &_title, const MTPstring &_description, const MTPstring &_url, const MTPPhoto &_photo, const MTPDocument &_document) {
+	return MTP::internal::TypeCreator::new_game(_flags, _id, _access_hash, _short_name, _title, _description, _url, _photo, _document);
+}
+
+inline uint32 MTPinputGame::innerLength() const {
+	switch (_type) {
+		case mtpc_inputGameID: {
+			const MTPDinputGameID &v(c_inputGameID());
+			return v.vid.innerLength() + v.vaccess_hash.innerLength();
+		}
+		case mtpc_inputGameShortName: {
+			const MTPDinputGameShortName &v(c_inputGameShortName());
+			return v.vbot_id.innerLength() + v.vshort_name.innerLength();
+		}
+	}
+	return 0;
+}
+inline mtpTypeId MTPinputGame::type() const {
+	if (!_type) throw mtpErrorUninitialized();
+	return _type;
+}
+inline void MTPinputGame::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) {
+	if (cons != _type) setData(0);
+	switch (cons) {
+		case mtpc_inputGameID: _type = cons; {
+			if (!data) setData(new MTPDinputGameID());
+			MTPDinputGameID &v(_inputGameID());
+			v.vid.read(from, end);
+			v.vaccess_hash.read(from, end);
+		} break;
+		case mtpc_inputGameShortName: _type = cons; {
+			if (!data) setData(new MTPDinputGameShortName());
+			MTPDinputGameShortName &v(_inputGameShortName());
+			v.vbot_id.read(from, end);
+			v.vshort_name.read(from, end);
+		} break;
+		default: throw mtpErrorUnexpected(cons, "MTPinputGame");
+	}
+}
+inline void MTPinputGame::write(mtpBuffer &to) const {
+	switch (_type) {
+		case mtpc_inputGameID: {
+			const MTPDinputGameID &v(c_inputGameID());
+			v.vid.write(to);
+			v.vaccess_hash.write(to);
+		} break;
+		case mtpc_inputGameShortName: {
+			const MTPDinputGameShortName &v(c_inputGameShortName());
+			v.vbot_id.write(to);
+			v.vshort_name.write(to);
+		} break;
+	}
+}
+inline MTPinputGame::MTPinputGame(mtpTypeId type) : mtpDataOwner(0), _type(type) {
+	switch (type) {
+		case mtpc_inputGameID: setData(new MTPDinputGameID()); break;
+		case mtpc_inputGameShortName: setData(new MTPDinputGameShortName()); break;
+		default: throw mtpErrorBadTypeId(type, "MTPinputGame");
+	}
+}
+inline MTPinputGame::MTPinputGame(MTPDinputGameID *_data) : mtpDataOwner(_data), _type(mtpc_inputGameID) {
+}
+inline MTPinputGame::MTPinputGame(MTPDinputGameShortName *_data) : mtpDataOwner(_data), _type(mtpc_inputGameShortName) {
+}
+inline MTPinputGame MTP_inputGameID(const MTPlong &_id, const MTPlong &_access_hash) {
+	return MTP::internal::TypeCreator::new_inputGameID(_id, _access_hash);
+}
+inline MTPinputGame MTP_inputGameShortName(const MTPInputUser &_bot_id, const MTPstring &_short_name) {
+	return MTP::internal::TypeCreator::new_inputGameShortName(_bot_id, _short_name);
+}
+
+inline MTPhighScore::MTPhighScore() : mtpDataOwner(new MTPDhighScore()) {
+}
+
+inline uint32 MTPhighScore::innerLength() const {
+	const MTPDhighScore &v(c_highScore());
+	return v.vpos.innerLength() + v.vuser_id.innerLength() + v.vscore.innerLength();
+}
+inline mtpTypeId MTPhighScore::type() const {
+	return mtpc_highScore;
+}
+inline void MTPhighScore::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) {
+	if (cons != mtpc_highScore) throw mtpErrorUnexpected(cons, "MTPhighScore");
+
+	if (!data) setData(new MTPDhighScore());
+	MTPDhighScore &v(_highScore());
+	v.vpos.read(from, end);
+	v.vuser_id.read(from, end);
+	v.vscore.read(from, end);
+}
+inline void MTPhighScore::write(mtpBuffer &to) const {
+	const MTPDhighScore &v(c_highScore());
+	v.vpos.write(to);
+	v.vuser_id.write(to);
+	v.vscore.write(to);
+}
+inline MTPhighScore::MTPhighScore(MTPDhighScore *_data) : mtpDataOwner(_data) {
+}
+inline MTPhighScore MTP_highScore(MTPint _pos, MTPint _user_id, MTPint _score) {
+	return MTP::internal::TypeCreator::new_highScore(_pos, _user_id, _score);
+}
+
+inline MTPmessages_highScores::MTPmessages_highScores() : mtpDataOwner(new MTPDmessages_highScores()) {
+}
+
+inline uint32 MTPmessages_highScores::innerLength() const {
+	const MTPDmessages_highScores &v(c_messages_highScores());
+	return v.vscores.innerLength() + v.vusers.innerLength();
+}
+inline mtpTypeId MTPmessages_highScores::type() const {
+	return mtpc_messages_highScores;
+}
+inline void MTPmessages_highScores::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) {
+	if (cons != mtpc_messages_highScores) throw mtpErrorUnexpected(cons, "MTPmessages_highScores");
+
+	if (!data) setData(new MTPDmessages_highScores());
+	MTPDmessages_highScores &v(_messages_highScores());
+	v.vscores.read(from, end);
+	v.vusers.read(from, end);
+}
+inline void MTPmessages_highScores::write(mtpBuffer &to) const {
+	const MTPDmessages_highScores &v(c_messages_highScores());
+	v.vscores.write(to);
+	v.vusers.write(to);
+}
+inline MTPmessages_highScores::MTPmessages_highScores(MTPDmessages_highScores *_data) : mtpDataOwner(_data) {
+}
+inline MTPmessages_highScores MTP_messages_highScores(const MTPVector<MTPHighScore> &_scores, const MTPVector<MTPUser> &_users) {
+	return MTP::internal::TypeCreator::new_messages_highScores(_scores, _users);
+}
 inline MTPDmessage::Flags mtpCastFlags(MTPDmessageService::Flags flags) { return MTPDmessage::Flags(QFlag(flags)); }
 inline MTPDmessage::Flags mtpCastFlags(MTPflags<MTPDmessageService::Flags> flags) { return mtpCastFlags(flags.v); }
 inline MTPDmessage::Flags mtpCastFlags(MTPDupdateShortMessage::Flags flags) { return MTPDmessage::Flags(QFlag(flags)); }
diff --git a/Telegram/SourceFiles/overview/overview_layout.cpp b/Telegram/SourceFiles/overview/overview_layout.cpp
index 752546ac0..dad19fdab 100644
--- a/Telegram/SourceFiles/overview/overview_layout.cpp
+++ b/Telegram/SourceFiles/overview/overview_layout.cpp
@@ -888,13 +888,13 @@ bool Document::updateStatusText() const {
 Link::Link(HistoryMedia *media, HistoryItem *parent) : ItemBase(parent) {
 	AddComponents(Info::Bit());
 
-	const auto textWithEntities = _parent->originalText();
+	auto textWithEntities = _parent->originalText();
 	QString mainUrl;
 
 	auto text = textWithEntities.text;
 	auto &entities = textWithEntities.entities;
 	int32 from = 0, till = text.size(), lnk = entities.size();
-	for_const (const auto &entity, entities) {
+	for_const (auto &entity, entities) {
 		auto type = entity.type();
 		if (type != EntityInTextUrl && type != EntityInTextCustomUrl && type != EntityInTextEmail) {
 			continue;
@@ -908,7 +908,7 @@ Link::Link(HistoryMedia *media, HistoryItem *parent) : ItemBase(parent) {
 	}
 	while (lnk > 0 && till > from) {
 		--lnk;
-		const auto &entity = entities.at(lnk);
+		auto &entity = entities.at(lnk);
 		auto type = entity.type();
 		if (type != EntityInTextUrl && type != EntityInTextCustomUrl && type != EntityInTextEmail) {
 			++lnk;
diff --git a/Telegram/SourceFiles/pspecific_win.cpp b/Telegram/SourceFiles/pspecific_win.cpp
index 636db7fdd..61fcde541 100644
--- a/Telegram/SourceFiles/pspecific_win.cpp
+++ b/Telegram/SourceFiles/pspecific_win.cpp
@@ -29,6 +29,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
 #include "lang.h"
 #include "application.h"
 #include "mainwidget.h"
+#include "history/history_location_manager.h"
 
 #include "localstorage.h"
 
diff --git a/Telegram/SourceFiles/structs.cpp b/Telegram/SourceFiles/structs.cpp
index 82a986752..e0b2d2201 100644
--- a/Telegram/SourceFiles/structs.cpp
+++ b/Telegram/SourceFiles/structs.cpp
@@ -717,11 +717,11 @@ void PhotoData::cancel() {
 }
 
 void PhotoData::notifyLayoutChanged() const {
-	const PhotoItems &items(App::photoItems());
-	PhotoItems::const_iterator i = items.constFind(const_cast<PhotoData*>(this));
+	auto &items = App::photoItems();
+	auto i = items.constFind(const_cast<PhotoData*>(this));
 	if (i != items.cend()) {
-		for (HistoryItemsMap::const_iterator j = i->cbegin(), e = i->cend(); j != e; ++j) {
-			Notify::historyItemLayoutChanged(j.key());
+		for_const (auto item, i.value()) {
+			Notify::historyItemLayoutChanged(item);
 		}
 	}
 }
@@ -1441,12 +1441,9 @@ void DocumentData::cancel() {
 }
 
 void DocumentData::notifyLayoutChanged() const {
-	const DocumentItems &items(App::documentItems());
-	DocumentItems::const_iterator i = items.constFind(const_cast<DocumentData*>(this));
-	if (i != items.cend()) {
-		for (HistoryItemsMap::const_iterator j = i->cbegin(), e = i->cend(); j != e; ++j) {
-			Notify::historyItemLayoutChanged(j.key());
-		}
+	auto &items = App::documentItems();
+	for (auto item : items.value(const_cast<DocumentData*>(this))) {
+		Notify::historyItemLayoutChanged(item);
 	}
 
 	if (auto items = InlineBots::Layout::documentItems()) {
@@ -1632,6 +1629,16 @@ WebPageData::WebPageData(const WebPageId &id, WebPageType type, const QString &u
 , pendingTill(pendingTill) {
 }
 
+GameData::GameData(const GameId &id, const uint64 &accessHash, const QString &shortName, const QString &title, const QString &description, const QString &url, PhotoData *photo, DocumentData *document) : id(id)
+, accessHash(accessHash)
+, shortName(shortName)
+, title(title)
+, description(description)
+, url(url)
+, photo(photo)
+, document(document) {
+}
+
 void PeerOpenClickHandler::onClickImpl() const {
 	if (App::main()) {
 		if (peer() && peer()->isChannel() && App::main()->historyPeer() != peer()) {
@@ -1651,18 +1658,3 @@ MsgId clientMsgId() {
 	Q_ASSERT(currentClientMsgId < EndClientMsgId);
 	return currentClientMsgId++;
 }
-
-QString LocationClickHandler::copyToClipboardContextItemText() const {
-	return lang(lng_context_copy_link);
-}
-
-void LocationClickHandler::onClick(Qt::MouseButton button) const {
-	if (!psLaunchMaps(_coords)) {
-		QDesktopServices::openUrl(_text);
-	}
-}
-
-void LocationClickHandler::setup() {
-	QString latlon(qsl("%1,%2").arg(_coords.lat).arg(_coords.lon));
-	_text = qsl("https://maps.google.com/maps?q=") + latlon + qsl("&ll=") + latlon + qsl("&z=16");
-}
diff --git a/Telegram/SourceFiles/structs.h b/Telegram/SourceFiles/structs.h
index 85c8bd028..acabe1021 100644
--- a/Telegram/SourceFiles/structs.h
+++ b/Telegram/SourceFiles/structs.h
@@ -137,11 +137,12 @@ inline TimeId dateFromMessage(const MTPmessage &msg) {
 	return 0;
 }
 
-typedef uint64 PhotoId;
-typedef uint64 VideoId;
-typedef uint64 AudioId;
-typedef uint64 DocumentId;
-typedef uint64 WebPageId;
+using PhotoId = uint64;
+using VideoId = uint64;
+using AudioId = uint64;
+using DocumentId = uint64;
+using WebPageId = uint64;
+using GameId = uint64;
 static const WebPageId CancelledWebPageId = 0xFFFFFFFFFFFFFFFFULL;
 
 inline bool operator==(const FullMsgId &a, const FullMsgId &b) {
@@ -1351,6 +1352,7 @@ struct WebPageData {
 	WebPageData(const WebPageId &id, WebPageType type = WebPageArticle, const QString &url = QString(), const QString &displayUrl = QString(), const QString &siteName = QString(), const QString &title = QString(), const QString &description = QString(), DocumentData *doc = nullptr, PhotoData *photo = nullptr, int32 duration = 0, const QString &author = QString(), int32 pendingTill = -1);
 
 	void forget() {
+		if (document) document->forget();
 		if (photo) photo->forget();
 	}
 
@@ -1365,6 +1367,22 @@ struct WebPageData {
 
 };
 
+struct GameData {
+	GameData(const GameId &id, const uint64 &accessHash = 0, const QString &shortName = QString(), const QString &title = QString(), const QString &description = QString(), const QString &url = QString(), PhotoData *photo = nullptr, DocumentData *doc = nullptr);
+
+	void forget() {
+		if (document) document->forget();
+		if (photo) photo->forget();
+	}
+
+	GameId id;
+	uint64 accessHash;
+	QString shortName, title, description, url;
+	PhotoData *photo;
+	DocumentData *document;
+
+};
+
 QString saveFileName(const QString &title, const QString &filter, const QString &prefix, QString name, bool savingAs, const QDir &dir = QDir());
 MsgId clientMsgId();
 
@@ -1397,70 +1415,3 @@ struct MessageCursor {
 inline bool operator==(const MessageCursor &a, const MessageCursor &b) {
 	return (a.position == b.position) && (a.anchor == b.anchor) && (a.scroll == b.scroll);
 }
-
-struct LocationCoords {
-	LocationCoords() : lat(0), lon(0) {
-	}
-	LocationCoords(float64 lat, float64 lon) : lat(lat), lon(lon) {
-	}
-	LocationCoords(const MTPDgeoPoint &point) : lat(point.vlat.v), lon(point.vlong.v) {
-	}
-	float64 lat, lon;
-};
-inline bool operator==(const LocationCoords &a, const LocationCoords &b) {
-	return (a.lat == b.lat) && (a.lon == b.lon);
-}
-inline bool operator<(const LocationCoords &a, const LocationCoords &b) {
-	return (a.lat < b.lat) || ((a.lat == b.lat) && (a.lon < b.lon));
-}
-inline uint qHash(const LocationCoords &t, uint seed = 0) {
-#ifndef OS_MAC_OLD
-	return qHash(QtPrivate::QHashCombine().operator()(qHash(t.lat), t.lon), seed);
-#else // OS_MAC_OLD
-	uint h1 = qHash(t.lat, seed);
-	uint h2 = qHash(t.lon, seed);
-	return ((h1 << 16) | (h1 >> 16)) ^ h2 ^ seed;
-#endif // OS_MAC_OLD
-}
-
-struct LocationData {
-	LocationData(const LocationCoords &coords) : coords(coords), loading(false) {
-	}
-
-	LocationCoords coords;
-	ImagePtr thumb;
-	bool loading;
-
-	void load();
-};
-
-class LocationClickHandler : public ClickHandler {
-public:
-	LocationClickHandler(const LocationCoords &coords) : _coords(coords) {
-		setup();
-	}
-
-	void onClick(Qt::MouseButton button) const override;
-
-	QString tooltip() const override {
-		return QString();
-	}
-
-	QString dragText() const override {
-		return _text;
-	}
-
-	void copyToClipboard() const override {
-		if (!_text.isEmpty()) {
-			QApplication::clipboard()->setText(_text);
-		}
-	}
-	QString copyToClipboardContextItemText() const override;
-
-private:
-
-	void setup();
-	LocationCoords _coords;
-	QString _text;
-
-};
diff --git a/Telegram/gyp/Telegram.gyp b/Telegram/gyp/Telegram.gyp
index 88212978f..b18821687 100644
--- a/Telegram/gyp/Telegram.gyp
+++ b/Telegram/gyp/Telegram.gyp
@@ -218,6 +218,8 @@
       '<(src_loc)/dialogs/dialogs_row.h',
       '<(src_loc)/history/field_autocomplete.cpp',
       '<(src_loc)/history/field_autocomplete.h',
+      '<(src_loc)/history/history_location_manager.cpp',
+      '<(src_loc)/history/history_location_manager.h',
       '<(src_loc)/history/history_service_layout.cpp',
       '<(src_loc)/history/history_service_layout.h',
       '<(src_loc)/inline_bots/inline_bot_layout_internal.cpp',