Objectives: UI
This is the manager that displays all active objectives for the client. It is written in the exp language created by John Haggerty.
Exp Cheatsheet:
- aslongas - keeps the current scope alive "as long as" the expression remains true
- whenever - Runs the following statement repeatedly, once each time the expression is true, ending the statement when it becomes false, and waiting for it to become true again when the statement ends
- meantime - Whenever may be paired with "meantime" to provide a statement that will be run when the expression is false
- thread - Exp "threads" are asynchronous function calls. They are akin to coroutines in some other languages: they take turns executing and so are not truly asynchronous.
- localthread - A localthread is a thread that is guaranteed to end when the scope it is defined in is exited. You can customize the scope it is attached to with the @ symbol.
- cleanup - After a cleanup block is passed during execution, the statement (or block of statements) after cleanup is guaranteed to run when the scope is exited.
// Currently only supports one mission at a time shared maywait fn APlayer::UIMissionThread() { // waits for a mission instance to be active watchobj< AMissionBase? > missionInstanceWatch = watchexpr GetMissionForUI() scope MissionLoop // defines a scope used by aslongas, endwhen, etc loop { const AMissionBase? mission = missionInstanceWatch.val watchobj< bool > shouldDisplayThisMission = watchexpr missionInstanceWatch.val == mission if ( !mission ) { waitwhile shouldDisplayThisMission continue } localthread @MissionLoop mission.WhileMissionActiveForPlayerHud( this ) // Play the intro animation for a mission UIMissionSequence_Intro( mission ) bool isFirstObjective = true watchobj< AObjectiveBase? > activeObjectiveWatch = watchexpr mission.GetActiveObjective() while ( shouldDisplayThisMission ) scope ObjectiveLoop { // gets the active objective, and can use exp magic to detect if it changes prematurely const AObjectiveBase? activeObjective = activeObjectiveWatch.val watchobj< bool > shouldDisplayThisObjective = watchexpr shouldDisplayThisMission && activeObjectiveWatch.val == activeObjective if ( !activeObjective ) { waitwhile shouldDisplayThisObjective continue } localthread @ObjectiveLoop activeObjective.WhileObjectiveActiveForPlayerHud( this ) // play the animations for introducing a new objective if ( isFirstObjective ) ObjectiveSequence_Intro( activeObjective ) else ObjectiveSequence_IntroAdditional( activeObjective ) isFirstObjective = false localthread { // update objective info while its active. ObjectiveSequence_Update( activeObjective ) loop { waitfor activeObjective.objectiveUpdated ObjectiveSequence_Update( activeObjective ) } } waitfor !shouldDisplayThisObjective // Update and Completed OnRep's come in on the same frame, out of order. So wait one frame to catch an update if its there. WaitFrame() if ( activeObjective.IsObjectiveCompleted() ) { waitfor !activeObjective.GetIsUpdatingInHud() ObjectiveSequence_Completed( activeObjective ) } } // outro for the mission if ( mission.IsMissionCompleted() ) UIMissionSequence_Completed( mission.IsMissionCompletedSuccessfully() ) } }