A couple more "quick" inquiries

Can't find it on the UI reference. :/ What parameters does it pass?
Also, do you know if it's G&K-compatible?
 
So, the algorithm isn't working... :/
Spoiler :
Code:
GameEvents.UnitPrekill.Add(
function(iOwner, iUnit, iUnitType, iX, iY, bDelay, iKiller)
	print("")
	print("GameEvents.UnitPrekill("..tostring(iOwner)..", "..tostring(iUnit)..", "..tostring(iUnitType)..", "..tostring(iX)..", "..tostring(iY)..", "..tostring(bDelay)..", "..tostring(iKiller)..")")
	if (iKiller < 0) then return end -- this is so that it's not impossible to manually delete your unit - I learned the hard way that this needs to be here :P
	if (iUnitType == GameInfoTypes.UNIT_AW_UNIT) then return end
	local pPlayer = Players[iOwner]
	local pUnit = pPlayer:GetUnitByID(iUnit)
	if not bDelay then
		print("Trying to resurrect the unit")
		print("Identifying resurrectable properties;")

		-- INDENTIFY PROMOTIONS --

		local tPromotions = {}
		for row in GameInfo.UnitPromotions() do if (pUnit:IsHasPromotion(row.ID)) then table.insert(tPromotions, row.ID) end end -- Have fun reading that :p

		-- FIND EXPERIENCE

		local iExperience = pUnit:GetExperience() + GameInfo.Units[GameInfoTypes.UNIT_AW_UNIT].XPValueDefense
		
		-- RESURRECT UNIT --

		print("Resurrecting unit;")
		local pNewUnit = pPlayer:InitUnit(GameInfoTypes.UNIT_AW_UNIT, iX, iY)
		pNewUnit:SetExperience(iExperience)
		for k,v in pairs(tPromotions) do pMetsikhovne:SetHasPromotion(v, true) end
		print("unit brought back from the brink of death!")
		Events.GameplayAlertMessage("Invincible HAXX0R unit saved by the power of illuminarty")
	else	-- find the killer and whisk them off the plot (heaven forbid that we should move)
		print("Firing to move the heathen enemy unit;")
		for mUnit in Players[iKiller]:Units() do
			if (mUnit:GetPlot() == Map.GetPlot(iX, iY)) then
				MoveUnitBackwards(mUnit)
				print("Heathen enemy unit moved back!")
			end
		end
	end
end)
It was able to resurrect the unit, until I discovered that that wouldn't stop the killer unit from still wandering onto the plot. And so I basically ended up with a unit on the same plot as 6 enemy units, when I surrounded it with 6 Barbarian marines so it would be instantly killed... :crazyeye:
So I added in the last segment of code (beginning with "else"), which is supposed to push the killer unit back one tile after being killed - that's the MoveUnitBackwards() function at the end of the code:
Spoiler :
Code:
function MoveUnitBackwards(pUnit, numTiles)
	if (numTiles == nil) then numTiles = 1 end
	local iFacingDirection = pUnit:GetFacingDirection()
	-- so we need to find the opposite direction of that; that's the direction we want to move the unit
	local iDirectionChange = math.ceil(DirectionTypes.NUM_DIRECTION_TYPES / 2)
	local iDirectionToMove = iFacingDirection - iDirectionChange
	if (iDirectionToMove < 0) then -- whoops! We screwed this up and subtracted when we should've added
		iDirectionToMove = iDirectionToMove + (2 * iDirectionChange)
	end
	-- so now we have the opposite direction, now we need to figure out the target tile
	-- so I guess I'll find the adjacent tile, and then if numTiles > 1, find that adjacent tile, and if numTiles > 2, find the next adjacent tile...
	local pPlot = pUnit:GetPlot()
	local iX = pPlot:GetX()
	local iY = pPlot:GetY()
	local toPlot
	for i = 0, numTiles, 1 do
		toPlot = Map.PlotDirection(iX, iY, iDirectionToMove)
		iX = toPlot:GetX()
		iY = toPlot:GetY()
	end
	pUnit:SetXY(iX, iY)
