1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-10 00:43:59 +02:00

Merge pull request #5030 from vcmi/timed_events_objects_removal

Timed events objects removal
This commit is contained in:
Ivan Savenko 2024-12-06 16:07:21 +02:00 committed by GitHub
commit 3115894307
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 198 additions and 17 deletions

View File

@ -403,6 +403,18 @@ void CPlayerInterface::heroKilled(const CGHeroInstance* hero)
localState->erasePath(hero);
}
void CPlayerInterface::townRemoved(const CGTownInstance* town)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
if(town->tempOwner == playerID)
{
localState->removeOwnedTown(town);
adventureInt->onTownChanged(town);
}
}
void CPlayerInterface::heroVisit(const CGHeroInstance * visitor, const CGObjectInstance * visitedObj, bool start)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
@ -1424,6 +1436,12 @@ void CPlayerInterface::objectRemoved(const CGObjectInstance * obj, const PlayerC
const CGHeroInstance * h = static_cast<const CGHeroInstance *>(obj);
heroKilled(h);
}
if(obj->ID == Obj::TOWN && obj->tempOwner == playerID)
{
const CGTownInstance * t = static_cast<const CGTownInstance *>(obj);
townRemoved(t);
}
GH.fakeMouseMove();
}

View File

@ -220,6 +220,7 @@ private:
};
void heroKilled(const CGHeroInstance* hero);
void townRemoved(const CGTownInstance* town);
void garrisonsChanged(std::vector<const CArmedInstance *> objs);
void requestReturningToMainMenu(bool won);
void acceptTurn(QueryID queryID, bool hotseatWait); //used during hot seat after your turn message is close

View File

@ -378,6 +378,9 @@ void CGTownInstance::onHeroLeave(const CGHeroInstance * h) const
std::string CGTownInstance::getObjectName() const
{
if(ID == Obj::RANDOM_TOWN )
return CGObjectInstance::getObjectName();
return getNameTranslated() + ", " + getTown()->faction->getNameTranslated();
}

View File

@ -51,6 +51,12 @@ void FlaggableMapObject::onHeroVisit( const CGHeroInstance * h ) const
giveBonusTo(h->getOwner());
}
void FlaggableMapObject::markAsDeleted() const
{
if(getOwner().isValidPlayer())
takeBonusFrom(getOwner());
}
void FlaggableMapObject::initObj(vstd::RNG & rand)
{
if(getOwner().isValidPlayer())

View File

@ -28,6 +28,7 @@ public:
using CGObjectInstance::CGObjectInstance;
void onHeroVisit(const CGHeroInstance * h) const override;
void markAsDeleted() const;
void initObj(vstd::RNG & rand) override;
const IOwnableObject * asOwnable() const final;

View File

@ -103,6 +103,9 @@ void CMapEvent::serializeJson(JsonSerializeFormat & handler)
handler.serializeInt("firstOccurrence", firstOccurrence);
handler.serializeInt("nextOccurrence", nextOccurrence);
resources.serializeJson(handler, "resources");
auto deletedObjects = handler.enterArray("deletedObjectsInstances");
deletedObjects.serializeArray(deletedObjectsInstances);
}
void CCastleEvent::serializeJson(JsonSerializeFormat & handler)

View File

@ -12,6 +12,7 @@
#include "../ResourceSet.h"
#include "../texts/MetaString.h"
#include "../int3.h"
VCMI_LIB_NAMESPACE_BEGIN
@ -42,6 +43,8 @@ public:
ui32 firstOccurrence;
ui32 nextOccurrence; /// specifies after how many days the event will occur the next time; 0 if event occurs only one time
std::vector<ObjectInstanceID> deletedObjectsInstances;
template <typename Handler>
void serialize(Handler & h)
{
@ -64,6 +67,10 @@ public:
h & computerAffected;
h & firstOccurrence;
h & nextOccurrence;
if(h.version >= Handler::Version::EVENT_OBJECTS_DELETION)
{
h & deletedObjectsInstances;
}
}
virtual void serializeJson(JsonSerializeFormat & handler);

View File

@ -45,6 +45,7 @@
#include "mapObjectConstructors/CObjectClassesHandler.h"
#include "campaign/CampaignState.h"
#include "IGameSettings.h"
#include "mapObjects/FlaggableMapObject.h"
VCMI_LIB_NAMESPACE_BEGIN
@ -1184,7 +1185,6 @@ void RemoveBonus::applyGs(CGameState *gs)
void RemoveObject::applyGs(CGameState *gs)
{
CGObjectInstance *obj = gs->getObjInstance(objectID);
logGlobal->debug("removing object id=%d; address=%x; name=%s", objectID, (intptr_t)obj, obj->getObjectName());
//unblock tiles
@ -1197,10 +1197,7 @@ void RemoveObject::applyGs(CGameState *gs)
{
auto * beatenHero = dynamic_cast<CGHeroInstance *>(obj);
assert(beatenHero);
PlayerState * p = gs->getPlayerState(beatenHero->tempOwner);
gs->map->heroesOnMap -= beatenHero;
p->removeOwnedObject(beatenHero);
auto * siegeNode = beatenHero->whereShouldBeAttachedOnSiege(gs);
@ -1254,6 +1251,18 @@ void RemoveObject::applyGs(CGameState *gs)
}
}
if(obj->getOwner().isValidPlayer())
{
gs->getPlayerState(obj->getOwner())->removeOwnedObject(obj); //object removed via map event or hero got beaten
FlaggableMapObject* flaggableObject = dynamic_cast<FlaggableMapObject*>(obj);
if(flaggableObject)
{
flaggableObject->markAsDeleted();
}
}
gs->map->instanceNames.erase(obj->instanceName);
gs->map->objects[objectID.getNum()].dellNull();
gs->map->calculateGuardingGreaturePositions();//FIXME: excessive, update only affected tiles

