Question regarding "Unit:Convert(unit)"

Mezzzzz

Chieftain
Joined
Jun 1, 2014
Messages
29
Location
Paris area, France
Hello,

I'd like to know if it is possible to turn one of your own unit into a barbarian unit?
I assume the Unit:Convert(unit) lua feature allows such thing.

The closest thing I've found so far is the Bucaneers mod by Pouakai although the UA indicates units may switch sides, not turn into barbarian.

Thanks for your insight :)
 
You mean have the unit taken away from you and given to the Barbs?

I would think it would, but remember that you have to init the 'new' unit before you can do the convert, and the unit init requires the player pointer info. Luckily for the barbs the player ID is always 63 (unless perhaps you are using one of the crazy barb mods).

--------------------------------------------------------------------------------------------

I assume this would work, though 1st you have to get the original unit's "pOldUnit" pointer:
Code:
local iUnitType = pOldUnit:GetUnitType()
local pBarbPlayer = Players[63]
local pNewUnit = pBarbPlayer:InitUnit(iUnitType, pOldUnit:GetX(), pOldUnit:GetY())
pNewUnit:Convert(pOldUnit)
Even if the game refuses to "Convert" across players, you can always grab the needed data from the original Unit, Kill it using pOldUnit:Kill(), and then create a new unit for the Barb player based on the info you grabbed before you killed the original unit.
 
Thanks for your quick reply. My goal is to turn a unit which has just spawned into a barbarian which triggers an alert.
Ex: you build a warrior in your capital, warrior spawns, turns barbarian, stays on your territory and mess with your tiles.

Your snippet was useful although it still eludes me to understand what I'm doing wrong.
Would you care to explain me where is my mistake? Here's the code I've got so far:

Code:
local pPlayer		= Players[playerID]
local pBarbPlayer	= Players[63]
local pNewUnit		= pBarbPlayer:InitUnit(pUnit:GetUnitType(), pUnit:GetX(), pUnit:GetY())
local Description	= Locale.ConvertTextKey("TXT_KEY_STRING")
local DescriptionShort	= Locale.ConvertTextKey("TXT_KEY_STRING_SHORT")

function ConvertToBarbarian(playerID)
    for pUnit in pPlayer:Units() do
		if pUnit:GetUnitType() == GameInfoTypes["UNIT_DUMMY_UNIT"] then
			pNewUnit:Convert(pUnit)
			if pPlayer:IsHuman() then
				Players[Game.GetActivePlayer()]:AddNotification(NotificationTypes["NOTIFICATION_BARBARIAN"], Description, DescriptionShort)
				Events.AudioPlay2DSound("AS2D_EVENT_NOTIFICATION_VERY_BAD")
			end
		end
    end
end
Events.SerialEventUnitCreated.Add(ConvertToBarbarian)
 
Even if the game refuses to "Convert" across players, you can always grab the needed data from the original Unit, Kill it using pOldUnit:Kill(), and then create a new unit for the Barb player based on the info you grabbed before you killed the original unit.

It does let you convert across players, but you have to manually kill the original unit when doing so.
 
  1. As soon as you mention a unit created in a city, then replacing that unit with a barb unit, you open additional levels of complexity that have to be resolved.
  2. If any two players are at war, and you spawn a unit for Player-B in a city belonging to Player-A, you are in fact giving the city to Player-B. Even placing the unit and then instantly removing it can cause this city-ownership conversion.
    • Since Barbs are always at war with every other player, you must not spawn a barb unit in a city belonging to a 'real' player.
  3. What is needed is to find a plot that is safe to spawn the barb unit. The plot has to conform to at least these conditions:
    • It has to be the correct Domain for the original unit that is being converted
    • Only the original unit that is to be converted can be on the plot. (Otherwise, any additional unit on the same plot will be destroyed by the placement of the Barb unit on the plot)
    • If the unit is a land unit, the plot cannot be a mountain.
    • If the unit is a land unit, the plot cannot be a city plot. (This restriction is not relevant for a Sea unit because the plot has to be a non-Lake Water plot, which means it cannot be a city plot)
    • If any of these conditions are not met, then the conversion to a Barb unit should not be done.
  4. I believe the following code will accomplish all this, but the code does not address the larger question of how the original unit is created. I certainly would not build a unit in my city if I knew it was going to be converted into a Barb unit and pillage stuff around my city.
  5. Also I did not investigate the correctness of your code for the notification, nor did I alter your references to TXT_KEYS for the Description and DescriptionShort.
Code:
local iBarbarianPlayerID = 63
local iDummyUnit = GameInfoTypes["UNIT_DUMMY_UNIT"]
local sDummyUnitDomain = GameInfo.Units[iDummyUnit].Domain
local bRequiresLand = (sDummyUnitDomain == "DOMAIN_LAND")
local bRequiresSea = (sDummyUnitDomain == "DOMAIN_SEA")
local bRequiresAir = (sDummyUnitDomain == "DOMAIN_AIR")
local Description = Locale.ConvertTextKey("TXT_KEY_STRING")
local DescriptionShort = Locale.ConvertTextKey("TXT_KEY_STRING_SHORT")

