Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EvaluateAll attribute in CCreatureTrigger is broken #165

Open
meekee7 opened this issue Apr 4, 2021 · 0 comments
Open

EvaluateAll attribute in CCreatureTrigger is broken #165

meekee7 opened this issue Apr 4, 2021 · 0 comments

Comments

@meekee7
Copy link
Contributor

meekee7 commented Apr 4, 2021

The trigger class CCreatureTrigger has an EvaluateAll attribute. The intent is to fire the trigger only when all the creatures listed in the trigger have died. (The more general CCreatureTrigger usage also supports other creature events.)

In the original levels, EvaluateAll is used in only one place: in Industrial Jungle right after the waterfall, at the entrance of the valley.
TPass050

  1. When the raptor from the fighting ground dies, it will cause another raptor to appear at spawn point 1.
  2. When the raptor from the fighting ground, the raptor from spawn point 1 and the albertosaurus are all dead, it is supposed to cause two more raptors to appear around spawn point 2. This event is the CCreatureTrigger in question with EvaluateAll.

The type of death does not matter; the dinosaurs can kill each other.

The problem is that in the situation above, with the current engine code and the level script as-is, the EvaluateAll attribute is unused. The trigger fires when any one of the three dinosaurs dies.

The are-all-dinos-dead check happens in CCreatureTrigger::bEvaluateNow(), which is never called.

To use EvaluateAll, the trigger would require a FireExpression as an additional condition to be checked when attempting to trigger. In T-Script, the expression would have to be a "query expression", starting with @. This would cause CCreatureTrigger::bEvaluateNow() to be called. Such FireExpressions are also possible for other trigger types and definitely exist in the level script code.

One might propose to auto-insert the the FireExpression by adding these lines near the end of the CCreatureTrigger constructor:

if (bEvaluateAll && !peeFireExpression) {
    peeFireExpression = new CExpressionEvaluate();
    peeFireExpression->AddExpressionOperand(this, true);
}

But it does not work. The created expression is supposed to have the state EELEMENT_STATE_QUERY (4), but when the check happens in CExpressionEvaluate::EvaluateExpression(), it has EELEMENT_STATE_NOT_FIRED (0).

And finally, if one hacks around this problem as well and finally gets to the call of CCreatureTrigger::bEvaluateNow(), it will cause the game to crash. The function searches for the dino entities in the word data, but the query fails for all three dinos. Because there is no nullptr check for the search result, but merely an Assert, this will cause a crash.

Question to resolve:

  • Are self-referential query FireExpressions, as required here, possible in T-Script?
  • Why does the auto-insert snippet above not work? Why does the state get lost/changed?
  • How can CCreatureTrigger::bEvaluateNow() be repaired? How are the dinosaurs and their state supposed to be queried here?
    • The solution must also be serializable (pcSave and pcLoad). That means if the player creates a savefile with one or two of the dinos already dead, then loads that save, the trigger must still work when the rest of the dinos die.
    • The above still holds when an alternative solution without FireExpressions is implemented.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant