area/
build/testing/
log/
player/
player/backup/
/***************************************************************************
 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
 *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
 *                                                                         *
 *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          *
 *  Chastain, Michael Quan, and Mitchell Tse.                              *
 *                                                                         *
 *  In order to use any part of this Merc Diku Mud, you must comply with   *
 *  both the original Diku license in 'license.doc' as well the Merc       *
 *  license in 'license.txt'.  In particular, you may not remove either of *
 *  these copyright notices.                                               *
 *                                                                         *
 *  Much time and thought has gone into this software and you are          *
 *  benefitting.  We hope that you share your changes too.  What goes      *
 *  around, comes around.                                                  *
 ***************************************************************************/
#include <glib.h>

#if defined(macintosh)
#include <types.h>
#else
#include <sys/types.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <merc.h>
#include <tables.h>
#include <interp.h>
#include <fight.h>

void set_attack_flag(CHAR_DATA *ch, CHAR_DATA *victim)
{
	if ( ch == victim )
		return;
	if (ch == NULL || victim == NULL)
		return;
	if (IS_NPC(ch) || IS_NPC(victim))
		return;
	/* Attack Flag Check */
	if (!CAN_PK(ch) || !CAN_PK(victim))
		return;

	if (IS_SABBAT(victim))
	{
		ch->attack_timer = 8;
		if (!IS_SET(ch->act, PLR_ATTACK))
			SET_BIT(ch->act, PLR_ATTACK);
		if (!IS_SET(ch->pk_sect, ATTACK_SABBAT))
			SET_BIT(ch->pk_sect, ATTACK_SABBAT); 
	}
	else if (IS_FOLLOWERS(victim))
	{
		ch->attack_timer = 8;
		if (!IS_SET(ch->act, PLR_ATTACK))
			SET_BIT(ch->act, PLR_ATTACK);
		if (!IS_SET(ch->pk_sect, ATTACK_SABBAT))
			SET_BIT(ch->pk_sect, ATTACK_FOLLOWERS); 
	}
	else if (IS_CAMARILLA(victim))
	{
		ch->attack_timer = 8;
		if (!IS_SET(ch->act, PLR_ATTACK))
			SET_BIT(ch->act, PLR_ATTACK);
		if (!IS_SET(ch->pk_sect, ATTACK_CAMARILLA))
			SET_BIT(ch->pk_sect, ATTACK_CAMARILLA); 
	}
	else if (IS_WYRM(victim))
	{
		ch->attack_timer = 8;
		if (!IS_SET(ch->act, PLR_ATTACK))
			SET_BIT(ch->act, PLR_ATTACK);
		if (!IS_SET(ch->pk_sect, ATTACK_WYRM))
			SET_BIT(ch->pk_sect, ATTACK_WYRM); 
	}
	else if (IS_PACK(victim))
	{
		ch->attack_timer = 8;
		if (!IS_SET(ch->act, PLR_ATTACK))
			SET_BIT(ch->act, PLR_ATTACK);
		if (!IS_SET(ch->pk_sect, ATTACK_PACK))
			SET_BIT(ch->pk_sect, ATTACK_PACK); 
	}
	else if (IS_CLASS(victim,CLASS_VAMPIRE))
	{
		ch->attack_timer = 8;
		if (!IS_SET(ch->act, PLR_ATTACK))
			SET_BIT(ch->act, PLR_ATTACK);
		if (!IS_SET(ch->pk_sect, ATTACK_VAMP))
			SET_BIT(ch->pk_sect, ATTACK_VAMP); 
	}
	else if (IS_CLASS(victim,CLASS_MAGE))
	{
		ch->attack_timer = 8;
		if (!IS_SET(ch->act, PLR_ATTACK))
			SET_BIT(ch->act, PLR_ATTACK);
		if (!IS_SET(ch->pk_sect, ATTACK_MAGE))
		SET_BIT(ch->pk_sect, ATTACK_MAGE); 
	}
	else if (IS_SWWF(victim))
	{
		ch->attack_timer = 8;
		if (!IS_SET(ch->act, PLR_ATTACK))
			SET_BIT(ch->act, PLR_ATTACK);
		if (!IS_SET(ch->pk_sect, ATTACK_WWF))
			SET_BIT(ch->pk_sect, ATTACK_WWF); 
	}
	return;
}


bool check_pk_range(CHAR_DATA *ch, CHAR_DATA *victim)
{
	int chclass,victimclass;	
	
        if (ch->race <= 0 ) chclass = 0;
        else if (ch->race <= 4 ) chclass = 1;
        else if (ch->race <= 9 ) chclass = 2;
        else if (ch->race <= 14) chclass = 3;
        else if (ch->race <= 19) chclass = 4;
        else if (ch->race <= 24) chclass = 5;
        else chclass = 6;

        if (victim->race <= 0 ) victimclass = 0;
        else if (victim->race <= 4 ) victimclass = 1;
        else if (victim->race <= 9 ) victimclass = 2;
        else if (victim->race <= 14) victimclass = 3;
        else if (victim->race <= 19) victimclass = 4;
        else if (victim->race <= 24) victimclass = 5;
        else victimclass = 6;
	
	if ( chclass > victimclass )
		return TRUE;
	else
		return FALSE;
}

