1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-26 03:52:01 +02:00

* version set 0.73b

* config entry for 1600x1200 resolution
* several fixes
* http://vcmi.antypika.aplus.pl/forum/viewtopic.php?p=3185#3185
This commit is contained in:
Michał W. Urbańczyk 2009-08-03 23:53:18 +00:00
parent b987f02cb0
commit de1ed92379
21 changed files with 388 additions and 128 deletions

View File

@ -460,7 +460,7 @@ std::vector<int> CBattleLogic::GetAvailableHexesForAttacker(CStack *defender, CS
BattleAction CBattleLogic::MakeDefend(int stackID)
{
BattleAction ba;
ba.side = 1;
ba.side = m_side;
ba.actionType = action_defend;
ba.stackNumber = stackID;
ba.additionalInfo = -1;
@ -470,7 +470,7 @@ BattleAction CBattleLogic::MakeDefend(int stackID)
BattleAction CBattleLogic::MakeWait(int stackID)
{
BattleAction ba;
ba.side = 1;
ba.side = m_side;
ba.actionType = action_wait;
ba.stackNumber = stackID;
ba.additionalInfo = -1;
@ -479,11 +479,21 @@ BattleAction CBattleLogic::MakeWait(int stackID)
BattleAction CBattleLogic::MakeAttack(int attackerID, int destinationID)
{
CStack *attackerStack = m_cb->battleGetStackByID(attackerID),
*destinationStack = m_cb->battleGetStackByID(destinationID);
assert(attackerStack && destinationStack);
//don't attack ourselves
if(destinationStack->attackerOwned == !m_side)
{
return MakeDefend(attackerID);
}
if (m_cb->battleCanShoot(attackerID, m_cb->battleGetPos(destinationID)))
{
// shoot
BattleAction ba;
ba.side = 1;
ba.side = m_side;
ba.additionalInfo = -1;
ba.actionType = action_shoot; // shoot
ba.stackNumber = attackerID;
@ -528,7 +538,7 @@ BattleAction CBattleLogic::MakeAttack(int attackerID, int destinationID)
}
BattleAction ba;
ba.side = 1;
ba.side = m_side;
//ba.actionType = 6; // go and attack
ba.stackNumber = attackerID;
ba.destinationTile = static_cast<ui16>(dest_tile);
@ -547,9 +557,6 @@ BattleAction CBattleLogic::MakeAttack(int attackerID, int destinationID)
int nearest_pos = -1;
// if double wide calculate tail
CStack *attackerStack = m_cb->battleGetStackByID(attackerID);
assert(attackerStack != NULL);
int tail_pos = -1;
if (attackerStack->creature->isDoubleWide())
{
@ -572,6 +579,8 @@ BattleAction CBattleLogic::MakeAttack(int attackerID, int destinationID)
#if defined PRINT_DEBUG
PrintBattleAction(ba);
#endif
assert(m_cb->battleGetStackByPos(ba.additionalInfo)); //if action is action_walk_and_attack additional info must point on enemy stack
assert(m_cb->battleGetStackByPos(ba.additionalInfo) != attackerStack); //don't attack ourselve
return ba;
}
}
@ -585,6 +594,8 @@ BattleAction CBattleLogic::MakeAttack(int attackerID, int destinationID)
#if defined PRINT_DEBUG
PrintBattleAction(ba);
#endif
assert(m_cb->battleGetStackByPos(ba.additionalInfo)); //if action is action_walk_and_attack additional info must point on enemy stack
assert(m_cb->battleGetStackByPos(ba.additionalInfo) != attackerStack); //don't attack ourselve
return ba;
}
int d = m_battleHelper.GetDistanceWithObstacles(dest_tile, *it);
@ -606,6 +617,7 @@ BattleAction CBattleLogic::MakeAttack(int attackerID, int destinationID)
#if defined PRINT_DEBUG
PrintBattleAction(ba);
#endif
return ba;
}
}

View File

