Splash  
About WOCNews, Help, etc.Build AreasContributor CreditsUseful Links

Login

Build Zones
Build Rooms
Build Shops
Build Mobs
Build Objects

Search Areas
Building Guides
BlobbieScript

Documents
  

Most of these documents are EXTREMELY outdated and are kept more for historical reasons than informative reasons. Most outdated is the building information since Carnage no longer runs on a DIKU data system but rather uses a custom XML structure. Despite all this the information can be very useful when designing your area.


Creating Spells (The BlobbieScript Way)
---------------------------------------

As you may have read in the BlobbieScript documentation, the BlobbieScript
language is extremely flexible and power and opens up the possibility to do
almost any thing in script that can be done internally. the advantage to
implementing spells in BlobbieScript is that the logic and data can be
reloaded into the MUD server without the need for a reboot. This is an
extremely powerful feature during the tweaking stage of any new spell. For the
most part you will use the Web interface for setting spell data like skill %
gained per practice, how much mana is consumed, is the spell aggressive, what
classes can use the spell, and from what base stats (str, int, wis, etc) is
the spell derived. This document serves only to cover the scripting aspect.

An Example Spell
----------------

To greatly help with the learning process I will first provide an example
spell written in BlobbieScript and then i will continue by describing what
data it receives, and what specialized functions are available to minimise the
repetitive work necessary for creating a spell.

    Armour Spell Example:

    protect
    {
        %spellRoutineMobileTargets( group, 1 )

        @duration = 24;
        @duration = 1 MAX ((@duration * @quality) / 100)

        foreach( @targets as @target )
        {
            %spellRoutineMobilesOnly( @target )
            %spellRoutineCheckAllowedTarget( @actor, @target )

            if( !%skillAffectExists( @target, @spellId ) )
            {
                %echoTo(
                \   "You feel someone protecting you.\n", @target )

                %act( "$n's armour shimmers for a moment.",
                \      0, @target, %null(), %null(), skipActor )

                %skillAffectAdd( @target, @spellId, ac, -20, @duration )
            }
            endif
        }
        endforeach
    }
    endprotect

For the most part the script is fairly simple adhering to the constructs of
BlobbieScript and using various documented functions. There are however THREE
special functions also used:

    - %spellRoutineMobileTargets( group, 1 )
    - %spellRoutineMobilesOnly( @target )
    - %spellRoutineCheckAllowedTarget( @actor, @target )

These are special because the rely on the script being structure a certain
way. More specifically the require the script be populated with data intended
for a spell script.

The first function, %spellRoutineMobileTargets(), uses the parameters given
and the variables predefined for a spell script to find the targets for the
spell script and populate them into the @targets array without any extra work
by you. This is extremely useful since otherwise the spell script must check
the type of caster, the type of targets, whther there are predefined targets,
etc. This function encapsulates a lot of low level repetitive checks and data
manipulation (which generaly contribute about 100 lines of code).

The second function, %spellRoutineMobilesOnly(), checks to see if a given
target is a mobile (PC or NPC) and if not then it automatically performs a
CONTINUE to jump script execution back to the top of the FOREACH loop. For
this reason it is important that you use the FOREACH loop when traversing the
@targets list. In this particular case the code saved is only a couple of
lines, but in most cases a lot of code is saved, and more importantly for the
implementors, the script EXACTLY follows the same format as internal C code
which uses macros to the same effect.

The last function, %spellRoutineCheckAllowedTarget(), checks that the @actor
(mobile, object, room, etc) is allowed to cast the spell on the @target. When
sepaking of allowed here, we mean in the sense that a guilded cannot attack a
non-guilded and vice versa. This principle isn't used in the game anymore, but
we retain it's functionality in case we should choose to revert to some system
of protection in the future.

These functions and several others that are specific to spells (denoted by the
%spellRoutineXxx() naming scheme) are documented fully in the BlobbieScript
%documentation.


Traversing Targets
------------------

In our example there is a FOREACH loop which we use to traverse the spell's
targets. You might be tempted to say:

    "the armor spell only targets the caster or their victim so I
     don't need a FOREACH loop"

This attitude is flawed (unless you have a really good reason for doing so).
The reason being that this same script is used by wands, potions, staves,
scrolls, etc. It may even be invoked by another script with a preset list of
targets. For this reason it is imperative that you use the FOREACH loop to
traverse ALL of the targets found.

