2
0
Эх сурвалжийг харах

Hero movement speed and map scrolling speed now matches H3

Ivan Savenko 2 жил өмнө
parent
commit
ebe996fa74

+ 14 - 0
Global.h

@@ -442,6 +442,20 @@ namespace vstd
 		}
 	}
 
+	// c++17: makes a to fit the range <b, c>
+	template <typename t1, typename t2, typename t3>
+	t1 clamp(const t1 &value, const t2 &low, const t3 &high)
+	{
+		if ( value > high)
+			return high;
+
+		if ( value < low)
+			return low;
+
+		return value;
+	}
+
+
 	//makes a to fit the range <b, c>
 	template <typename t1, typename t2, typename t3>
 	t1 &abetween(t1 &a, const t2 &b, const t3 &c)

+ 7 - 5
client/adventureMap/CAdvMapInt.cpp

@@ -592,20 +592,22 @@ void CAdvMapInt::show(SDL_Surface * to)
 
 void CAdvMapInt::handleMapScrollingUpdate()
 {
-	int scrollSpeed = static_cast<int>(settings["adventure"]["scrollSpeed"].Float());
+	uint32_t timePassed = GH.mainFPSmng->getElapsedMilliseconds();
+	double scrollSpeedPixels = settings["adventure"]["scrollSpeedPixels"].Float();
+	int32_t scrollDistance = static_cast<int32_t>(scrollSpeedPixels * timePassed / 1000);
 	//if advmap needs updating AND (no dialog is shown OR ctrl is pressed)
 
 	if(scrollingDir & LEFT)
-		terrain->moveViewBy(Point(-scrollSpeed, 0));
+		terrain->moveViewBy(Point(-scrollDistance, 0));
 
 	if(scrollingDir & RIGHT)
-		terrain->moveViewBy(Point(+scrollSpeed, 0));
+		terrain->moveViewBy(Point(+scrollDistance, 0));
 
 	if(scrollingDir & UP)
-		terrain->moveViewBy(Point(0, -scrollSpeed));
+		terrain->moveViewBy(Point(0, -scrollDistance));
 
 	if(scrollingDir & DOWN)
-		terrain->moveViewBy(Point(0, +scrollSpeed));
+		terrain->moveViewBy(Point(0, +scrollDistance));
 
 	if(scrollingDir)
 	{

+ 1 - 2
client/adventureMap/MapRenderer.cpp

@@ -396,8 +396,7 @@ std::shared_ptr<IImage> MapRendererObjects::getImage(const IMapRendererContext &
 	if(animation->size(groupIndex) == 0)
 		return nullptr;
 
-	size_t frameCounter = context.getAnimationTime() / context.getAnimationPeriod();
-	size_t frameIndex = frameCounter % animation->size(groupIndex);
+	size_t frameIndex = context.objectImageIndex(obj->id, animation->size(groupIndex));
 
 	return animation->getImage(frameIndex, groupIndex);
 }

+ 2 - 5
client/adventureMap/MapRendererContext.h

@@ -58,11 +58,8 @@ public:
 	/// returns object animation transparency. IF set to 0, object will not be visible
 	virtual double objectTransparency(ObjectInstanceID objectID) const = 0;
 
-	/// returns how long should each frame of animation be visible, in milliseconds
-	virtual uint32_t getAnimationPeriod() const = 0;
-
-	/// returns total animation time since creation of this context
-	virtual uint32_t getAnimationTime() const = 0;
+	/// returns animation frame for selected object
+	virtual size_t objectImageIndex(ObjectInstanceID objectID, size_t groupSize) const = 0;
 
 	/// returns size of ouput tile, in pixels. 32x32 for "standard" map, may be smaller for world view mode
 	virtual Point getTileSize() const = 0;

+ 39 - 18
client/adventureMap/MapView.cpp

@@ -166,19 +166,24 @@ const CGPath * MapRendererContext::currentPath() const
 	return &LOCPLINT->paths.getPath(hero);
 }
 
-uint32_t MapRendererContext::getAnimationPeriod() const
+size_t MapRendererContext::objectImageIndex(ObjectInstanceID objectID, size_t groupSize) const
 {
+	assert(groupSize > 0);
+	if (groupSize == 0)
+		return 0;
+
 	// H3 timing for adventure map objects animation is 180 ms
 	// Terrain animations also use identical interval, however those are only present in HotA and/or HD Mod
-	// TODO: duration of fade-in/fade-out for teleport, entering/leaving boat, removal of objects
-	// TOOD: duration of hero movement animation, frame timing of hero movement animation, effect of hero speed option
-	// TOOD: duration of enemy hero movement animation, frame timing of enemy hero movement animation, effect of enemy hero speed option
-	return 180;
-}
+	size_t baseFrameTime = 180;
 
-uint32_t MapRendererContext::getAnimationTime() const
-{
-	return animationTime;
+	// hero movement animation always plays at ~50ms / frame
+	// in-game setting only affect movement across screen
+	if (movementAnimation && movementAnimation->target == objectID)
+		 baseFrameTime = 50;
+
+	size_t frameCounter = animationTime / baseFrameTime;
+	size_t frameIndex = frameCounter % groupSize;
+	return frameIndex;
 }
 
 Point MapRendererContext::getTileSize() const
@@ -193,14 +198,19 @@ bool MapRendererContext::showGrid() const
 
 void MapViewController::setViewCenter(const int3 & position)
 {
-	model->setViewCenter(Point(position.x, position.y) * model->getSingleTileSize());
-	model->setLevel(position.z);
+	assert(context->isInMap(position));
+	setViewCenter(Point(position) * model->getSingleTileSize(), position.z);
 }
 
 void MapViewController::setViewCenter(const Point & position, int level)
 {
-	model->setViewCenter(position);
-	model->setLevel(level);
+	Point betterPosition = {
+		vstd::clamp(position.x, 0, context->getMapSize().x * model->getSingleTileSize().x),
+		vstd::clamp(position.y, 0, context->getMapSize().y * model->getSingleTileSize().y)
+	};
+
+	model->setViewCenter(betterPosition);
+	model->setLevel(vstd::clamp(level, 0, context->getMapSize().z));
 }
 
 void MapViewController::setTileSize(const Point & tileSize)
@@ -452,14 +462,16 @@ void MapViewController::update(uint32_t timeDelta)
 {
 	static const double fadeOutDuration = 1.0;
 	static const double fadeInDuration = 1.0;
-	static const double heroMoveDuration = 1.0;
 	static const double heroTeleportDuration = 1.0;
 
 	//FIXME: remove code duplication?
 
 	if (context->movementAnimation)
 	{
-		context->movementAnimation->progress += heroMoveDuration * timeDelta / 1000;
+		// TODO: enemyMoveTime
+		double heroMoveTime = settings["adventure"]["heroMoveTime"].Float();
+
+		context->movementAnimation->progress += timeDelta / heroMoveTime;
 
 		Point positionFrom = Point(context->movementAnimation->tileFrom) * model->getSingleTileSize();
 		Point positionDest = Point(context->movementAnimation->tileDest) * model->getSingleTileSize();
@@ -503,7 +515,7 @@ void MapViewController::update(uint32_t timeDelta)
 	}
 
 	context->animationTime += timeDelta;
-	context->tileSize =model->getSingleTileSize();
+	context->tileSize = model->getSingleTileSize();
 }
 
 void MapViewController::onObjectFadeIn(const CGObjectInstance * obj)
@@ -539,8 +551,17 @@ void MapViewController::onHeroMoved(const CGHeroInstance * obj, const int3 & fro
 {
 	assert(!context->movementAnimation);
 	context->removeObject(obj);
-	context->addMovingObject(obj, from, dest);
-	context->movementAnimation = HeroAnimationState{ obj->id, from, dest, 0.0 };
+
+	if (settings["adventure"]["heroMoveTime"].Float() > 1)
+	{
+		context->addMovingObject(obj, from, dest);
+		context->movementAnimation = HeroAnimationState{ obj->id, from, dest, 0.0 };
+	}
+	else
+	{
+		// instant movement
+		context->addObject(obj);
+	}
 }
 
 void MapViewController::onHeroRotated(const CGHeroInstance * obj, const int3 & from, const int3 & dest)

+ 1 - 2
client/adventureMap/MapView.h

@@ -65,8 +65,7 @@ public:
 	size_t objectGroupIndex(ObjectInstanceID objectID) const override;
 	Point objectImageOffset(ObjectInstanceID objectID, const int3 & coordinates) const override;
 	double objectTransparency(ObjectInstanceID objectID) const override;
-	uint32_t getAnimationPeriod() const override;
-	uint32_t getAnimationTime() const override;
+	size_t objectImageIndex(ObjectInstanceID objectID, size_t groupSize) const override;
 	Point getTileSize() const override;
 	bool showGrid() const override;
 };

+ 0 - 1
client/windows/GUIClasses.cpp

@@ -424,7 +424,6 @@ CLevelWindow::~CLevelWindow()
 	LOCPLINT->showingDialog->setn(false);
 }
 
