Understanding Messages


This tutorial is intended to explain in detail how the engine treats messages and to help beginners understand message concepts.

Predefined Messages

Every message known to the engine becomes a variable in your cog automatically. Even when you don't declare a message in a cog's symbols section, it is still there and it has a value. Say, for example, that you did not declare user0 in the symbols. If you had PrintInt(user0); in the code section, it would print 27 when it was run. That is because all messages are predefined constants. It is this fact that lets us use code such as:

SendMessage(otherCog, user0);

when user0 has not been declared in the cog that sent the message. Now to explain the 27.

The Value of a Message

Messages, while being of type message, have integer values. When you use a variable in an expression, the engine first finds the variable's value. When you use a message name in an expression, the engine does the same. It finds the value of the message and uses this value (instead of the name of the message) to know which message was intended.

This means that it is also possible to reference a message by its number. For example, this code:

SendMessage(GetSelfCog(), 27);

will call the user0 message.

Called Messages and Values

The call keyword is used to manually call messages. Because call is used to run custom messages that have no predefined value, call cannot use the value of the message. It must search the code section for a message name matching the name that was given to it.

Why Declare Messages?

Knowing that every message is predefined in the cog, you may wonder why message are declared in the cog. This is probably because the engine requires messages to be defined in the symbols so it can know if a message exists in the code section without searching the entire code section for it. If the engine had to search cogs for every message that was called, it would consume a lot more processing power than it if looked up the message in a small array of messages that the cog had declared.

Messages as Starting Points

It is often helpful to think of a messages as a single entity - as a body of code. And indeed, the term "message" is often used to refer to the code between a message name and the next return. But this way of thinking can be deceptive to beginners. Messages are only starting points in the code section. The engine will start executing code after the name of the message and continue until it reaches the next return statement. Not understanding this, the question of "Can a message be run again while it is sleeping?" becomes confusing.

Message Properties

Now that we know messages are only starting points, lets examine message properties. In theory, a message's property is retrieved from "inside" the message. But since a message is only a starting position, these properties are given to the cog when the message is received. So it is the cog that holds the current message properties for verbs like GetSenderRef() to retrieve. Look at this example:
#--------------------------------------------------------
activated:
	call custom;

Return;
#--------------------------------------------------------
custom:
	player=GetSourceRef();

Return;
#--------------------------------------------------------
Even though the engine is running code "inside" the custom message, it can retrieve the sourceref from the activated message because calling the custom message does not overwrite the message properties that activated gave to the cog. The next time a message is received and handled by the cog, new message properties will be assigned to it - overwriting the values that activated gave.

Continue