Jump to content
Search In
  • More options...
Find results that contain...
Find results in...

[EO] - Simple Graphical Quest System


iSKweek
 Share

Recommended Posts

Hi there! This is my first tutorial so be kind :P

This quest system is based off of Richy's tutorial found [here.](http://www.touchofdeathforums.com/smf/index.php/topic,68426.0.html) You will need to follow the first part of the tutorial (the quest part) for this to all work.

The first thing that needs to be done is to change how he has the Quest scripts set up, I have mine all in a module named 'modQuest'. So create that or just put this where you want (I recommend creating a new module).

Paste this code in there and delete the 'Sub QuestScript' from Richy's tutorial.
```
Option Explicit

Dim msg, qtype, finmsg, updatemsg As String
Dim questnum, reward, rewardamount As Long
'itemquests
Dim reqitem, reqitemamount As Long
'killquests
Dim npcnumber, npckillamount As Long

Public Sub QuestScript(attacker, Script)

Select Case Script
'Script num = npc num
Case 1

    'Check Quest Progress
    Select Case Player(attacker).NPCQuest(Int(Script)).NPCQuestProgress
        Case 0

            'set required item, the item number
            reqitem = 2
            'set req item amount
            reqitemamount = 1
            'set reward, the item number
            reward = 1
            'set reward amount
            rewardamount = 100

            msg = "This is a test quest, go get me a Tentacle Axe and I will give you moneyz."
            qtype = "Get Item"
            questnum = Script

            Call QuestWindow(attacker, msg, qtype, questnum)

        Case 1
            If HasItem(attacker, reqitem) Then
                finmsg = "Thanks for that, have some cash bro"

                Call TakeInvItem(attacker, reqitem, reqitemamount)
                Call GiveInvItem(attacker, reward, rewardamount)

                Call QuestFinish(attacker, finmsg, Script)

            Else: updatemsg = "You don't have the item yet."
            Call QuestUpdate(attacker, updatemsg)
            End If

        Case 2
            updatemsg = "I don't have anymore quests for you."
            Call QuestUpdate(attacker, updatemsg)
        'etc etc

        End Select
Exit Sub

Case 2

'Check Quest Progress
    Select Case Player(attacker).NPCQuest(Int(Script)).NPCQuestProgress

        'not started
        Case 0
                        'set required npc, the npc number
            npcnumber = 3
            'set killamount amount
            npckillamount = 20
            'set reward, the item number
            reward = 1
            'set reward amount
            rewardamount = 100
            msg = "This is a test kill quest, kill 20 female dogs and I will give you moar moneyz."
            qtype = "Kill x"
            questnum = Script

            Call QuestWindow(attacker, msg, qtype, questnum)

        Case 1
            If npckillamount > 0 Then
            updatemsg = "You still need to kill another " & npckillamount & "."
            Call QuestUpdate(attacker, updatemsg)
            Else: finmsg = "Thanks for that, have some cash bro"

                Call GiveInvItem(attacker, reward, rewardamount)
                Call QuestFinish(attacker, finmsg, Script)
            End If

        Case 2
            updatemsg = "I don't have anymore quests for you."
            Call QuestUpdate(attacker, updatemsg)

    End Select
Exit Sub

Case 3
'npc num 3
Exit Sub

Case Else
Call PlayerMsg(attacker, "There is no quest script for NPC Number " & Int(Script) & ". Check the source..", BrightRed)
Exit Sub

End Select
End Sub

'Quest handlers
Sub QuestWindow(ByVal index As Long, ByVal msg As String, ByVal qtype As String, ByVal questnum As Long)

Dim Buffer As clsBuffer
Set Buffer = New clsBuffer
Buffer.WriteLong SQuestWindow
Buffer.WriteString msg
Buffer.WriteString qtype
Buffer.WriteLong questnum
SendDataTo index, Buffer.ToArray()

    Set Buffer = Nothing
End Sub

Sub QuestFinish(ByVal index As Long, ByVal finmsg As String, ByVal questnum As Long)

Dim Buffer As clsBuffer
Set Buffer = New clsBuffer

Buffer.WriteLong SQuestFinish
Buffer.WriteString finmsg
Buffer.WriteLong questnum
SendDataTo index, Buffer.ToArray()

Set Buffer = Nothing
End Sub

Sub QuestUpdate(ByVal index As Long, ByVal updatemsg As String)

Dim Buffer As clsBuffer
Set Buffer = New clsBuffer

Buffer.WriteLong SQuestUpdate
Buffer.WriteString updatemsg
SendDataTo index, Buffer.ToArray()

Set Buffer = Nothing
End Sub

Sub KillQuestCount(ByVal index As Long, ByVal npcnum As Long)
If npcnum = npcnumber Then
    If npckillamout > 0 Then
        npckillamount = npckillamount - 1
        Call PlayerMsg(index, npckillamount & " left to kill.", Green)
    End If
End If

End Sub

```
Each case is the npcNum, which dictates which NPC gives which quest. I am not going to explain the code because most people will just copy and paste it anyway, if you do want help understanding it feel free to ask.

