// Town 2 Charm Altar v1.0
// t2altar.txt 
// by Kelandon (tomwatts@berkeley.edu)
//
// An altar that forces the party to fight against itself.
//
// Specifically, the script focuses on the leading character. The point is to
// make the party fight against the leading character. The idea is that the
// party enters an area, the lead character disappears and is charmed, and at
// some point, he comes back and attacks the party.
//
// There are two problems: one, this doesn't work very well if the party is not
// in combat mode, and two, this completely fails with singletons. If the party
// is not in combat mode, this script just does a lot of damage to the leading
// character and eventually kills him and starts in on the second character. If
// the party is a singleton, the script follows a completely different path and
// just causes the character to emulate striking himself occasionally.
//
// The solution is to use Ritual of Sanctification on the altar.
//
// Memory Cells - 
//	0,1 - Coordinates of an SDF to activate and deactivate the altar. If this
//		flag is 0, the altar has not been activated. If it's 1, the altar is
//		active. If it's 2, the altar has been deactivated.
//	2 - Number of the terrain to turn the altar into when it gets deactivated.
//		Recommended: 0 (nothing, destroy altar entirely), 137 or 138 (rubble),
//		or 276 (good altar).
//	3,4 - Type of experience to award the party. 3 is the amount of xp, and 4 is
//		the level from which it comes (as if killing a monster of this level --
//		for more details, see the docs' notes on award_party_xp).
//	5 - How many turns between singleton hurting himself (so if this is 0, every
//		turn.
//	6,7 - Coordinates to relocate the leading character when taking him away
//		from the party.
// 
// If you intend to make use of this script, you'll also have to modify state
// 32, probably.
//
// In Bahssikava, the memory cells are set as follows:
// 0: 2
// 1: 15
// 2: 138
// 3: 200
// 4: 50
// 5: 2
// 6: 35
// 7: 19


beginterrainscript; 

variables;

short i,j; // counting variables
short first_char; // The number of the lead character.
short turns_shot = 0; // Times the lead char has been blasted not in combat.
short last_hurt_self; // Turn when singleton last hit himself.
short melee,pol_pri; // What kind of skills the singleton has.
short damage_to_do; // How much damage for the singleton to do himself.
short first_time = 1; // If this is the first time the effect happened.
short last_run_time; // Makes once-per-turn effects work.
short lead_loc_x,lead_loc_y; // For saving the lead character's location.
string dlgstr; // A message when the altar is sanctified.

body; 

beginstate INIT_STATE; // state 0 
	set_script_mode(3);
	
	if (get_flag(get_memory_cell(0),get_memory_cell(1)) == 2)
		set_terrain(my_loc_x(),my_loc_y(),get_memory_cell(2));
	
	last_hurt_self = get_current_tick();
	last_run_time = get_current_tick();
	
	first_char = 0;
	while (char_ok(first_char) == 0)
		{first_char = first_char + 1; }
	
	// The rest of the state only matters for singletons. For details, see state
	// 20.
	
	// If melee skills are better, character is a warrior.
	if (get_stat(first_char,0) + get_stat(first_char,4) + get_stat(first_char,5) + get_stat(first_char,21) > get_stat(first_char,2) + get_stat(first_char,11) + get_stat(first_char,12) + get_stat(first_char,25))
		melee = 1;
	else
		melee = 0;
	
	// If char is a warrior, check whether pole or melee skill is higher.
	if (melee) {
		if (get_stat(first_char,4) > get_stat(first_char,5))
			pol_pri = 0;
		else
			pol_pri = 1;
		}
	else // Otherwise, check whether mage or priest skill is higher.
		if (get_stat(first_char,11) > get_stat(first_char,12))
			pol_pri = 0;
		else
			pol_pri = 1;
break; 

