wear_template/
Wear Template Code
  by Justice (Kwon J. Ekstrom)
Updated: June 14, 2006

In mud.h:
Add: (command declaration)
DECLARE_DO_FUN( do_wtemplate ); // Wear Template Snippet

Add: (preferably before struct area_data)

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
 * Wear Template Snippet
 *   Allow a mob to be easily equipped.
 *    -- Justice (05-29-2003)
 *   Cleaned up and updated for SmaugFUSS
 *    -- Justice (06-14-2006)
 */
// Typedefs
typedef struct wear_template_data WEAR_TEMPLATE_DATA;
typedef struct wear_template_item WEAR_TEMPLATE_ITEM;

// Global list
extern WEAR_TEMPLATE_DATA *first_wear_template; // global list
extern WEAR_TEMPLATE_DATA *last_wear_template;  // global list

// Maximum container nest
#define MAX_WEAR_TEMPLATE_NEST   10

// Template filename
#define WEAR_TEMPLATE_FILE       SYSTEM_DIR "template.dat"

// Template data
struct wear_template_data
{
    WEAR_TEMPLATE_DATA *next;
    WEAR_TEMPLATE_DATA *prev;
    WEAR_TEMPLATE_ITEM *data;
    char               *name;
};

// Single template record
struct wear_template_item
{
    WEAR_TEMPLATE_ITEM  *next;
    WEAR_TEMPLATE_ITEM  *prev;

    WEAR_TEMPLATE_ITEM  *first_child;
    WEAR_TEMPLATE_ITEM  *last_child;

    OBJ_INDEX_DATA *obj;
    int             wear_loc;
    int             nest;
};


In db.c:
Add: (near top)
// Wear Template Snippet
// Function Prototypes
void load_wear_template();


In db.c:
After:
   /*
    * Initialize area weather data 
    */
   load_weatherdata(  );
   init_area_weather(  );
Add:
   // Wear Template Snippet
   // Load wear templates
   log_string("Loading wear templates.");
   load_wear_template();


In act_wiz.c:
Add: (near top)

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
 * Wear Template Snippet
 *   Declarations
 */

// Command function prototypes
void do_wear_template_create(CHAR_DATA *ch, char *argument);
void do_wear_template_apply(CHAR_DATA *ch, char *argument);

// Util function prototypes
void create_wear_template(char *name, CHAR_DATA *ch);
void create_wear_template2(WEAR_TEMPLATE_ITEM *root, OBJ_DATA *first, OBJ_DATA *last, int level);
void list_wear_template(CHAR_DATA *ch, WEAR_TEMPLATE_DATA *templ);
int  list_wear_template2(CHAR_DATA *ch, WEAR_TEMPLATE_ITEM *first, WEAR_TEMPLATE_ITEM *last, bool header, int level);
void apply_wear_template(CHAR_DATA *ch, OBJ_DATA *con, WEAR_TEMPLATE_ITEM *root, int obj_level);

// Load/Write function prototypes
void save_wear_template();
void load_wear_template();
void fwrite_wear_template(FILE *fp, WEAR_TEMPLATE_ITEM *root, int level);
void fread_wear_template(FILE *fp);
void fread_wear_template2(FILE *fp, WEAR_TEMPLATE_ITEM *root);

// List declarations
WEAR_TEMPLATE_DATA  *first_wear_template;
WEAR_TEMPLATE_DATA  *last_wear_template;


In act_wiz.c:
Add:
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
 * Wear Template Snippet
 *   Implementation
 */
