zim/area/
zim/bin/
zim/clans/plists/
zim/corefiles/
zim/doc/muddy/
zim/gods/
zim/log/
zim/player/
zim/skill_tree/
zim/tmp/
/* $Id: olc_race.c 849 2006-04-22 13:08:54Z zsuzsu $ */

/************************************************************************************
 *    Copyright 2004 Astrum Metaphora consortium                                    *
 *                                                                                  *
 *    Licensed under the Apache License, Version 2.0 (the "License");               *
 *    you may not use this file except in compliance with the License.              *
 *    You may obtain a copy of the License at                                       *
 *                                                                                  *
 *    http://www.apache.org/licenses/LICENSE-2.0                                    *
 *                                                                                  *
 *    Unless required by applicable law or agreed to in writing, software           *
 *    distributed under the License is distributed on an "AS IS" BASIS,             *
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.      *
 *    See the License for the specific language governing permissions and           *
 *    limitations under the License.                                                *
 *                                                                                  *
 ************************************************************************************/
 
#include <stdio.h>
#include <stdlib.h>

#include "merc.h"
#include "olc.h"

#define EDIT_RACE(ch, race) (race = (race_t*) ch->desc->pEdit)

DECLARE_OLC_FUN(raceed_create   );
DECLARE_OLC_FUN(raceed_edit     );
DECLARE_OLC_FUN(raceed_touch    );
DECLARE_OLC_FUN(raceed_show     );
DECLARE_OLC_FUN(raceed_list     );

DECLARE_OLC_FUN(raceed_name     );
DECLARE_OLC_FUN(raceed_filename );
DECLARE_OLC_FUN(raceed_flags    );
DECLARE_OLC_FUN(raceed_parts    );
DECLARE_OLC_FUN(raceed_act      );
DECLARE_OLC_FUN(raceed_off      );
DECLARE_OLC_FUN(raceed_aff      );
DECLARE_OLC_FUN(raceed_form     );
DECLARE_OLC_FUN(raceed_immune   );
DECLARE_OLC_FUN(raceed_resist   );
DECLARE_OLC_FUN(raceed_vulnerable   );
DECLARE_OLC_FUN(raceed_size     );
DECLARE_OLC_FUN(raceed_sex      );
DECLARE_OLC_FUN(raceed_ac       );
DECLARE_OLC_FUN(raceed_dodge    );
DECLARE_OLC_FUN(raceed_damtype  );
DECLARE_OLC_FUN(raceed_align	);


DECLARE_OLC_FUN(raceed_spec_part);
DECLARE_OLC_FUN(raceed_love_sect);
DECLARE_OLC_FUN(raceed_hate_sect);

DECLARE_OLC_FUN(pcraceed_create);
DECLARE_OLC_FUN(pcraceed_skill    );
DECLARE_OLC_FUN(pcraceed_age      );

DECLARE_OLC_FUN(pcraceed_skill_add);
DECLARE_OLC_FUN(pcraceed_skill_del);

static DECLARE_VALIDATE_FUN(validate_name  );
static DECLARE_VALIDATE_FUN(validate_haspcdata  );

static bool touch_race(race_t *r);

olc_cmd_t olc_cmds_race[] =
{
    { 5, "create",	raceed_create,				},
    { 5, "edit",	raceed_edit,				},
    { 5, "touch",	raceed_touch,				},
    { 0, "show",	raceed_show,				},
    { 0, "list",        raceed_list,				},

    { 5, "name",        raceed_name,		validate_name		},
    { 5, "filename",    raceed_filename,	validate_filename	},
    { 5, "align",	raceed_align,					},
    { 5, "sex",		raceed_sex,		sex_table		},
    { 5, "size",	raceed_size,		size_table		},
    /*
    { 5, "ac",		raceed_armor,		armor_table		},
    { 5, "armor",	raceed_armor,		armor_table		},
    */
    { 5, "dodge",       raceed_dodge,				},
    { 5, "damtype",	raceed_damtype,				},
    /*
    { 5, "spec_part",  raceed_spec_part,5,                   },
    { 5, "love_sect",  raceed_love_sect,5, sector_flag_types },
    { 5, "hate_sect",  raceed_hate_sect,5, sector_flag_types },
    */
    { 5, "form",        raceed_form,	form_flags		},
    { 5, "part",        raceed_parts,	part_flags		},
    { 5, "imm",         raceed_immune,	imm_flags		},
    { 5, "res",         raceed_resist,	imm_flags		},
    { 5, "vuln",        raceed_vulnerable,	imm_flags	},
    { 5, "off",         raceed_off,	off_flags		},
    { 5, "act",         raceed_act,	act_flags		},
    { 5, "affect",      raceed_aff,	affect_flags		},

   /* { 9, "pcrace",      pcraceed_create,				},
    { 8, "age",		pcraceed_age,				},
    { 5, "skill",       pcraceed_skill,	validate_haspcdata	},
    */

    { 0, "commands",    show_commands,				},
    { 0, NULL}
};

OLC_FUN(raceed_create)
{
    int rn;
    race_t *race;

    if (ch->pcdata->security < SECURITY_RACES)
    {
        char_puts("RaceEd: Insufficient security for editing races\n", ch);
        return FALSE;
    }

    if (argument[0] == '\0')
    {
        do_help(ch, "'OLC CREATE'");
        return FALSE;
    }

    if ((rn = rn_lookup(argument)) >= 0)
    {
        char_printf(ch, "RaceEd: %s: already exists.\n", RACE(rn)->name);
        return FALSE;
    }

    race            = race_new();
    race->name      = str_dup(argument);
    race->file_name = str_printf("race%02d.race", races.nused-1);

    ch->desc->pEdit     = (void *)race;
    OLCED(ch)   = olced_lookup(ED_RACE);
    touch_race(race);
    char_puts("Race created.\n",ch);
    return FALSE;
}

OLC_FUN(raceed_edit)
{
    int rn;
    char arg[MAX_STRING_LENGTH];

        if (ch->pcdata->security < SECURITY_RACES)
    {
        char_puts("RaceEd: Insufficient security.\n", ch);
        return FALSE;
    }
    one_argument(argument, arg, sizeof(arg));
    if (arg[0] == '\0')
    {
        do_help(ch, "'OLC EDIT'");
        return FALSE;
    }
    if ((rn = rn_lookup(arg)) < 0)
    {
        char_printf(ch, "RaceEd: %s: No such race.\n", argument);
        return FALSE;
    }
    ch->desc->pEdit     = RACE(rn);
    OLCED(ch)   = olced_lookup(ED_RACE);
    return FALSE;
}

OLC_FUN(raceed_touch)
{
    race_t *race;
    EDIT_RACE(ch, race);
    return touch_race(race);
}


OLC_FUN(raceed_dodge)
{
    race_t *race;
    EDIT_RACE(ch, race);
    
    return olced_number(ch, argument, cmd, &race->dodge);
}

OLC_FUN(raceed_parts    )
{
    race_t *race;
    EDIT_RACE(ch, race);

    return olced_flag32(ch, argument, cmd, &race->parts);
}

OLC_FUN(raceed_act      )
{
    race_t *race;
    EDIT_RACE(ch, race);

    return olced_flag64(ch, argument, cmd, &race->act);
}

OLC_FUN(raceed_off      )
{
    race_t *race;
    EDIT_RACE(ch, race);

    return olced_flag32(ch, argument, cmd, &race->off);
}

OLC_FUN(raceed_aff      )
{
    race_t *race;
    EDIT_RACE(ch, race);

    return olced_flag64(ch, argument, cmd, &race->aff);
}

OLC_FUN(raceed_form     )
{
    race_t *race;
    EDIT_RACE(ch, race);

    return olced_flag32(ch, argument, cmd, &race->form);
}

OLC_FUN(raceed_immune   )
{
    race_t *race;
    EDIT_RACE(ch, race);

    return olced_flag32(ch, argument, cmd, &race->imm);
}

OLC_FUN(raceed_resist   )
{
    race_t *race;
    EDIT_RACE(ch, race);

    return olced_flag32(ch, argument, cmd, &race->res);
}

OLC_FUN(raceed_vulnerable   )
{
    race_t *race;
    EDIT_RACE(ch, race);

    return olced_flag32(ch, argument, cmd, &race->vuln);
}

OLC_FUN(raceed_show)
{
    char arg[MAX_STRING_LENGTH];
    int i;
    BUFFER *output;
    race_t *race;
    pcrace_t *pcr;

    one_argument(argument, arg, sizeof(arg));
    if (arg[0] == '\0')
    {
        if (IS_EDIT(ch, ED_RACE))
            EDIT_RACE(ch, race);
        else
        {
            do_help(ch, "'OLC ASHOW'");
            return FALSE;
        }
    }
    else
    {
        if ((i = rn_lookup(arg)) < 0)
        {
            char_printf(ch, "RaceEd: %s: No such race.\n",  argument);
            return FALSE;
        }
        race = RACE(i);
    }
    output = buf_new(ch->lang);

        buf_printf(output, "Name:          [%s]\n",    race->name);
        buf_printf(output, "Filename:      [%s]\n",    race->file_name);
	buf_printf(output, "Align:         [%4d]\n",race->alignment);
	buf_printf(output, "Sex:           [%s]\n", flag_string(sex_table, race->sex));
	buf_printf(output, "Size:          [%s]\n", flag_string(size_table, race->size));
        buf_printf(output, "Dodge Skill:   [%d] (NPC only)\n",    race->dodge);

	buf_printf(output, "DamType:       [%s]\n",	attack_table[race->dam_type].name);

        buf_printf(output, "Act:           [%s]\n",    flag_string(act_flags, race->act));
        buf_printf(output, "Aff:           [%s]\n",    flag_string(affect_flags, race->aff));
        buf_printf(output, "Off:           [%s]\n",    flag_string(off_flags, race->off));

        buf_printf(output, "Immune:        [%s]\n",    flag_string(imm_flags, race->imm));
        buf_printf(output, "Resists:       [%s]\n",    flag_string(imm_flags, race->res));
        buf_printf(output, "Vuln:          [%s]\n",    flag_string(imm_flags, race->vuln));
        buf_printf(output, "Body parts:    [%s]\n",    flag_string(part_flags, race->parts));
        buf_printf(output, "Flags:         [%s]\n",    flag_string(race_flags, race->flags));
    
    /*
    buf_printf (output, "Loves sectors: [%s]\n", flag_string(sector_flag_types, race->loved_sectors));
    buf_printf (output, "Hates sectors: [%s]\n", flag_string(sector_flag_types, race->hated_sectors));
    */

    
    /*
    for (i = 0; i < MAX_DAM; i++)
        if (race->resists[i])
            buf_printf(output, "Res:           [%-16.16s:%4d%%]\n", flag_string(dam_flags, i), race->resists[i]);
    
    for (i = 0; i < MAX_SPEC_PARTS; ++i)
        if (race->spec_parts[i] != 0)
            break;

    if (i < MAX_SPEC_PARTS)
    {
        OBJ_INDEX_DATA * obj;

        buf_add (output, "Special parts:\n");
        buf_add (output, "{x    Min. level Probability Object        :\n");
        for (i = 0; i < MAX_SPEC_PARTS; ++i)
        {
            obj = get_obj_index (race->spec_parts[i]);
            buf_printf (output, "{G%2d{x.   [%3d]       [%4d]   [%7d] %s\n", 
                i + 1,
                race->spec_levels[i],
                race->spec_prob[i],
                race->spec_parts[i], 
                obj == NULL ? "non-existent object" : mlstr_cval (obj->short_descr, ch));
        }
    }
    */
    if ((pcr = race->pcdata))
    {
        buf_printf(output, "\n{WPC data:{x\n\n");
        buf_printf(output, "ShortName:    [%s]\n", pcr->who_name);
        buf_printf(output, "Points:       [%d]\n", pcr->points);
        for (i = 0; i < pcr->classes.nused; i++) 
        {
             rclass_t *race_class = VARR_GET(&pcr->classes, i);
             int cn;

             if ((cn = cn_lookup(race_class->name)) < 0)
                        continue;
             buf_printf(output, "Class:        '%s' (mult %d)\n", CLASS(cn)->name, race_class->mult);
        }
        
	buf_printf(output, "BonusSkills   [%s]\n", pcr->bonus_skills);
        
        for (i = 0; i < pcr->skills.nused; i++) 
        {
             rskill_t *race_skill = VARR_GET(&pcr->skills, i);
             skill_t *skill;

             if (race_skill->sn <= 0  || (skill = skill_lookup(race_skill->sn)) == NULL)
             continue;
             buf_printf(output, "Skill:       '%s' (level %d)\n",
             
             skill->name, race_skill->level);
        }
        
        buf_printf(output, "Stats        ");
        for (i = 0; i < MAX_STATS; i++)         buf_printf(output, " %d", pcr->stats[i]);
        buf_printf(output, "\n");
        buf_printf(output, "MaxStats     ");
        for (i = 0; i < MAX_STATS; i++)         buf_printf(output, " %d", pcr->max_stats[i]);
        buf_printf(output, "\n");
	buf_printf(output, "Size:         [%s]\n", flag_string(size_table, pcr->size));
        buf_printf(output, "HPBonus:      [%d]\n", pcr->hp_bonus);
        buf_printf(output, "ManaBonus:    [%d]\n", pcr->mana_bonus);
        buf_printf(output, "PracBonus:    [%d]\n", pcr->prac_bonus);
        buf_printf(output, "RestrictAlign [%s]\n", flag_string(ralign_names, pcr->restrict_align));
        buf_printf(output, "RestrictEthos [%s]\n", flag_string(ethos_table, pcr->restrict_ethos));
	/*
        if (pcr->restrict_sex)     buf_printf(output, "RestrictSex   [%s]\n", flag_string(restrict_sex_table, pcr->restrict_sex));
	*/
        buf_printf(output, "Slang         [%s]\n", flag_string(slang_table, pcr->slang));
	buf_printf(output, "Flags:        [%s]",  flag_string(race_flags, pcr->flags));
    }

    buf_printf(output, "\n\r");
    page_to_char(buf_string(output), ch);
    buf_free(output);

    return FALSE;
}

