1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-03-25 21:38:59 +02:00

Rewritten code handling growth to eliminate duplication and make it conformant to OH3 mechanics. Proper support for Statue of Legion.

Displaying shield over minimap during AI turn.
This commit is contained in:
Michał W. Urbańczyk 2011-08-26 20:32:05 +00:00
parent 74620dc685
commit 18444fc72f
13 changed files with 353 additions and 370 deletions

View File

@ -1,11 +1,13 @@
0.85 -> 0.86 (Aug 01 2011)
0.85 -> 0.86 (Sep 01 2011?)
GENERAL:
* Reinstated music support
* Bonus system optimizations (caching)
* converted many config files to JSON
* .tga file support
* New artifacts supported
- Admiral's Hat
- Statue of Legion
- Titan's Thunder
* vERM parser & interpreter
* Bonus caching system
* .tga file support
BATTLES:
* Correct handling of siege obstacles

View File

@ -58,6 +58,8 @@ CAdvMapInt *adventureInt;
CMinimap::CMinimap(bool draw)
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
used = LCLICK | RCLICK | HOVER;
int3 mapSizes = LOCPLINT->cb->getMapSize();
statusbarTxt = CGI->generaltexth->zelp[291].first;
rcText = CGI->generaltexth->zelp[291].second;
@ -67,6 +69,7 @@ CMinimap::CMinimap(bool draw)
pos.w=ADVOPT.minimapH;
temps = newSurface(pos.w,pos.h);
aiShield = new CPicture("AISHIELD.bmp");
const JsonNode config(DATA_DIR "/config/minimap.json");
const JsonVector &minimap_vec = config["MinimapColors"].Vector();
@ -114,48 +117,55 @@ CMinimap::~CMinimap()
void CMinimap::draw(SDL_Surface * to)
{
int3 mapSizes = LOCPLINT->cb->getMapSize();
//draw terrain
blitAt(map[adventureInt->position.z],0,0,temps);
//draw heroes
std::vector <const CGHeroInstance *> hh = LOCPLINT->cb->getHeroesInfo(false);
int mw = map[0]->w, mh = map[0]->h,
wo = mw/mapSizes.x, ho = mh/mapSizes.y;
for (size_t i=0; i < hh.size(); ++i)
if(LOCPLINT->makingTurn)
{
int3 hpos = hh[i]->getPosition(false);
if(hpos.z!=adventureInt->position.z)
continue;
//float zawx = ((float)hpos.x/CGI->mh->sizes.x), zawy = ((float)hpos.y/CGI->mh->sizes.y);
int3 maplgp ( (hpos.x*mw)/mapSizes.x, (hpos.y*mh)/mapSizes.y, hpos.z );
for (int ii=0; ii<wo; ii++)
int3 mapSizes = LOCPLINT->cb->getMapSize();
//draw terrain
blitAt(map[adventureInt->position.z],0,0,temps);
//draw heroes
std::vector <const CGHeroInstance *> hh = LOCPLINT->cb->getHeroesInfo(false);
int mw = map[0]->w, mh = map[0]->h,
wo = mw/mapSizes.x, ho = mh/mapSizes.y;
for (size_t i=0; i < hh.size(); ++i)
{
for (int jj=0; jj<ho; jj++)
int3 hpos = hh[i]->getPosition(false);
if(hpos.z!=adventureInt->position.z)
continue;
//float zawx = ((float)hpos.x/CGI->mh->sizes.x), zawy = ((float)hpos.y/CGI->mh->sizes.y);
int3 maplgp ( (hpos.x*mw)/mapSizes.x, (hpos.y*mh)/mapSizes.y, hpos.z );
for (int ii=0; ii<wo; ii++)
{
SDL_PutPixelWithoutRefresh(temps,maplgp.x+ii,maplgp.y+jj,graphics->playerColors[hh[i]->getOwner()].r,
for (int jj=0; jj<ho; jj++)
{
SDL_PutPixelWithoutRefresh(temps,maplgp.x+ii,maplgp.y+jj,graphics->playerColors[hh[i]->getOwner()].r,
graphics->playerColors[hh[i]->getOwner()].g,graphics->playerColors[hh[i]->getOwner()].b);
}
}
}
blitAt(flObjs[adventureInt->position.z],0,0,temps);
blitAt(FoW[adventureInt->position.z],0,0,temps);
//draw radar
const int tilesw=(ADVOPT.advmapW+31)/32;
const int tilesh=(ADVOPT.advmapH+31)/32;
int bx = (((float)adventureInt->position.x)/(((float)mapSizes.x)))*pos.w,
by = (((float)adventureInt->position.y)/(((float)mapSizes.y)))*pos.h,
rx = (((float)tilesw)/(mapSizes.x))*((float)pos.w), //width
ry = (((float)tilesh)/(mapSizes.y))*((float)pos.h); //height
CSDL_Ext::drawDashedBorder(temps, Rect(bx, by, rx, ry), int3(255,75,125));
//blitAt(radar,bx,by,temps);
blitAt(temps,pos.x,pos.y,to);
}
else
{
aiShield->showAll(to);
}
blitAt(flObjs[adventureInt->position.z],0,0,temps);
blitAt(FoW[adventureInt->position.z],0,0,temps);
//draw radar
const int tilesw=(ADVOPT.advmapW+31)/32;
const int tilesh=(ADVOPT.advmapH+31)/32;
int bx = (((float)adventureInt->position.x)/(((float)mapSizes.x)))*pos.w,
by = (((float)adventureInt->position.y)/(((float)mapSizes.y)))*pos.h,
rx = (((float)tilesw)/(mapSizes.x))*((float)pos.w), //width
ry = (((float)tilesh)/(mapSizes.y))*((float)pos.h); //height
CSDL_Ext::drawDashedBorder(temps, Rect(bx, by, rx, ry), int3(255,75,125));
//blitAt(radar,bx,by,temps);
blitAt(temps,pos.x,pos.y,to);
}
void CMinimap::redraw(int level)// (level==-1) => redraw all levels
{
@ -275,13 +285,11 @@ void CMinimap::clickRight(tribool down, bool previousState)
void CMinimap::clickLeft(tribool down, bool previousState)
{
if (down && (!previousState))
activateMouseMove();
else if (!down)
{
if (std::find(GH.motioninterested.begin(),GH.motioninterested.end(),this)!=GH.motioninterested.end())
deactivateMouseMove();
}
if (down && !(used & MOVE))
changeUsedEvents(MOVE, true);
else if (!down && used & MOVE)
changeUsedEvents(MOVE, false);
//ClickableL::clickLeft(down);
if (!((bool)down))
return;
@ -314,20 +322,12 @@ void CMinimap::mouseMoved (const SDL_MouseMotionEvent & sEvent)
}
void CMinimap::activate()
{
activateLClick();
activateRClick();
activateHover();
if (pressedL)
activateMouseMove();
CIntObject::activate();
}
void CMinimap::deactivate()
{
if (pressedL)
deactivateMouseMove();
deactivateLClick();
deactivateRClick();
deactivateHover();
CIntObject::deactivate();
}
void CMinimap::showTile(const int3 &pos)
@ -439,11 +439,6 @@ void CMinimap::hideTile(const int3 &pos)
}
}
void CMinimap::show( SDL_Surface * to )
{
}
CTerrainRect::CTerrainRect()
:curHoveredTile(-1,-1,-1), currentPath(NULL)
{

View File

@ -44,6 +44,7 @@ public:
class CMinimap : public CIntObject
{
public:
CPicture *aiShield; //the graphic displayed during AI turn
SDL_Surface * temps;
std::map<int,SDL_Color> colors;
std::map<int,SDL_Color> colorsBlocked;
@ -52,7 +53,6 @@ public:
CMinimap(bool draw=true);
~CMinimap();
void show(SDL_Surface * to);
void draw(SDL_Surface * to);
void redraw(int level=-1);// (level==-1) => redraw all levels
void initMap(int level=-1);// (level==-1) => redraw all levels

View File

@ -5,6 +5,7 @@
#include <boost/assign/std/vector.hpp>
#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/foreach.hpp>
#include "CCastleInterface.h"
#include "../CCallback.h"
@ -1130,76 +1131,14 @@ int CCreaInfo::AddToString(std::string from, std::string & to, int numb)
std::string CCreaInfo::genGrowthText()
{
int summ=0;
std::string descr=CGI->generaltexth->allTexts[589];//Growth of creature is number
boost::algorithm::replace_first(descr,"%s", creature->nameSing);
boost::algorithm::replace_first(descr,"%d", boost::lexical_cast<std::string>(town->creatureGrowth(level)));
GrowthInfo gi = town->getGrowthInfo(level);
std::string descr = boost::str(boost::format(CGI->generaltexth->allTexts[589]) % creature->nameSing % gi.totalGrowth());
descr +="\n"+CGI->generaltexth->allTexts[590];
summ = creature->growth;
boost::algorithm::replace_first(descr,"%d", boost::lexical_cast<std::string>(summ));
if ( level>=0 && level<CREATURES_PER_TOWN)
BOOST_FOREACH(const GrowthInfo::Entry &entry, gi.entries)
{
if ( vstd::contains(town->builtBuildings, Buildings::CASTLE))
summ+=AddToString(CGI->buildh->buildings[town->subID][Buildings::CASTLE]->Name()+" %+d",descr,summ);
else if ( vstd::contains(town->builtBuildings, Buildings::CITADEL))
summ+=AddToString(CGI->buildh->buildings[town->subID][Buildings::CITADEL]->Name()+" %+d",descr,summ/2);
summ+=AddToString(CGI->generaltexth->allTexts[63] + " %+d",descr, //double growth or plague
summ * creature->valOfBonuses(Bonus::CREATURE_GROWTH_PERCENT)/100);
summ+=AddToString(CGI->generaltexth->artifNames[133] + " %+d",descr,
summ * town->valOfGlobalBonuses
(Selector::type(Bonus::CREATURE_GROWTH_PERCENT) && Selector::sourceType(Bonus::ARTIFACT))/100); //Statue of Legion
if(town->town->hordeLvl[0]==level)//horde, x to summ
if( vstd::contains(town->builtBuildings, Buildings::HORDE_1) || vstd::contains(town->builtBuildings, Buildings::HORDE_1_UPGR))
summ+=AddToString(CGI->buildh->buildings[town->subID][Buildings::HORDE_1]->Name()+" %+d",descr,
creature->hordeGrowth);
if(town->town->hordeLvl[1]==level)//horde, x to summ
if( vstd::contains(town->builtBuildings, Buildings::HORDE_2) || vstd::contains(town->builtBuildings, Buildings::HORDE_2_UPGR))
summ+=AddToString(CGI->buildh->buildings[town->subID][Buildings::HORDE_2]->Name()+" %+d",descr,
creature->hordeGrowth);
int cnt = 0;
std::vector< const CGDwelling * > myDwellings = LOCPLINT->cb->getMyDwellings();
for (std::vector<const CGDwelling*>::const_iterator it = myDwellings.begin(); it != myDwellings.end(); ++it)
if (CGI->creh->creatures[town->town->basicCreatures[level]]->idNumber == (*it)->creatures[0].second[0])
cnt++;//external dwellings count to summ
summ+=AddToString(CGI->generaltexth->allTexts[591],descr,cnt);
boost::shared_ptr<BonusList> bl;
const CGHeroInstance *hero = town->garrisonHero;
if (hero)
{
bl = hero->getAllBonuses(Selector::type(Bonus::CREATURE_GROWTH) && Selector::subtype(level)
&& Selector::sourceType(Bonus::ARTIFACT), 0, hero);
}
hero = town->visitingHero;
if (hero)
{
boost::shared_ptr<BonusList> blAppend = hero->getAllBonuses(Selector::type(Bonus::CREATURE_GROWTH) && Selector::subtype(level)
&& Selector::sourceType(Bonus::ARTIFACT), 0, hero);
if (town->garrisonHero)
bl->insert(bl->size(), blAppend->begin(), blAppend->end());
else
bl = blAppend;
}
if (bl->size())
summ+=AddToString (CGI->arth->artifacts[bl->front()->sid]->Name()+" %+d", descr, bl->totalValue());
//TODO: player bonuses
if(vstd::contains(town->builtBuildings, Buildings::GRAIL)) //grail - +50% to ALL growth
summ+=AddToString(CGI->buildh->buildings[town->subID][Buildings::GRAIL]->Name()+" %+d",descr,summ/2);
summ+=AddToString(CGI->generaltexth->allTexts[63] + " %+d",descr, creature->valOfBonuses(Bonus::CREATURE_GROWTH));
descr +="\n" + entry.description;
}
return descr;
}

View File

@ -502,8 +502,22 @@ void CArtHandler::giveArtBonus( int aid, Bonus::BonusType type, int val, int sub
Bonus *added = new Bonus(Bonus::PERMANENT,type,Bonus::ARTIFACT,val,aid,subtype);
added->valType = valType;
added->limiter.reset(limiter);
if(type == Bonus::MORALE || Bonus::LUCK)
if(type == Bonus::MORALE || type == Bonus::LUCK)
added->description = artifacts[aid]->Name() + (val > 0 ? " +" : " ") + boost::lexical_cast<std::string>(val);
else
added->description = artifacts[aid]->Name();
artifacts[aid]->addNewBonus(added);
}
void CArtHandler::giveArtBonus(int aid, Bonus::BonusType type, int val, int subtype, IPropagator* propagator /*= NULL*/)
{
Bonus *added = new Bonus(Bonus::PERMANENT,type,Bonus::ARTIFACT,val,aid,subtype);
added->valType = Bonus::BASE_NUMBER;
added->propagator.reset(propagator);
if(type == Bonus::MORALE || type == Bonus::LUCK)
added->description = artifacts[aid]->Name() + (val > 0 ? " +" : " ") + boost::lexical_cast<std::string>(val);
else
added->description = artifacts[aid]->Name();
artifacts[aid]->addNewBonus(added);
}
@ -677,11 +691,11 @@ void CArtHandler::addBonuses()
giveArtBonus(116,Bonus::GENERATE_RESOURCE,+750, Res::GOLD); //Endless Bag of Gold
giveArtBonus(117,Bonus::GENERATE_RESOURCE,+500, Res::GOLD); //Endless Purse of Gold
giveArtBonus(118,Bonus::CREATURE_GROWTH,+5,1); //Legs of Legion
giveArtBonus(119,Bonus::CREATURE_GROWTH,+4,2); //Loins of Legion
giveArtBonus(120,Bonus::CREATURE_GROWTH,+3,3); //Torso of Legion
giveArtBonus(121,Bonus::CREATURE_GROWTH,+2,4); //Arms of Legion
giveArtBonus(122,Bonus::CREATURE_GROWTH,+1,5); //Head of Legion
giveArtBonus(118,Bonus::CREATURE_GROWTH,+5,1, new CPropagatorNodeType(CBonusSystemNode::TOWN_AND_VISITOR)); //Legs of Legion
giveArtBonus(119,Bonus::CREATURE_GROWTH,+4,2, new CPropagatorNodeType(CBonusSystemNode::TOWN_AND_VISITOR)); //Loins of Legion
giveArtBonus(120,Bonus::CREATURE_GROWTH,+3,3, new CPropagatorNodeType(CBonusSystemNode::TOWN_AND_VISITOR)); //Torso of Legion
giveArtBonus(121,Bonus::CREATURE_GROWTH,+2,4, new CPropagatorNodeType(CBonusSystemNode::TOWN_AND_VISITOR)); //Arms of Legion
giveArtBonus(122,Bonus::CREATURE_GROWTH,+1,5, new CPropagatorNodeType(CBonusSystemNode::TOWN_AND_VISITOR)); //Head of Legion
//Sea Captain's Hat
giveArtBonus(123,Bonus::WHIRLPOOL_PROTECTION,0);
@ -722,7 +736,7 @@ void CArtHandler::addBonuses()
giveArtBonus(132, Bonus::OPENING_BATTLE_SPELL, 50, 52); // Misfortune
// Statue of Legion - gives only 50% growth
giveArtBonus(133, Bonus::CREATURE_GROWTH_PERCENT, 50, -1);
giveArtBonus(133, Bonus::CREATURE_GROWTH_PERCENT, 50, -1, new CPropagatorNodeType(CBonusSystemNode::PLAYER));
//Power of the Dragon Father
giveArtBonus(134, Bonus::LEVEL_SPELL_IMMUNITY, 4, -1, Bonus::INDEPENDENT_MAX);
@ -880,7 +894,6 @@ CArtifactInstance::CArtifactInstance( CArtifact *Art)
{
init();
setType(Art);
}
// CArtifactInstance::CArtifactInstance(int aid)
@ -911,6 +924,7 @@ CArtifactInstance * CArtifactInstance::createScroll( const CSpell *s)
void CArtifactInstance::init()
{
id = -1;
setNodeType(ARTIFACT_INSTANCE);
}
int CArtifactInstance::firstAvailableSlot(const CGHeroInstance *h) const

View File

@ -198,6 +198,7 @@ public:
class DLL_EXPORT CArtHandler //handles artifacts
{
void giveArtBonus(int aid, Bonus::BonusType type, int val, int subtype = -1, int valType = Bonus::BASE_NUMBER, ILimiter * limiter = NULL);
void giveArtBonus(int aid, Bonus::BonusType type, int val, int subtype, IPropagator* propagator);
public:
std::vector<CArtifact*> treasures, minors, majors, relics;
std::vector< ConstTransitivePtr<CArtifact> > artifacts;

View File

@ -26,6 +26,7 @@
#include <boost/foreach.hpp>
#include <boost/format.hpp>
#include <boost/algorithm/string/trim.hpp>
#include "CBuildingHandler.h"
using namespace boost::assign;
@ -1871,49 +1872,64 @@ int CGTownInstance::getHordeLevel(const int & HID) const//HID - 0 or 1; returns
}
int CGTownInstance::creatureGrowth(const int & level) const
{
if (level<0 || level >=CREATURES_PER_TOWN)
return 0;
if (!vstd::contains(builtBuildings, Buildings::DWELL_FIRST+level))
return 0; //no dwelling
TCreature creid = town->basicCreatures[level];
int ret = VLC->creh->creatures[creid]->growth;
switch(fortLevel())
{
case 3:
ret*=2;break;
case 2:
ret*=(1.5); break;
}
ret *= (1 + VLC->creh->creatures[creid]->valOfBonuses(Bonus::CREATURE_GROWTH_PERCENT)/100); // double growth or plague
if(tempOwner != NEUTRAL_PLAYER)
{
ret *= (100.0f + cb->gameState()->players[tempOwner].valOfBonuses
(Selector::type(Bonus::CREATURE_GROWTH_PERCENT) && Selector::sourceType(Bonus::ARTIFACT)))/100; //Statue of Legion
for (std::vector<ConstTransitivePtr<CGDwelling> >::const_iterator it = cb->gameState()->players[tempOwner].dwellings.begin(); it != cb->gameState()->players[tempOwner].dwellings.end(); ++it)
{ //+1 for each dwelling
if (VLC->creh->creatures[creid]->idNumber == (*it)->creatures[0].second[0])
++ret;
}
}
if(getHordeLevel(0)==level)
if((builtBuildings.find(18)!=builtBuildings.end()) || (builtBuildings.find(19)!=builtBuildings.end()))
ret+=VLC->creh->creatures[creid]->hordeGrowth;
if(getHordeLevel(1)==level)
if((builtBuildings.find(24)!=builtBuildings.end()) || (builtBuildings.find(25)!=builtBuildings.end()))
ret+=VLC->creh->creatures[creid]->hordeGrowth;
//support for legs of legion etc.
if(garrisonHero)
ret += garrisonHero->valOfBonuses(Bonus::CREATURE_GROWTH, level);
if(visitingHero)
ret += visitingHero->valOfBonuses(Bonus::CREATURE_GROWTH, level);
if(builtBuildings.find(26)!=builtBuildings.end()) //grail - +50% to ALL growth
ret*=1.5;
//spcecial week unaffected by grail (bug in original game?)
ret += VLC->creh->creatures[creid]->valOfBonuses(Bonus::CREATURE_GROWTH);
return ret;//check CCastleInterface.cpp->CCastleInterface::CCreaInfo::clickRight if this one will be modified
return getGrowthInfo(level).totalGrowth();
}
GrowthInfo CGTownInstance::getGrowthInfo(int level) const
{
GrowthInfo ret;
if (level<0 || level >=CREATURES_PER_TOWN)
return ret;
if (!vstd::contains(builtBuildings, Buildings::DWELL_FIRST+level))
return ret; //no dwelling
const CCreature *creature = VLC->creh->creatures[town->basicCreatures[level]];
const int base = creature->growth;
int castleBonus = 0;
ret.entries.push_back(GrowthInfo::Entry(VLC->generaltexth->allTexts[590], base));// \n\nBasic growth %d"
if ( vstd::contains(builtBuildings, Buildings::CASTLE))
ret.entries.push_back(GrowthInfo::Entry(subID, Buildings::CASTLE, castleBonus = base));
else if ( vstd::contains(builtBuildings, Buildings::CITADEL))
ret.entries.push_back(GrowthInfo::Entry(subID, Buildings::CITADEL, castleBonus = base / 2));
if(town->hordeLvl[0] == level)//horde 1
if( vstd::contains(builtBuildings, Buildings::HORDE_1) || vstd::contains(builtBuildings, Buildings::HORDE_1_UPGR))
ret.entries.push_back(GrowthInfo::Entry(subID, Buildings::HORDE_1, creature->hordeGrowth));
if(town->hordeLvl[1] == level)//horde 2
if(vstd::contains(builtBuildings, Buildings::HORDE_2) || vstd::contains(builtBuildings, Buildings::HORDE_2_UPGR))
ret.entries.push_back(GrowthInfo::Entry(subID, Buildings::HORDE_2, creature->hordeGrowth));
int dwellingBonus = 0;
if(const PlayerState *p = cb->getPlayer(tempOwner, false))
{
BOOST_FOREACH(const CGDwelling *dwelling, p->dwellings)
if(creature->idNumber == dwelling->creatures[0].second[0])
dwellingBonus++;
}
if(dwellingBonus)
ret.entries.push_back(GrowthInfo::Entry(VLC->generaltexth->allTexts[591], dwellingBonus));// \nExternal dwellings %+d
//other *-of-legion-like bonuses (%d to growth cumulative with grail)
boost::shared_ptr<BonusList> bonuses = getBonuses(Selector::type(Bonus::CREATURE_GROWTH) && Selector::subtype(level));
BOOST_FOREACH(const Bonus *b, *bonuses)
ret.entries.push_back(GrowthInfo::Entry(b->Description() + " %+d", b->val));
//statue-of-legion-like bonus: % to base+castle
boost::shared_ptr<BonusList> bonuses2 = getBonuses(Selector::type(Bonus::CREATURE_GROWTH_PERCENT));
BOOST_FOREACH(const Bonus *b, *bonuses2)
ret.entries.push_back(GrowthInfo::Entry(b->Description() + " %+d", b->val * (base + castleBonus) / 100));
if(vstd::contains(builtBuildings, Buildings::GRAIL)) //grail - +50% to ALL (so far added) growth
ret.entries.push_back(GrowthInfo::Entry(subID, Buildings::GRAIL, ret.totalGrowth() / 2));
return ret;
}
int CGTownInstance::dailyIncome() const
{
int ret = 0;
@ -7070,3 +7086,29 @@ void CGUniversity::onHeroVisit(const CGHeroInstance * h) const
ow.window = OpenWindow::UNIVERSITY_WINDOW;
cb->sendAndApply(&ow);
}
GrowthInfo::Entry::Entry(const std::string &format, int _count)
: count(_count)
{
description = boost::str(boost::format(format) % count);
}
GrowthInfo::Entry::Entry(int subID, Buildings::EBuilding building, int _count)
: count(_count)
{
description = boost::str(boost::format("%s %+d") % VLC->buildh->buildings[subID][building]->Name() % count);
}
CTownAndVisitingHero::CTownAndVisitingHero()
{
setNodeType(TOWN_AND_VISITOR);
}
int GrowthInfo::totalGrowth() const
{
int ret = 0;
BOOST_FOREACH(const Entry &entry, entries)
ret += entry.count;
return ret;
}

View File

@ -519,6 +519,22 @@ public:
class DLL_EXPORT CTownAndVisitingHero : public CBonusSystemNode
{
public:
CTownAndVisitingHero();
};
struct DLL_EXPORT GrowthInfo
{
struct Entry
{
int count;
std::string description;
Entry(const std::string &format, int _count);
Entry(int subID, Buildings::EBuilding building, int _count);
};
std::vector<Entry> entries;
int totalGrowth() const;
};
class DLL_EXPORT CGTownInstance : public CGDwelling, public IShipyard, public IMarket
@ -591,6 +607,7 @@ public:
bool creatureDwelling(const int & level, bool upgraded=false) const;
int getHordeLevel(const int & HID) const; //HID - 0 or 1; returns creature level or -1 if that horde structure is not present
int creatureGrowth(const int & level) const;
GrowthInfo getGrowthInfo(int level) const;
bool hasFort() const;
bool hasCapitol() const;
int dailyIncome() const; //calculates daily income of this town

View File

@ -587,7 +587,7 @@ public:
}
enum ENodeTypes
{
UNKNOWN, STACK_INSTANCE, STACK_BATTLE, SPECIALITY, ARTIFACT, CREATURE, ARTIFACT_INSTANCE, HERO, PLAYER, TEAM
UNKNOWN, STACK_INSTANCE, STACK_BATTLE, SPECIALITY, ARTIFACT, CREATURE, ARTIFACT_INSTANCE, HERO, PLAYER, TEAM, TOWN_AND_VISITOR
};
};