View File

@ -69,6 +69,7 @@ enum class ESerializationVersion : int32_t
FOLDER_NAME_REWORK, // 870 - rework foldername
REWARDABLE_GUARDS, // 871 - fix missing serialization of guards in rewardable objects
MARKET_TRANSLATION_FIX, // 872 - remove serialization of markets translateable strings
EVENT_OBJECTS_DELETION, //873 - allow events to remove map objects
CURRENT = MARKET_TRANSLATION_FIX
CURRENT = EVENT_OBJECTS_DELETION
};

View File

@ -17,6 +17,7 @@ enum MapEditorRoles
PlayerIDRole,
BuildingIDRole,
SpellIDRole,
ObjectInstanceIDRole,
ArtifactIDRole,
ArtifactSlotRole
ArtifactSlotRole,
};

View File

@ -14,6 +14,8 @@
#include "../../lib/mapObjects/CGTownInstance.h"
#include "../../lib/mapObjects/CGHeroInstance.h"
Q_DECLARE_METATYPE(int3)
//parses date for lose condition (1m 1w 1d)
int expiredDate(const QString & date);
QString expiredDate(int date);

View File

@ -55,6 +55,28 @@ TResources resourcesFromVariant(const QVariant & v)
return TResources(vJson);
}
QVariant toVariant(std::vector<ObjectInstanceID> objects)
{
QVariantList result;
for(auto obj : objects)
{
result.push_back(QVariant::fromValue(obj.num));
}
return result;
}
std::vector<ObjectInstanceID> deletedObjectsIdsFromVariant(const QVariant & v)
{
std::vector<ObjectInstanceID> result;
for(auto idAsVariant : v.toList())
{
auto id = idAsVariant.value<int>();
result.push_back(ObjectInstanceID(id));
}
return result;
}
QVariant toVariant(const CMapEvent & event)
{
QVariantMap result;
@ -66,6 +88,7 @@ QVariant toVariant(const CMapEvent & event)
result["firstOccurrence"] = QVariant::fromValue(event.firstOccurrence);
result["nextOccurrence"] = QVariant::fromValue(event.nextOccurrence);
result["resources"] = toVariant(event.resources);
result["deletedObjectsInstances"] = toVariant(event.deletedObjectsInstances);
return QVariant(result);
}
@ -81,6 +104,7 @@ CMapEvent eventFromVariant(CMapHeader & mapHeader, const QVariant & variant)
result.firstOccurrence = v.value("firstOccurrence").toInt();
result.nextOccurrence = v.value("nextOccurrence").toInt();
result.resources = resourcesFromVariant(v.value("resources"));
result.deletedObjectsInstances = deletedObjectsIdsFromVariant(v.value("deletedObjectsInstances"));
return result;
}
@ -137,6 +161,6 @@ void EventSettings::on_timedEventRemove_clicked()
void EventSettings::on_eventsList_itemActivated(QListWidgetItem *item)
{
new TimedEvent(item, parentWidget());
new TimedEvent(*controller, item, parentWidget());
}

View File

