// Formulas take from OSI's combat formulas
// attack speed should be determined here.
// attack speed = 15000 / ((DEX+100) * weapon speed)
static void SetWeaponTimeout(P_CHAR Attacker, P_ITEM Weapon)
{
	int x,j;
	
	if (Weapon) 
	{ 
		if (Weapon->spd==0) Weapon->spd=35;
		x = (15000*MY_CLOCKS_PER_SEC) / ((Attacker->effDex()+100) * Weapon->spd); //Calculate combat delay
	}
	else 
	{
		if(Attacker->skill[WRESTLING]>200) j = 35;
		else if(Attacker->skill[WRESTLING]>400) j = 40;
		else if(Attacker->skill[WRESTLING]>600) j = 45;
		else if(Attacker->skill[WRESTLING]>800) j = 50;
		else j = 30;
		x = (15000*MY_CLOCKS_PER_SEC) / ((Attacker->effDex()+100) * j);
	}
	Attacker->timeout=uiCurrentTime+x;
}
bool cAllTmpEff::Add(P_CHAR pc_source, P_CHAR pc_dest, int num, unsigned char more1, unsigned char more2, unsigned char more3, short dur)
{
    unsigned int ic; // antichrist' changes
    int color, color1, color2, socket; //used for incognito spell
    int	loopexit=0;

    if ( pc_source == NULL || pc_dest == NULL )
        return false;

    if (teffectcount>=cmem*5)
        return false;

    cTmpEff *pTE;
    for (ic=0; ic<teffectcount; ic++)	// If there is already an effect of the same or similar kind, reverse it first (Duke)
    {
        pTE = &teffects[ic];
        if (pTE->getDest() == pc_dest->serial)
        {
            if ((pTE->num==3 && num==3)||
                    (pTE->num==4 && num==4)||
                    (pTE->num==5 && num==5)||
                    (pTE->num==6 && num==6)||
                    (pTE->num==7 && num==7)||
                    (pTE->num==8 && num==8)||
                    (pTE->num==11&& num==11)||
                    (pTE->num==12&& num==12)||
                    (pTE->num==18&& num==18)|| //added Poly reverse - AntiChrist (9/99)
                    (pTE->num==21&& num==21)||
                    (pTE->num==19&& num==19)|| //added Incognito reverse - AntiChrist (12/99)
                    (pTE->num==18&& num==19)|| //reverse poly effect if we have to use incognito - AntiChrist (12/99)
                    (pTE->num==19&& num==18) )  //reverse incognito effect if we have to use poly - AntiChrist (12/99)
            {
                pTE->Reverse();
                AllTmpEff->Remove(pTE);
            }
        }
    }

    pTE=new cTmpEff;
    pTE->Init();
    pTE->setSour(pc_source->serial);
    pTE->setDest(pc_dest->serial);
    pTE->num=num;

    switch (num)
    {
    case 1:
        pc_dest->priv2 |= 0x02;
        pTE->setExpiretime_s(pc_source->skill[MAGERY]/100);
        pTE->more1=0;
        pTE->more2=0;
        pTE->dispellable=1;
        break;
    case 2:	// night sight
        pc_dest->fixedlight=worldbrightlevel;
        dolight(calcSocketFromChar((pc_dest)), worldbrightlevel);
        Magic->afterParticles(6, pc_dest); // shows particles for UO:3D clients, like On OSI servers

        if(dur > 0)		// if a duration is given (potions), use that (Duke, 30.12.2000)
            pTE->setExpiretime_s(dur);
        else
            pTE->setExpiretime_s(pc_source->skill[MAGERY]*10);
        pTE->more1=0;
        pTE->more2=0;
        pTE->dispellable=1;
        break;
    case 3:
        if (pc_dest->effDex()<more1)
            more1=pc_dest->effDex();
        pc_dest->chgDex(-1 * more1);
        pc_dest->stm=min(pc_dest->stm, (int)pc_dest->effDex());
        statwindow(calcSocketFromChar(pc_dest), pc_dest);
        pTE->setExpiretime_s(pc_source->skill[MAGERY]/10);
        pTE->more1=more1;
        pTE->more2=0;
        pTE->dispellable=1;
        break;
    case 4:
        if (pc_dest->in<more1)
            more1=pc_dest->in;
        pc_dest->in-=more1;
        pc_dest->mn=min(pc_dest->mn, pc_dest->in);
        statwindow(calcSocketFromChar(pc_dest), pc_dest);
        pTE->setExpiretime_s(pc_source->skill[MAGERY]/10);
        pTE->more1=more1;
        pTE->more2=0;
        pTE->dispellable=1;
        break;
    case 5:
        if (pc_dest->st<more1)
            more1=pc_dest->st;
        pc_dest->st-=more1;
        pc_dest->hp=min(pc_dest->hp, pc_dest->st);
        statwindow(calcSocketFromChar(pc_dest), pc_dest);
        pTE->setExpiretime_s(pc_source->skill[MAGERY]/10);
        pTE->more1=more1;
        pTE->more2=0;
        pTE->dispellable=1;
        break;
    case 6:
        if (pc_dest->effDex()+more1>250)
            more1=250-pc_dest->effDex();
        pc_dest->chgDex(more1);
        statwindow(calcSocketFromChar(pc_dest), pc_dest);
        if(dur > 0)		// if a duration is given (potions), use that (Duke, 31.10.2000)
            pTE->setExpiretime_s(dur);
        else
            pTE->setExpiretime_s(pc_source->skill[MAGERY]/10);
        pTE->more1=more1;
        pTE->more2=0;
        pTE->dispellable=1;
        break;
    case 7:
        if (pc_dest->in+more1>255)
            more1=pc_dest->in-255;
        pc_dest->in+=more1;
        statwindow(calcSocketFromChar(pc_dest), pc_dest);
        pTE->setExpiretime_s(pc_source->skill[MAGERY]/10);
        pTE->more1=more1;
        pTE->more2=0;
        pTE->dispellable=1;
        break;
    case 8:
        if (pc_dest->st+more1>255)
            more1=pc_dest->st-255;
        pc_dest->st+=more1;
        statwindow(calcSocketFromChar(pc_dest), pc_dest);
        if(dur > 0)		// if a duration is given (potions), use that (Duke, 31.10.2000)
            pTE->setExpiretime_s(dur);
        else			// else use caster's skill
            pTE->setExpiretime_s(pc_source->skill[MAGERY]/10);
        pTE->more1=more1;
        pTE->more2=0;
        pTE->dispellable=1;
        break;
    case 9:
        pTE->setExpiretime_s(more2);
        pTE->more1=more1;
        pTE->more2=more2;
        break;
    case 10:
        pTE->setExpiretime_s(12);
        pTE->more1=more1;
        pTE->more2=more2;
        break;
    case 11: // Bless
        if (pc_dest->st+more1>255)
            more1=pc_dest->st-255;
        if (pc_dest->effDex()+more2>250)
            more2=250-pc_dest->effDex();
        if (pc_dest->in+more3>255)
            more3=pc_dest->in-255;
        pc_dest->st+=more1;
        pc_dest->chgDex(more2);
        pc_dest->in+=more3;
        statwindow(calcSocketFromChar(pc_dest), pc_dest);
        pTE->setExpiretime_s(pc_source->skill[MAGERY]/10);
        pTE->more1=more1;
        pTE->more2=more2;
        pTE->more3=more3;
        pTE->dispellable=1;
        break;
    case 12: // Curse
        if (pc_dest->st<more1)
            more1=pc_dest->st;
        if (pc_dest->effDex()<more2)
            more2=pc_dest->effDex();
        if (pc_dest->in<more3)
            more3=pc_dest->in;
        pc_dest->st-=more1;
        pc_dest->chgDex(-1 * more2);
        pc_dest->in-=more3;
        statwindow(calcSocketFromChar(pc_dest), pc_dest);
        pTE->setExpiretime_s(pc_source->skill[MAGERY]/10);
        pTE->more1=more1;
        pTE->more2=more2;
        pTE->more3=more3;
        pTE->dispellable=1;
        break;
    case 15: // Reactive armor
        pTE->setExpiretime_s(pc_source->skill[MAGERY]/10);
        pTE->dispellable=1;
        break;
    case 16: //Explosion potions	Tauriel
        pTE->setExpiretime_s(more2);
        pTE->more1=more1; //item/potion
        pTE->more2=more2; //seconds
        pTE->more3=more3; //countdown#
        break;
    case 18: //Polymorph - AntiChrist 09/99
        pTE->setExpiretime_s(polyduration);

        int c1,b,k;
        //Grey flag when polymorphed - AntiChrist (9/99)
        pc_dest->crimflag=(polyduration*MY_CLOCKS_PER_SEC)+uiCurrentTime;
        if(pc_dest->onhorse)
            k = unmounthorse(calcSocketFromChar(pc_dest));
        k=(more1<<8)+more2;

        pc_dest->xid = pc_dest->id();//let's backup previous id

        if (k>=0x000 && k<=0x3e1) // lord binary, body-values >0x3e crash the client
        {
            pc_dest->id1=k>>8; // allow only non crashing ones
            pc_dest->id2=k%256;

            c1 = pc_dest->skin; // transparency for monsters allowed, not for players,
            // if polymorphing from monster to player we have to switch from transparent to semi-transparent
            b=c1&0x4000;
            if (b==16384 && (k >=0x0190 && k<=0x03e1))
            {
                if (c1!=0x8000)
                {
                    pc_dest->skin = pc_dest->xskin = 0xF000;
                }
            }
        }
        pc_dest->polymorph=true;
        break;
    case 19://incognito spell - AntiChrist (10/99)//revised by AntiChrist - 9/12/99
    {
        pTE->setExpiretime_s(90);

        //AntiChrist 11/11/99
        //If char is already under polymorph effect, let's reverse the
        //polymorph effect to avoid problems
        if(pc_dest->polymorph)
        {
            pc_dest->setId(pc_dest->xid);
            pc_dest->polymorph=false;
            teleport(pc_dest);
        }
        int j;

        //first: let's search for beard and hair serial
        //(we could use alredy saved serials...but it's better
        //to recalculate them)
        pc_dest->hairserial=-1;
        pc_dest->beardserial=-1;

        P_ITEM pi;
        unsigned int ci;
        vector<SERIAL> vecContainer = contsp.getData(pc_dest->serial);
        for ( ci = 0; ci < vecContainer.size(); ci++)
        {
            pi = FindItemBySerial(vecContainer[ci]);
            if(pi->layer==0x10)//beard
                pc_dest->beardserial=pi->serial;
            if(pi->layer==0x0B)//hairs
                pc_dest->hairserial=pi->serial;
        }
        // ------ SEX ------
        pc_dest->xid = pc_dest->id();
        pc_dest->id1=0x01;
        //if we already have a beard..can't turn to female
        if(pc_dest->beardserial>-1)
        {   //if character has a beard...only male
            pc_dest->id2='\x90';//male
        } else
        {   //if no beard let's randomly change
            if((rand()%2)==0) pc_dest->id2='\x90';//male
            else pc_dest->id2='\x91';//or female
        }

        // --- SKINCOLOR ---
        pc_dest->xskin = pc_dest->skin;
        color=rand()%6;
        switch(color)
        {
        case 0:
            pc_dest->skin = 0x83EA;
            break;
        case 1:
            pc_dest->skin = 0x8405;
            break;
        case 2:
            pc_dest->skin = 0x83EF;
            break;
        case 3:
            pc_dest->skin = 0x83F5;
            break;
        case 4:
            pc_dest->skin = 0x841C;
            break;
        case 5:
            pc_dest->skin = 0x83FB;
            break;
        default:
            break;
        }

        // ------ NAME -----
        pc_dest->orgname = pc_dest->name;

        if(pc_dest->id2==0x90)
            setrandomname(pc_dest, "1");//get a name from male list
        else
            setrandomname(pc_dest, "2");//get a name from female list

        //
        //damn..this formula seems to include also some bad color...
        //i'll test this later
        //AntiChrist
        //
        //use unique color for hair&beard
        //color=0x044E+(rand()%(0x04AD-0x044E));

        //i had to track down some valid value
        //for hair/beard colors, cause that
        //formula contained some bad value =(
        //but now it works perfectly :)
        //AntiChrist-11/11/99
        color=rand()%8;
        switch(color)
        {
        case 0:
            color=0x044e;
            break;
        case 1:
            color=0x0455;
            break;
        case 2:
            color=0x045e;
            break;
        case 3:
            color=0x0466;
            break;
        case 4:
            color=0x046a;
            break;
        case 5:
            color=0x0476;
            break;
        case 6:
            color=0x0473;
            break;
        case 7:
            color=0x047c;
            break;
        default://it should not go here...but..who nows =P
            color=0x044e;
        }
        color1=color>>8;
        color2=color%256;

        // ------ HAIR -----
        if(pc_dest->hairserial>-1)//if hairs exist
        {   //change hair style/color
            P_ITEM pHair = FindItemBySerial(pc_dest->hairserial);
            if(pHair)
            {
                //stores old hair values...
                pHair->moreb1 = static_cast<unsigned char>(pHair->color>>8);
                pHair->moreb2 = static_cast<unsigned char>(pHair->color%256);
                pHair->moreb3=pHair->id1;
                pHair->moreb4=pHair->id2;

                //and change them with random ones
                switch(rand()%10)
                {
                case 0:
                    pHair->id2='\x3B';
                    break;
                case 1:
                    pHair->id2='\x3C';
                    break;
                case 2:
                    pHair->id2='\x3D';
                    break;
                case 3:
                    pHair->id2='\x44';
                    break;
                case 4:
                    pHair->id2='\x45';
                    break;
                case 5:
                    pHair->id2='\x46';
                    break;
                case 6:
                    pHair->id2='\x47';
                    break;
                case 7:
                    pHair->id2='\x48';
                    break;
                case 8:
                    pHair->id2='\x49';
                    break;
                case 9:
                    pHair->id2='\x4A';
                    break;
                default:
                    pHair->id2='\x4A';
                    break;
                }

                //random color
                pHair->color = color;
                //let's check for invalid values
                if ( pHair->color < 0x044E || pHair->color > 0x04AD )
                {
                    pHair->color = 0x044E;
                }

                pHair->incognito = true;//AntiChrist
            }//if j!=-1
        }//if hairserial!=-1


        // -------- BEARD --------
        if(pc_dest->id2==0x90)// only if a man
            if(pc_dest->beardserial>-1)//if beard exist
            {   //change beard style/color
                P_ITEM pBeard = FindItemBySerial(pc_dest->beardserial);
                if(pBeard)
                {
                    //clConsole.send("BEARD FOUND!!\n");
                    //stores old beard values
                    pBeard->moreb1 = static_cast<unsigned char>(pBeard->color>>8);
                    pBeard->moreb2 = static_cast<unsigned char>(pBeard->color%256);
                    pBeard->moreb3 = static_cast<unsigned char>(pBeard->id() >> 8);
                    pBeard->moreb4 = static_cast<unsigned char>(pBeard->id()%256);

                    //changes them with random ones
                    switch(rand()%7)
                    {
                    case 0:
                        pBeard->id2='\x3E';
                        break;
                    case 1:
                        pBeard->id2='\x3F';
                        break;
                    case 2:
                        pBeard->id2='\x40';
                        break;
                    case 3:
                        pBeard->id2='\x41';
                        break;
                    case 4:
                        pBeard->id2='\x4B';
                        break;
                    case 5:
                        pBeard->id2='\x4C';
                        break;
                    case 6:
                        pBeard->id2='\x4D';
                        break;
                    default:
                        pBeard->id2='\x4D';
                        break;
                    }

                    //random color
                    pBeard->color = color;

                    if ( pBeard->color < 0x044E || pBeard->color > 0x04AD )
                    {
                        pBeard->color = 0x044E;
                    }

                    pBeard->incognito=true;//AntiChrist
                }//if j!=-1
            }//if beardserial!=-1
void cDragItems::equipItem( P_CLIENT client )
{
	// Get the packet information
	SERIAL itemId = LongFromCharPtr( &buffer[ client->socket() ][ 1 ] );
	SERIAL playerId = LongFromCharPtr( &buffer[ client->socket() ][ 6 ] );

	P_ITEM pItem = FindItemBySerial( itemId );
	P_CHAR pWearer = FindCharBySerial( playerId );

	if( !pItem || !pWearer )
		return;

	P_CHAR pChar = client->player();

	// We're dead and can't do that
	if( pChar->dead )
	{
		client->sysMessage( "You are dead and can't do that." );
		bounceItem( client, pItem );
		return;
	}

	// Our target is dead
	if( ( pWearer != pChar ) && pWearer->dead )
	{
		client->sysMessage( "You can't equip dead players." );
		bounceItem( client, pItem );
		return;
	}

	// Get our tile-information
	tile_st pTile;
	Map->SeekTile( pItem->id(), &pTile );

	// Is the item wearable ? ( layer == 0 | equip-flag not set )
	// Multis are not wearable are they :o)
	if( pTile.layer == 0 || !( pTile.flag3 & 0x40 ) || pItem->isMulti() )
	{
		client->sysMessage( "This item cannot be equipped." );
		bounceItem( client, pItem );
		return;
	}

	// Required Strength
	if( pItem->st > pWearer->st )
	{
		if( pWearer == pChar )
			client->sysMessage( "You cannot wear that item, you seem not strong enough" );
		else
			client->sysMessage( "This person can't wear that armor, it seems not strong enough" );

		bounceItem( client, pItem );
		return;
	}

	// Required Dexterity
	if( pItem->dx > pWearer->effDex() )
	{
		if( pWearer == pChar )
			client->sysMessage( "You cannot wear that item, you seem not agile enough" );
		else
			client->sysMessage( "This person can't wear that armor, it seems not agile enough" );

		bounceItem( client, pItem );
		return;
	}
	
	// Required Intelligence
	if( pItem->in > pWearer->in )
	{
		if( pWearer == pChar )
			client->sysMessage( "You cannot wear that item, you seem not smart enough" );
		else
			client->sysMessage( "This person can't wear that armor, it seems not smart enough" );

		bounceItem( client, pItem );
		return;
	}

	// Males can't wear female armor
	if( ( pChar->id() == 0x0190 ) && ( pItem->id() >= 0x1C00 ) && ( pItem->id() <= 0x1C0D ) )
	{
		client->sysMessage( "You cannot wear female armor." );
		bounceItem( client, pItem );
		return;
	}

	// Needs a check (!)
	// Checks for equipment on the same layer
	// If there is any it tries to unequip it
	// If that fails it cancels
	UI08 layer = pItem->layer();
	vector< SERIAL > equipment = contsp.getData( pWearer->serial );

	for( UI32 i = 0; i < equipment.size(); i++ )
	{
		P_ITEM pEquip = FindItemBySerial( equipment[ i ] );

		if( pEquip )
			continue;

		// We found an item which is on the same layer (!)
		// Unequip it if we can 
		bool twoHanded = false;

		if( pEquip->twohanded() && ( layer == 1 || layer == 2 ) )
			twoHanded = true;

		if( pItem->twohanded() && ( pEquip->layer() == 1 || pEquip->layer() == 2 ) )
			twoHanded = true;
			
		if( ( pEquip->layer() == layer ) || twoHanded )
		{
			if( pChar->canPickUp( pEquip ) ) // we're equipping so we do the check
				pEquip->toBackpack( pWearer );

			// If it's still on the char: cancel equipment
			if( pEquip->contserial == pWearer->serial )
			{
				client->sysMessage( "You already have an item on that layer." );
				bounceItem( client, pItem );
				return;
			}
		}
	}

	// At this point we're certain that we can wear the item
	pItem->setContSerial( playerId );
	pItem->setLayer( pTile.layer ); // Don't trust the user input on this one

	// Handle the weight if the item is leaving our "body"
	if( pWearer != pChar )
	{
		pChar->weight -= pItem->getWeight();
		pWearer->weight += pItem->getWeight();

		// Update the status-windows
		statwindow( client->socket(), pChar );
		statwindow( calcSocketFromChar( pWearer ), pWearer );
	}

	if( pTile.layer == 0x19 )
		pWearer->setOnHorse( true );

	// Apply the bonuses
	pWearer->st += pItem->st2;
	pWearer->chgDex( pItem->dx2 );
	pWearer->in += pItem->in2;

	// Show debug information if requested
	if( showlayer )
		clConsole.send( QString( "Item (%1) equipped on layer %2" ).arg( pItem->name() ).arg( pItem->layer() ) );

	// I don't think we need to remove the item
	// as it's only visible to the current char
	// And he looses contact anyway
	// SndRemoveitem( pi->serial );

	// Build our packets
	cWornItems wearItem( pWearer->serial, pItem->serial, pItem->layer(), pItem->id(), pItem->color() );
	cSoundEffect soundEffect( 0x57, pWearer->pos );

	// Send to all sockets in range
	// ONLY the new equipped item and the sound-effect
	for( UOXSOCKET s = 0; s < now; s++ )
		if( perm[s] && inrange1p( pWearer, currchar[s] ) )
		{
			soundEffect.send( s );
			wearItem.send( s );
		}

	// Lord Binaries Glow stuff
	if( pItem->glow != INVALID_SERIAL )
	{
		pChar->removeHalo( pItem );
		pWearer->addHalo( pItem );
		pWearer->glowHalo( pItem );
	}
}
void cCombat::DoCombat(P_CHAR pc_attacker, unsigned int currenttime)
{
	int x, bowtype=0;// spamanachecking, tmp;

	if ( pc_attacker == NULL )
		return;
	if (pc_attacker->free) return;
	P_ITEM pWeapon=pc_attacker->getWeapon();

	P_CHAR pc_defender = FindCharBySerial(pc_attacker->targ);
	/*if (pc_attacker->priv2&2) //The char is paralyzed 
	{ 
        sysmessage(calcSocketFromChar(pc_attacker), "You are frozen and cannot attack."); 
        return; 
	}*/
	if ((pc_defender == NULL) || (pc_defender->isPlayer() && !online(pc_defender) || pc_defender->isHidden()) && pc_attacker->war)
	{
		pc_attacker->war=false; // LB
		pc_attacker->timeout=0;
		pc_attacker->attacker = INVALID_SERIAL;
		pc_attacker->resetAttackFirst();
		return;
	}
	if (( pc_attacker->isNpc() || online(pc_attacker) ) && pc_defender != NULL )
	{			
		if (pc_defender == NULL) return;
		if (pc_defender->free) return;
		if (pc_attacker->dispz > (pc_defender->dispz +10)) return;//FRAZAI
		if (pc_attacker->dispz < (pc_defender->dispz -10)) return;//FRAZAI
		
		if ((pc_defender->isNpc() && pc_defender->npcaitype!=17) || (online(pc_defender) && !pc_defender->dead) ) // ripper		
		{
			if (chardist( pc_attacker, pc_defender ) > SrvParams->attack_distance())
			{
				if (pc_attacker->npcaitype==4 && pc_attacker->inGuardedArea()) // changed from 0x40 to 4, LB
				{
					pc_attacker->moveTo(pc_defender->pos);
					
					teleport(pc_attacker);
					soundeffect2(pc_attacker, 0x01FE); // crashfix, LB
					staticeffect(pc_attacker, 0x37, 0x2A, 0x09, 0x06);
					npctalkall(pc_attacker,"Halt, scoundrel!",1);
				}
				else 
				{ // else -> npcaityes != 4
					pc_attacker->targ = INVALID_SERIAL;
					pc_attacker->timeout=0;
					P_CHAR pc = FindCharBySerial(pc_attacker->attacker);
					if (pc != NULL)
					{
						pc->resetAttackFirst();
						pc->attacker = INVALID_SERIAL; // lb crashfix
					}
					pc_attacker->attacker=INVALID_SERIAL;
					pc_attacker->resetAttackFirst();
					if (pc_attacker->isNpc() && pc_attacker->npcaitype!=17 && !pc_attacker->dead && pc_attacker->war)
						npcToggleCombat(pc_attacker); // ripper
				}
			}
			else
			{
				if (pc_attacker->targ == INVALID_SERIAL)
				{
					npcsimpleattacktarget(pc_attacker, pc_defender);
					x=(((100-pc_attacker->effDex())*MY_CLOCKS_PER_SEC)/25)+(1*MY_CLOCKS_PER_SEC); //Yet another attempt.
					pc_attacker->timeout=currenttime+x;
					return;
				}
				if (Combat->TimerOk(pc_attacker))
				{
					int los = line_of_sight(-1, pc_attacker->pos, pc_defender->pos, WALLS_CHIMNEYS+DOORS+FLOORS_FLAT_ROOFING);
					UOXSOCKET s1 = calcSocketFromChar(pc_attacker);
					int fightskill=Skills->GetCombatSkill(pc_attacker);
					x=0;
					if (fightskill==ARCHERY)
					{
						if (los)
						{
							int arrowsquant;
							bowtype=Combat->GetBowType(pc_attacker);
							if (bowtype==1) 
								arrowsquant=getamount(pc_attacker, 0x0F3F);
							else 
								arrowsquant=getamount(pc_attacker, 0x1BFB);
							if (arrowsquant>0)
								x=1;
							//else
							//	sysmessage(s1, "You are out of ammunitions!"); //-Fraz- this message can cause problems removed
						}
					}
					if ( chardist( pc_attacker, pc_defender )<2 && fightskill!=ARCHERY ) x=1;
					if (x)
					{
						// - Do stamina maths - AntiChrist (6) -
						if(abs(SrvParams->attackstamina())>0 && !pc_attacker->isGM())
						{
							if((SrvParams->attackstamina()<0)&&(pc_attacker->stm<abs(SrvParams->attackstamina())))
							{
								sysmessage(s1, tr("You are too tired to attack."));
								SetWeaponTimeout(pc_attacker, pWeapon);
								return;
							}
							pc_attacker->stm += SrvParams->attackstamina();
							if (pc_attacker->stm>pc_attacker->effDex()) pc_attacker->stm=pc_attacker->effDex();
							if (pc_attacker->stm<0) pc_attacker->stm=0;
							updatestats((pc_attacker),2); //LB, crashfix, was currchar[a]
							// --------ATTACK STAMINA END ------
						}
						
						DoCombatAnimations( pc_attacker, pc_defender, fightskill, bowtype, los);

						if (((chardist( pc_attacker, pc_defender )<2)||(fightskill==ARCHERY))&&!(pc_attacker->npcaitype==4)) // changed from 0x40 to 4
                        {
							if (los)
							{
								npcsimpleattacktarget(pc_attacker, pc_defender);
							}
						}
						if (pc_attacker->timeout2 > uiCurrentTime) return; //check shotclock memory-BackStab
						if (fightskill==ARCHERY)
							Combat->CombatHit(pc_attacker, pc_defender, currenttime,los);
						else
							pc_attacker->swingtarg = pc_defender->serial;
					}

					SetWeaponTimeout(pc_attacker, pWeapon);
					pc_attacker->timeout2=pc_attacker->timeout; // set shotclock memory-BackStab
					if (!pc_defender->isInvul())
					{
						NpcSpellAttack(pc_attacker,pc_defender,currenttime,los);
					}
					if (fightskill!=ARCHERY)
					{
						Combat->CombatHit(pc_attacker, pc_defender, currenttime, los); // LB !!!
						//return; // Ripper	???? (Duke)
					}
				}
			}			
			if (pc_defender->hp<1)//Highlight //Repsys
			{
				if((pc_attacker->npcaitype==4 || pc_attacker->npcaitype==9) && pc_defender->isNpc())
				{
					npcaction(pc_defender, 0x15);
					
					PlayDeathSound(pc_defender);
					
					Npcs->DeleteChar(pc_defender);//Guards, don't give body
				}
				else
				{
					deathstuff(pc_defender);
				}
				//murder count \/
				
				if ((pc_attacker->isPlayer())&&(pc_defender->isPlayer()))//Player vs Player
				{
					if(pc_defender->isInnocent() && GuildCompare(pc_attacker, pc_defender )==0 )
					{
						++pc_attacker->kills;
						UOXSOCKET attacker_socket = calcSocketFromChar(pc_attacker);
						sysmessage(attacker_socket, tr("You have killed %1 innocent people.").arg(pc_attacker->kills));
						//clConsole.send("DEBUG %s's kills are now -> %i\n",pc_attacker->name,pc_attacker->kills);
						if (pc_attacker->kills==SrvParams->maxkills()+1)
							sysmessage(attacker_socket, tr("You are now a murderer!"));
					}
					
					if (SrvParams->pvpLog())
					{
						sprintf((char*)temp,"%s was killed by %s!\n",pc_defender->name.c_str(), pc_attacker->name.c_str());
						savelog((char*)temp,"PvP.log");
					}
					
				}
				npcToggleCombat(pc_attacker);
				return; // LB
			}
		}
	}
}
// CombatHit now expects that LineOfSight has been checked before (Duke, 10.7.2001)
void cCombat::CombatHit(P_CHAR pc_attacker, P_CHAR pc_deffender, unsigned int currenttime, short los)
{
	char hit;

	if (pc_deffender == NULL || pc_attacker == NULL)
		return;

	UOXSOCKET s1=calcSocketFromChar(pc_attacker), s2=calcSocketFromChar(pc_deffender);
	unsigned short fightskill = Skills->GetCombatSkill(pc_attacker), bowtype = Combat->GetBowType(pc_attacker),splitnum,splitcount,hitin;
	unsigned int basedamage;
	int damage; // removed from unsigne by Magius(CHE)
	signed int x;
	// Magius(CHE) - For armour absorbtion system
	int maxabs, maxnohabs, tmpj;


	P_ITEM pWeapon=pc_attacker->getWeapon();// get the weapon item only once

	if (pWeapon && !(rand()%50)	// a 2 percent chance (Duke, 07.11.2000)
		&& pWeapon->type !=9)	// but not for spellbooks (Duke, 09/10/00)
	{
		pWeapon->hp--; //Take off a hit point
		if(pWeapon->hp<=0)
		{
			sysmessage(s1, tr("Your weapon has been destroyed"));
			if ((pWeapon->trigon==1) && (pWeapon->layer>0))// -Frazurbluu- Trigger Type 2 is my new trigger type *-
			{
				Trig->triggerwitem(s1, pWeapon, 1); // trigger is fired when item destroyed
			}				
			Items->DeleItem(pWeapon);
		}
	}

	// End here - Magius(CHE) - For armour absorbtion system



	pc_attacker->swingtarg=-1;

	if((chardist(pc_attacker, pc_deffender)>1 && fightskill!=ARCHERY) || !los) return;
	if(pc_deffender->isNpc() && pc_deffender->isInvul()) return; // ripper


	hit=Skills->CheckSkill(pc_attacker, fightskill, 0, 1000);  // increase fighting skill for attacker and defender
	if (!hit)
	{
		if (pc_attacker->isPlayer())
			doMissedSoundEffect(pc_attacker);
		if ((fightskill==ARCHERY)&&(los))
		{
			if (rand()%3-1)//-1 0 or 1
			{
				short id=0x1BFB;	// bolts
				if (bowtype==1)
					id=0x0F3F;		// arrows

				P_ITEM pAmmo=Items->SpawnItem(pc_deffender,1,"#",1,id,0,0);
				if(pAmmo)
				{
					pAmmo->moveTo(pc_deffender->pos);
					pAmmo->priv=1;
					RefreshItem(pAmmo);
				}
			}
		}
	}
	else
	{
		if (!pc_deffender->isInvul())
		{
			if (pc_deffender->xid==0x0191) soundeffect2(pc_deffender,0x014b);
			else if (pc_deffender->xid==0x0190) soundeffect2(pc_deffender,0x0156);
			playmonstersound(pc_deffender, pc_deffender->id(), SND_DEFEND);
			//AntiChrist -- for poisoned weapons
			if((pWeapon) && (pWeapon->poisoned>0))
			{
				   pc_deffender->poisoned=pWeapon->poisoned;
				   pc_deffender->poisontime=uiCurrentTime+(MY_CLOCKS_PER_SEC*(40/pc_deffender->poisoned)); // a lev.1 poison takes effect after 40 secs, a deadly pois.(lev.4) takes 40/4 secs - AntiChrist
			       pc_deffender->poisonwearofftime=pc_deffender->poisontime+(MY_CLOCKS_PER_SEC*SrvParams->poisonTimer()); //wear off starts after poison takes effect - AntiChrist
			}
			CheckPoisoning(s2, pc_attacker, pc_deffender);	// attacker poisons defender
			CheckPoisoning(s1, pc_deffender, pc_attacker); // and vice versa

			if ((pc_deffender->effDex()>0)) pc_deffender->priv2&=0xFD;	// unfreeze

			if (fightskill!=WRESTLING && los)
				Combat->ItemSpell(pc_attacker, pc_deffender);
			
			if (fightskill!=WRESTLING || pc_attacker->isNpc())
				basedamage=Combat->CalcAtt(pc_attacker); // Calc base damage
			else
			{
				if ((pc_attacker->skill[WRESTLING]/100) > 0) 
				{
					if (pc_attacker->skill[WRESTLING]/100!=0)
						basedamage=rand()%(pc_attacker->skill[WRESTLING]/100);
					else basedamage=0;
				}
				else basedamage=rand()%2;
			}

			if((pc_attacker->isPlayer()) && (fightskill!=WRESTLING))
			{ 
				if (pWeapon->racehate != 0 && pc_deffender->race != 0)//-Fraz- Racehating combat
				{
					if (pWeapon->racehate==pc_deffender->race)
					{
						basedamage *=2;
							if(pc_deffender->isPlayer())
							{
								sysmessage(s2, tr("You scream in agony from being hit by the accursed metal!"));
								if (pc_deffender->xid == 0x0191) soundeffect2(pc_deffender,0x0152);
								else if (pc_deffender->xid==0x0190) soundeffect2(pc_deffender,0x0157);
							}// can add a possible effect below here for npc's being hit
					}
							
				}
			}
			Skills->CheckSkill(pc_attacker, TACTICS, 0, 1000);
			damage=(int)(basedamage*((pc_attacker->skill[TACTICS]+500.0)/1000.0)); // Add Tactical bonus
			damage=damage+(int)((basedamage*(pc_attacker->st/500.0))); // Add Strength bonus

			//Adds a BONUS DAMAGE for ANATOMY
			//Anatomy=100 -> Bonus +20% Damage - AntiChrist (11/10/99)
			if (Skills->CheckSkill(pc_attacker, ANATOMY, 0, 1000))
			{
				float multiplier=(((pc_attacker->skill[ANATOMY]*20)/1000.0f)/100.0f)+1;
				damage=(int)  (damage * multiplier);
			}
			//Adds a BONUS DEFENCE for TACTICS
			//Tactics=100 -> Bonus -20% Damage - AntiChrist (11/10/99)
			float multiplier=1-(((pc_deffender->skill[TACTICS]*20)/1000.0f)/100.0f);
			damage=(int)  (damage * multiplier);
			P_ITEM pShield=pc_deffender->getShield();
			if(pShield)
			{
				if (Skills->CheckSkill(pc_deffender, PARRYING, 0, 1000))// chance to block with shield
				{
					if (pShield->def!=0) damage-=rand()%(pShield->def);// damage absorbed by shield
					if(rand()%2) pShield->hp--; //Take off a hit point
					if(pShield->hp<=0)
					{
						sysmessage(s2, tr("Your shield has been destroyed"));
						if ((pShield->trigon==1) && (pShield->layer >0))// -Frazurbluu- Trigger Type 2 is my new trigger type *-
						{
							Trig->triggerwitem(s2, pShield, 1); // trigger is fired when item destroyed
						}	
						Items->DeleItem(pShield);
					}
				}
			}
			// Armor destruction and sped up by hitting with maces should go in here somewhere 
			// According to lacation of body hit Id imagine -Frazurbluu- **NEEDS ADDED**
			x=rand()%100;// determine area of body hit
			if (!SrvParams->combatHitMessage())
			{
				if (x<=44) x=1; // body
				else if (x<=58) x=2; // arms
				else if (x<=72) x=3; // head
				else if (x<=86) x=4; // legs
				else if (x<=93) x=5; // neck
				else x=6; // hands
			}
			else
			{
				temp[0] = '\0';
				hitin = rand()%2;
				if (x<=44)
				{
					x=1;       // body
					switch (hitin)
					{
					case 1:
						//later take into account dir facing attacker during battle
						if (damage < 10) strcpy(temp, "hits you in your Chest!");
						else if (damage >=10) strcpy(temp, "lands a terrible blow to your Chest!");
						break;
					case 2:
						if (damage < 10) strcpy(temp, "lands a blow to your Stomach!");
						else if (damage >=10) strcpy(temp, "knocks the wind out of you!");
						break;
					default:
						if (damage < 10) strcpy(temp, "hits you in your Ribs!");
						else if (damage >=10) strcpy(temp, "broken your Rib?!");
					}
				}
				else if (x<=58)
				{
					if (damage > 1)
					{
						x=2;  // arms
						switch (hitin)
						{
						case 1:	strcpy(temp, "hits you in Left Arm!");	break;
						case 2:	strcpy(temp, "hits you in Right Arm!");	break;
						default:strcpy(temp, "hits you in Right Arm!");
						}
					}
				}
				else if (x<=72)
				{
					x=3;  // head
					switch (hitin)
					{
					case 1:
						if (damage < 10) strcpy(temp, "hits you you straight in the Face!");
						else if (damage >=10) strcpy(temp, "lands a stunning blow to your Head!");
						break;
					case 2:
						if (damage < 10) strcpy(temp, "hits you to your Head!"); //kolours - (09/19/98)
						else if (damage >=10) strcpy(temp, "smashed a blow across your Face!");
						break;
					default:
						if (damage < 10) strcpy(temp, "hits you you square in the Jaw!");
						else if (damage >=10) strcpy(temp, "lands a terrible hit to your Temple!");
					}
				}
				else if (x<=86) 
				{
					x=4;  // legs
					switch (hitin)
					{
					case 1:	strcpy(temp, "hits you in Left Thigh!");	break;
					case 2:	strcpy(temp, "hits you in Right Thigh!");	break;
					default:strcpy(temp, "hits you in Groin!");
					}
				}
				else if (x<=93)
				{
					x=5;  // neck
					strcpy(temp, "hits you to your Throat!");
				}
				else
				{
					x=6;  // hands
					switch (hitin)
					{
					case 1:
						if (damage > 1) strcpy(temp, tr("hits you in Left Hand!").latin1());
						break;
					case 2:
						if (damage > 1) strcpy(temp, tr("hits you in Right Hand!").latin1());
						break;
					default:
						if (damage > 1) strcpy(temp, tr("hits you in Right Hand!").latin1());
					}
				}

				sprintf((char*)temp2,"%s %s",pc_attacker->name.c_str(), temp);
				if (pc_deffender->isPlayer() && s2!=-1) sysmessage(s2, (char*)temp2); //kolours -- hit display
			}
			x = CalcDef(pc_deffender,x);
			
			// Magius(CHE) - For armour absorbtion system
			maxabs = 20; //
			           // there are monsters with DEF >20, this makes them undefeatable
			maxnohabs=100;
			if (SrvParams->maxAbsorbtion() > 0)
			{
				maxabs = SrvParams->maxAbsorbtion();
			}
			if (SrvParams->maxnohabsorbtion() > 0)
			{
				maxnohabs = SrvParams->maxnohabsorbtion();
			}		
			if (!ishuman(pc_deffender)) maxabs=maxnohabs;
			tmpj=(int) (damage*x)/maxabs; // Absorbtion by Magius(CHE)
			damage -= tmpj;
			if (damage<0) damage=0;
			if (pc_deffender->isPlayer()) damage /= SrvParams->npcdamage(); // Rate damage against other players
			// End Armour Absorbtion by Magius(CHE) (See alse reactive armour spell damage)

			if (pc_attacker->isPlayer())//Zippy
				ItemCastSpell(s1, pc_deffender,pWeapon);

			//AntiChrist - 26/10/99
			//when hitten and damage >1, defender fails if casting a spell!
			if(damage>1 && pc_deffender->isPlayer())//only if damage>1 and against a player
			{
				if(pc_deffender->casting && currentSpellType[s2]==0 )
				{//if casting a normal spell (scroll: no concentration loosen)
					Magic->SpellFail(s2);
					currentSpellType[s2]=0;
					pc_deffender->spell=-1;
					pc_deffender->casting=0;
					pc_deffender->spelltime=0;
					pc_deffender->priv2 &= 0xfd; // unfreeze, bugfix LB
				}
			}

			if(damage>0)
			{
				if (pc_deffender->ra) // For reactive armor spell
				{
					// -Frazurbluu- RA may need a rewrite to be more OSI standard here
					// Its said 80% deflected 10% to attacker / 10% defender gotta check special effects
					int damage1;
					damage1=(int)( damage*(pc_deffender->skill[MAGERY]/2000.0));
					pc_deffender->hp -= damage-damage1;
					if (pc_deffender->isNpc()) damage1 = damage1 * SrvParams->npcdamage(); // by Magius(CHE)
					pc_attacker->hp -= damage1;  // Remove damage from attacker
					staticeffect(pc_deffender, 0x37, 0x4A, 0, 15);//RA effect - AntiChrist (9/99)
					if ((fightskill==MACEFIGHTING) && (IsSpecialMace(pWeapon->id())))// Stamina Loss -Fraz-
					{ 
						//pc_attacker->stm-=3+(rand()%4);
					}
					if ((fightskill==FENCING) && (IsFencing2H(pWeapon->id())))// Paralyzing -Fraz-
					{ 
						//will call the combat caused paralyzation **NEED TO DO**
					}
					if ((fightskill==SWORDSMANSHIP) && (IsAxe(pWeapon->id())))// Concussion Hit -Fraz-
					{ 
						//will call the combat caused concussion (loss of int for 30 secs) **NEED TO DO**
						// for now make it subtract mana
						//pc_attacker->mn-=(pc_attacker->mn/2);
					}
					updatestats(pc_attacker, 0);
				}
				else 
				{	// -Fraz- Now needs adjusted to happen on a skill percentage 
					pc_deffender->hp-=damage; // Remove damage from defender only apply special hits to non-npc's
					if ((fightskill==MACEFIGHTING) && (IsSpecialMace(pWeapon->id())) && (pc_deffender->isPlayer()))// Stamina Loss -Fraz-
					{ 
						pc_deffender->stm-=3+(rand()%3);
					}
					if ((fightskill==FENCING) && (IsFencing2H(pWeapon->id())) && (pc_deffender->isPlayer()))// Paralyzing -Fraz-
					{ 
						tempeffect(pc_attacker, pc_deffender, 44, 0, 0, 0);
						sysmessage(s1, tr("You delivered a paralyzing blow"));
											}
					if ((fightskill==SWORDSMANSHIP) && (IsAxe(pWeapon->id())) && (pc_deffender->isPlayer()))// Concussion Hit -Fraz-
					{ 
						tempeffect(pc_attacker, pc_deffender, 45, 0, 0, 0);
						//pc_attacker->mn-=(pc_attacker->mn/2); //-Fraz- temp use of this for concussion
					}
					updatestats((pc_deffender), 0);
				}
				// blood shred by blackwind
				if (damage>10)
				{
	               short id = 0x122c;	
	               if (damage>50) id=0x122a;
				   else if (damage>40) id=0x122d;
	               else if (damage>30) id=0x122e;
	               else if (damage>20) id=0x122b;
				   P_ITEM pBlood = Items->SpawnItem(pc_deffender, 1, "#", 0, id, 0, 0);
				   if (pBlood)
				   {
					  pBlood->moveTo(pc_deffender->pos);
					  pBlood->priv = 1;
					  pBlood->setGMMovable(); //Moveable by GM
					  RefreshItem(pBlood);
					  pBlood->decaytime = (SrvParams->decayTime()/2)*MY_CLOCKS_PER_SEC+uiCurrentTime;
				   }
				}

				/////////  For Splitting NPCs ///  McCleod
				if ((pc_deffender->split>0)&&(pc_deffender->hp>=1))
				{
					if (rand()%100<=pc_deffender->splitchnc)
					{
						if (pc_deffender->split==1) splitnum=1;
						else splitnum=rand()%pc_deffender->split+1;
						
						for (splitcount=0;splitcount<splitnum;splitcount++)
							Npcs->Split(pc_deffender);
					}
				}
				////////      End of spliting NPCs
			}
			if (pc_attacker->isPlayer())
				if((fightskill==ARCHERY && los)|| fightskill!=ARCHERY)
					doSoundEffect(pc_attacker, fightskill, pWeapon);
			if (pc_deffender->hp<0) pc_deffender->hp=0;
			updatestats((pc_deffender), 0);
			x = pc_deffender->id();
			if (x>=0x0190)
			{
				if (!pc_deffender->onhorse) 
					npcaction(pc_deffender, 0x14);
			}
		}
	}
}