void do_wtemplate(CHAR_DATA *ch, char *argument)
{
    char arg[MAX_INPUT_LENGTH];

    // No argument....
    if (argument[0] == '\0')
    {
        send_to_char("Syntax: wtemplate create <name> <victim>\n\r", ch);
        send_to_char("Syntax: wtemplate list\n\r",                   ch);
        send_to_char("Syntax: wtemplate stat <name>\n\r",            ch);
        send_to_char("Syntax: wtemplate apply <name> <victim>\n\r",  ch);
        send_to_char("Syntax: wtemplate save\n\r",  ch);
        return;
    }

    // Get the first argument.
    argument = one_argument(argument, arg);

    // Create a new template.
    if (!str_cmp(arg, "create"))
    {
        do_wear_template_create(ch, argument);
        return;
    }

    if (!str_cmp(arg, "save"))
    {
        save_wear_template();
        send_to_char("Saved.\n\r", ch);
        return;
    }

    if (!str_cmp(arg, "load"))
    {
        first_wear_template = NULL;
        last_wear_template  = NULL;
        load_wear_template();
        send_to_char("Loaded... this load doesn't cleanup old wear templates!", ch);
        send_to_char("Please only use for testing purposes.", ch);
        return;
    }

    // List existing templates.
    if (!str_cmp(arg, "list"))
    {
        WEAR_TEMPLATE_DATA *templ;
        int            cnt = 0;

        if (!first_wear_template)
        {
            send_to_char("There aren't any wear templates.\n\r", ch);
            return;
        }

        send_to_char("|  #  | Name\n\r", ch);
        send_to_char("|-----+--------------------\n\r", ch);

        for (templ = first_wear_template; templ; templ = templ->next)
            ch_printf(ch, "| %-3d | %s\n\r", ++cnt, templ->name);
        send_to_char("|-----+--------------------\n\r", ch);

        ch_printf(ch, "There %s %d wear template%s.\n\r",
            (cnt == 1 ? "is" : "are"), cnt, (cnt == 1 ? "" : "s"));
        return;
    }

    if (!str_cmp(arg, "stat"))
    {
        WEAR_TEMPLATE_DATA *templ;

        for (templ = first_wear_template; templ; templ = templ->next)
            if (!str_cmp(templ->name, argument))
                break;

        if (!templ)
        {
            ch_printf(ch, "There isn't a wear template named '%s'\n\r", argument);
            return;
        }

        list_wear_template(ch, templ);
        return;
    }

    if (!str_cmp(arg, "apply"))
    {
        do_wear_template_apply(ch, argument);
        return;
    }

    // Default action
    do_wtemplate(ch, "");
    return;
}

void do_wear_template_create(CHAR_DATA *ch, char *argument)
{
    WEAR_TEMPLATE_DATA *templ;
    CHAR_DATA     *vict;
    char           arg1[MAX_INPUT_LENGTH];
    char           arg2[MAX_INPUT_LENGTH];

    set_char_color(AT_IMMORT, ch);
    if (argument[0] == '\0')
    {
        do_wtemplate(ch, "");
        return;
    }

    argument = one_argument(argument, arg1);
    argument = one_argument(argument, arg2);

    if ( arg1[0] == '\0')
    {
        do_wtemplate(ch, "");
        send_to_char("What should the wear template be named?\n\r", ch);
        return;
    }

    if (arg2[0] == '\0')
    {
        do_wtemplate(ch, "");
        send_to_char("Who should be used as the wear template's target?\n\r", ch);
        return;
    }

    for (templ = first_wear_template; templ; templ = templ->next)
    {
        ch_printf(ch, " %s / ", templ->name);
        if (!str_cmp(templ->name, arg1))
            break;
        ch_printf(ch, "%s\n\r", templ->name);
    }

    if (templ)
    {
        send_to_char("There is already a wear template with that name.\n\r", ch);
        return;
    }

    if ((vict = get_char_room(ch, arg2)) == NULL)
    {
        send_to_char("Who do you want to make a wear template of?\n\r", ch);
        return;
    }

    create_wear_template(arg1, vict);
    send_to_char("Created.\n\r", ch);
    return;
}

void do_wear_template_apply(CHAR_DATA *ch, char *argument)
{
    WEAR_TEMPLATE_DATA *templ;
    CHAR_DATA     *vict;
    char           arg1[MAX_INPUT_LENGTH];
    char           arg2[MAX_INPUT_LENGTH];

    set_char_color(AT_IMMORT, ch);
    if (argument[0] == '\0')
    {
        do_wtemplate(ch, "");
        return;
    }

    argument = one_argument(argument, arg1);
    argument = one_argument(argument, arg2);

    if (arg1[0] == '\0')
    {
        do_wtemplate(ch, "");
        send_to_char("What wear template should be applied?\n\r", ch);
        return;
    }

    if (arg2[0] == '\0' || (vict = get_char_room(ch, arg2)) == NULL)
    {
        do_wtemplate(ch, "");
        send_to_char("Who should be used as the wear template's target?\n\r", ch);
        return;
    }

    for (templ = first_wear_template; templ; templ = templ->next)
        if (!str_cmp(templ->name, arg1))
            break;

    if (!templ)
    {
        send_to_char("There isn't a wear template with that name.\n\r", ch);
        return;
    }

    apply_wear_template(vict, NULL, templ->data, get_trust(ch));
    send_to_char("Applied.\n\r", ch);
    return;
}


