better attack modifications
Something I'd been thinking about ever since I started with the req_context struct (#43809) was to replace the other_player argument of requirement evaluation (which is currently only used for DiplRel stuff) with a second complete req_context, the same way action enablers have it – and subsequently adding yet another flag to requirements to choose which side they're evaluated against (or in the case of DiplRel, whether the sides should be flipped). That would make stuff like this possible.
Primary problems / roadblocks for that idea:
All of those would need solving before we could even start to add additional targets of the same type to the other side. Though it would probably be a robust long-term solution.
But there might be some solutions requiring less large-scale restructuring that I'm overlooking.
The possibly most important potential blocker here is the growing load of complexity that affects not only the developers and the hardware but also the ruleset authors and the players. The more flexible are the rules, the less portable is the knowledge of how to make a good Freeciv ruleset and how to play a Feeeciv game... or maybe I exaggerate it.
My own idea was introducing relations, things that work like requirements but are different from them and have two ranges, one for actor and the another for target.
; some action or effect only by an actor unseen by the target ; within 3 tiles radius rels = {"type", "value", "actor_range", "target_range", "present" "MaxDistance", 3, "Tile", "Tile", TRUE "IsSeen", "ActorByTarget", "Local", "Player", FALSE }Closer to what is asked, yes, probably we should not create dozens of action duplicates just to modify their effects for some actor-target combinations while basically all do the same (but it still remains an option, if we make user defined action variants, group them with e.g. flags and have "ActionFlag" requirement for effects). An alternative way would be assigning some flags to action enablers and remembering what flags are checked to the time when we calculate effects for the action (but it requires a good ruleset preprocessor to avoid ambiguity), but it's not that different from creating action duplicates.
The ingenous problem of all the requirements system is that the context includes a city, a player etc. but it's not opaque what city, player or tile is meant in each specific case. For example, you can only learn by heart that bribery resistance depends on target unit home city while for most other effects evaluated for units "City" range means the city in which center they are located; also, some of such "unit-ranged" effects don't have unit itself specified in their context while some do. Maybe, insead of ranges we should have used from the start an object notation like
[effect_fortress_vision] type = "Unit_Vision_Radius_Sq" value = 8 reqs = {"Parameter", "Value" "Unit.Location.Extra", "Fortress" "Unit.Owner.Tech", "Astronomy" }but that brings us to the start of my post, it's way more complicated, and any way it has not been done this way.
Reply To alienvalkyrie
But there might be some solutions requiring less large-scale restructuring that I'm overlooking.
i completely i agree with the sentiment of not needing a large-scale restructuring, we could have this be applicable only for effects for which it makes sense to separate in actor/target or active/passive and have 2 types of effect sections or something similar, adding a new section type which implements what is needed and leaving the current effects as they are.
Reply To dark-ether
we could have this be applicable only for effects for which it makes sense to separate in actor/target or active/passive and have 2 types of effect sections or something similar, adding a new section type which implements what is needed and leaving the current effects as they are.
I feel like that would be more work, for ultimately less gain – we'd still have to create the same functionality, we'd still have to migrate all the effects that make use of it, but now we'd have to maintain two similar-but-separate systems... I think if we do the whole two-requirement-contexts thing at all, it would be more sensible to make it in such a way that any effects we don't change keep working the same – just like how requirement lists that don't contain any negated requirements were always able to omit the present field completely (as well as its predecessor, the negated field) and thus unaffected by the introduction thereof.
Reply To ihnatus
The possibly most important potential blocker here is the growing load of complexity that affects not only the developers and the hardware but also the ruleset authors and the players.
Yeah, that's my problem as well – there are likely plenty of people out there who'd find it less accessible; it'd be yet another factor contributing to the game's "by nerds, for nerds"-ness.
My own idea was introducing relations, things that work like requirements but are different from them and have two ranges, one for actor and the another for target.
That is an interesting idea. It does feel more like a large new thing than an extension of an existing thing, but it might help untangle the five (I think?) different DiplRel requirement types we currently have, so it's probably worth thinking more about in the future.
Closer to what is asked, yes, probably we should not create dozens of action duplicates just to modify their effects for some actor-target combinations while basically all do the same (but it still remains an option, if we make user defined action variants, group them with e.g. flags and have "ActionFlag" requirement for effects).
User-defined action flags are probably something we'll want anyhow once user-defined actions are a thing. Good point tho; we probably want a more general solution before ruleset authors put in all the effort of doing everything indirectly. (Also, it wouldn't even work for things that aren't action-based anyhow.)
The ingenous problem of all the requirements system is that the context includes a city, a player etc. but it's not opaque what city, player or tile is meant in each specific case.
Funny you should mention that; a couple months ago, I'd started prototyping (before getting sidetracked) something I called context component specifications, where e.g. for a given effect type, you could say "we always need a player, and always need a city, and the player must always be the owner of the city" – which would be a definitive source for that kind of information, could be verified at runtime in debug builds, could be used to autocomplete contexts (player is missing? spec says we should use the city owner), and more. And it would work without changing the requirements system itself, unlike...
Maybe, insead of ranges we should have used from the start an object notation
...this, which is clearly a superior idea wrt abstraction and usability. You know, if we were using any programming language other than C, I would've proposed something like that ages ago – tho I hadn't considered merging the requirement type and range into one, just having more advanced ranges (like "Unit.Tile.City.Owner.Capital.Traderoutes.CityArea"). But I haven't been able to come up with safe, non-hassle ways to create the necessary abstractions in C.
About the issue of complexity: My main issue is having each requirement line ending up with a bunch of booleans, so you always have to look closely at the header line to see which is which (or get absolutely screwed if they're ever in an unexpected order) – a possible solution to look into might be replacing them with enums, hopefully leading to something like
reqs = { "type", "name", "range", "present", "quiet" "Gov", "Anarchy", "Player", PRESENT, QUIET "Building", "Pyramids", "Player", NEGATED, VISIBLE "Tech", "Railroad", "Player", NEGATED, VISIBLE "OutputType", "Gold", "Local", NEGATED, QUIET "OutputType", "Luxury", "Local", NEGATED, QUIET "OutputType", "Science", "Local", NEGATED, QUIET }(example taken from civ2civ3's effect_gov_tile_penalty_anarchy), where a human ruleset author could once again understand each requirement even if the headers were missing altogether.
This would keep the "two sides" idea relatively clear, like
reqs = { "type", "name", "side", "range", "present" "UnitFlag", "Cities", ACTIVE, "Local", PRESENT "UnitState", "OnLivableTile", ACTIVE, "Local", PRESENT "MinMoveFrags", "1", ACTIVE, "Local", PRESENT "CityTile", "Claimed", PASSIVE, "Tile", NEGATED "TerrainFlag", "NoCities", PASSIVE, "Tile", NEGATED }(example taken from civ2civ3's actionenabler_build_city_pioneer).
(Sidenote: What's better, one big comment about nothing and everything all at once – like this – or a bunch of small ones about each individual thing?)
(Sidenote: What's better, one big comment about nothing and everything all at once – like this – or a bunch of small ones about each individual thing?)
in my opinion a big comment is fine .
It just occurred to me could we make them a new range? Like range "Other"? Although we would need to break either the defense or the attack bonus effect as both refer to the attacking unit currently. It would hopefully leave most things unchanged, as most effects currently refer to the target of effects.
About the issue of complexity: My main issue is having each requirement line ending up with a bunch of booleans, so you always have to look closely at the header line to see which is which (or get absolutely screwed if they're ever in an unexpected order) – a possible solution to look into might be replacing them with enums, hopefully leading to something like
reqs = { "type", "name", "range", "present", "quiet" "Gov", "Anarchy", "Player", PRESENT, QUIET "Building", "Pyramids", "Player", NEGATED, VISIBLE "Tech", "Railroad", "Player", NEGATED, VISIBLE "OutputType", "Gold", "Local", NEGATED, QUIET "OutputType", "Luxury", "Local", NEGATED, QUIET "OutputType", "Science", "Local", NEGATED, QUIET }(example taken from civ2civ3's effect_gov_tile_penalty_anarchy), where a human ruleset author could once again understand each requirement even if the headers were missing altogether. This would keep the "two sides" idea relatively clear, likereqs = { "type", "name", "side", "range", "present" "UnitFlag", "Cities", ACTIVE, "Local", PRESENT "UnitState", "OnLivableTile", ACTIVE, "Local", PRESENT "MinMoveFrags", "1", ACTIVE, "Local", PRESENT "CityTile", "Claimed", PASSIVE, "Tile", NEGATED "TerrainFlag", "NoCities", PASSIVE, "Tile", NEGATED }
Good point. I vote for this implementation. The repetition of booleans in the current code is an important cause of bugs (and difficulty to notice them) when developing rulesets.
I'm also looking forward to the possibility to check both actor and target in some effects, like Defend_Bonus.
Having value like PRESENT at the very low level of secfile handling would take some effort - especially if we want to provide an API for the higher level to define such types. Maybe more realistic effort would be to handle them as strings in the lowest level -> meaning that the ruleset format would have them in quotes -> "PRESENT"
i want to give attacks bonuses and penalties based on things like wonders, and technologies that both players have, i also want to depend on unit flags of attacker and defender, there is currently no way to modify attacks based on requirements like these however we already are checking for both actors and target requirements for action enablers.
an example of a requirement which can't be expressed right now is the following if the attacker has unit flag paper and tech paper combat, and if the target also has unit flag rock and doesn't know rock defense give a 100 percent bonus to attacker's firepower, as a action enabler requirement this would be
actor_reqs = {"type","name","range"
"UnitFlag","Paper","Local"
"Tech","Paper combat","Player"
}
target_reqs = {"type","name","range","present"
"UnitFlag","Rock","Local",TRUE
"Tech","Rock Defense","Player",FALSE
}
to expose this functionality to the ruleset we either need a new type of section or to modify how effect sections work, modifying how effect sections work seems really hard and wouldn't make sense for most types of effects.
the section type that i propose would be action modifier/effect section, besides making sense for attacks, we could extend these sections to other types of actions and add modifiers for them, this could be an alternative to adding copies of actions and could even be used to give some effects to general actions without lua.