[EO] Images by player names (base for further specific coding)

This sounded like a fun little morning challenge. Here’s a picture of what this looks like. It renders the same as your player sprite in terms of what layer it’s on. So when you go below a fringe, you name is there but your pic is not. I’m diggin’ the shmexy bitten-bread shield. So simple. Oh, but it’s a doozy. I have a level display (the [1]) on for kicks. You won’t, unless you use this in modText sub DrawPlayerName:```
Name = Trim$(Player(index).Name) & " [" & GetPlayerLevel(index) & “]”


I'm hereafter referring to this as a namepic, simply for cohesion with the variable name I used. Names are centered normally when there isn't one, with the combination of name + pic centering when there is. It automatically adjusts to different sprite sizes and player names. The picture is added into modTypes and is player-specific. For simplicity, this tutorial uses item pictures as the rendered image by the player's name. Below there is a spoiler to create a separate graphics type, to be in a folder graphics\namepics\.

This always renders on the right side (in part as snuff against those who want to copy Ragnarok Online and seemingly-every-game-ever that puts it on the left). It's an easy swap to put it on the left, but that's up to your tinkering.

First, how this works. If you're new to VB6, this tutorial includes a _lot._ In some ways it's not for beginners, because it may seem daunting. In other ways it's a perfect tutorial for a beginner because it touches so many different parts of how the client and server work individually and as a couple. But the best learning opportunity for the novice, is that **i****f you simply copy and paste this, it will not work yet.** Sub SetNamePic still has to be included somewhere in your code!

**Overview**

*   An extra variable is added to the player to store their namepic. Because of this, some extra coding is needed to prevent RTE9s on that variable.
*   I have included a sub to change the player's namepic and another sub to update it. **This sub is included, but _not implemented_ this sub in the server's code. It is up to you to decide and then figure out how to add Call SetNamePic(index, namepic) into your game. This tutorial will do absolutely nothing if you don't do so.** Suggestions include on guild joining and leaving (if you have guilds), when using a new item type, by a "/np player #" command, or included in the admin panel. Implementation is your time to shine.
*   Next up some TCP subs were needed to transfer the variable. That means handles are necessary to transfer that number between client and server.
*   Finally, client-side a sub and an extra line of code are needed to add in the namepic rendering.
*   I have included a minor modification to recenter the player's name+icon over the player, rather than simply having the icon extend past the player's name. Although not necessary, if not included you must add 15 to the x value of the namepic blt before convertmapx.

**Both sides now**

I recommend getting the parallels between client and server out of the way first. In modTypes on both client and serverside, add```
NamePic As Long
```within Private Type PlayerRec. It doesn't matter where you put it. Try before End Type.

You will also need to include SPlayerNamePic in modEnumerations. This must be done in perfectly parallel fashion between client and server. I recommend just above SMSG_COUNT.

Now then, to the **server side** of this!

In modPlayer, add this under Sub JoinGame with the other calls:

Call SendPlayerNamePic(Index)


Then throw this sub somewhere in modPlayer.

Function SetPlayerNamePic(ByVal index As Long, ByVal NamePic As Long)

Player(index).NamePic = NamePic

Call SendPlayerNamePic(Index)

End Function


in modServerTCP add:

Sub SendPlayerNamePic(ByVal Index As Long)

Dim buffer As clsBuffer

Set buffer = New clsBuffer

buffer.WriteLong SPlayerNamePic

buffer.WriteLong NamePic

SendDataTo Index, buffer.ToArray()

Set buffer = Nothing

End Sub


That's it server-side from me. It's up to you to creatively include SetPlayerNamePic somewhere! ; ]

Into the belly of the ~~beast~~ **CLIENT**!

**Client-side** in modDirectDraw7, add in this timer with the others Just do a search for timer() to find them.

Public NamePicTimer() As Long


In the same mod, add in this sub.

Public Sub bltNamePic(ByVal index As Long)

Dim picnum As Long

Dim rec As DxVBLib.RECT

Dim MaxFrames As Byte

Dim x As Long, y As Long

Dim width As Long

Dim height As Long

’ If debug mode, handle error then exit out

If Options.Debug = 1 Then On Error GoTo errorhandler

'For an image

picnum = Player(index).NamePic

’ Is the player’s height more than 32…?

If (DDSD_Character(Player(index).Sprite).lHeight) > 32 Then

 ' Create a 32 pixel offset for larger sprites

 y = GetPlayerY(index) * PIC_Y + Player(index).YOffset - ((DDSD_Character(Player(index).Sprite).lHeight / 4) - 32) - 22

Else

'Proceed As Normal

 y = GetPlayerY(index) * PIC_Y + Player(index).YOffset - 8

End If

'Necessary reconversion for scrolling maps, plus fix pic to blt after the name

x = ConvertMapX(GetPlayerX(index) * PIC_X) + Player(index).XOffset + 21 + getWidth(TexthDC, Trim$(Player(index).Name & Player(index).Level & “”))

y = ConvertMapY(y)

NamePicTimer(picnum) = GetTickCount + SurfaceTimerMax

 With rec

	 .top = 0

	 .Bottom = PIC_Y

	 .Left = 0

	 .Right = PIC_X

 End With

If DDS_Item(picnum) Is Nothing Then

	 Call InitDDSurf("items\" & picnum, DDSD_Item(picnum), DDS_Item(picnum))

End If

’ clipping

If y < 0 Then

 With rec

	 .top = .top - y

 End With

 y = 0

End If

If x < 0 Then

 With rec

	 .Left = .Left - x

 End With

 x = 0

End If

width = (rec.Right - rec.Left)

height = (rec.Bottom - rec.top)

If y + height > DDSD_BackBuffer.lHeight Then

 rec.Bottom = rec.Bottom - (y + height - DDSD_BackBuffer.lHeight)

End If

If x + width > DDSD_BackBuffer.lWidth Then

 rec.Right = rec.Right - (x + width - DDSD_BackBuffer.lWidth)

End If

’ /clipping

Call Engine_BltFast(x, y, DDS_Item(picnum), rec, DDBLTFAST_WAIT Or DDBLTFAST_SRCCOLORKEY)

Exit Sub

’ Error handler

errorhandler:

HandleError “BltNamePic”, “modDirectDraw7”, Err.Number, Err.Description, Err.Source, Err.HelpContext

Err.Clear

Exit Sub

End Sub


Then, under renderGraphics, find```

		 ' Players

		 For i = 1 To Player_HighIndex

			 If IsPlaying(i) And GetPlayerMap(i) = GetPlayerMap(MyIndex) Then

				 If Player(i).y = y Then

					 Call BltPlayer(i)

				 End If

			 End If

		 Next

