fa icon indicating copy to clipboard operation
fa copied to clipboard

Refactor Scenario Framework part 1

Open Hdt80bro opened this issue 2 years ago • 12 comments

Covers [a bit more than its fair share of] the first third of annotating the scenario framework. Incidentally, these functions are basically pulled from scenariotriggers.lua, so I also ended up annotating those copied functions as well. And when I say "annotate" I kinda mean "refactor"--but don't worry, its mostly just variable renaming. This one definitely became larger than I thought it was going to be, even breaking it into chunks... I'll reevaluate my methods.

Hdt80bro avatar Jul 20 '22 10:07 Hdt80bro

@speed2CZ could you find the time to look over these changes too?

Garanas avatar Jul 20 '22 11:07 Garanas

The IDE is really good about letting you about problems with annotations--are you talking about making sure I renamed parameters correctly or the small logical equivalences I did?

Hdt80bro avatar Jul 20 '22 14:07 Hdt80bro

The logic changes, it needs debugging. Ideally to test it on couple of missions.

speed2CZ avatar Jul 20 '22 15:07 speed2CZ

Hhm, ~~FAF is currently completely broken as to anything to do with the campaign, so it can't be properly tested~~ I have recently been informed about the fa-coop project. I've summarized the kinds of logical changes here if you'd like to review them manually. Would you prefer that I revert them instead?

- function PlatoonMoveRoute(platoon, route, squad)
-     for _, v in route do
-         if type(v) == 'string' then
-             if squad then
-                 platoon:MoveToLocation(ScenarioUtils.MarkerToPosition(v), false, squad)
-             else
-                 platoon:MoveToLocation(ScenarioUtils.MarkerToPosition(v), false)
-             end
-         else
-             if squad then
-                 platoon:MoveToLocation(v, false, squad)
-             else
-                 platoon:MoveToLocation(v, false)
-             end
-         end
-     end
- end
+ function PlatoonMoveRoute(platoon, route, squad)
+     for _, node in route do
+         if type(node) == 'string' then
+             node = ScenarioUtils.MarkerToPosition(node)
+         end
+         if squad then
+             platoon:MoveToLocation(v, false, squad)
+         else
+             platoon:MoveToLocation(v, false)
+         end
+     end
+ end

- function GroupProgressTimerThread(group, time)
-     ...
-     v:SetWorkProgress(currTime/time)
-     ...
- end
+ function GroupProgressTimerThread(units, time)
+     ...
+     local prog = currTime / time
+     ...
+     unit:SetWorkProgress(prog)
+     ...
+ end

- function Dialogue(dialogueTable, callback, critical, speaker)
-     local canSpeak = true
-     if speaker and speaker.Dead then
-         canSpeak = false
-     end
- 
-     if canSpeak then
-         ...
-     end
- end
+ function Dialogue(dialogueTable, callback, critical, speaker)
+     if not (speaker and speaker.Dead) then
+         ...
+     end
+ end

- SetupMFDSync(movieTable, text)
-     ...
-     local timeSecs = GetGameTimeSeconds()
-     tempData.time = string.format("%02d:%02d:%02d", math.floor(timeSecs/360), math.floor(timeSecs/60), math.mod(timeSecs, 60))
-     tempData.color = 'ffffffff'
-     if movieTable[4] == 'UEF' then
-         ...
-     end
-     ...
- end
+ SetupMFDSync(movieTable, text)
+     ...
+     local time = GetGameTimeSeconds()
+     local hours = math.floor(time / 3600)
+     local minutes = math.mod(time, math.floor(time / 60), 60)
+     local seconds = math.mod(time, 60)
+     tempData.time = string.format("%02d:%02d:%02d", hours, minutes, seconds)
+     if movieTable[4] == 'UEF' then
+         ...
+     else
+         tempData.color = 'ffffffff'
+     end
+     ...
+ end

*variable storage changes not included
- function PlayDialogue()
-     ...
-     if v.text and not v.vid then
-         if not v.vid then
-             DisplayMissionText(v.text)
-         end
-     end
-     ...
-     local vidText = ''
-     if v.text then
-         vidText = v.text
-     end
-     ...
-     SetupMFDSync(movieData, vidText)
-     ...
- end
+ function PlayDialogue()
+     ...
+     if text and not vid then
+         DisplayMissionText(text)
+     end
+     ...
+     text = text or ""
+     ...
+     SetupMFDSync(movieData, text)
+     ...
+ end

