01-06-2006, 09:16 PM
----===== Chest Tile tutorial =====----
Difficulty: 3/5
All this tutorial will do is allow chests to be placed on tiles, display them being opened and closed, allow you to block players from opening them a second time and update the chests.
This isn’t exactly based on anything else, though I did advise someone to try copying what’s already in the code I’m doing it this way because I can implement features better like this =)
Overview (Written after finishing this)
When this is finished you should be able to create a chest with the help of a chest editor that will display 3 item lists that will also give the name, type of item and the picture once you’ve clicked on an item. You can also set if a player is able to open the chest more then once and if the chest is edited then a player is automatically able to reopen the new chest. Only problem with this is that if you use two or more of the same chests anywhere and one is opened, they are all set as opened until the time set to close after has elapsed, same for if the player is only allowed to open the chest once, even if they open the same map in a different location it will count as the same map.
![[Image: chesteditoraction1hb.th.png]](http://img372.imageshack.us/img372/8498/chesteditoraction1hb.th.png)
^^^ ChestEditor
![[Image: chestmap6as.th.png]](http://img216.imageshack.us/img216/9051/chestmap6as.th.png)
^^^ Chest Tile
Ok, Lets start by adding a Chest type that will basically describe a new data type and what it will store (Like chest items etc)
Add the following code to the bottom of modTypes in both server and client
Now we need to add a constant that dictates how many different chests can be made add one time, so in both Client and server in modConstants find’MAX_PLAYERS’ and under it, add:
Now we need to actually make the variable that will store each chests detail so find in both Server and clients
And add under it add
Now, add a new form to the client, and change the following properties
Name - frmChestEditor
BorderStyle - 1 - Fixed Single
Caption - Chest Editor
StartUpPosition - 2 - Center Screen
Now, add a textbox somewhere (This will be the chest name)
Name - txtName
Text - (empty)
Now add three ListBoxes and for each one change the properties to
Name - lstItem
Index - Give the 1st listbox 1
2nd listbox 2
3rd listbox 3
Add 3 Labels, each one under the Listboxes above, then Change the properties to
Name - lblItemName
Alignment - 2 - Center
Caption - Item Name
Index - 1, 2, 3 (Corresponding to the listboxs above them)
Yet again, add another 3 labels under the above labels
Name - lblItemType
Alignment - 2 - Center
Caption - Item Type
Index - 1, 2, 3 (Corresponding to the labels above them)
Now we need some Picture boxes for the items to blt into, so start this off by adding three picture boxes under the label you’ve just added and change the properties to these:
Name - picItem
Index - 1, 2, 3 (Same as above, give it the same index as the objects above it)
Height - 480 (32 pixels)
Width - 480 (32 Pixels)
Yay, still more to come, add a checkbox and the change the properties to;
Name - chkOpenAgain
Caption - Open Once
Time for the objects that will help with how the long the chest will be open for =)
Add a Horizontal Scrollbar (or vertical which ever you prefer)
Name - scrlTime
LargeChange - 100
Max - 32767
Value - 10
Min - 1
Now a label
Name - lblTime
Caption - 10
And a textbox
Name - txtTime
Text - 10
And finally add two command buttons
Name - cmdSave and cmdCancel
Cancel - cmdCancel = true
Default - cmdSave = true
Now all you need to do is add a few labels to show what each thing does.
Once you’ve done that, you should have a form that looks something like this…
![[Image: chesteditor9tw.th.png]](http://img132.imageshack.us/img132/8099/chesteditor9tw.th.png)
Now a bit of code for the form, this is all the code that will go into this form, but it’ll do for now
Double Click on the cancel button and add
Basic line just closes the form and clears it from memory (It also serves to close a form I’ll be adding later)
Now we need the scrollbar to change the textbox and the label that display the same value so double click the scrollbar and add
We also need to do the same for the text box but since we cannot place a limit on the text box, we need to add some range checks and check if the number is numeric, so double click the text box and put this code in, it should be self explanatory.
Now we need a way to activate Chest Editor so let’s start with the text command, find
And below it add;
Basically, it checks if the first 12 letters = /chesteditor and if it is, it will send a packet to the server requesting chest editor and will then clear the text onscreen.
Now we need code for the server to run once it’s received the packet so find in the server:
And under it, add;
Now, we need to allow the client to do something when we receive the packet so find in the client:
And under it add:
This pretty much opens up index form and lists all the chest names down in the list and also set a flag (InChestEditor) so we know what were meant to be editing.
Now, we need to declare the flag so find: (Still in the client)
And add:
Now you also need to find
And add:
And also find:
And under that, add
Now this is the part where the server actually sends the chest details to the client for editing so find what you added earlier in the server
Now underneath it add:
Also find
And add:
The code above just sends one of the chests details to the client ready to be viewed and edited.
The client needs to interpret this, so find what you did earlier:
And add under it:
Now, we need to create the sub ‘ChestEditorInit’ that we’ve called in the above piece of code, all the sub does is load the details onto the Chest Editor form then loads the form, so find the sub
And underneath the sub, add this sub
Ok, now we need to add some more code to the chest editor, this new bit of code will add the ability to view item picture, name and type when we click on it. First let’s deal with getting the item name.
Double click on one of the listbox on the chest editor window and add this piece of code:
This just checks if an item is selected, if it is, it will retrieve the item name, if not it will just replace it with N/A
Now we need to change the item type label, so under(Which you just added) Add this bit:
This may look like quite a bit but its nothing really, all it is checking what type it is, and depending on the type of item, will change the label to different text
Also, under the other bit you just addedAdd:
TADA
Now the form displays the item details, but now we can go one step better and display a picture. I’m not going to do this the normal way where another copy of the items.bmp is loaded into a picture box since that wastes so much memory considering its already loaded into a direct draw surface, so I’m going to do some blting!! YAY!
*cough* Anyway, since a lot of you don’t understand how to blt, I’m going to try explain this as easy as I can (But don’t expect miracles, since I suck at explaining things)
First, we’ll start by adding a timer, that every time is set off, will draw the item back into the picture boxes, so create a timer called ‘tmrBlt’ with an interval of 50.
Then add this code
Not much difficult to understand with this code
DC = DD_ItemSurf.GetDC
This is like an address to the surface which we need to be able to blt something directly from the direct draw surface, only problem is that by doing this, we lock up the surface (I’ll tell you how to unlock it later)
For n = 1 To 3
If lstItem(n).ListIndex > 0 Then
Call BitBlt(picItem(n).hdc, 0, 0, PIC_X, PIC_Y, DC, 0, Item(lstItem(n).ListIndex).Pic * PIC_Y, SRCCOPY)
Else
picItem(n).Refresh
End If
Next n
That is the main section, all it does it runs through each picture box, checks if there’s an item selected in the list box, if there isn’t, it clears the picture box to make it blank by using the refresh function.
If there is an item to be bltted then it will call bitblt.
The first argument, picitem(n).hdc is basically the address for the picture box that were drawing to
The next two arguments are the x,y coordinates and since we want to blt it at the very top corner of the picture box, we have it as 0,0
The next two following them are the width, and height, and for both I have used a constant which at default are both 32 (Same size as the picture box)
Onto the next argument, this is where we supply the address to the source, which in this case is the direct draw surface, which if you remember, we saved to the variable DC
Next two arguments are the source x,y. Since we start on the very left of the item sheet, x = 0, but since y changes depending on the item, we find out what picture number the item is assigned, then we multiply by 32(pic_y) pixels to get the actual location on the items sheet
The final Argument tells it what type of blt to perform, there are many different types, depending on what effects you want but this one (SRCCOPY) just copies the image directly over as it is
The final piece of text (Call DD_ItemSurf.ReleaseDC(DC)) is the part that unlocks the surface we used as a source
Ok so we’ve done the bltting part, but we just need to quickly edit the cancel button before we go onto
Double click cancel button and add this under unload me
Ok, now we need to make another addition to the chest editor. The ability to select what the chest looks like while open or closed, so open up frmChestEditor and add two more picture boxes and a command button and change properties to these:
First Picture Box;-
Name - picOpen
Borderstyle - 0 –None
Width -480 (32 pixels, or equal to pic_x)
Height - 480 (32 Pixels, or equal to pic_y)
Second Picture Box;-
Name - picClose
Borderstyle - 0 –None
Width -480 (32 pixels, or equal to pic_x)
Height - 480 (32 Pixels, or equal to pic_y)
Command Button;-
Name -cmdTile
Caption - View Tiles
Now double click cmdTile and add this code
Now we need to add a new form that will display all the tiles, don’t ask why I decided to put it in a new form, just felt like it =D
Anyway, you need to add the following controls
Timer = Name – tmrBlt interval – 50
Picture Box = Name – picTiles Height – 5760 Width – 3360
ScrollBar(Best horizontal) = Name – scrlTiles
Now, I’m not going to tell you what the code does that I’m about to give you since its pretty explanatory so replace all the code in frmTiles with the following
After you’ve done the above, find the sub you added earlir called and somewhere in the sub, add the following code
Now’s the part where we start doing something, we now have to send the update to the server, and be able to save and load the chests from file.
First lets send the update to the server, double click cmdSave and input this code
All this does is update the clients version of the chest, calls the sub that will read what’s saved and send it and finally unload the windows associated with the ChestEditor by using the unload command
Now for the Sub that organises the info that’s to be send, find and under the sub add this subNow find what you added earlier
And under it, add
Yay, done the majority of the work, now all we got to do is check if a player can open it and gain a prize and then close it after.
First, we need to add two temp variables to the chest type server side, so find type ChestRec in the server and in the bottom add
Also, in both the client and server, findAnd under it add
We now need to add the chest tile to map editor with a new form to allow a chest to be placed on the map, so first add an option button onto the attributes frame called optChest and double click it and add the code
For the people who don’t know what vbmodal does, it just pretty much loads the form on top of the owner (if not specified, like here, it’s just the form it was called from) and doesn’t allow control to the form owner until the window is closed.
Ok, so make a new form and change the following properties
Name - frmMapChest
BorderStyle - Fixed Style
ShowInTask - False
Now add the following controls and edited properties
ListBox
Name - lstChest
3 Labels
Name - lblItem
Index - 1,2, 3
Two command buttons
Name -cmdOK and cmdCancel
Cancel -cmdCancel = true
Default -cmdOk = true
Ok, in this form, will be a list with chest names and every time we click on a chest name, the 3 labels will update with what the chests contain so when we load the form, we need to make a request to the server for the chest names and items so add the following to the bottom of modClientTcp
Then in the server at the bottom of modHandleData within the main sub add the following
This doesn’t do much, if the chest packet arrives, it will create a packet consisting of chest names and the items to be sent back to the client.
Now we need to do something similar to the client, so at the bottom of modHandleData in the client (Again in the main sub) add the following
Ok, find in the client
And under it add the following variable
Now open up the frmMapChest form again and copy and paste the following code into it
Again, not much interesting there so I don’t think it warrants an explanation
Ok, find
And under it add
All this bit of code does is actually turn the tile type into a chest
Find:
And under it add
Not much here but this is still quite important, after all what are the mappers going to do if they cant see where they’ve placed the chest tiles.
I’ll go into a bit of an explanation of what this does, the first argument, TexthDC is just the ‘address’ to the surface we are going to blt the text on.
The next two arguments are the x,y arguments (no need to explain them I think)
The following argument is the text that were going to blt, hence were bltting the letter c onto the tile
The final argument is the colour, you can either use rgb() to get a colour, or use the visual basic built in ones that you can call using qbcolor()
Yay, not much to go now, all we need to do is edit a bit of code to stop players walking over chests, code to blt the chests on map and a bit more to allow players to open the chests.
Let’s start with blocking players if they try to walk over the chests
Starting Client side, find in sub CanMove
Swap that with
Find
Swap that with
Again, find
And change that with
And find
And change that with
That change alone is enough to stop most players, but if there’s someone with a hacked, or old client, they wont be stopped so we need to change server side aswell, so find in sub PlayerMove
And change that with
Same with
And change that with
Yet again, find
swap with
Yet again, find
swap with
Ok, time for the OPENING CHEST part, woooo000ooo
Server side in modHandleData locate and add the following code
All this does is looks for a chest in front of the player and calls the sub that will soon do all the item giving
Now we need to create the routine that will do all the opening chest business so open up modGameLogic server side and at the bottom at
Pretty basic, checks if it’s a valid chest then checks if the chest is still open from someone else. It will then follow that by checking if a user has opened it before by checking what version the chest was when they last opened it (If they have) and if it’s the same as current version, then shouldn’t allow them (that is if the chest disallows it)
Now then, we now know the user can open the chest so lets do it, first we give the user the 3 items (If one of the items is blank, I wont do anything) and following that it will try construct a message depending on how many items were collected
Need to add a quick edit to the client, find the ChestRec type and add to the bottom
Now add the following to the bottom of the main sub in modHandleData
These two packets handle the open and closed chest packets from the server which are used for deciding if a chest is to be blted with an open or closed tile.
Now for some actual bltting, add the following sub to the bottom of modGameLogic
And then find
And under it add
Now for the final bit, getting the server to close the chests so find
And add under it
Also declare TotalTime at the top of the sub
That’s the tut finished, horay, not much else to say, I started rushing this towards the end since this amazingly took me 3 nights =/ (mainly because I kept watching tv, doing coursework or playing games every 10 mins)
Ok, forgot one small part that updates the chests for players, find in the server
And under that sub add the following sub
Also find in modHandleData in the serverAnd under it add
Now add to the bottom of modHandleData in the client (Within the main sub)
Difficulty: 3/5
All this tutorial will do is allow chests to be placed on tiles, display them being opened and closed, allow you to block players from opening them a second time and update the chests.
This isn’t exactly based on anything else, though I did advise someone to try copying what’s already in the code I’m doing it this way because I can implement features better like this =)
Overview (Written after finishing this)
When this is finished you should be able to create a chest with the help of a chest editor that will display 3 item lists that will also give the name, type of item and the picture once you’ve clicked on an item. You can also set if a player is able to open the chest more then once and if the chest is edited then a player is automatically able to reopen the new chest. Only problem with this is that if you use two or more of the same chests anywhere and one is opened, they are all set as opened until the time set to close after has elapsed, same for if the player is only allowed to open the chest once, even if they open the same map in a different location it will count as the same map.
![[Image: chesteditoraction1hb.th.png]](http://img372.imageshack.us/img372/8498/chesteditoraction1hb.th.png)
^^^ ChestEditor
![[Image: chestmap6as.th.png]](http://img216.imageshack.us/img216/9051/chestmap6as.th.png)
^^^ Chest Tile
Ok, Lets start by adding a Chest type that will basically describe a new data type and what it will store (Like chest items etc)
Add the following code to the bottom of modTypes in both server and client
Code:
Type ChestRec
ChestName As String ' ShortHandName
ItemOne As Integer
ItemTwo As Integer
ItemThree As Integer
StayOpen As Integer ' How long it stays open (Seconds)
OpenOnce As Boolean ' Weither players can open it more then once
Revision As Byte ' Chest Version (If chest is editted we might want player to open it again)
' --- Open Chest Anim
OpenTileX As Integer
OpenTileY As Integer
' --- Closed Chest Anim
ClosedTileX As Integer
ClosedTileY As Integer
End Type
Now we need to add a constant that dictates how many different chests can be made add one time, so in both Client and server in modConstants find’MAX_PLAYERS’ and under it, add:
Code:
Public Const MAX_CHESTS = 100
Now we need to actually make the variable that will store each chests detail so find in both Server and clients
Code:
Public Spell(1 To MAX_SPELLS) As SpellRec
And add under it add
Code:
Public Chest(1 To MAX_CHESTS) As ChestRec
Now, add a new form to the client, and change the following properties
Name - frmChestEditor
BorderStyle - 1 - Fixed Single
Caption - Chest Editor
StartUpPosition - 2 - Center Screen
Now, add a textbox somewhere (This will be the chest name)
Name - txtName
Text - (empty)
Now add three ListBoxes and for each one change the properties to
Name - lstItem
Index - Give the 1st listbox 1
2nd listbox 2
3rd listbox 3
Add 3 Labels, each one under the Listboxes above, then Change the properties to
Name - lblItemName
Alignment - 2 - Center
Caption - Item Name
Index - 1, 2, 3 (Corresponding to the listboxs above them)
Yet again, add another 3 labels under the above labels
Name - lblItemType
Alignment - 2 - Center
Caption - Item Type
Index - 1, 2, 3 (Corresponding to the labels above them)
Now we need some Picture boxes for the items to blt into, so start this off by adding three picture boxes under the label you’ve just added and change the properties to these:
Name - picItem
Index - 1, 2, 3 (Same as above, give it the same index as the objects above it)
Height - 480 (32 pixels)
Width - 480 (32 Pixels)
Yay, still more to come, add a checkbox and the change the properties to;
Name - chkOpenAgain
Caption - Open Once
Time for the objects that will help with how the long the chest will be open for =)
Add a Horizontal Scrollbar (or vertical which ever you prefer)
Name - scrlTime
LargeChange - 100
Max - 32767
Value - 10
Min - 1
Now a label
Name - lblTime
Caption - 10
And a textbox
Name - txtTime
Text - 10
And finally add two command buttons
Name - cmdSave and cmdCancel
Cancel - cmdCancel = true
Default - cmdSave = true
Now all you need to do is add a few labels to show what each thing does.
Once you’ve done that, you should have a form that looks something like this…
![[Image: chesteditor9tw.th.png]](http://img132.imageshack.us/img132/8099/chesteditor9tw.th.png)
Now a bit of code for the form, this is all the code that will go into this form, but it’ll do for now
Double Click on the cancel button and add
Code:
Unload me
Unload frmTiles
Now we need the scrollbar to change the textbox and the label that display the same value so double click the scrollbar and add
Code:
' --- Change the values for the txt and lbls
lblTime.Caption = scrlTime.Value
txtTime.Text = scrlTime.Value
Code:
' --- Check if the time entered is within range and is actually a number
If Not IsNumeric(txtTime.Text) Then txtTime.Text = 10
If txtTime.Text > scrlTime.Max Then txtTime.Text = scrlTime.Max
If txtTime.Text < scrlTime.Min Then txtTime.Text = scrlTime.Min
' --- Change the values for the txt and lbls
lblTime.Caption = txtTime.Text
scrlTime.Value = txtTime.Text
Code:
' Map Editor
If LCase(Mid(MyText, 1, 10)) = "/mapeditor" Then
Call SendRequestEditMap
MyText = ""
Exit Sub
End If
Code:
' Chest Editor
If LCase(Mid(MyText, 1, 12)) = "/chesteditor" Then
Call SendRequestEditChest
MyText = ""
Exit Sub
End If
Basically, it checks if the first 12 letters = /chesteditor and if it is, it will send a packet to the server requesting chest editor and will then clear the text onscreen.
Now we need code for the server to run once it’s received the packet so find in the server:
Code:
' :::::::::::::::::::::::::::::
' :: Request edit map packet ::
' :::::::::::::::::::::::::::::
If LCase(Parse(0)) = "requesteditmap" Then
' Prevent hacking
If GetPlayerAccess(Index) < ADMIN_MAPPER Then
Call HackingAttempt(Index, "Admin Cloning")
Exit Sub
End If
Call SendDataTo(Index, "EDITMAP" & SEP_CHAR & END_CHAR)
Exit Sub
End If
Code:
' :::::::::::::::::::::::::::::::
' :: Request edit Chest packet ::
' :::::::::::::::::::::::::::::::
If LCase(Parse(0)) = "requesteditchest" Then
' Prevent hacking
If GetPlayerAccess(Index) < ADMIN_MAPPER Then
Call HackingAttempt(Index, "Admin Cloning")
Exit Sub
End If
Dim packet As String
packet = "CHESTEDITOR" & SEP_CHAR
For n = 1 To MAX_CHESTS
packet = packet & Chest(n).ChestName & SEP_CHAR
Next n
Call SendDataTo(Index, packet & END_CHAR)
Exit Sub
End If
Now, we need to allow the client to do something when we receive the packet so find in the client:
Code:
' ::::::::::::::::::::
' :: Social packets ::
' ::::::::::::::::::::
If (LCase(Parse(0)) = "saymsg") Or (LCase(Parse(0)) = "broadcastmsg") Or (LCase(Parse(0)) = "globalmsg") Or (LCase(Parse(0)) = "playermsg") Or (LCase(Parse(0)) = "mapmsg") Or (LCase(Parse(0)) = "adminmsg") Then
Call AddText(Parse(1), Val(Parse(2)))
Exit Sub
End If
And under it add:
Code:
' :::::::::::::::::::::::::
' :: Chest editor packet ::
' :::::::::::::::::::::::::
If (LCase(Parse(0)) = "chesteditor") Then
InChestEditor = True
'---Update chest names
For n = 1 To MAX_CHESTS
Chest(n).ChestName = Parse(n + 1)
Next n
frmIndex.Show
frmIndex.lstIndex.Clear
' Add the names
For i = 1 To MAX_CHESTS
frmIndex.lstIndex.AddItem i & ": " & Trim(Chest(i).ChestName)
Next i
frmIndex.lstIndex.ListIndex = 0
Exit Sub
End If
This pretty much opens up index form and lists all the chest names down in the list and also set a flag (InChestEditor) so we know what were meant to be editing.
Now, we need to declare the flag so find: (Still in the client)
Code:
Public InSpellEditor As Boolean
Code:
Public InChestEditor As Boolean
Now you also need to find
Code:
InSpellEditor = False
Code:
InChestEditor = False
Code:
If InSpellEditor = True Then
Call SendData("EDITSPELL" & SEP_CHAR & EditorIndex & SEP_CHAR & END_CHAR)
End If
And under that, add
Code:
If InChestEditor = True Then
Call SendData("EDITCHEST" & SEP_CHAR & EditorIndex & SEP_CHAR & END_CHAR)
End If
Now this is the part where the server actually sends the chest details to the client for editing so find what you added earlier in the server
Code:
' :::::::::::::::::::::::::::::::
' :: Request edit Chest packet ::
' :::::::::::::::::::::::::::::::
If LCase(Parse(0)) = "requesteditchest" Then
' Prevent hacking
If GetPlayerAccess(Index) < ADMIN_MAPPER Then
Call HackingAttempt(Index, "Admin Cloning")
Exit Sub
End If
Dim packet As String
packet = "CHESTEDITOR" & SEP_CHAR
For n = 1 To MAX_CHESTS
packet = packet & Chest(n).ChestName & SEP_CHAR
Next n
Call SendDataTo(Index, packet & END_CHAR)
Exit Sub
End If
Now underneath it add:
Code:
' :::::::::::::::::::::::
' :: Edit chest packet ::
' :::::::::::::::::::::::
If LCase(Parse(0)) = "editchest" Then
' Prevent hacking
If GetPlayerAccess(Index) < ADMIN_MAPPER Then
Call HackingAttempt(Index, "Admin Cloning")
Exit Sub
End If
' The item #
n = Val(Parse(1))
' Prevent hacking
If n < 0 Or n > MAX_CHESTS Then
Call HackingAttempt(Index, "Invalid Item Index")
Exit Sub
End If
Call AddLog(GetPlayerName(Index) & " editing item #" & n & ".", ADMIN_LOG)
Call SendEditChestTo(Index, n)
End If
Also find
Code:
Sub SendPlayerXY(ByVal Index As Long)
Dim Packet As String
Packet = "PLAYERXY" & SEP_CHAR & GetPlayerX(Index) & SEP_CHAR & GetPlayerY(Index) & SEP_CHAR & END_CHAR
Call SendDataTo(Index, Packet)
End Sub
And add:
Code:
Sub SendEditChestTo(ByVal Index As Long, ByVal ChestNum As Long)
Dim Packet As String
Packet = "EDITCHEST" & SEP_CHAR & ChestNum & SEP_CHAR & Trim(Chest(ChestNum).ChestName) & SEP_CHAR & Chest(ChestNum).ItemOne & SEP_CHAR & Chest(ChestNum).ItemTwo & SEP_CHAR & Chest(ChestNum).ItemThree & SEP_CHAR & Chest(ChestNum).OpenOnce & SEP_CHAR & Chest(ChestNum).StayOpen & SEP_CHAR & Chest(ChestNum).ClosedTileX & SEP_CHAR & Chest(ChestNum).ClosedTileY & SEP_CHAR & Chest(ChestNum).OpenTileX & SEP_CHAR & Chest(ChestNum).OpenTileY & SEP_CHAR & END_CHAR
Call SendDataTo(Index, Packet)
End Sub
The code above just sends one of the chests details to the client ready to be viewed and edited.
The client needs to interpret this, so find what you did earlier:
Code:
' :::::::::::::::::::::::::
' :: Chest editor packet ::
' :::::::::::::::::::::::::
If (LCase(Parse(0)) = "chesteditor") Then
InChestEditor = True
'---Update chest names
For n = 1 To MAX_CHESTS
Chest(n).ChestName = Parse(n + 1)
Next n
frmIndex.Show
frmIndex.lstIndex.Clear
' Add the names
For i = 1 To MAX_CHESTS
frmIndex.lstIndex.AddItem i & ": " & Trim(Chest(i).ChestName)
Next i
frmIndex.lstIndex.ListIndex = 0
Exit Sub
End If
And add under it:
Code:
' :::::::::::::::::::::::
' :: Edit Chest packet ::
' :::::::::::::::::::::::
If (LCase(Parse(0)) = "editchest") Then
n = Val(Parse(1))
' Update the chest
Chest(n).ChestName = Parse(2)
Chest(n).ItemOne = Val(Parse(3))
Chest(n).ItemTwo = Val(Parse(4))
Chest(n).ItemThree = Val(Parse(5))
Chest(n).OpenOnce = Parse(6)
Chest(n).StayOpen = Val(Parse(7))
Chest(n).ClosedTileX = Val(Parse(8))
Chest(n).ClosedTileY = Val(Parse(9))
Chest(n).OpenTileX = Val(Parse(10))
Chest(n).OpenTileY = Val(Parse(11))
' Initialize the chest editor
Call ChestEditorInit
Exit Sub
End If
Now, we need to create the sub ‘ChestEditorInit’ that we’ve called in the above piece of code, all the sub does is load the details onto the Chest Editor form then loads the form, so find the sub
Code:
Public Sub ItemEditorBltItem()
Code:
Public Sub ChestEditorInit()
Dim n As Long, i As Long
' --- Set all the basic settings
frmChestEditor.txtName = Chest(EditorIndex).ChestName
If Chest(EditorIndex).OpenOnce = True Then frmChestEditor.chkOpenAgain = 1
If Chest(EditorIndex).StayOpen < frmChestEditor.scrlTime.Value Then Chest(EditorIndex).StayOpen = frmChestEditor.scrlTime.Min
frmChestEditor.scrlTime.Value = Chest(EditorIndex).StayOpen
' --- Add the items to the listboxes
For n = 1 To 3
frmChestEditor.lstItem(n).AddItem "No Item"
For i = 1 To MAX_ITEMS
frmChestEditor.lstItem(n).AddItem i & ": " & Item(i).Name
Next i
Next n
frmChestEditor.lstItem(1).ListIndex = Chest(EditorIndex).ItemOne
frmChestEditor.lstItem(2).ListIndex = Chest(EditorIndex).ItemTwo
frmChestEditor.lstItem(3).ListIndex = Chest(EditorIndex).ItemThree
frmChestEditor.Show
End Sub
Ok, now we need to add some more code to the chest editor, this new bit of code will add the ability to view item picture, name and type when we click on it. First let’s deal with getting the item name.
Double click on one of the listbox on the chest editor window and add this piece of code:
Code:
If frmChestEditor.lstItem(Index).ListIndex > 0 Then
lblItemName(Index).Caption = Trim(Item(lstItem(Index).ListIndex).Name) Else
lblItemName(Index).Caption = "N/A"
End If
This just checks if an item is selected, if it is, it will retrieve the item name, if not it will just replace it with N/A
Now we need to change the item type label, so under
Code:
lblItemName(Index).Caption = Trim(Item(lstItem(Index).ListIndex).Name)
Code:
Select Case Item(lstItem(Index).ListIndex).Type
Case 0
lblItemType(Index).Caption = "None"
Case 1
lblItemType(Index).Caption = "Weapon"
Case 2
lblItemType(Index).Caption = "Armour"
Case 3
lblItemType(Index).Caption = "Helmet"
Case 4
lblItemType(Index).Caption = "Shield"
Case 5
lblItemType(Index).Caption = "Potion Add HP"
Case 6
lblItemType(Index).Caption = "Potion Add MP"
Case 7
lblItemType(Index).Caption = "Potion Add SP"
Case 8
lblItemType(Index).Caption = "Potion SUB HP"
Case 9
lblItemType(Index).Caption = "Potion SUB MP"
Case 10
lblItemType(Index).Caption = "Potion SUB SP"
Case 11
lblItemType(Index).Caption = "Key"
Case 12
lblItemType(Index).Caption = "Currency"
Case 13
lblItemType(Index).Caption = "Spell"
End Select
This may look like quite a bit but its nothing really, all it is checking what type it is, and depending on the type of item, will change the label to different text
Also, under the other bit you just added
Code:
lblItemName(Index).Caption = "N/A"
Code:
lblItemType(Index).Caption = "N/A"
TADA
Now the form displays the item details, but now we can go one step better and display a picture. I’m not going to do this the normal way where another copy of the items.bmp is loaded into a picture box since that wastes so much memory considering its already loaded into a direct draw surface, so I’m going to do some blting!! YAY!
*cough* Anyway, since a lot of you don’t understand how to blt, I’m going to try explain this as easy as I can (But don’t expect miracles, since I suck at explaining things)
First, we’ll start by adding a timer, that every time is set off, will draw the item back into the picture boxes, so create a timer called ‘tmrBlt’ with an interval of 50.
Then add this code
Code:
Dim n As Integer
Dim DC As Long
' Get the DD Item surface DC
DC = DD_ItemSurf.GetDC
For n = 1 To 3
If lstItem(n).ListIndex > 0 Then
Call BitBlt(picItem(n).hdc, 0, 0, PIC_X, PIC_Y, DC, 0, Item(lstItem(n).ListIndex).Pic * PIC_Y, SRCCOPY)
Else
picItem(n).Refresh
End If
Next n
' Not 100% sure, but it unlocks the surface after you've gotten its dc
Call DD_ItemSurf.ReleaseDC(DC)
DC = DD_ItemSurf.GetDC
This is like an address to the surface which we need to be able to blt something directly from the direct draw surface, only problem is that by doing this, we lock up the surface (I’ll tell you how to unlock it later)
For n = 1 To 3
If lstItem(n).ListIndex > 0 Then
Call BitBlt(picItem(n).hdc, 0, 0, PIC_X, PIC_Y, DC, 0, Item(lstItem(n).ListIndex).Pic * PIC_Y, SRCCOPY)
Else
picItem(n).Refresh
End If
Next n
That is the main section, all it does it runs through each picture box, checks if there’s an item selected in the list box, if there isn’t, it clears the picture box to make it blank by using the refresh function.
If there is an item to be bltted then it will call bitblt.
The first argument, picitem(n).hdc is basically the address for the picture box that were drawing to
The next two arguments are the x,y coordinates and since we want to blt it at the very top corner of the picture box, we have it as 0,0
The next two following them are the width, and height, and for both I have used a constant which at default are both 32 (Same size as the picture box)
Onto the next argument, this is where we supply the address to the source, which in this case is the direct draw surface, which if you remember, we saved to the variable DC
Next two arguments are the source x,y. Since we start on the very left of the item sheet, x = 0, but since y changes depending on the item, we find out what picture number the item is assigned, then we multiply by 32(pic_y) pixels to get the actual location on the items sheet
The final Argument tells it what type of blt to perform, there are many different types, depending on what effects you want but this one (SRCCOPY) just copies the image directly over as it is
The final piece of text (Call DD_ItemSurf.ReleaseDC(DC)) is the part that unlocks the surface we used as a source
Ok so we’ve done the bltting part, but we just need to quickly edit the cancel button before we go onto
Double click cancel button and add this under unload me
Code:
InChestEditor = False
Ok, now we need to make another addition to the chest editor. The ability to select what the chest looks like while open or closed, so open up frmChestEditor and add two more picture boxes and a command button and change properties to these:
First Picture Box;-
Name - picOpen
Borderstyle - 0 –None
Width -480 (32 pixels, or equal to pic_x)
Height - 480 (32 Pixels, or equal to pic_y)
Second Picture Box;-
Name - picClose
Borderstyle - 0 –None
Width -480 (32 pixels, or equal to pic_x)
Height - 480 (32 Pixels, or equal to pic_y)
Command Button;-
Name -cmdTile
Caption - View Tiles
Now double click cmdTile and add this code
Code:
frmTiles.Show
Now we need to add a new form that will display all the tiles, don’t ask why I decided to put it in a new form, just felt like it =D
Anyway, you need to add the following controls
Timer = Name – tmrBlt interval – 50
Picture Box = Name – picTiles Height – 5760 Width – 3360
ScrollBar(Best horizontal) = Name – scrlTiles
Now, I’m not going to tell you what the code does that I’m about to give you since its pretty explanatory so replace all the code in frmTiles with the following
Code:
Option Explicit
Private Sub Form_Load()
' --- Set scrl Limits same as main mapeditor
scrlTiles.Max = frmMirage.scrlPicture.Max
' --- Open it on the side of the chest editor
Me.Left = frmChestEditor.Left + frmChestEditor.Width
Me.top = frmChestEditor.top
End Sub
Private Sub picTiles_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Button = 1 Then
ChestOpenedX = Int(X / PIC_X)
ChestOpenedY = Int(Y / PIC_Y) + scrlTiles.Value
ElseIf Button = 2 Then
ChestClosedX = Int(X / PIC_X)
ChestClosedY = Int(Y / PIC_Y) + scrlTiles.Value
End If
End Sub
Private Sub picTiles_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
If Button = 1 Then
ChestOpenedX = Int(X / PIC_X)
ChestOpenedY = Int(Y / PIC_Y) + scrlTiles.Value
ElseIf Button = 2 Then
ChestClosedX = Int(X / PIC_X)
ChestClosedY = Int(Y / PIC_Y) + scrlTiles.Value
End If
End Sub
Private Sub tmrBlt_Timer()
Dim DC As Long
DC = DD_TileSurf.GetDC
Call BitBlt(picTiles.hdc, 0, 0, picTiles.Width, picTiles.Height, DC, 0, scrlTiles.Value * 32, SRCCOPY)
DD_TileSurf.ReleaseDC (DC)
End Sub
Code:
ChestEditorInit
Code:
ChestClosedX = Chest(EditorIndex).ClosedTileX
ChestClosedY = Chest(EditorIndex).ClosedTileY
ChestopenedX = Chest(EditorIndex).OpenTileX
Chestopenedy = Chest(EditorIndex).OpenTileY
Now’s the part where we start doing something, we now have to send the update to the server, and be able to save and load the chests from file.
First lets send the update to the server, double click cmdSave and input this code
Code:
With Chest(EditorIndex)
.ChestName = txtName.Text
.ItemOne = lstItem(1).ListIndex
.ItemTwo = lstItem(2).ListIndex
.ItemThree = lstItem(3).ListIndex
If chkOpenAgain.Value = 1 Then
.OpenOnce = True
Else
.OpenOnce = True
End If
.StayOpen = scrlTime.Value
.ClosedTileX = ChestClosedX
.ClosedTileY = ChestClosedY
.OpenTileX = ChestOpenedX
.OpenTileY = ChestOpenedY
End With
' Send update =D
Call SendSaveChest(EditorIndex)
InChestEditor = False
' Unload form and the tiles form
Unload frmTiles
Unload Me
Now for the Sub that organises the info that’s to be send, find
Code:
Public Sub SendSaveItem(ByVal ItemNum As Long)
Code:
Public Sub SendSaveChest(ByVal chestnum As Long)
Dim Packet As String
With Chest(chestnum)
Packet = "SAVECHEST" & SEP_CHAR & chestnum & SEP_CHAR & .ChestName & SEP_CHAR & .ItemOne & SEP_CHAR & .ItemTwo & SEP_CHAR & .ItemThree & SEP_CHAR & .OpenOnce & SEP_CHAR & .StayOpen & SEP_CHAR & .ClosedTileX & SEP_CHAR & Chest(chestnum).ClosedTileY & SEP_CHAR & .OpenTileX & SEP_CHAR & .OpenTileY & SEP_CHAR & END_CHAR
End With
Call SendData(Packet)
End Sub
Code:
' :::::::::::::::::::::::
' :: Edit chest packet ::
' :::::::::::::::::::::::
If LCase(Parse(0)) = "editchest" Then
' Prevent hacking
If GetPlayerAccess(Index) < ADMIN_MAPPER Then
Call HackingAttempt(Index, "Admin Cloning")
Exit Sub
End If
' The item #
n = Val(Parse(1))
' Prevent hacking
If n < 0 Or n > MAX_CHESTS Then
Call HackingAttempt(Index, "Invalid Item Index")
Exit Sub
End If
Call AddLog(GetPlayerName(Index) & " editing item #" & n & ".", ADMIN_LOG)
Call SendEditChestTo(Index, n)
End If
Code:
' :::::::::::::::::::::::
' :: Save chest packet ::
' :::::::::::::::::::::::
If LCase(Parse(0)) = "savechest" Then
' Prevent hacking
If GetPlayerAccess(Index) < ADMIN_MAPPER Then
Call HackingAttempt(Index, "Admin Cloning")
Exit Sub
End If
n = Val(Parse(1))
If n < 0 Or n > MAX_CHESTS Then
Call HackingAttempt(Index, "Invalid Chest Index")
Exit Sub
End If
' Update the chest
Chest(n).ChestName = Parse(2)
Chest(n).ItemOne = Val(Parse(3))
Chest(n).ItemTwo = Val(Parse(4))
Chest(n).ItemThree = Val(Parse(5))
Chest(n).OpenOnce = Parse(6)
Chest(n).StayOpen = Val(Parse(7))
Chest(n).ClosedTileX = Val(Parse(8))
Chest(n).ClosedTileY = Val(Parse(9))
Chest(n).OpenTileX = Val(Parse(10))
Chest(n).OpenTileY = Val(Parse(11))
' Save it
Call Savechest(n)
Call AddLog(GetPlayerName(Index) & " saved Chest #" & n & ".", ADMIN_LOG)
Exit Sub
End If
Yay, done the majority of the work, now all we got to do is check if a player can open it and gain a prize and then close it after.
First, we need to add two temp variables to the chest type server side, so find type ChestRec in the server and in the bottom add
Code:
' --- Some temp stuff
AlreadyOpen As Boolean
TimeOpen As Long ' Stores the tick the chest was opened at
Also, in both the client and server, find
Code:
Public Const TILE_TYPE_KEYOPEN = 6
Code:
Public Const TILE_TYPE_CHEST = 7
We now need to add the chest tile to map editor with a new form to allow a chest to be placed on the map, so first add an option button onto the attributes frame called optChest and double click it and add the code
Code:
frmMapchest.show vbmodal
For the people who don’t know what vbmodal does, it just pretty much loads the form on top of the owner (if not specified, like here, it’s just the form it was called from) and doesn’t allow control to the form owner until the window is closed.
Ok, so make a new form and change the following properties
Name - frmMapChest
BorderStyle - Fixed Style
ShowInTask - False
Now add the following controls and edited properties
ListBox
Name - lstChest
3 Labels
Name - lblItem
Index - 1,2, 3
Two command buttons
Name -cmdOK and cmdCancel
Cancel -cmdCancel = true
Default -cmdOk = true
Ok, in this form, will be a list with chest names and every time we click on a chest name, the 3 labels will update with what the chests contain so when we load the form, we need to make a request to the server for the chest names and items so add the following to the bottom of modClientTcp
Code:
Public Sub SendChestInfoRequest()
Dim packet As String
packet = "REQUESTCHESTINFO" & SEP_CHAR & END_CHAR
Call SendData(packet)
End Sub
Then in the server at the bottom of modHandleData within the main sub add the following
Code:
' :::::::::::::::::::::::
' :: Chest Info packet ::
' :::::::::::::::::::::::
If LCase(Parse(0)) = "requestchestinfo" Then
If GetPlayerAccess(Index) < ADMIN_MAPPER Then
Call HackingAttempt(Index, "Admin Cloning")
Exit Sub
End If
packet = "REQUESTCHESTINFO" & SEP_CHAR
For n = 1 To MAX_CHESTS
packet = packet & Chest(n).ChestName & SEP_CHAR & Chest(n).ItemOne & SEP_CHAR & Chest(n).ItemTwo & SEP_CHAR & Chest(n).ItemThree & SEP_CHAR
Next n
packet = packet & END_CHAR
Call SendDataTo(Index, packet)
Exit Sub
End If
This doesn’t do much, if the chest packet arrives, it will create a packet consisting of chest names and the items to be sent back to the client.
Now we need to do something similar to the client, so at the bottom of modHandleData in the client (Again in the main sub) add the following
Code:
' :::::::::::::::::::::::
' :: Chest Info packet ::
' :::::::::::::::::::::::
If LCase(Parse(0)) = "requestchestinfo" Then
i = 1
For n = 1 To MAX_CHESTS
Chest(n).ChestName = Parse(i)
frmMapChest.lstChest.AddItem n & ": " & Trim(Chest(n).ChestName)
Chest(n).ItemOne = Val(Parse(i + 1))
Chest(n).ItemTwo = Val(Parse(i + 2))
Chest(n).ItemThree = Val(Parse(i + 3))
i = i + 4
Next n
Exit Sub
End If
Ok, find in the client
Code:
' Used for map key opene ditor
Public KeyOpenEditorX As Long
Public KeyOpenEditorY As Long
And under it add the following variable
Code:
' Used for Chest ditor
Public ChestListNum As Long
Now open up the frmMapChest form again and copy and paste the following code into it
Code:
Option Explicit
Private Sub cmdCancel_Click()
Unload Me
End Sub
Private Sub cmdOk_Click()
Unload Me
End Sub
Private Sub Form_Load()
' --- Update chest info
Call SendChestInfoRequest
End Sub
Private Sub lstChest_Click()
ChestListNum = lstChest.ListIndex + 1
If Chest(lstChest.ListIndex + 1).ItemOne = 0 Then
lblItem(1).Caption = "N/A"
Else
lblItem(1).Caption = Trim(Item(Chest(lstChest.ListIndex + 1).ItemOne).Name)
End If
If Chest(lstChest.ListIndex + 1).ItemTwo = 0 Then
lblItem(2).Caption = "N/A"
Else
lblItem(2).Caption = Trim(Item(Chest(lstChest.ListIndex + 1).ItemTwo).Name)
End If
If Chest(lstChest.ListIndex + 1).ItemThree = 0 Then
lblItem(3).Caption = "N/A"
Else
lblItem(3).Caption = Trim(Item(Chest(lstChest.ListIndex + 1).ItemThree).Name)
End If
End Sub
Again, not much interesting there so I don’t think it warrants an explanation
Ok, find
Code:
If frmMirage.optKeyOpen.Value = True Then
.Type = TILE_TYPE_KEYOPEN
.Data1 = KeyOpenEditorX
.Data2 = KeyOpenEditorY
.Data3 = 0
End If
And under it add
Code:
If frmMirage.optChest.Value = True And ChestListNum > 0 Then
.Type = TILE_TYPE_CHEST
.Data1 = ChestListNum
.Data2 = 0
.Data3 = 0
End If
Find:
Code:
If .Type = TILE_TYPE_KEYOPEN Then Call DrawText(TexthDC, x * PIC_X + 8, y * PIC_Y + 8, "O", QBColor(White))
And under it add
Code:
If .Type = TILE_TYPE_CHEST Then Call DrawText(TexthDC, x * PIC_X + 8, y * PIC_Y + 8, "C", QBColor(Yellow))
Not much here but this is still quite important, after all what are the mappers going to do if they cant see where they’ve placed the chest tiles.
I’ll go into a bit of an explanation of what this does, the first argument, TexthDC is just the ‘address’ to the surface we are going to blt the text on.
The next two arguments are the x,y arguments (no need to explain them I think)
The following argument is the text that were going to blt, hence were bltting the letter c onto the tile
The final argument is the colour, you can either use rgb() to get a colour, or use the visual basic built in ones that you can call using qbcolor()
Yay, not much to go now, all we need to do is edit a bit of code to stop players walking over chests, code to blt the chests on map and a bit more to allow players to open the chests.
Let’s start with blocking players if they try to walk over the chests
Starting Client side, find in sub CanMove
Code:
If Map.Tile(GetPlayerX(MyIndex), GetPlayerY(MyIndex) - 1).Type = TILE_TYPE_BLOCKED Then
Swap that with
Code:
If Map.Tile(GetPlayerX(MyIndex), GetPlayerY(MyIndex) - 1).Type = TILE_TYPE_BLOCKED Or Map.Tile(GetPlayerX(MyIndex), GetPlayerY(MyIndex) - 1).Type = TILE_TYPE_CHEST Then
Find
Code:
If Map.Tile(GetPlayerX(MyIndex), GetPlayerY(MyIndex) + 1).Type = TILE_TYPE_BLOCKED Then
Swap that with
Code:
If Map.Tile(GetPlayerX(MyIndex), GetPlayerY(MyIndex) + 1).Type = TILE_TYPE_BLOCKED Or Map.Tile(GetPlayerX(MyIndex), GetPlayerY(MyIndex) + 1).Type = TILE_TYPE_CHEST Then
Again, find
Code:
If Map.Tile(GetPlayerX(MyIndex) - 1, GetPlayerY(MyIndex)).Type = TILE_TYPE_BLOCKED Then
And change that with
Code:
If Map.Tile(GetPlayerX(MyIndex) - 1, GetPlayerY(MyIndex)).Type = TILE_TYPE_BLOCKED Or Map.Tile(GetPlayerX(MyIndex) - 1, GetPlayerY(MyIndex)).Type = TILE_TYPE_CHEST Then
And find
Code:
If Map.Tile(GetPlayerX(MyIndex) + 1, GetPlayerY(MyIndex)).Type = TILE_TYPE_BLOCKED Then
And change that with
Code:
If Map.Tile(GetPlayerX(MyIndex) + 1, GetPlayerY(MyIndex)).Type = TILE_TYPE_BLOCKED Or Map.Tile(GetPlayerX(MyIndex) + 1, GetPlayerY(MyIndex)).Type = TILE_TYPE_CHEST Then
That change alone is enough to stop most players, but if there’s someone with a hacked, or old client, they wont be stopped so we need to change server side aswell, so find in sub PlayerMove
Code:
If Map(GetPlayerMap(Index)).Tile(GetPlayerX(Index), GetPlayerY(Index) - 1).Type TILE_TYPE_BLOCKED Then
And change that with
Code:
If Map(GetPlayerMap(Index)).Tile(GetPlayerX(Index), GetPlayerY(Index) - 1).Type TILE_TYPE_BLOCKED And Map(GetPlayerMap(Index)).Tile(GetPlayerX(Index), GetPlayerY(Index) - 1).Type TILE_TYPE_CHEST Then
Same with
Code:
If Map(GetPlayerMap(Index)).Tile(GetPlayerX(Index), GetPlayerY(Index) + 1).Type TILE_TYPE_BLOCKED Then
And change that with
Code:
If Map(GetPlayerMap(Index)).Tile(GetPlayerX(Index), GetPlayerY(Index) + 1).Type TILE_TYPE_BLOCKED And Map(GetPlayerMap(Index)).Tile(GetPlayerX(Index), GetPlayerY(Index) + 1).Type TILE_TYPE_CHEST Then
Yet again, find
Code:
If Map(GetPlayerMap(Index)).Tile(GetPlayerX(Index) - 1, GetPlayerY(Index)).Type TILE_TYPE_BLOCKED Then
swap with
Code:
If Map(GetPlayerMap(Index)).Tile(GetPlayerX(Index) - 1, GetPlayerY(Index)).Type TILE_TYPE_BLOCKED And Map(GetPlayerMap(Index)).Tile(GetPlayerX(Index) - 1, GetPlayerY(Index)).Type TILE_TYPE_CHEST Then
Yet again, find
Code:
If Map(GetPlayerMap(Index)).Tile(GetPlayerX(Index) + 1, GetPlayerY(Index)).Type TILE_TYPE_BLOCKED Then
swap with
Code:
If Map(GetPlayerMap(Index)).Tile(GetPlayerX(Index) + 1, GetPlayerY(Index)).Type TILE_TYPE_BLOCKED And Map(GetPlayerMap(Index)).Tile(GetPlayerX(Index) + 1, GetPlayerY(Index)).Type TILE_TYPE_CHEST Then
Ok, time for the OPENING CHEST part, woooo000ooo
Server side in modHandleData locate
Code:
If LCase(Parse(0)) = "attack" Then
Code:
' Check for chests infront of the player
Select Case GetPlayerDir(Index)
Case DIR_UP
If Map(GetPlayerMap(Index)).Tile(GetPlayerX(Index), GetPlayerY(Index) - 1).Type = TILE_TYPE_CHEST Then
' Check what chest number it is and the open it
Call OpenChest(Index, Map(GetPlayerMap(Index)).Tile(GetPlayerX(Index), GetPlayerY(Index) - 1).Data1)
End If
Case DIR_DOWN
If Map(GetPlayerMap(Index)).Tile(GetPlayerX(Index), GetPlayerY(Index) + 1).Type = TILE_TYPE_CHEST Then
' Check what chest number it is and the open it
Call OpenChest(Index, Map(GetPlayerMap(Index)).Tile(GetPlayerX(Index), GetPlayerY(Index) + 1).Data1)
End If
Case DIR_LEFT
If Map(GetPlayerMap(Index)).Tile(GetPlayerX(Index) - 1, GetPlayerY(Index)).Type = TILE_TYPE_CHEST Then
' Check what chest number it is and the open it
Call OpenChest(Index, Map(GetPlayerMap(Index)).Tile(GetPlayerX(Index) - 1, GetPlayerY(Index)).Data1)
End If
Case DIR_RIGHT
If Map(GetPlayerMap(Index)).Tile(GetPlayerX(Index) + 1, GetPlayerY(Index)).Type = TILE_TYPE_CHEST Then
' Check what chest number it is and the open it
Call OpenChest(Index, Map(GetPlayerMap(Index)).Tile(GetPlayerX(Index) + 1, GetPlayerY(Index)).Data1)
End If
End Select
All this does is looks for a chest in front of the player and calls the sub that will soon do all the item giving
Now we need to create the routine that will do all the opening chest business so open up modGameLogic server side and at the bottom at
Code:
Public Sub OpenChest(ByVal Index As Long, ByVal ChestNum As Long)
Dim FileName As String
Dim Msg As String
Dim OneOrMore As Boolean
If ChestNum < 1 Then Exit Sub
' --- Check if the chest is already open
If Chest(ChestNum).AlreadyOpen = True Then Exit Sub
FileName = App.Path & "\Accounts\" & Trim(Player(Index).Login) & ".ini"
' --- Check if players already opened it (If revision = current revision then they've opened it)
If Val(GetVar(FileName, "CHEST", STR(ChestNum))) = Chest(ChestNum).Revision And Chest(ChestNum).OpenOnce Then
Call PlayerMsg(Index, "The Chests still Closed tight since you last opened it!", Green)
Exit Sub
End If
' --- Give items to player then construct a message to send player
Call GiveItem(Index, Chest(ChestNum).ItemOne, 1)
Call GiveItem(Index, Chest(ChestNum).ItemTwo, 1)
Call GiveItem(Index, Chest(ChestNum).ItemThree, 1)
' --- Custom message if chest is empty (You evil soul =p)
If Chest(ChestNum).ItemOne = 0 And Chest(ChestNum).ItemTwo = 0 And Chest(ChestNum).ItemThree = 0 Then
Call PlayerMsg(Index, "You opened the chest but it appears that its empty after all that trouble you went to!", QBColor(BrightGreen))
Else
Msg = "You opened the chest and found a "
If Chest(ChestNum).ItemOne > 0 Then
Msg = Msg & Trim(Item(Chest(ChestNum).ItemOne).Name)
' --- So I can create a grammatically correct message
OneOrMore = True
End If
If Chest(ChestNum).ItemTwo > 0 Then
If OneOrMore Then Msg = Msg & " along with a "
Msg = Msg & Trim(Item(Chest(ChestNum).ItemTwo).Name)
' --- So I can create a grammatically correct message
OneOrMore = True
End If
If Chest(ChestNum).ItemThree > 0 Then
If OneOrMore Then Msg = Msg & " and "
Msg = Msg & Trim(Item(Chest(ChestNum).ItemThree).Name)
End If
' --- Now update Player file to say that its been opened
Call PutVar(FileName, "CHEST", STR(ChestNum), STR(Chest(ChestNum).Revision))
Call PlayerMsg(Index, Msg, BrightGreen)
' --- Set it so the chest appears open (And record time opened)
Chest(ChestNum).AlreadyOpen = True
Chest(ChestNum).TimeOpen = GetTickCount
' Update everyone on the map
Call SendDataToMap(GetPlayerMap(Index), "CHESTOPEN" & SEP_CHAR & ChestNum & SEP_CHAR & END_CHAR)
End If
End Sub
Pretty basic, checks if it’s a valid chest then checks if the chest is still open from someone else. It will then follow that by checking if a user has opened it before by checking what version the chest was when they last opened it (If they have) and if it’s the same as current version, then shouldn’t allow them (that is if the chest disallows it)
Now then, we now know the user can open the chest so lets do it, first we give the user the 3 items (If one of the items is blank, I wont do anything) and following that it will try construct a message depending on how many items were collected
Need to add a quick edit to the client, find the ChestRec type and add to the bottom
Code:
AlreadyOpen As Boolean
Now add the following to the bottom of the main sub in modHandleData
Code:
' :::::::::::::::::::::::
' :: Chest Open packet ::
' :::::::::::::::::::::::
If LCase(Parse(0)) = "chestopen" Then
Chest(Val(Parse(1))).AlreadyOpen = True
Exit Sub
End If
' ::::::::::::::::::::::::
' :: Chest Close packet ::
' ::::::::::::::::::::::::
If LCase(Parse(0)) = "chestclose" Then
Chest(Val(Parse(1))).AlreadyOpen = False
Exit Sub
End If
These two packets handle the open and closed chest packets from the server which are used for deciding if a chest is to be blted with an open or closed tile.
Now for some actual bltting, add the following sub to the bottom of modGameLogic
Code:
Public Sub BltChest(ByVal ChestNum As Long, ByVal X As Long, ByVal Y As Long)
Dim rSrc As RECT
With Chest(ChestNum)
If .AlreadyOpen = True Then
rSrc.top = .OpenTileY * PIC_Y
rSrc.Bottom = rsrc.top + PIC_Y
rSrc.Left = .OpenTileX * PIC_X
rSrc.Right = rsrc.Left + PIC_X
Call DD_BackBuffer.BltFast(X * PIC_X, Y * PIC_Y, DD_TileSurf, rSrc, DDBLTFAST_WAIT Or DDBLTFAST_SRCCOLORKEY)
Else
rSrc.top = .ClosedTileY * PIC_Y
rSrc.Bottom = rsrc.top + PIC_Y
rSrc.Left = .ClosedTileX * PIC_X
rSrc.Right = rsrc.Left + PIC_X
Call DD_BackBuffer.BltFast(X * PIC_X, Y * PIC_Y, DD_TileSurf, rSrc, DDBLTFAST_WAIT Or DDBLTFAST_SRCCOLORKEY)
End If
End With
End Sub
And then find
Code:
Call BltTile(X, Y)
Code:
If Map.Tile(X, Y).Type = TILE_TYPE_CHEST Then
Call BltChest(Map.Tile(X, Y).Data1, X, Y)
End If
Now for the final bit, getting the server to close the chests so find
Code:
' Check for disconnections
For i = 1 To MAX_PLAYERS
If frmServer.Socket(i).State > 7 Then
Call CloseSocket(i)
End If
Next i
And add under it
Code:
' --- Check to Close Chests
For i = 1 To MAX_CHESTS
If Chest(i).AlreadyOpen = True Then
TotalTime = Chest(i).StayOpen
TotalTime = TotalTime * 1000
TotalTime = TotalTime + Chest(i).TimeOpen
If TotalTime < GetTickCount Then
Chest(i).AlreadyOpen = False
Call SendDataToAll("CHESTCLOSE" & SEP_CHAR & i & SEP_CHAR & END_CHAR)
End If
End If
Next i
Also declare TotalTime at the top of the sub
That’s the tut finished, horay, not much else to say, I started rushing this towards the end since this amazingly took me 3 nights =/ (mainly because I kept watching tv, doing coursework or playing games every 10 mins)
Ok, forgot one small part that updates the chests for players, find in the server
Code:
Sub SendItems(ByVal Index As Long)
And under that sub add the following sub
Code:
Sub SendChests(ByVal Index As Long)
Dim packet As String
Dim i As Long
packet = "CHESTSDETAILS" & SEP_CHAR
For i = 1 To MAX_CHESTS
packet = packet & Chest(i).ClosedTileX & SEP_CHAR & Chest(i).ClosedTileY & SEP_CHAR & Chest(i).OpenTileX & SEP_CHAR & Chest(i).OpenTileY & SEP_CHAR
Next i
Call SendDataTo(Index, packet & END_CHAR)
End Sub
Also find in modHandleData in the server
Code:
' Save it
Call SaveChest(n)
Code:
Call SendDataToAll("CHESTUPDATE" & n & SEP_CHAR & Chest(n).ClosedTileX & SEP_CHAR & Chest(n).ClosedTileY & SEP_CHAR & Chest(n).OpenTileX & SEP_CHAR & Chest(n).OpenTileY & SEP_CHAR & END_CHAR)
Now add to the bottom of modHandleData in the client (Within the main sub)
Code:
' :::::::::::::::::::::::::
' :: Chest Detail packet ::
' :::::::::::::::::::::::::
If LCase(Parse(0)) = "chestsdetails" Then
i = 1
For n = 1 To MAX_CHESTS
Chest(n).ClosedTileX = Val(Parse(i))
Chest(n).ClosedTileY = Val(Parse(i + 1))
Chest(n).OpenTileX = Val(Parse(i + 2))
Chest(n).OpenTileY = Val(Parse(i + 3))
i = i + 4
Next n
Exit Sub
End If
' :::::::::::::::::::::::::
' :: Chest Update packet ::
' :::::::::::::::::::::::::
If LCase(Parse(0)) = "chestupdate" Then
Chest(Parse(1)).ClosedTileX = Parse(2)
Chest(Parse(1)).ClosedTileY = Val(Parse(3))
Chest(Parse(1)).OpenTileX = Val(Parse(4))
Chest(Parse(1)).OpenTileY = Val(Parse(5))
Exit Sub
End If