/**
* Checks for common craft recipe problems and reports them to ch.
*
* @param craft_data *craft The item to audit.
* @param char_data *ch The person to report to.
* @return bool TRUE if any problems were reported; FALSE if all good.
*/
bool audit_craft(craft_data *craft, char_data *ch) {
	bool problem = FALSE;

	if (GET_CRAFT_REQUIRES_OBJ(craft) == NOTHING && GET_CRAFT_ABILITY(craft) == NO_ABIL) {
		olc_audit_msg(ch, GET_CRAFT_VNUM(craft), "Craft requires no object or ability");
		problem = TRUE;
	}
	if (IS_SET(GET_CRAFT_FLAGS(craft), CRAFT_IN_DEVELOPMENT)) {
		olc_audit_msg(ch, GET_CRAFT_VNUM(craft), "IN-DEVELOPMENT");
		problem = TRUE;
	}
	if (!IS_SET(GET_CRAFT_FLAGS(craft), CRAFT_APIARIES | CRAFT_GLASS) && GET_CRAFT_RESOURCES(craft)[0].vnum == NOTHING) {
		olc_audit_msg(ch, GET_CRAFT_VNUM(craft), "Craft requires no resources");
		problem = TRUE;
	}
	if (!IS_SET(GET_CRAFT_FLAGS(craft), CRAFT_SOUP) && (GET_CRAFT_OBJECT(craft) == NOTHING || !obj_proto(GET_CRAFT_OBJECT(craft))) && (GET_CRAFT_BUILD_TYPE(craft) == NOTHING || !building_proto(GET_CRAFT_BUILD_TYPE(craft)))) {
		olc_audit_msg(ch, GET_CRAFT_VNUM(craft), "Craft makes nothing");
		problem = TRUE;
	}
	if (!str_cmp(GET_CRAFT_NAME(craft), "unnamed recipe")) {
		olc_audit_msg(ch, GET_CRAFT_VNUM(craft), "Craft not named");
		problem = TRUE;
	}
	if (GET_CRAFT_TYPE(craft) == CRAFT_TYPE_ERROR) {
		olc_audit_msg(ch, GET_CRAFT_VNUM(craft), "Craft type not set");
		problem = TRUE;
	}
	if (GET_CRAFT_TYPE(craft) != CRAFT_TYPE_BUILD && GET_CRAFT_OBJECT(craft) != NOTHING && GET_CRAFT_OBJECT(craft) != GET_CRAFT_VNUM(craft)) {
		olc_audit_msg(ch, GET_CRAFT_VNUM(craft), "Craft creates item with different vnum");
		problem = TRUE;
	}
	if (GET_CRAFT_TYPE(craft) == CRAFT_TYPE_BUILD && GET_CRAFT_BUILD_TYPE(craft) != NOTHING && GET_CRAFT_BUILD_TYPE(craft) != GET_CRAFT_VNUM(craft)) {
		olc_audit_msg(ch, GET_CRAFT_VNUM(craft), "Craft creates building with different vnum");
		problem = TRUE;
	}
	if (GET_CRAFT_QUANTITY(craft) == 0 && GET_CRAFT_TYPE(craft) != CRAFT_TYPE_BUILD) {
		olc_audit_msg(ch, GET_CRAFT_VNUM(craft), "Craft creates 0 quantity");
		problem = TRUE;
	}
	if (GET_CRAFT_TIME(craft) == 0 && GET_CRAFT_TYPE(craft) != CRAFT_TYPE_BUILD) {
		olc_audit_msg(ch, GET_CRAFT_VNUM(craft), "Craft requires 0 time");
		problem = TRUE;
	}
		
	return problem;
}
/**
* Checks for common building problems and reports them to ch.
*
* @param bld_data *bld The building to audit.
* @param char_data *ch The person to report to.
* @return bool TRUE if any problems were reported; FALSE if all good.
*/
bool audit_building(bld_data *bld, char_data *ch) {
	extern bool audit_extra_descs(any_vnum vnum, struct extra_descr_data *list, char_data *ch);
	extern bool audit_interactions(any_vnum vnum, struct interaction_item *list, int attach_type, char_data *ch);
	extern bool audit_spawns(any_vnum vnum, struct spawn_info *list, char_data *ch);
	
	bool problem = FALSE;
	
	if (!str_cmp(GET_BLD_NAME(bld), "Unnamed Building")) {
		olc_audit_msg(ch, GET_BLD_VNUM(bld), "Name not set");
		problem = TRUE;
	}
	if (!str_cmp(GET_BLD_TITLE(bld), "An Unnamed Building")) {
		olc_audit_msg(ch, GET_BLD_VNUM(bld), "Title not set");
		problem = TRUE;
	}
	if (!IS_SET(GET_BLD_FLAGS(bld), BLD_ROOM) && !str_cmp(GET_BLD_ICON(bld), "&0[  ]")) {
		olc_audit_msg(ch, GET_BLD_VNUM(bld), "Icon not set");
		problem = TRUE;
	}
	if (!IS_SET(GET_BLD_FLAGS(bld), BLD_OPEN) && (!GET_BLD_DESC(bld) || !*GET_BLD_DESC(bld) || !str_cmp(GET_BLD_DESC(bld), "Nothing.\r\n"))) {
		olc_audit_msg(ch, GET_BLD_VNUM(bld), "Description not set");
		problem = TRUE;
	}
	else if (!IS_SET(GET_BLD_FLAGS(bld), BLD_OPEN) && !strn_cmp(GET_BLD_DESC(bld), "Nothing.", 8)) {
		olc_audit_msg(ch, GET_BLD_VNUM(bld), "Description starting with 'Nothing.'");
		problem = TRUE;
	}
	if (GET_BLD_EXTRA_ROOMS(bld) > 0 && IS_SET(GET_BLD_FLAGS(bld), BLD_ROOM)) {
		olc_audit_msg(ch, GET_BLD_VNUM(bld), "Designated room has extra rooms set");
		problem = TRUE;
	}
	if (GET_BLD_EXTRA_ROOMS(bld) > 0 && GET_BLD_DESIGNATE_FLAGS(bld) == NOBITS) {
		olc_audit_msg(ch, GET_BLD_VNUM(bld), "Has extra rooms but no designate flags");
		problem = TRUE;
	}
	if (IS_SET(GET_BLD_FLAGS(bld), BLD_ROOM) && IS_SET(GET_BLD_FLAGS(bld), BLD_OPEN | BLD_CLOSED | BLD_TWO_ENTRANCES | BLD_ATTACH_ROAD | BLD_INTERLINK)) {
		olc_audit_msg(ch, GET_BLD_VNUM(bld), "Designated room has incompatible flag(s)");
		problem = TRUE;
	}
	if (!IS_SET(GET_BLD_FLAGS(bld), BLD_ROOM) && IS_SET(GET_BLD_FLAGS(bld), BLD_SECONDARY_TERRITORY)) {
		olc_audit_msg(ch, GET_BLD_VNUM(bld), "2ND-TERRITORY flag on a non-designated building");
		problem = TRUE;
	}
	
	problem |= audit_extra_descs(GET_BLD_VNUM(bld), GET_BLD_EX_DESCS(bld), ch);
	problem |= audit_spawns(GET_BLD_VNUM(bld), GET_BLD_SPAWNS(bld), ch);
	problem |= audit_interactions(GET_BLD_VNUM(bld), GET_BLD_INTERACTIONS(bld), TYPE_ROOM, ch);
	
	return problem;
}
/**
* Checks for common crop problems and reports them to ch.
*
* @param crop_data *cp The item to audit.
* @param char_data *ch The person to report to.
* @return bool TRUE if any problems were reported; FALSE if all good.
*/
bool audit_crop(crop_data *cp, char_data *ch) {
	extern adv_data *get_adventure_for_vnum(rmt_vnum vnum);
	extern struct icon_data *get_icon_from_set(struct icon_data *set, int type);
	extern const char *icon_types[];
	
	struct interaction_item *inter;
	char temp[MAX_STRING_LENGTH];
	bool problem = FALSE;
	bool harv, forage;
	adv_data *adv;
	int iter;
	
	adv = get_adventure_for_vnum(GET_CROP_VNUM(cp));
	
	if (!GET_CROP_NAME(cp) || !*GET_CROP_NAME(cp) || !str_cmp(GET_CROP_NAME(cp), "Unnamed Crop")) {
		olc_audit_msg(ch, GET_CROP_VNUM(cp), "No name set");
		problem = TRUE;
	}
	
	strcpy(temp, GET_CROP_NAME(cp));
	strtolower(temp);
	if (strcmp(GET_CROP_NAME(cp), temp)) {
		olc_audit_msg(ch, GET_CROP_VNUM(cp), "Non-lowercase name");
		problem = TRUE;
	}
	
	if (!GET_CROP_TITLE(cp) || !*GET_CROP_TITLE(cp) || !str_cmp(GET_CROP_TITLE(cp), "An Unnamed Crop")) {
		olc_audit_msg(ch, GET_CROP_VNUM(cp), "No title set");
		problem = TRUE;
	}
	
	if (adv && !CROP_FLAGGED(cp, CROPF_NOT_WILD)) {
		olc_audit_msg(ch, GET_CROP_VNUM(cp), "Missing !WILD flag in adventure crop");
		problem = TRUE;
	}
	if (!adv && CROP_FLAGGED(cp, CROPF_NOT_WILD)) {
		olc_audit_msg(ch, GET_CROP_VNUM(cp), "!WILD flag on non-adventure crop");
		problem = TRUE;
	}
	if (GET_CROP_MAPOUT(cp) == 0) {	// slightly magic-numbered
		olc_audit_msg(ch, GET_CROP_VNUM(cp), "Mapout color not set");
		problem = TRUE;
	}
	for (iter = 0; iter < NUM_TILESETS; ++iter) {
		if (!get_icon_from_set(GET_CROP_ICONS(cp), iter)) {
			olc_audit_msg(ch, GET_CROP_VNUM(cp), "No icon for '%s' tileset", icon_types[iter]);
			problem = TRUE;
		}
	}
	if (GET_CROP_CLIMATE(cp) == CLIMATE_NONE) {
		olc_audit_msg(ch, GET_CROP_VNUM(cp), "Climate not set");
		problem = TRUE;
	}
	if (!GET_CROP_SPAWNS(cp)) {
		olc_audit_msg(ch, GET_CROP_VNUM(cp), "No spawns set");
		problem = TRUE;
	}
	
	harv = forage = FALSE;
	LL_FOREACH(GET_CROP_INTERACTIONS(cp), inter) {
		if (inter->type == INTERACT_HARVEST) {
			harv = TRUE;
		}
		else if (inter->type == INTERACT_FORAGE) {
			forage = TRUE;
		}
	}
	if (!harv) {
		olc_audit_msg(ch, GET_CROP_VNUM(cp), "No HARVEST");
		problem = TRUE;
	}
	if (!forage) {
		olc_audit_msg(ch, GET_CROP_VNUM(cp), "No FORAGE");
		problem = TRUE;
	}
	
	return problem;
}
/**
* Checks for common mob problems and reports them to ch.
*
* @param char_data *mob The mob to audit.
* @param char_data *ch The person to report to.
* @return bool TRUE if any problems were reported; FALSE if all good.
*/
bool audit_mobile(char_data *mob, char_data *ch) {
	extern adv_data *get_adventure_for_vnum(rmt_vnum vnum);
	
	bool is_adventure = (get_adventure_for_vnum(GET_MOB_VNUM(mob)) != NULL);
	char temp[MAX_STRING_LENGTH], *ptr;
	bool problem = FALSE;

	if (!str_cmp(GET_PC_NAME(mob), "mobile new")) {
		olc_audit_msg(ch, GET_MOB_VNUM(mob), "Keywords not set");
		problem = TRUE;
	}
	
	ptr = GET_PC_NAME(mob);
	do {
		ptr = any_one_arg(ptr, temp);
		if (*temp && !str_str(GET_SHORT_DESC(mob), temp) && !str_str(GET_LONG_DESC(mob), temp)) {
			olc_audit_msg(ch, GET_MOB_VNUM(mob), "Keyword '%s' not found in strings", temp);
			problem = TRUE;
		}
	} while (*ptr);
	
	if (!str_cmp(GET_SHORT_DESC(mob), "a new mobile")) {
		olc_audit_msg(ch, GET_MOB_VNUM(mob), "Short desc not set");
		problem = TRUE;
	}
	any_one_arg(GET_SHORT_DESC(mob), temp);
	if ((fill_word(temp) || reserved_word(temp)) && isupper(*temp)) {
		olc_audit_msg(ch, GET_MOB_VNUM(mob), "Short desc capitalized");
		problem = TRUE;
	}
	if (ispunct(GET_SHORT_DESC(mob)[strlen(GET_SHORT_DESC(mob)) - 1])) {
		olc_audit_msg(ch, GET_MOB_VNUM(mob), "Short desc has punctuation");
		problem = TRUE;
	}
	
	ptr = GET_SHORT_DESC(mob);
	do {
		ptr = any_one_arg(ptr, temp);
		// remove trailing punctuation
		while (*temp && ispunct(temp[strlen(temp)-1])) {
			temp[strlen(temp)-1] = '\0';
		}
		if (*temp && !fill_word(temp) && !reserved_word(temp) && !isname(temp, GET_PC_NAME(mob))) {
			olc_audit_msg(ch, GET_MOB_VNUM(mob), "Suggested missing keyword '%s'", temp);
			problem = TRUE;
		}
	} while (*ptr);
	
	if (!str_cmp(GET_LONG_DESC(mob), "A new mobile is standing here.\r\n")) {
		olc_audit_msg(ch, GET_MOB_VNUM(mob), "Long desc not set");
		problem = TRUE;
	}
	if (!ispunct(GET_LONG_DESC(mob)[strlen(GET_LONG_DESC(mob)) - 3])) {
		olc_audit_msg(ch, GET_MOB_VNUM(mob), "Long desc missing punctuation");
		problem = TRUE;
	}
	if (islower(*GET_LONG_DESC(mob))) {
		olc_audit_msg(ch, GET_MOB_VNUM(mob), "Long desc not capitalized");
		problem = TRUE;
	}
	if (!is_adventure && GET_MAX_SCALE_LEVEL(mob) == 0) {
		olc_audit_msg(ch, GET_MOB_VNUM(mob), "No maximum scale level on non-adventure mob");
		problem = TRUE;
	}
	if (MOB_ATTACK_TYPE(mob) == TYPE_RESERVED) {
		olc_audit_msg(ch, GET_MOB_VNUM(mob), "Invalid attack type");
		problem = TRUE;
	}
	if (MOB_FLAGGED(mob, MOB_ANIMAL) && !has_interaction(mob->interactions, INTERACT_SKIN)) {
		olc_audit_msg(ch, GET_MOB_VNUM(mob), "Animal has no skin");
		problem = TRUE;
	}
	if (MOB_FLAGGED(mob, MOB_ANIMAL) && !has_interaction(mob->interactions, INTERACT_BUTCHER)) {
		olc_audit_msg(ch, GET_MOB_VNUM(mob), "Animal can't be butchered");
		problem = TRUE;
	}
	
	return problem;
}