Strategy game, Researching and creating units (Post #20 / Strategy game #11)

 In the previous post we created the structures for our research and construction, and their interface windows. Now we will connect everything and start actually researching and building units.

This is going to be a bit of a pickle since we'll have to update multiple parts of our code, one sub calls another one and they all connect to different parts of the renderer.  We need to also restrict which technologies or buildings the player can create based on what is researched until now.

Connecting our data structures to our UI

We'll start by creating visuals for hiding our non researched or non available units and technologies. (We'll simply hide the non available technologies and make the researched ones green, which we will also do for our construction window).

Now let's update our rendering code for our research window first. (Inside SUIWindow = 2 clause)

'New code
                For Z = 60 To 87
                    If Lib_Research_S(Z - 59).Available = 0 Then 'If a technology is not available then draw a gray box over it
                        sRect = New Rectangle(SButton(Z).X * ScreenWidth, SButton(Z).Y * ScreenHeight, SButton(Z).Width * ScreenWidth, SButton(Z).Height * ScreenHeight)
                        DrawQuad(sRect.X, sRect.Y, sRect.Width, sRect.Height, 1.0F, 1.0F, 0.04, 0.04, 0.04F)
                    Else
                        If Lib_Research_S(Z - 59).Researched = 1 Then  'If a technology has already been researched draw a green box over it
                            sRect = New Rectangle(SButton(Z).X * ScreenWidth, SButton(Z).Y * ScreenHeight, SButton(Z).Width * ScreenWidth, SButton(Z).Height * ScreenHeight)
                            DrawQuad(sRect.X, sRect.Y, sRect.Width, sRect.Height, 1.0F, 0.4F, 0.04, 1, 0.04)
                        End If
                    End If
                Next
                'Updated/changed code
                If SButtonHover >= 60 And SButtonHover <= 87 Then
                    If Lib_Research_S(SButtonHover - 59).Available = 1 Then
                        If Lib_Research_S(SButtonHover - 59).Name.Contains(" ") Then
                            DrawText(Split(Lib_Research_S(SButtonHover - 59).Name, " ")(0), 697 * (ScreenWidth / UISizeW), 436 * (ScreenHeight / UISizeH), 1.1, 1, 0.8, 0.8, 0.8, 1)
                            DrawText(Split(Lib_Research_S(SButtonHover - 59).Name, " ")(1), 697 * (ScreenWidth / UISizeW), 446 * (ScreenHeight / UISizeH), 1.1, 1, 0.8, 0.8, 0.8, 1)
                            DrawText(Int(
Lib_Research_S(SButtonHover - 59).Turns - Lib_Research_S(SButtonHover - 59).Turns * (Faction(0).STLibrary.BasicB(1) + Faction(0).STLibrary.BasicB(4) + Faction(0).STLibrary.BasicB(7)) / 100), 783 * (ScreenWidth / UISizeW), 436 * (ScreenHeight / UISizeH), 1.3, 1, 0.8, 0.8, 0.8, 1)
                        Else
                            DrawText(Lib_Research_S(SButtonHover - 59).Name, 697 * (ScreenWidth / UISizeW), 436 * (ScreenHeight / UISizeH), 1.1, 1, 0.8, 0.8, 0.8, 1)
                            DrawText(Int(
Lib_Research_S(SButtonHover - 59).Turns - Lib_Research_S(SButtonHover - 59).Turns * (Faction(0).STLibrary.BasicB(1) + Faction(0).STLibrary.BasicB(4) + Faction(0).STLibrary.BasicB(7)) / 100), 783 * (ScreenWidth / UISizeW), 436 * (ScreenHeight / UISizeH), 1.3, 1, 0.8, 0.8, 0.8, 1)
                        End If
                    Else
                        DrawText("None", 697 * (ScreenWidth / UISizeW), 436 * (ScreenHeight / UISizeH), 1.3, 1, 0.8, 0.8, 0.8, 1) 'Construction Hovering over
                    End If
                Else
                    DrawText("None", 697 * (ScreenWidth / UISizeW), 436 * (ScreenHeight / UISizeH), 1.3, 1, 0.8, 0.8, 0.8, 1) 'Construction Hovering over
                End If