bool check_pk(CHAR_DATA *ch, CHAR_DATA *victim,int flag)
{
	/* Universal Check all by Spiralsoft(tm) <g> */
	bool pksect = FALSE;
	bool canpk = FALSE;

	if ( ch == NULL || victim == NULL)
		return FALSE;

	if (IS_NPC(victim) || IS_NPC(ch))
		return FALSE;

	if (!CAN_PK(ch) || !CAN_PK(victim))
		return TRUE;

	if (IS_SET(flag,CHECK_DELAY))
	{
		if (HAS_DELAY(ch) || HAS_DELAY(victim))
		{
			if (IS_NPC(victim))
			{
				bug("Damn mobs.",0);
				return FALSE;
			}
			send_to_char("You or your victim has a delay timer, please wait to attack (type 'help wait' for more info.)\n\r",ch);
			return TRUE;
		}
	}
	
	if (IS_ITEMAFF(victim, ITEMA_ARTIFACT)){
		return FALSE;
	}
	canpk = check_pk_range(ch,victim);

	if (IS_SET(flag,CHECK_ATTACK))
	{

		/* Check for attack flag */
		if ( canpk && !IS_SET(victim->act,PLR_ATTACK))
		{
			send_to_char("Go pick on someone else.\n\r",ch);
			return TRUE;
		} 

	        if (IS_SET(victim->act,PLR_ATTACK) && canpk )  	
		{
			/* Check for Sect, this is done by bit */
			if (IS_SET(victim->pk_sect,ATTACK_SABBAT) && !IS_SABBAT(ch))
				pksect = TRUE;	
			if (IS_SET(victim->pk_sect,ATTACK_FOLLOWERS) && !IS_FOLLOWERS(ch))
				pksect = TRUE;	
			if (IS_SET(victim->pk_sect,ATTACK_CAMARILLA) && !IS_CAMARILLA(ch))
				pksect = TRUE;	
			if (IS_SET(victim->pk_sect,ATTACK_WYRM) && !IS_WYRM(ch))
				pksect = TRUE;	
			if (IS_SET(victim->pk_sect,ATTACK_PACK) && !IS_PACK(ch))
				pksect = TRUE;	
			if (IS_SET(victim->pk_sect,ATTACK_VAMP) && !IS_CLASS(ch,CLASS_VAMPIRE))
				pksect = TRUE;	
			if (IS_SET(victim->pk_sect,ATTACK_WWF) && !IS_CLASS(ch,CLASS_WEREWOLF))
				pksect = TRUE;	
			if (IS_SET(victim->pk_sect,ATTACK_MAGE) && !IS_CLASS(ch,CLASS_MAGE))
				pksect = TRUE;	
			if (IS_SET(victim->pk_sect,ATTACK_ANYONE))
				pksect = TRUE;
				
			if (pksect == TRUE)
			{
				send_to_char("They did nothing to you or your sect, you can't attack them.\n\r",ch);
				return TRUE;
			}
		}
	}

	return FALSE;
}


bool check_safe_imm(CHAR_DATA *ch)
{
	CHAR_DATA *wch;

	for (wch = char_list; wch != NULL; wch = wch->next)
	{
		if (wch->in_room == NULL)
			continue;

		if (!IS_NPC(wch) && wch->in_room == ch->in_room 
			&& IS_IMMORTAL(wch) && IS_SET(wch->pcdata->comm, COMM_IMM_SAFE))
			return TRUE;
	}
	return FALSE;
}

bool is_tempsafe( CHAR_DATA *ch )
{
	if ( ch->fighting == NULL && ch->in_room != NULL && IS_SET(ch->in_room->room_flags,ROOM_SAFE) )
	{
		switch (weather_info[ch->in_room->sector_type].sunlight)
		{
			case SUN_DARK:
				return FALSE;	
			case SUN_LIGHT:
			case SUN_SET:
			case SUN_RISE:
				return TRUE;
		}
	}
	return FALSE;	
}

