Just A Test To See If I Can Share This Code Snippet.
Below here is a code snippet I wrote for my MUD (currently offline,
but that may change soon). The goal is to A.) see how well I'm
actually able to share snippets here without being able to attach .txt or
.c files and B.) see how easy it is for anyone to follow what I've
done. So with no small degree of trepidation and a hearty handful
of intrepidity, here goes -
/*
* Plant Seed Version 1.0
* Copyright 2026 Theodryck
*
* This code snippet is the for the skill Plant Seed, which allows players
* grow plants that have magical fruit. The player must have a seed, a shovel
* and be outside in order to use this skill. This is meant to be a very
* powerful ability for only extremely high level characters. Feel free
* to manipulate the object VNUMS as you need to. For the shovel, I used
* the one that comes with the stock area Cemetary - VNUM 3604. The idea
* is simple: create a plot in a room (an object with no take or hold flags)
* put a timer on it, when that hits 0, extract the object and replace it with
* the plant, which is a type of container, and the fruit is loaded inside.
* Once the fruit is "picked", the plant vanishes with a message. I'll try
* to make this as easy and straightforward to use as I can. Feel free to
* use it as you like so long as the original documentation is unchanged
* and credit for this code is given -- Theo
*/
/*First, let's get all the declarations out of the way. In merc.h add these */
#define AFF_POWER BV36 /*If you haven't adjusted your bitvectors to handle 64 bits, you'll have to */
/*set this to a 32 bit integer below BV31; possibly repurpose an existing bitvector */
#define OBJ_VNUM_PLOT 7
#define OBJ_VNUM_BEAN 24
#define OBJ_VNUM_SHOVEL 3604 /*Adjust these VNUMS as needed */
#define OBJ_VNUM_PLANT 25
#define OBJ_VNUM_FRUIT 26
#define ITEM_PLOT 37 /*Adjust these numbers to fit your needs*/
#define ITEM_BEAN 38
/* In the DO_FUN section we add this: */
DECLARE_DO_FUN( do_plant_seed ) ; /* Specialization skill --Theo */
/* And in the SPELL_FUN section we add this: */
DECLARE_SPELL_FUN( spell_power_aura );
/*That's all for merc.h */
/* In bit.c we'll need to add to the item tables for the new item types */
/*the struct for type_flags[]:*/
const struct flag_type type_flags[ ]=
{
{"light", ITEM_LIGHT, TRUE},
{"scroll", ITEM_SCROLL, TRUE},
{"wand", ITEM_WAND, TRUE},
{"staff", ITEM_STAFF, TRUE},
{"weapon", ITEM_WEAPON, TRUE},
{"treasure", ITEM_TREASURE, TRUE},
{"armor", ITEM_ARMOR, TRUE},
{"potion", ITEM_POTION, TRUE},
{"furniture", ITEM_FURNITURE, TRUE}, <---------Find this table
{"trash", ITEM_TRASH, TRUE},
{"container", ITEM_CONTAINER, TRUE},
{"drink-container", ITEM_DRINK_CON, TRUE},
{"key", ITEM_KEY, TRUE},
{"food", ITEM_FOOD, TRUE},
{"money", ITEM_MONEY, TRUE},
{"boat", ITEM_BOAT, TRUE},
{"npc_corpse", ITEM_CORPSE_NPC, TRUE},
{"pc_corpse", ITEM_CORPSE_PC, FALSE},
{"fountain", ITEM_FOUNTAIN, TRUE},
{"pill", ITEM_PILL, TRUE},
{"portal", ITEM_PORTAL, TRUE},
{"warp_stone", ITEM_WARP_STONE, TRUE},
{"clothing", ITEM_CLOTHING, TRUE},
{"ranged_weapon", ITEM_RANGED_WEAPON, TRUE},
{"ammo", ITEM_AMMO, TRUE},
{"gem", ITEM_GEM, TRUE},
/*Add these to it*/
{ "plot", ITEM_PLOT, TRUE }, /*New item types do_plant_seed() function --Theo */
/* Next in db.c we need to add the name types to the switch statment*/
/* Find this switch statement*/
/*
* Mess with object properties.
*/
switch ( obj->item_type )
{
default:
bug( "Read_object: vnum %d bad type.", pObjIndex->vnum );
break;
case ITEM_LIGHT:
case ITEM_TREASURE:
case ITEM_FURNITURE:
case ITEM_TRASH:
case ITEM_CONTAINER:
case ITEM_DRINK_CON:
case ITEM_KEY:
case ITEM_FOOD:
case ITEM_BOAT:
case ITEM_CORPSE_NPC:
case ITEM_CORPSE_PC:
case ITEM_FOUNTAIN:
case ITEM_PORTAL:
case ITEM_WARP_STONE:
case ITEM_AMMO:
case ITEM_GEM:
/*Add this to the bottom of it BEFORE the 'break;'*/
case ITEM_PLOT:
/**************************COPY BELOW HERE************************/
/* The main function, I have a dedicated .c file for things of this type,
* but you can just put it at the end of fight.c if you don't have anywhere
* else that you use.
*/
void do_plant_seed( CHAR_DATA * ch, char * argument )
{
OBJ_DATA *seed;
OBJ_DATA *shovel;
OBJ_DATA *plot;
OBJ_DATA *ground;
/* First we need to check and see if player has the right items */
for ( seed = ch->carrying; seed; seed = seed->next_content )
{
if ( seed->pIndexData->vnum == OBJ_VNUM_SEED )
break;
}
if ( !IS_OUTSIDE( ch ) )
{
send_to_char( "You gonna hack through the floor? You have to be outside in order to work the ground.\n\r", ch );
return;
}
/* Gotta have a seed to be able to plant */
if ( !seed )
{
send_to_char( "You do not have a magical seed.\n\r", ch );
return;
}
/* Need to be using a shovel to work the ground */
shovel = ( get_eq_char ( ch, WEAR_WIELD ) );
if( !shovel || shovel->pIndexData->vnum != OBJ_VNUM_SHOVEL )
{
send_to_char("You need a shovel to work the ground!\n\r", ch );
return;
}
for ( ground = ch->in_room->contents; ground;ground = ground->next_content )
{
if ( ground->item_type == ITEM_PLOT)
{
send_to_char("There is already a plot of dirt here!\n\r",ch);
return;
}
if( ground->pIndexData->vnum == OBJ_VNUM_PLANT )
{
send_to_char( "Harvest the fruit that's here already before trying to plant another seed.\n\r", ch );
return;
}
}
plot = create_object( get_obj_index( OBJ_VNUM_PLOT ), 0 );
obj_to_room( plot, ch->in_room );
plot->timer = number_fuzzy( 10 );
act( "You work the ground to create a plot.", ch, plot, NULL, TO_CHAR );
act( "$n works the ground to create a plot.", ch, plot, NULL, TO_ROOM );
extract_obj( seed );
return;
}
/***************************END OF FUNCTION******************************/
/*
* in magic.c we need to add a couple of bits to do_cast( ) because the power aura
* ability asociated with the plant seed skill. It increases the power of spells
* by 50% and decreases mana cost by half. If you wish the fruit to give a players
* different ability, then you can just omit this part and subsitute your own spell
* instead. If you do plan on using power aura as-is, find this section concerning
* casting with gems in function do_cast()
*/
if ( gem_mana > 0 )
{
take_mana_char( ch, mana/2, skill_table[sn].mana_type );
if ( gem_mana < mana / 2 )
ch->mana -= mana/2 - gem_mana;
}
else
ch->mana -= mana/2;
}
else
{
if ( gem_mana > 0 )
{
take_mana_char( ch, mana, skill_table[sn].mana_type );
if ( gem_mana < mana )
ch->mana -= mana - gem_mana;
}
/* Immediately after, add this code */
/**************************COPY BELOW HERE************************/
if (ch->level < 100 && !IS_SET( ch->affected_by, AFF_POWER ) )
{
ch->mana -= mana;
(*skill_table[sn].spell_fun) ( sn,URANGE( 1, ch->level, 100 ),ch, vo );
}
else if ( ch->level >= 100 && !IS_SET( ch->affected_by, AFF_POWER ) )
{
ch->mana -= mana;
(*skill_table[sn].spell_fun) (sn, URANGE (1,dlevel,100),ch, vo );
}
else /* For players affected by the aura of power spell */
{
dlevel += 50;
mana = mana / 2;
ch->mana -= mana;
(*skill_table[sn].spell_fun) (sn, URANGE (1,dlevel,150),ch, vo );
}
/*******************END COPY**********************/
/*
* We also need to create a spell in magic.c that will handle the magical abilities
* of the object created.
*
/* This "spell" just sets a bit that we can use. I use it to increase
* the power of spells by 50% as well as halve the mana cost. You can
* change this to suit your own needs.
*/
/**************************COPY BELOW HERE************************/
void spell_power_aura( int sn, int level, CHAR_DATA *ch, void *vo )
{
CHAR_DATA *victim = (CHAR_DATA *) vo;
AFFECT_DATA af;
int chance;
char buf[MAX_STRING_LENGTH];
sn = skill_lookup( "power aura" ); /*This is to set sn to the "proper" values listed in const.c --Theo */
if ( is_affected( victim, sn ) )
return;
af.type = sn;
af.duration = number_fuzzy( 10 ); /* All we want is to set the bit AFF_POWER which we can then use elswere -- Theo */
af.location = APPLY_NONE;
af.modifier = 0;
af.bitvector = AFF_POWER;
affect_to_char( victim, &af );
send_to_char( "An aura of {bPOWER{x surrounds you!\n\r", victim );
act( "An aura of {bPOWER{x surrounds $n!\n\r",
victim, NULL, NULL, TO_ROOM );
return;
}
/*******************END COPY**********************/
/* And since we added a spell, we need to add it to the skill_table[] in const.c Add it right to the end
* of the struct. Just above where you see this - }; */
/**************************COPY BELOW HERE************************/
"power aura",{ L_ARC },
spell_power_aura,TAR_CHAR_DEFENSIVE,POS_STANDING,
NULL,5,12,
"","Your {bPOWERFUL{x aura fades...",
SCHOOL_CONJURATION,
MANA_EARTH
},
/*******************END COPY**********************/
/* We need to add a few things to update.c in obj_update
* in order to turn the plot into a plant that loads the
* fruit for picking
*/
/*Add these variables to the start of obj_update( ) */
OBJ_DATA *plant;
OBJ_DATA *fruit;
int num;
/* In obj_update( ) look for the switch statement and add this: */
switch ( obj->item_type )
{
default: message = "$p vanishes."; break;
case ITEM_FOUNTAIN: message = "$p dries up."; break;
case ITEM_PLOT: message = "The fruits of hard work have paid off and $p has fully matured."; break; <-------Add this line here.
case ITEM_CORPSE_NPC:
case ITEM_CORPSE_PC: message = "$p decays into dust.";
/* A little further down you'll see this block of code: */
if ( obj->carried_by )
{
act( message, obj->carried_by, obj, NULL, TO_CHAR );
}
else
if ( obj->in_room && ( rch = obj->in_room->people ) )
{
act( message, rch, obj, NULL, TO_ROOM );
act( message, rch, obj, NULL, TO_CHAR );
}
/* Add this right below it: */
/**************************COPY BELOW HERE************************/
/*
* For "do_plant" specialization
* if obj is a plot, remove it and replace
* with a plant bearing fruit
* --Theo
*/
if( obj->pIndexData->vnum == OBJ_VNUM_PLOT )
{
plant = create_object( get_obj_index( OBJ_VNUM_PLANT ), 0 );
obj_to_room( plant, obj->in_room );
for( num = 1; num <= ( number_fuzzy( 2 ) ); num++ ) /* Each plant yeilds between 1-3 fruit */
{
fruit = ( create_object( get_obj_index( OBJ_VNUM_FRUIT ) , 0 ) );
obj_to_obj( fruit, plant );
}
}
/**************END COPY********************/
/* In act_object.c, in the function do_get( ), we need to add a bit
* of code to get the plant to vanish once the fruit has been picked.
*/
/* First we need to see if player only takes one fruit at a time and check that
* to see if anything remains in the plant, and if not, extract the plant.
* So find this block of code -
*/
if ( str_cmp( arg1, "all" ) && str_prefix( "all.", arg1 ) )
{
/* 'get obj container' */
obj = get_obj_list( ch, arg1, container->contains );
if ( !obj )
{
act( "I see nothing like that in the $T.",
ch, NULL, arg2, TO_CHAR );
return;
}
get_obj( ch, obj, container );
/* Immediately after, add this code to check the contents of the plant.
* Make sure the added code is INSIDE the braces for the if statement.
*/
/**************************COPY BELOW HERE************************/
if ( (container->pIndexData->vnum == OBJ_VNUM_PLANT) && !container->contains )
{
act( "$p has given up its fruit and withers to the ground.", ch, container, NULL, TO_ROOM );
act( "$p has given up its fruit and withers to the ground.", ch, container, NULL, TO_CHAR );
extract_obj( container );
found = TRUE;
}
/**************END COPY********************/
/* And then find the else statement right after that looks for "get all container" */
else
{
/* 'get all container' or 'get all.obj container' */
OBJ_DATA *obj_next;
found = FALSE;
for ( obj = container->contains; obj; obj = obj_next )
{
obj_next = obj->next_content;
if ( obj->deleted )
continue;
if ( ( arg1[3] == '\0' || is_name( &arg1[4], obj->name ) )
&& can_see_obj( ch, obj ) )
{
found = TRUE;
get_obj( ch, obj, container );
/* Add this code right after. Again, make sure you add the code INSIDE the braces for the if statement.
* Otherwise it might compile, but it won't work.
*/
/**************************COPY BELOW HERE************************/
if ( (container->pIndexData->vnum == OBJ_VNUM_PLANT) && (arg1[3] == '\0') )
{
act( "$p has given up its fruit and withers to the ground.", ch, container, NULL, TO_ROOM );
act( "$p has given up its fruit and withers to the ground.", ch, container, NULL, TO_CHAR );
extract_obj( container );
}
/**************END COPY********************/
/* And lastly, we need to add the "plant seed" command to the command table in interp.c */
{ "plant seed" , do_plant_seed, POS_STANDING, 0, LOG_NORMAL, 1,}, /* Plant seed skill -- Theo */
/* That's all for the code parts */
/*****ITEMS NEEDED****/
/*
* I created these in limbo.are, but you can use any area you want
*/
/*The seed */
#39
magical seed~
a magical seed~
A small white seed sits on the ground.~
~
37 0 1
0~ 0~ 0~ 0~ 0~
1 0 00
/*The plot */
#7
dirt plot~
a plot of dirt~
A plot of dirt used for gardening is here.~
~
37 0 0
0~ 0~ 0~ 0~ 0~
0 0 00
/*The plant - with color code. You can adjust the long_descr to be A Magical plant is growing here. if you don't have/want the color.*/
/* NOTE: This is a container that only holds 1kg*/
#25
magical plant~
a magical plant~
{o{gA {wM{yA{wG{yI{wC{yA{wL{g plant is growing here.{x~
~
15 68 0
1~ 0~ 0~ 0~ 0~
0 0 00
/*The magical fruit, again with color code. */
#26
magical fruit~
{o{gA '/{wM{yA{wG{yI{wC{yA{wL{g\' {mF{cr{ru{ci{mt{x~
A {ygolden{x {o{mf{cr{ru{ci{mt{x that seems to call to you lies on the ground...~
~
26 0 1
100~ power aura~ ~ ~ ~
1 100 00
#30
clean parchment~
a clean parchment~
A clean parchment lies here~
~
2 0 16385
0~ ~ ~ ~ ~
/*
* And that should be all there is. It should be fairly straightforward to install on most
* DIKU/Merc/Envy/whatever variants. You can adjust things to make it based on learned percentage
* like you would any other spell or skill, or you can do what I do and link it to a check_improve( )
* function that checks to see if the skill is improved slightly with each use.
*/