He touched the fish, saying in a terrible voice, `Fish, fish, are you doing your duty?' To these words the fish lifting up their heads replied, `Yes, yes. If you reckon, we reckon. If you pay your debts, we pay ours. If you fly, we conquer, and are content.'
Most of the time, the data objects you create will be pre-defined, or at least derived from one of the pre-defined types. However, it is possible to make your own datum from scratch. Such an object may be useful for your own specialized purpose when you don't need all the extra baggage associated with the built-in types.
To define a new data type, simply derive it from the root, rather than from
an existing object type. The following code demonstrates the syntax by
defining a Quest
datum.
Quest var mob/sponsor quest_obj_type reward_obj_type desc proc Check() var/mob/M var/obj/O for(M in view(sponsor,1)) O = locate(quest_obj_type) in M if(O) Reward(M,O) return 1 Reward(mob/M,obj/O) var/obj/R = new reward_obj_type(M) O.Move(sponsor) M << "You have completed the quest!" M << "[sponsor] takes [O] and rewards you with \an [R]."
As you can see, object variables and procs are defined just as with any other data object. Inheritance works the same too, so you can derive new types from ones you have already defined.
Generic data objects are intended to have as small of a pre-defined "footprint" as possible. As a result, there are very few built-in variables. These are described in the following list.
There are only a few pre-defined procedures for data objects. These all have the same meaning as for the atomic objects which have already been introduced. Figure 18.27 lists the procedures and the page where you may find a full description.
Procedure | See Page |
New | [7.2] |
Del | [7.2] |
Topic | [7.6] |
Read | [12.4] |
Write | [12.4] |
The new instruction is used to create data objects and del is used to destroy them. The following example shows how the previously defined quest object might be used.
mob/king var/quests[0] verb/beg() //get a new quest set src in view() var/Quest/q = RandQuest() usr << q.desc quests += q verb/bow() //finish quest set src in view() var/Quest/q for(q in quests) if(q.Check()) quests -= q return
proc/RandQuest() var/qtype = pick(typesof(/Quest) - /Quest) var/Quest/q = new qtype() q.sponsor = src return q
Quest/Goblin quest_obj_type = /obj/corpse/goblin reward_obj_type = /obj/potion/newlife desc = "Bring us the head of a goblin and ye shall have new life!" Quest/Ring quest_obj_type = /obj/magic_ring reward_obj_type = /obj/wand/lightning desc = "Bring us a golden ring and thy reward shall be great!"
By begging the king, one receives a new quest. With the requested object in hand, one must simply bow before the king to receive the reward. The typesof instruction was used here to pick a quest randomly from all that are defined in the code.
Obviously one could add all sorts of improvements to this basic system. For example, other types of rewards and requests could be added. However, it is a good start and a nice demonstration of a user-defined datum.
Note that we never bothered to delete the quest when it was finished but simply remove it from the list. Since there are no longer any references to the object anywhere, it will be automatically deleted by the garbage collector.