mirror of
https://github.com/vcmi/vcmi.git
synced 2025-06-17 00:07:41 +02:00
Merge pull request #4439 from IvanSavenko/event_timing
Trigger map and town events on start of player turn
This commit is contained in:
@ -44,8 +44,7 @@ DisposedHero::DisposedHero() : heroId(0), portrait(255)
|
|||||||
}
|
}
|
||||||
|
|
||||||
CMapEvent::CMapEvent()
|
CMapEvent::CMapEvent()
|
||||||
: players(0)
|
: humanAffected(false)
|
||||||
, humanAffected(false)
|
|
||||||
, computerAffected(false)
|
, computerAffected(false)
|
||||||
, firstOccurrence(0)
|
, firstOccurrence(0)
|
||||||
, nextOccurrence(0)
|
, nextOccurrence(0)
|
||||||
@ -53,21 +52,51 @@ CMapEvent::CMapEvent()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CMapEvent::earlierThan(const CMapEvent & other) const
|
bool CMapEvent::occursToday(int currentDay) const
|
||||||
{
|
{
|
||||||
return firstOccurrence < other.firstOccurrence;
|
if (currentDay == firstOccurrence + 1)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (nextOccurrence == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (currentDay < firstOccurrence)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return (currentDay - firstOccurrence - 1) % nextOccurrence == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CMapEvent::earlierThanOrEqual(const CMapEvent & other) const
|
bool CMapEvent::affectsPlayer(PlayerColor color, bool isHuman) const
|
||||||
{
|
{
|
||||||
return firstOccurrence <= other.firstOccurrence;
|
if (players.count(color) == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!isHuman && !computerAffected)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (isHuman && !humanAffected)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMapEvent::serializeJson(JsonSerializeFormat & handler)
|
void CMapEvent::serializeJson(JsonSerializeFormat & handler)
|
||||||
{
|
{
|
||||||
handler.serializeString("name", name);
|
handler.serializeString("name", name);
|
||||||
handler.serializeStruct("message", message);
|
handler.serializeStruct("message", message);
|
||||||
handler.serializeInt("players", players);
|
if (!handler.saving && handler.getCurrent()["players"].isNumber())
|
||||||
|
{
|
||||||
|
// compatibility for old maps
|
||||||
|
int playersMask = 0;
|
||||||
|
handler.serializeInt("players", playersMask);
|
||||||
|
for (int i = 0; i < 8; ++i)
|
||||||
|
if ((playersMask & (1 << i)) != 0)
|
||||||
|
players.insert(PlayerColor(i));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
handler.serializeIdArray("players", players);
|
||||||
|
}
|
||||||
handler.serializeInt("humanAffected", humanAffected);
|
handler.serializeInt("humanAffected", humanAffected);
|
||||||
handler.serializeInt("computerAffected", computerAffected);
|
handler.serializeInt("computerAffected", computerAffected);
|
||||||
handler.serializeInt("firstOccurrence", firstOccurrence);
|
handler.serializeInt("firstOccurrence", firstOccurrence);
|
||||||
|
@ -136,7 +136,7 @@ public:
|
|||||||
std::set<SpellID> allowedSpells;
|
std::set<SpellID> allowedSpells;
|
||||||
std::set<ArtifactID> allowedArtifact;
|
std::set<ArtifactID> allowedArtifact;
|
||||||
std::set<SecondarySkill> allowedAbilities;
|
std::set<SecondarySkill> allowedAbilities;
|
||||||
std::list<CMapEvent> events;
|
std::vector<CMapEvent> events;
|
||||||
int3 grailPos;
|
int3 grailPos;
|
||||||
int grailRadius;
|
int grailRadius;
|
||||||
|
|
||||||
|
@ -30,13 +30,13 @@ public:
|
|||||||
CMapEvent();
|
CMapEvent();
|
||||||
virtual ~CMapEvent() = default;
|
virtual ~CMapEvent() = default;
|
||||||
|
|
||||||
bool earlierThan(const CMapEvent & other) const;
|
bool occursToday(int currentDay) const;
|
||||||
bool earlierThanOrEqual(const CMapEvent & other) const;
|
bool affectsPlayer(PlayerColor player, bool isHuman) const;
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
MetaString message;
|
MetaString message;
|
||||||
TResources resources;
|
TResources resources;
|
||||||
ui8 players; // affected players, bit field?
|
std::set<PlayerColor> players;
|
||||||
bool humanAffected;
|
bool humanAffected;
|
||||||
bool computerAffected;
|
bool computerAffected;
|
||||||
ui32 firstOccurrence;
|
ui32 firstOccurrence;
|
||||||
@ -48,7 +48,18 @@ public:
|
|||||||
h & name;
|
h & name;
|
||||||
h & message;
|
h & message;
|
||||||
h & resources;
|
h & resources;
|
||||||
h & players;
|
if (h.version >= Handler::Version::EVENTS_PLAYER_SET)
|
||||||
|
{
|
||||||
|
h & players;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui8 playersMask = 0;
|
||||||
|
h & playersMask;
|
||||||
|
for (int i = 0; i < 8; ++i)
|
||||||
|
if ((playersMask & (1 << i)) != 0)
|
||||||
|
players.insert(PlayerColor(i));
|
||||||
|
}
|
||||||
h & humanAffected;
|
h & humanAffected;
|
||||||
h & computerAffected;
|
h & computerAffected;
|
||||||
h & firstOccurrence;
|
h & firstOccurrence;
|
||||||
|
@ -2244,7 +2244,7 @@ CGObjectInstance * CMapLoaderH3M::readTown(const int3 & position, std::shared_pt
|
|||||||
|
|
||||||
reader->readResources(event.resources);
|
reader->readResources(event.resources);
|
||||||
|
|
||||||
event.players = reader->readUInt8();
|
reader->readBitmaskPlayers(event.players, false);
|
||||||
if(features.levelSOD)
|
if(features.levelSOD)
|
||||||
event.humanAffected = reader->readBool();
|
event.humanAffected = reader->readBool();
|
||||||
else
|
else
|
||||||
@ -2313,7 +2313,7 @@ void CMapLoaderH3M::readEvents()
|
|||||||
event.message.appendTextID(readLocalizedString(TextIdentifier("event", eventID, "description")));
|
event.message.appendTextID(readLocalizedString(TextIdentifier("event", eventID, "description")));
|
||||||
|
|
||||||
reader->readResources(event.resources);
|
reader->readResources(event.resources);
|
||||||
event.players = reader->readUInt8();
|
reader->readBitmaskPlayers(event.players, false);
|
||||||
if(features.levelSOD)
|
if(features.levelSOD)
|
||||||
{
|
{
|
||||||
event.humanAffected = reader->readBool();
|
event.humanAffected = reader->readBool();
|
||||||
|
@ -55,8 +55,6 @@ public:
|
|||||||
virtual void visitSetCommanderProperty(SetCommanderProperty & pack) {}
|
virtual void visitSetCommanderProperty(SetCommanderProperty & pack) {}
|
||||||
virtual void visitAddQuest(AddQuest & pack) {}
|
virtual void visitAddQuest(AddQuest & pack) {}
|
||||||
virtual void visitUpdateArtHandlerLists(UpdateArtHandlerLists & pack) {}
|
virtual void visitUpdateArtHandlerLists(UpdateArtHandlerLists & pack) {}
|
||||||
virtual void visitUpdateMapEvents(UpdateMapEvents & pack) {}
|
|
||||||
virtual void visitUpdateCastleEvents(UpdateCastleEvents & pack) {}
|
|
||||||
virtual void visitChangeFormation(ChangeFormation & pack) {}
|
virtual void visitChangeFormation(ChangeFormation & pack) {}
|
||||||
virtual void visitRemoveObject(RemoveObject & pack) {}
|
virtual void visitRemoveObject(RemoveObject & pack) {}
|
||||||
virtual void visitTryMoveHero(TryMoveHero & pack) {}
|
virtual void visitTryMoveHero(TryMoveHero & pack) {}
|
||||||
|
@ -225,16 +225,6 @@ void UpdateArtHandlerLists::visitTyped(ICPackVisitor & visitor)
|
|||||||
visitor.visitUpdateArtHandlerLists(*this);
|
visitor.visitUpdateArtHandlerLists(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateMapEvents::visitTyped(ICPackVisitor & visitor)
|
|
||||||
{
|
|
||||||
visitor.visitUpdateMapEvents(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdateCastleEvents::visitTyped(ICPackVisitor & visitor)
|
|
||||||
{
|
|
||||||
visitor.visitUpdateCastleEvents(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChangeFormation::visitTyped(ICPackVisitor & visitor)
|
void ChangeFormation::visitTyped(ICPackVisitor & visitor)
|
||||||
{
|
{
|
||||||
visitor.visitChangeFormation(*this);
|
visitor.visitChangeFormation(*this);
|
||||||
@ -907,17 +897,6 @@ void UpdateArtHandlerLists::applyGs(CGameState * gs) const
|
|||||||
gs->allocatedArtifacts = allocatedArtifacts;
|
gs->allocatedArtifacts = allocatedArtifacts;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateMapEvents::applyGs(CGameState * gs) const
|
|
||||||
{
|
|
||||||
gs->map->events = events;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdateCastleEvents::applyGs(CGameState * gs) const
|
|
||||||
{
|
|
||||||
auto * t = gs->getTown(town);
|
|
||||||
t->events = events;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChangeFormation::applyGs(CGameState * gs) const
|
void ChangeFormation::applyGs(CGameState * gs) const
|
||||||
{
|
{
|
||||||
gs->getHero(hid)->setFormation(formation);
|
gs->getHero(hid)->setFormation(formation);
|
||||||
|
@ -545,34 +545,6 @@ struct DLL_LINKAGE UpdateArtHandlerLists : public CPackForClient
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DLL_LINKAGE UpdateMapEvents : public CPackForClient
|
|
||||||
{
|
|
||||||
std::list<CMapEvent> events;
|
|
||||||
|
|
||||||
void applyGs(CGameState * gs) const;
|
|
||||||
void visitTyped(ICPackVisitor & visitor) override;
|
|
||||||
|
|
||||||
template <typename Handler> void serialize(Handler & h)
|
|
||||||
{
|
|
||||||
h & events;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DLL_LINKAGE UpdateCastleEvents : public CPackForClient
|
|
||||||
{
|
|
||||||
ObjectInstanceID town;
|
|
||||||
std::vector<CCastleEvent> events;
|
|
||||||
|
|
||||||
void applyGs(CGameState * gs) const;
|
|
||||||
void visitTyped(ICPackVisitor & visitor) override;
|
|
||||||
|
|
||||||
template <typename Handler> void serialize(Handler & h)
|
|
||||||
{
|
|
||||||
h & town;
|
|
||||||
h & events;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DLL_LINKAGE ChangeFormation : public CPackForClient
|
struct DLL_LINKAGE ChangeFormation : public CPackForClient
|
||||||
{
|
{
|
||||||
ObjectInstanceID hid;
|
ObjectInstanceID hid;
|
||||||
|
@ -44,8 +44,6 @@ void registerTypesClientPacks(Serializer &s)
|
|||||||
s.template registerType<CPackForClient, PlayerReinitInterface>();
|
s.template registerType<CPackForClient, PlayerReinitInterface>();
|
||||||
s.template registerType<CPackForClient, RemoveBonus>();
|
s.template registerType<CPackForClient, RemoveBonus>();
|
||||||
s.template registerType<CPackForClient, UpdateArtHandlerLists>();
|
s.template registerType<CPackForClient, UpdateArtHandlerLists>();
|
||||||
s.template registerType<CPackForClient, UpdateMapEvents>();
|
|
||||||
s.template registerType<CPackForClient, UpdateCastleEvents>();
|
|
||||||
s.template registerType<CPackForClient, ChangeFormation>();
|
s.template registerType<CPackForClient, ChangeFormation>();
|
||||||
s.template registerType<CPackForClient, RemoveObject>();
|
s.template registerType<CPackForClient, RemoveObject>();
|
||||||
s.template registerType<CPackForClient, TryMoveHero>();
|
s.template registerType<CPackForClient, TryMoveHero>();
|
||||||
|
@ -50,6 +50,7 @@ enum class ESerializationVersion : int32_t
|
|||||||
BANK_UNIT_PLACEMENT, // 843 Banks have unit placement flag
|
BANK_UNIT_PLACEMENT, // 843 Banks have unit placement flag
|
||||||
|
|
||||||
RELEASE_152 = BANK_UNIT_PLACEMENT,
|
RELEASE_152 = BANK_UNIT_PLACEMENT,
|
||||||
|
RELEASE_156 = BANK_UNIT_PLACEMENT,
|
||||||
|
|
||||||
COMPACT_STRING_SERIALIZATION, // 844 - optimized serialization of previously encountered strings
|
COMPACT_STRING_SERIALIZATION, // 844 - optimized serialization of previously encountered strings
|
||||||
COMPACT_INTEGER_SERIALIZATION, // 845 - serialize integers in forms similar to protobuf
|
COMPACT_INTEGER_SERIALIZATION, // 845 - serialize integers in forms similar to protobuf
|
||||||
@ -61,6 +62,7 @@ enum class ESerializationVersion : int32_t
|
|||||||
PLAYER_HANDICAP, // 851 - player handicap selection at game start
|
PLAYER_HANDICAP, // 851 - player handicap selection at game start
|
||||||
STATISTICS, // 852 - removed random number generators from library classes
|
STATISTICS, // 852 - removed random number generators from library classes
|
||||||
CAMPAIGN_REGIONS, // 853 - configurable campaign regions
|
CAMPAIGN_REGIONS, // 853 - configurable campaign regions
|
||||||
|
EVENTS_PLAYER_SET, // 854 - map & town events use std::set instead of bitmask to store player list
|
||||||
|
|
||||||
CURRENT = CAMPAIGN_REGIONS
|
CURRENT = EVENTS_PLAYER_SET
|
||||||
};
|
};
|
||||||
|
@ -69,7 +69,7 @@ QVariant toVariant(const CCastleEvent& event)
|
|||||||
QVariantMap result;
|
QVariantMap result;
|
||||||
result["name"] = QString::fromStdString(event.name);
|
result["name"] = QString::fromStdString(event.name);
|
||||||
result["message"] = QString::fromStdString(event.message.toString());
|
result["message"] = QString::fromStdString(event.message.toString());
|
||||||
result["players"] = QVariant::fromValue(event.players);
|
result["players"] = toVariant(event.players);
|
||||||
result["humanAffected"] = QVariant::fromValue(event.humanAffected);
|
result["humanAffected"] = QVariant::fromValue(event.humanAffected);
|
||||||
result["computerAffected"] = QVariant::fromValue(event.computerAffected);
|
result["computerAffected"] = QVariant::fromValue(event.computerAffected);
|
||||||
result["firstOccurrence"] = QVariant::fromValue(event.firstOccurrence);
|
result["firstOccurrence"] = QVariant::fromValue(event.firstOccurrence);
|
||||||
@ -87,7 +87,7 @@ CCastleEvent eventFromVariant(CMapHeader& map, const CGTownInstance& town, const
|
|||||||
auto v = variant.toMap();
|
auto v = variant.toMap();
|
||||||
result.name = v.value("name").toString().toStdString();
|
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.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.players = playersFromVariant(v.value("players"));
|
||||||
result.humanAffected = v.value("humanAffected").toInt();
|
result.humanAffected = v.value("humanAffected").toInt();
|
||||||
result.computerAffected = v.value("computerAffected").toInt();
|
result.computerAffected = v.value("computerAffected").toInt();
|
||||||
result.firstOccurrence = v.value("firstOccurrence").toInt();
|
result.firstOccurrence = v.value("firstOccurrence").toInt();
|
||||||
|
@ -16,6 +16,24 @@
|
|||||||
#include "../../lib/constants/NumericConstants.h"
|
#include "../../lib/constants/NumericConstants.h"
|
||||||
#include "../../lib/constants/StringConstants.h"
|
#include "../../lib/constants/StringConstants.h"
|
||||||
|
|
||||||
|
QVariant toVariant(const std::set<PlayerColor> & players)
|
||||||
|
{
|
||||||
|
QVariantList result;
|
||||||
|
for(auto const id : players)
|
||||||
|
result.push_back(QString::fromStdString(id.toString()));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::set<PlayerColor> playersFromVariant(const QVariant & v)
|
||||||
|
{
|
||||||
|
std::set<PlayerColor> result;
|
||||||
|
|
||||||
|
for(auto const & id : v.toList())
|
||||||
|
result.insert(PlayerColor(PlayerColor::decode(id.toString().toStdString())));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
QVariant toVariant(const TResources & resources)
|
QVariant toVariant(const TResources & resources)
|
||||||
{
|
{
|
||||||
QVariantMap result;
|
QVariantMap result;
|
||||||
@ -30,7 +48,6 @@ TResources resourcesFromVariant(const QVariant & v)
|
|||||||
for(auto r : v.toMap().keys())
|
for(auto r : v.toMap().keys())
|
||||||
vJson[r.toStdString()].Integer() = v.toMap().value(r).toInt();
|
vJson[r.toStdString()].Integer() = v.toMap().value(r).toInt();
|
||||||
return TResources(vJson);
|
return TResources(vJson);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant toVariant(const CMapEvent & event)
|
QVariant toVariant(const CMapEvent & event)
|
||||||
@ -38,7 +55,7 @@ QVariant toVariant(const CMapEvent & event)
|
|||||||
QVariantMap result;
|
QVariantMap result;
|
||||||
result["name"] = QString::fromStdString(event.name);
|
result["name"] = QString::fromStdString(event.name);
|
||||||
result["message"] = QString::fromStdString(event.message.toString());
|
result["message"] = QString::fromStdString(event.message.toString());
|
||||||
result["players"] = QVariant::fromValue(event.players);
|
result["players"] = toVariant(event.players);
|
||||||
result["humanAffected"] = QVariant::fromValue(event.humanAffected);
|
result["humanAffected"] = QVariant::fromValue(event.humanAffected);
|
||||||
result["computerAffected"] = QVariant::fromValue(event.computerAffected);
|
result["computerAffected"] = QVariant::fromValue(event.computerAffected);
|
||||||
result["firstOccurrence"] = QVariant::fromValue(event.firstOccurrence);
|
result["firstOccurrence"] = QVariant::fromValue(event.firstOccurrence);
|
||||||
@ -53,7 +70,7 @@ CMapEvent eventFromVariant(CMapHeader & mapHeader, const QVariant & variant)
|
|||||||
auto v = variant.toMap();
|
auto v = variant.toMap();
|
||||||
result.name = v.value("name").toString().toStdString();
|
result.name = v.value("name").toString().toStdString();
|
||||||
result.message.appendTextID(mapRegisterLocalizedString("map", mapHeader, TextIdentifier("header", "event", result.name, "message"), v.value("message").toString().toStdString()));
|
result.message.appendTextID(mapRegisterLocalizedString("map", mapHeader, TextIdentifier("header", "event", result.name, "message"), v.value("message").toString().toStdString()));
|
||||||
result.players = v.value("players").toInt();
|
result.players = playersFromVariant(v.value("players"));
|
||||||
result.humanAffected = v.value("humanAffected").toInt();
|
result.humanAffected = v.value("humanAffected").toInt();
|
||||||
result.computerAffected = v.value("computerAffected").toInt();
|
result.computerAffected = v.value("computerAffected").toInt();
|
||||||
result.firstOccurrence = v.value("firstOccurrence").toInt();
|
result.firstOccurrence = v.value("firstOccurrence").toInt();
|
||||||
|
@ -16,7 +16,10 @@ class EventSettings;
|
|||||||
}
|
}
|
||||||
|
|
||||||
QVariant toVariant(const TResources & resources);
|
QVariant toVariant(const TResources & resources);
|
||||||
|
QVariant toVariant(const std::set<PlayerColor> & players);
|
||||||
|
|
||||||
TResources resourcesFromVariant(const QVariant & v);
|
TResources resourcesFromVariant(const QVariant & v);
|
||||||
|
std::set<PlayerColor> playersFromVariant(const QVariant & v);
|
||||||
|
|
||||||
class EventSettings : public AbstractSettings
|
class EventSettings : public AbstractSettings
|
||||||
{
|
{
|
||||||
|
@ -584,11 +584,6 @@ void CGameHandler::init(StartInfo *si, Load::ProgressAccumulator & progressTrack
|
|||||||
reinitScripting();
|
reinitScripting();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool evntCmp(const CMapEvent &a, const CMapEvent &b)
|
|
||||||
{
|
|
||||||
return a.earlierThan(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CGameHandler::setPortalDwelling(const CGTownInstance * town, bool forced=false, bool clear = false)
|
void CGameHandler::setPortalDwelling(const CGTownInstance * town, bool forced=false, bool clear = false)
|
||||||
{// bool forced = true - if creature should be replaced, if false - only if no creature was set
|
{// bool forced = true - if creature should be replaced, if false - only if no creature was set
|
||||||
|
|
||||||
@ -635,6 +630,11 @@ void CGameHandler::onPlayerTurnStarted(PlayerColor which)
|
|||||||
{
|
{
|
||||||
events::PlayerGotTurn::defaultExecute(serverEventBus.get(), which);
|
events::PlayerGotTurn::defaultExecute(serverEventBus.get(), which);
|
||||||
turnTimerHandler->onPlayerGetTurn(which);
|
turnTimerHandler->onPlayerGetTurn(which);
|
||||||
|
|
||||||
|
handleTimeEvents(which);
|
||||||
|
|
||||||
|
for (auto t : getPlayerState(which)->towns)
|
||||||
|
handleTownEvents(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameHandler::onPlayerTurnEnded(PlayerColor which)
|
void CGameHandler::onPlayerTurnEnded(PlayerColor which)
|
||||||
@ -860,7 +860,6 @@ void CGameHandler::onNewTurn()
|
|||||||
for (CGTownInstance *t : gs->map->towns)
|
for (CGTownInstance *t : gs->map->towns)
|
||||||
{
|
{
|
||||||
PlayerColor player = t->tempOwner;
|
PlayerColor player = t->tempOwner;
|
||||||
handleTownEvents(t, n);
|
|
||||||
if (newWeek) //first day of week
|
if (newWeek) //first day of week
|
||||||
{
|
{
|
||||||
if (t->hasBuilt(BuildingSubID::PORTAL_OF_SUMMONING))
|
if (t->hasBuilt(BuildingSubID::PORTAL_OF_SUMMONING))
|
||||||
@ -1017,7 +1016,6 @@ void CGameHandler::onNewTurn()
|
|||||||
checkVictoryLossConditionsForAll(); // check for map turn limit
|
checkVictoryLossConditionsForAll(); // check for map turn limit
|
||||||
|
|
||||||
logGlobal->trace("Info about turn %d has been sent!", n.day);
|
logGlobal->trace("Info about turn %d has been sent!", n.day);
|
||||||
handleTimeEvents();
|
|
||||||
//call objects
|
//call objects
|
||||||
for (auto & elem : gs->map->objects)
|
for (auto & elem : gs->map->objects)
|
||||||
{
|
{
|
||||||
@ -3406,148 +3404,87 @@ bool CGameHandler::queryReply(QueryID qid, std::optional<int32_t> answer, Player
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameHandler::handleTimeEvents()
|
void CGameHandler::handleTimeEvents(PlayerColor color)
|
||||||
{
|
{
|
||||||
gs->map->events.sort(evntCmp);
|
for (auto const & event : gs->map->events)
|
||||||
while(gs->map->events.size() && gs->map->events.front().firstOccurrence+1 == gs->day)
|
|
||||||
{
|
{
|
||||||
CMapEvent ev = gs->map->events.front();
|
if (!event.occursToday(gs->day))
|
||||||
|
continue;
|
||||||
|
|
||||||
for (int player = 0; player < PlayerColor::PLAYER_LIMIT_I; player++)
|
if (!event.affectsPlayer(color, getPlayerState(color)->isHuman()))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
InfoWindow iw;
|
||||||
|
iw.player = color;
|
||||||
|
iw.text = event.message;
|
||||||
|
|
||||||
|
//give resources
|
||||||
|
if (!event.resources.empty())
|
||||||
{
|
{
|
||||||
auto color = PlayerColor(player);
|
giveResources(color, event.resources);
|
||||||
|
for (GameResID i : GameResID::ALL_RESOURCES())
|
||||||
const PlayerState * pinfo = getPlayerState(color, false); //do not output error if player does not exist
|
if (event.resources[i])
|
||||||
|
iw.components.emplace_back(ComponentType::RESOURCE, i, event.resources[i]);
|
||||||
if (pinfo //player exists
|
|
||||||
&& (ev.players & 1<<player) //event is enabled to this player
|
|
||||||
&& ((ev.computerAffected && !pinfo->human)
|
|
||||||
|| (ev.humanAffected && pinfo->human)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
{
|
|
||||||
//give resources
|
|
||||||
giveResources(color, ev.resources);
|
|
||||||
|
|
||||||
//prepare dialog
|
|
||||||
InfoWindow iw;
|
|
||||||
iw.player = color;
|
|
||||||
iw.text = ev.message;
|
|
||||||
|
|
||||||
for (GameResID i : GameResID::ALL_RESOURCES())
|
|
||||||
{
|
|
||||||
if (ev.resources[i]) //if resource is changed, we add it to the dialog
|
|
||||||
iw.components.emplace_back(ComponentType::RESOURCE, i, ev.resources[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
sendAndApply(&iw); //show dialog
|
|
||||||
}
|
|
||||||
} //PLAYERS LOOP
|
|
||||||
|
|
||||||
if (ev.nextOccurrence)
|
|
||||||
{
|
|
||||||
gs->map->events.pop_front();
|
|
||||||
|
|
||||||
ev.firstOccurrence += ev.nextOccurrence;
|
|
||||||
auto it = gs->map->events.begin();
|
|
||||||
while(it != gs->map->events.end() && it->earlierThanOrEqual(ev))
|
|
||||||
it++;
|
|
||||||
gs->map->events.insert(it, ev);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gs->map->events.pop_front();
|
|
||||||
}
|
}
|
||||||
|
sendAndApply(&iw); //show dialog
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO send only if changed
|
|
||||||
UpdateMapEvents ume;
|
|
||||||
ume.events = gs->map->events;
|
|
||||||
sendAndApply(&ume);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameHandler::handleTownEvents(CGTownInstance * town, NewTurn &n)
|
void CGameHandler::handleTownEvents(CGTownInstance * town)
|
||||||
{
|
{
|
||||||
std::sort(town->events.begin(), town->events.end(), evntCmp);
|
for (auto const & event : town->events)
|
||||||
while(town->events.size() && town->events.front().firstOccurrence == gs->day)
|
|
||||||
{
|
{
|
||||||
PlayerColor player = town->tempOwner;
|
if (!event.occursToday(gs->day))
|
||||||
CCastleEvent ev = town->events.front();
|
continue;
|
||||||
const PlayerState * pinfo = getPlayerState(player, false);
|
|
||||||
|
|
||||||
if (pinfo //player exists
|
PlayerColor player = town->getOwner();
|
||||||
&& (ev.players & 1<<player.getNum()) //event is enabled to this player
|
if (!event.affectsPlayer(player, getPlayerState(player)->isHuman()))
|
||||||
&& ((ev.computerAffected && !pinfo->human)
|
continue;
|
||||||
|| (ev.humanAffected && pinfo->human)))
|
|
||||||
|
// dialog
|
||||||
|
InfoWindow iw;
|
||||||
|
iw.player = player;
|
||||||
|
iw.text = event.message;
|
||||||
|
|
||||||
|
if (event.resources.nonZero())
|
||||||
{
|
{
|
||||||
// dialog
|
giveResources(player, event.resources);
|
||||||
InfoWindow iw;
|
|
||||||
iw.player = player;
|
|
||||||
iw.text = ev.message;
|
|
||||||
|
|
||||||
if (ev.resources.nonZero())
|
for (GameResID i : GameResID::ALL_RESOURCES())
|
||||||
|
if (event.resources[i])
|
||||||
|
iw.components.emplace_back(ComponentType::RESOURCE, i, event.resources[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto & i : event.buildings)
|
||||||
|
{
|
||||||
|
// Only perform action if:
|
||||||
|
// 1. Building exists in town (don't attempt to build Lvl 5 guild in Fortress
|
||||||
|
// 2. Building was not built yet
|
||||||
|
// othervice, silently ignore / skip it
|
||||||
|
if (town->town->buildings.count(i) && !town->hasBuilt(i))
|
||||||
{
|
{
|
||||||
TResources was = n.res[player];
|
buildStructure(town->id, i, true);
|
||||||
n.res[player] += ev.resources;
|
iw.components.emplace_back(ComponentType::BUILDING, BuildingTypeUniqueID(town->getFaction(), i));
|
||||||
n.res[player].amax(0);
|
|
||||||
|
|
||||||
for (GameResID i : GameResID::ALL_RESOURCES())
|
|
||||||
if (ev.resources[i] && pinfo->resources[i] != n.res.at(player)[i]) //if resource had changed, we add it to the dialog
|
|
||||||
iw.components.emplace_back(ComponentType::RESOURCE, i, n.res.at(player)[i] - was[i]);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (auto & i : ev.buildings)
|
if (!event.creatures.empty())
|
||||||
|
{
|
||||||
|
SetAvailableCreatures sac;
|
||||||
|
sac.tid = town->id;
|
||||||
|
sac.creatures = town->creatures;
|
||||||
|
|
||||||
|
for (si32 i=0;i<event.creatures.size();i++) //creature growths
|
||||||
{
|
{
|
||||||
// Only perform action if:
|
if (!town->creatures.at(i).second.empty() && event.creatures.at(i) > 0)//there is dwelling
|
||||||
// 1. Building exists in town (don't attempt to build Lvl 5 guild in Fortress
|
|
||||||
// 2. Building was not built yet
|
|
||||||
// othervice, silently ignore / skip it
|
|
||||||
if (town->town->buildings.count(i) && !town->hasBuilt(i))
|
|
||||||
{
|
{
|
||||||
buildStructure(town->id, i, true);
|
sac.creatures[i].first += event.creatures.at(i);
|
||||||
iw.components.emplace_back(ComponentType::BUILDING, BuildingTypeUniqueID(town->getFaction(), i));
|
iw.components.emplace_back(ComponentType::CREATURE, town->creatures.at(i).second.back(), event.creatures.at(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ev.creatures.empty() && !vstd::contains(n.cres, town->id))
|
|
||||||
{
|
|
||||||
n.cres[town->id].tid = town->id;
|
|
||||||
n.cres[town->id].creatures = town->creatures;
|
|
||||||
}
|
|
||||||
auto & sac = n.cres[town->id];
|
|
||||||
|
|
||||||
for (si32 i=0;i<ev.creatures.size();i++) //creature growths
|
|
||||||
{
|
|
||||||
if (!town->creatures.at(i).second.empty() && ev.creatures.at(i) > 0)//there is dwelling
|
|
||||||
{
|
|
||||||
sac.creatures[i].first += ev.creatures.at(i);
|
|
||||||
iw.components.emplace_back(ComponentType::CREATURE, town->creatures.at(i).second.back(), ev.creatures.at(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sendAndApply(&iw); //show dialog
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ev.nextOccurrence)
|
|
||||||
{
|
|
||||||
town->events.erase(town->events.begin());
|
|
||||||
|
|
||||||
ev.firstOccurrence += ev.nextOccurrence;
|
|
||||||
auto it = town->events.begin();
|
|
||||||
while(it != town->events.end() && it->earlierThanOrEqual(ev))
|
|
||||||
it++;
|
|
||||||
town->events.insert(it, ev);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
town->events.erase(town->events.begin());
|
|
||||||
}
|
}
|
||||||
|
sendAndApply(&iw); //show dialog
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO send only if changed
|
|
||||||
UpdateCastleEvents uce;
|
|
||||||
uce.town = town->id;
|
|
||||||
uce.events = town->events;
|
|
||||||
sendAndApply(&uce);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CGameHandler::complain(const std::string &problem)
|
bool CGameHandler::complain(const std::string &problem)
|
||||||
|
@ -229,8 +229,8 @@ public:
|
|||||||
void onNewTurn();
|
void onNewTurn();
|
||||||
void addStatistics();
|
void addStatistics();
|
||||||
|
|
||||||
void handleTimeEvents();
|
void handleTimeEvents(PlayerColor player);
|
||||||
void handleTownEvents(CGTownInstance *town, NewTurn &n);
|
void handleTownEvents(CGTownInstance *town);
|
||||||
bool complain(const std::string &problem); //sends message to all clients, prints on the logs and return true
|
bool complain(const std::string &problem); //sends message to all clients, prints on the logs and return true
|
||||||
void objectVisited( const CGObjectInstance * obj, const CGHeroInstance * h );
|
void objectVisited( const CGObjectInstance * obj, const CGHeroInstance * h );
|
||||||
void objectVisitEnded(const CObjectVisitQuery &query);
|
void objectVisitEnded(const CObjectVisitQuery &query);
|
||||||
|
Reference in New Issue
Block a user