Hex Conquer (Borders Only)

Perhaps I misinterpreted this... I was under the impression Brazil AND another were razing... If it's just the other than it doesn't make sense that it was Brazil, and maybe the events that Brazil was doing are unrelated.

There's something confusing about your scenario in that crash occurs between Inuit and Brazil turn as per your description, but the city involved belongs to neither. iirc my razing check should only apply to a player on their own turn, and to that player's owned cities... And yet it seems to clearly be crashing during a raze check. It might be as simple as applying an additional conditional in the Lua to double check that whatever city is being processed by the raze function actually belongs to the relevant player... It's unclear how the raze check would even find a non-player city to begin with, it literally just loops all the current player's cities to check for razing status and pop=1

In any case there's some rare scenario during tile reassignment that CTD's the game, maybe @dailyminerals can shed some light on what was happening in there game when it occurred
I wanted to test it again, but it appears I saved the mod list on my Google Drive and had to delete it later, so I would have to download all of them with the correct versions and I just really don't want to do that right now. Hopefully the issue comes up in my current game too, but if not, I'll probably do this in the summer when I have more time.
 
Yeah I didn't test for same reason... But I did take a brief cruise through the logs... It's strange that the crash occurs when it does ie between Brazil/Inuit turn, despite an Assyrian city being razed.

This suggests that some part of the game engine is still considering the razing city as belonging to one of the other two civs nearby, even though that's clearly not the case in the screenshot.

Speculatively, it might be fixable if we added an additional conditional to ensure that the city being assessed actually belongs to the player the city loop function it returns from, but this shouldn't be necessary.

Too weird, need more info to narrow in on what is occurring

edit:

@Captain Carrot do you remember if there were any players that had been elminated? perhaps whose turn fell between brazil and inuit?
 
Last edited:
the speculative fix I have in mind is not too difficult to code -- I'm not sure if it fixes what's going wrong here, but nonetheless, I have pasted it here. Do the following:
  1. open main.lua in text editor (highly recommend anyone attempting this use notepad++ rather than just notepad)
  2. navigate to line 264, find the HexCREndTurn function
  3. replace the entire function (delete, then copy/paste from below) -- make sure just the function and not the hook below it
  4. save file, launch civ, load game, try to progress through CTD turn
  5. report back here with results
Spoiler :