OLC_FUN(raceed_list)
{
    int i;
    for (i = 0; i < races.nused; i++)
        char_printf(ch, "[%d] %s\n", i, RACE(i)->name);
    return FALSE;
}

OLC_FUN(raceed_name)
{
    race_t *race;
    EDIT_RACE(ch, race);
    return olced_str(ch, argument, cmd, &race->name);
}

OLC_FUN(raceed_filename)
{
    race_t *race;
    EDIT_RACE(ch, race);
    return olced_str(ch, argument, cmd, &race->file_name);
}

OLC_FUN(raceed_flags)
{
    race_t *race;
    EDIT_RACE(ch, race);
    return olced_flag32(ch, argument, cmd, &race->flags);
}


OLC_FUN(raceed_damtype)
{
	char arg[MAX_INPUT_LENGTH];
	int dt;
	race_t *race;
	EDIT_RACE(ch, race);

	one_argument(argument, arg, sizeof(arg));
	if (arg[0] == '\0') {
		char_puts("Syntax: damtype [damage message]\n", ch);
		char_puts("Syntax: damtype ?\n", ch);
		return FALSE;
	}

	if (!str_cmp(arg, "?")) {
		BUFFER *output = buf_new(-1);
		show_attack_types(output);
		page_to_char(buf_string(output), ch);
		buf_free(output);
		return FALSE;
	}

	if ((dt = attack_lookup(arg)) < 0) {
		char_printf(ch, "RaceEd: %s: unknown damtype.\n", arg);
		return FALSE;
	}

	race->dam_type = dt;
	char_puts("Damage type set.\n", ch);
	return TRUE;
}

OLC_FUN(raceed_align)
{
	race_t *race;
	EDIT_RACE(ch, race);
	return olced_number(ch, argument, cmd, &race->alignment);
}

OLC_FUN(raceed_sex)
{
	race_t *race;
	EDIT_RACE(ch, race);
	return olced_flag32(ch, argument, cmd, &race->sex);
}

OLC_FUN(raceed_size)
{
	race_t *race;
	EDIT_RACE(ch, race);
	return olced_flag32(ch, argument, cmd, &race->size);
}


/*
OLC_FUN(raceed_love_sect)
{
    race_t *race;
    EDIT_RACE(ch, race);
    return olced_flag64(ch, argument, cmd, &race->loved_sectors);
}

OLC_FUN(raceed_hate_sect)
{
    race_t *race;
    EDIT_RACE(ch, race);
    return olced_flag64(ch, argument, cmd, &race->hated_sectors);
}

OLC_FUN(raceed_spec_part)
{
    race_t *race;
    char arg[MAX_STRING_LENGTH];
    int num, vnum, prob, level;

    EDIT_RACE(ch, race);

    // number
    argument = one_argument (argument, arg, sizeof(arg));
    num = atoi (arg);
    if (num < 1 || num > MAX_SPEC_PARTS)
    {
        char_act ("Syntax: spec_part <num> <vnum> <probability> <min_level>", ch);
        char_printf (ch, "Num must be between 1 and %d.\n", MAX_SPEC_PARTS);
        return FALSE;
    }

    // vnum 
    argument = one_argument (argument, arg, sizeof(arg));
    vnum = atoi (arg);
    vnum = UMAX (0, vnum);
    // validate vnum
    if (vnum != 0 && get_obj_index (vnum) == NULL)
    {
        char_printf (ch, "Obj vnum %d does not exist.\n", vnum);
        return FALSE;
    }

    // probability
    argument = one_argument (argument, arg, sizeof(arg));
    prob = atoi (arg);
    prob = UMAX (0, prob);
    if (prob > MAX_SPEC_PROB)
    {
        char_act ("Syntax: spec_part <num> <vnum> <probability> <min_level>", ch);
        char_printf (ch, "Probability must be between 0 and %d.\n", MAX_SPEC_PROB);
        return FALSE;
    }

    // level
    argument = one_argument (argument, arg, sizeof(arg));
    level = atoi (arg);
    level = UMAX (0, level);

    // fill the arrays
    race->spec_prob[num - 1] = prob;
    race->spec_parts[num - 1] = vnum;
    race->spec_levels[num - 1] = level;
    char_act ("Ok.", ch);
    return TRUE;
}
*/

