/*
....[@@@..[@@@..............[@.................. 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
------------------------------------------------------------------------------
pulse.cc
*/

#include "string.h"
#include "llist.h"
#include "room.h"
#include "indexable.h"
#include "area.h"
#include "pc.h"
#include "npc.h"
#include "object.h"
#include "env.h"

#include "global.h"

Environment envir;

const int PULSE_NPC = 8;
const int PULSE_OBJ = 8;
const int PULSE_PC = 8;
const int PULSE_COMBAT = 3;
const int PULSE_UPDATE = 45;

void pulseArea();
void pulsePC();
void pulseNPC();
void pulseObj();
void pulseCombat();

// Heartbeat of the game.
// This is what makes the MUD run.

void heartbeat()
{
	static int combat_timer = PULSE_COMBAT;	
	static int npc_timer = PULSE_NPC;
	static int obj_timer = PULSE_OBJ;
	static int pc_timer = PULSE_PC;
	static int update_timer = PULSE_UPDATE;

	if( ! combat_timer-- )
	{
		pulseCombat();
		combat_timer = PULSE_COMBAT;
	}

	if( ! npc_timer-- )
	{
		pulseNPC();
		npc_timer = PULSE_NPC; 
	}

	if( ! obj_timer-- )
	{
		pulseObj();
		obj_timer = PULSE_OBJ; 
	}

	if( ! pc_timer-- )
	{
		pulsePC();
		pc_timer = PULSE_PC;
	}

	if( ! update_timer-- )
	{
		envir.update();
		pulseArea();
		update_timer = PULSE_UPDATE;	
	}
}


void pulseArea()
{
	Area * area;

	areas.reset();
	while( ( area = areas.peek() ) )
	{
		areas.next();
		area->tick();
	}
}


void pulsePC()
{
	PC *pc;
	LList<PC> tlist = pcs;
	tlist.reset();

	while( ( pc = tlist.peek() ) )
	{
		pc->pulse();
		tlist.next();
	}
}


void pulseNPC()
{
	NPC *npc;
	LList<NPC> tlist = npcs;
	tlist.reset();

	while( ( npc = tlist.peek() ) )
	{
		tlist.next();
		if( randgen.get( 0, 4 ) )
			continue;

		npc->moveDir( randgen.get( 0, 5 ) );
	}
}


void pulseObj()
{
	Object *obj;
	objects.reset();

	while( ( obj = objects.peek() ) )
	{
		if( obj->getTimer() )
		{
			if( obj->tick() )
			{
				objects.next();
				continue;
			}
			
			if( obj->inRoom() )
			{
				obj->inRoom()->out( obj->getShort() );
				obj->inRoom()->out( " decays into dust.\n\r" );

				if( obj->getType() == ITEM_CORPSE )
				{
					obj->setName( "pile bones" );
					obj->setShort( "a pile of old bones" );
					obj->setLong( "A pile of old bones is here." );
					objects.next();
					continue;
				}

				obj->fromRoom();
			}
			else if( obj->carriedBy() )
			{
				obj->carriedBy()->out( obj->getShort() );
				obj->carriedBy()->out( " crumbles in your hands.\n\r" );
				obj->fromChar();
			}

			// call to remove expects obj to be current.
			// after remove current points to the next node so no ++
			objects.remove();
			delete obj;
		}
		else
		{
			objects.next();
		}
	}
}


void pulseCombat()
{
	Char *ch;
	Char *vict;

	// Run through npc list first	
	npcs.reset();

	while( ( ch = npcs.peek() ) )
	{
		npcs.next();

		vict = ch->getFighting();
		if( !vict )
			continue;

		ch->attack( vict, -1 );
	}

	pcs.reset();

	while( ( ch = pcs.peek() ) )
	{
		pcs.next();

		vict = ch->getFighting();
		if( !vict )
			continue;

		ch->attack( vict, -1 );
	}
}