As the loop moves through each target it checks to see if @target is already
affected by the armour spell:

    if( !%skillAffectExists( @target, @spellId ) )

And if not then is applies the spell:

    %skillAffectAdd( @target, @spellId, ac, -20, @duration )

With a little bit of output for the caster (if applicable) and the victim.

The @spellId variable is automatically populated for you as are many others.
It is useful enough to mention that where we have used @spellId we could also
have used "armour" for the same effect. It just happens though, that using the
ID is more efficient than using the name. It also ensures that if the name is
changed, that the spell continues to work properly.


Prepopulated Variables
----------------------

Many variables are prepulated into the script so that the script writer can
implement powerful spells with a minimum of effort. below are listed all of
the variables currently populated for the spell creator:

    variable @ch:

        If the spell has been invoked by a mobile AND @spellType is set to
        "cast" then this will be set to the actor. This is a convenient
        shorthand for sending output that should only be sent when the spell
        has been cast by a mobile.

    variable @actor:

        This is a text pointer to the invoker of the spell. Note that it can
        be any valid text pointer (room, mobile, object, etc). It may also be
        %null() for an anonymous spell source. in the case of a wand, staff,
        etc., this will be set to the user of the given artifact.

    variable @master:

        This is a text pointer to the master of the spell invocation. For
        instance if you are forced, commanded, or suggested to cast the spell,
        then you would be the @actor, and the person controlling you would be
        the @master. In the case of a wand, staff, etc., this will be set to
        the artifact. This can be %null().

    variable @command:

        This is the command input to facilitate the spell. For instance
        "cast", or in the case of a staff, "use". It may also be other strange
        commands like "throw" if the spell was the result of throwing a
        potion. This can be %null().

    variable @arguments:

        This will contain all the arguments passed to the spell when it was
        invoked. Normally this is used to determine the target of the spell,
        but sometimes the @targets will have been preset and this will
        generally be ignored. Note that when the spell is cast, this variable
        will not contain the spell portion itself, it will contain everything
        after the spell name. For instance "cast armour self" would result in
        "self" being the value of @arguments.

    variable @spell:

        The name of the spell that has been cast. Generally this isn't needed
        but it can be used in output where the spell's name is needed and will
        prevent any problems if the spell's name is changed.

    variable @spellId:

        This is set to the ID of the spell. Spell creators have no control
        over the ID assigned to their spells; however, they can see it in the
        URL of the spell editor after it has been saved once. As shown in our
        example this can be used to apply affects to a given @target.

    variable @manaCost:

        The amount of mana normally charged when this spell is cast. This will
        have been subtracted before the script is run (if the spell was cast)
        and is provided in case the spell creator has other needs for it
        (perhaps to refund some mana based on some state of the caster).

    variable @castingTime:

        The amount of time the caster should be delayed (generally only
        applicable to mobiles) when the spell has been cast. If your spell has
        set the "shareScript" flag then the waiting period will have already
        been handled by the default spell script wrapper.

    variable @level:

        This will be set to the level at which the spell was invoked. This can
        and generally SHOULD be used to aid in the determination of spell
        duration and power. It is most often used in combination with the
        @quality variable.

    variable @quality:

        This will be set to the quality of the spell. This is a percentage and
        should be used to modify the power or duration of a spell. In the case
        of spells with boolean non-duration based spells, then this should be
        used against a 1d100 dice roll to determine if the spell's affect
        should occur at all:

            if( 1d100 < @quality )

        When a player casts a spell the @quality parameter calculated as a
        measure of their effective skill level and of the source stats for the
        spell. For instance 70% skill and a relevant stat of 15 (out of 19)
        would result in a quality of about 55%.

    variable @targets:

        If the spell has been passed a preset list of tragets, then this
        variable will be set; otherwise it will not be set at all. When set
        your spell should ignore any targetting arguments and use this preset
        list only.

    variable @spellType:

        This is set to the type of spell. Generally this provides information
        about how the spell was invoked. The following are possible values for
        this variable:

            cast            staff
            potion          scroll
            wand            other

        For instance if the spell is the result of using a wand then this will
        be set to "wand".

    variable @commandUserFlags:

        Generally you will never need this variable but it is provided in case
        the event does arise. This variable contains any user flag settings
        for the invoked command:

            other           pc
            room            npc
            object          nonPc

        For instance if the "room" and "object" flags were set then only rooms
        and objects could have issued the command that invoked the spell.

    variable @commandSourceFlags:

        This is set to any of the command source flags that were set when the
        command was issued. The following are possible flags:

            gameLoop        lordOrdered
            trigger         commanded
            forced          suggested
            ordered

        Some of these can be very useful to your script. For instance you
        might check to see if the command was suggested, commanded, or ordered
        and provide alternate functionality as a result.

    variable @commandAttributeFlags:

        This variable will contain any attribute information for the command
        that was issued. The following are recognized:

            isRepeatable    isGhostAction
            doSpecials      noForce
            noOverride      noOrder
            fullTrigger     noLordOrder
            isAction        skipCommOut
            allowInHell

        Again these can be useful, but for the most part you will never have
        any need for them.

    variable @skillSources:

        This will contain a set of flags which denote from which base stat sources
        the spell is derived. The following values are recognized:

            strength        dexterity
            intelligence    constitution
            wisdom          charisma

        As with most flags you probably won't need to use these since.

    variable @skillClasses:

        This will consist of a set of flags which denote to which class
        (discipline) the skill belongs.

            mage            immortal
            cleric          hero
            thief           forsaken
            warrior         necromancer
            ranger          blackKnight
            paladin         enchanter
            druid           shaman

        As with most flags you probably won't need to use these since.

    variable @skillFlags:

        Various flag information that aplies to this spell will be set in this
        variable. The following values are recognized:

            isSpell         isAggressive
            isOffensive     isBuff
            isDefensive     pcHide

        These flags are used by the %spellRoutineCheckAllowedTarget() function
        (as seen in our example). If you need to provide functionality of your
        based on whether the skill is aggressive, offensive, etc. then you
        will want to use this variable.

    variable @spellFlags:

        This is set to any flags that pertain to the spell itself. Currently
        the only recognized member is "shareScript" which denotes that the
        spell uses the common spell wrapper.



