/* Team skills, sorta like that of Chronotrigger, you make your choices, and hopefully, you make a good combonation
 * as when you do, you get an amazing outcome, being in the form of a skill/spell against your target.
 *
 * Note: teamskills only work on enemies, but can have affects that cure your group, which makes it always very
 * fun.
 *
 * note for installation, damage_new must return the damage delt, not a true/false
 * this is done to affect our skillz.
 */

class teamskill {
	public:
		teamskill() { ch_name = NULL; buddy_name = NULL; victim_name = NULL; }
		~teamskill() { extern void free_string(const char *); free_string(buddy_name); free_string(ch_name); free_string(victim_name); }
	int ch_skill;
	int bd_skill;
	const char *ch_name;
	const char *buddy_name;
	const char *victim_name;
};

/* Create unique skills
 * Basically, the intent of this is to take the teamskill information, and generate a 'new' skill where
 * its effects can be anything from healing, to hurting, or both!
 * skill 1 - primary skill
 * skill 2 - modifier skill
 * based on the first skill selected, the second skill will change the outcome of the overall system
 * As seen :)
 */
void perform_teamskill(struct teamskill *tk) {
	int skill_1 = tk->ch_skill;
	int skill_2 = bd->skill;
	bool failed = false;
	int wait_adjustment = 8;		// skill wait timer handled here.
	// all 3 existed at the start!
	CHAR_DATA *ch = get_char_world(NULL, tk->ch_name);
	CHAR_DATA *buddy = get_char_world(NULL, tk->buddy_name);
	CHAR_DATA *victim = get_char_world(NULL, tk->victim_name);

	// we protect against a most horrible issue that may occur should someone die, quit, extract, or 'gulp' bug out ;)
	if(!ch || !victim || !buddy) {
		if(ch) {
			ch->Sendf("Your teamskill failed!  Someone is missing!!\n\r");
			delete ch->teamskill;
			turn_end(ch->turn, 10, ch);
		}
		if(victim) {
			// hmm, we have a victim, but someone else is missing, crazy!
		}
		if(buddy) {
			buddy->Sendf("Your teamskill failed!  Someone is missing!!\n\r");
			delete buddy->teamskill;
			turn_end(buddy->turn, 10, buddy);
		}
		return;
	}

	/* We just want to leave alittle message here, showing that they are doing things in a little mystical way
	 * since the mud has little magic referance, we make team-skills based on them, removing 'restrictions'
	 * since there is no need to have restrictions on mystical powers.
	 *			-- This is explained by our story why people can do this.
	 */
	switch(number_range(0,3)) {
		default: case 0:
			act("$n and $N make identical moves, as they swirl with mystic energies!", ch, NULL, buddy, TO_ROOM);
			act("You and $N make identical moves.", ch, NULL, buddy, TO_CHAR);
			act("You and $n make identical moves.", ch, NULL, buddy, TO_VICT);
			break;
		case 1:
			act("$N, with the assistance of $n, surround themselves with swirling colours.", ch, NULL, buddy, TO_ROOM);
			act("You and $N focus intently, as swirling colours surround you.", ch, NULL, buddy, TO_CHAR);
			act("You and $n focus intently, as swirling colours surround you.", ch, NULL, buddy, TO_VICT);
			break;
		case 2:
			act("$N begins to eminate a blinding light as $n channels $s power through $M!", ch, NULL, buddy, TO_ROOM);
			act("You channel your power through $N, focusing through a blinding light!", ch, NULL, buddy, TO_CHAR);
			act("You begin eminating a blinding light as $n channels $s power through you!", ch, NULL, buddy, TO_VICT);
			break;
		case 3:
			act("$n and $N vanishes abruptly!", ch, NULL, buddy, TO_ROOM);
			act("You vanish abruptly!", ch, NULL, buddy, TO_CHAR);
			act("You vanish abruptly!", ch, NULL, buddy, TO_VICT);
			break;
	}
	// lets parse through the overall skills, and create a new skill!
	switch(skill_1) {
		default: failed = true;	break;
		case gsn_backstab:
			switch(skill_2) {
				default: failed = true;	break;
				case gsn_backstab:		// double backstab
					act("$n and $N pair up, and double backstab $t with spirit daggers!", ch, victim->name, buddy, TO_ROOM);
					damage_new(ch, victim, dam, gsn_backstab, NULL, TRUE, FALSE, DAM_PIERCE);
					damage_new(buddy, victim, dam, gsn_backstab, NULL, TRUE, FALSE, DAM_PIERCE);
					break;
				case gsn_envenom:		// damage + poison
					break;
				case gsn_steal:			// damage and swipe stuff
					break;
			}
			break;
		case gsn_bash:
			switch(skill_2) {
				default:	failed = true;	break;
				case gsn_backstab:		// 'hammer' the dagger into the victim
					break;
				case gsn_triage:		// damage enemy, heal group with % of damage delt.
				{
					int dam = 0;
					int cnt = 0;
					int chance;
					/* size  and weight */    
					chance += ch->carry_weight / 250;    
					chance -= victim->carry_weight / 200;     
					if (ch->size < victim->size)	
						chance += (ch->size - victim->size) * 15;    
					else	
						chance += (ch->size - victim->size) * 10;       

					/* stats */    
					chance += get_curr_stat(ch,STAT_STR);    
					chance -= (get_curr_stat(victim,STAT_DEX) * 4)/3;    
					chance -= GET_AC(victim,AC_BASH) /25;    

					/* Triage helps us out here for our overall bonus!*/
					change += get_skill(buddy, gsn_triage)/3;

					/* speed */    
					if (IS_SET(ch->off_flags,OFF_FAST) || IS_AFFECTED(ch,AFF_HASTE))        
						chance += 10;    
					if (IS_SET(victim->off_flags,OFF_FAST) || IS_AFFECTED(victim,AFF_HASTE))        
						chance -= 30;     

					/* level */    
					chance += (ch->level - victim->level);

					/* get the damage delt! */
					dam = damage_new(ch, victim, number_range(2,2 + 2 * ch->size + chance/20), gsn_bash, NULL, TRUE, FALSE, DAM_BASH);

					if(dam != 0) {
						CHAR_DATA *list;
						for (list = ch->in_battle->unit_list; list != NULL; list = list->next_in_battle)
							if(is_same_group(ch, list)) cnt++;
	
						// Okay, now we heal the party for a small percentage of the damage delt. + triage-skill-level bonus :)
						for (list = ch->in_battle->unit_list; list != NULL; list = list->next_in_battle) {
							if(is_same_group(ch,list)) {
								// knocked out cold?
								if(IS_AFFECTED(list, AFF_KNOCKOUT))
									revive_unit(list);
								list->hit += dam/cnt + get_skill(buddy, gsn_triage)/7;
								if(list->hit > list->max_hit)
									list->hit = list->max_hit;
							}
						}
					}
					ch->wait_adjustment+=9;
				}
				break;
				case gsn_search:		// finds secret weakness
					break;
			}
			break;
		case gsn_berserk:
			switch(skill_2) {
				default:	failed = true; break;
				case gsn_backstab: break;	// mass backstabbing!
				case gsn_bash: break;		// overpowering bash
				case gsn_trip: break;		// thundering trip
				case gsn_dirt: break;		// boulders to the face
			}
			break;
		case gsn_steal:
			switch(skill_2) {
				default: failed = true; break;
				case gsn_hide:	break;		// steals armed weapon
				case gsn_backstab: break;	// causes victim to drop coin's
				case gsn_parry: break;		// causes 100% chance of coin stealing (divies to group)
				case gsn_bow:	break;		// shoot victim, causing victims gold/20 damage.
			}
			break;
		case gsn_disarm:
			switch(skill_2) {
				default: failed = true; break;
				case gsn_bash: break;		// causes massive damage to victims weapon
				case gsn_disarm: break;		// disarm chance *3 + damage on disarm
				case gsn_parry: break;		// causes rend-damage loss
			}
			break;
		case gsn_triage:
			switch(skill_2) {
				default:	failed = true; break;
				case gsn_bash:	break;		// heals group 1 point for every bit of damage delt.
				case gsn_revive: break;		// drains live from victim, restores party
				case gsn_polearm: 
				{
					act("$n screams 'BLOOD SIPHON' in unison with $N as they hold onto a mystical polearm and impale $t!", ch, victim->name, buddy, TO_ROOM);
					int max = victim->max_hit/2;
					victim->hit -= max;
					victim->killer = number_range(0,1) ? ch : buddy;
					if(victim->hit < 0)
						kill_unit(victim);
					switch(number_range(0,1)) {
						default: case 0:
							ch->hit = ch->max_hit;
							break;
						case 1:
							buddy->hit = buddy->max_hit;
							break;
					}
					ch->wait_adjustment+=3;
				}
				break;	// blood siphon ch || buddy is healed 100%, victim damaged for 50% of their health.
				case gsn_shield_block: break;	// causes victim's turn to be pushed back.
			}
			break;
		case gsn_sword:
			switch(skill_2) {
				default: failed = true; break;
				case gsn_second_attack: {
					act("$n and $N pair up, and unleash a hidden fury!", ch, NULL, buddy, TO_ROOM);
					for(int x = 0; x < 3; x++) {
						one_hit(ch, victim, false);
						one_hit(buddy, victim, false);
					}
				} 
				break;	// 3 attacks per person against victim (one_hits)
				case gsn_third_attack: 		
					act("$n and $N pair up, and unleash a hidden fury!", ch, NULL, buddy, TO_ROOM);
					for(int x = 0; x < 4; x++) {
						one_hit(ch, victim, false);
						one_hit(buddy, victim, false);
					}
				break;	// 4 attacks per person against victim (one_hits)
				case gsn_enhanced_damage:
					act("$n wields 2 bright blue, and humming scimitars.", ch, NULL, NULL, TO_ROOM);
					act("$n wields 2 bright green, and humming rapiers.", buddy, NULL, NULL, TO_ROOM);					
					for(int x = 0; x < 2; x++) {
						one_hit(ch, victim, false);
						one_hit(ch, victim, true);
						one_hit(buddy, victim, false);
						one_hit(buddy, victim, true);
					}
					wait_adjustment+=number_range(3,9);
				break;	// 2 hits per person against victim
			}
			break;
		case gsn_polearm:
			switch(skill_2) {
				default: failed = true;	break;
				case gsn_polearm:	break;	// buddy dies, victim takes buddy's max_health as damage
				case gsn_cpr:		break;	// ch dies, victim takes ch's max_health as damage
				case gsn_grenade:	break;	// requires a grenade, if it finds one, it arms it, and bats it at the enemy. instantly exploding.
			}
			break;
		case gsn_swimming:
			switch(skill_2) {
				default: failed = true; break;
				case gsn_arm:		break;	// Completely random effect!
			}
			break;		
	}

	// yeah, we went there!
	delete ch->teamskill;
	delete buddy->teamskill;

	// failure is not an option!
	if(failed) {
		ch->Sendf("Your teamskill failed!\n\r");
		buddy->Sendf("Your teamskill failed!\n\r");
		turn_end(ch->turn, 300-GET_SPEED(ch), ch);
		turn_end(buddy->turn, 300-GET_SPEED(ch), ch);
		ch->skill_wait = 3;
		buddy->skill_wait = 3;
		return;
	}

	// combat still lingers!
	if(is_fighting(ch)) {
		turn_end(ch->turn, 600-GET_SPEED(ch), ch);
		turn_end(buddy->turn, 600-GET_SPEED(ch), ch);
		ch->skill_wait = wait_adjustment;
		buddy->skill_wait = wait_adjustment;
	}

	return;
}