View File

@ -950,7 +950,7 @@ struct HeroVisit : CPackForClient //531
struct NewTurn : public CPackForClient //101
{
enum weekType {NORMAL, DOUBLE_GROWTH, BONUS_GROWTH, DEITYOFFIRE, PLAGUE, CUSTOM, NO_ACTION, NONE};
enum weekType {NORMAL, DOUBLE_GROWTH, BONUS_GROWTH, DEITYOFFIRE, PLAGUE, NO_ACTION};
void applyCl(CClient *cl);
DLL_EXPORT void applyGs(CGameState *gs);

View File

@ -766,65 +766,23 @@ DLL_EXPORT void NewTurn::applyGs( CGameState *gs )
BOOST_FOREACH(SetAvailableCreatures h, cres) //set available creatures in towns
h.applyGs(gs);
if (specialWeek != NO_ACTION) //first pack applied, reset all effects and aplly new
gs->globalEffects.popBonuses(Bonus::OneDay); //works for children -> all game objs
if(gs->getDate(1)) //new week
gs->globalEffects.popBonuses(Bonus::OneWeek); //works for children -> all game objs
//TODO not really a single root hierarchy, what about bonuses placed elsewhere? [not an issue with H3 mechanics but in the future...]
//count days without town
for( std::map<ui8, PlayerState>::iterator i=gs->players.begin() ; i!=gs->players.end();i++)
{
//TODO? won't work for battles lasting several turns (not an issue now but...)
gs->globalEffects.popBonuses(Bonus::OneDay); //works for children -> all game objs
if(gs->getDate(1)) //new week, Monday that is
{
gs->globalEffects.popBonuses(Bonus::OneWeek); //works for children -> all game objs
Bonus *b = new Bonus();
b->duration = Bonus::ONE_WEEK;
b->source = Bonus::SPECIAL_WEEK;
b->effectRange = Bonus::NO_LIMIT;
b->valType = Bonus::BASE_NUMBER; //certainly not intuitive
switch (specialWeek)
{
case DOUBLE_GROWTH:
b->val = 100;
b->type = Bonus::CREATURE_GROWTH_PERCENT;
b->limiter.reset(new CCreatureTypeLimiter(*VLC->creh->creatures[creatureid], false));
break;
case BONUS_GROWTH:
b->val = 5;
b->type = Bonus::CREATURE_GROWTH;
b->limiter.reset(new CCreatureTypeLimiter(*VLC->creh->creatures[creatureid], false));
break;
case DEITYOFFIRE:
b->val = 15;
b->type = Bonus::CREATURE_GROWTH;
b->limiter.reset(new CCreatureTypeLimiter(*VLC->creh->creatures[42], true));
break;
case PLAGUE:
b->val = -100; //no basic creatures
b->type = Bonus::CREATURE_GROWTH_PERCENT;
break;
default:
b->val = 0;
}
if (b->val)
gs->globalEffects.addNewBonus(b);
}
}
else //second pack is applied
{
//count days without town
for( std::map<ui8, PlayerState>::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++;
}
if(resetBuilded) //reset amount of structures set in this turn in towns
{
BOOST_FOREACH(CGTownInstance* t, gs->map->towns)
t->builded = 0;
}
if(i->second.towns.size() || gs->day == 1)
i->second.daysWithoutCastle = 0;
else
i->second.daysWithoutCastle++;
}
BOOST_FOREACH(CGTownInstance* t, gs->map->towns)
t->builded = 0;
}
DLL_EXPORT void SetObjectProperty::applyGs( CGameState *gs )

