.-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-. | | | | | | | 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;