@ -11,13 +11,15 @@
#include "timedevent.h"
#include "ui_timedevent.h"
#include "eventsettings.h"
#include "../mapeditorroles.h"
#include "../../lib/constants/EntityIdentifiers.h"
#include "../../lib/constants/StringConstants.h"
TimedEvent::TimedEvent(QListWidgetItem * t, QWidget *parent) :
TimedEvent::TimedEvent(MapController & c, QListWidgetItem * t, QWidget *parent) :
controller(c),
QDialog(parent),
target(t),
ui(new Ui::TimedEvent)
ui(new Ui::TimedEvent),
target(t)
{
ui->setupUi(this);
@ -51,7 +53,14 @@ TimedEvent::TimedEvent(QListWidgetItem * t, QWidget *parent) :
nval->setFlags(nval->flags() | Qt::ItemIsEditable);
ui->resources->setItem(i, 1, nval);
}
auto deletedObjectInstances = params.value("deletedObjectsInstances").toList();
for(auto const & idAsVariant : deletedObjectInstances)
{
auto id = ObjectInstanceID(idAsVariant.toInt());
auto obj = controller.map()->objects[id];
if(obj)
insertObjectToDelete(obj);
}
show();
}
@ -89,10 +98,63 @@ void TimedEvent::on_TimedEvent_finished(int result)
}
descriptor["resources"] = res;
QVariantList deletedObjects;
for(int i = 0; i < ui->deletedObjects->count(); ++i)
{
auto const & item = ui->deletedObjects->item(i);
auto data = item->data(MapEditorRoles::ObjectInstanceIDRole);
auto id = ObjectInstanceID(data.value<int>());
deletedObjects.push_back(QVariant::fromValue(id.num));
}
descriptor["deletedObjectsInstances"] = QVariant::fromValue(deletedObjects);
target->setData(Qt::UserRole, descriptor);
target->setText(ui->eventNameText->text());
}
void TimedEvent::on_addObjectToDelete_clicked()
{
for(int lvl : {0, 1})
{
auto & l = controller.scene(lvl)->objectPickerView;
l.highlight<const CGObjectInstance>();
l.update();
QObject::connect(&l, &ObjectPickerLayer::selectionMade, this, &TimedEvent::onObjectPicked);
}
hide();
dynamic_cast<QWidget *>(parent()->parent()->parent()->parent()->parent()->parent()->parent())->hide();
}
void TimedEvent::on_removeObjectToDelete_clicked()
{
delete ui->deletedObjects->takeItem(ui->deletedObjects->currentRow());
}
void TimedEvent::onObjectPicked(const CGObjectInstance * obj)
{
show();
dynamic_cast<QWidget *>(parent()->parent()->parent()->parent()->parent()->parent()->parent())->show();
for(int lvl : {0, 1})
{
auto & l = controller.scene(lvl)->objectPickerView;
l.clear();
l.update();
QObject::disconnect(&l, &ObjectPickerLayer::selectionMade, this, &TimedEvent::onObjectPicked);
}
if(!obj)
return;
insertObjectToDelete(obj);
}
void TimedEvent::insertObjectToDelete(const CGObjectInstance * obj)
{
QString objectLabel = QString("%1, x: %2, y: %3, z: %4").arg(QString::fromStdString(obj->getObjectName())).arg(obj->pos.x).arg(obj->pos.y).arg(obj->pos.z);
auto * item = new QListWidgetItem(objectLabel);
item->setData(MapEditorRoles::ObjectInstanceIDRole, QVariant::fromValue(obj->id.num));
ui->deletedObjects->addItem(item);
}
void TimedEvent::on_pushButton_clicked()
{

View File

@ -11,6 +11,8 @@
#include <QDialog>
#include "mapcontroller.h"
namespace Ui {
class TimedEvent;
}
@ -20,18 +22,23 @@ class TimedEvent : public QDialog
Q_OBJECT
public:
explicit TimedEvent(QListWidgetItem *, QWidget *parent = nullptr);
explicit TimedEvent(MapController & map, QListWidgetItem *, QWidget * parent = nullptr);
~TimedEvent();
private slots:
void on_TimedEvent_finished(int result);
void on_addObjectToDelete_clicked();
void on_removeObjectToDelete_clicked();
void onObjectPicked(const CGObjectInstance * obj);
void insertObjectToDelete(const CGObjectInstance * obj);
void on_pushButton_clicked();
void on_resources_itemDoubleClicked(QTableWidgetItem *item);
void on_resources_itemDoubleClicked(QTableWidgetItem * item);
private:
Ui::TimedEvent *ui;
MapController & controller;
Ui::TimedEvent * ui;
QListWidgetItem * target;
};

View File

@ -9,8 +9,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>620</width>
<height>371</height>
<width>730</width>
<height>422</height>
</rect>
</property>
<property name="windowTitle">
@ -201,6 +201,34 @@
</column>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="deletedObjectsLabel">
<property name="text">
<string>Objects to delete</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="addObjectToDelete">
<property name="text">
<string>Add</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="removeObjectToDelete">
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="deletedObjects"/>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">

View File

@ -787,7 +787,7 @@ bool CGameHandler::removeObject(const CGObjectInstance * obj, const PlayerColor
ro.initiator = initiator;
sendAndApply(ro);
checkVictoryLossConditionsForAll(); //eg if monster escaped (removing objs after battle is done dircetly by endBattle, not this function)
checkVictoryLossConditionsForAll(); //e.g. if monster escaped (removing objs after battle is done directly by endBattle, not this function)
return true;
}

View File

@ -61,6 +61,14 @@ void NewTurnProcessor::handleTimeEvents(PlayerColor color)
if (event.resources[i])
iw.components.emplace_back(ComponentType::RESOURCE, i, event.resources[i]);
}
//remove objects specified by event
for(const ObjectInstanceID objectIdToRemove : event.deletedObjectsInstances)
{
auto objectInstance = gameHandler->getObj(objectIdToRemove, false);
if(objectInstance != nullptr)
gameHandler->removeObject(objectInstance, PlayerColor::NEUTRAL);
}
gameHandler->sendAndApply(iw); //show dialog
}
}