mirror of
https://github.com/vcmi/vcmi.git
synced 2025-08-13 19:54:17 +02:00
New files for lib:
* lib/ERMScriptModule.cpp * lib/ERMScriptModule.h * lib/CObstacleInstance.h More jugglery with callbacks. Moving stuff from CGameState to CGameInfoCallback. Work on unified game events interface for player (AI or GUI) and script module. Directing events to ERM interpretetr, first attempts of calling some triggers. Crashy, if there any scripts. Some other changes, including fighting amount of includes in includes and tracking of hero visits (need further work).
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
#include "../../lib/VCMI_Lib.h"
|
||||
#include "../../lib/NetPacks.h"
|
||||
#include "AIPriorities.h"
|
||||
#include "../../lib/CGameState.h"
|
||||
|
||||
using std::endl;
|
||||
using geniusai::CGeniusAI;
|
||||
|
@@ -170,10 +170,10 @@ void CStupidAI::battleEnd(const BattleResult *br)
|
||||
print("battleEnd called");
|
||||
}
|
||||
|
||||
void CStupidAI::battleResultsApplied()
|
||||
{
|
||||
print("battleResultsApplied called");
|
||||
}
|
||||
// void CStupidAI::battleResultsApplied()
|
||||
// {
|
||||
// print("battleResultsApplied called");
|
||||
// }
|
||||
|
||||
void CStupidAI::battleNewRoundFirst(int round)
|
||||
{
|
||||
|
@@ -18,7 +18,7 @@ public:
|
||||
void battleAttack(const BattleAttack *ba) OVERRIDE; //called when stack is performing attack
|
||||
void battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa) OVERRIDE; //called when stack receives damage (after battleAttack())
|
||||
void battleEnd(const BattleResult *br) OVERRIDE;
|
||||
void battleResultsApplied() OVERRIDE; //called when all effects of last battle are applied
|
||||
//void battleResultsApplied() OVERRIDE; //called when all effects of last battle are applied
|
||||
void battleNewRoundFirst(int round) OVERRIDE; //called at the beginning of each turn before changes are applied;
|
||||
void battleNewRound(int round) OVERRIDE; //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
|
||||
void battleStackMoved(const CStack * stack, THex dest, int distance, bool end) OVERRIDE;
|
||||
|
@@ -47,10 +47,6 @@ public:
|
||||
|
||||
class IGameActionCallback
|
||||
{
|
||||
// IGameActionCallback(CGameState * GS, int Player);
|
||||
// bool isVisible(int3 pos, int Player) const;
|
||||
// bool isVisible(const CGObjectInstance *obj, int Player) const;
|
||||
// virtual bool hasAccess(int playerId) const;
|
||||
public:
|
||||
//hero
|
||||
virtual bool moveHero(const CGHeroInstance *h, int3 dst) =0; //dst must be free, neighbouring tile (this function can move hero only by one tile)
|
||||
|
@@ -5,6 +5,7 @@
|
||||
#include <vector>
|
||||
#include "lib/BattleAction.h"
|
||||
#include "client/FunctionList.h"
|
||||
#include "lib/IGameEventsReceiver.h"
|
||||
|
||||
/*
|
||||
* CGameInterface.h, part of VCMI engine
|
||||
@@ -54,7 +55,7 @@ template <typename Serializer> class CISer;
|
||||
template <typename Serializer> class COSer;
|
||||
struct ArtifactLocation;
|
||||
|
||||
class CBattleGameInterface
|
||||
class CBattleGameInterface : public IBattleEventsReceiver
|
||||
{
|
||||
public:
|
||||
bool human;
|
||||
@@ -62,90 +63,21 @@ public:
|
||||
std::string dllName;
|
||||
|
||||
virtual ~CBattleGameInterface() {};
|
||||
|
||||
virtual void init(CBattleCallback * CB){};
|
||||
|
||||
//battle call-ins
|
||||
virtual void actionFinished(const BattleAction *action){};//occurs AFTER every action taken by any stack or by the hero
|
||||
virtual void actionStarted(const BattleAction *action){};//occurs BEFORE every action taken by any stack or by the hero
|
||||
virtual BattleAction activeStack(const CStack * stack)=0; //called when it's turn of that stack
|
||||
virtual void battleAttack(const BattleAttack *ba){}; //called when stack is performing attack
|
||||
virtual void battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa){}; //called when stack receives damage (after battleAttack())
|
||||
virtual void battleEnd(const BattleResult *br){};
|
||||
virtual void battleResultsApplied(){}; //called when all effects of last battle are applied
|
||||
virtual void battleNewRoundFirst(int round){}; //called at the beginning of each turn before changes are applied;
|
||||
virtual void battleNewRound(int round){}; //called at the beginning of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
|
||||
virtual void battleStackMoved(const CStack * stack, THex dest, int distance, bool end){};
|
||||
virtual void battleSpellCast(const BattleSpellCast *sc){};
|
||||
virtual void battleStacksEffectsSet(const SetStackEffect & sse){};//called when a specific effect is set to stacks
|
||||
virtual void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side){}; //called by engine when battle starts; side=0 - left, side=1 - right
|
||||
virtual void battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks, bool lifeDrain, si32 lifeDrainFrom){}; //called when stacks are healed / resurrected first element of pair - stack id, second - healed hp
|
||||
virtual void battleNewStackAppeared(const CStack * stack){}; //not called at the beginning of a battle or by resurrection; called eg. when elemental is summoned
|
||||
virtual void battleObstaclesRemoved(const std::set<si32> & removedObstacles){}; //called when a certain set of obstacles is removed from batlefield; IDs of them are given
|
||||
virtual void battleCatapultAttacked(const CatapultAttack & ca){}; //called when catapult makes an attack
|
||||
virtual void battleStacksRemoved(const BattleStacksRemoved & bsr){}; //called when certain stack is completely removed from battlefield
|
||||
};
|
||||
|
||||
/// Central class for managing human player / AI interface logic
|
||||
class CGameInterface : public CBattleGameInterface
|
||||
class CGameInterface : public CBattleGameInterface, public IGameEventsReceiver
|
||||
{
|
||||
public:
|
||||
virtual void buildChanged(const CGTownInstance *town, int buildingID, int what){}; //what: 1 - built, 2 - demolished
|
||||
|
||||
//garrison operations
|
||||
virtual void stackChagedCount(const StackLocation &location, const TQuantity &change, bool isAbsolute){}; //if absolute, change is the new count; otherwise count was modified by adding change
|
||||
virtual void stackChangedType(const StackLocation &location, const CCreature &newType){}; //used eg. when upgrading creatures
|
||||
virtual void stacksErased(const StackLocation &location){}; //stack removed from previously filled slot
|
||||
virtual void stacksSwapped(const StackLocation &loc1, const StackLocation &loc2){};
|
||||
virtual void newStackInserted(const StackLocation &location, const CStackInstance &stack){}; //new stack inserted at given (previously empty position)
|
||||
virtual void stacksRebalanced(const StackLocation &src, const StackLocation &dst, TQuantity count){}; //moves creatures from src stack to dst slot, may be used for merging/splittint/moving stacks
|
||||
//virtual void garrisonChanged(const CGObjectInstance * obj){};
|
||||
|
||||
//artifacts operations
|
||||
virtual void artifactPut(const ArtifactLocation &al){};
|
||||
virtual void artifactRemoved(const ArtifactLocation &al){};
|
||||
virtual void artifactAssembled(const ArtifactLocation &al){};
|
||||
virtual void artifactDisassembled(const ArtifactLocation &al){};
|
||||
virtual void artifactMoved(const ArtifactLocation &src, const ArtifactLocation &dst){};
|
||||
|
||||
virtual void heroCreated(const CGHeroInstance*){};
|
||||
virtual void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback)=0; //pskill is gained primary skill, interface has to choose one of given skills and call callback with selection id
|
||||
virtual void heroInGarrisonChange(const CGTownInstance *town){};
|
||||
//virtual void heroKilled(const CGHeroInstance*){};
|
||||
virtual void heroMoved(const TryMoveHero & details){};
|
||||
virtual void heroPrimarySkillChanged(const CGHeroInstance * hero, int which, si64 val){};
|
||||
virtual void heroSecondarySkillChanged(const CGHeroInstance * hero, int which, int val){};
|
||||
virtual void heroManaPointsChanged(const CGHeroInstance * hero){} //not called at the beginning of turn and after spell casts
|
||||
virtual void heroMovePointsChanged(const CGHeroInstance * hero){} //not called at the beginning of turn and after movement
|
||||
virtual void heroVisitsTown(const CGHeroInstance* hero, const CGTownInstance * town){};
|
||||
virtual void init(CCallback * CB){};
|
||||
virtual void receivedResource(int type, int val){};
|
||||
virtual void showInfoDialog(const std::string &text, const std::vector<Component*> &components, int soundID){};
|
||||
virtual void showRecruitmentDialog(const CGDwelling *dwelling, const CArmedInstance *dst, int level){}
|
||||
virtual void showShipyardDialog(const IShipyard *obj){} //obj may be town or shipyard; state: 0 - can buid, 1 - lack of resources, 2 - dest tile is blocked, 3 - no water
|
||||
virtual void yourTurn(){};
|
||||
virtual void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback)=0; //pskill is gained primary skill, interface has to choose one of given skills and call callback with selection id
|
||||
virtual void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, const int soundID, bool selection, bool cancel) = 0; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.
|
||||
virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function<void()> &onEnd) = 0; //all stacks operations between these objects become allowed, interface has to call onEnd when done
|
||||
virtual void showPuzzleMap(){};
|
||||
virtual void showMarketWindow(const IMarket *market, const CGHeroInstance *visitor){};
|
||||
virtual void showUniversityWindow(const IMarket *market, const CGHeroInstance *visitor){};
|
||||
virtual void showHillFortWindow(const CGObjectInstance *object, const CGHeroInstance *visitor){};
|
||||
virtual void showTavernWindow(const CGObjectInstance *townOrTavern){};
|
||||
virtual void advmapSpellCast(const CGHeroInstance * caster, int spellID){}; //called when a hero casts a spell
|
||||
virtual void tileHidden(const boost::unordered_set<int3, ShashInt3> &pos){};
|
||||
virtual void tileRevealed(const boost::unordered_set<int3, ShashInt3> &pos){};
|
||||
virtual void newObject(const CGObjectInstance * obj){}; //eg. ship built in shipyard
|
||||
virtual void availableArtifactsChanged(const CGBlackMarket *bm = NULL){}; //bm may be NULL, then artifacts are changed in the global pool (used by merchants in towns)
|
||||
virtual void yourTurn(){};
|
||||
virtual void centerView (int3 pos, int focusTime){};
|
||||
virtual void availableCreaturesChanged(const CGDwelling *town){};
|
||||
virtual void heroBonusChanged(const CGHeroInstance *hero, const Bonus &bonus, bool gain){};//if gain hero received bonus, else he lost it
|
||||
virtual void playerBonusChanged(const Bonus &bonus, bool gain){};//if gain hero received bonus, else he lost it
|
||||
virtual void requestRealized(PackageApplied *pa){};
|
||||
virtual void heroExchangeStarted(si32 hero1, si32 hero2){};
|
||||
virtual void objectPropertyChanged(const SetObjectProperty * sop){}; //eg. mine has been flagged
|
||||
virtual void objectRemoved(const CGObjectInstance *obj){}; //eg. collected resource, picked artifact, beaten hero
|
||||
virtual void playerBlocked(int reason){}; //reason: 0 - upcoming battle
|
||||
virtual void gameOver(ui8 player, bool victory){}; //player lost or won the game
|
||||
virtual void serialize(COSer<CSaveFile> &h, const int version){}; //saving
|
||||
virtual void serialize(CISer<CLoadFile> &h, const int version){}; //loading
|
||||
};
|
||||
|
@@ -31,6 +31,7 @@
|
||||
#include "../lib/CSpellHandler.h"
|
||||
#include <boost/foreach.hpp>
|
||||
#include "CSoundBase.h"
|
||||
#include "../lib/CGameState.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (disable : 4355)
|
||||
@@ -193,7 +194,7 @@ void CMinimap::initMap(int level)
|
||||
{
|
||||
int mx=(mapSizes.x*x)/pos.w;
|
||||
int my=(mapSizes.y*y)/pos.h;
|
||||
const TerrainTile * tile = LOCPLINT->cb->getTileInfo(int3(mx, my, i));
|
||||
const TerrainTile * tile = LOCPLINT->cb->getTile(int3(mx, my, i), false);
|
||||
if(tile)
|
||||
{
|
||||
if (tile->blocked && (!tile->visitable))
|
||||
@@ -342,7 +343,7 @@ void CMinimap::showTile(const int3 &pos)
|
||||
if ((pos.x*wo+ii<this->pos.w) && (pos.y*ho+jj<this->pos.h))
|
||||
CSDL_Ext::SDL_PutPixelWithoutRefresh(FoW[pos.z],pos.x*wo+ii,pos.y*ho+jj,0,0,0,0);
|
||||
|
||||
const TerrainTile * tile = LOCPLINT->cb->getTileInfo(pos);
|
||||
const TerrainTile * tile = LOCPLINT->cb->getTile(pos, false);
|
||||
if(tile)
|
||||
{
|
||||
if (tile->blocked && (!tile->visitable))
|
||||
@@ -1776,14 +1777,14 @@ void CAdvMapInt::tileLClicked(const int3 &mp)
|
||||
|
||||
std::vector < const CGObjectInstance * > bobjs = LOCPLINT->cb->getBlockingObjs(mp), //blocking objects at tile
|
||||
vobjs = LOCPLINT->cb->getVisitableObjs(mp); //visitable objects
|
||||
const TerrainTile *tile = LOCPLINT->cb->getTileInfo(mp);
|
||||
const TerrainTile *tile = LOCPLINT->cb->getTile(mp);
|
||||
const CGObjectInstance *topBlocking = bobjs.size() ? bobjs.back() : NULL;
|
||||
|
||||
|
||||
int3 selPos = selection->getSightCenter();
|
||||
if(spellBeingCasted && isInScreenRange(selPos, mp))
|
||||
{
|
||||
const TerrainTile *heroTile = LOCPLINT->cb->getTileInfo(selPos);
|
||||
const TerrainTile *heroTile = LOCPLINT->cb->getTile(selPos);
|
||||
|
||||
switch(spellBeingCasted->id)
|
||||
{
|
||||
@@ -1898,9 +1899,9 @@ void CAdvMapInt::tileHovered(const int3 &tile)
|
||||
return;
|
||||
case Spells::DIMENSION_DOOR:
|
||||
{
|
||||
const TerrainTile *t = LOCPLINT->cb->getTileInfo(tile);
|
||||
const TerrainTile *t = LOCPLINT->cb->getTile(tile, false);
|
||||
int3 hpos = selection->getSightCenter();
|
||||
if((!t || t->isClear(LOCPLINT->cb->getTileInfo(hpos))) && isInScreenRange(hpos, tile))
|
||||
if((!t || t->isClear(LOCPLINT->cb->getTile(hpos))) && isInScreenRange(hpos, tile))
|
||||
CCS->curh->changeGraphic(0, 41);
|
||||
else
|
||||
CCS->curh->changeGraphic(0, 0);
|
||||
@@ -2023,7 +2024,7 @@ void CAdvMapInt::tileHovered(const int3 &tile)
|
||||
} else {
|
||||
if(pnode->land)
|
||||
{
|
||||
if(LOCPLINT->cb->getTileInfo(h->getPosition(false))->tertype != TerrainTile::water)
|
||||
if(LOCPLINT->cb->getTile(h->getPosition(false))->tertype != TerrainTile::water)
|
||||
CCS->curh->changeGraphic(0, 4 + turns*6);
|
||||
else
|
||||
CCS->curh->changeGraphic(0, 7 + turns*6); //anchor
|
||||
@@ -2060,7 +2061,7 @@ void CAdvMapInt::tileRClicked(const int3 &mp)
|
||||
if(!objs.size())
|
||||
{
|
||||
// Bare or undiscovered terrain
|
||||
const TerrainTile * tile = LOCPLINT->cb->getTileInfo(mp);
|
||||
const TerrainTile * tile = LOCPLINT->cb->getTile(mp);
|
||||
if (tile)
|
||||
{
|
||||
std::string hlp;
|
||||
|
@@ -21,6 +21,7 @@
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include "../lib/CGameState.h"
|
||||
|
||||
using namespace CSDL_Ext;
|
||||
|
||||
|
@@ -1,5 +1,6 @@
|
||||
#ifndef __CHEROWINDOW_H__
|
||||
#define __CHEROWINDOW_H__
|
||||
#include "..\lib\HeroBonus.h"
|
||||
|
||||
|
||||
//#include "CPlayerInterface.h"
|
||||
|
@@ -44,6 +44,7 @@
|
||||
#include <boost/filesystem.hpp>
|
||||
#include "../StartInfo.h"
|
||||
#include <boost/foreach.hpp>
|
||||
#include "../lib/CGameState.h"
|
||||
|
||||
#ifdef min
|
||||
#undef min
|
||||
@@ -1058,7 +1059,7 @@ bool CPlayerInterface::moveHero( const CGHeroInstance *h, CGPath path )
|
||||
enum TerrainTile::EterrainType newTerrain;
|
||||
int sh = -1;
|
||||
|
||||
const TerrainTile * curTile = cb->getTileInfo(CGHeroInstance::convertPosition(h->pos, false));
|
||||
const TerrainTile * curTile = cb->getTile(CGHeroInstance::convertPosition(h->pos, false));
|
||||
|
||||
for(int i=path.nodes.size()-1; i>0 && (stillMoveHero.data == CONTINUE_MOVE || curTile->blocked); i--)
|
||||
{
|
||||
@@ -1076,7 +1077,7 @@ bool CPlayerInterface::moveHero( const CGHeroInstance *h, CGPath path )
|
||||
sh = CCS->soundh->playSound(soundBase::horseFlying, -1);
|
||||
#endif
|
||||
{
|
||||
newTerrain = cb->getTileInfo(CGHeroInstance::convertPosition(path.nodes[i].coord, false))->tertype;
|
||||
newTerrain = cb->getTile(CGHeroInstance::convertPosition(path.nodes[i].coord, false))->tertype;
|
||||
|
||||
if (newTerrain != currentTerrain) {
|
||||
CCS->soundh->stopSound(sh);
|
||||
@@ -2009,11 +2010,11 @@ void CPlayerInterface::tryDiggging(const CGHeroInstance *h)
|
||||
std::string hlp;
|
||||
if(h->movement < h->maxMovePoints(true))
|
||||
showInfoDialog(CGI->generaltexth->allTexts[56]); //"Digging for artifacts requires a whole day, try again tomorrow."
|
||||
else if(cb->getTileInfo(h->getPosition(false))->tertype == TerrainTile::water)
|
||||
else if(cb->getTile(h->getPosition(false))->tertype == TerrainTile::water)
|
||||
showInfoDialog(CGI->generaltexth->allTexts[60]); //Try looking on land!
|
||||
else
|
||||
{
|
||||
const TerrainTile *t = cb->getTileInfo(h->getPosition());
|
||||
const TerrainTile *t = cb->getTile(h->getPosition());
|
||||
CGI->mh->getTerrainDescr(h->getPosition(false), hlp, false);
|
||||
if(hlp.length() || t->blockingObjects.size() > 1)
|
||||
showInfoDialog(CGI->generaltexth->allTexts[97]); //Try searching on clear ground.
|
||||
|
@@ -33,9 +33,11 @@
|
||||
#include "CPreGame.h"
|
||||
#include "CBattleInterface.h"
|
||||
#include "../CThreadHelper.h"
|
||||
#include "../lib/ERMScriptModule.h"
|
||||
|
||||
#define NOT_LIB
|
||||
#include "../lib/RegisterTypes.cpp"
|
||||
|
||||
extern std::string NAME;
|
||||
namespace intpr = boost::interprocess;
|
||||
|
||||
@@ -300,19 +302,6 @@ void CClient::loadGame( const std::string & fname )
|
||||
}
|
||||
}
|
||||
|
||||
int CClient::getCurrentPlayer()
|
||||
{
|
||||
return gs->currentPlayer;
|
||||
}
|
||||
|
||||
int CClient::getSelectedHero()
|
||||
{
|
||||
if(const CGHeroInstance *selHero = IGameCallback::getSelectedHero(getCurrentPlayer()))
|
||||
return selHero->id;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
void CClient::newGame( CConnection *con, StartInfo *si )
|
||||
{
|
||||
enum {SINGLE, HOST, GUEST} networkMode = SINGLE;
|
||||
@@ -436,7 +425,10 @@ void CClient::newGame( CConnection *con, StartInfo *si )
|
||||
serv->addStdVecItems(const_cast<CGameInfo*>(CGI)->state);
|
||||
hotSeat = (humanPlayers > 1);
|
||||
|
||||
|
||||
CERMScriptModule *erm = new CERMScriptModule();
|
||||
privilagedGameEventReceivers.push_back(erm);
|
||||
privilagedBattleEventReceivers.push_back(erm);
|
||||
erm->init();
|
||||
}
|
||||
|
||||
template <typename Handler>
|
||||
|
@@ -18,6 +18,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
class IGameEventsReceiver;
|
||||
class IBattleEventsReceiver;
|
||||
class CBattleGameInterface;
|
||||
struct StartInfo;
|
||||
class CGameState;
|
||||
@@ -62,6 +64,8 @@ class CClient : public IGameCallback
|
||||
public:
|
||||
CCallback *cb;
|
||||
std::set<CCallback*> callbacks; //callbacks given to player interfaces
|
||||
std::vector<IGameEventsReceiver*> privilagedGameEventReceivers; //scripting modules, spectator interfaces
|
||||
std::vector<IBattleEventsReceiver*> privilagedBattleEventReceivers; //scripting modules, spectator interfaces
|
||||
std::map<ui8,CGameInterface *> playerint;
|
||||
std::map<ui8,CBattleGameInterface *> battleints;
|
||||
bool hotSeat;
|
||||
@@ -96,10 +100,6 @@ public:
|
||||
boost::thread *connectionHandler; //thread running run() method
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//from IGameCallback
|
||||
int getCurrentPlayer();
|
||||
int getSelectedHero();
|
||||
|
||||
//not working yet, will be implement somewhen later with support for local-sim-based gameplay
|
||||
void changeSpells(int hid, bool give, const std::set<ui32> &spells) OVERRIDE {};
|
||||
bool removeObject(int objid) OVERRIDE {return false;};
|
||||
@@ -116,8 +116,8 @@ public:
|
||||
void showThievesGuildWindow(int requestingObjId) OVERRIDE {};
|
||||
void giveResource(int player, int which, int val) OVERRIDE {};
|
||||
|
||||
void giveCreatures (const CArmedInstance * objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) OVERRIDE {};
|
||||
void takeCreatures (int objid, std::vector<CStackBasicDescriptor> creatures) OVERRIDE {};
|
||||
void giveCreatures(const CArmedInstance * objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) OVERRIDE {};
|
||||
void takeCreatures(int objid, const std::vector<CStackBasicDescriptor> &creatures) OVERRIDE {};
|
||||
bool changeStackType(const StackLocation &sl, CCreature *c) OVERRIDE {return false;};
|
||||
bool changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue = false) OVERRIDE {return false;};
|
||||
bool insertNewStack(const StackLocation &sl, const CCreature *c, TQuantity count) OVERRIDE {return false;};
|
||||
|
@@ -52,6 +52,7 @@
|
||||
#include "../lib/CCreatureHandler.h"
|
||||
#include "CMusicHandler.h"
|
||||
#include "../lib/BattleState.h"
|
||||
#include "../lib/CGameState.h"
|
||||
|
||||
/*
|
||||
* GUIClasses.cpp, part of VCMI engine
|
||||
|
@@ -22,6 +22,7 @@
|
||||
#include "CBitmapHandler.h"
|
||||
#include "../lib/CObjectHandler.h"
|
||||
#include "../lib/CDefObjInfoHandler.h"
|
||||
#include "../lib/CGameState.h"
|
||||
|
||||
using namespace boost::assign;
|
||||
using namespace CSDL_Ext;
|
||||
|
@@ -28,18 +28,48 @@
|
||||
|
||||
|
||||
//macro to avoid code duplication - calls given method with given arguments if interface for specific player is present
|
||||
#define INTERFACE_CALL_IF_PRESENT(player,function,...) \
|
||||
if(vstd::contains(cl->playerint,player)) \
|
||||
cl->playerint[player]->function(__VA_ARGS__);
|
||||
#define CALL_ONLY_THAT_INTERFACE(player, function, ...) \
|
||||
do \
|
||||
{ \
|
||||
if(vstd::contains(cl->playerint,player)) \
|
||||
cl->playerint[player]->function(__VA_ARGS__); \
|
||||
}while(0)
|
||||
|
||||
|
||||
#define INTERFACE_CALL_IF_PRESENT(player,function,...) \
|
||||
do \
|
||||
{ \
|
||||
CALL_ONLY_THAT_INTERFACE(player, function, __VA_ARGS__);\
|
||||
BOOST_FOREACH(IGameEventsReceiver *ger, cl->privilagedGameEventReceivers)\
|
||||
ger->function(__VA_ARGS__); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define CALL_ONLY_THT_BATTLE_INTERFACE(player,function,...) \
|
||||
do \
|
||||
{ \
|
||||
if(vstd::contains(cl->battleints,player)) \
|
||||
cl->battleints[player]->function(__VA_ARGS__); \
|
||||
} while (0);
|
||||
|
||||
#define BATTLE_INTERFACE_CALL_RECEIVERS(function,...) \
|
||||
do \
|
||||
{ \
|
||||
BOOST_FOREACH(IBattleEventsReceiver *ber, cl->privilagedBattleEventReceivers)\
|
||||
ber->function(__VA_ARGS__); \
|
||||
} while(0)
|
||||
|
||||
#define BATTLE_INTERFACE_CALL_IF_PRESENT(player,function,...) \
|
||||
if(vstd::contains(cl->battleints,player)) \
|
||||
cl->battleints[player]->function(__VA_ARGS__);
|
||||
do \
|
||||
{ \
|
||||
CALL_ONLY_THAT_INTERFACE(player, function, __VA_ARGS__);\
|
||||
BATTLE_INTERFACE_CALL_RECEIVERS(function, __VA_ARGS__); \
|
||||
} while(0)
|
||||
|
||||
#define BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(function,...) \
|
||||
BATTLE_INTERFACE_CALL_IF_PRESENT(GS(cl)->curB->sides[0], function, __VA_ARGS__) \
|
||||
BATTLE_INTERFACE_CALL_IF_PRESENT(GS(cl)->curB->sides[1], function, __VA_ARGS__) \
|
||||
BATTLE_INTERFACE_CALL_IF_PRESENT(254, function, __VA_ARGS__)
|
||||
#define BATTLE_INTERFACE_CALL_IF_PRESENT_FOR_BOTH_SIDES(function,...) \
|
||||
CALL_ONLY_THT_BATTLE_INTERFACE(GS(cl)->curB->sides[0], function, __VA_ARGS__) \
|
||||
CALL_ONLY_THT_BATTLE_INTERFACE(GS(cl)->curB->sides[1], function, __VA_ARGS__) \
|
||||
BATTLE_INTERFACE_CALL_RECEIVERS(function, __VA_ARGS__)
|
||||
/*
|
||||
* NetPacksClient.cpp, part of VCMI engine
|
||||
*
|
||||
@@ -62,7 +92,7 @@ void SetResource::applyCl( CClient *cl )
|
||||
|
||||
void SetPrimSkill::applyCl( CClient *cl )
|
||||
{
|
||||
const CGHeroInstance *h = GS(cl)->getHero(id);
|
||||
const CGHeroInstance *h = cl->getHero(id);
|
||||
if(!h)
|
||||
{
|
||||
tlog1 << "Cannot find hero with ID " << id << std::endl;
|
||||
@@ -73,7 +103,7 @@ void SetPrimSkill::applyCl( CClient *cl )
|
||||
|
||||
void SetSecSkill::applyCl( CClient *cl )
|
||||
{
|
||||
const CGHeroInstance *h = GS(cl)->getHero(id);
|
||||
const CGHeroInstance *h = cl->getHero(id);
|
||||
if(!h)
|
||||
{
|
||||
tlog1 << "Cannot find hero with ID " << id << std::endl;
|
||||
@@ -84,9 +114,11 @@ void SetSecSkill::applyCl( CClient *cl )
|
||||
|
||||
void HeroVisitCastle::applyCl( CClient *cl )
|
||||
{
|
||||
if(start() && vstd::contains(cl->playerint,GS(cl)->getHero(hid)->tempOwner))
|
||||
const CGHeroInstance *h = cl->getHero(hid);
|
||||
|
||||
if(start())
|
||||
{
|
||||
cl->playerint[GS(cl)->getHero(hid)->tempOwner]->heroVisitsTown(GS(cl)->getHero(hid),GS(cl)->getTown(tid));
|
||||
INTERFACE_CALL_IF_PRESENT(h->tempOwner, heroVisitsTown, h, GS(cl)->getTown(tid));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,33 +129,28 @@ void ChangeSpells::applyCl( CClient *cl )
|
||||
|
||||
void SetMana::applyCl( CClient *cl )
|
||||
{
|
||||
CGHeroInstance *h = GS(cl)->getHero(hid);
|
||||
if(vstd::contains(cl->playerint,h->tempOwner))
|
||||
cl->playerint[h->tempOwner]->heroManaPointsChanged(h);
|
||||
const CGHeroInstance *h = cl->getHero(hid);
|
||||
INTERFACE_CALL_IF_PRESENT(h->tempOwner, heroManaPointsChanged, h);
|
||||
}
|
||||
|
||||
void SetMovePoints::applyCl( CClient *cl )
|
||||
{
|
||||
CGHeroInstance *h = GS(cl)->getHero(hid);
|
||||
const CGHeroInstance *h = cl->getHero(hid);
|
||||
|
||||
if (cl->IGameCallback::getSelectedHero(LOCPLINT->playerID) == h)//if we have selected that hero
|
||||
{
|
||||
GS(cl)->calculatePaths(h, *cl->pathInfo);
|
||||
}
|
||||
|
||||
if(vstd::contains(cl->playerint,h->tempOwner))
|
||||
cl->playerint[h->tempOwner]->heroMovePointsChanged(h);
|
||||
INTERFACE_CALL_IF_PRESENT(h->tempOwner, heroMovePointsChanged, h);
|
||||
}
|
||||
|
||||
void FoWChange::applyCl( CClient *cl )
|
||||
{
|
||||
if(!vstd::contains(cl->playerint,player))
|
||||
return;
|
||||
|
||||
if(mode)
|
||||
cl->playerint[player]->tileRevealed(tiles);
|
||||
INTERFACE_CALL_IF_PRESENT(player, tileRevealed, tiles);
|
||||
else
|
||||
cl->playerint[player]->tileHidden(tiles);
|
||||
INTERFACE_CALL_IF_PRESENT(player, tileHidden, tiles);
|
||||
|
||||
cl->updatePaths();
|
||||
}
|
||||
@@ -135,24 +162,24 @@ void SetAvailableHeroes::applyCl( CClient *cl )
|
||||
|
||||
void ChangeStackCount::applyCl( CClient *cl )
|
||||
{
|
||||
INTERFACE_CALL_IF_PRESENT(sl.army->tempOwner,stackChagedCount, sl, count, absoluteValue);
|
||||
INTERFACE_CALL_IF_PRESENT(sl.army->tempOwner, stackChagedCount, sl, count, absoluteValue);
|
||||
}
|
||||
|
||||
void SetStackType::applyCl( CClient *cl )
|
||||
{
|
||||
INTERFACE_CALL_IF_PRESENT(sl.army->tempOwner,stackChangedType,sl, *type);
|
||||
INTERFACE_CALL_IF_PRESENT(sl.army->tempOwner, stackChangedType, sl, *type);
|
||||
}
|
||||
|
||||
void EraseStack::applyCl( CClient *cl )
|
||||
{
|
||||
INTERFACE_CALL_IF_PRESENT(sl.army->tempOwner,stacksErased,sl);
|
||||
INTERFACE_CALL_IF_PRESENT(sl.army->tempOwner, stacksErased, sl);
|
||||
}
|
||||
|
||||
void SwapStacks::applyCl( CClient *cl )
|
||||
{
|
||||
INTERFACE_CALL_IF_PRESENT(sl1.army->tempOwner,stacksSwapped, sl1, sl2);
|
||||
INTERFACE_CALL_IF_PRESENT(sl1.army->tempOwner, stacksSwapped, sl1, sl2);
|
||||
if(sl1.army->tempOwner != sl2.army->tempOwner)
|
||||
INTERFACE_CALL_IF_PRESENT(sl2.army->tempOwner,stacksSwapped, sl1, sl2);
|
||||
INTERFACE_CALL_IF_PRESENT(sl2.army->tempOwner, stacksSwapped, sl1, sl2);
|
||||
}
|
||||
|
||||
void InsertNewStack::applyCl( CClient *cl )
|
||||
@@ -194,6 +221,12 @@ void DisassembledArtifact::applyCl( CClient *cl )
|
||||
INTERFACE_CALL_IF_PRESENT(al.hero->tempOwner, artifactDisassembled, al);
|
||||
}
|
||||
|
||||
void HeroVisit::applyCl( CClient *cl )
|
||||
{
|
||||
INTERFACE_CALL_IF_PRESENT(hero->tempOwner, heroVisit, hero, obj, starting);
|
||||
}
|
||||
|
||||
|
||||
void GiveBonus::applyCl( CClient *cl )
|
||||
{
|
||||
switch(who)
|
||||
@@ -346,13 +379,6 @@ void TryMoveHero::applyCl( CClient *cl )
|
||||
}
|
||||
}
|
||||
|
||||
// void SetGarrisons::applyCl( CClient *cl )
|
||||
// {
|
||||
// for(std::map<ui32,CCreatureSet>::iterator i = garrs.begin(); i!=garrs.end(); i++)
|
||||
// if(vstd::contains(cl->playerint,cl->getOwner(i->first)))
|
||||
// cl->playerint[cl->getOwner(i->first)]->garrisonChanged(cl->getObj(i->first));
|
||||
// }
|
||||
|
||||
void NewStructures::applyCl( CClient *cl )
|
||||
{
|
||||
CGTownInstance *town = GS(cl)->getTown(tid);
|
||||
@@ -692,7 +718,7 @@ void PlayerBlocked::applyCl( CClient *cl )
|
||||
|
||||
void YourTurn::applyCl( CClient *cl )
|
||||
{
|
||||
INTERFACE_CALL_IF_PRESENT(player,yourTurn);
|
||||
CALL_ONLY_THAT_INTERFACE(player,yourTurn);
|
||||
}
|
||||
|
||||
void SaveGame::applyCl(CClient *cl)
|
||||
|
@@ -5,7 +5,7 @@
|
||||
#include "CCreatureSet.h"
|
||||
#include "CObjectHandler.h"
|
||||
#include "CCreatureHandler.h"
|
||||
|
||||
#include "CObstacleInstance.h"
|
||||
#include "ConstTransitivePtr.h"
|
||||
|
||||
/*
|
||||
@@ -25,17 +25,6 @@ class CGTownInstance;
|
||||
class CStackInstance;
|
||||
struct BattleStackAttacked;
|
||||
|
||||
struct DLL_EXPORT CObstacleInstance
|
||||
{
|
||||
int uniqueID;
|
||||
int ID; //ID of obstacle (defines type of it)
|
||||
int pos; //position on battlefield
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & ID & pos & uniqueID;
|
||||
}
|
||||
};
|
||||
|
||||
//only for use in BattleInfo
|
||||
struct DLL_EXPORT SiegeInfo
|
||||
{
|
||||
|
@@ -7,8 +7,6 @@
|
||||
#include <set>
|
||||
|
||||
#include "../lib/HeroBonus.h"
|
||||
#include "../lib/CGameState.h"
|
||||
#include "../lib/CCreatureSet.h"
|
||||
#include "../lib/ConstTransitivePtr.h"
|
||||
|
||||
/*
|
||||
@@ -38,7 +36,7 @@ public:
|
||||
ui32 ammMin, ammMax;
|
||||
ui8 level; // 0 - unknown
|
||||
std::string abilityText; //description of abilities
|
||||
std::string abilityRefs; //references to abilities, in textformat
|
||||
std::string abilityRefs; //references to abilities, in text format
|
||||
std::string animDefName;
|
||||
si32 idNumber;
|
||||
si8 faction; //-1 = neutral
|
||||
|
@@ -535,34 +535,7 @@ int CGameState::pickHero(int owner)
|
||||
}
|
||||
return h;
|
||||
}
|
||||
CGHeroInstance *CGameState::getHero(int objid)
|
||||
{
|
||||
if(objid<0 || objid>=map->objects.size() || map->objects[objid]->ID!=HEROI_TYPE)
|
||||
return NULL;
|
||||
return static_cast<CGHeroInstance *>(map->objects[objid].get());
|
||||
}
|
||||
|
||||
const CGHeroInstance * CGameState::getHero( int objid ) const
|
||||
{
|
||||
return (const_cast<CGameState *>(this))->getHero(objid);
|
||||
}
|
||||
|
||||
CGTownInstance *CGameState::getTown(int objid)
|
||||
{
|
||||
if(objid<0 || objid>=map->objects.size())
|
||||
return NULL;
|
||||
CGObjectInstance *obj = map->objects[objid];
|
||||
|
||||
if(obj->ID != TOWNI_TYPE)
|
||||
return NULL;
|
||||
|
||||
return static_cast<CGTownInstance *>(obj);
|
||||
}
|
||||
|
||||
const CGTownInstance * CGameState::getTown( int objid ) const
|
||||
{
|
||||
return (const_cast<CGameState *>(this))->getTown(objid);
|
||||
}
|
||||
|
||||
std::pair<int,int> CGameState::pickObject (CGObjectInstance *obj)
|
||||
{
|
||||
@@ -810,6 +783,7 @@ int CGameState::getDate(int mode) const
|
||||
}
|
||||
CGameState::CGameState()
|
||||
{
|
||||
gs = this;
|
||||
mx = new boost::shared_mutex();
|
||||
applierGs = new CApplier<CBaseForGSApply>;
|
||||
registerTypes2(*applierGs);
|
||||
@@ -1871,152 +1845,12 @@ int CGameState::getMovementCost(const CGHeroInstance *h, const int3 &src, const
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::set<int> CGameState::getBuildingRequiments(const CGTownInstance *t, int ID)
|
||||
{
|
||||
std::set<int> used;
|
||||
used.insert(ID);
|
||||
std::set<int> reqs = VLC->townh->requirements[t->subID][ID];
|
||||
|
||||
while(true)
|
||||
{
|
||||
size_t noloop=0;
|
||||
for(std::set<int>::iterator i=reqs.begin();i!=reqs.end();i++)
|
||||
{
|
||||
if(used.find(*i)==used.end()) //we haven't added requirements for this building
|
||||
{
|
||||
used.insert(*i);
|
||||
for(
|
||||
std::set<int>::iterator j=VLC->townh->requirements[t->subID][*i].begin();
|
||||
j!=VLC->townh->requirements[t->subID][*i].end();
|
||||
j++)
|
||||
{
|
||||
reqs.insert(*j);//creating full list of requirements
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
noloop++;
|
||||
}
|
||||
}
|
||||
if(noloop==reqs.size())
|
||||
break;
|
||||
}
|
||||
return reqs;
|
||||
}
|
||||
|
||||
int CGameState::canBuildStructure( const CGTownInstance *t, int ID )
|
||||
{
|
||||
int ret = Buildings::ALLOWED;
|
||||
|
||||
if(t->builded >= MAX_BUILDING_PER_TURN)
|
||||
ret = Buildings::CANT_BUILD_TODAY; //building limit
|
||||
|
||||
CBuilding * pom = VLC->buildh->buildings[t->subID][ID];
|
||||
|
||||
if(!pom)
|
||||
return Buildings::ERROR;
|
||||
|
||||
//checking resources
|
||||
for(int res=0; res<RESOURCE_QUANTITY; res++)
|
||||
{
|
||||
if(pom->resources[res] > getPlayer(t->tempOwner)->resources[res])
|
||||
ret = Buildings::NO_RESOURCES; //lack of res
|
||||
}
|
||||
|
||||
//checking for requirements
|
||||
std::set<int> reqs = getBuildingRequiments(t, ID);//getting all requiments
|
||||
|
||||
for( std::set<int>::iterator ri = reqs.begin(); ri != reqs.end(); ri++ )
|
||||
{
|
||||
if(t->builtBuildings.find(*ri)==t->builtBuildings.end())
|
||||
ret = Buildings::PREREQUIRES; //lack of requirements - cannot build
|
||||
}
|
||||
|
||||
//can we build it?
|
||||
if(t->forbiddenBuildings.find(ID)!=t->forbiddenBuildings.end())
|
||||
ret = Buildings::FORBIDDEN; //forbidden
|
||||
|
||||
if(ID == 13) //capitol
|
||||
{
|
||||
for(unsigned int in = 0; in < map->towns.size(); in++)
|
||||
{
|
||||
if(map->towns[in]->tempOwner==t->tempOwner && vstd::contains(map->towns[in]->builtBuildings,13))
|
||||
{
|
||||
ret = Buildings::HAVE_CAPITAL; //no more than one capitol
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(ID == 6) //shipyard
|
||||
{
|
||||
int3 tile = t->bestLocation();
|
||||
if( !map->isInTheMap(tile) || map->getTile(tile).tertype != TerrainTile::water )
|
||||
ret = Buildings::NO_WATER; //lack of water
|
||||
}
|
||||
|
||||
if(t->builtBuildings.find(ID)!=t->builtBuildings.end()) //already built
|
||||
ret = Buildings::ALREADY_PRESENT;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CGameState::apply(CPack *pack)
|
||||
{
|
||||
ui16 typ = typeList.getTypeID(pack);
|
||||
applierGs->apps[typ]->applyOnGS(this,pack);
|
||||
}
|
||||
|
||||
TeamState *CGameState::getTeam(ui8 teamID)
|
||||
{
|
||||
if(vstd::contains(teams,teamID))
|
||||
{
|
||||
return &teams[teamID];
|
||||
}
|
||||
else
|
||||
{
|
||||
tlog2 << "Warning: Cannot find info for team " << int(teamID) << std::endl;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TeamState *CGameState::getPlayerTeam(ui8 color)
|
||||
{
|
||||
PlayerState * ps = getPlayer(color);
|
||||
if (ps)
|
||||
return getTeam(ps->team);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PlayerState * CGameState::getPlayer( ui8 color, bool verbose )
|
||||
{
|
||||
if(vstd::contains(players,color))
|
||||
{
|
||||
return &players[color];
|
||||
}
|
||||
else
|
||||
{
|
||||
if(verbose)
|
||||
tlog2 << "Warning: Cannot find info for player " << int(color) << std::endl;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
const PlayerState * CGameState::getPlayer( ui8 color, bool verbose ) const
|
||||
{
|
||||
return (const_cast<CGameState *>(this))->getPlayer(color, verbose);
|
||||
}
|
||||
|
||||
|
||||
const TeamState * CGameState::getTeam( ui8 teamID ) const
|
||||
{
|
||||
return (const_cast<CGameState *>(this))->getTeam(teamID);
|
||||
}
|
||||
|
||||
const TeamState * CGameState::getPlayerTeam( ui8 teamID ) const
|
||||
{
|
||||
return (const_cast<CGameState *>(this))->getPlayerTeam(teamID);
|
||||
}
|
||||
|
||||
bool CGameState::getPath(int3 src, int3 dest, const CGHeroInstance * hero, CPath &ret)
|
||||
{
|
||||
if(!map->isInTheMap(src) || !map->isInTheMap(dest)) //check input
|
||||
@@ -2505,7 +2339,7 @@ bool CGameState::checkForVisitableDir( const int3 & src, const TerrainTile *pom,
|
||||
|
||||
int CGameState::victoryCheck( ui8 player ) const
|
||||
{
|
||||
const PlayerState *p = getPlayer(player);
|
||||
const PlayerState *p = CGameInfoCallback::getPlayer(player);
|
||||
if(map->victoryCondition.condition == winStandard || map->victoryCondition.allowNormalVictory)
|
||||
if(player == checkForStandardWin())
|
||||
return -1;
|
||||
@@ -2659,7 +2493,7 @@ ui8 CGameState::checkForStandardWin() const
|
||||
bool CGameState::checkForStandardLoss( ui8 player ) const
|
||||
{
|
||||
//std loss condition is: player lost all towns and heroes
|
||||
const PlayerState &p = *getPlayer(player);
|
||||
const PlayerState &p = *CGameInfoCallback::getPlayer(player);
|
||||
return !p.heroes.size() && !p.towns.size();
|
||||
}
|
||||
|
||||
@@ -2848,7 +2682,7 @@ void CGameState::obtainPlayersStats(SThievesGuildInfo & tgi, int level)
|
||||
|
||||
int CGameState::lossCheck( ui8 player ) const
|
||||
{
|
||||
const PlayerState *p = getPlayer(player);
|
||||
const PlayerState *p = CGameInfoCallback::getPlayer(player);
|
||||
//if(map->lossCondition.typeOfLossCon == lossStandard)
|
||||
if(checkForStandardLoss(player))
|
||||
return -1;
|
||||
|
@@ -22,6 +22,7 @@
|
||||
#endif
|
||||
|
||||
#include "ConstTransitivePtr.h"
|
||||
#include "IGameCallback.h"
|
||||
|
||||
|
||||
/*
|
||||
@@ -310,7 +311,7 @@ struct DLL_EXPORT DuelParameters
|
||||
|
||||
struct BattleInfo;
|
||||
|
||||
class DLL_EXPORT CGameState
|
||||
class DLL_EXPORT CGameState : public CNonConstInfoCallback
|
||||
{
|
||||
public:
|
||||
ConstTransitivePtr<StartInfo> scenarioOps, initialOpts; //second one is a copy of settings received from pregame (not randomized)
|
||||
@@ -324,6 +325,7 @@ public:
|
||||
bmap<ui8, TeamState> teams; //ID <-> team state
|
||||
bmap<int, ConstTransitivePtr<CGDefInfo> > villages, forts, capitols; //def-info for town graphics
|
||||
CBonusSystemNode globalEffects;
|
||||
bmap<const CGHeroInstance*, const CGObjectInstance*> ongoingVisits;
|
||||
|
||||
struct DLL_EXPORT HeroesPool
|
||||
{
|
||||
@@ -339,28 +341,17 @@ public:
|
||||
} hpool; //we have here all heroes available on this map that are not hired
|
||||
|
||||
boost::shared_mutex *mx;
|
||||
PlayerState *getPlayer(ui8 color, bool verbose = true);
|
||||
TeamState *getTeam(ui8 teamID);//get team by team ID
|
||||
TeamState *getPlayerTeam(ui8 color);// get team by player color
|
||||
const PlayerState *getPlayer(ui8 color, bool verbose = true) const;
|
||||
const TeamState *getTeam(ui8 teamID) const;
|
||||
const TeamState *getPlayerTeam(ui8 color) const;
|
||||
|
||||
void init(StartInfo * si, ui32 checksum, int Seed);
|
||||
void loadTownDInfos();
|
||||
void randomizeObject(CGObjectInstance *cur);
|
||||
std::pair<int,int> pickObject(CGObjectInstance *obj); //chooses type of object to be randomized, returns <type, subtype>
|
||||
int pickHero(int owner);
|
||||
void apply(CPack *pack);
|
||||
CGHeroInstance *getHero(int objid);
|
||||
CGTownInstance *getTown(int objid);
|
||||
const CGHeroInstance *getHero(int objid) const;
|
||||
const CGTownInstance *getTown(int objid) const;
|
||||
int battleGetBattlefieldType(int3 tile = int3());// 1. sand/shore 2. sand/mesas 3. dirt/birches 4. dirt/hills 5. dirt/pines 6. grass/hills 7. grass/pines 8. lava 9. magic plains 10. snow/mountains 11. snow/trees 12. subterranean 13. swamp/trees 14. fiery fields 15. rock lands 16. magic clouds 17. lucid pools 18. holy ground 19. clover field 20. evil fog 21. "favourable winds" text on magic plains background 22. cursed ground 23. rough 24. ship to ship 25. ship
|
||||
UpgradeInfo getUpgradeInfo(const CStackInstance &stack);
|
||||
int getPlayerRelations(ui8 color1, ui8 color2);// 0 = enemy, 1 = ally, 2 = same player
|
||||
//float getMarketEfficiency(int player, int mode=0);
|
||||
std::set<int> getBuildingRequiments(const CGTownInstance *t, int ID);
|
||||
int canBuildStructure(const CGTownInstance *t, int ID);// 0 - no more than one capitol, 1 - lack of water, 2 - forbidden, 3 - Add another level to Mage Guild, 4 - already built, 5 - cannot build, 6 - cannot afford, 7 - build, 8 - lack of requirements
|
||||
bool checkForVisitableDir(const int3 & src, const int3 & dst) const; //check if src tile is visitable from dst tile
|
||||
bool checkForVisitableDir(const int3 & src, const TerrainTile *pom, const int3 & dst) const; //check if src tile is visitable from dst tile
|
||||
bool getPath(int3 src, int3 dest, const CGHeroInstance * hero, CPath &ret); //calculates path between src and dest; returns pointer to newly allocated CPath or NULL if path does not exists
|
||||
|
@@ -420,7 +420,7 @@ void CGObjectInstance::hideTiles(int ourplayer, int radius) const
|
||||
if ( !vstd::contains(i->second.players, ourplayer ))//another team
|
||||
{
|
||||
for (std::set<ui8>::iterator j = i->second.players.begin(); j != i->second.players.end(); j++)
|
||||
if ( cb->getPlayerState(*j)->status == PlayerState::INGAME )//seek for living player (if any)
|
||||
if ( cb->getPlayer(*j)->status == PlayerState::INGAME )//seek for living player (if any)
|
||||
{
|
||||
FoWChange fw;
|
||||
fw.mode = 0;
|
||||
@@ -2184,7 +2184,7 @@ int CGTownInstance::getMarketEfficiency() const
|
||||
if(!vstd::contains(builtBuildings, 14))
|
||||
return 0;
|
||||
|
||||
const PlayerState *p = cb->getPlayerState(tempOwner);
|
||||
const PlayerState *p = cb->getPlayer(tempOwner);
|
||||
assert(p);
|
||||
|
||||
int marketCount = 0;
|
||||
@@ -6313,7 +6313,7 @@ int3 IBoatGenerator::bestLocation() const
|
||||
|
||||
for (int i = 0; i < offsets.size(); ++i)
|
||||
{
|
||||
TerrainTile *tile = IObjectInterface::cb->getTile(o->pos + offsets[i]);
|
||||
const TerrainTile *tile = IObjectInterface::cb->getTile(o->pos + offsets[i]);
|
||||
if (tile) //tile is in the map
|
||||
{
|
||||
if (tile->tertype == TerrainTile::water && (!tile->blocked || tile->blockingObjects.front()->ID == 8)) //and is water and is not blocked or is blocked by boat
|
||||
@@ -6326,7 +6326,7 @@ int3 IBoatGenerator::bestLocation() const
|
||||
int IBoatGenerator::state() const
|
||||
{
|
||||
int3 tile = bestLocation();
|
||||
TerrainTile *t = IObjectInterface::cb->getTile(tile);
|
||||
const TerrainTile *t = IObjectInterface::cb->getTile(tile);
|
||||
if(!t)
|
||||
return 2; //no available water
|
||||
else if(!t->blockingObjects.size())
|
||||
|
12
lib/CObstacleInstance.h
Normal file
12
lib/CObstacleInstance.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
struct DLL_EXPORT CObstacleInstance
|
||||
{
|
||||
int uniqueID;
|
||||
int ID; //ID of obstacle (defines type of it)
|
||||
int pos; //position on battlefield
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & ID & pos & uniqueID;
|
||||
}
|
||||
};
|
@@ -1,3 +1,4 @@
|
||||
#define VCMI_DLL
|
||||
#include "ERMInterpreter.h"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
@@ -1118,6 +1119,18 @@ void ERMInterpreter::executeTriggerType( VERMInterpreter::TriggerType tt, bool p
|
||||
}
|
||||
}
|
||||
|
||||
void ERMInterpreter::executeTriggerType(const char *trigger, int id)
|
||||
{
|
||||
TIDPattern tip;
|
||||
tip[0] = std::vector<int>(1, id);
|
||||
executeTriggerType(VERMInterpreter::TriggerType(trigger), true, tip);
|
||||
}
|
||||
|
||||
void ERMInterpreter::executeTriggerType(const char *trigger)
|
||||
{
|
||||
executeTriggerType(VERMInterpreter::TriggerType(trigger), true, TIDPattern());
|
||||
}
|
||||
|
||||
ERM::Ttrigger ERMInterpreter::retrieveTrigger( ERM::TLine line )
|
||||
{
|
||||
if(line.which() == 1)
|
||||
@@ -1253,6 +1266,11 @@ FunctionLocalVars * ERMInterpreter::getFuncVars( int funNum )
|
||||
return funcVars + funNum - 1;
|
||||
}
|
||||
|
||||
void ERMInterpreter::executeInstructions()
|
||||
{
|
||||
//TODO implement me
|
||||
}
|
||||
|
||||
const std::string ERMInterpreter::triggerSymbol = "trigger";
|
||||
const std::string ERMInterpreter::postTriggerSymbol = "postTrigger";
|
||||
const std::string ERMInterpreter::defunSymbol = "defun";
|
||||
|
@@ -507,7 +507,10 @@ class ERMInterpreter
|
||||
IexpValStr getVar(std::string toFollow, boost::optional<int> initVal) const;
|
||||
public:
|
||||
typedef std::map< int, std::vector<int> > TIDPattern;
|
||||
void executeInstructions(); //called when starting a new game, before most of the map settings are done
|
||||
void executeTriggerType(VERMInterpreter::TriggerType tt, bool pre, const TIDPattern & identifier); //use this to run triggers
|
||||
void executeTriggerType(const char *trigger, int id); //convenience version of above, for pre-trigger when there is only one argument
|
||||
void executeTriggerType(const char *trigger); //convenience version of above, for pre-trigger when there are no args
|
||||
void init(); //sets up environment etc.
|
||||
void scanForScripts();
|
||||
|
||||
|
49
lib/ERMScriptModule.cpp
Normal file
49
lib/ERMScriptModule.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
#define VCMI_DLL
|
||||
|
||||
#include "ERMScriptModule.h"
|
||||
#include "ERMInterpreter.h"
|
||||
#include <boost/assign/std/vector.hpp>
|
||||
#include <boost/assign/list_of.hpp>
|
||||
#include "CObjectHandler.h"
|
||||
|
||||
using namespace boost::assign;
|
||||
|
||||
CScriptingModule::~CScriptingModule()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CERMScriptModule::CERMScriptModule(void)
|
||||
{
|
||||
}
|
||||
|
||||
CERMScriptModule::~CERMScriptModule(void)
|
||||
{
|
||||
}
|
||||
|
||||
void CERMScriptModule::init()
|
||||
{
|
||||
interpreter = new ERMInterpreter();
|
||||
interpreter->init();
|
||||
interpreter->scanForScripts();
|
||||
interpreter->scanScripts();
|
||||
interpreter->executeInstructions();
|
||||
interpreter->executeTriggerType("PI");
|
||||
}
|
||||
|
||||
void CERMScriptModule::heroVisit(const CGHeroInstance *visitor, const CGObjectInstance *visitedObj, bool start)
|
||||
{
|
||||
ERMInterpreter::TIDPattern tip;
|
||||
tip[1] = list_of(visitedObj->ID);
|
||||
tip[2] = list_of(visitedObj->ID)(visitedObj->subID);
|
||||
tip[3] = list_of(visitedObj->pos.x)(visitedObj->pos.y)(visitedObj->pos.z);
|
||||
interpreter->executeTriggerType(VERMInterpreter::TriggerType("OB"), start, tip);
|
||||
}
|
||||
|
||||
void CERMScriptModule::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side)
|
||||
{
|
||||
interpreter->executeTriggerType("BA", 0);
|
||||
interpreter->executeTriggerType("BR", -1);
|
||||
interpreter->executeTriggerType("BF", 0);
|
||||
//TODO tactics or not
|
||||
}
|
28
lib/ERMScriptModule.h
Normal file
28
lib/ERMScriptModule.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "..\global.h"
|
||||
#include "IGameEventsReceiver.h"
|
||||
|
||||
class ERMInterpreter;
|
||||
|
||||
class DLL_EXPORT CScriptingModule : public IGameEventsReceiver, public IBattleEventsReceiver
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void init(){}; //called upon the start of game (after map randomization, before first turn)
|
||||
virtual ~CScriptingModule();
|
||||
};
|
||||
|
||||
class DLL_EXPORT CERMScriptModule : public CScriptingModule
|
||||
{
|
||||
public:
|
||||
ERMInterpreter *interpreter;
|
||||
|
||||
CERMScriptModule(void);
|
||||
~CERMScriptModule(void);
|
||||
|
||||
virtual void heroVisit(const CGHeroInstance *visitor, const CGObjectInstance *visitedObj, bool start) OVERRIDE;
|
||||
virtual void init() OVERRIDE;
|
||||
virtual void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side) OVERRIDE;
|
||||
};
|
||||
|
@@ -14,6 +14,7 @@
|
||||
#include <boost/foreach.hpp>
|
||||
#include "NetPacks.h"
|
||||
#include <boost/bind.hpp>
|
||||
#include "CBuildingHandler.h"
|
||||
|
||||
/*
|
||||
* IGameCallback.cpp, part of VCMI engine
|
||||
@@ -25,10 +26,11 @@
|
||||
*
|
||||
*/
|
||||
|
||||
//TODO make clean
|
||||
#define ERROR_SILENT_RET_VAL_IF(cond, txt, retVal) do {if(cond){return retVal;}} while(0)
|
||||
#define ERROR_VERBOSE_OR_NOT_RET_VAL_IF(cond, verbose, txt, retVal) do {if(cond){if(verbose)tlog1 << BOOST_CURRENT_FUNCTION << ": " << txt << std::endl; return retVal;}} while(0)
|
||||
#define ERROR_RET_IF(cond, txt) do {if(cond){tlog1 << BOOST_CURRENT_FUNCTION << ": " << txt << std::endl; return;}} while(0)
|
||||
#define ERROR_RET_VAL_IF(cond, txt, retVal) do {if(cond){tlog1 << BOOST_CURRENT_FUNCTION << ": " << txt << std::endl; return retVal;}} while(0)
|
||||
//#define ERROR_RET_IF(cond, printCond, txt, retVal) do {if(cond){ if(printCond) tlog1 << BOOST_CURRENT_FUNCTION << ": " << txt << std::endl; return retVal;}} while(0)
|
||||
|
||||
extern boost::rand48 ran;
|
||||
|
||||
@@ -347,7 +349,7 @@ int CGameInfoCallback::getOwner(int heroID) const
|
||||
|
||||
int CGameInfoCallback::getResource(int Player, int which) const
|
||||
{
|
||||
const PlayerState *p = getPlayerState(Player);
|
||||
const PlayerState *p = getPlayer(Player);
|
||||
ERROR_RET_VAL_IF(!p, "No player info!", -1);
|
||||
ERROR_RET_VAL_IF(p->resources.size() <= which || which < 0, "No such resource!", -1);
|
||||
return p->resources[which];
|
||||
@@ -355,7 +357,7 @@ int CGameInfoCallback::getResource(int Player, int which) const
|
||||
|
||||
const CGHeroInstance* CGameInfoCallback::getSelectedHero( int Player ) const
|
||||
{
|
||||
const PlayerState *p = getPlayerState(Player);
|
||||
const PlayerState *p = getPlayer(Player);
|
||||
ERROR_RET_VAL_IF(!p, "No player info!", NULL);
|
||||
return getHero(p->currentSelection);
|
||||
}
|
||||
@@ -446,7 +448,7 @@ void CPrivilagedInfoCallback::getFreeTiles (std::vector<int3> &tiles) const
|
||||
{
|
||||
floors.push_back(b);
|
||||
}
|
||||
TerrainTile *tinfo;
|
||||
const TerrainTile *tinfo;
|
||||
for (std::vector<int>::const_iterator i = floors.begin(); i!= floors.end(); i++)
|
||||
{
|
||||
register int zd = *i;
|
||||
@@ -519,17 +521,18 @@ void CPrivilagedInfoCallback::getAllowedSpells(std::vector<ui16> &out, ui16 leve
|
||||
}
|
||||
}
|
||||
|
||||
inline TerrainTile * CPrivilagedInfoCallback::getTile( int3 pos ) const
|
||||
inline TerrainTile * CNonConstInfoCallback::getTile( int3 pos )
|
||||
{
|
||||
if(!gs->map->isInTheMap(pos))
|
||||
return NULL;
|
||||
return &gs->map->getTile(pos);
|
||||
}
|
||||
|
||||
const PlayerState * CGameInfoCallback::getPlayerState(int color) const
|
||||
const PlayerState * CGameInfoCallback::getPlayer(int color, bool verbose) const
|
||||
{
|
||||
ERROR_RET_VAL_IF(!hasAccess(color), "Cannot access player " << color << "info!", NULL);
|
||||
return gs->getPlayer(color, false);
|
||||
ERROR_VERBOSE_OR_NOT_RET_VAL_IF(!hasAccess(color), verbose, "Cannot access player " << color << "info!", NULL);
|
||||
ERROR_VERBOSE_OR_NOT_RET_VAL_IF(!vstd::contains(gs->players,color), verbose, "Cannot find player " << color << "info!", NULL);
|
||||
return &gs->players[color];
|
||||
}
|
||||
|
||||
const CTown * CGameInfoCallback::getNativeTown(int color) const
|
||||
@@ -703,7 +706,7 @@ std::vector < std::string > CGameInfoCallback::getObjDescriptions(int3 pos) cons
|
||||
{
|
||||
//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||
std::vector<std::string> ret;
|
||||
const TerrainTile *t = getTileInfo(pos);
|
||||
const TerrainTile *t = getTile(pos);
|
||||
ERROR_RET_VAL_IF(!t, "Not a valid tile given!", ret);
|
||||
|
||||
|
||||
@@ -715,7 +718,8 @@ bool CGameInfoCallback::verifyPath(CPath * path, bool blockSea) const
|
||||
{
|
||||
for (size_t i=0; i < path->nodes.size(); ++i)
|
||||
{
|
||||
const TerrainTile *t = getTileInfo(path->nodes[i].coord); //current tile
|
||||
const TerrainTile *t = getTile(path->nodes[i].coord); //current tile
|
||||
ERROR_RET_VAL_IF(!t, "Path contains not visible tile: " << path->nodes[i].coord << "!", false);
|
||||
if (t->blocked && !t->visitable)
|
||||
return false; //path is wrong - one of the tiles is blocked
|
||||
|
||||
@@ -724,7 +728,7 @@ bool CGameInfoCallback::verifyPath(CPath * path, bool blockSea) const
|
||||
if (i==0)
|
||||
continue;
|
||||
|
||||
const TerrainTile *prev = getTileInfo(path->nodes[i-1].coord); //tile of previous node on the path
|
||||
const TerrainTile *prev = getTile(path->nodes[i-1].coord); //tile of previous node on the path
|
||||
if (( t->tertype == TerrainTile::water && prev->tertype != TerrainTile::water)
|
||||
|| (t->tertype != TerrainTile::water && prev->tertype == TerrainTile::water)
|
||||
|| prev->tertype == TerrainTile::rock
|
||||
@@ -740,7 +744,7 @@ bool CGameInfoCallback::verifyPath(CPath * path, bool blockSea) const
|
||||
bool CGameInfoCallback::isVisible(int3 pos, int Player) const
|
||||
{
|
||||
//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||
return gs->map->isInTheMap(pos) && gs->isVisible(pos, Player);
|
||||
return gs->map->isInTheMap(pos) && (Player == -1 || gs->isVisible(pos, Player));
|
||||
}
|
||||
|
||||
bool CGameInfoCallback::isVisible(int3 pos) const
|
||||
@@ -771,7 +775,7 @@ bool CGameInfoCallback::isVisible(const CGObjectInstance *obj) const
|
||||
std::vector < const CGObjectInstance * > CGameInfoCallback::getBlockingObjs( int3 pos ) const
|
||||
{
|
||||
std::vector<const CGObjectInstance *> ret;
|
||||
const TerrainTile *t = getTileInfo(pos);
|
||||
const TerrainTile *t = getTile(pos);
|
||||
ERROR_RET_VAL_IF(!t, "Not a valid tile requested!", ret);
|
||||
|
||||
BOOST_FOREACH(const CGObjectInstance * obj, t->blockingObjects)
|
||||
@@ -782,7 +786,7 @@ std::vector < const CGObjectInstance * > CGameInfoCallback::getBlockingObjs( int
|
||||
std::vector < const CGObjectInstance * > CGameInfoCallback::getVisitableObjs( int3 pos ) const
|
||||
{
|
||||
std::vector<const CGObjectInstance *> ret;
|
||||
const TerrainTile *t = getTileInfo(pos);
|
||||
const TerrainTile *t = getTile(pos);
|
||||
ERROR_RET_VAL_IF(!t, "Not a valid tile requested!", ret);
|
||||
//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||
|
||||
@@ -794,7 +798,7 @@ std::vector < const CGObjectInstance * > CGameInfoCallback::getVisitableObjs( in
|
||||
std::vector < const CGObjectInstance * > CGameInfoCallback::getFlaggableObjects(int3 pos) const
|
||||
{
|
||||
std::vector<const CGObjectInstance *> ret;
|
||||
const TerrainTile *t = getTileInfo(pos);
|
||||
const TerrainTile *t = getTile(pos);
|
||||
ERROR_RET_VAL_IF(!t, "Not a valid tile requested!", ret);
|
||||
BOOST_FOREACH(const CGObjectInstance *obj, t->blockingObjects)
|
||||
if(obj->tempOwner != 254)
|
||||
@@ -822,10 +826,9 @@ std::vector<const CGHeroInstance *> CGameInfoCallback::getAvailableHeroes(const
|
||||
return ret;
|
||||
}
|
||||
|
||||
const TerrainTile * CGameInfoCallback::getTileInfo( int3 tile ) const
|
||||
const TerrainTile * CGameInfoCallback::getTile( int3 tile, bool verbose) const
|
||||
{
|
||||
//ERROR_RET_VAL_IF(!gs->map->isInTheMap(tile), tile << " is outside the map!", NULL);
|
||||
ERROR_SILENT_RET_VAL_IF(!isVisible(tile), tile << " is not visible!", NULL);
|
||||
ERROR_VERBOSE_OR_NOT_RET_VAL_IF(!isVisible(tile), verbose, tile << " is not visible!", NULL);
|
||||
|
||||
//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||
return &gs->map->getTile(tile);
|
||||
@@ -834,13 +837,97 @@ const TerrainTile * CGameInfoCallback::getTileInfo( int3 tile ) const
|
||||
int CGameInfoCallback::canBuildStructure( const CGTownInstance *t, int ID )
|
||||
{
|
||||
ERROR_RET_VAL_IF(!canGetFullInfo(t), "Town is not owned!", -1);
|
||||
return gs->canBuildStructure(t,ID);
|
||||
|
||||
int ret = Buildings::ALLOWED;
|
||||
if(t->builded >= MAX_BUILDING_PER_TURN)
|
||||
ret = Buildings::CANT_BUILD_TODAY; //building limit
|
||||
|
||||
CBuilding * pom = VLC->buildh->buildings[t->subID][ID];
|
||||
|
||||
if(!pom)
|
||||
return Buildings::ERROR;
|
||||
|
||||
//checking resources
|
||||
for(int res=0; res<RESOURCE_QUANTITY; res++)
|
||||
{
|
||||
if(pom->resources[res] > getResource(t->tempOwner, res))
|
||||
ret = Buildings::NO_RESOURCES; //lack of res
|
||||
}
|
||||
|
||||
//checking for requirements
|
||||
std::set<int> reqs = getBuildingRequiments(t, ID);//getting all requirements
|
||||
|
||||
for( std::set<int>::iterator ri = reqs.begin(); ri != reqs.end(); ri++ )
|
||||
{
|
||||
if(t->builtBuildings.find(*ri)==t->builtBuildings.end())
|
||||
ret = Buildings::PREREQUIRES; //lack of requirements - cannot build
|
||||
}
|
||||
|
||||
//can we build it?
|
||||
if(t->forbiddenBuildings.find(ID)!=t->forbiddenBuildings.end())
|
||||
ret = Buildings::FORBIDDEN; //forbidden
|
||||
|
||||
if(ID == 13) //capitol
|
||||
{
|
||||
const PlayerState *ps = getPlayer(t->tempOwner);
|
||||
if(ps)
|
||||
{
|
||||
BOOST_FOREACH(const CGTownInstance *t, ps->towns)
|
||||
{
|
||||
if(vstd::contains(t->builtBuildings, 13))
|
||||
{
|
||||
ret = Buildings::HAVE_CAPITAL; //no more than one capitol
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(ID == 6) //shipyard
|
||||
{
|
||||
const TerrainTile *tile = getTile(t->bestLocation());
|
||||
|
||||
if(!tile || tile->tertype != TerrainTile::water )
|
||||
ret = Buildings::NO_WATER; //lack of water
|
||||
}
|
||||
|
||||
if(t->builtBuildings.find(ID)!=t->builtBuildings.end()) //already built
|
||||
ret = Buildings::ALREADY_PRESENT;
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::set<int> CGameInfoCallback::getBuildingRequiments( const CGTownInstance *t, int ID )
|
||||
{
|
||||
ERROR_RET_VAL_IF(!canGetFullInfo(t), "Town is not owned!", std::set<int>());
|
||||
return gs->getBuildingRequiments(t,ID);
|
||||
|
||||
std::set<int> used;
|
||||
used.insert(ID);
|
||||
std::set<int> reqs = VLC->townh->requirements[t->subID][ID];
|
||||
|
||||
while(true)
|
||||
{
|
||||
size_t noloop=0;
|
||||
for(std::set<int>::iterator i=reqs.begin();i!=reqs.end();i++)
|
||||
{
|
||||
if(used.find(*i)==used.end()) //we haven't added requirements for this building
|
||||
{
|
||||
used.insert(*i);
|
||||
for(
|
||||
std::set<int>::iterator j=VLC->townh->requirements[t->subID][*i].begin();
|
||||
j!=VLC->townh->requirements[t->subID][*i].end();
|
||||
j++)
|
||||
{
|
||||
reqs.insert(*j);//creating full list of requirements
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
noloop++;
|
||||
}
|
||||
}
|
||||
if(noloop==reqs.size())
|
||||
break;
|
||||
}
|
||||
return reqs;
|
||||
}
|
||||
|
||||
const CMapHeader * CGameInfoCallback::getMapHeader() const
|
||||
@@ -850,7 +937,7 @@ const CMapHeader * CGameInfoCallback::getMapHeader() const
|
||||
|
||||
bool CGameInfoCallback::hasAccess(int playerId) const
|
||||
{
|
||||
return gs->getPlayerRelations( playerId, player ) || player < 0;
|
||||
return player < 0 || gs->getPlayerRelations( playerId, player );
|
||||
}
|
||||
|
||||
int CGameInfoCallback::getPlayerStatus(int player) const
|
||||
@@ -896,7 +983,7 @@ bool CGameInfoCallback::isOwnedOrVisited(const CGObjectInstance *obj) const
|
||||
if(canGetFullInfo(obj))
|
||||
return true;
|
||||
|
||||
const TerrainTile *t = getTileInfo(obj->visitablePos()); //get entrance tile
|
||||
const TerrainTile *t = getTile(obj->visitablePos()); //get entrance tile
|
||||
const CGObjectInstance *visitor = t->visitableObjects.back(); //visitong hero if present or the obejct itself at last
|
||||
return visitor->ID == HEROI_TYPE && canGetFullInfo(visitor); //owned or allied hero is a visitor
|
||||
}
|
||||
@@ -1014,7 +1101,7 @@ int CPlayerSpecificInfoCallback::howManyHeroes(bool includeGarrisoned) const
|
||||
|
||||
const CGHeroInstance* CPlayerSpecificInfoCallback::getHeroBySerial(int serialId) const
|
||||
{
|
||||
const PlayerState *p = getPlayerState(serialId);
|
||||
const PlayerState *p = getPlayer(serialId);
|
||||
ERROR_RET_VAL_IF(!p, "No player info", NULL);
|
||||
ERROR_RET_VAL_IF(serialId < 0 || serialId >= p->heroes.size(), "No player info", NULL);
|
||||
return p->heroes[serialId];
|
||||
@@ -1022,7 +1109,7 @@ const CGHeroInstance* CPlayerSpecificInfoCallback::getHeroBySerial(int serialId)
|
||||
|
||||
const CGTownInstance* CPlayerSpecificInfoCallback::getTownBySerial(int serialId) const
|
||||
{
|
||||
const PlayerState *p = getPlayerState(serialId);
|
||||
const PlayerState *p = getPlayer(serialId);
|
||||
ERROR_RET_VAL_IF(!p, "No player info", NULL);
|
||||
ERROR_RET_VAL_IF(serialId < 0 || serialId >= p->towns.size(), "No player info", NULL);
|
||||
return p->towns[serialId];
|
||||
@@ -1041,3 +1128,46 @@ std::vector<si32> CPlayerSpecificInfoCallback::getResourceAmount() const
|
||||
ERROR_RET_VAL_IF(player == -1, "Applicable only for player callbacks", std::vector<si32>());
|
||||
return gs->players[player].resources;
|
||||
}
|
||||
|
||||
CGHeroInstance *CNonConstInfoCallback::getHero(int objid)
|
||||
{
|
||||
return const_cast<CGHeroInstance*>(CGameInfoCallback::getHero(objid));
|
||||
}
|
||||
|
||||
CGTownInstance *CNonConstInfoCallback::getTown(int objid)
|
||||
{
|
||||
|
||||
return const_cast<CGTownInstance*>(CGameInfoCallback::getTown(objid));
|
||||
}
|
||||
|
||||
TeamState *CNonConstInfoCallback::getTeam(ui8 teamID)
|
||||
{
|
||||
return const_cast<TeamState*>(CGameInfoCallback::getTeam(teamID));
|
||||
}
|
||||
|
||||
TeamState *CNonConstInfoCallback::getPlayerTeam(ui8 color)
|
||||
{
|
||||
return const_cast<TeamState*>(CGameInfoCallback::getPlayerTeam(color));
|
||||
}
|
||||
|
||||
PlayerState * CNonConstInfoCallback::getPlayer( ui8 color, bool verbose )
|
||||
{
|
||||
return const_cast<PlayerState*>(CGameInfoCallback::getPlayer(color, verbose));
|
||||
}
|
||||
|
||||
const TeamState * CGameInfoCallback::getTeam( ui8 teamID ) const
|
||||
{
|
||||
ERROR_RET_VAL_IF(!vstd::contains(gs->teams, teamID), "Cannot find info for team " << int(teamID), NULL);
|
||||
const TeamState *ret = &gs->teams[teamID];
|
||||
ERROR_RET_VAL_IF(player != -1 && !vstd::contains(ret->players, player), "Illegal attempt to access team data!", NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const TeamState * CGameInfoCallback::getPlayerTeam( ui8 teamID ) const
|
||||
{
|
||||
const PlayerState * ps = getPlayer(teamID);
|
||||
if (ps)
|
||||
return getTeam(ps->team);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@@ -5,8 +5,7 @@
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include "../client/FunctionList.h"
|
||||
#include "CCreatureSet.h"
|
||||
#include "BattleState.h"
|
||||
#include "CObstacleInstance.h"
|
||||
|
||||
/*
|
||||
* IGameCallback.h, part of VCMI engine
|
||||
@@ -51,6 +50,11 @@ struct InfoAboutHero;
|
||||
class CMapHeader;
|
||||
struct BattleAction;
|
||||
class CStack;
|
||||
class CSpell;
|
||||
class CCreatureSet;
|
||||
class CCreature;
|
||||
class CStackBasicDescriptor;
|
||||
class TeamState;
|
||||
|
||||
typedef std::vector<const CStack*> TStacks;
|
||||
|
||||
@@ -104,7 +108,7 @@ public:
|
||||
si8 battleGetTacticDist(); //returns tactic distance for calling player or 0 if player is not in tactic phase
|
||||
ui8 battleGetMySide(); //return side of player in battle (attacker/defender)
|
||||
|
||||
//convienience methods using the ones above
|
||||
//convenience methods using the ones above
|
||||
TStacks battleGetAllStacks() //returns all stacks, alive or dead or undead or mechanical :)
|
||||
{
|
||||
return battleGetStacks(MINE_AND_ENEMY, false);
|
||||
@@ -121,7 +125,7 @@ protected:
|
||||
bool isVisible(const CGObjectInstance *obj, int Player) const;
|
||||
bool isVisible(const CGObjectInstance *obj) const;
|
||||
|
||||
bool canGetFullInfo(const CGObjectInstance *obj) const; //true we player owns obj or ally owns obj or privilaged mode
|
||||
bool canGetFullInfo(const CGObjectInstance *obj) const; //true we player owns obj or ally owns obj or privileged mode
|
||||
bool isOwnedOrVisited(const CGObjectInstance *obj) const;
|
||||
|
||||
public:
|
||||
@@ -131,7 +135,7 @@ public:
|
||||
bool isAllowed(int type, int id); //type: 0 - spell; 1- artifact; 2 - secondary skill
|
||||
|
||||
//player
|
||||
const PlayerState * getPlayerState(int color) const;
|
||||
const PlayerState * getPlayer(int color, bool verbose = true) const;
|
||||
int getResource(int Player, int which) const;
|
||||
bool isVisible(int3 pos) const;
|
||||
int getPlayerRelations(ui8 color1, ui8 color2) const;// 0 = enemy, 1 = ally, 2 = same player
|
||||
@@ -140,15 +144,19 @@ public:
|
||||
int getCurrentPlayer() const; //player that currently makes move // TODO synchronous turns
|
||||
const PlayerSettings * getPlayerSettings(int color) const;
|
||||
|
||||
|
||||
//armed object
|
||||
void getUpgradeInfo(const CArmedInstance *obj, int stackPos, UpgradeInfo &out)const;
|
||||
|
||||
//hero
|
||||
const CGHeroInstance* getHero(int objid) const;
|
||||
int getHeroCount(int player, bool includeGarrisoned) const;
|
||||
bool getHeroInfo(const CGObjectInstance *hero, InfoAboutHero &dest) const;
|
||||
int getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const; //when called during battle, takes into account creatures' spell cost reduction
|
||||
int estimateSpellDamage(const CSpell * sp, const CGHeroInstance * hero) const; //estimates damage of given spell; returns 0 if spell causes no dmg
|
||||
bool verifyPath(CPath * path, bool blockSea)const;
|
||||
const CGHeroInstance* getSelectedHero(int player) const; //NULL if no hero is selected
|
||||
int getSelectedHero() const; //of current (active) player
|
||||
|
||||
//objects
|
||||
const CGObjectInstance* getObj(int objid, bool verbose = true) const;
|
||||
@@ -157,14 +165,16 @@ public:
|
||||
std::vector <const CGObjectInstance * > getFlaggableObjects(int3 pos) const;
|
||||
std::vector <std::string > getObjDescriptions(int3 pos)const; //returns descriptions of objects at pos in order from the lowest to the highest
|
||||
int getOwner(int heroID) const;
|
||||
const CGObjectInstance *getObjByQuestIdentifier(int identifier) const; //NULL if object has been removed (eg. killed)
|
||||
|
||||
//map
|
||||
int3 guardingCreaturePosition (int3 pos) const;
|
||||
const CMapHeader * getMapHeader()const;
|
||||
int3 getMapSize() const; //returns size of map - z is 1 for one - level map and 2 for two level map
|
||||
const TerrainTile * getTileInfo(int3 tile) const;
|
||||
const TerrainTile * getTile(int3 tile, bool verbose = true) const;
|
||||
|
||||
//town
|
||||
const CGTownInstance* getTown(int objid) const;
|
||||
int howManyTowns(int Player) const;
|
||||
const CGTownInstance * getTownInfo(int val, bool mode)const; //mode = 0 -> val = player town serial; mode = 1 -> val = object id (serial)
|
||||
std::vector<const CGHeroInstance *> getAvailableHeroes(const CGObjectInstance * townOrTavern) const; //heroes that can be recruited
|
||||
@@ -172,15 +182,13 @@ public:
|
||||
int canBuildStructure(const CGTownInstance *t, int ID);//// 0 - no more than one capitol, 1 - lack of water, 2 - forbidden, 3 - Add another level to Mage Guild, 4 - already built, 5 - cannot build, 6 - cannot afford, 7 - build, 8 - lack of requirements
|
||||
std::set<int> getBuildingRequiments(const CGTownInstance *t, int ID);
|
||||
virtual bool getTownInfo(const CGObjectInstance *town, InfoAboutTown &dest) const;
|
||||
|
||||
//moved
|
||||
const CGHeroInstance* getHero(int objid) const;
|
||||
const CGTownInstance* getTown(int objid) const;
|
||||
|
||||
const CGHeroInstance* getSelectedHero(int player) const; //NULL if no hero is selected
|
||||
const CGObjectInstance *getObjByQuestIdentifier(int identifier) const; //NULL if object has been removed (eg. killed)
|
||||
int getSelectedHero() const;
|
||||
const CTown *getNativeTown(int color) const;
|
||||
|
||||
//from gs
|
||||
const TeamState *getTeam(ui8 teamID) const;
|
||||
const TeamState *getPlayerTeam(ui8 color) const;
|
||||
std::set<int> getBuildingRequiments(const CGTownInstance *t, int ID) const;
|
||||
int canBuildStructure(const CGTownInstance *t, int ID) const;// 0 - no more than one capitol, 1 - lack of water, 2 - forbidden, 3 - Add another level to Mage Guild, 4 - already built, 5 - cannot build, 6 - cannot afford, 7 - build, 8 - lack of requirements
|
||||
};
|
||||
|
||||
|
||||
@@ -210,7 +218,6 @@ class DLL_EXPORT CPrivilagedInfoCallback : public CGameInfoCallback
|
||||
{
|
||||
public:
|
||||
CGameState *const gameState ();
|
||||
TerrainTile * getTile(int3 pos) const;
|
||||
void getFreeTiles (std::vector<int3> &tiles) const; //used for random spawns
|
||||
void getTilesInRange(boost::unordered_set<int3, ShashInt3> &tiles, int3 pos, int radious, int player=-1, int mode=0) const; //mode 1 - only unrevealed tiles; mode 0 - all, mode -1 - only unrevealed
|
||||
void getAllTiles (boost::unordered_set<int3, ShashInt3> &tiles, int player=-1, int level=-1, int surface=0) const; //returns all tiles on given level (-1 - both levels, otherwise number of level); surface: 0 - land and water, 1 - only land, 2 - only water
|
||||
@@ -221,6 +228,17 @@ public:
|
||||
void getAllowedSpells(std::vector<ui16> &out, ui16 level);
|
||||
};
|
||||
|
||||
class DLL_EXPORT CNonConstInfoCallback : public CPrivilagedInfoCallback
|
||||
{
|
||||
public:
|
||||
PlayerState *getPlayer(ui8 color, bool verbose = true);
|
||||
TeamState *getTeam(ui8 teamID);//get team by team ID
|
||||
TeamState *getPlayerTeam(ui8 color);// get team by player color
|
||||
CGHeroInstance *getHero(int objid);
|
||||
CGTownInstance *getTown(int objid);
|
||||
TerrainTile * getTile(int3 pos);
|
||||
};
|
||||
|
||||
/// Interface class for handling general game logic and actions
|
||||
class DLL_EXPORT IGameCallback : public CPrivilagedInfoCallback
|
||||
{
|
||||
@@ -243,8 +261,8 @@ public:
|
||||
virtual void showThievesGuildWindow(int requestingObjId) =0;
|
||||
virtual void giveResource(int player, int which, int val)=0;
|
||||
|
||||
virtual void giveCreatures (const CArmedInstance *objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) =0;
|
||||
virtual void takeCreatures (int objid, std::vector<CStackBasicDescriptor> creatures) =0;
|
||||
virtual void giveCreatures(const CArmedInstance *objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) =0;
|
||||
virtual void takeCreatures(int objid, const std::vector<CStackBasicDescriptor> &creatures) =0;
|
||||
virtual bool changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue = false) =0;
|
||||
virtual bool changeStackType(const StackLocation &sl, CCreature *c) =0;
|
||||
virtual bool insertNewStack(const StackLocation &sl, const CCreature *c, TQuantity count = -1) =0; //count -1 => moves whole stack
|
||||
|
@@ -927,6 +927,21 @@ struct DisassembledArtifact : CArtifactOperationPack //530
|
||||
}
|
||||
};
|
||||
|
||||
struct HeroVisit : CPackForClient //531
|
||||
{
|
||||
const CGHeroInstance *hero;
|
||||
const CGObjectInstance *obj;
|
||||
bool starting; //false -> ending
|
||||
|
||||
void applyCl(CClient *cl);
|
||||
DLL_EXPORT void applyGs(CGameState *gs);
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & hero & obj & starting;
|
||||
}
|
||||
};
|
||||
|
||||
struct NewTurn : public CPackForClient //101
|
||||
{
|
||||
enum weekType {NORMAL, DOUBLE_GROWTH, BONUS_GROWTH, DEITYOFFIRE, PLAGUE, CUSTOM, NO_ACTION, NONE};
|
||||
|
@@ -710,6 +710,14 @@ DLL_EXPORT void DisassembledArtifact::applyGs( CGameState *gs )
|
||||
gs->map->eraseArtifactInstance(disassembled);
|
||||
}
|
||||
|
||||
DLL_EXPORT void HeroVisit::applyGs( CGameState *gs )
|
||||
{
|
||||
if(starting)
|
||||
gs->ongoingVisits[hero] = obj;
|
||||
else
|
||||
gs->ongoingVisits.erase(hero);
|
||||
}
|
||||
|
||||
DLL_EXPORT void SetAvailableArtifacts::applyGs( CGameState *gs )
|
||||
{
|
||||
if(id >= 0)
|
||||
|
@@ -173,6 +173,7 @@ void registerTypes2(Serializer &s)
|
||||
s.template registerType<MoveArtifact>();
|
||||
s.template registerType<AssembledArtifact>();
|
||||
s.template registerType<DisassembledArtifact>();
|
||||
s.template registerType<HeroVisit>();
|
||||
|
||||
s.template registerType<SaveGame>();
|
||||
s.template registerType<SetSelection>();
|
||||
|
@@ -50,12 +50,6 @@ DLL_EXPORT void initDLL(CConsoleHandler *Console, std::ostream *Logfile)
|
||||
{
|
||||
VLC->init();
|
||||
} HANDLE_EXCEPTION;
|
||||
|
||||
|
||||
ERMInterpreter ei;
|
||||
// ei.scanForScripts();
|
||||
// //ei.printScripts();
|
||||
// ei.scanScripts();
|
||||
}
|
||||
|
||||
DLL_EXPORT void loadToIt(std::string &dest, const std::string &src, int &iter, int mode)
|
||||
|
@@ -183,6 +183,7 @@
|
||||
<ClCompile Include="CTownHandler.cpp" />
|
||||
<ClCompile Include="ERMInterpreter.cpp" />
|
||||
<ClCompile Include="ERMParser.cpp" />
|
||||
<ClCompile Include="ERMScriptModule.cpp" />
|
||||
<ClCompile Include="HeroBonus.cpp" />
|
||||
<ClCompile Include="IGameCallback.cpp" />
|
||||
<ClCompile Include="map.cpp" />
|
||||
@@ -209,6 +210,7 @@
|
||||
<ClInclude Include="CLodHandler.h" />
|
||||
<ClInclude Include="CMapInfo.h" />
|
||||
<ClInclude Include="CObjectHandler.h" />
|
||||
<ClInclude Include="CObstacleInstance.h" />
|
||||
<ClInclude Include="CondSh.h" />
|
||||
<ClInclude Include="Connection.h" />
|
||||
<ClInclude Include="ConstTransitivePtr.h" />
|
||||
@@ -216,8 +218,10 @@
|
||||
<ClInclude Include="CTownHandler.h" />
|
||||
<ClInclude Include="ERMInterpreter.h" />
|
||||
<ClInclude Include="ERMParser.h" />
|
||||
<ClInclude Include="ERMScriptModule.h" />
|
||||
<ClInclude Include="HeroBonus.h" />
|
||||
<ClInclude Include="IGameCallback.h" />
|
||||
<ClInclude Include="IGameEventsReceiver.h" />
|
||||
<ClInclude Include="Interprocess.h" />
|
||||
<ClInclude Include="map.h" />
|
||||
<ClInclude Include="NetPacks.h" />
|
||||
|
@@ -23,6 +23,7 @@
|
||||
#include <boost/random/mersenne_twister.hpp>
|
||||
#include <boost/random/variate_generator.hpp>
|
||||
#include <boost/random/poisson_distribution.hpp>
|
||||
#include "../lib/CCreatureSet.h"
|
||||
|
||||
/*
|
||||
* CGameHandler.cpp, part of VCMI engine
|
||||
@@ -492,7 +493,7 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance *hero1, const CGHer
|
||||
sah.army[0].setCreature(0, VLC->creh->nameToID[loserHero->type->refTypeStack[0]],1);
|
||||
}
|
||||
|
||||
if(const CGHeroInstance *another = getPlayerState(loser)->availableHeroes[1])
|
||||
if(const CGHeroInstance *another = getPlayer(loser)->availableHeroes[1])
|
||||
sah.hid[1] = another->subID;
|
||||
else
|
||||
sah.hid[1] = -1;
|
||||
@@ -1592,13 +1593,14 @@ void CGameHandler::giveCreatures(const CArmedInstance *obj, const CGHeroInstance
|
||||
tryJoiningArmy(obj, h, remove, true);
|
||||
}
|
||||
|
||||
void CGameHandler::takeCreatures(int objid, std::vector<CStackBasicDescriptor> creatures)
|
||||
void CGameHandler::takeCreatures(int objid, const std::vector<CStackBasicDescriptor> &creatures)
|
||||
{
|
||||
if (creatures.size() <= 0)
|
||||
std::vector<CStackBasicDescriptor> cres = creatures;
|
||||
if (cres.size() <= 0)
|
||||
return;
|
||||
const CArmedInstance* obj = static_cast<const CArmedInstance*>(getObj(objid));
|
||||
|
||||
BOOST_FOREACH(CStackBasicDescriptor &sbd, creatures)
|
||||
BOOST_FOREACH(CStackBasicDescriptor &sbd, cres)
|
||||
{
|
||||
TQuantity collected = 0;
|
||||
while(collected < sbd.count)
|
||||
@@ -1608,14 +1610,14 @@ void CGameHandler::takeCreatures(int objid, std::vector<CStackBasicDescriptor> c
|
||||
{
|
||||
if(i->second->type == sbd.type)
|
||||
{
|
||||
TQuantity take = std::min(sbd.count - collected, i->second->count); //collect as much creatures as we can
|
||||
TQuantity take = std::min(sbd.count - collected, i->second->count); //collect as much cres as we can
|
||||
changeStackCount(StackLocation(obj, i->first), take, false);
|
||||
collected += take;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(i == obj->Slots().end()) //we went through the whole loop and haven't found appropriate creatures
|
||||
if(i == obj->Slots().end()) //we went through the whole loop and haven't found appropriate cres
|
||||
{
|
||||
complain("Unexpected failure during taking creatures!");
|
||||
return;
|
||||
@@ -3880,7 +3882,7 @@ bool CGameHandler::isAllowedExchange( int id1, int id2 )
|
||||
&& distance(o1->pos, o2->pos) < 2) //hero stands on the same tile or on the neighbouring tiles
|
||||
{
|
||||
//TODO: it's workaround, we should check if first hero visited second and player hasn't closed exchange window
|
||||
//(to block moving stacks for free [without visiting] beteen heroes)
|
||||
//(to block moving stacks for free [without visiting] between heroes)
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3889,7 +3891,17 @@ bool CGameHandler::isAllowedExchange( int id1, int id2 )
|
||||
|
||||
void CGameHandler::objectVisited( const CGObjectInstance * obj, const CGHeroInstance * h )
|
||||
{
|
||||
HeroVisit hv;
|
||||
hv.obj = obj;
|
||||
hv.hero = h;
|
||||
hv.starting = true;
|
||||
sendAndApply(&hv);
|
||||
|
||||
obj->onHeroVisit(h);
|
||||
|
||||
hv.obj = NULL; //not necessary, moreover may have been deleted in the meantime
|
||||
hv.starting = false;
|
||||
sendAndApply(&hv);
|
||||
}
|
||||
|
||||
bool CGameHandler::buildBoat( ui32 objid )
|
||||
|
@@ -143,8 +143,8 @@ public:
|
||||
void showThievesGuildWindow(int requestingObjId) OVERRIDE; //TODO: make something more general?
|
||||
void giveResource(int player, int which, int val) OVERRIDE;
|
||||
|
||||
void giveCreatures (const CArmedInstance *objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) OVERRIDE;
|
||||
void takeCreatures (int objid, std::vector<CStackBasicDescriptor> creatures) OVERRIDE;
|
||||
void giveCreatures(const CArmedInstance *objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) OVERRIDE;
|
||||
void takeCreatures(int objid, const std::vector<CStackBasicDescriptor> &creatures) OVERRIDE;
|
||||
bool changeStackType(const StackLocation &sl, CCreature *c) OVERRIDE;
|
||||
bool changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue = false) OVERRIDE;
|
||||
bool insertNewStack(const StackLocation &sl, const CCreature *c, TQuantity count) OVERRIDE;
|
||||
|
Reference in New Issue
Block a user