end
And now... the unit just dies and nothing else happens.
I'm pretty sure you should be able to plug the code into any mod and change UNIT_AW_UNIT to whatever else you want, add one to the game via IGE, surround with Barbs, and see for yourself.
 
without looking into anything else, there's a problem right here: "pMetsikhovne:SetHasPromotion(v, true)". This is undefined so far as I can see: pMetsikhovne.

Don't try to recreate the 'killed' unit on the same plot as this is bound to have troubles, just shift the resurrected unit to the nearest valid plot.
Code:
local tPromotions = {}
for row in GameInfo.UnitPromotions() do if (pUnit:IsHasPromotion(row.ID)) then table.insert(tPromotions, row.ID) end end -- Have fun reading that :p
local iLevel = pUnit:GetLevel()
local iExperience = pUnit:GetExperience() + GameInfo.Units[GameInfoTypes.UNIT_AW_UNIT].XPValueDefense
local pNewUnit = pPlayer:InitUnit(GameInfoTypes.UNIT_AW_UNIT, iX, iY)
[COLOR="Blue"]pNewUnit:JumpToNearestValidPlot()[/COLOR]
pNewUnit:SetExperience(iExperience)
pNewUnit:SetLevel(iLevel)

for k,v in pairs(tPromotions) do pNewUnit:SetHasPromotion(v, true) end
print("unit brought back from the brink of death!")
If you want to you can then reposition the enemy unit that occupied the original tile, and re-position pNewUnit to the original tile where it was positioned, and then re-re-position the enemy unit.

The other thing you are not doing is setting any damage to pNewUnit, so not only does it get resurrected, it gets returned to 100% health.

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

edit -->

  • bDelay returns true before unit is killed (before UnitKilledInCombat) and there will be only one unit on the plot
  • bDelay returns false after the unit is killed (after UnitKilledInCombat) and an enemy melee unit may be on the same plot at this point. Both the victorious unit and the defeated unit will be 'seen as' occupying the plot at this point, as well as any civilian unit which survived the combat.

  • iKiller will be the ID # of the victorious player only when bDelay is true (edit: and there was actual combat)
  • iKiller will be '-1' when bDelay is false
  • the only way that iKiller can be '-1' and bDelay can be true is if you kill off your own unit, for example, use a settler to create a city.
  • the only way that bDelay can be false and iKiller can be anything except '-1' is if a Barb (for example) kills off a civilian unit. It is the civilian unit that is the key to the behavior in this case.

You actually need to run your code when bDelay is 'false' and when 'iKiller' is '-1', because then all units seen under the event as being 'on the plot' will still give valid data, including the unit that is 'dead', as well as any civilian units that were on the plot and under the protection of the defeated unit. Plus, the game is not still in the process of killing off the defeated unit, which it still is in the method you are employing.
 
without looking into anything else, there's a problem right here: "pMetsikhovne:SetHasPromotion(v, true)". This is undefined so far as I can see: pMetsikhovne.
"pMetsikhovne" is just the name of the variable that I renamed to pNewUnit for the purpose of posting this code here. Redaction, you know. Secrecy. Looks I missed one though. :/
Don't try to recreate the 'killed' unit on the same plot as this is bound to have troubles, just shift the resurrected unit to the nearest valid plot.
Code:
local tPromotions = {}
for row in GameInfo.UnitPromotions() do if (pUnit:IsHasPromotion(row.ID)) then table.insert(tPromotions, row.ID) end end -- Have fun reading that :p
local iLevel = pUnit:GetLevel()
local iExperience = pUnit:GetExperience() + GameInfo.Units[GameInfoTypes.UNIT_AW_UNIT].XPValueDefense
local pNewUnit = pPlayer:InitUnit(GameInfoTypes.UNIT_AW_UNIT, iX, iY)
[COLOR="Blue"]pNewUnit:JumpToNearestValidPlot()[/COLOR]
pNewUnit:SetExperience(iExperience)
pNewUnit:SetLevel(iLevel)

