Add AI goals for destroying turrets of a certain type - #7700
Kestrellius wants to merge 12 commits into
Conversation
Goober5000
left a comment
There was a problem hiding this comment.
Partial review for now; still looking through this
|
|
||
| // Goober5000 - before doing anything else, check if this is a disarm goal for an arrived ship... | ||
| if ((status == SHIP_STATUS_ARRIVED) && (aigp->ai_mode == AI_GOAL_DISARM_SHIP || aigp->ai_mode == AI_GOAL_DISARM_SHIP_TACTICAL)) | ||
| if ((status == SHIP_STATUS_ARRIVED) && (aigp->ai_mode == AI_GOAL_DISARM_SHIP || aigp->ai_mode == AI_GOAL_DISARM_SHIP_TACTICAL || aigp->ai_mode == AI_GOAL_DESTROY_TURRET_TYPE_ON_SHIP)) |
There was a problem hiding this comment.
I don't think AI_GOAL_DESTROY_TURRET_TYPE_ON_SHIP should be lumped in with standard disarm here. I think it needs its own separate handling, just like the other places.
There was a problem hiding this comment.
Hmm. What other behavior are you envisioning? I suppose I could check whether any turret aboard the ship has the specified weapon.
There was a problem hiding this comment.
That block checked whether the ship had any turrets. A ship with dozens of turrets but none of the desired type would pass the check.
However, on further investigation, this is actually a dead code path for your case. The no-turrets-with-desired-weapon is already checked and returns SATISFIED. So you can just delete the block that you added on line 2115. In fact, you can delete my block too, since it's also dead code: commit 6e9b31c made the goal check the actual status of the subsystem rather than the mission log.
|
Good catches, thank you! |
Goober5000
left a comment
There was a problem hiding this comment.
Several more review comments. Also, dialog support for initial goals in FRED and QtFRED needs work. You'll need to test adding and modifying both goals in both editors. Alternatively, you could just remove these goals from the initial goals list and designate them as SEXP-only goals
|
|
||
| case OP_AI_DESTROY_TURRET_TYPE: | ||
| aigp->ai_mode = AI_GOAL_DESTROY_TURRET_TYPE; | ||
| aigp->int_data = weapon_info_lookup(ai_get_goal_target_name( CTEXT(CDR(node)), &dummy )); | ||
| break; | ||
|
|
||
| case OP_AI_DESTROY_TURRET_TYPE_ON_SHIP: | ||
| aigp->ai_mode = AI_GOAL_DESTROY_TURRET_TYPE_ON_SHIP; | ||
| aigp->int_data = weapon_info_lookup(ai_get_goal_target_name( CTEXT(CDR(node)), &dummy )); | ||
| aigp->target_name = ai_get_goal_target_name( CTEXT(CDDR(node)), &aigp->target_name_index ); | ||
| break; |
There was a problem hiding this comment.
These cases need to assign the goal's priority
| case AI_GOAL_DESTROY_TURRET_TYPE: | ||
| str = "ai-destroy-turret-type"; | ||
| break; | ||
|
|
There was a problem hiding this comment.
This doesn't fit the pattern of goal/target/priority, so it will need to be specially handled in the above else if series
| case AI_GOAL_DESTROY_TURRET_TYPE_ON_SHIP: | ||
| str = "ai-destroy-turret-type-on-ship"; | ||
| break; | ||
|
|
| if (aigp->ai_mode == AI_GOAL_DESTROY_TURRET_TYPE) { | ||
| for (auto so : list_range(&Ship_obj_list)) { | ||
| auto type_objp = &Objects[so->objnum]; | ||
| if (type_objp->type != OBJ_SHIP || type_objp->flags[Object::Object_Flags::Should_be_dead] || !Weapon_info.in_bounds(aigp->int_data)) |
There was a problem hiding this comment.
The Weapon_info.in_bounds() check should be extracted and placed above the loop, and it should return NOT_ACHIEVABLE for an invalid weapon. See the waypoints check a few lines up for an example.
| Assertion(current_goal->int_data >= 0, "The target of AI_GOAL_DESTROY_TURRET_TYPE_ON_SHIP must refer to a valid weapon class!"); | ||
| other_obj = current_goal_target_ship->objp(); | ||
| ai_attack_object( objp, other_obj); | ||
| ai_set_attack_subsystem( objp, SUBSYSTEM_TURRET, current_goal->int_data ); |
There was a problem hiding this comment.
sorry, this should be -SUBSYSTEM_TURRET (note the minus sign in front)
| } | ||
| } | ||
|
|
||
| ssp = GET_NEXT( ssp ); |
There was a problem hiding this comment.
Copy-paste error, I think.
| return false; | ||
| } | ||
|
|
||
| float ship_get_turret_type_aggregate_hits(ship *shipp, int wi_index) |
There was a problem hiding this comment.
this could be const ship *shipp
| ssp = GET_FIRST(&shipp->subsys_list); | ||
| while ( ssp != END_OF_LIST( &shipp->subsys_list ) ) { | ||
| ship_weapon *swp = &ssp->weapons; | ||
| bool weapon_found = false; | ||
| for ( auto& i : swp->primary_bank_weapons ) { | ||
| if (weapon_found) { | ||
| break; | ||
| } | ||
| if (i == wi_index) { | ||
| weapon_found = true; | ||
| strength += ssp->current_hits; | ||
| } | ||
| } | ||
| for ( auto& i : swp->secondary_bank_weapons ) { | ||
| if (weapon_found) { | ||
| break; | ||
| } | ||
| if (i == wi_index) { | ||
| weapon_found = true; | ||
| strength += ssp->current_hits; | ||
| } | ||
| } | ||
|
|
||
| ssp = GET_NEXT( ssp ); | ||
| } |
There was a problem hiding this comment.
This whole thing can be reduced to something like:
for (auto ssp: list_range(&shipp->subsys_list)) {
if (ssp->system_info->type == SUBSYSTEM_TURRET && turret_has_weapon(ssp, wi_index))
strength += ssp->current_hits;
}| { OP_AI_DESTROY_TURRET_TYPE, "Ai-destroy-turret-type (Ship/wing goal)\r\n" | ||
| "\tThis AI goal causes a ship/wing to destroy all enemy turrets in the mission that " | ||
| "are carrying a specified weapon." | ||
| "Takes 2 arguments...\r\n" |
There was a problem hiding this comment.
Should be 2 or 3 arguments. Also the previous line needs \r\n\r\n
| { OP_AI_DESTROY_TURRET_TYPE_ON_SHIP, "Ai-destroy-turret-type-on-ship (Ship/wing goal)\r\n" | ||
| "\tThis AI goal causes a ship/wing to destroy all turrets on a specified ship that " | ||
| "are carrying a specified weapon." | ||
| "Takes 2 arguments...\r\n" |
There was a problem hiding this comment.
Should be 3 or 4 arguments. Also the previous line needs \r\n\r\n
Yeah, they'll have to be left out for now. In the long term they ought to have initial-goal support, but I am not up to trying to figure out UI stuff right at the moment. |
Introduces two new AI goals,
AI_GOAL_DESTROY_TURRET_TYPEandAI_GOAL_DESTROY_TURRET_TYPE_ON_SHIP, which cause the AI to target turrets carrying a specific class of weapon, either on a targeted ship or on any enemy ship in the mission. From a player-experience perspective, this should help to resolve a certain type of irritating situation that occurs when destroying multiple heavy weapons on an enemy warship is necessary, but wingmen can't effectively help without impractical amounts of micromanagement.At present, these orders are accessible only through SEXPs and scripting, but future plans involve integrating them into the player commands system.