beginstate START_STATE; // state 2
	// Only run if the altar is active.
	if (get_flag(get_memory_cell(0),get_memory_cell(1)) == 1) {
		// Find the leading character of the party.
		first_char = 0;
		while (char_ok(first_char) == 0)
			{first_char = first_char + 1; }
		
		// Direct to the appropriate state.
		if (is_combat() == 0)
			set_state_continue(10);
		else {
			if (party_size() == 1)
				set_state_continue(20);
			else
				set_state_continue(30);
			}
		}
break; 

beginstate SEARCH_STATE; // state 100 
break; 

beginstate UNLOCK_SPELL_STATE; // state 101 
break; 

beginstate SANCTIFICATION_STATE; // state 102
	// If the altar has already been deactivated, tell them they're fools.
	if (get_flag(get_memory_cell(0),get_memory_cell(1)) == 2)
		message_dialog("You perform the Ritual of Santification again, but since you've already sanctified this altar, nothing happens.","Oh well.");
	
	// If the altar is active, give them a message and blow up the altar.
	if (get_flag(get_memory_cell(0),get_memory_cell(1)) == 1) {
		clear_buffer();
		append_string("You use the powerful Ritual of Sanctification on the evil altar, hoping to save ");
		if (party_size() > 1)
			append_string("your friend and keep him from killing you.");
		else
			append_string("yourself and end these self-destructive urges.");
		get_buffer_text(dlgstr);
		message_dialog(dlgstr,"And it works!");
		
		set_flag(get_memory_cell(0),get_memory_cell(1),2);
		i = 10;
		while (i < 120)
			{if (char_ok(i)) 
				if (get_attitude(i) >= 10){
					put_jagged_zap(my_loc_x(),my_loc_y(),char_loc_x(i),char_loc_y(i),2);
					run_animation_sound(-65);
					kill_char(i,2,0);
					}
			i = i + 1;
			}
		put_jagged_zap(my_loc_x(),my_loc_y(),char_loc_x(first_char),char_loc_y(first_char),2);
		run_animation_sound(-65);
		set_char_status(first_char,8,0 - get_char_status(first_char,8),1,0); // Charmed
		put_boom_on_space(my_loc_x(),my_loc_y(),0,0);
		run_animation_sound(51);
		set_terrain(my_loc_x(),my_loc_y(),get_memory_cell(2));
		force_instant_terrain_redraw();
		award_party_xp(get_memory_cell(3),get_memory_cell(4));
		}
break; 

beginstate BLOCK_MOVE_STATE; // state 112 
break; 

beginstate DISPEL_BARRIER_STATE; // state 113 
break; 

beginstate STEP_INTO_SPOT_STATE; // state 114 
break;

beginstate 10;
	// The party is idiotically  not in combat. Badly damage the leading
	// character. If this is the fourth turn still not in combat, kill him.
// Only run once per turn.
if (tick_difference(last_run_time,get_current_tick()) > 0) {
	last_run_time = get_current_tick();
	turns_shot = turns_shot + 1;
	
	print_str("Your leading member gets blasted badly!");
	put_jagged_zap(my_loc_x(),my_loc_y(),char_loc_x(first_char),char_loc_y(first_char),2);
	if (turns_shot >= 4) {
		kill_char(first_char,3,1);
		if (char_ok(first_char) == 0) {
			turns_shot = 0; // This actually killed him, so start over.
			message_dialog("Since you are being attacked from an unknown location by an exceedingly powerful force, you might wish to enter combat mode in order to fight it.","");
			}
		}
	else
		damage_char(first_char,get_max_health(first_char) / 4,4);
	set_state(START_STATE);
	}
break;