The above should give give something like the image below, where we can distinguish researched items and show only the available ones.

And for our unit and building window we do the same process under If SUIWindowConstruct = 1 

                    'New code
                    For Z = 23 To 58
                        If Lib_Construct_S(Z - 22).Unlocked = 0 Then 'If a technology is not available then draw a gray box over it
                            sRect = New Rectangle(SButton(Z).X * ScreenWidth, SButton(Z).Y * ScreenHeight, SButton(Z).Width * ScreenWidth, SButton(Z).Height * ScreenHeight)
                            DrawQuad(sRect.X, sRect.Y, sRect.Width, sRect.Height, 1.0F, 1.0F, 0.04, 0.04, 0.04F)
                        End If
                    Next

                    'Updated code
                    If SButtonHover >= 23 And SButtonHover <= 44 Then
                        If Lib_Construct_S(SButtonHover - 22).Unlocked = 1 Then
                            DrawText(Lib_Construct_S(SButtonHover - 22).Name & " (" & Int(Lib_Construct_S(SButtonHover - 22).Turns - Lib_Construct_S(SButtonHover - 22).Turns * (Faction(0).STLibrary.BasicB(6) + Faction(0).STLibrary.BasicB(4)) / 100) & ")", 17 * (ScreenWidth / UISizeW), 507 * (ScreenHeight / UISizeH), 1.3, 1, 0.8, 0.8, 0.8, 1) 'Units Hovering over
                        End If
                    ElseIf SButtonHover >= 45 And SButtonHover <= 58 Then
                        If Lib_Construct_S(SButtonHover - 22).Unlocked = 1 Then
                            DrawText(Lib_Construct_S(SButtonHover - 22).Name & " (" & Int(Lib_Construct_S(SButtonHover - 22).Turns - Lib_Construct_S(SButtonHover - 22).Turns * (Faction(0).STLibrary.BasicB(7) + Faction(0).STLibrary.BasicB(4)) / 100) & ")", 17 * (ScreenWidth / UISizeW), 507 * (ScreenHeight / UISizeH), 1.3, 1, 0.8, 0.8, 0.8, 1) 'Buildings Hovering over
                        End If
                    Else
                            DrawText("None", 21 * (ScreenWidth / UISizeW), 507 * (ScreenHeight / UISizeH), 1.3, 1, 0.8, 0.8, 0.8, 1) 'Construction Hovering over
                    End If
                End If

And we get the following result for the construction window

Now let's make these buttons to actually work in our game.
For the player to start with some researches and units already available I added this code to Game_Library_Construct sub

            Q = 1
            Lib_Research_S(Q).Researched = 0
            Lib_Research_S(Q).Available = 1
            Q = 8
            Lib_Research_S(Q).Researched = 0
            Lib_Research_S(Q).Available = 1
            Q = 15
            Lib_Research_S(Q).Researched = 0
            Lib_Research_S(Q).Available = 1
            Q = 22
            Lib_Research_S(Q).Researched = 0
            Lib_Research_S(Q).Available = 1
            Lib_Construct_S(1).Unlocked = 1
            Lib_Construct_S(2).Unlocked = 1

 Also added these two variables on FactionStruct structure (They will hold current research, turns and flags enabled from some research)

Dim CurResearchID As Integer
        Dim CurResearchTurns As Integer

        Dim CanBuildFarms As Integer
        Dim CanBuildRoads As Integer

 Which will have two units and the four main technology trees available at the start of the game.

