/**
* WARNING: This function actually deletes a crop.
*
* @param char_data *ch The person doing the deleting.
* @param crop_vnum vnum The vnum to delete.
*/
void olc_delete_crop(char_data *ch, crop_vnum vnum) {
	void remove_crop_from_table(crop_data *crop);
	extern const sector_vnum climate_default_sector[NUM_CLIMATES];
	
	obj_data *obj, *next_obj;
	descriptor_data *desc;
	struct map_data *map;
	room_data *room;
	crop_data *crop;
	sector_data *base = NULL;
	int count;
	
	if (!(crop = crop_proto(vnum))) {
		msg_to_char(ch, "There is no such crop %d.\r\n", vnum);
		return;
	}
	
	if (HASH_COUNT(crop_table) <= 1) {
		msg_to_char(ch, "You can't delete the last crop.\r\n");
		return;
	}

	// remove it from the hash table first
	remove_crop_from_table(crop);
	
	// save base sect for later
	base = sector_proto(climate_default_sector[GET_CROP_CLIMATE(crop)]);

	// save index and crop file now
	save_index(DB_BOOT_CROP);
	save_library_file_for_vnum(DB_BOOT_CROP, vnum);
	
	// update world
	count = 0;
	LL_FOREACH(land_map, map) {
		room = real_real_room(map->vnum);
		
		if (map->crop_type == crop || (room && ROOM_CROP(room) == crop)) {
			if (!room) {
				room = real_room(map->vnum);
			}
			set_crop_type(room, NULL);	// remove it explicitly
			change_terrain(room, GET_SECT_VNUM(base));
			++count;
		}
	}
/**
*
* @param room_data *location Where the morph affinity is happening.
* @param int morph Which MORPH_x the person is trying to morph into.
* @return bool TRUE if the morph passes the affinities check.
*/
bool morph_affinity_ok(room_data *location, int morph) {
	int climate = NOTHING;
	crop_data *cp;
	bool ok = TRUE;
	
	if (ROOM_SECT_FLAGGED(location, SECTF_HAS_CROP_DATA) && (cp = crop_proto(ROOM_CROP_TYPE(location)))) {
		climate = GET_CROP_CLIMATE(cp);
	}
	else {
		climate = GET_SECT_CLIMATE(SECT(location));
	}
	
	if (IS_SET(morph_data[(morph)].morph_flags, MORPH_FLAG_TEMPERATE_AFFINITY) && climate != CLIMATE_TEMPERATE) {
		ok = FALSE;
	}
	if (IS_SET(morph_data[(morph)].morph_flags, MORPH_FLAG_ARID_AFFINITY) && climate != CLIMATE_ARID) {
		ok = FALSE;
	}
	if (IS_SET(morph_data[(morph)].morph_flags, MORPH_FLAG_TROPICAL_AFFINITY) && climate != CLIMATE_TROPICAL) {
		ok = FALSE;
	}
	
	return ok;
}
/**
* 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;
}