Today's lesson is going to feed into next week's lesson, for the first two-parter of the series. Today, we're going to learn about the map editor, and why polymorphism isn't a database.
Know your role:
Of course, these descriptions are all a bit of a laugh really, but you'll notice that these four roles are going to be what you and your team tend to fall into. Some teams will have members that take multiple roles, and some team members won't really have a role on this list. Of course, as an hobbyist, these roles aren't all-important.
Based on these roles, a logical structure for how your maps should work starts to emerge.
Let's take a look at the structure here:
Basically, what happens, is your designer becomes a central point of contact between each of the three specializations that actually work on the project itself.
The Designer's job is to ensure that the right bits get to the right people. If the programmers need art to test a feature, the designer gets that art. If the artists need a tool to make their art life easier, the designer figures out the requirements and gives them to the programmers. If the environment artist needs the programmers to fix an issue with a tile prototype, that goes through the designer.
I'm not saying these groups should never speak to one another, as synergy is good, but you should never have a situation where the environment artists need to know about programming to do their job, and the programmers know about art to do their job.
If you have set your project up correctly, these three disciplines should maintain their separation until they are combined by the designer for the final product.
What does this have to do with mapping, you may ask? Well, let's look at how BYOND projects tend to do it to explain why this is relevant.
How to fail:
This is a screenshot of Zeta's map. The map itself isn't the worst I've ever seen, but it's certainly not the best. My problem, is primarily within the structure of the object tree itself.
Zeta's code was leaked, ironically by a mapper. Notice how there are pages and pages of objects in a big line down the object tree? That makes it borderline impossible to actually create a map, due to a lack of structure and organization.
Not only that, the way the objects themselves are defined is just plain scary bad!
Let's take a look at what's wrong:
turf
grass
icon = 'turfs.dmi'
icon_state = "grass" //Summer Time
//icon_state = "snow" //Winter Time
density = 0
buildingtop
icon = 'turfs.dmi'
icon_state = "buildingtop"
density = 1
Bridge1
icon = 'turfs7.dmi'
icon_state = "bridge1"
density = 0
Bridge2
icon = 'turfs7.dmi'
icon_state = "bridge2"
density = 0
Bridge3
icon = 'turfs7.dmi'
icon_state = "bridge3"
density = 0
Bridge4
icon = 'turfs7.dmi'
icon_state = "bridge4"
density = 0
Bridge
icon = 'turfs7.dmi'
icon_state = "bridge"
Wall
icon = 'turfs7.dmi'
icon_state = "wall"
density = 1
Wall1
icon = 'turfs7.dmi'
icon_state = "wall1"
density = 1
Wall2
icon = 'turfs7.dmi'
icon_state = "wall2"
density = 1
Wall3
icon = 'turfs7.dmi'
icon_state = "wall3"
density = 1
Wall4
icon = 'turfs7.dmi'
icon_state = "wall4"
density = 1
Wall5
icon = 'turfs7.dmi'
icon_state = "wall5"
density = 1
Wall6
icon = 'turfs7.dmi'
icon_state = "wall6"
density = 1
Wall7
icon = 'turfs7.dmi'
icon_state = "wall7"
density = 1
Cliff
icon = 'turfs7.dmi'
icon_state = "cliff"
density = 1
Don't see anything wrong with this? That's because Zeta was where this bad habit started to spread. None of these turfs need to be hard-coded. None of these icons need to be hard-coded. They should be soft-coded. Why?
Look back up to the diagram I drew of project structure. The mapper should not need to know how to write code in order to use the art assets. Even simple copy-pasta like this is bad practice, as it unnecessarily muddies your project's structure and hinders your environment artists from doing their job.
Polymorphism is not a database
Let's talk about polymorphism for a minute. Polymorphism is a fundamental programming concept that is best described by the common rhetorical phrase: "All letters are symbols, but not all symbols are letters."
Something can be a sort of thing, but have its own properties differentiating itself from another. For instance, a squirrel is an ermine, and has all the properties of an ermine. A weasel is also an ermine, also having all the properties of an ermine, but not having all the properties of a squirrel.
Since the weasel and squirrel are both types of Ermine, we can say with certainty, that either a squirrel or a weasel are ermines, and behave similarly to ermines.
The same is true in programming. In the above bad example, grass, buildingtop, Bridge1, Bridge2, Bridge3, etc. are all types of /turf. The only way in which they differ is in the value of their variables.
This alone is not enough to justify the creation of a new type within the source code. Having the variables is enough to justify the type, but changing them is not. New behavior would, on the other hand, justify having these different types. Let's say we have a type of turf that when walked on, will hurt the player. That should be a different type from the rest of the turfs that don't do that. Let's add on to that, by pretending we also need a turf that will kill the player when they step on it, and one that will teleport the player to another location when they step on it:
turf
hurtplayer
var
damage = 10
Entered(atom/movable/o)
if(istype(o,/mob/player))
var/mob/player/p = o
p.TakeDamage(src,damage)
killplayer
Entered(atom/movable/o)
if(istype(o,/mob/player))
var/mob/player/p = o
p.Die(src)
teleporter
var
relocate_x
relocate_y
relocate_z
Entered(atom/movable/o)
if(istype(o,/mob/player))
if(!p.HasFlag("teleporting"))
var/mob/player/p = o
p.AddFlag("teleporting")
p.Move(locate(relocate_x,relocate_y,relocate_z))
p.RemoveFlag("teleporting")
As you can see, we have three types of turf now. If you want to have different turfs that cause different amounts of damage, or different turfs that teleport you different places, you should use the instance editor, and not hard-code the variable changes without good reason. I will go over the instance editor next.
The neglected instance editor:
The instance editor is a powerful little tool. It allows you to create variations of object types on the map simply by changing variables.
Go into the map editor, and click on the type in the object tree you wish to create an instance of. Now right click on any instance in the object subpanel to bring up the context menu. Click on New "Instance..."
This will bring up the instance editor subwindow, which will allow you to specify variables for this instance. Only what is needed is maintained by the project, so next time you compile, any instances you have created that don't have at least one painted somewhere on the map will disappear from the object panel. This usually discourages people from using this feature, but don't give up on it!
As you can see in my map, I have several dozen variations of this one type all stored under one type. That might seem somewhat disorganized to you, but we'll go over that later.
I have over 75 different turfs on my map without a single one being hard-coded. There is no code specifying the variable changes in my project. I can change the graphics on the fly without having to browse the code, and any environment artists can do the same without knowing a lick of code. Not only that, the programmers don't have to even know the art for the project exists, because all of the project's art was specified in the instance editor on the map itself!
Use an atlas, ya dingus!
So now, you've got hundreds of different turfs all crammed into one little 200 pixel wide context box, right? Now it's just gonna be such a pain to sort through it and find all your turfs, right? Wrong. Don't bother with the left half of the map editor's interface at all. There's literally no need.
What you want to do, is paint an atlas on your map somewhere, that you can drag around with you while you work. Here's mine:
This little atlas makes life a lot easier. Plus, this handy shortcut: Press Ctrl+shift+left click on an object, or a tile to make that object the active object you will be painting with. This is what our atlas is great for. Drag it around with you, and use it to select your pieces from.
A few additional tips:
Right clicking an instance in the object panel will allow you to edit all instances of that modified type on the map at once. Right clicking an instance in the map will allow you to edit that sole instance.
If you create a new instance with the same variables as another instance, it will not create a new type, just change the existing type to the one that already exists, or select the old type.
Ctrl+Click allows you to overwrite all turfs at that location with the currently selected turf.
What just a few hours of work looks like using this technique:
Happy mapping!
1+ post