1. We have added the ability to collapse/expand forum categories and widgets on forum home.
    Dismiss Notice
  2. All Civ avatars are brought back and available for selection in the Avatar Gallery! There are 945 avatars total.
    Dismiss Notice
  3. To make the site more secure, we have installed SSL certificates and enabled HTTPS for both the main site and forums.
    Dismiss Notice
  4. Civ6 is released! Order now! (Amazon US | Amazon UK | Amazon CA | Amazon DE | Amazon FR)
    Dismiss Notice
  5. Dismiss Notice
  6. Forum account upgrades are available for ad-free browsing.
    Dismiss Notice

How do you prevent a building from being damaged when the city is captured?

Discussion in 'Mod Creation Help' started by isau, Mar 6, 2018.

  1. isau

    isau Warlord

    Joined:
    Jan 15, 2007
    Messages:
    2,697
    Any ideas on how to stop a building from being destroyed when a city is captured? I have some "dummy" buildings that are used for attaching modifiers. They work great, except when the city is captured they are destroyed and can't be repaired. Any ideas?
     
  2. Gedemon

    Gedemon Modder Moderator

    Joined:
    Oct 4, 2004
    Messages:
    7,490
    Location:
    France
    AFAIK there is just a global switch, per district.

    Code:
    UPDATE Districts SET CaptureRemovesBuildings = '0' WHERE DistrictType ='DISTRICT_CITY_CENTER';
    IIRC I've also tried using Lua to manually remove then replace the damaged dummy buildings, but I don't remember if it was working.

    (when are they going to give us "Set" functions in Lua for modifiers BTW ?)
     
    isau likes this.
  3. LeeS

    LeeS Imperator

    Joined:
    Jul 23, 2013
    Messages:
    5,411
    Location:
    Illinois, USA
    In lua you should be able to just use
    Code:
    if pCity:GetBuildings():IsPillaged(iBuilding) then
    	pCity:GetBuildings():SetPillaged(iBuilding, false)
    end
    Rather than deleting and then re-creating. So far as I am able to determine this works correctly.

    But for city capture events I just re-build the set of dummies needed in a given city. This works for me in my mod since I am basing everything on the resources, terrain, features, etc., belonging to and surrounding the city, so I have no need to worry about data persistence issues or tracking whether CityX ever had BuildingX.


    erm -- clarity note: I was talking to Gedemon
    -----------------------------

    And yes please can we have some AssignStartingPlots "Set" methods for modifiers directly from lua already !
     
    Last edited: Mar 6, 2018
    isau likes this.
  4. isau

    isau Warlord

    Joined:
    Jan 15, 2007
    Messages:
    2,697


    Ah, the holy grail. :) I imagine if we ever get DLL access that will be one of the first things someone creates, as well as Modifier "riders" for units, leaders, civilizations. But cities especially need them, since for units at least there are Abilities which are proximally close. Cities basically need the equivalent of "Abilities."


    I'll try this. Do you have an idea what event it should belong to? The Lua portion of the code is still kind of opaque to me. I understand it in theory (I'm an old school Flash Actionscript programmer) but many of the particulars to Civ 6 are still dangerously vague to me, in the crash-to-desktop way.
     
  5. LeeS

    LeeS Imperator

    Joined:
    Jul 23, 2013
    Messages:
    5,411
    Location:
    Illinois, USA
    I've been using Events.CityInitialized(iPlayer, iCityID) because it fires both when a city is first founded and as part of a series of events that fire when a city is captured. RaF may add more but I don't yet have RaF.

    I use Events.CityInitialized as for example like this (a bunch of additional toolkit functions not shown for clarity) to show what is needed to translate the arguments passed from the gamecore into usable lua objects as understood by Civ6:
    Code:
    function PlayerFoundedCity(iPlayer, iCityID)
    	PrintToLog("[PlayerFoundedCity] iPlayer is " .. tostring(iPlayer))
    	if iPlayer == 63 then
    		PrintToLog("[PlayerFoundedCity] Player # " .. iPlayer .. " (Barbarians) cannot normally have cities")
    		return
    	end
    	local pPlayer = Players[iPlayer]
    	local pCity = pPlayer:GetCities():FindID(iCityID)
    	if pCity ~= nil then
    		PrintToLog("[PlayerFoundedCity] The founded city was " .. Locale.Lookup(pCity:GetName()))
    		-- SetCityUnlockerStatuses is the actual work-horse that sets or removes my dummy buildings
    		SetCityUnlockerStatuses(pCity, "PlayerFoundedCity")
    	else
    		PrintToLog("[PlayerFoundedCity] The founded city was nil")
    	end
    end
    function OnLoadScreenClose()
    	--delay until after LoadScreenClose to avoid un-needed executions on reloading saved game
    	Events.CityInitialized.Add(PlayerFoundedCity);
    end
    Events.LoadScreenClose.Add(OnLoadScreenClose)
    These all fire in the order shown as part of a city conquest
    Code:
    GameEvents.CityConquered
    Events.CityRemovedFromMap
    Events.CityAddedToMap
    Events.CityPopulationChanged
    Events.CityTileOwnershipChanged (fires in succession for each tile whose ownership was altered)
    Events.CityInitialized
    Events.CityProductionCompleted
    Events.CityPopulationChanged	(you seem to get two firings of this event as part of a city-capture)
    Events.CityProductionCompleted	(you seem to get two or more firings of this event as part of a city-capture)
    From functions I wrote as a listeners to see what arguments the gamecore passes to GameEvents.CityConquered and Events.CityInitialized
    Spoiler :
    Code:
    function GetArgumentDatas(sOrigin, tTable)
    	print("============================================================================================")
    	print("[" .. sOrigin .. "]: Dumping Event Hook Argument Data")
    	print("............................................................................................")
    	for k,v in pairs(tTable) do
    		local sKeyType = type(k)
    		local sValueType = type(v)
    		print("[" .. sOrigin .. "]: Key is of type " .. sKeyType .. " = " .. tostring(k) .. ", Value is of type " .. sValueType .. " = " .. tostring(v))
    	end
    	print("............................................................................................")
    	print("[" .. sOrigin .. "]: dump completed for this firing of the event")
    	print("============================================================================================")
    end
    
    --############################################### CityConquered ########################################################
    
    function OnCityConquered(...)
    	--OnCityConquered(iVictoriousPlayer, iDefeatedPlayer, iNewCityID, iCityPlotX, iCityPlotY)
    	--iNewCityID gives the ID # the city is using for the new owner (ie, iVictoriousPlayer)
    	--iNewCityID will NOT as a general rule match to the ID # used for the same city for the previous owner (ie, iDefeatedPlayer)
    	--CityConquered fires before CityRemovedFromMap, CityAddedToMap, and CityInitialized
    	--Firing Order: (all functions subscribed to these events fire in this order as part of a city conquest)
    	--	GameEvents.CityConquered
    	--	Events.CityRemovedFromMap
    	--	Events.CityAddedToMap
    	--	Events.CityPopulationChanged
    	--	Events.CityTileOwnershipChanged (fires in succession for each tile whose ownership was altered)
    	--	Events.CityInitialized
    	--	Events.CityProductionCompleted
    	--	Events.CityPopulationChanged	(you seem to get two firings of this event as part of a city-capture)
    	--	Events.CityProductionCompleted	(you seem to get two or more firings of this event as part of a city-capture)
    	print("GameEvents.CityConquered fired for function OnCityConquered")
    	GetArgumentDatas("OnCityConquered", {...})
    end
    GameEvents.CityConquered.Add(OnCityConquered)
    
    --############################################### CityInitialized ########################################################
    
    function OnCityInitialized(...)
    	--OnCityInitialized(...)
    	--OnCityInitialized(iPlayer, iCityID, iX, iY)
    	print("Events.CityInitialized fired for function OnCityInitialized")
    	GetArgumentDatas("OnCityInitialized", {...})
    end
    function OnLoadScreenClose()
    	--delay until after LoadScreenClose to avoid massive dumps in the log on reloading saved game
    	Events.CityInitialized.Add(OnCityInitialized)
    end
    Events.LoadScreenClose.Add(OnLoadScreenClose)
     
    isau likes this.
  6. LeeS

    LeeS Imperator

    Joined:
    Jul 23, 2013
    Messages:
    5,411
    Location:
    Illinois, USA
    Looking at your update it should be possible via lua to constrain the free China bedrock thing based on a required number of tiles. This would of course run parallel to all the other requirements for the bedrock thing.

    Though the logic would take some thinking through, since adding or removing a Great Wall tile improvement would require plot scanning and city-finding, and then after finding nearby cities, determination if the addition or removal of the improvement now qualifies a city for the bedrock thing, or disqualifies it. To simplify matters I would probably not recommend ever removing the Bedrock building even if an improvement was later removed, even though this would set up an exploit.
     
  7. isau

    isau Warlord

    Joined:
    Jan 15, 2007
    Messages:
    2,697

    Thanks for looking into it. :) I figured it as doable with Lua, but I prefer to stick to Modifiers and RequirementSets as much as possible, in part because so many users of my mod end up editing the mod to their taste. You're correct that the Bedrock building is permanent if a player ever builds a piece of Great Wall or does anything else to trigger Bedrock. I figure they paid for Bedrock with their Builder charge, so no harm in letting the Bedrock stay permanently even if they bulldoze the improvement later.

    It was nice of Firaxis in R&F to add a Requirement that looks at the number of terrain tiles. That's how I was able to create the Renaissance Bedrock unlock that counts Ocean tiles. I bet there's a lot of cool stuff we modders can use that Requirement for. Mountains, perhaps?
     
  8. LeeS

    LeeS Imperator

    Joined:
    Jul 23, 2013
    Messages:
    5,411
    Location:
    Illinois, USA
    Just wanted to let you know it would be do-able, just would take some logic and thinkery-do.

    Heh. I don't have RaF yet so I don't know what-all they added, but my code for the Dummy Buildings Systems was doing this via lua already. # of required moountains in order to construct a "real" building, # of specific feature, specified district adjacent to mountains, specified district adjacent to a required number of mountains, specified terrain (and/or number of plots of given terrain) adjacent or owned by a city, etc.
     

Share This Page