and replace with```

	 ' Players

	 For i = 1 To Player_HighIndex

		 If IsPlaying(i) And GetPlayerMap(i) = GetPlayerMap(MyIndex) Then

			 If Player(i).y = y Then

				 Call BltPlayer(i)

If Player(i).NamePic > 0 Then bltNamePic(i)

End If

		 End If

	 Next

So that text is properly centered, add this line _after_ the textx equation in modText in SubDrawPlayerName. You can adjust the "-16" part if you find it slightly too far left.

If Player(index).NamePic > 0 Then TextX = TextX - 16


Now to receive those precious server packets, go to modHandleData. Search for AddressOf and add this in with the others```
 HandleDataSub(SPlayerNamePic) = GetAddress(AddressOF HandlePlayerNamePic)

and then this sub```
Private Sub HandlePlayerNamePic(ByVal index As Long, ByRef Data() As Byte, ByVal StartAddr As Long, ByVal ExtraVar As Long)

Dim Buffer As clsBuffer

Dim i As Long

’ If debug mode, handle error then exit out

If Options.Debug = 1 Then On Error GoTo errorhandler

Set Buffer = New clsBuffer

Buffer.WriteBytes Data()

Player(index).NamePic = Buffer.ReadLong

’ Error handler

Exit Sub

errorhandler:

HandleError “HandlePlayerStats”, “modHandleData”, Err.Number, Err.Description, Err.Source, Err.HelpContext

Err.Clear

Exit Sub

End Sub


Then, in modDatabase, replace CheckItems() with this

Public Sub CheckItems()

Dim i As Long

’ If debug mode, handle error then exit out

If Options.Debug = 1 Then On Error GoTo errorhandler

i = 1

While FileExist(GFX_PATH & “Items” & i & GFX_EXT)

 NumItems = NumItems + 1

 i = i + 1

Wend

If NumItems = 0 Then Exit Sub

ReDim DDS_Item(1 To NumItems)

ReDim DDSD_Item(1 To NumItems)

ReDim ItemTimer(1 To NumItems)

ReDim NamePicTimer(1 To NumItems)

’ Error handler

Exit Sub

errorhandler:

HandleError “CheckItems”, “modDatabase”, Err.Number, Err.Description, Err.Source, Err.HelpContext

Err.Clear

Exit Sub

End Sub


That's all! You might be wondering right now why that's in CheckItems and not in a separate sub. The Check subs make an array of timers for the graphics based on the available files. Since we're using item graphics rather than include a separate graphics type (I figured it would be much easier to implement this way), the redimming of the timer falls under CheckItems(). Without including this, the array is never created and you get RTE9\. It would be more efficient to array only the namepic you intend to use. If you'd like to do this, it's as simple as making a separate CheckNamePic() sub and a graphics\namepic\ folder (You will also have to change the gfx location in the bltnamepic sub). Just title each image 1.bmp, 2.bmp, etc. Where copy/paste tutorials are mostly used by those who are not VB6 experts, I have sacrificed some memory for the benefit of this tutorial's ease-of-use and avoidance of some RTE9s by tltr. Plus, who doesn't want a pile of gold or a potion next to their name. Righteous!

For anyone who would rather use a separate graphics time, here you go:

>! Ignore the CheckItems sub. Use this instead:
>! ```
>! Public Sub CheckNamePics()
>! Dim i As Long
>! ' If debug mode, handle error then exit out
>! If Options.Debug = 1 Then On Error GoTo errorhandler
>! i = 1
>! While FileExist(GFX_PATH & "NamePics\" & i & GFX_EXT)
>! 	 NumNamePics = NumNamePics + 1
>! 	 i = i + 1
>! Wend
>! If NumItems = 0 Then Exit Sub
>! ReDim DDS_NamePic(1 To NumNamePics)
>! ReDim DDSD_NamePic(1 To NumNamePics)
>! ReDim NamePicTimer(1 To NumNamePics)
>! ' Error handler
>! Exit Sub
>! errorhandler:
>! HandleError "CheckItems", "modDatabase", Err.Number, Err.Description, Err.Source, Err.HelpContext
>! Err.Clear
>! Exit Sub
>! End Sub
>! ```
and use this bltnamepics instead:
>! ```
>! Public Sub bltNamePic(ByVal index As Long)
>! Dim picnum As Long
>! Dim rec As DxVBLib.RECT
>! Dim MaxFrames As Byte
>! Dim x As Long, y As Long
>! Dim width As Long
>! Dim height As Long
>! ' If debug mode, handle error then exit out
>! If Options.Debug = 1 Then On Error GoTo errorhandler
>! 'For an image
>! picnum = Player(index).NamePic
>! 'Prevent RTE9
>! If picnum > NumNamePics Then Exit sub
>! ' Is the player's height more than 32..?
>! If (DDSD_Character(Player(index).Sprite).lHeight) > 32 Then
>! 	 ' Create a 32 pixel offset for larger sprites
>! 	 y = GetPlayerY(index) * PIC_Y + Player(index).YOffset - ((DDSD_Character(Player(index).Sprite).lHeight / 4) - 32) - 22
>! Else
>! 'Proceed As Normal
>! 	 y = GetPlayerY(index) * PIC_Y + Player(index).YOffset - 8
>! End If
>! 'Necessary reconversion for scrolling maps, plus fix pic to blt after the name
>! x = ConvertMapX(GetPlayerX(index) * PIC_X) + Player(index).XOffset + 21 + getWidth(TexthDC, Trim$(Player(index).Name & Player(index).Level & ""))
>! y = ConvertMapY(y)
>! NamePicTimer(picnum) = GetTickCount + SurfaceTimerMax
>! 	 With rec
>! 		 .top = 0
>! 		 .Bottom = PIC_Y
>! 		 .Left = 0
>! 		 .Right = PIC_X
>! 	 End With
>! If DDS_NamePic(picnum) Is Nothing Then
>! 		 Call InitDDSurf("namepics\" & picnum, DDSD_NamePic(picnum), DDS_NamePic(picnum))
>! End If
>! ' clipping
>! If y < 0 Then
>! 	 With rec
>! 		 .top = .top - y
>! 	 End With
>! 	 y = 0
>! End If
>! If x < 0 Then
>! 	 With rec
>! 		 .Left = .Left - x
>! 	 End With
>! 	 x = 0
>! End If
>! width = (rec.Right - rec.Left)
>! height = (rec.Bottom - rec.top)
>! If y + height > DDSD_BackBuffer.lHeight Then
>! 	 rec.Bottom = rec.Bottom - (y + height - DDSD_BackBuffer.lHeight)
>! End If
>! If x + width > DDSD_BackBuffer.lWidth Then
>! 	 rec.Right = rec.Right - (x + width - DDSD_BackBuffer.lWidth)
>! End If
>! ' /clipping
>! Call Engine_BltFast(x, y, DDS_NamePic(picnum), rec, DDBLTFAST_WAIT Or DDBLTFAST_SRCCOLORKEY)
>! Exit Sub
>! ' Error handler
>! errorhandler:
>! HandleError "BltNamePic", "modDirectDraw7", Err.Number, Err.Description, Err.Source, Err.HelpContext
>! Err.Clear
>! Exit Sub
>! End Sub
>! ```
Finally, go to modDirectDraw7\. Add this in your gfx buffers```
Public DDS_NamePic() As DirectDrawSurface7

and this a bit below in your number of graphics files

! Public NumNamePics As Longthis with your graphics descriptions```
Public DDSD_NamePic As DDSURFACEDESC2

and under DestroyDirectDraw```
 For i = 1 To NumNamePics
>! Set DDS_NamePics(1) = Nothing
>! ZeroMemory ByVal VarPtr(DDSD_NamePic(i)), LenB(DDSD_NamePic(i))
>! Next
>! ```
I don't think the DDSD_NamePic is actually needed. Then again, I don't think the MaxFrames is needed in nearly every DD7 sub in EO. Meh.
>! As said before, you will need a \graphics\namepics\ folder and the contents should be 32x32 bitmaps, each labeled 1,2,3, … 

Have fun! This worked great for me, but if you find any bugs let me know and I'll fix them in this post. Happy Friday! : ]

wow Nice.

tl;dr

This shows the playername to other players, but the sprite is visible to only players who are on the same layer as the user.

Thanks Abhi.

the sprite is visible to only players who are on the same layer as the user.

I don’t understand what you mean by this. It’s coded to be visible to players on the same map.

This is a very nice release, is it your own original code? If not be sure to credit <_<

This is a very nice release, is it your own original code? If not be sure to credit <_<

Thanks. Yeah.

Actually, I can’t lie to you… This is 99.8% Eclipse. :rolleyes:

I don’t understand what you mean by this. It’s coded to be visible to players on the same map.

That came out wrong. lol

Good Job!

EFF??

EFF? if this is DX 7 code… then ik its not ETFF, so O.o EFF?

Hahaha. Oh, dear. Ahahaha!

So what happened is, I’ve been working on my own engine with EFF as a base. I decided to make this tutorial using EO. Then today, I saw the topic title and thought “huh? I’ve been using EFF” and changed it. Some days there’s isn’t enough coffee in the world. Sorry for the mishap.

Hahaha. Oh, dear. Ahahaha!

So what happened is, I’ve been working on my own engine with EFF as a base. I decided to make this tutorial using EO. Then today, I saw the topic title and thought “huh? I’ve been using EFF” and changed it. Some days there’s isn’t enough coffee in the world. Sorry for the mishap.

Thanks for clearing that up because like Flame over there, I saw EFF and DX7 code. Those two don’t go together, I should know. I develop EFF ;)

Log in to reply