| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287 | /* * PlayerLocalState.cpp, 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 * */#include "StdInc.h"#include "PlayerLocalState.h"#include "../CCallback.h"#include "../lib/mapObjects/CGHeroInstance.h"#include "../lib/mapObjects/CGTownInstance.h"#include "../lib/pathfinder/CGPathNode.h"#include "CPlayerInterface.h"#include "adventureMap/AdventureMapInterface.h"PlayerLocalState::PlayerLocalState(CPlayerInterface & owner)	: owner(owner)	, currentSelection(nullptr){}void PlayerLocalState::saveHeroPaths(std::map<const CGHeroInstance *, int3> & pathsMap){	for(auto & p : paths)	{		if(p.second.nodes.size())			pathsMap[p.first] = p.second.endPos();		else			logGlobal->debug("%s has assigned an empty path! Ignoring it...", p.first->getNameTranslated());	}}void PlayerLocalState::loadHeroPaths(std::map<const CGHeroInstance *, int3> & pathsMap){	if(owner.cb)	{		for(auto & p : pathsMap)		{			CGPath path;			owner.cb->getPathsInfo(p.first)->getPath(path, p.second);			paths[p.first] = path;			logGlobal->trace("Restored path for hero %s leading to %s with %d nodes", p.first->nodeName(), p.second.toString(), path.nodes.size());		}	}}void PlayerLocalState::setPath(const CGHeroInstance * h, const CGPath & path){	paths[h] = path;}const CGPath & PlayerLocalState::getPath(const CGHeroInstance * h) const{	assert(hasPath(h));	return paths.at(h);}bool PlayerLocalState::hasPath(const CGHeroInstance * h) const{	return paths.count(h) > 0;}bool PlayerLocalState::setPath(const CGHeroInstance * h, const int3 & destination){	CGPath path;	if(!owner.cb->getPathsInfo(h)->getPath(path, destination))	{		paths.erase(h); //invalidate previously possible path if selected (before other hero blocked only path / fly spell expired)		return false;	}	setPath(h, path);	return true;}void PlayerLocalState::removeLastNode(const CGHeroInstance * h){	assert(hasPath(h));	if(!hasPath(h))		return;	auto & path = paths[h];	path.nodes.pop_back();	if(path.nodes.size() < 2) //if it was the last one, remove entire path and path with only one tile is not a real path		erasePath(h);}void PlayerLocalState::erasePath(const CGHeroInstance * h){	paths.erase(h);	adventureInt->onHeroChanged(h);}void PlayerLocalState::verifyPath(const CGHeroInstance * h){	if(!hasPath(h))		return;	setPath(h, getPath(h).endPos());}const CGHeroInstance * PlayerLocalState::getCurrentHero() const{	if(currentSelection && currentSelection->ID == Obj::HERO)		return dynamic_cast<const CGHeroInstance *>(currentSelection);	else		return nullptr;}const CGHeroInstance * PlayerLocalState::getNextWanderingHero(const CGHeroInstance * currentHero){	bool currentHeroFound = false;	const CGHeroInstance * firstSuitable = nullptr;	const CGHeroInstance * nextSuitable = nullptr;	for(const auto * hero : getWanderingHeroes())	{		if (hero == currentHero)		{			currentHeroFound = true;			continue;		}		if (isHeroSleeping(hero))			continue;		if (hero->movementPointsRemaining() == 0)			continue;		if (!firstSuitable)			firstSuitable = hero;		if (!nextSuitable && currentHeroFound)			nextSuitable = hero;	}	// if we found suitable hero after currently selected hero -> return this hero	if (nextSuitable)		return nextSuitable;	// othervice -> loop over and return first suitable hero in the list (or null if none)	return firstSuitable;}const CGTownInstance * PlayerLocalState::getCurrentTown() const{	if(currentSelection && currentSelection->ID == Obj::TOWN)		return dynamic_cast<const CGTownInstance *>(currentSelection);	else		return nullptr;}const CArmedInstance * PlayerLocalState::getCurrentArmy() const{	if(currentSelection)		return dynamic_cast<const CArmedInstance *>(currentSelection);	else		return nullptr;}void PlayerLocalState::setSelection(const CArmedInstance * selection){	if (currentSelection == selection)		return;	currentSelection = selection;	if (selection)		adventureInt->onSelectionChanged(selection);}bool PlayerLocalState::isHeroSleeping(const CGHeroInstance * hero) const{	return vstd::contains(sleepingHeroes, hero);}void PlayerLocalState::setHeroAsleep(const CGHeroInstance * hero){	assert(hero);	assert(vstd::contains(wanderingHeroes, hero));	assert(!vstd::contains(sleepingHeroes, hero));	sleepingHeroes.push_back(hero);}void PlayerLocalState::setHeroAwaken(const CGHeroInstance * hero){	assert(hero);	assert(vstd::contains(wanderingHeroes, hero));	assert(vstd::contains(sleepingHeroes, hero));	vstd::erase(sleepingHeroes, hero);}const std::vector<const CGHeroInstance *> & PlayerLocalState::getWanderingHeroes(){	return wanderingHeroes;}const CGHeroInstance * PlayerLocalState::getWanderingHero(size_t index){	if(index < wanderingHeroes.size())		return wanderingHeroes[index];	throw std::runtime_error("No hero with index " + std::to_string(index));}void PlayerLocalState::addWanderingHero(const CGHeroInstance * hero){	assert(hero);	assert(!vstd::contains(wanderingHeroes, hero));	wanderingHeroes.push_back(hero);}void PlayerLocalState::removeWanderingHero(const CGHeroInstance * hero){	assert(hero);	assert(vstd::contains(wanderingHeroes, hero));	if (hero == currentSelection)	{		auto const * nextHero = getNextWanderingHero(hero);		setSelection(nextHero);	}	vstd::erase(wanderingHeroes, hero);	vstd::erase(sleepingHeroes, hero);	if (currentSelection == nullptr && !wanderingHeroes.empty())		setSelection(wanderingHeroes.front());	if (currentSelection == nullptr && !ownedTowns.empty())		setSelection(ownedTowns.front());}void PlayerLocalState::swapWanderingHero(size_t pos1, size_t pos2){	assert(wanderingHeroes[pos1] && wanderingHeroes[pos2]);	std::swap(wanderingHeroes.at(pos1), wanderingHeroes.at(pos2));	adventureInt->onHeroOrderChanged();}const std::vector<const CGTownInstance *> & PlayerLocalState::getOwnedTowns(){	return ownedTowns;}const CGTownInstance * PlayerLocalState::getOwnedTown(size_t index){	if(index < ownedTowns.size())		return ownedTowns[index];	throw std::runtime_error("No town with index " + std::to_string(index));}void PlayerLocalState::addOwnedTown(const CGTownInstance * town){	assert(town);	assert(!vstd::contains(ownedTowns, town));	ownedTowns.push_back(town);}void PlayerLocalState::removeOwnedTown(const CGTownInstance * town){	assert(town);	assert(vstd::contains(ownedTowns, town));	vstd::erase(ownedTowns, town);	if (town == currentSelection)		setSelection(nullptr);	if (currentSelection == nullptr && !wanderingHeroes.empty())		setSelection(wanderingHeroes.front());	if (currentSelection == nullptr && !ownedTowns.empty())		setSelection(ownedTowns.front());}void PlayerLocalState::swapOwnedTowns(size_t pos1, size_t pos2){	assert(ownedTowns[pos1] && ownedTowns[pos2]);	std::swap(ownedTowns.at(pos1), ownedTowns.at(pos2));	adventureInt->onTownOrderChanged();}
 |