for k,v in pairs(tPromotions) do pNewUnit:SetHasPromotion(v, true) end
print("unit brought back from the brink of death!")
If you want to you can then reposition the enemy unit that occupied the original tile, and re-position pNewUnit to the original tile where it was positioned, and then re-re-position the enemy unit.
I'm wary of Unit.JumpToNearestValidPlot(). During an earlier test, I believe that line was somewhere in the code, and my unit got teleported some ridiculous number of tiles away and, surprise! I suddenly meet Shaka because my unit died. Plot jumping makes weird things happen. :crazyeye:

The other thing you are not doing is setting any damage to pNewUnit, so not only does it get resurrected, it gets returned to 100% health.
Intended
  • iKiller will be the ID # of the victorious player only when bDelay is true (edit: and there was actual combat)
    [*]iKiller will be '-1' when bDelay is false
  • the only way that iKiller can be '-1' and bDelay can be true is if you kill off your own unit, for example, use a settler to create a city.
  • the only way that bDelay can be false and iKiller can be anything except '-1' is if a Barb (for example) kills off a civilian unit. It is the civilian unit that is the key to the behavior in this case.
So then... this line should've spit out an error:
Code:
for mUnit in Players[iKiller]:Units() do
Because there is no player #-1. But if it never spit out an error, then it must be because it never reached that line... because why?
You actually need to run your code when bDelay is 'false' and when 'iKiller' is '-1', because then all units seen under the event as being 'on the plot' will still give valid data, including the unit that is 'dead', as well as any civilian units that were on the plot and under the protection of the defeated unit. Plus, the game is not still in the process of killing off the defeated unit, which it still is in the method you are employing.
I guess then I would have to have a variable outside of the function that stores the value of iKiller when bDelay = true...

So:
When bDelay = true and 0 <= iKiller <= GameDefines.MAX_MAJOR_CIVS, retrieve iKiller and store outside the function[/INDENT]
Else: move the killer unit THEN proceed to resurrect the dead unit

Should that work, or have I still misunderstood something?
 
"pMetsikhovne" is just the name of the variable that I renamed to pNewUnit for the purpose of posting this code here. Redaction, you know. Secrecy. Looks I missed one though. :/

I'm wary of Unit.JumpToNearestValidPlot(). During an earlier test, I believe that line was somewhere in the code, and my unit got teleported some ridiculous number of tiles away and, surprise! I suddenly meet Shaka because my unit died. Plot jumping makes weird things happen. :crazyeye:


Intended
So then... this line should've spit out an error:
Code:
for mUnit in Players[iKiller]:Units() do
Because there is no player #-1. But if it never spit out an error, then it must be because it never reached that line... because why?

I guess then I would have to have a variable outside of the function that stores the value of iKiller when bDelay = true...

So:
When bDelay = true and 0 <= iKiller <= GameDefines.MAX_MAJOR_CIVS, retrieve iKiller and store outside the function[/INDENT]
Else: move the killer unit THEN proceed to resurrect the dead unit

Should that work, or have I still misunderstood something?

You won't have viable data on the 'killer' until after UnitKilledInCombat fires, ie, when ikiller is -1 and bDelay is false. And then you will only have info for a melee or other direct-attack unit that occupied the target tile as a result of the combat. Ranged units will never 'folloow-up and occuy the tile' so there will never be any usable information on them.

So, yes, you'll need to cache the iKiller info when bDelay is true and then make use of iKiller data you just cached as necessary when bDelay is false. So you'll need a variable outside of the UnitPreKill event that stores this info, which you then stick the 'iKiller' data info when bDelay it true, read back out of when bDelay is false, and then set back to some form of 'nil' value as soon as your code has completed running when bDelay is false.

But you also have to sort out and discard the cases of self-killed units, such as by disbanding. bDelay should be true in such cases, and the ikiller data at that point should be the same as the iOwner data.

