form-on-wing and stay-still updates#6630
Conversation
891e90b to
cda582f
Compare
|
Testing all works as expected with both new behavior and current existing behavior if flags are off, thanks for all the work on this! |
8776d72 to
a60b287
Compare
jg18
left a comment
There was a problem hiding this comment.
A few thoughts from a first pass, but I need to look more closely.
| "\tCauses the specified ship to stay still. The ship will do nothing until attacked at " | ||
| "which time the ship will come to life and defend itself.\r\n\r\n" | ||
| "which time the ship will come to life and defend itself. By default all goals on the ship's goal list will be cleared when this goal runs.\r\n\r\n" | ||
| "Takes 2 arguments...\r\n" |
There was a problem hiding this comment.
Let's update this to "2 to 3 arguments".
| enum ai_goal_mode : uint8_t | ||
| { | ||
| AI_GOAL_NONE = 0, | ||
| AI_GOAL_PLACEHOLDER_1, |
There was a problem hiding this comment.
Wondering why what would normally be a breaking enum change is OK? I take it this enum isn't serialized anywhere?
There was a problem hiding this comment.
It isn't, but as it turned out, I ended up using this placeholder spot for another enum from another PR. I'll rebase this PR and fix the conflicts.
jg18
left a comment
There was a problem hiding this comment.
Still studying, but this is what I have so far.
There was a "must fix" in the previous comments about updating the SEXP help text.
| aigp->target_name = ai_get_goal_target_name( target_name, &aigp->target_name_index ); | ||
|
|
||
| // set up the clear-goals flag for certain goals | ||
| if ((mode == AI_GOAL_STAY_STILL && !The_mission.ai_profile->flags[AI::Profile_Flags::Do_not_clear_goals_when_assigning_stay_still]) |
There was a problem hiding this comment.
Since this code fragment appears again below, I'd highly encourage creating an internal/static helper function for readability/maintainability.
Suggested function signature:
void ai_goal_set_clear_goals_flag_if_needed(ai_goal *aigp, ai_goal_mode mode)You might want to create a helper function for the check for Do_not_set_override_when_assigning_form_on_wing as well, since both places check it, but up to you.
| goals[gindex].flags.set(AI::Goal_Flags::Purge); | ||
|
|
||
| // if this is the active goal, don't consider it for pre-emption!! | ||
| if (gindex == active_goal) |
There was a problem hiding this comment.
I think there's now a bug below when setting/updating oldest_index. We first need to check that goals[gindex].ai_mode != AI_GOAL_NONE.
Creating a helper function might be handy to use both here and above, but up to you:
bool ai_goal_is_goal_slot_empty(const ai_goal *goals, int gIndex)There was a problem hiding this comment.
That's probably rare in practice, and shouldn't matter since if the active goal is NONE, all the other goals would also be NONE and it would just pick the next index. But fair point.
| int ai_goal_find_empty_slot( ai_goal *goals, int active_goal ) | ||
| { | ||
| int gindex, oldest_index; | ||
| int oldest_index = -1, empty_index = -1; |
There was a problem hiding this comment.
The name first_empty_index is clearer IMO.
| case AI_GOAL_WAYPOINTS_ONCE: { | ||
| int flags = 0; | ||
| if (current_goal->ai_mode == AI_GOAL_WAYPOINTS) | ||
| if (current_goal_ai_mode == AI_GOAL_WAYPOINTS) |
There was a problem hiding this comment.
Why are we still dereferencing current_goal below?
There was a problem hiding this comment.
(addressed elsewhere)
|
|
||
| // save the current goal (if any) first, in case it's wiped out by the next action | ||
| int current_goal_ai_mode = current_goal->ai_mode; | ||
| auto current_goal_target_name = current_goal->target_name; |
There was a problem hiding this comment.
This should probably be const auto, or even better, just spell out the type: const char *.
| // save the current goal (if any) first, in case it's wiped out by the next action | ||
| int current_goal_ai_mode = current_goal->ai_mode; | ||
| auto current_goal_target_name = current_goal->target_name; | ||
| auto current_goal_target_ship = current_goal_target_name ? ship_registry_get(current_goal_target_name) : nullptr; |
There was a problem hiding this comment.
This should probably be const auto or (better IMHO) const auto *.
There was a problem hiding this comment.
It's already const by virtue of the return value of ship_registry_get
| } | ||
|
|
||
|
|
||
| // save the current goal (if any) first, in case it's wiped out by the next action |
There was a problem hiding this comment.
After we check for Clear_all_goals_first below, we shouldn't refer to current_goal again, right?
So there's more data from current_goal we need to save at this point, right?
Although I'm a bit confused. Since we were clearing goals before, why do we need to backup data from current_goal? Why wasn't this necessary before?
There was a problem hiding this comment.
On 2nd thought, instead of saving individual fields from *current_goal, here's what I suggest:
- Keep an extra
ai_goalinstance in memory called, say,current_goal_backup. - Right before calling
ai_clear_ship_goals()below, first copy the contents of*current_goaltocurrent_goal_backup, and then setcurrent_goalto be¤t_goal_backup.
That way, current_goal will always be a valid pointer.
Will need to confirm that there aren't unintended consequences from this change.
There was a problem hiding this comment.
This wasn't necessary before because the implementations of the relevant goals handled the clearing themselves. (In the case of form-on-wing it had a bug analogous to use-after-free, but it worked anyhow). Since the clearing is now generalized, saving the data is now necessary.
Your idea of backing up the current goal is a really good one. I'll implement it with a slight tweak.
|
@Goober5000 @wookieejedi I looked into whether multi is OK, and I think it is. When the player sends orders like "Form on my wing" in multi, the result is a call to The server handles the order in |
a60b287 to
58318a7
Compare
There was a problem hiding this comment.
@Goober5000 Found two bugs in ai_remove_goal_sexp_sub() for case OP_AI_FORM_ON_WING:
- The 1st argument to
eval_priority_et_seq()should be the node corresponding to the priority argument and not hardcoded to -1. - The default priority should be
The_mission.ai_profile->default_form_on_wing_priorityand not hardcoded to 99.
|
@Goober5000 @wookieejedi I'm confused on how this PR meshes with existing priority code for form-on-wing in // Goober5000 - same with form-on-wing, since it's a type of staying near
else if ( mode == AI_GOAL_FORM_ON_WING )
aigp->priority = PLAYER_PRIORITY_SUPPORT_LOW;Shouldn't we be setting This would be quite a behavior change WRT priority boost, though, since One idea: set the priority to As an aside, I wonder if the above code snippet explains why it always felt like issuing a "Form on my wing" order had no effect back when I used to play. |
|
Semi-related: strange that the |
There was a problem hiding this comment.
The giveOrder Lua function doesn't support using The_mission.ai_profile->default_form_on_wing_priority with form-on-wing orders. Should it?
jg18
left a comment
There was a problem hiding this comment.
Some requests/suggestions around setting priority for these AI goals via SEXP.
| "By default it will also take priority over all other goals.\r\n\r\n" | ||
| "Takes 1 to 5 arguments...\r\n" | ||
| "\t1:\tShip to form on.\r\n" | ||
| "\t2:\tGoal priority (number between 0 and 89, optional). If not specified this will be 99, or the number defined in ai_profiles.\r\n" |
There was a problem hiding this comment.
If we make priority the 2nd argument for ai-form-on-wing, then there's no way for the FREDder to customize the boolean flags (remaining optional arguments) and simultaneously leverage the default form-on-wing priority.
Therefore, consider making priority the 5th argument instead.
There was a problem hiding this comment.
@wookieejedi said it's more important not to break existing missions, so scratch this idea.
Presumably, if being able to use the default priority while specifying other flags were important, the SEXP would have been designed with the priority as the last arg.
There was a problem hiding this comment.
Yeah, most of the optional sexp flags were added after the priority arguments already existed.
58318a7 to
6697ce1
Compare
69d48f8 to
a9a70e6
Compare
Added a case for this in FRED and qtFRED.
Added save code
Done, plus the equivalent in qtFRED
Hmm, it probably should. |
3240ce3 to
719dc6d
Compare
719dc6d to
a14729d
Compare
Not necessarily, because that is intended for orders given specifically via sexp. In the messaging system, orders always had different priorities:
That itself is a behavior change from retail, as those lines were added in 09d116f. I think the best thing to do is remove those lines to restore the original squad-commanded behavior. Presumably with the fixes to the codebase over the years and in this PR, it will cause form-on-wing to work properly, but we'll test it.
Those lines were intended to fix that exact bug, but if the order had no effect for you, they probably didn't do their job. |
a14729d to
f281827
Compare
jg18
left a comment
There was a problem hiding this comment.
Good improvements. Still studying, but a few questions so far.
| @@ -603,7 +615,7 @@ void ai_goal_purge_all_invalid_goals(ai_goal *aigp) | |||
| ship_obj *sop; | |||
|
|
|||
| // only purge goals if a new goal is one of the types in next statement | |||
There was a problem hiding this comment.
Does this comment still make sense? Did it make sense even before this change?
There was a problem hiding this comment.
Well, yes. For example, issuing an attack order causes any previously issued ignore orders to be removed.
There was a problem hiding this comment.
To clarify, I was referring to the "next statement" part of the comment.
Presumably, the list of relevant goal types was in the if condition at one point, and then the list was moved to a helper function, so the relevant goal types no longer appear here.
Anyway, it's not important, as long as coders know what it means.
There was a problem hiding this comment.
Oh, I see what you mean. I'll tweak the comment.
0f80684 to
f4cb41c
Compare
97e551a to
66d31b7
Compare
…l, and adapt goal assignment accordingly
66d31b7 to
0c736b7
Compare
|
Alrighty, at long last the PR is ready for review :D |
jg18
left a comment
There was a problem hiding this comment.
We've agreed that I'll pre-approve the updated version now and then re-review in depth during 25.0 RC phase. The RC cycle shouldn't be blocked by a re-review of this PR.
Various goal enhancements requested by FotG. The original ai-form-on-wing and ai-stay-still goals automatically cleared all other goals assigned to the same ship or wing, which is not always desired. This adds several flags to goals and ai_profiles to provide more fine-grained control over these behaviors.
Also removes
AI_GOAL_PLACEHOLDER_1since it is not needed; goals higher thanAI_GOAL_NONEdo not need to be a specific value.Supersedes #6520.
In draft pending testing.