addpr guards mudl
setpr guards 0 every_1
if(target(bearer(%o)) AND isnpc(target(bearer(%o))) AND
type(target(bearer(%o)))='dragon' AND (equipment(bearer(%o),3)=%o
OR equipment(bearer(%o),4)=%o),
(
if(affected_by_spell(bearer(%o),'fire breath'),
(
remove_affect(bearer(%o),'fire breath','')
),(
msg_character(bearer(%o),'\\d03Your $$p begins to glow brightly!',%o),
msg_everyone_else(bearer(%o),'\\d03$$n~`s $$p begins to glow brightly!',%o)
)
),
affect(bearer(%o),'fire breath','location=immune_blast level=45 seconds=30')
)
)
@
setpr guards 0 proc_enabled 1
/*
* Receives: func(param, …. )
* Breaks up parameters, and recurses into each.
*
* To add a new function, simply add it to the long if-statements.
*/
VARIABLE_DATA *eval_function( void * owner, int type, char *exp )
{
VARIABLE_DATA *value=NULL;
char name[MAX_STRING_LENGTH];
char buf[MAX_STRING_LENGTH];
VARIABLE_DATA *ppoint[MAX_PARAMS];
char params [MAX_PARAMS][MAX_STRING_LENGTH];
char *point;
char *original;
int x;
if ( *exp == '\0' ) return NULL;
if ( *exp == '{' || *exp == ';
char *point;
char *original;
int x;
if ( *exp == '\0' ) return NULL;
if ( *exp == '{' || *exp == '[' )
return new_variable( TYPE_STRING, str_dup( exp ) );
original = exp;
/*
* Prepare the pointers for the parameters.
*/
for ( x = 0; x < MAX_PARAMS; x++ )
{
params[x][0] = '\0';
ppoint[x] = NULL;
}
/*
* Grab the function name.
* func(param, …. )
* ^
*/
exp = skip_spaces( exp );
point = name;
while ( *exp != '('
&& *exp != ' '
&& *exp != '\0' ) *point++ = *exp++;
*point = '\0';
exp = skip_spaces( exp );
/*
* Grab and evaluate, recursively, each parameter.
* func(param, …. )
* ^
*/
[/code]
A translate variables statement, and a 'mini parser' which is used for some sub-routines such as the if conditional.
I don't find it to be the greatest language in the world and would have written it differently, but as far as I'm concerned 'case closed' on this part of the project. All I do now is add functions when necessary. It is a powerful language, and has been through several iterations. Parts of it are reminiscent of MS-DOS batch file format (in variable declarations only) and the rest is sort of like C.
The most innovative parts of the language are around the spell and skill applications of the language, where you can write spells in the three coexisting magical systems on the fly.
These are the functions related to this part of the language:
[quote]
Spell-related functions for use with both elemental and alchemical
systems.
mana(t,g) Modifies the mana of a target t by gain g
mix(t,types,quantities)
Attempts to mix reagents of mage t, returns TRUE if succeeds, types
and quantities quantify 1:1, ex:
mix(Locke, 10 2 33 201 222, * mixes components 10,2,33,201,222
1 1 1 2 1 ); * one of each, 2 of component 201
reagents(t,types,quantities)
Checks to see if a mage t has the required reagents, returns TRUE if
quantities are in the possession of the mage t
reagents(Locke, 10 2 33 201 222, * components index list
1 1 1 2 1 ); * one of each, 2 of component 201
[/quote]
The three systems (elemental, natural and alchemical) are also controlled by the spell type edited in the OLC's SPEDITOR.
Another interesting part of the language is the AGE or Ascii Graphical Engine, which works much like the meta-language Processing (www.processing.org)
You can create panels, animations and even buttons for Zmud in this language if you combine it with MXP.
Here is the function list for the AGE:
[quote]
> help graphics-functions^M
GRAPHICS-FUNCTIONS (Script)
Graphics functions work with the internal graphics buffer and are grouped
under the sub-system 'Ascii Graphics Engine' - a specialized MXP-enabled
ascii GUI/typesetting renderer. Utilizes a frame buffer with dynamic
resolution to store a screen buffer, which can be displayed to the user.
show() displays the framebuffer to the user
box(x,y,dx,dy) Draw a box using the current line style
rect(x,y,dx,dy) Draw a rectangle using the current brush
line(x,y,dx,dy) Draw a line using the current brush
circle(x,y,r) Draw a circle of radius r at x,y using current brush
color(a) Returns a color code, 255 if MXP, 16 colors if ansi
stroke(a) Set the color for drawing (see above)
point(x,y) Draws with current brush at x,y
draw or draw() Displays the current contents of the frame buffer
blank or blank() Blanks the frame buffer, redraws ruler (see rulers)
gmode(x,y) Sets the resolution of the framebuffer, x-size, y-size
By default, the frame buffer is usually 77x25
mode(0|1) same as below (?)
style(0|1) boxstyle setting, 0=thin 1=thick
ruler(0|1) toggles debug ruler; 0=off 1=on, mud-boot default=1
rulers or rulers() Returns the current value of the rulers toggle
clear or clear() Clears the screen, determined by 'set clrscr'
brush© Sets the 'brush' character
hline(y) Draws a horizontal line with the current brush
vline(x) Draws a verticle line with the current brush
column(x,y,w,{t}) display text in a formatted column (unimplemented)
wrap({text}) Wordwrap standard formatting 77 character
fill(x,y,dx,dy) Fill an area with the current brush character (?)
fills(x,y,dx,dy,s) Fill an area with a string, used w/ column (?)
text(x,y,{content}) Draws text content at x,y
textline(x,y,dx,dy,{content}) Draws text content along a line x,y->dx,dy
popup(x,y,w,h,{title}) Display a box with a title
button(x,y,{label}) Display an MXP button
[/quote]
Here's some interesting automations from NiM5:
Displacer Beast, uses 3 scripts, basic behavior is that it will randomly teleport itself around the mud, but when attacked, will randomly teleport its assailants around the mud.
Here, we'll create and stat the existing displacer beast mob,
which has 3 scripts attached to it.
Name: [displacer beast]
Vnum: [16720] zone: [ 40] Wilderness
Hp: [130/130] Mana: [ 0/160] Move: [280/280] Karma: [0] Exp: [100]
Drunk: [ 0/100] Thirst: [ 0/100] Full: [0/100]
Size: [ 24] Race: [ 0] Sex: [neutral] Scene: Outside Rask's
[1010]
Str: [ 18] Int: [ 18] Wis: [ 18] Dex: [ 18] Con: [ 18]
Lv: [ -1] AC: [ 70] Coins: [ 0] Fight: [0, 0]
Wait: [ 0] Invis: [ 0] Bounty: [ 0] Owed: [ 0]
Age: [ 17] Timer: [ 0] Trace: [ -1] Played: [0, 0]
Act: [npc aggressive wimpy] 0
Bonuses: []
Wielding: [0/25] Hitroll/Damroll: [2/4] [standing]
Carrying 0 items of weight 0.
Short: [a displacer beast]
Long:
A displacer beast is grazing nearby.
[16701] displacer-assist (0,0)
[16721] displacer-teleport (642,0)
[16720] displacer (9,0)
Note the three scripts on the displacer beast:
displacer-assist,
displacer-teleport,
displacer
The numbers next to the names of the scripts are coordinates
for the script, the first coordinate is the current delay in 20ths
of a second. The second number designates the value of the
autowait counter, between each line of the script.
The number to the left of the script name in the stat display is the vnum of the associated script. In (Link removed in accordance with Rule 5), the command 'stat <vnum>' displays the vnum for a script.
Let's take a look at the code for each script:
Script 16701 repeats each pulse. A pulse is about a 20th of a second and is part of a tick. The pulse script is a looping script. It waits 5 pulses (about a second) before it attempts to assist another displacer beast who is being attacked. This is a standard assist script and is used throughout the mud for various mobiles who assist each other.
There is 1 copy of the script on each displacer beast.
Here's the next script:
Displacer beasts do wander from room to room, but they also jump randomly between rooms every 1-1000 pulses, or about once every 4-5 minutes.
This is also a looping "pulse" script, which is constantly running and is attached to each displacer. If you attached this script twice to the same displacer, you could double the speed it teleports, but it is probably not worth it since you could also just decrease the random number generated in the wait() function call on line 1 of this script.
The final script for the displacer is for combat. While NiM5 has a combat script, it is not consistent and this is a much better way of writing a round-for-round special attack or special action script to be executed when the creature enters combat either aggressively or by being attacked.
Here is the "displacer" script, which is the combat-round special attack for the displacer:
In this script line 1 is the delay between teleports. For each round of combat, the creature could teleport an assailant at 15 pulse intervals, or about once every 3 seconds. The second line is a conditional which is standard for all combat scripts. This basically determines if the creature is fighting or not.
When the creature is fighting, the creature will emote "glows with an eerie blue light!", automatically disarm its foe, and then attempt to teleport its foe as many times as necessary until the foe is successfully teleported to a room with a vnum less than or equal to 25000, and greater than 0 (or, basically, any room in my 25000 vnum world).
So, that's basically how a displacer beast can be written with NiMScripts! Happy mudding!