text: //#include include/shrines.js, include/npc_quests.js, include/npc_conversation.js, include/npc_ai.js, include/events.js
  
  var label = "Shrine to Friendly";
  var version = "1351536731";
  var name_single = "Shrine to Friendly";
  var name_plural = "Shrines to Friendly";
  var article = "a";
  var description = "This is a shrine to Friendly, the giant who oversees all things celestial, nocturnal, lunar, stygian and murky. Despite this, he is, as his name implies, considered by many to be the nicest of the giants and the one most likely to loan you twenty currants till payday.";
  var is_hidden = false;
  var has_info = true;
  var has_infopage = true;
  var proxy_item = "npc_shrine_friendly";
  var is_routable = false;
  var adjusted_scale = 1;
  var stackmax = 1;
  var base_cost = 0;
  var input_for = [];
  var parent_classes = ["npc_shrine_ix_friendly", "npc_shrine_friendly", "npc_shrine_base", "npc"];
  var has_instance_props = true;
  
  var classProps = {
  	"got_quest_text"	: "I've got something for you...",	// defined by npc
  	"no_quest_text"	: ""	// defined by npc
  };
  
  function initInstanceProps(){
  	this.instanceProps = {};
  	this.instanceProps.ai_debug = "0";	// defined by npc
  }
  
  var instancePropsDef = {
  	ai_debug : ["Turn on ai debugging for this instance"],
  };
  
  var instancePropsChoices = {
  	ai_debug : [""],
  };
  
  var verbs = {};
  
  verbs.debug = { // defined by npc
  	"name"				: "debug",
  	"ok_states"			: ["in_location"],
  	"requires_target_pc"		: false,
  	"requires_target_item"		: false,
  	"include_target_items_from_location"		: false,
  	"is_default"			: false,
  	"is_emote"			: false,
  	"sort_on"			: 10,
  	"tooltip"			: "",
  	"get_tooltip"			: function(pc, verb, effects){
  
  		if (this.debugging === undefined || this.debugging == false) {
  			return "ADMIN ONLY: Turn on debug displays for this NPC.";
  		}
  		else {
  			return "ADMIN ONLY: Turn off debug displays for this NPC.";
  		}
  	},
  	"is_drop_target"		: false,
  	"conditions"			: function(pc, drop_stack){
  
  		if (pc.is_god) { return {state:'enabled'} };
  
  		// Do not show this for non-devs:
  		return {state:null};
  	},
  	"handler"			: function(pc, msg, suppress_activity){
  
  		var failed = 0;
  		var orig_count = this.count;
  		var self_msgs = [];
  		var self_effects = [];
  		var they_effects = [];
  
  		 
  		if (this.debugging === undefined) {
  			this.debugging = true;
  		}
  		else {
  			this.debugging = !(this.debugging);
  		}
  
  		this.target_pc = pc;
  
  		if (this.debugging) {
  			var pre_msg = this.buildVerbMessage(msg.count, 'debug', 'are debugging', failed, self_msgs, self_effects, they_effects);	
  		}
  		else {
  			var pre_msg = this.buildVerbMessage(msg.count, 'debug', 'stopped debugging', failed, self_msgs, self_effects, they_effects);	
  		}
  
  		if (!suppress_activity && pre_msg) pc.sendActivity(pre_msg);
  
  		return failed ? false : true;
  	}
  };
  
  verbs.give_cubimal = { // defined by npc
  	"name"				: "Give a cubimal to",
  	"ok_states"			: ["in_location"],
  	"requires_target_pc"		: false,
  	"requires_target_item"		: false,
  	"include_target_items_from_location"		: false,
  	"is_default"			: false,
  	"is_emote"			: false,
  	"sort_on"			: 50,
  	"tooltip"			: "",
  	"get_tooltip"			: function(pc, verb, effects){
  
  		return 'Give '+this.label+' a cubimal likeness';
  	},
  	"is_drop_target"		: false,
  	"conditions"			: function(pc, drop_stack){
  
  		var cubimal = this.hasCubimal();
  
  		if (!cubimal) return {state: null};
  
  		if (pc.getQuestStatus('mini_me_mini_you') != 'todo') return {state: null};
  
  		if (pc.counters_get_label_count('npcs_given_cubimals', cubimal)) return {state:'disabled', reason: "You already gave away a "+this.label+" cubimal"}
  
  		if (!pc.findFirst(cubimal)) return {state:'disabled', reason: "You don't have a cubimal of "+this.label};
  
  		return {state: 'enabled'};
  	},
  	"handler"			: function(pc, msg, suppress_activity){
  
  		var failed = 0;
  		var orig_count = this.count;
  		var self_msgs = [];
  		var self_effects = [];
  		var they_effects = [];
  
  		var cubimal = this.hasCubimal();
  		var stack = null;
  
  		if (!cubimal){
  			failed = 1;
  		} else {
  			stack = pc.findFirst(cubimal);
  		}
  
  		var responses = [
  		'Pour moi? How kind of you! I feel all fluttery inside!',
  		'Oh yes, this is very handsome. Thank you so much!',
  		'A passable likeness. Always nice to know that someone is thinking of little old me!',
  		'Well what have we here? It\'s a bit... square. But it captures the essence, doesn\'t it?',
  		'Cubimals are my favorite! And this one is my favoritest favorite!',
  		'I shall carry it with me always, and cherish the memory of your kindness'
  		];
  
  
  		if (stack){
  			var item = pc.removeItemStack(stack.path);
  			item.apiDelete();
  			this.sendBubble(choose_one(responses), 10000, pc);
  			pc.counters_increment('npcs_given_cubimals', cubimal);
  			pc.quests_inc_counter('npcs_given_cubimals', 1);
  		} else {
  			failed = 1;
  		}
  
  
  		var pre_msg = this.buildVerbMessage(msg.count, 'Give a cubimal to', 'Gave a cubimal to', failed, self_msgs, self_effects, they_effects);
  		if (!suppress_activity && pre_msg) pc.sendActivity(pre_msg);
  
  		return failed ? false : true;
  	}
  };
  
  verbs.prime = { // defined by npc_shrine_base
  	"name"				: "prime",
  	"ok_states"			: ["in_location"],
  	"requires_target_pc"		: false,
  	"requires_target_item"		: false,
  	"include_target_items_from_location"		: false,
  	"is_default"			: false,
  	"is_emote"			: false,
  	"sort_on"			: 51,
  	"tooltip"			: "Prime the shrine as a weapon against the rook. Costs $energy_cost energy",
  	"is_drop_target"		: false,
  	"conditions"			: function(pc, drop_stack){
  
  		if (!pc.skills_has('piety_1')) {
  			if (this.container.isRooked()) {
  				return {state:'disabled', reason: "You need to know Piety I to prime Shrines during Rook Attacks."};
  			}
  			else { 
  				return {state: null};
  			}
  
  			return {state:null};
  		}
  		if (!this.container.isRooked()) {
  			return {state: 'disabled', reason: "You can prime a shrine only in the presence of enemies of imagination."};
  		}
  		if (!this.container.canAttack()) {
  			return {state: 'disabled', reason: "You must stun the Rook using your Focusing Orb before it is vulnerable to shrine attacks."};
  		}
  
  		return {state: 'enabled'};
  	},
  	"effects"			: function(pc){
  
  		return {energy_cost: 10};
  	},
  	"handler"			: function(pc, msg, suppress_activity){
  
  		var failed = 0;
  		var orig_count = this.count;
  		var self_msgs = [];
  		var self_effects = [];
  		var they_effects = [];
  
  		var energy_loss = 10;
  		if (pc.buffs_has('rook_armor')) energy_loss = energy_loss / 2;
  
  		if(pc.metabolics_get_energy() <= energy_loss) {
  			pc.sendActivity("You don't have enough energy to do that!");
  			return;
  		}
  
  		this.primeStart(pc);
  
  		var val = pc.metabolics_lose_energy(energy_loss);
  		if(val) {
  			self_effects.push({
  				'type': 'metabolic_dec',
  				'which': 'energy',
  				'value': val
  			});
  		}
  
  		var pre_msg = this.buildVerbMessage(msg.count, 'prime', 'primed', failed, self_msgs, self_effects, they_effects);
  		if (!suppress_activity && pre_msg) pc.sendActivity(pre_msg);
  
  		return failed ? false : true;
  	}
  };
  
  verbs.talk_to = { // defined by npc_shrine_base
  	"name"				: "talk to",
  	"ok_states"			: ["in_location"],
  	"requires_target_pc"		: false,
  	"requires_target_item"		: false,
  	"include_target_items_from_location"		: false,
  	"is_default"			: false,
  	"is_emote"			: false,
  	"sort_on"			: 52,
  	"tooltip"			: "I have something to tell you!",
  	"is_drop_target"		: false,
  	"conditions"			: function(pc, drop_stack){
  
  		var convos = pc.conversations_offered_for_item(this);
  		if (convos.length) return {state:'enabled'};
  
  		return {state:null};
  	},
  	"handler"			: function(pc, msg, suppress_activity){
  
  		var failed = 1;
  		var orig_count = this.count;
  		var self_msgs = [];
  		var self_effects = [];
  		var they_effects = [];
  
  		var convos = pc.conversations_offered_for_item(this);
  		for (var i=0; i<convos.length; i++){
  			var conversation_runner = "conversation_run_"+convos[i];
  			if (this[conversation_runner]){
  				failed = 0;
  				this[conversation_runner](pc, msg);
  				break;
  			}
  		}
  
  		var pre_msg = this.buildVerbMessage(msg.count, 'talk to', 'talked to', failed, self_msgs, self_effects, they_effects);
  		if (!suppress_activity && pre_msg) pc.sendActivity(pre_msg);
  
  		return failed ? false : true;
  	}
  };
  
  verbs.donate_to = { // defined by npc_shrine_base
  	"name"				: "donate to",
  	"ok_states"			: ["in_location"],
  	"requires_target_pc"		: false,
  	"requires_target_item"		: true,
  	"include_target_items_from_location"		: false,
  	"is_default"			: false,
  	"is_emote"			: false,
  	"sort_on"			: 53,
  	"tooltip"			: "Or, drag item to shrine",
  	"get_tooltip"			: function(pc, verb, effects){
  
  		var t = verb.tooltip;
  
  		if (config.is_dev) {
  			t += this.getFavorText(pc);
  		}
  
  		if (pc.buffs_has('extremely_hallowed')){
  			t += ' <b>Triple rewards!</b>';
  		}
  
  		if (pc.buffs_has('fairly_hallowed')){
  			t += ' <b>Double rewards!</b>';
  		}
  
  		return t;
  	},
  	"is_drop_target"		: true,
  	"drop_many"			: false,
  	"drop_tip"			: "Donate {$stack_name} to {$item_name}",
  	"drop_ok_code"			: function(stack, pc){
  
  		if(this.primed) {
  			var emblem_name = 'emblem_'+this.get_giant();
  			
  			// If we have been primed, allow our own emblems.
  			if ((!stack.is_bag && !stack.hasTag('emblem') && !stack.hasTag('machine') && !stack.hasTag('no_donate')) || (stack.class_tsid == emblem_name)){
  				return true;
  			}
  		} else {
  			if (!stack.is_bag && !stack.hasTag('emblem') && !stack.hasTag('machine')){ // No bags, no emblems, no machines
  				return true;
  			}
  		}
  
  		return false;
  	},
  	"conditions"			: function(pc, drop_stack){
  
  		if(this.container.isRooked()) {
  			if(!this.container.canAttack()) {
  				return {state: 'disabled', reason: "Interference from the Rook is blocking donations."};
  			} else if (!this.primed) {
  				return {state: 'disabled', reason: "This shrine must be primed in order to attack the Rook."};
  			} else {
  				return {state: 'enabled'};
  			}
  		} else {
  			var giant = this.get_giant();
  			if (pc.stats_has_favor_points(giant, pc.stats_get_max_favor(giant))){ 
  				return {state: 'disabled', reason: "Pick up your emblem first."};
  			}
  			else {
  				return {state: 'enabled'};
  			}
  		}
  	},
  	"requires_target_item_count"	: true,
  	"choices_are_stacks"	: false,
  	"valid_items"		: function(pc){
  
  		var uniques = {};
  		var items = pc.apiGetAllItems();
  		for (var i in items){
  			var it = items[i];
  			if(this.primed) {
  				var emblem_name = 'emblem_'+this.get_giant();
  			
  				// If we have been primed, allow our own emblems.
  				if ((!it.is_bag && !it.hasTag('emblem') && !it.hasTag('machine') && !it.hasTag('no_donate')) || (it.class_tsid == emblem_name)){ // No bags, no emblems, no machines
  					uniques[it.class_tsid] = it.tsid;
  				}
  			} else {
  				if (!it.is_bag && !it.hasTag('emblem') && !it.hasTag('machine')){ // No bags, no emblems, no machines
  					uniques[it.class_tsid] = it.tsid;
  				}
  			}
  		}
  
  		var possibles = [];
  		for (var i in uniques){
  			possibles.push(i);
  		}
  
  		if (possibles.length){
  			return {
  				'ok' : 1,
  				'choices' : possibles,
  			};
  		}else{
  			pc.sendActivity("You don't have anything the "+this.name_single+" wants!");
  			return {
  				'ok' : 0,
  				'txt' : "You don't have anything the "+this.name_single+" wants!",
  			};
  		}
  	},
  	"handler"			: function(pc, msg, suppress_activity){
  
  		if(this.container.isRooked()) {
  			if(!this.container.canAttack()) {
  				pc.sendActivity("Interference from the Rook prevents your donation.");
  				return false;
  			} else if (!this.primed) {
  				pc.sendActivity("The shrine must be primed before you can attack the Rook.");
  				return false;
  			} else {
  				return this.shrineAttack(pc,msg);
  			}
  		} else {
  			this.conversation_end(pc, msg);
  			return this.evalDonate(pc, msg);
  		}
  	}
  };
  
  verbs.get_emblem = { // defined by npc_shrine_base
  	"name"				: "get emblem",
  	"ok_states"			: ["in_location"],
  	"requires_target_pc"		: false,
  	"requires_target_item"		: false,
  	"include_target_items_from_location"		: false,
  	"is_default"			: false,
  	"is_emote"			: false,
  	"sort_on"			: 54,
  	"tooltip"			: "Retrieve your emblem",
  	"is_drop_target"		: false,
  	"conditions"			: function(pc, drop_stack){
  
  		var giant = this.get_giant();
  
  		if (pc.stats_has_favor_points(giant, pc.stats_get_max_favor(giant))){
  			var temp = apiNewItemStack('emblem_'+giant, 1);
  			if (pc.isBagFull(temp)){
  				temp.apiDelete();
  				return {state:'disabled', reason: "Your inventory is full!"};
  			}
  
  			temp.apiDelete();
  
  			if(this.container.isRooked()) {
  				return {state: 'disabled', reason: "The Rook is interfering with Shrine activity."};
  			}
  			return {state:'enabled'};
  		}
  		else{
  			return {state:null};
  		}
  	},
  	"handler"			: function(pc, msg, suppress_activity){
  
  		var failed = 0;
  		var orig_count = this.count;
  		var self_msgs = [];
  		var self_effects = [];
  		var they_effects = [];
  
  		var failed = !this.give_emblem(pc);
  
  		var pre_msg = this.buildVerbMessage(msg.count, 'get an emblem from', 'got an emblem from', failed, self_msgs, self_effects, they_effects);
  		if (!suppress_activity && pre_msg) pc.sendActivity(pre_msg);
  
  		return failed ? false : true;
  	}
  };
  
  verbs.check_favor = { // defined by npc_shrine_base
  	"name"				: "check favor",
  	"ok_states"			: ["in_location"],
  	"requires_target_pc"		: false,
  	"requires_target_item"		: false,
  	"include_target_items_from_location"		: false,
  	"is_default"			: false,
  	"is_emote"			: false,
  	"sort_on"			: 55,
  	"tooltip"			: "View & spend favor points",
  	"is_drop_target"		: false,
  	"disable_proximity"		: true,
  	"conditions"			: function(pc, drop_stack){
  
  		var giant = this.get_giant();
  
  		if (pc.stats_has_favor_points(giant, pc.stats_get_max_favor(giant))){
  			return {state:null};
  		}
  		else{
  			if(this.container.isRooked()) {
  				return {state: 'disabled', reason: "The Rook is interfering with Shrine activity."};
  			}
  			return {state:'enabled'};
  		}
  	},
  	"handler"			: function(pc, msg, suppress_activity){
  
  		this.check_favor(pc);
  		return true;
  	}
  };
  
  function getFavorText(pc){ // defined by npc_shrine_base
  	var text = "";
  
  	if (pc) { 
  		var giant = this.get_giant();
  		var points = pc.stats_get_favor_points(giant);
  		var max = pc.stats_get_max_favor(giant);
  
  		log.info("SHRINE: doing getFavorText,  max is "+max+" for giant "+giant);
  
  		text += " Current favor: "+points+"/"+max;
  	}
  
  
  	return text;
  }
  
  function onConversation(pc, msg){ // defined by npc_shrine_base
  	var conversation_runner = "conversation_run_"+msg.choice.split('-')[0];
  	if (this[conversation_runner]) return this[conversation_runner](pc, msg);
  
  	if (msg.choice == "yes"){
  		this.doDonate(pc, this.pendingDonations[pc.tsid]);
  	}
  	else if (msg.choice === "giveEmblem") {
  		this.give_emblem(pc);
  		this.setAndBroadcastState('close');
  	}
  	else{
  		this.setAndBroadcastState('close');
  	}
  
  	if (this.pendingDonations && this.pendingDonations[pc.tsid]) { 
  		delete this.pendingDonations[pc.tsid];
  	}
  
  	this.conversation_end(pc, msg);
  }
  
  function onCreate(){ // defined by npc_shrine_base
  	this.initInstanceProps();
  	this.dir = 'right';
  	this.apiSetHitBox(400, 400);
  	this.apiAddHitBox("emblem", 200, 400);
  	this.apiSetPlayersCollisions(true);
  	this.default_state = 'closed';
  	this.setAndBroadcastState('close');
  	this.initInstanceProps();
  	this.fsm_init();
  }
  
  function onLoad(){ // defined by npc_shrine_base
  	this.apiSetHitBox(400, 400);
  	this.apiSetPlayersCollisions(true);
  	this.dir = 'right';
  
  	this.apiRemoveHitBox("emblem");
  	this.apiAddHitBox("emblem", 400, 400);
  }
  
  function onOverlayClicked(pc, payload){ // defined by npc_shrine_base
  	if(this.primed) {
  		// Stub for now. Do nothing.
  	} else {
  		this.primeStart(pc);
  		return true;
  	}
  }
  
  function onPlayerCollision(pc, hitbox){ // defined by npc_shrine_base
  	if (config.is_dev) log.info(this+' collided with '+pc);
  
  	if (pc.getQuestStatus('donate_to_all_shrines') == 'none' && !pc.shrine_announced){
  		if (!pc.shrines_passed) pc.shrines_passed = {};
  		if (!pc.shrines_passed[this.tsid]) pc.shrines_passed[this.tsid] = 0;
  		pc.shrines_passed[this.tsid]++;
  
  		if (utils.lengthOfObj(pc.shrines_passed) == 3){
  			pc.announce_vog_fade("Lo, a shrine to "+capitalize(this.get_giant())+"//Try donating something.");
  			pc.shrine_announced = true;
  			return;
  		}
  	}
  	else if (this.get_giant() == 'grendaline' && pc.getQuestStatus('donate_to_all_shrines') == 'done' && pc.getQuestStatus('last_pilgrimage_of_esquibeth') == 'none'){
  		
  		var donate_to_all_shrines = pc.getQuestInstance('donate_to_all_shrines');
  		if (donate_to_all_shrines && donate_to_all_shrines.ts_done && time() - donate_to_all_shrines.ts_done >= 30*60) pc.quests_offer('last_pilgrimage_of_esquibeth');
  	}
  
  	if (this.conversations){
  		for (var i=0; i<this.conversations.length; i++){
  			if (pc.conversations_offer(this, this.conversations[i])){
  				return pc.conversations_offer_bubble(this);
  			}
  		}
  	}
  
  	if ( hitbox === "emblem"){
  		var giant = this.get_giant();
  
  		if (pc.stats_has_favor_points(giant, pc.stats_get_max_favor(giant))){
  			var temp = apiNewItemStack('emblem_'+giant, 1);
  			if (pc.isBagFull(temp)){
  				temp.apiDelete();
  				this.sendBubble("I have an Emblem for you, but your pack is full. Free up some space to get it!", 3000, pc);
  				return;
  			}
  
  			temp.apiDelete();
  
  			this.give_emblem(pc);
  		}
  	}
  }
  
  function onPlayerExit(pc){ // defined by npc_shrine_base
  	this.npc_onPlayerExit(pc);
  
  	if(this.primed && pc == this.priming_pc) {
  		this.primeComplete();
  	}
  }
  
  function onPrototypeChanged(){ // defined by npc_shrine_base
  	this.onLoad();
  }
  
  function checkWaiting(){ // defined by npc
  	if (!this.isWaiting) return;
  	if (!this.container) this.apiSetTimer('checkWaiting', 1000);
  
  	//
  	// remove any keys we can, because user has logged off, or is far away
  	//
  
  	if (this.waitingFor.__iterator__ == null) delete this.waitingFor.__iterator__;
  	for (var i in this.waitingFor){
  		if (!this.container.activePlayers) continue;
  
  		var pc = this.container.activePlayers[i];
  		if (pc){
  			if (this.distanceFromPlayer(pc) > config.verb_radius){
  				delete this.waitingFor[i];
  			}
  		}else{
  			delete this.waitingFor[i];
  		}
  	}
  
  
  	//
  	// done waiting?
  	//
  
  	if (!num_keys(this.waitingFor)){
  		this.isWaiting = 0;
  		if (this.onWaitEnd) this.onWaitEnd();
  	}else{
  		this.apiSetTimer("checkWaiting", 1000);
  	}
  }
  
  function clearMovementLimits(){ // defined by npc
  	delete this.move_limits;
  }
  
  function fullStop(){ // defined by npc
  	this.apiStopMoving();
  	this.apiCancelTimer('startMoving');
  }
  
  function hasCubimal(){ // defined by npc
  	var cubimal_map = {
  		hell_bartender:					'npc_cubimal_hellbartender',
  		npc_batterfly:					'npc_cubimal_batterfly',
  		npc_bureaucrat:				'npc_cubimal_bureaucrat',
  		npc_butterfly:					'npc_cubimal_butterfly',
  		npc_cactus:					'npc_cubimal_cactus',
  		npc_cooking_vendor:			'npc_cubimal_mealvendor',
  		npc_crab:						'npc_cubimal_crab',
  		npc_crafty_bot:					'npc_cubimal_craftybot',
  		npc_deimaginator:				'npc_cubimal_deimaginator',
  		npc_firefly:					'npc_cubimal_firefly',
  		npc_fox:						'npc_cubimal_fox',
  		npc_fox_ranger:				'npc_cubimal_foxranger',
  		npc_garden_gnome:				'npc_cubimal_gnome',
  		npc_gardening_vendor:			'npc_cubimal_gardeningtoolsvendor',
  		npc_gwendolyn:				'npc_cubimal_gwendolyn',
  		npc_jabba2:					'npc_cubimal_helga',
  		npc_jabba1:					'npc_cubimal_unclefriendly',
  		npc_juju_black:					'npc_cubimal_juju',
  		npc_juju_green:				'npc_cubimal_juju',
  		npc_juju_red:					'npc_cubimal_juju',
  		npc_juju_yellow:				'npc_cubimal_juju',
  		npc_maintenance_bot:			'npc_cubimal_maintenancebot',
  		npc_newxp_dustbunny:			'npc_cubimal_dustbunny',
  		npc_piggy:					'npc_cubimal_piggy',
  		npc_piggy_explorer:				'npc_cubimal_ilmenskiejones',
  		npc_quest_giver_widget: 			'npc_cubimal_greeterbot',
  		npc_rube:						'npc_cubimal_rube',
  		npc_sloth:						'npc_cubimal_sloth',
  		npc_smuggler:					'npc_cubimal_smuggler',
  		npc_sno_cone_vending_machine:	'npc_cubimal_snoconevendor',
  		npc_squid:					'npc_cubimal_squid',
  		npc_tool_vendor:				'npc_cubimal_toolvendor',
  		npc_yoga_frog:					'npc_cubimal_frog',
  		phantom_glitch:				'npc_cubimal_phantom',
  		street_spirit_firebog:				'npc_cubimal_firebogstreetspirit',
  		street_spirit_groddle:			'npc_cubimal_groddlestreetspirit',
  		street_spirit_zutto:				'npc_cubimal_uraliastreetspirit'
  	};
  
  	return cubimal_map[this.class_id];
  }
  
  function onInteractionEnding(pc){ // defined by npc
  	this.fsm_event_notify('interaction_ending', pc);
  	if (this.waitingFor){
  		delete this.waitingFor[pc.tsid];
  	}
  	this.checkWaiting();
  }
  
  function onInteractionInterval(pc, interval){ // defined by npc
  	this.onInteractionStarting(pc);
  	this.events_add({callback: 'onInteractionIntervalEnd', pc: pc}, interval);
  }
  
  function onInteractionIntervalEnd(details){ // defined by npc
  	if (details.pc) {
  		this.onInteractionEnding(details.pc);
  	}
  }
  
  function onInteractionStarting(pc, mouseInteraction){ // defined by npc
  	this.fsm_event_notify('interaction_starting', pc);
  	if (!this.waitingFor) this.waitingFor = {};
  	this.waitingFor[pc.tsid] = 1;
  	if (!this.isWaiting){
  		this.isWaiting = 1;
  		if (this.onWaitStart) this.onWaitStart(pc, mouseInteraction);
  		this.apiSetTimer("checkWaiting", 1000);
  	}
  }
  
  function onPathing(args){ // defined by npc
  	this.fsm_event_notify('pathing', args);
  }
  
  function npc_onPlayerCollision(pc){ // defined by npc
  	apiResetThreadCPUClock();
  	this.fsm_event_notify('player_collision', pc);
  	apiResetThreadCPUClock("onPlayerCollision_"+this.class_tsid);
  }
  
  function onPlayerEnter(pc){ // defined by npc
  	this.fsm_event_notify('player_enter', pc);
  
  	if (this.pathfinding_paused) this.startMoving();
  }
  
  function npc_onPlayerExit(pc){ // defined by npc
  	this.fsm_event_notify('player_exit', pc);
  }
  
  function onWaitEnd(){ // defined by npc
  	this.fsm_event_notify('wait_end', null);
  }
  
  function onWaitStart(pc){ // defined by npc
  	this.fsm_event_notify('wait_start', pc);
  }
  
  function setMovementLimits(x_pos, y_pos, width){ // defined by npc
  	this.move_limits = {x:x_pos, y:y_pos, w:width};
  
  	//log.info("move_limits is "+this.move_limits);
  }
  
  function conversation_canoffer_from_the_books_of_the_giants_3(pc){ // defined by conversation auto-builder for "from_the_books_of_the_giants_3"
  	var chain = {
  		id: "from_the_books_of_the_giants",
  		level: 3,
  		max_level: 3
  	};
  	if (!pc.conversations_can_do_chain(chain)) return false;
  
  	if (pc.conversations_has_completed(null, "from_the_books_of_the_giants_2")){
  		return true;
  	}
  	return false;
  }
  
  function conversation_run_from_the_books_of_the_giants_3(pc, msg, replay){ // defined by conversation auto-builder for "from_the_books_of_the_giants_3"
  	if (!msg.count) msg.count = 1;
  	var self_effects = [];
  	var conversation_id = "from_the_books_of_the_giants_3";
  	var conversation_title = "From the Books of the Giants";
  	var chain = {
  		id: "from_the_books_of_the_giants",
  		level: 3,
  		max_level: 3
  	};
  	var choices = {};
  
  	choices['0'] = {};
  	choices['1'] = {};
  	choices['2'] = {};
  	choices['3'] = {};
  	choices['4'] = {};
  	choices['5'] = {};
  	choices['6'] = {};
  	if (!msg.choice){
  		choices['0']['from_the_books_of_the_giants_3-0-2'] = {txt: "Alertity: On.", value: 'from_the_books_of_the_giants_3-0-2'};
  		this.conversation_start(pc, "Par-parrrrrrrp. Silence and alertity, Little Child of Friendly, for your daily proverb from the Epic of Friendly.", choices['0'], null, null, null, {title: conversation_title});
  		pc.conversations_set_current_state(this.tsid, 'from_the_books_of_the_giants_3', msg.choice);
  	}
  
  	if (msg.choice == "from_the_books_of_the_giants_3-0-2"){
  		choices['1']['from_the_books_of_the_giants_3-1-2'] = {txt: "What?", value: 'from_the_books_of_the_giants_3-1-2'};
  		this.conversation_reply(pc, msg, "\"Proverb 4,8: 15 - When two friends meet together, at night, in the shadow of the rook, the one bearing the greatest booze-concoction shall triumph...\"", choices['1'], null, null, null, {title: conversation_title});
  		pc.conversations_set_current_state(this.tsid, 'from_the_books_of_the_giants_3', msg.choice);
  	}
  
  	if (msg.choice == "from_the_books_of_the_giants_3-1-2"){
  		choices['2']['from_the_books_of_the_giants_3-2-2'] = {txt: "Huh?", value: 'from_the_books_of_the_giants_3-2-2'};
  		this.conversation_reply(pc, msg, "\"...The other will be called “He who smells of very stinky cheese” by all who meet him.\"", choices['2'], null, null, null, {title: conversation_title});
  		pc.conversations_set_current_state(this.tsid, 'from_the_books_of_the_giants_3', msg.choice);
  	}
  
  	if (msg.choice == "from_the_books_of_the_giants_3-2-2"){
  		choices['3']['from_the_books_of_the_giants_3-3-2'] = {txt: "But...", value: 'from_the_books_of_the_giants_3-3-2'};
  		this.conversation_reply(pc, msg, "“Also: never trust Zillots.”", choices['3'], null, null, null, {title: conversation_title});
  		pc.conversations_set_current_state(this.tsid, 'from_the_books_of_the_giants_3', msg.choice);
  	}
  
  	if (msg.choice == "from_the_books_of_the_giants_3-3-2"){
  		choices['4']['from_the_books_of_the_giants_3-4-2'] = {txt: "But what did she SAY?", value: 'from_the_books_of_the_giants_3-4-2'};
  		this.conversation_reply(pc, msg, "Friendly has spoken.", choices['4'], null, null, null, {title: conversation_title});
  		pc.conversations_set_current_state(this.tsid, 'from_the_books_of_the_giants_3', msg.choice);
  	}
  
  	if (msg.choice == "from_the_books_of_the_giants_3-4-2"){
  		choices['5']['from_the_books_of_the_giants_3-5-2'] = {txt: "You’re annoying.", value: 'from_the_books_of_the_giants_3-5-2'};
  		this.conversation_reply(pc, msg, "End of proverb. Parrr-parrrrrrrp.", choices['5'], null, null, null, {title: conversation_title});
  		pc.conversations_set_current_state(this.tsid, 'from_the_books_of_the_giants_3', msg.choice);
  	}
  
  	if (msg.choice == "from_the_books_of_the_giants_3-5-2"){
  		pc.conversations_complete(this.class_tsid, conversation_id, chain);
  		this.conversation_end(pc, msg);
  		pc.conversations_clear_current_state();
  	}
  
  }
  
  var conversations = [
  	"from_the_books_of_the_giants_3",
  ];
  
  function getDescExtras(pc){
  	var out = [];
  	return out;
  }
  
  var tags = [
  	"shrine",
  	"no_trade"
  ];
  
  var responses = {
  	"donated_item_tier1": [
  		"C'mon, really?!?",
  		"Not so hot.",
  		"This verges on negligible.",
  		"Friendly thought you were a better Friend than this.",
  		"This is weak. Like bad, bad hooch.",
  	],
  	"donated_item_tier2": [
  		"Passable.",
  		"Hm. Other glitches are nicer, you know.",
  		"See where you're coming from, friend. But bigger is better.",
  		"Friends don't let Friends give mediocre donations.",
  		"This? It is the warm cheap beer of donations.",
  	],
  	"donated_item_tier3": [
  		"Getting there.",
  		"Other glitches could learn a thing from you.",
  		"Friendly feels friendly.",
  		"For this, Friendly will raise a glass in your honour.",
  		"This is an act of glorious altruism.",
  	],
  	"donated_item_tier4": [
  		"YES, Friend. This is more like it.",
  		"Now we're talking. Now this is a party.",
  		"Friendly will remember you fondly and often for this.",
  		"Hot stuff, little Friend.",
  		"Friendly will drink to you. Heavily.",
  	],
  	"super_donation_20x_xp": [
  		"Drinks are on Friendly. Metaphorical drinks.",
  		"Yes! Party like it is Year 19, little Friend.  Or Year 9999! Whatever!",
  		"A toast! A toast to you, firm friend of Friendly.",
  	],
  	"super_donation_5x_xp": [
  		"A little extra in your glass of life.",
  		"An extra pour for you.",
  		"A little chaser for your generosity.",
  	],
  };
  
  // this is a temporary fix, while the client doesn't load item defs
  // from the XML files. we pass this data on login events.
  
  function getAssetInfo(){
  	return {
  		'position': {"x":-84,"y":-216,"w":169,"h":216},
  		'thumb': "iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM\/rhtAAAHx0lEQVR42s2Y2VNTWR7H\/QOminnp\neZgXn\/qlZ2qYpym7um1c2xkBIyiJrGFXZEcg7EkIgUAS0hACshkXVNotgLK4wEUkKggkhBDAANER\nWgQhrIozD9+55yJx7a6ZTDLTt+pbN4ST3\/2c3zm\/5dwtW\/4P12R9reuoSha\/5dd4ETijQmwdKhTw\nf81wGKmQqx1iFBMTLkSOsEW8RuCIxs9VUuS7Pp9Il+fX8rnmYh7LbqNPNBd1joDUS7I1Q1Ih9MIM\njNfILAMnoqmhrATo4o7btx8nJBKXwQK+dbhYjLEapcZeMOIlkzAx3pCVaNWnxKA\/NgqdAVzcDQgm\nsn8v9ooy4jeXZPTkD5afG2eS7dpqKNrptqmZa5ms6R9FfENWAtUbGWl9EBGBB9wwdAeG2HSP1n1u\nqJXA2wXXExDqapDwqLGSHIyV8mGuyIOlOotPNFGarjCJkykC0BPPoh5m\/gX6vG9hkHlCL\/WiJ+OP\nu+G+uOMXxIjAbao5OomBY\/4OCuPa7T2tX9jWzQd8TpQ\/Fw\/DuRjI24lnyt2wXjiMxYZgPK87Ap1g\nGx5XRTEg2qBQ5k6Wk9x7jkZBm5SIvuho++Gucziu7X5cCzFOZno9Po0B2vRCJ\/0wIm3sHjyp9cZM\n+T7o+Cw8Pe2PYWUwltpPQCf5Hi2RLEut50HNqQNe3FJvz21NccdxKTwEzalJsBvujKcXizZqbT0S\ngCa2Lxp8NnSD4wfy3XW2H+q9fRh1xHyD2frDmFZ9j65ED4yUHqE9GojVe2kwVx+C+cy7AOhIT3Tr\nLeBjsEgI89lKi8OS640TsVRTzFFcigzD5cjwDyLuVsSX1EztfsxX74Mp\/yA6ErwYwKlL8QzgaBXH\nlj4MRUI3ozQXRrkIj9UqymGAnZnJikf0zPuKctGTk\/oB4BX333JN0h2wyPfDLPPCuNIPLxujMN8W\nB12BG0h0b45tz0pmkrRRJsLTxouOK3P3hLx4U2khRiuKYSqTfjLzztg\/arTJf8az82xM1Qdg4pQP\nenO+thqkOz+oDD2iDAbQVCKhq0iV4xqFjuwUt5EyKUiypmf\/2aVp5vye1ej9Oz51\/CtGJBd+POaR\nOFNNlpjYMpUXuTkM8DaP52KgjZKlMavL7Y6+u3weNUQHyFjlDyAVyqFdyCC9LEZ5HogH7LXRL86i\nSB0mHnR4m2SsVlIEjuyfqbarrvbYeJSXZd0omQrK4YB6lVw9rBAzHrR3\/2iF6Rs1vapU7XBAnVLK\nH62QM4BjlcVcktOIhiRC0kzwR1RSfq8oTd2WFkFtqr0gmeoqoPddoUBjVlfwDYp8BpCMdThgVw6P\nZSiVMqmmLS0SpcG7IA\/cjuxDf\/q3VOC7DQZlIfT8TJjPV7McDngvl+fanZuNprAw6GRi3MrPwMnj\n\/jSkJ1JZ335WqtBDuBwTis6UOPTExW50NdExIJ53ynmit7gApw944SzLm9EVP380BAWhNSQEN0Np\nELrn6z56FA+PRYEKCkEH3VyQhuKmbyBaAtjoEYdiQMLDFmddxqoSXX3AQZxne+ACx4O5170V+dzg\n74X2Y1x0hHDQFsbC3SQ2tAI2xtQRmGvnYfF+DugDk8VpgPoKOdWRzkFD\/DY0JWzDjaSv0ZL6DVp5\n29Ga9h3uZO9Cj9Qd42pfzDZEYqU9EXOtsVjs5GH5fjamNOkwSASU0wAHK0v4RoUA2qydGJXswKR8\nN17UuGPh\/CG8qPPB4tVALFwLxkJTOKwtUQzg\/K0ELHSkYKk7E2PlyTAUChROA+wWpnNJFPflBqFf\n+B0mZbsxXfE3zNd54+UF9i8CPqk7xqQYkpacBtglTHEbVsmYBz0QsnRD4h2YoL04oz7wCeDL60ex\neDMWM1fC6XOMj65bkMxUEadFsK3ppOsoeRBJvNrM7Sx93g7qsXQPnpW746daL0yrD2OKbrcmVAdh\nVh6wjJcdYM4dWkEa8zuTLG+rUwEHpLmMJ8bo\/WjrUjK3U4\/y96K\/cB96afUXe2K0hkN9rsw5\/d1K\nv6KAYuqpSmY7xE8q9lLWeg4WrwRg7nIgs8SLLVG2dHKdF+PaI8p0bgTbuuK8TAVpXN\/vSAjgwkX2\nO8BGOkiaj9m81ZQS69afn008qHE6IGn\/iQeHSwst7wO+OHeYAZx9C7jUetwG2Jgcx3oL6LzXbW+G\nTrr+01TuZtFI4s2nCj5oOp8q91k\/Blxui7b9vzk1gW+UC\/D3y4UKYoOIPtz898GyPlrNemO+qFh\/\nfM6ybqrCmr7UpuW+YkZzXfRy01E8e9r7E8C5rjzL+7+xaVCFf0xes76xXOVjotK+1n+FClOvaU\/g\ntV6G9ZFarBlrsKpX0saVeGUow+shFfOwWSoXOvEuPCnZh59qDuL5GTZmLvhjsISF2c7cjYn0K2wT\nWtWX4dXIWaybL2F9VI3V7iTLV1988Zv\/\/CRXvPMPL67tT5lrcG9ebvbEym0\/rGmT8KpPRMOVYX24\nggFd1ZXQICIMnw63yaJJwlKv\/N1khk9ujNcVYe1hBlbuBGKp2UO30uzBX2nxdEzipiFZyzc8FUs3\nPCwEeO2RCJ9dvvf0mmyLB6lYvsnGfKPH9KzGXTV1+a8+uL3HxamR\/Lp5\/9bnt+N0r3VS\/KzorfFq\nQALd2YBa06m9X\/7PX4bPN7griCd\/SeOXOA\/s2l8fXf8C8GRzfxACMzEAAAAASUVORK5CYII=",
  	};
  };
  
  var itemDef = {
  	label		: this.label,
  	name_plural	: this.name_plural,
  	stackmax	: this.stackmax,
  	is_hidden	: this.is_hidden,
  	has_info	: this.has_info,
  	adjusted_scale	: this.adjusted_scale,
  	asset_swf_v	: "\/c2.glitch.bz\/items\/2010-03\/1268361091-4273.swf",
  	admin_props	: true,
  	obey_physics	: false,
  	in_background	: true,
  	in_foreground	: false,
  	has_status	: false,
  	not_selectable	: false,
  };
  
  if (this.consumable_label_single) itemDef.consumable_label_single = this.consumable_label_single;
  if (this.consumable_label_plural) itemDef.consumable_label_plural = this.consumable_label_plural;
  
  itemDef.verbs = {
  };
  itemDef.hasConditionalVerbs = 1;
  itemDef.emote_verbs = {
  };
  itemDef.hasConditionalEmoteVerbs = 0;
  itemDef.tags = [
  	"shrine",
  	"no_trade"
  ];
  itemDef.keys_in_location = {
  	"c"	: "check_favor",
  	"e"	: "debug",
  	"o"	: "donate_to",
  	"g"	: "get_emblem",
  	"v"	: "give_cubimal",
  	"h"	: "prime",
  	"t"	: "talk_to"
  };
  itemDef.keys_in_pack = {};
  
  // generated ok 2012-10-29 11:52:11 by lizg
  