-
 CTavernWindow::CTavernWindow(const CGObjectInstance * TavernObj)
 	: CStatusbarWindow(PLAYER_COLORED, "TPTAVERN"),
 	tavernObj(TavernObj)

+ 4 - 4
client/windows/settings/AdventureOptionsTab.cpp

@@ -37,15 +37,15 @@ AdventureOptionsTab::AdventureOptionsTab()
 	const JsonNode config(ResourceID("config/widgets/settings/adventureOptionsTab.json"));
 	addCallback("playerHeroSpeedChanged", [](int value)
 	{
-		return setIntSetting("adventure", "heroSpeed", value);
+		return setIntSetting("adventure", "heroMoveTime", value);
 	});
 	addCallback("enemyHeroSpeedChanged", [](int value)
 	{
-		return setIntSetting("adventure", "enemySpeed", value);
+		return setIntSetting("adventure", "enemyMoveTime", value);
 	});
 	addCallback("mapScrollSpeedChanged", [](int value)
 	{
-		return setIntSetting("adventure", "scrollSpeed", value);
+		return setIntSetting("adventure", "scrollSpeedPixels", value);
 	});
 	addCallback("heroReminderChanged", [](bool value)
 	{
@@ -93,4 +93,4 @@ AdventureOptionsTab::AdventureOptionsTab()
 
 	std::shared_ptr<CToggleButton> showGridCheckbox = widget<CToggleButton>("showGridCheckbox");
 	showGridCheckbox->setSelected(settings["gameTweaks"]["showGrid"].Bool());
-}
+}

