diff --git a/client/NetPacksClient.cpp b/client/NetPacksClient.cpp index cb9138f8d..1cb368518 100644 --- a/client/NetPacksClient.cpp +++ b/client/NetPacksClient.cpp @@ -152,7 +152,7 @@ void RemoveObject::applyFirstCl( CClient *cl ) void RemoveObject::applyCl( CClient *cl ) { - if(cl->pathInfo->hero) + if(cl->pathInfo->hero && cl->pathInfo->hero->id != id) GS(cl)->calculatePaths(cl->pathInfo->hero, *cl->pathInfo); } diff --git a/lib/CGameState.cpp b/lib/CGameState.cpp index e07946f82..9d367e3a4 100644 --- a/lib/CGameState.cpp +++ b/lib/CGameState.cpp @@ -217,6 +217,9 @@ void MetaString::getLocalString(const std::pair &txt, std::string &dst case SEC_SKILL_NAME: vec = &VLC->generaltexth->skillName; break; + case COLOR: + vec = &VLC->generaltexth->capColors; + break; } dst = (*vec)[ser]; } @@ -3224,6 +3227,9 @@ int CGameState::lossCheck( ui8 player ) const } } + if(!p->towns.size() && p->daysWithoutCastle >= 7) + return 2; + return false; } diff --git a/lib/NetPacks.h b/lib/NetPacks.h index 10ce6b4f5..9cdf41736 100644 --- a/lib/NetPacks.h +++ b/lib/NetPacks.h @@ -73,7 +73,7 @@ private: enum EMessage {TEXACT_STRING, TLOCAL_STRING, TNUMBER, TREPLACE_ESTRING, TREPLACE_LSTRING, TREPLACE_NUMBER}; public: enum {GENERAL_TXT=1, XTRAINFO_TXT, OBJ_NAMES, RES_NAMES, ART_NAMES, ARRAY_TXT, CRE_PL_NAMES, CREGENS, MINE_NAMES, - MINE_EVNTS, ADVOB_TXT, ART_EVNTS, SPELL_NAME, SEC_SKILL_NAME, CRE_SING_NAMES, CREGENS4}; + MINE_EVNTS, ADVOB_TXT, ART_EVNTS, SPELL_NAME, SEC_SKILL_NAME, CRE_SING_NAMES, CREGENS4, COLOR}; std::vector message; //vector of EMessage @@ -631,7 +631,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, MORALE=8, LUCK, HERO}; + enum {PRIM_SKILL, SEC_SKILL, RESOURCE, CREATURE, ARTIFACT, EXPERIENCE, SPELL, MORALE=8, LUCK, HERO, FLAG}; 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 diff --git a/lib/NetPacksLib.cpp b/lib/NetPacksLib.cpp index 3658b554c..81c4bba60 100644 --- a/lib/NetPacksLib.cpp +++ b/lib/NetPacksLib.cpp @@ -575,6 +575,15 @@ DLL_EXPORT void NewTurn::applyGs( CGameState *gs ) if(gs->getDate(1) == 7) //new week BOOST_FOREACH(CGHeroInstance *h, gs->map->heroes) h->bonuses.remove_if(HeroBonus::OneWeek); + + //count days without town + for( std::map::iterator i=gs->players.begin() ; i!=gs->players.end();i++) + { + if(i->second.towns.size() || gs->day == 1) + i->second.daysWithoutCastle = 0; + else + i->second.daysWithoutCastle++; + } } DLL_EXPORT void SetObjectProperty::applyGs( CGameState *gs ) diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 84cb62937..56fef77ab 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -912,6 +912,38 @@ void CGameHandler::newTurn() gs->map->objects[i]->newTurn(); winLoseHandle(0xff); + + //warn players without town + if(gs->day) + { + for (std::map::iterator i=gs->players.begin() ; i!=gs->players.end();i++) + { + if(i->second.status || i->second.towns.size() || i->second.color >= PLAYER_LIMIT) + continue; + + InfoWindow iw; + iw.player = i->first; + iw.components.push_back(Component(Component::FLAG,i->first,0,0)); + + if(!i->second.daysWithoutCastle) + { + iw.text.addTxt(MetaString::GENERAL_TXT,6); //%s, you have lost your last town. If you do not conquer another town in the next week, you will be eliminated. + iw.text.addReplacement(MetaString::COLOR, i->first); + } + else if(i->second.daysWithoutCastle == 6) + { + iw.text.addTxt(MetaString::ARRAY_TXT,129); //%s, this is your last day to capture a town or you will be banished from this land. + iw.text.addReplacement(MetaString::COLOR, i->first); + } + else + { + iw.text.addTxt(MetaString::ARRAY_TXT,128); //%s, you only have %d days left to capture a town or you will be banished from this land. + iw.text.addReplacement(MetaString::COLOR, i->first); + iw.text.addReplacement(7 - i->second.daysWithoutCastle); + } + sendAndApply(&iw); + } + } } void CGameHandler::run(bool resume) { @@ -1583,10 +1615,18 @@ bool CGameHandler::moveHero( si32 hid, int3 dst, ui8 instant, ui8 asker /*= 255* } void CGameHandler::setOwner(int objid, ui8 owner) { + ui8 oldOwner = getOwner(objid); SetObjectProperty sop(objid,1,owner); sendAndApply(&sop); - winLoseHandle(1<getPlayer(owner)->towns.size()) //player lost last town + { + InfoWindow iw; + iw.player = oldOwner; + iw.text.addTxt(MetaString::GENERAL_TXT, 6); //%s, you have lost your last town. If you do not conquer another town in the next week, you will be eliminated. + sendAndApply(&iw); + } } void CGameHandler::setHoverName(int objid, MetaString* name) { @@ -2877,7 +2917,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba ) break; } } - if(ba.stackNumber == gs->curB->activeStack) + if(ba.stackNumber == gs->curB->activeStack || battleResult.get()) //active stack has moved or battle has finished battleMadeAction.setn(true); return ok; } @@ -3522,7 +3562,7 @@ void CGameHandler::checkLossVictory( ui8 player ) return; InfoWindow iw; - getLossVicMessage(player, vic ? vic < 0 : loss < 0, vic, iw); + getLossVicMessage(player, vic ? vic : loss , vic, iw); sendAndApply(&iw); PlayerEndsGame peg; @@ -3530,7 +3570,7 @@ void CGameHandler::checkLossVictory( ui8 player ) peg.victory = vic; sendAndApply(&peg); - if(vic) //one player won -> all enemies lost //TODO: allies + if(vic > 0) //one player won -> all enemies lost //TODO: allies { iw.text.localStrings.front().second++; //message about losing because enemy won first is just after victory message @@ -3549,18 +3589,25 @@ void CGameHandler::checkLossVictory( ui8 player ) } else //player lost -> all his objects become unflagged (neutral) { - for (std::vector::const_iterator i = gs->map->objects.begin(); i != gs->map->objects.end(); i++) + std::vector hlp = p->heroes; + for (std::vector::const_iterator i = hlp.begin(); i != hlp.end(); i++) //eliminate heroes + removeObject((*i)->id); + + for (std::vector::const_iterator i = gs->map->objects.begin(); i != gs->map->objects.end(); i++) //unflag objs { if(*i && (*i)->tempOwner == player) setOwner((**i).id,NEUTRAL_PLAYER); } + + //eliminating one player may cause victory of anoother: + winLoseHandle(ALL_PLAYERS & ~(1<getPlayer(player); // if(!p->human) @@ -3570,7 +3617,7 @@ void CGameHandler::getLossVicMessage( ui8 player, bool standard, bool victory, I if(victory) { - if(!standard) //not std loss + if(standard < 0) //not std loss { switch(gs->map->victoryCondition.condition) { @@ -3626,12 +3673,12 @@ void CGameHandler::getLossVicMessage( ui8 player, bool standard, bool victory, I } else { - + out.text.addTxt(MetaString::GENERAL_TXT, 659); //Congratulations! You have reached your destination, precious cargo intact, and can claim victory! } } else { - if(!standard) //not std loss + if(standard < 0) //not std loss { switch(gs->map->lossCondition.typeOfLossCon) { @@ -3656,6 +3703,12 @@ void CGameHandler::getLossVicMessage( ui8 player, bool standard, bool victory, I break; } } + else if(standard == 2) + { + out.text.addTxt(MetaString::GENERAL_TXT, 7);//%s, your heroes abandon you, and you are banished from this land. + out.text.addReplacement(MetaString::COLOR, player); + out.components.push_back(Component(Component::FLAG,player,0,0)); + } else //lost all towns and heroes { out.text.addTxt(MetaString::GENERAL_TXT, 660); //All your forces have been defeated, and you are banished from this land! diff --git a/server/CGameHandler.h b/server/CGameHandler.h index 77dad4627..bfa18bd12 100644 --- a/server/CGameHandler.h +++ b/server/CGameHandler.h @@ -91,7 +91,7 @@ public: void startBattle(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank, boost::function cb, const CGTownInstance *town = NULL); //use hero=NULL for no hero void checkLossVictory(ui8 player); void winLoseHandle(ui8 players=255); //players: bit field - colours of players to be checked; default: all - void getLossVicMessage(ui8 player, bool standard, bool victory, InfoWindow &out) const; + void getLossVicMessage(ui8 player, ui8 standard, bool victory, InfoWindow &out) const; ////used only in endBattle - don't touch elsewhere boost::function * battleEndCallback;