Now let's go to our button click clause inside GameButtons("CLICK")

            ElseIf sbuttonhover >= 60 And sbuttonhover <= 87 Then
                If Lib_Research_S(SButtonHover - 59).Available = 1 And Lib_Research_S(SButtonHover - 59).Researched = 0 Then 'Technology is available and not researched
                    Faction(0).CurResearchID = SButtonHover - 59
                    Faction(0).CurResearchTurns = Int(Lib_Research_S(SButtonHover - 59).Turns - Lib_Research_S(SButtonHover - 59).Turns * (Faction(0).STLibrary.BasicB(1) + Faction(0).STLibrary.BasicB(4) + Faction(0).STLibrary.BasicB(7)) / 100)
                End If

            ElseIf SButtonHover = 88 Then 'If the mouse is over close research button
                If SUIWindow = 2 Then
                    SUIWindow = 0
                End If

And creating that button with index (88) that you see above on GameButtons("CREATE") so we can close our research window

SButton(88).Text = "Close Research"
            SButton(88).Enabled = 1
            SButton(88).X = 694 : SButton(88).Y = 502
            SButton(88).Width = 116 : SButton(88).Height = 22
            SButton(88).UIState = 2

On Faction_F("END_TURN") add the following

            I = 0
            If Faction(I).CurResearchID > 0 Then
                If Faction(I).CurResearchTurns > 0 Then
                    Faction(I).CurResearchTurns -= 1
                ElseIf Faction(I).CurResearchTurns = 0 Then
                    Lib_Research_S(Faction(I).CurResearchID).Researched = 1
                    Game_Library_Construct("REFRESH_RESEARCH", Faction(I).CurResearchID, 0)
                    Faction(I).CurResearchID = 0
                End If
            End If

So when the research is finished it will be flagged as researched and will call the sub Game_Library_Construct("REFRESH_RESEARCH", 0, 0) to unlock technologies.

What we haven't created is the system where when one technology research is finished it makes other technologies or units available. This, we will create inside our Loading libraries sub.

Inside Game_Library_Construct("LOAD",0,0)

For IndexID = 1 To 6 'This loop assigns the research to unlock the next index in the tree of the 4 tech trees
                Lib_Research_S(IndexID).ResearchID1 = IndexID + 1
                Lib_Research_S(IndexID + 7).ResearchID1 = IndexID + 8
                Lib_Research_S(IndexID + 14).ResearchID1 = IndexID + 15
                Lib_Research_S(IndexID + 21).ResearchID1 = IndexID + 22
            Next

