Airlift, Airports, Ingame.lua and Worldview.lua

jerseymike25

Chieftain
Joined
Dec 24, 2005
Messages
50
After another late-game war that was completely bogged down by having to move units halfway across the map, I started digging around for the Airport mod I remembered seeing once upon a time. That mod would be found here - a Military Airbase and Airport.

Unfortunately, it seems that mod didn't see much action after that initial posting, and there hasn't been much discussion around trying to create an Airport that I've seen since then - the wish for it here and there, including a couple of comments about Airlift stubs.

First, it is indeed possible to create a building that allows the airlifting of units to other friendly cities. The implementation of it seems pretty basic:
1. Unit must not yet have moved (same as Civ 4, from what I remember)
2. Destination city does NOT require an Airport, and does NOT need to be void of any unit. (That is, you can send a unit to a city even though there's a unit there already.)

The current version of the Airport. Tech Prereq and cost are just for debugging purposes at the moment, so I can build it whenever:
Spoiler :

<Row>
<Type>BUILDING_AIRPORT</Type>
<BuildingClass>BUILDINGCLASS_AIRPORT</BuildingClass>
<Cost>10</Cost>
<GoldMaintenance>0</GoldMaintenance>
<PrereqTech>TECH_AGRICULTURE</PrereqTech>
<Help>TXT_KEY_BUILDING_AIRPORT_HELP</Help>
<Description>TXT_KEY_BUILDING_AIRPORT</Description>
<Civilopedia>TXT_KEY_CIV5_BUILDINGS_AIRPORT_TEXT</Civilopedia>
<Strategy>TXT_KEY_BUILDING_AIRPORT_STRATEGY</Strategy>
<ArtDefineTag>ART_DEF_BUILDING_MILITARY_ACADEMY</ArtDefineTag>
<MinAreaSize>-1</MinAreaSize>
<Airlift>5</Airlift>
<HurryCostModifier>25</HurryCostModifier>
<IconAtlas>BW_ATLAS_1</IconAtlas>
<PortraitIndex>9</PortraitIndex>
</Row>


Now, I have no idea what the value for Airlift means (5) - I haven't played with it yet to see if it does anything different. Maybe it's range? All of my tests so far have been with cities in close proximity.

I went poking around looking for other mentions of AIRLIFT, finding mentions in the Ingame.lua and Worldview.lua. In Ingame.lua, the UI Handlers for it were commented out (actually referring to nil, but the reference to it was commented), so I wrote a couple of basic UI handlers, basically the Rebase handlers with the Range calculations removed:

Spoiler :

local OldInterfaceModeChangeHandler =
{
--[InterfaceModeTypes.INTERFACEMODE_DEBUG] = nil,
--[InterfaceModeTypes.INTERFACEMODE_SELECTION] = nil,
--[InterfaceModeTypes.INTERFACEMODE_PING] = nil,
[InterfaceModeTypes.INTERFACEMODE_MOVE_TO] = HideMovementRangeIndicator,
--[InterfaceModeTypes.INTERFACEMODE_MOVE_TO_TYPE] = nil,
--[InterfaceModeTypes.INTERFACEMODE_MOVE_TO_ALL] = nil,
--[InterfaceModeTypes.INTERFACEMODE_ROUTE_TO] = nil,
-- MOD CHANGE MOD CHANGE MOD CHANGE
[InterfaceModeTypes.INTERFACEMODE_AIRLIFT] = HideAirLiftView,
-- MOD CHANGE MOD CHANGE MOD CHANGE
[InterfaceModeTypes.INTERFACEMODE_NUKE] = EndNukeAttack,
[InterfaceModeTypes.INTERFACEMODE_PARADROP] = HideParadropRangeIndicator,
[InterfaceModeTypes.INTERFACEMODE_ATTACK] = ClearUnitHexHighlights,
[InterfaceModeTypes.INTERFACEMODE_RANGE_ATTACK] = EndRangedAttack,
[InterfaceModeTypes.INTERFACEMODE_CITY_RANGE_ATTACK] = EndRangedAttack,
[InterfaceModeTypes.INTERFACEMODE_AIRSTRIKE] = EndAirAttack,
--[InterfaceModeTypes.INTERFACEMODE_AIR_SWEEP] = nil,
[InterfaceModeTypes.INTERFACEMODE_REBASE] = HideRebaseRangeIndicator,
[InterfaceModeTypes.INTERFACEMODE_PLACE_UNIT] = ClearUnitHexHighlights,
[InterfaceModeTypes.INTERFACEMODE_EMBARK] = ClearUnitHexHighlights,
[InterfaceModeTypes.INTERFACEMODE_DISEMBARK] = ClearUnitHexHighlights,
[InterfaceModeTypes.INTERFACEMODE_GIFT_UNIT] = ClearUnitHexHighlights,
--[InterfaceModeTypes.INTERFACEMODE_CITY_PLOT_SELECTION] = ExitCityPlotSelection
--[InterfaceModeTypes.INTERFACEMODE_PURCHASE_PLOT] = ClearUnitHexHighlights
};

local NewInterfaceModeChangeHandler =
{
--[InterfaceModeTypes.INTERFACEMODE_DEBUG] = nil,
[InterfaceModeTypes.INTERFACEMODE_SELECTION] = ClearUnitHexHighlights,
--[InterfaceModeTypes.INTERFACEMODE_PING] = nil,
[InterfaceModeTypes.INTERFACEMODE_MOVE_TO] = ShowMovementRangeIndicator,
--[InterfaceModeTypes.INTERFACEMODE_MOVE_TO_TYPE] = nil,
--[InterfaceModeTypes.INTERFACEMODE_MOVE_TO_ALL] = nil,
--[InterfaceModeTypes.INTERFACEMODE_ROUTE_TO] = nil,
-- MOD CHANGE MOD CHANGE MOD CHANGE
[InterfaceModeTypes.INTERFACEMODE_AIRLIFT] = ShowAirLiftView,
-- MOD CHANGE MOD CHANGE MOD CHANGE
[InterfaceModeTypes.INTERFACEMODE_NUKE] = BeginNukeAttack,
[InterfaceModeTypes.INTERFACEMODE_PARADROP] = ShowParadropRangeIndicator,
[InterfaceModeTypes.INTERFACEMODE_ATTACK] = ShowAttackTargetsIndicator,
[InterfaceModeTypes.INTERFACEMODE_RANGE_ATTACK] = BeginRangedAttack,
[InterfaceModeTypes.INTERFACEMODE_CITY_RANGE_ATTACK] = BeginRangedAttack,
[InterfaceModeTypes.INTERFACEMODE_AIRSTRIKE] = BeginAirAttack,
--[InterfaceModeTypes.INTERFACEMODE_AIR_SWEEP] = nil,
[InterfaceModeTypes.INTERFACEMODE_REBASE] = ShowRebaseRangeIndicator,
[InterfaceModeTypes.INTERFACEMODE_PLACE_UNIT] = nil, -- this actually has some special case code with it in CityBannerManager and/or CityView
[InterfaceModeTypes.INTERFACEMODE_EMBARK] = HighlightEmbarkPlots,
[InterfaceModeTypes.INTERFACEMODE_DISEMBARK] = HighlightEmbarkPlots,
[InterfaceModeTypes.INTERFACEMODE_GIFT_UNIT] = HighlightGiftUnits,
--[InterfaceModeTypes.INTERFACEMODE_CITY_PLOT_SELECTION] = EnterCityPlotSelection
--[InterfaceModeTypes.INTERFACEMODE_PURCHASE_PLOT] = nil
};

Spoiler :

--------------------------------------------------------------------------------------------
-- JerseyMike25 MOD: Add a handler for INTERFACEMODE_AIRLIFT
-- ShowAirLiftView will highlight the tiles around a City where a unit can be airlifted to.
-- Shows green for cities that can be airlifted to, red for cities that cannot.
-- Whether or not a unit can actually go to that city will be handled inside of WorldView.lua.
--------------------------------------------------------------------------------------------
function ShowAirLiftView()
local pPlayer = Players[Game.GetActivePlayer()];
local plotColorHasAirport = Vector4( 0, 1, 0, 1 );
local plotColorHasNoAirport = Vector4( 1, 0, 0, 1 );

for pCity in pPlayer:Cities() do
local plotX = pCity:GetX();
local plotY = pCity:GetY();
local hexID = ToHexFromGrid( Vector2( plotX, plotY) );
if pCity:IsHasBuilding(GameInfo.Buildings["BUILDING_AIRPORT"].ID) then
Events.SerialEventHexHighlight( hexID, true, plotColorHasAirport);
else
Events.SerialEventHexHighlight( hexID, true, plotColorHasNoAirport);
end -- if pCity:IsHasBuilding
end -- for loop
end -- function

--------------------------------------------------------------------------------------------
-- JerseyMike25 MOD: Add a handler for INTERFACEMODE_AIRLIFT
-- HideAirLiftView simply clears all of the Hex Highlights.
--------------------------------------------------------------------------------------------
function HideAirLiftView()
ClearAllHighlights();
end


It looks like Ingame.lua would be used to control highlighting which cities could accept an airlifted unit, for example: if the city has an Airport or doesn't already contain a unit. It would not, however, prevent actually sending a unit to a non-highlighted city, which if we want control of where it could go, is something we would want.

Worldview.lua appears to let us control that using the MouseButtons.LButtonUp hook. In Vanilla, the Airlift LButtonUp is registered to the default handler, and changing that done like so:
Spoiler :

InterfaceModeMessageHandler[InterfaceModeTypes.INTERFACEMODE_AIRLIFT][MouseEvents.LButtonUp] =
function( wParam, lParam )
local plot = Map.GetPlot( UI.GetMouseOverHex() );
local plotX = plot:GetX();
local plotY = plot:GetY();

-- Get the city at that plot
-- Does that city have an airport
-- if not, then return

-- Did the plot clicked actually have a city? If not, simply return.
if plot:IsCity() == false then
return true;
end

-- Figure out what city this is, does it have an airport?
local city = plot:GetPlotCity();
if city:IsHasBuilding( GameInfo.Buildings["BUILDING_AIRPORT"].ID) then
-- Call the standard handler and let it go from here.
missionTypeLButtonUpHandler(wParam, lParam);
end

-- If we get here, either the missionTypeLButtonUpHandler happened or it didn't have an airport.
return true;
end


Still have questions pending, though:
1. Can the AI be convinced to use this method of transport? (Perhaps borrow from Rebase logic?)
2. Can the Airport be used to provide a trade route? (I suppose look at anything special with the Harbor?)
 
jerseymike25 said:
-- Figure out what city this is, does it have an airport?
-- !! Need to get the ID of the Airport building. !!
-- !! Logic isn't great, is there a better way to find what City this is?

function AirportAtPlot(plot)
local city = plot:GetPlotCity()
return (city ~= nil) and city:IsHasBuilding( GameInfo.Buildings["BUILDING_MIL_AIRBASE"].ID) or false
end
 
Easier than expected - thanks. That logic is implemented, now posted up top.

As best I can tell, the trade route logic is buried in the DLL itself and can't be changed (function is called IsCapitalConnectedToCity )? I was hoping I could use AllowsWaterRoutes -- basically hoping it was just a boolean that if set true, meant that the route magically existed. Didn't work, though.

Full XML chunk if someone wants to play around with this:
Spoiler :

<GameData>
<Buildings>
<Row>
<Type>BUILDING_AIRPORT</Type>
<BuildingClass>BUILDINGCLASS_AIRPORT</BuildingClass>
<Cost>10</Cost>
<GoldMaintenance>0</GoldMaintenance>
<PrereqTech>TECH_AGRICULTURE</PrereqTech>
<Help>TXT_KEY_BUILDING_AIRPORT_HELP</Help>
<Description>TXT_KEY_BUILDING_AIRPORT</Description>
<Civilopedia>TXT_KEY_CIV5_BUILDINGS_AIRPORT_TEXT</Civilopedia>
<Strategy>TXT_KEY_BUILDING_AIRPORT_STRATEGY</Strategy>
<ArtDefineTag>ART_DEF_BUILDING_MILITARY_ACADEMY</ArtDefineTag>
<MinAreaSize>-1</MinAreaSize>
<Airlift>5</Airlift>
<HurryCostModifier>25</HurryCostModifier>
<IconAtlas>BW_ATLAS_1</IconAtlas>
<PortraitIndex>9</PortraitIndex>
</Row>
</Buildings>
<Building_Flavors>
<Row>
<BuildingType>BUILDING_AIRPORT</BuildingType>
<FlavorType>FLAVOR_MILITARY_TRAINING</FlavorType>
<Flavor>10</Flavor>
</Row>
</Building_Flavors>
<Building_DomainFreeExperiences>
<Row>
<BuildingType>BUILDING_AIRPORT</BuildingType>
<DomainType>DOMAIN_AIR</DomainType>
</Row>
</Building_DomainFreeExperiences>
<BuildingClasses>
<Row>
<Type>BUILDINGCLASS_AIRPORT</Type>
<DefaultBuilding>BUILDING_AIRPORT</DefaultBuilding>
<Description>TXT_KEY_BUILDING_AIRPORT</Description>
</Row>
</BuildingClasses>
<Language_en_US>
<Row Tag="TXT_KEY_BUILDING_AIRPORT">
<Text>Airport</Text>
</Row>
<Row Tag="TXT_KEY_BUILDING_AIRPORT_STRATEGY">
<Text>Military Airbase provide training facilities for your air units and allows to airlift an unit to another city.</Text>
</Row>
<Row Tag="TXT_KEY_CIV5_BUILDINGS_AIRPORT_TEXT">
<Text>
Some text about an Airport
</Text>
</Row>
<Row Tag="TXT_KEY_BUILDING_AIRPORT_HELP">
<Text>Airports allow units to be airlifted to another city with an Airport.[NEWLINE]Airports also serve as a way to connect trade routes.</Text>
</Row>
<Row Tag="TXT_KEY_BUILDING_AIRPORT_HEADING">
<Text>Airport</Text>
</Row>
</Language_en_US>
</GameData>
 
I was hoping I could use AllowsWaterRoutes -- basically hoping it was just a boolean that if set true, meant that the route magically existed. Didn't work, though.

Did you build two airports? One in a city connected to the capital by road/rail (or in the capital itself) and one in the "disconnected" city?
 
Water routes are more complicated than it might seem, as they don't just magically work - you have to have explored a route through the water, and it not be blockaded. So, not sure it's likely that AllowsWaterRoutes would work.

What we can hope for is a TestAny GameEvent for IsCapitalConnectedToCity, with the test also including the two existing means of connection. Then we'd be able to add more ways to establish the connection quite easily, particularly if they add some little functions to determine connections transitively... so we'd need a function to access the builtin connection types, to make it easy, so if a city is being tested, doesn't have a basic connection itself, but does have an airport, you'd want to look at all cities with airports to see if any of them are connected with either basic connection.

I'd suggest airports ought to have a pretty huge maintenance, though, as the trade route power is pretty powerful (and a potential money saver) and then there's the airlift facility as well...
 
Did you build two airports? One in a city connected to the capital by road/rail (or in the capital itself) and one in the "disconnected" city?

Just a single land-locked city with the airport, and the capital with the airport.

Water routes are more complicated than it might seem, as they don't just magically work - you have to have explored a route through the water, and it not be blockaded. So, not sure it's likely that AllowsWaterRoutes would work.

What we can hope for is a TestAny GameEvent for IsCapitalConnectedToCity, with the test also including the two existing means of connection. Then we'd be able to add more ways to establish the connection quite easily, particularly if they add some little functions to determine connections transitively... so we'd need a function to access the builtin connection types, to make it easy, so if a city is being tested, doesn't have a basic connection itself, but does have an airport, you'd want to look at all cities with airports to see if any of them are connected with either basic connection.

I'd suggest airports ought to have a pretty huge maintenance, though, as the trade route power is pretty powerful (and a potential money saver) and then there's the airlift facility as well...

I suppose so. Like I said, I was hoping that AllowsWaterRoutes was actually a fancy name for a dumb variable - that if a particular building had "AllowsWaterRoutes" attached to it, it would mean that it was connected without actually checking for any sort of route - assuming a blockade wasn't present between itself and the Capital City.

Poking around the lua, I think it might be possible to fake the connection in terms of UI appearance and what a trade route provides, but since the game internals wouldn't actually consider it connected via trade route, it may be more work than it's worth.

Yeah, as far as maintenance goes - it should be high, and the building itself should cost a lot to build/purchase. Calling it a "Military Airbase" may be the best thing to do if the whole trade network issue can't be fixed; it doesn't quite imply that it should have a trade network associated with it.
 
Top Bottom