Never claimed any of this would be easy -- just claimed it would be possible.

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

Code:
if (iKiller < 0) then return end
Is why you never got a nil value error for trying to index 'Players' with a nil value.
 
So you'll need a variable outside of the UnitPreKill event that stores this info, which you then stick the 'iKiller' data info when bDelay it true, read back out of when bDelay is false, and then set back to some form of 'nil' value as soon as your code has completed running when bDelay is false.

You'll need to use an array/hash and index by a combination of iPlayerId and iUnitId for the dying unit, as the DLL is capable of sending nested events, eg PreKill(A, 1, false), PreKill(B, 2, false), PreKill(B, 2, true), PreKill(A, 1, true)
 
Eh? :confused: But the player and unit IDs are still passed by the game event even when bDelay is false, so I don't understand why they need to be stored. iKiller does need to be stored since its value changes with bDelay, but why are we bringing an extra table into this?

(part of this is that I only understood the first half of your sentence to begin with. :/ "Nested events" are unfamiliar and uncharted lua territories to the 16NP)
 
PreKill(A, 1, false)
PreKill(B, 2, false)
PreKill(B, 2, true)
PreKill(A, 1, true)

The events for the death of B are complete enclosed (nested within) the events for A.

If you use a single variable to remember something from the bDelay=false event, what you remembered for A will be overwritten by that for B so when you get the final event for A you will not be using the remembered value for A but the one for B (or possibly nil, depending on how you code it). So anything you need to remember for a unit between the bDelay=false and bDelay=true events has to be remembered against the unit (which is playerId + unitId)
 
Alright, I understand now, thanks. But looking at the logs, nothing seems to be nesting. I added the table in anyway, just to be safe, though.
But doesn't the killer, then, similarly need to be mapped to the victim player ID, such that it doesn't get screwed up by nesting as well?

The problem, I found, that was completely screwing everything up was...
Spoiler :
Code:
GameEvents.UnitPrekill.Add(
function(iOwner, iUnit, iUnitType, iX, iY, bDelay, iKiller)
	print("")
	print("GameEvents.UnitPrekill("..tostring(iOwner)..", "..tostring(iUnit)..", "..tostring(iUnitType)..", "..tostring(iX)..", "..tostring(iY)..", "..tostring(bDelay)..", "..tostring(iKiller)..")")
	if (iKiller < 0) then return end -- this is so that it's not impossible to manually delete your unit - I learned the hard way that this needs to be here :P
	if (iUnitType [B][COLOR="Red"]==[/COLOR][/B] GameInfoTypes.UNIT_AW_UNIT) then return end
	local pPlayer = Players[iOwner]
	local pUnit = pPlayer:GetUnitByID(iUnit)
	if not bDelay then
		print("Trying to resurrect the unit")
		print("Identifying resurrectable properties;")

		-- INDENTIFY PROMOTIONS --

		local tPromotions = {}
		for row in GameInfo.UnitPromotions() do if (pUnit:IsHasPromotion(row.ID)) then table.insert(tPromotions, row.ID) end end -- Have fun reading that :p

		-- FIND EXPERIENCE

		local iExperience = pUnit:GetExperience() + GameInfo.Units[GameInfoTypes.UNIT_AW_UNIT].XPValueDefense
		
		-- RESURRECT UNIT --

		print("Resurrecting unit;")
		local pNewUnit = pPlayer:InitUnit(GameInfoTypes.UNIT_AW_UNIT, iX, iY)
		pNewUnit:SetExperience(iExperience)
		for k,v in pairs(tPromotions) do pMetsikhovne:SetHasPromotion(v, true) end
		print("unit brought back from the brink of death!")
		Events.GameplayAlertMessage("Invincible HAXX0R unit saved by the power of illuminarty")
	else	-- find the killer and whisk them off the plot (heaven forbid that we should move)
		print("Firing to move the heathen enemy unit;")
		for mUnit in Players[iKiller]:Units() do
			if (mUnit:GetPlot() == Map.GetPlot(iX, iY)) then
				MoveUnitBackwards(mUnit)
				print("Heathen enemy unit moved back!")
			end
		end
	end
end)
Whoops. :lol: So I added a "not" in front of the parenthesis. And it works (pretty much) now! Definitely the most BA unit I ever made. I just tack on the invisible number 9001 (over 9000 :p) to the unit and surround it with barb marines. Marines attack the unit, unit says "come at me bro", and then the marines die before my unit does. :D