Lib_Research_S(1).ConstructionID1 = 23 : Lib_Research_S(1).ConstructionID2 = 0 'Can build farms
            Lib_Research_S(2).ConstructionID1 = 26 : Lib_Research_S(2).ConstructionID2 = 0
            Lib_Research_S(3).ConstructionID1 = 6 : Lib_Research_S(3).ConstructionID2 = 0
            Lib_Research_S(4).ConstructionID1 = 7 : Lib_Research_S(4).ConstructionID2 = 0
            Lib_Research_S(5).ConstructionID1 = 21 : Lib_Research_S(5).ConstructionID2 = 0
            Lib_Research_S(6).ConstructionID1 = 10 : Lib_Research_S(6).ConstructionID2 = 0
            Lib_Research_S(7).ConstructionID1 = 31 : Lib_Research_S(7).ConstructionID2 = 0
            Lib_Research_S(8).ConstructionID1 = 3 : Lib_Research_S(8).ConstructionID2 = 26
            Lib_Research_S(9).ConstructionID1 = 5 : Lib_Research_S(9).ConstructionID2 = 27
            Lib_Research_S(10).ConstructionID1 = 4 : Lib_Research_S(10).ConstructionID2 = 5
            Lib_Research_S(11).ConstructionID1 = 8 : Lib_Research_S(11).ConstructionID2 = 9
            Lib_Research_S(12).ConstructionID1 = 11 : Lib_Research_S(12).ConstructionID2 = 0
            Lib_Research_S(13).ConstructionID1 = 31 : Lib_Research_S(13).ConstructionID2 = 0
            Lib_Research_S(14).ConstructionID1 = 16 : Lib_Research_S(14).ConstructionID2 = 19
            Lib_Research_S(15).ConstructionID1 = 0 : Lib_Research_S(15).ConstructionID2 = 0
            Lib_Research_S(16).ConstructionID1 = 29 : Lib_Research_S(16).ConstructionID2 = 0 'Can build Roads
            Lib_Research_S(17).ConstructionID1 = 14 : Lib_Research_S(17).ConstructionID2 = 25
            Lib_Research_S(18).ConstructionID1 = 13 : Lib_Research_S(18).ConstructionID2 = 34
            Lib_Research_S(19).ConstructionID1 = 12 : Lib_Research_S(19).ConstructionID2 = 32
            Lib_Research_S(20).ConstructionID1 = 36 : Lib_Research_S(20).ConstructionID2 = 0
            Lib_Research_S(21).ConstructionID1 = 18 : Lib_Research_S(21).ConstructionID2 = 20
            Lib_Research_S(22).ConstructionID1 = 0 : Lib_Research_S(22).ConstructionID2 = 0
            Lib_Research_S(23).ConstructionID1 = 24 : Lib_Research_S(23).ConstructionID2 = 0
            Lib_Research_S(24).ConstructionID1 = 28 : Lib_Research_S(24).ConstructionID2 = 30
            Lib_Research_S(25).ConstructionID1 = 33 : Lib_Research_S(25).ConstructionID2 = 0
            Lib_Research_S(26).ConstructionID1 = 0 : Lib_Research_S(26).ConstructionID2 = 0
            Lib_Research_S(27).ConstructionID1 = 15 : Lib_Research_S(27).ConstructionID2 = 17
            Lib_Research_S(28).ConstructionID1 = 22 : Lib_Research_S(28).ConstructionID2 = 0

So this Index redirecting above will tell us in the next bit of code if technology indexed X is researched, Construction indexed Y is available. Now since I just added some variables like CanBuildRoads like this without indexing we'll just throw them in as available using some exceptions on the next code.

On the same sub Game_Library_Construct create a clause REFRESH_RESEARCH

ElseIf func = "REFRESH_RESEARCH" Then
            I = Lib_Research_S(X).ConstructionID1
            Q = Lib_Research_S(X).ConstructionID2
            Lib_Construct_S(I).Unlocked = 1 'Unlock construction 1
            Lib_Construct_S(Q).Unlocked = 1 'Unlock construction 2
            Lib_Research_S(Lib_Research_S(X).ResearchID1).Available = 1 'Unlock new research
            If X = 1 Then Faction(0).CanBuildFarms = 1
            If X = 16 Then Faction(0).CanBuildRoads = 1

As seen on the image, one research unlocked a new one and a building is available for construction.

Now the process of a building or a unit to show up as available for construction is ready and we need to write the code to actually construct it. We need to have a city selected to actually build something, and we are going to add the buildings that are finished in the city screen render afterwards.

Let's go step by step with images since this is going to be a bit long.

Constructing units and buildings

Adding buttons to shuffle through our cities - GameButtons("CREATE")

SButton(89).Text = "Previous city"
            SButton(89).Enabled = 1
            SButton(89).X = 638 : SButton(89).Y = 326
            SButton(89).Width = 15 : SButton(89).Height = 15
            SButton(89).UIState = 1
            SButton(90).Text = "Next city"
            SButton(90).Enabled = 1
            SButton(90).X = 800 : SButton(90).Y = 326
            SButton(90).Width = 15 : SButton(90).Height = 15
            SButton(90).UIState = 1

