.-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-.  
 |                                                                       |  
 |                                                                       |  
 |                                                                       |  
 |                             ROOM AFFECTS                              |  
 |                                                                       |  
 !                                                                       !  
 :                         A Snippet written by                          :  
 :                              Valcados                                 :  
 .                           for SMAUG MUDs                              .  
 .                                                                       .  
 :                                                                       :  
 :                                                                       :  
 !                                                                       !  
 |                                                                       |  
 |                                                                       |  
 |                                                                       |  
 |                                                                       |  
 |                                                                       |  
 `-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-'


DESCRIPTION:
     Stock SMAUG comes packaged with a bare bones system for adding
     affects to rooms, but it is incomplete and very unsafe to use.
     This snippet changes that and elevates the inegrity of the room
     affect system to a point where you can use room affects to your
     heart's content and sleep easy.

     What's a room affect?  It's just like an object affect, but on
     a room.  For example, want everyone in a certain room to have
     +50 max hp?  Simply go there and "redit affect hit 50".


TESTING:
     Since this is a pretty new project of mind, it does not have a
     whole lot of testing.  The basic testing I've performed shows
     everything to work fine.  In any case, it's far more stable than
     the stock system SMAUG already has.


KNOWN PROBLEMS/BUGS:
     As a tradeoff for the extra stability, I changed it so the
     wearspell, removespell, and stripsn affects won't do anything
     on a room.  If one were to include these, and guarantee that
     the system would not crash or loop in extreme situations, the
     necessary complexity of the code would increase massively.

     The way I set up the saving (the stock SMAUG room affect
     system does not save the affects to the area), areas built
     with room affects should still load up fine on MUDs which
     haven't installed this snippet (but of course the room
     affects will not load).


IN-GAME MECHANICS:
     Affects are put on a room using redit, with the same syntax
     used for putting affects on objects:
     redit affect (field) (value)

     To remove an affect, use "redit rmaffect (number)".

     To see the affects on a particular room, and to get the
     number for removing affects, use rstat.

     To save affects to an area, save the area in the usual way.


HOW TO INSTALL:


1.  In build.c, in do_redit, find the block displayed when a builder types
    redit with no argument; add "affect" and "rmaffect" to the list of
    fields there.  (This step is optional but will certainly be helpful to
    your builders)


2.  In build.c, in do_redit, in the block where arg == "affect", find something like this:


		    send_to_char ("Unknown spell name.\n\r", ch);
		    return;
		}
	    }
	    else
		value = atoi (arg3);


Change it to this:


                    send_to_char ("Unknown spell name.\n\r", ch);
                    return;
                }
            }
            else
              if ( loc == APPLY_EXT_AFFECT )
              {
                value = get_aflag( arg3 );
                if ( value == -1 )
                {
                  send_to_char( "Invalid affected_by.\n\r", ch );
                  return;
                }
              }
              else
                value = atoi (arg3);



3.  Slightly further below the above change, find something like this:


	LINK(paf, location->first_affect, location->last_affect, next, prev);
	++top_affect;
	send_to_char ("Done.\n\r", ch);
	return;


Change that to this:


        LINK(paf, location->first_affect, location->last_affect, next, prev);
        ++top_affect;
        send_to_char ("Done.\n\r", ch);
        if ( paf->location != APPLY_WEARSPELL && paf->location != APPLY_REMOVESPELL && paf->location != APPLY_STRIPSN )
        {
          CHAR_DATA *vch;

          for ( vch = ch->in_room->first_person; vch; vch = vch->next_in_room )
            affect_modify( vch, paf, TRUE );
        }
        return;


4.  Further below, now in the block where arg == "rmaffect", find something like this:


	for ( paf = location->first_affect; paf; paf = paf->next )
	{
	    if ( ++count == loc )
	    {
		UNLINK(paf, location->first_affect, location->last_affect, next, prev);
		DISPOSE(paf);
		send_to_char( "Removed.\n\r", ch );
		--top_affect;
		return;
	    }
	}


Change it to this:


        for ( paf = location->first_affect; paf; paf = paf->next )
        {
            if ( ++count == loc )
            {
                UNLINK(paf, location->first_affect, location->last_affect, next, prev);
                if ( paf->location != APPLY_WEARSPELL && paf->location != APPLY_REMOVESPELL && paf->location != APPLY_STRIPSN )
                {
                  CHAR_DATA *vch;

                  for ( vch = ch->in_room->first_person; vch; vch = vch->next_in_room )
                    affect_modify( vch, paf, FALSE );
                }
                DISPOSE(paf);
                send_to_char( "Removed.\n\r", ch );
                --top_affect;
                return;
            }
        }


5.  In build.c, in fold_area, find something like this:


	for ( ed = pObjIndex->first_extradesc; ed; ed = ed->next )
	   fprintf( fpout, "E\n%s~\n%s~\n",
			ed->keyword, strip_cr( ed->description )	);


Below it, add this:


        for ( paf = room->first_affect; paf; paf = paf->next )
          fprintf( fpout, "E\nAffectData~\n%d %d~\n", paf->location,
             ((paf->location == APPLY_WEAPONSPELL
            || paf->location == APPLY_WEARSPELL
            || paf->location == APPLY_REMOVESPELL
            || paf->location == APPLY_STRIPSN
            || paf->location == APPLY_RECURRINGSPELL)
            && IS_VALID_SN(paf->modifier))
            ? skill_table[paf->modifier]->slot : paf->modifier          );


6.  Near the top of db.c, find something like this:


void init_supermob();


Below it, add this:


void read_two_numbers args(( char *buf, sh_int *loc, int *mod ));


7.  In db.c, in load_rooms, find something like this:


	    else if ( letter == 'E' )
	    {
		EXTRA_DESCR_DATA *ed;

		CREATE( ed, EXTRA_DESCR_DATA, 1 );
		ed->keyword		= fread_string( fp );
		ed->description		= fread_string( fp );
		LINK( ed, pRoomIndex->first_extradesc, pRoomIndex->last_extradesc,
			  next, prev );
		top_ed++;
	    }


Change it to this:


            else if (letter == 'E')
            {
                EXTRA_DESCR_DATA *ed;
                AFFECT_DATA *paf;
                char *ed_key = fread_string(fp);

                if ( !str_cmp( ed_key, "AffectData" ) )
                {
                  str_free( ed_key );
                  ed_key = fread_string_nohash(fp);
                  CREATE( paf, AFFECT_DATA, 1 );
                  read_two_numbers( ed_key, &paf->location, &paf->modifier );
                  free( ed_key );
                  paf->type = -1;
                  paf->duration = -1;
                  xCLEAR_BITS( paf->bitvector );
                  if ( paf->location == APPLY_WEAPONSPELL || paf->location == APPLY_WEARSPELL
                  ||   paf->location == APPLY_REMOVESPELL || paf->location == APPLY_STRIPSN
                  ||   paf->location == APPLY_RECURRINGSPELL )
                    paf->modifier = slot_lookup( paf->modifier );
                  LINK( paf, pRoomIndex->first_affect, pRoomIndex->last_affect, next, prev );
                  top_affect++;
                  if ( oldroom && paf->location != APPLY_WEARSPELL && paf->location != APPLY_REMOVESPELL && paf->location != APPLY_STRIPSN )
                  {
                    CHAR_DATA *vch;

                    for ( vch = pRoomIndex->first_person; vch; vch = vch->next_in_room )
                      affect_modify( vch, paf, TRUE );
                  }
                }
                else
                {
                  CREATE(ed, EXTRA_DESCR_DATA, 1);
                  ed->keyword                = ed_key;
                  ed->description                = fread_string(fp);
                  LINK(ed, pRoomIndex->first_extradesc, pRoomIndex->last_extradesc,
                          next, prev);
                  top_ed++;
                }
            }

8.  (Step 8 deleted on a revision, thanks to Kiasyn who pointed out it wasn't needed.  Thanks Kiasyn!!!)

9.  In db.c, function delete_room, declare this new variable:


  AFFECT_DATA *paf;


10. Further down in delete_room, find something like this:


  while ((ed = room->first_extradesc) != NULL)
  {
    room->first_extradesc = ed->next;
    STRFREE(ed->keyword);
    STRFREE(ed->description);
    DISPOSE(ed);
    --top_ed;
  }


Below it, add this:


  while ( ( paf = room->first_affect ) != NULL )
  {
    UNLINK( paf, room->first_affect, room->last_affect, next, prev );
    free( paf );
  }


11. Somewhere in db.c (for example the very bottom), add this function:


void read_two_numbers( char *buf, sh_int *loc, int *mod )
{
  char buf2[MAX_STRING_LENGTH], *p=buf, *q = buf2;

  while ( *p != ' ' && *p != '\0' )
    *q++ = *p++;

  *q = '\0';
  *loc = atoi( buf2 );

  if ( !*p )
  {
    *mod = 0;
    return;
  }

  p++;
  q = buf2;
  while ( *p != '\0' )
    *q++ = *p++;

  *q = '\0';
  *mod = atoi( buf2 );

  return;
}


12. In handler.c, in function affect_to_char, find something like this:


    affect_modify( ch, paf_new, TRUE );


Below it, add this:


    if ( ch->in_room )
      room_affect( ch->in_room, paf_new, TRUE );


13. Just slightly below, in function affect_remove, find something like this:


    affect_modify( ch, paf, FALSE );


Below it, add this:


    if ( ch->in_room )
      room_affect( ch->in_room, paf, FALSE );


14. In handler.c, in char_from_room, find this block (or similar):


    if ( !char_died(ch) )
    {
	for ( paf = ch->in_room->first_affect; paf; paf = paf->next )
	    affect_modify(ch, paf, FALSE);

	if ( char_died(ch) )	/* could die from removespell, etc */
	    return;
    }


Delete it and replace it with this:


    for ( paf = ch->in_room->first_affect; paf; paf = paf->next )
    {
      if ( paf->location != APPLY_WEARSPELL && paf->location != APPLY_REMOVESPELL && paf->location != APPLY_STRIPSN )
        affect_modify( ch, paf, FALSE );
    }


15. Further down, in char_to_room, find a block like this:


    if ( !char_died(ch) )
    {
	for ( paf = pRoomIndex->first_affect; paf; paf = paf->next )
	    affect_modify(ch, paf, TRUE);

	if ( char_died(ch) )	/* could die from a wearspell, etc */
	    return;
    }


Delete it and replace it with this:


    for ( paf = pRoomIndex->first_affect; paf; paf = paf->next )
    {
      if ( paf->location != APPLY_WEARSPELL && paf->location != APPLY_REMOVESPELL && paf->location != APPLY_STRIPSN )
        affect_modify( ch, paf, TRUE );
    }


16. In handler.c, in function clean_room, add these variable declarations:


   AFFECT_DATA *paf;
   CHAR_DATA *vch;


17. Further below in clean_room, find something like this:


   for ( pexit = room->first_exit; pexit; pexit = pexit_next )
   {
	pexit_next = pexit->next;
	STRFREE( pexit->keyword );
	STRFREE( pexit->description );
	DISPOSE( pexit );
	top_exit--;
   }


Below that, add this:


   while ( ( paf = room->first_affect ) != NULL )
   {
     if ( paf->location != APPLY_WEARSPELL && paf->location != APPLY_WEAPONSPELL )
     {
       for ( vch = room->first_person; vch; vch = vch->next )
         affect_modify( vch, paf, FALSE );
     }
     UNLINK( paf, room->first_affect, room->last_affect, next, prev );
     free( paf );
   }


18. In handler.c, in function fix_char, find something like this:


    for ( aff = ch->first_affect; aff; aff = aff->next )
	affect_modify( ch, aff, FALSE );


Below that, add this:


    if ( ch->in_room )
    {
      for ( aff = ch->in_room->first_affect; aff; aff = aff->next )
      {
        if ( aff->location != APPLY_WEARSPELL && aff->location != APPLY_REMOVESPELL && aff->location != APPLY_STRIPSN )
          affect_modify( ch, aff, FALSE );
      }
    }


Then further down in fix_char, find something like this:


    for ( aff = ch->first_affect; aff; aff = aff->next )
	affect_modify( ch, aff, TRUE );


And below it add this:


    if ( ch->in_room )
    {
      for ( aff = ch->in_room->first_affect; aff; aff = aff->next )
      {
        if ( aff->location != APPLY_WEARSPELL && aff->location != APPLY_REMOVESPELL && aff->location != APPLY_STRIPSN )
          affect_modify( ch, aff, TRUE );
      }
    }


19. In handler.c, in function update_aris, find something like this:


	/* Add in effect from spells */
	for (paf = ch->first_affect; paf; paf = paf->next)
	    aris_affect(ch, paf);


Below it, add this:


        if ( ch->in_room )
        {
          for ( paf = ch->in_room->first_affect; paf; paf = paf->next )
            aris_affect( ch, paf );
        }


20. In save.c, in function de_equip_char, find something like this:


	    unequip_char(ch, obj);
	}
}


Change that to this:


	    unequip_char(ch, obj);
	}
    if ( ch->in_room )
    {
      AFFECT_DATA *paf;
      for ( paf = ch->in_room->first_affect; paf; paf = paf->next )
        if ( paf->location != APPLY_WEARSPELL && paf->location != APPLY_REMOVESPELL )
          affect_modify( ch, paf, FALSE );
    }
}


21.  Just below, in function re_equip_char, find something like this:


	   }
	   else
		break;
}


Change that to this:


	   }
	   else
		break;
    if ( ch->in_room )
    {
      AFFECT_DATA *paf;
      for ( paf = ch->in_room->first_affect; paf; paf = paf->next )
        if ( paf->location != APPLY_WEARSPELL && paf->location != APPLY_REMOVESPELL )
          affect_modify( ch, paf, TRUE );
    }
}


22. In db.c, in function make_room, find something like this:

        pRoomIndex->first_exit                = NULL;
        pRoomIndex->last_exit                = NULL;


Below that, add this:


        pRoomIndex->first_affect = NULL;
        pRoomIndex->last_affect = NULL;


23. In db.c, in function load_rooms, find something like this:


        fBootDb = tmpBootDb;
        pRoomIndex->area                = tarea;
        pRoomIndex->vnum                = vnum;
        pRoomIndex->first_extradesc        = NULL;
        pRoomIndex->last_extradesc        = NULL;

        if (fBootDb)
        {
          if (!tarea->low_r_vnum)


Change it to this:


        fBootDb = tmpBootDb;
        pRoomIndex->area                = tarea;
        pRoomIndex->vnum                = vnum;
        pRoomIndex->first_extradesc        = NULL;
        pRoomIndex->last_extradesc        = NULL;
        pRoomIndex->first_affect        = NULL;
        pRoomIndex->last_affect         = NULL;

        if (fBootDb)
        {
          if (!tarea->low_r_vnum)


24.  In act_move.c, in function generate_exit, find something like this:


    if ( !found )
    {
        CREATE( room, ROOM_INDEX_DATA, 1 );


Below that, add this:


        room->first_affect = NULL;
        room->last_affect = NULL;