Okay, I've possessed myself to expand on this a bit.
Difficulty: 4/5 Requires knowledge of VB/MSE programming
Original Post can be found here:
http://ms.shannaracorp.com/forums/viewtopic.php?t=174
The flag idea and quest was taken from Unkown_raven
This version of the code uses tile, which you can set with the Mapeditor. I'll give an example of how to set up each quest at the end of this tutorial. There are probably easier ways to do what I have but this works for me
.
Let's do the client side first:
Open up frmMirage
On picMapEditor add an option button to your attributes frame, name it optQuest.
Double click it and add this to the code:
Code:
Private Sub optQuest_Click()
frmQuest.Show vbModal
End Sub
Now, Open up modGameLogic and in the
Sub GameLoop find:
Code:
If .Type = TILE_TYPE_KEYOPEN Then Call DrawText(TexthDC, x * PIC_X + 8, y * PIC_Y + 8, "O", QBColor(White))
Under it add:
Code:
If .Type = TILE_TYPE_QUEST Then Call DrawText(TexthDC, x * PIC_X + 8, y * PIC_Y + 8, "Q", QBColor(BrightRed))
Then in
Sub EditorMouseDown find:
Code:
If frmMirage.optKeyOpen.Value = True Then
.Type = TILE_TYPE_KEYOPEN
.Data1 = KeyOpenEditorX
.Data2 = KeyOpenEditorY
.Data3 = 0
End If
Under it, add:
Code:
If frmMirage.optQuest.Value = True Then
.Type = TILE_TYPE_QUEST
.Data1 = QuestEditorNum
.Data2 = 0
.Data3 = 0
End If
Now, open modConstants and find:
Code:
Public Const TILE_TYPE_KEYOPEN = 6
And under it, add:
Code:
Public Const TILE_TYPE_QUEST = 7
Now open modGlobals:
Anywhere in that module, add:
Code:
' Used for Quest Chooser
Public QuestEditorNum As Long
Okay, now we're going to create the form that will be used to choose which quest we want to start when the player walks over the specified tile.
So, add a new form and name it
frmQuestAdd a scroll bar:
Name: scrlQuestNum
Max: 250
Add a Label:
Name: lblQuestNum
Add a command button:
Name: cmdOK
Caption: Okay
Add a command button:
Name: cmdCancel
Caption: Cancel
Double click the form and add the following:
Code:
Private Sub cmdOk_Click()
QuestEditorNum = scrlQuestNum.Value
Unload Me
End Sub
Private Sub cmdCancel_Click()
Unload Me
End Sub
Private Sub scrlQuestNum_Change()
lblQuestnum.Caption = STR(scrlQuestNum.Value)
End Sub
That's all for the client side. Now on to the server.
Open frmServer and add a new timer to it.
Name: QuestMapNotice
Enabled: False
Interval: 5000
Double click on it and add the following to its sub routine:
Code:
CHECKQUEST = True
Open modGameLogic and in the PlayerWarp sub find:
Code:
' Sets it so we know to process npcs on the map
PlayersOnMap(MapNum) = YES
Under it, add:
Code:
frmServer.tmrQuestMapNotice.Enabled = True
If CHECKQUEST = True Then
If Dir(App.Path & "\Quest Maps\" & GetPlayerName(index) & ".ini") <> "" Then
If GetQuestMap(index, GetPlayerMap(index)) = 1 Then
Call QuestMapData(index)
frmServer.tmrQuestMapNotice.Enabled = False
Else
frmServer.tmrQuestMapNotice.Enabled = False
End If
End If
End If
Now find:
Code:
' They tried to hack
If Moved = NO Then
Call HackingAttempt(index, "Position Modification")
End If
And under it add:
Code:
If Map(GetPlayerMap(index)).Tile(GetPlayerX(index), GetPlayerY(index)).Type = TILE_TYPE_QUEST Then
Call CheckQuestTile(index)
End If
In Sub JoinGame, find:
Code:
' Warp the player to his saved location
Call PlayerWarp(index, GetPlayerMap(index), GetPlayerX(index), GetPlayerY(index))
and under it add:
Code:
filename = App.Path & "\Flags\" & GetPlayerName(index) & ".ini"
If Dir(filename) = "" Then
Num = 1
'Change the 3 to number of flags you want per player
Do While Num <= 250
Call PutVar(filename, GetPlayerName(index), "Flag" & Num, 0)
Num = Num + 1
Loop
Call PlayerMsg(index, "Quest Variables Set - If you see this message again please notify an admin or use the /bug command.", 10)
End If
filename = App.Path & "\Quest Maps\" & GetPlayerName(index) & ".ini"
If Dir(filename) = "" Then
Num = 1
'Change the 3 to number of flags you want per player
Do While Num <= MAX_MAPS
Call PutVar(filename, GetPlayerName(index), "Map" & Num, 0)
Num = Num + 1
Loop
Call PlayerMsg(index, "Map Variables Set - If you see this message again please notify an admin or use the /bug command.", 10)
End If
*** Note: in my game we have a bug reporting tool. Every game should have one! :p
Now, open mogGeneral, find:
Code:
' Check if the accounts directory is there, if its not make it
If LCase(Dir(App.Path & "\accounts", vbDirectory)) <> "accounts" Then
Call MkDir(App.Path & "\accounts")
End If
And after it add:
Code:
' Check if the Quest maps directory is there, if its not make it
If LCase(Dir(App.Path & "\quest maps", vbDirectory)) <> "quest maps" Then
Call MkDir(App.Path & "\quest maps")
End If
' Check if the Flags directory is there, if its not make it
If LCase(Dir(App.Path & "\flags", vbDirectory)) <> "flags" Then
Call MkDir(App.Path & "\flags")
End If
Open modConstants, and add the following:
Code:
Public Const MAX_QUEST_MAPS = 200 ' You can change this to whatever you choose, 200 seemed sutiable for my game.
Find:
Code:
Public Const TILE_TYPE_KEYOPEN = 6
Under it add:
Code:
Public Const TILE_TYPE_QUEST = 7
in modGlobals, add:
Code:
' Used for checking quest data
Public CHECKQUEST As Boolean
Now, make a new module and name it modQuest
In that module add all of this:
Code:
Option Explicit
Function GetFlagHeight(ByVal index As Integer, ByVal Flagnum As Integer) As Long
Dim X
Dim filename As String
filename = App.Path & "\flags\" & GetPlayerName(index) & ".ini"
X = GetVar(filename, GetPlayerName(index), "Flag" & Flagnum)
GetFlagHeight = X
Call SendDataTo(index, ("FLAGHEIGHT" & SEP_CHAR & X & SEP_CHAR & Flagnum & SEP_CHAR & END_CHAR))
End Function
Sub RaiseFlag(ByVal index As Integer, ByVal Flagnum As Integer, ByVal height As Integer)
Dim filename As String
filename = App.Path & "\flags\" & GetPlayerName(index) & ".ini"
Call PutVar(filename, GetPlayerName(index), "Flag" & Flagnum, STR(GetVar(filename, GetPlayerName(index), "Flag" & Flagnum) + height))
End Sub
Sub LowerFlag(ByVal index As Integer, ByVal Flagnum As Integer, ByVal height As Integer)
Dim filename As String
filename = App.Path & "\flags\" & GetPlayerName(index) & ".ini"
Call PutVar(filename, GetPlayerName(index), "Flag" & Flagnum, STR(GetVar(filename, GetPlayerName(index), "Flag" & Flagnum) - height))
End Sub
Sub SetFlag(ByVal index As Integer, ByVal Flagnum As Integer, ByVal height As Integer)
Dim filename As String
filename = App.Path & "\flags\" & GetPlayerName(index) & ".ini"
Call PutVar(filename, GetPlayerName(index), "Flag" & Flagnum, STR(0))
Call PutVar(filename, GetPlayerName(index), "Flag" & Flagnum, STR(GetVar(filename, GetPlayerName(index), "Flag" & Flagnum) + height))
Call PutVar(filename, GetPlayerName(index), "Flag" & Flagnum, STR(height))
End Sub
Sub SetQuestMap(ByVal index As Long, ByVal MapNum As Long, ByVal QuestMap As Byte)
Dim filename As String
Dim i As Long
filename = App.Path & "\Quest Maps\" & GetPlayerName(index) & ".ini"
For i = 1 To MAX_MAPS
If GetVar(filename, GetPlayerName(index), "Map" & i) = 0 Then
Resume Next
Else
Call PutVar(filename, GetPlayerName(index), "Map" & i, STR(QuestMap))
End If
Next i
End Sub
Function GetQuestMap(ByVal index As Integer, ByVal MapNum As Integer) As Long
Dim X
Dim filename As String
filename = App.Path & "\Quest Maps\" & GetPlayerName(index) & ".ini"
X = GetVar(filename, GetPlayerName(index), "Map" & MapNum)
GetQuestMap = X
End Function
'=======================================
'Hard Code Your Quests Here
'=======================================
Sub CheckQuestTile(ByVal index As Integer)
Select Case Map(GetPlayerMap(index)).Tile(GetPlayerX(index), GetPlayerY(index)).Data1
Case 1 ' This is the quest number you will choose with the frmQuest on your client.
End Select
End Sub
Sub QuestMapData(index)
Select Case GetPlayerMap(index)
Case 1 ' Your Quest Map
' Quest Map Events Go Here
End Select
End Sub
Okay now that thats all done. Let's make ourselves a quest!
We're going to use my example from the last tutorial. Janelle wants you to go find out if the forest is muddy :o
Okay, so let's make this quest one. Let's start by programming the quest into the sub we just added.
Code:
Case 1
If GetFlagHeight(index, 1) = 0 Then 'this checks the height of Flag1
Call PlayerMsg(index, "Janelle Says: 'Hi, could you do this quest for me? I need you to go to the forest and see if it is muddy.'", 10)
Call RaiseFlag(index, 1, 1) 'raises the flag a level so the event cannot be repeated.
Call SetQuestMap(index, 3, 1) ' sets the map to be a quest map for the player
End If
If GetFlagHeight(index, 1) = 1 Then
Call PlayerMsg(index, "Janelle Says: 'Please hurry to the forest!'", 10)
End If
If GetFlagHeight(index, 1) = 2 Then
Call PlayerMsg(index, "Janelle Says: 'Oh thank you please take this reward.'", 10)
If FindOpenInvSlot(index, 1) = 0 Then 'looks for an empty slot
Call PlayerMsg(index, "Janelle Says: 'I am sorry but your inventory is full.'", 10)
Call PlayerMsg(index, "Janelle Says: 'Come back when you've got some room.'", 10)
Else
Call GiveItem(index, 1, 100) ' 1 = item number, 100=amount of item(1)
Call PlayerMsg(index, "You recieved some gold.", BrightYellow)
Call PlayerMsg(index, "You completed this quest!.", BrightYellow)
Call RaiseFlag(index, 1, 1) 'raises the flag a level so the event cannot be repeated.
Call SetQuestMap(index, 3, 0)
End If
End If
If GetFlagHeight(index, 1) = 3 Then
Call PlayerMsg(index, "Janelle Says: 'I'll never forget you, " & GetPlayerName(index) & ".'", 10)
End If
Exit Sub
Okay, parts of the code are commented allready but I'll break this all down anyways.
First of all let's examine this block:
Code:
Case 1
If GetFlagHeight(index, 1) = 0 Then 'this checks the height of Flag1
Call PlayerMsg(index, "Janelle Says: 'Hi, could you do this quest for me? I need you to go to the forest and see if it is muddy.'", 10)
Call RaiseFlag(index, 1, 1) 'raises the flag a level so the event cannot be repeated.
Call SetQuestMap(index, 3, 1) ' sets the map to be a quest map for the player
End If
Line for line, here it is:
Case 1 - This checks to see what quest is associated with the tile we stepped on. In this case, it's quest #1.
If GetFlagHeight(index, 1) = 0 Then - This gets the height of flag 1, which is our quest flag, because we are doing quest one. Smart huh? This says if it is at a height of 0, to execute the rest of the statement.
Call PlayerMsg(index, "Janelle Says: 'Hi, could you do this quest for me? I need you to go to the forest and see if it is muddy.'", 10) - this is a cheap way of getting an NPC to talk lol. Worked for me, better ways to do it.
Call RaiseFlag(index, 1, 1) - This raises flag 1 to a height of 1 so that this event can't be repeated.
Call SetQuestMap(index, 3, 1) - This turns the map into a quest map. In this case, we want map 3 to be the forest, so we set it up this way so we can retrieve that info later. Note that this is saved into an INI file which is specific to the player. Long explanantion short, it makes sure other players cant interfere.
End if - Duh :p
Okay now we've set the map, it's time to move on to the next part. What if someone hasn't vissted the forest yet, but returns to Janelle. She can't give the quest again because we flagged it, but we don't want a blank response either. So let's throw this is for amusement.
Code:
If GetFlagHeight(index, 1) = 1 Then
Call PlayerMsg(index, "Janelle Says: 'Please hurry to the forest!'", 10)
End If
Pretty sure that's easy to understand.
Now, at this point we're going to program the events for when the user warps to the quest map.
In your QuestMapData sub, we want to ads this:
Code:
Select Case GetPlayerMap(index)
Case 3
If GetFlagHeight(index, 1) = 1 Then
Call PlayerMsg(index, "You notice that the forest is not very muddy.", 10)
Call RaiseFlag(index, 1, 1)
End If
End Select
Okay, I wont go into enormous detail here, you should start to get the hang of the flag commands.
This checks to see if we are on the quest map, if we are, we make sure the flag height is 1, because if not then we haven' started the quest yet.
Then we are going to use the raise flag command to raise flag 1, by 1 more, so now it = 2.
Now, we go back into the quest sub and finish off the quest.
Code:
If GetFlagHeight(index, 1) = 2 Then
Call PlayerMsg(index, "Janelle Says: 'Oh thank you please take this reward.'", 10)
If FindOpenInvSlot(index, 1) = 0 Then 'looks for an empty slot
Call PlayerMsg(index, "Janelle Says: 'I am sorry but your inventory is full.'", 10)
Call PlayerMsg(index, "Janelle Says: 'Come back when you've got some room.'", 10)
Else
Call GiveItem(index, 1, 100) 'gives them item 20
Call PlayerMsg(index, "You recieved some gold.", BrightYellow)
Call PlayerMsg(index, "You completed this quest!.", BrightYellow)
Call RaiseFlag(index, 1, 1) 'raises the flag a level so the event cannot be repeated.
Call SetQuestMap(index, 3, 0)
End If
End If
If GetFlagHeight(index, 1) = 3 Then
Call PlayerMsg(index, "Janelle Says: 'I'll never forget you, " & GetPlayerName(index) & ".'", 10)
End If
What this does is tell the game we went to the forest and we found out it wasn't that muddy. But our inventory is full. So she tells us to come back. We hit the bank and drop some stuff, run back to janelle and she rewards us with 100 gold coins!
**Note: I know it's commented but I'll say it anyways. The GiveItem(index, 1, 100) command is programmed in relation to my game, where item 1 is gold. You can choose whatever you want as your reward for the quest, so long as you know the item number.
Now, we raise the flag to 3 so the quest can never be repeated again, unless the admin deletes the flag files. After that we set the Questmap back to 0 so that it can later be deleted from the INI file. Makes it a bit smaller.
And that's it. Now all you need to do is start up the game, and go to the map editor. Choose attributes, click Quest Tile, and select the quest, then select a tile you wish to start it on.
If anyone has any issues pleasse tell me. I found minor bugs when doing the tutorial and fixed them without testing
.