Greasy Fork is available in English.

Clanheart Alpha Creator Extended

This script changes the drop downs on CH's alpha creator to colours. No more wondering what colour Galaxy or Brick is!

// ==UserScript==
// @name         Clanheart Alpha Creator Extended
// @namespace    fortytwo
// @version      1.34
// @description  This script changes the drop downs on CH's alpha creator to colours. No more wondering what colour Galaxy or Brick is!
// @author       fortytwo
// @match        http://clan.arvixecloud.com/~jakosse/laravel/public/
// @require		 https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js
// @grant		 none
// ==/UserScript==

/***
	NOTICE: YOU ARE AGREEING THAT ANY USE OF THE FOLLOWING SCRIPT IS AT
	YOUR OWN RISK. I DO NOT MAKE ANY GUARANTEES THE SCRIPT WILL WORK, NOR 
	WILL I HOLD MYSELF ACCOUNTABLE FOR DAMAGE TO YOUR DEVICE.

	IF THE SCRIPT ISN'T WORKING FOR YOU, FEEL FREE TO SEND ME A MESSAGE: http://games-fortytwo.tumblr.com/
***/
$(document).ready(function(){
//mapping colour names to the appropriate rgb
//http://clanheart.tumblr.com/post/125971903821/eimitanrising-a-polished-collection-of-the
var colours =[
	["None", '255, 255, 255'],
	["Zinnia Red", '232, 5, 5'],
	["Hot Pink", '255, 15, 127'],
	["Neon Purple", '255, 15, 247'],
	["Royal Purple", '179, 15, 225'],
	["Galaxy", '119, 15, 225'],
	["Cobalt", '51, 15, 255'],
	["Azure", '15, 107, 255'],
	["Cerulean", '15, 147, 255'],
	["Aqua", '15, 195, 255'],
	["Teal", '16, 255, 231'],
	["Leaf", '16, 255, 159'],
	["Harlequin", '16, 255, 75'],
	["Chartreuse", '135, 255, 15'],
	["Pear", '195, 255, 15'],
	["Sunlight", '243, 255, 15'],
	["Gold", '255, 199, 15'],
	["Monarch", '255, 139, 15'],
	["Pumpkin", '255, 87, 15'],
	["Coral", '255, 79, 79'],
	["Fuschia", '255, 79, 138'],
	["Magenta", '255, 79, 240'],
	["Electric Purple", '205, 79, 255'],
	["Violet", '144, 79, 255'],
	["Sapphire Blue", '79, 100, 255'],
	["Cornflower", '79, 146, 255'],
	["Sky Blue", '79, 176, 255'],
	["Electric Blue", '79, 232, 255'],
	["Tropical Sea", '79, 255, 214'],
	["Eucalpytis", '79, 255, 141'],
	["Emerald", '88, 255, 79'],
	["Clover", '146, 255, 79'],
	["Key Lime", '188, 255, 79'],
	["Lemon", '237, 255, 79'],
	["Jasmine", '255, 211, 79'],
	["Amber", '255, 167, 79'],
	["Carrot", '255, 129, 79'],
	["Salmon", '255, 153, 153'],
	["Bubblegum", '255, 153, 182'],
	["Carnation", '255, 153, 212'],
	["Heliotrope", '245, 153, 255'],
	["Crocus", '204, 153, 255'],
	["Wisteria", '163, 153, 255'],
	["Powder Blue", '153, 184, 255'],
	["Baby Blue", '153, 219, 255'],
	["Cyan", '153, 255, 250'],
	["Aquamarine", '153, 255, 204'],
	["Mint", '153, 255, 167'],
	["Celery", '182, 255, 153'],
	["Peridot", '228, 255, 153'],
	["Canary", '255, 230, 153'],
	["Peach", '255, 211, 153'],
	["Apricot", '255, 184, 153'],
	["Rose Quartz", '255, 212, 212'],
	["Blush", '255, 212, 229'],
	["Petal Pink", '255, 212, 241'],
	["Lilac", '241, 212, 255'],
	["Lavender", '222, 212, 255'],
	["Periwinkle", '212, 217, 255'],
	["Frost", '212, 233, 255'],
	["Ice", '212, 250, 255'],
	["Spearmint", '212, 255, 244'],
	["Cucumber", '212, 255, 225'],
	["Honeydew", '228, 255, 212'],
	["Ivory", '246, 255, 212'],
	["Cream", '255, 238, 212'],
	["Eggshell", '255, 225, 212'],
	["White", '255, 255, 255'],
	["Ash", '235, 235, 235'],
	["Oyster", '212, 212, 212'],
	["Silver", '181, 181, 181'],
	["Gray", '148, 148, 148'],
	["Overcast", '122, 122, 122'],
	["Smoke", '94, 94, 94'],
	["Coal", '66, 66, 66'],
	["Caviar", '38, 38, 38'],
	["Black", '0, 0, 0'],
	["Garnet", '21, 2, 2'],
	["Burgundy", '51, 2, 41'],
	["Blackberry", '35, 2, 51'],
	["Tanzanite", '9, 2, 51'],
	["Prussian Blue", '2, 31, 51'],
	["Amazon", '2, 51, 50'],
	["Hunter Green", '2, 51, 27'],
	["Moss", '23, 38, 3'],
	["Olive", '43, 43, 2'],
	["Chocolate", '43, 28, 2'],
	["Seal", '43, 12, 2'],
	["Cinnamon", '84, 38, 38'],
	["Brick", '84, 38, 64'],
	["Maroon", '80, 38, 84'],
	["Plum", '56, 38, 84'],
	["Vineyard", '38, 42, 84'],
	["Indigo", '38, 59, 84'],
	["Deep Sea", '38, 80, 84'],
	["Denim", '40, 86, 72'], //CLOSEST MATCH
	["Hunter", '38, 84, 61'], //RENAMED. OFFICIAL 
	["Fern", '56, 84, 38'],
	["Avocado", '83, 84, 38'],
	["Sage", '84, 68, 38'],
	["Sepia", '84, 56, 33'], //CLOSEST MATCH
	["Sienna", '84, 52, 38'], //OFFICIAL
	["Dusty Rose", '140, 91, 116'],
	["Mauve", '136, 91, 140'],
	["Eggplant", '107, 91, 140'],
	["Ube", '91, 97, 140'],
	["Lazuli", '91, 121, 140'],
	["Slate", '91, 130, 135'],//CLOSEST MATCH
	["Juniper", '91, 140, 135'], //OFFICIAL
	["Jade", '91, 140, 106'], //OFFICIAL
	["Asparagus", '104, 140, 91'],
	["Clay", '140, 135, 91'],
	["Beaver", '140, 123, 91'],
	["Umber", '140, 108, 91'],
	["Taupe", '140, 98, 91'],
	["Redwood", '164, 90, 82'], //OFFICIAL
	["Blood", '196, 79, 79'],
	["Mulberry", '196, 79, 145'],
	["Orchid", '173, 79, 196'],
	["Amethyst", '126, 79, 196'],
	["Blueberry", '79, 86, 196'],
	["Hydrangea", '79, 149, 196'],
	["Turqouise", '79, 196, 183'],
	["Grass", '79, 196, 116'],
	["Shamrock", '116, 196, 79'],
	["Citron", '179, 196, 79'],
	["Goldenrod", '196, 183, 79'],
	["Fawn", '196, 147, 79'],
	["Rust", '196, 108, 79'],
	["Poinsetta", '196, 79, 79'] //OFFICIAL
];

/*** STYLING ***/
$('head').append(
"<style>"+
".ace-overlay{position:absolute;top:0px;left:0px;}"+
".custom-dropdown-text{width:100% !important}"+
"</style>");

/***
	CUSTOM DROP DOWN SCRIPT BY FORTYTWO
***/
function dropDown(appendTo, name){
	this.element = $(appendTo);
	this.name = name;
	this.text = this.hidden = this.select = null;
	this.events ={ onchange: [], onmenuclose: [], onmenuopen: [] };

	this._init();
}

dropDown.prototype ={
	/*** INTERNAL FUNCTIONS ***/
	//css stuff and the block
	_firstRun: function(){
		$("head").append($(
		"<style>"+
		".custom-dropdown-text{border-radius:4px;padding:6px 12px;width:100%;border:1px solid #ccc;}"+
		".custom-dropdown-text-active{"+
		"	box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6)}"+
		".custom-dropdown-select{display:none;}"+
		".custom-dropdown-select-active{height:300px; width:300px; overflow-y:scroll;position:absolute;"+
		"	background:#fff;z-index:10510; border: 1px solid #66afe9;display:block; }"+
		".custom-dropdown-option{whitespace:pre;min-height:1.2em;padding:3px 12px;}"+
		".custom-dropdown-option:hover{opacity:0.5}"+
		"#custom-dropdown-overlay{top:0;right:0;left:0;bottom:0;opacity:10;"+
		"	position:fixed;z-index:10500; display:none;}"+
		".custom-dropdown-overlay-active{display:block !important;}"+
		".custom-noselect{-webkit-touch-callout: none; -webkit-user-select: none;"+
		"	-khtml-user-select: none; -moz-user-select: none;"+
		"	user-select: none;}"+
		"</style>"));

		this.block = $("<div />", {id: "custom-dropdown-overlay"});
		this.block.addClass('custom-dropdown-overlay');
		$("body").append(this.block);
	},

	_init: function(){
		var _this = this;
		//create elements and styles
		this.text = $("<input />", {
			type: 'text',
			'class': 'custom-dropdown-text',
			//prevents editing of the content
			readonly: true
		});

		this.hidden = $("<input />", {
			type: 'hidden',
			'class': 'custom-dropdown-hidden',
			name: this.name,
			id: this.name
		});
		
		this.select = $("<div />", { 'class': 'custom-dropdown-select custom-noselect'});
		//disable right click to act like select
		this.select.on('contextmenu', function(){ return false; });
	
		//we use this fixed full-page overlay behind the drop down
		//in order for us to be able to click out of it efficiently
			
		//check we don't have one already
		if(document.getElementById('custom-dropdown-overlay') === null)
			this._firstRun();
		//if we do, use it
		else
			this.block = $('#custom-dropdown-overlay');

		//now we need to install some normal behaviour
		this
			.on('MenuClose', function(){
				_this.select.removeClass("custom-dropdown-select-active");
				_this.block.removeClass("custom-dropdown-overlay-active");
				_this.text.removeClass("custom-dropdown-text-active");
				$('body').removeClass('custom-noselect');
			})
			.on('MenuOpen', function(){
				_this.select.addClass("custom-dropdown-select-active");
				_this.block.addClass("custom-dropdown-overlay-active");
				_this.text.addClass("custom-dropdown-text-active");
				
				//makes it so nothing can be selected just like <select>
				$('body').addClass('custom-noselect');
				
				//ensure our select fits the viewport
				//to do this, we'll utilize positions relative the viewport.
				//this just makes it easier for us.
				var bodyRect	= document.body.getBoundingClientRect(),
					textRect	= _this.text[0].getBoundingClientRect(),
					selectRect	= _this.select[0].getBoundingClientRect(),
					//height of the size we can see, essentially
					viewport	= document.documentElement.clientHeight,
					//distance from top of VP to the element
					textTop		= textRect.top,
					textHeight	= textRect.height,
					menuHeight	= selectRect.height;

				//if there's not enough space below to display our complete, display
				//it above the text box
				if((textTop + textHeight + menuHeight) > viewport){
					_this.select.css('top', -(menuHeight-1));
				}
				else{
					//back to normal
					_this.select.css('top', textHeight-1);
				}
				
				//additionally, also match the dropdown's width to the textbox
				_this.select.css('width', textRect.width);
			})
			.on('Change', function(data){
				//we need to set our hidden's value
				_this.hidden.val(data.value);
				_this.text.val(data.option.html());

				//trigger any onchange handlers so it works much like a select
				_this.hidden.change();
			});

		this.text.on('click', function(){
			_this.trigger("onMenuOpen");
		});

		this.block.on('click', function(){
			_this.trigger("onMenuClose");
		});
		
		this.text.on('resize', function(){
			//_this._adjustDropDownArrow($(this));
		});
		
		//add these elements
		this.element.append(this.text).append(this.hidden).append(this.select);
		//this._adjustDropDownArrow(this.text);

		return this;
	},

	/* for determining where to position the drop down arrow */
	_adjustDropDownArrow: function(textbox){
		var textRect = textbox[0].getBoundingClientRect();
		var position = (textRect.width-13)+"px";
	//	textbox.css('background', "#fff url('"+GM_getResourceURL('arrow')+"') no-repeat "+position+" center");
	},

	/*** PUBLIC FUNCTIONS ***/
	/* triggers an event to occur */
	trigger: function(event, data){
		var eventsToCall = this.events[event.toLowerCase()];
		
		for(i = 0; i < eventsToCall.length; ++i){
			eventsToCall[i](data);
		}
		return this;
	},

	/* allows for event-like functionality */
	on: function(event, callback){
		//use lowercase to ensure people don't use the wrong case
		event = event.toLowerCase();
		this.events['on'+event].push(callback);
		return this;
	},

	addOption: function(data){
		var _this = this;
		
		var option = $("<div />")
			.html(data.text)
			.addClass('custom-dropdown-option');

		if(data.unselectable !== undefined){
			option.attr('data-unselectable', (data.unselectable ? true : false));
		}
		//if it's selectable, then it also has a value.
		else{
			option.attr('data-value', data.value);
		}

		//for when option is selected
		option.on('click', function(){
			if(!$(this).attr('data-unselectable')){
				//call menu close event
				_this.trigger('onMenuClose');
				//trigger the change handler
				_this.trigger('onChange', {
					value: $(this).attr('data-value'),
					option: $(this)
				});
			}	
		});

		this.select.append(option);

		//return it so we can use it outside
		return option;
	}
};

//based on http://stackoverflow.com/questions/8022885/rgb-to-hsv-color-in-javascript
function getV(rgbString){
	var components = rgbString.split(", ");
	var r = components[0] / 255,
        g = components[1] / 255,
        b = components[2] / 255;

     return Math.round((Math.max(r, g, b)) * 100);
}

function customDropDowns(){
	//our selects that we wanna change
	var selects	= $('#bases, #eyes, #dyn, #marking_color'),
		//get all the columns we're gonna change
		columns	= selects.parent();

	for(i = 0; i < columns.length; i++){
		var column		= $(columns[i]),
			//fetch the id so we can replicate the form-like action
			select		= selects.eq(i),
			//make our custom dropper
			dropdown	= new dropDown(column, select.attr('id'));

		//remove previous content
		select.remove();

		//because we want to do some fancy css stuff to the bg
		dropdown.on('Change', function(data){
			var option = data.option;

			//hack because dropdown.text.css({ ... }) doesn't work properly??
			var textbox = option.parent().prev().prev();
			textbox.css({
				"background-color": option.css("background-color"),
				"color": option.css('color')
			});
		});

		//go through and add the colours to our custom
		for(id = 0; id < colours.length; ++id){
			var
				name = colours[id][0],
				rgb = colours[id][1],
				v = getV(rgb);

			titleize(dropdown, name);

			//add our option
			dropdown
				.addOption({
					value: id,
					text: name
				})
				.css({
					'background-color': "rgb("+rgb+")",
					'color': (v < 50 ? "#fff" : "#000")
				});
		}
	}
}

//this code adds headers to the select boxes, so we know what it's classed as
function titleize(dropdown, name){
	switch(name){
		case "Zinnia Red": var text = "BRIGHT COLOURS"; break;
		case "Coral": var text = "DARK PASTEL"; break;
		case "Salmon": var text = "PASTEL COLOURS"; break;
		case "Rose Quartz": var text = "PALE COLOURS"; break;
		case "White": var text = "GREYSCALE COLOURS"; break;
		case "Garnet": var text = "DARK COLOURS"; break;
		case "Cinnamon": var text = "MIDDLE COLOURS"; break;
		case "Dusty Rose": var text = "UNSATURATED COLOURS"; break;
		case "Blood": var text = "RICH COLOURS"; break;
	}

	//if we have a title, put it in
	if(text){
		dropdown.addOption({
			text: text,
			unselectable: true
		});
	}
}

//'nother mac fix...
function overrideBehaviour(){
	//change some styling
	$('#petgencont').css('position', 'relative');
	//hack by removing the default behaviour
	$('#continue input[type="button"]')
		.attr('onclick', "")
		//add our own overriding functionality
		.on('click', function(){
			
			//first, get the pet image
			$('#petgencont').fadeOut(200, function() {
				$.ajax({
					url: 'index.php/create/genpet',
					type: 'GET',
					data: {
						'baseid' :  $('#bases').val(),
						'eyeid' : $('#eyes').val(),
						'speciesid' : $('#species').val(),
						'shading_color' : $('#shading_color').val(),
						'highlight_color' : $('#highlight_color').val(),
						'lineart_color' : $('#lineart_color').val(),
						'markingid' : $('#markings').val(),
						'marking_color' : $('#marking_color').val(),
						'dyn_color' : $('#dyn').val(),
						//CH doesn't understand true/false
						'apply_dyn' : ($('#apply_dyn').prop("checked") ? 1 : 0),
						//CH doesn't use this, but we might as well keep it in 
						//for future-proofing
						'gender': $('input[name=gender]:checked').val()
					},
					success: function(msg) {
						//replace the content
						$('#petgencont').html(msg.replace("index.php/", "")).delay(500);
						$('#petgencont').fadeIn(200);

						//now add any overlays. line by line
						if($('#ace-overlays').val().length > 0){
						var overlays = $('#ace-overlays').val().split("\n");
						for(i = 0; i < overlays.length; ++i){
							var overlayURL = overlays[i];
							$("<img src='"+overlayURL+"' class='ace-overlay' />").appendTo($('#petgencont'));
						}
						}
					}
				});
			});
			

		});
}

function addOverlaysBox(){
	var row = $("<div class='align-center'>Add things (such as accessories or dyes) here. It must be an image URL. Separate each URL by a new line. Make sure each one is the same dimensions as the pet image.<br /></div>").insertBefore($('#continue'));
	var textarea = $("<textarea id='ace-overlays' cols='50' rows='5'></textarea>").appendTo(row);
}


//run app
customDropDowns();
addOverlaysBox();
overrideBehaviour();
});