void create_wear_template(char *name, CHAR_DATA *ch)
{
    WEAR_TEMPLATE_DATA *templ;
    WEAR_TEMPLATE_ITEM *root;

    // need to check if one exists.
    CREATE(templ, WEAR_TEMPLATE_DATA, 1);
    LINK(templ, first_wear_template, last_wear_template, next, prev);

    CREATE(root, WEAR_TEMPLATE_ITEM, 1);

    templ->name = str_dup(name);
    templ->data = root;

    // Setup the root's defaults.
    root->nest     = -1;
    root->wear_loc = WEAR_NONE;
    root->obj      = NULL;

    // Start building the item list.
    create_wear_template2(root, ch->first_carrying, ch->last_carrying, 0);
}

void create_wear_template2(WEAR_TEMPLATE_ITEM *root, OBJ_DATA *first, OBJ_DATA *last, int nest)
{
    WEAR_TEMPLATE_ITEM *cur;
    OBJ_DATA      *obj;

    for (obj=first; obj; obj=obj->next_content)
    {
        // Instantiate and link
        CREATE(cur, WEAR_TEMPLATE_ITEM, 1);
        LINK(cur, root->first_child, root->last_child, next, prev);

        // Get the wear loc, only "top" nest items can have a wear location.
        cur->wear_loc = (nest == 0 ? obj->wear_loc : WEAR_NONE);

        // Reference the index and the nest.
        cur->obj      = obj->pIndexData;
        cur->nest     = nest;

        // Recursively build the item list.
        if (obj->first_content && nest <= MAX_WEAR_TEMPLATE_NEST)
            create_wear_template2(cur, obj->first_content, obj->last_content, nest+1);
        // Usable defaults.
        else
        {
            cur->first_child = NULL;
            cur->last_child  = NULL;
        }
    }
}

void list_wear_template(CHAR_DATA *ch, WEAR_TEMPLATE_DATA *templ)
{
    int count = 0;

    ch_printf(ch, "Wear Template: %s\n\r", templ->name);
    if (templ->data->first_child)
    {
        count = list_wear_template2(ch, templ->data->first_child, templ->data->last_child, TRUE, 0);

        ch_printf(ch, "There %s %d item%s.\n\r",
            (count == 1 ? "is" : "are"),
            count,
            (count == 1 ? "" : "s")
        );
    }
}

int list_wear_template2(CHAR_DATA *ch, WEAR_TEMPLATE_ITEM *first, WEAR_TEMPLATE_ITEM *last, bool header, int nest)
{
    WEAR_TEMPLATE_ITEM *cur;
    int cnt = 0;

    if (header)
        send_to_char("|      Wear     |  Vnum  | Item (nest)\n\r", ch);

    for (cur = first; cur; cur = cur->next)
    {
        cnt++;

        // Output data.
        ch_printf(ch, "| %-13.13s | %-6d | %s (%d)\n\r",
            (cur->wear_loc == WEAR_NONE ? "none" : wear_locs[cur->wear_loc]),
            cur->obj->vnum,
            cur->obj->short_descr,
            nest
        );

        // Recursive Call to build the tree.
        if (cur->first_child && nest <= MAX_WEAR_TEMPLATE_NEST)
            cnt += list_wear_template2(ch, cur->first_child, cur->last_child, FALSE, nest+1);
    }
    return cnt;
}

void apply_wear_template(CHAR_DATA *ch, OBJ_DATA *con, WEAR_TEMPLATE_ITEM *root, int obj_level)
{
    WEAR_TEMPLATE_ITEM *cur   = NULL;
    OBJ_DATA      *obj   = NULL;
    int            nest;

    // Invalid data checks.
    if (!ch || !root)
        return;

    // Handle nesting.
    nest = root->nest;
    obj_level = URANGE(0, obj_level, LEVEL_AVATAR);

    // The "root" has a nest of -1, which means it doesn't have an obj.
    if (nest != -1)
    {
        if (!root->obj)
            return;

        obj = create_object(root->obj, obj_level);
        obj->level = obj_level;

        if (nest == 0)
        {
            obj = obj_to_char(obj, ch);

            if (root->wear_loc != WEAR_NONE)
                equip_char(ch, obj, root->wear_loc);
        }
        else if (con)
        {
            obj = obj_to_obj(obj, con);
        }
        else return;
    }

    // Check for recursive apply.
    if (root->first_child && nest < MAX_WEAR_TEMPLATE_NEST)
        for (cur=root->first_child; cur; cur=cur->next)
            apply_wear_template(ch, obj, cur, obj_level);
}

