So, you'd make a map B when you wanted to have, say, the player being on the balcony of a house, on the first floor. You want them to be able to see the ground floor (map a) and all the people on it?
Basically, it all depends on how many levels you want to be able to store. I'm going to explain it using static variables, because dynamic a bit more complicated.
At the moment, the client on stores one map. This is where you have:
Code:
Public Map as MapRec
(Or something similar, I don't have a copy of Mirage.
What you want to do, for a simple working system, is store a temporary map which will store all the map data for the level below the current map. Something like this:
Code:
Public TempMap as MapRec
Now, you're going to have to set something in the MapRec to store the number of the map which is 'below' it. Just add something simple, like:
Code:
GroundMap as integer
(Use whatever datatype you have MAX_MAPS set to.)
Now, edit all the packets based around the map data to handle this extra piece of data, and add a simple scrollbar/text box in the Map Editor so the GroundMap can be set. Now go into all the editor subroutines and make it save and load to the map data properly.
You should now have a few extra bytes of data per map, but that's fine.
For the actual loading of the data, you're going to have to replicate the subroutines which send the map data. I think it's SendMapTo, or something similar. Unless you know what you're doing, I suggest you simply copy & paste the subroutine and re-name it to SendTempMapTo, or whatever feels right. If you do have a decent knowledge of the source, then you can add an extra optional value to the SendMapTo subroutine, which can be set to send the map data to either the normal Map rec in the client, or our new Temp map rec. It's up to you :]
In this new subroutine (or add a switch statement in the old subroutine), you'll want to send a map rec that's different to the one the player is actually on. If in the subroutine's header you've got a 'mapnum' value or something, just ignore me, but if it's set in the actual subroutine, then change it to:
Code:
Map(GetPlayerMap(index)).GroundMap
Now we're going to be sending the map data of the map we set in the map editor.
Once you've done this, change the name of the packet in the new subroutine (or in the switch statement if you've simply edited the subroutine) and make sure you add it to the Enum of both the client AND the server. If you don't, you're going to get some errors. Now that you have something that can send the map data to the client, you'll need to edit the client to handle this new data.
I haven't checked Mirage recently, but if it's still using the old Case system, add a new case and copy the way the normal map is saved. As we're wanting to save it differently, set it all to TempMap instead of Map.
Okay. If that all worked out, and I didn't miss anything, then we should now have:
- An amount of allocated memory of a second map to be saved client-side.
- The recieving/sending of the new map data sorted.
- A couple of extra bytes in the MapRec to store the 'GroundMap' value.
- A textbox/scrollbar to edit this value in the MapEditor.
- A subroutine to call server-side to send the map data to the client.
What we need to get done now, is sort out the sending of the data, which is simple enough. I'm not aware of any changes Dmitry has done to the server in this area, but if something is different you'll need to work it out yourself.
Go to JoinMap (or something similar) and find out where the normal map data is sent. Underneath do a simple check.
Code:
If Map(MapNum).GroundMap > 0 then
SendTempMapTo index
End if
This should now, whenever the player changes map, send the GroundMap's data as well.
Now what you need to do, is handle all this data. I'll point out now, that I'm going to breifly cover how to handle the rendering, then you'll need to sort out the packet handling yourself.
At the moment, packet data is only sent to the player, or the entire map, for events native to that specific map. What you'll need to do, in all the packets which are sent to a player/map concerning the movement of players, the change in status of items and npcs... all of these events, you'll need to do a small check to see if the map has a GroundMap value. If so, you'll need to send all the data for that map
as well as the usual data.
Sorry if that's a bit convoluted. It's a hell of a lot simpler than it sounds, but I don't have the source with me, so I can't point out what exactly you'll need to do. I'll say now that you should, for now, sort out the packets concerning player/npc movement. Once you get those to work, the others will be easy to manage.
Now, in the client all that remains to do is sort out the rendering. What you'll need to do, is go into the rendering subroutine which is called each loop. I think it's Render_Graphics, or something similar.
In this subroutine, you'll need to copy and paste all the current rendering code for Players, Npcs and the map itself. Paste these below the existing calls, so you should have something like this:
Code:
The lower-map rendering.
Items rendering.
Players/Npcs rendering.
The upper-map rendering.
The lower-map rendering.
Items rendering.
Players/Npcs rendering.
The upper-map rendering.
So you should have all the rendering code out
twice, directly below each other.
Now, for the code at the top, eg. the first lower-map rendering, items rendering, players/npcs rendering and upper-map rendering.
Now, you know all the For...Nexts around those calls? You'll want to edit them. Instead of checking the current map, you'll want them to check the TempMap. So, you should have it rendering the Lower-map of the TempMap, then all the objects, then the Upper-map. Then, above
all that, you'll have the normal items rendering.
After all this, there's still some more to do. If you've got a decent understanding of Mirage and VB6, it should only take a day or so to get it all done, maybe a bit more if you get some annoying bugs.
To be honest, I'll probably download a copy of MS4 later this month and give it a try myself. It's easy enough to do, just a bit daunting.