Get Started With Lua Events Lesson 5: Even More Examples: Difference between revisions

From Scenario League Wiki
Jump to navigationJump to search
(Created Lesson 5)
 
Line 6: Line 6:


===Fixing The Sea Unit Disbandment Bug===
===Fixing The Sea Unit Disbandment Bug===
In Civilization II, when a city is captured, all the units supported by that city are disbanded.  It turns out that the <code>civ.scen.onCityTaken(function (city, defender) -> void)</code> event trigger happens ''before'' units are disbanded.  This means that we can use the <code>civ.scen.onCityTaken</code> event trigger to do things involving soon to be disbanded units.
One thing we can do is perform the disbanding action ourselves.  The reason for this is that a bug exists that disbands all the units on a sea square if a ship there is disbanded (try it).  This is obviously very undesirable, but we can override it in the case of city capture by doing the disbandment ourselves.
Essentially, when a city is captured we do a for loop over all the units in the game, and if the unit is supported by the captured city, or carried by a unit supported by it, then we delete the unit.  Units disbanded due to city capture that are in other cities do not contribute shields to production, so we don't have to worry about that.
The first attempt at the code was:
<code>
local function doOnCityTaken(city,defender)
    for unit in civ.iterateUnits() do
    if unit.homeCity == city or (unit.carriedBy and unit.carriedBy.homeCity == city) then
    civ.deleteUnit(unit)
    end
    end
end
</code>
This code goes through all the units in the game and checks if the unit in question has its home as the captured city or if it is being carried by a unit homed to the captured city.  If either of those conditions is met, the unit is deleted.
I was expecting this code not to be correct because in some instances, the ship would be deleted before the unit being carried.  However, when I introduced some print statements into the code, I found that a Celtic settler near Milan was being deleted (when I was capturing a Carthaginian city), since the game decided it was being "carried" by a deleted caravan that had the home city of the city I was capturing.
Running an appropriate print statement for all the units in the game revealed that many units are being "carriedBy" something that doesn't make any sense.  I don't know if this is an artifact of the fact that this scenario was converted from an older version of the game, but it is best to account for it anyway.
Thus, my second iteration of the code is
<code>
local function doOnCityTaken(city,defender)
for unit in civ.iterateUnits() do
if unit.homeCity == city then
for sameSquareUnit in unit.location.units do
if sameSquareUnit.carriedBy == unit and sameSquareUnit ~= unit then
print(sameSquareUnit,"deleted.")
civ.deleteUnit(sameSquareUnit)
end
end
print(unit,"deleted")
civ.deleteUnit(unit)
end
end
end
civ.scen.onCityTaken(doOnCityTaken)
</code>
[[File:getStartedWithLuaLesson5-01-DisbandingUnits.jpg]]
This code will not delete aircraft on a carrier (and will also not delete just created units that haven't been moved with the ship, presumably since they haven't been given a carriedBy entry yet), which probably isn't a big concern for our purposes, though it might be in other cases.  However, this code will delete a unit in port that was carried there by a disbanded unit (though the ground unit itself is not supported by the captured city).  It appears that carriedBy is not cleared upon entering port, so we should check that our unit is actually at sea before checking the square for units being carried by it.  Since carriedBy isn't reliable, let's also check that the "carrying" unit is a sea unit and also has a carrying capacity before checking the square. 
<code>
local function doOnCityTaken(city,defender)
for unit in civ.iterateUnits() do
if unit.homeCity == city then
if unit.location.terrainType % 16 == terrainAliases.ocean and unit.type.domain == 2 and unit.type.hold > 0 then
for sameSquareUnit in unit.location.units do
if sameSquareUnit.carriedBy == unit and sameSquareUnit ~= unit then
print(sameSquareUnit,"deleted.")
civ.deleteUnit(sameSquareUnit)
end
end
end
print(unit,"deleted")
civ.deleteUnit(unit)
end
end
end
civ.scen.onCityTaken(doOnCityTaken)
</code>
[[File:getStartedWithLuaLesson5-02-DisbandingUnits-2.jpg]]
This function appears to work (with the exception of air units surviving a carrier disbandment).


===Keeping Units Supported by a Captured City===
===Keeping Units Supported by a Captured City===