beginstate 20;
	// The party is a singleton. Make him hurt himself periodically. This is a
	// bit weird. Basically, if the singleton is more a warrior than a
	// magic-user, he hits himself with melee damage. If he's more a magic-user,
	// he casts spells upon himself.
	//
	// For warriors:
	// To figure out hit percentage:
	// Accuracy = 6 + bladesmaster + dexterity + highest weapons type - defense
	//	- gymnastics
	// Then 5 * Accuracy gives the percent chance to hit.
	//
	// Then for damage:
	// I total the damage-doing skills: melee/pole (whichever is greater),
	// strength, and bladesmaster. That becomes the number of dice. For every
	// successful hit, I do a damage equal to the roll of that number of
	// ten-sided dice. For more details, see the docs on get_ran().
	//
	// Because I have no idea what Assassination and Lethal Blow do, I've added
	// a small chance depending on the level of those skills for a double- or
	// quintuple-damage blow, respectively.
	//
	// For mages:
	// Basically, I figure that they're casting a new spell. It always hits, but
	// it only does damage almost like that of Arcane Blow at level 2.
	// In other words, it does 6-108 + 3 * Bonus, where
	// Bonus = Intelligence + Mage/Priest Spells + Magery
	//
	// And yes, I know that this is strange.
	
if (tick_difference(last_hurt_self,get_current_tick()) > get_memory_cell(5)) {
	last_hurt_self = get_current_tick();
	set_character_pose(first_char,1);
	force_instant_terrain_redraw();
	if (first_time) {
		reset_dialog();
		add_dialog_str(0,"The rage that you've been feeling finally boils over. You can take it no longer. Your separate halves begin fighting each other.",0);
		if (melee)
			add_dialog_str(1,"You begin to strike yourself with your own weapons!",0);
		else
			add_dialog_str(1,"You begin to cast terrible destructive spells on yourself!",0);
		first_time = run_dialog(1) - 1;
		}
	if (melee) {
		if (get_ran(1,1,100) < 5 * (6 + get_stat(first_char,1) + get_stat(first_char,4 + pol_pri) + get_stat(first_char,21) - get_stat(first_char,9) + get_stat(first_char,23))) {
			damage_to_do = get_ran(get_stat(first_char,0) + get_stat(first_char,4 + pol_pri) + get_stat(first_char,21),1,10);
			if (get_ran(1,1,100) < 5 * get_stat(first_char,28))
				damage_to_do = damage_to_do * 5;
			else if (get_ran(1,1,100) < 5 * get_stat(first_char,10))
				damage_to_do = damage_to_do * 2;
			print_str("You strike youself!");
			damage_char(first_char,damage_to_do,0);
			play_sound(71);
			}
		else {
			print_str("You attack and miss yourself!");
			play_sound(19);
			}
		}
	else {
		damage_to_do = get_ran(6,1,18);
		damage_to_do = damage_to_do + (3 * (get_stat(first_char,2) + get_stat(first_char,11 + pol_pri) + get_stat(first_char,25)));
		print_str("You cast a spell on yourself!");
		damage_char(first_char,damage_to_do,3);
		}
	set_character_pose(first_char,2);
	force_instant_terrain_redraw();
	}

	set_state(START_STATE);
	
break;

beginstate 30;
	// The party is normal. Do the intended effect: take away a character, charm
	// him, and make him attack the party. Bless, haste, and otherwise spell up
	// the charmed character, too, just to make him more nasty and simulate
	// berserk frenzy.
	
	if (first_time) 
		set_state_continue(31);
	
	// Spell character up and charm him.
if (get_char_status(first_char,1) < 10)
	set_char_status(first_char,1,10,1,0); // Bless
if (get_char_status(first_char,3) < 10)
	set_char_status(first_char,3,10,1,0); // Haste
if (get_char_status(first_char,5) < 10)
	set_char_status(first_char,5,10,1,0); // Magic resistant
if (get_char_status(first_char,8) < 10)
	set_char_status(first_char,8,10,1,0); // Charmed
if (get_char_status(first_char,16) < 10)
	set_char_status(first_char,16,10,1,0); // Divinely touched
if (get_char_status(first_char,22) < 10)
	set_char_status(first_char,22,10,1,0); // Regenerating
	
	// Once per turn, check if the party has managed to get too far away from
	// the charmed member. If they can't see him, they're too far away.