OLC_FUN(pcraceed_create)
{
        race_t *race;
        EDIT_RACE(ch, race);
        if (race->pcdata != NULL)
        {
                char_printf(ch, "RaceEd: %s: pcrace already exists.\n", race->name);
                return FALSE;
        }
        race->pcdata = pcrace_new();
        return TRUE;
}

OLC_FUN(pcraceed_age)
{
    race_t *race;
    EDIT_RACE(ch, race);
        if (race->pcdata != NULL)
        {
                char_printf(ch, "RaceEd: %s: isn't a PC race.\n", race->name);
                return FALSE;
        }
    
    return olced_number(ch, argument, cmd, &race->pcdata->age_modifier);
}

OLC_FUN(pcraceed_skill)
{
    char arg[MAX_STRING_LENGTH];
    argument = one_argument(argument, arg, sizeof(arg));
    if (!str_prefix(arg, "add"))
        return pcraceed_skill_add(ch, argument, cmd);
    else if (!str_prefix(arg, "delete"))
        return pcraceed_skill_del(ch, argument, cmd);
    do_help(ch, "'OLC RACE SKILL'");
    return FALSE;
}

OLC_FUN(pcraceed_skill_add)
{
    int sn;
    rskill_t *race_skill;
    char    arg1[MAX_STRING_LENGTH];
    char    arg2[MAX_STRING_LENGTH];
    race_t *race;
    EDIT_RACE(ch, race);
    argument = one_argument(argument, arg1, sizeof(arg1));
    argument = one_argument(argument, arg2, sizeof(arg2));
    if (arg1[0] == '\0' || arg2[0] == '\0')
    {
        do_help(ch, "'OLC RACE SKILL'");
        return FALSE;
    }
    if ((sn = sn_lookup(arg1)) <= 0)
    {
        char_printf(ch, "RaceEd: %s: unknown skill.\n", arg1);
        return FALSE;
    }

    if ((race_skill = rskill_lookup(race, sn)))
    {
        char_printf(ch, "RaceEd: %s: already there.\n",
                    SKILL(sn)->name);
        return FALSE;
    }

    race_skill = varr_enew(&race->pcdata->skills);
    race_skill->sn = sn;
    race_skill->level = atoi(arg2);
    varr_qsort(&race->pcdata->skills, cmpint);

    return TRUE;
}

OLC_FUN(pcraceed_skill_del)
{
    char    arg[MAX_STRING_LENGTH];
    rskill_t *race_skill;
    race_t *race;
    EDIT_RACE(ch, race);
    one_argument(argument, arg, sizeof(arg));
    if ((race_skill = skill_vlookup(&race->pcdata->skills, arg)) == NULL)
    {
        char_printf(ch, "RaceEd: %s: not found in pcrace skill list.\n", arg);
        return FALSE;
    }
    race_skill->sn = 0;
    varr_qsort(&race->pcdata->skills, cmpint);
    return TRUE;
}

static VALIDATE_FUN(validate_name)
{
    int i;
    race_t *race;
    EDIT_RACE(ch, race);

    for (i = 0; i < races.nused; i++)
        if (RACE(i) != race  &&  !str_cmp(RACE(i)->name, arg))
        {
            char_printf(ch, "RaceEd: %s: duplicate race name.\n", arg);
            return FALSE;
        }
    return TRUE;
}

static VALIDATE_FUN(validate_haspcdata)
{
        race_t *race;
        EDIT_RACE(ch, race);
        if (race->pcdata == NULL)
        {
                char_printf(ch, "RaceEd: %s: no race pcdata.\n", race->name);
                return FALSE;
        }
        return TRUE;
}

static bool touch_race(race_t *race)
{
    SET_BIT(race->flags, RACE_CHANGED);
    return FALSE;
}