Project

Profile

Help

HostedRedmine.com has moved to the Planio platform. All logins and passwords remained the same. All users will be able to login and use Redmine just as before. Read more...

Feature #817749

A signal after a combat survived by both parts

Added by Alexandro Ignatiev about 3 years ago. Updated 8 months ago.

Status:
Closed
Priority:
Normal
Category:
Server
Sprint/Milestone:
Start date:
Due date:
% Done:

0%

Estimated time:

Description

Inspired by [[http://forum.freeciv.org/f/viewtopic.php?f=11&t=91131]]: we have unit_lost(unit, loser, "killed") callback after a combat where some unit(s) died but now we have ways for a defender to survive even if tbe attacker lives:
  • bombardment
  • escaping
  • Combat_Rounds runoff
    I suggest to handle the battle's end with a callback like units_survived_in_battle(attacker, defender, attacked_tile), where defender is:
  • bombardment - nil, called once per attack
  • escaping - the escaped unit, called per each one
  • rounds runoff - the unit that defended the tile.
    Just a draft, maybe the interface can be more logical.

Related issues

Blocks Freeciv - Task #673656: S3_1 datafile format freeze (d3f)Closed

<a title="Actions" class="icon-only icon-actions js-contextmenu" href="#">Actions</a>

History

#1 Updated by Marko Lindqvist 11 months ago

  • Blocks Task #673656: S3_1 datafile format freeze (d3f) added

#2 Updated by Marko Lindqvist 10 months ago

The current interface with just unit_lost() also does not reveal winner unit. That would seem like the next inconsistency with the proposed addition of units_survived_in_battle() that reveals both parties, but only when nobody wins.

I've yet to come up with an API both capable of handling all situations and simple (both from user's and engine's perspective)

#3 Updated by Alexandro Ignatiev 10 months ago

Marko Lindqvist wrote:

The current interface with just unit_lost() also does not reveal winner unit. That would seem like the next inconsistency with the proposed addition of units_survived_in_battle() that reveals both parties, but only when nobody wins.

I've yet to come up with an API both capable of handling all situations and simple (both from user's and engine's perspective)

We can catch who attacks whom in action_started_unit_unit() e.g. via a static variable, but we can't handle the outcome if neither party loses. May we have action_ended_unit_*(action, actor, target, result) callback or something? (like, called after the result is determined by RNG but before it is applied, dubious what result is and how it works on escaping, maybe better catch escaping with unit_moved()...)

#4 Updated by Marko Lindqvist 10 months ago

I have mostly ready patch that adds 'survived_combat' signal. The idea is that for every unit involved in a battle (attacker, defender, and other units in defending stack) either 'unit_lost' or 'survived_combat' gets emitted. 'survived_combat' parameters tell unit's role in combat (attacker/defender/stack), tile where combat occurred (can be different from defender's current tile after Escape), and the reason why the unit survived (winner/nonfatal action/rounds runoff/no stack death/escaped).
There's some corner cases about which reason gets given, e.g., when the defender wins and the stack would not be vulnerable even if it didn't, but maybe that's not a big deal with the actual use-cases?

#5 Updated by Alexandro Ignatiev 10 months ago

Marko Lindqvist wrote:

There's some corner cases about which reason gets given, e.g., when the defender wins and the stack would not be vulnerable even if it didn't, but maybe that's not a big deal with the actual use-cases?

Emitting a signal for units not actually involved in a battle just does not sound a good idea... I'd prefer single call for a single event but since it's you who do write the code I would get whatever works.

#6 Updated by Marko Lindqvist 10 months ago

Alexandro Ignatiev wrote:

Marko Lindqvist wrote:

There's some corner cases about which reason gets given, e.g., when the defender wins and the stack would not be vulnerable even if it didn't, but maybe that's not a big deal with the actual use-cases?

Emitting a signal for units not actually involved in a battle just does not sound a good idea... I'd prefer single call for a single event but since it's you who do write the code I would get whatever works.

Well, when I were toying with this it became clear that sometimes the whole stack is more involved (escaping units, death of whole stack, bombing which has no single main defender at all) than other times. It seems cleaner to me that the signal gets emitted every time than only in special cases; for some units (e.g. escaping ones), sometimes. Might make script-side tracking of events simpler, I'd assume. But I don't have any specific use-case in mind, so if you have better insight, please tell.

#7 Updated by Alexandro Ignatiev 10 months ago

If you want my vision: when an action is ended, it is as an event as when it was started. Handling it in multiple callbacks per each involved object is possible but I doubt it's optimal and logical, especially if we sometimes include ones not actually involved in the action. We'd better have a ticket describing any action/rule-driven procedure and a Lua function that lets each callback get a ticket of the ongoing thing that causes the event; so unit_lost's and unit_moved's of the stack would know what a battle has caused them; currently, the problem with it is that the defender may be wiped (see kill_unit_full()) before some of the collateral losses so you may need to store some information not as a defending unit pointer in the ticket but in some Lua cache associated with it during action_started_*_*. Note that we as well may destroy a participant of the action from within a callback even if we call such callbacks before applying the action's result.

Thus, the action_ended_unit_unit callback may have unit parameters that both may be Unexistent's and also should be able to rely on the ticket-associated cache. About bombardment, we probably need to either make a method (Unit):can_be_object_of_action(Unit actor, Action action) and record the targets at action start, or as you suggest make an event like unit_is_action_target and call for each potentially touched unit. However you iterate over the action participants, at the end you need to specify what to do with all that you have done, that's why I speak about an action_ended callback.

About use-case: for example, we want to give a scripted defense bonus out of our requirement system, like, when a unit attacks hill from plains, we put a fortress on the attacked tile in action_started... and remove it in action_ended.... Or, as in the link in the first post, we want to give some movement to a unit after performing bombardment (or to rescue it to a sxripted position).

#8 Updated by Marko Lindqvist 9 months ago

Attaching the WIP patch, mainly for safekeeping, that I were working on before hardware problems on my primary development machine.

As about the two different approaches suggested (mine and Alexandro's) I may end up implementing both for testing them in practice before choosing one.

#9 Updated by Marko Lindqvist 9 months ago

Alexandro Ignatiev wrote:

About use-case: for example, we want to give a scripted defense bonus out of our requirement system, like, when a unit attacks hill from plains, we put a fortress on the attacked tile in action_started... and remove it in action_ended.... Or, as in the link in the first post, we want to give some movement to a unit after performing bombardment (or to rescue it to a sxripted position).

Ok, for these your suggestion of action_ended_... signals is far superior + it provides functionality beyond the combat case.

#11 Updated by Marko Lindqvist 8 months ago

  • Status changed from Resolved to In Progress

README.actions needs updating.

#12 Updated by Marko Lindqvist 8 months ago

- With documentation updates included

#13 Updated by Marko Lindqvist 8 months ago

  • Status changed from Resolved to Closed
  • Assignee set to Marko Lindqvist

Also available in: Atom PDF