mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Merge branch 'develop' into SpellsRefactoring8
This commit is contained in:
commit
ea2e336f54
@ -697,7 +697,9 @@ void VCAI::showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *do
|
||||
//you can't request action from action-response thread
|
||||
requestActionASAP([=]()
|
||||
{
|
||||
pickBestCreatures (down, up);
|
||||
if(removableUnits)
|
||||
pickBestCreatures(down, up);
|
||||
|
||||
answerQuery(queryID, 0);
|
||||
});
|
||||
}
|
||||
|
@ -248,7 +248,8 @@ int main(int argc, char** argv)
|
||||
("loadserverip",po::value<std::string>(),"IP for loaded game server")
|
||||
("loadserverport",po::value<std::string>(),"port for loaded game server")
|
||||
("testingport",po::value<std::string>(),"port for testing, override specified in config file")
|
||||
("testingfileprefix",po::value<std::string>(),"prefix for auto save files");
|
||||
("testingfileprefix",po::value<std::string>(),"prefix for auto save files")
|
||||
("testingsavefrequency",po::value<int>(),"how often auto save should be created");
|
||||
|
||||
if(argc > 1)
|
||||
{
|
||||
@ -313,6 +314,7 @@ int main(int argc, char** argv)
|
||||
testingSettings["enabled"].Bool() = true;
|
||||
testingSettings["port"].String() = vm["testingport"].as<std::string>();
|
||||
testingSettings["prefix"].String() = vm["testingfileprefix"].as<std::string>();
|
||||
testingSettings["savefrequency"].Float() = vm.count("testingsavefrequency") ? vm["testingsavefrequency"].as<int>() : 1;
|
||||
}
|
||||
|
||||
// Initialize logging based on settings
|
||||
|
@ -178,7 +178,7 @@ void CPlayerInterface::yourTurn()
|
||||
}
|
||||
firstCall = 0;
|
||||
}
|
||||
else
|
||||
else if(settings["testing"].isNull() || cb->getDate() % static_cast<int>(settings["testing"]["savefrequency"].Float()) == 0)
|
||||
{
|
||||
LOCPLINT->cb->save("Saves/" + prefix + "Autosave_" + boost::lexical_cast<std::string>(autosaveCount++ + 1));
|
||||
autosaveCount %= 5;
|
||||
|
@ -699,7 +699,10 @@ CSelectionScreen::CSelectionScreen(CMenuScreen::EState Type, CMenuScreen::EMulti
|
||||
if(isHost())
|
||||
{
|
||||
assert(playerNames.size() == 1 && vstd::contains(playerNames, 1)); //TODO hot-seat/network combo
|
||||
serv = sh->connectToServer();
|
||||
if(CServerHandler::DO_NOT_START_SERVER)
|
||||
serv = CServerHandler::justConnectToServer(Address, Port);
|
||||
else
|
||||
serv = sh->connectToServer();
|
||||
*serv << (ui8) 4;
|
||||
myNameID = 1;
|
||||
}
|
||||
@ -3129,14 +3132,17 @@ void CMultiMode::hostTCP()
|
||||
Settings name = settings.write["general"]["playerName"];
|
||||
name->String() = txt->text;
|
||||
GH.popIntTotally(this);
|
||||
GH.pushInt(new CSelectionScreen(CMenuScreen::newGame, CMenuScreen::MULTI_NETWORK_HOST));
|
||||
if(CServerHandler::DO_NOT_START_SERVER)
|
||||
GH.pushInt(new CSimpleJoinScreen(CMenuScreen::MULTI_NETWORK_HOST));
|
||||
else
|
||||
GH.pushInt(new CSelectionScreen(CMenuScreen::newGame, CMenuScreen::MULTI_NETWORK_HOST));
|
||||
}
|
||||
|
||||
void CMultiMode::joinTCP()
|
||||
{
|
||||
Settings name = settings.write["general"]["playerName"];
|
||||
name->String() = txt->text;
|
||||
GH.pushInt(new CSimpleJoinScreen);
|
||||
GH.pushInt(new CSimpleJoinScreen(CMenuScreen::MULTI_NETWORK_GUEST));
|
||||
}
|
||||
|
||||
CHotSeatPlayers::CHotSeatPlayers(const std::string &firstPlayer)
|
||||
@ -4273,7 +4279,7 @@ void CPrologEpilogVideo::clickLeft( tribool down, bool previousState )
|
||||
exitCb();
|
||||
}
|
||||
|
||||
CSimpleJoinScreen::CSimpleJoinScreen()
|
||||
CSimpleJoinScreen::CSimpleJoinScreen(CMenuScreen::EMultiMode mode)
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
bg = new CPicture("MUDIALOG.bmp"); // address background
|
||||
@ -4289,7 +4295,7 @@ CSimpleJoinScreen::CSimpleJoinScreen()
|
||||
port->cb += std::bind(&CSimpleJoinScreen::onChange, this, _1);
|
||||
port->filters += std::bind(&CTextInput::numberFilter, _1, _2, 0, 65535);
|
||||
|
||||
ok = new CButton(Point( 26, 142), "MUBCHCK.DEF", CGI->generaltexth->zelp[560], std::bind(&CSimpleJoinScreen::enterSelectionScreen, this), SDLK_RETURN);
|
||||
ok = new CButton(Point( 26, 142), "MUBCHCK.DEF", CGI->generaltexth->zelp[560], std::bind(&CSimpleJoinScreen::enterSelectionScreen, this, mode), SDLK_RETURN);
|
||||
cancel = new CButton(Point(142, 142), "MUBCANC.DEF", CGI->generaltexth->zelp[561], std::bind(&CGuiHandler::popIntTotally, std::ref(GH), this), SDLK_ESCAPE);
|
||||
bar = new CGStatusBar(new CPicture(Rect(7, 186, 218, 18), 0));
|
||||
|
||||
@ -4298,15 +4304,15 @@ CSimpleJoinScreen::CSimpleJoinScreen()
|
||||
address->giveFocus();
|
||||
}
|
||||
|
||||
void CSimpleJoinScreen::enterSelectionScreen()
|
||||
void CSimpleJoinScreen::enterSelectionScreen(CMenuScreen::EMultiMode mode)
|
||||
{
|
||||
std::string textAddress = address->text;
|
||||
std::string textPort = port->text;
|
||||
|
||||
GH.popIntTotally(this);
|
||||
GH.pushInt(new CSelectionScreen(CMenuScreen::newGame, CMenuScreen::MULTI_NETWORK_GUEST, nullptr, textAddress, textPort));
|
||||
}
|
||||
|
||||
GH.pushInt(new CSelectionScreen(CMenuScreen::newGame, mode, nullptr, textAddress, textPort));
|
||||
}
|
||||
void CSimpleJoinScreen::onChange(const std::string & newText)
|
||||
{
|
||||
ok->block(address->text.empty() || port->text.empty());
|
||||
|
@ -642,10 +642,10 @@ class CSimpleJoinScreen : public CIntObject
|
||||
CTextInput * address;
|
||||
CTextInput * port;
|
||||
|
||||
void enterSelectionScreen();
|
||||
void enterSelectionScreen(CMenuScreen::EMultiMode mode);
|
||||
void onChange(const std::string & newText);
|
||||
public:
|
||||
CSimpleJoinScreen();
|
||||
CSimpleJoinScreen(CMenuScreen::EMultiMode mode);
|
||||
};
|
||||
|
||||
extern ISelectionScreenInfo *SEL;
|
||||
|
@ -285,7 +285,7 @@ void CClient::loadGame(const std::string & fname, const bool server, const std::
|
||||
|
||||
if(clientSaveName.empty())
|
||||
throw std::runtime_error("Cannot open client part of " + fname);
|
||||
if(controlServerSaveName.empty())
|
||||
if(controlServerSaveName.empty() || !boost::filesystem::exists(controlServerSaveName))
|
||||
throw std::runtime_error("Cannot open server part of " + fname);
|
||||
|
||||
{
|
||||
|
@ -344,6 +344,12 @@ void CHeroWindow::commanderWindow()
|
||||
|
||||
}
|
||||
|
||||
void CHeroWindow::updateGarrisons()
|
||||
{
|
||||
CWindowWithGarrison::updateGarrisons();
|
||||
morale->set(&heroWArt);
|
||||
}
|
||||
|
||||
void CHeroWindow::showAll(SDL_Surface * to)
|
||||
{
|
||||
CIntObject::showAll(to);
|
||||
|
@ -91,6 +91,7 @@ public:
|
||||
void questlog(); //show quest log in hero window
|
||||
void commanderWindow();
|
||||
void switchHero(); //changes displayed hero
|
||||
virtual void updateGarrisons() override; //updates the morale widget and calls the parent
|
||||
|
||||
//friends
|
||||
friend void CArtPlace::clickLeft(tribool down, bool previousState);
|
||||
|
@ -151,7 +151,7 @@
|
||||
"mirror" :
|
||||
{
|
||||
"type" : "MAGIC_MIRROR",
|
||||
"val" : 30
|
||||
"val" : 20
|
||||
},
|
||||
"casts" :
|
||||
{
|
||||
|
@ -432,8 +432,10 @@ ui8 CBattleInfoEssentials::battleGetSiegeLevel() const
|
||||
bool CBattleInfoEssentials::battleCanSurrender(PlayerColor player) const
|
||||
{
|
||||
RETURN_IF_NOT_BATTLE(false);
|
||||
//conditions like for fleeing + enemy must have a hero
|
||||
return battleCanFlee(player) && battleHasHero(!playerToSide(player));
|
||||
ui8 mySide = playerToSide(player);
|
||||
bool iAmSiegeDefender = ( mySide == BattleSide::DEFENDER && battleGetSiegeLevel() );
|
||||
//conditions like for fleeing (except escape tunnel presence) + enemy must have a hero
|
||||
return battleCanFlee(player) && !iAmSiegeDefender && battleHasHero(!mySide);
|
||||
}
|
||||
|
||||
bool CBattleInfoEssentials::battleHasHero(ui8 side) const
|
||||
|
@ -255,7 +255,8 @@ void CGHeroInstance::setType(si32 ID, si32 subID)
|
||||
assert(ID == Obj::HERO); // just in case
|
||||
type = VLC->heroh->heroes[subID];
|
||||
portrait = type->imageIndex;
|
||||
CGObjectInstance::setType(ID, type->heroClass->id);
|
||||
CGObjectInstance::setType(ID, type->heroClass->id); // to find object handler we must use heroClass->id
|
||||
this->subID = subID; // after setType subID used to store unique hero identify id. Check issue 2277 for details
|
||||
randomizeArmy(type->heroClass->faction);
|
||||
}
|
||||
|
||||
|
@ -65,35 +65,49 @@ void CGPandoraBox::giveContentsUpToExp(const CGHeroInstance *h) const
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::pair<SecondarySkill, ui8>> unpossessedAbilities; //ability + ability level
|
||||
int abilitiesRequiringSlot = 0;
|
||||
|
||||
if(gainedExp || changesPrimSkill || abilities.size())
|
||||
//filter out unnecessary secondary skills
|
||||
for (int i = 0; i < abilities.size(); i++)
|
||||
{
|
||||
int curLev = h->getSecSkillLevel(abilities[i]);
|
||||
bool abilityCanUseSlot = !curLev && ((h->secSkills.size() + abilitiesRequiringSlot) < GameConstants::SKILL_PER_HERO); //limit new abilities to number of slots
|
||||
|
||||
if (abilityCanUseSlot)
|
||||
abilitiesRequiringSlot++;
|
||||
|
||||
if ((curLev && curLev < abilityLevels[i]) || abilityCanUseSlot)
|
||||
{
|
||||
unpossessedAbilities.push_back({ abilities[i], abilityLevels[i] });
|
||||
}
|
||||
}
|
||||
|
||||
if(gainedExp || changesPrimSkill || unpossessedAbilities.size())
|
||||
{
|
||||
TExpType expVal = h->calculateXp(gainedExp);
|
||||
//getText(iw,afterBattle,175,h); //wtf?
|
||||
iw.text.addTxt(MetaString::ADVOB_TXT, 175); //%s learns something
|
||||
iw.text.addReplacement(h->name);
|
||||
|
||||
|
||||
if(expVal)
|
||||
iw.components.push_back(Component(Component::EXPERIENCE,0,expVal,0));
|
||||
|
||||
for(int i=0; i<primskills.size(); i++)
|
||||
if(primskills[i])
|
||||
iw.components.push_back(Component(Component::PRIM_SKILL,i,primskills[i],0));
|
||||
|
||||
for(int i=0; i<abilities.size(); i++)
|
||||
iw.components.push_back(Component(Component::SEC_SKILL,abilities[i],abilityLevels[i],0));
|
||||
|
||||
for(auto abilityData : unpossessedAbilities)
|
||||
iw.components.push_back(Component(Component::SEC_SKILL, abilityData.first, abilityData.second, 0));
|
||||
|
||||
cb->showInfoDialog(&iw);
|
||||
|
||||
//give sec skills
|
||||
for(int i=0; i<abilities.size(); i++)
|
||||
{
|
||||
int curLev = h->getSecSkillLevel(abilities[i]);
|
||||
for (auto abilityData : unpossessedAbilities)
|
||||
cb->changeSecSkill(h, abilityData.first, abilityData.second, true);
|
||||
|
||||
if( (curLev && curLev < abilityLevels[i]) || (h->canLearnSkill() ))
|
||||
{
|
||||
cb->changeSecSkill(h,abilities[i],abilityLevels[i],true);
|
||||
}
|
||||
}
|
||||
assert(h->secSkills.size() <= GameConstants::SKILL_PER_HERO);
|
||||
|
||||
//give prim skills
|
||||
for(int i=0; i<primskills.size(); i++)
|
||||
@ -106,6 +120,7 @@ void CGPandoraBox::giveContentsUpToExp(const CGHeroInstance *h) const
|
||||
if(expVal)
|
||||
cb->changePrimSkill(h, PrimarySkill::EXPERIENCE, expVal, false);
|
||||
}
|
||||
//else { } //TODO:Create information that box was empty for now, and deliver to CGPandoraBox::giveContentsAfterExp or refactor
|
||||
|
||||
if(!cb->isVisitCoveredByAnotherQuery(this, h))
|
||||
giveContentsAfterExp(h);
|
||||
|
@ -618,16 +618,16 @@ void CGTownInstance::initObj(CRandomGenerator & rand)
|
||||
|
||||
switch (subID)
|
||||
{ //add new visitable objects
|
||||
case 0:
|
||||
case ETownType::CASTLE:
|
||||
bonusingBuildings.push_back (new COPWBonus(BuildingID::STABLES, this));
|
||||
break;
|
||||
case 5:
|
||||
case ETownType::DUNGEON:
|
||||
bonusingBuildings.push_back (new COPWBonus(BuildingID::MANA_VORTEX, this));
|
||||
//fallthrough
|
||||
case 2: case 3: case 6:
|
||||
case ETownType::TOWER: case ETownType::INFERNO: case ETownType::STRONGHOLD:
|
||||
bonusingBuildings.push_back (new CTownBonus(BuildingID::SPECIAL_4, this));
|
||||
break;
|
||||
case 7:
|
||||
case ETownType::FORTRESS:
|
||||
bonusingBuildings.push_back (new CTownBonus(BuildingID::SPECIAL_1, this));
|
||||
break;
|
||||
}
|
||||
|
@ -867,10 +867,10 @@ void CGResource::initObj(CRandomGenerator & rand)
|
||||
{
|
||||
switch(subID)
|
||||
{
|
||||
case 6:
|
||||
amount = rand.nextInt(500, 1000);
|
||||
case Res::GOLD:
|
||||
amount = rand.nextInt(5, 10) * 100;
|
||||
break;
|
||||
case 0: case 2:
|
||||
case Res::WOOD: case Res::ORE:
|
||||
amount = rand.nextInt(6, 10);
|
||||
break;
|
||||
default:
|
||||
|
@ -1356,7 +1356,7 @@ static bool evntCmp(const CMapEvent &a, const CMapEvent &b)
|
||||
|
||||
void CGameHandler::setPortalDwelling(const CGTownInstance * town, bool forced=false, bool clear = false)
|
||||
{// bool forced = true - if creature should be replaced, if false - only if no creature was set
|
||||
const PlayerState *p = gs->getPlayer(town->tempOwner);
|
||||
const PlayerState * p = getPlayer(town->tempOwner);
|
||||
if(!p)
|
||||
{
|
||||
logGlobal->warn("There is no player owner of town %s at %s", town->name, town->pos());
|
||||
@ -1626,7 +1626,7 @@ void CGameHandler::newTurn()
|
||||
fw.mode = 1;
|
||||
fw.player = player;
|
||||
// find all hidden tiles
|
||||
const auto & fow = gs->getPlayerTeam(player)->fogOfWarMap;
|
||||
const auto & fow = getPlayerTeam(player)->fogOfWarMap;
|
||||
for (size_t i=0; i<fow.size(); i++)
|
||||
for (size_t j=0; j<fow.at(i).size(); j++)
|
||||
for (size_t k=0; k<fow.at(i).at(j).size(); k++)
|
||||
@ -1638,7 +1638,7 @@ void CGameHandler::newTurn()
|
||||
}
|
||||
if (t->hasBonusOfType (Bonus::DARKNESS))
|
||||
{
|
||||
for (auto & player : gameState()->players)
|
||||
for(auto & player : gs->players)
|
||||
{
|
||||
if (getPlayerStatus(player.first) == EPlayerStatus::INGAME &&
|
||||
getPlayerRelations(player.first, t->tempOwner) == PlayerRelations::ENEMIES)
|
||||
@ -1863,7 +1863,7 @@ void CGameHandler::setupBattle( int3 tile, const CArmedInstance *armies[2], cons
|
||||
{
|
||||
battleResult.set(nullptr);
|
||||
|
||||
const auto t = gs->getTile(tile);
|
||||
const auto t = getTile(tile);
|
||||
ETerrainType terrain = t->terType;
|
||||
if(gs->map->isCoastalTile(tile)) //coastal tile is always ground
|
||||
terrain = ETerrainType::SAND;
|
||||
@ -1972,7 +1972,7 @@ bool CGameHandler::moveHero( ObjectInstanceID hid, int3 dst, ui8 teleporting, bo
|
||||
return false;
|
||||
}
|
||||
|
||||
const TerrainTile t = *gs->getTile(hmpos);
|
||||
const TerrainTile t = *getTile(hmpos);
|
||||
const int3 guardPos = gs->guardingCreaturePosition(hmpos);
|
||||
|
||||
const bool embarking = !h->boat && !t.visitableObjects.empty() && t.visitableObjects.back()->ID == Obj::BOAT;
|
||||
@ -2181,7 +2181,7 @@ void CGameHandler::setOwner(const CGObjectInstance * obj, PlayerColor owner)
|
||||
|
||||
if (oldOwner < PlayerColor::PLAYER_LIMIT) //old owner is real player
|
||||
{
|
||||
if (gs->getPlayer(oldOwner)->towns.empty())//previous player lost last last town
|
||||
if(getPlayer(oldOwner)->towns.empty()) //previous player lost last last town
|
||||
{
|
||||
InfoWindow iw;
|
||||
iw.player = oldOwner;
|
||||
@ -2192,11 +2192,11 @@ void CGameHandler::setOwner(const CGObjectInstance * obj, PlayerColor owner)
|
||||
}
|
||||
}
|
||||
|
||||
const PlayerState * p = gs->getPlayer(owner);
|
||||
const PlayerState * p = getPlayer(owner);
|
||||
|
||||
if((obj->ID == Obj::CREATURE_GENERATOR1 || obj->ID == Obj::CREATURE_GENERATOR4 ) && p && p->dwellings.size()==1)//first dwelling captured
|
||||
{
|
||||
for(const CGTownInstance *t : gs->getPlayer(owner)->towns)
|
||||
for(const CGTownInstance * t : getPlayer(owner)->towns)
|
||||
{
|
||||
if (t->hasBuilt(BuildingID::PORTAL_OF_SUMMON, ETownType::DUNGEON))
|
||||
setPortalDwelling(t);//set initial creatures for all portals of summoning
|
||||
@ -2226,7 +2226,7 @@ void CGameHandler::giveResource(PlayerColor player, Res::ERes which, int val) //
|
||||
SetResource sr;
|
||||
sr.player = player;
|
||||
sr.resid = which;
|
||||
sr.val = gs->players.find(player)->second.resources.at(which) + val;
|
||||
sr.val = getPlayer(player)->resources.at(which) + val;
|
||||
sendAndApply(&sr);
|
||||
}
|
||||
|
||||
@ -2505,7 +2505,7 @@ void CGameHandler::heroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2)
|
||||
{
|
||||
auto h1 = getHero(hero1), h2 = getHero(hero2);
|
||||
|
||||
if( gameState()->getPlayerRelations(h1->getOwner(), h2->getOwner()))
|
||||
if(getPlayerRelations(h1->getOwner(), h2->getOwner()))
|
||||
{
|
||||
auto exchange = std::make_shared<CGarrisonDialogQuery>(h1, h2);
|
||||
ExchangeDialog hex;
|
||||
@ -2610,8 +2610,8 @@ void CGameHandler::close()
|
||||
|
||||
bool CGameHandler::arrangeStacks( ObjectInstanceID id1, ObjectInstanceID id2, ui8 what, SlotID p1, SlotID p2, si32 val, PlayerColor player )
|
||||
{
|
||||
const CArmedInstance *s1 = static_cast<CArmedInstance*>(gs->getObjInstance(id1)),
|
||||
*s2 = static_cast<CArmedInstance*>(gs->getObjInstance(id2));
|
||||
const CArmedInstance * s1 = static_cast<const CArmedInstance *>(getObjInstance(id1)),
|
||||
* s2 = static_cast<const CArmedInstance *>(getObjInstance(id2));
|
||||
const CCreatureSet &S1 = *s1, &S2 = *s2;
|
||||
StackLocation sl1(s1, p1), sl2(s2, p2);
|
||||
if(!sl1.slot.validSlot() || !sl2.slot.validSlot())
|
||||
@ -2626,6 +2626,21 @@ bool CGameHandler::arrangeStacks( ObjectInstanceID id1, ObjectInstanceID id2, ui
|
||||
return false;
|
||||
}
|
||||
|
||||
// We can always put stacks into locked garrison, but not take them out of it
|
||||
auto notRemovable = [&](const CArmedInstance * army)
|
||||
{
|
||||
if(id1 != id2) // Stack arrangement inside locked garrison is allowed
|
||||
{
|
||||
auto g = dynamic_cast<const CGGarrison *>(army);
|
||||
if(g && !g->removableUnits)
|
||||
{
|
||||
complain("Stacks in this garrison are not removable!\n");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if(what==1) //swap
|
||||
{
|
||||
if ( ((s1->tempOwner != player && s1->tempOwner != PlayerColor::UNFLAGGABLE) && s1->getStackCount(p1))
|
||||
@ -2641,6 +2656,16 @@ bool CGameHandler::arrangeStacks( ObjectInstanceID id1, ObjectInstanceID id2, ui
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!s1->slotEmpty(p1) && !s2->slotEmpty(p2))
|
||||
{
|
||||
if(notRemovable(sl1.army) || notRemovable(sl2.army))
|
||||
return false;
|
||||
}
|
||||
if(s1->slotEmpty(p1) && notRemovable(sl2.army))
|
||||
return false;
|
||||
else if(s2->slotEmpty(p2) && notRemovable(sl1.army))
|
||||
return false;
|
||||
|
||||
swapStacks(sl1, sl2);
|
||||
}
|
||||
else if(what==2)//merge
|
||||
@ -2649,6 +2674,14 @@ bool CGameHandler::arrangeStacks( ObjectInstanceID id1, ObjectInstanceID id2, ui
|
||||
|| (((s1->tempOwner != player && s1->tempOwner != PlayerColor::UNFLAGGABLE) && s2->getStackCount(p2)) && complain("Can't take troops from another player!")))
|
||||
return false;
|
||||
|
||||
if(s1->slotEmpty(p1) || s2->slotEmpty(p2))
|
||||
{
|
||||
complain("Cannot merge empty stack!");
|
||||
return false;
|
||||
}
|
||||
else if(notRemovable(sl1.army))
|
||||
return false;
|
||||
|
||||
moveStack(sl1, sl2);
|
||||
}
|
||||
else if(what==3) //split
|
||||
@ -2681,6 +2714,17 @@ bool CGameHandler::arrangeStacks( ObjectInstanceID id1, ObjectInstanceID id2, ui
|
||||
return false;
|
||||
}
|
||||
|
||||
if(notRemovable(sl1.army))
|
||||
{
|
||||
if(s1->getStackCount(p1) > countLeftOnSrc)
|
||||
return false;
|
||||
}
|
||||
else if(notRemovable(sl2.army))
|
||||
{
|
||||
if(s2->getStackCount(p1) < countLeftOnSrc)
|
||||
return false;
|
||||
}
|
||||
|
||||
moveStack(sl1, sl2, countToMove);
|
||||
//S2.slots[p2]->count = val;
|
||||
//S1.slots[p1]->count = total - val;
|
||||
@ -2693,6 +2737,8 @@ bool CGameHandler::arrangeStacks( ObjectInstanceID id1, ObjectInstanceID id2, ui
|
||||
return false;
|
||||
}
|
||||
|
||||
if(notRemovable(sl1.army))
|
||||
return false;
|
||||
|
||||
moveStack(sl1, sl2, val);
|
||||
}
|
||||
@ -2727,7 +2773,7 @@ PlayerColor CGameHandler::getPlayerAt( CConnection *c ) const
|
||||
|
||||
bool CGameHandler::disbandCreature( ObjectInstanceID id, SlotID pos )
|
||||
{
|
||||
CArmedInstance *s1 = static_cast<CArmedInstance*>(gs->getObjInstance(id));
|
||||
const CArmedInstance * s1 = static_cast<const CArmedInstance *>(getObjInstance(id));
|
||||
if(!vstd::contains(s1->stacks,pos))
|
||||
{
|
||||
complain("Illegal call to disbandCreature - no such stack in army!");
|
||||
@ -2760,7 +2806,7 @@ bool CGameHandler::buildStructure( ObjectInstanceID tid, BuildingID requestedID,
|
||||
switch (requestedBuilding->mode)
|
||||
{
|
||||
case CBuilding::BUILD_NORMAL :
|
||||
if (gs->canBuildStructure(t, requestedID) != EBuildingState::ALLOWED)
|
||||
if(canBuildStructure(t, requestedID) != EBuildingState::ALLOWED)
|
||||
COMPLAIN_RET("Cannot build that building!");
|
||||
break;
|
||||
|
||||
@ -2877,7 +2923,7 @@ bool CGameHandler::buildStructure( ObjectInstanceID tid, BuildingID requestedID,
|
||||
{
|
||||
SetResources sr;
|
||||
sr.player = t->tempOwner;
|
||||
sr.res = gs->getPlayer(t->tempOwner)->resources - requestedBuilding->resources;
|
||||
sr.res = getPlayer(t->tempOwner)->resources - requestedBuilding->resources;
|
||||
sendAndApply(&sr);
|
||||
}
|
||||
|
||||
@ -2935,7 +2981,7 @@ void CGameHandler::sendMessageToAll( const std::string &message )
|
||||
|
||||
bool CGameHandler::recruitCreatures(ObjectInstanceID objid, ObjectInstanceID dstid, CreatureID crid, ui32 cram, si32 fromLvl )
|
||||
{
|
||||
const CGDwelling *dw = static_cast<const CGDwelling*>(gs->getObj(objid));
|
||||
const CGDwelling * dw = static_cast<const CGDwelling *>(getObj(objid));
|
||||
const CArmedInstance *dst = nullptr;
|
||||
const CCreature *c = VLC->creh->creatures.at(crid);
|
||||
bool warMachine = c->hasBonusOfType(Bonus::SIEGE_WEAPON);
|
||||
@ -2970,7 +3016,7 @@ bool CGameHandler::recruitCreatures(ObjectInstanceID objid, ObjectInstanceID dst
|
||||
SlotID slot = dst->getSlotFor(crid);
|
||||
|
||||
if( (!found && complain("Cannot recruit: no such creatures!"))
|
||||
|| (cram > VLC->creh->creatures.at(crid)->maxAmount(gs->getPlayer(dst->tempOwner)->resources) && complain("Cannot recruit: lack of resources!"))
|
||||
|| (cram > VLC->creh->creatures.at(crid)->maxAmount(getPlayer(dst->tempOwner)->resources) && complain("Cannot recruit: lack of resources!"))
|
||||
|| (cram<=0 && complain("Cannot recruit: cram <= 0!"))
|
||||
|| (!slot.validSlot() && !warMachine && complain("Cannot recruit: no available slot!")))
|
||||
{
|
||||
@ -2980,7 +3026,7 @@ bool CGameHandler::recruitCreatures(ObjectInstanceID objid, ObjectInstanceID dst
|
||||
//recruit
|
||||
SetResources sr;
|
||||
sr.player = dst->tempOwner;
|
||||
sr.res = gs->getPlayer(dst->tempOwner)->resources - (c->cost * cram);
|
||||
sr.res = getPlayer(dst->tempOwner)->resources - (c->cost * cram);
|
||||
|
||||
SetAvailableCreatures sac;
|
||||
sac.tid = objid;
|
||||
@ -3021,12 +3067,13 @@ bool CGameHandler::recruitCreatures(ObjectInstanceID objid, ObjectInstanceID dst
|
||||
|
||||
bool CGameHandler::upgradeCreature( ObjectInstanceID objid, SlotID pos, CreatureID upgID )
|
||||
{
|
||||
CArmedInstance *obj = static_cast<CArmedInstance*>(gs->getObjInstance(objid));
|
||||
const CArmedInstance * obj = static_cast<const CArmedInstance *>(getObjInstance(objid));
|
||||
if (!obj->hasStackAtSlot(pos))
|
||||
{
|
||||
COMPLAIN_RET("Cannot upgrade, no stack at slot " + boost::to_string(pos));
|
||||
}
|
||||
UpgradeInfo ui = gs->getUpgradeInfo(obj->getStack(pos));
|
||||
UpgradeInfo ui;
|
||||
getUpgradeInfo(obj, pos, ui);
|
||||
PlayerColor player = obj->tempOwner;
|
||||
const PlayerState *p = getPlayer(player);
|
||||
int crQuantity = obj->stacks.at(pos)->count;
|
||||
@ -3100,7 +3147,7 @@ void CGameHandler::moveArmy(const CArmedInstance *src, const CArmedInstance *dst
|
||||
|
||||
bool CGameHandler::garrisonSwap( ObjectInstanceID tid )
|
||||
{
|
||||
CGTownInstance *town = gs->getTown(tid);
|
||||
const CGTownInstance * town = getTown(tid);
|
||||
if(!town->garrisonHero && town->visitingHero) //visiting => garrison, merge armies: town army => hero army
|
||||
{
|
||||
|
||||
@ -3218,8 +3265,7 @@ bool CGameHandler::moveArtifact(const ArtifactLocation &al1, const ArtifactLocat
|
||||
*/
|
||||
bool CGameHandler::assembleArtifacts (ObjectInstanceID heroID, ArtifactPosition artifactSlot, bool assemble, ArtifactID assembleTo)
|
||||
{
|
||||
|
||||
CGHeroInstance *hero = gs->getHero(heroID);
|
||||
const CGHeroInstance * hero = getHero(heroID);
|
||||
const CArtifactInstance *destArtifact = hero->getArt(artifactSlot);
|
||||
|
||||
if(!destArtifact)
|
||||
@ -3253,8 +3299,8 @@ bool CGameHandler::assembleArtifacts (ObjectInstanceID heroID, ArtifactPosition
|
||||
|
||||
bool CGameHandler::buyArtifact( ObjectInstanceID hid, ArtifactID aid )
|
||||
{
|
||||
CGHeroInstance *hero = gs->getHero(hid);
|
||||
CGTownInstance *town = hero->visitedTown;
|
||||
const CGHeroInstance * hero = getHero(hid);
|
||||
const CGTownInstance * town = hero->visitedTown;
|
||||
if(aid==ArtifactID::SPELLBOOK)
|
||||
{
|
||||
if((!town->hasBuilt(BuildingID::MAGES_GUILD_1) && complain("Cannot buy a spellbook, no mage guild in the town!"))
|
||||
@ -3274,7 +3320,7 @@ bool CGameHandler::buyArtifact( ObjectInstanceID hid, ArtifactID aid )
|
||||
int price = VLC->arth->artifacts[aid]->price;
|
||||
|
||||
if(( hero->getArt(ArtifactPosition(9+aid)) && complain("Hero already has this machine!"))
|
||||
|| (gs->getPlayer(hero->getOwner())->resources.at(Res::GOLD) < price && complain("Not enough gold!")))
|
||||
|| (getPlayer(hero->getOwner())->resources.at(Res::GOLD) < price && complain("Not enough gold!")))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -3399,8 +3445,8 @@ bool CGameHandler::buySecSkill( const IMarket *m, const CGHeroInstance *h, Secon
|
||||
|
||||
bool CGameHandler::tradeResources(const IMarket *market, ui32 val, PlayerColor player, ui32 id1, ui32 id2)
|
||||
{
|
||||
int r1 = gs->getPlayer(player)->resources.at(id1),
|
||||
r2 = gs->getPlayer(player)->resources.at(id2);
|
||||
int r1 = getPlayer(player)->resources.at(id1),
|
||||
r2 = getPlayer(player)->resources.at(id2);
|
||||
|
||||
vstd::amin(val, r1); //can't trade more resources than have
|
||||
|
||||
@ -3490,15 +3536,15 @@ bool CGameHandler::transformInUndead(const IMarket *market, const CGHeroInstance
|
||||
|
||||
bool CGameHandler::sendResources(ui32 val, PlayerColor player, Res::ERes r1, PlayerColor r2)
|
||||
{
|
||||
const PlayerState *p2 = gs->getPlayer(r2, false);
|
||||
const PlayerState *p2 = getPlayer(r2, false);
|
||||
if(!p2 || p2->status != EPlayerStatus::INGAME)
|
||||
{
|
||||
complain("Dest player must be in game!");
|
||||
return false;
|
||||
}
|
||||
|
||||
si32 curRes1 = gs->getPlayer(player)->resources.at(r1),
|
||||
curRes2 = gs->getPlayer(r2)->resources.at(r1);
|
||||
si32 curRes1 = getPlayer(player)->resources.at(r1),
|
||||
curRes2 = getPlayer(r2)->resources.at(r1);
|
||||
val = std::min(si32(val),curRes1);
|
||||
|
||||
SetResource sr;
|
||||
@ -3533,8 +3579,8 @@ bool CGameHandler::setFormation(ObjectInstanceID hid, ui8 formation)
|
||||
|
||||
bool CGameHandler::hireHero(const CGObjectInstance *obj, ui8 hid, PlayerColor player)
|
||||
{
|
||||
const PlayerState *p = gs->getPlayer(player);
|
||||
const CGTownInstance *t = gs->getTown(obj->id);
|
||||
const PlayerState * p = getPlayer(player);
|
||||
const CGTownInstance * t = getTown(obj->id);
|
||||
|
||||
//common preconditions
|
||||
// if( (p->resources.at(Res::GOLD)<GOLD_NEEDED && complain("Not enough gold for buying hero!"))
|
||||
@ -4217,7 +4263,7 @@ void CGameHandler::playerMessage( PlayerColor player, const std::string &message
|
||||
SetMana sm;
|
||||
GiveBonus giveBonus(GiveBonus::HERO);
|
||||
|
||||
CGHeroInstance *h = gs->getHero(currObj);
|
||||
const CGHeroInstance * h = getHero(currObj);
|
||||
if(!h && complain("Cannot realize cheat, no hero selected!")) return;
|
||||
|
||||
sm.hid = h->id;
|
||||
@ -4243,13 +4289,13 @@ void CGameHandler::playerMessage( PlayerColor player, const std::string &message
|
||||
}
|
||||
else if (message == "vcmiarmenelos") //build all buildings in selected town
|
||||
{
|
||||
CGHeroInstance *hero = gs->getHero(currObj);
|
||||
CGTownInstance *town;
|
||||
const CGHeroInstance * hero = getHero(currObj);
|
||||
const CGTownInstance * town;
|
||||
|
||||
if (hero)
|
||||
town = hero->visitedTown;
|
||||
else
|
||||
town = gs->getTown(currObj);
|
||||
town = getTown(currObj);
|
||||
|
||||
if (town)
|
||||
{
|
||||
@ -4266,7 +4312,7 @@ void CGameHandler::playerMessage( PlayerColor player, const std::string &message
|
||||
}
|
||||
else if(message == "vcmiainur") //gives 5 archangels into each slot
|
||||
{
|
||||
CGHeroInstance *hero = gs->getHero(currObj);
|
||||
const CGHeroInstance * hero = getHero(currObj);
|
||||
const CCreature *archangel = VLC->creh->creatures.at(13);
|
||||
if(!hero) return;
|
||||
|
||||
@ -4276,7 +4322,7 @@ void CGameHandler::playerMessage( PlayerColor player, const std::string &message
|
||||
}
|
||||
else if(message == "vcmiangband") //gives 10 black knight into each slot
|
||||
{
|
||||
CGHeroInstance *hero = gs->getHero(currObj);
|
||||
const CGHeroInstance * hero = getHero(currObj);
|
||||
const CCreature *blackKnight = VLC->creh->creatures.at(66);
|
||||
if(!hero) return;
|
||||
|
||||
@ -4286,7 +4332,7 @@ void CGameHandler::playerMessage( PlayerColor player, const std::string &message
|
||||
}
|
||||
else if(message == "vcmiglaurung") //gives 5000 crystal dragons into each slot
|
||||
{
|
||||
CGHeroInstance *hero = gs->getHero(currObj);
|
||||
const CGHeroInstance * hero = getHero(currObj);
|
||||
const CCreature *crystalDragon = VLC->creh->creatures.at(133);
|
||||
if(!hero) return;
|
||||
|
||||
@ -4296,7 +4342,7 @@ void CGameHandler::playerMessage( PlayerColor player, const std::string &message
|
||||
}
|
||||
else if(message == "vcminoldor") //all war machines
|
||||
{
|
||||
CGHeroInstance *hero = gs->getHero(currObj);
|
||||
const CGHeroInstance * hero = getHero(currObj);
|
||||
if(!hero) return;
|
||||
|
||||
if(!hero->getArt(ArtifactPosition::MACH1))
|
||||
@ -4308,7 +4354,7 @@ void CGameHandler::playerMessage( PlayerColor player, const std::string &message
|
||||
}
|
||||
else if (message == "vcmiforgeofnoldorking") //hero gets all artifacts except war machines, spell scrolls and spell book
|
||||
{
|
||||
CGHeroInstance *hero = gs->getHero(currObj);
|
||||
const CGHeroInstance *hero = gs->getHero(currObj);
|
||||
if(!hero) return;
|
||||
for (int g = 7; g < VLC->arth->artifacts.size(); ++g) //including artifacts from mods
|
||||
giveHeroNewArtifact(hero, VLC->arth->artifacts[g], ArtifactPosition::PRE_FIRST);
|
||||
@ -4331,23 +4377,23 @@ void CGameHandler::playerMessage( PlayerColor player, const std::string &message
|
||||
{
|
||||
SetResources sr;
|
||||
sr.player = player;
|
||||
sr.res = gs->getPlayer(player)->resources;
|
||||
sr.res = getPlayer(player)->resources;
|
||||
for(int i=0;i<Res::GOLD;i++)
|
||||
sr.res[i] += 100;
|
||||
sr.res[Res::GOLD] += 100000; //100k
|
||||
sendAndApply(&sr);
|
||||
}
|
||||
else if(message == "vcmieagles") //reveal FoW
|
||||
else if(message == "vcmieagles" || message == "vcmiungoliant") //reveal or conceal FoW
|
||||
{
|
||||
FoWChange fc;
|
||||
fc.mode = 1;
|
||||
fc.mode = (message == "vcmieagles" ? 1 : 0);
|
||||
fc.player = player;
|
||||
auto hlp_tab = new int3[gs->map->width * gs->map->height * (gs->map->twoLevel ? 2 : 1)];
|
||||
int lastUnc = 0;
|
||||
for(int i=0;i<gs->map->width;i++)
|
||||
for(int j=0;j<gs->map->height;j++)
|
||||
for(int k = 0; k < (gs->map->twoLevel ? 2 : 1); k++)
|
||||
if(!gs->getPlayerTeam(fc.player)->fogOfWarMap.at(i).at(j).at(k))
|
||||
if(!gs->getPlayerTeam(fc.player)->fogOfWarMap.at(i).at(j).at(k) || message == "vcmiungoliant")
|
||||
hlp_tab[lastUnc++] = int3(i,j,k);
|
||||
fc.tiles.insert(hlp_tab, hlp_tab + lastUnc);
|
||||
delete [] hlp_tab;
|
||||
@ -4669,7 +4715,7 @@ void CGameHandler::handleTimeEvents()
|
||||
{
|
||||
auto color = PlayerColor(player);
|
||||
|
||||
PlayerState *pinfo = gs->getPlayer(color, false); //do not output error if player does not exist
|
||||
const PlayerState * pinfo = getPlayer(color, false); //do not output error if player does not exist
|
||||
|
||||
if( pinfo //player exists
|
||||
&& (ev.players & 1<<player) //event is enabled to this player
|
||||
@ -4733,7 +4779,7 @@ void CGameHandler::handleTownEvents(CGTownInstance * town, NewTurn &n)
|
||||
{
|
||||
PlayerColor player = town->tempOwner;
|
||||
CCastleEvent ev = town->events.front();
|
||||
PlayerState *pinfo = gs->getPlayer(player, false);
|
||||
const PlayerState * pinfo = getPlayer(player, false);
|
||||
|
||||
if( pinfo //player exists
|
||||
&& (ev.players & 1<<player.getNum()) //event is enabled to this player
|
||||
@ -4944,7 +4990,7 @@ bool CGameHandler::buildBoat( ObjectInstanceID objid )
|
||||
const PlayerColor playerID = obj->o->tempOwner;
|
||||
TResources boatCost;
|
||||
obj->getBoatCost(boatCost);
|
||||
TResources aviable = gs->getPlayer(playerID)->resources;
|
||||
TResources aviable = getPlayer(playerID)->resources;
|
||||
|
||||
if (!aviable.canAfford(boatCost))
|
||||
{
|
||||
@ -4989,7 +5035,7 @@ void CGameHandler::checkVictoryLossConditions(const std::set<PlayerColor> & play
|
||||
{
|
||||
for(auto playerColor : playerColors)
|
||||
{
|
||||
if(gs->getPlayer(playerColor, false))
|
||||
if(getPlayer(playerColor, false))
|
||||
checkVictoryLossConditionsForPlayer(playerColor);
|
||||
}
|
||||
}
|
||||
@ -5006,7 +5052,7 @@ void CGameHandler::checkVictoryLossConditionsForAll()
|
||||
|
||||
void CGameHandler::checkVictoryLossConditionsForPlayer(PlayerColor player)
|
||||
{
|
||||
const PlayerState *p = gs->getPlayer(player);
|
||||
const PlayerState * p = getPlayer(player);
|
||||
if(p->status != EPlayerStatus::INGAME) return;
|
||||
|
||||
auto victoryLossCheckResult = gs->checkForVictoryAndLoss(player);
|
||||
@ -5027,10 +5073,10 @@ void CGameHandler::checkVictoryLossConditionsForPlayer(PlayerColor player)
|
||||
//one player won -> all enemies lost
|
||||
for (auto i = gs->players.cbegin(); i!=gs->players.cend(); i++)
|
||||
{
|
||||
if(i->first != player && gs->getPlayer(i->first)->status == EPlayerStatus::INGAME)
|
||||
if(i->first != player && getPlayer(i->first)->status == EPlayerStatus::INGAME)
|
||||
{
|
||||
peg.player = i->first;
|
||||
peg.victoryLossCheckResult = gameState()->getPlayerRelations(player, i->first) == PlayerRelations::ALLIES ?
|
||||
peg.victoryLossCheckResult = getPlayerRelations(player, i->first) == PlayerRelations::ALLIES ?
|
||||
victoryLossCheckResult : victoryLossCheckResult.invert(); // ally of winner
|
||||
|
||||
InfoWindow iw;
|
||||
@ -5119,7 +5165,7 @@ void CGameHandler::checkVictoryLossConditionsForPlayer(PlayerColor player)
|
||||
//notify all players
|
||||
for (auto pc : playerColors)
|
||||
{
|
||||
if (gs->getPlayer(pc)->status == EPlayerStatus::INGAME)
|
||||
if(getPlayer(pc)->status == EPlayerStatus::INGAME)
|
||||
{
|
||||
InfoWindow iw;
|
||||
getVictoryLossMessage(player, victoryLossCheckResult.invert(), iw);
|
||||
@ -5130,7 +5176,7 @@ void CGameHandler::checkVictoryLossConditionsForPlayer(PlayerColor player)
|
||||
checkVictoryLossConditions(playerColors);
|
||||
}
|
||||
|
||||
auto playerInfo = gs->getPlayer(gs->currentPlayer, false);
|
||||
auto playerInfo = getPlayer(gs->currentPlayer, false);
|
||||
// If we are called before the actual game start, there might be no current player
|
||||
if (playerInfo && playerInfo->status != EPlayerStatus::INGAME)
|
||||
{
|
||||
@ -6018,7 +6064,7 @@ void CGameHandler::changeFogOfWar(int3 center, ui32 radius, PlayerColor player,
|
||||
if (hide)
|
||||
{
|
||||
std::unordered_set<int3, ShashInt3> observedTiles; //do not hide tiles observed by heroes. May lead to disastrous AI problems
|
||||
auto p = gs->getPlayer(player);
|
||||
auto p = getPlayer(player);
|
||||
for (auto h : p->heroes)
|
||||
{
|
||||
getTilesInRange(observedTiles, h->getSightCenter(), h->getSightRadius(), h->tempOwner, -1);
|
||||
|
Loading…
Reference in New Issue
Block a user