From d80afb1902590795916da61b3297082d53cecdc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20W=2E=20Urba=C5=84czyk?= Date: Thu, 16 Apr 2009 00:28:54 +0000 Subject: [PATCH] * server sends confirmation (given later to player interface) after applying request (will be needed for AI) * created new package for injuring multiple units - needed for area spells (not tested) * proper screen updating on garrison change * spell effects will be removed when they time out * Corpse (Skeleton) will be accessible from all directions * new objects supported: - Corpse - Lean To - Wagon - Warrior's Tomb * several minor improvements --- CGameInterface.h | 2 + CPlayerInterface.cpp | 12 +-- client/Client.cpp | 16 ++- client/Client.h | 4 +- client/NetPacksClient.cpp | 11 ++ global.h | 1 + hch/CArtHandler.cpp | 10 +- hch/CArtHandler.h | 18 ++-- hch/CDefObjInfoHandler.cpp | 2 +- hch/CObjectHandler.cpp | 208 ++++++++++++++++++++++++++++++++++++- hch/CObjectHandler.h | 19 ++++ lib/IGameCallback.cpp | 28 +++++ lib/IGameCallback.h | 10 +- lib/NetPacks.h | 74 +++++++++---- lib/NetPacksLib.cpp | 16 +++ lib/RegisterTypes.cpp | 3 + map.cpp | 8 ++ server/CGameHandler.cpp | 194 ++++++++++++++++++++++------------ server/CGameHandler.h | 32 +++--- server/NetPacksServer.cpp | 88 +++++++++------- 20 files changed, 576 insertions(+), 180 deletions(-) diff --git a/CGameInterface.h b/CGameInterface.h index 4ed86d37d..accf6fae1 100644 --- a/CGameInterface.h +++ b/CGameInterface.h @@ -35,6 +35,7 @@ struct BattleStackAttacked; struct SpellCasted; struct SetStackEffect; struct HeroBonus; +struct PackageApplied; class CLoadFile; class CSaveFile; template class CISer; @@ -88,6 +89,7 @@ public: virtual void yourTurn(){}; virtual void availableCreaturesChanged(const CGTownInstance *town){}; virtual void heroBonusChanged(const CGHeroInstance *hero, const HeroBonus &bonus, bool gain){};//if gain hero received bonus, else he lost it + virtual void requestRealized(PackageApplied *pa){} virtual void serialize(COSer &h, const int version){}; //saving virtual void serialize(CISer &h, const int version){}; //loading diff --git a/CPlayerInterface.cpp b/CPlayerInterface.cpp index bf3afe3a1..4d3abcc93 100644 --- a/CPlayerInterface.cpp +++ b/CPlayerInterface.cpp @@ -2112,8 +2112,8 @@ void CPlayerInterface::garrisonChanged(const CGObjectInstance * obj) wasGarrison = true; } } - if(wasGarrison) - LOCPLINT->totalRedraw(); + + LOCPLINT->totalRedraw(); } void CPlayerInterface::buildChanged(const CGTownInstance *town, int buildingID, int what) //what: 1 - built, 2 - demolished @@ -4761,14 +4761,14 @@ void CGarrisonWindow::deactivate() void CGarrisonWindow::show(SDL_Surface * to) { - blitAt(graphics->flags->ourImages[garr->odown->getOwner()].bitmap,pos.x+29,pos.y+125,to); - blitAt(graphics->portraitLarge[static_cast(garr->odown)->portrait],pos.x+29,pos.y+222,to); - printAtMiddle(CGI->generaltexth->allTexts[709],pos.x+275,pos.y+30,GEOR16,tytulowy,to); - blitAt(bg,pos,to); split->show(to); quit->show(to); garr->show(to); + + blitAt(graphics->flags->ourImages[garr->odown->getOwner()].bitmap,pos.x+29,pos.y+125,to); + blitAt(graphics->portraitLarge[static_cast(garr->odown)->portrait],pos.x+29,pos.y+222,to); + printAtMiddle(CGI->generaltexth->allTexts[709],pos.x+275,pos.y+30,GEOR16,tytulowy,to); } CGarrisonWindow::CGarrisonWindow( const CArmedInstance *up, const CGHeroInstance *down ) diff --git a/client/Client.cpp b/client/Client.cpp index 52c49d2cb..3662dca27 100644 --- a/client/Client.cpp +++ b/client/Client.cpp @@ -124,10 +124,16 @@ void CClient::run() CPack *pack; while(1) { - tlog5 << "Listening... "; - *serv >> pack; - tlog5 << "\treceived server message of type " << typeid(*pack).name() << std::endl; - CBaseForCLApply *apply = applier->apps[typeList.getTypeID(pack)]; + + //get the package from the server + { + boost::unique_lock lock(*serv->rmx); + tlog5 << "Listening... "; + *serv >> pack; + tlog5 << "\treceived server message of type " << typeid(*pack).name() << std::endl; + } + + CBaseForCLApply *apply = applier->apps[typeList.getTypeID(pack)]; //find the applier if(apply) { apply->applyOnClBefore(this,pack); @@ -139,7 +145,7 @@ void CClient::run() } else { - tlog5 << "Message cannot be applied, cannot find applier!\n"; + tlog1 << "Message cannot be applied, cannot find applier!\n"; } delete pack; pack = NULL; diff --git a/client/Client.h b/client/Client.h index bffdd5d40..12ad80e7c 100644 --- a/client/Client.h +++ b/client/Client.h @@ -79,7 +79,7 @@ public: //not working yet, will be implement somewhen later with support for local-sim-based gameplay void changeSpells(int hid, bool give, const std::set &spells){}; - void removeObject(int objid){}; + bool removeObject(int objid){return false;}; void setBlockVis(int objid, bool bv){}; void setOwner(int objid, ui8 owner){}; void setHoverName(int objid, MetaString * name){}; @@ -98,7 +98,7 @@ public: void startBattleI(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, boost::function cb){}; //use hero=NULL for no hero void startBattleI(int heroID, CCreatureSet army, int3 tile, boost::function cb){}; //for hero<=>neutral army void setAmount(int objid, ui32 val){}; - void moveHero(si32 hid, int3 dst, ui8 instant, ui8 asker = 255){}; + bool moveHero(si32 hid, int3 dst, ui8 instant, ui8 asker = 255){return false;}; void giveHeroBonus(GiveBonus * bonus){}; void setMovePoints(SetMovePoints * smp){}; void setManaPoints(int hid, int val){}; diff --git a/client/NetPacksClient.cpp b/client/NetPacksClient.cpp index 37199b2ad..5734f216b 100644 --- a/client/NetPacksClient.cpp +++ b/client/NetPacksClient.cpp @@ -404,6 +404,12 @@ void SetStackEffect::applyCl( CClient *cl ) cl->playerint[GS(cl)->curB->side2]->battleStacksEffectsSet(*this); } +void StacksInjured::applyCl( CClient *cl ) +{ + INTERFACE_CALL_IF_PRESENT(GS(cl)->curB->side1,battleStacksAttacked,stacks); + INTERFACE_CALL_IF_PRESENT(GS(cl)->curB->side2,battleStacksAttacked,stacks); +} + CGameState* CPackForClient::GS( CClient *cl ) { return cl->gs; @@ -418,6 +424,11 @@ void EndAction::applyCl( CClient *cl ) cl->curbaction = NULL; } +void PackageApplied::applyCl( CClient *cl ) +{ + INTERFACE_CALL_IF_PRESENT(GS(cl)->currentPlayer,requestRealized,this); +} + void SystemMessage::applyCl( CClient *cl ) { std::ostringstream str; diff --git a/global.h b/global.h index 59912f2a1..b9a20b99b 100644 --- a/global.h +++ b/global.h @@ -54,6 +54,7 @@ enum ElossCon {lossCastle, lossHero, timeExpires, lossStandard=255}; enum EHeroClasses {HERO_KNIGHT, HERO_CLERIC, HERO_RANGER, HERO_DRUID, HERO_ALCHEMIST, HERO_WIZARD, HERO_DEMONIAC, HERO_HERETIC, HERO_DEATHKNIGHT, HERO_NECROMANCER, HERO_WARLOCK, HERO_OVERLORD, HERO_BARBARIAN, HERO_BATTLEMAGE, HERO_BEASTMASTER, HERO_WITCH, HERO_PLANESWALKER, HERO_ELEMENTALIST}; +enum EartClass {ART_SPECIAL=1, ART_TREASURE=2, ART_MINOR=4, ART_MAJOR=8, ART_RELIC=16}; //artifact classes enum EAbilities {DOUBLE_WIDE, FLYING, SHOOTER, TWO_HEX_ATTACK, SIEGE_ABILITY, SIEGE_WEAPON, KING1, KING2, KING3, MIND_IMMUNITY, NO_OBSTACLE_PENALTY, NO_CLOSE_COMBAT_PENALTY, JOUSTING, FIRE_IMMUNITY, TWICE_ATTACK, NO_ENEMY_RETALIATION, NO_MORAL_PENALTY, diff --git a/hch/CArtHandler.cpp b/hch/CArtHandler.cpp index 3fcb317df..4651d6628 100644 --- a/hch/CArtHandler.cpp +++ b/hch/CArtHandler.cpp @@ -43,7 +43,7 @@ void CArtHandler::loadArtifacts(bool onlyTxt) std::vector slots; slots += 17, 16, 15,14,13, 18, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0; std::map classes = - map_list_of('S',SartClass)('T',TartClass)('N',NartClass)('J',JartClass)('R',RartClass); + map_list_of('S',ART_SPECIAL)('T',ART_TREASURE)('N',ART_MINOR)('J',ART_MAJOR)('R',ART_RELIC); std::string buf = bitmaph->getTextFile("ARTRAITS.TXT"), dump, pom; int it=0; for(int i=0; i<2; ++i) @@ -112,16 +112,16 @@ void CArtHandler::sortArts() { switch (artifacts[i].aClass) { - case TartClass: + case ART_TREASURE: treasures.push_back(&(artifacts[i])); break; - case NartClass: + case ART_MINOR: minors.push_back(&(artifacts[i])); break; - case JartClass: + case ART_MAJOR: majors.push_back(&(artifacts[i])); break; - case RartClass: + case ART_RELIC: relics.push_back(&(artifacts[i])); break; } diff --git a/hch/CArtHandler.h b/hch/CArtHandler.h index 533f087f8..01b2eabd5 100644 --- a/hch/CArtHandler.h +++ b/hch/CArtHandler.h @@ -6,17 +6,15 @@ #include #include -/* - * CArtHandler.h, part of VCMI engine - * - * Authors: listed in file AUTHORS in main folder - * - * License: GNU General Public License v2.0 or later - * Full text of license available in license.txt file, in main folder - * +/* + * CArtHandler.h, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * */ - -enum EartClass {SartClass=0, TartClass, NartClass, JartClass, RartClass}; //artifact class (relict, treasure, strong, weak etc.) class CDefHandler; class DLL_EXPORT CArtifact //container for artifacts diff --git a/hch/CDefObjInfoHandler.cpp b/hch/CDefObjInfoHandler.cpp index 180f316ec..104fea57b 100644 --- a/hch/CDefObjInfoHandler.cpp +++ b/hch/CDefObjInfoHandler.cpp @@ -89,7 +89,7 @@ void CDefObjInfoHandler::load() } else { - static int visitableFromTop[] = {111,33,81,12,9,212,215}; //whirlpool, garrison, scholar, campfire, borderguard, bordergate, questguard + static int visitableFromTop[] = {111,33,81,12,9,212,215,22}; //whirlpool, garrison, scholar, campfire, borderguard, bordergate, questguard, corpse for(int i=0; i < ARRAY_COUNT(visitableFromTop); i++) { if(visitableFromTop[i] == nobj->id) diff --git a/hch/CObjectHandler.cpp b/hch/CObjectHandler.cpp index af7a3315f..d1da64565 100644 --- a/hch/CObjectHandler.cpp +++ b/hch/CObjectHandler.cpp @@ -778,7 +778,8 @@ double CGHeroInstance::getHeroStrength() const int CGHeroInstance::getTotalStrength() const { - return getHeroStrength() * getArmyStrength(); + double ret = getHeroStrength() * getArmyStrength(); + return (int) ret; } ui8 CGHeroInstance::getSpellSchoolLevel(const CSpell * spell) const @@ -1444,14 +1445,14 @@ int CGCreature::takenAction(const CGHeroInstance *h, bool allowJoin) const //TODO: it's provisional formula, should be replaced with original one (or something closer to it) //TODO: should be deterministic (will be needed for Vision spell) - int hlp2 = (hlp - 2)*1000; + int hlp2 = (int) (hlp - 2)*1000; if(!neverFlees && hlp2 >= 0 && rand()%2000 < hlp2 ) - return -1; + return -1; //flee else - return -2; + return -2; //fight } @@ -2425,3 +2426,202 @@ void CGScholar::initObj() } } } + +void CGOnceVisitable::onHeroVisit( const CGHeroInstance * h ) const +{ + int txtid = -1; + switch(ID) + { + case 22: //Corpse + txtid = 37; + break; + case 39: //Lean To + txtid = 64; + break; + case 105://Wagon + txtid = 154; + break; + case 108: + break; + default: + tlog1 << "Error: Unknown object (" << ID <<") treated as CGOnceVisitable!\n"; + return; + } + + if(ID == 108)//Warrior's Tomb + { + //ask if player wants to search the Tomb + BlockingDialog bd(true, false); + bd.player = h->getOwner(); + bd.text.addTxt(MetaString::ADVOB_TXT,161); + cb->showBlockingDialog(&bd,boost::bind(&CGOnceVisitable::searchTomb,this,h,_1)); + return; + } + + InfoWindow iw; + iw.player = h->getOwner(); + + if(players.size()) //we have been already visited... + { + txtid++; + if(ID == 105) //wagon has extra text (for finding art) we need to ommit + txtid++; + + iw.text.addTxt(MetaString::ADVOB_TXT, txtid); + } + else //first visit - give bonus! + { + if(ID == 105 && artOrRes == 1) + { + txtid++; + iw.text.replacements.push_back(VLC->arth->artifacts[bonusType].Name()); + } + + + switch(artOrRes) + { + case 0: + txtid++; + break; + case 1: //art + iw.components.push_back(Component(Component::ARTIFACT,bonusType,0,0)); + cb->giveHeroArtifact(bonusType,h->id,-2); + break; + case 2: //res + iw.components.push_back(Component(Component::RESOURCE,bonusType,bonusVal,0)); + cb->giveResource(h->getOwner(),bonusType,bonusVal); + break; + } + + iw.text.addTxt(MetaString::ADVOB_TXT, txtid); + } + + cb->showInfoDialog(&iw); + cb->setObjProperty(id,10,h->getOwner()); +} + +const std::string & CGOnceVisitable::getHoverText() const +{ + hoverName = VLC->generaltexth->names[ID] + " "; + + hoverName += (hasVisited(cb->getCurrentPlayer()) + ? (VLC->generaltexth->allTexts[352]) //visited + : ( VLC->generaltexth->allTexts[353])); //not visited + + return hoverName; +} + +void CGOnceVisitable::initObj() +{ + switch(ID) + { + case 22: //Corpse + { + blockVisit = true; + int hlp = ran()%100; + if(hlp < 20) + { + artOrRes = 1; + std::vector arts; + cb->getAllowed(arts, ART_TREASURE | ART_MINOR | ART_MAJOR); + bonusType = arts[ran() % arts.size()]->id; + } + else + { + artOrRes = 0; + } + } + break; + + case 39: //Lean To + { + artOrRes = 2; + bonusType = ran()%6; //any basic resource without gold + bonusVal = ran()%4 + 1; + break; + } + + case 108://Warrior's Tomb + { + artOrRes = 1; + + std::vector arts; + + int hlp = ran()%100; + if(hlp < 30) + cb->getAllowed(arts,ART_TREASURE); + else if(hlp < 80) + cb->getAllowed(arts,ART_MINOR); + else if(hlp < 95) + cb->getAllowed(arts,ART_MAJOR); + else + cb->getAllowed(arts,ART_RELIC); + + bonusType = arts[ran() % arts.size()]->id; + } + break; + + case 105://Wagon + { + int hlp = ran()%100; + + if(hlp < 10) + { + artOrRes = 0; // nothing... :( + } + else if(hlp < 50) //minor or treasure art + { + artOrRes = 1; + std::vector arts; + cb->getAllowed(arts, ART_TREASURE | ART_MINOR); + bonusType = arts[ran() % arts.size()]->id; + } + else //2 - 5 of non-gold resource + { + artOrRes = 2; + bonusType = ran()%6; + bonusVal = ran()%4 + 2; + } + + break; + } + } +} + +void CGOnceVisitable::searchTomb(const CGHeroInstance *h, ui32 accept) const +{ + if(accept) + { + InfoWindow iw; + iw.player = h->getOwner(); + iw.components.push_back(Component(Component::MORALE,0,-3,0)); + + if(players.size()) //we've been already visited, player found nothing + { + iw.text.addTxt(MetaString::ADVOB_TXT,163); + } + else //first visit - give artifact + { + iw.text.addTxt(MetaString::ADVOB_TXT,162); + iw.components.push_back(Component(Component::ARTIFACT,bonusType,0,0)); + iw.text.replacements.push_back(VLC->arth->artifacts[bonusType].Name()); + + cb->giveHeroArtifact(bonusType,h->id,-2); + } + + if(!h->getBonus(HeroBonus::OBJECT,ID)) //we don't have modifier from this object yet + { + //ruin morale + GiveBonus gb; + gb.hid = h->id; + gb.bonus = HeroBonus(HeroBonus::ONE_BATTLE,HeroBonus::MORALE,HeroBonus::OBJECT,-3,id,""); + gb.bdescr.addTxt(MetaString::ARRAY_TXT,104); //Warrior Tomb Visited -3 + cb->giveHeroBonus(&gb); + } + + cb->showInfoDialog(&iw); + + //add player to the visitors (for visited tooltop) + cb->setObjProperty(id,10,h->getOwner()); + } +} \ No newline at end of file diff --git a/hch/CObjectHandler.h b/hch/CObjectHandler.h index 1f6cc606b..b283e87af 100644 --- a/hch/CObjectHandler.h +++ b/hch/CObjectHandler.h @@ -705,6 +705,25 @@ public: } }; +class DLL_EXPORT CGOnceVisitable : public CPlayersVisited //wagon, corpse, lean to, warriors tomb +{ +public: + ui8 artOrRes; //0 - nothing; 1 - artifact; 2 - resource + ui32 bonusType, //id of res or artifact + bonusVal; //resource amount (or not used) + + void onHeroVisit(const CGHeroInstance * h) const; + const std::string & getHoverText() const; + void initObj(); + void searchTomb(const CGHeroInstance *h, ui32 accept) const; + + template void serialize(Handler &h, const int version) + { + h & static_cast(*this) & static_cast(*this);; + h & bonusType & bonusVal; + } +}; + class DLL_EXPORT CObjectHandler diff --git a/lib/IGameCallback.cpp b/lib/IGameCallback.cpp index f2ae77c9c..52f95bd9b 100644 --- a/lib/IGameCallback.cpp +++ b/lib/IGameCallback.cpp @@ -4,6 +4,8 @@ #include "../map.h" #include "../hch/CObjectHandler.h" #include "../StartInfo.h" +#include "../hch/CArtHandler.h" +#include "../lib/VCMI_Lib.h" /* * IGameCallback.cpp, part of VCMI engine @@ -112,8 +114,34 @@ bool IGameCallback::isAllowed( int type, int id ) { case 0: return gs->map->allowedSpell[id]; + case 1: + return gs->map->allowedArtifact[id]; default: tlog1 << "Wrong call to IGameCallback::isAllowed!\n"; return false; } +} + +void IGameCallback::getAllowedArts(std::vector &out, std::vector CArtHandler::*arts) +{ + for(int i = 0; i < (VLC->arth->*arts).size(); i++) + { + CArtifact *art = (VLC->arth->*arts)[i]; + if(isAllowed(1,art->id)) + { + out.push_back(art); + } + } +} + +void IGameCallback::getAllowed(std::vector &out, int flags) +{ + if(flags & ART_TREASURE) + getAllowedArts(out,&CArtHandler::treasures); + if(flags & ART_MINOR) + getAllowedArts(out,&CArtHandler::minors); + if(flags & ART_MAJOR) + getAllowedArts(out,&CArtHandler::majors); + if(flags & ART_RELIC) + getAllowedArts(out,&CArtHandler::relics); } \ No newline at end of file diff --git a/lib/IGameCallback.h b/lib/IGameCallback.h index 5623f01a7..f4060dfd4 100644 --- a/lib/IGameCallback.h +++ b/lib/IGameCallback.h @@ -29,6 +29,8 @@ struct BattleResult; class CGameState; struct PlayerSettings; struct CPackForClient; +class CArtHandler; +class CArtifact; class DLL_EXPORT IGameCallback { @@ -49,11 +51,13 @@ public: virtual const PlayerSettings * getPlayerSettings(int color); virtual int getHeroCount(int player, bool includeGarrisoned); virtual void getTilesInRange(std::set &tiles, int3 pos, int radious, int player=-1, int mode=0); //mode 1 - only unrevealed tiles; mode 0 - all, mode -1 - only unrevealed - virtual bool isAllowed(int type, int id); //type: 0 - spell + virtual bool isAllowed(int type, int id); //type: 0 - spell; 1- artifact + virtual void getAllowedArts(std::vector &out, std::vector CArtHandler::*arts); + virtual void getAllowed(std::vector &out, int flags); //flags: bitfield uses EartClass //do sth virtual void changeSpells(int hid, bool give, const std::set &spells)=0; - virtual void removeObject(int objid)=0; + virtual bool removeObject(int objid)=0; virtual void setBlockVis(int objid, bool bv)=0; virtual void setOwner(int objid, ui8 owner)=0; virtual void setHoverName(int objid, MetaString * name)=0; @@ -72,7 +76,7 @@ public: virtual void startBattleI(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, boost::function cb)=0; //use hero=NULL for no hero virtual void startBattleI(int heroID, CCreatureSet army, int3 tile, boost::function cb)=0; //for hero<=>neutral army virtual void setAmount(int objid, ui32 val)=0; - virtual void moveHero(si32 hid, int3 dst, ui8 instant, ui8 asker = 255)=0; + virtual bool moveHero(si32 hid, int3 dst, ui8 instant, ui8 asker = 255)=0; virtual void giveHeroBonus(GiveBonus * bonus)=0; virtual void setMovePoints(SetMovePoints * smp)=0; virtual void setManaPoints(int hid, int val)=0; diff --git a/lib/NetPacks.h b/lib/NetPacks.h index 8e1d2c44f..247e3f01e 100644 --- a/lib/NetPacks.h +++ b/lib/NetPacks.h @@ -57,7 +57,7 @@ struct CPackForServer : public CPack c = NULL; }; - void applyGh(CGameHandler *gh)//called after applying to gs + bool applyGh(CGameHandler *gh)//called after applying to gs {}; }; @@ -108,6 +108,21 @@ struct MetaString : public CPack //2001 helper for object scrips /***********************************************************************************************************/ +struct PackageApplied : public CPackForClient //94 +{ + PackageApplied() {type = 94;} + PackageApplied(ui8 Result) : result(Result) {type = 94;} + void applyCl(CClient *cl); + + ui8 result; //0 - something went wrong, request hasn't been realized; 1 - OK + ui32 packType; //type id of applied package + + template void serialize(Handler &h, const int version) + { + h & result; + } +}; + struct SystemMessage : public CPackForClient //95 { SystemMessage(const std::string Text) : text(Text){type = 95;}; @@ -490,7 +505,7 @@ struct NewTurn : public CPackForClient //101 struct Component : public CPack //2002 helper for object scrips informations { - enum {PRIM_SKILL,SEC_SKILL,RESOURCE,CREATURE,ARTIFACT,EXPERIENCE,SPELL}; + enum {PRIM_SKILL,SEC_SKILL,RESOURCE,CREATURE,ARTIFACT,EXPERIENCE,SPELL, MORALE=8, LUCK}; ui16 id, subtype; //id uses ^^^ enums, when id==EXPPERIENCE subtype==0 means exp points and subtype==1 levels) si32 val; // + give; - take si16 when; // 0 - now; +x - within x days; -x - per x days @@ -814,6 +829,19 @@ struct SetStackEffect : public CPackForClient //3010 } }; +struct StacksInjured : public CPackForClient //3011 +{ + StacksInjured(){type = 3011;} + DLL_EXPORT void applyGs(CGameState *gs); + void applyCl(CClient *cl); + + std::set stacks; + template void serialize(Handler &h, const int version) + { + h & stacks; + } +}; + struct ShowInInfobox : public CPackForClient //107 { ShowInInfobox(){type = 107;}; @@ -832,14 +860,14 @@ struct ShowInInfobox : public CPackForClient //107 struct CloseServer : public CPackForServer { - void applyGh(CGameHandler *gh); + bool applyGh(CGameHandler *gh); template void serialize(Handler &h, const int version) {} }; struct EndTurn : public CPackForServer { - void applyGh(CGameHandler *gh); + bool applyGh(CGameHandler *gh); template void serialize(Handler &h, const int version) {} }; @@ -850,7 +878,7 @@ struct DismissHero : public CPackForServer DismissHero(si32 HID) : hid(HID) {}; si32 hid; - void applyGh(CGameHandler *gh); + bool applyGh(CGameHandler *gh); template void serialize(Handler &h, const int version) { h & hid; @@ -864,7 +892,7 @@ struct MoveHero : public CPackForServer int3 dest; si32 hid; - void applyGh(CGameHandler *gh); + bool applyGh(CGameHandler *gh); template void serialize(Handler &h, const int version) { h & dest & hid; @@ -881,7 +909,7 @@ struct ArrangeStacks : public CPackForServer ui8 p1, p2; //positions of first and second stack si32 id1, id2; //ids of objects with garrison si32 val; - void applyGh(CGameHandler *gh); + bool applyGh(CGameHandler *gh); template void serialize(Handler &h, const int version) { h & what & p1 & p2 & id1 & id2 & val; @@ -895,7 +923,7 @@ struct DisbandCreature : public CPackForServer ui8 pos; //stack pos si32 id; //object id - void applyGh(CGameHandler *gh); + bool applyGh(CGameHandler *gh); template void serialize(Handler &h, const int version) { h & pos & id; @@ -908,7 +936,7 @@ struct BuildStructure : public CPackForServer BuildStructure(si32 TID, si32 BID):bid(BID),tid(TID){}; si32 bid, tid; //structure and town ids - void applyGh(CGameHandler *gh); + bool applyGh(CGameHandler *gh); template void serialize(Handler &h, const int version) { h & tid & bid; @@ -922,7 +950,7 @@ struct RecruitCreatures : public CPackForServer si32 tid; //town id ui32 crid, amount;//creature ID and amount - void applyGh(CGameHandler *gh); + bool applyGh(CGameHandler *gh); template void serialize(Handler &h, const int version) { h & tid & crid & amount; @@ -937,7 +965,7 @@ struct UpgradeCreature : public CPackForServer si32 id; //object id si32 cid; //id of type to which we want make upgrade - void applyGh(CGameHandler *gh); + bool applyGh(CGameHandler *gh); template void serialize(Handler &h, const int version) { h & pos & id & cid; @@ -950,7 +978,7 @@ struct GarrisonHeroSwap : public CPackForServer GarrisonHeroSwap(si32 TID):tid(TID){}; si32 tid; - void applyGh(CGameHandler *gh); + bool applyGh(CGameHandler *gh); template void serialize(Handler &h, const int version) { h & tid; @@ -965,7 +993,7 @@ struct ExchangeArtifacts : public CPackForServer si32 hid1, hid2; ui16 slot1, slot2; - void applyGh(CGameHandler *gh); + bool applyGh(CGameHandler *gh); template void serialize(Handler &h, const int version) { h & hid1 & hid2 & slot1 & slot2; @@ -978,7 +1006,7 @@ struct BuyArtifact : public CPackForServer BuyArtifact(si32 HID, si32 AID):hid(HID),aid(AID){}; si32 hid, aid; //hero and artifact id - void applyGh(CGameHandler *gh); + bool applyGh(CGameHandler *gh); template void serialize(Handler &h, const int version) { h & hid & aid; @@ -996,7 +1024,7 @@ struct TradeOnMarketplace : public CPackForServer ui32 r1, r2; //mode 0: r1 - sold resource, r2 - bought res ui32 val; //units of sold resource - void applyGh(CGameHandler *gh); + bool applyGh(CGameHandler *gh); template void serialize(Handler &h, const int version) { h & player & mode & /*id & */r1 & r2 & val; @@ -1010,7 +1038,7 @@ struct SetFormation : public CPackForServer si32 hid; ui8 formation; - void applyGh(CGameHandler *gh); + bool applyGh(CGameHandler *gh); template void serialize(Handler &h, const int version) { h & hid & formation; @@ -1023,7 +1051,7 @@ struct HireHero : public CPackForServer HireHero(si32 HID, si32 TID):hid(HID),tid(TID){}; si32 hid, tid; //available hero serial and town id - void applyGh(CGameHandler *gh); + bool applyGh(CGameHandler *gh); template void serialize(Handler &h, const int version) { h & hid & tid; @@ -1036,7 +1064,7 @@ struct QueryReply : public CPackForServer QueryReply(ui32 QID, ui32 Answer):qid(QID),answer(Answer){}; ui32 qid, answer; //hero and artifact id - void applyGh(CGameHandler *gh); + bool applyGh(CGameHandler *gh); template void serialize(Handler &h, const int version) { h & qid & answer; @@ -1049,7 +1077,7 @@ struct MakeAction : public CPackForServer MakeAction(const BattleAction &BA):ba(BA){}; BattleAction ba; - void applyGh(CGameHandler *gh); + bool applyGh(CGameHandler *gh); template void serialize(Handler &h, const int version) { h & ba; @@ -1062,7 +1090,7 @@ struct MakeCustomAction : public CPackForServer MakeCustomAction(const BattleAction &BA):ba(BA){}; BattleAction ba; - void applyGh(CGameHandler *gh); + bool applyGh(CGameHandler *gh); template void serialize(Handler &h, const int version) { h & ba; @@ -1079,7 +1107,7 @@ struct SaveGame : public CPackForClient, public CPackForServer void applyCl(CClient *cl); void applyGs(CGameState *gs){}; - void applyGh(CGameHandler *gh); + bool applyGh(CGameHandler *gh); template void serialize(Handler &h, const int version) { h & fname; @@ -1094,7 +1122,7 @@ struct PlayerMessage : public CPackForClient, public CPackForServer //513 {CPackForClient::type = 513;}; void applyCl(CClient *cl); void applyGs(CGameState *gs){}; - void applyGh(CGameHandler *gh); + bool applyGh(CGameHandler *gh); ui8 player; std::string text; @@ -1110,7 +1138,7 @@ struct SetSelection : public CPackForClient, public CPackForServer //514 { SetSelection(){CPackForClient::type = 514;}; DLL_EXPORT void applyGs(CGameState *gs); - void applyGh(CGameHandler *gh); + bool applyGh(CGameHandler *gh); ui8 player; ui32 id; diff --git a/lib/NetPacksLib.cpp b/lib/NetPacksLib.cpp index e9b028873..f3c195ebd 100644 --- a/lib/NetPacksLib.cpp +++ b/lib/NetPacksLib.cpp @@ -448,6 +448,16 @@ DLL_EXPORT void BattleNextRound::applyGs( CGameState *gs ) s->state -= MOVED; s->state -= HAD_MORALE; s->counterAttacks = 1; + + //remove effects and restore only those with remaining turns in duration + std::vector tmpEffects = s->effects; + s->effects.clear(); + for(int i=0; i < tmpEffects.size(); i++) + { + tmpEffects[i].turnsRemain--; + if(tmpEffects[i].turnsRemain > 0) + s->effects.push_back(tmpEffects[i]); + } } } @@ -545,6 +555,12 @@ DLL_EXPORT void SetStackEffect::applyGs( CGameState *gs ) } } +DLL_EXPORT void StacksInjured::applyGs( CGameState *gs ) +{ + BOOST_FOREACH(BattleStackAttacked stackAttacked, stacks) + stackAttacked.applyGs(gs); +} + DLL_EXPORT void YourTurn::applyGs( CGameState *gs ) { gs->currentPlayer = player; diff --git a/lib/RegisterTypes.cpp b/lib/RegisterTypes.cpp index b97d1d915..be1149c2f 100644 --- a/lib/RegisterTypes.cpp +++ b/lib/RegisterTypes.cpp @@ -42,12 +42,14 @@ void registerTypes1(Serializer &s) s.template registerType(); s.template registerType(); s.template registerType(); + s.template registerType(); s.template registerType(); } template DLL_EXPORT void registerTypes2(Serializer &s) { + s.template registerType(); s.template registerType(); s.template registerType(); s.template registerType(); @@ -89,6 +91,7 @@ void registerTypes2(Serializer &s) s.template registerType(); s.template registerType(); s.template registerType(); + s.template registerType(); s.template registerType(); s.template registerType(); diff --git a/map.cpp b/map.cpp index 303078bbd..5d7e9308d 100644 --- a/map.cpp +++ b/map.cpp @@ -1802,6 +1802,14 @@ void Mapa::readObjects( unsigned char * bufor, int &i) nobj = new CGObservatory(); break; } + case 22: //Corpse + case 39: //Lean To + case 105://Wagon + case 108://Warrior's Tomb + { + nobj = new CGOnceVisitable(); + break; + } case 214: //hero placeholder { i+=3; //TODO: handle it more properly diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index db21684a6..90fd7a101 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -55,16 +55,16 @@ CondSh battleResult(NULL); class CBaseForGHApply { public: - virtual void applyOnGH(CGameHandler *gh, CConnection *c, void *pack) const =0; + virtual bool applyOnGH(CGameHandler *gh, CConnection *c, void *pack) const =0; }; template class CApplyOnGH : public CBaseForGHApply { public: - void applyOnGH(CGameHandler *gh, CConnection *c, void *pack) const + bool applyOnGH(CGameHandler *gh, CConnection *c, void *pack) const { T *ptr = static_cast(pack); ptr->c = c; - ptr->applyGh(gh); + return ptr->applyGh(gh); } }; @@ -484,17 +484,32 @@ void CGameHandler::handleConnection(std::set players, CConnection &c) { while(!end2) { - c >> pack; - tlog5 << "Received client message of type " << typeid(*pack).name() << std::endl; - CBaseForGHApply *apply = applier->apps[typeList.getTypeID(pack)]; + { + boost::unique_lock lock(*c.rmx); + c >> pack; //get the package + tlog5 << "Received client message of type " << typeid(*pack).name() << std::endl; + } + + int packType = typeList.getTypeID(pack); //get the id of type + CBaseForGHApply *apply = applier->apps[packType]; //and appropriae applier object + if(apply) { - apply->applyOnGH(this,&c,pack); - tlog5 << "Message successfully applied!\n"; + bool result = apply->applyOnGH(this,&c,pack); + tlog5 << "Message successfully applied (result=" << result << ")!\n"; + + //send confirmation that we've applied the package + PackageApplied applied; + applied.result = result; + applied.packType = packType; + { + boost::unique_lock lock(*c.wmx); + c << &applied; + } } else { - tlog5 << "Message cannot be applied, cannot find applier!\n"; + tlog1 << "Message cannot be applied, cannot find applier (unregistered type)!\n"; } delete pack; pack = NULL; @@ -759,6 +774,7 @@ void CGameHandler::run(bool resume) { YourTurn yt; yt.player = i->first; + boost::unique_lock lock(*connections[i->first]->wmx); *connections[i->first] << &yt; } @@ -1063,11 +1079,19 @@ void CGameHandler::setBlockVis(int objid, bool bv) SetObjectProperty sop(objid,2,bv); sendAndApply(&sop); } -void CGameHandler::removeObject(int objid) + +bool CGameHandler::removeObject( int objid ) { + if(!getObj(objid)) + { + tlog1 << "Something wrong, that object already has been removed or hasn't existed!\n"; + return false; + } + RemoveObject ro; ro.id = objid; sendAndApply(&ro); + return true; } void CGameHandler::setAmount(int objid, ui32 val) @@ -1076,7 +1100,7 @@ void CGameHandler::setAmount(int objid, ui32 val) sendAndApply(&sop); } -void CGameHandler::moveHero(si32 hid, int3 dst, ui8 instant, ui8 asker) +bool CGameHandler::moveHero( si32 hid, int3 dst, ui8 instant, ui8 asker /*= 255*/ ) { bool blockvis = false; const CGHeroInstance *h = getHero(hid); @@ -1085,7 +1109,7 @@ void CGameHandler::moveHero(si32 hid, int3 dst, ui8 instant, ui8 asker) ) { tlog1 << "Illegal call to move hero!\n"; - return; + return false; } tlog5 << "Player " <pos << " to " << dst << std::endl; @@ -1109,7 +1133,7 @@ void CGameHandler::moveHero(si32 hid, int3 dst, ui8 instant, ui8 asker) { tlog2 << "Cannot move hero, destination tile is blocked!\n"; sendAndApply(&tmh); - return; + return false; } //checks for standard movement @@ -1121,7 +1145,7 @@ void CGameHandler::moveHero(si32 hid, int3 dst, ui8 instant, ui8 asker) { tlog2 << "Cannot move hero, not enough move points or tiles are not neighbouring!\n"; sendAndApply(&tmh); - return; + return false; } //check if there is blocking visitable object @@ -1148,7 +1172,7 @@ void CGameHandler::moveHero(si32 hid, int3 dst, ui8 instant, ui8 asker) } } tlog5 << "Blocking visit at " << hmpos << std::endl; - return; + return true; } else //normal move { @@ -1169,6 +1193,7 @@ void CGameHandler::moveHero(si32 hid, int3 dst, ui8 instant, ui8 asker) } } tlog5 << "Movement end!\n"; + return true; } else //instant move - teleportation { @@ -1177,16 +1202,17 @@ void CGameHandler::moveHero(si32 hid, int3 dst, ui8 instant, ui8 asker) if(obj->ID==HEROI_TYPE) { if(obj->tempOwner==h->tempOwner) - return;//TODO: exchange + return true;//TODO: exchange //TODO: check for ally CGHeroInstance *dh = static_cast(obj); startBattleI(&h->army,&dh->army,dst,h,dh,0); - return; + return true; } } tmh.result = instant+1; getTilesInRange(tmh.fowRevealed,h->getSightCenter()+(tmh.end-tmh.start),h->getSightRadious(),h->tempOwner,1); sendAndApply(&tmh); + return true; } } void CGameHandler::setOwner(int objid, ui8 owner) @@ -1452,7 +1478,7 @@ void CGameHandler::close() //exit(0); } -void CGameHandler::arrangeStacks(si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, si32 val) +bool CGameHandler::arrangeStacks( si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, si32 val ) { CArmedInstance *s1 = static_cast(gs->map->objects[id1]), *s2 = static_cast(gs->map->objects[id2]); @@ -1462,7 +1488,7 @@ void CGameHandler::arrangeStacks(si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, s if(!isAllowedExchange(id1,id2)) { complain("Cannot exchange stacks between these two objects!\n"); - return; + return false; } if(what==1) //swap @@ -1480,7 +1506,7 @@ void CGameHandler::arrangeStacks(si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, s if(S1.slots[p1].first != S2.slots[p2].first) //not same creature { complain("Cannot merge different creatures stacks!"); - return; + return false; } S2.slots[p2].second += S1.slots[p1].second; @@ -1492,7 +1518,7 @@ void CGameHandler::arrangeStacks(si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, s if((!vstd::contains(S1.slots,p1) && complain("no creatures to split")) || (val<1 && complain("no creatures to split")) ) { - return; + return false; } @@ -1503,7 +1529,7 @@ void CGameHandler::arrangeStacks(si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, s || (S2.slots[p2].first != S1.slots[p1].first && complain("Cannot rebalance different creatures stacks!")) ) { - return; + return false; } S2.slots[p2].second = val; @@ -1514,7 +1540,7 @@ void CGameHandler::arrangeStacks(si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, s if(S1.slots[p1].second < val)//not enough creatures { complain("Cannot split that stack, not enough creatures!"); - return; + return false; } S2.slots[p2].first = S1.slots[p1].first; S2.slots[p2].second = val; @@ -1529,7 +1555,7 @@ void CGameHandler::arrangeStacks(si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, s ) { complain("Cannot take the last stack!"); - return; //leave without applying changes to garrison + return false; //leave without applying changes to garrison } //apply changes @@ -1538,6 +1564,7 @@ void CGameHandler::arrangeStacks(si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, s if(s1 != s2) sg.garrs[id2] = S2; sendAndApply(&sg); + return true; } int CGameHandler::getPlayerAt( CConnection *c ) const @@ -1564,21 +1591,22 @@ int CGameHandler::getPlayerAt( CConnection *c ) const } } -void CGameHandler::disbandCreature(si32 id, ui8 pos) +bool CGameHandler::disbandCreature( si32 id, ui8 pos ) { CArmedInstance *s1 = static_cast(gs->map->objects[id]); if(!vstd::contains(s1->army.slots,pos)) { complain("Illegal call to disbandCreature - no such stack in army!"); - return; + return false; } s1->army.slots.erase(pos); SetGarrisons sg; sg.garrs[id] = s1->army; sendAndApply(&sg); + return true; } -void CGameHandler::buildStructure(si32 tid, si32 bid) +bool CGameHandler::buildStructure( si32 tid, si32 bid ) { CGTownInstance * t = static_cast(gs->map->objects[tid]); CBuilding * b = VLC->buildh->buildings[t->subID][bid]; @@ -1586,7 +1614,7 @@ void CGameHandler::buildStructure(si32 tid, si32 bid) if(gs->canBuildStructure(t,bid) != 7) { complain("Cannot build that building!"); - return; + return false; } NewStructures ns; @@ -1625,6 +1653,8 @@ void CGameHandler::buildStructure(si32 tid, si32 bid) if(t->garrisonHero) giveSpells(t,t->garrisonHero); } + + return true; } void CGameHandler::sendMessageToAll( const std::string &message ) @@ -1634,7 +1664,7 @@ void CGameHandler::sendMessageToAll( const std::string &message ) sendToAllClients(&sm); } -void CGameHandler::recruitCreatures( si32 objid, ui32 crid, ui32 cram ) +bool CGameHandler::recruitCreatures( si32 objid, ui32 crid, ui32 cram ) { si32 ser = -1; CGTownInstance * t = static_cast(gs->map->objects[objid]); @@ -1654,11 +1684,13 @@ void CGameHandler::recruitCreatures( si32 objid, ui32 crid, ui32 cram ) } int slot = t->army.getSlotFor(crid); - if(!found || //no such creature - cram > VLC->creh->creatures[crid].maxAmount(gs->getPlayer(t->tempOwner)->resources) || //lack of resources - cram<=0 || - slot<0 ) - return; + if(!found && complain("Cannot recruit: no such creatures!") + || cram > VLC->creh->creatures[crid].maxAmount(gs->getPlayer(t->tempOwner)->resources) && complain("Cannot recruit: lack of resources!") + || cram<=0 && complain("Cannot recruit: cram <= 0!") + || slot<0 && complain("Cannot recruit: no available slot!")) + { + return false; + } //recruit SetResources sr; @@ -1684,9 +1716,10 @@ void CGameHandler::recruitCreatures( si32 objid, ui32 crid, ui32 cram ) sendAndApply(&sr); sendAndApply(&sac); sendAndApply(&sg); + return true; } -void CGameHandler::upgradeCreature( ui32 objid, ui8 pos, ui32 upgID ) +bool CGameHandler::upgradeCreature( ui32 objid, ui8 pos, ui32 upgID ) { CArmedInstance *obj = static_cast(gs->map->objects[objid]); UpgradeInfo ui = gs->getUpgradeInfo(obj,pos); @@ -1694,8 +1727,10 @@ void CGameHandler::upgradeCreature( ui32 objid, ui8 pos, ui32 upgID ) int crQuantity = obj->army.slots[pos].second; //check if upgrade is possible - if(ui.oldID<0 || !vstd::contains(ui.newID,upgID)) - return; + if((ui.oldID<0 || !vstd::contains(ui.newID,upgID)) && complain("That upgrade is not possible!")) + { + return false; + } //check if player has enough resources for(int i=0;i >::iterator j=ui.cost[i].begin(); j!=ui.cost[i].end(); j++) { if(gs->getPlayer(player)->resources[j->first] < j->second*crQuantity) - return; + { + complain("Cannot upgrade, not enough resources!"); + return false; + } } } @@ -1725,9 +1763,10 @@ void CGameHandler::upgradeCreature( ui32 objid, ui8 pos, ui32 upgID ) sg.garrs[objid] = obj->army; sg.garrs[objid].slots[pos].first = upgID; sendAndApply(&sg); + return true; } -void CGameHandler::garrisonSwap(si32 tid) +bool CGameHandler::garrisonSwap( si32 tid ) { CGTownInstance *town = gs->getTown(tid); if(!town->garrisonHero && town->visitingHero) //visiting => garrison, merge armies @@ -1737,7 +1776,10 @@ void CGameHandler::garrisonSwap(si32 tid) { int pos = csn.getSlotFor(cso.slots.begin()->second.first); if(pos<0) - return; + { + complain("Cannot make garrison swap, not enough free slots!"); + return false; + } if(csn.slots.find(pos)!=csn.slots.end()) //add creatures to the existing stack { csn.slots[pos].second += cso.slots.begin()->second.second; @@ -1759,6 +1801,7 @@ void CGameHandler::garrisonSwap(si32 tid) intown.visiting = -1; intown.garrison = town->visitingHero->id; sendAndApply(&intown); + return true; } else if (town->garrisonHero && !town->visitingHero) //move hero out of the garrison { @@ -1766,7 +1809,7 @@ void CGameHandler::garrisonSwap(si32 tid) if(getHeroCount(town->garrisonHero->tempOwner,true) >= 8) { complain("Cannot move hero out of the garrison, there are already 8 wandering heroes!"); - return; + return false; } SetHeroesInTown intown; @@ -1779,6 +1822,7 @@ void CGameHandler::garrisonSwap(si32 tid) SetGarrisons sg; sg.garrs[tid] = CCreatureSet(); sendAndApply(&sg); + return true; } else if (town->garrisonHero && town->visitingHero) //swap visiting and garrison hero { @@ -1792,18 +1836,21 @@ void CGameHandler::garrisonSwap(si32 tid) intown.visiting = town->garrisonHero->id; sendAndApply(&intown); sendAndApply(&sg); + return true; } else { complain("Cannot swap garrison hero!"); + return false; } } -void CGameHandler::swapArtifacts( si32 hid1, si32 hid2, ui16 slot1, ui16 slot2 ) +bool CGameHandler::swapArtifacts( si32 hid1, si32 hid2, ui16 slot1, ui16 slot2 ) { CGHeroInstance *h1 = gs->getHero(hid1), *h2 = gs->getHero(hid2); if((distance(h1->pos,h2->pos) > 1.0) || (h1->tempOwner != h2->tempOwner)) - return; + return false; + const CArtifact *a1 = h1->getArt(slot1), *a2=h2->getArt(slot2); @@ -1813,7 +1860,7 @@ void CGameHandler::swapArtifacts( si32 hid1, si32 hid2, ui16 slot1, ui16 slot2 ) { //artifact doesn't fit dst slot complain("Cannot swap artifacts!"); - return; + return false; } @@ -1832,9 +1879,11 @@ void CGameHandler::swapArtifacts( si32 hid1, si32 hid2, ui16 slot1, ui16 slot2 ) sha.setArtAtPos(slot2,h1->getArtAtPos(slot1)); sendAndApply(&sha); } + + return true; } -void CGameHandler::buyArtifact( ui32 hid, si32 aid ) +bool CGameHandler::buyArtifact( ui32 hid, si32 aid ) { CGHeroInstance *hero = gs->getHero(hid); CGTownInstance *town = hero->visitedTown; @@ -1844,29 +1893,32 @@ void CGameHandler::buyArtifact( ui32 hid, si32 aid ) || getResource(hero->getOwner(),6)<500 && complain("Cannot buy a spellbook, not enough gold!") || hero->getArt(17) && complain("Cannot buy a spellbook, hero already has a one!") ) - return; + return false; giveResource(hero->getOwner(),6,-500); giveHeroArtifact(0,hid,17); giveSpells(town,hero); + return true; } else if(aid < 7 && aid > 3) //war machine { int price = VLC->arth->artifacts[aid].price; - if(vstd::contains(hero->artifWorn,ui16(9+aid)) //hero already has this machine - || !vstd::contains(town->builtBuildings,si32(16)) //no blackismith - || gs->getPlayer(hero->getOwner())->resources[6] < price //no gold - || town->town->warMachine!= aid ) //this machine is not available here (//TODO: support ballista yard in stronghold) + if(vstd::contains(hero->artifWorn,ui16(9+aid)) && complain("Hero already has this machine!") + || !vstd::contains(town->builtBuildings,si32(16)) && complain("No blackismith!") + || gs->getPlayer(hero->getOwner())->resources[6] < price && complain("Not enough gold!") //no gold + || town->town->warMachine!= aid && complain("This machine is unavailale here!") ) //TODO: ballista yard in Stronghold { - return; + return false; } giveResource(hero->getOwner(),6,-price); giveHeroArtifact(aid,hid,9+aid); + return true; } + return false; } -void CGameHandler::tradeResources( ui32 val, ui8 player, ui32 id1, ui32 id2 ) +bool CGameHandler::tradeResources( ui32 val, ui8 player, ui32 id1, ui32 id2 ) { val = std::min(si32(val),gs->getPlayer(player)->resources[id1]); double uzysk = (double)gs->resVals[id1] * val * gs->getMarketEfficiency(player); @@ -1880,22 +1932,25 @@ void CGameHandler::tradeResources( ui32 val, ui8 player, ui32 id1, ui32 id2 ) sr.resid = id2; sr.val = gs->getPlayer(player)->resources[id2] + (int)uzysk; sendAndApply(&sr); + + return true; } -void CGameHandler::setFormation( si32 hid, ui8 formation ) +bool CGameHandler::setFormation( si32 hid, ui8 formation ) { gs->getHero(hid)->army.formation = formation; + return true; } -void CGameHandler::hireHero( ui32 tid, ui8 hid ) +bool CGameHandler::hireHero( ui32 tid, ui8 hid ) { CGTownInstance *t = gs->getTown(tid); - if(!vstd::contains(t->builtBuildings,5) //no tavern in the town - || gs->getPlayer(t->tempOwner)->resources[6]<2500 //not enough gold - || t->visitingHero //there is visiting hero - no place + if(!vstd::contains(t->builtBuildings,5) && complain("No tavern!") + || gs->getPlayer(t->tempOwner)->resources[6]<2500 && complain("Not enough gold for buying hero!") + || t->visitingHero && complain("There is visiting hero - no place!") || getHeroCount(t->tempOwner,false) >= 8 && complain("Cannot hire hero, only 8 wandering heroes are allowed!") ) - return; + return false; CGHeroInstance *nh = gs->getPlayer(t->tempOwner)->availableHeroes[hid]; HeroRecruited hr; @@ -1919,9 +1974,10 @@ void CGameHandler::hireHero( ui32 tid, ui8 hid ) sendAndApply(&sr); giveSpells(t,nh); + return true; } -void CGameHandler::queryReply( ui32 qid, ui32 answer ) +bool CGameHandler::queryReply( ui32 qid, ui32 answer ) { boost::unique_lock lock(gsm); if(vstd::contains(callbacks,qid)) @@ -1941,11 +1997,14 @@ void CGameHandler::queryReply( ui32 qid, ui32 answer ) else { tlog1 << "Unknown query reply...\n"; + return false; } + return true; } -void CGameHandler::makeBattleAction( BattleAction &ba ) +bool CGameHandler::makeBattleAction( BattleAction &ba ) { + bool ok = true; switch(ba.actionType) { case 2: //walk @@ -1985,11 +2044,13 @@ void CGameHandler::makeBattleAction( BattleAction &ba ) if(curStack->position != ba.destinationTile) //we wasn't able to reach destination tile { tlog3<<"We cannot move this stack to its destination "<creature->namePl<= VLC->spellh->spells.size()) { tlog2 << "Wrong spell id (" << ba.additionalInfo << ")!\n"; - return; + return false; } CSpell *s = &VLC->spellh->spells[ba.additionalInfo]; @@ -2210,7 +2272,7 @@ void CGameHandler::makeCustomAction( BattleAction &ba ) ) { tlog2 << "Spell cannot be casted!\n"; - return; + return false; } sendAndApply(&StartAction(ba)); //start spell casting @@ -2343,8 +2405,10 @@ void CGameHandler::makeCustomAction( BattleAction &ba ) } } sendAndApply(&EndAction()); + return true; } } + return false; } void CGameHandler::handleTimeEvents() diff --git a/server/CGameHandler.h b/server/CGameHandler.h index 829416a1a..980eb1eef 100644 --- a/server/CGameHandler.h +++ b/server/CGameHandler.h @@ -103,7 +103,7 @@ public: //do sth void changeSpells(int hid, bool give, const std::set &spells); - void removeObject(int objid); + bool removeObject(int objid); void setBlockVis(int objid, bool bv); void setOwner(int objid, ui8 owner); void setHoverName(int objid, MetaString * name); @@ -124,7 +124,7 @@ public: void startBattleI(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, boost::function cb); //use hero=NULL for no hero void startBattleI(int heroID, CCreatureSet army, int3 tile, boost::function cb); //for hero<=>neutral army void setAmount(int objid, ui32 val); - void moveHero(si32 hid, int3 dst, ui8 instant, ui8 asker = 255); + bool moveHero(si32 hid, int3 dst, ui8 instant, ui8 asker = 255); void giveHeroBonus(GiveBonus * bonus); void setMovePoints(SetMovePoints * smp); void setManaPoints(int hid, int val); @@ -137,20 +137,20 @@ public: int getPlayerAt(CConnection *c) const; void playerMessage( ui8 player, const std::string &message); - void makeBattleAction(BattleAction &ba); - void makeCustomAction(BattleAction &ba); - void queryReply( ui32 qid, ui32 answer ); - void hireHero( ui32 tid, ui8 hid ); - void setFormation( si32 hid, ui8 formation ); - void tradeResources( ui32 val, ui8 player, ui32 id1, ui32 id2 ); - void buyArtifact( ui32 hid, si32 aid ); - void swapArtifacts( si32 hid1, si32 hid2, ui16 slot1, ui16 slot2 ); - void garrisonSwap(si32 tid); - void upgradeCreature( ui32 objid, ui8 pos, ui32 upgID ); - void recruitCreatures(si32 objid, ui32 crid, ui32 cram); - void buildStructure(si32 tid, si32 bid); - void disbandCreature( si32 id, ui8 pos ); - void arrangeStacks( si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, si32 val ); + bool makeBattleAction(BattleAction &ba); + bool makeCustomAction(BattleAction &ba); + bool queryReply( ui32 qid, ui32 answer ); + bool hireHero( ui32 tid, ui8 hid ); + bool setFormation( si32 hid, ui8 formation ); + bool tradeResources( ui32 val, ui8 player, ui32 id1, ui32 id2 ); + bool buyArtifact( ui32 hid, si32 aid ); + bool swapArtifacts( si32 hid1, si32 hid2, ui16 slot1, ui16 slot2 ); + bool garrisonSwap(si32 tid); + bool upgradeCreature( ui32 objid, ui8 pos, ui32 upgID ); + bool recruitCreatures(si32 objid, ui32 crid, ui32 cram); + bool buildStructure(si32 tid, si32 bid); + bool disbandCreature( si32 id, ui8 pos ); + bool arrangeStacks( si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, si32 val ); void save(const std::string &fname); void close(); void handleTimeEvents(); diff --git a/server/NetPacksServer.cpp b/server/NetPacksServer.cpp index be6f2de03..6eb8a24c8 100644 --- a/server/NetPacksServer.cpp +++ b/server/NetPacksServer.cpp @@ -5,7 +5,7 @@ #define PLAYER_OWNS(id) (gh->getPlayerAt(c)==gh->getOwner(id)) #define ERROR_AND_RETURN {if(c) *c << &SystemMessage("You are not allowed to perform this action!"); \ tlog1<<"Player is not allowed to perform this action!\n"; \ - return;} + return false;} #define ERROR_IF_NOT_OWNS(id) if(!PLAYER_OWNS(id)) ERROR_AND_RETURN /* @@ -23,128 +23,136 @@ CGameState* CPackForServer::GS(CGameHandler *gh) return gh->gs; } -void SaveGame::applyGh( CGameHandler *gh ) +bool SaveGame::applyGh( CGameHandler *gh ) { gh->sendMessageTo(*c,"Saving..."); gh->save(fname); gh->sendMessageTo(*c,"Game has been succesfully saved!"); + return true; } -void CloseServer::applyGh( CGameHandler *gh ) +bool CloseServer::applyGh( CGameHandler *gh ) { gh->close(); + return true; } -void EndTurn::applyGh( CGameHandler *gh ) +bool EndTurn::applyGh( CGameHandler *gh ) { gh->states.setFlag(GS(gh)->currentPlayer,&PlayerStatus::makingTurn,false); + return true; } -void DismissHero::applyGh( CGameHandler *gh ) +bool DismissHero::applyGh( CGameHandler *gh ) { ERROR_IF_NOT_OWNS(hid); - gh->removeObject(hid); + return gh->removeObject(hid); } -void MoveHero::applyGh( CGameHandler *gh ) +bool MoveHero::applyGh( CGameHandler *gh ) { ERROR_IF_NOT_OWNS(hid); - gh->moveHero(hid,dest,0,gh->getPlayerAt(c)); + return gh->moveHero(hid,dest,0,gh->getPlayerAt(c)); } -void ArrangeStacks::applyGh( CGameHandler *gh ) +bool ArrangeStacks::applyGh( CGameHandler *gh ) { - //ERROR_IF_NOT_OWNS(id1); - //ERROR_IF_NOT_OWNS(id2); - gh->arrangeStacks(id1,id2,what,p1,p2,val); + //checks for owning in the gh func + return gh->arrangeStacks(id1,id2,what,p1,p2,val); } -void DisbandCreature::applyGh( CGameHandler *gh ) +bool DisbandCreature::applyGh( CGameHandler *gh ) { ERROR_IF_NOT_OWNS(id); - gh->disbandCreature(id,pos); + return gh->disbandCreature(id,pos); } -void BuildStructure::applyGh( CGameHandler *gh ) +bool BuildStructure::applyGh( CGameHandler *gh ) { ERROR_IF_NOT_OWNS(tid); - gh->buildStructure(tid,bid); + return gh->buildStructure(tid,bid); } -void RecruitCreatures::applyGh( CGameHandler *gh ) +bool RecruitCreatures::applyGh( CGameHandler *gh ) { ERROR_IF_NOT_OWNS(tid); - gh->recruitCreatures(tid,crid,amount); + return gh->recruitCreatures(tid,crid,amount); } -void UpgradeCreature::applyGh( CGameHandler *gh ) +bool UpgradeCreature::applyGh( CGameHandler *gh ) { ERROR_IF_NOT_OWNS(id); - gh->upgradeCreature(id,pos,cid); + return gh->upgradeCreature(id,pos,cid); } -void GarrisonHeroSwap::applyGh( CGameHandler *gh ) +bool GarrisonHeroSwap::applyGh( CGameHandler *gh ) { ERROR_IF_NOT_OWNS(tid); - gh->garrisonSwap(tid); + return gh->garrisonSwap(tid); } -void ExchangeArtifacts::applyGh( CGameHandler *gh ) +bool ExchangeArtifacts::applyGh( CGameHandler *gh ) { ERROR_IF_NOT_OWNS(hid1); ERROR_IF_NOT_OWNS(hid2); - gh->swapArtifacts(hid1,hid2,slot1,slot2); + return gh->swapArtifacts(hid1,hid2,slot1,slot2); } -void BuyArtifact::applyGh( CGameHandler *gh ) +bool BuyArtifact::applyGh( CGameHandler *gh ) { ERROR_IF_NOT_OWNS(hid); - gh->buyArtifact(hid,aid); + return gh->buyArtifact(hid,aid); } -void TradeOnMarketplace::applyGh( CGameHandler *gh ) +bool TradeOnMarketplace::applyGh( CGameHandler *gh ) { if(gh->getPlayerAt(c) != player) ERROR_AND_RETURN; - gh->tradeResources(val,player,r1,r2); + return gh->tradeResources(val,player,r1,r2); } -void SetFormation::applyGh( CGameHandler *gh ) +bool SetFormation::applyGh( CGameHandler *gh ) { ERROR_IF_NOT_OWNS(hid); - gh->setFormation(hid,formation); + return gh->setFormation(hid,formation); } -void HireHero::applyGh( CGameHandler *gh ) +bool HireHero::applyGh( CGameHandler *gh ) { ERROR_IF_NOT_OWNS(tid); - gh->hireHero(tid,hid); + return gh->hireHero(tid,hid); } -void QueryReply::applyGh( CGameHandler *gh ) +bool QueryReply::applyGh( CGameHandler *gh ) { - gh->queryReply(qid,answer); + //TODO - check if player matches the query + return gh->queryReply(qid,answer); } -void MakeAction::applyGh( CGameHandler *gh ) +bool MakeAction::applyGh( CGameHandler *gh ) { + if(!GS(gh)->curB) ERROR_AND_RETURN; if(gh->connections[GS(gh)->curB->getStack(GS(gh)->curB->activeStack)->owner] != c) ERROR_AND_RETURN; - gh->makeBattleAction(ba); + return gh->makeBattleAction(ba); } -void MakeCustomAction::applyGh( CGameHandler *gh ) +bool MakeCustomAction::applyGh( CGameHandler *gh ) { + if(!GS(gh)->curB) ERROR_AND_RETURN; if(gh->connections[GS(gh)->curB->getStack(GS(gh)->curB->activeStack)->owner] != c) ERROR_AND_RETURN; - gh->makeCustomAction(ba); + return gh->makeCustomAction(ba); } -void PlayerMessage::applyGh( CGameHandler *gh ) +bool PlayerMessage::applyGh( CGameHandler *gh ) { if(gh->getPlayerAt(c) != player) ERROR_AND_RETURN; gh->playerMessage(player,text); + return true; } -void SetSelection::applyGh( CGameHandler *gh ) +bool SetSelection::applyGh( CGameHandler *gh ) { if(gh->getPlayerAt(c) != player) ERROR_AND_RETURN; + if(!gh->getObj(id)) ERROR_AND_RETURN; gh->sendAndApply(this); + return true; } \ No newline at end of file