This section is all SERVER side.

In modEnumerations add```
'Quest
    CQuestAccept
    CQuestFinish
```above the ' Make sure CMSG_COUNT is below everything else

and also```
'Quest
    SQuestWindow
    SQuestFinish
SQuestUpdate
```above the 'Make sure SMSG_COUNT is below everything else

Then in modHandleData add
```
'Quest
    HandleDataSub(CQuestAccept) = GetAddress(AddressOf HandleQuestAccept)
    HandleDataSub(CQuestFinish) = GetAddress(AddressOf HandleQuestFinish)
```to the bottom of InitMessages and then```
'Quest
Public Sub HandleQuestAccept(ByVal index As Long, ByRef Data() As Byte, ByVal StartAddR As Long, ByVal ExtraVar As Long)
    Dim questnum As Long
    Dim Buffer As clsBuffer
    Set Buffer = New clsBuffer

    Buffer.WriteBytes Data()
    questnum = Buffer.ReadLong
    Player(index).NPCQuest(Int(questnum)).NPCQuestProgress = 1

End Sub
Public Sub HandleQuestFinish(ByVal index As Long, ByRef Data() As Byte, ByVal StartAddR As Long, ByVal ExtraVar As Long)
    Dim questnum As Long
    Dim Buffer As clsBuffer
    Set Buffer = New clsBuffer

    Buffer.WriteBytes Data()
    questnum = Buffer.ReadLong
    Player(index).NPCQuest(Int(questnum)).NPCQuestProgress = 2

End Sub

```to the very bottom of the module.

In modCombat -> PlayerAttackNpc, look for```
If Damage >= MapNpc(mapNum).Npc(mapNpcNum).Vital(Vitals.HP) Then
```and add```
'check if a quest npc, if so minus one from kills needed
        Call KillQuestCount(attacker, npcnum)
```under it.

That is all for the Server.

**CLIENT side.**

First some form work. Add 3 pictureboxes. One named picQuestWindow, picQuestFinish, the other named picQuestUpdate.

picQuestWindow
Add 4 labels, one named lblQuestMsg, one lblQuestNum, the other lblQuestType and one with a caption of "Quest Window".
Add 2 command buttons, one cmdQuestOk the other cmdQuestCancel.

picQuestFinish
Add 3 labels, one named lblQuestFinishMsg, the other lblQuestType and one with a caption of "Quest Window".
Add a command button, cmdQuestFinish.

picQuestUpdate
Label named lblQuestUpdate and a cmdButton named cmdQuestUpdateOK.

In frmMain add```
Private Sub cmdQuestFinish_Click()
    Dim questnum As Long
    questnum = lblquesnum2.Caption
    Call QuestFinish(questnum)
    picQuestFinish.Visible = False
End Sub

Private Sub cmdQuestOk_Click()
    Dim questnum As Integer
    questnum = lblQuestNum.Caption
    picQuestWindow.Visible = False
    Call AcceptQuest(questnum)
End Sub

Private Sub cmdQuestCancel_Click()
    picQuestWindow.Visible = False
End Sub

Private Sub cmdQuestUpdateOK_Click()
    picQuestUpdate.Visible = False
End Sub
```

In modClientTCP add```
'Quest
Public Sub AcceptQuest(ByVal questnum As Long)
    Dim Buffer As clsBuffer
    Set Buffer = New clsBuffer
    Buffer.WriteLong CQuestAccept
    Buffer.WriteLong questnum
    SendData Buffer.ToArray
    Set Buffer = Nothing
End Sub
Public Sub FinishQuest(ByVal questnum As Long)
    Dim Buffer As clsBuffer
    Set Buffer = New clsBuffer
    Buffer.WriteLong CQuestAccept
    Buffer.WriteLong questnum
    SendData Buffer.ToArray
    Set Buffer = Nothing
End Sub

Public Sub QuestFinish(ByVal questnum As Long)
    Dim Buffer As clsBuffer
    Set Buffer = New clsBuffer
    Buffer.WriteLong CQuestFinish
    Buffer.WriteLong questnum
    SendData Buffer.ToArray
    Set Buffer = Nothing
End Sub

Private Sub HandleQuestUpdate(ByVal Index As Long, ByRef Data() As Byte, ByVal EditorIndex As Byte, ByVal StartAddr As Long, ByVal ExtraVar As Long)

Dim Buffer As clsBuffer
Dim Msg As String

Set Buffer = New clsBuffer
Buffer.WriteBytes Data()

Msg = Buffer.ReadString

frmMain.picQuestUpdate.top = frmMain.picScreen.top / 2

frmMain.picQuestUpdate.Visible = True
frmMain.lblQuestUpdate.Caption = "Quest Update: " & Msg

End Sub

```at the bottom of the module.

