Browse Source

Merge pull request #4225 from godric3/map-editor-town-configuration-improvements

Map editor town configuration improvements (buildings, spells, events)
Ivan Savenko 1 year ago
parent
commit
ffb8efc415

+ 1 - 1
lib/gameState/CGameState.cpp

@@ -875,7 +875,7 @@ void CGameState::initTowns()
 		}
 		//init spells
 		vti->spells.resize(GameConstants::SPELL_LEVELS);
-
+		vti->possibleSpells -= SpellID::PRESET;
 		for(ui32 z=0; z<vti->obligatorySpells.size();z++)
 		{
 			const auto * s = vti->obligatorySpells[z].toSpell();

+ 6 - 0
lib/mapObjects/CGTownInstance.cpp

@@ -1221,6 +1221,12 @@ void CGTownInstance::serializeJsonOptions(JsonSerializeFormat & handler)
 		handler.serializeIdArray( "possibleSpells", possibleSpells);
 		handler.serializeIdArray( "obligatorySpells", obligatorySpells);
 	}
+
+	{
+		auto eventsHandler = handler.enterArray("events");
+		eventsHandler.syncSize(events, JsonNode::JsonType::DATA_VECTOR);
+		eventsHandler.serializeStruct(events);
+	}
 }
 
 FactionID CGTownInstance::getFaction() const

+ 1 - 1
lib/mapObjects/CGTownInstance.h

@@ -65,7 +65,7 @@ public:
 	std::vector<CGTownBuilding*> bonusingBuildings;
 	std::vector<SpellID> possibleSpells, obligatorySpells;
 	std::vector<std::vector<SpellID> > spells; //spells[level] -> vector of spells, first will be available in guild
-	std::list<CCastleEvent> events;
+	std::vector<CCastleEvent> events;
 	std::pair<si32, si32> bonusValue;//var to store town bonuses (rampart = resources from mystic pond);
 
 	//////////////////////////////////////////////////////////////////////////

+ 1 - 1
lib/networkPacks/PacksForClient.h

