11#include " ShipGoalsDialogModel.h"
22#include < globalincs/linklist.h>
33#include < mission/object.h>
4+ #include < model/model.h>
45namespace fso {
56 namespace fred {
67 namespace dialogs {
@@ -134,7 +135,6 @@ namespace fso {
134135
135136 void ShipGoalsDialogModel::update_item (const int item)
136137 {
137- char * docker, * dockee, * subsys;
138138 ai_goal_mode mode;
139139 char save[80 ]{};
140140 SCP_string error_message;
@@ -179,30 +179,47 @@ namespace fso {
179179 case AI_GOAL_CHASE_SHIP_CLASS :
180180 break ;
181181
182- case AI_GOAL_DESTROY_SUBSYSTEM :
183- subsys = nullptr ;
184- if (!m_multi_edit || (m_object[item] && (m_subsys[item].c_str () != nullptr )))
185- subsys = (char *)m_subsys[item].c_str ();
186- // MODIFY(goalp[item].ai_submode, m_subsys[item] + 1);
187-
188- if (!subsys) {
182+ case AI_GOAL_DESTROY_SUBSYSTEM : {
183+ if (m_subsys[item].empty ()) {
189184 sprintf (error_message, " Order #%d doesn't have valid subsystem name. Order will be removed" , item + 1 );
190185 _viewport->dialogProvider ->showButtonDialog (DialogType::Information,
191186 " Order Error" ,
192187 error_message,
193188 { DialogButton::Ok });
194189 modify (goalp[item].ai_mode , AI_GOAL_NONE );
195190 return ;
191+ }
196192
193+ // Look up the subsystem in the target ship to get a persistent name pointer.
194+ // Storing m_subsys[item].c_str() directly would dangle after the model is destroyed.
195+ const char * persistent_name = nullptr ;
196+ int target_ship_idx = m_object[item] & DATA_MASK ;
197+ if (target_ship_idx >= 0 && target_ship_idx < MAX_SHIPS ) {
198+ ship_subsys* cur_ss = GET_FIRST (&Ships[target_ship_idx].subsys_list );
199+ while (cur_ss != END_OF_LIST (&Ships[target_ship_idx].subsys_list )) {
200+ if (!stricmp (cur_ss->system_info ->subobj_name , m_subsys[item].c_str ())) {
201+ persistent_name = cur_ss->system_info ->subobj_name ;
202+ break ;
203+ }
204+ cur_ss = GET_NEXT (cur_ss);
205+ }
197206 }
198- else {
199- if (!goalp[item].docker .name || (goalp[item].docker .name && !stricmp (goalp[item].docker .name , subsys)))
200- set_modified ();
201207
202- goalp[item].docker .name = subsys;
208+ if (!persistent_name) {
209+ sprintf (error_message, " Order #%d doesn't have valid subsystem name. Order will be removed" , item + 1 );
210+ _viewport->dialogProvider ->showButtonDialog (DialogType::Information,
211+ " Order Error" ,
212+ error_message,
213+ { DialogButton::Ok });
214+ modify (goalp[item].ai_mode , AI_GOAL_NONE );
215+ return ;
203216 }
204217
218+ if (!goalp[item].docker .name || stricmp (goalp[item].docker .name , persistent_name) != 0 )
219+ set_modified ();
220+ goalp[item].docker .name = persistent_name;
205221 break ;
222+ }
206223
207224 case AI_GOAL_CHASE :
208225 case AI_GOAL_CHASE_WING :
@@ -219,19 +236,37 @@ namespace fso {
219236
220237 break ;
221238
222- case AI_GOAL_DOCK :
223- docker = nullptr ;
224- if (!m_multi_edit || (m_object[item] && (m_subsys[item].c_str () != nullptr )))
225- docker = (char *)m_subsys[item].c_str ();
226-
227- dockee = nullptr ;
228- if (!m_multi_edit || (m_object[item] && (m_dock2[item] >= 0 )))
229- dockee = (char *)m_dock2[item];
239+ case AI_GOAL_DOCK : {
240+ // Resolve persistent dock bay name pointers from the polymodel.
241+ // Storing m_subsys[item].c_str() directly would dangle after the model is destroyed.
242+ char * docker = nullptr ;
243+ char * dockee = nullptr ;
244+
245+ if (!m_multi_edit || (m_object[item] && !m_subsys[item].empty ())) {
246+ if (self_ship >= 0 ) {
247+ int model_num = Ship_info[Ships[self_ship].ship_info_index ].model_num ;
248+ polymodel* pm = model_get (model_num);
249+ if (pm) {
250+ for (int b = 0 ; b < pm->n_docks ; b++) {
251+ if (!stricmp (pm->docking_bays [b].name , m_subsys[item].c_str ())) {
252+ docker = pm->docking_bays [b].name ;
253+ break ;
254+ }
255+ }
256+ }
257+ }
258+ }
230259
231- if (docker == (char *)SIZE_MAX )
232- docker = nullptr ;
233- if (dockee == (char *)SIZE_MAX )
234- dockee = nullptr ;
260+ if (!m_multi_edit || (m_object[item] && (m_dock2[item] >= 0 ))) {
261+ int dockee_ship = m_object[item] & DATA_MASK ;
262+ if (dockee_ship >= 0 && dockee_ship < MAX_SHIPS && m_dock2[item] >= 0 ) {
263+ int model_num = Ship_info[Ships[dockee_ship].ship_info_index ].model_num ;
264+ polymodel* pm = model_get (model_num);
265+ if (pm && m_dock2[item] < pm->n_docks ) {
266+ dockee = pm->docking_bays [m_dock2[item]].name ;
267+ }
268+ }
269+ }
235270
236271 if (!docker || !dockee) {
237272 sprintf (error_message, " Order #%d doesn't have valid docking points. Order will be removed" , item + 1 );
@@ -241,24 +276,18 @@ namespace fso {
241276 { DialogButton::Ok });
242277 modify (goalp[item].ai_mode , AI_GOAL_NONE );
243278 return ;
244-
245- }
246- else {
247- if (!goalp[item].docker .name )
279+ } else {
280+ if (!goalp[item].docker .name || stricmp (goalp[item].docker .name , docker) != 0 )
248281 set_modified ();
249- else if (!stricmp (goalp[item].docker .name , docker))
250- set_modified ();
251-
252- if (!goalp[item].dockee .name )
253- set_modified ();
254- else if (!stricmp (goalp[item].dockee .name , dockee))
282+ if (!goalp[item].dockee .name || stricmp (goalp[item].dockee .name , dockee) != 0 )
255283 set_modified ();
256284
257285 goalp[item].docker .name = docker;
258286 goalp[item].dockee .name = dockee;
259287 }
260288
261289 break ;
290+ }
262291
263292 case AI_GOAL_GUARD :
264293 case AI_GOAL_GUARD_WING :
@@ -433,19 +462,19 @@ namespace fso {
433462 init_combo_data ();
434463
435464 if (self_ship >= 0 ) {
436- initialize (Ai_info[Ships[self_ship].ai_index ].goals , self_ship );
465+ initialize (Ai_info[Ships[self_ship].ai_index ].goals );
437466 }
438467 else if (self_wing >= 0 ) {
439- initialize (Wings[self_wing].ai_goals , _editor-> cur_ship );
468+ initialize (Wings[self_wing].ai_goals );
440469 }
441470 else {
442471 initialize_multi ();
443472 }
444473 modelChanged ();
445474 }
446- void ShipGoalsDialogModel::initialize (ai_goal* goals, int ship )
475+ void ShipGoalsDialogModel::initialize (ai_goal* goals)
447476 {
448- int i, item, num, inst, flag;
477+ int i, item, inst, flag;
449478 ai_goal_mode mode;
450479 object* ptr;
451480 SCP_vector<SCP_string> docks;
@@ -522,22 +551,16 @@ namespace fso {
522551 break ;
523552
524553 case AI_GOAL_DESTROY_SUBSYSTEM :
525- num = ship_name_lookup (goalp[item]. target_name , 1 );
526- if (num != - 1 )
527- m_subsys[item] = ship_find_subsys (&Ships[num], goalp[item].docker .name );
528-
554+ // docker.name already holds the subsystem name string... copy it directly.
555+ // (ship_find_subsys returns an int index, not the name, so don't use it here. )
556+ if ( goalp[item].docker .name != nullptr )
557+ m_subsys[item] = goalp[item]. docker . name ;
529558 break ;
530559
531560 case AI_GOAL_DOCK :
532- m_subsys[item] = -1 ;
533- docks = _editor->get_docking_list (Ship_info[Ships[ship].ship_info_index ].model_num );
534- for (i = 0 ; unsigned (i) < docks.size (); i++) {
535- if (!stricmp (goalp[item].docker .name , docks[i].c_str ())) {
536- m_subsys[item] = i;
537- break ;
538- }
539- }
540-
561+ // Store the docker bay name string directly; the persistent pointer lives in the polymodel.
562+ if (goalp[item].docker .name != nullptr )
563+ m_subsys[item] = goalp[item].docker .name ;
541564 break ;
542565
543566 case AI_GOAL_CHASE_WING :
@@ -647,7 +670,7 @@ namespace fso {
647670 ptr = GET_FIRST (&obj_used_list);
648671 while (ptr != END_OF_LIST (&obj_used_list)) {
649672 if (((ptr->type == OBJ_SHIP ) || (ptr->type == OBJ_START )) && (ptr->flags [Object::Object_Flags::Marked])) {
650- initialize (Ai_info[Ships[ptr->instance ].ai_index ].goals , ptr-> instance );
673+ initialize (Ai_info[Ships[ptr->instance ].ai_index ].goals );
651674 if (!flag) {
652675 flag = 1 ;
653676 for (i = 0 ; i < ED_MAX_GOALS ; i++) {
0 commit comments