Code:
function HexCREndTurn(iPlayer)
    print ("Hex CR razing check started")
    local pPlayer = Players[iPlayer]
    if pPlayer ~= nil and pPlayer:IsAlive() then
        for city in pPlayer:Cities() do
            local pCity = city
            if pCity ~= nil and (pCity:IsRazing()) and (pCity:GetPopulation() == 1) and (pCity:GetOwner() == iPlayer) then
                print ("Hex CR: city being razed has reached one pop")
                local pPlot = pCity:Plot()
                local pCityOwner = Players[pCity:GetOwner()]
                local pOwnerTeam = Teams[pCityOwner:GetTeam()]
                local iCityOriginalOwner = pCity:GetOriginalOwner()
                for i = 0, pCity:GetNumCityPlots()-1, 1 do
                    local lPlot = pCity:GetCityIndexPlot(i)
                    local ourCityAvailable = false
                    local teamAvailable = false
                    local allyAvailable = false
                    local friendAvailable = false
                    local noWarAvailable = false
                    local dPactAvailable = false
                    if (lPlot ~= nil) and ( (lPlot:GetOwner()) == (pCity:GetOwner()) ) then
                        local CityCandidates = {}
                        for pID = 0, GameDefines.MAX_MAJOR_CIVS-1, 1 do
                            local nearCity, dist = getNearestCityWithException( pID, lPlot, pCity)
                            if (nearCity ~= nil) and (dist < 4) then
                                local us = (Players[pID] == pCityOwner)
                                local sameteam = (not us) and (Teams[Players[pID]:GetTeam()] == pOwnerTeam)
                                local friends = (not us) and (pCityOwner:IsDoF(pID))
                                local allies = (not us) and (pCityOwner:IsAllies(pID))
                                local war = (not us) and (pOwnerTeam:IsAtWar(Players[pID]:GetTeam()))
                                local dpact = (not us) and (pOwnerTeam:IsDefensivePact(Players[pID]:GetTeam()))
                      
                                if us then
                                    ourCityAvailable = true
                                end
                                if sameteam then
                                    teamAvailable = true
                                end
                                if friends then
                                    friendAvailable = true
                                end
                                if allies then
                                    allyAvailable = true
                                end
                                if not war then
                                    noWarAvailable = true
                                end
                                if dpact then
                                    dPactAvailable = true
                                end
                                table.insert(CityCandidates, {iPlayer = pID, bUs = us, bTeam = sameteam, bFriends = friends, bAllies = allies, bWar = war, bDpact = dpact, cNearCity = nearCity})
                          
                            end
                        end
                        if #CityCandidates > 0 then
                            if ourCityAvailable then
                                for i = 1, #CityCandidates, 1 do
                                    if CityCandidates[i] ~= nil then
                                        local lUs = CityCandidates[i].bUs
                                        if not lUs then
                                            table.remove(CityCandidates, i)
                                            i = i - 1
                                        end
                                    end
                                end
                            elseif teamAvailable then
                                for i = 1, #CityCandidates, 1 do
                                    if CityCandidates[i] ~= nil then
                                        local lTeam = CityCandidates[i].bTeam
                                        if not lTeam then
                                            table.remove(CityCandidates, i)
                                            i = i - 1
                                        end
                                    end
                                end
                            elseif dPactAvailable then
                                for i = 1, #CityCandidates, 1 do
                                    if CityCandidates[i] ~= nil then
                                        local lDpact = CityCandidates[i].bDpact
                                        if not lDpact then
                                            table.remove(CityCandidates, i)
                                            i = i - 1
                                        end
                                    end
                                end
                            elseif allyAvailable then
                                for i = 1, #CityCandidates, 1 do
                                    if CityCandidates[i] ~= nil then
                                        local lAlly = CityCandidates[i].bAllies
                                        if not lAlly then
                                            table.remove(CityCandidates, i)
                                            i = i - 1
                                        end
                                    end
                                end
                            elseif friendAvailable then
                                for i = 1, #CityCandidates, 1 do
                                    if CityCandidates[i] ~= nil then
                                        local lFriend = CityCandidates[i].bFriends
                                        if not lFriend then
                                            table.remove(CityCandidates, i)
                                            i = i - 1
                                        end
                                    end
                                end
                            elseif noWarAvailable then
                                for i = 1, #CityCandidates, 1 do
                                    if CityCandidates[i] ~= nil then
                                        local lNoWar = not CityCandidates[i].bWar
                                        if not lNoWar then
                                            table.remove(CityCandidates, i)
                                            i = i - 1
                                        end
                                    end
                                end
                            end
                            local randPlayer = math.random(#CityCandidates)
                            local iAssignPlayer = CityCandidates[randPlayer].iPlayer
                            local AssignCity = CityCandidates[randPlayer].cNearCity
                            if AssignCity == nil then return end -- city not found?
                            if Map.PlotDistance( AssignCity:GetX(), AssignCity:GetY(), lPlot:GetX(), lPlot:GetY() ) < 4 then
                                print("reassigning plot belonging to nearly razed city")
                                if ourCityAvailable then
                                    lPlot:SetOwner(-1, -1, false, false)
                                end
                                lPlot:SetOwner( iAssignPlayer, AssignCity, true, true )
                            end
                        end
                    end
                end
            end
        end
    end
end


@dailyminerals , if you still have your save, can you try this and let us know?
 
Last edited:
@Captain Carrot do you remember if there were any players that had been elminated? perhaps whose turn fell between brazil and inuit?
No, there was only one successful warmonger and they just made a vassal.

Speculatively, it might be fixable if we added an additional conditional to ensure that the city being assessed actually belongs to the player the city loop function it returns from, but this shouldn't be necessary.
If I had a dollar for every seemingly unnecessary check that ended up fixing everything...
 
If I had a dollar for every seemingly unnecessary check that ended up fixing everything...
Yeah on reviewing I realized I never put anything in to catch player=nil. Don't know how things like players exist in the game database while defined as nil, but apparently this is somewhat regular occurrence. That said it usually throws Lua exception rather than CTD when these checks are forgotten. Anyway my code above has this and a few others added in. Whoever next encounters razing crash needs to test
 
I checked-in with Gaia, the dev working on sapiens mod -- we're both under the impression that her version *should* work with VP. She has been developing one of the versions I worked on, and by now has done a lot of additional bugfixing and rebalancing. Specifically, I believe her version has addressed the puppet tile claiming issue. The razing issue may or may not persist there, she hasn't heard of it -- but its possible her edits to this mod got out in front of it anyway.

If it's not to everyone's liking, I'll look at making an proper update at some point specifically for VP, but I'd rather focus my limited time on other projects.

I suggest we all move on to Gaia's version for now, and reconvene here for any specific VP-related concerns -- alternatively, report any issues in the discussion on steam workshop, Gaia is pretty good at fixing things quickly. I'm tagged there too and will at least keep any reported issues in-mind if I do end up revisiting this. usadefcon's version is also a possible option

 
Last edited:
Top Bottom