Author Topic: Turret AI settings  (Read 7244 times)

0 Members and 1 Guest are viewing this topic.

Offline Sushi

  • Art Critic
  • 211
Code review time! :)

Looks like you missed a case around line 2145:

 
Code: [Select]
// make sure salvo fire mode does not turn into autofire
if ((tp->flags & MSS_FLAG_TURRET_SALVO) && ((i + 1) == number_of_firings)) {
ai_info *parent_aip = &Ai_info[Ships[Objects[parent_objnum].instance].ai_index];
turret_set_next_fire_timestamp(valid_weapons[0], wip, ss, parent_aip);
}

also around 338
Code: [Select]
if ( (!(wip->wi_flags & WIF_BOMB) && !(Ai_info[Ships[turret_parent->instance].ai_index].ai_profile_flags & AIPF_ALLOW_TURRETS_TARGET_WEAPONS_FREELY) ) ) {
    return 0;
}

and 472:
Code: [Select]
if ((Ai_info[Ships[turret_parent_obj->instance].ai_index].ai_profile_flags & AIPF_PREVENT_TARGETING_BOMBS_BEYOND_RANGE) && (dist > eeo->weapon_travel_dist)) {
check_weapon = false;
}

You also missed a case in the for loop starting around 793:
Code: [Select]
for(int i = 0; i < NUM_TURRET_ORDER_TYPES; i++)
{
    ai_info *aip = &Ai_info[Ships[Objects[eeo.turret_parent_objnum].instance].ai_index];
    switch(turret_subsys->turret_targeting_order[i])
...
    //Return if a bomb is found
    //don't fire anti capital ship turrets at bombs.
    if ( !((aip->ai_profile_flags & AIPF_HUGE_TURRET_WEAPONS_IGNORE_BOMBS) && big_only_flag) )


Line 1270:
Code: [Select]
if (Ai_info[shipp->ai_index].ai_profile_flags & AIPF_SMART_SUBSYSTEM_TARGETING_FOR_TURRETS) {

I think that's all of them, although you may also want to look for and consider cases like:
Code: [Select]
if (Ai_info[Ships[objp->instance].ai_index].ai_profile_flags & AIPF_SMART_SUBSYSTEM_TARGETING_FOR_TURRETS) {
where a turret-specific behavior is applied at the ship level, but it might make sense to be able to apply it at the per-turret level too.

  

Offline The E

  • He's Ebeneezer Goode
  • Moderator
  • 213
  • Nothing personal, just tech support.
    • Steam
    • Twitter
Thanks for the feedback, Sushi.

One question, however: How do I get the current turret subsystem if all I have is a pointer to the turret parent?

NM, figured it out.

EDIT: New patch:
Code: [Select]
Index: ai/ai_profiles.cpp
===================================================================
--- ai/ai_profiles.cpp (revision 6316)
+++ ai/ai_profiles.cpp (working copy)
@@ -395,6 +395,8 @@
 
  set_flag(profile, "$big ships manage shields:", AIPF2_BIG_SHIELD_MANAGE, AIP_FLAG2);
 
+ set_flag(profile, "$turrets use separate ai class:", AIPF2_TURRETS_USE_SEPARATE_AI, AIP_FLAG2);
+
  // if we've been through once already and are at the same place, force a move
  if ( saved_Mp && (saved_Mp == Mp) )
  Mp++;
Index: ai/ai_profiles.h
===================================================================
--- ai/ai_profiles.h (revision 6316)
+++ ai/ai_profiles.h (working copy)
@@ -55,6 +55,7 @@
 #define AIPF2_NO_SPECIAL_PLAYER_AVOID (1 << 1)
 #define AIPF2_PERFORM_LESS_SCREAM_CHECKS (1 << 2)
 #define AIPF2_BIG_SHIELD_MANAGE (1 << 3)
+#define AIPF2_TURRETS_USE_SEPARATE_AI (1 << 4)
 
 #define MAX_AI_PROFILES 5
 
Index: ai/aiturret.cpp
===================================================================
--- ai/aiturret.cpp (revision 6316)
+++ ai/aiturret.cpp (working copy)
@@ -286,11 +286,23 @@
  return longest_range_so_far;
 }
 
+//Sets up an ai profile for a given turret, using the turret parent, turret subsystem and current AI profile from the mission
+ai_info* init_turret_aip(ship* parent, ship_subsys* turret)
+{
+ ai_info* turret_aip = &Ai_info[parent->ai_index];
+
+ if (The_mission.ai_profile->flags2 & AIPF2_TURRETS_USE_SEPARATE_AI)
+ init_aip_from_class_and_profile(turret_aip, &Ai_classes[turret->weapons.ai_class], The_mission.ai_profile);
+
+ Assertion((turret_aip != NULL), "No AI class set for turret %s", turret->system_info->subobj_name);
+ return turret_aip;
+}
+
 // return !0 if objp can be considered for a turret target, 0 otherwise
 // input: objp => object that turret is considering as an enemy
 // turret_parent => object of ship that turret sits on
 // turret => turret pointer
-int valid_turret_enemy(object *objp, object *turret_parent)
+int valid_turret_enemy(object *objp, object *turret_parent, ship_subsys* turret)
 {
  if ( objp == turret_parent ) {
  return 0;
@@ -335,7 +347,9 @@
  weapon *wp = &Weapons[objp->instance];
  weapon_info *wip = &Weapon_info[wp->weapon_info_index];
 
- if ( (!(wip->wi_flags & WIF_BOMB) && !(Ai_info[Ships[turret_parent->instance].ai_index].ai_profile_flags & AIPF_ALLOW_TURRETS_TARGET_WEAPONS_FREELY) ) ) {
+ ai_info* turret_aip = init_turret_aip(&Ships[turret_parent->instance], turret);
+
+ if ( (!(wip->wi_flags & WIF_BOMB) && !(turret_aip->ai_profile_flags & AIPF_ALLOW_TURRETS_TARGET_WEAPONS_FREELY) ) ) {
  return 0;
  }
 
@@ -366,7 +380,7 @@
  return;
  }
 
- if ( !valid_turret_enemy(objp, turret_parent_obj) ) {
+ if ( !valid_turret_enemy(objp, turret_parent_obj, eeo->turret_subsys) ) {
  return;
  }
 
@@ -469,7 +483,9 @@
  // check if bomb is homing on the turret parent ship
  bool check_weapon = true;
 
- if ((Ai_info[Ships[turret_parent_obj->instance].ai_index].ai_profile_flags & AIPF_PREVENT_TARGETING_BOMBS_BEYOND_RANGE) && (dist > eeo->weapon_travel_dist)) {
+ ai_info* turret_aip = init_turret_aip(&Ships[turret_parent_obj->instance], ss);
+
+ if ((turret_aip->ai_profile_flags & AIPF_PREVENT_TARGETING_BOMBS_BEYOND_RANGE) && (dist > eeo->weapon_travel_dist)) {
  check_weapon = false;
  }
 
@@ -792,7 +808,8 @@
 
  for(int i = 0; i < NUM_TURRET_ORDER_TYPES; i++)
  {
- ai_info *aip = &Ai_info[Ships[Objects[eeo.turret_parent_objnum].instance].ai_index];
+ ai_info *aip = init_turret_aip(&Ships[Objects[eeo.turret_parent_objnum].instance], eeo.turret_subsys);
+
  switch(turret_subsys->turret_targeting_order[i])
  {
  case -1:
@@ -1147,7 +1164,9 @@
  vm_vec_unrotate(&turret_norm, &turret_subsysp->system_info->turret_norm, &objp->orient);
  float dot_return = vm_vec_dot(&turret_norm, &vector_out);
 
- if (Ai_info[Ships[objp->instance].ai_index].ai_profile_flags & AIPF_SMART_SUBSYSTEM_TARGETING_FOR_TURRETS) {
+ ai_info* turret_aip = init_turret_aip(&Ships[objp->instance], turret_subsysp);
+
+ if (turret_aip->ai_profile_flags & AIPF_SMART_SUBSYSTEM_TARGETING_FOR_TURRETS) {
  if (dot_return > turret_subsysp->system_info->turret_fov) {
  // target is in sight and in fov
  return dot_return;
@@ -1267,7 +1286,9 @@
  int idx;
  float dot_fov_modifier = 0.0f;
 
- if (Ai_info[shipp->ai_index].ai_profile_flags & AIPF_SMART_SUBSYSTEM_TARGETING_FOR_TURRETS) {
+ ai_info* turret_aip = init_turret_aip(shipp, ssp);
+
+ if (turret_aip->ai_profile_flags & AIPF_SMART_SUBSYSTEM_TARGETING_FOR_TURRETS) {
  if (ssp->system_info->turret_fov < 0)
  dot_fov_modifier = ssp->system_info->turret_fov;
  }
@@ -1413,7 +1434,7 @@
 {
  matrix turret_orient;
  int weapon_objnum;
- ai_info *parent_aip;
+ ai_info *turret_aip = init_turret_aip(&Ships[Objects[parent_objnum].instance], turret);
  ship *parent_ship;
  float flak_range = 0.0f;
  weapon_info *wip;
@@ -1437,7 +1458,6 @@
  if((!timestamp_elapsed(get_turret_weapon_next_fire_stamp(&turret->weapons, weapon_num))) && last_shot_in_salvo)
  return false;
 
- parent_aip = &Ai_info[Ships[Objects[parent_objnum].instance].ai_index];
  parent_ship = &Ships[Objects[parent_objnum].instance];
  wip = get_turret_weapon_wip(&turret->weapons, weapon_num);
  int turret_weapon_class = WEAPON_INFO_INDEX(wip);
@@ -1448,7 +1468,7 @@
 
  // set next fire timestamp for the turret
  if (last_shot_in_salvo)
- turret_set_next_fire_timestamp(weapon_num, wip, turret, parent_aip);
+ turret_set_next_fire_timestamp(weapon_num, wip, turret, turret_aip);
 
  // if this weapon is a beam weapon, handle it specially
  if (wip->wi_flags & WIF_BEAM) {
@@ -1551,7 +1571,7 @@
  }
  }
  //Not useful -WMC
- else if (!(parent_aip->ai_profile_flags & AIPF_DONT_INSERT_RANDOM_TURRET_FIRE_DELAY) && last_shot_in_salvo)
+ else if (!(turret_aip->ai_profile_flags & AIPF_DONT_INSERT_RANDOM_TURRET_FIRE_DELAY) && last_shot_in_salvo)
  {
  float wait = 1000.0f * frand_range(0.9f, 1.1f);
  turret->turret_next_fire_stamp = timestamp((int) wait);
@@ -2144,8 +2164,9 @@
  } else {
  // make sure salvo fire mode does not turn into autofire
  if ((tp->flags & MSS_FLAG_TURRET_SALVO) && ((i + 1) == number_of_firings)) {
- ai_info *parent_aip = &Ai_info[Ships[Objects[parent_objnum].instance].ai_index];
- turret_set_next_fire_timestamp(valid_weapons[0], wip, ss, parent_aip);
+ ai_info *turret_aip = init_turret_aip(&Ships[Objects[parent_objnum].instance], ss);
+
+ turret_set_next_fire_timestamp(valid_weapons[0], wip, ss, turret_aip);
  }
  }
  // moved this here so we increment the fire pos only after we have fired and not during it

There are still a few instances left where flags that deal with turret behaviour are only checked using the missions' AI profile. I thought it was best to leave those as they are.
« Last Edit: July 20, 2010, 11:27:00 am by The E »
If I'm just aching this can't go on
I came from chasing dreams to feel alone
There must be changes, miss to feel strong
I really need lifе to touch me
--Evergrey, Where August Mourns

 

Offline General Battuta

  • Poe's Law In Action
  • 214
  • i wonder when my postcount will exceed my iq
Oh boy....

If this flag gets in and is enabled, every turret in every mission would have to be checked what AI class it has not to alter mission balance. I hope you're prepared for that. From the looks of it, you'd have to set AI class for each and every turret manually as opposed to just the ship pilot. Would be a lot of work.

It would only be a problem if you enabled an AI profile that used turret AI in a given mission.

So while it would destroy (for example) War in Heaven if enabled in all missions, we could create a special AI profile with this flag and only enable it in some.

 

Offline Sushi

  • Art Critic
  • 211

There are still a few instances left where flags that deal with turret behaviour are only checked using the missions' AI profile. I thought it was best to leave those as they are.

Yeah, I noticed those too. When I was first adding the ability to do stuff in AI classes as well as AI profiles, I tried to distinguish between things that were AI behaviors and things that were essentially gameplay/engine tweaks. Since then, a few new flags have been added by others, and I don't know which (if any) were added with AI.tbl in mind.

I don't have time to check the whole patch right now, but I do see one major problem up front: it looks like init_turret_aip actually overrides the parent aip struct with what the turret had...watch your pointers. The fact that init_turret_aip is also being called constantly (several times per frame?) is also less than ideal.

What needs to happen is that each turret object has its own aip struct, initialized once when the ship is being loaded. I don't know if turret objects already have their own aip which just remains unused, but if we want AI class to matter for turrets, each turret will definitely need its own, and you should only have to init them once.

 

Offline chief1983

  • Still lacks a custom title
  • Moderator
  • 212
  • ⬇️⬆️⬅️⬅️🅰➡️⬇️
    • Skype
    • Steam
    • Twitter
    • Fate of the Galaxy
It sounds like this feature isn't as simple as originally planned, so take your time The E.
Fate of the Galaxy - Now Hiring!  Apply within | Diaspora | SCP Home | Collada Importer for PCS2
Karajorma's 'How to report bugs' | Mantis
#freespace | #scp-swc | #diaspora | #SCP | #hard-light on EsperNet

"You may not sell or otherwise commercially exploit the source or things you created based on the source." -- Excerpt from FSO license, for reference

Nuclear1:  Jesus Christ zack you're a little too hamyurger for HLP right now...
iamzack:  i dont have hamynerge i just want ptatoc hips D:
redsniper:  Platonic hips?!
iamzack:  lays

 

Offline The E

  • He's Ebeneezer Goode
  • Moderator
  • 213
  • Nothing personal, just tech support.
    • Steam
    • Twitter
I don't have time to check the whole patch right now, but I do see one major problem up front: it looks like init_turret_aip actually overrides the parent aip struct with what the turret had...watch your pointers. The fact that init_turret_aip is also being called constantly (several times per frame?) is also less than ideal.

Problem is, it needs to be called several times per frame, as the turret ai class may change during gameplay if a FREDer calls change-ai-class on it.
« Last Edit: July 20, 2010, 02:47:41 pm by The E »
If I'm just aching this can't go on
I came from chasing dreams to feel alone
There must be changes, miss to feel strong
I really need lifе to touch me
--Evergrey, Where August Mourns

 

Offline Sushi

  • Art Critic
  • 211
I don't have time to check the whole patch right now, but I do see one major problem up front: it looks like init_turret_aip actually overrides the parent aip struct with what the turret had...watch your pointers. The fact that init_turret_aip is also being called constantly (several times per frame?) is also less than ideal.

Problem is, it needs to be called several times per frame, as the turret ai class may change during gameplay if a FREDer calls change-ai-class on it.

In that case, change-ai-class should trigger a "rebuild" of aip, but only once. That's what it does now, it would just need to apply to the turrets too.

Does the change-ai-class SEXP even work on subsystems? If not, it wouldn't make a difference. :)


 

Offline The E

  • He's Ebeneezer Goode
  • Moderator
  • 213
  • Nothing personal, just tech support.
    • Steam
    • Twitter
Yes, it does. It's set up to set subsystem AI classes already. And yes, the init thing should be done only once, if you can give me a pointer as to how this is done for ships, I'd be grateful. This would also make adding the subsystem tbl option infinitely easier.
If I'm just aching this can't go on
I came from chasing dreams to feel alone
There must be changes, miss to feel strong
I really need lifе to touch me
--Evergrey, Where August Mourns

 

Offline Sushi

  • Art Critic
  • 211
if you can give me a pointer as to how this is done for ships, I'd be grateful.

Don't remember it all off the op of my head, but if you look at calls to "init_aip_from_class_and_profile" you should be able to find all of the cases.

 

Offline The E

  • He's Ebeneezer Goode
  • Moderator
  • 213
  • Nothing personal, just tech support.
    • Steam
    • Twitter
Hmm.

Doing it properly seems to necessitate bumping the number of AI slots. Right now, the number of AI slots is set to the same number as the number of ships in-mission (that is, 400).
If I'm just aching this can't go on
I came from chasing dreams to feel alone
There must be changes, miss to feel strong
I really need lifе to touch me
--Evergrey, Where August Mourns

 

Offline Sushi

  • Art Critic
  • 211
Hmm.

Doing it properly seems to necessitate bumping the number of AI slots. Right now, the number of AI slots is set to the same number as the number of ships in-mission (that is, 400).

Yeah, I was afraid of that. This means we're going to invoke quite a bit of additional data storage to get this working. :/

 

Offline The E

  • He's Ebeneezer Goode
  • Moderator
  • 213
  • Nothing personal, just tech support.
    • Steam
    • Twitter
Or, I follow a sensible suggestion by FUBAR and just add an ai_info field to the ship_weapons struct.
If I'm just aching this can't go on
I came from chasing dreams to feel alone
There must be changes, miss to feel strong
I really need lifе to touch me
--Evergrey, Where August Mourns

 

Offline FUBAR-BDHR

  • Self-Propelled Trouble Magnet
  • 212
  • Master Drunk
    • 165th Beer Drinking Hell Raisers
Yea there's a nice new head shaped dent in his desk.
No-one ever listens to Zathras. Quite mad, they say. It is good that Zathras does not mind. He's even grown to like it. Oh yes. -Zathras

 

Offline The E

  • He's Ebeneezer Goode
  • Moderator
  • 213
  • Nothing personal, just tech support.
    • Steam
    • Twitter
Okay, here's a completely new approach. This time, I added an optional field ("$Turret AI class:") to the subsystem entry, placed after "$Armor Type:", which works in the same way as the ship default AI entry.

Note that, as of right now, I can only confirm that it builds, not that it actually works (but I will, once I had a few hours' sleep).

EDIT:

Yeah, that so didn't work. Anyway, here's a new patch, and this time it's even tested!

Code: [Select]
Index: ai/ai_profiles.cpp
===================================================================
--- ai/ai_profiles.cpp (revision 6320)
+++ ai/ai_profiles.cpp (working copy)
@@ -395,6 +395,8 @@
 
  set_flag(profile, "$big ships manage shields:", AIPF2_BIG_SHIELD_MANAGE, AIP_FLAG2);
 
+ set_flag(profile, "$turrets use separate ai class:", AIPF2_TURRETS_USE_SEPARATE_AI, AIP_FLAG2);
+
  // if we've been through once already and are at the same place, force a move
  if ( saved_Mp && (saved_Mp == Mp) )
  Mp++;
Index: ai/ai_profiles.h
===================================================================
--- ai/ai_profiles.h (revision 6320)
+++ ai/ai_profiles.h (working copy)
@@ -55,6 +55,7 @@
 #define AIPF2_NO_SPECIAL_PLAYER_AVOID (1 << 1)
 #define AIPF2_PERFORM_LESS_SCREAM_CHECKS (1 << 2)
 #define AIPF2_BIG_SHIELD_MANAGE (1 << 3)
+#define AIPF2_TURRETS_USE_SEPARATE_AI (1 << 4)
 
 #define MAX_AI_PROFILES 5
 
Index: ai/aiturret.cpp
===================================================================
--- ai/aiturret.cpp (revision 6320)
+++ ai/aiturret.cpp (working copy)
@@ -286,11 +286,21 @@
  return longest_range_so_far;
 }
 
+//Returns a pointer to the AI profile of a given turret, or a pointer to the ships' AI profile
+//if no separate AI class is defined or the TURRETS_USE_SEPARATE_AI flag isn't set
+ai_info* get_current_turret_aip(ship_subsys* turret){
+ if ((The_mission.ai_profile->flags2 & AIPF2_TURRETS_USE_SEPARATE_AI) && turret->weapons.ai_index == -1){
+ return &turret->weapons.turret_aip;
+ } else {
+ return &Ai_info[turret->weapons.ai_index];
+ }
+}
+
 // return !0 if objp can be considered for a turret target, 0 otherwise
 // input: objp => object that turret is considering as an enemy
 // turret_parent => object of ship that turret sits on
 // turret => turret pointer
-int valid_turret_enemy(object *objp, object *turret_parent)
+int valid_turret_enemy(object *objp, object *turret_parent, ship_subsys* turret)
 {
  if ( objp == turret_parent ) {
  return 0;
@@ -335,7 +345,7 @@
  weapon *wp = &Weapons[objp->instance];
  weapon_info *wip = &Weapon_info[wp->weapon_info_index];
 
- if ( (!(wip->wi_flags & WIF_BOMB) && !(Ai_info[Ships[turret_parent->instance].ai_index].ai_profile_flags & AIPF_ALLOW_TURRETS_TARGET_WEAPONS_FREELY) ) ) {
+ if ( (!(wip->wi_flags & WIF_BOMB) && !(get_current_turret_aip(turret)->ai_profile_flags & AIPF_ALLOW_TURRETS_TARGET_WEAPONS_FREELY) ) ) {
  return 0;
  }
 
@@ -366,7 +376,7 @@
  return;
  }
 
- if ( !valid_turret_enemy(objp, turret_parent_obj) ) {
+ if ( !valid_turret_enemy(objp, turret_parent_obj, eeo->turret_subsys) ) {
  return;
  }
 
@@ -469,7 +479,7 @@
  // check if bomb is homing on the turret parent ship
  bool check_weapon = true;
 
- if ((Ai_info[Ships[turret_parent_obj->instance].ai_index].ai_profile_flags & AIPF_PREVENT_TARGETING_BOMBS_BEYOND_RANGE) && (dist > eeo->weapon_travel_dist)) {
+ if ((get_current_turret_aip(eeo->turret_subsys)->ai_profile_flags & AIPF_PREVENT_TARGETING_BOMBS_BEYOND_RANGE) && (dist > eeo->weapon_travel_dist)) {
  check_weapon = false;
  }
 
@@ -792,7 +802,7 @@
 
  for(int i = 0; i < NUM_TURRET_ORDER_TYPES; i++)
  {
- ai_info *aip = &Ai_info[Ships[Objects[eeo.turret_parent_objnum].instance].ai_index];
+ ai_info *aip = get_current_turret_aip(eeo.turret_subsys);
  switch(turret_subsys->turret_targeting_order[i])
  {
  case -1:
@@ -1147,7 +1157,7 @@
  vm_vec_unrotate(&turret_norm, &turret_subsysp->system_info->turret_norm, &objp->orient);
  float dot_return = vm_vec_dot(&turret_norm, &vector_out);
 
- if (Ai_info[Ships[objp->instance].ai_index].ai_profile_flags & AIPF_SMART_SUBSYSTEM_TARGETING_FOR_TURRETS) {
+ if (get_current_turret_aip(turret_subsysp)->ai_profile_flags & AIPF_SMART_SUBSYSTEM_TARGETING_FOR_TURRETS) {
  if (dot_return > turret_subsysp->system_info->turret_fov) {
  // target is in sight and in fov
  return dot_return;
@@ -1267,7 +1277,7 @@
  int idx;
  float dot_fov_modifier = 0.0f;
 
- if (Ai_info[shipp->ai_index].ai_profile_flags & AIPF_SMART_SUBSYSTEM_TARGETING_FOR_TURRETS) {
+ if (get_current_turret_aip(ssp)->ai_profile_flags & AIPF_SMART_SUBSYSTEM_TARGETING_FOR_TURRETS) {
  if (ssp->system_info->turret_fov < 0)
  dot_fov_modifier = ssp->system_info->turret_fov;
  }
@@ -1437,7 +1447,7 @@
  if((!timestamp_elapsed(get_turret_weapon_next_fire_stamp(&turret->weapons, weapon_num))) && last_shot_in_salvo)
  return false;
 
- parent_aip = &Ai_info[Ships[Objects[parent_objnum].instance].ai_index];
+ parent_aip = get_current_turret_aip(turret);
  parent_ship = &Ships[Objects[parent_objnum].instance];
  wip = get_turret_weapon_wip(&turret->weapons, weapon_num);
  int turret_weapon_class = WEAPON_INFO_INDEX(wip);
@@ -1551,7 +1561,7 @@
  }
  }
  //Not useful -WMC
- else if (!(parent_aip->ai_profile_flags & AIPF_DONT_INSERT_RANDOM_TURRET_FIRE_DELAY) && last_shot_in_salvo)
+ else if (!(turret->weapons.turret_aip.ai_profile_flags & AIPF_DONT_INSERT_RANDOM_TURRET_FIRE_DELAY) && last_shot_in_salvo)
  {
  float wait = 1000.0f * frand_range(0.9f, 1.1f);
  turret->turret_next_fire_stamp = timestamp((int) wait);
@@ -2144,8 +2154,8 @@
  } else {
  // make sure salvo fire mode does not turn into autofire
  if ((tp->flags & MSS_FLAG_TURRET_SALVO) && ((i + 1) == number_of_firings)) {
- ai_info *parent_aip = &Ai_info[Ships[Objects[parent_objnum].instance].ai_index];
- turret_set_next_fire_timestamp(valid_weapons[0], wip, ss, parent_aip);
+ //ai_info *parent_aip = &Ai_info[Ships[Objects[parent_objnum].instance].ai_index];
+ turret_set_next_fire_timestamp(valid_weapons[0], wip, ss, get_current_turret_aip(ss));
  }
  }
  // moved this here so we increment the fire pos only after we have fired and not during it
Index: model/model.h
===================================================================
--- model/model.h (revision 6320)
+++ model/model.h (working copy)
@@ -144,6 +144,9 @@
  float max_subsys_strength; // maximum hits of this subsystem
  int armor_type_idx; //Armor type on teh subsystem -C
 
+ int ai_class; // Stuff for per-subsystem AI
+ int ai_index;
+
  // The following items are specific to turrets and will probably be moved to
  // a separate struct so they don't take up space for all subsystem types.
  char crewspot[MAX_NAME_LEN]; // unique identifying name for this turret -- used to assign AI class and multiplayer people
Index: ship/ship.cpp
===================================================================
--- ship/ship.cpp (revision 6320)
+++ ship/ship.cpp (working copy)
@@ -2711,6 +2711,7 @@
  sp->max_subsys_strength = 0.0f;
  sp->turret_turning_rate = 0.0f;
  sp->weapon_rotation_pbank = -1;
+ sp->ai_class = sip->ai_class; //Default to ship AI
 
  memset(sp->alt_sub_name, 0, sizeof(sp->alt_sub_name) );
  memset(sp->alt_dmg_sub_name, 0, sizeof(sp->alt_dmg_sub_name) );
@@ -2796,6 +2797,19 @@
  WarningEx(LOCATION, "Ship %s, subsystem %s\nInvalid armor type %s!", sip->name, sp->subobj_name, buf);
  }
 
+ //Get the optional subsystem AI class. If it is != the ship default AI class, set AI index to -1, else leave at ship default.
+ //find_and_stuff_optional("$Turret AI Class:", &sp->ai_class, F_NAME, Ai_class_names, Num_ai_classes, "AI class names");
+ if (optional_string("$Turret AI Class:")){
+ stuff_string(buf, F_NAME, SHIP_MULTITEXT_LENGTH);
+ for (i=0; i<Num_ai_classes; i++){
+ if (!stricmp(Ai_class_names[i], buf))
+ sp->ai_class = i;
+ }
+ sp->ai_index = -1;
+ } else {
+ sp->ai_class = sip->ai_class;
+ }
+
  // Get default primary bank weapons
  if (optional_string("$Default PBanks:")){
 strcat_s(parse_error_text,"'s default primary banks");
@@ -4774,7 +4788,54 @@
 
 }
 
+void init_turret_aip(ai_info* aip)
+{
+ aip->ai_flags = 0;
+ aip->previous_mode = AIM_NONE;
+ aip->mode_time = -1;
+ aip->target_objnum = -1;
+ aip->target_signature = -1;
+ aip->previous_target_objnum = -1;
+ aip->target_time = 0.0f;
+ aip->enemy_wing = -1;
+ aip->attacker_objnum = -1;
+ aip->goal_objnum = -1;
+ aip->goal_signature = -1;
+ aip->guard_objnum = -1;
+ aip->guard_signature = -1;
+ aip->guard_wingnum = -1;
+ aip->submode = 0;
+ aip->previous_submode = 0;
+ aip->best_dot_to_enemy = -1.0f;
+ aip->best_dot_from_enemy = -1.0f;
+ aip->best_dot_to_time = 0;
+ aip->best_dot_from_time = 0;
+ aip->submode_start_time = 0;
+ aip->submode_parm0 = 0;
+ aip->active_goal = -1;
+ aip->goal_check_time = timestamp(0);
+ aip->time_enemy_in_range = 0.0f;
+ aip->time_enemy_near = 0.0f;
+ aip->last_attack_time = 0;
+ aip->last_hit_time = 0;
+ aip->last_hit_quadrant = 0;
+ aip->hitter_objnum = -1;
+ aip->hitter_signature = -1;
+ aip->resume_goal_time = -1;
+ aip->prev_accel = 0.0f;
+ aip->prev_dot_to_goal = 0.0f;
 
+ aip->ignore_objnum = UNUSED_OBJNUM;
+ aip->ignore_signature = -1;
+
+ // Goober5000
+ for (int i = 0; i < MAX_IGNORE_NEW_OBJECTS; i++)
+ {
+ aip->ignore_new_objnums[i] = UNUSED_OBJNUM;
+ aip->ignore_new_signatures[i] = -1;
+ }
+}
+
 // ignore_subsys_info => default parameter with value of 0.  This is
 // only set to 1 by the save/restore code
 int subsys_set(int objnum, int ignore_subsys_info)
@@ -4868,7 +4929,23 @@
  ship_system->favor_current_facing = model_system->favor_current_facing;
  ship_system->subsys_cargo_name = -1;
  ship_system->time_subsys_cargo_revealed = 0;
-
+
+ //Init subsystem AI
+ //We only need to set up a whole new AI profile if the subsystem in question
+ //actually has a custom AI setting and the TURRETS_USE_SEPARATE_AI flag is active.
+ //If that isn't the case, we'll just default to the parent ships' ai profile.
+ ship_system->weapons.ai_class = model_system->ai_class;
+ ship_system->weapons.ai_index = model_system->ai_index;
+ if (ship_system->weapons.ai_index == -1 && (The_mission.ai_profile->flags2 & AIPF2_TURRETS_USE_SEPARATE_AI))
+ {
+ init_turret_aip(&ship_system->weapons.turret_aip);
+ init_aip_from_class_and_profile(&ship_system->weapons.turret_aip, &Ai_classes[ship_system->weapons.ai_class], The_mission.ai_profile);
+ }
+ else
+ {
+ ship_system->weapons.ai_index = shipp->ai_index;
+ }
+
  j = 0;
  int number_of_weapons = 0;
 
@@ -15324,22 +15401,31 @@
  Assert(new_ai_class >= 0);
 
  ship_subsys *ss;
+ //Only do this if we really need to
+ if (The_mission.ai_profile->flags2 & AIPF2_TURRETS_USE_SEPARATE_AI) {
+ // find the ship subsystem by searching ship's subsys_list
+ ss = GET_FIRST( &Ships[ship_num].subsys_list );
+ while ( ss != END_OF_LIST( &Ships[ship_num].subsys_list ) )
+ {
+ // if we found the subsystem
+ if ( !subsystem_stricmp(ss->system_info->subobj_name, subsystem))
+ {
+ // set ai class and ai profile
+ ss->weapons.ai_class = new_ai_class;
+ if (new_ai_class != Ai_info[Ships[ship_num].ai_index].ai_class) {
+ init_aip_from_class_and_profile(&ss->weapons.turret_aip, &Ai_classes[new_ai_class], The_mission.ai_profile);
+ if ( ss->weapons.ai_index != -1 )
+ ss->weapons.ai_index = -1;
+ return;
+ } else {
+ ss->weapons.ai_index = Ships[ship_num].ai_index;
+ }
+ }
 
- // find the ship subsystem by searching ship's subsys_list
- ss = GET_FIRST( &Ships[ship_num].subsys_list );
- while ( ss != END_OF_LIST( &Ships[ship_num].subsys_list ) )
- {
- // if we found the subsystem
- if ( !subsystem_stricmp(ss->system_info->subobj_name, subsystem))
- {
- // set ai class
- ss->weapons.ai_class = new_ai_class;
- return;
+ ss = GET_NEXT( ss );
  }
-
- ss = GET_NEXT( ss );
+ // Int3(); // subsystem not found
  }
- // Int3(); // subsystem not found
 }
 
 // Goober5000 - will attempt to load an insignia bitmap and set it as active for the wing
Index: ship/ship.h
===================================================================
--- ship/ship.h (revision 6320)
+++ ship/ship.h (working copy)
@@ -133,6 +133,8 @@
  int last_fired_weapon_signature; // Signature of last fired weapon.
  int detonate_weapon_time; // time at which last fired weapon can be detonated
  int ai_class;
+ int ai_index;
+ ai_info turret_aip;
 
  int flags; // see SW_FLAG_* defines above
  ubyte primary_animation_position[MAX_SHIP_PRIMARY_BANKS];
« Last Edit: July 21, 2010, 11:08:32 am by The E »
If I'm just aching this can't go on
I came from chasing dreams to feel alone
There must be changes, miss to feel strong
I really need lifе to touch me
--Evergrey, Where August Mourns

 

Offline The E

  • He's Ebeneezer Goode
  • Moderator
  • 213
  • Nothing personal, just tech support.
    • Steam
    • Twitter
Hrm.

I keep running into issues.

I have it running so that changing the ai class via sexp works, but I seem to run into brick walls when setting it up to use AI settings done via tbl or using the FRED ships editor.

Basically, it seems that the ai profile associated with the turret does not get initialized correctly. While it gets set up correctly in missionparse, by the time the mission is entered, those settings are gone again (having been reset to the "Captain" values somewhere along the line).

Can someone tell me what I'm doing wrong?

Code: [Select]
Index: ai/ai.h
===================================================================
--- ai/ai.h (revision 6320)
+++ ai/ai.h (working copy)
@@ -609,6 +609,7 @@
 extern void ai_ship_destroy(int shipnum, int method);
 extern void ai_turn_towards_vector(vec3d *dest, object *objp, float frametime, float turn_time, vec3d *slide_vec, vec3d *rel_pos, float bank_override, int flags, vec3d *rvec = NULL, int sexp_flags = 0);
 extern void init_ai_object(int objnum);
+extern void init_turret_aip(ai_info* aip);
 extern void ai_init(void); // Call this one to parse ai.tbl.
 extern void ai_level_init(void); // Call before each level to reset AI
 
Index: ai/ai_profiles.cpp
===================================================================
--- ai/ai_profiles.cpp (revision 6320)
+++ ai/ai_profiles.cpp (working copy)
@@ -395,6 +395,8 @@
 
  set_flag(profile, "$big ships manage shields:", AIPF2_BIG_SHIELD_MANAGE, AIP_FLAG2);
 
+ set_flag(profile, "$turrets use separate ai class:", AIPF2_TURRETS_USE_SEPARATE_AI, AIP_FLAG2);
+
  // if we've been through once already and are at the same place, force a move
  if ( saved_Mp && (saved_Mp == Mp) )
  Mp++;
Index: ai/ai_profiles.h
===================================================================
--- ai/ai_profiles.h (revision 6320)
+++ ai/ai_profiles.h (working copy)
@@ -55,6 +55,7 @@
 #define AIPF2_NO_SPECIAL_PLAYER_AVOID (1 << 1)
 #define AIPF2_PERFORM_LESS_SCREAM_CHECKS (1 << 2)
 #define AIPF2_BIG_SHIELD_MANAGE (1 << 3)
+#define AIPF2_TURRETS_USE_SEPARATE_AI (1 << 4)
 
 #define MAX_AI_PROFILES 5
 
Index: ai/aicode.cpp
===================================================================
--- ai/aicode.cpp (revision 6320)
+++ ai/aicode.cpp (working copy)
@@ -14531,6 +14531,54 @@
  memset(&aip->ai_override_ci,0,sizeof(control_info));
 }
 
+void init_turret_aip(ai_info* aip)
+{
+ aip->ai_flags = 0;
+ aip->previous_mode = AIM_NONE;
+ aip->mode_time = -1;
+ aip->target_objnum = -1;
+ aip->target_signature = -1;
+ aip->previous_target_objnum = -1;
+ aip->target_time = 0.0f;
+ aip->enemy_wing = -1;
+ aip->attacker_objnum = -1;
+ aip->goal_objnum = -1;
+ aip->goal_signature = -1;
+ aip->guard_objnum = -1;
+ aip->guard_signature = -1;
+ aip->guard_wingnum = -1;
+ aip->submode = 0;
+ aip->previous_submode = 0;
+ aip->best_dot_to_enemy = -1.0f;
+ aip->best_dot_from_enemy = -1.0f;
+ aip->best_dot_to_time = 0;
+ aip->best_dot_from_time = 0;
+ aip->submode_start_time = 0;
+ aip->submode_parm0 = 0;
+ aip->active_goal = -1;
+ aip->goal_check_time = timestamp(0);
+ aip->time_enemy_in_range = 0.0f;
+ aip->time_enemy_near = 0.0f;
+ aip->last_attack_time = 0;
+ aip->last_hit_time = 0;
+ aip->last_hit_quadrant = 0;
+ aip->hitter_objnum = -1;
+ aip->hitter_signature = -1;
+ aip->resume_goal_time = -1;
+ aip->prev_accel = 0.0f;
+ aip->prev_dot_to_goal = 0.0f;
+
+ aip->ignore_objnum = UNUSED_OBJNUM;
+ aip->ignore_signature = -1;
+
+ // Goober5000
+ for (int i = 0; i < MAX_IGNORE_NEW_OBJECTS; i++)
+ {
+ aip->ignore_new_objnums[i] = UNUSED_OBJNUM;
+ aip->ignore_new_signatures[i] = -1;
+ }
+}
+
 void init_ai_objects()
 {
  int i;
Index: ai/aiturret.cpp
===================================================================
--- ai/aiturret.cpp (revision 6320)
+++ ai/aiturret.cpp (working copy)
@@ -286,11 +286,24 @@
  return longest_range_so_far;
 }
 
+//Returns a pointer to the AI profile of a given turret, or a pointer to the ships' AI profile
+//if no separate AI class is defined or the TURRETS_USE_SEPARATE_AI flag isn't set
+ai_info* get_current_turret_aip(ship_subsys* turret){
+ ai_info* aip = NULL;
+ if ((The_mission.ai_profile->flags2 & AIPF2_TURRETS_USE_SEPARATE_AI) && turret->weapons.ai_index == -1){
+ aip = &turret->weapons.turret_aip;
+ } else {
+ aip = &Ai_info[turret->weapons.ai_index];
+ }
+ Assert(aip != NULL);
+ return aip;
+}
+
 // return !0 if objp can be considered for a turret target, 0 otherwise
 // input: objp => object that turret is considering as an enemy
 // turret_parent => object of ship that turret sits on
 // turret => turret pointer
-int valid_turret_enemy(object *objp, object *turret_parent)
+int valid_turret_enemy(object *objp, object *turret_parent, ship_subsys* turret)
 {
  if ( objp == turret_parent ) {
  return 0;
@@ -335,7 +348,7 @@
  weapon *wp = &Weapons[objp->instance];
  weapon_info *wip = &Weapon_info[wp->weapon_info_index];
 
- if ( (!(wip->wi_flags & WIF_BOMB) && !(Ai_info[Ships[turret_parent->instance].ai_index].ai_profile_flags & AIPF_ALLOW_TURRETS_TARGET_WEAPONS_FREELY) ) ) {
+ if ( (!(wip->wi_flags & WIF_BOMB) && !(get_current_turret_aip(turret)->ai_profile_flags & AIPF_ALLOW_TURRETS_TARGET_WEAPONS_FREELY) ) ) {
  return 0;
  }
 
@@ -366,7 +379,7 @@
  return;
  }
 
- if ( !valid_turret_enemy(objp, turret_parent_obj) ) {
+ if ( !valid_turret_enemy(objp, turret_parent_obj, eeo->turret_subsys) ) {
  return;
  }
 
@@ -469,7 +482,7 @@
  // check if bomb is homing on the turret parent ship
  bool check_weapon = true;
 
- if ((Ai_info[Ships[turret_parent_obj->instance].ai_index].ai_profile_flags & AIPF_PREVENT_TARGETING_BOMBS_BEYOND_RANGE) && (dist > eeo->weapon_travel_dist)) {
+ if ((get_current_turret_aip(eeo->turret_subsys)->ai_profile_flags & AIPF_PREVENT_TARGETING_BOMBS_BEYOND_RANGE) && (dist > eeo->weapon_travel_dist)) {
  check_weapon = false;
  }
 
@@ -792,7 +805,7 @@
 
  for(int i = 0; i < NUM_TURRET_ORDER_TYPES; i++)
  {
- ai_info *aip = &Ai_info[Ships[Objects[eeo.turret_parent_objnum].instance].ai_index];
+ ai_info *aip = get_current_turret_aip(eeo.turret_subsys);
  switch(turret_subsys->turret_targeting_order[i])
  {
  case -1:
@@ -1147,7 +1160,7 @@
  vm_vec_unrotate(&turret_norm, &turret_subsysp->system_info->turret_norm, &objp->orient);
  float dot_return = vm_vec_dot(&turret_norm, &vector_out);
 
- if (Ai_info[Ships[objp->instance].ai_index].ai_profile_flags & AIPF_SMART_SUBSYSTEM_TARGETING_FOR_TURRETS) {
+ if (get_current_turret_aip(turret_subsysp)->ai_profile_flags & AIPF_SMART_SUBSYSTEM_TARGETING_FOR_TURRETS) {
  if (dot_return > turret_subsysp->system_info->turret_fov) {
  // target is in sight and in fov
  return dot_return;
@@ -1267,7 +1280,7 @@
  int idx;
  float dot_fov_modifier = 0.0f;
 
- if (Ai_info[shipp->ai_index].ai_profile_flags & AIPF_SMART_SUBSYSTEM_TARGETING_FOR_TURRETS) {
+ if (get_current_turret_aip(ssp)->ai_profile_flags & AIPF_SMART_SUBSYSTEM_TARGETING_FOR_TURRETS) {
  if (ssp->system_info->turret_fov < 0)
  dot_fov_modifier = ssp->system_info->turret_fov;
  }
@@ -1437,7 +1450,7 @@
  if((!timestamp_elapsed(get_turret_weapon_next_fire_stamp(&turret->weapons, weapon_num))) && last_shot_in_salvo)
  return false;
 
- parent_aip = &Ai_info[Ships[Objects[parent_objnum].instance].ai_index];
+ parent_aip = get_current_turret_aip(turret);
  parent_ship = &Ships[Objects[parent_objnum].instance];
  wip = get_turret_weapon_wip(&turret->weapons, weapon_num);
  int turret_weapon_class = WEAPON_INFO_INDEX(wip);
@@ -1551,7 +1564,7 @@
  }
  }
  //Not useful -WMC
- else if (!(parent_aip->ai_profile_flags & AIPF_DONT_INSERT_RANDOM_TURRET_FIRE_DELAY) && last_shot_in_salvo)
+ else if (!(get_current_turret_aip(turret)->ai_profile_flags & AIPF_DONT_INSERT_RANDOM_TURRET_FIRE_DELAY) && last_shot_in_salvo)
  {
  float wait = 1000.0f * frand_range(0.9f, 1.1f);
  turret->turret_next_fire_stamp = timestamp((int) wait);
@@ -2144,8 +2157,8 @@
  } else {
  // make sure salvo fire mode does not turn into autofire
  if ((tp->flags & MSS_FLAG_TURRET_SALVO) && ((i + 1) == number_of_firings)) {
- ai_info *parent_aip = &Ai_info[Ships[Objects[parent_objnum].instance].ai_index];
- turret_set_next_fire_timestamp(valid_weapons[0], wip, ss, parent_aip);
+ //ai_info *parent_aip = &Ai_info[Ships[Objects[parent_objnum].instance].ai_index];
+ turret_set_next_fire_timestamp(valid_weapons[0], wip, ss, get_current_turret_aip(ss));
  }
  }
  // moved this here so we increment the fire pos only after we have fired and not during it
Index: mission/missionparse.cpp
===================================================================
--- mission/missionparse.cpp (revision 6320)
+++ mission/missionparse.cpp (working copy)
@@ -2161,8 +2161,14 @@
 
  ptr->subsys_cargo_name = sssp->subsys_cargo_name;
 
- if (sssp->ai_class != SUBSYS_STATUS_NO_CHANGE)
+ if ((The_mission.ai_profile->flags2 & AIPF2_TURRETS_USE_SEPARATE_AI) && sssp->ai_class != SUBSYS_STATUS_NO_CHANGE)
+ {
+ init_turret_aip(&ptr->weapons.turret_aip);
  ptr->weapons.ai_class = sssp->ai_class;
+ ptr->weapons.ai_index = -1;
+ init_aip_from_class_and_profile(&ptr->weapons.turret_aip, &Ai_classes[ptr->weapons.ai_class], The_mission.ai_profile);
+ ship_subsystem_set_new_ai_class(shipnum, ptr->system_info->subobj_name, sssp->ai_class);
+ }
 
  ptr->turret_best_weapon = -1;
  ptr->turret_animation_position = 0; // MA_POS_NOT_SET -> model animation position is not set
Index: model/model.h
===================================================================
--- model/model.h (revision 6320)
+++ model/model.h (working copy)
@@ -144,6 +144,9 @@
  float max_subsys_strength; // maximum hits of this subsystem
  int armor_type_idx; //Armor type on teh subsystem -C
 
+ int ai_class; // Stuff for per-subsystem AI
+ int ai_index;
+
  // The following items are specific to turrets and will probably be moved to
  // a separate struct so they don't take up space for all subsystem types.
  char crewspot[MAX_NAME_LEN]; // unique identifying name for this turret -- used to assign AI class and multiplayer people
Index: ship/ship.cpp
===================================================================
--- ship/ship.cpp (revision 6320)
+++ ship/ship.cpp (working copy)
@@ -2711,6 +2711,7 @@
  sp->max_subsys_strength = 0.0f;
  sp->turret_turning_rate = 0.0f;
  sp->weapon_rotation_pbank = -1;
+ sp->ai_class = sip->ai_class; //Default to ship AI
 
  memset(sp->alt_sub_name, 0, sizeof(sp->alt_sub_name) );
  memset(sp->alt_dmg_sub_name, 0, sizeof(sp->alt_dmg_sub_name) );
@@ -2796,6 +2797,20 @@
  WarningEx(LOCATION, "Ship %s, subsystem %s\nInvalid armor type %s!", sip->name, sp->subobj_name, buf);
  }
 
+ //Get the optional subsystem AI class. If it is != the ship default AI class, set AI index to -1, else leave at ship default.
+ //find_and_stuff_optional("$Turret AI Class:", &sp->ai_class, F_NAME, Ai_class_names, Num_ai_classes, "AI class names");
+ if (optional_string("$Turret AI Class:")){
+ stuff_string(buf, F_NAME, SHIP_MULTITEXT_LENGTH);
+ for (i=0; i<Num_ai_classes; i++){
+ if (!stricmp(Ai_class_names[i], buf))
+ sp->ai_class = i;
+ }
+ sp->ai_index = -1;
+ } else {
+ sp->ai_class = sip->ai_class;
+ sp->ai_index = -2;
+ }
+
  // Get default primary bank weapons
  if (optional_string("$Default PBanks:")){
 strcat_s(parse_error_text,"'s default primary banks");
@@ -4771,10 +4786,8 @@
  break;
  }
  // }
-
 }
 
-
 // ignore_subsys_info => default parameter with value of 0.  This is
 // only set to 1 by the save/restore code
 int subsys_set(int objnum, int ignore_subsys_info)
@@ -4868,7 +4881,28 @@
  ship_system->favor_current_facing = model_system->favor_current_facing;
  ship_system->subsys_cargo_name = -1;
  ship_system->time_subsys_cargo_revealed = 0;
-
+
+ //Init subsystem AI
+ //We only need to set up a whole new AI profile if the subsystem in question
+ //actually has a custom AI setting and the TURRETS_USE_SEPARATE_AI flag is active.
+ //If that isn't the case, we'll just default to the parent ships' ai profile.
+ ship_system->weapons.ai_class = model_system->ai_class;
+ ship_system->weapons.ai_index = model_system->ai_index;
+ if ((The_mission.ai_profile->flags2 & AIPF2_TURRETS_USE_SEPARATE_AI))
+ {
+ if (ship_system->weapons.ai_index == -2)
+ {
+ ship_system->weapons.ai_index = shipp->ai_index;
+ ship_system->weapons.ai_class = Ai_info[shipp->ai_index].ai_class;
+ }
+ init_turret_aip(&ship_system->weapons.turret_aip);
+ init_aip_from_class_and_profile(&ship_system->weapons.turret_aip, &Ai_classes[ship_system->weapons.ai_class], The_mission.ai_profile);
+ }
+ else
+ {
+ ship_system->weapons.ai_index = shipp->ai_index;
+ }
+
  j = 0;
  int number_of_weapons = 0;
 
@@ -15324,22 +15358,31 @@
  Assert(new_ai_class >= 0);
 
  ship_subsys *ss;
+ //Only do this if we really need to
+ if (The_mission.ai_profile->flags2 & AIPF2_TURRETS_USE_SEPARATE_AI) {
+ // find the ship subsystem by searching ship's subsys_list
+ ss = GET_FIRST( &Ships[ship_num].subsys_list );
+ while ( ss != END_OF_LIST( &Ships[ship_num].subsys_list ) )
+ {
+ // if we found the subsystem
+ if ( !subsystem_stricmp(ss->system_info->subobj_name, subsystem))
+ {
+ // set ai class and ai profile
+ ss->weapons.ai_class = new_ai_class;
+ if (new_ai_class != Ai_info[Ships[ship_num].ai_index].ai_class ) {
+ init_aip_from_class_and_profile(&ss->weapons.turret_aip, &Ai_classes[new_ai_class], The_mission.ai_profile);
+ if ( ss->weapons.ai_index != -1 )
+ ss->weapons.ai_index = -1;
+ return;
+ } else {
+ ss->weapons.ai_index = Ships[ship_num].ai_index;
+ }
+ }
 
- // find the ship subsystem by searching ship's subsys_list
- ss = GET_FIRST( &Ships[ship_num].subsys_list );
- while ( ss != END_OF_LIST( &Ships[ship_num].subsys_list ) )
- {
- // if we found the subsystem
- if ( !subsystem_stricmp(ss->system_info->subobj_name, subsystem))
- {
- // set ai class
- ss->weapons.ai_class = new_ai_class;
- return;
+ ss = GET_NEXT( ss );
  }
-
- ss = GET_NEXT( ss );
+ // Int3(); // subsystem not found
  }
- // Int3(); // subsystem not found
 }
 
 // Goober5000 - will attempt to load an insignia bitmap and set it as active for the wing
Index: ship/ship.h
===================================================================
--- ship/ship.h (revision 6320)
+++ ship/ship.h (working copy)
@@ -133,6 +133,8 @@
  int last_fired_weapon_signature; // Signature of last fired weapon.
  int detonate_weapon_time; // time at which last fired weapon can be detonated
  int ai_class;
+ int ai_index;
+ ai_info turret_aip;
 
  int flags; // see SW_FLAG_* defines above
  ubyte primary_animation_position[MAX_SHIP_PRIMARY_BANKS];
If I'm just aching this can't go on
I came from chasing dreams to feel alone
There must be changes, miss to feel strong
I really need lifе to touch me
--Evergrey, Where August Mourns

 

Offline Sushi

  • Art Critic
  • 211
Or, I follow a sensible suggestion by FUBAR and just add an ai_info field to the ship_weapons struct.

Um, that's still additional data storage. Just in a different place. :)

IMO it still makes more sense to just increase the number of AI slots, so they're all lumped together. Much more transparent and easy to understand what's going on and exactly how much extra storage is being invoked.
(Alternately, we could get rid of the Ai_info array and just bundle the data structure in with the ship...hmmm...)

As to why things aren't  working: couldn't tell based on a quick scan of the diff, but you're juggling a lot of pointers and indexes and those are almost certainly the cause of the problem.