Browse Source

Merge pull request #1738 from IvanSavenko/advmap_fixes

Fixes for regressions related to adventure map
Ivan Savenko 2 years ago
parent
commit
56a02c240e

+ 6 - 3
client/CPlayerInterface.cpp

@@ -583,6 +583,7 @@ void CPlayerInterface::heroInGarrisonChange(const CGTownInstance *town)
 		castleInt->garr->setArmy(town->visitingHero, 1);
 		castleInt->garr->recreateSlots();
 		castleInt->heroes->update();
+		castleInt->redraw();
 	}
 	for (auto isa : GH.listInt)
 	{
@@ -591,9 +592,9 @@ void CPlayerInterface::heroInGarrisonChange(const CGTownInstance *town)
 		{
 			ki->townChanged(town);
 			ki->updateGarrisons();
+			ki->redraw();
 		}
 	}
-	GH.totalRedraw();
 }
 void CPlayerInterface::heroVisitsTown(const CGHeroInstance* hero, const CGTownInstance * town)
 {
@@ -1510,6 +1511,7 @@ void CPlayerInterface::objectRemoved(const CGObjectInstance * obj)
 		const CGHeroInstance * h = static_cast<const CGHeroInstance *>(obj);
 		heroKilled(h);
 	}
+	GH.fakeMouseMove();
 }
 
 void CPlayerInterface::objectRemovedAfter()
@@ -1559,7 +1561,6 @@ void CPlayerInterface::update()
 	}
 
 	assert(adventureInt);
-	assert(adventureInt->selection);
 
 	// Handles mouse and key input
 	GH.updateTime();
@@ -2032,7 +2033,9 @@ bool CPlayerInterface::capturedAllEvents()
 		return true;
 	}
 