void save_wear_template()
{
    FILE *fp;
    WEAR_TEMPLATE_DATA *templ;

    if (!(fp = fopen(WEAR_TEMPLATE_FILE, "w")))
    {
        bug("save_wear_template: Unable to open file for writing.");
        return;
    }

    for (templ=first_wear_template; templ; templ=templ->next)
    {
        fprintf(fp, "#WEARTEMPLATE\n");
        fprintf(fp, "%s~\n", templ->name);

        fwrite_wear_template(fp, templ->data, 0);
        fprintf(fp, "End\n");
    }
    fprintf(fp, "#END\n");
	fclose(fp);
}

void fwrite_wear_template(FILE *fp, WEAR_TEMPLATE_ITEM *root, int nest)
{
    WEAR_TEMPLATE_ITEM *cur;

    for (cur = root->first_child; cur; cur=cur->next)
    {
        fprintf(fp, "Item       %d %d %d\n",
            cur->obj->vnum,
            cur->wear_loc,
            nest
        );

        // Recursive save.
        if (cur->first_child && nest < MAX_WEAR_TEMPLATE_NEST)
            fwrite_wear_template(fp, cur, nest+1);
    }
}

void load_wear_template()
{
    FILE          *fp;
	char          *word;
	char           letter;

    if (!(fp = fopen(WEAR_TEMPLATE_FILE, "r")))
    {
        bug("load_wear_template: Unable to open file for reading.");
        return;
    }

    while(TRUE)
    {
        letter = fread_letter( fp );

        if (letter == '*')
        {
			fread_to_eol(fp);
			continue;
		}

		if (letter != '#')
        {
			bug("load_wear_template: # not found.");
			break;
		}

		word = fread_word(fp);
        if (!strcmp(word, "WEARTEMPLATE"))
        {
            fread_wear_template(fp);
            return;
        }
    }
}

void fread_wear_template(FILE *fp)
{
    WEAR_TEMPLATE_DATA *templ;

    CREATE(templ,       WEAR_TEMPLATE_DATA, 1);
    CREATE(templ->data, WEAR_TEMPLATE_ITEM, 1);
    LINK(templ, first_wear_template, last_wear_template, next, prev);

    templ->name = fread_string_nohash(fp);

    templ->data->nest     = -1;
    templ->data->wear_loc = WEAR_NONE;
    templ->data->obj      = NULL;

    fread_wear_template2(fp, templ->data);
}

void fread_wear_template2(FILE *fp, WEAR_TEMPLATE_ITEM *root)
{
    char *word;
    char *line;
    int   vnum;
    int   wear;
    int   nest;
    int   last_nest = -1;
    int   i;

    OBJ_INDEX_DATA *obj;
    WEAR_TEMPLATE_ITEM  *hist[MAX_WEAR_TEMPLATE_NEST];
    WEAR_TEMPLATE_ITEM  *cur;
    WEAR_TEMPLATE_ITEM  *tmp;

    while(TRUE)
    {
        obj   = NULL;
        vnum  = -1;
        wear  = WEAR_NONE;
        nest = -2;

        if (feof(fp))
            return;

        word = fread_word(fp);

        if (!str_cmp(word, "End"))
            return;

        if (str_cmp(word, "Item"))
        {
            bug("Unrecognized word in wear template file.");
            continue;
        }

        line = fread_line(fp);
        sscanf(line, "%d %d %d", &vnum, &wear, &nest);

        // Object check.
        if (!(obj = get_obj_index(vnum)))
            continue;

        // Nest consistency check.
        if (nest < 0 || nest >= MAX_WEAR_TEMPLATE_NEST)
            continue;

        // Valid data should only allow the "nest" to increase by 1 at a time.
        if (nest > last_nest+1)
            continue;

        // 0 is root, otherwise use "nest-1"
        if (nest == 0)
            tmp = root;
        else
            tmp = hist[nest-1];

        // Make sure we have a "parent"
        if (!tmp)
            continue;

        // Finally, read in the data.
        CREATE(cur, WEAR_TEMPLATE_ITEM, 1);
        cur->obj      = obj;
        cur->wear_loc = wear;
        cur->nest     = nest;

        // Link it to it's parent.
        LINK(cur, tmp->first_child, tmp->last_child, next, prev);

        // Update history data.
        hist[nest] = cur;
        last_nest  = nest;

        // Clear all "post" nest data from the history.
        for (i=nest+1; i<MAX_WEAR_TEMPLATE_NEST; i++)
            hist[i] = NULL;
    }
}