if (tick_difference(last_run_time,get_current_tick()) > 0) {
	last_run_time = get_current_tick();
	
	// First, save his location.
	lead_loc_x = char_loc_x(first_char);
	lead_loc_y = char_loc_y(first_char);
	
	// Now, relocate him far away.
	relocate_character(first_char,1,1);
	
	// If the party can't see his old location, they've lost him. Go to the
	// appropriate state.
	if (party_can_see_loc(lead_loc_x,lead_loc_y) == 0)
		set_state_continue(32);
	// Otherwise, bring him back.
	else
		relocate_character(first_char,lead_loc_x,lead_loc_y);
	}
	
	set_state(START_STATE);
break;

beginstate 31;
	// This is the first time that the effect happened. Give the party a message
	// about what's going on and take away the leading character.
	
	// Give message.
	reset_dialog();
	add_dialog_str(0,"The strain that you saw on the leader of your party is growing worse by the moment, and you stand helpless to do anything about it. Then, suddenly, your leader's eyes turn away, looking into the distance, unfocused, as if hearing a far-away voice.",0);
	clear_buffer();
	append_string("_");
	append_char_name(first_char);
	append_string("?_ you ask. You get no response. You repeat the name again, but those eyes remain fixed away from you.");
	get_buffer_text(dlgstr);
	add_dialog_str(1,dlgstr,0);
	add_dialog_str(2,"Suddenly, your leader disappears!",0);
	first_time = run_dialog(1) - 1;
	
	// Take character away.
	put_boom_on_char(first_char,2,0);
	run_animation_sound(10);
	restore_pc(first_char);
	relocate_character(first_char,get_memory_cell(6),get_memory_cell(7));
	force_instant_terrain_redraw();
	
	// Now head back to the normal state.
	set_state_continue(30);
break;

beginstate 32;
	// The party has managed to evade the lead character who is attacking them.
	// Simply relocate the character to different positions until he's nearby
	// again.
		
	// If the party just hasn't progressed north yet, let it be. Check all the
	// members' locations, and if none of them are too far north or south, then
	// do nothing. Otherwise
	j = 0;
	i = first_char + 1;
	while ((i < 4) && (j == 0)) {
		if (char_ok(i)) 
			if ((char_loc_y(i) >= 39) || (char_loc_y(i) <= 22))
				j = 1; // break
		i = i + 1;
		}
	if (j == 0) {
		relocate_character(first_char,lead_loc_x,lead_loc_y);
		set_state(START_STATE);
		}
	
	// If the party has retreated south, just lay him in wait for them.
	else if (char_loc_y(i) >= 39) {
		relocate_character(first_char,43,25);
		set_state_continue(33);
		}
	
	// Otherwise, try positions. The list of positions is (reversed):
	// (37,21), (43,15), (39,6), (28,3), (19,4), (33,14), (28,8)
	if (party_can_see_loc(37,21)) {
		relocate_character(first_char,28,8);
		set_state_continue(33);
		}
		
	if (party_can_see_loc(33,14)) {
		relocate_character(first_char,33,14);
		set_state_continue(33);
		}
		
	if (party_can_see_loc(19,4)) {
		relocate_character(first_char,19,4);
		set_state_continue(33);
		}
		
	if (party_can_see_loc(28,3)) {
		relocate_character(first_char,28,3);
		set_state_continue(33);
		}
		
	if (party_can_see_loc(39,6)) {
		relocate_character(first_char,39,6);
		set_state_continue(33);
		}
		
	if (party_can_see_loc(43,15)) {
		relocate_character(first_char,43,15);
		set_state_continue(33);
		}
	
	if (party_can_see_loc(37,21)) {
		relocate_character(first_char,37,21);
		set_state_continue(33);
		}
	
	// If none of these locations worked, just put him at (18,13) in the dark
	// temple.
	relocate_character(first_char,18,13);
	set_state(START_STATE);
	
break;

beginstate 33;
	print_str("The lead character teleports!");
	put_boom_on_char(first_char,2,0);
	run_animation_sound(10);
	set_state(START_STATE);
break;