diff --git a/Moose Development/Moose/Core/Condition.lua b/Moose Development/Moose/Core/Condition.lua index 8d9824a72..80f80cf52 100644 --- a/Moose Development/Moose/Core/Condition.lua +++ b/Moose Development/Moose/Core/Condition.lua @@ -23,6 +23,7 @@ -- @type CONDITION -- @field #string ClassName Name of the class. -- @field #string lid Class id string for output to DCS log file. +-- @field #string name Name of the condition. -- @field #boolean isAny General functions are evaluated as any condition. -- @field #boolean negateResult Negeate result of evaluation. -- @field #table functionsGen General condition functions. @@ -55,7 +56,7 @@ CONDITION = { --- CONDITION class version. -- @field #string version -CONDITION.version="0.1.0" +CONDITION.version="0.2.0" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO list @@ -206,6 +207,10 @@ function CONDITION:Evaluate(AnyTrue) return result end +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Private Functions +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + --- Check if all given condition are true. -- @param #CONDITION self -- @param #table functions Functions to evaluate. @@ -290,6 +295,71 @@ function CONDITION:_CreateCondition(Function, ...) return condition end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Global Condition Functions +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Condition to check if time is greater than a given threshold time. +-- @param #number Time Time in seconds. +-- @param #boolean Absolute If `true`, abs. mission time from `timer.getAbsTime()` is checked. Default is relative mission time from `timer.getTime()`. +-- @return #boolean Returns `true` if time is greater than give the time. +function CONDITION.IsTimeGreater(Time, Absolute) + + local Tnow=nil + + if Absolute then + Tnow=timer.getAbsTime() + else + Tnow=timer.getTime() + end + + if Tnow>Time then + return true + else + return false + end + + return nil +end + +--- Function that returns `true` (success) with a certain probability. For example, if you specify `Probability=80` there is an 80% chance that `true` is returned. +-- Technically, a random number between 0 and 100 is created. If the given success probability is less then this number, `true` is returned. +-- @param #number Probability Success probability in percent. Default 50 %. +-- @return #boolean Returns `true` for success and `false` otherwise. +function CONDITION.IsRandomSuccess(Probability) + + Probability=Probability or 50 + + -- Create some randomness. + math.random() + math.random() + math.random() + + -- Number between 0 and 100. + local N=math.random()*100 + + if N%s"), Phase.status, Status) + + -- Debug message. + self:T(self.lid..string.format("Phase %s status: %s-->%s", tostring(Phase.name), tostring(Phase.status), tostring(Status))) + + -- Set status. Phase.status=Status + + -- Set time stamp when phase becase active. + if Phase.status==OPERATION.PhaseStatus.ACTIVE then + Phase.Tstart=timer.getAbsTime() + env.info("FF Setting phase start time stamp") + elseif Phase.status==OPERATION.PhaseStatus.OVER then + -- Trigger PhaseOver event. + self:PhaseOver(Phase) + end + end + return self end @@ -461,7 +495,7 @@ end -- @return #OPERATION self function OPERATION:SetPhaseConditonOver(Phase, Condition) if Phase then - self:T(self.lid..string.format("Setting phase %s conditon over %s"), Phase.name, Condition and Condition.name or "None") + self:T(self.lid..string.format("Setting phase %s conditon over %s", self:GetPhaseName(Phase), Condition and Condition.name or "None")) Phase.conditionOver=Condition end return self @@ -502,19 +536,6 @@ function OPERATION:GetPhaseConditonOver(Phase, Condition) return Phase.conditionOver end ---- Get currrently active phase. --- @param #OPERATION self --- @param #OPERATION.Phase Phase The phase. --- @param #string Status New status, e.g. `OPERATION.PhaseStatus.OVER`. --- @return #OPERATION self -function OPERATION:SetPhaseStatus(Phase, Status) - if Phase then - self:T(self.lid..string.format("Phase \"%s\" status: %s-->%s", Phase.name, Phase.status, Status)) - Phase.status=Status - end - return self -end - --- Get currrently active phase. -- @param #OPERATION self -- @return #OPERATION.Phase Current phase or `nil` if no current phase is active. @@ -657,6 +678,13 @@ function OPERATION:AddBranch(Name) return branch end +--- Get the master branch. This is the default branch and should always exist (if it was not explicitly deleted). +-- @param #OPERATION self +-- @return #OPERATION.Branch The master branch. +function OPERATION:GetBranchMaster() + return self.branchMaster +end + --- Get the currently active branch. -- @param #OPERATION self -- @return #OPERATION.Branch The active branch. If no branch is active, the master branch is returned. @@ -678,19 +706,21 @@ end --- Add an edge between two branches. -- @param #OPERATION self --- @param #OPERATION.Branch BranchTo The branch *to* which to switch. --- @param #OPERATION.Phase PhaseAfter The phase of the *from* branch *after* which to switch. --- @param #OPERATION.Phase PhaseNext The phase of the *to* branch *to* which to switch. +-- @param #OPERATION.Phase PhaseFrom The phase of the *from* branch *after* which to switch. +-- @param #OPERATION.Phase PhaseTo The phase of the *to* branch *to* which to switch. -- @param Core.Condition#CONDITION ConditionSwitch (Optional) Condition(s) when to switch the branches. -- @return #OPERATION.Branch Branch table object. -function OPERATION:AddEdge(BranchTo, PhaseAfter, PhaseNext, ConditionSwitch) +function OPERATION:AddEdge(PhaseFrom, PhaseTo, ConditionSwitch) local edge={} --#OPERATION.Edge - edge.branchFrom=PhaseAfter and PhaseAfter.branch or self.branchMaster - edge.phaseFrom=PhaseAfter - edge.branchTo=BranchTo - edge.phaseTo=PhaseNext + + edge.phaseFrom=PhaseFrom + edge.phaseTo=PhaseTo + + edge.branchFrom=PhaseFrom.branch + edge.branchTo=PhaseTo.branch + edge.conditionSwitch=ConditionSwitch or CONDITION:New("Edge") table.insert(edge.branchFrom.edges, edge) @@ -896,6 +926,39 @@ function OPERATION:IsStopped() return is end +--- Check if phase is in status "Active". +-- @param #OPERATION self +-- @param #OPERATION.Phase Phase The phase. +-- @return #boolean If `true`, phase is active. +function OPERATION:IsPhaseActive(Phase) + if Phase and Phase.status and Phase.status==OPERATION.PhaseStatus.ACTIVE then + return true + end + return false +end + +--- Check if phase is in status "Planned". +-- @param #OPERATION self +-- @param #OPERATION.Phase Phase The phase. +-- @return #boolean If `true`, phase is Planned. +function OPERATION:IsPhasePlanned(Phase) + if Phase and Phase.status and Phase.status==OPERATION.PhaseStatus.PLANNED then + return true + end + return false +end + +--- Check if phase is in status "Over". +-- @param #OPERATION self +-- @param #OPERATION.Phase Phase The phase. +-- @return #boolean If `true`, phase is over. +function OPERATION:IsPhaseOver(Phase) + if Phase and Phase.status and Phase.status==OPERATION.PhaseStatus.OVER then + return true + end + return false +end + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Status Update @@ -1026,7 +1089,9 @@ function OPERATION:onafterPhaseChange(From, Event, To, Phase) -- Previous phase (if any). local oldphase="None" if self.phase then - self:SetPhaseStatus(self.phase, OPERATION.PhaseStatus.OVER) + if self.phase.status~=OPERATION.PhaseStatus.OVER then + self:SetPhaseStatus(self.phase, OPERATION.PhaseStatus.OVER) + end oldphase=self.phase.name end @@ -1048,7 +1113,8 @@ end -- @param #string Event Event. -- @param #string To To state. -- @param #OPERATION.Branch Branch The new branch. -function OPERATION:onafterBranchSwitch(From, Event, To, Branch) +-- @param #OPERATION.Phase Phase The phase. +function OPERATION:onafterBranchSwitch(From, Event, To, Branch, Phase) -- Debug info. self:T(self.lid..string.format("Switching to branch %s", Branch.name)) @@ -1056,6 +1122,9 @@ function OPERATION:onafterBranchSwitch(From, Event, To, Branch) -- Set active branch. self.branchActive=Branch + -- Change phase. + self:PhaseChange(Phase) + return self end @@ -1064,7 +1133,6 @@ end -- @param #string From From state. -- @param #string Event Event. -- @param #string To To state. --- @param #OPERATION.Phase Phase The new phase. function OPERATION:onafterOver(From, Event, To) -- Debug message. @@ -1078,7 +1146,9 @@ function OPERATION:onafterOver(From, Event, To) local branch=_branch --#OPERATION.Branch for _,_phase in pairs(branch.phases) do local phase=_phase --#OPERATION.Phase - self:SetPhaseStatus(phase, OPERATION.PhaseStatus.OVER) + if not self:IsPhaseOver(phase) then + self:SetPhaseStatus(phase, OPERATION.PhaseStatus.OVER) + end end end @@ -1099,6 +1169,13 @@ function OPERATION:_CheckPhases() -- Check if active phase is over if conditon over is defined. if phase and phase.conditionOver then local isOver=phase.conditionOver:Evaluate() + + local Tnow=timer.getAbsTime() + + if phase.duration and phase.Tstart and Tnow-phase.Tstart>phase.duration then + isOver=true + end + if isOver then self:SetPhaseStatus(phase, OPERATION.PhaseStatus.OVER) end @@ -1117,21 +1194,35 @@ function OPERATION:_CheckPhases() if switch then - -- Switch to new branch. - self:BranchSwitch(edge.branchTo) + -- Get next phase of the branch + local phaseTo=edge.phaseTo or self:GetPhaseNext(edge.branchTo, nil) - -- If we want to switch to a specific phase of the branch. - if edge.phaseTo then - - -- Change phase. - self:PhaseChange(edge.phaseTo) + if phaseTo then + + -- Switch to new branch. + self:BranchSwitch(edge.branchTo, phaseTo) + + else + + self:Over() - -- Done here! - return end - -- Break the loop. - break + -- Done here! + return + +-- -- If we want to switch to a specific phase of the branch. +-- if edge.phaseTo then +-- +-- -- Change phase. +-- self:PhaseChange(edge.phaseTo) +-- +-- -- Done here! +-- return +-- end +-- +-- -- Break the loop. +-- break end end