/*
....[@@@..[@@@..............[@.................. MUD++ is a written from
....[@..[@..[@..[@..[@..[@@@@@....[@......[@.... scratch multi-user swords and
....[@..[@..[@..[@..[@..[@..[@..[@@@@@..[@@@@@.. sorcery game written in C++.
....[@......[@..[@..[@..[@..[@....[@......[@.... This server is an ongoing
....[@......[@..[@@@@@..[@@@@@.................. development project.  All 
................................................ contributions are welcome. 
....Copyright(C).1995.Melvin.Smith.............. Enjoy. 
------------------------------------------------------------------------------
Melvin Smith (aka Fusion)         msmith@falcon.mercer.peachnet.edu 
MUD++ development mailing list    mudpp-list@spice.com
------------------------------------------------------------------------------
char_combat.cc
*/

#include "config.h"

#include "bit.h"
#include "io.h"
#include "string.h"
#include "llist.h"
#include "indexable.h"
#include "room.h"
#include "random.h"
#include "combat.h"
#include "char.h"

#include "global.h"


Object * makeCorpse( Char * ch )
{
//	int zone_type;
	String str;

//	Object *inv;
	Object *corpse = new Object( ITEM_CORPSE );

	str << "corpse ";
	str << ch->getName();
	corpse->setName( str );
	str.clr();

	str << "the corpse of " << ch->getShort();
	corpse->setShort( str );
	str << " lies here.";
	corpse->setLong( str );

	corpse->toWorld();
	return corpse;
}


// Perform an attack
void Char::attack( Char *ch, int )
{
	String str;
	fighting = ch;
	Attack * this_atck;
	int success;
	int dt;
	int dam;
	attacks.reset();

	while( ( this_atck = attacks.peek() ) )
	{
		dt = this_atck->getType();

		attacks.next();

		switch( success = hit( ch, this_atck ) )
		{
			case FUMBLE:
				// fumble - something bad happens

				continue;
	
			case MISSED:
				out( "You miss " );
				out( ch->getShort() );
				out( ".\n\r" );
				ch->out( shortdesc );
				ch->out( " swings at you but misses!\n\r" );
				continue;

			case DODGED:
				out( ch->shortdesc );
				out( " dodges your attack.\n\r" );
				ch->out( "You dodge " );
				ch->out( shortdesc );
				ch->out( "'s attack.\n\r" );
				continue;

			case HIT:
				dam = randgen.get( this_atck->getMin(), this_atck->getMax() );
				dam += this_atck->getDam();

				str.sprintf( "Your %s %s %s.\n\r",	damTypeName( dt ),
													damRangeName( dam, true ),
													ch->getShort().chars() );

				out( str );

				str.sprintf( "%s's %s %s you.",		getShort().chars(),
													damTypeName( dt ),
													damRangeName( dam, true ) );

				ch->out( str );
				ch->damage( dam, dt );
				break;

			case CRIT_HIT:
				dam = randgen.get( this_atck->getMin(), this_atck->getMax() );
				dam += this_atck->getDam();
				dam *= 2;
				out( "You strike a -FEARSOME- blow to " );
				out( ch->getShort() );
				out( "!\n\r" );
				ch->damage( dam, dt );
				ch->out( getShort() );
				ch->out( " deals you a -FEARSOME- blow!\n\r" );
				break;
		}

		if( ch->getHp() < 0 )
		{
			stopFighting();
			str.clr();
			str << ch->getShort() << " is DEAD!!\n\r";
			in_room->outAllCharExcept( str, ch, 0 );
			Object *corpse = makeCorpse( ch );
			in_room->addObjInv( corpse );
			str.clr();
			str << "You gain " << ch->getExp() << " exp.\n\r";
			gainExp( ch->getExp() );
			out( str );

			if( ch->isNPC() )
			{
				in_room->rmCharInv( ch );
				ch->fromWorld();
				delete ch;
				return;
			}

			ch->out( "You have been KILLED!!!\n\r" );
			ch->setHp( 1 );
			ch->stopFighting();
			return;
		}
	}

	fighting = ch;
}


// Do a single hit, calculate success
int Char::hit( Char *, Attack * att )
{
	// Char * vict parameter is unused until we get serious here.

	int success;

	success = randgen.get( 1000 ) + att->getHit();

	if( success < 25 )
		return FUMBLE;
	else if( success < 200 )
		return MISSED;
	else if( success < 975 )
	{
		int dodged;

		dodged = randgen.get( 1000 );
		if( dodged >= success )
			return DODGED;
		else
			return HIT;
	}
	else
		return CRIT_HIT;
}


// Inflict damage and calculate percent that armor absorbs
int Char::damage( int dam, int )
{
	int actual_dam = dam;

	// Do immunity and armor calcs here and return actual damage taken
	actual_dam -= armor;
	hp -= actual_dam;
	return actual_dam;
}