Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
races.as: Fixed and commented
races.addCancelPoint()
I've set out to thoroughly study the race system script by Neorej16. I would like to create an editor for it and make it multiplayer. Then I'd like to extend it with other game modes. First thing I noticed is that there's an extensible callback mechanism - modder can call `races.setCallback()` with callback type and function satisfying `funcdef void RACE_EVENT_CALLBACK(dictionary@);`. When invoked, the function gets all params as dictionary. The available callback types are nicely documented directly in the raceManager setup: ``` // we initialize the callbacks dictionary this.callbacks.set("RaceFinish", null); // when a race was finished this.callbacks.set("RaceCancel", null); // when a race was canceled by any means (race_abort box or forbidden user action) this.callbacks.set("RaceStart", null); // when a race starts this.callbacks.set("AdvanceLap", null); // when a lap is done, but not when the race is done this.callbacks.set("Checkpoint", null); // when a checkpoint is taken (excluding start and finish) this.callbacks.set("NewBestLap", null); // When a new best lap time is set this.callbacks.set("NewBestRace", null);// When a new best race time is set this.callbacks.set("LockedRace", null); // When the user passes the start line of a locked race this.callbacks.set("RaceEvent", null); // When the user passes the start line of a locked race this.callbacks.set("PenaltyEvent", null); // When the user gets in a race_penalty box, handled by the raceEvent method this.callbacks.set("AbortEvent", null); // When the user gets in a race_abort box, handled by the raceEvent method ``` As you can see, there can be only one common callback of every type, and the entry in `this.callbacks` is "type name => function pointer". That's enough though, as each checkpoint has instance name of scheme "checkpoint|$raceID|$sequenceNumber|$splitTrailNumber" (yes, the race system supports tracks with multi-checkpoint split sections!) and this went as parameter to the callback every time. However, there was one callback type other than the rest - cancel point callback. The entry in `this.callback` was "instance name => dictionary", where dictionary held all the info normally embedded in the instance name, and also field named "callback" with the actual function pointer. Apparently the programmer intended to support multiple cancel points, each with it's own callback. I don't understand why, as following the checkpoint mechanic would archieve the same, only instead of 2 functions you'd have one that decides what to do based on the arguments dictionary. Either way, there was a bug in the code: the `cancelPointCount` was never updated, so there could effectively be just one common callback, and it was still broken because as I already wrote it didn't encode info to instance name but kept it inside the `this.callbacks` dictionary. While deciding how to fix it, I noticed there are in total 3 (!) callbacks for race cancelling - the broken cancel points, "AbortEvent" and "RaceCancel". Apparently "RaceCancel" was invoked each time race was aborted for any reason. "AbortEvent", though, would only be invoked when driving through an event box called "race_abort". I fulltext-searched our resources if we have any .ODEF with such eventbox, and no we don't. So either map creators knew, or it went unused. Either way, "AbortEvent" was basically the same thing as the broken cancel points, except that it kept data in instance names like checkpoints do. So I ended up fixing the cancel points by actually redirecting them to "AbortEvent", only ignoring the box name. I'd hate to break Neorej16's code so I tested using modified Auriga Proving Grounds terrain (which uses one cancel point). I added a secondary cancel point and tested they're indeed broken as I thought. Then I tested again with my fix.
- Loading branch information