View File

@ -853,55 +853,70 @@ void CGameHandler::newTurn()
{
tlog5 << "Turn " << gs->day+1 << std::endl;
NewTurn n;
n.specialWeek = NewTurn::NO_ACTION;
n.creatureid = -1;
n.day = gs->day + 1;
n.resetBuilded = true;
bool newmonth = false;
bool firstTurn = !getDate(0);
bool newWeek = getDate(1) == 7; //day numbers are confusing, as day was not yet switched
bool newMonth = getDate(4) == 28;
std::map<ui8, si32> hadGold;//starting gold - for buildings like dwarven treasury
srand(time(NULL));
if (getDate(1) == 7 && getDate(0)>1) //new week (day numbers are confusing, as day was not yet switched)
if (newWeek && !firstTurn)
{
int monthType = rand()%100;
if(getDate(4) == 28) //new month
n.specialWeek = NewTurn::NORMAL;
bool deityOfFireBuilt = false;
BOOST_FOREACH(const CGTownInstance *t, gs->map->towns)
{
newmonth = true;
if (monthType < 40) //double growth
if(t->subID == 3 && vstd::contains(t->builtBuildings, Buildings::GRAIL))
{
n.specialWeek = NewTurn::DOUBLE_GROWTH;
if (ALLCREATURESGETDOUBLEMONTHS)
deityOfFireBuilt = true;
break;
}
}
if(deityOfFireBuilt)
{
n.specialWeek = NewTurn::DEITYOFFIRE;
n.creatureid = 42;
}
else
{
int monthType = rand()%100;
if(newMonth) //new month
{
if (monthType < 40) //double growth
{
std::pair<int,int> newMonster(54, VLC->creh->pickRandomMonster(boost::ref(rand)));
n.specialWeek = NewTurn::DOUBLE_GROWTH;
if (ALLCREATURESGETDOUBLEMONTHS)
{
std::pair<int,int> newMonster(54, VLC->creh->pickRandomMonster(boost::ref(rand)));
n.creatureid = newMonster.second;
}
else
{
std::set<TCreature>::const_iterator it = VLC->creh->doubledCreatures.begin();
std::advance (it, rand() % VLC->creh->doubledCreatures.size()); //picking random element of set is tiring
n.creatureid = *it;
}
}
else if (monthType < 50)
n.specialWeek = NewTurn::PLAGUE;
}
else //it's a week, but not full month
{
if (monthType < 25)
{
n.specialWeek = NewTurn::BONUS_GROWTH; //+5
std::pair<int,int> newMonster (54, VLC->creh->pickRandomMonster(boost::ref(rand)));
//TODO do not pick neutrals
n.creatureid = newMonster.second;
}
else
{
std::set<TCreature>::const_iterator it = VLC->creh->doubledCreatures.begin();
std::advance (it, rand() % VLC->creh->doubledCreatures.size()); //picking random elelemnt of set is tiring
n.creatureid = *it;
}
}
else if (monthType < 90)
n.specialWeek = NewTurn::NORMAL;
else
n.specialWeek = NewTurn::PLAGUE;
}
else //it's a week, but not full month
{
newmonth = false;
if (monthType < 25)
{
n.specialWeek = NewTurn::BONUS_GROWTH; //+5
std::pair<int,int> newMonster (54, VLC->creh->pickRandomMonster(boost::ref(rand)));
n.creatureid = newMonster.second;
}
else
n.specialWeek = NewTurn::NORMAL;
}
}
else
n.specialWeek = NewTurn::NO_ACTION; //don't remove bonuses
bmap<ui32, ConstTransitivePtr<CGHeroInstance> > pool = gs->hpool.heroesPool;
@ -915,7 +930,7 @@ void CGameHandler::newTurn()
std::pair<ui8,si32> playerGold(i->first,i->second.resources[Res::GOLD]);
hadGold.insert(playerGold);
if(gs->getDate(1)==7) //first day of week - new heroes in tavern
if(newWeek) //new heroes in tavern
{
SetAvailableHeroes sah;
sah.player = i->first;
@ -955,7 +970,7 @@ void CGameHandler::newTurn()
n.heroes.insert(hth);
if(gs->day) //not first day
if(!firstTurn) //not first day
{
n.res[i->first][Res::GOLD] += h->valOfBonuses(Selector::typeSubtype(Bonus::SECONDARY_SKILL_PREMY, CGHeroInstance::ESTATES)); //estates
@ -969,131 +984,113 @@ void CGameHandler::newTurn()
// townID, creatureID, amount
std::map<si32, std::map<si32, si32> > newCreas;//creatures that needs to be added by town events
for(std::vector<ConstTransitivePtr<CGTownInstance> >::iterator j = gs->map->towns.begin(); j!=gs->map->towns.end(); j++)//handle towns
BOOST_FOREACH(CGTownInstance *t, gs->map->towns)
{
ui8 player = (*j)->tempOwner;
if(gs->getDate(1)==7) //first day of week
ui8 player = t->tempOwner;
handleTownEvents(t, n, newCreas);
if(newWeek) //first day of week
{
if ((*j)->subID == 5 && vstd::contains((*j)->builtBuildings, 22))
setPortalDwelling(*j, true, (n.specialWeek == NewTurn::PLAGUE ? true : false)); //set creatures for Portal of Summoning
if(t->subID == 5 && vstd::contains(t->builtBuildings, Buildings::SPECIAL_3))
setPortalDwelling(t, true, (n.specialWeek == NewTurn::PLAGUE ? true : false)); //set creatures for Portal of Summoning
if ((**j).subID == 1 && gs->getDate(0) && player < PLAYER_LIMIT && vstd::contains((**j).builtBuildings, 22))//dwarven treasury
n.res[player][Res::GOLD] += hadGold[player]/10; //give 10% of starting gold
}
if(gs->day && player < PLAYER_LIMIT)//not the first day and town not neutral
{
////SetResources r;
//r.player = (**j).tempOwner;
if(vstd::contains((**j).builtBuildings, Buildings::RESOURCE_SILO)) //there is resource silo
if(!firstTurn)
if (t->subID == 1 && player < PLAYER_LIMIT && vstd::contains(t->builtBuildings, Buildings::SPECIAL_3))//dwarven treasury
n.res[player][Res::GOLD] += hadGold[player]/10; //give 10% of starting gold
SetAvailableCreatures sac;
sac.tid = t->id;
sac.creatures = t->creatures;
for (int k=0; k < CREATURES_PER_TOWN; k++) //creature growths
{
if((**j).town->primaryRes == 127) //we'll give wood and ore
if(t->creatureDwelling(k))//there is dwelling (k-level)
{
ui32 &availableCount = sac.creatures[k].first;
const CCreature *cre = VLC->creh->creatures[t->creatureDwelling(k, true) ? t->town->upgradedCreatures[k] : t->town->basicCreatures[k]];
if (n.specialWeek == NewTurn::PLAGUE)
availableCount = t->creatures[k].first / 2; //halve their number, no growth
else
{
if(firstTurn) //first day of game: use only basic growths
availableCount = cre->growth;
else
availableCount += t->creatureGrowth(k);
if(n.creatureid == cre->idNumber
|| n.specialWeek == NewTurn::DEITYOFFIRE && (cre->idNumber == 42 || cre->idNumber == 43))
{
if(n.specialWeek == NewTurn::DOUBLE_GROWTH)
availableCount *= 2;
else if(n.specialWeek == NewTurn::BONUS_GROWTH)
availableCount += 5;
else if(n.specialWeek == NewTurn::DEITYOFFIRE)
availableCount += 15;
}
}
}
}
//add creatures from town events
if (vstd::contains(newCreas, t->id))
for(std::map<si32, si32>::iterator i=newCreas[t->id].begin() ; i!=newCreas[t->id].end(); i++)
sac.creatures[i->first].first += i->second;
n.cres.push_back(sac);
}
if(!firstTurn && player < PLAYER_LIMIT)//not the first day and town not neutral
{
if(vstd::contains(t->builtBuildings, Buildings::RESOURCE_SILO)) //there is resource silo
{
if(t->town->primaryRes == 127) //we'll give wood and ore
{
n.res[player][Res::WOOD] ++;
n.res[player][Res::ORE] ++;
}
else
{
n.res[player][(**j).town->primaryRes] ++;;
n.res[player][t->town->primaryRes] ++;
}
}
n.res[player][Res::GOLD] += (**j).dailyIncome();
n.res[player][Res::GOLD] += t->dailyIncome();
}
handleTownEvents(*j, n, newCreas);
if (vstd::contains((**j).builtBuildings, Buildings::GRAIL))
if(vstd::contains(t->builtBuildings, Buildings::GRAIL) && t->subID == 2)
{
switch ((**j).subID)
{
case 2: // Skyship, probably easier to handle same as Veil of darkness
{ //do it every new day after veils apply
FoWChange fw;
fw.mode = 1;
fw.player = player;
getAllTiles(fw.tiles, player, -1, 0);
sendAndApply (&fw);
}
break;
case 3: //Deity of Fire
{
if (getDate(0) > 1)
{
n.specialWeek = NewTurn::DEITYOFFIRE; //spawn familiars on new month
n.creatureid = 42; //familiar
}
}
break;
}
// Skyship, probably easier to handle same as Veil of darkness
//do it every new day after veils apply
FoWChange fw;
fw.mode = 1;
fw.player = player;
getAllTiles(fw.tiles, player, -1, 0);
sendAndApply (&fw);
}
if ((**j).hasBonusOfType (Bonus::DARKNESS))
if (t->hasBonusOfType (Bonus::DARKNESS))
{
(**j).hideTiles((**j).getOwner(), (**j).getBonus(Selector::type(Bonus::DARKNESS))->val);
t->hideTiles(t->getOwner(), t->getBonus(Selector::type(Bonus::DARKNESS))->val);
}
//unhiding what shouldn't be hidden? //that's handled in netpacks client
}
if(getDate(2) == 1) //first week
if(newMonth)
{
SetAvailableArtifacts saa;
saa.id = -1;
pickAllowedArtsSet(saa.arts);
sendAndApply(&saa);
}
sendAndApply(&n);
if (gs->getDate(1)==1) //first day of week, day has already been changed
if(newWeek)
{
if (getDate(4) == 1 && (n.specialWeek == NewTurn::DOUBLE_GROWTH || n.specialWeek == NewTurn::DEITYOFFIRE))
{ //spawn wandering monsters
std::vector<int3>::iterator tile;
std::vector<int3> tiles;
getFreeTiles(tiles);
ui32 amount = (tiles.size()) >> 6;
std::random_shuffle(tiles.begin(), tiles.end(), p_myrandom);
tlog5 << "Spawning wandering monsters. Found " << tiles.size() << " free tiles. Creature type: " << n.creatureid << std::endl;
const CCreature *cre = VLC->creh->creatures[n.creatureid];
for (int i = 0; i < amount; ++i)
{
tile = tiles.begin();
tlog5 << "\tSpawning monster at " << *tile << std::endl;
putNewMonster(n.creatureid, cre->getRandomAmount(std::rand), *tile);
tiles.erase(tile); //not use it again
}
//spawn wandering monsters
if (newMonth && (n.specialWeek == NewTurn::DOUBLE_GROWTH || n.specialWeek == NewTurn::DEITYOFFIRE))
{
spawnWanderingMonsters(n.creatureid);
}
NewTurn n2; //just to handle creature growths after bonuses are applied
n2.specialWeek = NewTurn::NO_ACTION;
n2.day = gs->day;
n2.resetBuilded = true;
for(std::vector<ConstTransitivePtr<CGTownInstance> >::iterator j = gs->map->towns.begin(); j!=gs->map->towns.end(); j++)//handle towns
//new week info popup
if(!firstTurn)
{
SetAvailableCreatures sac;
sac.tid = (**j).id;
sac.creatures = (**j).creatures;
for (int k=0; k < CREATURES_PER_TOWN; k++) //creature growths
{
if((**j).creatureDwelling(k))//there is dwelling (k-level)
{
if (n.specialWeek == NewTurn::PLAGUE)
sac.creatures[k].first = (**j).creatures[k].first / 2; //halve their number, no growth
else
{
sac.creatures[k].first += (**j).creatureGrowth(k);
if(gs->getDate(0) == 1) //first day of game: use only basic growths
amin(sac.creatures[k].first, VLC->creh->creatures[(*j)->town->basicCreatures[k]]->growth);
}
}
}
//creatures from town events
if (vstd::contains(newCreas, (**j).id))
for(std::map<si32, si32>::iterator i=newCreas[(**j).id].begin() ; i!=newCreas[(**j).id].end(); i++)
sac.creatures[i->first].first += i->second;
n2.cres.push_back(sac);
}
if (gs->getDate(0) > 1)
{
InfoWindow iw; //new week info
InfoWindow iw;
switch (n.specialWeek)
{
case NewTurn::DOUBLE_GROWTH:
@ -1118,7 +1115,7 @@ void CGameHandler::newTurn()
iw.text.addReplacement2(15); //%+d 15
break;
default:
iw.text.addTxt(MetaString::ARRAY_TXT, (newmonth ? 130 : 133));
iw.text.addTxt(MetaString::ARRAY_TXT, (newMonth ? 130 : 133));
iw.text.addReplacement(MetaString::ARRAY_TXT, 43 + rand()%15);
}
for (std::map<ui8, PlayerState>::iterator i=gs->players.begin() ; i!=gs->players.end(); i++)
@ -1127,9 +1124,8 @@ void CGameHandler::newTurn()
sendAndApply(&iw);
}
}
sendAndApply(&n2);
}
tlog5 << "Info about turn " << n.day << "has been sent!" << std::endl;
handleTimeEvents();
//call objects
@ -3884,6 +3880,7 @@ void CGameHandler::handleTimeEvents()
void CGameHandler::handleTownEvents(CGTownInstance * town, NewTurn &n, std::map<si32, std::map<si32, si32> > &newCreas)
{
//TODO event removing desync!!!
town->events.sort(evntCmp);
while(town->events.size() && town->events.front()->firstOccurence == gs->day)
{
@ -5208,6 +5205,23 @@ void CGameHandler::commitPackage( CPackForClient *pack )
sendAndApply(pack);
}
void CGameHandler::spawnWanderingMonsters(int creatureID)
{
std::vector<int3>::iterator tile;
std::vector<int3> tiles;
getFreeTiles(tiles);
ui32 amount = (tiles.size()) >> 6;
std::random_shuffle(tiles.begin(), tiles.end(), p_myrandom);
tlog5 << "Spawning wandering monsters. Found " << tiles.size() << " free tiles. Creature type: " << creatureID << std::endl;
const CCreature *cre = VLC->creh->creatures[creatureID];
for (int i = 0; i < amount; ++i)
{
tile = tiles.begin();
tlog5 << "\tSpawning monster at " << *tile << std::endl;
putNewMonster(creatureID, cre->getRandomAmount(std::rand), *tile);
tiles.erase(tile); //not use it again
}
}
CasualtiesAfterBattle::CasualtiesAfterBattle(const CArmedInstance *army, BattleInfo *bat)
{
int color = army->tempOwner;

View File

@ -254,6 +254,7 @@ public:
void handleAfterAttackCasting (const BattleAttack & bat);
void attackCasting(const BattleAttack & bat, Bonus::BonusType attackMode, const CStack * attacker);
bool sacrificeArtifact(const IMarket * m, const CGHeroInstance * hero, int slot);
void spawnWanderingMonsters(int creatureID);
friend class CVCMIServer;
friend class CScriptCallback;
};