// For our global aggression (every 5 minutes)
// parses players only, but because of it, can cause aggression towards monsters
// which is just cool if you ask me!  Monsters fighting monsters, monsters fighting
// people, Just makes sense.  FUll world aggression!
void aggro_update(void) {
	// we only parse players to make this go fast!
	FOREACH(Lexi::List<CHAR_DATA *>, player_list, player_iter) {
		CHAR_DATA *ch = (*player_iter);
		aggression(ch);				// cause mass aggression!
	}
	return;
}

// Aggression never looked so good!
// stock aggression code searches the entire character list, then parses the people list
// for every mob, and then another people list check within that check.  Eating up according
// to merc, 25%-35% of ALL cpu usage.  This function, called on movement into a room
// and once every 5 minutes (globally) incase people sit and don't move but meanwhile the aggressor
// does or what-have-you.  This affectively cuts out 25-35% of ALL CPU usage, until movement, then it
// causes about 0.1-0.5% cpu usage, and vanish's again.  Affectively saving MASSIVE amounts of CPU usage.
// even if every character on the mud, (including npc's) moved at the same time, this would eat up
// no more then mercs projected 35% cpu usage.  Making this a far more effective method.
// Merc said it was too tricky to do it room based, apparently, they don't think like me.
//						-- Darien 21:01 PM 2008-12-14
void aggression( CHAR_DATA *ch ){    
	CHAR_DATA *victims[10000];
	CHAR_DATA *aggressor[10000];
	register CHAR_DATA *wch = NULL, *wch_next = NULL;
	register CHAR_DATA *vch = NULL, *vch_next = NULL;
							// Register usage, though the compiler may disregard them
							// putting these value's into the register has the potential
							// to speed up processing, and considering the high-level of
							// usage, we expect the best performance, so we register with
							// hopes that the compiler will accept.

	int cnt = 0;

	// Lets protect vs crashing
	if(!ch) {
		log_string("%s: called on NULL character, preventing bad things(tm)", __PRETTY_FUNCTION__);
		return;
	}

	// stranger things have happened, but safety persists!
	if(!ch->in_room) {
		log_string("%s called on a character(%s) will a Null Room!", __PRETTY_FUNCTION__, IS_NPC(ch) ? ch->short_descr : ch->name);
		return;
	}

	// safe room, no aggression, period!
	if(IS_SET(ch->in_room->room_flags, ROOM_SAFE))
		return;


	// Only person in the room, lets not bother hitting any loops
	// characters are always put at the start of the list when they enter a room
	// this is called whenever you change rooms, thus making you the first person
	// in the room.  No aggression.  Only works off-world-map, as on-world-map
	// you never change room, just x/y.
	if(!ON_MAP(ch)) {
		if(ch->in_room->people == ch && ch->next_in_room == NULL) {
			return;
		}
	}

	// chance to stop aggression if your sneaking!
	// 100% sneak with 25 dex >= 100% chance of non-aggression. (atleast you won't cause it)
	// but someone-else may cause you to get suckered into it if they aggress.
	if(IS_AFFECTED(ch, AFF_SNEAK)) {
		int chance;	
		chance = get_skill(ch,gsn_sneak);	
		chance += get_curr_stat(ch,STAT_DEX) * 3/2; 	
		chance -= number_range(0,ch->level) /2;

		// random chance!
		if (number_percent() < chance)	    
			return;
	}

	// we are hidden, no aggression here, despite can_see has a chance to see you, we want
	// to ensure that we don't call this function too much, so things like this help.
	// hide stops on movement, so this is only affecting when the 5-minute interval aggression
	// check happens.
	if(IS_AFFECTED(ch, AFF_HIDE))
		return;

	// look for an aggressive monster (add to the aggressive monster list.)	
	for ( wch = ch->in_room->people; wch != NULL; wch = wch_next )	
	{	    
		int count; 	    
		wch_next	= wch->next_in_room; 	    

		if(IS_NPC(wch)
		&& IS_SET(wch->act, ACT_AGGRESSIVE)
		&& !is_fighting(wch)
		&& IS_AWAKE(wch)
		&& (ch->x == wch->x && ch->y == wch->y)		// ensure we are the same x/y for map interaction
		&& number_bits(1) == 0)				// chance we don't aggress
		{
			aggressor[cnt] = wch;
			cnt++;
			if(cnt == 10000) break;			// safety!
		}

	}

	// we didn't count any monsters!  No aggression!
	if(cnt == 0)	return;

	// pick the aggressor. (yay randomized aggression)
	CHAR_DATA *monster = aggressor[number_range(0,cnt-1)];	// 0 0 results in 0 return.
	if(!monster)	return;					// we got a null monster, but there was a monster list
								// lets safely assume something *bad* happened and we
								// move to save the day here.

	cnt = 0;						// reset our counter for the victims list.


	// find our random victims.  Other monsters can be victims!
	// so-long as they match the requirements. (sects not matching, alliance vs rebellion goes on)
	for(vch = monster->in_room->people; vch; vch = vch_next) {
		if(vch->rebel != monster->rebel
		&& can_see(monster, vch)
		&& !is_same_group(monster, vch)			// potential if aggressive pet! (beastmaster class can set aggro on pet)
		&& (vch->level <= (monster->level +10))		// over 10 levels, we don't aggress anymore!
		&& (vch->x == wch->x && vch->y == wch->y)	// safety net again!
		&& !is_fighting(vch))
		{
			victims[cnt] = vch;
			cnt++;
			if(cnt == 10000) break;			// safety!
		}
	}

	// we didn't find any victims we could attack with our random monster!  No aggression!
	if(cnt == 0)	return;

	// lets find our victim to feel the pain!
	CHAR_DATA *feel_n_pain = victims[number_range(0, cnt-1)]; // 0 0 results in 0 return (only one person found)
	if(!feel_n_pain) { 
		if(ch->rebel != monster->rebel
		&& (ch->x == monster->x && monster->y == ch->y)
		&& (ch->level <= monster->level+10) 		// really, monsters aren't stupid enough to attack them!
		&& can_see(monster, ch))
			feel_n_pain = ch;			// haven't escaped the pain yet!
		else
			return; 
	}

	if(!feel_n_pain) return;				// can only happen if ch gets nulled, as this is the double-check
								// nulled ch should *NOT* beable to happen after this has been
								// called, but, stranger things have happened.  Safety persists.


	// We've done allot of work, lets finally check and see if we are good to go for
	// aggression.  We hope to aggress here, as this was a very painstaking adventure in
	// building a list of aggressors and victims to aggress against.  hehehehe
	// notibly, we don't want to always aggress, thus we leave it up to chance.
	if(number_bits(1) == 0) {
		// here we determine our methods of attacking (based on monster class/level eventually)
		// as it stands, this is a simple method to start aggression.
		switch(monster->iclass) {
			default: multi_hit(monster, feel_n_pain, TYPE_UNDEFINED);		break;
			case 3: switch(number_range(0, 3)) {
				case 2: do_function(monster, do_backstab, feel_n_pain->name); 	break;
				default:  multi_hit(monster, feel_n_pain, TYPE_UNDEFINED);    	break;
			}
		}
	}

	return;
}