Well, technically not, anyway. The unit dies, of course... a lot... but then just gets replaced by a new one. :p

Anyways, thanks everyone for their debugging aid! :D
 
But looking at the logs, nothing seems to be nesting.

Because it only happens very occasionally. Every time you get in a car it doesn't crash, but that's no excuse not to allow for the eventuality.
 
Ah gots an algorithmic problem!
(I'm sure I make lots of friends from reporting constant problem)
Mostly a math problem, actually. Anyone here good with math?

I currently have a functional script which forcefully hands over cities from player X to player Y whenever Z happens. Since that's not technically possible, technically I have a functional script that finds X's cities, records their population, name, plot, and list of buildings therein, and subsequently destroys them; afterwards a new player Y city is plopped atop the plot and modified to fit those specifications.

What it does not account for, as you can tell, is religious followers. Religion will therefore be utterly wiped out upon city conversion. I could make a table that records the number of followers for each religion present, since there's a City.GetNumFollowers() function:
Code:
local tFollowers = {}
for row in GameInfo.Religions() do
	tFollowers[row.ID] = pCity:GetNumFollowers(row.ID)
end

...but how do I extract that data back out? There's no City.SetNumFollowers function, at least according to the Modiki.

There's a City.ConvertPercentFollowers, but therein is the problem... percent. We could find the population and divide by the number of, say, Tengriists in the city, and multiply by 100 to get the percentage of followers of Religion #-1 to convert to Tengriism. Right?
So that's all well and good until we throw in Taoism, since now the number of followers of -1 is no longer equivalent to the population of the city, but population minus Tengriists. Therefore, if I try the same algorithm as above, I'll end up converting a fewer number of -1ists to Taoism than I should.

So... anyone know how to logically end that line of calculations?

TL;DR If I know how many followers of each religion exist in a city, is there a way to give the same number of followers per religion to another city?
 
That all seems unnecessary... I have a function that transfers cities from a city state to a player and does so without wholesale reconstruction. I'd have to look it over and I will post it when I get home, but it seems to me you are doing a lot of uneeded stuff.

Of course, I could easily be misunderstanding your intent.

I will post a copy of code in a 1/2 hour or so when I get home... it may or may not be useful to you....
 
This is a really simple code...

Code:
--this transfers City States and their units to Northumbria at the acquisition of a certain technology

function OnTechNorthumbriaResearched(team, tech, change)

local NorthumbriaTeam
local NorthumbriaTeamID
local DeiraTeam
local DeiraTeamID
local Northumbria
local Deira
local iNorthumbria

-- Set up Northumbria Player

	for iPlayer=0, GameDefines.MAX_MAJOR_CIVS-1 do 

	local pNorthumbria = Players[iPlayer]

		if (GameInfo.Civilizations.CIVILIZATION_RUSSIA.ID == pNorthumbria:GetCivilizationType()) then
	
		Northumbria = pNorthumbria
		NorthumbriaTeamID = Northumbria:GetTeam();
		NorthumbriaTeam= Teams[ Northumbria:GetTeam() ]
		iNorthumbria = iPlayer

		end	
	end

-- Set up Deira Player

	for iPlayer=GameDefines.MAX_MAJOR_CIVS, GameDefines.MAX_CIV_PLAYERS-1, 1 do 

	local pDeira = Players[iPlayer]

		if (GameInfo.MinorCivilizations.MINOR_CIV_DEIRA.ID == pDeira:GetMinorCivType()) then
	
		Deira = pDeira	
		DeiraTeamID = Deira:GetTeam();
		DeiraTeam= Teams[ Deira:GetTeam() ]
	
		end
	end

--local pPlayerTeam

	if	(tech == (GameInfoTypes["TECH_NOBILITY"])) and team == NorthumbriaTeamID and Deira:IsAlive() and Deira:IsAllies(iNorthumbria) then
			
		-- Find Deira Units

		for unit in Deira:Units() do

		pUnit = unit
		pNewOwner = Northumbria
		convertUnitOwner(pUnit, pNewOwner)

		end

		--convert Deira Cities

		for pCity in Deira:Cities() do

			if pCity ~= nil then
			
				print("Transferring...", pCity:GetName(), "to" , Northumbria:GetName(), "from", Deira:GetName() )
						
				Northumbria:AcquireCity(pCity, false, true)
				pCity:DoTask(TaskTypes.TASK_UNRAZE);

			end
		end

	end

end

GameEvents.TeamTechResearched.Add(OnTechNorthumbriaResearched);

My main question is, why aren't you using player:AcquireCity()? You can set it to "trade" rather than by "conquest". It maintains the same population. If it's a matter of buildings, it would likely be the same as a traded city (which I think means no destruction). The population will not fall if set to "traded" is true. You can also transfer units in the plot area by iterating plots... so why not use it.

Unless I am totally missing something.
 
I might, um, not have known that that function existed. :blush:
...well, it obsoletes a day of coding, but if it works...

Although, what's the convertUnitOwner function? Is that basically the unit equivalent of what I've so far been doing for cities?

Also: In my mod the UU can be expended to construct a unique improvement. Or, is supposed to be, anyway - the improvement shows up in the unit panel as buildable, but upon pressing the button... the first clue that something is wrong is that neither the unit dies nor does an improvement show up. :p
If anyone wants to take a look, the mod is here --> https://www.dropbox.com/s/jp23t9yx0itf2vv/AW's Improvement Gone All Screwy Mod (v 1).zip?dl=0
 
For completeness, I'll post this. It would go below the code posted in #315...

Code:
-- Convert Units

function convertUnitOwner(pUnit, pNewOwner)
  print(string.format("convertUnit(%s, %s)", pUnit:GetName(), pNewOwner:GetName()))

  local pNewUnit = pNewOwner:InitUnit(pUnit:GetUnitType(), pUnit:GetX(), pUnit:GetY())
  pNewUnit:SetOriginalOwner(pUnit:GetOwner());
  pNewUnit:SetDamage(pUnit:GetDamage())
  pNewUnit:SetExperience(pUnit:GetExperience())
  pNewUnit:SetLevel(pUnit:GetLevel())

  for unitPromotion in GameInfo.UnitPromotions() do
    local iPromotionID = unitPromotion.ID;
        
    if (pUnit:IsHasPromotion(iPromotionID)) then
      if (pNewUnit:IsPromotionValid(iPromotionID)) then
        pNewUnit:SetHasPromotion(iPromotionID, true)
      end
    end
  end

  return pNewUnit
end

I likely pulled the code out from another source... don't ask me where, for I've no idea. Thank-you unknown benefactor :).
 