-	if (ignoreEvents)
+	bool needToLockAdventureMap = adventureInt->active && CGI->mh->hasOngoingAnimations();
+
+	if (ignoreEvents || needToLockAdventureMap)
 	{
 		boost::unique_lock<boost::mutex> un(eventsM);
 		while(!SDLEventsQueue.empty())

+ 1 - 1
client/ClientCommandManager.h

@@ -17,7 +17,7 @@ class CIntObject;
 
 class ClientCommandManager //take mantis #2292 issue about account if thinking about handling cheats from command-line
 {
-	bool currentCallFromIngameConsole;
+	bool currentCallFromIngameConsole = false;
 
 	void giveTurn(const PlayerColor &color);
 	void printInfoAboutInterfaceObject(const CIntObject *obj, int level);

+ 10 - 1
client/NetPacksClient.cpp

@@ -514,6 +514,11 @@ void ApplyClientNetPackVisitor::visitNewStructures(NewStructures & pack)
 	{
 		callInterfaceIfPresent(cl, town->tempOwner, &IGameEventsReceiver::buildChanged, town, id, 1);
 	}
+
+	// invalidate section of map view with our object and force an update
+	CGI->mh->onObjectInstantRemove(town);
+	CGI->mh->onObjectInstantAdd(town);
+
 }
 void ApplyClientNetPackVisitor::visitRazeStructures(RazeStructures & pack)
 {
@@ -522,6 +527,10 @@ void ApplyClientNetPackVisitor::visitRazeStructures(RazeStructures & pack)
 	{
 		callInterfaceIfPresent(cl, town->tempOwner, &IGameEventsReceiver::buildChanged, town, id, 2);
 	}
+
+	// invalidate section of map view with our object and force an update
+	CGI->mh->onObjectInstantRemove(town);
+	CGI->mh->onObjectInstantAdd(town);
 }
 
 void ApplyClientNetPackVisitor::visitSetAvailableCreatures(SetAvailableCreatures & pack)
@@ -607,7 +616,7 @@ void ApplyClientNetPackVisitor::visitSetObjectProperty(SetObjectProperty & pack)
 
 	if (pack.what == ObjProperty::OWNER)
 	{
-		// invalidate section of map view with our objec and force an update with new flag color
+		// invalidate section of map view with our object and force an update with new flag color
 		CGI->mh->onObjectInstantRemove(gs.getObjInstance(pack.id));
 		CGI->mh->onObjectInstantAdd(gs.getObjInstance(pack.id));
 	}

+ 2 - 1
client/adventureMap/CAdvMapInt.cpp

@@ -986,7 +986,6 @@ void CAdvMapInt::initializeNewTurn()
 {
 	heroList->update();
 	townList->update();
-	mapAudio->onPlayerTurnStarted();
 
 	const CGHeroInstance * heroToSelect = nullptr;
 
@@ -1017,6 +1016,7 @@ void CAdvMapInt::initializeNewTurn()
 
 	updateNextHero(nullptr);
 	showAll(screen);
+	mapAudio->onPlayerTurnStarted();
 
 	if(settings["session"]["autoSkip"].Bool() && !GH.isKeyboardShiftDown())
 	{
@@ -1404,6 +1404,7 @@ void CAdvMapInt::aiTurnStarted()
 	mapAudio->onEnemyTurnStarted();
 	adventureInt->minimap->setAIRadar(true);
 	adventureInt->infoBar->startEnemyTurn(LOCPLINT->cb->getCurrentPlayer());
+	adventureInt->minimap->showAll(screen);//force refresh on inactive object
 	adventureInt->infoBar->showAll(screen);//force refresh on inactive object
 }
 

+ 53 - 39
client/adventureMap/CInGameConsole.cpp

@@ -24,71 +24,85 @@
 #include "../../lib/TextOperations.h"
 #include "../../lib/mapObjects/CArmedInstance.h"
 
-#include <SDL_timer.h>
-
 CInGameConsole::CInGameConsole()
-	: CIntObject(KEYBOARD | TEXTINPUT),
-	prevEntDisp(-1),
-	defaultTimeout(10000),
-	maxDisplayedTexts(10)
+	: CIntObject(KEYBOARD | TIME | TEXTINPUT)
+	, prevEntDisp(-1)
+{
+	type |= REDRAW_PARENT;
+}
+
+void CInGameConsole::showAll(SDL_Surface * to)
 {
+	show(to);
 }
 
 void CInGameConsole::show(SDL_Surface * to)
 {
 	int number = 0;
 
-	std::vector<std::list< std::pair< std::string, uint32_t > >::iterator> toDel;
-
 	boost::unique_lock<boost::mutex> lock(texts_mx);
-	for(auto it = texts.begin(); it != texts.end(); ++it, ++number)
+	for(auto & text : texts)
 	{
 		Point leftBottomCorner(0, pos.h);
+		Point textPosition(leftBottomCorner.x + 50, leftBottomCorner.y - texts.size() * 20 - 80 + number * 20);
 
-		graphics->fonts[FONT_MEDIUM]->renderTextLeft(to, it->first, Colors::GREEN,
-			Point(leftBottomCorner.x + 50, leftBottomCorner.y - (int)texts.size() * 20 - 80 + number*20));
+		graphics->fonts[FONT_MEDIUM]->renderTextLeft(to, text.text, Colors::GREEN, textPosition );
 
-		if((int)(SDL_GetTicks() - it->second) > defaultTimeout)
-		{
-			toDel.push_back(it);
-		}
+		number++;
 	}
+}
 
-	for(auto & elem : toDel)
+void CInGameConsole::tick(uint32_t msPassed)
+{
+	size_t sizeBefore = texts.size();
 	{
-		texts.erase(elem);
+		boost::unique_lock<boost::mutex> lock(texts_mx);
+
+		for(auto & text : texts)
+			text.timeOnScreen += msPassed;
+
+		vstd::erase_if(
+			texts,
+			[&](const auto & value)
+			{
+				return value.timeOnScreen > defaultTimeout;
+			}
+		);
 	}
+
+	if(sizeBefore != texts.size())
+		GH.totalRedraw(); // FIXME: ingame console has no parent widget set
 }
 
-void CInGameConsole::print(const std::string &txt)
+void CInGameConsole::print(const std::string & txt)
 {
-	boost::unique_lock<boost::mutex> lock(texts_mx);
-	int lineLen = conf.go()->ac.outputLineLength;
-
-	if(txt.size() < lineLen)
+	// boost::unique_lock scope
 	{
-		texts.push_back(std::make_pair(txt, SDL_GetTicks()));
-		if(texts.size() > maxDisplayedTexts)
+		boost::unique_lock<boost::mutex> lock(texts_mx);
+		int lineLen = conf.go()->ac.outputLineLength;
+
+		if(txt.size() < lineLen)
 		{
-			texts.pop_front();
+			texts.push_back({txt, 0});
 		}
-	}
-	else
-	{
-		assert(lineLen);
-		for(int g=0; g<txt.size() / lineLen + 1; ++g)
+		else
 		{
-			std::string part = txt.substr(g * lineLen, lineLen);
-			if(part.size() == 0)
-				break;
-
-			texts.push_back(std::make_pair(part, SDL_GetTicks()));
-			if(texts.size() > maxDisplayedTexts)
+			assert(lineLen);
+			for(int g = 0; g < txt.size() / lineLen + 1; ++g)
 			{
-				texts.pop_front();
+				std::string part = txt.substr(g * lineLen, lineLen);
+				if(part.empty())
+					break;
+
+				texts.push_back({part, 0});
 			}
 		}
+
+		while(texts.size() > maxDisplayedTexts)
+			texts.erase(texts.begin());
 	}
+
+	GH.totalRedraw(); // FIXME: ingame console has no parent widget set
 }
 
 void CInGameConsole::keyPressed (const SDL_Keycode & key)
@@ -136,7 +150,7 @@ void CInGameConsole::keyPressed (const SDL_Keycode & key)
 		}
 	case SDLK_UP: //up arrow
 		{
-			if(previouslyEntered.size() == 0)
+			if(previouslyEntered.empty())
 				break;
 
 			if(prevEntDisp == -1)
@@ -178,7 +192,7 @@ void CInGameConsole::keyPressed (const SDL_Keycode & key)
 
 void CInGameConsole::textInputed(const std::string & inputtedText)
 {
-	if(!captureAllKeys || enteredText.size() == 0)
+	if(!captureAllKeys || enteredText.empty())
 		return;
 	enteredText.resize(enteredText.size()-1);
 

+ 26 - 7
client/adventureMap/CInGameConsole.h

@@ -14,20 +14,39 @@
 class CInGameConsole : public CIntObject
 {
 private:
-	std::list< std::pair< std::string, uint32_t > > texts; //list<text to show, time of add>
-	boost::mutex texts_mx;		// protects texts
-	std::vector< std::string > previouslyEntered; //previously entered texts, for up/down arrows to work
-	int prevEntDisp; //displayed entry from previouslyEntered - if none it's -1
-	int defaultTimeout; //timeout for new texts (in ms)
-	int maxDisplayedTexts; //hiw many texts can be displayed simultaneously
+	struct TextState
+	{
+		std::string text;
+		uint32_t timeOnScreen;
+	};
+
+	/// Currently visible texts in the overlay
+	std::vector<TextState> texts;
+
+	/// protects texts
+	boost::mutex texts_mx;
+
+	/// previously entered texts, for up/down arrows to work
+	std::vector<std::string> previouslyEntered;
+
+	/// displayed entry from previouslyEntered - if none it's -1
+	int prevEntDisp;
+
+	/// timeout for new texts (in ms)
+	static constexpr int defaultTimeout = 10000;
+
+	/// how many texts can be displayed simultaneously
+	static constexpr int maxDisplayedTexts = 10;
 
 	std::weak_ptr<IStatusBar> currentStatusBar;
 	std::string enteredText;
 
 public:
-	void print(const std::string &txt);
+	void print(const std::string & txt);
 
+	void tick(uint32_t msPassed) override;
 	void show(SDL_Surface * to) override;
+	void showAll(SDL_Surface * to) override;
 	void keyPressed(const SDL_Keycode & key) override;
 	void textInputed(const std::string & enteredText) override;
 	void textEdited(const std::string & enteredText) override;

+ 23 - 5
client/adventureMap/CInfoBar.cpp

@@ -254,11 +254,21 @@ void CInfoBar::showSelection()
 	showGameStatus();//FIXME: may be incorrect but shouldn't happen in general
 }
 
-void CInfoBar::tick()
+void CInfoBar::tick(uint32_t msPassed)
 {
-	removeUsedEvents(TIME);
-	if(GH.topInt() == adventureInt)
-		popComponents(true);
+	assert(timerCounter > 0);
+
+	if (msPassed >= timerCounter)
+	{
+		timerCounter = 0;
+		removeUsedEvents(TIME);
+		if(GH.topInt() == adventureInt)
+			popComponents(true);
+	}
+	else
+	{
+		timerCounter -= msPassed;
+	}
 }
 
 void CInfoBar::clickLeft(tribool down, bool previousState)
@@ -290,6 +300,7 @@ void CInfoBar::hover(bool on)
 
 CInfoBar::CInfoBar(const Rect & position)
 	: CIntObject(LCLICK | RCLICK | HOVER, position.topLeft()),
+	timerCounter(0),
 	state(EMPTY)
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
@@ -302,6 +313,14 @@ CInfoBar::CInfoBar(const Point & position): CInfoBar(Rect(position.x, position.y
 {
 }
 
+
+void CInfoBar::setTimer(uint32_t msToTrigger)
+{
+	if (!(active & TIME))
+		addUsedEvents(TIME);
+	timerCounter = msToTrigger;
+}
+
 void CInfoBar::showDate()
 {
 	OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE);
@@ -312,7 +331,6 @@ void CInfoBar::showDate()
 	redraw();
 }
 
-
 void CInfoBar::pushComponents(const std::vector<Component> & components, std::string message, int timer)
 {
 	auto actualPush = [&](const std::vector<Component> & components, std::string message, int timer, size_t max){

+ 3 - 1
client/adventureMap/CInfoBar.h

@@ -138,6 +138,7 @@ private:
 
 	std::shared_ptr<CVisibleInfo> visibleInfo;
 	EState state;
+	uint32_t timerCounter;
 	bool shouldPopAll = false;
 
 	std::queue<std::pair<VisibleComponentInfo::Cache, int>> componentsQueue;
@@ -151,13 +152,14 @@ private:
 	//removes all information about current state, deactivates timer (if any)
 	void reset();
 
-	void tick() override;
+	void tick(uint32_t msPassed) override;
 
 	void clickLeft(tribool down, bool previousState) override;
 	void clickRight(tribool down, bool previousState) override;
 	void hover(bool on) override;
 
 	void playNewDaySound();
+	void setTimer(uint32_t msToTrigger);
 public:
 	CInfoBar(const Rect & pos);
 	CInfoBar(const Point & pos);

+ 1 - 1
client/adventureMap/CList.cpp

@@ -77,7 +77,7 @@ void CList::CListItem::onSelect(bool on)
 	if(on)
 		selection = genSelection();
 	select(on);
-	GH.totalRedraw();
+	redraw();
 }
 
 CList::CList(int Size, Point position, std::string btnUp, std::string btnDown, size_t listAmount, int helpUp, int helpDown, CListBox::CreateFunc create)

+ 1 - 4
client/adventureMap/CMinimap.cpp

@@ -222,10 +222,7 @@ void CMinimap::setAIRadar(bool on)
 		aiShield->disable();
 		update();
 	}
-
-	// this may happen during AI turn when this interface is inactive
-	// force redraw in order to properly update interface
-	GH.totalRedraw();
+	redraw();
 }
 
 void CMinimap::updateTile(const int3 &pos)

+ 1 - 1
client/gui/CGuiHandler.cpp

@@ -192,7 +192,7 @@ void CGuiHandler::updateTime()
 	for (auto & elem : hlp)
 	{
 		if(!vstd::contains(timeinterested,elem)) continue;
-		(elem)->onTimer(ms);
+		(elem)->tick(ms);
 	}
 }
 

+ 0 - 19
client/gui/CIntObject.cpp

@@ -29,7 +29,6 @@ CIntObject::CIntObject(int used_, Point pos_):
 	active(active_m)
 {
 	hovered = captureAllKeys = strongInterest = false;
-	toNextTick = timerDelay = 0;
 	used = used_;
 
 	recActions = defActions = GH.defActionsDef;
@@ -60,24 +59,6 @@ CIntObject::~CIntObject()
 		parent_m->removeChild(this);
 }
 
-void CIntObject::setTimer(int msToTrigger)
-{
-	if (!(active & TIME))
-		activate(TIME);
-	toNextTick = timerDelay = msToTrigger;
-	used |= TIME;
-}
-
-void CIntObject::onTimer(int timePassed)
-{
-	toNextTick -= timePassed;
-	if (toNextTick < 0)
-	{
-		toNextTick += timerDelay;
-		tick();
-	}
-}
-
 void CIntObject::show(SDL_Surface * to)
 {
 	if(defActions & UPDATE)

+ 1 - 8
client/gui/CIntObject.h

@@ -65,14 +65,8 @@ class CIntObject : public IShowActivatable //interface object
 {
 	ui16 used;//change via addUsed() or delUsed
 
-	//time handling
-	int toNextTick;
-	int timerDelay;
-
 	std::map<MouseButton, bool> currentMouseState;
 
-	void onTimer(int timePassed);
-
 	//non-const versions of fields to allow changing them in CIntObject
 	CIntObject *parent_m; //parent object
 	ui16 active_m;
@@ -129,8 +123,7 @@ public:
 	virtual void mouseMoved (const Point & cursorPosition){}
 
 	//time handling
-	void setTimer(int msToTrigger);//set timer delay and activate timer if needed.
-	virtual void tick(){}
+	virtual void tick(uint32_t msPassed){}
 
 	//mouse wheel
 	virtual void wheelScrolled(bool down, bool in){}

+ 4 - 2
client/mapView/MapView.cpp

@@ -60,14 +60,14 @@ BasicMapView::BasicMapView(const Point & offset, const Point & dimensions)
 void BasicMapView::render(Canvas & target, bool fullUpdate)
 {
 	Canvas targetClipped(target, pos);
-
-	controller->update(GH.mainFPSmng->getElapsedMilliseconds());
 	tilesCache->update(controller->getContext());
 	tilesCache->render(controller->getContext(), targetClipped, fullUpdate);
 }
 
 void BasicMapView::show(SDL_Surface * to)
 {
+	controller->update(GH.mainFPSmng->getElapsedMilliseconds());
+
 	Canvas target(to);
 	CSDL_Ext::CClipRectGuard guard(to, pos);
 	render(target, false);
@@ -75,6 +75,8 @@ void BasicMapView::show(SDL_Surface * to)
 
 void BasicMapView::showAll(SDL_Surface * to)
 {
+	controller->update(0);
+
 	Canvas target(to);
 	CSDL_Ext::CClipRectGuard guard(to, pos);
 	render(target, true);

+ 1 - 17
client/mapView/MapViewActions.cpp

@@ -24,7 +24,6 @@
 MapViewActions::MapViewActions(MapView & owner, const std::shared_ptr<MapViewModel> & model)
 	: model(model)
 	, owner(owner)
-	, curHoveredTile(-1, -1, -1)
 	, isSwiping(false)
 {
 	pos.w = model->getPixelsVisibleDimensions().x;
@@ -47,17 +46,6 @@ void MapViewActions::setContext(const std::shared_ptr<IMapRendererContext> & con
 	this->context = context;
 }
 
-void MapViewActions::activate()
-{
-	CIntObject::activate();
-}
-
-void MapViewActions::deactivate()
-{
-	CIntObject::deactivate();
-	curHoveredTile = int3(-1, -1, -1); //we lost info about hovered tile when disabling
-}
-
 void MapViewActions::clickLeft(tribool down, bool previousState)
 {
 	if(indeterminate(down))
@@ -159,11 +147,7 @@ void MapViewActions::handleHover(const Point & cursorPosition)
 		return;
 	}
 
-	if(tile != curHoveredTile)
-	{
-		curHoveredTile = tile;
-		adventureInt->onTileHovered(tile);
-	}
+	adventureInt->onTileHovered(tile);
 }
 
 void MapViewActions::hover(bool on)

+ 0 - 4
client/mapView/MapViewActions.h

@@ -23,8 +23,6 @@ class MapViewActions : public CIntObject
 	Point swipeInitialViewPos;
 	Point swipeInitialRealPos;
 
-	int3 curHoveredTile;
-
 	MapView & owner;
 	std::shared_ptr<MapViewModel> model;
 	std::shared_ptr<IMapRendererContext> context;
@@ -39,8 +37,6 @@ public:
 
 	void setContext(const std::shared_ptr<IMapRendererContext> & context);
 
-	void activate() override;
-	void deactivate() override;
 	void clickLeft(tribool down, bool previousState) override;
 	void clickRight(tribool down, bool previousState) override;
 	void clickMiddle(tribool down, bool previousState) override;

+ 22 - 2
client/mapView/MapViewController.cpp

@@ -251,6 +251,26 @@ void MapViewController::fadeInObject(const CGObjectInstance * obj)
 
 void MapViewController::removeObject(const CGObjectInstance * obj)
 {
+	if (obj->ID == Obj::BOAT)
+	{
+		auto * boat = dynamic_cast<const CGBoat*>(obj);
+		if (boat->hero)
+		{
+			view->invalidate(context, boat->hero->id);
+			state->removeObject(boat->hero);
+		}
+	}
+
+	if (obj->ID == Obj::HERO)
+	{
+		auto * hero = dynamic_cast<const CGHeroInstance*>(obj);
+		if (hero->boat)
+		{
+			view->invalidate(context, hero->boat->id);
+			state->removeObject(hero->boat);
+		}
+	}
+
 	view->invalidate(context, obj->id);
 	state->removeObject(obj);
 }
@@ -265,7 +285,7 @@ void MapViewController::onBeforeHeroEmbark(const CGHeroInstance * obj, const int
 {
 	if(isEventVisible(obj, from, dest))
 	{
-		onObjectFadeOut(obj);
+		fadeOutObject(obj);
 		setViewCenter(obj->getSightCenter());
 	}
 	else
@@ -288,7 +308,7 @@ void MapViewController::onAfterHeroDisembark(const CGHeroInstance * obj, const i
 {
 	if(isEventVisible(obj, from, dest))
 	{
-		onObjectFadeIn(obj);
+		fadeInObject(obj);
 		setViewCenter(obj->getSightCenter());
 	}
 	addObject(obj);

+ 2 - 1
client/mapView/mapHandler.cpp

@@ -229,5 +229,6 @@ IMapObjectObserver::IMapObjectObserver()
 
 IMapObjectObserver::~IMapObjectObserver()
 {
-	CGI->mh->removeMapObserver(this);
+	if (CGI && CGI->mh)
+		CGI->mh->removeMapObserver(this);
 }