Now that we can build units, buildings and research technologies, we'll focus a bit more on the actual map of the game and how it's refreshed through turns.
➤ Creating a game system based on turns
I changed a bit the UI sprite sheet to include some animations for when "End Turn" button is pressed. I'll include the updated sheet at another post since the difference is some sprites that resemble status bars and a sequence for when clicking the button. Now I added some variables that will hold end turn steps, which when updated will show the process update on the screen.
Public TurnChange As Boolean = False 'A switch between states
Public TurnSteps As Int16 = 0 'A counter for turn sequence
Public TurnStepsL As Int16 = 0 'A Long counter for turn sequence
Let's first disallow player from clicking on the screen while enemy turn isn't finished. (I will just add a clause on GLMouseDown Sub)
Public Sub GLMouseDown(ByVal Btn As MouseEventArgs) 'Just call this from you clicking on screen event
If TurnChange = False Then 'Addition
If Btn.Button = MouseButtons.Left Then
Unit_F("MOUSE_MOVE_UNIT", UnitSelected)
GameButtons("CLICK")
End If
End If
End Sub
And at the following rendering code part (which draws the arrows and the select box under our selected unit, I added the same clause).
If TurnChange = False Then 'Addition
'Here we draw the points around the unit where it can move (if mouse is over one of them it's drawn with a different color
For Z = 0 To 7
If Faction(Y).Unit(X).TileToM(Z).X >= 0 And Faction(Y).Unit(X).TileToM(Z).X <= MaxGridX And Faction(Y).Unit(X).TileToM(Z).Y >= 0 And Faction(Y).Unit(X).TileToM(Z).Y <= MaxGridY Then
sRect = New Rectangle((11 + Z) * 64, 392, 64, 56) 'Y * 56
dRect = New Rectangle(GridWorld(Faction(Y).Unit(X).TileToM(Z).X, Faction(Y).Unit(X).TileToM(Z).Y).SX + OffSetX, GridWorld(Faction(Y).Unit(X).TileToM(Z).X, Faction(Y).Unit(X).TileToM(Z).Y).SY + OffSetY - 24 * ZoomVar, 64 * ZoomVar, 56 * ZoomVar)
If Z = UnitSelectedMouseHover Then
DrawTexturedQuad(sRect, dRect, 1472, 448, 1, 1, 1, 0, 0, 0.6)
Else
DrawTexturedQuad(sRect, dRect, 1472, 448, 1, 1, 1, 1, 1, 0.6)
End If
End If
Next
'Here we draw tile animation underneath our selected unit
sRect = New Rectangle((UnitSelectF \ 4) * 64, 392, 64, 56) 'Y * 56
dRect = New Rectangle(Faction(Y).Unit(X).X + OffSetX, Faction(Y).Unit(X).Y + OffSetY - 24 * ZoomVar, 64 * ZoomVar, 56 * ZoomVar)
DrawTexturedQuad(sRect, dRect, 1472, 448, 1, 1, 1, 1, 1, 0.6) 'GridWorld(Faction(Y).Unit(X).TileX, Faction(Y).Unit(X).TIleY).Z
End If
As you can see, now if TurnSteps is 0 then you can do stuff, If not then you have to wait until enemy turn is finished.
Reminder : When we click on our "End Turn" button, it calls this Faction_F("END_TURN")
ElseIf func = "END_TURN" Then 'I removed all previous code from this and just added this
TurnChange = True
ElseIf func = "END_TURN_STEPS" Then 'This is our new code part which we'll add our previous code with some more steps.
'For now add the code we had on END_TURN here.
And at the end of Faction_F("REFRESH_FACTIONS") add the following code
If TurnChange = True Then
If TurnStepsL < 89 Then
TurnStepsL += 1
Else
TurnChange = False
TurnStepsL = 0
Faction_F("END_TURN_STEPS")
End If
TurnSteps = TurnStepsL \ 8
End If
What we are trying to do here is to create a sequence that will get called till it's finished, and it will call another code while it's enabled. (added it at refresh_factions which is a call that's called all the time.
(In order to check how this works I added the visuals in our sprite sheet that I said at the start of the post which we'll add now)
Add the following inside our UI draw after drawing the side bar
'Turn button
sRect = New Rectangle(857, 0 + 26 * TurnSteps, 130, 26)
dRect = New Rectangle(825 * (ScreenWidth / UISizeW), 509 * (ScreenHeight / UISizeH), sRect.Width * (ScreenWidth / UISizeW), sRect.Height * (ScreenHeight / UISizeH))
DrawTexturedQuad(sRect, dRect, 1020, 548, 3, 1.0F, 1, 1, 1, 1)
The above code will give us the following visual result.
So our turn is now finished after the animation effect has played.
Another thing we'll jump into now is adding visuals for Unit health and available movement.
➤ Unit visuals (Health and Movement bars)
For these property bars I created specific bars in the sprite sheet for 100%, 66%, 33% and 0% of each. Now there will correspond to a system of min = 0 and max = 3. I did a max of 3 tiles to move and a max of 3 to health to keep the battles and movement to a small amount each turn. Now when later on we create the library from which our units will get these values assigned, they will get picked from a pool where let's say a primitive warrior will have 1 tile to move each turn and a warrior on a horse will have 3 tiles to move each turn. And they will show over our unit like the image below.
For these I just added (After 'Drawing units code inside the faction & unit loop part of our rendering code) the following'Health & Movement bars
sRect = New Rectangle(806, 297 + (3 - Faction(Y).Unit(X).Health) * 3, 51, 4)
dRect = New Rectangle(Faction(Y).Unit(X).X + OffSetX, Faction(Y).Unit(X).Y + OffSetY - 34 * ZoomVar, 51 * ZoomVar, 4 * ZoomVar)
DrawTexturedQuad(sRect, dRect, 1020, 548, 3, 1.0F, 1, 1, 1, 1)
sRect = New Rectangle(806, 310 + (3 - Faction(Y).Unit(X).TurnPoints) * 3, 51, 4)
dRect = New Rectangle(Faction(Y).Unit(X).X + OffSetX, Faction(Y).Unit(X).Y + OffSetY - 30 * ZoomVar, 51 * ZoomVar, 4 * ZoomVar)
DrawTexturedQuad(sRect, dRect, 1020, 548, 3, 1.0F, 1, 1, 1, 1)
Which are just calls to our sprite sheet based on unit's health and turn points variables.
Now let's create our library and assign our units four properties (Health, Turn Points, Attack, Defence). Since we have already a library in our structure Library_Constructions_S in which we hold the creation of our units let's go in and add these properties in there. I declared them as single, so go ahead and change these references on our faction.units as single too (except turn points).
Public Structure Library_Constructions_S
Dim Name As String
Dim UnlockID As Integer 'An index which when called will unlock the unit
Dim Unlocked As Integer 'Is the unit or structure unlocked
Dim Turns As Integer
'Additional variables
Dim Health As Single
Dim TurnPoints As Int16
Dim Attack As Single
Dim Defence As Single
End Structure
And add this pre-calculated values code inside our library initialize sub (Game_Library_Construct)
I = 1 'Settler
Lib_Construct_S(I).Health = 2 : Lib_Construct_S(I).TurnPoints = 2 : Lib_Construct_S(I).Attack = 0.1F : Lib_Construct_S(I).Defence = 0.5F
I = 2 'Worker
Lib_Construct_S(I).Health = 2 : Lib_Construct_S(I).TurnPoints = 1 : Lib_Construct_S(I).Attack = 0.2F : Lib_Construct_S(I).Defence = 0.4F
I = 3 'Warriors
Lib_Construct_S(I).Health = 1 : Lib_Construct_S(I).TurnPoints = 1 : Lib_Construct_S(I).Attack = 0.6F : Lib_Construct_S(I).Defence = 0.7F
I = 4 'Archers
Lib_Construct_S(I).Health = 1 : Lib_Construct_S(I).TurnPoints = 1 : Lib_Construct_S(I).Attack = 0.7F : Lib_Construct_S(I).Defence = 0.3F
I = 5 'Pikemen
Lib_Construct_S(I).Health = 2 : Lib_Construct_S(I).TurnPoints = 1 : Lib_Construct_S(I).Attack = 0.5F : Lib_Construct_S(I).Defence = 0.5F
I = 6 'Cavalry
Lib_Construct_S(I).Health = 2 : Lib_Construct_S(I).TurnPoints = 2 : Lib_Construct_S(I).Attack = 0.4F : Lib_Construct_S(I).Defence = 0.9F
I = 7 'Catapult
Lib_Construct_S(I).Health = 1 : Lib_Construct_S(I).TurnPoints = 1 : Lib_Construct_S(I).Attack = 1.2F : Lib_Construct_S(I).Defence = 0.3F
I = 8 'Longbowmen
Lib_Construct_S(I).Health = 2 : Lib_Construct_S(I).TurnPoints = 1 : Lib_Construct_S(I).Attack = 1.0F : Lib_Construct_S(I).Defence = 0.5F
I = 9 'Knights
Lib_Construct_S(I).Health = 2 : Lib_Construct_S(I).TurnPoints = 2 : Lib_Construct_S(I).Attack = 0.9F : Lib_Construct_S(I).Defence = 0.9F
I = 10 'Riflemen
Lib_Construct_S(I).Health = 3 : Lib_Construct_S(I).TurnPoints = 2 : Lib_Construct_S(I).Attack = 1.3F : Lib_Construct_S(I).Defence = 0.6F
I = 11 'Cannon
Lib_Construct_S(I).Health = 2 : Lib_Construct_S(I).TurnPoints = 2 : Lib_Construct_S(I).Attack = 1.5F : Lib_Construct_S(I).Defence = 0.5F
I = 12 'Infantry
Lib_Construct_S(I).Health = 3 : Lib_Construct_S(I).TurnPoints = 2 : Lib_Construct_S(I).Attack = 1.4F : Lib_Construct_S(I).Defence = 0.6F
I = 13 'Parachuters
Lib_Construct_S(I).Health = 3 : Lib_Construct_S(I).TurnPoints = 2 : Lib_Construct_S(I).Attack = 1.5F : Lib_Construct_S(I).Defence = 0.3F
I = 14 'Light Vehicle
Lib_Construct_S(I).Health = 2 : Lib_Construct_S(I).TurnPoints = 2 : Lib_Construct_S(I).Attack = 1.4F : Lib_Construct_S(I).Defence = 1.0F
I = 15 'Marines
Lib_Construct_S(I).Health = 3 : Lib_Construct_S(I).TurnPoints = 2 : Lib_Construct_S(I).Attack = 1.5F : Lib_Construct_S(I).Defence = 0.6F
I = 16 'AA Vehicle
Lib_Construct_S(I).Health = 2 : Lib_Construct_S(I).TurnPoints = 2 : Lib_Construct_S(I).Attack = 1.4F : Lib_Construct_S(I).Defence = 1.2F
I = 17 'Tank
Lib_Construct_S(I).Health = 3 : Lib_Construct_S(I).TurnPoints = 2 : Lib_Construct_S(I).Attack = 1.7F : Lib_Construct_S(I).Defence = 1.5F
I = 18 'Helicopter
Lib_Construct_S(I).Health = 3 : Lib_Construct_S(I).TurnPoints = 2 : Lib_Construct_S(I).Attack = 1.6F : Lib_Construct_S(I).Defence = 0.8F
I = 19 'Airplane
Lib_Construct_S(I).Health = 3 : Lib_Construct_S(I).TurnPoints = 2 : Lib_Construct_S(I).Attack = 1.0F : Lib_Construct_S(I).Defence = 1.0F
I = 20 'Fighter Jet
Lib_Construct_S(I).Health = 3 : Lib_Construct_S(I).TurnPoints = 2 : Lib_Construct_S(I).Attack = 2.0F : Lib_Construct_S(I).Defence = 1.3F
I = 21 'Ship
Lib_Construct_S(I).Health = 2 : Lib_Construct_S(I).TurnPoints = 2 : Lib_Construct_S(I).Attack = 0.8F : Lib_Construct_S(I).Defence = 0.8F
I = 22 'Warship
Lib_Construct_S(I).Health = 3 : Lib_Construct_S(I).TurnPoints = 2 : Lib_Construct_S(I).Attack = 1.7F : Lib_Construct_S(I).Defence = 1.5F
Now whenever we spawn a unit (so we'll jump onto our CREATE_UNIT sub), we'll also assign these values like shown below.
Where we had only this line Faction(FactionID).Unit(Q).TurnPoints = Y, we'll now have these lines
Faction(FactionID).Unit(Q).TurnPoints = Lib_Construct_S(UnitID).TurnPoints
Faction(FactionID).Unit(Q).Health = Lib_Construct_S(UnitID).Health
Faction(FactionID).Unit(Q).Attack = Lib_Construct_S(UnitID).Attack
Faction(FactionID).Unit(Q).Defence = Lib_Construct_S(UnitID).Defence
Do the same for this code when we spawn our first settler (Faction_F(Create_Factions))
Faction(I).Unit(0).TurnPoints = Lib_Construct_S(1).TurnPoints
Faction(I).Unit(0).Health = Lib_Construct_S(1).Health
Faction(I).Unit(0).Attack = Lib_Construct_S(1).Attack
Faction(I).Unit(0).Defence = Lib_Construct_S(1).Defence
Let's test our new code.
When I created a new unit, it spawned with the values that it got assigned from our library. You could create another two bars or other visuals to represent it's attack and defense values.
➤ Unit movement - restrictions
Now we'll restrict our unit from moving more than it's turn points, and every turn we'll refresh it's turn points back to full from the library values.
Inside our Faction_F("END_TURN_STEPS")
'Turn Points re-assign at the beginning of turn
For I = 0 To MaxFactions
For Q = 0 To MaxUnitsPF
If Faction(I).Unit(Q).ID > 0 Then
Faction(I).Unit(Q).TurnPoints = Lib_Construct_S(Faction(I).Unit(Q).ID).TurnPoints
End If
Next
Next
Inside our Unit_F("MOUSE_MOVE_UNIT")
Just add inside our clause this line at the end Faction(0).Unit(UnitSelected).TurnPoints -= 1. Now everytime you click on a tile to move (If the unit has enough turn points it will move and lose one)
We can now move our units (X times or turn points / turn)
Another restriction we'll introduce here is for ground units not passing through water tiles and for sea units not passing through ground tiles.
Add to UnitStruct the following
Dim TileToMA() As Boolean 'Here we'll check if unit can move to this TileToM(Index)
And ReDim Faction(I).Unit(Q).TileToMA(7) inside Faction_F("CREATE_FACTIONS") under TileToM redim
And the rest code to the following parts
Unit_F(,) Inside "MOVE_CALCULATE" After the tile position calculations add the following loop, which will check what kind of tiles are the available to move on ones and flag them as Can move to or Can't move to depending on what unit is the move calculated for.
For Q = 0 To 7
If GridWorld(Faction(0).Unit(ID).TileToM(Q).X, Faction(0).Unit(ID).TileToM(Q).Y).ID <= 3 Then 'Sea tiles
If Faction(0).Unit(ID).ID >= 20 Then 'If it's a sea or flying unit
Faction(0).Unit(ID).TileToMA(Q) = True
Else 'If it's a ground unit
Faction(0).Unit(ID).TileToMA(Q) = False
End If
Else 'ground tiles
If Faction(0).Unit(ID).ID >= 22 Then 'If it's a sea unit
Faction(0).Unit(ID).TileToMA(Q) = False
Else 'If it's a ground or flying unit
Faction(0).Unit(ID).TileToMA(Q) = True
End If
End If
Next
Now let's put this newly assigned boolean to use.
On the same sub under "MOUSE_HOVER_UNIT" change the clause to this
If GridPX = Faction(0).Unit(ID).TileToM(Q).X And GridPY = Faction(0).Unit(ID).TileToM(Q).Y And Faction(0).Unit(ID).TileToMA(Q) = True Then
So it takes into account our boolean when checking the mouse hovering over tile.
Let's also update our rendering code too in order to hide the available positions if they are incompatible with our unit type.
Inside Draw_Calls under our Draw Unit Loop change the clause to this
If Faction(Y).Unit(X).TileToM(Z).X >= 0 And Faction(Y).Unit(X).TileToM(Z).X <= MaxGridX And Faction(Y).Unit(X).TileToM(Z).Y >= 0 And Faction(Y).Unit(X).TileToM(Z).Y <= MaxGridY And Faction(Y).Unit(X).TileToMA(Z) = True Then 'The addition is Faction(Y).Unit(X).TileToMA(Z) = True
Now a ground unit can only move on ground tiles and a sea unit on water tiles, while a flying unit can move on both. (We also prevent our rendering code to show these restricted tiles as shown above in the image)
➤ Small fix
One thing that was off that I found in the code was when the hovering tile was drawn on the minimap which wasn't updated on different resolutions and was shown way off the minimap. The code now is like shown below. (Inside drawing minimap loop)
If X = GridPX And Y = GridPY Then
dRect = New Rectangle(ScreenWidth - 140 * (ScreenWidth / UISizeW) + 4 * (ScreenWidth / UISizeW) + X * GridMiniSizeW, 5 * (ScreenHeight / UISizeH) + Y * GridMiniSizeH, GridMiniSizeW, GridMiniSizeH)
DrawQuad(dRect.X, dRect.Y, dRect.Width, dRect.Height, 1.0F, 1.0F, 1, 0.4, 1)
'DrawQuad(ScreenWidth - 140 * (ScreenWidth / UISizeW) * 2 + 4 * (ScreenWidth / UISizeW) + X * GridMiniSizeW, 5 * (ScreenHeight / UISizeH) + Y * GridMiniSizeH, GridMiniSizeW, GridMiniSizeH, 1.0F, 1.0F, 1, 0.4, 1) That was the old code
End If
Now that most of our movement and value assigning is done, we can move forward to adding enemy movement and creating our battle system.
Comments
Post a Comment