Revision as of 19:19, 26 January 2019

Back to Get Started With Lua Events

This lesson is currently under construction.

You can find the copy of events that I started Lesson 5 with here.

Fixing The Sea Unit Disbandment Bug

In Civilization II, when a city is captured, all the units supported by that city are disbanded. It turns out that the civ.scen.onCityTaken(function (city, defender) -> void) event trigger happens before units are disbanded. This means that we can use the civ.scen.onCityTaken event trigger to do things involving soon to be disbanded units.

One thing we can do is perform the disbanding action ourselves. The reason for this is that a bug exists that disbands all the units on a sea square if a ship there is disbanded (try it). This is obviously very undesirable, but we can override it in the case of city capture by doing the disbandment ourselves.

Essentially, when a city is captured we do a for loop over all the units in the game, and if the unit is supported by the captured city, or carried by a unit supported by it, then we delete the unit. Units disbanded due to city capture that are in other cities do not contribute shields to production, so we don't have to worry about that.


The first attempt at the code was:

local function doOnCityTaken(city,defender)
   for unit in civ.iterateUnits() do
   	if unit.homeCity == city or (unit.carriedBy and unit.carriedBy.homeCity == city) then
   		civ.deleteUnit(unit)
   	end
   end
end

This code goes through all the units in the game and checks if the unit in question has its home as the captured city or if it is being carried by a unit homed to the captured city. If either of those conditions is met, the unit is deleted.

I was expecting this code not to be correct because in some instances, the ship would be deleted before the unit being carried. However, when I introduced some print statements into the code, I found that a Celtic settler near Milan was being deleted (when I was capturing a Carthaginian city), since the game decided it was being "carried" by a deleted caravan that had the home city of the city I was capturing.

Running an appropriate print statement for all the units in the game revealed that many units are being "carriedBy" something that doesn't make any sense. I don't know if this is an artifact of the fact that this scenario was converted from an older version of the game, but it is best to account for it anyway.

Thus, my second iteration of the code is

local function doOnCityTaken(city,defender)
	for unit in civ.iterateUnits() do
		if unit.homeCity == city then
			for sameSquareUnit in unit.location.units do
				if sameSquareUnit.carriedBy == unit and sameSquareUnit ~= unit then
					print(sameSquareUnit,"deleted.")
					civ.deleteUnit(sameSquareUnit)
				end
			end
			print(unit,"deleted")
			civ.deleteUnit(unit)
		end
	end
end
civ.scen.onCityTaken(doOnCityTaken)

GetStartedWithLuaLesson5-01-DisbandingUnits.jpg

This code will not delete aircraft on a carrier (and will also not delete just created units that haven't been moved with the ship, presumably since they haven't been given a carriedBy entry yet), which probably isn't a big concern for our purposes, though it might be in other cases. However, this code will delete a unit in port that was carried there by a disbanded unit (though the ground unit itself is not supported by the captured city). It appears that carriedBy is not cleared upon entering port, so we should check that our unit is actually at sea before checking the square for units being carried by it. Since carriedBy isn't reliable, let's also check that the "carrying" unit is a sea unit and also has a carrying capacity before checking the square.

local function doOnCityTaken(city,defender)
	for unit in civ.iterateUnits() do
		if unit.homeCity == city then
			if unit.location.terrainType % 16 == terrainAliases.ocean and unit.type.domain == 2 and unit.type.hold > 0 then
				for sameSquareUnit in unit.location.units do
					if sameSquareUnit.carriedBy == unit and sameSquareUnit ~= unit then
						print(sameSquareUnit,"deleted.")
						civ.deleteUnit(sameSquareUnit)
					end
				end
			end
			print(unit,"deleted")
			civ.deleteUnit(unit)
		end
	end
end
civ.scen.onCityTaken(doOnCityTaken)

GetStartedWithLuaLesson5-02-DisbandingUnits-2.jpg

This function appears to work (with the exception of air units surviving a carrier disbandment).

Keeping Units Supported by a Captured City

Generating Money With Units On Key Press

Creating and Deleting Ammunition

Creating Land Units At Sea

Unit Attack Bonus with Complementary Units In Square

Conclusion