31-07-2009, 04:06 PM
A Simple Day And Night System
Note: There is no alpha blending or actual graphic change involved in this tutorial. This is just the actual time engine. You have to figure out the graphical aspect yourself
So this is going to be a fairly simple, copy and paste tutorial. If you have any questions or problems doing the tutorial, feel free to ask
The system will work based on minutes, hours and days. I did not add in seconds because I always felt in-game time should be faster. This system will basically make every second count as a minute, so a complete 24 hour game cycle would last 24 minutes in real life.
Server Side
Open up modTypes
Open up modGlobals
Open up modDatabase
Now we have to actually use the saving and loading functions, so we will load the time when we are starting up the server, and save it when we are closing the server.
Open up modGeneral
We now have a working time engine which saves and loads the values. However, we have no actual code which makes the time change, so let's add that in now
Open up modServerLoop
Open up modGameLogic
So there you have it. That is the base for the time engine. I will add extras as time goes on. Enjoy
Time Events:
As an optional add-on, I will show you how to add time events. This add-on is entirely server side.
/time Command:
Adding a /time command to find out the time on the client side will be a fairly easy process as long as you follow my exact directions. This will give you a peek at creating and sending a packet.
On both the Client Side and Server Side, go to modEnumerations
On the Client Side, open up modInput
Very good! Now for the server side, open up modHandleData
Note: There is no alpha blending or actual graphic change involved in this tutorial. This is just the actual time engine. You have to figure out the graphical aspect yourself

So this is going to be a fairly simple, copy and paste tutorial. If you have any questions or problems doing the tutorial, feel free to ask