- function AreaTriggerThread(callbackFunction, rectangleTable, category, onceOnly, invert, aiBrain, number, requireBuilt, name)
-     ...
-     for _, v in rectangleTable do
-         table.insert(recTable, ...)
-     end
- 
-     ...
-     for _, v in recTable do
-         ...
-         totalEntities[table.getn(totalEntities) + 1] = ve
-         ...
-     end
-     ...
-     local numEntities = table.getn(totalEntities)
-     if numEntities > 0 then
-     ...
-     if number and ((amount >= number and not invert) or (amount < number and invert)) then
-     ...
-     if (triggered and not invert and not number) or (not triggered and invert and not number) or (triggered and number) then
-     ...
- end
+ function AreaTriggerThread(callback, rectangles, category, onceOnly, invert, aiBrain, unitCount, requireBuilt, name)
+     ...
+     for i, rect in rectangles do
+         recTable[i] = ...
+     end
+ 
+     ...
+     local totalEntityCount = 0
+     for _, rect in recTable do
+         ...
+         totalEntityCount = totalEntityCount + 1
+         totalEntities[totalEntityCount] = entity
+         ...
+     end
+     ...
+     if totalEntityCount > 0 then
+     ...
+     if unitCount and ((amount >= unitCount) ~= invert) then
+     ...
+     if (not unitCount and (triggered ~= invert)) or (triggered and unitCount) then
+     ...
+ end

- function ThreatTriggerAroundUnitThread(callbackFunction, aiBrain, unit, rings, onceOnly, value, greater, name)
-     ...
-     if greater and threat >= value then
-         -- stuff
-     elseif not greater and threat <= value then
-         -- same stuff
-     end
-     ...
- end
+ function ThreatTriggerAroundUnitThread(callback, aiBrain, unit, rings, onceOnly, value, greater, name)
+     ...
+     if (greater and threat >= value) or (not greater and threat <= value) then
+         -- that stuff
+     end
+     ...
+ end

- function TimerTriggerThread(callbackFunction, seconds, name, displayBool, onTickFunc)
-     ...
-     local ticking = true
-     local targetTime = math.floor(GetGameTimeSeconds()) + seconds
- 
-     while ticking do
-         onTickFunc(targetTime - math.floor(GetGameTimeSeconds()))
- 
-         if targetTime - math.floor(GetGameTimeSeconds()) < 0 then
-             ticking = false
-         end
- 
-         WaitSeconds(1)
-     end
-     ...
- end
+ function TimerTriggerThread(callback, seconds, name, display, onTickSecond)
+     ...
+     local targetTime = math.floor(GetGameTimeSeconds()) + seconds
+     onTickSecond(seconds)
+ 
+     while true do
+         WaitSeconds(1)
+         local time = targetTime - math.floor(GetGameTimeSeconds())
+         onTickSecond(time)
+         if time < 0 then
+             break
+         end
+     end
+     ...
+ end

- function CreateArmyStatTrigger(callbackFunction, aiBrain, name, triggerTable)
-     ...
-     if string.find (triggerData.StatType, "Economy_") then
-         aiBrain:GetArmyStat(triggerData.StatType, 0.0)
-     else
-         aiBrain:GetArmyStat(triggerData.StatType, 0)
-     end
-     ...
- end
+ function CreateArmyStatTrigger(callbackFunction, aiBrain, name, triggerTable)
+     ...
+     aiBrain:GetArmyStat(trigger.StatType, 0)
+     ...
+ end

- function UnitToPositionDistanceTriggerThread(cb, unit, marker, distance, name)
-     ...
-     local fired = false
-     while not fired do
-         ...
-         fired = true
-         if name then
-             cb(TriggerManager, name, unit)
-             return
-         else
-             cb(unit)
-             return
-         end
-         ...
-     end
- end
+ function UnitToPositionDistanceTriggerThread(callback, unit, marker, distance, name)
+     ...
+     while true do
+         ...
+         if name then
+             callback(TriggerManager, name, unit)
+         else
+             callback(unit)
+         end
+         return
+     end
+ end

