.-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-. 
 |                                                                       | 
 |                                                                       | 
 |                                                                       | 
 |                           ELEMENTAL ITEMS                             | 
 |                                                                       | 
 !                                                                       ! 
 :                         A Snippet written by                          : 
 :                              Valcados                                 : 
 .                           for SMAUG 1.02                              . 
 .                                                                       . 
 :                                                                       : 
 :                                                                       : 
 !                                                                       ! 
 |                                                                       | 
 |                                                                       | 
 |                                                                       | 
 |                                                                       | 
 |                                                                       | 
 `-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-'
 
 DESCRIPTION:
 	This code snippet adds support for elemental items in the
 	SMAUG codebase.  This mainly effects weapons and armors.
 	When a fighter uses a non-elemental weapon, his attacks are
 	influenced by his opponent's resistance/susceptibility/immunity
 	just to the weapon's type:  slash, pierce, etc.
 	If the weapon is elemental, the attacks are then also influenced
 	by his opponent's res/susc/immunity to the element.
 	For example, a fire elemental sword will do no damage to an
 	enemy who is immune to fire, even if the enemy is susceptible to
 	swords.  Thus an elemental weapon can be stronger than a non-
 	elemental weapon against appropriate foes, but it is a very
 	specialized tool, and in most cases is actually weaker, since
 	enemies tend to have more resistances than susceptibility.
 	
 	Elemental armor is more likely to be damaged and scrapped by
 	attacks from weapons of the opposite element, and less likely
 	to be damaged and scrapped by attacks from weapons of the same
 	element.
 	
 	Additionally, fire elemental items can be instantly destroyed
 	by the "frost breath" spell, and cold elemental items can be
 	instantly destroyed by the "fire breath" spell.  This depends
 	upon the victim's saving spell vs. breath.  Fire items, cold
 	items, and acid items are immune to destruction from fire breath,
 	frost breath, and acid breath, respectively.
 	
 TESTING:
 	This code has been in use on the Lands of Aethar MUD
 	(www.aethar.com) for several years now and is thoroughly
 	assimilated into that MUD.  However, in writing this
 	snippet, I've made some tiny changes to make things more
 	SMAUGlike, and those are untested.
 	Also, bear in mind that Lands of Aethar code in general
 	is thoroughly modified, and is built out of an earlier
 	code release than 1.4a.
 	
 KNOWN PROBLEMS/BUGS:
 	In stock SMAUG 1.02, backstab and circle, although requiring
 	stabbing weapons to be wielded, don't actually automatically
 	deal the damage with the stabbing weapon, for instance if you
 	wield a dagger and a club, and backstab, the club may actually
 	be the weapon which is used.  This of course means if the club
 	was fire elemental, your backstab/circle may be fire elemental
 	even though your dagger is not.
 	
 	It hardly needs to be said, but an area with elemental items
 	might not be loadable on a MUD where this snippet is uninstalled.
 	
 	Overall problem/bug assessment:  utterly negligible.
 	
IN-GAME MECHANICS:
	Elements are set on items using the oset or mposet command.
	It is possible to have items with elements different than their
	prototypes, allowing such things as granting elements as quest
	rewards or programming mobs to spawn the item with a randomized
	element.
	Elements are visible to players with "identify" and with the
	status screen on the "auction" command.  Also, certain elemental
	weapons have extra adjectives (Your blazing slash wounds the
	goblin).  They are also visible with ostat.

HOW TO INSTALL:

1.  in act_obj.c, in do_auction, find the code for when a player
	enters no argument and thus is shown the item's stats.
	At an appropriate place (I like to put it right after the
	wearlocation is displayed) add:
	
	show_element_to_char( ch, obj );
	
2.  in act_wiz.c, in do_ostat, wherever you think appropriate
	(I like to put it right after the "Extra affects"), add
	
	show_element_to_char( ch, obj );
	
3.  in build.c, if it isn't already there (or in mud.h), add the global
	function prototype (near the top, you can put it right after the
	#includes)
	
	int get_sdamage args( ( char *name ) );
	
4.  in build.c, in do_oset, find the list of fields for when a builder
	types oset with no arguments, and add "element" to the list.
	
5.  in build.c, in do_oset, find the line "if ( !str_cmp( arg2, "short" ) )"
	Right above this, add the new block
	
        if ( !str_cmp( arg2, "element" ) )
        {
                sh_int new_element = get_sdamage( arg3 );
                if ( new_element == -1 )
                {
                        send_to_char( "That's not a spell damage type.\n\r", ch );
                        return;
                }
                if ( IS_OBJ_STAT( obj, ITEM_PROTOTYPE ) )
                {
                        if ( !can_omodify( ch, obj ) )
                        {
                                send_to_char( "You can't edit this item.\n\r", ch );
                                return;
                        }
                        obj->pIndexData->element = new_element;
                }
                if ( obj->element != new_element )
                switch ( new_element )
                {
                    case SD_NONE:
                    set_char_color( AT_PLAIN, ch );
                    ch_printf( ch, "You drain the elemental power from %s...\n\r", obj->short_descr );
                    break;
                    case SD_FIRE:
                    set_char_color( AT_FIRE, ch );
                    ch_printf( ch, "With a crackle, bright flames burst forth from %s!\n\r", obj->short_descr );
                    break;
                    case SD_COLD:
                    set_char_color( AT_LBLUE, ch );
                    ch_printf( ch, "Swirls of cold coalesce into %s, leaving flecks of ice over its surface...\n\r", obj->short_descr );
                    break;
                    case SD_ELECTRICITY:
                    set_char_color( AT_YELLOW, ch );
                    ch_printf( ch, "Currents of electricity run along the surface of %s, crackling...\n\r", obj->short_descr );
                    break;
                    case SD_ENERGY:
                    set_char_color( AT_WHITE, ch );
		        ch_printf( ch, "As mysterious energies are drawn into %s, it begins trembling with raw power!\n\r", obj->short_descr );
		        break;
		        case SD_ACID:
		        set_char_color( AT_GREEN, ch );
		        ch_printf( ch, "Drops of deadly acid fall from %s and sizzle in a pool on the ground...\n\r", obj->short_descr );
		        break;
		        case SD_POISON:
		        set_char_color( AT_DGREEN, ch );
		        ch_printf( ch, "Drops of deadly poison fall from %s and gather in a pool on the ground...\n\r", obj->short_descr );
		        break;
		        case SD_DRAIN:
		        set_char_color( AT_BLOOD, ch );
		        ch_printf( ch, "Nearby life forces begin to slowly converge into %s ...\n\r", obj->short_descr );
                        break;
                        default:
                        break;
                }
                obj->element = new_element;
                set_char_color( AT_PURPLE, ch );
                send_to_char( "Done.\n\r", ch );
                return;
        }
        
6.  in build.c, in fold_area, find this code (or something like it):

        if ( pObjIndex->layers )
          fprintf( fpout, "%d %s %d %d\n",      pObjIndex->item_type,
                                print_bitvector(&pObjIndex->extra_flags),
                                                pObjIndex->wear_flags,
                                                pObjIndex->layers       );
        else
          fprintf( fpout, "%d %s %d\n", pObjIndex->item_type,
                        print_bitvector(&pObjIndex->extra_flags),
                                        pObjIndex->wear_flags           );
                                        
    Replace it with the following:
    
        fprintf( fpout, "%d %s %d %d %d\n", pObjIndex->item_type,
         			print_bitvector(&pObjIndex->extra_flags),
         					pObjIndex->wear_flags,
         					pObjIndex->layers,
                                    pObjIndex->element );
                                        
7.  At the bottom of build.c, add the following function:

void show_element_to_char( CHAR_DATA *ch, OBJ_DATA *obj )
{
        char *txt = NULL;

        if ( obj->element == SD_NONE )
        return;

        switch ( obj->element )
        {
                case SD_FIRE:
                set_char_color( AT_FIRE, ch );
                txt = "fire";
                break;
                case SD_COLD:
                set_char_color( AT_LBLUE, ch );
                txt = "ice";
                break;
                case SD_ELECTRICITY:
                set_char_color( AT_YELLOW, ch );
                txt = "lightning";
                break;
                case SD_ENERGY:
                set_char_color( AT_WHITE, ch );
                txt = "energy";
                break;
                case SD_ACID:
                set_char_color( AT_GREEN, ch );
                txt = "acid";
                break;
                case SD_POISON:
                set_char_color( AT_DGREEN, ch );
                txt = "poison";
                break;
                case SD_DRAIN:
                set_char_color( AT_BLOOD, ch );
                txt = "life draining";
                break;
                default:
                break;
        }
        if ( txt )
        ch_printf( ch, "This item has been imbued with the element of %s.\n\r", txt );
        set_char_color( AT_MAGIC, ch );
        return;
}


8.  In db.c, in load_objects, find the following code (or something similar):

        x1=x2=0;
        sscanf(ln, "%d %d",
                &x1, &x2);
        pObjIndex->wear_flags                = x1;
        pObjIndex->layers                = x2;
        
    Replace it with the following:
    
        x1=x2=x3=0;
        sscanf(ln, "%d %d %d",
                &x1, &x2, &x3);
        pObjIndex->wear_flags                = x1;
        pObjIndex->layers                = x2;
        pObjIndex->element		 = x3;


9.  In db.c, in create_object, find the line "obj->cost                = pObjIndex->cost;" (or similar)
	and below it, add the line
	
	obj->element = pObjIndex->element;
	

10. In db.c, in make_object, find the line "pObjIndex->cost                = 0;" (or similar)
	and below it, add the line
	
	pObjIndex->element = SD_NONE;
	
	
11. In db.c, in make_object, find the line
		"pObjIndex->short_descr        = QUICKLINK(cObjIndex->short_descr);"  (or similar)
	and below it, add the line
	
		pObjIndex->element              = cObjIndex->element;
		
		
12. In fight.c, in the global function declarations, change the
	new_dam_message declaration from
	
	void	new_dam_message	args( ( CHAR_DATA *ch, CHAR_DATA *victim, int dam,
			    int dt, OBJ_DATA *obj ) );
			  
	to
	
	void	new_dam_message	args( ( CHAR_DATA *ch, CHAR_DATA *victim, int dam,
			    int dt, OBJ_DATA *obj, sh_int elem ) );
			    

13. In fight.c, just above where the is_attack_supressed function
	starts, add the following.

	const int ris_from_sd[] = { -1, RIS_FIRE, RIS_COLD, RIS_ELECTRICITY, RIS_ENERGY, RIS_ACID,
                                  RIS_POISON, RIS_DRAIN };

	const sh_int opposite_elements[] = { SD_NONE, SD_COLD, SD_FIRE, SD_ACID, SD_DRAIN, SD_ELECTRICITY,
                                           SD_ENERGY, SD_ENERGY };

	char * const attack_adjective[] = { "", "blazing ", "freezing ", "", "", "corrossive ", "", "" };
	
	
    Incidentally, if you want to remove the elemental attack adjectives, or
    add new ones, the attack_adjectives array above is the place to do it.
	
14. In fight.c, in one_hit, find the following code (or similar):
    
    if ( (retcode = damage( ch, victim, dam, dt )) != rNONE )
	return retcode;
	
    replace it with this:
    
        if ( wield )
          retcode = specific_damage( ch, victim, dam, dt, wield->element );
        else
          retcode = damage( ch, victim, dam, dt );
          
        if ( retcode != rNONE )
          return retcode;


15.  In fight.c, find the damage function.  Change the top line

	ch_ret damage(CHAR_DATA *ch, CHAR_DATA *victim, int dam, int dt )
	
     to
     
        ch_ret specific_damage(CHAR_DATA *ch, CHAR_DATA *victim, int dam, int dt, sh_int elem )
        

16.  (fight.c) Now right above what was the damage function, and is now the
	specific_damage function, add the following:
	
	ch_ret damage( CHAR_DATA *ch, CHAR_DATA *victim, int dam, int dt )
	{
	        return specific_damage( ch, victim, dam, dt, SD_NONE );
	}
	

17.  (fight.c) Now in the specific_damage function, find the code
	where damage is modified by the victim's res/susc/immunity to
	the weapon.  It might look something like this...
	
	if ( dt == (TYPE_HIT + DAM_POUND) || dt == (TYPE_HIT + DAM_CRUSH)
	||   dt == (TYPE_HIT + DAM_STONE) || dt == (TYPE_HIT + DAM_PEA) )
	  dam = ris_damage(victim, dam, RIS_BLUNT);
	else
	if ( dt == (TYPE_HIT + DAM_STAB) || dt == (TYPE_HIT + DAM_PIERCE)
	||   dt == (TYPE_HIT + DAM_BITE) || dt == (TYPE_HIT + DAM_BOLT)
	||   dt == (TYPE_HIT + DAM_DART) || dt == (TYPE_HIT + DAM_ARROW) )
	  dam = ris_damage(victim, dam, RIS_PIERCE);
	else
	if ( dt == (TYPE_HIT + DAM_SLICE) || dt == (TYPE_HIT + DAM_SLASH)
	||   dt == (TYPE_HIT + DAM_WHIP)  || dt == (TYPE_HIT + DAM_CLAW) )
	  dam = ris_damage(victim, dam, RIS_SLASH);
	  
	Right below it, add the following:
	
        if ( dam > 0 && elem != SD_NONE )
          dam = ris_damage( victim, dam, ris_from_sd[elem] );
          

18.  Still in fight.c and still in specific_damage, find the block
	similar to this:
	
	if ( damobj )
	{
	    if ( dam > get_obj_resistance(damobj)
	    &&   number_bits(1) == 0 )
	    {
		set_cur_obj(damobj);
		damage_obj(damobj);
	    }
	    dam -= 5;  /* add a bonus for having something to block the blow */
	}
	
	Change it to this:
	
        if ( damobj && dam )
        {
                sh_int dam_mult = 1;
                sh_int skin_bonus = 5;

		    /*
		     *  Elemental items more resistant against same element,
		     *    less resistant against opposite element.
		     */
                if ( damobj->element != SD_NONE && elem != SD_NONE )
                {
                   if ( damobj->element == elem )
                     dam_mult += 2, skin_bonus -= 2;
                   else if ( damobj->element == opposite_elements[elem] )
                     dam_mult -= 2, skin_bonus += 2;
                }

                if ( dam > ( get_obj_resistance( damobj ) * dam_mult )
                && ( dam_mult > 2 || number_bits(1) == 0 ) )
                {
                  set_cur_obj(damobj);
                  damage_obj(damobj);
                }
                dam -= skin_bonus;  /* add a bonus for having something to block the blow */
        }
        

19. Still in fight.c in specific_damage, find a line like

        dam_message(ch, victim, dam, dt );
	        
    Replace it with
    
    	dam_message(ch, victim, dam, dt, elem);


20. In fight.c, find the dam_message function.  Change the very top line
	from something like
	
	void new_dam_message( CHAR_DATA *ch, CHAR_DATA *victim, int dam, int dt, OBJ_DATA *obj )
	
	to
	
	void new_dam_message( CHAR_DATA *ch, CHAR_DATA *victim, int dam, int dt, OBJ_DATA *obj, sh_int elem )
	

21. In fight.c, in dam_message, find something like

	sprintf( buf1, "$n's poisoned %s %s $N%c", attack, vp, punct );
	sprintf( buf2, "Your poisoned %s %s $N%c", attack, vp, punct );
	sprintf( buf3, "$n's poisoned %s %s you%c", attack, vp, punct );
	
    Change it to
    
        sprintf( buf1, "$n's %spoisoned %s %s $N%c", attack_adjective[elem], attack, vp, punct );
        sprintf( buf2, "Your %spoisoned %s %s $N%c", attack_adjective[elem], attack, vp, punct );
        sprintf( buf3, "$n's %spoisoned %s %s you%c", attack_adjective[elem], attack, vp, punct );
      
        

22. In fight.c, in dam_message, find something like

	sprintf( buf1, "$n's %s %s $N%c",  attack, vp, punct );
	sprintf( buf2, "Your %s %s $N%c",  attack, vp, punct );
	sprintf( buf3, "$n's %s %s you%c", attack, vp, punct );
	
    Change it to
    
        sprintf( buf1, "$n's %s%s %s $N%c", attack_adjective[elem], attack, vp, punct );
        sprintf( buf2, "Your %s%s %s $N%c", attack_adjective[elem], attack, vp, punct );
        sprintf( buf3, "$n's %s%s %s you%c", attack_adjective[elem], attack, vp, punct );


23. In fight.c, where the local functions are declared (near the top),
	find the declaration of dam_message, something like
	
	void    dam_message args( ( CHAR_DATA *ch, CHAR_DATA *victim, int dam,
                            int dt, OBJ_DATA *obj ) );

	Change it to
	
	void    new_dam_message args( ( CHAR_DATA *ch, CHAR_DATA *victim, int dam,
                            int dt, OBJ_DATA *obj, sh_int elem ) );
                            

24. In handler.c, in clone_object, right below a line like
	
	clone->value[5]     = obj->value[5];
	
    insert the new line
    
    	clone->element  = obj->element;
    	

25. In handler.c, in group_object, right below a line like

	&&   obj1->item_type        == obj2->item_type
	
    insert the new line
    
    	&&   obj1->element	    == obj2->element
    	

26. In magic.c, in spell_identify, at an appropriate point in the
	midst of the identify info (I like to put it right after
	the "special properties" blurb), add

	show_element_to_char( ch, obj );


27. In magic.c, in spell_acid_breath, right below a line like
	
	obj_next = obj_lose->next_content;
	
    add the lines

	/*
	 *  Acid-elemental items immune to acid breath destruction
	 */
	if ( obj_lose->element == SD_ACID )
	  continue;


28. In magic.c, in spell_fire_breath, right some lines like

            if ( number_bits( 2 ) != 0 )
                continue;
	
    add the lines

	/*
	 *  Fire-elemental items immune to immolation
	 */
	if ( obj_lose->element == SD_FIRE )
	  continue;


29. In magic.c, in spell_fire_breath, find a line like

	default:             continue;

     and replace it with this:
     
	default:
	  /*
	   *  Cold-elemental items susceptible to immolation,
	   *    even if their item type is not usually burnable
	   */
	  if ( obj_lose->element == SD_COLD )
	  {
	    msg = "$p flashes bright blue before disintegrating!";
	    break;
	  }
	  else
	    continue;


30. In magic.c, in spell_frost_breath, find a line like

	obj_next = obj_lose->next_content;
	
    below it, add this:
    
	/*
	 *  Cold-elemental items immune to frost breath destruction
	 */
	if ( obj_lose->element == SD_COLD )
	  continue;


31. In magic.c, in spell_frost_breath, find a line like

	default:            continue;

    replace it with:
    
	default:
	  /*
	   *  Fire-elemental items susceptible to freezing,
	   *    even if their item type is not usually freezable
	   */
	  if ( obj_lose->element == SD_FIRE )
	  {
	    msg = "$p flares up one last time before succumbing to the cold!";
	    break;
	  }
	  else
	    continue;


32. In mpxset.c, if it isn't already declared there (or in mud.h),
	declare the global function
	
	int get_sdamage args( ( char *name ) );

    You could maybe, for example, put this right below a line like
    
	int     get_trigflag    args( ( char *flag ) );
	

33. In mpxset.c, in do_mposet, find a block of code something like

    if ( !str_cmp( arg2, "name" ) )
    {
        STRFREE( obj->name );
        obj->name = STRALLOC( arg3 );
        return;
    }
    
    Below it, add the following:

    if ( !str_cmp( arg2, "element" ) )
    {
      sh_int new_el = get_sdamage( arg3 );
      if ( new_el == -1 )
      {
        progbug( "Mposet element: bad element", ch );
        return;
      }
      obj->element = new_el;
      return;
    }
    

34. In save.c, in fwrite_obj, look for some lines like this:

	if ( !xSAME_BITS(obj->extra_flags, obj->pIndexData->extra_flags) )
          fprintf( fp, "ExtraFlags   %s\n",       print_bitvector(&obj->extra_flags) );

    beneath them, add this:

        if ( obj->element != obj->pIndexData->element )
          fprintf( fp, "Element %d\n", obj->element );


35. In save.c, in fread_obj, in the variable declarations at the top of
	the function, declare new variable

	bool fElement = FALSE;


36. In save.c, in fread_obj, find a line similar to

	KEY( "ExtraFlags",  obj->extra_flags,       fread_bitvector( fp ) );

    Below it, add this:

            if ( !strcmp( word, "Element" ) )
            {
              fMatch = TRUE;
              fElement = TRUE;
              obj->element = fread_number( fp );
              break;
            }


37. In save.c, in fread_obj, find some lines like

                    if ( !obj->name )
                        obj->name = QUICKLINK( obj->pIndexData->name );

    Beneath them, add this:

                    if ( !fElement )
                      obj->element = obj->pIndexData->element;

38. In mud.h, find the obj_index_data structure.  Give it a new
	entry:
	
	sh_int element;


39. Repeat step 38 but this time for the obj_data structure.


40. In mud.h, find the global function declarations from build.c.
	The easiest way to do this is probably searching for
	"build.c", if that doesnt work then search for
	"get_cmdflag", if that still doesn't work, well, it
	doesn't REALLY matter very much where this line goes.
	Add the global function declaration:

	void show_element_to_char args(( CHAR_DATA *ch, OBJ_DATA *obj ));


41. Similarly, in the section for global function declarations
	from fight.c, declare the global function
	
	ch_ret specific_damage args((CHAR_DATA *ch, CHAR_DATA *victim, int dam, int dt, sh_int elem ));


42. Recompile, reboot the mud, and have fun!!!