View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0003052 | FSSCP | SEXPs | public | 2014-05-30 18:53 | 2014-06-09 01:22 |
Reporter | The_E | Assigned To | MageKing17 | ||
Priority | normal | Severity | minor | Reproducibility | always |
Status | resolved | Resolution | fixed | ||
Product Version | 3.7.2 | ||||
Target Version | 3.7.2 | ||||
Summary | 0003052: "targeted" sexp returns KNOWN_FALSE in conjunction with argument list | ||||
Description | In the BP WiH mission "Her Finest Hour", we're using a sexp with an argument list as part of the mechanism that allows the player to call in artillery strikes. That system works for some time, but stops soon. Thanks to diligent debugging work by MageKing17, we finally found the cause. The "targeted" sexp returns "KNOWN_FALSE" when asked to evaluate a target that is already dead, this causes the entire (when-argument controlled) event to go into "KNOWN_FALSE", thus stopping the event from working. A patch to change this behaviour (So that targeted returns "CANT_EVAL" in cases like this) is attached. | ||||
Tags | No tags attached. | ||||
|
sexp.cpp.patch (399 bytes)
Index: sexp.cpp =================================================================== --- sexp.cpp (revision 10726) +++ sexp.cpp (working copy) @@ -14911,9 +14911,7 @@ ship_subsys *ptr; z = ship_query_state(CTEXT(node)); - if (z == 1){ - return SEXP_KNOWN_FALSE; // ship isn't around, nor will it ever be - } else if (z == -1) { + if (z == 1 || z == -1) { return SEXP_CANT_EVAL; } |
|
Out of curiosity, I looked into the SEXP code to see exactly what it was doing, and I'm scratching my head, because eval_any_of isn't supposed to return SEXP_KNOWN_FALSE unless every single valid argument returns SEXP_KNOWN_FALSE. Whether or not "targeted" should return SEXP_KNOWN_FALSE, it shouldn't actually be locking out "any-of" in this case, so the bug would seem to be with "any-of", not "targeted". |
|
From reading MageKing17's note I don't believe this is ready for review yet. |
|
sexp.cpp.mk17.patch (2,009 bytes)
Index: sexp.cpp =================================================================== --- sexp.cpp (revision 10739) +++ sexp.cpp (working copy) @@ -8468,13 +8468,13 @@ // only eval this argument if it's valid if (Sexp_nodes[n].flags & SNF_ARGUMENT_VALID) { - // flush conditional to avoid short-circuiting - flush_sexp_tree(condition_node); - // evaluate conditional for current argument Sexp_replacement_arguments.push_back(Sexp_nodes[n].text); val = eval_sexp(condition_node); + // flush conditional to avoid short-circuiting + flush_sexp_tree(condition_node); + switch (val) { case SEXP_TRUE: @@ -8542,13 +8542,13 @@ { // since we can't see or modify the validity, assume all are valid { - // flush conditional to avoid short-circuiting - flush_sexp_tree(condition_node); - // evaluate conditional for current argument Sexp_replacement_arguments.push_back(argument_vector[i]); val = eval_sexp(condition_node); + // flush conditional to avoid short-circuiting + flush_sexp_tree(condition_node); + switch (val) { case SEXP_TRUE: @@ -8741,12 +8741,14 @@ { // flush stuff Sexp_applicable_argument_list.clear_nesting_level(); - flush_sexp_tree(condition_node); // evaluate conditional for current argument Sexp_replacement_arguments.push_back(Sexp_nodes[n].text); val = eval_sexp(condition_node); + // flush conditional to avoid short-circuiting + flush_sexp_tree(condition_node); + // true? if (val == SEXP_TRUE || val == SEXP_KNOWN_TRUE) { @@ -8790,12 +8792,14 @@ { // flush stuff Sexp_applicable_argument_list.clear_nesting_level(); - flush_sexp_tree(condition_node); // evaluate conditional for current argument Sexp_replacement_arguments.push_back(Sexp_nodes[n].text); val = eval_sexp(condition_node); + // flush conditional to avoid short-circuiting + flush_sexp_tree(condition_node); + // true? if (val == SEXP_TRUE || val == SEXP_KNOWN_TRUE) { |
|
I've attached a patch (which I have tested with Her Finest Hour) that should fix the root problem. |
|
Whoa, this should not have been committed without a lot more review. I've rolled it back. First of all, this patch violates the assumption of the multiple argument technique, which is that the evaluation starts off with a clean slate. Moving the tree flushing to *after* the evaluation causes the evaluation to occur with whatever values the sexp tree previously held. Now one might argue that the effect is the same in either case, but the fact that the patch changes the behavior indicates that it is not a no-op. Second of all, the "targeted" sexp is a retail sexp. Likewise, "known-false" is a retail condition. Returning known-false when the ship is destroyed is precisely the correct behavior for this sexp. I am curious as to what exactly is going on with ships that apparently need to be evaluated even after they are destroyed, but in any case, if the evaluation needs to happen repeatedly without regard to known-x, the proper solution is to use the every-time or every-time-argument conditional. So this is a FRED bug, not a code bug. All that said, MageKing17's first comment on this bug ticket is an appropriate concern. I would like to talk to him to get more details on his bug hunting efforts. It is certainly possible that there is indeed a bug, albeit not the one assumed by this ticket report. |
|
I made a mission that reproduces the original issue from BP:WiH. There's an when any-of argument that sends a message when one of the three capital ships is targetted. Press 1 to self destruct the Deimos (the last argument). When the Deimos finishes blowing up, the messages stop being sent when the remaining 2 ships are targetted. |
|
|
|
revised_sexp.cpp.patch (1,015 bytes)
Index: code/parse/sexp.cpp =================================================================== --- code/parse/sexp.cpp (revision 10747) +++ code/parse/sexp.cpp (working copy) @@ -8294,7 +8294,7 @@ */ int eval_when(int n, int when_op_num) { - int cond, val, actions; + int arg_handler = -1, cond, val, actions; Assert( n >= 0 ); arg_item *ptr; @@ -8301,7 +8301,7 @@ // get the parts of the sexp and evaluate the conditional if (is_blank_argument_op(when_op_num)) { - int arg_handler = CAR(n); + arg_handler = CAR(n); cond = CADR(n); actions = CDDR(n); @@ -8393,7 +8393,10 @@ Sexp_current_argument_nesting_level--; } - if (Sexp_nodes[cond].value == SEXP_KNOWN_FALSE) + // thanks to MageKing17, we need to short-circuit on the correct node! + int short_circuit_node = (arg_handler >= 0) ? arg_handler : cond; + + if (Sexp_nodes[short_circuit_node].value == SEXP_KNOWN_FALSE) return SEXP_KNOWN_FALSE; // no need to waste time on this anymore if (val == SEXP_KNOWN_FALSE) |
|
Fix committed to trunk@10748. |
|
This fix should be credited to MageKing17 aka AdmiralRalwood, so I'm unassigning it. |
|
The actual cause of the bug was a loose end that escaped notice in the original design of when-argument. A function was using the most recent conditional value evaluated by an argument handler (such as any-of) instead of the value of the argument handler itself. |
fs2open: trunk r10741 2014-06-02 11:07 Ported: N/A Details Diff |
From MageKing17: Fix for Mantis 3502 (Flush the sexp result tree after argument evaluation to avert accidental short-circuit results) |
Affected Issues 0003052 |
|
mod - /trunk/fs2_open/code/parse/sexp.cpp | Diff File | ||
fs2open: trunk r10743 2014-06-02 21:28 Ported: N/A Details Diff |
roll back r10741 pending further code review; see Mantis 0003052 |
Affected Issues 0003052 |
|
mod - /trunk/fs2_open/code/parse/sexp.cpp | Diff File | ||
fs2open: trunk r10748 2014-06-02 23:21 Ported: N/A Details Diff |
fix a bug in the when-argument sexp that managed to escape detection from its original design! spotted by MageKing17, fixes Mantis 0003052 |
Affected Issues 0003052 |
|
mod - /trunk/fs2_open/code/parse/sexp.cpp | Diff File |
Date Modified | Username | Field | Change |
---|---|---|---|
2014-05-30 18:53 | The_E | New Issue | |
2014-05-30 18:53 | The_E | Status | new => assigned |
2014-05-30 18:53 | The_E | Assigned To | => The_E |
2014-05-30 18:53 | The_E | File Added: sexp.cpp.patch | |
2014-05-31 04:43 | MageKing17 | Note Added: 0015775 | |
2014-05-31 07:22 | Echelon9 | Status | assigned => code review |
2014-05-31 08:43 | niffiwan | Note Added: 0015777 | |
2014-06-02 05:29 | MageKing17 | File Added: sexp.cpp.mk17.patch | |
2014-06-02 05:30 | MageKing17 | Note Added: 0015781 | |
2014-06-03 02:12 | Goober5000 | Note Added: 0015783 | |
2014-06-03 02:12 | Goober5000 | Changeset attached | => fs2open trunk r10743 |
2014-06-03 02:12 | Goober5000 | Assigned To | The_E => Goober5000 |
2014-06-03 02:12 | Goober5000 | Status | code review => assigned |
2014-06-03 02:13 | Goober5000 | Changeset attached | => fs2open trunk r10741 |
2014-06-03 02:33 | Axem | Note Added: 0015784 | |
2014-06-03 02:33 | Axem | File Added: TargettingArgs.fs2 | |
2014-06-03 03:38 | Goober5000 | File Added: revised_sexp.cpp.patch | |
2014-06-03 04:04 | Goober5000 | Changeset attached | => fs2open trunk r10748 |
2014-06-03 04:04 | Goober5000 | Note Added: 0015785 | |
2014-06-03 04:04 | Goober5000 | Status | assigned => resolved |
2014-06-03 04:04 | Goober5000 | Resolution | open => fixed |
2014-06-03 04:06 | Goober5000 | Note Added: 0015786 | |
2014-06-03 04:06 | Goober5000 | Assigned To | Goober5000 => |
2014-06-03 04:07 | Goober5000 | Note Added: 0015787 | |
2014-06-09 01:22 | Goober5000 | Assigned To | => MageKing17 |