I might, um, not have known that that function existed. :blush:
...well, it obsoletes a day of coding, but if it works...

Although, what's the convertUnitOwner function? Is that basically the unit equivalent of what I've so far been doing for cities?

Also: In my mod the UU can be expended to construct a unique improvement. Or, is supposed to be, anyway - the improvement shows up in the unit panel as buildable, but upon pressing the button... the first clue that something is wrong is that neither the unit dies nor does an improvement show up. :p
If anyone wants to take a look, the mod is here --> https://www.dropbox.com/s/jp23t9yx0itf2vv/AW's Improvement Gone All Screwy Mod (v 1).zip?dl=0

I don't see a unit 'WorkRate' for the Mozarabs, nor a cusom version of UnitPanel to get around the need for a 'WorkRate'.
 
Ayup, I was. Works like a charm now. :goodjob:

Now... I'm using Player.AcquireCity but it's kind of irritating how I get asked whether or not I want to annex the city. But DonQuiche apparently figure it out:
Spoiler :
Code:
function OnCaptureCityClick()
	if IGE.currentPlayerID ~= currentCity:GetOwner() then
		local pPlayer = Players[IGE.currentPlayerID];
		pPlayer:AcquireCity(currentCity);	
	end
	InvalidateCity();
end
Controls.CaptureCityButton:RegisterCallback(Mouse.eLClick, OnCaptureCityClick);
I guess the other two parameters just need to be nil?
He also apparently figured out the religion problem:
Spoiler :
Code:
function ConvertState(state, sourceID, targetID, toConvert)
	-- Enough people from that other religion?
	local converted = toConvert
	if state[sourceID] < toConvert then
		converted = state[sourceID]
	end

	state[sourceID] = state[sourceID] - converted;
	state[targetID] = state[targetID] + converted;
	return toConvert - converted;