@@ -561,7 +561,7 @@ struct DLL_LINKAGE UpdateMapEvents : public CPackForClient
 struct DLL_LINKAGE UpdateCastleEvents : public CPackForClient
 {
 	ObjectInstanceID town;
-	std::list<CCastleEvent> events;
+	std::vector<CCastleEvent> events;
 
 	void applyGs(CGameState * gs) const;
 	void visitTyped(ICPackVisitor & visitor) override;

+ 10 - 0
mapeditor/CMakeLists.txt

@@ -29,6 +29,9 @@ set(editor_SRCS
 		validator.cpp
 		inspector/inspector.cpp
 		inspector/townbuildingswidget.cpp
+		inspector/towneventdialog.cpp
+		inspector/towneventswidget.cpp
+		inspector/townspellswidget.cpp
 		inspector/armywidget.cpp
 		inspector/messagewidget.cpp
 		inspector/rewardswidget.cpp
@@ -70,6 +73,9 @@ set(editor_HEADERS
 		validator.h
 		inspector/inspector.h
 		inspector/townbuildingswidget.h
+		inspector/towneventdialog.h
+		inspector/towneventswidget.h
+		inspector/townspellswidget.h
 		inspector/armywidget.h
 		inspector/messagewidget.h
 		inspector/rewardswidget.h
@@ -79,6 +85,7 @@ set(editor_HEADERS
 		inspector/PickObjectDelegate.h
 		inspector/portraitwidget.h
 		resourceExtractor/ResourceConverter.h
+		mapeditorroles.h
 )
 
 set(editor_FORMS
@@ -98,6 +105,9 @@ set(editor_FORMS
 		playerparams.ui
 		validator.ui
 		inspector/townbuildingswidget.ui
+		inspector/towneventdialog.ui
+		inspector/towneventswidget.ui
+		inspector/townspellswidget.ui
 		inspector/armywidget.ui
 		inspector/messagewidget.ui
 		inspector/rewardswidget.ui

+ 4 - 0
mapeditor/inspector/inspector.cpp

@@ -21,6 +21,8 @@
 #include "../lib/constants/StringConstants.h"
 
 #include "townbuildingswidget.h"
+#include "towneventswidget.h"
+#include "townspellswidget.h"
 #include "armywidget.h"
 #include "messagewidget.h"
 #include "rewardswidget.h"
@@ -342,6 +344,8 @@ void Inspector::updateProperties(CGTownInstance * o)
 	
 	auto * delegate = new TownBuildingsDelegate(*o);
 	addProperty("Buildings", PropertyEditorPlaceholder(), delegate, false);
+	addProperty("Spells", PropertyEditorPlaceholder(), new TownSpellsDelegate(*o), false);
+	addProperty("Events", PropertyEditorPlaceholder(), new TownEventsDelegate(*o, controller), false);
 }
 
 void Inspector::updateProperties(CGArtifact * o)

+ 144 - 43
mapeditor/inspector/townbuildingswidget.cpp

@@ -10,6 +10,7 @@
 #include "StdInc.h"
 #include "townbuildingswidget.h"
 #include "ui_townbuildingswidget.h"
+#include "mapeditorroles.h"
 #include "../lib/entities/building/CBuilding.h"
 #include "../lib/entities/faction/CTownHandler.h"
 #include "../lib/texts/CGeneralTextHandler.h"
@@ -68,6 +69,56 @@ std::string defaultBuildingIdConversion(BuildingID bId)
 	}
 }
 
+QStandardItem * getBuildingParentFromTreeModel(const CBuilding * building, const QStandardItemModel & model)
+{
+	QStandardItem * parent = nullptr;
+	std::vector<QModelIndex> stack(1);
+	do
+	{
+		auto pindex = stack.back();
+		stack.pop_back();
+		auto rowCount = model.rowCount(pindex);
+		for (int i = 0; i < rowCount; ++i)
+		{
+			QModelIndex index = model.index(i, 0, pindex);
+			if (building->upgrade.getNum() == model.itemFromIndex(index)->data(MapEditorRoles::BuildingIDRole).toInt())
+			{
+				parent = model.itemFromIndex(index);
+				break;
+			}
+			if (model.hasChildren(index))
+				stack.push_back(index);
+		}
+	} while(!parent && !stack.empty());
+	return parent;
+}
+
+QVariantList getBuildingVariantsFromModel(const QStandardItemModel & model, int modelColumn, Qt::CheckState checkState)
+{
+	QVariantList result;
+	std::vector<QModelIndex> stack(1);
+	do
+	{
+		auto pindex = stack.back();
+		stack.pop_back();
+		auto rowCount = model.rowCount(pindex);
+		for (int i = 0; i < rowCount; ++i)
+		{
+			QModelIndex index = model.index(i, modelColumn, pindex);
+			auto * item = model.itemFromIndex(index);
+			if(item && item->checkState() == checkState)
+				result.push_back(item->data(MapEditorRoles::BuildingIDRole));
+			index = model.index(i, 0, pindex);
+			if (model.hasChildren(index))
+				stack.push_back(index);
+		}
+	} while(!stack.empty());
+
+	return result;
+}
+
+
+
 TownBuildingsWidget::TownBuildingsWidget(CGTownInstance & t, QWidget *parent) :
 	town(t),
 	QDialog(parent),
@@ -76,8 +127,8 @@ TownBuildingsWidget::TownBuildingsWidget(CGTownInstance & t, QWidget *parent) :
 	ui->setupUi(this);
 	ui->treeView->setModel(&model);
 	//ui->treeView->setColumnCount(3);
-	model.setHorizontalHeaderLabels(QStringList() << QStringLiteral("Type") << QStringLiteral("Enabled") << QStringLiteral("Built"));
-	
+	model.setHorizontalHeaderLabels(QStringList() << tr("Type") << tr("Enabled") << tr("Built"));
+	connect(&model, &QStandardItemModel::itemChanged, this, &TownBuildingsWidget::onItemChanged);
 	//setAttribute(Qt::WA_DeleteOnClose);
 }
 
@@ -96,7 +147,7 @@ QStandardItem * TownBuildingsWidget::addBuilding(const CTown & ctown, int bId, s
 		return nullptr;
 	}
 	
-	QString name = tr(building->getNameTranslated().c_str());
+	QString name = QString::fromStdString(building->getNameTranslated());
 	
 	if(name.isEmpty())
 		name = QString::fromStdString(defaultBuildingIdConversion(buildingId));
@@ -104,17 +155,17 @@ QStandardItem * TownBuildingsWidget::addBuilding(const CTown & ctown, int bId, s
 	QList<QStandardItem *> checks;
 	
 	checks << new QStandardItem(name);
-	checks.back()->setData(bId, Qt::UserRole);
+	checks.back()->setData(bId, MapEditorRoles::BuildingIDRole);
 	
 	checks << new QStandardItem;
 	checks.back()->setCheckable(true);
 	checks.back()->setCheckState(town.forbiddenBuildings.count(buildingId) ? Qt::Unchecked : Qt::Checked);
-	checks.back()->setData(bId, Qt::UserRole);
+	checks.back()->setData(bId, MapEditorRoles::BuildingIDRole);
 	
 	checks << new QStandardItem;
 	checks.back()->setCheckable(true);
 	checks.back()->setCheckState(town.builtBuildings.count(buildingId) ? Qt::Checked : Qt::Unchecked);
-	checks.back()->setData(bId, Qt::UserRole);
+	checks.back()->setData(bId, MapEditorRoles::BuildingIDRole);
 	
 	if(building->getBase() == buildingId)
 	{
@@ -122,25 +173,7 @@ QStandardItem * TownBuildingsWidget::addBuilding(const CTown & ctown, int bId, s
 	}
 	else
 	{
-		QStandardItem * parent = nullptr;
-		std::vector<QModelIndex> stack;
-		stack.push_back(QModelIndex());
-		while(!parent && !stack.empty())
-		{
-			auto pindex = stack.back();
-			stack.pop_back();
-			for(int i = 0; i < model.rowCount(pindex); ++i)
-			{
-				QModelIndex index = model.index(i, 0, pindex);
-				if(building->upgrade.getNum() == model.itemFromIndex(index)->data(Qt::UserRole).toInt())
-				{
-					parent = model.itemFromIndex(index);
-					break;
-				}
-				if(model.hasChildren(index))
-					stack.push_back(index);
-			}
-		}
+		QStandardItem * parent = getBuildingParentFromTreeModel(building, model);
 		
 		if(!parent)
 			parent = addBuilding(ctown, building->upgrade.getNum(), remaining);
@@ -172,36 +205,23 @@ void TownBuildingsWidget::addBuildings(const CTown & ctown)
 
 std::set<BuildingID> TownBuildingsWidget::getBuildingsFromModel(int modelColumn, Qt::CheckState checkState)
 {
+	auto buildingVariants = getBuildingVariantsFromModel(model, modelColumn, checkState);
 	std::set<BuildingID> result;
-	std::vector<QModelIndex> stack;
-	stack.push_back(QModelIndex());
-	while(!stack.empty())
+	for (const auto & buildingId : buildingVariants)
 	{
-		auto pindex = stack.back();
-		stack.pop_back();
-		for(int i = 0; i < model.rowCount(pindex); ++i)
-		{
-			QModelIndex index = model.index(i, modelColumn, pindex);
-			if(auto * item = model.itemFromIndex(index))
-				if(item->checkState() == checkState)
-					result.emplace(item->data(Qt::UserRole).toInt());
-			index = model.index(i, 0, pindex); //children are linked to first column of the model
-			if(model.hasChildren(index))
-				stack.push_back(index);
-		}
+		result.insert(buildingId.toInt());
 	}
-	
 	return result;
 }
 
 std::set<BuildingID> TownBuildingsWidget::getForbiddenBuildings()
 {
-	return getBuildingsFromModel(1, Qt::Unchecked);
+	return getBuildingsFromModel(Column::ENABLED, Qt::Unchecked);
 }
 
 std::set<BuildingID> TownBuildingsWidget::getBuiltBuildings()
 {
-	return getBuildingsFromModel(2, Qt::Checked);
+	return getBuildingsFromModel(Column::BUILT, Qt::Checked);
 }
 
 void TownBuildingsWidget::on_treeView_expanded(const QModelIndex &index)
@@ -214,6 +234,87 @@ void TownBuildingsWidget::on_treeView_collapsed(const QModelIndex &index)
 	ui->treeView->resizeColumnToContents(0);
 }
 
+void TownBuildingsWidget::on_buildAll_clicked()
+{
+	setAllRowsColumnCheckState(Column::BUILT, Qt::Checked);
+}
+
+void TownBuildingsWidget::on_demolishAll_clicked()
+{
+	setAllRowsColumnCheckState(Column::BUILT, Qt::Unchecked);
+}
+
+void TownBuildingsWidget::on_enableAll_clicked()
+{
+	setAllRowsColumnCheckState(Column::ENABLED, Qt::Checked);
+}
+
+void TownBuildingsWidget::on_disableAll_clicked()
+{
+	setAllRowsColumnCheckState(Column::ENABLED, Qt::Unchecked);
+}
+
+
+void TownBuildingsWidget::setRowColumnCheckState(const QStandardItem * item, Column column, Qt::CheckState checkState) {
+	auto sibling = item->model()->sibling(item->row(), column, item->index());
+	model.itemFromIndex(sibling)->setCheckState(checkState);
+}
+
+void TownBuildingsWidget::setAllRowsColumnCheckState(Column column, Qt::CheckState checkState)
+{
+	std::vector<QModelIndex> stack(1);
+	do
+	{
+		auto parentIndex = stack.back();
+		stack.pop_back();
+		auto rowCount = model.rowCount(parentIndex);
+		for (int i = 0; i < rowCount; ++i)
+		{
+			QModelIndex index = model.index(i, column, parentIndex);
+			if (auto* item = model.itemFromIndex(index))
+				item->setCheckState(checkState);
+			index = model.index(i, 0, parentIndex);
+			if (model.hasChildren(index))
+				stack.push_back(index);
+		}
+	} while(!stack.empty());
+}
+
+void TownBuildingsWidget::onItemChanged(const QStandardItem * item) {
+	disconnect(&model, &QStandardItemModel::itemChanged, this, &TownBuildingsWidget::onItemChanged);
+	auto rowFirstColumnIndex = item->model()->sibling(item->row(), Column::TYPE, item->index());
+	QStandardItem * nextRow = model.itemFromIndex(rowFirstColumnIndex);
+	if (item->checkState() == Qt::Checked) {
+		while (nextRow) {
+			setRowColumnCheckState(nextRow, Column(item->column()), Qt::Checked);
+			if (item->column() == Column::BUILT) {
+				setRowColumnCheckState(nextRow, Column::ENABLED, Qt::Checked);
+			}
+			nextRow = nextRow->parent();
+
+		}
+	}
+	else if (item->checkState() == Qt::Unchecked) {
+		std::vector<QStandardItem*> stack;
+		stack.push_back(nextRow);
+		do
+		{
+			nextRow = stack.back();
+			stack.pop_back();
+			setRowColumnCheckState(nextRow, Column(item->column()), Qt::Unchecked);
+			if (item->column() == Column::ENABLED) {
+				setRowColumnCheckState(nextRow, Column::BUILT, Qt::Unchecked);
+			}
+			if (nextRow->hasChildren()) {
+				for (int i = 0; i < nextRow->rowCount(); ++i) {
+					stack.push_back(nextRow->child(i, Column::TYPE));
+				}
+			}
+			
+		} while(!stack.empty());
+	}
+	connect(&model, &QStandardItemModel::itemChanged, this, &TownBuildingsWidget::onItemChanged);
+}
 
 TownBuildingsDelegate::TownBuildingsDelegate(CGTownInstance & t): town(t), QStyledItemDelegate()
 {

+ 22 - 2
mapeditor/inspector/townbuildingswidget.h

@@ -19,6 +19,10 @@ class TownBuildingsWidget;
 
 std::string defaultBuildingIdConversion(BuildingID bId);
 
+QStandardItem * getBuildingParentFromTreeModel(const CBuilding * building, const QStandardItemModel & model);
+
+QVariantList getBuildingVariantsFromModel(const QStandardItemModel & model, int modelColumn, Qt::CheckState checkState);
+
 class TownBuildingsWidget : public QDialog
 {
 	Q_OBJECT
@@ -26,9 +30,13 @@ class TownBuildingsWidget : public QDialog
 	QStandardItem * addBuilding(const CTown & ctown, int bId, std::set<si32> & remaining);
 	
 public:
+	enum Column
+	{
+		TYPE, ENABLED, BUILT
+	};
 	explicit TownBuildingsWidget(CGTownInstance &, QWidget *parent = nullptr);
 	~TownBuildingsWidget();
-	
+
 	void addBuildings(const CTown & ctown);
 	std::set<BuildingID> getForbiddenBuildings();
 	std::set<BuildingID> getBuiltBuildings();
@@ -38,9 +46,21 @@ private slots:
 
 	void on_treeView_collapsed(const QModelIndex &index);
 
+	void on_buildAll_clicked();
+
+	void on_demolishAll_clicked();
+
+	void on_enableAll_clicked();
+
+	void on_disableAll_clicked();
+
+	void onItemChanged(const QStandardItem * item);
+
 private:
 	std::set<BuildingID> getBuildingsFromModel(int modelColumn, Qt::CheckState checkState);
-	
+	void setRowColumnCheckState(const QStandardItem * item, Column column, Qt::CheckState checkState);
+	void setAllRowsColumnCheckState(Column column, Qt::CheckState checkState);
+
 	Ui::TownBuildingsWidget *ui;
 	CGTownInstance & town;
 	mutable QStandardItemModel model;

+ 34 - 2
mapeditor/inspector/townbuildingswidget.ui

@@ -9,7 +9,7 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>480</width>
+    <width>580</width>
     <height>280</height>
    </rect>
   </property>
@@ -21,7 +21,7 @@
   </property>
   <property name="minimumSize">
    <size>
-    <width>480</width>
+    <width>580</width>
     <height>280</height>
    </size>
   </property>
@@ -45,6 +45,38 @@
      </attribute>
     </widget>
    </item>
+   <item>
+    <layout class="QVBoxLayout" name="verticalLayout">
+     <item>
+      <widget class="QPushButton" name="buildAll">
+       <property name="text">
+        <string>Build all</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="demolishAll">
+       <property name="text">
+        <string>Demolish all</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="enableAll">
+       <property name="text">
+        <string>Enable all</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="disableAll">
+       <property name="text">
+        <string>Disable all</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
   </layout>
  </widget>
  <resources/>

+ 289 - 0
mapeditor/inspector/towneventdialog.cpp

@@ -0,0 +1,289 @@
+/*
+ * towneventdialog.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+#include "../StdInc.h"
+#include "townbuildingswidget.h"
+#include "towneventdialog.h"
+#include "ui_towneventdialog.h"
+#include "mapeditorroles.h"
+#include "../../lib/entities/building/CBuilding.h"
+#include "../../lib/entities/faction/CTownHandler.h"
+#include "../../lib/constants/NumericConstants.h"
+#include "../../lib/constants/StringConstants.h"
+
+static const int FIRST_DAY_FOR_EVENT = 1;
+static const int LAST_DAY_FOR_EVENT = 999;
+static const int MAXIMUM_EVENT_REPEAT_AFTER = 999;
+
+static const int MAXIMUM_GOLD_CHANGE = 999999;
+static const int MAXIMUM_RESOURCE_CHANGE = 999;
+static const int GOLD_STEP = 100;
+static const int RESOURCE_STEP = 1;
+
+static const int MAXIMUM_CREATURES_CHANGE = 999999;
+
+TownEventDialog::TownEventDialog(CGTownInstance & t, QListWidgetItem * item, QWidget * parent) :
+	QDialog(parent),
+	ui(new Ui::TownEventDialog),
+	town(t),
+	townEventListItem(item)
+{
+	ui->setupUi(this);
+
+	ui->buildingsTree->setModel(&buildingsModel);
+
+	params = townEventListItem->data(MapEditorRoles::TownEventRole).toMap();
+	ui->eventFirstOccurrence->setMinimum(FIRST_DAY_FOR_EVENT);
+	ui->eventFirstOccurrence->setMaximum(LAST_DAY_FOR_EVENT);
+	ui->eventRepeatAfter->setMaximum(MAXIMUM_EVENT_REPEAT_AFTER);
+	ui->eventNameText->setText(params.value("name").toString());
+	ui->eventMessageText->setPlainText(params.value("message").toString());
+	ui->eventAffectsCpu->setChecked(params.value("computerAffected").toBool());
+	ui->eventAffectsHuman->setChecked(params.value("humanAffected").toBool());
+	ui->eventFirstOccurrence->setValue(params.value("firstOccurrence").toInt()+1);
+	ui->eventRepeatAfter->setValue(params.value("nextOccurrence").toInt());
+
+	initPlayers();
+	initResources();
+	initBuildings();
+	initCreatures();
+}
+
+TownEventDialog::~TownEventDialog()
+{
+	delete ui;
+}
+
+void TownEventDialog::initPlayers()
+{
+	for (int i = 0; i < PlayerColor::PLAYER_LIMIT_I; ++i)
+	{
+		bool isAffected = (1 << i) & params.value("players").toInt();
+		auto * item = new QListWidgetItem(QString::fromStdString(GameConstants::PLAYER_COLOR_NAMES[i]));
+		item->setData(MapEditorRoles::PlayerIDRole, QVariant::fromValue(i));
+		item->setCheckState(isAffected ? Qt::Checked : Qt::Unchecked);
+		ui->playersAffected->addItem(item);
+	}
+}
+
+void TownEventDialog::initResources()
+{
+	ui->resourcesTable->setRowCount(GameConstants::RESOURCE_QUANTITY);
+	auto resourcesMap = params.value("resources").toMap();
+	for (int i = 0; i < GameConstants::RESOURCE_QUANTITY; ++i)
+	{
+		auto name = QString::fromStdString(GameConstants::RESOURCE_NAMES[i]);
+		auto * item = new QTableWidgetItem();
+		item->setFlags(item->flags() & ~Qt::ItemIsEditable);
+		item->setText(name);
+		ui->resourcesTable->setItem(i, 0, item);
+
+		int val = resourcesMap.value(name).toInt();
+		auto * edit = new QSpinBox(ui->resourcesTable);
+		edit->setMaximum(i == GameResID::GOLD ? MAXIMUM_GOLD_CHANGE : MAXIMUM_RESOURCE_CHANGE);
+		edit->setMinimum(i == GameResID::GOLD ? -MAXIMUM_GOLD_CHANGE : -MAXIMUM_RESOURCE_CHANGE);
+		edit->setSingleStep(i == GameResID::GOLD ? GOLD_STEP : RESOURCE_STEP);
+		edit->setValue(val);
+
+		ui->resourcesTable->setCellWidget(i, 1, edit);
+	}
+}
+
+void TownEventDialog::initBuildings()
+{
+	auto * ctown = town.town;
+	if (!ctown)
+		ctown = VLC->townh->randomTown;
+	if (!ctown)
+		throw std::runtime_error("No Town defined for type selected");
+	auto allBuildings = ctown->getAllBuildings();
+	while (!allBuildings.empty())
+	{
+		addBuilding(*ctown, *allBuildings.begin(), allBuildings);
+	}
+	ui->buildingsTree->resizeColumnToContents(0);
+
+	connect(&buildingsModel, &QStandardItemModel::itemChanged, this, &TownEventDialog::onItemChanged);
+}
+
+QStandardItem * TownEventDialog::addBuilding(const CTown& ctown, BuildingID buildingId, std::set<si32>& remaining)
+{
+	auto bId = buildingId.num;
+	const CBuilding * building = ctown.buildings.at(buildingId);
+
+	QString name = QString::fromStdString(building->getNameTranslated());
+
+	if (name.isEmpty())
+		name = QString::fromStdString(defaultBuildingIdConversion(buildingId));
+
+	QList<QStandardItem *> checks;
+
+	checks << new QStandardItem(name);
+	checks.back()->setData(bId, MapEditorRoles::BuildingIDRole);
+
+	checks << new QStandardItem;
+	checks.back()->setCheckable(true);
+	checks.back()->setCheckState(params["buildings"].toList().contains(bId) ? Qt::Checked : Qt::Unchecked);
+	checks.back()->setData(bId, MapEditorRoles::BuildingIDRole);
+
+	if (building->getBase() == buildingId)
+	{
+		buildingsModel.appendRow(checks);
+	}
+	else
+	{
+		QStandardItem * parent = getBuildingParentFromTreeModel(building, buildingsModel);
+
+		if (!parent)
+			parent = addBuilding(ctown, building->upgrade.getNum(), remaining);
+
+		parent->appendRow(checks);
+	}
+
+	remaining.erase(bId);
+	return checks.front();
+}
+
+void TownEventDialog::initCreatures()
+{
+	auto creatures = params.value("creatures").toList();
+	auto * ctown = town.town;
+	for (int i = 0; i < GameConstants::CREATURES_PER_TOWN; ++i)
+	{
+		QString creatureNames;
+		if (!ctown)
+		{
+			creatureNames.append(tr("Creature level %1 / Creature level %1 Upgrade").arg(i + 1));
+		}
+		else
+		{
+			auto creaturesOnLevel = ctown->creatures.at(i);
+			for (auto& creature : creaturesOnLevel)
+			{
+				auto cre = VLC->creatures()->getById(creature);
+				auto creatureName = QString::fromStdString(cre->getNameSingularTranslated());
+				creatureNames.append(creatureNames.isEmpty() ? creatureName : " / " + creatureName);
+			}
+		}
+		auto * item = new QTableWidgetItem();
+		item->setFlags(item->flags() & ~Qt::ItemIsEditable);
+		item->setText(creatureNames);
+		ui->creaturesTable->setItem(i, 0, item);
+
+		auto creatureNumber = creatures.size() > i ? creatures.at(i).toInt() : 0;
+		auto * edit = new QSpinBox(ui->creaturesTable);
+		edit->setValue(creatureNumber);
+		edit->setMaximum(MAXIMUM_CREATURES_CHANGE);
+		ui->creaturesTable->setCellWidget(i, 1, edit);
+
+	}
+	ui->creaturesTable->resizeColumnToContents(0);
+}
+
+void TownEventDialog::on_TownEventDialog_finished(int result)
+{
+	QVariantMap descriptor;
+	descriptor["name"] = ui->eventNameText->text();
+	descriptor["message"] = ui->eventMessageText->toPlainText();
+	descriptor["humanAffected"] = QVariant::fromValue(ui->eventAffectsHuman->isChecked());
+	descriptor["computerAffected"] = QVariant::fromValue(ui->eventAffectsCpu->isChecked());
+	descriptor["firstOccurrence"] = QVariant::fromValue(ui->eventFirstOccurrence->value()-1);
+	descriptor["nextOccurrence"] = QVariant::fromValue(ui->eventRepeatAfter->value());
+	descriptor["players"] = playersToVariant();
+	descriptor["resources"] = resourcesToVariant();
+	descriptor["buildings"] = buildingsToVariant();
+	descriptor["creatures"] = creaturesToVariant();
+
+	townEventListItem->setData(MapEditorRoles::TownEventRole, descriptor);
+	auto itemText = tr("Day %1 - %2").arg(ui->eventFirstOccurrence->value(), 3).arg(ui->eventNameText->text());
+	townEventListItem->setText(itemText);
+}
+
+QVariant TownEventDialog::playersToVariant()
+{
+	int players = 0;
+	for (int i = 0; i < ui->playersAffected->count(); ++i)
+	{
+		auto * item = ui->playersAffected->item(i);
+		if (item->checkState() == Qt::Checked)
+			players |= 1 << i;
+	}
+	return QVariant::fromValue(players);
+}
+
+QVariantMap TownEventDialog::resourcesToVariant()
+{
+	auto res = params.value("resources").toMap();
+	for (int i = 0; i < GameConstants::RESOURCE_QUANTITY; ++i)
+	{
+		auto * itemType = ui->resourcesTable->item(i, 0);
+		auto * itemQty = static_cast<QSpinBox *> (ui->resourcesTable->cellWidget(i, 1));
+
+		res[itemType->text()] = QVariant::fromValue(itemQty->value());
+	}
+	return res;
+}
+
+QVariantList TownEventDialog::buildingsToVariant()
+{
+	return getBuildingVariantsFromModel(buildingsModel, 1, Qt::Checked);
+}
+
+QVariantList TownEventDialog::creaturesToVariant()
+{
+	QVariantList creaturesList;
+	for (int i = 0; i < GameConstants::CREATURES_PER_TOWN; ++i)
+	{
+		auto * item = static_cast<QSpinBox *>(ui->creaturesTable->cellWidget(i, 1));
+		creaturesList.push_back(item->value());
+	}
+	return creaturesList;
+}
+
+void TownEventDialog::on_okButton_clicked()
+{
+	close();
+}
+
+void TownEventDialog::setRowColumnCheckState(const QStandardItem * item, int column, Qt::CheckState checkState) {
+	auto sibling = item->model()->sibling(item->row(), column, item->index());
+	buildingsModel.itemFromIndex(sibling)->setCheckState(checkState);
+}
+
+void TownEventDialog::onItemChanged(const QStandardItem * item)
+{
+	disconnect(&buildingsModel, &QStandardItemModel::itemChanged, this, &TownEventDialog::onItemChanged);
+	auto rowFirstColumnIndex = item->model()->sibling(item->row(), 0, item->index());
+	QStandardItem * nextRow = buildingsModel.itemFromIndex(rowFirstColumnIndex);
+	if (item->checkState() == Qt::Checked) {
+		while (nextRow) {
+			setRowColumnCheckState(nextRow,item->column(), Qt::Checked);
+			nextRow = nextRow->parent();
+
+		}
+	}
+	else if (item->checkState() == Qt::Unchecked) {
+		std::vector<QStandardItem *> stack;
+		stack.push_back(nextRow);
+		do
+		{
+			nextRow = stack.back();
+			stack.pop_back();
+			setRowColumnCheckState(nextRow, item->column(), Qt::Unchecked);
+			if (nextRow->hasChildren()) {
+				for (int i = 0; i < nextRow->rowCount(); ++i) {
+					stack.push_back(nextRow->child(i, 0));
+				}
+			}
+
+		} while(!stack.empty());
+	}
+	connect(&buildingsModel, &QStandardItemModel::itemChanged, this, &TownEventDialog::onItemChanged);
+}

+ 53 - 0
mapeditor/inspector/towneventdialog.h

@@ -0,0 +1,53 @@
+/*
+ * towneventdialog.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#pragma once
+
+#include "../StdInc.h"
+#include <QDialog>
+#include "../lib/mapObjects/CGTownInstance.h"
+
+namespace Ui {
+	class TownEventDialog;
+}
+
+class TownEventDialog : public QDialog
+{
+	Q_OBJECT
+
+public:
+	explicit TownEventDialog(CGTownInstance & town, QListWidgetItem * item, QWidget * parent);
+	~TownEventDialog();
+
+
+private slots:
+	void onItemChanged(const QStandardItem * item);
+	void on_TownEventDialog_finished(int result);
+	void on_okButton_clicked();
+	void setRowColumnCheckState(const QStandardItem * item, int column, Qt::CheckState checkState);
+
+private:
+	void initPlayers();
+	void initResources();
+	void initBuildings();
+	void initCreatures();
+
+	QVariant playersToVariant();
+	QVariantMap resourcesToVariant();
+	QVariantList buildingsToVariant();
+	QVariantList creaturesToVariant();
+
+	QStandardItem * addBuilding(const CTown & ctown, BuildingID bId, std::set<si32> & remaining);
+
+	Ui::TownEventDialog * ui;
+	CGTownInstance & town;
+	QListWidgetItem * townEventListItem;
+	QMap<QString, QVariant> params;
+	QStandardItemModel buildingsModel;
+};

+ 266 - 0
mapeditor/inspector/towneventdialog.ui

@@ -0,0 +1,266 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>TownEventDialog</class>
+ <widget class="QDialog" name="TownEventDialog">
+  <property name="windowModality">
+   <enum>Qt::ApplicationModal</enum>
+  </property>
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>693</width>
+    <height>525</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="windowTitle">
+   <string>Town event</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout_16">
+   <property name="spacing">
+    <number>0</number>
+   </property>
+   <property name="leftMargin">
+    <number>3</number>
+   </property>
+   <property name="rightMargin">
+    <number>3</number>
+   </property>
+   <item>
+    <widget class="QTabWidget" name="tabWidget">
+     <property name="currentIndex">
+      <number>0</number>
+     </property>
+     <widget class="QWidget" name="generalTab">
+      <attribute name="title">
+       <string>General</string>
+      </attribute>
+      <widget class="QWidget" name="verticalLayoutWidget">
+       <property name="geometry">
+        <rect>
+         <x>9</x>
+         <y>9</y>
+         <width>511</width>
+         <height>351</height>
+        </rect>
+       </property>
+       <layout class="QVBoxLayout" name="verticalLayout" stretch="0,0">
+        <item>
+         <widget class="QLineEdit" name="eventNameText">
+          <property name="placeholderText">
+           <string>Event name</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QPlainTextEdit" name="eventMessageText">
+          <property name="placeholderText">
+           <string>Type event message text</string>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+      <widget class="QWidget" name="horizontalLayoutWidget">
+       <property name="geometry">
+        <rect>
+         <x>10</x>
+         <y>370</y>
+         <width>511</width>
+         <height>61</height>
+        </rect>
+       </property>
+       <layout class="QHBoxLayout" name="horizontalLayout">
+        <item>
+         <layout class="QVBoxLayout" name="verticalLayout_2">
+          <item>
+           <widget class="QLabel" name="eventFirstOccurrenceText">
+            <property name="text">
+             <string>Day of first occurrence</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QSpinBox" name="eventFirstOccurrence"/>
+          </item>
+         </layout>
+        </item>
+        <item>
+         <layout class="QVBoxLayout" name="verticalLayout_3">
+          <item>
+           <widget class="QLabel" name="eventRepeatAfterText">
+            <property name="text">
+             <string>Repeat after (0 = no repeat)</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QSpinBox" name="eventRepeatAfter"/>
+          </item>
+         </layout>
+        </item>
+       </layout>
+      </widget>
+      <widget class="QWidget" name="verticalLayoutWidget_4">
+       <property name="geometry">
+        <rect>
+         <x>529</x>
+         <y>9</y>
+         <width>141</width>
+         <height>421</height>
+        </rect>
+       </property>
+       <layout class="QVBoxLayout" name="verticalLayout_4">
+        <item>
+         <widget class="QLabel" name="playersAffectedText">
+          <property name="text">
+           <string>Affected players</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QListWidget" name="playersAffected">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="maximumSize">
+           <size>
+            <width>200</width>
+            <height>16777215</height>
+           </size>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QCheckBox" name="eventAffectsHuman">
+          <property name="text">
+           <string>affects human</string>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <layout class="QHBoxLayout" name="horizontalLayout_2">
+          <item>
+           <widget class="QCheckBox" name="eventAffectsCpu">
+            <property name="text">
+             <string>affects AI</string>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </item>
+       </layout>
+      </widget>
+     </widget>
+     <widget class="QWidget" name="resourcesTab">
+      <attribute name="title">
+       <string>Resources</string>
+      </attribute>
+      <widget class="QTableWidget" name="resourcesTable">
+       <property name="geometry">
+        <rect>
+         <x>10</x>
+         <y>10</y>
+         <width>661</width>
+         <height>421</height>
+        </rect>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>0</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="columnCount">
+        <number>2</number>
+       </property>
+       <attribute name="horizontalHeaderVisible">
+        <bool>false</bool>
+       </attribute>
+       <attribute name="verticalHeaderVisible">
+        <bool>false</bool>
+       </attribute>
+       <column/>
+       <column/>
+      </widget>
+     </widget>
+     <widget class="QWidget" name="buildingsTab">
+      <attribute name="title">
+       <string>Buildings</string>
+      </attribute>
+      <widget class="QTreeView" name="buildingsTree">
+       <property name="geometry">
+        <rect>
+         <x>10</x>
+         <y>10</y>
+         <width>661</width>
+         <height>421</height>
+        </rect>
+       </property>
+       <property name="editTriggers">
+        <set>QAbstractItemView::NoEditTriggers</set>
+       </property>
+       <attribute name="headerVisible">
+        <bool>false</bool>
+       </attribute>
+      </widget>
+     </widget>
+     <widget class="QWidget" name="creaturesTab">
+      <attribute name="title">
+       <string>Creatures</string>
+      </attribute>
+      <widget class="QTableWidget" name="creaturesTable">
+       <property name="geometry">
+        <rect>
+         <x>10</x>
+         <y>10</y>
+         <width>661</width>
+         <height>421</height>
+        </rect>
+       </property>
+       <property name="rowCount">
+        <number>7</number>
+       </property>
+       <property name="columnCount">
+        <number>2</number>
+       </property>
+       <attribute name="horizontalHeaderVisible">
+        <bool>false</bool>
+       </attribute>
+       <attribute name="verticalHeaderVisible">
+        <bool>false</bool>
+       </attribute>
+       <row/>
+       <row/>
+       <row/>
+       <row/>
+       <row/>
+       <row/>
+       <row/>
+       <column/>
+       <column/>
+      </widget>
+     </widget>
+    </widget>
+   </item>
+   <item>
+    <widget class="QPushButton" name="okButton">
+     <property name="text">
+      <string>OK</string>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>

+ 177 - 0
mapeditor/inspector/towneventswidget.cpp

@@ -0,0 +1,177 @@
+/*
+ * towneventswidget.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+#include "../StdInc.h"
+#include "towneventswidget.h"
+#include "ui_towneventswidget.h"
+#include "towneventdialog.h"
+#include "mapeditorroles.h"
+#include "mapsettings/eventsettings.h"
+#include "../../lib/constants/NumericConstants.h"
+#include "../../lib/constants/StringConstants.h"
+
+TownEventsWidget::TownEventsWidget(CGTownInstance & town, QWidget * parent) :
+	QDialog(parent),
+	ui(new Ui::TownEventsWidget),
+	town(town)
+{
+	ui->setupUi(this);
+}
+
+TownEventsWidget::~TownEventsWidget()
+{
+	delete ui;
+}
+
+QVariant toVariant(const std::set<BuildingID> & buildings)
+{
+	QVariantList result;
+	for (auto b : buildings)
+		result.push_back(QVariant::fromValue(b.num));
+	return result;
+}
+
+QVariant toVariant(const std::vector<si32> & creatures)
+{
+	QVariantList result;
+	for (auto c : creatures)
+		result.push_back(QVariant::fromValue(c));
+	return result;
+}
+
+std::set<BuildingID> buildingsFromVariant(const QVariant& v)
+{
+	std::set<BuildingID> result;
+	for (const auto & r : v.toList()) {
+		result.insert(BuildingID(r.toInt()));
+	}
+	return result;
+}
+
+std::vector<si32> creaturesFromVariant(const QVariant& v)
+{
+	std::vector<si32> result;
+	for (const auto & r : v.toList()) {
+		result.push_back(r.toInt());
+	}
+	return result;
+}
+
+QVariant toVariant(const CCastleEvent& event)
+{
+	QVariantMap result;
+	result["name"] = QString::fromStdString(event.name);
+	result["message"] = QString::fromStdString(event.message.toString());
+	result["players"] = QVariant::fromValue(event.players);
+	result["humanAffected"] = QVariant::fromValue(event.humanAffected);
+	result["computerAffected"] = QVariant::fromValue(event.computerAffected);
+	result["firstOccurrence"] = QVariant::fromValue(event.firstOccurrence);
+	result["nextOccurrence"] = QVariant::fromValue(event.nextOccurrence);
+	result["resources"] = toVariant(event.resources);
+	result["buildings"] = toVariant(event.buildings);
+	result["creatures"] = toVariant(event.creatures);
+
+	return QVariant(result);
+}
+
+CCastleEvent eventFromVariant(CMapHeader& map, const CGTownInstance& town, const QVariant& variant)
+{
+	CCastleEvent result;
+	auto v = variant.toMap();
+	result.name = v.value("name").toString().toStdString();
+	result.message.appendTextID(mapRegisterLocalizedString("map", map, TextIdentifier("town", town.instanceName, "event", result.name, "message"), v.value("message").toString().toStdString()));
+	result.players = v.value("players").toInt();
+	result.humanAffected = v.value("humanAffected").toInt();
+	result.computerAffected = v.value("computerAffected").toInt();
+	result.firstOccurrence = v.value("firstOccurrence").toInt();
+	result.nextOccurrence = v.value("nextOccurrence").toInt();
+	result.resources = resourcesFromVariant(v.value("resources"));
+	result.buildings = buildingsFromVariant(v.value("buildings"));
+	result.creatures = creaturesFromVariant(v.value("creatures"));
+	return result;
+}
+
+void TownEventsWidget::obtainData()
+{
+	for (const auto & event : town.events)
+	{
+		auto eventName = QString::fromStdString(event.name);
+		auto itemText = tr("Day %1 - %2").arg(event.firstOccurrence+1, 3).arg(eventName);
+
+		auto * item = new QListWidgetItem(itemText);
+		item->setData(MapEditorRoles::TownEventRole, toVariant(event));
+		ui->eventsList->addItem(item);
+	}
+}
+
+void TownEventsWidget::commitChanges(MapController& controller)
+{
+	town.events.clear();
+	for (int i = 0; i < ui->eventsList->count(); ++i)
+	{
+		const auto * item = ui->eventsList->item(i);
+		town.events.push_back(eventFromVariant(*controller.map(), town, item->data(MapEditorRoles::TownEventRole)));
+	}
+}
+
+void TownEventsWidget::on_timedEventAdd_clicked()
+{
+	CCastleEvent event;
+	event.name = tr("New event").toStdString();
+	auto* item = new QListWidgetItem(QString::fromStdString(event.name));
+	item->setData(MapEditorRoles::TownEventRole, toVariant(event));
+	ui->eventsList->addItem(item);
+	on_eventsList_itemActivated(item);
+}
+
+void TownEventsWidget::on_timedEventRemove_clicked()
+{
+	delete ui->eventsList->takeItem(ui->eventsList->currentRow());
+}
+
+void TownEventsWidget::on_eventsList_itemActivated(QListWidgetItem* item)
+{
+	TownEventDialog dlg{ town, item, parentWidget() };
+	dlg.exec();
+}
+
+
+TownEventsDelegate::TownEventsDelegate(CGTownInstance & town, MapController & c) : QStyledItemDelegate(), town(town), controller(c)
+{
+}
+
+QWidget* TownEventsDelegate::createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const
+{
+	return new TownEventsWidget(town, parent);
+}
+
+void TownEventsDelegate::setEditorData(QWidget * editor, const QModelIndex & index) const
+{
+	if (auto * ed = qobject_cast<TownEventsWidget *>(editor))
+	{
+		ed->obtainData();
+	}
+	else
+	{
+		QStyledItemDelegate::setEditorData(editor, index);
+	}
+}
+
+void TownEventsDelegate::setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const
+{
+	if (auto * ed = qobject_cast<TownEventsWidget *>(editor))
+	{
+		ed->commitChanges(controller);
+	}
+	else
+	{
+		QStyledItemDelegate::setModelData(editor, model, index);
+	}
+}

+ 58 - 0
mapeditor/inspector/towneventswidget.h

@@ -0,0 +1,58 @@
+/*
+ * towneventswidget.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#pragma once
+
+#include "../StdInc.h"
+#include <QDialog>
+#include "../lib/mapping/CMapDefines.h"
+#include "../lib/mapObjects/CGTownInstance.h"
+#include "../mapcontroller.h"
+
+namespace Ui {
+	class TownEventsWidget;
+}
+
+class TownEventsWidget : public QDialog
+{
+	Q_OBJECT
+
+public:
+	explicit TownEventsWidget(CGTownInstance &, QWidget * parent = nullptr);
+	~TownEventsWidget();
+
+	void obtainData();
+	void commitChanges(MapController & controller);
+private slots:
+	void on_timedEventAdd_clicked();
+	void on_timedEventRemove_clicked();
+	void on_eventsList_itemActivated(QListWidgetItem * item);
+
+private:
+
+	Ui::TownEventsWidget * ui;
+	CGTownInstance & town;
+};
+
+class TownEventsDelegate : public QStyledItemDelegate
+{
+	Q_OBJECT
+public:
+	using QStyledItemDelegate::QStyledItemDelegate;
+
+	TownEventsDelegate(CGTownInstance &, MapController &);
+
+	QWidget* createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const override;
+	void setEditorData(QWidget * editor, const QModelIndex & index) const override;
+	void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const override;
+
+private:
+	CGTownInstance & town;
+	MapController & controller;
+};

+ 93 - 0
mapeditor/inspector/towneventswidget.ui

@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>TownEventsWidget</class>
+ <widget class="QDialog" name="TownEventsWidget">
+  <property name="windowModality">
+   <enum>Qt::ApplicationModal</enum>
+  </property>
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>691</width>
+    <height>462</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="minimumSize">
+   <size>
+    <width>400</width>
+    <height>400</height>
+   </size>
+  </property>
+  <property name="windowTitle">
+   <string>Town events</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_7">
+     <item>
+      <widget class="QLabel" name="timedEventText">
+       <property name="text">
+        <string>Timed events</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="timedEventAdd">
+       <property name="minimumSize">
+        <size>
+         <width>90</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>Add</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="timedEventRemove">
+       <property name="minimumSize">
+        <size>
+         <width>90</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>Remove</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="QListWidget" name="eventsList">
+     <property name="sortingEnabled">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>

+ 166 - 0
mapeditor/inspector/townspellswidget.cpp

@@ -0,0 +1,166 @@
+/*
+ * townspellswidget.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#include "StdInc.h"
+#include "townspellswidget.h"
+#include "ui_townspellswidget.h"
+#include "inspector.h"
+#include "mapeditorroles.h"
+#include "../../lib/constants/StringConstants.h"
+#include "../../lib/spells/CSpellHandler.h"
+
+TownSpellsWidget::TownSpellsWidget(CGTownInstance & town, QWidget * parent) :
+	QDialog(parent),
+	ui(new Ui::TownSpellsWidget),
+	town(town)
+{
+	ui->setupUi(this);
+
+	possibleSpellLists = { ui->possibleSpellList1, ui->possibleSpellList2, ui->possibleSpellList3, ui->possibleSpellList4, ui->possibleSpellList5 };
+	requiredSpellLists = { ui->requiredSpellList1, ui->requiredSpellList2, ui->requiredSpellList3, ui->requiredSpellList4, ui->requiredSpellList5 };
+
+	std::array<BuildingID, 5> mageGuilds = {BuildingID::MAGES_GUILD_1, BuildingID::MAGES_GUILD_2, BuildingID::MAGES_GUILD_3, BuildingID::MAGES_GUILD_4, BuildingID::MAGES_GUILD_5};
+	for (int i = 0; i < mageGuilds.size(); i++)
+	{
+		ui->tabWidget->setTabEnabled(i, vstd::contains(town.getTown()->buildings, mageGuilds[i]));
+	}
+}
+
+TownSpellsWidget::~TownSpellsWidget()
+{
+	delete ui;
+}
+
+
+void TownSpellsWidget::obtainData()
+{
+	initSpellLists();
+	if (vstd::contains(town.possibleSpells, SpellID::PRESET)) {
+		ui->customizeSpells->setChecked(true);
+	}
+	else
+	{
+		ui->customizeSpells->setChecked(false);
+		ui->tabWidget->setEnabled(false);
+	}
+}
+
+void TownSpellsWidget::resetSpells()
+{
+	town.possibleSpells.clear();
+	town.obligatorySpells.clear();
+	for (auto spellID : VLC->spellh->getDefaultAllowed())
+		town.possibleSpells.push_back(spellID);
+}
+
+void TownSpellsWidget::initSpellLists()
+{
+	auto spells = VLC->spellh->getDefaultAllowed();
+	for (int i = 0; i < GameConstants::SPELL_LEVELS; i++)
+	{
+		std::vector<SpellID> spellsByLevel;
+		auto getSpellsByLevel = [i](auto spellID) {
+			return spellID.toEntity(VLC)->getLevel() == i + 1;
+		};
+		vstd::copy_if(spells, std::back_inserter(spellsByLevel), getSpellsByLevel);
+		possibleSpellLists[i]->clear();
+		requiredSpellLists[i]->clear();
+		for (auto spellID : spellsByLevel)
+		{
+			auto spell = spellID.toEntity(VLC);
+			auto * possibleItem = new QListWidgetItem(QString::fromStdString(spell->getNameTranslated()));
+			possibleItem->setData(MapEditorRoles::SpellIDRole, QVariant::fromValue(spell->getIndex()));
+			possibleItem->setFlags(possibleItem->flags() | Qt::ItemIsUserCheckable);
+			possibleItem->setCheckState(vstd::contains(town.possibleSpells, spell->getId()) ? Qt::Checked : Qt::Unchecked);
+			possibleSpellLists[i]->addItem(possibleItem);
+
+			auto * requiredItem = new QListWidgetItem(QString::fromStdString(spell->getNameTranslated()));
+			requiredItem->setData(MapEditorRoles::SpellIDRole, QVariant::fromValue(spell->getIndex()));
+			requiredItem->setFlags(requiredItem->flags() | Qt::ItemIsUserCheckable);
+			requiredItem->setCheckState(vstd::contains(town.obligatorySpells, spell->getId()) ? Qt::Checked : Qt::Unchecked);
+			requiredSpellLists[i]->addItem(requiredItem);
+		}
+	}
+}
+
+void TownSpellsWidget::commitChanges()
+{
+	if (!ui->tabWidget->isEnabled())
+	{
+		resetSpells();
+		return;
+	}
+
+	auto updateTownSpellList = [](auto uiSpellLists, auto & townSpellList) {
+		for (const QListWidget * spellList : uiSpellLists)
+		{
+			for (int i = 0; i < spellList->count(); ++i)
+			{
+				const auto * item = spellList->item(i);
+				if (item->checkState() == Qt::Checked)
+				{
+					townSpellList.push_back(item->data(MapEditorRoles::SpellIDRole).toInt());
+				}
+			}
+		}
+	};
+
+	town.possibleSpells.clear();
+	town.obligatorySpells.clear();
+	town.possibleSpells.push_back(SpellID::PRESET);
+	updateTownSpellList(possibleSpellLists, town.possibleSpells);
+	updateTownSpellList(requiredSpellLists, town.obligatorySpells);
+}
+
+void TownSpellsWidget::on_customizeSpells_toggled(bool checked)
+{
+	if (checked)
+	{
+		town.possibleSpells.push_back(SpellID::PRESET);
+	}
+	else
+	{
+		resetSpells();
+	}
+	ui->tabWidget->setEnabled(checked);
+	initSpellLists();
+}
+
+TownSpellsDelegate::TownSpellsDelegate(CGTownInstance & town) : QStyledItemDelegate(), town(town)
+{
+}
+
+QWidget * TownSpellsDelegate::createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const
+{
+	return new TownSpellsWidget(town, parent);
+}
+
+void TownSpellsDelegate::setEditorData(QWidget * editor, const QModelIndex & index) const
+{
+	if (auto * ed = qobject_cast<TownSpellsWidget *>(editor))
+	{
+		ed->obtainData();
+	}
+	else
+	{
+		QStyledItemDelegate::setEditorData(editor, index);
+	}
+}
+
+void TownSpellsDelegate::setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const
+{
+	if (auto * ed = qobject_cast<TownSpellsWidget *>(editor))
+	{
+		ed->commitChanges();
+	}
+	else
+	{
+		QStyledItemDelegate::setModelData(editor, model, index);
+	}
+}

+ 60 - 0
mapeditor/inspector/townspellswidget.h

@@ -0,0 +1,60 @@
+/*
+ * townspellswidget.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#pragma once
+
+#include <QDialog>
+#include "../../lib/mapObjects/CGTownInstance.h"
+
+namespace Ui {
+	class TownSpellsWidget;
+}
+
+
+class TownSpellsWidget : public QDialog
+{
+	Q_OBJECT
+
+public:
+	explicit TownSpellsWidget(CGTownInstance &, QWidget * parent = nullptr);
+	~TownSpellsWidget();
+
+	void obtainData();
+	void commitChanges();
+
+private slots:
+	void on_customizeSpells_toggled(bool checked);
+
+private:
+	Ui::TownSpellsWidget * ui;
+
+	CGTownInstance & town;
+
+	std::array<QListWidget *, 5> possibleSpellLists;
+	std::array<QListWidget *, 5> requiredSpellLists;
+
+	void resetSpells();
+	void initSpellLists();
+};
+
+class TownSpellsDelegate : public QStyledItemDelegate
+{
+	Q_OBJECT
+public:
+	using QStyledItemDelegate::QStyledItemDelegate;
+
+	TownSpellsDelegate(CGTownInstance&);
+
+	QWidget * createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex& index) const override;
+	void setEditorData(QWidget * editor, const QModelIndex & index) const override;
+	void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const override;
+
+private:
+	CGTownInstance& town;
+};

+ 304 - 0
mapeditor/inspector/townspellswidget.ui

@@ -0,0 +1,304 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>TownSpellsWidget</class>
+ <widget class="QDialog" name="TownSpellsWidget">
+  <property name="windowModality">
+   <enum>Qt::NonModal</enum>
+  </property>
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>600</width>
+    <height>480</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="minimumSize">
+   <size>
+    <width>600</width>
+    <height>480</height>
+   </size>
+  </property>
+  <property name="windowTitle">
+   <string>Spells</string>
+  </property>
+  <property name="layoutDirection">
+   <enum>Qt::LeftToRight</enum>
+  </property>
+  <property name="modal">
+   <bool>true</bool>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="spacing">
+    <number>10</number>
+   </property>
+   <property name="topMargin">
+    <number>5</number>
+   </property>
+   <item>
+    <widget class="QCheckBox" name="customizeSpells">
+     <property name="text">
+      <string>Customize spells</string>
+     </property>
+     <property name="checked">
+      <bool>false</bool>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QTabWidget" name="tabWidget">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="currentIndex">
+      <number>0</number>
+     </property>
+     <property name="documentMode">
+      <bool>true</bool>
+     </property>
+     <widget class="QWidget" name="level1">
+      <property name="sizePolicy">
+       <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+        <horstretch>0</horstretch>
+        <verstretch>0</verstretch>
+       </sizepolicy>
+      </property>
+      <attribute name="title">
+       <string>Level 1</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="verticalLayout_level1">
+       <property name="leftMargin">
+        <number>12</number>
+       </property>
+       <property name="rightMargin">
+        <number>12</number>
+       </property>
+       <property name="bottomMargin">
+        <number>12</number>
+       </property>
+       <item>
+        <layout class="QGridLayout" name="gridLayout1">
+         <item row="0" column="0">
+          <widget class="QLabel" name="possibleSpellsText1">
+           <property name="text">
+            <string>Spell that may appear in mage guild</string>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="1">
+          <widget class="QLabel" name="requiredSpellsText1">
+           <property name="text">
+            <string>Spell that must appear in mage guild</string>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="0">
+          <widget class="QListWidget" name="possibleSpellList1"/>
+         </item>
+         <item row="1" column="1">
+          <widget class="QListWidget" name="requiredSpellList1"/>
+         </item>
+        </layout>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="level2">
+      <property name="sizePolicy">
+       <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+        <horstretch>0</horstretch>
+        <verstretch>0</verstretch>
+       </sizepolicy>
+      </property>
+      <attribute name="title">
+       <string>Level 2</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="verticalLayout_level2">
+       <property name="leftMargin">
+        <number>12</number>
+       </property>
+       <property name="rightMargin">
+        <number>12</number>
+       </property>
+       <property name="bottomMargin">
+        <number>12</number>
+       </property>
+       <item>
+        <layout class="QGridLayout" name="gridLayout2">
+         <item row="0" column="0">
+          <widget class="QLabel" name="possibleSpellsText2">
+           <property name="text">
+            <string>Spell that may appear in mage guild</string>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="1">
+          <widget class="QLabel" name="requiredSpellsText2">
+           <property name="text">
+            <string>Spell that must appear in mage guild</string>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="0">
+          <widget class="QListWidget" name="possibleSpellList2"/>
+         </item>
+         <item row="1" column="1">
+          <widget class="QListWidget" name="requiredSpellList2"/>
+         </item>
+        </layout>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="level3">
+      <property name="sizePolicy">
+       <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+        <horstretch>0</horstretch>
+        <verstretch>0</verstretch>
+       </sizepolicy>
+      </property>
+      <attribute name="title">
+       <string>Level 3</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="verticalLayout_level3">
+       <property name="leftMargin">
+        <number>12</number>
+       </property>
+       <property name="rightMargin">
+        <number>12</number>
+       </property>
+       <property name="bottomMargin">
+        <number>12</number>
+       </property>
+       <item>
+        <layout class="QGridLayout" name="gridLayout3">
+         <item row="0" column="0">
+          <widget class="QLabel" name="possibleSpellsText3">
+           <property name="text">
+            <string>Spell that may appear in mage guild</string>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="1">
+          <widget class="QLabel" name="requiredSpellsText3">
+           <property name="text">
+            <string>Spell that must appear in mage guild</string>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="0">
+          <widget class="QListWidget" name="possibleSpellList3"/>
+         </item>
+         <item row="1" column="1">
+          <widget class="QListWidget" name="requiredSpellList3"/>
+         </item>
+        </layout>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="level4">
+      <property name="sizePolicy">
+       <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+        <horstretch>0</horstretch>
+        <verstretch>0</verstretch>
+       </sizepolicy>
+      </property>
+      <attribute name="title">
+       <string>Level 4</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="verticalLayout_level4">
+       <property name="leftMargin">
+        <number>12</number>
+       </property>
+       <property name="rightMargin">
+        <number>12</number>
+       </property>
+       <property name="bottomMargin">
+        <number>12</number>
+       </property>
+       <item>
+        <layout class="QGridLayout" name="gridLayout4">
+         <item row="0" column="0">
+          <widget class="QLabel" name="possibleSpellsText4">
+           <property name="text">
+            <string>Spell that may appear in mage guild</string>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="1">
+          <widget class="QLabel" name="requiredSpellsText4">
+           <property name="text">
+            <string>Spell that must appear in mage guild</string>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="0">
+          <widget class="QListWidget" name="possibleSpellList4"/>
+         </item>
+         <item row="1" column="1">
+          <widget class="QListWidget" name="requiredSpellList4"/>
+         </item>
+        </layout>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="level5">
+      <property name="sizePolicy">
+       <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+        <horstretch>0</horstretch>
+        <verstretch>0</verstretch>
+       </sizepolicy>
+      </property>
+      <attribute name="title">
+       <string>Level 5</string>
+      </attribute>
+      <layout class="QVBoxLayout" name="verticalLayout_level5">
+       <property name="leftMargin">
+        <number>12</number>
+       </property>
+       <property name="rightMargin">
+        <number>12</number>
+       </property>
+       <property name="bottomMargin">
+        <number>12</number>
+       </property>
+       <item>
+        <layout class="QGridLayout" name="gridLayout5">
+         <item row="0" column="0">
+          <widget class="QLabel" name="possibleSpellsText5">
+           <property name="text">
+            <string>Spell that may appear in mage guild</string>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="1">
+          <widget class="QLabel" name="requiredSpellsText5">
+           <property name="text">
+            <string>Spell that must appear in mage guild</string>
+           </property>
+          </widget>
+         </item>
+         <item row="1" column="0">
+          <widget class="QListWidget" name="possibleSpellList5"/>
+         </item>
+         <item row="1" column="1">
+          <widget class="QListWidget" name="requiredSpellList5"/>
+         </item>
+        </layout>
+       </item>
+      </layout>
+     </widget>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>

+ 20 - 0
mapeditor/mapeditorroles.h

@@ -0,0 +1,20 @@
+/*
+ * mapeditorroles.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#pragma once
+
+#include "StdInc.h"
+
+enum MapEditorRoles
+{
+	TownEventRole = Qt::UserRole + 1,
+	PlayerIDRole,
+	BuildingIDRole,
+	SpellIDRole
+};

+ 3 - 0
mapeditor/mapsettings/eventsettings.h

@@ -15,6 +15,9 @@ namespace Ui {
 class EventSettings;
 }
 
+QVariant toVariant(const TResources & resources);
+TResources resourcesFromVariant(const QVariant & v);
+
 class EventSettings : public AbstractSettings
 {
 	Q_OBJECT

+ 211 - 21
mapeditor/translation/chinese.ts

@@ -715,7 +715,7 @@
 <context>
     <name>MapView</name>
     <message>
-        <location filename="../mapview.cpp" line="625"/>
+        <location filename="../mapview.cpp" line="626"/>
         <source>Can&apos;t place object</source>
         <translation>无法放置物体</translation>
     </message>
@@ -889,38 +889,38 @@
         <translation>高级</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="36"/>
+        <location filename="../inspector/inspector.cpp" line="38"/>
         <source>Compliant</source>
         <translation>屈服的</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="37"/>
+        <location filename="../inspector/inspector.cpp" line="39"/>
         <source>Friendly</source>
         <translation>友善的</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="38"/>
+        <location filename="../inspector/inspector.cpp" line="40"/>
         <source>Aggressive</source>
         <translation>好斗的</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="39"/>
+        <location filename="../inspector/inspector.cpp" line="41"/>
         <source>Hostile</source>
         <translation>有敌意的</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="40"/>
+        <location filename="../inspector/inspector.cpp" line="42"/>
         <source>Savage</source>
         <translation>野蛮的</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="843"/>
-        <location filename="../inspector/inspector.cpp" line="932"/>
+        <location filename="../inspector/inspector.cpp" line="847"/>
+        <location filename="../inspector/inspector.cpp" line="936"/>
         <source>neutral</source>
         <translation>中立</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="841"/>
+        <location filename="../inspector/inspector.cpp" line="845"/>
         <source>UNFLAGGABLE</source>
         <translation>没有旗帜</translation>
     </message>
@@ -1435,6 +1435,208 @@
         <source>Buildings</source>
         <translation>建筑</translation>
     </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="53"/>
+        <source>Build all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="60"/>
+        <source>Demolish all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="67"/>
+        <source>Enable all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="74"/>
+        <source>Disable all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Type</source>
+        <translation type="unfinished">类型</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Enabled</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Built</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>TownEventDialog</name>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="23"/>
+        <source>Town event</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="42"/>
+        <source>General</source>
+        <translation type="unfinished">通用</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="57"/>
+        <source>Event name</source>
+        <translation type="unfinished">事件名</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="64"/>
+        <source>Type event message text</source>
+        <translation type="unfinished">输入事件信息文本</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="85"/>
+        <source>Day of first occurrence</source>
+        <translation type="unfinished">首次发生天数</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="99"/>
+        <source>Repeat after (0 = no repeat)</source>
+        <translation type="unfinished">重复周期 (0 = 不重复)</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="123"/>
+        <source>Affected players</source>
+        <translation type="unfinished">生效玩家</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="146"/>
+        <source>affects human</source>
+        <translation type="unfinished">人类玩家生效</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="155"/>
+        <source>affects AI</source>
+        <translation type="unfinished">AI玩家生效</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="166"/>
+        <source>Resources</source>
+        <translation type="unfinished">资源</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="198"/>
+        <source>Buildings</source>
+        <translation type="unfinished">建筑</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="216"/>
+        <source>Creatures</source>
+        <translation type="unfinished">生物</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="255"/>
+        <source>OK</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.cpp" line="177"/>
+        <source>Creature level %1 / Creature level %1 Upgrade</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.cpp" line="219"/>
+        <source>Day %1 - %2</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>TownEventsWidget</name>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="29"/>
+        <source>Town events</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="37"/>
+        <source>Timed events</source>
+        <translation type="unfinished">计时事件</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="63"/>
+        <source>Add</source>
+        <translation type="unfinished">添加</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="76"/>
+        <source>Remove</source>
+        <translation type="unfinished">移除</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.cpp" line="105"/>
+        <source>Day %1 - %2</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.cpp" line="126"/>
+        <source>New event</source>
+        <translation type="unfinished">新事件</translation>
+    </message>
+</context>
+<context>
+    <name>TownSpellsWidget</name>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="29"/>
+        <source>Spells</source>
+        <translation type="unfinished">魔法</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="47"/>
+        <source>Customize spells</source>
+        <translation type="unfinished">自定义魔法</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="76"/>
+        <source>Level 1</source>
+        <translation type="unfinished">1级</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="93"/>
+        <location filename="../inspector/townspellswidget.ui" line="139"/>
+        <location filename="../inspector/townspellswidget.ui" line="185"/>
+        <location filename="../inspector/townspellswidget.ui" line="231"/>
+        <location filename="../inspector/townspellswidget.ui" line="277"/>
+        <source>Spell that may appear in mage guild</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="100"/>
+        <location filename="../inspector/townspellswidget.ui" line="146"/>
+        <location filename="../inspector/townspellswidget.ui" line="192"/>
+        <location filename="../inspector/townspellswidget.ui" line="238"/>
+        <location filename="../inspector/townspellswidget.ui" line="284"/>
+        <source>Spell that must appear in mage guild</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="122"/>
+        <source>Level 2</source>
+        <translation type="unfinished">2级</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="168"/>
+        <source>Level 3</source>
+        <translation type="unfinished">3级</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="214"/>
+        <source>Level 4</source>
+        <translation type="unfinished">4级</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="260"/>
+        <source>Level 5</source>
+        <translation type="unfinished">5级</translation>
+    </message>
 </context>
 <context>
     <name>Translations</name>
@@ -1698,18 +1900,6 @@
         <source>Width</source>
         <translation>宽度</translation>
     </message>
-    <message>
-        <source>S (36x36)</source>
-        <translation type="vanished">小(36x36)</translation>
-    </message>
-    <message>
-        <source>M (72x72)</source>
-        <translation type="vanished">中(72x72)</translation>
-    </message>
-    <message>
-        <source>L (108x108)</source>
-        <translation type="vanished">大(108x108)</translation>
-    </message>
     <message>
         <location filename="../windownewmap.ui" line="179"/>
         <source>XL (144x144)</source>

+ 211 - 21
mapeditor/translation/czech.ts

@@ -715,7 +715,7 @@
 <context>
     <name>MapView</name>
     <message>
-        <location filename="../mapview.cpp" line="625"/>
+        <location filename="../mapview.cpp" line="626"/>
         <source>Can&apos;t place object</source>
         <translation>Nelze umístit objekt</translation>
     </message>
@@ -889,38 +889,38 @@
         <translation>Expert</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="36"/>
+        <location filename="../inspector/inspector.cpp" line="38"/>
         <source>Compliant</source>
         <translation>Ochotná</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="37"/>
+        <location filename="../inspector/inspector.cpp" line="39"/>
         <source>Friendly</source>
         <translation>Přátelská</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="38"/>
+        <location filename="../inspector/inspector.cpp" line="40"/>
         <source>Aggressive</source>
         <translation>Agresivní</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="39"/>
+        <location filename="../inspector/inspector.cpp" line="41"/>
         <source>Hostile</source>
         <translation>Nepřátelská</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="40"/>
+        <location filename="../inspector/inspector.cpp" line="42"/>
         <source>Savage</source>
         <translation>Brutální</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="843"/>
-        <location filename="../inspector/inspector.cpp" line="932"/>
+        <location filename="../inspector/inspector.cpp" line="847"/>
+        <location filename="../inspector/inspector.cpp" line="936"/>
         <source>neutral</source>
         <translation>neutrální</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="841"/>
+        <location filename="../inspector/inspector.cpp" line="845"/>
         <source>UNFLAGGABLE</source>
         <translation>NEOZNAČITELNÝ</translation>
     </message>
@@ -1435,6 +1435,208 @@
         <source>Buildings</source>
         <translation>Budovy</translation>
     </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="53"/>
+        <source>Build all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="60"/>
+        <source>Demolish all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="67"/>
+        <source>Enable all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="74"/>
+        <source>Disable all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Type</source>
+        <translation type="unfinished">Druh</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Enabled</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Built</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>TownEventDialog</name>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="23"/>
+        <source>Town event</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="42"/>
+        <source>General</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="57"/>
+        <source>Event name</source>
+        <translation type="unfinished">Název události</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="64"/>
+        <source>Type event message text</source>
+        <translation type="unfinished">Zadejte text zprávy události</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="85"/>
+        <source>Day of first occurrence</source>
+        <translation type="unfinished">Den prvního výskytu</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="99"/>
+        <source>Repeat after (0 = no repeat)</source>
+        <translation type="unfinished">Opakovat po (0 = bez opak.)</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="123"/>
+        <source>Affected players</source>
+        <translation type="unfinished">Ovlivnění hráči</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="146"/>
+        <source>affects human</source>
+        <translation type="unfinished">ovlivňuje lidi</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="155"/>
+        <source>affects AI</source>
+        <translation type="unfinished">ovlivňuje AI</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="166"/>
+        <source>Resources</source>
+        <translation type="unfinished">Zdroje</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="198"/>
+        <source>Buildings</source>
+        <translation type="unfinished">Budovy</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="216"/>
+        <source>Creatures</source>
+        <translation type="unfinished">Jednotky</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="255"/>
+        <source>OK</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.cpp" line="177"/>
+        <source>Creature level %1 / Creature level %1 Upgrade</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.cpp" line="219"/>
+        <source>Day %1 - %2</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>TownEventsWidget</name>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="29"/>
+        <source>Town events</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="37"/>
+        <source>Timed events</source>
+        <translation type="unfinished">Načasované události</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="63"/>
+        <source>Add</source>
+        <translation type="unfinished">Přidat</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="76"/>
+        <source>Remove</source>
+        <translation type="unfinished">Odebrat</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.cpp" line="105"/>
+        <source>Day %1 - %2</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.cpp" line="126"/>
+        <source>New event</source>
+        <translation type="unfinished">Nová událost</translation>
+    </message>
+</context>
+<context>
+    <name>TownSpellsWidget</name>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="29"/>
+        <source>Spells</source>
+        <translation type="unfinished">Kouzla</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="47"/>
+        <source>Customize spells</source>
+        <translation type="unfinished">Přizpůsobit kouzla</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="76"/>
+        <source>Level 1</source>
+        <translation type="unfinished">Úroveň 1</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="93"/>
+        <location filename="../inspector/townspellswidget.ui" line="139"/>
+        <location filename="../inspector/townspellswidget.ui" line="185"/>
+        <location filename="../inspector/townspellswidget.ui" line="231"/>
+        <location filename="../inspector/townspellswidget.ui" line="277"/>
+        <source>Spell that may appear in mage guild</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="100"/>
+        <location filename="../inspector/townspellswidget.ui" line="146"/>
+        <location filename="../inspector/townspellswidget.ui" line="192"/>
+        <location filename="../inspector/townspellswidget.ui" line="238"/>
+        <location filename="../inspector/townspellswidget.ui" line="284"/>
+        <source>Spell that must appear in mage guild</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="122"/>
+        <source>Level 2</source>
+        <translation type="unfinished">Úroveň 2</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="168"/>
+        <source>Level 3</source>
+        <translation type="unfinished">Úroveň 3</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="214"/>
+        <source>Level 4</source>
+        <translation type="unfinished">Úroveň 4</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="260"/>
+        <source>Level 5</source>
+        <translation type="unfinished">Úroveň 5</translation>
+    </message>
 </context>
 <context>
     <name>Translations</name>
@@ -1698,18 +1900,6 @@
         <source>Width</source>
         <translation>Šířka</translation>
     </message>
-    <message>
-        <source>S (36x36)</source>
-        <translation type="vanished">S (36x36)</translation>
-    </message>
-    <message>
-        <source>M (72x72)</source>
-        <translation type="vanished">M (72x72)</translation>
-    </message>
-    <message>
-        <source>L (108x108)</source>
-        <translation type="vanished">L (108x108)</translation>
-    </message>
     <message>
         <location filename="../windownewmap.ui" line="179"/>
         <source>XL (144x144)</source>

+ 211 - 9
mapeditor/translation/english.ts

@@ -715,7 +715,7 @@
 <context>
     <name>MapView</name>
     <message>
-        <location filename="../mapview.cpp" line="625"/>
+        <location filename="../mapview.cpp" line="626"/>
         <source>Can&apos;t place object</source>
         <translation type="unfinished"></translation>
     </message>
@@ -889,38 +889,38 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="36"/>
+        <location filename="../inspector/inspector.cpp" line="38"/>
         <source>Compliant</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="37"/>
+        <location filename="../inspector/inspector.cpp" line="39"/>
         <source>Friendly</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="38"/>
+        <location filename="../inspector/inspector.cpp" line="40"/>
         <source>Aggressive</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="39"/>
+        <location filename="../inspector/inspector.cpp" line="41"/>
         <source>Hostile</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="40"/>
+        <location filename="../inspector/inspector.cpp" line="42"/>
         <source>Savage</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="843"/>
-        <location filename="../inspector/inspector.cpp" line="932"/>
+        <location filename="../inspector/inspector.cpp" line="847"/>
+        <location filename="../inspector/inspector.cpp" line="936"/>
         <source>neutral</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="841"/>
+        <location filename="../inspector/inspector.cpp" line="845"/>
         <source>UNFLAGGABLE</source>
         <translation type="unfinished"></translation>
     </message>
@@ -1435,6 +1435,208 @@
         <source>Buildings</source>
         <translation type="unfinished"></translation>
     </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="53"/>
+        <source>Build all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="60"/>
+        <source>Demolish all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="67"/>
+        <source>Enable all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="74"/>
+        <source>Disable all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Type</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Enabled</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Built</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>TownEventDialog</name>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="23"/>
+        <source>Town event</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="42"/>
+        <source>General</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="57"/>
+        <source>Event name</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="64"/>
+        <source>Type event message text</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="85"/>
+        <source>Day of first occurrence</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="99"/>
+        <source>Repeat after (0 = no repeat)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="123"/>
+        <source>Affected players</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="146"/>
+        <source>affects human</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="155"/>
+        <source>affects AI</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="166"/>
+        <source>Resources</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="198"/>
+        <source>Buildings</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="216"/>
+        <source>Creatures</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="255"/>
+        <source>OK</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.cpp" line="177"/>
+        <source>Creature level %1 / Creature level %1 Upgrade</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.cpp" line="219"/>
+        <source>Day %1 - %2</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>TownEventsWidget</name>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="29"/>
+        <source>Town events</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="37"/>
+        <source>Timed events</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="63"/>
+        <source>Add</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="76"/>
+        <source>Remove</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.cpp" line="105"/>
+        <source>Day %1 - %2</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.cpp" line="126"/>
+        <source>New event</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>TownSpellsWidget</name>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="29"/>
+        <source>Spells</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="47"/>
+        <source>Customize spells</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="76"/>
+        <source>Level 1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="93"/>
+        <location filename="../inspector/townspellswidget.ui" line="139"/>
+        <location filename="../inspector/townspellswidget.ui" line="185"/>
+        <location filename="../inspector/townspellswidget.ui" line="231"/>
+        <location filename="../inspector/townspellswidget.ui" line="277"/>
+        <source>Spell that may appear in mage guild</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="100"/>
+        <location filename="../inspector/townspellswidget.ui" line="146"/>
+        <location filename="../inspector/townspellswidget.ui" line="192"/>
+        <location filename="../inspector/townspellswidget.ui" line="238"/>
+        <location filename="../inspector/townspellswidget.ui" line="284"/>
+        <source>Spell that must appear in mage guild</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="122"/>
+        <source>Level 2</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="168"/>
+        <source>Level 3</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="214"/>
+        <source>Level 4</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="260"/>
+        <source>Level 5</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>Translations</name>

+ 213 - 23
mapeditor/translation/french.ts

@@ -560,8 +560,8 @@
     </message>
     <message>
         <location filename="../mainwindow.cpp" line="280"/>
-        <source>Unsaved changes will be lost, are you sur?</source>
-        <translation>Des modifications non sauvegardées vont être perdues. Êtes-vous sûr ?</translation>
+        <source>Unsaved changes will be lost, are you sure?</source>
+        <translation type="unfinished"></translation>
     </message>
     <message>
         <location filename="../mainwindow.cpp" line="406"/>
@@ -715,7 +715,7 @@
 <context>
     <name>MapView</name>
     <message>
-        <location filename="../mapview.cpp" line="625"/>
+        <location filename="../mapview.cpp" line="626"/>
         <source>Can&apos;t place object</source>
         <translation>Impossible de placer l&apos;objet</translation>
     </message>
@@ -889,38 +889,38 @@
         <translation>Expert</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="36"/>
+        <location filename="../inspector/inspector.cpp" line="38"/>
         <source>Compliant</source>
         <translation>Compérhensif</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="37"/>
+        <location filename="../inspector/inspector.cpp" line="39"/>
         <source>Friendly</source>
         <translation>Amical</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="38"/>
+        <location filename="../inspector/inspector.cpp" line="40"/>
         <source>Aggressive</source>
         <translation>Aggressif</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="39"/>
+        <location filename="../inspector/inspector.cpp" line="41"/>
         <source>Hostile</source>
         <translation>Hostile</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="40"/>
+        <location filename="../inspector/inspector.cpp" line="42"/>
         <source>Savage</source>
         <translation>Sauvage</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="843"/>
-        <location filename="../inspector/inspector.cpp" line="932"/>
+        <location filename="../inspector/inspector.cpp" line="847"/>
+        <location filename="../inspector/inspector.cpp" line="936"/>
         <source>neutral</source>
         <translation>neutre</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="841"/>
+        <location filename="../inspector/inspector.cpp" line="845"/>
         <source>UNFLAGGABLE</source>
         <translation>INCLASSABLE</translation>
     </message>
@@ -1435,6 +1435,208 @@
         <source>Buildings</source>
         <translation>Bâtiments</translation>
     </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="53"/>
+        <source>Build all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="60"/>
+        <source>Demolish all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="67"/>
+        <source>Enable all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="74"/>
+        <source>Disable all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Type</source>
+        <translation type="unfinished">Type</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Enabled</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Built</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>TownEventDialog</name>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="23"/>
+        <source>Town event</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="42"/>
+        <source>General</source>
+        <translation type="unfinished">Général</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="57"/>
+        <source>Event name</source>
+        <translation type="unfinished">Nom de l&apos;évènement</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="64"/>
+        <source>Type event message text</source>
+        <translation type="unfinished">Taper le message d&apos;évènement</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="85"/>
+        <source>Day of first occurrence</source>
+        <translation type="unfinished">Jour de la première occurrence</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="99"/>
+        <source>Repeat after (0 = no repeat)</source>
+        <translation type="unfinished">Récurrence (0 = pas de récurrence)</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="123"/>
+        <source>Affected players</source>
+        <translation type="unfinished">Joueurs affectés</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="146"/>
+        <source>affects human</source>
+        <translation type="unfinished">afttecte les joueurs</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="155"/>
+        <source>affects AI</source>
+        <translation type="unfinished">affecte l&apos;ordinateur</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="166"/>
+        <source>Resources</source>
+        <translation type="unfinished">Resources</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="198"/>
+        <source>Buildings</source>
+        <translation type="unfinished">Bâtiments</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="216"/>
+        <source>Creatures</source>
+        <translation type="unfinished">Créatures</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="255"/>
+        <source>OK</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.cpp" line="177"/>
+        <source>Creature level %1 / Creature level %1 Upgrade</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.cpp" line="219"/>
+        <source>Day %1 - %2</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>TownEventsWidget</name>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="29"/>
+        <source>Town events</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="37"/>
+        <source>Timed events</source>
+        <translation type="unfinished">Evenements timés</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="63"/>
+        <source>Add</source>
+        <translation type="unfinished">Ajouter</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="76"/>
+        <source>Remove</source>
+        <translation type="unfinished">Supprimer</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.cpp" line="105"/>
+        <source>Day %1 - %2</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.cpp" line="126"/>
+        <source>New event</source>
+        <translation type="unfinished">Nouvel évènement</translation>
+    </message>
+</context>
+<context>
+    <name>TownSpellsWidget</name>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="29"/>
+        <source>Spells</source>
+        <translation type="unfinished">Sorts</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="47"/>
+        <source>Customize spells</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="76"/>
+        <source>Level 1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="93"/>
+        <location filename="../inspector/townspellswidget.ui" line="139"/>
+        <location filename="../inspector/townspellswidget.ui" line="185"/>
+        <location filename="../inspector/townspellswidget.ui" line="231"/>
+        <location filename="../inspector/townspellswidget.ui" line="277"/>
+        <source>Spell that may appear in mage guild</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="100"/>
+        <location filename="../inspector/townspellswidget.ui" line="146"/>
+        <location filename="../inspector/townspellswidget.ui" line="192"/>
+        <location filename="../inspector/townspellswidget.ui" line="238"/>
+        <location filename="../inspector/townspellswidget.ui" line="284"/>
+        <source>Spell that must appear in mage guild</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="122"/>
+        <source>Level 2</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="168"/>
+        <source>Level 3</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="214"/>
+        <source>Level 4</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="260"/>
+        <source>Level 5</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>Translations</name>
@@ -1698,18 +1900,6 @@
         <source>Width</source>
         <translation>Largeur</translation>
     </message>
-    <message>
-        <source>S (36x36)</source>
-        <translation type="vanished">Petite (36x36)</translation>
-    </message>
-    <message>
-        <source>M (72x72)</source>
-        <translation type="vanished">Moyenne (72x72)</translation>
-    </message>
-    <message>
-        <source>L (108x108)</source>
-        <translation type="vanished">Grande (108x108)</translation>
-    </message>
     <message>
         <location filename="../windownewmap.ui" line="179"/>
         <source>XL (144x144)</source>

+ 211 - 21
mapeditor/translation/german.ts

@@ -715,7 +715,7 @@
 <context>
     <name>MapView</name>
     <message>
-        <location filename="../mapview.cpp" line="625"/>
+        <location filename="../mapview.cpp" line="626"/>
         <source>Can&apos;t place object</source>
         <translation>Objekt kann nicht platziert werden</translation>
     </message>
@@ -889,38 +889,38 @@
         <translation>Experte</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="36"/>
+        <location filename="../inspector/inspector.cpp" line="38"/>
         <source>Compliant</source>
         <translation>Konform</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="37"/>
+        <location filename="../inspector/inspector.cpp" line="39"/>
         <source>Friendly</source>
         <translation>Freundlich</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="38"/>
+        <location filename="../inspector/inspector.cpp" line="40"/>
         <source>Aggressive</source>
         <translation>Aggressiv</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="39"/>
+        <location filename="../inspector/inspector.cpp" line="41"/>
         <source>Hostile</source>
         <translation>Feindlich</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="40"/>
+        <location filename="../inspector/inspector.cpp" line="42"/>
         <source>Savage</source>
         <translation>Wild</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="843"/>
-        <location filename="../inspector/inspector.cpp" line="932"/>
+        <location filename="../inspector/inspector.cpp" line="847"/>
+        <location filename="../inspector/inspector.cpp" line="936"/>
         <source>neutral</source>
         <translation>neutral</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="841"/>
+        <location filename="../inspector/inspector.cpp" line="845"/>
         <source>UNFLAGGABLE</source>
         <translation>UNFLAGGBAR</translation>
     </message>
@@ -1435,6 +1435,208 @@
         <source>Buildings</source>
         <translation>Gebäude</translation>
     </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="53"/>
+        <source>Build all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="60"/>
+        <source>Demolish all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="67"/>
+        <source>Enable all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="74"/>
+        <source>Disable all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Type</source>
+        <translation type="unfinished">Typ</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Enabled</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Built</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>TownEventDialog</name>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="23"/>
+        <source>Town event</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="42"/>
+        <source>General</source>
+        <translation type="unfinished">Allgemein</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="57"/>
+        <source>Event name</source>
+        <translation type="unfinished">Name des Ereignisses</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="64"/>
+        <source>Type event message text</source>
+        <translation type="unfinished">Ereignistext eingeben</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="85"/>
+        <source>Day of first occurrence</source>
+        <translation type="unfinished">Tag des ersten Auftretens</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="99"/>
+        <source>Repeat after (0 = no repeat)</source>
+        <translation type="unfinished">Wiederholung nach (0 = keine Wiederholung)</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="123"/>
+        <source>Affected players</source>
+        <translation type="unfinished">Betroffene Spieler</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="146"/>
+        <source>affects human</source>
+        <translation type="unfinished">beeinflusst Menschen</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="155"/>
+        <source>affects AI</source>
+        <translation type="unfinished">beeinflusst KI</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="166"/>
+        <source>Resources</source>
+        <translation type="unfinished">Ressourcen</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="198"/>
+        <source>Buildings</source>
+        <translation type="unfinished">Gebäude</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="216"/>
+        <source>Creatures</source>
+        <translation type="unfinished">Kreaturen</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="255"/>
+        <source>OK</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.cpp" line="177"/>
+        <source>Creature level %1 / Creature level %1 Upgrade</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.cpp" line="219"/>
+        <source>Day %1 - %2</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>TownEventsWidget</name>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="29"/>
+        <source>Town events</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="37"/>
+        <source>Timed events</source>
+        <translation type="unfinished">Zeitlich begrenzte Ereignisse</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="63"/>
+        <source>Add</source>
+        <translation type="unfinished">Hinzufügen</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="76"/>
+        <source>Remove</source>
+        <translation type="unfinished">Entfernen</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.cpp" line="105"/>
+        <source>Day %1 - %2</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.cpp" line="126"/>
+        <source>New event</source>
+        <translation type="unfinished">Neues Ereignis</translation>
+    </message>
+</context>
+<context>
+    <name>TownSpellsWidget</name>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="29"/>
+        <source>Spells</source>
+        <translation type="unfinished">Zaubersprüche</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="47"/>
+        <source>Customize spells</source>
+        <translation type="unfinished">Zaubersprüche anpassen</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="76"/>
+        <source>Level 1</source>
+        <translation type="unfinished">Level 1</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="93"/>
+        <location filename="../inspector/townspellswidget.ui" line="139"/>
+        <location filename="../inspector/townspellswidget.ui" line="185"/>
+        <location filename="../inspector/townspellswidget.ui" line="231"/>
+        <location filename="../inspector/townspellswidget.ui" line="277"/>
+        <source>Spell that may appear in mage guild</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="100"/>
+        <location filename="../inspector/townspellswidget.ui" line="146"/>
+        <location filename="../inspector/townspellswidget.ui" line="192"/>
+        <location filename="../inspector/townspellswidget.ui" line="238"/>
+        <location filename="../inspector/townspellswidget.ui" line="284"/>
+        <source>Spell that must appear in mage guild</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="122"/>
+        <source>Level 2</source>
+        <translation type="unfinished">Level 2</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="168"/>
+        <source>Level 3</source>
+        <translation type="unfinished">Level 3</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="214"/>
+        <source>Level 4</source>
+        <translation type="unfinished">Level 4</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="260"/>
+        <source>Level 5</source>
+        <translation type="unfinished">Level 5</translation>
+    </message>
 </context>
 <context>
     <name>Translations</name>
@@ -1698,18 +1900,6 @@
         <source>Width</source>
         <translation>Breite</translation>
     </message>
-    <message>
-        <source>S (36x36)</source>
-        <translation type="vanished">S (36x36)</translation>
-    </message>
-    <message>
-        <source>M (72x72)</source>
-        <translation type="vanished">M (72x72)</translation>
-    </message>
-    <message>
-        <source>L (108x108)</source>
-        <translation type="vanished">L (108x108)</translation>
-    </message>
     <message>
         <location filename="../windownewmap.ui" line="179"/>
         <source>XL (144x144)</source>

+ 211 - 21
mapeditor/translation/polish.ts

@@ -715,7 +715,7 @@
 <context>
     <name>MapView</name>
     <message>
-        <location filename="../mapview.cpp" line="625"/>
+        <location filename="../mapview.cpp" line="626"/>
         <source>Can&apos;t place object</source>
         <translation>Nie można umieścić obiektu</translation>
     </message>
@@ -889,38 +889,38 @@
         <translation>Ekspert</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="36"/>
+        <location filename="../inspector/inspector.cpp" line="38"/>
         <source>Compliant</source>
         <translation>Przyjazny</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="37"/>
+        <location filename="../inspector/inspector.cpp" line="39"/>
         <source>Friendly</source>
         <translation>Przychylny</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="38"/>
+        <location filename="../inspector/inspector.cpp" line="40"/>
         <source>Aggressive</source>
         <translation>Agresywny</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="39"/>
+        <location filename="../inspector/inspector.cpp" line="41"/>
         <source>Hostile</source>
         <translation>Wrogi</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="40"/>
+        <location filename="../inspector/inspector.cpp" line="42"/>
         <source>Savage</source>
         <translation>Nienawistny</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="843"/>
-        <location filename="../inspector/inspector.cpp" line="932"/>
+        <location filename="../inspector/inspector.cpp" line="847"/>
+        <location filename="../inspector/inspector.cpp" line="936"/>
         <source>neutral</source>
         <translation>neutralny</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="841"/>
+        <location filename="../inspector/inspector.cpp" line="845"/>
         <source>UNFLAGGABLE</source>
         <translation>NIEOFLAGOWYWALNY</translation>
     </message>
@@ -1435,6 +1435,208 @@
         <source>Buildings</source>
         <translation>Budynki</translation>
     </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="53"/>
+        <source>Build all</source>
+        <translation>Zbuduj wsyzstkie</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="60"/>
+        <source>Demolish all</source>
+        <translation>Zburz wszystkie</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="67"/>
+        <source>Enable all</source>
+        <translation>Włącz wszystkie</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="74"/>
+        <source>Disable all</source>
+        <translation>Wyłącz wszystkie</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Type</source>
+        <translation>Typ</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Enabled</source>
+        <translation>Włączony</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Built</source>
+        <translation>Zbudowany</translation>
+    </message>
+</context>
+<context>
+    <name>TownEventDialog</name>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="23"/>
+        <source>Town event</source>
+        <translation>Zdarzenie miasta</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="42"/>
+        <source>General</source>
+        <translation>Ogólne</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="57"/>
+        <source>Event name</source>
+        <translation>Nazwa zdarzenia</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="64"/>
+        <source>Type event message text</source>
+        <translation>Wpisz treść komunikatu zdarzenia</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="85"/>
+        <source>Day of first occurrence</source>
+        <translation>Dzień pierwszego wystąpienia</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="99"/>
+        <source>Repeat after (0 = no repeat)</source>
+        <translation>Powtórz po... (0 = nigdy)</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="123"/>
+        <source>Affected players</source>
+        <translation>Dotyczy graczy</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="146"/>
+        <source>affects human</source>
+        <translation>dotyczy graczy ludzkich</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="155"/>
+        <source>affects AI</source>
+        <translation>dotyczy graczy AI</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="166"/>
+        <source>Resources</source>
+        <translation>Zasoby</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="198"/>
+        <source>Buildings</source>
+        <translation>Budynki</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="216"/>
+        <source>Creatures</source>
+        <translation>Stworzenia</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="255"/>
+        <source>OK</source>
+        <translation>OK</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.cpp" line="177"/>
+        <source>Creature level %1 / Creature level %1 Upgrade</source>
+        <translation>Stworzenie poziomu %1 / Ulepszone stworzenie poziomu %1</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.cpp" line="219"/>
+        <source>Day %1 - %2</source>
+        <translation>Dzień %1 - %2</translation>
+    </message>
+</context>
+<context>
+    <name>TownEventsWidget</name>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="29"/>
+        <source>Town events</source>
+        <translation>Zdarzenia miasta</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="37"/>
+        <source>Timed events</source>
+        <translation>Zdarzenia czasowe</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="63"/>
+        <source>Add</source>
+        <translation>Dodaj</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="76"/>
+        <source>Remove</source>
+        <translation>Usuń</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.cpp" line="105"/>
+        <source>Day %1 - %2</source>
+        <translation>Dzień %1 - %2</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.cpp" line="126"/>
+        <source>New event</source>
+        <translation>Nowe zdarzenie</translation>
+    </message>
+</context>
+<context>
+    <name>TownSpellsWidget</name>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="29"/>
+        <source>Spells</source>
+        <translation>Zaklęcia</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="47"/>
+        <source>Customize spells</source>
+        <translation>Własne zaklęcia</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="76"/>
+        <source>Level 1</source>
+        <translation>Poziom 1</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="93"/>
+        <location filename="../inspector/townspellswidget.ui" line="139"/>
+        <location filename="../inspector/townspellswidget.ui" line="185"/>
+        <location filename="../inspector/townspellswidget.ui" line="231"/>
+        <location filename="../inspector/townspellswidget.ui" line="277"/>
+        <source>Spell that may appear in mage guild</source>
+        <translation>Zaklecia, które mogą pojawić się w gildii magów</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="100"/>
+        <location filename="../inspector/townspellswidget.ui" line="146"/>
+        <location filename="../inspector/townspellswidget.ui" line="192"/>
+        <location filename="../inspector/townspellswidget.ui" line="238"/>
+        <location filename="../inspector/townspellswidget.ui" line="284"/>
+        <source>Spell that must appear in mage guild</source>
+        <translation>Zaklecia, które muszą pojawić się w gildii magów</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="122"/>
+        <source>Level 2</source>
+        <translation>Poziom 2</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="168"/>
+        <source>Level 3</source>
+        <translation>Poziom 3</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="214"/>
+        <source>Level 4</source>
+        <translation>Poziom 4</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="260"/>
+        <source>Level 5</source>
+        <translation>Poziom 5</translation>
+    </message>
 </context>
 <context>
     <name>Translations</name>
@@ -1698,18 +1900,6 @@
         <source>Width</source>
         <translation>Szerokość</translation>
     </message>
-    <message>
-        <source>S (36x36)</source>
-        <translation type="vanished">S (36x36)</translation>
-    </message>
-    <message>
-        <source>M (72x72)</source>
-        <translation type="vanished">M (72x72)</translation>
-    </message>
-    <message>
-        <source>L (108x108)</source>
-        <translation type="vanished">L (108x108)</translation>
-    </message>
     <message>
         <location filename="../windownewmap.ui" line="179"/>
         <source>XL (144x144)</source>

+ 211 - 21
mapeditor/translation/portuguese.ts

@@ -715,7 +715,7 @@
 <context>
     <name>MapView</name>
     <message>
-        <location filename="../mapview.cpp" line="625"/>
+        <location filename="../mapview.cpp" line="626"/>
         <source>Can&apos;t place object</source>
         <translation>Não é possível colocar objeto</translation>
     </message>
@@ -889,38 +889,38 @@
         <translation>Experiente</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="36"/>
+        <location filename="../inspector/inspector.cpp" line="38"/>
         <source>Compliant</source>
         <translation>Conformista</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="37"/>
+        <location filename="../inspector/inspector.cpp" line="39"/>
         <source>Friendly</source>
         <translation>Amigável</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="38"/>
+        <location filename="../inspector/inspector.cpp" line="40"/>
         <source>Aggressive</source>
         <translation>Agressivo</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="39"/>
+        <location filename="../inspector/inspector.cpp" line="41"/>
         <source>Hostile</source>
         <translation>Hostil</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="40"/>
+        <location filename="../inspector/inspector.cpp" line="42"/>
         <source>Savage</source>
         <translation>Selvagem</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="843"/>
-        <location filename="../inspector/inspector.cpp" line="932"/>
+        <location filename="../inspector/inspector.cpp" line="847"/>
+        <location filename="../inspector/inspector.cpp" line="936"/>
         <source>neutral</source>
         <translation>neutro</translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="841"/>
+        <location filename="../inspector/inspector.cpp" line="845"/>
         <source>UNFLAGGABLE</source>
         <translation>NÃO TEM BANDEIRA</translation>
     </message>
@@ -1435,6 +1435,208 @@
         <source>Buildings</source>
         <translation>Estruturas</translation>
     </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="53"/>
+        <source>Build all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="60"/>
+        <source>Demolish all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="67"/>
+        <source>Enable all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="74"/>
+        <source>Disable all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Type</source>
+        <translation type="unfinished">Tipo</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Enabled</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Built</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>TownEventDialog</name>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="23"/>
+        <source>Town event</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="42"/>
+        <source>General</source>
+        <translation type="unfinished">Geral</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="57"/>
+        <source>Event name</source>
+        <translation type="unfinished">Nome do evento</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="64"/>
+        <source>Type event message text</source>
+        <translation type="unfinished">Introduza o texto da mensagem do evento</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="85"/>
+        <source>Day of first occurrence</source>
+        <translation type="unfinished">Dia da primeira ocorrência</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="99"/>
+        <source>Repeat after (0 = no repeat)</source>
+        <translation type="unfinished">Repetir após (0 = não repetir)</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="123"/>
+        <source>Affected players</source>
+        <translation type="unfinished">Jogadores afetados</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="146"/>
+        <source>affects human</source>
+        <translation type="unfinished">afeta humano</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="155"/>
+        <source>affects AI</source>
+        <translation type="unfinished">afeta IA</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="166"/>
+        <source>Resources</source>
+        <translation type="unfinished">Recursos</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="198"/>
+        <source>Buildings</source>
+        <translation type="unfinished">Estruturas</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="216"/>
+        <source>Creatures</source>
+        <translation type="unfinished">Criaturas</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="255"/>
+        <source>OK</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.cpp" line="177"/>
+        <source>Creature level %1 / Creature level %1 Upgrade</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.cpp" line="219"/>
+        <source>Day %1 - %2</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>TownEventsWidget</name>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="29"/>
+        <source>Town events</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="37"/>
+        <source>Timed events</source>
+        <translation type="unfinished">Eventos Temporizados</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="63"/>
+        <source>Add</source>
+        <translation type="unfinished">Adicionar</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="76"/>
+        <source>Remove</source>
+        <translation type="unfinished">Remover</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.cpp" line="105"/>
+        <source>Day %1 - %2</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.cpp" line="126"/>
+        <source>New event</source>
+        <translation type="unfinished">Novo Evento</translation>
+    </message>
+</context>
+<context>
+    <name>TownSpellsWidget</name>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="29"/>
+        <source>Spells</source>
+        <translation type="unfinished">Feitiços</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="47"/>
+        <source>Customize spells</source>
+        <translation type="unfinished">Personalizar feitiços</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="76"/>
+        <source>Level 1</source>
+        <translation type="unfinished">Nível 1</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="93"/>
+        <location filename="../inspector/townspellswidget.ui" line="139"/>
+        <location filename="../inspector/townspellswidget.ui" line="185"/>
+        <location filename="../inspector/townspellswidget.ui" line="231"/>
+        <location filename="../inspector/townspellswidget.ui" line="277"/>
+        <source>Spell that may appear in mage guild</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="100"/>
+        <location filename="../inspector/townspellswidget.ui" line="146"/>
+        <location filename="../inspector/townspellswidget.ui" line="192"/>
+        <location filename="../inspector/townspellswidget.ui" line="238"/>
+        <location filename="../inspector/townspellswidget.ui" line="284"/>
+        <source>Spell that must appear in mage guild</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="122"/>
+        <source>Level 2</source>
+        <translation type="unfinished">Nível 2</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="168"/>
+        <source>Level 3</source>
+        <translation type="unfinished">Nível 3</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="214"/>
+        <source>Level 4</source>
+        <translation type="unfinished">Nível 4</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="260"/>
+        <source>Level 5</source>
+        <translation type="unfinished">Nível 5</translation>
+    </message>
 </context>
 <context>
     <name>Translations</name>
@@ -1698,18 +1900,6 @@
         <source>Width</source>
         <translation>Largura</translation>
     </message>
-    <message>
-        <source>S (36x36)</source>
-        <translation type="vanished">P (36x36)</translation>
-    </message>
-    <message>
-        <source>M (72x72)</source>
-        <translation type="vanished">M (72x72)</translation>
-    </message>
-    <message>
-        <source>L (108x108)</source>
-        <translation type="vanished">G (108x108)</translation>
-    </message>
     <message>
         <location filename="../windownewmap.ui" line="179"/>
         <source>XL (144x144)</source>

+ 211 - 21
mapeditor/translation/russian.ts

@@ -715,7 +715,7 @@
 <context>
     <name>MapView</name>
     <message>
-        <location filename="../mapview.cpp" line="625"/>
+        <location filename="../mapview.cpp" line="626"/>
         <source>Can&apos;t place object</source>
         <translation type="unfinished"></translation>
     </message>
@@ -889,38 +889,38 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="36"/>
+        <location filename="../inspector/inspector.cpp" line="38"/>
         <source>Compliant</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="37"/>
+        <location filename="../inspector/inspector.cpp" line="39"/>
         <source>Friendly</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="38"/>
+        <location filename="../inspector/inspector.cpp" line="40"/>
         <source>Aggressive</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="39"/>
+        <location filename="../inspector/inspector.cpp" line="41"/>
         <source>Hostile</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="40"/>
+        <location filename="../inspector/inspector.cpp" line="42"/>
         <source>Savage</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="843"/>
-        <location filename="../inspector/inspector.cpp" line="932"/>
+        <location filename="../inspector/inspector.cpp" line="847"/>
+        <location filename="../inspector/inspector.cpp" line="936"/>
         <source>neutral</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="841"/>
+        <location filename="../inspector/inspector.cpp" line="845"/>
         <source>UNFLAGGABLE</source>
         <translation type="unfinished"></translation>
     </message>
@@ -1435,6 +1435,208 @@
         <source>Buildings</source>
         <translation>Постройки</translation>
     </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="53"/>
+        <source>Build all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="60"/>
+        <source>Demolish all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="67"/>
+        <source>Enable all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="74"/>
+        <source>Disable all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Type</source>
+        <translation type="unfinished">Тип</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Enabled</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Built</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>TownEventDialog</name>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="23"/>
+        <source>Town event</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="42"/>
+        <source>General</source>
+        <translation type="unfinished">Общее</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="57"/>
+        <source>Event name</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="64"/>
+        <source>Type event message text</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="85"/>
+        <source>Day of first occurrence</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="99"/>
+        <source>Repeat after (0 = no repeat)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="123"/>
+        <source>Affected players</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="146"/>
+        <source>affects human</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="155"/>
+        <source>affects AI</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="166"/>
+        <source>Resources</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="198"/>
+        <source>Buildings</source>
+        <translation type="unfinished">Постройки</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="216"/>
+        <source>Creatures</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="255"/>
+        <source>OK</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.cpp" line="177"/>
+        <source>Creature level %1 / Creature level %1 Upgrade</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.cpp" line="219"/>
+        <source>Day %1 - %2</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>TownEventsWidget</name>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="29"/>
+        <source>Town events</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="37"/>
+        <source>Timed events</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="63"/>
+        <source>Add</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="76"/>
+        <source>Remove</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.cpp" line="105"/>
+        <source>Day %1 - %2</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.cpp" line="126"/>
+        <source>New event</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>TownSpellsWidget</name>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="29"/>
+        <source>Spells</source>
+        <translation type="unfinished">Заклинания</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="47"/>
+        <source>Customize spells</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="76"/>
+        <source>Level 1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="93"/>
+        <location filename="../inspector/townspellswidget.ui" line="139"/>
+        <location filename="../inspector/townspellswidget.ui" line="185"/>
+        <location filename="../inspector/townspellswidget.ui" line="231"/>
+        <location filename="../inspector/townspellswidget.ui" line="277"/>
+        <source>Spell that may appear in mage guild</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="100"/>
+        <location filename="../inspector/townspellswidget.ui" line="146"/>
+        <location filename="../inspector/townspellswidget.ui" line="192"/>
+        <location filename="../inspector/townspellswidget.ui" line="238"/>
+        <location filename="../inspector/townspellswidget.ui" line="284"/>
+        <source>Spell that must appear in mage guild</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="122"/>
+        <source>Level 2</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="168"/>
+        <source>Level 3</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="214"/>
+        <source>Level 4</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="260"/>
+        <source>Level 5</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>Translations</name>
@@ -1698,18 +1900,6 @@
         <source>Width</source>
         <translation>Ширина</translation>
     </message>
-    <message>
-        <source>S (36x36)</source>
-        <translation type="vanished">Мал. (36x36)</translation>
-    </message>
-    <message>
-        <source>M (72x72)</source>
-        <translation type="vanished">Ср. (72x72)</translation>
-    </message>
-    <message>
-        <source>L (108x108)</source>
-        <translation type="vanished">Бол. (108x108)</translation>
-    </message>
     <message>
         <location filename="../windownewmap.ui" line="179"/>
         <source>XL (144x144)</source>

+ 211 - 21
mapeditor/translation/spanish.ts

@@ -715,7 +715,7 @@
 <context>
     <name>MapView</name>
     <message>
-        <location filename="../mapview.cpp" line="625"/>
+        <location filename="../mapview.cpp" line="626"/>
         <source>Can&apos;t place object</source>
         <translation type="unfinished"></translation>
     </message>
@@ -889,38 +889,38 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="36"/>
+        <location filename="../inspector/inspector.cpp" line="38"/>
         <source>Compliant</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="37"/>
+        <location filename="../inspector/inspector.cpp" line="39"/>
         <source>Friendly</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="38"/>
+        <location filename="../inspector/inspector.cpp" line="40"/>
         <source>Aggressive</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="39"/>
+        <location filename="../inspector/inspector.cpp" line="41"/>
         <source>Hostile</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="40"/>
+        <location filename="../inspector/inspector.cpp" line="42"/>
         <source>Savage</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="843"/>
-        <location filename="../inspector/inspector.cpp" line="932"/>
+        <location filename="../inspector/inspector.cpp" line="847"/>
+        <location filename="../inspector/inspector.cpp" line="936"/>
         <source>neutral</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="841"/>
+        <location filename="../inspector/inspector.cpp" line="845"/>
         <source>UNFLAGGABLE</source>
         <translation type="unfinished"></translation>
     </message>
@@ -1435,6 +1435,208 @@
         <source>Buildings</source>
         <translation>Edificios</translation>
     </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="53"/>
+        <source>Build all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="60"/>
+        <source>Demolish all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="67"/>
+        <source>Enable all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="74"/>
+        <source>Disable all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Type</source>
+        <translation type="unfinished">Tipo</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Enabled</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Built</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>TownEventDialog</name>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="23"/>
+        <source>Town event</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="42"/>
+        <source>General</source>
+        <translation type="unfinished">General</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="57"/>
+        <source>Event name</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="64"/>
+        <source>Type event message text</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="85"/>
+        <source>Day of first occurrence</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="99"/>
+        <source>Repeat after (0 = no repeat)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="123"/>
+        <source>Affected players</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="146"/>
+        <source>affects human</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="155"/>
+        <source>affects AI</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="166"/>
+        <source>Resources</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="198"/>
+        <source>Buildings</source>
+        <translation type="unfinished">Edificios</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="216"/>
+        <source>Creatures</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="255"/>
+        <source>OK</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.cpp" line="177"/>
+        <source>Creature level %1 / Creature level %1 Upgrade</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.cpp" line="219"/>
+        <source>Day %1 - %2</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>TownEventsWidget</name>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="29"/>
+        <source>Town events</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="37"/>
+        <source>Timed events</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="63"/>
+        <source>Add</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="76"/>
+        <source>Remove</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.cpp" line="105"/>
+        <source>Day %1 - %2</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.cpp" line="126"/>
+        <source>New event</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>TownSpellsWidget</name>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="29"/>
+        <source>Spells</source>
+        <translation type="unfinished">Hechizos</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="47"/>
+        <source>Customize spells</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="76"/>
+        <source>Level 1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="93"/>
+        <location filename="../inspector/townspellswidget.ui" line="139"/>
+        <location filename="../inspector/townspellswidget.ui" line="185"/>
+        <location filename="../inspector/townspellswidget.ui" line="231"/>
+        <location filename="../inspector/townspellswidget.ui" line="277"/>
+        <source>Spell that may appear in mage guild</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="100"/>
+        <location filename="../inspector/townspellswidget.ui" line="146"/>
+        <location filename="../inspector/townspellswidget.ui" line="192"/>
+        <location filename="../inspector/townspellswidget.ui" line="238"/>
+        <location filename="../inspector/townspellswidget.ui" line="284"/>
+        <source>Spell that must appear in mage guild</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="122"/>
+        <source>Level 2</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="168"/>
+        <source>Level 3</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="214"/>
+        <source>Level 4</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="260"/>
+        <source>Level 5</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>Translations</name>
@@ -1698,18 +1900,6 @@
         <source>Width</source>
         <translation>Ancho</translation>
     </message>
-    <message>
-        <source>S (36x36)</source>
-        <translation type="vanished">S (36x36)</translation>
-    </message>
-    <message>
-        <source>M (72x72)</source>
-        <translation type="vanished">M (72x72)</translation>
-    </message>
-    <message>
-        <source>L (108x108)</source>
-        <translation type="vanished">L (108x108)</translation>
-    </message>
     <message>
         <location filename="../windownewmap.ui" line="179"/>
         <source>XL (144x144)</source>

+ 211 - 21
mapeditor/translation/ukrainian.ts

@@ -715,7 +715,7 @@
 <context>
     <name>MapView</name>
     <message>
-        <location filename="../mapview.cpp" line="625"/>
+        <location filename="../mapview.cpp" line="626"/>
         <source>Can&apos;t place object</source>
         <translation type="unfinished"></translation>
     </message>
@@ -889,38 +889,38 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="36"/>
+        <location filename="../inspector/inspector.cpp" line="38"/>
         <source>Compliant</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="37"/>
+        <location filename="../inspector/inspector.cpp" line="39"/>
         <source>Friendly</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="38"/>
+        <location filename="../inspector/inspector.cpp" line="40"/>
         <source>Aggressive</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="39"/>
+        <location filename="../inspector/inspector.cpp" line="41"/>
         <source>Hostile</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="40"/>
+        <location filename="../inspector/inspector.cpp" line="42"/>
         <source>Savage</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="843"/>
-        <location filename="../inspector/inspector.cpp" line="932"/>
+        <location filename="../inspector/inspector.cpp" line="847"/>
+        <location filename="../inspector/inspector.cpp" line="936"/>
         <source>neutral</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="841"/>
+        <location filename="../inspector/inspector.cpp" line="845"/>
         <source>UNFLAGGABLE</source>
         <translation type="unfinished"></translation>
     </message>
@@ -1435,6 +1435,208 @@
         <source>Buildings</source>
         <translation>Будівлі</translation>
     </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="53"/>
+        <source>Build all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="60"/>
+        <source>Demolish all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="67"/>
+        <source>Enable all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="74"/>
+        <source>Disable all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Type</source>
+        <translation type="unfinished">Тип</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Enabled</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Built</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>TownEventDialog</name>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="23"/>
+        <source>Town event</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="42"/>
+        <source>General</source>
+        <translation type="unfinished">Загальний</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="57"/>
+        <source>Event name</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="64"/>
+        <source>Type event message text</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="85"/>
+        <source>Day of first occurrence</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="99"/>
+        <source>Repeat after (0 = no repeat)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="123"/>
+        <source>Affected players</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="146"/>
+        <source>affects human</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="155"/>
+        <source>affects AI</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="166"/>
+        <source>Resources</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="198"/>
+        <source>Buildings</source>
+        <translation type="unfinished">Будівлі</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="216"/>
+        <source>Creatures</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="255"/>
+        <source>OK</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.cpp" line="177"/>
+        <source>Creature level %1 / Creature level %1 Upgrade</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.cpp" line="219"/>
+        <source>Day %1 - %2</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>TownEventsWidget</name>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="29"/>
+        <source>Town events</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="37"/>
+        <source>Timed events</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="63"/>
+        <source>Add</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="76"/>
+        <source>Remove</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.cpp" line="105"/>
+        <source>Day %1 - %2</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.cpp" line="126"/>
+        <source>New event</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>TownSpellsWidget</name>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="29"/>
+        <source>Spells</source>
+        <translation type="unfinished">Закляття</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="47"/>
+        <source>Customize spells</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="76"/>
+        <source>Level 1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="93"/>
+        <location filename="../inspector/townspellswidget.ui" line="139"/>
+        <location filename="../inspector/townspellswidget.ui" line="185"/>
+        <location filename="../inspector/townspellswidget.ui" line="231"/>
+        <location filename="../inspector/townspellswidget.ui" line="277"/>
+        <source>Spell that may appear in mage guild</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="100"/>
+        <location filename="../inspector/townspellswidget.ui" line="146"/>
+        <location filename="../inspector/townspellswidget.ui" line="192"/>
+        <location filename="../inspector/townspellswidget.ui" line="238"/>
+        <location filename="../inspector/townspellswidget.ui" line="284"/>
+        <source>Spell that must appear in mage guild</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="122"/>
+        <source>Level 2</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="168"/>
+        <source>Level 3</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="214"/>
+        <source>Level 4</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="260"/>
+        <source>Level 5</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>Translations</name>
@@ -1698,18 +1900,6 @@
         <source>Width</source>
         <translation>Ширина</translation>
     </message>
-    <message>
-        <source>S (36x36)</source>
-        <translation type="vanished">М (36x36)</translation>
-    </message>
-    <message>
-        <source>M (72x72)</source>
-        <translation type="vanished">С (72x72)</translation>
-    </message>
-    <message>
-        <source>L (108x108)</source>
-        <translation type="vanished">В (108x108)</translation>
-    </message>
     <message>
         <location filename="../windownewmap.ui" line="179"/>
         <source>XL (144x144)</source>

+ 211 - 21
mapeditor/translation/vietnamese.ts

@@ -715,7 +715,7 @@
 <context>
     <name>MapView</name>
     <message>
-        <location filename="../mapview.cpp" line="625"/>
+        <location filename="../mapview.cpp" line="626"/>
         <source>Can&apos;t place object</source>
         <translation>Không thể đặt vật thể</translation>
     </message>
@@ -889,38 +889,38 @@
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="36"/>
+        <location filename="../inspector/inspector.cpp" line="38"/>
         <source>Compliant</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="37"/>
+        <location filename="../inspector/inspector.cpp" line="39"/>
         <source>Friendly</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="38"/>
+        <location filename="../inspector/inspector.cpp" line="40"/>
         <source>Aggressive</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="39"/>
+        <location filename="../inspector/inspector.cpp" line="41"/>
         <source>Hostile</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="40"/>
+        <location filename="../inspector/inspector.cpp" line="42"/>
         <source>Savage</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="843"/>
-        <location filename="../inspector/inspector.cpp" line="932"/>
+        <location filename="../inspector/inspector.cpp" line="847"/>
+        <location filename="../inspector/inspector.cpp" line="936"/>
         <source>neutral</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../inspector/inspector.cpp" line="841"/>
+        <location filename="../inspector/inspector.cpp" line="845"/>
         <source>UNFLAGGABLE</source>
         <translation type="unfinished"></translation>
     </message>
@@ -1435,6 +1435,208 @@
         <source>Buildings</source>
         <translation>Công trình</translation>
     </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="53"/>
+        <source>Build all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="60"/>
+        <source>Demolish all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="67"/>
+        <source>Enable all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.ui" line="74"/>
+        <source>Disable all</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Type</source>
+        <translation type="unfinished">Loại</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Enabled</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townbuildingswidget.cpp" line="77"/>
+        <source>Built</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>TownEventDialog</name>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="23"/>
+        <source>Town event</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="42"/>
+        <source>General</source>
+        <translation type="unfinished">Chung</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="57"/>
+        <source>Event name</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="64"/>
+        <source>Type event message text</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="85"/>
+        <source>Day of first occurrence</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="99"/>
+        <source>Repeat after (0 = no repeat)</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="123"/>
+        <source>Affected players</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="146"/>
+        <source>affects human</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="155"/>
+        <source>affects AI</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="166"/>
+        <source>Resources</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="198"/>
+        <source>Buildings</source>
+        <translation type="unfinished">Công trình</translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="216"/>
+        <source>Creatures</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.ui" line="255"/>
+        <source>OK</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.cpp" line="177"/>
+        <source>Creature level %1 / Creature level %1 Upgrade</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventdialog.cpp" line="219"/>
+        <source>Day %1 - %2</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>TownEventsWidget</name>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="29"/>
+        <source>Town events</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="37"/>
+        <source>Timed events</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="63"/>
+        <source>Add</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.ui" line="76"/>
+        <source>Remove</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.cpp" line="105"/>
+        <source>Day %1 - %2</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/towneventswidget.cpp" line="126"/>
+        <source>New event</source>
+        <translation type="unfinished"></translation>
+    </message>
+</context>
+<context>
+    <name>TownSpellsWidget</name>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="29"/>
+        <source>Spells</source>
+        <translation type="unfinished">Phép</translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="47"/>
+        <source>Customize spells</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="76"/>
+        <source>Level 1</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="93"/>
+        <location filename="../inspector/townspellswidget.ui" line="139"/>
+        <location filename="../inspector/townspellswidget.ui" line="185"/>
+        <location filename="../inspector/townspellswidget.ui" line="231"/>
+        <location filename="../inspector/townspellswidget.ui" line="277"/>
+        <source>Spell that may appear in mage guild</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="100"/>
+        <location filename="../inspector/townspellswidget.ui" line="146"/>
+        <location filename="../inspector/townspellswidget.ui" line="192"/>
+        <location filename="../inspector/townspellswidget.ui" line="238"/>
+        <location filename="../inspector/townspellswidget.ui" line="284"/>
+        <source>Spell that must appear in mage guild</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="122"/>
+        <source>Level 2</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="168"/>
+        <source>Level 3</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="214"/>
+        <source>Level 4</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../inspector/townspellswidget.ui" line="260"/>
+        <source>Level 5</source>
+        <translation type="unfinished"></translation>
+    </message>
 </context>
 <context>
     <name>Translations</name>
@@ -1698,18 +1900,6 @@
         <source>Width</source>
         <translation>Rộng</translation>
     </message>
-    <message>
-        <source>S (36x36)</source>
-        <translation type="vanished">Nhỏ (36x36)</translation>
-    </message>
-    <message>
-        <source>M (72x72)</source>
-        <translation type="vanished">Vừa (72x72)</translation>
-    </message>
-    <message>
-        <source>L (108x108)</source>
-        <translation type="vanished">Lớn (108x108)</translation>
-    </message>
     <message>
         <location filename="../windownewmap.ui" line="179"/>
         <source>XL (144x144)</source>

+ 3 - 3
server/CGameHandler.cpp

@@ -3424,7 +3424,7 @@ void CGameHandler::handleTimeEvents()
 
 void CGameHandler::handleTownEvents(CGTownInstance * town, NewTurn &n)
 {
-	town->events.sort(evntCmp);
+	std::sort(town->events.begin(), town->events.end(), evntCmp);
 	while(town->events.size() && town->events.front().firstOccurrence == gs->day)
 	{
 		PlayerColor player = town->tempOwner;
@@ -3485,7 +3485,7 @@ void CGameHandler::handleTownEvents(CGTownInstance * town, NewTurn &n)
 
 		if (ev.nextOccurrence)
 		{
-			town->events.pop_front();
+			town->events.erase(town->events.begin());
 
 			ev.firstOccurrence += ev.nextOccurrence;
 			auto it = town->events.begin();
@@ -3495,7 +3495,7 @@ void CGameHandler::handleTownEvents(CGTownInstance * town, NewTurn &n)
 		}
 		else
 		{
-			town->events.pop_front();
+			town->events.erase(town->events.begin());
 		}
 	}