From cc6b4aee621f3959152043c4863896db2bf97950 Mon Sep 17 00:00:00 2001 From: Daniel Bergman Date: Sun, 16 Aug 2026 08:36:55 -0400 Subject: [PATCH 1/2] persist attack through attacker transformation Invert the decision made earlier on this branch. Transformation now leaves an in-progress attack running instead of ending it. `pAttackTarget` lives in `phenotype.cell_interactions`, so `phenotype = cd.phenotype` would drop it; hold it across the assignment and put it back. The other two halves of the attack link -- the target's `attacked_by` and the shared spring -- live in `state`, which transformation already leaves alone, so restoring `pAttackTarget` keeps all three consistent without touching the spring. This also makes transformation symmetric: attacks *against* a transforming cell already persisted, while attacks *by* it were ended. --- core/PhysiCell_cell.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/PhysiCell_cell.cpp b/core/PhysiCell_cell.cpp index cbeb4e239..364464bf7 100644 --- a/core/PhysiCell_cell.cpp +++ b/core/PhysiCell_cell.cpp @@ -1158,12 +1158,11 @@ void Cell::convert_to_cell_definition( Cell_Definition& cd ) Molecular cell_molecular = phenotype.molecular; Custom_Cell_Data cell_custom_data = custom_data; - // pAttackTarget is phenotype state, and the assignment below replaces it, so - // end this cell's own attack. attacked_by and the spring are in state, which - // transformation preserves, so attacks against this cell continue. - remove_self_from_attacked(); - // should we also remove all attackers? That would be a change in behavior, so for now we don't. - // remove_all_attackers(); + // pAttackTarget is phenotype state, and the assignment below replaces it, so hold + // on to it and put it back afterwards. attacked_by and the spring are in state, + // which transformation preserves, so restoring pAttackTarget keeps the whole + // attack link intact -- matching attacks against this cell, which already persist. + Cell* cell_attack_target = phenotype.cell_interactions.pAttackTarget; // use the cell defaults; type = cd.type; @@ -1184,6 +1183,7 @@ void Cell::convert_to_cell_definition( Cell_Definition& cd ) phenotype.geometry = cell_geometry; // leave the geometry alone phenotype.molecular.internalized_total_substrates = cell_molecular.internalized_total_substrates; + phenotype.cell_interactions.pAttackTarget = cell_attack_target; // leave any ongoing attack alone for( int nn = 0 ; nn < custom_data.variables.size() ; nn++ ) { From 1855646c7c418fb9f35825847237edd1a1590e69 Mon Sep 17 00:00:00 2001 From: Daniel Bergman Date: Sun, 16 Aug 2026 08:53:38 -0400 Subject: [PATCH 2/2] carry total_damage_delivered across transformation It lives in phenotype.cell_interactions too, so the transformation reset the attacker's lifetime damage tally to zero -- now visibly wrong when the attack it was counting is still running afterwards. --- core/PhysiCell_cell.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/PhysiCell_cell.cpp b/core/PhysiCell_cell.cpp index 364464bf7..340734a88 100644 --- a/core/PhysiCell_cell.cpp +++ b/core/PhysiCell_cell.cpp @@ -1163,6 +1163,9 @@ void Cell::convert_to_cell_definition( Cell_Definition& cd ) // which transformation preserves, so restoring pAttackTarget keeps the whole // attack link intact -- matching attacks against this cell, which already persist. Cell* cell_attack_target = phenotype.cell_interactions.pAttackTarget; + // a lifetime tally of this cell's own doing, so carry it across the transformation + // rather than restarting it partway through an attack that is still running + double cell_total_damage_delivered = phenotype.cell_interactions.total_damage_delivered; // use the cell defaults; type = cd.type; @@ -1184,6 +1187,7 @@ void Cell::convert_to_cell_definition( Cell_Definition& cd ) phenotype.geometry = cell_geometry; // leave the geometry alone phenotype.molecular.internalized_total_substrates = cell_molecular.internalized_total_substrates; phenotype.cell_interactions.pAttackTarget = cell_attack_target; // leave any ongoing attack alone + phenotype.cell_interactions.total_damage_delivered = cell_total_damage_delivered; for( int nn = 0 ; nn < custom_data.variables.size() ; nn++ ) {