1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-27 22:49:25 +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

@@ -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;