Server Side
Open up modTypes
- This will be the UDT for time. Add the following at the bottom :
Code:Public Type TimeRec
Minute As Byte
Hour As Byte
Day As Byte
Month As Byte
Year As Integer
End Type
Open up modGlobals
- Now we will add the global variable for the time engine. Add this at the bottom :
Code:' Game time
Public GameTime as TimeRec
Open up modDatabase
- Now we will make the saving and loading functions so that the date remains the same when we close the server. Add these subs at the bottom:
Code:Public Sub SaveTime()
Dim FileName As String
FileName = App.Path & "\data\time.ini"
With GameTime
PutVar FileName, "TIME", "DAY", CStr(.Day)
PutVar FileName, "TIME", "MONTH", CStr(.Month)
PutVar FileName, "TIME", "HOUR", CStr(.Hour)
PutVar FileName, "TIME", "YEAR", CStr(.Year)
PutVar FileName, "TIME", "MINUTE", CStr(.Minute
End With
End Sub
Public Sub LoadTime()
Dim FileName As String
FileName = App.Path & "\data\time.ini"
With GameTime
If FileExist(FileName,True) Then
.Day = Val(GetVar(FileName, "TIME", "DAY"))
.Hour = Val(GetVar(FileName, "TIME", "HOUR"))
.Year = Val(GetVar(FileName, "TIME", "YEAR"))
.Month = Val(GetVar(FileName, "TIME", "MONTH"))
.Minute = Val(GetVar(FileName, "TIME", "MINUTE"))
Else
.Day = 1
.Month = 1
.Year = 1
SaveTime
End If
End With
End Sub
Now we have to actually use the saving and loading functions, so we will load the time when we are starting up the server, and save it when we are closing the server.
Open up modGeneral
- In sub InitServer, under the following line :
Add :Code:Call SetStatus("Spawning map Npcs...")
Call SpawnAllMapNpcs
Code:Call SetStatus("Loading time engine...")
Call LoadTime
In sub DestroyServer, under the following line:
Add :Code:Call SetStatus("Destroying System Tray...")
Call DestroySystemTray
Code:Call SetStatus("Saving time values...")
Call SaveTime
We now have a working time engine which saves and loads the values. However, we have no actual code which makes the time change, so let's add that in now

Open up modServerLoop
- Look through the sub until you get to :
Code:If Tick > tmr1000 Then
This is basically the code that will run every second. Since we want every second to be a minute, we're going to add in our code here. However, to keep the server loop clean, we're going to make our own sub for processing the time. So let's add our call to that sub. Under
Add :Code:' Handle shutting down server
If isShuttingDown Then
Call HandleShutdown
End If
Code:' A second has passed, so process the time
Call ProcessTime
Open up modGameLogic
- Add the following at the bottom. This is the sub that handles the time as well as a function the returns the last length of each month (For example February has 28 days, December has 12, etc..). Note : I did not add leap years, you can do that yourself if you really want to
.
Code:Public Sub ProcessTime()
With GameTime
.Minute = .Minute + 1
If .Minute >= 60 Then
.Hour = .Hour + 1
.Minute = 0
If .Hour >= 24 Then
.Day = .Day + 1
.Hour = 0
If .Day > GetMonthMax Then
.Month = .Month + 1
.Day = 1
If .Month > 12 Then
.Year = .Year + 1
.Month = 1
End If
End If
End If
End If
End With
End Sub
Public Function GetMonthMax() As Byte
Dim M As Byte
M = GameTime.Month
If M = 1 Or M = 3 Or M = 5 Or M = 7 Or M = 8 Or M = 10 Or M = 12 Then
GetMonthMax = 31
ElseIf M = 4 Or M = 6 Or M = 9 Or M = 11 Then
GetMonthMax = 30
ElseIf M = 2 Then
GetMonthMax = 28
End If
End Function
So there you have it. That is the base for the time engine. I will add extras as time goes on. Enjoy

Time Events:
As an optional add-on, I will show you how to add time events. This add-on is entirely server side.
- Open up modGameLogic
Replace the old ProcessTime sub with the following :
Note : I did not add in a handler for events when the minute change, as I feel this would be called too often for no reason. You can add it in if you really want to have an event based on the minute, it's fairly simple, just add in a ChangeMinuteEvents call in the ProcessTime sub and make a ChangeMinuteEvents subCode:Public Sub ProcessTime()
With GameTime
.Minute = .Minute + 1
If .Minute >= 60 Then
.Hour = .Hour + 1
.Minute = 0
If .Hour >= 24 Then
.Day = .Day + 1
.Hour = 0
ChangeDayEvents
If .Day > GetMonthMax Then
.Month = .Month + 1
.Day = 1
ChangeMonthEvents
If .Month > 12 Then
.Year = .Year + 1
.Month = 1
ChangeYearEvents
End If
End If
End If
End If
End With
End Sub
Now, under that sub, add the following :
These are your event subs. They are called every time the day/month/year changes. For example, if you wanted to make an event that wished everyone happy new year, you would change the ChangeYearEvents sub to look like this :Code:Public Sub ChangeDayEvents()
End Sub
Public Sub ChangeMonthEvents()
End Sub
Public Sub ChangeYearEvents()
End Sub
You could easily add, for example, an automated event that would give every player that is online at the time experience. For another example, let's make an event for when it is Valentine's Day in-game. This would be in the ChangeDayEvents :Code:Public Sub ChangeYearEvents()
Call GlobalMsg("All the villagers of Gameland are celebrating the new game year!", Cyan)
End Sub
This would, for example, message every player and give them an item.Code:Public Sub ChangeDayEvents()
Dim I As Long
If GameTime.Day = 14 And GameTime.Month = 2 Then
For I = 1 To High_Index
If IsPlaying(I) Then
Call PlayerMsg(I, "An anonymous villager has sent you a chocolate as a present for Valentine's Day!", Red)
Call GiveItem(I, 1, 1)
End If
Next I
End If
End Sub
So as you can see, time events are incredibly versitile and can be used to make many automated events to add a sense of realism and time to your game.
/time Command:
Adding a /time command to find out the time on the client side will be a fairly easy process as long as you follow my exact directions. This will give you a peek at creating and sending a packet.
On both the Client Side and Server Side, go to modEnumerations
- Look for the following :
It will be in the 'enum' :Code:'The following enum member automatically stores the number of messages,
'since it is last. Any new messages must be placed above this entry.
CMSG_COUNT
End Enum
Right above the comment, add :Code:Public Enum ClientPackets
.Code:CTimeRequest
Make sure you add this to both the Client modEnumerations and the Server modEnumerations.
On the Client Side, open up modInput
- Go to sub HandleKeyPresses and look for the following code:
Code:' Request stats
Case "/stats"
Set Buffer = New clsBuffer
Buffer.PreAllocate 2
Buffer.WriteInteger CGetStats
SendData Buffer.ToArray()
and under it, add :
Code:' Request time
Case "/time"
Set Buffer = New clsBuffer
Buffer.PreAllocate 2
Buffer.WriteInteger CTimeRequest
SendData Buffer.ToArray()
Very good! Now for the server side, open up modHandleData
- At the bottom of the sub InitMessages, add the following line :
Code:HandleDataSub(CTimeRequest) = GetAddress(AddressOf HandleTimeRequest)
And now add the following sub anywhere in that module :
Note that we use the built-in VB6 function MonthName to get the name of the Month. If you wish to have your own month names, or you modify the code to have a smaller amount of months with custom names, you will have to make a function that will give you the name of the month.Code:' :::::::::::::::::::::::::
' :: Time Request packet ::
' :::::::::::::::::::::::::
Private Sub HandleTimeRequest(ByVal Index As Long, ByRef Data() As Byte, ByVal StartAddr As Long, ByVal ExtraVar As Long)
Dim TimeString As String, DateString As String, MinuteString As String
With GameTime
MinuteString = .Minute
If Len(MinuteString) = 1 Then MinuteString = "0" & MinuteString
If .Hour > 12 Then
TimeString = (.Hour - 12) & ":" & MinuteString & " PM"
ElseIf .Hour = 12 Then
TimeString = .Hour & ":" & MinuteString & " PM"
Else
TimeString = .Hour & ":" & MinuteString & " AM"
End If
DateString = Right(.Day, 1)
If DateString = 1 Then
DateString = .Day & "st"
ElseIf DateString = 2 Then
DateString = .Day & "nd"
ElseIf DateString = 3 Then
DateString = .Day & "rd"
Else
DateString = .Day & "th"
End If
Call PlayerMsg(Index, "The current game time is " & TimeString & ". The date is currently the " & DateString & " of " & MonthName(.Month) & ", Year " & .Year & ".", White)
End With
End Sub
You now have a fully working /time function!