function ConvertToBarbarian(PlayerID, UnitID, hexVec, unitType, cultureType, civID, primaryColor, secondaryColor, unitFlagIndex, fogState)
	if PlayerID ~= iBarbarianPlayerID then
		local pPlayer = Players[PlayerID]
		local pOldUnit = pPlayer:GetUnitByID(UnitID)
		if(pOldUnit == nil or
			pOldUnit:IsDead()) then
			return
		end
		local iUnitType = pOldUnit:GetUnitType()
		if iUnitType == iDummyUnit then
			local pPlot = pOldUnit:GetPlot()
			local iSpawnX, iSpawnY = pPlot:GetX(), pPlot:GetY()
			local bProperSpawnPlotFound = false
			if pPlot:IsCity() or (pPlot:GetNumUnits() > 1) then
				for direction = 0, DirectionTypes.NUM_DIRECTION_TYPES - 1, 1 do
					local pAdjacentPlot = Map.PlotDirection(pPlot:GetX(), pPlot:GetY(), direction)
					if pAdjacentPlot and not pAdjacentPlot:IsUnit() then
						if bRequiresLand then
							if (not pAdjacentPlot:IsCity()) and (not pAdjacentPlot:IsLake()) and (not pAdjacentPlot:IsWater()) and (not pAdjacentPlot:IsMountain()) then
								iSpawnX, iSpawnY = pAdjacentPlot:GetX(), pAdjacentPlot:GetY()
								bProperSpawnPlotFound = true
								break
							end
						elseif bRequiresSea then
							if (not pAdjacentPlot:IsLake()) and (pAdjacentPlot:IsWater()) then
								iSpawnX, iSpawnY = pAdjacentPlot:GetX(), pAdjacentPlot:GetY()
								bProperSpawnPlotFound = true
								break
							end
						end
					end
				end
			else
				if not bRequiresAir then
					bProperSpawnPlotFound = true
				end
			end
			if bProperSpawnPlotFound then
				local pBarbPlayer = Players[iBarbarianPlayerID]
				local pNewUnit = pBarbPlayer:InitUnit(iUnitType, iSpawnX, iSpawnY)
				pNewUnit:Convert(pOldUnit)
				if pOldUnit then
					pOldUnit:Kill()
				end
				if pPlayer:IsHuman() then
					pPlayer:AddNotification(NotificationTypes["NOTIFICATION_BARBARIAN"], Description, DescriptionShort)
					Events.AudioPlay2DSound("AS2D_EVENT_NOTIFICATION_VERY_BAD")
				end
			end
		end
	end
end
Events.SerialEventUnitCreated.Add(ConvertToBarbarian)
An alternative method would be to always kill off the original unit regardless of whether the conversion to a Barb unit ever occured. See the differences highlighted in blue in the spoiler:
Spoiler :
Code:
local iBarbarianPlayerID = 63
local iDummyUnit = GameInfoTypes["UNIT_DUMMY_UNIT"]
local sDummyUnitDomain = GameInfo.Units[iDummyUnit].Domain
local bRequiresLand = (sDummyUnitDomain == "DOMAIN_LAND")
local bRequiresSea = (sDummyUnitDomain == "DOMAIN_SEA")
local bRequiresAir = (sDummyUnitDomain == "DOMAIN_AIR")
local Description = Locale.ConvertTextKey("TXT_KEY_STRING")
local DescriptionShort = Locale.ConvertTextKey("TXT_KEY_STRING_SHORT")

function ConvertToBarbarian(PlayerID, UnitID, hexVec, unitType, cultureType, civID, primaryColor, secondaryColor, unitFlagIndex, fogState)
	if PlayerID ~= iBarbarianPlayerID then
		local pPlayer = Players[PlayerID]
		local pOldUnit = pPlayer:GetUnitByID(UnitID)
		if(pOldUnit == nil or
			pOldUnit:IsDead()) then
			return
		end
		local iUnitType = pOldUnit:GetUnitType()
		if iUnitType == iDummyUnit then
			local pPlot = pOldUnit:GetPlot()
			local iSpawnX, iSpawnY = pPlot:GetX(), pPlot:GetY()
			local bProperSpawnPlotFound = false
			if pPlot:IsCity() or (pPlot:GetNumUnits() > 1) then
				for direction = 0, DirectionTypes.NUM_DIRECTION_TYPES - 1, 1 do
					local pAdjacentPlot = Map.PlotDirection(pPlot:GetX(), pPlot:GetY(), direction)
					if pAdjacentPlot and not pAdjacentPlot:IsUnit() then
						if bRequiresLand then
							if (not pAdjacentPlot:IsCity()) and (not pAdjacentPlot:IsLake()) and (not pAdjacentPlot:IsWater()) and (not pAdjacentPlot:IsMountain()) then
								iSpawnX, iSpawnY = pAdjacentPlot:GetX(), pAdjacentPlot:GetY()
								bProperSpawnPlotFound = true
								break
							end
						elseif bRequiresSea then
							if (not pAdjacentPlot:IsLake()) and (pAdjacentPlot:IsWater()) then
								iSpawnX, iSpawnY = pAdjacentPlot:GetX(), pAdjacentPlot:GetY()
								bProperSpawnPlotFound = true
								break
							end
						end
					end
				end
			else
				if not bRequiresAir then
					bProperSpawnPlotFound = true
				end
			end
			[color="blue"]if bProperSpawnPlotFound then
				local pBarbPlayer = Players[iBarbarianPlayerID]
				local pNewUnit = pBarbPlayer:InitUnit(iUnitType, iSpawnX, iSpawnY)
				pNewUnit:Convert(pOldUnit)
				if pPlayer:IsHuman() then
					pPlayer:AddNotification(NotificationTypes["NOTIFICATION_BARBARIAN"], Description, DescriptionShort)
					Events.AudioPlay2DSound("AS2D_EVENT_NOTIFICATION_VERY_BAD")
				end
			end
			if pOldUnit then
				pOldUnit:Kill()
			end[/color]
		end
	end
end
Events.SerialEventUnitCreated.Add(ConvertToBarbarian)
 
Hello LeeS,

I haven't had a chance to try your solution yet but I really appreciate you took the time to help me. It's not the first time, so, if I there's anything I can help you with, such as icons, loading map, civilopedia or translation etc., feel free to ask.

Mezzzzz.
 
Back
Top Bottom