void CHSInterface::AtrDel(int obj, const char *atrname, int owner) { if (false == ValidObject(obj)) { hs_log(HSPrintf("AtrDel() invalid object: %d, atr: %s", obj, atrname)); return; } #ifdef PENNMUSH // No change in code between versions atr_clr(obj, atrname, owner); #endif #if defined(TM3) || defined(MUX) my_atr_clear(obj, atrname); #endif }
void my_atr_clear(dbref obj, const char *atrname) { int atr; char name[SBUF_SIZE]; strcpy(name, atrname); #ifdef TM3 atr = mkattr((char *) atrname); #endif #ifdef MUX atr = mkattr(GOD, (char *) atrname); #endif atr_clr(obj, atr); }
int nfy_que(dbref sem, int attr, int key, int count) { int cSemaphore = 1; if (attr) { int aflags; dbref aowner; char *str = atr_get(sem, attr, &aowner, &aflags); cSemaphore = mux_atol(str); free_lbuf(str); } Notify_Num_Done = 0; if (cSemaphore > 0) { Notify_Key = key; Notify_Sem = sem; Notify_Attr = attr; Notify_Num_Max = count; if ( key == NFY_NFY || key == NFY_QUIET) { scheduler.TraverseOrdered(CallBack_NotifySemaphoreFirstOrQuiet); } else { scheduler.TraverseUnordered(CallBack_NotifySemaphoreDrainOrAll); } } // Update the sem waiters count. // if ( NFY_NFY == key || NFY_QUIET == key) { add_to(sem, -count, attr); } else { atr_clr(sem, attr); } return Notify_Num_Done; }
/** Clone an object. * \verbatim * This is the top-level function for @clone, which creates a duplicate * of a (non-player) object. * \endverbatim * \param player the enactor. * \param name the name of the object to clone. * \param newname the name to give the duplicate. * \param preserve if 1, preserve ownership and privileges on duplicate. * \param newdbref the (unparsed) dbref to give the object, or NULL to use the next free * \param pe_info The pe_info to use for lock and \@command priv checks * \return dbref of the duplicate, or NOTHING. */ dbref do_clone(dbref player, char *name, char *newname, int preserve, char *newdbref, NEW_PE_INFO *pe_info) { dbref clone, thing; char dbnum[BUFFER_LEN]; thing = noisy_match_result(player, name, NOTYPE, MAT_EVERYTHING); if (thing == NOTHING) return NOTHING; if (newname && *newname && !ok_name(newname, IsExit(thing))) { notify(player, T("That is not a reasonable name.")); return NOTHING; } if (!controls(player, thing) || IsPlayer(thing) || (IsRoom(thing) && !command_check_byname(player, "@dig", pe_info)) || (IsExit(thing) && !command_check_byname(player, "@open", pe_info)) || (IsThing(thing) && !command_check_byname(player, "@create", pe_info))) { notify(player, T("Permission denied.")); return NOTHING; } /* don't allow cloning of destructed things */ if (IsGarbage(thing)) { notify(player, T("There's nothing left of it to clone!")); return NOTHING; } if (preserve && !Wizard(player)) { notify(player, T("You cannot @CLONE/PRESERVE. Use normal @CLONE instead.")); return NOTHING; } if (!make_first_free_wrapper(player, newdbref)) { return NOTHING; } /* make sure owner can afford it */ switch (Typeof(thing)) { case TYPE_THING: if (can_pay_fees(player, Pennies(thing))) { clone = clone_object(player, thing, newname, preserve); notify_format(player, T("Cloned: Object %s."), unparse_dbref(clone)); if (IsRoom(player)) moveto(clone, player, player, "cloned"); else moveto(clone, Location(player), player, "cloned"); current_state.things++; local_data_clone(clone, thing, preserve); real_did_it(player, clone, NULL, NULL, NULL, NULL, "ACLONE", NOTHING, NULL, 0, 0); return clone; } return NOTHING; break; case TYPE_ROOM: if (can_pay_fees(player, ROOM_COST)) { clone = clone_object(player, thing, newname, preserve); Exits(clone) = NOTHING; notify_format(player, T("Cloned: Room #%d."), clone); current_state.rooms++; local_data_clone(clone, thing, preserve); real_did_it(player, clone, NULL, NULL, NULL, NULL, "ACLONE", NOTHING, NULL, 0, 0); return clone; } return NOTHING; break; case TYPE_EXIT: /* For exits, we don't want people to be able to link it to a location they can't with @open. So, all this stuff. */ switch (Location(thing)) { case NOTHING: strcpy(dbnum, "#-1"); break; case HOME: strcpy(dbnum, "home"); break; case AMBIGUOUS: strcpy(dbnum, "variable"); break; default: strcpy(dbnum, unparse_dbref(Location(thing))); } if (newname && *newname) clone = do_real_open(player, newname, dbnum, NOTHING, pe_info); else clone = do_real_open(player, Name(thing), dbnum, NOTHING, pe_info); if (!GoodObject(clone)) { return NOTHING; } else { char *alias_val = NULL; ATTR *alias_attr = NULL; alias_attr = atr_get_noparent(clone, "ALIAS"); if (alias_attr) { alias_val = safe_atr_value(alias_attr, "atrval.do_clone"); atr_clr(clone, "ALIAS", GOD); } atr_cpy(clone, thing); if (alias_val) { atr_add(clone, "ALIAS", alias_val, player, 0); mush_free(alias_val, "atrval.do_clone"); } clone_locks(player, thing, clone); Zone(clone) = Zone(thing); Parent(clone) = Parent(thing); Flags(clone) = clone_flag_bitmask("FLAG", Flags(thing)); if (!preserve) { clear_flag_internal(clone, "WIZARD"); clear_flag_internal(clone, "ROYALTY"); Warnings(clone) = 0; /* zap warnings */ Powers(clone) = new_flag_bitmask("POWER"); /* zap powers */ } else { Warnings(clone) = Warnings(thing); Powers(clone) = clone_flag_bitmask("POWER", Powers(thing)); } if (Wizard(clone) || Royalty(clone) || Warnings(clone) || !null_flagmask("POWER", Powers(clone))) notify(player, T ("Warning: @CLONE/PRESERVE on an object with WIZ, ROY, @powers, or @warnings.")); notify_format(player, T("Cloned: Exit #%d."), clone); local_data_clone(clone, thing, preserve); return clone; } } return NOTHING; }
void do_dbclean( dbref player, dbref cause, int key ) { VATTR *vp, *vpx; dbref i, end; int ca, n_oldtotal, n_oldtop, n_deleted, n_renumbered, n_objt, n_atrt, got; char *as, *str; int *used_table; ATTR **new_table; UFUN *ufp; CMDENT *cmdp; ADDENT *addp; raw_broadcast( 0, "GAME: Cleaning database. Game may freeze for a few minutes." ); used_table = ( int * ) XCALLOC( mudstate.attr_next, sizeof( int ), "dbclean.used_table" ); n_oldtotal = mudstate.attr_next; n_oldtop = anum_alc_top; n_deleted = n_renumbered = n_objt = n_atrt = 0; /* * Non-user-defined attributes are always considered used. */ for( i = 0; i < A_USER_START; i++ ) { used_table[i] = i; } /* * Walk the database. Mark all the attribute numbers in use. */ atr_push(); DO_WHOLE_DB( i ) { for( ca = atr_head( i, &as ); ca; ca = atr_next( &as ) ) { used_table[ca] = ca; } } atr_pop(); /* * Walk the vattr table. If a number isn't in use, zorch it. */ vp = vattr_first(); while( vp ) { vpx = vp; vp = vattr_next( vp ); if( used_table[vpx->number] == 0 ) { anum_set( vpx->number, NULL ); hashdelete( vpx->name, &mudstate.vattr_name_htab ); XFREE( vpx, "dbclean.vpx" ); n_deleted++; } } /* * The user-defined function, added command, and hook structures embed * * attribute numbers. Clean out the ones we've deleted, resetting them * * to the *Invalid (A_TEMP) attr. */ for( ufp = ( UFUN * ) hash_firstentry( &mudstate.ufunc_htab ); ufp != NULL; ufp = ( UFUN * ) hash_nextentry( &mudstate.ufunc_htab ) ) { if( used_table[ufp->atr] == 0 ) { ufp->atr = A_TEMP; } } for( cmdp = ( CMDENT * ) hash_firstentry( &mudstate.command_htab ); cmdp != NULL; cmdp = ( CMDENT * ) hash_nextentry( &mudstate.command_htab ) ) { if( cmdp->pre_hook ) { if( used_table[cmdp->pre_hook->atr] == 0 ) { cmdp->pre_hook->atr = A_TEMP; } } if( cmdp->post_hook ) { if( used_table[cmdp->post_hook->atr] == 0 ) { cmdp->post_hook->atr = A_TEMP; } } if( cmdp->userperms ) { if( used_table[cmdp->userperms->atr] == 0 ) { cmdp->userperms->atr = A_TEMP; } } if( cmdp->callseq & CS_ADDED ) { for( addp = ( ADDENT * ) cmdp->info.added; addp != NULL; addp = addp->next ) { if( used_table[addp->atr] == 0 ) { addp->atr = A_TEMP; } } } } /* * Walk the table we've created of used statuses. When we find free * * slots, walk backwards to the first used slot at the end of the * * table. Write the number of the free slot into that used slot. */ for( i = A_USER_START, end = mudstate.attr_next - 1; ( i < mudstate.attr_next ) && ( i < end ); i++ ) { if( used_table[i] == 0 ) { while( ( end > i ) && ( used_table[end] == 0 ) ) { end--; } if( end > i ) { used_table[end] = used_table[i] = i; end--; } } } /* * Renumber the necessary attributes in the vattr tables. */ for( i = A_USER_START; i < mudstate.attr_next; i++ ) { if( used_table[i] != i ) { vp = ( VATTR * ) anum_get( i ); if( vp ) { vp->number = used_table[i]; vp->flags |= AF_DIRTY; anum_set( used_table[i], ( ATTR * ) vp ); anum_set( i, NULL ); n_renumbered++; } } } /* * Now we walk the database. For every object, if we have an attribute * * we're renumbering (the slot number is not equal to the array value * * at that slot), we delete the old attribute and add the new one. */ atr_push(); DO_WHOLE_DB( i ) { got = 0; for( ca = atr_head( i, &as ); ca; ca = atr_next( &as ) ) { if( used_table[ca] != ca ) { str = atr_get_raw( i, ca ); atr_add_raw( i, used_table[ca], str ); atr_clr( i, ca ); n_atrt++; got = 1; } } if( got ) { n_objt++; } } atr_pop(); /* * The new end of the attribute table is the first thing we've * * renumbered. */ for( end = A_USER_START; ( ( end == used_table[end] ) && ( end < mudstate.attr_next ) ); end++ ); mudstate.attr_next = end; /* * We might be able to shrink the size of the attribute table. * * If the current size of the table is less than the initial * * size, shrink it back down to the initial size. * * Otherwise, shrink it down so it's the current top plus the * * initial size, as if we'd just called anum_extend() for it. */ if( anum_alc_top > mudconf.init_size + A_USER_START ) { if( mudstate.attr_next < mudconf.init_size + A_USER_START ) { end = mudconf.init_size + A_USER_START; } else { end = mudstate.attr_next + mudconf.init_size; } if( end < anum_alc_top ) { new_table = ( ATTR ** ) XCALLOC( end + 1, sizeof( ATTR * ), "dbclean.new_table" ); for( i = 0; i < mudstate.attr_next; i++ ) { new_table[i] = anum_table[i]; } XFREE( anum_table, "dbclean.anum_table" ); anum_table = new_table; anum_alc_top = end; } } /* * Go through the function and added command tables again, and * * take care of the attributes that got renumbered. */ for( ufp = ( UFUN * ) hash_firstentry( &mudstate.ufunc_htab ); ufp != NULL; ufp = ( UFUN * ) hash_nextentry( &mudstate.ufunc_htab ) ) { if( used_table[ufp->atr] != ufp->atr ) { ufp->atr = used_table[ufp->atr]; } } for( cmdp = ( CMDENT * ) hash_firstentry( &mudstate.command_htab ); cmdp != NULL; cmdp = ( CMDENT * ) hash_nextentry( &mudstate.command_htab ) ) { if( cmdp->pre_hook ) { if( used_table[cmdp->pre_hook->atr] != cmdp->pre_hook->atr ) cmdp->pre_hook->atr = used_table[cmdp->pre_hook->atr]; } if( cmdp->post_hook ) { if( used_table[cmdp->post_hook->atr] != cmdp->post_hook->atr ) cmdp->post_hook->atr = used_table[cmdp->post_hook->atr]; } if( cmdp->userperms ) { if( used_table[cmdp->userperms->atr] != cmdp->userperms->atr ) cmdp->userperms->atr = used_table[cmdp->userperms->atr]; } if( cmdp->callseq & CS_ADDED ) { for( addp = ( ADDENT * ) cmdp->info.added; addp != NULL; addp = addp->next ) { if( used_table[addp->atr] != addp->atr ) { addp->atr = used_table[addp->atr]; } } } } /* * Clean up. */ XFREE( used_table, "dbclean.used_table" ); if( anum_alc_top != n_oldtop ) { notify_check( player, player, MSG_PUP_ALWAYS|MSG_ME_ALL|MSG_F_DOWN, "Cleaned %d user attribute slots (reduced to %d): %d deleted, %d renumbered (%d objects and %d individual attrs touched). Table size reduced from %d to %d.", n_oldtotal - A_USER_START, mudstate.attr_next - A_USER_START, n_deleted, n_renumbered, n_objt, n_atrt, n_oldtop, anum_alc_top ); } else { notify_check( player, player, MSG_PUP_ALWAYS|MSG_ME_ALL|MSG_F_DOWN, "Cleaned %d attributes (now %d): %d deleted, %d renumbered (%d objects and %d individual attrs touched).", n_oldtotal, mudstate.attr_next, n_deleted, n_renumbered, n_objt, n_atrt ); } raw_broadcast( 0, "GAME: Database cleaning complete." ); }