// Teamskills start at level 20!
COMMAND(do_teamskill) {
	char arg[MIL], arg2[MIL], arg3[MIL];
	CHAR_DATA *search, *buddy = NULL, *victim = NULL;

	// okay, we want to decimate everything!
	if(!NullString(argument) && !str_cmp(argument, "confirm")) {
		if(ch->teamskill) {
			if(!str_cmp(ch->name, ch->teamskill->buddy_name)) {
				perform_teamskill(ch->teamskill);
				return;
			}
			ch->Sendf("You started the teamskill!  You cannot confirm its action!\n\r");
			return;
		}
		ch->Sendf("There is no teamskill for you to confirm!\n\r");
		return;
	}

	// not a confirmation?
	argument = one_argument(argument, arg);
	argument = one_argument(argument, arg2);
	argument = one_argument(argument, arg3);

	if(NullString(argument)) {
		ch->Sendf("Syntax: teamskill <buddy> <their skill> <your skill> <victim>\n\r");
		ch->Sendf("-------------------------------------------------------------\n\r");
		ch->Sendf("Teamskill allows you to experiment with skills, and create a\n\r");
		ch->Sendf("powerful combonation, though you have to be careful, as the\n\r");
		ch->Sendf("skills you choose, may or may not work with eachother to create\n\r");
		ch->Sendf("the joyful teamskill.\n\r");
		return;
	}


	if(!is_fighting(ch)) {
		ch->Sendf("But your not fighting!\n\r");
		return;
	}

	if(!is_active(ch)) {
		ch->Sendf("Its not your turn!\n\r");
		return;
	}

	for (search = ch->in_battle->unit_list; search != NULL; search = search->next_in_battle)	{		

		if(!str_cmp(arg, search->name) && is_same_group(ch, search)) {
			buddy = search;
		}

		if(!str_cmp(argument, search->name) && !is_same_group(ch, search)) {
			victim = search;
		}

		if(victim && buddy)
			break;

	}

	if(!buddy || !victim) {
		ch->Sendf("Make sure your buddy name, and victim name are correct!\n\r");
		return;
	}

	// require level 20!
	if(buddy->level < 20) {
		ch->Sendf("%s does not know the team mystic arts yet!\n\r");
		return;
	}

	if(buddy->teamskill) {
		ch->Sendf("They are already working on a teamskill!\n\r");
		return;
	}

	int sn = skill_lookup(arg2);
	int sn2 = skill_lookup(arg3);

	if(get_skill(ch, sn2) == 0) {
		ch->Sendf("You do not know that skill!\n\r");
		return;
	}

	if(get_skill(buddy, sn) == 0) {
		ch->Sendf("Your buddy doesn't know that skill!\n\r");
		return;
	}

	if(ch->teamskill)
		delete ch->teamskill();
	ch->teamskill = new teamskill();
	ch->teamskill->ch_skill = sn2;
	ch->teamskill->bd_skill = sn;
	ch->teamskill->ch_name = str_dup(ch->name);
	ch->teamskill->buddy_name = str_dup(buddy->name);
	ch->teamskill->victim_name = str_dup(victim->name);

	// duplicated here!
	buddy->teamskill = new teamskill();
	buddy->teamskill->ch_skill = sn2;
	buddy->teamskill->bd_skill = sn;
	buddy->teamskill->ch_name = str_dup(ch->name);
	buddy->teamskill->buddy_name = str_dup(buddy->name);
	buddy->teamskill->victim_name = str_dup(victim->name);

	if(is_fighting(ch)) {
		turn_end(ch->turn, 200-GET_SPEED(ch), ch);
		ch->skill_wait = 8;
	}
	return;
}