+ 7 - 7
config/schemas/settings.json

@@ -161,19 +161,19 @@
 			"type" : "object",
 			"additionalProperties" : false,
 			"default": {},
-			"required" : [ "heroSpeed", "enemySpeed", "scrollSpeed", "heroReminder", "quickCombat" ],
+			"required" : [ "heroMoveTime", "enemyMoveTime", "scrollSpeedPixels", "heroReminder", "quickCombat" ],
 			"properties" : {
-				"heroSpeed" : {
+				"heroMoveTime" : {
 					"type" : "number",
-					"default" : 2
+					"default" : 150
 				},
-				"enemySpeed" : {
+				"enemyMoveTime" : {
 					"type" : "number",
-					"default" : 2
+					"default" : 150
 				},
-				"scrollSpeed" : {
+				"scrollSpeedPixels" : {
 					"type" : "number",
-					"default" : 1
+					"default" : 800
 				},
 				"heroReminder" : {
 					"type" : "boolean",

+ 12 - 12
config/widgets/settings/adventureOptionsTab.json

@@ -31,7 +31,7 @@
 			"items":
 			[
 				{
-					"index": 1,
+					"index": 200,
 					"type": "toggleButton",
 					"image": "sysopb1",
 					"help": "core.help.349",
@@ -39,7 +39,7 @@
 				},
 
 				{
-					"index": 2,
+					"index": 150,
 					"type": "toggleButton",
 					"image": "sysopb2",
 					"help": "core.help.350",
@@ -47,7 +47,7 @@
 				},
 
 				{
-					"index": 4,
+					"index": 100,
 					"type": "toggleButton",
 					"image": "sysopb3",
 					"help": "core.help.351",
@@ -55,7 +55,7 @@
 				},
 
 				{
-					"index": 16,
+					"index": 0,
 					"type": "toggleButton",
 					"image": "sysopb4",
 					"help": "core.help.352",
@@ -80,7 +80,7 @@
 			"items":
 			[
 				{
-					"index": 2,
+					"index": 150,
 					"type": "toggleButton",
 					"image": "sysopb5",
 					"help": "core.help.353",
@@ -88,7 +88,7 @@
 				},
 
 				{
-					"index": 4,
+					"index": 100,
 					"type": "toggleButton",
 					"image": "sysopb6",
 					"help": "core.help.354",
@@ -96,7 +96,7 @@
 				},
 
 				{
-					"index": 8,
+					"index": 0,
 					"type": "toggleButton",
 					"image": "sysopb7",
 					"help": "core.help.355",
@@ -104,7 +104,7 @@
 				},
 
 				{
-					"index": 0,
+					"index": -1,
 					"type": "toggleButton",
 					"image": "sysopb8",
 					"help": "core.help.356",
@@ -121,7 +121,7 @@
 			"items":
 			[
 				{
-					"index": 1,
+					"index": 400,
 					"type": "toggleButton",
 					"image": "sysopb9",
 					"help": "core.help.357",
@@ -129,7 +129,7 @@
 				},
 
 				{
-					"index": 2,
+					"index": 800,
 					"type": "toggleButton",
 					"image": "sysob10",
 					"help": "core.help.358",
@@ -137,7 +137,7 @@
 				},
 
 				{
-					"index": 4,
+					"index": 1200,
 					"type": "toggleButton",
 					"image": "sysob11",
 					"help": "core.help.359",
@@ -264,4 +264,4 @@
 			"callback": "showGridChanged"
 		}
 	]
-}
+}