@ -25,7 +25,7 @@ void DbgBox(const char *msg, bool messageBox)
}
CGeniusAI::CGeniusAI()
: m_generalAI(),turn(0),firstTurn(true)
: m_generalAI(), turn(0), m_state(NO_BATTLE), firstTurn(true)
{
}
@ -272,6 +272,20 @@ void GeniusAI::CGeniusAI::showGarrisonDialog( const CArmedInstance *up, const CG
onEnd();
}
void GeniusAI::CGeniusAI::playerBlocked( int reason )
{
if(reason == 0) //battle is coming...
{
m_state.setn(UPCOMING_BATTLE);
}
}
void GeniusAI::CGeniusAI::battleResultsApplied()
{
assert(m_state.get() == ENDING_BATTLE);
m_state.setn(NO_BATTLE);
}
void CGeniusAI::showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, const int soundID, bool selection, bool cancel)
{
m_cb->selectionMade(cancel ? 0 : 1, askID);
@ -321,7 +335,10 @@ void CGeniusAI::battleStacksAttacked(std::set<BattleStackAttacked> & bsa)
void CGeniusAI::battleStart(CCreatureSet *army1, CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side)
{
assert(!m_battleLogic); //************** assert fails when AI starts two battles at same time? ***************
assert(!m_battleLogic);
assert(playerID > PLAYER_LIMIT || m_state.get() == UPCOMING_BATTLE); //we have been informed that battle will start (or we are neutral AI)
m_state.setn(ONGOING_BATTLE);
m_battleLogic = new BattleAI::CBattleLogic(m_cb, army1, army2, tile, hero1, hero2, side);
DbgBox("** CGeniusAI::battleStart **");
@ -341,6 +358,9 @@ void CGeniusAI::battleEnd(BattleResult *br)
delete m_battleLogic;
m_battleLogic = NULL;
assert(m_state.get() == ONGOING_BATTLE);
m_state.setn(ENDING_BATTLE);
DbgBox("** CGeniusAI::battleEnd **");
}
/**

View File

@ -4,12 +4,21 @@
#include "Common.h"
#include "BattleLogic.h"
#include "GeneralAI.h"
#include "..\..\lib\CondSh.h"
#include "../../lib/VCMI_Lib.h"
#include <set>
#include <list>
#include <queue>
namespace GeniusAI {
enum BattleState
{
NO_BATTLE,
UPCOMING_BATTLE,
ONGOING_BATTLE,
ENDING_BATTLE
};
class CGeniusAI : public CGlobalAI
{
private:
@ -75,6 +84,7 @@ private:
void getObjectives(HypotheticalGameState & hgs);
void reportResources();
int turn;
CondSh<BattleState> m_state; //are we engaged into battle?
bool firstTurn;
@ -195,6 +205,7 @@ public:
virtual void tileHidden(int3 pos);
virtual void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback);
virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, boost::function<void()> &onEnd);
virtual void playerBlocked(int reason);
// battle
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
@ -211,6 +222,7 @@ public:
virtual void battleStackAttacking(int ID, int dest);
virtual void battleStackIsAttacked(int ID, int dmg, int killed, int IDby, bool byShooting);
virtual BattleAction activeStack(int stackID);
void battleResultsApplied();
};
}

View File

@ -1,4 +1,5 @@
#include "GeneralAI.h"
#include "../../CCallback.h"
using namespace GeniusAI::GeneralAI;
@ -15,4 +16,5 @@ void CGeneralAI::init(ICallback *CB)
{
assert(CB != NULL);
m_cb = CB;
CB->waitTillRealize = true;
}

View File

@ -58,10 +58,10 @@ template <ui16 N> bool isType(CPack *pack)
return pack->getType() == N;
}
bool CCallback::moveHero(const CGHeroInstance *h, int3 dst) const
bool CCallback::moveHero(const CGHeroInstance *h, int3 dst)
{
MoveHero pack(dst,h->id);
*cl->serv << &pack;
sendRequest(&pack);
return true;
}
void CCallback::selectionMade(int selection, int asker)
@ -74,7 +74,7 @@ void CCallback::recruitCreatures(const CGObjectInstance *obj, ui32 ID, ui32 amou
if(player!=obj->tempOwner) return;
RecruitCreatures pack(obj->id,ID,amount);
*cl->serv << &pack;
sendRequest(&pack);
}
@ -84,20 +84,20 @@ bool CCallback::dismissCreature(const CArmedInstance *obj, int stackPos)
return false;
DisbandCreature pack(stackPos,obj->id);
*cl->serv << &pack;
sendRequest(&pack);
return true;
}
bool CCallback::upgradeCreature(const CArmedInstance *obj, int stackPos, int newID)
{
UpgradeCreature pack(stackPos,obj->id,newID);
*cl->serv << &pack;
sendRequest(&pack);
return false;
}
void CCallback::endTurn()
{
tlog5 << "Player " << (unsigned)player << " end his turn." << std::endl;
EndTurn pack;
*cl->serv << &pack; //report that we ended turn
sendRequest(&pack); //report that we ended turn
}
UpgradeInfo CCallback::getUpgradeInfo(const CArmedInstance *obj, int stackPos) const
{
@ -349,20 +349,20 @@ const CCreatureSet* CCallback::getGarrison(const CGObjectInstance *obj) const
int CCallback::swapCreatures(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2)
{
ArrangeStacks pack(1,p1,p2,s1->id,s2->id,0);
*cl->serv << &pack;
sendRequest(&pack);
return 0;
}
int CCallback::mergeStacks(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2)
{
ArrangeStacks pack(2,p1,p2,s1->id,s2->id,0);
*cl->serv << &pack;
sendRequest(&pack);
return 0;
}
int CCallback::splitStack(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2, int val)
{
ArrangeStacks pack(3,p1,p2,s1->id,s2->id,val);
*cl->serv << &pack;
sendRequest(&pack);
return 0;
}
@ -371,7 +371,7 @@ bool CCallback::dismissHero(const CGHeroInstance *hero)
if(player!=hero->tempOwner) return false;
DismissHero pack(hero->id);
*cl->serv << &pack;
sendRequest(&pack);
return true;
}
@ -387,7 +387,7 @@ bool CCallback::swapArtifacts(const CGHeroInstance * hero1, ui16 pos1, const CGH
return false;
ExchangeArtifacts ea(hero1->id, hero2->id, pos1, pos2);
*cl->serv << &ea;
sendRequest(&ea);
return true;
}
@ -403,7 +403,7 @@ bool CCallback::buildBuilding(const CGTownInstance *town, si32 buildingID)
return false; //lack of resources
BuildStructure pack(town->id,buildingID);
*cl->serv << &pack;
sendRequest(&pack);
return true;
}
@ -444,7 +444,7 @@ CStack* CCallback::battleGetStackByID(int ID)
int CCallback::battleMakeAction(BattleAction* action)
{
MakeCustomAction mca(*action);
*cl->serv << &mca;
sendRequest(&mca);
return 0;
}
@ -582,7 +582,7 @@ void CCallback::swapGarrisonHero( const CGTownInstance *town )
if(town->tempOwner != player) return;
GarrisonHeroSwap pack(town->id);
*cl->serv << &pack;
sendRequest(&pack);
}
void CCallback::buyArtifact(const CGHeroInstance *hero, int aid)
@ -590,7 +590,7 @@ void CCallback::buyArtifact(const CGHeroInstance *hero, int aid)
if(hero->tempOwner != player) return;
BuyArtifact pack(hero->id,aid);
*cl->serv << &pack;
sendRequest(&pack);
}
std::vector < const CGObjectInstance * > CCallback::getBlockingObjs( int3 pos ) const
@ -660,14 +660,14 @@ void CCallback::trade( int mode, int id1, int id2, int val1 )
int p1, p2;
getMarketOffer(id1,id2,p1,p2,mode);
TradeOnMarketplace pack(player,mode,id1,id2,val1);
*cl->serv << &pack;
sendRequest(&pack);
}
void CCallback::setFormation(const CGHeroInstance * hero, bool tight)
{
const_cast<CGHeroInstance*>(hero)->army.formation = tight;
SetFormation pack(hero->id,tight);
*cl->serv << &pack;
sendRequest(&pack);
}
void CCallback::setSelection(const CArmedInstance * obj)
@ -675,7 +675,7 @@ void CCallback::setSelection(const CArmedInstance * obj)
SetSelection ss;
ss.player = player;
ss.id = obj->id;
*cl->serv << &ss;
sendRequest(&ss);
}
void CCallback::recruitHero(const CGTownInstance *town, const CGHeroInstance *hero)
@ -686,7 +686,7 @@ void CCallback::recruitHero(const CGTownInstance *town, const CGHeroInstance *he
if(gs->players[player].availableHeroes[i] == hero)
{
HireHero pack(i,town->id);
*cl->serv << &pack;
sendRequest(&pack);
return;
}
}
@ -731,14 +731,33 @@ void CCallback::save( const std::string &fname )
void CCallback::sendMessage(const std::string &mess)
{
PlayerMessage pm(player, mess);
*cl->serv << &pm;
sendRequest(&pm);
}
void CCallback::buildBoat( const IShipyard *obj )
{
BuildBoat bb;
bb.objid = obj->o->id;
*cl->serv << &bb;
sendRequest(&bb);
}
template <typename T>
void CCallback::sendRequest(const T* request)
{
//TODO? should be part of CClient but it would have to be very tricky cause template/serialization issues
if(waitTillRealize)
cl->waitingRequest.set(true);
*cl->serv << request;
if(waitTillRealize)
cl->waitingRequest.waitWhileTrue();
}
CCallback::CCallback( CGameState * GS, int Player, CClient *C )
:gs(GS), cl(C), player(Player)
{
waitTillRealize = false;
}
InfoAboutHero::InfoAboutHero()

View File

@ -38,6 +38,7 @@ class CClient;
struct TerrainTile;
class CHeroClass;
class IShipyard;
struct CPackForServer;
struct InfoAboutHero
{
@ -84,8 +85,9 @@ struct InfoAboutTown
class ICallback
{
public:
bool waitTillRealize; //if true, request functions will return after they are realized by server
//hero
virtual bool moveHero(const CGHeroInstance *h, int3 dst) const =0; //dst must be free, neighbouring tile (this function can move hero only by one tile)
virtual bool moveHero(const CGHeroInstance *h, int3 dst) =0; //dst must be free, neighbouring tile (this function can move hero only by one tile)
virtual bool dismissHero(const CGHeroInstance * hero)=0; //dismisses given hero; true - successfuly, false - not successfuly
//town
@ -185,18 +187,19 @@ struct HeroMoveDetails
class CCallback : public ICallback
{
private:
CCallback(CGameState * GS, int Player, CClient *C):gs(GS), cl(C), player(Player){};
CCallback(CGameState * GS, int Player, CClient *C);;
CGameState * gs;
CClient *cl;
bool isVisible(int3 pos, int Player) const;
bool isVisible(const CGObjectInstance *obj, int Player) const;
template <typename T> void sendRequest(const T*request);
protected:
int player;
public:
//commands
bool moveHero(const CGHeroInstance *h, int3 dst) const; //dst must be free, neighbouring tile (this function can move hero only by one tile)
bool moveHero(const CGHeroInstance *h, int3 dst); //dst must be free, neighbouring tile (this function can move hero only by one tile)
void selectionMade(int selection, int asker);
int swapCreatures(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2);
int mergeStacks(const CArmedInstance *s1, const CArmedInstance *s2, int p1, int p2); //first goes to the second

View File

@ -76,7 +76,7 @@ public:
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 heroKilled(const CGHeroInstance*){};
virtual void heroMoved(const TryMoveHero & details){};
virtual void heroPrimarySkillChanged(const CGHeroInstance * hero, int which, int val){};
virtual void heroManaPointsChanged(const CGHeroInstance * hero){} //not called at the beginning of turn and after spell casts
@ -87,8 +87,6 @@ public:
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 showSelDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID){};
//virtual void showYesNoDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID){};
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, boost::function<void()> &onEnd) = 0; //all stacks operations between these objects become allowed, interface has to call onEnd when done
virtual void tileHidden(const std::set<int3> &pos){};
@ -100,6 +98,8 @@ public:
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 serialize(COSer<CSaveFile> &h, const int version){}; //saving
virtual void serialize(CISer<CLoadFile> &h, const int version){}; //loading
@ -110,6 +110,7 @@ public:
virtual void battleAttack(BattleAttack *ba){}; //called when stack is performing attack
virtual void battleStacksAttacked(std::set<BattleStackAttacked> & bsa){}; //called when stack receives damage (after battleAttack())
virtual void battleEnd(BattleResult *br){};
virtual void battleResultsApplied(){}; //called when all effects of last battle are applied
virtual void battleNewRound(int round){}; //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
virtual void battleStackMoved(int ID, int dest, int distance, bool end){};
virtual void battleSpellCast(SpellCast *sc){};

View File

@ -1789,6 +1789,15 @@ void CPlayerInterface::newObject( const CGObjectInstance * obj )
}
}
void CPlayerInterface::objectRemoved( const CGObjectInstance *obj )
{
if(obj->ID == HEROI_TYPE && obj->tempOwner == playerID)
{
const CGHeroInstance *h = static_cast<const CGHeroInstance*>(obj);
heroKilled(h);
}
}
void SystemOptions::setMusicVolume( int newVolume )
{
musicVolume = newVolume;

View File

@ -154,7 +154,6 @@ public:
void heroCreated(const CGHeroInstance* hero);
void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback);
void heroInGarrisonChange(const CGTownInstance *town);
void heroKilled(const CGHeroInstance* hero);
void heroMoved(const TryMoveHero & details);
void heroPrimarySkillChanged(const CGHeroInstance * hero, int which, int val);
void heroManaPointsChanged(const CGHeroInstance * hero);
@ -175,6 +174,7 @@ public:
void requestRealized(PackageApplied *pa);
void heroExchangeStarted(si32 hero1, si32 hero2);
void objectPropertyChanged(const SetObjectProperty * sop);
void objectRemoved(const CGObjectInstance *obj);
void serialize(COSer<CSaveFile> &h, const int version); //saving
void serialize(CISer<CLoadFile> &h, const int version); //loading
@ -195,6 +195,7 @@ public:
//-------------//
void heroKilled(const CGHeroInstance* hero);
void waitWhileDialog();
bool shiftPressed() const; //determines if shift key is pressed (left or right or both)
void redrawHeroWin(const CGHeroInstance * hero);

View File

@ -95,10 +95,12 @@ void CClient::init()
}
CClient::CClient(void)
:waitingRequest(false)
{
init();
}
CClient::CClient(CConnection *con, StartInfo *si)
:waitingRequest(false)
{
init();
newGame(con,si);
@ -418,5 +420,16 @@ void CClient::serialize( Handler &h, const int version )
}
}
//void CClient::sendRequest( const CPackForServer *request, bool waitForRealization )
//{
// if(waitForRealization)
// waitingRequest.set(true);
//
// *serv << request;
//
// if(waitForRealization)
// waitingRequest.waitWhileTrue();
//}
template void CClient::serialize( CISer<CLoadFile> &h, const int version );
template void CClient::serialize( COSer<CSaveFile> &h, const int version );

View File

@ -5,6 +5,7 @@
#include "../global.h"
#include <boost/thread.hpp>
#include "../lib/IGameCallback.h"
#include "../lib/CondSh.h"
/*
* Client.h, part of VCMI engine
@ -62,7 +63,10 @@ public:
SharedMem *shared;
BattleAction *curbaction;
CondSh<bool> waitingRequest;
void waitForMoveAndSend(int color);
//void sendRequest(const CPackForServer *request, bool waitForRealization);
CClient(void);
CClient(CConnection *con, StartInfo *si);
~CClient(void);

View File

@ -125,12 +125,18 @@ void ChangeObjPos::applyCl( CClient *cl )
void RemoveObject::applyFirstCl( CClient *cl )
{
CGI->mh->hideObject(cl->getObj(id));
CGHeroInstance *h = GS(cl)->getHero(id);
if(h)
const CGObjectInstance *o = cl->getObj(id);
CGI->mh->hideObject(o);
int3 pos = o->pos - o->getVisitableOffset();
//notify interfaces about removal
for(std::map<ui8, CGameInterface*>::iterator i=cl->playerint.begin();i!=cl->playerint.end();i++)
{
if(vstd::contains(cl->playerint,h->tempOwner))
cl->playerint[h->tempOwner]->heroKilled(h);
if(i->first >= PLAYER_LIMIT) continue;
if(GS(cl)->players[i->first].fogOfWarMap[pos.x][pos.y][pos.z])
{
i->second->objectRemoved(o);
}
}
}
@ -422,6 +428,12 @@ void StacksInjured::applyCl( CClient *cl )
INTERFACE_CALL_IF_PRESENT(GS(cl)->curB->side2,battleStacksAttacked,stacks);
}
void BattleResultsApplied::applyCl( CClient *cl )
{
INTERFACE_CALL_IF_PRESENT(player1,battleResultsApplied);
INTERFACE_CALL_IF_PRESENT(player2,battleResultsApplied);
}
CGameState* CPackForClient::GS( CClient *cl )
{
return cl->gs;
@ -439,6 +451,8 @@ void EndAction::applyCl( CClient *cl )
void PackageApplied::applyCl( CClient *cl )
{
INTERFACE_CALL_IF_PRESENT(GS(cl)->currentPlayer,requestRealized,this);
if(cl->waitingRequest.get())
cl->waitingRequest.setn(false);
}
void SystemMessage::applyCl( CClient *cl )
@ -451,6 +465,11 @@ void SystemMessage::applyCl( CClient *cl )
LOCPLINT->cingconsole->print(str.str());
}
void PlayerBlocked::applyCl( CClient *cl )
{
INTERFACE_CALL_IF_PRESENT(player,playerBlocked,reason);
}
void YourTurn::applyCl( CClient *cl )
{
boost::thread(boost::bind(&CGameInterface::yourTurn,cl->playerint[player]));

View File

@ -125,4 +125,32 @@ GUISettings
ButtonEndTurn: x=1159 y=524 graphic=IAM001.DEF playerColoured=1;
};
}
1600x1200 //setting specific for this resolution
{
AdventureMap
{
AdvMap: x=7 y=6 width=1395 height=1147 smoothMove=1;
InfoBox: x=1406 y=989;
gem0: x=6 y=1108 graphic=agemLL.def;
gem1: x=1356 y=1108 graphic=agemLR.def;
gem2: x=6 y=6 graphic=agemUL.def;
gem3: x=1356 y=6 graphic=agemUR.def;
background=ADVMAP4.pcx;
HeroList: size=23 x=1409 y=201 movePoints=IMOBIL.DEF manaPoints=IMANA.DEF arrowUp=IAM012.DEF arrowDown=IAM013.DEF;
TownList: size=23 x=1547 y=201 arrowUp=IAM014.DEF arrowDown=IAM015.DEF;
Minimap: width=144 height=144 x=1430 y=26;
Statusbar: x=285 y=1155 graphic=ADROLLVR3.pcx;
ResDataBar: x=0 y=1175 graphic=ZRESBAR3.pcx offsetX=65 offsetY=2 resSpace=192 resDateSpace=210;
ButtonKingdomOv: x=1479 y=197 graphic=IAM002L.DEF playerColoured=1;
ButtonUnderground: x=1479 y=229 graphic=IAM010L.DEF playerColoured=1 additionalDefs=(IAM003L.DEF);
ButtonQuestLog: x=1479 y=261 graphic=IAM004L.DEF playerColoured=1;
ButtonSleepWake: x=1479 y=294 graphic=IAM005L.DEF playerColoured=1;
ButtonMoveHero: x=1479 y=327 graphic=IAM006L.DEF playerColoured=1;
ButtonSpellbook: x=1479 y=359 graphic=IAM007L.DEF playerColoured=1;
ButtonAdvOptions: x=1479 y=393 graphic=IAM008L.DEF playerColoured=1;
ButtonSysOptions: x=1479 y=426 graphic=IAM009L.DEF playerColoured=1;
ButtonNextHero: x=1479 y=458 graphic=IAM000.DEF playerColoured=1;
ButtonEndTurn: x=1479 y=491 graphic=IAM001.DEF playerColoured=1;
};
}
}

View File

@ -19,7 +19,7 @@ typedef boost::int8_t si8; //signed int 8 bits (1 byte)
#define THC
#endif
#define NAME_VER ("VCMI 0.73")
#define NAME_VER ("VCMI 0.73b")
extern std::string NAME; //full name
extern std::string NAME_AFFIX; //client / server
#define CONSOLE_LOGGING_LEVEL 5

View File

@ -1868,7 +1868,7 @@ void CGCreature::joinDecision(const CGHeroInstance *h, int cost, ui32 accept) co
cb->showInfoDialog(&iw);
//act as if player refused
joinDecision(h,cost,true);
joinDecision(h,cost,false);
return;
}

View File

@ -1625,7 +1625,9 @@ int CGameState::canBuildStructure( const CGTownInstance *t, int ID )
void CGameState::apply(CPack *pack)
{
applierGs->apps[typeList.getTypeID(pack)]->applyOnGS(this,pack);
ui16 typ = typeList.getTypeID(pack);
assert(typ >= 0);
applierGs->apps[typ]->applyOnGS(this,pack);
}
PlayerState * CGameState::getPlayer( ui8 color )

View File

@ -17,10 +17,55 @@ template <typename T> struct CondSh
T data;
boost::condition_variable cond;
boost::mutex mx;
CondSh(){};
CondSh(T t){data = t;};
void set(T t){mx.lock();data=t;mx.unlock();}; //set data
void setn(T t){mx.lock();data=t;mx.unlock();cond.notify_all();}; //set data and notify
T get(){boost::unique_lock<boost::mutex> lock(mx); return data;};
CondSh()
{}
CondSh(T t)
{
data = t;
}
void set(T t)
{
mx.lock();
data=t;
mx.unlock();
}
void setn(T t) //set data and notify
{
mx.lock();
data=t;
mx.unlock();
cond.notify_all();
};
T get() //get stored value
{
boost::unique_lock<boost::mutex> lock(mx);
return data;
}
void waitWhileTrue() //waits until data is set to false
{
boost::unique_lock<boost::mutex> un(mx);
while(data)
cond.wait(un);
}
void waitWhile(const T &t) //waits while data is set to arg
{
boost::unique_lock<boost::mutex> un(mx);
while(data == t)
cond.wait(un);
}
void waitUntil(const T &t) //waits until data is set to arg
{
boost::unique_lock<boost::mutex> un(mx);
while(data != t)
cond.wait(un);
}
};
#endif // __CONDSH_H__

View File

@ -170,6 +170,22 @@ struct SystemMessage : public CPackForClient //95
}
};
struct PlayerBlocked : public CPackForClient //96
{
PlayerBlocked(){type = 96;};
void applyCl(CClient *cl);
enum EReason { UPCOMING_BATTLE };
ui8 reason;
ui8 player;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & reason & player;
}
};
struct YourTurn : public CPackForClient //100
{
YourTurn(){type = 100;};
@ -921,6 +937,19 @@ struct StacksInjured : public CPackForClient //3011
}
};
struct BattleResultsApplied : public CPackForClient //3012
{
BattleResultsApplied(){type = 3012;}
ui8 player1, player2;
void applyCl(CClient *cl);
template <typename Handler> void serialize(Handler &h, const int version)
{
h & player1 & player2;
}
};
struct ShowInInfobox : public CPackForClient //107
{
ShowInInfobox(){type = 107;};
@ -1152,8 +1181,8 @@ struct BuildBoat : public CPackForServer
struct QueryReply : public CPackForServer
{
QueryReply(){};
QueryReply(ui32 QID, ui32 Answer):qid(QID),answer(Answer){};
QueryReply(){type = 6000;};
QueryReply(ui32 QID, ui32 Answer):qid(QID),answer(Answer){type = 6000;};
ui32 qid, answer; //hero and artifact id
bool applyGh(CGameHandler *gh);

View File

@ -54,6 +54,7 @@ void registerTypes2(Serializer &s)
{
s.template registerType<PackageApplied>();
s.template registerType<SystemMessage>();
s.template registerType<PlayerBlocked>();
s.template registerType<YourTurn>();
s.template registerType<SetResource>();
s.template registerType<SetResources>();
@ -95,6 +96,7 @@ void registerTypes2(Serializer &s)
s.template registerType<SpellCast>();
s.template registerType<SetStackEffect>();
s.template registerType<StacksInjured>();
s.template registerType<BattleResultsApplied>();
s.template registerType<ShowInInfobox>();
s.template registerType<OpenWindow>();
s.template registerType<NewObject>();

View File

@ -403,11 +403,15 @@ askInterfaceForMove:
}
}
BattleResultsApplied resultsApplied;
resultsApplied.player1 = army1->tempOwner;
resultsApplied.player2 = army2->tempOwner;
//unblock engaged players
if(hero1->tempOwner<PLAYER_LIMIT)
states.setFlag(hero1->tempOwner,&PlayerStatus::engagedIntoBattle,false);
if(hero2 && hero2->tempOwner<PLAYER_LIMIT)
states.setFlag(hero2->tempOwner,&PlayerStatus::engagedIntoBattle,false);
if(army1->tempOwner<PLAYER_LIMIT)
states.setFlag(army1->tempOwner,&PlayerStatus::engagedIntoBattle,false);
if(army2 && army2->tempOwner<PLAYER_LIMIT)
states.setFlag(army2->tempOwner,&PlayerStatus::engagedIntoBattle,false);
//casualties among heroes armies
SetGarrisons sg;
@ -442,6 +446,7 @@ askInterfaceForMove:
delete battleResult.data;
sendAndApply(&resultsApplied);
}
void CGameHandler::prepareAttacked(BattleStackAttacked &bsa, CStack *def)
{
@ -513,12 +518,15 @@ void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
tlog5 << "Message successfully applied (result=" << result << ")!\n";
//send confirmation that we've applied the package
PackageApplied applied;
applied.result = result;
applied.packType = packType;
if(pack->type != 6000) //WORKAROUND - not confirm query replies TODO: reconsider
{
boost::unique_lock<boost::mutex> lock(*c.wmx);
c << &applied;
PackageApplied applied;
applied.result = result;
applied.packType = packType;
{
boost::unique_lock<boost::mutex> lock(*c.wmx);
c << &applied;
}
}
}
else
@ -1201,11 +1209,6 @@ void CGameHandler::setupBattle( BattleInfo * curB, int3 tile, const CCreatureSet
//premies given
//block engaged players
if(hero1->tempOwner<PLAYER_LIMIT)
states.setFlag(hero1->tempOwner,&PlayerStatus::engagedIntoBattle,true);
if(hero2 && hero2->tempOwner<PLAYER_LIMIT)
states.setFlag(hero2->tempOwner,&PlayerStatus::engagedIntoBattle,true);
//send info about battles
BattleStart bs;
@ -1292,6 +1295,9 @@ bool CGameHandler::moveHero( si32 hid, int3 dst, ui8 instant, ui8 asker /*= 255*
return false;
}
if(states.checkFlag(h->tempOwner, &PlayerStatus::engagedIntoBattle) && complain("Cannot move hero during the battle"))
return false;
tlog5 << "Player " <<int(asker) << " wants to move hero "<< hid << " from "<< h->pos << " to " << dst << std::endl;
int3 hmpos = dst + int3(-1,0,0);
@ -1356,11 +1362,9 @@ bool CGameHandler::moveHero( si32 hid, int3 dst, ui8 instant, ui8 asker /*= 255*
//checks for standard movement
if(!instant)
{
if( (distance(h->pos,dst)>=1.5) //tiles are not neighbouring
|| (h->movement < cost && h->movement < 100) //lack of movement points
)
if( distance(h->pos,dst) >= 1.5 && complain("Tiles are not neighbouring!")
|| h->movement < cost && h->movement < 100 && complain("Not enough move points!"))
{
tlog2 << "Cannot move hero, not enough move points or tiles are not neighbouring!\n";
sendAndApply(&tmh);
return false;
}
@ -1556,6 +1560,12 @@ void CGameHandler::giveHeroArtifact(int artid, int hid, int position) //pos==-1
void CGameHandler::startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, boost::function<void(BattleResult*)> cb) //use hero=NULL for no hero
{
engageIntoBattle(army1->tempOwner);
engageIntoBattle(army2->tempOwner);
//block engaged players
if(army2->tempOwner < PLAYER_LIMIT)
states.setFlag(army2->tempOwner,&PlayerStatus::engagedIntoBattle,true);
boost::thread(boost::bind(&CGameHandler::startBattle,this,army1,army2,tile,hero1,hero2,cb));
}
@ -2442,19 +2452,35 @@ void CGameHandler::playerMessage( ui8 player, const std::string &message )
{
SetMana sm;
ChangeSpells cs;
SetHeroArtifacts sha;
CGHeroInstance *h = gs->getHero(gs->getPlayer(player)->currentSelection);
if(!h && complain("Cannot realize cheat, no hero selected!")) return;
sm.hid = cs.hid = h->id;
//give all spells
cs.learn = 1;
for(int i=0;i<VLC->spellh->spells.size();i++)
{
if(!VLC->spellh->spells[i].creatureAbility)
cs.spells.insert(i);
}
sm.hid = cs.hid = gs->players[player].currentSelection;
//give mana
sm.val = 999;
if(gs->getHero(cs.hid))
if(!h->getArt(17)) //hero doesn't have spellbook
{
sendAndApply(&cs);
sendAndApply(&sm);
//give spellbook
sha.artifacts = h->artifacts;
sha.artifWorn = h->artifWorn;
sha.artifWorn[17] = 0;
sendAndApply(&sha);
}
sendAndApply(&cs);
sendAndApply(&sm);
}
else if(message == "vcmiainur") //gives 5 archangels into each slot
{
@ -2467,7 +2493,7 @@ void CGameHandler::playerMessage( ui8 player, const std::string &message )
sg.garrs[hero->id].slots[i] = std::pair<ui32,si32>(13,5);
sendAndApply(&sg);
}
else if(message == "vcmiangband") //gives 10 black knightinto each slot
else if(message == "vcmiangband") //gives 10 black knight into each slot
{
SetGarrisons sg;
CGHeroInstance *hero = gs->getHero(gs->getPlayer(player)->currentSelection);
@ -2513,6 +2539,7 @@ void CGameHandler::playerMessage( ui8 player, const std::string &message )
else if(message == "vcmieagles") //reveal FoW
{
FoWChange fc;
fc.mode = 1;
fc.player = player;
for(int i=0;i<gs->map->width;i++)
for(int j=0;j<gs->map->height;j++)
@ -2979,3 +3006,15 @@ bool CGameHandler::buildBoat( ui32 objid )
return true;
}
void CGameHandler::engageIntoBattle( ui8 player )
{
if(vstd::contains(states.players, player))
states.setFlag(player,&PlayerStatus::engagedIntoBattle,true);
//notify interfaces
PlayerBlocked pb;
pb.player = player;
pb.reason = PlayerBlocked::UPCOMING_BATTLE;
sendAndApply(&pb);
}

View File

@ -160,6 +160,7 @@ public:
void handleTimeEvents();
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 engageIntoBattle( ui8 player );
template <typename Handler> void serialize(Handler &h, const int version)
{
@ -176,7 +177,6 @@ public:
void run(bool resume);
void newTurn();
friend class CVCMIServer;
friend class CScriptCallback;
};