More (probably) silly questions

Contribute, display and discuss rulesets and modpacks for use in Freeciv here.
John Campbell
Posts: 20
Joined: Wed Jan 18, 2023 6:57 pm

Re: More (probably) silly questions

Post by John Campbell »

I think all the actual AI behaviour is hard-coded, and moreover I don't think anyone actually understands it. My understanding is that the current AI code was practically all written by one guy years ago, and he's no longer involved in freeciv development, and no one else really knows how it works.

The effects files just let you apply limitations or bonuses to AI players, based on their difficulty level. This can indirectly affect their behaviour, but doesn't directly control it.

For example civ2civ3, when it first became the default ruleset, completely broke the Hard AI. Easy worked as well as it ever did, but Hard AIs would just stall out fairly early in the game and never advance. Like, the last civ2civ3 game I played with Hard AI, at the point where I hit the Singularity (as a Monarchy!), my closest competitors were two AIs who had been "working" on Chemistry for decades, and that was only because I'd given one of them Medicine as humanitarian gesture, and the other had stolen it from them. Other than that, there were two AIs working on Feudalism. The rest of them hadn't made it out of the Bronze Age. Some of them hadn't made it into the Bronze Age. Most of them were still missing first-tier techs.

I did some poking around and determined that this was because there was an effect that removed the government tax rate caps for Hard AIs. And civ2civ3 changed unit support so some of the early governments were supporting units with Gold. And this meant that AIs would get into fights with their neighbors, start cranking out units, then crank up their tax rates to support all the units they were building, until their tax rate was at 100% Gold, which was all immediately being spent on unit support, their scientific advancement ground to a complete stop, and ultimately they were still having wars by just throwing hordes of Warriors and Archers at each other while I was building my starship.

Later releases restored the tax rate caps, and the Hard AI started functioning normally again, not because what it actually wanted to do or was trying to do had changed, but just because it was no longer allowed to paperclip-maximize so hard that it stalled its own progress.
Elefant
Hardened
Posts: 252
Joined: Sat May 28, 2022 3:55 am

Re: More (probably) silly questions

Post by Elefant »

When i looked into it, the incomprehensible ai was removed sometime in the 2.x series in favor of a less competent but more flexible ai. So as I understand, the current ai is fairly well understood.
Civ 3 tileset: viewtopic.php?t=92953
3d Irrlicht desktop client development: viewtopic.php?t=92289&start=20
FriendAtArms
Posts: 34
Joined: Thu Apr 16, 2026 9:35 pm

Re: More (probably) silly questions

Post by FriendAtArms »

Well, since I'm still working with the 2.x series, I'll have to put my AI-customizing dreams to one side for a while. Disappointing, but it does simplify matters for me.

It does seem like I'll be able to use the Gain_AI_Love effect to change the default diplomatic state, for Easy and Handicapped difficulty. If I run into any problems, I'll post them here.
FriendAtArms
Posts: 34
Joined: Thu Apr 16, 2026 9:35 pm

Re: More (probably) silly questions

Post by FriendAtArms »

In the meantime, I'm running into more sanity checks.
in cityresult_fill() [../../../../../ai/default/aisettler.c::450]: assertion 'result->remaining >= 0' failed.
I'm not sure what this means, but given the reference to "ai/default/aisettler", I can think of two possibilities. One: my city-founder unit is separate from my worker unit, which has both the "Settlers" flag and the "Settlers" role. I've seen the AI creating cities just fine, but I've never seen it produce workers or any of the stuff workers build. (Roads, mines, etc.) Perhaps for some reason, AIs simply can't recognize customized worker/settler units?

Possibility Two: I'm also using a customized Default.LUA to create units from huts, as shown below. As you can see, it's more-or-less copied from the default Default file. It doesn't refer to "settlers" at all, and it works fine when I explore a hut...but maybe something goes wrong when the AI explores a hut?
-- Default event if intended village behavior is impossible.
function _deflua_hut_ghost_town(unit)
notify.event(owner, unit.tile, E.HUT_BARB_CITY_NEAR,
_("This village has been abandoned for a long time."))
end

-- Village becomes a player unit
function _deflua_hut_get_mercenaries(unit)
local owner = unit.owner
local utype = find.role_unit_type('HutTech', owner)

if not utype or not utype:can_exist_at_tile(unit.tile) then
utype = find.role_unit_type('Hut', nil)
if not utype or not utype:can_exist_at_tile(unit.tile) then
utype = nil
end
end

if utype then
notify.event(owner, unit.tile, E.HUT_MERC,
_("A band of hunter-gatherers agrees to join your people."))
owner:create_unit(unit.tile, utype, 0, unit:get_homecity(), -1)
return true
else
return false
end
end

-- Village becomes a barbarian unit,
-- unless close to a city, or king enters, or barbarians are disabled
-- Unit may die: returns true if unit is alive
function _deflua_hut_get_barbarians(unit)
local tile = unit.tile
local utype = unit.utype
local owner = unit.owner

if server.setting.get("barbarians") == "DISABLED"
or unit.tile:city_exists_within_max_city_map(true)
or utype:has_flag('Gameloss') then
notify.event(owner, unit.tile, E.HUT_BARB_CITY_NEAR,
_("This village has been abandoned for a long time."))
return true
end

local alive = tile:unleash_barbarians()
if alive then
notify.event(owner, tile, E.HUT_BARB,
_("A band of hunter-gatherers declares war on you!"));
else
notify.event(owner, tile, E.HUT_BARB_KILLED,
_("Your %s has been killed by barbarians!"),
utype:name_translation());
end
return alive
end

-- Randomly choose a hut event
function _deflua_hut_enter_callback(unit)
local chance = random(0, 2)
local alive = true

if chance == 0 then
_deflua_hut_ghost_town(unit)
elseif chance == 1 then
if not _deflua_hut_get_mercenaries(unit) then
_deflua_hut_ghost_town(unit)
end
elseif chance == 2 then
alive = _deflua_hut_get_barbarians(unit)
end

-- continue processing if unit is alive
return (not alive)
end

signal.connect("hut_enter", "_deflua_hut_enter_callback")
Post Reply