Keeping the boys home...?

sman1975

Emperor
Joined
Aug 27, 2016
Messages
1,370
Location
Dallas, TX
Hello,

I'm working on a WW2 Era mod that adds some militia units to the game. They are much weaker than normal units, with other restrictions as well.

It also seems appropriate that these units should never really leave friendly territory.

In test games, I've noticed the AI uses these militia like normal units, sending them straight to the front lines. Tends to add an ahistorical behavior that weakens the immersive qualities I'm trying hard to introduce.

I've played around with a few solutions, but they aren't working well. TBH, they're downright ugly, processor-intensive, and not reliable. Three things you don't want in your code.

Was hoping someone could point me in the direction of a way of ensuring these units remain in friendly (or at least not in enemy) territory?

Thanks in advance!

sman1975
 
Custom DLL or standard game? If the former, you can use the CanMoveInto (or whatever it's called) event. See my "Units - Railroad Artillery" mod
 
  1. Basic code method I've used to keep rival combat-units close to their home territory so long as there are any goody huts still on the game-map.
  2. I've deleted (I think) anything related to goody huts.
  3. You'd have to adapt the code a bit to specifically look at whether the unit in question is one of the militia units, and determine your 'best' value for 'iMaxWanderingDistance'.
  4. Since it runs on PlayerDoTurn it isn't as apparently processing-heavy as it actually is. PlayerDoTurn methods usually don't "seem" to the human player like they are doing much in terms of creating lag or bog-down unless of course the code is really long and really heavy in logic and execution of all that logic. It's usually the solution I go to for these sorts of things where it isn't actually necessary to execute on a real-time trigger hook-event.
Code:
local iMaxWanderingDistance = 8
local iDomainLand = GameInfoTypes.DOMAIN_LAND

-----------------------------------------------------------------------------------------
-- Get nearest city belonging to 'pPlayer' to plot 'pPlot'
-- data is returned as NearestCityObject, NearestCityDistance
-- so you would use as like: "local pCity, iDistance = GetNearestCityData(pPlot, pPlayer)"
-----------------------------------------------------------------------------------------

function GetNearestCityData(pPlot, pPlayer)
	local pNearestCity, iNearestDistance = "NONE", 9999
	for pCity in pPlayer:Cities() do
		local iDistance = Map.PlotDistance(pPlot:GetX(), pPlot:GetY(), pCity:GetX(), pCity:GetY())
		if (iDistance < iNearestDistance) then
			iNearestDistance = iDistance
			pNearestCity = pCity
		end
	end
	return pNearestCity, iNearestDistance
end
function PlayerDoTurnRepositionRivalUnits(iPlayer)
	local pPlayer = Players[iPlayer]
	if pPlayer:IsBarbarian() then return end
	if pPlayer:IsHuman() then return end
	if pPlayer:IsMinorCiv() then return end
	local sPlayerName = pPlayer:GetName()
	--print("PlayerDoTurnRepositionRivalUnits: The event ran for " .. sPlayerName)
	for pUnit in pPlayer:Units() do
		if pUnit:IsCombatUnit() then
			if pUnit:GetDomainType() == iDomainLand then
				local pUnitPlot = pUnit:GetPlot()
				local pNearestCity, iDistanceToNearestCity = GetNearestCityData(pUnitPlot, pPlayer)
				if iDistanceToNearestCity >= iMaxWanderingDistance then
					if pNearestCity ~= "NONE" then
						local iStartingX, iStartingY = pUnit:GetX(), pUnit:GetY()
						pUnit:SetXY(pNearestCity:GetX(), pNearestCity:GetY())
						pUnit:JumpToNearestValidPlot()
						print("A unit belonging to " .. sPlayerName .. " was re-positioned from " .. iStartingX .. "," .. iStartingY .. " to " .. pUnit:GetX() .. "," .. pUnit:GetY())
					else
						--print("A unit belonging to " .. sPlayerName .. " should have been re-positioned from " .. pUnit:GetX() .. "," .. pUnit:GetY() .. " but this failed because the pNearestCity data was invalid")
					end
				else
					--print("A unit belonging to " .. sPlayerName .. " did not need to be re-positioned from " .. pUnit:GetX() .. "," .. pUnit:GetY())
				end
			end
		end
	end
end
GameEvents.PlayerDoTurn.Add(PlayerDoTurnRepositionRivalUnits)
 
@LeeS - I don't know if I'm lucky or finally starting to learn a thing or two... :think:

I've been testing a strikingly similar function - the only real difference is where you use SetXY + JumpToNearestValidPlot, I was only conducting the test every 3 turns, then using a PushMission (MISSION_MOVE_TO) for any unit that is a militia or partisan unit.

From just a few test games, it "looked" like it was working acceptably, but I haven't put it through it's paces. The militia, with a move of 1, don't wander too far before "most of the time" it looked like they were heading home. The partisans, with a move of 2, had more opportunity for mischief, looked to be behaving properly about half of the time.

I think your code is (as always) much more determinative than mine, but I was wondering: if you don't have "quick moves" turned on, how does the forced move (teleport?) look on the map? Hinkey? Or "good enough?"

Thanks again, Mon! Really appreciate the solid suggestions! :thumbsup:
 
The thing I like about your approach is you have 100% control over what unit is where. I feel that often when I use PushMission, it is me making a suggestion to the AI, and sometimes they follow, sometimes they don't.

But in this case, my absolute #1 design criterion is that you cannot expect the Volkssturm to be invading other nations. Just breaks the realism/immersive qualities I'm trying to make sure are in the scenario.

No brainer to me (familiar territory, one might say...) - thanks for the code, @LeeS - it's going in the mod, making a fine bookend to the UnitSpawnHandler that is making it into the 3 mods I'm currently developing.

Appreciate it!
 
Yeah, the AI can and usually does override a Push Mission, so in order to preserve the mission you want the unit to do you have to keep coming back every turn (or on some other trigger event) and re-send the Push Mission if the AI has overridden it. I think some (or most) of the over-ride on a MOVE_TO is caused by pathing 'interferences' because the game's pathing system does not consider that while the target plot (for example) is currently blocked the unit that is moving to that plot is still 20 turns away from getting there.
 
Top Bottom