Using buttons to shuffle through our cities - GameButtons("CLICK")

            ElseIf SButtonHover = 89 Then 'Go to the previous city
                If SUICity > 0 Then
                    If Faction(0).City(SUICity - 1).Enabled = 1 Then
                        SUICity -= 1
                    End If
                End If
            ElseIf SButtonHover = 90 Then 'Go to the next city
                If SUICity < MaxCitiesPF Then
                    If Faction(0).City(SUICity + 1).Enabled = 1 Then
                        SUICity += 1
                    End If
                End If


Now that we can shuffle through our cities let's create a clause when clicking construct, in case the faction window is open but there is no city available (settlers only)

On button (22) click event add this clause

If Faction(0).City(SUICity).Enabled = 1 Then
                            SUIWindowConstruct = 1
                        End If

Now onwards to assigning something to get constructed

Inside our city struct add this variable : Dim Constructed() As Integer 'Holds index for built constructs

Inside our Faction_F("CREATE_FACTIONS") : 

For Q = 0 To MaxCitiesPF
                    ReDim Faction(I).City(Q).Constructed(100)
                Next

On button click

            ElseIf sbuttonhover >= 23 And sbuttonhover <= 44 Then 'Constructing unit buttons
                If Lib_Construct_S(SButtonHover - 22).Unlocked = 1 Then 'Unit is available to construct
                    Faction(0).City(SUICity).ConstructionID = SButtonHover - 22
                    Faction(0).City(SUICity).ConstructTurns = Int(Lib_Construct_S(SButtonHover - 22).Turns - Lib_Construct_S(SButtonHover - 22).Turns * (Faction(0).STLibrary.BasicB(6) + Faction(0).STLibrary.BasicB(4)) / 100)
                End If
            ElseIf sbuttonhover >= 45 And sbuttonhover <= 58 Then 'Constructing buildings buttons
                If Lib_Construct_S(SButtonHover - 22).Unlocked = 1 Then 'building is available to construct
                    If Faction(0).City(SUICity).Constructed(SButtonHover - 22) = 0 Then 'If this building has not been built
                        Faction(0).City(SUICity).ConstructionID = SButtonHover - 22
                        Faction(0).City(SUICity).ConstructTurns = Int(Lib_Construct_S(SButtonHover - 22).Turns - Lib_Construct_S(SButtonHover - 22).Turns * (Faction(0).STLibrary.BasicB(7) + Faction(0).STLibrary.BasicB(4)) / 100)
                    End If
                End If

Inside our city rendering

If Faction(0).City(SUICity).ConstructionID <> 0 Then
                        DrawText(Lib_Construct_S(Faction(0).City(SUICity).ConstructionID).Name, 642 * (ScreenWidth / UISizeW), (414) * (ScreenHeight / UISizeH), 1.2, 1, 0.8, 0.8, 0.8, 1)
                        DrawText(Faction(0).City(SUICity).ConstructTurns, 784 * (ScreenWidth / UISizeW), (414) * (ScreenHeight / UISizeH), 1.2, 1, 0.8, 0.8, 0.8, 1)
                    Else
                        DrawText("No construction", 642 * (ScreenWidth / UISizeW), (414) * (ScreenHeight / UISizeH), 1.2, 1, 0.8, 0.8, 0.8, 1)
                        DrawText("+1", 784 * (ScreenWidth / UISizeW), (414) * (ScreenHeight / UISizeH), 1.2, 1, 0.8, 0.8, 0.8, 1)
                    End If

Now we have almost all of our construction visuals and our clicking references ready so we can update our end turn code.

For I = 0 To MaxFactions
                For Q = 0 To MaxCitiesPF
                    If Faction(I).City(Q).ConstructionID > 0 Then
                        If Faction(I).City(Q).ConstructTurns > 0 Then
                            Faction(I).City(Q).ConstructTurns -= 1
                        Else 'If turns are finished
                            If Faction(I).City(Q).ConstructionID <= 22 Then 'If it's a unit that finished construction
                                CREATE_UNIT(Faction(I).City(Q).ConstructionID, Q, I)
                            Else 'If it's a building that finished construction
                                Faction(I).City(Q).Constructed(Faction(I).City(Q).ConstructionID) = 1
                            End If
                            Faction(I).City(Q).ConstructionID = 0 'Null construction
                        End If
                    Else 'No construction
                        Faction(I).STLibrary.BasicA(1) += 1 'Add to treasury
                    End If
                Next
            Next

