//***************************************************************************** // // set_val.c // // There are often times in-game when we will want to change the values of a // field in a character or object; most DIKU muds do this via a "set" command // that simply has a list of all of the fields, and how to handle performing // the set. However, because of our modular nature, it would be fairly // cumbersome to have all of the possible things to set in one big list. // Instead, we provide a way that modules can install new fields that can be // set for rooms, objects, and mobiles. // //***************************************************************************** #include "../mud.h" #include "../utils.h" #include "../world.h" #include "../zone.h" #include "../socket.h" #include "../character.h" #include "../object.h" #include "../room.h" #include "../races.h" #include "../handler.h" #include "../save.h" #include "set_val.h" //***************************************************************************** // mandatory modules //***************************************************************************** #include "../editor/editor.h" // for charGetNotepad //***************************************************************************** // setter functions //***************************************************************************** // // most everything already has a setter function done up, but because user // groups go through a bitvector, we need an extra function to get in and be // able to set a character's groups... void charSetUserGroups(CHAR_DATA *ch, const char *groups) { bitClear(charGetUserGroups(ch)); bitSet(charGetUserGroups(ch), groups); } //***************************************************************************** // local defines, datastructures, functions, and commands //***************************************************************************** HASHTABLE *char_set_table = NULL; HASHTABLE *obj_set_table = NULL; HASHTABLE *room_set_table = NULL; HASHTABLE *acct_set_table = NULL; typedef struct set_val_data { int type; // the type of data (int, double, long, string, etc...) void *setter; // the function to do the setting void *checker; // make sure the new value is an acceptable value } SET_VAL_DATA; SET_VAL_DATA *newSetValData(int type, void *setter, void *checker) { SET_VAL_DATA *data = malloc(sizeof(SET_VAL_DATA)); data->type = type; data->setter = setter; data->checker = checker; return data; } void deleteSetValData(SET_VAL_DATA *data) { free(data); } void try_set(CHAR_DATA *ch, void *tgt, HASHTABLE *table, const char *field, const char *val) { SET_VAL_DATA *data = hashGet(table, field); if(data == NULL) send_to_char(ch, "You cannot set that field!\r\n"); else { // make sure this is an acceptable value bool set_ok = TRUE; if(data->checker != NULL) { if(data->type == SET_TYPE_INT) set_ok = ((bool (*)(int)) data->checker)(atoi(val)); else if(data->type == SET_TYPE_LONG) set_ok = ((bool (*)(long)) data->checker)(atol(val)); else if(data->type == SET_TYPE_DOUBLE) set_ok = ((bool (*)(double)) data->checker)(atof(val)); else if(data->type == SET_TYPE_STRING) set_ok = ((bool (*)(const char *)) data->checker)(val); } // make sure the set is ok if(set_ok == FALSE) { send_to_char(ch, "'%s' is not an acceptable value!\r\n", val); return; } // perform the change if(data->type == SET_TYPE_INT) ((void (*)(void *, int)) data->setter)(tgt, atoi(val)); else if(data->type == SET_TYPE_LONG) ((void (*)(void *, long)) data->setter)(tgt, atol(val)); else if(data->type == SET_TYPE_DOUBLE) ((void (*)(void *, double)) data->setter)(tgt, atof(val)); else if(data->type == SET_TYPE_STRING) ((void (*)(void *, const char *)) data->setter)(tgt, val); send_to_char(ch, "Ok.\r\n"); } } // // The entrypoint to the set utility for players in the MUD // usage: set [thing] [field] [value] // // thing is expected to be a character's name, an object's name, a room's // vnum, or simply "room" for the current room. Optionally, the function can // take a value from the player's notepad instead of from the command line (this // is useful for if you need to write long lengths of formatted text). COMMAND(cmd_set) { char name [SMALL_BUFFER]; char field[SMALL_BUFFER]; bool player = FALSE; bool account = FALSE; // are we trying to modify a character on disk? if(!strncasecmp(arg, "player ", 7)) { player = TRUE; arg += 7; } // are we trying to modify an account? if(!strncasecmp(arg, "account ", 8)) { account = TRUE; arg += 8; } const char *val = two_args(arg, name, field); // check to see if we're trying to set from our notepad. Also, make sure // we have a socket and CAN access our notepad. if(!strcasecmp(cmd, "setpad")) { if(charGetSocket(ch) && bufferLength(socketGetNotepad(charGetSocket(ch)))) val = bufferString(socketGetNotepad(charGetSocket(ch))); else { send_to_char(ch, "Your notepad currently has no contents.\r\n"); return; } } if(!*val || !*name || !*field) send_to_char(ch, "Set which value on what?\r\n"); // we're trying to set something on someone's pfile else if(player == TRUE) { // make sure the player isn't online, currently CHAR_DATA *tgt = get_player(name); if(tgt == NULL) send_to_char(ch, "No pfile for %s exists!\r\n", name); else if(!charHasMoreUserGroups(ch, tgt)) { send_to_char(ch, "Sorry, %s has just as many priviledges as you.\r\n", HESHE(tgt)); unreference_player(tgt); } else { try_set(ch, tgt, char_set_table, field, val); save_player(tgt); unreference_player(tgt); } } // we're trying to edit an account else if(account == TRUE) { ACCOUNT_DATA *tgt = get_account(name); if(tgt == NULL) send_to_char(ch, "No such account exists!\r\n"); else { try_set(ch, tgt, acct_set_table, field, val); save_account(tgt); unreference_account(tgt); } } // are we setting a field on an object or character in game? else { int found = FOUND_NONE; void *tgt = NULL; tgt = generic_find(ch, name,FIND_TYPE_CHAR | FIND_TYPE_OBJ | FIND_TYPE_ROOM, FIND_SCOPE_ALL | FIND_SCOPE_VISIBLE, FALSE, &found); if(tgt == NULL) send_to_char(ch, "What was the target you were trying to modify?\r\n"); else if(found == FOUND_CHAR) { if(ch != tgt && !charHasMoreUserGroups(ch, tgt)) send_to_char(ch, "Sorry, %s has just as many priviledges as you.\r\n", HESHE(tgt)); else try_set(ch, tgt, char_set_table, field, val); } else if(found == FOUND_OBJ) try_set(ch, tgt, obj_set_table, field, val); else if(found == FOUND_ROOM) { if(!canEditZone(worldGetZone(gameworld,get_key_locale(roomGetClass(tgt))), ch)) send_to_char(ch, "You are not authorized to edit that zone.\r\n"); else try_set(ch, tgt, room_set_table, field, val); } } } //***************************************************************************** // // implementation of set_val.h // //***************************************************************************** void init_set() { // build all of our tables char_set_table = newHashtable(); obj_set_table = newHashtable(); room_set_table = newHashtable(); acct_set_table = newHashtable(); // add in the default sets for the core of the MUD /************************************************************/ /* WARNING */ /* */ /* If you are wanting to add new "set" fields to the set */ /* module, you are best off adding them with whatever module*/ /* the new data is included in. If the term "module" is not */ /* making any sense to you, READ THE DOCUMENTATION! */ /************************************************************/ // PLAYER SETS add_set("desc", SET_CHAR, SET_TYPE_STRING, charSetDesc, NULL); add_set("rdesc", SET_CHAR, SET_TYPE_STRING, charSetRdesc, NULL); add_set("name", SET_CHAR, SET_TYPE_STRING, charSetName, NULL); add_set("mrdesc", SET_CHAR, SET_TYPE_STRING, charSetMultiRdesc, NULL); add_set("mname", SET_CHAR, SET_TYPE_STRING, charSetMultiName, NULL); add_set("keywords", SET_CHAR, SET_TYPE_STRING, charSetKeywords, NULL); add_set("race", SET_CHAR, SET_TYPE_STRING, charSetRace, isRace); add_set("groups", SET_CHAR, SET_TYPE_STRING, charSetUserGroups, NULL); // ROOM SETS add_set("name", SET_ROOM, SET_TYPE_STRING, roomSetName, NULL); add_set("desc", SET_ROOM, SET_TYPE_STRING, roomSetDesc, NULL); // OBJECT SETS add_set("name", SET_OBJECT,SET_TYPE_STRING,objSetName, NULL); add_set("desc", SET_OBJECT,SET_TYPE_STRING,objSetDesc, NULL); add_set("rdesc", SET_OBJECT,SET_TYPE_STRING,objSetRdesc, NULL); add_set("name", SET_OBJECT,SET_TYPE_STRING,objSetName, NULL); add_set("mrdesc", SET_OBJECT,SET_TYPE_STRING,objSetMultiRdesc, NULL); add_set("mname", SET_OBJECT,SET_TYPE_STRING,objSetMultiName, NULL); add_set("keywords", SET_OBJECT,SET_TYPE_STRING,objSetKeywords, NULL); // now, add the admin commands for working with set add_cmd("set", NULL, cmd_set, "admin", FALSE); add_cmd("setpad", NULL, cmd_set, "admin", FALSE); } void add_set(const char *name, int set_for, int type, void *setter, void *checker) { HASHTABLE *table = NULL; // first, find our table if (set_for == SET_CHAR) table = char_set_table; else if(set_for == SET_OBJECT) table = obj_set_table; else if(set_for == SET_ROOM) table = room_set_table; else if(set_for == SET_ACCOUNT) table = acct_set_table; // if there was no table, we can't do anything if(table == NULL) return; // If old data exists, remove it SET_VAL_DATA *old_set = hashRemove(table, name); if(old_set) deleteSetValData(old_set); // now, build our new data and add it to the table SET_VAL_DATA *new_set = newSetValData(type, setter, checker); hashPut(table, name, new_set); }