New features via Lua script

Can you help improve your favourite game? Hardcore C mages, talented artists, and players with any level of experience are welcome!
cazfi
Elite
Posts: 3335
Joined: Tue Jan 29, 2013 6:54 pm

Re: New features via Lua script

Post by cazfi »

Molo_Parko wrote: Fri Nov 08, 2024 7:48 pm A flag for nation geographical type (island, coastal, inland or land-locked) in the ruleset files might be helpful.
Not really what you are asking for, but something that your comment inspired: https://redmine.freeciv.org/issues/1073
Molo_Parko
Hardened
Posts: 200
Joined: Fri Jul 02, 2021 4:00 pm

Re: New features via Lua script

Post by Molo_Parko »

This is the script section from the scenario "MiniMap Terrain Defense Trainer", shared at this link: https://forum.freeciv.org/f/viewtopic.php?p=110011

The first part provides 4 Fortresses, randomly placed on 4 of the map's land tiles. The second part places tile labels showing the tile terrain defense bonus. This script should work as-is when added to another scenario, though if the scenario is for Freeciv v3 and later then turn_started should be changed to turn_begin to avoid deprecation warnings. Ahh, and the # of tiles would change from 255, presumably.

Code: Select all

function setup()
	if find.tile( 255 ):has_extra( "River" ) then
		local count = 0
		for tries = 1, 10, 1 do
			tile = find.tile( random( 0, 255 ) )
			if tile.terrain:class_name() == "Land"
			and not tile:city()
			and tile.terrain:rule_name() ~= "Inaccessible"
			and not tile:has_extra ( "Fortress" ) then
				edit.create_extra( tile, "Fortress" )
				count = count + 1
				if count >= 4 then
					edit.remove_extra( find.tile( 255 ), "River" )
					goto all_done
				end
			end
		end
	end
	::all_done::
end
setup()

function s_map_labels( turn, year )
	for tile in whole_map_iterate() do
		local defense_bonus = 0
		local defense_multiplier = ""
		local defense_special = ""

		if tile.terrain == find.terrain( "Grassland" ) then defense_bonus = 1 end
		if tile.terrain == find.terrain( "Plains" ) then defense_bonus = 1 end
		if tile.terrain == find.terrain( "Tundra" ) then defense_bonus = 1 end
		if tile.terrain == find.terrain( "Desert" ) then defense_bonus = 1 end
		if tile.terrain == find.terrain( "Glacier" ) then defense_bonus = 1 end

		if tile.terrain == find.terrain( "Mountains" ) then defense_bonus = 3 end

		if tile.terrain == find.terrain( "Hills" ) then defense_bonus = 2 end

		if tile.terrain == find.terrain( "Jungle" ) then defense_bonus = 1.5 end
		if tile.terrain == find.terrain( "Swamp" ) then defense_bonus = 1.5 end
		if tile.terrain == find.terrain( "Forest" ) then defense_bonus = 1.5 end

		if tile:has_extra( "River" ) then defense_multiplier = " x 1.5" end

		if tile:has_extra( "Fortress" ) then
			defense_multiplier = defense_multiplier .. " x 2"
			defense_special = "No Stack Kill"
			-- plus Diplomat vs Diplomat +25% defense
		end

		local cityWalls = false
		if tile:city() then
			city = tile:city()
			defense_special = "No Stack Kill"

			local id, building, buildingName
			for id = 0, 67, 1 do
				building = find.building_type( id )
				buildingName = ( building ):rule_name()
				if buildingName == "City Walls" then
					if city:has_building( building ) then
						cityWalls = true
						defense_multiplier = defense_multiplier .. " x 3"
						break
					end
				end
				if buildingName == "Coinage" then break end
			end
			if cityWalls == false then
				defense_multiplier = defense_multiplier .. " x 1.5"
			end
		end

		if defense_bonus ~= 0 then
			edit.tile_set_label( tile, " + " .. defense_bonus .. "\n" .. defense_multiplier )
		else
			edit.tile_set_label( tile, "" )
		end
	end
end
signal.connect( "turn_started", "s_map_labels" )
^ version 1.1 with either City Walls x3 modifier or city only 1.5 modifier not both.
Molo_Parko
Hardened
Posts: 200
Joined: Fri Jul 02, 2021 4:00 pm

Re: New features via Lua script

Post by Molo_Parko »

These are the Lua scripts included in the scenario "The Gridiron", shared at this link: https://forum.freeciv.org/f/viewtopic.p ... 33#p110033

The top portion is "loose code" not within a function, such code runs once on gamestart and after reload of saved games.

Then the functions are:
  • function s_select_unit_type( player )
  • function s_add_new_tech( player )
  • function s_unit_moved( unit, src_tile, dst_tile )
  • function s_name( player )
  • function s_unit_lost( unit, loser, reason )
  • function s_endzone_and_bench_labels()
  • function s_main()
  • function s_position_units()
The function names begin with s_ to indicate that they are included in the Scenario / saved game's ".sav" file ( which is a plain text file, often compressed as in zip, bzip / bz, and so on.)

"s_unit_moved" is the routine which handles the movement of the football (a single segment of the River extra), touchdowns, kicks and field goals.

Code: Select all

if find.tile( 2, 0 ):has_extra( "River" ) then
	edit.remove_extra( find.tile( 2, 0 ), "River" )
	notify.event( nil, nil, E.REPORT, _(
	"[c fg=\"#0000ff\"][b]\n\n\
Welcome to The Gridiron scenario for Freeciv 2.6.4 and later[/b]\n\
Created and tested with Freeciv 2.6.4 and GTK2 client.\n\
A basic football game between two teams, to the death for one or the other!\n\n\
Victory is acheived by eliminating all eleven enemy units in a single turn.\n\
Unit losses are replaced at the beginning of each turn.\n\n\
Touchdowns earn six points, field goals two.\n\
Touchdowns and field goals also make new unit types available to both teams.\n\
Types of units are random among those of known technologies.\n\n\
The next turn after a touchdown or field goal begins with units returned to the starting formation.\n\n\
The football is blue. To carry it, move a unit onto the tile, and the unit will carry the ball.\n\
To kick, have one unit hold the football, and move a second unit onto the tile.\n\
The goalposts are the ends of the white tiles on either side of the field.\n\n\
In the final score report, the football score is the column labeled Culture\n\n[/c]" ) )
	_G.ReloadDetected = false
	log.error( "%s", "The game is about to begin" )