Closing Notes
-------------

Now you've been exposed to everything available to your spell script. Some
variables and functions you may never use, and others you will be sure to use
almost every time. Creativity is one of the best ingredients to any endeavour,
and it is no exception when creating spells; however, it is important to also
keep in mind balance whenever you create a new spell. To help further in your
task I have provided a second spell example:

    Acid Splash Example:

    protect
    {
        //
        // Set up various damage flags for the spell.
        //
        @damageFlags->1 = magic
        @damageFlags->2 = acid
        @damageFlags->3 = skipMinimum

        %spellRoutineMobileTargets( notGroup, 0 )

        foreach( @targets as @target )
        {
            %spellRoutineMobilesOnly( @target )
            %spellRoutineNoGhosts( @target )
            %spellRoutineCheckAllowedTarget( @actor, @target )

            @damage = ((((@level / 10) + 1) D 5) * @quality) / 100

            if( %saveVersusSpell( @target, @actor, @level ) )
            {
                @damage /= 2
            }
            endif

            %damage(
            \   @actor, @target, @damage,
            \   @damageFlags, "spell acid splash" )

            if( !%isImmortal( @target ) )
            {
                if( !%isGladiating( @actor, @target ) )
                {
                    %damage(
                    \   @actor, %getEquipment( @target ), 15 + 1d15,
                    \   @damageFlags, "spell acid splash" )
                }
                endif
            }
            endif
        }
        endforeach
    }
    endprotect




The Worlds of Carnage MUD is a non-profit, fantasy oriented, text-based game that is played over telnet. We are devoted to providing a social medium in which people can have fun while immersing themselves in a game that reads like a book. You can connect by clicking here or if that fails then here. This site is maintained and hosted by Robert Cummings, A.K.A Blobule and is powered by InterJinn, a PHP based multi-tier application framework connected to a MySQL backend and served via an Apache web server. The Worlds of Carnage are often recognized via the following aliases: Carnage; WoC; WoC MUD; Carnage MUD; CarnageMUD; WoCMUD. All submissions become the property of Robert Cummings where the submitter holds copyright. If you do not want to give ownership, then do not submit.