VB Mission Editor Tutorial Part 3

Dedicated Forum for developers of programs/utilities. To announce new or updated products, to share knowledge and ideas for development.

Moderator: CrazySchmidt

VB Mission Editor Tutorial Part 3

Postby CrazySchmidt on Sat Jan 22, 2005 6:33 am

Hi everyone and welcome to the part 3 of the tutorial. In this lesson we will expand the editor to work with all mission files (single player and co-op that is) and will add a lot of new controls and new code, plus we have a look at some required error checking to make the whole thing a little more stable! Remember you may download this entire VB project from the link at the bottom of this lesson.
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.
Image

Editor in design mode inside the VB6 interface.
Image

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:

Image

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
User avatar
CrazySchmidt
Utilities Developer
 
Posts: 358
Joined: Wed Dec 08, 2004 1:59 am
Location: Auckland, New Zealand

Return to Developers Central

Who is online

Users browsing this forum: No registered users and 3 guests