- function CreateUnitCapturedTrigger(cbOldUnit, cbNewUnit, unit)
-     if cbOldUnit then
-         unit:AddUnitCallback(cbOldUnit, 'OnCaptured')
-     end
-     if cbNewUnit then
-         unit:AddUnitCallback(cbNewUnit, 'OnCapturedNewUnit')
-     end
- end
+ function CreateUnitCapturedTrigger(cbOldUnit, cbNewUnit, unit)
+     unit:AddOnCapturedCallback(cbOldUnit, cbNewUnit)
+ end

- function VariableBoolCheckThread(cb, varName, value, name)
-     if value then
-         ...
-         cb(TriggerManager, name)
-     else
-         ...
-         cb(TriggerManager, name)
-     end
- end
+ function VariableBoolCheckThread(callback, varName, invert, name)
+     if invert then
+         ...
+     else
+         ...
+     end
+     callback(TriggerManager, name)
+ end

- function MissionNumberTriggerThread(cb, value, name)
-     ...
-     while not ScenarioInfo.VarTable['Mission Number'] == value do
-     ...
- end
+ function MissionNumberTriggerThread(callback, value, name)
+     ...
+     while ScenarioInfo.VarTable['Mission Number'] ~= value do
+     ...
+ end

- function CreateUnitGivenTrigger(cb, unit)
-     TriggerFile.CreateUnitGivenTrigger(cb, unit)
- end
+ CreateUnitGivenTrigger = TriggerFile.CreateUnitGivenTrigger

- function CreateThreatTriggerAroundUnit(callbackFunction, aiBrain, unit, rings, onceOnly, value, greater)
-     return ForkThread(ThreatTriggerAroundUnitThread, callbackFunction, aiBrain, unit, rings, onceOnly, value, greater)
- end
+ function CreateThreatTriggerAroundUnit(callbackFunction, aiBrain, unit, rings, onceOnly, value, greater, name)
+     return ForkThread(ThreatTriggerAroundUnitThread, callbackFunction, aiBrain, unit, rings, onceOnly, value, greater, name)
+ end

- function CreateTimerTrigger(cb, seconds, displayBool)
-     timerThread = TriggerFile.CreateTimerTrigger(cb, seconds, displayBool)
-     return timerThread
- end
+ function CreateTimerTrigger(callback, seconds, name, display, onTickSecond)
+     timerThread = TriggerFile.CreateTimerTrigger(callback, seconds, name, display, onTickSecond)
+     return timerThread
+ end

The only API "breaking" changes are the last three

  • ScenarioFramework.lua no longer directly calls scenariotriggers.lua functions, so changing functions in scenariotrigger.lua instead of ScenarioFramework.lua won't update them
  • adding support for the previously unused name parameter in all of the trigger functions means that any calls to these that derive their last argument from unadjusted multiple-return function calls will result in the callback function being called using the triggermanager + trailing name argument version
  • fixing the parameters in CreateTimerTrigger might mean that mods that, for some bizzare reason, rely on it being wrong need to be updated

Hdt80bro avatar Jul 21 '22 19:07 Hdt80bro

Alright, I've done some testing and ~~none of the errors are mine~~ the coop branch is a lot more finicky than I thought and there are lots of errors

Hdt80bro avatar Jul 21 '22 23:07 Hdt80bro

Can you copy some of the errors you encountered?

Garanas avatar Jul 22 '22 06:07 Garanas

Oooh, rats, I already moved back to fafdevelop. I can test a campaign map again the morning if you'd like.

Hdt80bro avatar Jul 22 '22 06:07 Hdt80bro

Sorry about all that @speed2CZ , I was still figuring out how to use the campaign branch. Everything's good now!

Hdt80bro avatar Jul 23 '22 00:07 Hdt80bro

Looks like all the reviews are resolved and this has become inactive--I'll merge soon.

Hdt80bro avatar Aug 03 '22 17:08 Hdt80bro

Hold up - allow me to run it over one more time tonight 😄

Garanas avatar Aug 04 '22 07:08 Garanas

@Garanas How'd it go?

Hdt80bro avatar Aug 18 '22 23:08 Hdt80bro

Lets merge it after the release is stable

Garanas avatar Aug 19 '22 09:08 Garanas