In modEnumerations add```
'Quest
    CQuestAccept
    CQuestFinish
```above 'Make sure CMSG_Count blah blah and```
'Quest
    SQuestWindow
    SQuestFinish
SQuestUpdate
```above 'Make sure SMSG_Count blah blah.

In modHandleData add```
'Quest
    HandleDataSub(SQuestWindow) = GetAddress(AddressOf HandleQuestWindow)
    HandleDataSub(SQuestFinish) = GetAddress(AddressOf HandleQuestFinish)
HandleDataSub(SQuestUpdate) = GetAddress(AddressOf HandleQuestUpdate)
```at the bottom of InitMessages and then```
'Quest
Private Sub HandleQuestWindow(ByVal Index As Long, ByRef Data() As Byte, ByVal EditorIndex As Byte, ByVal StartAddr As Long, ByVal ExtraVar As Long)

Dim Buffer As clsBuffer
Dim Msg As String
Dim Qtype As String
Dim questnum As Long

Set Buffer = New clsBuffer
Buffer.WriteBytes Data()

Msg = Buffer.ReadString
Qtype = Buffer.ReadString
questnum = Buffer.ReadLong

frmMain.picQuestWindow.Visible = True
frmMain.lblQuestMsg.Caption = "Quest Description: " & Msg
frmMain.lblQuestType.Caption = "Quest Type: " & Qtype
frmMain.lblQuestNum.Caption = questnum

End Sub

Private Sub HandleQuestFinish(ByVal Index As Long, ByRef Data() As Byte, ByVal EditorIndex As Byte, ByVal StartAddr As Long, ByVal ExtraVar As Long)

Dim Buffer As clsBuffer
Dim Msg As String
Dim questnum As Long

Set Buffer = New clsBuffer
Buffer.WriteBytes Data()

Msg = Buffer.ReadString
questnum = Buffer.ReadLong

frmMain.picQuestFinish.Visible = True
frmMain.lblQuestFinishMsg.Caption = "Quest Finish: " & Msg
frmMain.lblquesnum2.Caption = questnum

End Sub
```to the bottom of the module.

I think that is everything, it isn't too graphically pleasing but design isn't my strong point :P If there is any problems just let me know, report any bugs and if you have suggestions on how to improve the code please let me know :D

Thanks, Skweek.

Screenshots:

>! ![](http://img524.imageshack.us/img524/733/questdesc.jpg)

>! ![](http://img191.imageshack.us/img191/5048/questfin.jpg)

Exp rewards: http://www.touchofdeathforums.com/smf/index.php/topic,69793.0.html
Link to comment
Share on other sites

Ok, update time. I have added a few features that allow for kill x amount of x quests.

**Client:**

New picBox named picQuestUpdate. Label named lblQuestUpdate and a cmdButton named cmdQuestUpdateOK.

Add```
Private Sub cmdQuestUpdateOK_Click()
    picQuestUpdate.Visible = False
End Sub
```anywhere on frmMain.

Add```
Private Sub HandleQuestUpdate(ByVal Index As Long, ByRef Data() As Byte, ByVal EditorIndex As Byte, ByVal StartAddr As Long, ByVal ExtraVar As Long)

Dim Buffer As clsBuffer
Dim Msg As String

Set Buffer = New clsBuffer
Buffer.WriteBytes Data()

Msg = Buffer.ReadString

frmMain.picQuestUpdate.top = frmMain.picScreen.top / 2

frmMain.picQuestUpdate.Visible = True
frmMain.lblQuestUpdate.Caption = "Quest Update: " & Msg

End Sub
```to the bottom of modHandleData and```
HandleDataSub(SQuestUpdate) = GetAddress(AddressOf HandleQuestUpdate)
```to the bottom of InitMessages.

Add```
SQuestUpdate
```to modEnumerations (server and client)

**Server:**

Add```
Sub QuestUpdate(ByVal index As Long, ByVal updatemsg As String)

Dim Buffer As clsBuffer
Set Buffer = New clsBuffer

Buffer.WriteLong SQuestUpdate
Buffer.WriteString updatemsg
SendDataTo index, Buffer.ToArray()

Set Buffer = Nothing
End Sub