When a unit is finished as you see above calls a new sub called CREATE_UNIT so let's add that sub.

  Public Sub CREATE_UNIT(ByVal UnitID As Integer, ByVal CityID As Integer, ByVal FactionID As Integer)
        Dim I, Q As Integer
        For I = 0 To MaxUnitsPF
            If Faction(FactionID).Unit(I).ID = 0 Then
                Q = I
                Exit For
            End If
        Next
        Faction(FactionID).Unit(Q).ID = UnitID
        Faction(FactionID).Unit(Q).TileX = Faction(FactionID).City(CityID).TileX
        Faction(FactionID).Unit(Q).TileY = Faction(FactionID).City(CityID).TileY
        Dim X, Y As Integer
        X = Faction(FactionID).Unit(Q).TileX
        Y = Faction(FactionID).Unit(Q).TileY
        Faction(FactionID).Unit(Q).X = ((X - Y) * GridWidth / 2) * ZoomVar 'Making sure it gets the proper X,Y based on resizing
        Faction(FactionID).Unit(Q).Y = ((X + Y) * GridHeight / 2) * ZoomVar 'Making sure it gets the proper X,Y based on resizing
        Faction(FactionID).Unit(Q).TargetX = Faction(FactionID).Unit(Q).X
        Faction(FactionID).Unit(Q).TargetY = Faction(FactionID).Unit(Q).Y
        Faction(FactionID).Unit(Q).TurnPoints = 2
        Unit_F("MOVE_CALCULATE", Q)
    End Sub

The above new sub creates the unit specified, places it on the city that created it and calculates possible moves for it.

Units are finished, now let's create some visuals for the buildings too.

If you check above what happens when a building construction is finished, you'll see this line of code Faction(I).City(Q).Constructed(Faction(I).City(Q).ConstructionID) = 1, which is in effect a boolean. Let's do something with this boolean and our interface sprite sheet.

For Z = 23 To 36
                        If Faction(0).City(SUICity).Constructed(Z) = 1 Then
                            sRect = New Rectangle(280 + (Z - 22) * 23, 281, 23, 16)
                            If Z <= 28 Then
                                dRect = New Rectangle(660 * (ScreenWidth / UISizeW) + (Z - 23) * 23 * (ScreenWidth / UISizeW), 358 * (ScreenHeight / UISizeH), sRect.Width * (ScreenWidth / UISizeW), sRect.Height * (ScreenHeight / UISizeH))
                            ElseIf Z <= 32 Then
                                dRect = New Rectangle(660 * (ScreenWidth / UISizeW) + (Z - 28) * 23 * (ScreenWidth / UISizeW), 372 * (ScreenHeight / UISizeH), sRect.Width * (ScreenWidth / UISizeW), sRect.Height * (ScreenHeight / UISizeH))
                            Else
                                dRect = New Rectangle(660 * (ScreenWidth / UISizeW) + (Z - 32) * 23 * (ScreenWidth / UISizeW), 386 * (ScreenHeight / UISizeH), sRect.Width * (ScreenWidth / UISizeW), sRect.Height * (ScreenHeight / UISizeH))
                            End If
                            DrawTexturedQuad(sRect, dRect, 907, 548, 3, 1.0F, 1, 1, 1, 1)
                        End If
                    Next

The above code, when construction on a building finishes will take the building from the sprite sheet and place them as seen below.

These buildings draw on index order so their place on the window is fixed, if you want them to draw the one after the other one you can just create a second list and populate it with the current ones and their build order.


Comments