How to add a spell

Login to reply  Page: « < 1 of 1 > »
06 Dec 2008 - 22:07846
How to add a spell
Going through some of my old folders I found this that others may be interested in:


Quote:

in spells.h, add a #define for the spell (where all the others are),
giving it a unique number less than MAX_SPELLS (defined at the bottom
of the spell list, before the skill list).

if it is a manual spell, search for ASPELL and add one for the new
spell you are putting in.

furthermore, for manual spells, put the code itself for the spell at
the bottom of spells.c.

if it is not a manual spell, in magic.c, if it is a spell that does
damage, search for man_damage and put in a case for your spell. if it
affects a character in any way (e.g. strength, armor, blindness,
etc.), put in a case in mag_affects. etc. for the other spell types.
read the comments for each type - they are there for a reason :)

when all this is done, go over to spell_parser.c.
put the spell into char *spells[] in a slot marked UNUSED (it should
have an index number equal to the value you defined the spell to be in
spells.h, so if SPELL_KILL_BARNEY is defined as 101 in spells.h, it
better be in slot 101 in spells[] - the slots are marked every 5 for
convenience.
if the spell is a manual spell, in the call_magic function, add a case
for it where the other manual spells are.
finally, add a spello - there are detailed notes on what each value
should be, so it should not be difficult. if necessary, just copy
another spell of the same type and modify it to suit your needs.

finally, in constants.c, search for spell_wear_off_msg[] and add a
message at the end that will be displayed when the spell wears off.
even if that doesn't make sense (spells with instantaneous effect),
you need to put in the spell name (e.g. "!Kill Barney!",) anyway, so
the index number in the array correspond with the correct spell.


A more in-depth example with the stoneskin spell:

Open spells.h, go down to the last spell define, declared in the top of
the file.

Right below that one, add:

#define SPELL_STONE_SKIN


##
   where ## is the next available spell define.

Close and save the file.

Open magic.c

Go down to mag_affects in magic.c, and below the case SPELL_ARMOR (just
for reference), add:

   case SPELL_STONE_SKIN:
      af[0].location = APPLY_AC;
      af[0].modifier = -30;
      af[0].duration = 25;
      af[0].bitvector = AFF_STONE_SKIN;
      accum_duration = FALSE;

      to_vict = "You skin turns to stone!";
      to_room = "You watch in fascination as $n's skin turns to stone!";
      break;

EXPLANATION:
   The above block of code goes within the switch (spellnum) statement.

   You can hold up to 3 affects within a spell definition.
   If you wish to add another affect, instead of af[0] use af[1] or af[2]
   nothing higher than that.

   af[0].location = One of the applies as defined in structs.h

   af[0].duration = how long the spell lasts.

   af[0].modifier = How much the spell affects your stats.

   af[0].bitvector = AFF flag the spell sets, if any. If none, leave blank.

*NOTE* The aff bitvector needs to be defined in structs.h, and

       the actual affect for the bitvector needs to be defined

       in the appropriate file.
           ie: AFF_SANCTUARY actual modifications is set in fight.c

Close magic.c, open spell_parser.c

In the huge list of spells names near the top of the file, find the first
"!UNUSED!" and replace it with "stone skin".

This is the name used to practice or cast the spell.

Then, scroll to the bottom of the file, where the rest of the spello()
declares are.

  spello(SPELL_XXX, MAX_MANA, MIN_MANA, MANA_CHANGE, MIN_POSITION,

CHAR_BITVECTOR, VIOLENT?, FUNCTION WHERE DECLARED);

Explanation:

SPELL_XXXX
= Define of the spell, as defined in spells.h

MAX_MANA
= Mana cost when player first gets spells.

MIN_MANA
= Lowest mana cost of spell.

MANA_CHANGE
= Change of Mana cost per level.

CHAR_BITVECTOR  = See spells.h for a list of valid bitvectors

VIOLET

= True if yes, False if no.

FUNCTION
= one of the main spell functions.

So, a spello for stone skin could be:
  spello(SPELL_STONE_SKIN, 50, 25, 3, POS_STANDING,

TAR_CHAR_ROOM | TAR_SELF_ONLY, FALSE, MAG_AFFECTS);

Close spell_parser.c, open constants.c.

Scroll down to const char *spell_wear_off_msg[] =

At the bottom of that list, before the last "!UNUSED!", add:
"Your skin slowly softens as it returns to normal",

And finally 4 other spells I added years ago to an old MUD called Time Warp:
/*--------------------------------------ACT.INFORMATIVE.C---*/
+291
    if (IS_AFFECTED(i, AFF_SILENCE))
      act("...$e looks to be in deep contemplation..", FALSE, i, 0, ch, TO_VICT);

+304
  if(AFF_FLAGGED(i, AFF_FLYING))
    strcat(buf, " &w(&Bflying&w)");

+779
  if (IS_AFFECTED(ch, AFF_FLYING))
    strcat(buf, "&BFlying  ");
  if (IS_AFFECTED(ch, AFF_SILENCE))
    strcat(buf, "&RSilenced&n");
  if (IS_AFFECTED(ch, AFF_REGENERATION))
    strcat(buf, "&GRegenerating&n");

/*--------------------------------------ACT.MOVEMENT.C------*/
+70 in has_boat
  if ((IS_AFFECTED(ch, AFF_WATERWALK)) || (GET_LEVEL(ch) >= 
LVL_IMMORT) || (IS_AFFECTED(ch, AFF_FLYING)))
     return 1;

  need_movement = (movement_loss[SECT(ch->in_room)] +
		   movement_loss[SECT(EXIT(ch, dir)->to_room)]) / 2;
+126
  if (IS_AFFECTED(ch,AFF_FLYING)) 
    need_movement = 1;

!
  if (!AFF_FLAGGED(ch, AFF_SNEAK)) {
    sprintf(buf2, "$n leaves %s.", dirs[dir]);
    act(buf2, TRUE, ch, 0, 0, TO_ROOM);
  }
!158
  if (AFF_FLAGGED(ch, AFF_FLYING)) {
    sprintf(buf2, "$n flies %s.", dirs[dir]);
    act(buf2, TRUE, ch, 0, 0, TO_ROOM);
  }
    else if (!AFF_FLAGGED(ch, AFF_SNEAK)) {
      sprintf(buf2, "$n leaves %s.", dirs[dir]);
      act(buf2, TRUE, ch, 0, 0, TO_ROOM);
    }


/*-----------------------------------------CLASS.C-----------------*/
+2147
  spell_level(SPELL_FLY, CLASS_MAGIC_USER, 50);
  spell_level(SPELL_SILENCE, CLASS_MAGIC_USER, 65);
  spell_level(SPELL_REGENERATION, CLASS_MAGIC_USER, 38);
  spell_level(SPELL_ENTANGLE, CLASS_CLERIC, 7);
  spell_level(SPELL_REGENERATION, CLASS_CLERIC, 28);



/*--------------------------------------CONSTANTS.C------------------------------------------*/
/* AFF_x */
const char *affected_bits[] =
Add:222
  "SILENCE",
  "REGEN",
  "FLY",


Add:783
  "You slowly float to the ground.",
  "!Gate!",
  "You feel intelligent enough to cast spells once more.",
  "Your body stops regenerating at an unnatural rate.",
  "!Entangle!"
 
/*-----------------------------------------MAGIC.C---------------*/

+512
  case SPELL_FLY:
    af[0].duration = 1 + (GET_LEVEL(ch) / 10);
    af[0].bitvector = AFF_FLYING;
    accum_duration = TRUE;
    to_vict = "Your feet lift up off of the ground.";
    to_room = "$n starts to fly.";
   break;

  case SPELL_SILENCE:
    af[0].location = APPLY_INT;  
    af[0].modifier = -4;         
    af[0].duration = 10;
    af[0].bitvector = AFF_SILENCE;
    to_room = "$n looks puzzled for a moment and grimaces.";
    to_vict = "You can't seem to remember your spells...";
    break;

  case SPELL_REGENERATION:
    af[0].bitvector = AFF_REGENERATION;
    af[0].duration = 10;
    accum_duration = TRUE;
    to_vict = "You feel regenerated.";
    break;

+862
  case SPELL_ENTANGLE:
    GET_MOVE(victim) = 0;
    send_to_room("Roots erupt out of the ground, thrashing about 
you!\r\n", ch->in_room);
    send_to_char("You have been entangled!\r\n", victim);
    break;

/* add new spells above this line */


/*-----------------------------------------SPELLS.H------------------------------------------*/

+90
#define SPELL_FLY                    52
#define SPELL_GATE                   53
#define SPELL_SILENCE                54 
#define SPELL_REGENERATION           55
#define SPELL_ENTANGLE               56

/*----------------------------------------SPELL_PARSER.C-----------------*/

+918
  spello(SPELL_FLY, "fly", 40, 20, 2, POS_STANDING,
	TAR_CHAR_ROOM, FALSE, MAG_AFFECTS);

  spello(SPELL_GATE, "gate", 50, 50, 0, POS_STANDING,
         TAR_CHAR_WORLD | TAR_NOT_SELF, FALSE, MAG_MANUAL);

  spello(SPELL_SILENCE, "silence", 60, 45, 2, POS_STANDING,
	 TAR_CHAR_WORLD | TAR_NOT_SELF, TRUE, MAG_AFFECTS);

  spello(SPELL_REGENERATION, "regeneration", 60, 45, 2, POS_STANDING,
         TAR_CHAR_ROOM, FALSE, MAG_AFFECTS);

  spello(SPELL_ENTANGLE, "entangle", 50, 30, 1, POS_STANDING,
	 TAR_CHAR_ROOM, TRUE, MAG_POINTS);

+490
  if (IS_AFFECTED(ch, AFF_SILENCE)) {
     send_to_char("You are silenced, you can't!\r\n", ch);
     return 0;
  }
/*----------------------------------------STRUCTS.H-----------------*/
+246
#define AFF_SILENCE	      (1 << 16)	   /* Char can't cast spells    */
#define AFF_REGENERATION      (1 << 17)	   /* gain X3		        */
#define AFF_FLYING            (1 << 22)      /* flying                    */

/*----------------------------------------LIMITS.C----------------*/

This line goes in INT MANA_GAIN and HP and move.
+120, 170, 217
  if (AFF_FLAGGED(ch, AFF_REGENERATION))
    gain *= 3;





ASPELL(spell_recharge)
{
 int restored_charges = 0, explode = 0;

 if (ch == NULL || obj == NULL)
   return;

 if (GET_OBJ_TYPE(obj) == ITEM_WAND) {
   if (GET_OBJ_VAL(obj, 2) < GET_OBJ_VAL(obj, 1)) {
      send_to_char("You attempt to recharge the wand.\r\n", ch);
      restored_charges = number(1, 5);
      GET_OBJ_VAL(obj, 2) += restored_charges;
      if (GET_OBJ_VAL(obj, 2) > GET_OBJ_VAL(obj, 1)) {
        send_to_char("The wand is overcharged and explodes!\r\n", ch);
        sprintf(buf, "%s overcharges %s and it explodes!\r\n", GET_NAME(ch), obj->name);
        act(buf, TRUE, 0, 0, 0, TO_NOTVICT);
        explode = dice(GET_OBJ_VAL(obj, 2), 2);
        GET_HIT(ch) -= explode;
        update_pos(ch);
        extract_obj(obj);
        return;
        }
    else {
      sprintf(buf, "You restore %d charges to the wand.\r\n", restored_charges);
      send_to_char(buf, ch);
      return;
      }
    }
  else {
    send_to_char("That item is already at full charges!\r\n", ch);
    return;
    }
  }
else if (GET_OBJ_TYPE(obj) == ITEM_STAFF) {
  if (GET_OBJ_VAL(obj, 2) < GET_OBJ_VAL(obj, 1)) {
    send_to_char("You attempt to recharge the staff.\r\n", ch);
    restored_charges = number(1, 3);
    GET_OBJ_VAL(obj, 2) += restored_charges;
    if (GET_OBJ_VAL(obj, 2) > GET_OBJ_VAL(obj, 1)) {
      send_to_char("The staff is overcharged and explodes!\r\n", ch);
      sprintf(buf, "%s overcharges %s and it explodes!\r\n", GET_NAME(ch), obj->name);
      act(buf, TRUE, 0, 0, 0, TO_NOTVICT);
      explode = dice(GET_OBJ_VAL(obj, 2), 3);
      GET_HIT(ch) -= explode;
      update_pos(ch);
      extract_obj(obj);
      return;
      }
    else {
      sprintf(buf, "You restore %d charges to the staff.\r\n", restored_charges);
      send_to_char(buf, ch);
      return;
      }
    }
  else {
    send_to_char("That item is already at full charges!\r\n", ch);
    return;
    }
  }
}

Change spells.h with adding new spell define, change spell_parser.c with adding 
another spello(), another case to deal with manual spells and change one of the 
!UNUSED!... Add this little snippet to the spells.c and that's it... Hm, no also add 
one more ASPELL define in spells.h :)


__________________
Rumble
The Builder Academy
tbamud.com 9091

Last edited by Rumble (23 Dec 2009 - 19:32)
Login to reply  Page: « < 1 of 1 > »