Sub KillQuestCount(ByVal index As Long, ByVal npcnum As Long)
If npcnum = npcnumber Then
    If npckillamout > 0 Then
        npckillamount = npckillamount - 1
        Call PlayerMsg(index, npckillamount & " left to kill.", Green)
    End If
End If

```to the bottom of modQuest.
```
'killquests
Dim npcnumber, npckillamount As Long
```at the top of modQuest.

Add```
'check if a quest npc, if so minus one from kills needed
        Call KillQuestCount(attacker, npcnum)
```to modCombat. Add it anywhere in the```
If Damage >= MapNpc(mapNum).Npc(mapNpcNum).Vital(Vitals.HP) Then
```statement. I will update the first post with these changes.
Link to comment
Share on other sites

Well at the moment it is just a picture box, so if you designed your own UI and saved it in the client folder you could use```
frmMain.picQuestWindow.Picture = LoadPicture(App.Path & "\data files\graphics\gui\main\questUI.jpg")
```to load it up. It just might need some moving around of labels and such. :)
Link to comment
Share on other sites

@Xlithan:

> …..  :sad:  It doesn't work.  I have NPC 1 set as scripted, haven't changed the code for the quest from this post, I go to attack the NPC and nothing happens.

Let me just check something, I have a feeling I had to change something.

@Ezand:

> Looks good!

Thanks!

EDIT: To Xlithan,

Find```
' Check if at same coordinates
            Select Case GetPlayerDir(attacker)
                Case DIR_UP
                    NpcX = MapNpc(mapNum).Npc(mapNpcNum).x
                    NpcY = MapNpc(mapNum).Npc(mapNpcNum).y + 1
                Case DIR_DOWN
                    NpcX = MapNpc(mapNum).Npc(mapNpcNum).x
                    NpcY = MapNpc(mapNum).Npc(mapNpcNum).y - 1
                Case DIR_LEFT
                    NpcX = MapNpc(mapNum).Npc(mapNpcNum).x + 1
                    NpcY = MapNpc(mapNum).Npc(mapNpcNum).y
                Case DIR_RIGHT
                    NpcX = MapNpc(mapNum).Npc(mapNpcNum).x - 1
                    NpcY = MapNpc(mapNum).Npc(mapNpcNum).y
            End Select
```in modCombat (server side)

Underneath it there should be an if statement checking the npc type or something. I am not sure what the original code is :P

My section of that code looks like this```
If NpcX = GetPlayerX(attacker) Then
                If NpcY = GetPlayerY(attacker) Then
                    If Npc(npcnum).Behaviour = NPC_BEHAVIOUR_SCRIPTED Then
                        CanPlayerAttackNpc = False
                        Call QuestScript(attacker, Int(npcnum))
                        Exit Function
                    ElseIf Npc(npcnum).Behaviour = NPC_BEHAVIOUR_FRIENDLY Then
                        CanPlayerAttackNpc = False
                        Call SendNpcChat(attacker, npcnum)
                        Exit Function
                    Else: CanPlayerAttackNpc = True
                    End If
                End If
            End If
```
The main part is the```
If Npc(npcnum).Behaviour = NPC_BEHAVIOUR_SCRIPTED Then
                        CanPlayerAttackNpc = False
                        Call QuestScript(attacker, Int(npcnum))
                        Exit Function
```
Try adding that in and let me know if it works.
Link to comment
Share on other sites

Mine looks like this:

```
If NpcX = GetPlayerX(attacker) Then
                If NpcY = GetPlayerY(attacker) Then
                    If Npc(npcNum).Behaviour <> NPC_BEHAVIOUR_FRIENDLY And Npc(npcNum).Behaviour <> NPC_BEHAVIOUR_SHOPKEEPER And Npc(npcNum).Behaviour <> NPC_BEHAVIOUR_SCRIPTED Then
                        CanPlayerAttackNpc = True
                        If Npc(npcNum).Behaviour = NPC_BEHAVIOUR_SCRIPTED Then
                            CanPlayerAttackNpc = False
                            Call QuestScript(attacker, Int(npcNum))
                            Exit Function
                        End If
                        If Len(Trim$(Npc(npcNum).AttackSay)) > 0 Then
                            PlayerMsg attacker, Trim$(Npc(npcNum).Name) & ": " & Trim$(Npc(npcNum).AttackSay), White
                        End If
                    End If
                End If
            End If
```
Link to comment
Share on other sites

@iSkweek:

> Just use more checkpoints.
>
> like: checkpoint = 0 start of quest 1
> checkpoint = 1 started quest 1
> checkpoint = 2 finished quest 1
> checkpoint = 3 start of quest 2
>
> etc etc :)

So, a "checkpoint" Is the case inside each case, am i right?
also, sorry for so many questions. Where exactly would I put in that code you posted to add a UI to the quest boxes?
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...