else
	log.error( "%s", "Reload detected" )
	_G.ReloadDetected = true
	_G.endzone = {}
	_G.bench = {}
	if find.tile( 0, 18 ):has_extra( "Irrigation" ) then
		_G.endzone[ find.player( 0 ) ] = 0
		  _G.bench[ find.player( 0 ) ] = 1
		_G.endzone[ find.player( 1 ) ] = 32
		  _G.bench[ find.player( 1 ) ] = 17
	else
		_G.endzone[ find.player( 0 ) ] = 32
		  _G.bench[ find.player( 0 ) ] = 17
		_G.endzone[ find.player( 1 ) ] = 0
		  _G.bench[ find.player( 1 ) ] = 1
	end
	if _G.unit_type_names == nil then
		_G.unit_type_names = "Warriors|Horsemen|Phalanx|Archers"
	end
end


-- Emulate Fc 3.0 game.current_turn()
if game.current_turn == nil then
	function _G.game.current_turn()
		return math.floor( game.turn() )
	end
end


function s_select_unit_type( player )
	local unit_type_names_table = {}
	for field in string.gmatch( _G.unit_type_names, "[^|]+" ) do
		unit_type_names_table[ #unit_type_names_table + 1 ] = field
	end
	local unit_type_name = unit_type_names_table[ random( 1, #unit_type_names_table ) ]
	return find.unit_type( unit_type_name )
end


function s_add_new_tech( player )
	local military_land_unit_types_tech = { 
	"Horseback Riding", "Bronze Working", "Warrior Code", 
	"The Wheel", "Iron Working", "Mathematics", "Feudalism", 
	"Chivalry", "Gunpowder", "Metallurgy", "Leadership", 
	"Conscription", "Tactics", "Tactics", "Guerilla Warfare", 
	"Machine Tools", "Amphibious Warfare", "Mobile Warfare", 
	"Labor Union", "Robotics" }

	local military_land_unit_types_names = { 
	"Horsemen", "Phalanx", "Archers", "Chariot", 
	"Legion", "Catapult", "Pikemen", "Knights", 
	"Musketeers", "Cannon", "Dragoons", "Riflemen", 
	"Alpine Troops", "Cavalry", "Partisan", 
	"Artillery", "Marines", "Armor", "Mech. Inf.", 
	"Howitzer" }
	for i = 1, #military_land_unit_types_tech, 1 do
		local tech = find.tech_type( military_land_unit_types_tech[ i ] )
		if not player:knows_tech( tech ) then
			for player in players_iterate() do
				if player == find.player( 2 ) then goto skip_it end
				edit.give_tech( player, tech, -1, nil, "hut" )
				::skip_it::
			end
			_G.unit_type_names = _G.unit_type_names .. "|" .. military_land_unit_types_names[ i ]
			local output = military_land_unit_types_names[ i ] .. " units are now available for both teams."
			notify.event( nil, nil, E.REPORT, output )
			notify.event( nil, nil, E.CHAT_MSG, output )
			break
		end
	end
end


function s_unit_moved( unit, src_tile, dst_tile )
	edit.tile_set_label( dst_tile, math.floor( unit.id - 100 ) )
	edit.tile_set_label( src_tile, "" )

	if _G.position_units_in_progress == true then return end

	local ball_src_tile = _G.ball

	-- Remove Lures from endzone if unit enters endzone
	if ( unit.tile.x < 3 or unit.tile.x > 30 )
	and unit.utype ~= find.unit_type( "Spy" )
	and unit.utype ~= find.unit_type( "Workers" ) then
		if _G.lure_unit_1 ~= nil and _G.lure_unit_1:exists() then
			edit.unit_kill( _G.lure_unit_1, "disbanded", Barbarians )
		end
	end

	-- Touchdown and Own Goal
	if _G.ball == src_tile then

		edit.remove_extra( src_tile, "River" )
		edit.create_extra( dst_tile, "River" )
		_G.ball = dst_tile

		if _G.ball.x < 2 and _G.ball.y > 0 and _G.ball.y < 18 then
			if _G.endzone[ unit.owner ] ~= 0 then
				edit.add_player_history( unit.owner, 6 )
				_G.reset_positions_next_turn = true
				local output = "TOUCHDOWN! \tBy #" .. math.floor( tostring( unit.id ) ) ..
					" of " .. s_name( unit.owner ) .. "\t"
				notify.event( nil, nil, E.SCRIPT, output )
				notify.event( nil, nil, E.CHAT_MSG, output )
				s_add_new_tech( unit.owner )
				s_add_new_tech( unit.owner ) -- twice for touchdowns
				edit.remove_extra( dst_tile, "River" )
				_G.ball = find.tile( 16, 9 )
			elseif _G.endzone[ unit.owner ] == 0 then
				_G.reset_positions_next_turn = true
				if unit.owner.id == 0 then 
					edit.add_player_history( find.player( 1 ), 6 )
				else
					edit.add_player_history( find.player( 0 ), 6 )
				end
				local output = "OWN GOAL! " .. tostring( unit.owner ) ..
					" scored for the other team!"
				notify.event( nil, nil, E.SCRIPT, output )
				notify.event( nil, nil, E.CHAT_MSG, output )
				edit.remove_extra( dst_tile, "River" )
				_G.ball = find.tile( 16, 9 )
			end
		end

		if _G.ball.x > 30 and _G.ball.y > 0 and _G.ball.y < 18 then
			if _G.endzone[ unit.owner ] ~= 32 then
				edit.add_player_history( unit.owner, 6 )
				_G.reset_positions_next_turn = true
				local output = "TOUCHDOWN! By #" .. math.floor( tostring( unit.id ) ) ..
					" of " .. s_name( unit.owner )
				notify.event( nil, nil, E.SCRIPT, output )
				notify.event( nil, nil, E.CHAT_MSG, output )
				s_add_new_tech( unit.owner )
				s_add_new_tech( unit.owner ) -- twice for touchdowns
				edit.remove_extra( dst_tile, "River" )
				_G.ball = find.tile( 16, 9 )
			elseif _G.endzone[ unit.owner ] == 32 then
				_G.reset_positions_next_turn = true
				if unit.owner.id == 0 then 
					edit.add_player_history( find.player( 1 ), 6 )
				else
					edit.add_player_history( find.player( 0 ), 6 )
				end
				local output = "OWN GOAL! " .. tostring( unit.owner ) ..
					" scored for the other team!"
				notify.event( nil, nil, E.SCRIPT, output )
				notify.event( nil, nil, E.CHAT_MSG, output )
				edit.remove_extra( dst_tile, "River" )
				_G.ball = find.tile( 16, 9 )
			end
		end
	end

	-- Kick
	if src_tile ~= ball_src_tile and _G.ball == dst_tile and dst_tile:num_units() > 1 then
		local x_direction, y_direction, count = 0, 0, 0

		if dst_tile:num_units() > 1 and dst_tile == _G.ball then
			if src_tile.x < dst_tile.x then x_direction = 1 end
			if src_tile.x > dst_tile.x then x_direction = -1 end
			if src_tile.y < dst_tile.y then y_direction = 1 end
			if src_tile.y > dst_tile.y then y_direction = -1 end
			for i = 1, random( 2, 13 ), 1 do
 
				if ball.x + x_direction >= 14 and ball.x + x_direction <= 18 then
					if ball.y + y_direction == 0 or ball.y + y_direction == 18 then
						goto off_the_map
					end
				end

				if ball.x + x_direction < 0
				or ball.x + x_direction > 32 then
					goto off_the_map
				end
				if ball.y + y_direction < 0
				or ball.y + y_direction > 18 then
					goto off_the_map
				end
				edit.remove_extra( _G.ball, "River" )
				_G.ball = find.tile( ball.x + x_direction, ball.y + y_direction )
				edit.create_extra( _G.ball, "River" )
			end
			::off_the_map::

			-- Field goal
			if ( _G.ball.x < 2 or _G.ball.x > 30 )
			and ( _G.ball.y >= 7 and _G.ball.y <= 11 ) then
				edit.add_player_history( unit.owner, 2 )
				local output = "FIELD GOAL! " .. tostring( unit.owner )
				notify.event( nil, nil, E.SCRIPT, output )
				notify.event( nil, nil, E.CHAT_MSG, output )
				s_add_new_tech( unit.owner )
				_G.reset_positions_next_turn = true
			else

				local output = "#" .. math.floor( tostring( unit.id ) - 100 ) .. 
				" of " .. s_name( unit.owner ) .. " kicked the ball to " .. 
				math.floor( _G.ball.x ) .. ", " .. math.floor( _G.ball.y )

				notify.event( unit.owner, dst_tile, E.SCRIPT, output )
				notify.event( nil, dst_tile, E.CHAT_MSG, output )
			end
		end
		-- Remove lure after a kick
		if _G.lure_unit_1 ~= nil and _G.lure_unit_1:exists() then
			edit.unit_kill( _G.lure_unit_1, "disbanded", Barbarians )
		end
	end

	-- Fumble
	if ball == dst_tile and random( 1, 400 ) > 395 then
		edit.remove_extra( src_tile, "River" )
		edit.remove_extra( dst_tile, "River" )
		local x = dst_tile.x + random( -2, 2 )
		local y = dst_tile.y + random( -2, 2 )
		local tile = find.tile( x, y )
		if tile then
			edit.create_extra( tile, "River" )
			_G.ball = tile
		end
		if ball ~= dst_tile then

			local output = " FUMBLE by #" .. math.floor( unit.id - 100 ) .. 
			" of " .. s_name( unit.owner ) .. "!"

			notify.event( unit.owner, dst_tile, E.SCRIPT, output )
			notify.event( nil, dst_tile, E.CHAT_MSG, output )
		end
	end
end
signal.connect( "unit_moved", "s_unit_moved" )


function s_name( player )
	local playerName
	if player and player ~= "" then
		playerName = string.sub( tostring( player.nation ), 14, -2 )
		playerName = playerName:gsub( "^.-%s", "", 1 )
		playerName = ( "#" .. math.floor( player.id ) .. " " ..
				playerName .. " ( " .. player.name .. " )"
				)
		return playerName
	end
	return false
end


function s_unit_lost( unit, loser, reason )
	edit.tile_set_label( unit.tile, "" )
	local output
	if reason == "killed" then
		if unit.owner == find.player( 0 ) then
			output = "[c fg=\"#660000\"][b]"
		else
			output = "[c fg=\"#006600\"][b]"
		end

		output = output .. "Unit lost:  #" .. math.floor( unit.id - 100 ) .. " " .. unit.utype:rule_name() .. " of " .. s_name( unit.owner ) .. "!      \tRemaining:" .. math.floor( unit.owner:num_units() - 1 ) .. "[/b][/c]"
	notify.event( nil, dst_tile, E.CHAT_MSG, output )

		if loser.id == 0 then
			player_0_losses = player_0_losses + 1
			player_1_kills = player_1_kills + 1
		else
			player_1_losses = player_1_losses + 1
			player_0_kills = player_0_kills + 1
		end
	end
end
signal.connect( "unit_lost", "s_unit_lost" )


function s_endzone_and_bench_labels()
	local tile
	for player in players_iterate() do
		if player == find.player( 2 ) then goto fuggedaboutit end
		if _G.endzone[ player ] == 0 then
			tile = find.tile( 2, 8 )
			edit.tile_set_label( tile, player.nation:rule_name() )
			tile = find.tile( 16, 1 )
			edit.tile_set_label( tile, player.nation:rule_name() .. " bench" )
		elseif _G.endzone[ player ] == 32 then
			tile = find.tile( 30, 8 )
			edit.tile_set_label( tile, player.nation:rule_name() )
			tile = find.tile( 16, 17 )
			edit.tile_set_label( tile, player.nation:rule_name() .. " bench" )
		end
		::fuggedaboutit::
	end
end


function s_main()
	if ( not _G.ReloadDetected ) and ( game.current_turn() == 0 ) then

		local tech_types = { "Bronze Working", "Horseback Riding", "Warrior Code" }
		for tech_type = 1, 3, 1 do
			local tech = find.tech_type( tech_types[ tech_type ] )
			edit.give_tech( find.player( 0 ), tech, -1, nil, "hut" )
			edit.give_tech( find.player( 1 ), tech, -1, nil, "hut" )
		end
		_G.unit_type_names = "Warriors|Horsemen|Phalanx|Archers"

		Barbarians = edit.create_player( "Dedbreth", find.nation_type( "Barbarian" ), Land )

		_G.endzone = {}
		_G.bench = {}
		_G.ball = find.tile( 16, 9 )

		player_0_losses = 0
		player_1_losses = 0
		player_0_kills = 0
		player_1_kills = 0
		for player in players_iterate() do
			if player == find.player( 2 ) then goto no_thanks end
			for unit in player:units_iterate() do
				tile = unit.tile
				if tile.x <= 16 then
					_G.endzone[ player ] = 0
					_G.bench[ player ] = 1
				else
					_G.endzone[ player ] = 32
					_G.bench[ player ] = 17
				end
				break
			end
			::no_thanks::
		end

		-- for reloads
		if _G.endzone[ find.player( 0 ) ] == 0 then
			edit.create_extra( find.tile( 0, 18 ), "Irrigation" )
		end

		s_endzone_and_bench_labels()
		s_position_units()
	end

	if game.current_turn() > 0 and _G.ReloadDetected == false then
		local output = "[c fg=\"#000066\"][b]Turn: " .. game.current_turn() .. 
		" \t\tScore: " .. math.floor( find.player( 0 ):culture() ) .. " - " .. math.floor( find.player( 1 ):culture() ) .. 
		" \t\tKills: " .. player_0_kills .. " - " .. player_1_kills ..
		" \tUnits: Player 0: " .. math.floor( find.player( 0 ):num_units() ) .. " \tPlayer 1: " .. math.floor( find.player( 1 ):num_units() ) .. 
		" \t\tBall at: " .. math.floor( _G.ball.x ) .. ", " .. math.floor( _G.ball.y )  .. "[/b][/c]"
		notify.event( nil, dst_tile, E.REPORT, output )
		notify.event( nil, dst_tile, E.CHAT_MSG, "" )
		notify.event( nil, dst_tile, E.CHAT_MSG, output )
	end

	for player in players_iterate() do
		if player == find.player( 2 ) then goto not_now end
		local count = 0
		for unit in player:units_iterate() do
			count = count + 1
			if count > 11 then edit.unit_kill( unit, "disbanded", player ) end 
		end
		::not_now::
	end

	s_endzone_and_bench_labels()
	for player in players_iterate() do
		if player == find.player( 2 ) then goto no_way end
		if player:num_units() < 11 then
			repeat
				local tile = find.tile( random( 13, 19 ), _G.bench[ player ] )
				local unit_type = s_select_unit_type( player )
				pcall( edit.create_unit_full( player, tile, unit_type, 0, nil, -1, -1, nil ) )
			until player:num_units() >= 11
		end
		::no_way::
	end

	if _G.reset_positions_next_turn == true then
		_G.reset_positions_next_turn = false
		s_position_units()
	end

	-- Skip creating lures if units in the endzones
	local columns = {  0,  1, 31, 32 }
	for row = 1, 18, 1 do
		for x = 1, #columns, 1 do
			tile = find.tile( columns[ x ], row )
			for unit in tile:units_iterate() do
				if unit.owner ~= Barbarians then
					goto nevermind
				end
			end
		end
	end

	-- Lure whenever a computer-controlled team unit has the ball
	if game.current_turn() > 5 and find.player( 1 ):is_human() == false then
		local unit_type
		local lure_tileIDs_west = { 231, 264, 297, 330, 363 }
		local lure_tileIDs_east = { 263, 296, 329, 362, 395 }
		local lure_tile_west = find.tile( lure_tileIDs_west[ random( 1, #lure_tileIDs_west ) ] )
		local lure_tile_east = find.tile( lure_tileIDs_east[ random( 1, #lure_tileIDs_east ) ] )
		local lure_tile
		if random( 1, 2 ) == 1 then
			unit_type = find.unit_type( "Workers" )
		else
			unit_type = find.unit_type( "Spy" )
		end

		for unit in _G.ball:units_iterate() do
			if _G.endzone[ unit.owner ] == 0 then
				lure_tile = lure_tile_east
			else
				lure_tile = lure_tile_west
			end				
			if _G.lure_unit_1 ~= nil and _G.lure_unit_1:exists() then
				edit.unit_move( _G.lure_unit_1, lure_tile, 99 )
				edit.tile_set_label( lure_tile, "" )
			else
				_G.lure_unit_1 = edit.create_unit_full( Barbarians, lure_tile, unit_type, 0, nil, -1, -1, nil )
				local output = "Cheerleaders are dancing in the endzones!"
				notify.event( nil, nil, E.CHAT_MSG, output )
			end
			break
		end
	end
	::nevermind::
end
signal.connect( "turn_started", "s_main" )


function s_position_units()

	if _G.lure_unit_1 ~= nil and _G.lure_unit_1:exists() then
		edit.unit_kill( _G.lure_unit_1, "disbanded", Barbarians )
	end

	_G.position_units_in_progress = true
	if ball then edit.remove_extra( ball, "River" ) end
	ball = find.tile( 16, 9 )
	edit.create_extra( ball, "River" )

	local tileIDs_right = { 316, 184, 186, 217, 221, 318, 352, 415, 419, 448, 450 }
	local tileIDs_left  = { 310, 178, 176, 207, 211, 274, 308, 405, 409, 440, 442 }

	local tile
	for player in players_iterate() do
		if player == find.player( 2 ) then goto get_outta_here end
		if _G.endzone[ player ] == 0 then
			tile = find.tile( tileIDs_left[ 1 ] )
		elseif _G.endzone[ player ] == 32 then
			tile = find.tile( tileIDs_right[ 1 ] )
		end

		if player:num_units() < 11 then
			repeat
				local unit_type = s_select_unit_type( player )
				edit.create_unit_full( player, tile, unit_type, 0, nil, -1, -1, nil )
			until player:num_units() == 11
		end

		local i = 1
		if _G.endzone[ player ] == 32 then
			for unit in player:units_iterate() do
				edit.tile_set_label( unit.tile, "" )
				local offset_x = random( -1, 1 )
				local offset_y = random( -1, 1 )
				if offset_y == 1 then
					offset_y = -33
				elseif offset_y == 2 then
					offset_y = 33
				end
				tile = find.tile( tileIDs_right[ i ] + offset_x + offset_y )
				edit.unit_move( unit, tile, 0 )
				edit.tile_set_label( tile, math.floor( unit.id - 100 ) )
				i = i + 1
			end
		elseif _G.endzone[ player ] == 0 then
			for unit in player:units_iterate() do
				edit.tile_set_label( unit.tile, "" )
				local offset_x = random( -1, 1 )
				local offset_y = random( -1, 1 )
				if offset_y == 1 then
					offset_y = -33
				elseif offset_y == 2 then
					offset_y = 33
				end
				tile = find.tile( tileIDs_left[ i ] + offset_x + offset_y )
				edit.unit_move( unit, tile, 0 )
				edit.tile_set_label( tile, math.floor( unit.id - 100 ) )
				i = i + 1
			end
		end
		::get_outta_here::
	end
	_G.position_units_in_progress = false
end

Molo_Parko
Hardened
Posts: 200
Joined: Fri Jul 02, 2021 4:00 pm

Re: New features via Lua script

Post by Molo_Parko »

This routine demonstrates a variety of Lua script commands and functions.

Each entry shows the command, the live result, and the data type where applicable. The "userdata" output type = tolua.

Limited to Freeciv 2.6.4 to 2.6.11 compatible stuff, because I am using Freeciv 2.6.4 and 2.6.11.

The top part of the script is the "echo" output routine, the rest is the list of commands and their output.


Image
^ Sample output.

Code: Select all

function echo( return_type, command, output, note )
	if command == nil and output == nil then notify.event( nil, nil, E.CHAT_MSG, "" ) return end
	if output == nil then output = "" end
	if command == nil then command = "" end

	-- This output is to the Chat pane only
	notify.event( nil, nil, E.CHAT_MSG, return_type .. "\t" .. command .. " = " .. tostring( output ) )
	if note ~= "" then
		notify.event( nil, nil, E.CHAT_MSG, "\t\t" .. note )
	end

	-- A blank line after the output
	notify.event( nil, nil, E.CHAT_MSG, "")
end

function s_command_examples( turn, year )
	if game.turn() > 1 then return end
	echo()

	local output, note
	local return_type = ""
	local command = ""
	local Player = find.player( 0 )
	local Nation_type = find.nation_type( Player.nation.id )
	local Government = find.government( 0 )
	local Tech_type = find.tech_type( "Bridge Building" )
	local Terrain = find.terrain( "Hills" )
	local Unit_type = find.unit_type( "Phalanx" )
	local Building_type = find.building_type( "City Walls" )

	local Unit
	for unit in Player:units_iterate() do
		Unit = unit
		break
	end

	note = "[b]Examples of Freeciv 2.6.4 Lua commands and functions[/b]"
	notify.event( nil, nil, E.CHAT_MSG, "\t\t" .. note )
	notify.event( nil, nil, E.CHAT_MSG, "" )

	note = "Info source: https://freeciv.fandom.com/wiki/Lua_reference_manual#Tech_Type"
	notify.event( nil, nil, E.CHAT_MSG, "\t\t" .. note )
	notify.event( nil, nil, E.CHAT_MSG, "" )

	note = "Variable names are in [ c fg \"#000099\"]blue[/c]"
	notify.event( nil, nil, E.CHAT_MSG, "\t\t" .. note )
	notify.event( nil, nil, E.CHAT_MSG, "" )
	notify.event( nil, nil, E.CHAT_MSG, "" )

	note = "[b]Output	Command			Result[/b]"
	notify.event( nil, nil, E.CHAT_MSG, note )
	notify.event( nil, nil, E.CHAT_MSG, "" )

	output = fc_version() command = "fc_version()" return_type = type( output )
	note = ""
	echo( return_type, command, output, note )

	output = _VERSION command = '[ c fg \"#000099\"]_VERSION[/c] is a variable which holds the Lua version' return_type = type( output )
	note = ""
	echo( return_type, command, output, note )

	output = turn command = "[ c fg \"#000099\"]turn[/c]" return_type = type( output )
	note = ""
	echo( return_type, command, output, note )

	output = year command = "[ c fg \"#000099\"]year[/c]" return_type = type( output )
	note = ""
	echo( return_type, command, output, note )

	output = game.turn() command = "game.turn()" return_type = type( output )
	note = "Deprecated as of Freeciv 3.0. Use game.current_turn() instead."
	echo( return_type, command, output, note )

	output = math.floor( game.turn() ) command = "math.floor( game.turn() )" return_type = type( output )
	note = ""
	echo( return_type, command, output, note )

	output = find.player( 0 ) command = "find.player( 0 )" return_type = type( output )
	note = "Like \"player #0 AI*1\" before gamestart, after it is like \"Player #0 Klef\""
	echo( return_type, command, output, note )

	output = Player.id command = "[ c fg \"#000099\"](Player)[/c].id" return_type = type( output )
	note = ""
	echo( return_type, command, output, note )

	output = Player.name command = "[ c fg \"#000099\"](Player)[/c].name" return_type = type ( output )
	note = "Like \"AI*1\" before gamestart, after it is like \"Klef\""
	echo( return_type, command, output, note )

	output = Player.ai_controlled  command = "[ c fg \"#000099\"](Player)[/c].ai_controlled" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Player.is_alive  command = "[ c fg \"#000099\"](Player)[/c].is_alive" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Player:is_human()  command = "[ c fg \"#000099\"](Player)[/c]:is_human()" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Player:num_cities()  command = "[ c fg \"#000099\"](Player)[/c]:num_cities()" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Player:num_units()  command = "[ c fg \"#000099\"](Player)[/c]:num_units()" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Player:gold()  command = "[ c fg \"#000099\"](Player)[/c]:gold()" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Player:exists()  command = "[ c fg \"#000099\"](Player)[/c]:exists()" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = find.tech_type( "Bridge Building" )  command = "find.tech_type( \"Bridge Building\" )" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = find.tech_type( 8 )  command = "find.tech_type( 7 )" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Tech_type.id  command = "[ c fg \"#000099\"](Tech_type)[/c].id" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Tech_type:rule_name()  command = "[ c fg \"#000099\"](Tech_type)[/c]:rule_name()" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Tech_type:name_translation()  command = "[ c fg \"#000099\"](Tech_type)[/c]:name_translation()" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Player:knows_tech( Tech_type )  command = "[ c fg \"#000099\"](Player)[/c]:knows_tech( [ c fg \"#000099\"](Tech_type)[/c] )" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Player:units_iterate()  command = "[ c fg \"#000099\"](Player)[/c]:units_iterate()" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Player:cities_iterate()  command = "[ c fg \"#000099\"](Player)[/c]:cities_iterate()" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Player:shares_research( (Player) )  command = "[ c fg \"#000099\"](Player)[/c]:shares_research( [ c fg \"#000099\"](Player)[/c] )" return_type = type ( output )
	note = "I like that I share with myself. It gives me a warm feeling."
	echo( return_type, command, output, note )

	output = Player:culture()  command = "[ c fg \"#000099\"](Player)[/c]:culture()" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Player.nation command = "[ c fg \"#000099\"](Player)[/c].nation" return_type = type ( output )
	note = "nil before gamestart, after like \"<Nation_Type #269 Langobardic>\""
	echo( return_type, command, output, note )	

	output = Player.nation.id command = "[ c fg \"#000099\"](Player)[/c].nation.id" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = find.nation_type( Player.nation.id ) command = "find.nation_type( [ c fg \"#000099\"](Player)[/c].nation.id )" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = find.nation_type( 555 ) command = "find.nation_type( 555 )" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = find.nation_type( "Barbarian" ) command = "find.nation_type( \"Barbarian\" )" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = find.nation_type( "Pirate" ) command = "find.nation_type( \"Pirate\" )" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Player.nation:rule_name() command = "[ c fg \"#000099\"](Player)[/c].nation:rule_name()" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Player.nation:name_translation() command = "[ c fg \"#000099\"](Player)[/c].nation:name_translation()" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Player.nation:plural_translation() command = "[ c fg \"#000099\"](Player)[/c].nation:plural_translation()" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Nation_type:trait_min( "expansionist" ) command = "[ c fg \"#000099\"](Player)[/c].nation:trait_min( \"expansionist\" )" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Nation_type:trait_max( "expansionist" ) command = "[ c fg \"#000099\"](Player)[/c].nation:trait_max( \"expansionist\" )" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Nation_type:trait_default( "expansionist" ) command = "[ c fg \"#000099\"](Player)[/c].nation:trait_default( \"expansionist\" )" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Nation_type:trait_min( "trader" ) command = "[ c fg \"#000099\"](Player)[/c].nation:trait_min( \"trader\" )" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Nation_type:trait_max( "trader" ) command = "[ c fg \"#000099\"](Player)[/c].nation:trait_max( \"trader\" )" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Nation_type:trait_default( "trader" ) command = "[ c fg \"#000099\"](Player)[/c].nation:trait_default( \"trader\" )" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Nation_type:trait_min( "aggressive" ) command = "[ c fg \"#000099\"](Player)[/c].nation:trait_min( \"aggressive\" )" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Nation_type:trait_max( "aggressive" ) command = "[ c fg \"#000099\"](Player)[/c].nation:trait_max( \"aggressive\" )" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Nation_type:trait_default( "aggressive" ) command = "[ c fg \"#000099\"](Player)[/c].nation:trait_default( \"aggressive\" )" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = find.government( "Monarchy" ) command = "find.government( \"Monarchy\" )" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = find.government( 3 ) command = "find.government( 3 )" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Government:rule_name() command = "[ c fg \"#000099\"](Government)[/c]:rule_name()" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Government:name_translation() command = "[ c fg \"#000099\"](Government)[/c]:name_translation()" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = server.started() command = "server.started()" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = server.civilization_score( Player ) command = "server.civilization_score( [ c fg \"#000099\"](Player)[/c] )" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = server.setting.get( "startunits" ) command = "server.setting.get( \"startunits\" )" return_type = type ( output )
	note = "Works for settings listed in a scenario .sav file, and any omitted there and thus from current settings on server."
	echo( return_type, command, output, note )

	Direction = direction.str2dir( "west" )
	output = direction.str2dir( "north" ) command = "direction.str2dir( \"north\" )" return_type = type ( output )
	note = "Malfunctional in Freeciv 2.6.4 -- returns a string rather than a tolua object. Direction stuff won't work at all, including 'Unit:facing()'."
	echo( return_type, command, output, note )

	output = direction.next_ccw( Direction ) command = "direction.next_ccw( [ c fg \"#000099\"](Direction)[/c] )" return_type = type ( output )
	note = "Works in 2.6.11"
	echo( return_type, command, output, note )

	output = direction.next_cw( Direction ) command = "direction.next_cw( [ c fg \"#000099\"](Direction)[/c] )" return_type = type ( output )
	note = "Works in 2.6.11"
	echo( return_type, command, output, note )

	output = direction.opposite( Direction ) command = "direction.opposite( [ c fg \"#000099\"](Direction)[/c] )" return_type = type ( output )
	note = "Works in 2.6.11"
	echo( return_type, command, output, note )

	output = Unit:facing() command = "[ c fg \"#000099\"](Unit)[/c]:facing()" return_type = type ( output )
	note = "Works in 2.6.11"
	echo( return_type, command, output, note )

-- testing Directions
	for unit in Player:units_iterate() do
		Unit = unit
		Direction = direction.str2dir( "east" )
		output = edit.unit_turn( Unit, Direction ) command = "[ c fg \"#000099\"](Unit)[/c], [ c fg \"#000099\"](Direction)[/c] )" return_type = type ( output )
		note = "Works in 2.6.11?"
		echo( return_type, command, output, note )
	end

	output = find.building_type( 7 ) command = "find.building_type( 7 )" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = find.building_type( "City Walls" ) command = "find.building_type( \"City Walls\" )" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Building_type.build_cost command = "[ c fg \"#000099\"](Building_type)[/c].build_cost" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Building_type:build_shield_cost() command = "[ c fg \"#000099\"](Building_type)[/c]:build_shield_cost()" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Building_type.id command = "[ c fg \"#000099\"](Building_type)[/c].id" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Building_type:is_wonder() command = "[ c fg \"#000099\"](Building_type)[/c]:is_wonder()" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Building_type:is_great_wonder() command = "[ c fg \"#000099\"](Building_type)[/c]:is_great_wonder()" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Building_type:is_small_wonder() command = "[ c fg \"#000099\"](Building_type)[/c]:is_small_wonder()" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Building_type:is_improvement() command = "[ c fg \"#000099\"](Building_type)[/c]:is_improvement()" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Building_type:rule_name() command = "[ c fg \"#000099\"](Building_type)[/c]:rule_name()" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Building_type:name_translation() command = "[ c fg \"#000099\"](Building_type)[/c]:name_translation()" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = find.unit_type( 4 ) command = "find.unit_type( 4 )" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = find.unit_type( "Phalanx" ) command = "find.unit_type( \"Phalanx\" )" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Unit_type.build_cost command = "[ c fg \"#000099\"](Unit_type)[/c].build_cost" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Unit_type:build_shield_cost() command = "[ c fg \"#000099\"](Unit_type)[/c]:build_shield_cost()" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Unit_type:has_flag( "Paratroopers" ) command = "[ c fg \"#000099\"](Unit_type)[/c]:has_flag( \"Paratroopers\" )" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Unit_type:has_role( "AttackFastStartUnit" ) command = "[ c fg \"#000099\"](Unit_type)[/c].has_role( \"AttackFastStartUnit\" )" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = find.role_unit_type( "DefendGood", nil ) command = "find.role_unit_type( \"DefendGood\", nil )" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = find.role_unit_type( "DefendOk", Player ) command = "find.role_unit_type( \"DefendOk\", [ c fg \"#000099\"](Player)[/c] )" return_type = type ( output )
	note = "If nil is replaced with a player, then response unit type is limited to those which the player can build."
	echo( return_type, command, output, note )

	output = Unit_type:can_exist_at_tile( find.tile( 0, 1 ) ) command = "[ c fg \"#000099\"](Unit_type)[/c]:can_exist_at_tile( find.tile( 0, 1 )" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = find.tile( 10, 15 ) command = "find.tile( 10, 15 )" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = find.tile( 1810 ) command = "find.tile( 1810 )" return_type = type ( output )
	note = "Tile ID is ( x = 10 ) + ( ( y = 15 ) * server.setting.get( \"xsize\" ) )" 
	echo( return_type, command, output, note )

	Tech_type = find.tech_type( "Bronze Working" )
	output = edit.give_tech( Player, Tech_type, 0, nil, "hut" )  command = "edit.give_tech( [ c fg \"#000099\"](Player)[/c], [ c fg \"#000099\"](Tech_type)[/c], 0, nil, \"hut\" )" return_type = type ( output )
	note = "Fields are: player, tech_type or nil for random tech, cost, notify, reason"
	echo( return_type, command, output, note )

	output = find.terrain( 1 ) command = "find.terrain( 1 )" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = find.terrain( "Grassland" ) command = "find.terrain( \"Grassland\" )" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Terrain:rule_name() command = "[ c fg \"#000099\"](Terrain)[/c]:rule_name()" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Terrain:name_translation() command = "[ c fg \"#000099\"](Terrain)[/c]:name_translation()" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = Terrain:class_name() command = "[ c fg \"#000099\"](Terrain)[/c]:class_name()" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	output = effects.world_bonus( "Enable_Space" ) command = "effects.world_bonus( \"Enable_Space\" )" return_type = type ( output )
	note = "Effects names are listed in effects.ruleset"
	echo( return_type, command, output, note )

	output = effects.player_bonus( Player, "Specialist_Output" ) command = "effects.player_bonus( Player, \"Specialist_Output\" )" return_type = type ( output )
	note = ""
	echo( return_type, command, output, note )

	for index = 0, 100, 1 do
		Signal = find.signal( index )
		if Signal == nil then break end
		output = find.signal( index ) command = "find.signal( " .. index .. " )" return_type = type ( output )
		echo( return_type, command, output, note )
		output = find.signal_callback( Signal, index ) command = "find.signal_callback( Signal, index )" return_type = type ( output )
		if output ~= nil then echo( return_type, command, output, note ) end
	end

	notify.event( nil, nil, E.CHAT_MSG, "notify.event E.CHAT_MSG goes to the chat pane only, no pop-ups, no Messages pane, works on turn 0 too")

	notify.all( "notify.all: ALWAYS pop-up message even on turn 0, does not show in Messages or Chat panes on turn 0, does show in Messages and Chat panes after turn 0" )
	notify.event( nil, nil, E.SCRIPT, "notify.event E.SCRIPT: ALWAYS pop-up message, even on turn 0, but no message in Messages pane on turn 0, does show after turn 0" )

	notify.event( nil, nil, E.REPORT, "notify.event E.REPORT: goes to chat on turn 0, to Messages thereafter, never a pop-up" )

	log.error( "%s", "log.error: Appears on turn 0 and thereafter in Chat pane if msg is different each time, otherwise msg becomes only 'Last message repeated x times'', bright red text, also included in error log files." )


	notify.event( nil, nil, E.CHAT_MSG, "" )
	
option_names={ "aifill", "airliftingstyle", "allowtake", "alltemperate", "animals", "aqueductloss", "autoattack", "autosaves", "autotoggle", "barbarians", "borders", "citymindist", "citynames", "civilwarsize", "compress", "compresstype", "conquercost", "contactturns", "demography", "diplbulbcost", "diplchance", "diplgoldcost", "diplomacy", "disasters", "dispersion", "ec_chat", "ec_info", "ec_max_size", "ec_turns", "endspaceship", "endturn", "first_timeout", "fixedlength", "flatpoles", "foggedborders", "fogofwar", "foodbox", "freecost", "fulltradesize", "gameseed", "generator", "globalwarming", "gold", "happyborders", "homecaughtunits", "huts", "kicktime", "killcitizen", "killstack", "killunhomed", "landmass", "mapseed", "mapsize", "maxconnectionsperhost", "maxplayers", "mgr_distance", "mgr_foodneeded", "mgr_nationchance", "mgr_turninterval", "mgr_worldchance", "migration", "minplayers", "nationset", "naturalcitynames", "nettimeout", "netwait", "notradesize", "nuclearwinter", "occupychance", "onsetbarbs", "persistentready", "phasemode", "pingtime", "pingtimeout", "plrcolormode", "rapturedelay", "razechance", "restrictinfra", "revealmap", "revolen", "revolentype", "savefrequency", "savename", "savepalace", "saveturns", "sciencebox", "scorefile", "scorelog", "scoreloglevel", "separatepoles", "shieldbox", "singlepole", "size", "specials", "startcity", "startpos", "startunits", "steepness", "team_pooled_research", "teamplacement", "techlevel", "techlossforgiveness", "techlossrestore", "techlost_donor", "techlost_recv", "techpenalty", "temperature", "tilesperplayer", "timeaddenemymove", "timeout", "tinyisles", "topology", "trademindist", "trading_city", "trading_gold", "trading_tech", "traitdistribution", "turnblock", "unitwaittime", "unreachableprotects", "victories", "wetness", "xsize", "ysize"}

log.error( "%s", "\nNumber of known option names = " .. #option_names .. "\n" )

for i = 1, #option_names, 1 do

	-- if the server.setting.get output is a number then no quotes, else ""
	local option_value = server.setting.get( option_names[ i ] )

	if type( tonumber( option_value ) ) ~= "number" then option_value="\"" .. option_value .. "\"" end
	log.error("%s","\"" .. option_names[ i ] .. "\"" .. "," .. option_value )
end



	notify.event( nil, nil, E.CHAT_MSG, "" )
	notify.event( nil, nil, E.CHAT_MSG, "Dump global vars and functions list" )
	-- globals.lua
	-- show all global variables
	local seen={}
		function dump( t, i )
			seen[ t ] = true
			local s={}
			local n = 0
			for k in pairs( t ) do
				n = n + 1
				s[ n ] = k
			end
			table.sort(s)
			for k, v in ipairs( s ) do
				log.error( "%s", tostring(i) .. tostring(v) )
				v = t[ v ]
				if type( v ) == "table" and not seen[ v ] then
			                dump( v, i .. "\t" )
				end
			end
		end
	dump( _G, "	" )
	notify.event( nil, nil, E.CHAT_MSG, "" )


end
signal.connect( "turn_started", "s_command_examples" )
EDIT: Updated to include routine showing all known server.setting.get() values (such as the [settings] section of a scenario .sav file.) Updated version also includes at the end a "dump globals" feature to list all Lua global vars and functions.

EDIT: Updated the routine to list known options and values.

This is for Lua script development and testing rather than a game feature.
Last edited by Molo_Parko on Thu Dec 05, 2024 4:15 pm, edited 4 times in total.
Molo_Parko
Hardened
Posts: 200
Joined: Fri Jul 02, 2021 4:00 pm

Re: New features via Lua script

Post by Molo_Parko »

Code: Select all

option_names={ "aifill", "airliftingstyle", "allowtake", "alltemperate", "animals", "aqueductloss", "autoattack", "autosaves", "autotoggle", "barbarians", "borders", "citymindist", "citynames", "civilwarsize", "compress", "compresstype", "conquercost", "contactturns", "demography", "diplbulbcost", "diplchance", "diplgoldcost", "diplomacy", "disasters", "dispersion", "ec_chat", "ec_info", "ec_max_size", "ec_turns", "endspaceship", "endturn", "first_timeout", "fixedlength", "flatpoles", "foggedborders", "fogofwar", "foodbox", "freecost", "fulltradesize", "gameseed", "generator", "globalwarming", "gold", "happyborders", "homecaughtunits", "huts", "kicktime", "killcitizen", "killstack", "killunhomed", "landmass", "mapseed", "mapsize", "maxconnectionsperhost", "maxplayers", "mgr_distance", "mgr_foodneeded", "mgr_nationchance", "mgr_turninterval", "mgr_worldchance", "migration", "minplayers", "nationset", "naturalcitynames", "nettimeout", "netwait", "notradesize", "nuclearwinter", "occupychance", "onsetbarbs", "persistentready", "phasemode", "pingtime", "pingtimeout", "plrcolormode", "rapturedelay", "razechance", "restrictinfra", "revealmap", "revolen", "revolentype", "savefrequency", "savename", "savepalace", "saveturns", "sciencebox", "scorefile", "scorelog", "scoreloglevel", "separatepoles", "shieldbox", "singlepole", "size", "specials", "startcity", "startpos", "startunits", "steepness", "team_pooled_research", "teamplacement", "techlevel", "techlossforgiveness", "techlossrestore", "techlost_donor", "techlost_recv", "techpenalty", "temperature", "tilesperplayer", "timeaddenemymove", "timeout", "tinyisles", "topology", "trademindist", "trading_city", "trading_gold", "trading_tech", "traitdistribution", "turnblock", "unitwaittime", "unreachableprotects", "victories", "wetness", "xsize", "ysize"}

log.error( "%s", "\nNumber of known option names = " .. #option_names .. "\n" )

for i = 1, #option_names, 1 do

	-- if the server.setting.get output is a number then no quotes, else ""
	local option_value = server.setting.get( option_names[ i ] )
	if type( tonumber( option_value ) ) ~= "number" then option_value="\"" .. option_value .. "\"" end
	
	log.error("%s","\"" .. option_names[ i ] .. "\"" .. "," .. option_value )
end

Code: Select all

Number of known option names = 124

"aifill",13
"airliftingstyle",""
"allowtake","HAhadOo"
"alltemperate","DISABLED"
"animals",20
"aqueductloss",0
"autoattack","DISABLED"
"autosaves","TURN|GAMEOVER|QUITIDLE|INTERRUPT"
"autotoggle","DISABLED"
"barbarians","NORMAL"
"borders","ENABLED"
"citymindist",2
"citynames","PLAYER_UNIQUE"
"civilwarsize",10
"compress",6
"compresstype","BZIP2"
"conquercost",0
"contactturns",20
"demography","NASRLPEMOqrb"
"diplbulbcost",0
"diplchance",80
"diplgoldcost",0
"diplomacy","ALL"
"disasters",10
"dispersion",0
"ec_chat","ENABLED"
"ec_info","DISABLED"
"ec_max_size",256
"ec_turns",1
"endspaceship","ENABLED"
"endturn",5000
"first_timeout",-1
"fixedlength","DISABLED"
"flatpoles",100
"foggedborders","DISABLED"
"fogofwar","ENABLED"
"foodbox",100
"freecost",0
"fulltradesize",1
"gameseed",0
"generator","SCENARIO"
"globalwarming","ENABLED"
"gold",50
"happyborders","NATIONAL"
"homecaughtunits","ENABLED"
"huts",50
"kicktime",1800
"killcitizen","ENABLED"
"killstack","ENABLED"
"killunhomed",0
"landmass",33
"mapseed",0
"mapsize","FULLSIZE"
"maxconnectionsperhost",4
"maxplayers",11
"mgr_distance",0
"mgr_foodneeded","ENABLED"
"mgr_nationchance",50
"mgr_turninterval",5
"mgr_worldchance",10
"migration","DISABLED"
"minplayers",1
"nationset",""
"naturalcitynames","ENABLED"
"nettimeout",10
"netwait",4
"notradesize",0
"nuclearwinter","ENABLED"
"occupychance",0
"onsetbarbs",60
"persistentready","DISABLED"
"phasemode","ALL"
"pingtime",20
"pingtimeout",60
"plrcolormode","PLR_ORDER"
"rapturedelay",1
"razechance",20
"restrictinfra","DISABLED"
"revealmap",""
"revolen",5
"revolentype","RANDOM"
"savefrequency",15
"savename","freeciv"
"savepalace","ENABLED"
"saveturns",10
"sciencebox",150
"scorefile","freeciv-score.log"
"scorelog","DISABLED"
"scoreloglevel","ALL"
"separatepoles","ENABLED"
"shieldbox",100
"singlepole","DISABLED"
"size",4
"specials",250
"startcity","DISABLED"
"startpos","DEFAULT"
"startunits","ccxx"
"steepness",30
"team_pooled_research","ENABLED"
"teamplacement","CLOSEST"
"techlevel",3
"techlossforgiveness",-1
"techlossrestore",50
"techlost_donor",0
"techlost_recv",0
"techpenalty",100
"temperature",50
"tilesperplayer",100
"timeaddenemymove",0
"timeout",0
"tinyisles","DISABLED"
"topology","WRAPX"
"trademindist",9
"trading_city","ENABLED"
"trading_gold","ENABLED"
"trading_tech","ENABLED"
"traitdistribution","FIXED"
"turnblock","ENABLED"
"unitwaittime",0
"unreachableprotects","ENABLED"
"victories","ALLIED"
"wetness",50
"xsize",144
"ysize",96
^ Output

When the contents of the 'code' section are added to a scenario file's [script]code=$$ section, the above displays the values of all known scenario [settings] (Freeciv 2.6.4 to 2.6.11 at least) whether or not they are listed in the scenario file itself.

EDIT: Updated to show count of known options ( 124 ) and to output as "option name",30 or "option name","text_string" so that it matches the format used in sav files in v2.6.x.

This is for Lua script development and testing rather than a game feature.
Post Reply