Remember if you are building this project for yourself and only using the downloaded project files as a reference SAVE FREQUENTLY! Also I strongly recommend that you back up any mission files you intend to work with before commencing this tutorial
NOTE:Some of the code from part 2 has been modified quite a bit for this lesson because in part 2 we were working with one particular mission file and knew exactly where to find particular lines of data in that particular file. In this lesson we are dealing with what ever mission file the user may select and the data we will be working with in the editor could reside in a variety of different locations within the mission file.
This lesson also assumes that you have read and understood the logic and principles explained in lesson 2 and therefore the depth and volume of the comments within the accompanying VB project files have been reduced.
****************************************
Ok, lets start with the objects we will be using for the interface, firstly below is a screen shot of the compiled working editor for this lesson and directly below that is a screen shot from inside the Visual Basic 6 interface showing the objects at design time.
Compiled working editor.
Editor in design mode inside the VB6 interface.
Ok then, lets look at all the controls, their names and important property values:
NOTE: Below is not code. It shows all objects on the form indented to show relationships.
- Code: Select all
Frame object:
Name: “fraEnviron”
Caption: “Environment”
> Objects placed within the “fraEnviron” frame:
Label Object
Name: “lblHour”
Caption: “Hour”
Text Box Control
Name: “txtHour”
MaxLength: 2
Label Object
Name: “lblMins”
Caption: “Mins”
Text Box Control
Name: “txtMins”
MaxLength: 2
Label Object
Name: “lblWeather”
Caption: “Weather”
Combo Box Control
Name: “cboWeather”
Style: 2 Dropdown List
Label Object
Name: “lblCloud”
Caption: “Cloud”
Combo Box Control
Name: “cboCloud”
Style: 2 - Dropdown List
[i]End of frame associated objects[/i]
Label Object
Name: lblSelGrp
Alignment: Center
Font: Bold: Size 14
Frame object:
Name: “fraFlightGrpOpts”
Caption: “Flight Group Settings”
> Objects placed within the “fraFlightGrpOpts” frame:
Label Object
Name: “lblFlightGrps”
Caption: “Flight Groups”
List Box Control
Name: “lstFlightGrps”
Label Object
Name: “lblPlaneQty”
Caption: “Plane Quantity”
Combo Box Control
Name: “cboPlaneQty”
Style: 2 - Dropdown List
Label Object
Name: “lblFuel”
Caption: “Fuel”
Combo Box Control
Name: “cboFuel”
Style: 0 - Dropdown Combo
Label Object
Name: “lblPlane”
Caption: “Plane Choice”
SSTab Control
Name: “TabPlanes”
Tab 0 Caption: “Flyable”
Tab 1 Caption: “Non-Flyable”
Tabs: 2
TabsPerRow: 2
Inside Tab 0:
Combo Box Control
Name: “cboPlaneFly”
Style: 0 - Dropdown Combo
Inside Tab 1:
Combo Box Control
Name: “cboPlaneNonFly”
Style: 0 - Dropdown Combo
[i]End of SSTab associated objects[/i]
Command Button Control
Name: “btnApplyChange”
Caption: “Apply Changes To Group”
Command Button Control
Name: “btnFlyInGrp”
Caption: “Fly In This Group”
Frame object:
Name: “fraWaypoints”
Caption: “Waypoint Settings”
> Objects placed within the “fraFlightGrpOpts” frame:
Label Object
Name: “lblWayPoints”
Caption: “Waypoints”
List Box Control
Name: “lstWayPoints”
Label Object
Name: “lblAltitude”
Caption: “Altitude”
Text Box Control
Name: “txtAltitude”
MaxLength: 5
Label Object
Name: “lblSpeed”
Caption: “Speed”
Text Box Control
Name: “txtSpeed”
MaxLength: 3
Command Button Control
Name: “btnApply”
Caption: “Apply”
[i]End of frame “fraWaypoints” associated objects[/i]
[i]End of frame ”fraFlightGrpOpts” associated objects[/i]
Command Button Control
Name: “btnUpdate”
Caption: “Update Mission File”
Command Button Control
Name: “btnExit”
Caption: “Exit”
Common Dialog Control
CancelError: “True”
DialogTitle: “Select Mission File”
Caption: “Exit”
Filter: “IL-2 Mission File (*.mis)|*.mis”
List Box Control
Name: “lstMisFile”
It is good to keep the “lstMisFile” list box control visible when coding because it helps with error checking and seeing how the code is running. Once everything is working as you would like set the visible property to” false” and hide it off the visible form.
Arrange the controls as closely as you can to that shown in the screen shot “Editor in design mode inside the VB6 interface”.
Now add a module to the project and name it “PubFuncs”. This where we will store all the new user defined functions required for this project and save it into the project directory. (It would be easier just to use the module provided with the project files in the download)
Add a menu control to the main form with the following properties:
Name: “mnuFile”
Caption: “&File”
Then add sub menus’s:
Name: “mnuEdit”
Caption: “Edit Mission File...”
Name: “mnuSeparator”
Caption: “-”
Name: “mnuExit”
Caption: “Exit”
See screen shot below:
Ok it’s time to start looking at the code itself, we’ll start with the “Form_Initialize” of the main form and then work our way through the rest in sequence as closely as possible.
- Code: Select all
Private Sub Form_Initialize()
Call PopFlyPlaneType
Call PopNonFlyPlaneType
Call PopPlaneQty
Call PopFuel
Call PopWeather
Call PopCloud
lblSelGrp.Visible = False
MisFileName = ""
Dialog1.InitDir = "C:\Program Files\Ubi Soft\IL-2 Sturmovik Forgotten Battles\Missions"
End Sub
Right then, all the “Call Pop…….” Lines are simply populating the combo box controls ready for first time use. This we covered in lesson 2.
lblSelGrp.Visible = False
This simply suppresses visibility of the label control until data has been read in from the mission file.
Dialog1.InitDir = "C:\Program Files\Ubi Soft\IL-2 Sturmovik Forgotten Battles\Missions"
This is the default directory the common dialog control will start with so set it to a value relevant to your system. This saves the user having to navigate all over the system to get to the relevant directory.
NOTE:In a fully functional editor this would most likely be set by a variable read in from an “ini” file or something similar. For the sake of keeping it simple for this lesson we will hard code it.
Next lets look at the “mnuEdit_Click” click event. This is where the user opens the common dialog to select the desired mission file.
- Code: Select all
Private Sub mnuEdit_Click()
On Error GoTo ExitTheSub:
Dialog1.ShowOpen
MisFileName = Dialog1.FileName
Call OpenMisFile
ExitTheSub:
End Sub
On Error GoTo ExitTheSub:
If an error occurs during this procedure skip to the portion of the procedure headed ExitTheSub: and continue from that point in the code. Because we have set the common dialog controls “CancelError” property to equal “True”, if the user presses the escape key or presses the cancel button when the dialog control is active, the dialog control will cause an error and this will then cause the code to skip to the “ExitTheSub:” portion of the code which as you can see has no code after it. So the result is if the user cancels the dialog box the “Edit Mission File…” command exits quietly and seemingly without error.
Dialog1.ShowOpen
This line of code will invoke the visibility of the common dialog control. It will open at the location specified by the “InitDir” property as set earlier.
- Code: Select all
If Not Trim(MisFileName) = "" Then
btnUpdate.Enabled = True
btnApplyChange.Enabled = True
End If
If the Dialog1 control has returned a valid name enable the mission update and apply changes buttons.
Call OpenMisFile
Activate the user defined procedure “OpenMisFile”.
Now that the OpenMisFile procedure has been called lets examine that code.
We will only look at the code that has not been examined in lesson 2.
- Code: Select all
Public Sub OpenMisFile()
Dim FileData As String, MisTime As String
Dim MisWeather As String, MisCldHeight As String
Dim LoopCount As Integer
Dim MakeGroupList As Boolean
Dim FileIDNum As Integer
btnFlyInGrp.Enabled = False
PlyrGrp = ""
LoopCount = 1
FileIDNum = FreeFile()
On Error GoTo ErrorMessage:
Open MisFileName For Input As #FileIDNum
Do
Line Input #FileIDNum, FileData
If LoopCount = 3 Then
MisTime = Trim(FileData)
MisTime = Right(MisTime, Len(MisTime) - InStr(MisTime, " "))
Call SortTimeIn(MisTime)
End If
If LoopCount = 4 Then
MisWeather = Trim(FileData)
MisWeather = Right(MisWeather, Len(MisWeather) - InStr(MisWeather, " "))
cboWeather.ListIndex = Val(MisWeather)
End If
If LoopCount = 5 Then
MisCldHeight = Trim(FileData)
MisCldHeight = Right(MisCldHeight, Len(MisCldHeight) - InStr(MisCldHeight, " "))
cboCloud.ListIndex = GetCloudIndex(MisCldHeight)
End If
If UCase(Left(FileData, 9)) = " PLAYER " Then
PlyrGrp = Right(Trim(FileData), Len(Trim(FileData)) - InStr(Trim(FileData), " "))
PlyGrpIndex = LoopCount
End If
If FileData = "[Wing]" Then
MakeGroupList = True
End If
If MakeGroupList And Not FileData = "[Wing]" Then
If Not Left(FileData, 1) = "[" Then
lstFlightGrps.AddItem Trim(FileData)
Else
MakeGroupList = False
End If
End If
lstMisFile.AddItem FileData
LoopCount = LoopCount + 1
Loop Until EOF(FileIDNum)
Close #FileIDNum
lstFlightGrps.ListIndex = 0
Exit Sub
ErrorMessage:
MsgBox "An error has been encountered reading the mission file." + Chr(13) _
+ "The editor may not function correctly!", vbCritical + vbOKOnly, "Error Reading Mission File."
End Sub
PlyrGrp = ""
PlyrGrp is a public string variable declared in the “frmMisEditor” code used to store the current player flight group code. This is important and makes it easy to track which group the play belongs to. This codes initialises it for use with a new mission file.
FileIDNum = FreeFile()
FileIDNum is an integer variable that is used to store the file ID tag returned from the “FreeFile()” function. This indicates the next available file number from the system to be used with the file “Open” statement. In the last lesson we used the integer “#1” as a file ID tag because of the simplicity of the editor at that stage. It is standard practise to use the “FreeFile()” function when coding programmes that will be dealing with a multitude of files.
On Error GoTo ErrorMessage:
Because we will be dealing with a multitude of different mission files and those files are open text files, we cannot guarantee the integrity of each file, therefore we must safe guard against invalid data or invalid data placement within the file. So if the programme reads a bad file it won’t crash but rather display an error message to the user stating that there has been an error and that the programme may not function correctly.
Call SortTimeIn(MisTime)
Call the user defined procedure “SortTimeIn” with data contained within the variable “MisTime” as an argument.
Lets look more closely at the “SortTimeIn” prodedure.
- Code: Select all
Public Sub SortTimeIn(TimeVal As String)
Dim Hr As String, Mins As String
Hr = Left(TimeVal, InStr(TimeVal, ".") - 1)
Mins = Right(TimeVal, Len(TimeVal) - (InStr(TimeVal, ".") - 1))
Mins = CStr(Round(60 * Mins))
Mins = Left(Mins, 2)
If Len(Mins) = 1 Then
Mins = "0" + Mins
End If
txtHour = Hr
txtMins = Mins
End Sub
Mins = CStr(Round(60 * Mins))
The “Mins” variable holds a decimal percentage value that the mission file uses for minutes past the hour. So if the mission started 45 minutes past the given hour the variable “Mins” would contain .733334 minutes of and hour (60 minutes).
So 60 * . 733334 would equal 44.00004. Then round that value and it becomes 44. Finally convert it to a string value to be passed to the string variable “Mins”
- Code: Select all
If Len(Mins) = 1 Then
Mins = "0" + Mins
End If
If the minute value is less than 10 maintain a 2 digit value by placing a zero in front of it.
cboWeather.ListIndex = Val(MisWeather)
The weather value is simply a integer value that can be passed directly as the combo box “ListIndex” value.
cboCloud.ListIndex = GetCloudIndex(MisCldHeight)
“GetCloudIndex” is a user defined function that returns a “ListIndex” value based on the cloud height passed as an argument. So for example if the cloud height was “1000.0” then the function would return a value of 5 which is the “ListIndex” that contains the value “1000.0” see below:
- Code: Select all
Public Function GetCloudIndex(CldHeight As String) As Integer
Select Case CldHeight
Case "500.0"
GetCloudIndex = 0
Case "600.0"
GetCloudIndex = 1
Case "700.0"
GetCloudIndex = 2
Case "800.0"
GetCloudIndex = 3
Case "900.0"
GetCloudIndex = 4
Case "1000.0"
GetCloudIndex = 5
Case "1100.0"
GetCloudIndex = 6
Case "1200.0"
GetCloudIndex = 7
Case "1300.0"
GetCloudIndex = 8
Case "1400.0"
GetCloudIndex = 9
Case "1500.0"
GetCloudIndex = 10
End Select
End Function
- Code: Select all
If UCase(Left(FileData, 9)) = " PLAYER " Then
PlyrGrp = Right(Trim(FileData), Len(Trim(FileData)) - InStr(Trim(FileData), " "))
If the 9 left characters converted all to upper case of the current line being read = “ PLAYER” then that is the line that contains the player group ID, so store that group ID for later use with the editor.
- Code: Select all
PlyGrpIndex = LoopCount
Store the position of the data that holds the player flight group ID so that we don’t have to search for it when editing. This logic is used in several places with the editor and removes the need to continually search from the top down for specific lines of data when the user is editing the mission.
- Code: Select all
End If
If FileData = "[Wing]" Then
MakeGroupList = True
End If
If the current line of data being read = “[Wing]” the lines that follow are the flight group ID codes for this mission, so set the Boolean variable “MakeGroupList” to true in preparation for the next cycle through the loop.
- Code: Select all
If MakeGroupList And Not FileData = "[Wing]" Then
If Not Left(FileData, 1) = "[" Then
lstFlightGrps.AddItem Trim(FileData)
Else
MakeGroupList = False
End If
End If
If the Boolean variable “MakeGroupList” is set to true then this means that the loop has already reached the line of data that heads the list of flight group ID codes, so providing that the loop is not still on the same line of data as “[Wing]” start adding the flight group ID codes to the lstFlightGrps list box control.
Exit Sub
If the mission file has opened without error exit the procedure because the following lines of code should only be processed if there is a need to display an error message to the user.
- Code: Select all
ErrorMessage:
MsgBox "An error has been encountered reading the mission file." + Chr(13) _
+ "The editor may not function correctly!", vbCritical + vbOKOnly, "Error Reading Mission File."
If an error occurred during the reading of the mission file display the error message to the user so that they have idea as to what has happened and that the editor may not function correctly.
That covers the code that handles the selecting and opening of the mission file, so now lets look at the code to handle the general use of the editor starting with the controls at the top left of the form and working our way down.
Setting the hour value
KeyPress event:
- Code: Select all
Private Sub txtHour_KeyPress(KeyAscii As Integer)
If Not NumericalOnly(KeyAscii) Then
KeyAscii = 0
End If
End Sub
This ensures that only numerical values may be entered into the text box. The “NumericalOnly” function is a user defined function that looks at each Ascii character as the user presses a key on the keyboard, if the character is not a numerical value it returns “False” otherwise it returns “True” and allows the entry to be made.
NumericalOnly function:
NOTE: Ascii Numerical values are between 48 and 57. 8 is the Backspace character and is of course required for editing entries in the text box control.
- Code: Select all
Public Function NumericalOnly(AsciiChr As Integer) As Boolean
If Not AsciiChr = 8 Then
If AsciiChr < 48 Or AsciiChr > 57 Then
NumericalOnly = False
Else
NumericalOnly = True
End If
Else
NumericalOnly = True
End If
End Function
KeyUp event:
- Code: Select all
Private Sub txtHour_KeyUp(KeyCode As Integer, Shift As Integer)
If Val(txtHour.Text) >= 24 Then
If Val(txtHour.Text) > 24 Then
txtHour.Text = "24"
End If
txtMins.Text = "00"
ElseIf Val(txtHour.Text) < 1 Then
txtHour.Text = "1"
End If
End Sub
After each successful entry of any character by the user we must examine the value in the text box to ensure that it falls inside the parameters of what constitutes a valid time value, this can only be done with the consideration of the value in the minutes text box also. For example, if the user currently has a mission start time of 22:50 hours in the editors hour and minutes text box controls, we must ensure that if the hour value is changed to 24 or higher that the editor does not accept a value that cannot be processed. So seeing that the user wishes to make an hour entry of 24 we must of change the minutes value to equal “00” otherwise the editor would try to process a time value of 24:50 hours which of course is invalid.
Setting the minute value
The principals for this are very similar to setting the hour values, so no more needs to be explained here.
Setting weather conditions
I believe that where ever possible the programmer should remove the need for the user to type in their choices. This is so because when ever the user types in a value there is a chance for a typing error and also it is generally slower and more undesirable for the user. The weather combo box control is the perfect situation to offer the user a predefined list of options without requiring any typing because the list is small and it guarantees a constant value back from the control in the form of the list index value. Example below:
Code using the cboWeather control in the “UpdateList” sub:
- Code: Select all
If i = 3 Then
lstMisFile.RemoveItem i
lstMisFile.AddItem " CloudType " + CStr(cboWeather.ListIndex), i
End If
Setting cloud height
This is similar to setting the weather conditions but uses the function “GetCloudHeight” to convert the list index value into a valid cloud height for the mission. Example below:
Code using the cboCloud control in the “UpdateList” sub:
- Code: Select all
If i = 4 Then
lstMisFile.RemoveItem i
lstMisFile.AddItem " CloudHeight " + GetCloudHeight(cboCloud.ListIndex), i
End If
The “GetCloudHeight” is essentially the reverse coding of the previously explained function “GetCloudIndex”.
Selecting Flight Groups
Selecting a flight group to edit is controlled from the “lstFlightGrps_Click” event. Lets look at the code below.
- Code: Select all
Private Sub lstFlightGrps_Click()
Dim CurPlane As String
If lstFlightGrps.List(lstFlightGrps.ListIndex) = PlyrGrp Then
lblSelGrp.Caption = "Player Group Selected"
btnFlyInGrp.Enabled = False
TabPlanes.TabEnabled(1) = False
Else
lblSelGrp.Caption = "AI Group Selected"
TabPlanes.TabEnabled(1) = True
If Not PlyrGrp = "" Then
btnFlyInGrp.Enabled = True
End If
End If
ActiveGrpIndex = GetGrpIndex(lstFlightGrps.Text)
ActiveGrpWayIndex = GetGrpWayIndex(lstFlightGrps.Text)
lblSelGrp.Visible = True
CurPlane = GetPlaneType(lstFlightGrps.Text)
If IsFlyAble(CurPlane) Then
TabPlanes.Tab = 0
cboPlaneFly.Text = CurPlane
Else
TabPlanes.Tab = 1
btnFlyInGrp.Enabled = False
cboPlaneNonFly.Text = CurPlane
End If
cboPlaneQty.Text = GetPlaneQty(lstFlightGrps.Text)
cboFuel.Text = GetFuel(lstFlightGrps.Text)
lstWayPoints.Clear
Call WaypointsList(lstFlightGrps.Text)
End Sub
If lstFlightGrps.List(lstFlightGrps.ListIndex) = PlyrGrp Then
Earlier in the “OpenMisFile” procedure we stored the player flight group code in the variable “PlyrGrp”, here we use that variable to identify when the user has selected the player flight group from the lstFlightGrps list box and then take appropriate actions.
lblSelGrp.Caption = "Player Group Selected"
btnFlyInGrp.Enabled = False
TabPlanes.TabEnabled(1) = False
With the player flight group identified, display to the user that the player flight group is selected by the “lblSelCrp.Caption” property.
Disable the “FlyInGrp” button because the user is already flying in that group.
Disbale the ability for the user to select a non flyable plane by disabling the non flyable plane list tab.
Argument continues…
- Code: Select all
Else
lblSelGrp.Caption = "AI Group Selected"
TabPlanes.TabEnabled(1) = True
If Not PlyrGrp = "" Then
btnFlyInGrp.Enabled = True
End If
End If
If the player flight group is not selected then indicate to the user that an AI flight group has been selected by the “lblSelCrp.Caption” property.
Enable the non flyable planes tab so that the user may make a selection from that list if desired.
If in fact a player flight group has been identified (we have not opened a co-op mission where there is no player group for example) , enable the “FlyInGrp” button so that the user may choose to fly in that group.
ActiveGrpIndex = GetGrpIndex(lstFlightGrps.Text)
ActiveGrpWayIndex = GetGrpWayIndex(lstFlightGrps.Text)
These two lines record into variables two key index points in the list of the currently selected flight group, so that if any modifications are made to that flight group the editor knows what position in the list to go to rather than having to start a search for it from the head of the list. This is done by two user defiend functions “GetGrpIndex” and “GetGrpWayIndex”. Lets take a quick look at the “GetGrpIndex” function.
- Code: Select all
Public Function GetGrpIndex(FltGrp As String) As Integer
Dim ListPos As Integer
Dim ListPos As Integer, PosFound As Integer
Dim StopLoop As Boolean
With frmMisEditor.lstMisFile
ListPos = 0
Do
If Not Trim(.List(ListPos)) = "" Then
If .List(ListPos) = "[" + FltGrp + "]" Then
PosFound = ListPos
StopLoop = True
End If
End If
ListPos = ListPos + 1
Loop Until StopLoop Or ListPos = .ListCount - 1
End With
GetGrpIndex = PosFound
End Function
The editor uses the logic that it is faster to locate and store two key positions on the click event for later use, than potentially having to make several search sequences through the list from the top down to find the appropriate line of data to edit for each of the different properties relating to each flight group.
In the code above when the search loop sequence finds the line that identifies the currently selected flight group it stores that list position in the variable “PosFound” using the current list position with the code “PosFound = ListPos” and then breaks from the loop and finally returns that position to the calling procedure with the code “GetGrpIndex = PosFound”. You will see a very similar principle used with the “GetGrpWayIndex” function also.
CurPlane = GetPlaneType(lstFlightGrps.Text)
Here we use the stored selected flight group list position to speed up the search sequence for finding the plane type that is assigned to the currently selected flight group by using the “ActiveGrpIndex” variable inside the user defined function “GetPlaneType”. Lets take a quick look at that function.
- Code: Select all
Public Function GetPlaneType(FltGrp As String) As String
Dim ListPos As Integer
Dim StopLoop As Boolean
Dim PlaneType As String
PlaneType = ""
With frmMisEditor.lstMisFile
ListPos = ActiveGrpIndex
Do
If Not Trim(.List(ListPos)) = "" Then
If UCase(Trim(.List(ListPos))) Like "CLASS AIR*" Then
PlaneType = Right(.List(ListPos), Len(.List(ListPos)) _
- InStr(.List(ListPos), "."))
StopLoop = True
End If
End If
ListPos = ListPos + 1
Loop Until StopLoop Or ListPos = .ListCount - 1
End With
If Not PlaneType = "" Then
GetPlaneType = PlaneType
Else
MsgBox "Unable to isolate plane type for flight group " + FltGrp, vbCritical + vbOKOnly, _
"Error Reading Plane Type"
End If
End Function
This is a similar function to the “GetGrpIndex” except you will notice that the search loop sequence begins at “ActiveGrpIndex” instead of zero with the code “ListPos = ActiveGrpIndex”. This greatly reduces search and locate times for specific lines of data particularly on the larger mission files. The reason for having two stored index positions is so if the user is editing properties such as plane type, plane quantity, fuel etc… the editor can use the “ActiveGrpIndex” variable where as if the user is editing waypoint altitude or waypoint speed speed the “ActiveGrpWayIndex” would be more efficient because all waypoint settings follow the index position recorded in that variable. See example below of how a portion of the mission file may look and how the two stored index variables “ActiveGrpIndex” and “ActiveGrpWayIndex” relate to positions in the mission list.
Excerpt from the TB-3 mission
- Code: Select all
[I_JG5_111] = ActiveGrpIndex
Planes 4
OnlyAI 1
Skill0 2
Skill1 1
Skill2 2
Skill3 0
skin0 Hannes_Trautloft(Winter).bmp
skin1 Hannes_Trautloft(Winter).bmp
skin2 Hannes_Trautloft(Winter).bmp
skin3 Hannes_Trautloft(Winter).bmp
Class air.BF_109F4
Fuel 100
weapons default
StartTime 9
[I_JG5_111_Way] = ActiveGrpWayIndex
TAKEOFF 109555.16 96361.84 0 0
NORMFLY 131275.41 106486.14 1500.00 350.00
NORMFLY 149132.28 106050.60 1500.00 400.00
NORMFLY 149241.17 98428.77 1500.00 400.00
NORMFLY 130479.47 98818.08 1500.00 400.00
NORMFLY 104256.82 94428.80 600.00 400.00
LANDING 108042.63 95956.47 0 0
[Stab_KGrzbV9a12]**** Start of new flight group properties
As you can see from above it is far more efficient to start a search sequence for waypoint properties from the “ActiveGrpWayIndex” index position than the “ActiveGrpIndex” position. The difference in this case would be 14 cycles of the loop! If we didn’t have these at all the editor would have to start each search sequence from the top of the list for each change the user may desire.
Now having the current plane type isolated for the current flight group we can display it to the user as shown in the code below.
- Code: Select all
If IsFlyable(CurPlane) Then
TabPlanes.Tab = 0
cboPlaneFly.Text = CurPlane
Else
TabPlanes.Tab = 1
btnFlyInGrp.Enabled = False
cboPlaneNonFly.Text = CurPlane
End If
If the current plane type is flyable activate the flyable planes list tab and set the list to display the current plane type to the user.
If the plane is not flyable activate the non flyable planes list tab and set the list to display the current plane type to the user.
“IsFlyable” is a user defined function that returns a Boolean indicating whether a particular plane code is flyable or not.
Call WaypointsList(lstFlightGrps.Text)
The “WaypointsList” procedure is another search and locate procedure. This is slightly different from the others in that it breaks down each waypoint found that belongs to the current flight group and adds the X and Y co-ordinate portion of them to the “lstWayPoints” list box control. We will take a closer look at this on the click event for this control.
Changing altitude and speed
Changing altitude and speed is initiated by the click event of the “lstWayPoints” list box control. The user selects which waypoint in the list they wish to edit and then change the values in the “txtAltitude” and “txtSpeed” text box controls.
- Code: Select all
Private Sub lstWayPoints_Click()
If Trim(lstWayPoints.Text) Like "LANDING*" Or Trim(lstWayPoints.Text) Like "TAKEOFF*" Then
txtAltitude.Enabled = False
txtSpeed.Enabled = False
Else
txtAltitude.Enabled = True
txtSpeed.Enabled = True
End If
Call GetWayAltSpd
End Sub
If Trim(lstWayPoints.Text) Like "LANDING*" Or Trim(lstWayPoints.Text) Like "TAKEOFF*" Then
This argument looks to see if a landing or takeoff waypoint is selected. If either landing or takeoff points are selected then the text box controls are disabled because there is no speed or altitude to edit otherwise enable them so that the user may edit the values.
Call GetWayAltSpd
The “GetWayAltSpd” prodecure is responsible for breaking down the selected waypoint data and offering the altitude and speed values to the user through the “txtAltitude” and “txtSpeed” text box controls.
- Code: Select all
Private Sub GetWayAltSpd()
Dim StopLoop As Boolean
Dim ListPos As Integer, i As Integer
Dim Alt As String, Spd As String
ListPos = ActiveGrpWayIndex + 1
Do
If InStr(lstMisFile.List(ListPos), lstWayPoints.Text) Then
WayEditIndex = ListPos
Alt = Trim(lstMisFile.List(ListPos))
For i = 1 To 3
Alt = Right(Alt, Len(Alt) - InStr(Alt, " "))
Next i
txtAltitude.Text = CInt(Left(Alt, InStr(Alt, " ") - 1))
Spd = Right(Alt, Len(Alt) - InStr(Alt, " "))
If InStr(Spd, " ") Then
WayTailData = Right(Spd, Len(Spd) - InStr(Spd, " "))
Else
WayTailData = ""
End If
If InStr(Spd, " ") Then
txtSpeed.Text = CInt(Left(Spd, InStr(Spd, " ") - 1))
Else
txtSpeed.Text = CInt(Spd)
End If
StopLoop = True
Exit Sub
End If
If Left(lstMisFile.List(ListPos), 1) = "[" Then
StopLoop = True
Else
ListPos = ListPos + 1
End If
Loop Until StopLoop
End Sub
ListPos = ActiveGrpWayIndex + 1
Again using the stored list index position “ActiveGrpWayIndex” for the position of the current flight groups waypoint data section of the mission file.
If InStr(lstMisFile.List(ListPos), lstWayPoints.Text) Then
This is saying if the current line of data in the mission file contains the data the user has selected in the “lstWayPoints” list control, then this is the line of data we want to work with.
The breaking down of the altitude and speed data from this line was explained in lesson 2 so we won’t go over that again.
- Code: Select all
If InStr(Spd, " ") Then
WayTailData = Right(Spd, Len(Spd) - InStr(Spd, " "))
Else
WayTailData = ""
End If
This code checks to see if there is any data after the speed data of the current line such as attack assignments for example, if there is that data is stored in the variable “WayTailData” so that when the editor reconstructs the waypoint line of data it can append this at the same time. If there is no data after the speed data then the variable “WayTailData” has a blank assignment so that when the line is reconstructed it appends a blank value.
Applying altitude and speed changes
Applying waypoint changes is done via the “btnApply” click event and call the procedure “UpdateWayAltSpd” as described below.
- Code: Select all
Private Sub UpdateWayAltSpd()
Dim StopLoop As Boolean
Dim ListPos As Integer, i As Integer
Dim Alt As String, Spd As String, NormFlyLine As String, ModLine As String
NormFlyLine = Trim(lstMisFile.List(WayEditIndex))
For i = 1 To 3
ModLine = ModLine + Left(NormFlyLine, InStr(NormFlyLine, " "))
NormFlyLine = Right(NormFlyLine, Len(NormFlyLine) - InStr(NormFlyLine, " "))
Next i
ModLine = " " + ModLine + txtAltitude.Text + " " + txtSpeed.Text + " " + Trim(WayTailData)
lstMisFile.RemoveItem WayEditIndex
lstMisFile.AddItem ModLine, WayEditIndex
End Sub
NormFlyLine = Trim(lstMisFile.List(WayEditIndex))
Store the original mission waypoint data in the variable “NormFlyLine”.
[/code]
For i = 1 To 3
ModLine = ModLine + Left(NormFlyLine, InStr(NormFlyLine, " "))
NormFlyLine = Right(NormFlyLine, Len(NormFlyLine) - InStr(NormFlyLine, " "))
Next i
[/code]
Separate the first part of the waypoint line of data from the mission file up to the altitude value and store that data in the variable “ModLine”. So if the original line of data read:
“NORMFLY 131275.41 106486.14 1500.00 350.00”
then “NormFlyLine” would hold the data “NORMFLY 131275.41 106486.14”
ModLine = " " + ModLine + txtAltitude.Text + " " + txtSpeed.Text + " " + Trim(WayTailData)
Construct the new modified waypoint line of data with the original waypoint co-ordinates plus the altitude and speed values from the “txtAltitude” and “txtSpeed” text box controls plus what ever data was found after the speed value originally with the “WayTailData” variable.
lstMisFile.RemoveItem WayEditIndex
lstMisFile.AddItem ModLine, WayEditIndex
Remove the original value from the mission file list and then replace it with the new modified data.
Well that concludes this lesson (part 3). Although we could cover more command button control events such “Apply Changes To Group”, “Fly In This Group” and “Update Mission File” the principals and logic behind how these work have already been covered I feel and to continue further would only be explaining more of the same thing just with subtle differences.
Please download the Visual Basic project files for this lesson at the link below and examine them more closely and at your leisure. I know from my own experience it helps being able to examine code for yourself when understanding how a particular programme works.
Please, if you do not understand any part of this lesson ask me the question in this forum, I will be keeping a close eye open and will respond quickly with an answer to the best of my knowledge.
Next week we will conclude the tutorial with weapons options for each aircraft and a few other smaller options and perhaps you may choose to develop the programme further into something much bigger and better with your own personal touches.
Until then happy coding, CrazySchmidt.
Download project file here
http://airwarfare.com/AWX/Files/cs/VB%20Editor%20Lesson%203.zip