end
Code:
function SetFollowers(religionID, num)
	local current = currentCity:GetNumFollowers(religionID);
	if (num == current) then return end

	-- Get followers state
	local count = 0;
	local state = {}
	for _, v in pairs(data.religions) do
		state[v.ID] = currentCity:GetNumFollowers(v.ID);
		count = count + state[v.ID];
	end
	state[-1] = currentCity:GetPopulation() - count;

	--print("Converting...");
	--PrintReligionState(state);

	if num < current then
		-- Convert to atheists
		ConvertState(state, religionID, -1, current - num);
	else
		local toConvert = num - current;

		-- Convert from atheists
		toConvert = ConvertState(state, -1, religionID, toConvert)

		-- Convert from pantheon
		toConvert = ConvertState(state, 0, religionID, toConvert)

		-- Convert from group with max followers, one at a time
		while toConvert > 0 do
			local maxFollowers = 0;
			local sourceID = -1;
			for _, v in pairs(data.religions) do
				if v.ID ~= religionID and v.ID > 0 then
					if state[v.ID] > maxFollowers then
						sourceID = v.ID;
						maxFollowers = state[v.ID];
					end
				end
			end
			if sourceID == -1 then break end

			if ConvertState(state, sourceID, religionID, 1) == 0 then
				toConvert = toConvert - 1;
			end
		end
	end	

	SetReligionState(state);
	preserveSortOrder = true;
	LuaEvents.IGE_Update();
	Events.SerialEventCityInfoDirty();
end
Code:
function SetReligionState(state)
	PrintReligionState(state);

	-- What is the majority?
	local maxFollowers = -1;
	local majority = -1;
	for i in pairs(state) do
		state[i] = math.floor(state[i] + 0.5)
		if state[i] > maxFollowers then
			majority = i;
			maxFollowers = state[i]
		end
	end

	-- EDIT: Those crashes may actually have only been caused by tests with a religion not founded yet. Doesn't matter, leave the code like that
	-- ConvertPercentFollowers is full of nasty bugs (can only convert from majority to minority) hence this twisted method
	currentCity:AdoptReligionFully(majority);
	print("Done fully adopting")

	for i, v in pairs(state) do
		if i ~= majority and i >= 0 then
			-- Convert 1% at a time because followers are internally stored as real numbers.
			while (currentCity:GetNumFollowers(i) + 0.5) < v do
				currentCity:ConvertPercentFollowers(i, majority, 1)
			end
		end
	end
	print("Done increasing minorities.")

	-- We do atheists in the end because of a rounding error in civ5 (sum of followers can be population + 1)
	-- Since they're never displayed, we actually use the majority as a loop condition.
	if majority >= 0 then
		while (currentCity:GetNumFollowers(majority) - 0.5) > state[majority] do
			currentCity:ConvertPercentFollowers(-1, majority, 1)
		end
	end
	print("Done lowering majority.")
end
Now, I have absolutely no clue what any of this does.
 
Top Bottom