bool is_safe( CHAR_DATA *ch, CHAR_DATA *victim )
{
    /* Ethereal people can only attack other ethereal people */
	if (ch->plane != victim->plane){
		send_to_char("They are not on this plane.\n\r",ch);
		return TRUE;
	}

	
	if ( ch->in_room != NULL && IS_SET(ch->in_room->room_flags,ROOM_SAFE) && victim->pk_timer < 1)
	{
		switch (weather_info[ch->in_room->sector_type].sunlight)
		{
			case SUN_DARK:
				break;
			case SUN_LIGHT:
			case SUN_SET:
			case SUN_RISE:
				send_to_char( "You cannot fight in a safe room during the daytime.\n\r", ch );
				return TRUE;
		}
	}
	
	if ( IS_HEAD(ch,LOST_HEAD) || IS_EXTRA(ch,EXTRA_OSWITCH) )
	{
		send_to_char( "Objects cannot fight!\n\r", ch );
		return TRUE;
	}
	else if ( IS_HEAD(victim,LOST_HEAD) || IS_EXTRA(victim,EXTRA_OSWITCH))
	{
		send_to_char( "You cannot attack an object.\n\r", ch );
		return TRUE;
	}
	
	if ( IS_NPC(ch) || IS_NPC(victim) )
		return FALSE;
	
    /* Thx Josh! */
	if ( victim->fighting == ch )
		return FALSE;
	
	if (IS_ITEMAFF(ch, ITEMA_PEACE))
	{
		send_to_char( "You are unable to attack them.\n\r", ch );
		return TRUE;
	}
	switch(ch->plane)
	{
		case PLANE_SPIRIT:
			return TRUE;
		case PLANE_PUNISHMENT:
			return TRUE;
		case PLANE_IMMORTAL:
			return TRUE;
	}
	if (IS_ITEMAFF(victim, ITEMA_PEACE))
	{
		send_to_char( "You can't seem to attack them.\n\r", ch );
		return TRUE;
	}

        if ( check_pk(ch,victim,CHECK_DELAY))
        {
                return TRUE;
        }
	
	if ( ch->trust > LEVEL_BUILDER )
	{
		send_to_char( "You cannot fight if you have implementor powers!\n\r", ch );
		return TRUE;
	}
	
	if ( victim->trust > LEVEL_BUILDER )
	{
		send_to_char( "You cannot fight someone with implementor powers!\n\r", ch );
		return TRUE;
	}
	
	if ( !CAN_PK(ch) || !CAN_PK(victim) )
	{
		send_to_char( "Both players must be avatars to fight.\n\r", ch );
		return TRUE;
	}
	
	if ( ch->desc == NULL || ( victim->desc == NULL && victim->pk_timer < 1 ))
	{
		if (victim->position != POS_FIGHTING)
		{
			send_to_char( "They are currently link dead with no combat timer.\n\r", ch );
			send_to_char( "Are you that much of a pussy that you have to kill link dead?\n\r", ch );
			return TRUE;
		}
	}
	
	return FALSE;
}

bool no_attack( CHAR_DATA *ch, CHAR_DATA *victim )
{
    /* Ethereal people can only attack other ethereal people */
	if (ch->plane != victim->plane){
		send_to_char("They are not on this plane.\n\r",ch);
		return TRUE;
	}
	
	if ( ch->in_room != NULL && is_safe(ch,victim) )
	{
		send_to_char( "You cannot fight in a safe room.\n\r", ch );
		return TRUE;
	}
	
	if ( IS_HEAD(ch,LOST_HEAD) || IS_EXTRA(ch,EXTRA_OSWITCH) )
	{
		send_to_char( "Objects cannot fight!\n\r", ch );
		return TRUE;
	}
	else if ( IS_HEAD(victim,LOST_HEAD) || IS_EXTRA(victim,EXTRA_OSWITCH) )
	{
		send_to_char( "You cannot attack objects.\n\r", ch );
		return TRUE;
	}

	return FALSE;
}



/*
 * See if an attack justifies a KILLER flag.
 */
void check_killer( CHAR_DATA *ch, CHAR_DATA *victim )
{
    /*
     * Follow charm thread to responsible character.
     * Attacking someone's charmed char is hostile!
     */
	while ( IS_AFFECTED(victim, AFF_CHARM) && victim->master != NULL )
		victim = victim->master;
	
    /*
     * NPC's are fair game.
     * So are killers and thieves.
     */
	if ( IS_NPC(victim) )
		return;
	
    /*
     * Charm-o-rama.
     */
	if ( IS_SET(ch->affected_by, AFF_CHARM) )
	{
		if ( ch->master == NULL )
		{
			affect_strip( ch, gsn_charm_person );
			REMOVE_BIT( ch->affected_by, AFF_CHARM );
			return;
		}
		stop_follower( ch );
		return;
	}
	return;
}

void calc_stat(CHAR_DATA *ch, CHAR_DATA *victim)
{
	/* Check for attack flag */
	if ( victim->race >= ch->race && victim->race > 0 )
	{
		ch->race++;
		victim->race--;
	}
	ch->pkill++;
	victim->pdeath++;
}