/* ************************************************************************
*  file: mobact.c , Mobile action module.                 Part of DIKUMUD *
*  Usage: Procedures generating 'intelligent' behavior in the mobiles.    *
*  Copyright (C) 1990, 1991 - see 'license.doc' for complete information. *
************************************************************************* */

#include <stdio.h>

#include "utils.h"
#include "structs.h"
#include "db.h"
#include "comm.h"
#include "spells.h"

extern struct char_data *character_list;
extern struct index_data *mob_index;
extern struct room_data *world;
extern struct zone_data *zone_table;
extern struct str_app_type str_app[];

void do_kick(struct char_data *ch, char *argument, int cmd);
void do_bash(struct char_data *ch, char *argument, int cmd);
void cast_charm_person(byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_fire_breath( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_frost_breath( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_acid_breath( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_gas_breath( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_lightning_breath( byte level, struct char_data *ch, char *arg,
  int type, struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_sleep( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_colour_spray( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_blindness( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_burning_hands( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_call_lightning( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_chill_touch( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_shocking_grsp( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_colour_spray( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_earthquake( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_energy_drain( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_fireball( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_harm( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_lightning_bolt( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_magic_missile( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_armor( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_bless( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_blindness( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_cure_blind( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_cure_critic( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_cure_light( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_curse( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_heal( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_poison( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_remove_curse( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_remove_poison( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_sanctuary( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_sleep( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_strength( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_dispel_evil( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );
void cast_shocking_grasp( byte level, struct char_data *ch, char *arg, int type,
  struct char_data *tar_ch, struct obj_data *tar_obj );

void hit(struct char_data *ch, struct char_data *victim, int type);

int niceness(struct char_data *ch)
{
	struct char_data *tmp_ch;
	int count=0;
	int lv=0;
	int base;

	for(tmp_ch = world[ch->in_room].people; tmp_ch;
	    tmp_ch = tmp_ch->next_in_room){
		if(!IS_NPC(tmp_ch)){
			lv += tmp_ch->player.level;
			count++;
		}
	}
	/* base is random (2..4) to start.
	 * The base is modified on the number of people appearing
	 * in the room:
	 *  1 == person :  +1
	 *  3 <= person :  +0
         *  5 <= person :  -1
	 * Also by the average level of the people in the room:
	 *  5 <= lv	: +2
	 * 10 <= lv	: +1
	 * 15 <= lv	: +0
	 * 20 <= lv	: -1
	 * 25 <= lv	: -2
	 * -- Swiftest
	 */
	if(!count) count=1;
	base=number(2,4);
	switch(count){
	  case 1: case 2:
		base++;
		break;
	  case 3: case 4:
		/* no modifier */
		break;
	  default: base--;
		break;
	}
	switch(lv/count){
	  case 1: case 2: case 3: case 4: case 5:
		base += 2; break;
	  case 6: case 7: case 8: case 9: case 10:
		--base; break;
	  case 11: case 12: case 13: case 14: case 15:
		/* no modifier */
		break;
	  case 16: case 17: case 18: case 19: case 20:
		--base; break;
	  default:
		base -= 2; break;
	}
	return(base);
}

void mobile_activity(void)
{
	register struct char_data *ch;
	struct char_data *tmp_ch, *vict, *t_vict;
	struct obj_data *obj, *best_obj, *worst_obj;
	int door, found, max, min;
	char buf[100];
	MEMtMemoryRec *names;

	/* Added Player data to call for commands -Sman */

	void (*funct_ptr)( byte level, struct char_data *ch,
             char *arg, int type,
             struct char_data *tar_ch, struct obj_data *tar_obj );

	extern int no_specials;

	void do_move(struct char_data *ch, char *argument, int cmd);
	void do_get(struct char_data *ch, char *argument, int cmd);
	int chance;

	for (ch = character_list; ch; ch = ch->next)
		if (IS_MOB(ch))
		{
			/* For delaying mobs with bash, etc */
			if(ch->specials.timer) {
				ch->specials.timer--;
				continue;
			}
			/* Examine call for special procedure */
			if (IS_SET(ch->specials.act, ACT_SPEC) && !no_specials) {
				if (!mob_index[ch->nr].func) {
					sprintf(buf,"%s %d",ch->player.name,
						(int)ch->nr);
					log(buf);
					log("Attempting to call a non-existing MOB func. (mobact.c)");
					REMOVE_BIT(ch->specials.act, ACT_SPEC);
				} else {
			   	if ((*mob_index[ch->nr].func)	(ch, 0, 0, ""))
		      		continue;
				}
			}

			if (AWAKE(ch) && !(ch->specials.fighting)) {

				if (IS_SET(ch->specials.act, ACT_SCAVENGER)) {
					if (world[ch->in_room].contents && !number(0,10)) {
						for (max = 1, best_obj = 0, obj = world[ch->in_room].contents;
					       obj; obj = obj->next_content) {
							if (CAN_GET_OBJ(ch, obj)) {
								if (obj->obj_flags.cost > max) {
									best_obj = obj;
									max = obj->obj_flags.cost;
								}
							}
						} /* for */

						if (best_obj) {
							obj_from_room(best_obj);
							obj_to_char(best_obj, ch);
							act("$n gets $p.",FALSE,ch,best_obj,0,TO_ROOM);
						}
					}
				} /* Scavenger */

				/* Here is a contender for game's ugliest if */
				if ((!IS_SET(ch->specials.act, ACT_SENTINEL)||
					(IS_SET(ch->specials.act,ACT_AGGRESSIVE)
					&& IS_SET(world[ch->in_room].room_flags,SAFE)
					&& GET_HIT(ch) > GET_MAX_HIT(ch)/2)) &&
					(GET_POS(ch) >= POSITION_STANDING) &&
					((door=number(0,45))<=5) && CAN_GO(ch,door)&&
					!IS_SET(world[EXIT(ch, door)->to_room].room_flags, NO_MOB) &&
					 !IS_SET(world[EXIT(ch, door)->to_room].room_flags, DEATH)) {
					if (ch->specials.last_direction == door) {
						ch->specials.last_direction = -1;
					} else {
						if (!IS_SET(ch->specials.act, ACT_STAY_ZONE)) {
							ch->specials.last_direction = door;
							do_move(ch, "", ++door);
						} else {
							if (world[EXIT(ch, door)->to_room].zone == world[ch->in_room].zone) {
								ch->specials.last_direction = door;
								do_move(ch, "", ++door);
							}
						}
					}
				} /* if can go */


				if (IS_SET(ch->specials.act,ACT_AGGRESSIVE)) {
				   found = FALSE;
				   for (tmp_ch = world[ch->in_room].people; tmp_ch && !found;
				      tmp_ch = tmp_ch->next_in_room) {
				      if (!IS_NPC(tmp_ch) && CAN_SEE(ch, tmp_ch) && !IS_TRUSTED(tmp_ch) && !IS_AFFECTED(tmp_ch,AFF_HIDE)) {
				         if (!IS_SET(ch->specials.act, ACT_WIMPY) || !AWAKE(tmp_ch)) {
				            if ((IS_SET(ch->specials.act, ACT_AGGRESSIVE_EVIL) && 
				                 IS_EVIL(tmp_ch)) ||
					        (IS_SET(ch->specials.act, ACT_AGGRESSIVE_GOOD) && 
					         IS_GOOD(tmp_ch)) ||
					        (IS_SET(ch->specials.act, ACT_AGGRESSIVE_NEUTRAL) && 
					         IS_NEUTRAL(tmp_ch)) ||
						(!IS_SET(ch->specials.act, ACT_AGGRESSIVE_EVIL) && 
						 !IS_SET(ch->specials.act, ACT_AGGRESSIVE_NEUTRAL) &&
						 !IS_SET(ch->specials.act, ACT_AGGRESSIVE_GOOD) ) &&
						!(IS_EVIL(ch)&&IS_AFFECTED(tmp_ch,AFF_PROTECT_EVIL)&&GET_LEVEL(ch)<GET_LEVEL(tmp_ch))
						) {
						if(world[ch->in_room].room_flags
							& SAFE) {
						   if(GET_HIT(ch)>GET_MAX_HIT(ch)*3/4)
						   	do_action(ch,"",31);
						} else {
						 /* hit(ch, tmp_ch, 0);*/
						 /* Changed so that specs */
						 /* get called (witness)  */
						   sprintf(buf,"hit %s",
							GET_NAME(tmp_ch));
						   command_interpreter(ch,buf);
						   found = TRUE;
						}
				            }
				         }
				      }
				   }
				}

                                if (IS_SET(ch->specials.act, ACT_MEMORY)) {
				   found = FALSE;
				   for (tmp_ch = world[ch->in_room].people;
                                        tmp_ch != NULL && !found;
              			        tmp_ch = tmp_ch->next_in_room) {
				      for (names = ch->specials.memory;
          			           names != NULL && !found;
 				           names = names->next) {
				         if ((str_cmp(names->name, tmp_ch->player.name) == 0) && CAN_SEE(ch,tmp_ch) && ch!=tmp_ch) {
				            found = TRUE;
				            vict = tmp_ch;
 				         }
				      }
				   }

				   if (found) {
				      if(world[ch->in_room].room_flags & SAFE) {
					if(!number(0,6)) {
					  if(GET_HIT(ch)>GET_MAX_HIT(ch)*3/4)
					    act("\"Hey! I know you, you jerk! Care to step outside?\", exclaims the $n.",TRUE,ch,0,0,TO_ROOM);
					  else if(GET_HIT(ch)<GET_MAX_HIT(ch)/2)
					    do_say(ch,"Just wait until I heal up, buster!",0);
					}
				      } else {
				          act("\"Hey! You're the fiend that attacked me!!!!!\", exclaims the $n.", TRUE, ch, 0, 0, TO_ROOM);
                                          hit(ch, vict, 0);
				      }
                                   }
 				}
			} /* awake && not fighting */
	if (IS_SET(ch->specials.act, ACT_ISHUMANOID) &&
	    IS_FIGHTING(ch)){
		switch(GET_LEVEL(ch)){
		case 1:
		case 2:
		case 3:
		case 4:
		case 5:
		case 6:
		case 7:
		case 8:
		case 9:
		case 10:
		case 11:
		case 12:
		case 13:
		case 14:
		case 15:
		case 16:
		case 17:
		case 18:
		case 19:
		case 20:
		case 21:
		case 22:
		case 23:
		case 24:
		case 25:
		case 26:
		case 27:
		case 28:
		case 29:
		case 30:
		case 31:
		case 32:
		default:
		    if(IS_GOOD(ch))
			do_say(ch,"Make peace, not war!",0);
		}
	} /* ISHUMANOID */
	if (IS_SET(ch->specials.act, ACT_ISDRAGON) &&
	    IS_FIGHTING(ch)){
		chance = niceness(ch);

		vict=ch->specials.fighting;
		if(ch->in_room!=vict->in_room)
			return;
		if (IS_AFFECTED(ch, AFF_BLIND) && GET_LEVEL(ch)>5){
			act("$n says, 'Cure blindness!'", 1, ch, 0, 0, TO_ROOM);
			cast_cure_blind(GET_LEVEL(ch), ch, "",
			  SPELL_TYPE_SPELL, vict, 0);
		} else if(number(0,chance+1)==0){
			act("$n says, 'Sleep!'", 1, ch, 0, 0, TO_ROOM);
			for(t_vict=world[ch->in_room].people; t_vict;
			    t_vict=t_vict->next_in_room){
				if(!IS_NPC(t_vict) && CAN_SEE(ch, t_vict) &&
				   number(0,(31-GET_LEVEL(ch))/5)==0){
					cast_sleep(GET_LEVEL(ch), ch, "",
					  SPELL_TYPE_SPELL, t_vict, 0);
				}
			}
		} else if (vict && CAN_SEE(ch,vict) && number(0,chance)==0){
			act("$n says, 'Blindness!'", 1, ch, 0, 0, TO_ROOM);
			cast_blindness(GET_LEVEL(ch), ch, "",
			  SPELL_TYPE_SPELL, vict, 0);
		}

		funct_ptr=0;
		if(CAN_SEE(ch, vict) && number(0,9)==0){
			act("$n breathes fire!", 1, ch, 0, 0, TO_ROOM);
			funct_ptr=cast_fire_breath;
		} else if(CAN_SEE(ch, vict) && number(0,7)==0){
			act("$n breathes frost!", 1, ch, 0, 0, TO_ROOM);
			funct_ptr=cast_frost_breath;
		} else if(CAN_SEE(ch, vict) && number(0,5)==0){
			act("$n breathes acid!", 1, ch, 0, 0, TO_ROOM);
			funct_ptr=cast_acid_breath;
		} else if(CAN_SEE(ch, vict) && number(0,3)==0){
			act("$n breathes gas!", 1, ch, 0, 0, TO_ROOM);
			funct_ptr=cast_gas_breath;
		} else if(CAN_SEE(ch, vict) && number(0,2)==0){
			act("$n breathes lightning!", 1, ch, 0, 0, TO_ROOM);
			funct_ptr=cast_lightning_breath;
		}

		if(funct_ptr){
			if(vict)
				funct_ptr(GET_LEVEL(ch),ch, "",
				  SPELL_TYPE_SPELL, vict, 0);
			for(t_vict=world[ch->in_room].people; t_vict;
			    t_vict= t_vict->next_in_room){
				if(!IS_NPC(t_vict) && CAN_SEE(ch, t_vict) &&
				   number(0,(31-GET_LEVEL(ch))/5)==0 &&
				   t_vict != vict){
					funct_ptr(GET_LEVEL(ch),ch, "",
					  SPELL_TYPE_SPELL, t_vict, 0);
				}
			}
		}
	} /* ISDRAGON */
	if (IS_SET(ch->specials.act, ACT_ISDEMON) &&
	    IS_FIGHTING(ch)){
		if(ch->specials.fighting->in_room!=ch->in_room)
			return;
		vict=ch->specials.fighting;
		chance=niceness(ch);
		if(!CAN_SEE(ch, vict) && IS_AFFECTED(ch, AFF_BLIND)){
			act("$n says, 'Cure blindness!'", 1, ch, 0, 0, TO_ROOM);
			cast_cure_blind(GET_LEVEL(ch), ch, "",
			  SPELL_TYPE_SPELL, ch, 0);
		} else if(CAN_SEE(ch, vict) && number(0,chance)==0 &&
		   GET_HIT(ch)<100 && GET_LEVEL(ch)>=14){
			act("$n says, 'Heal!'", 1, ch, 0, 0, TO_ROOM);
			cast_heal(GET_LEVEL(ch), ch, "",
			  SPELL_TYPE_SPELL, ch, 0);
		} else if(CAN_SEE(ch, vict) && number(0,chance)==0 &&
			  GET_HIT(ch)<75 && GET_LEVEL(ch)>=9){
			act("$n says, 'Cure critical!'", 1, ch, 0, 0, TO_ROOM);
			cast_cure_critic(GET_LEVEL(ch), ch, "",
			  SPELL_TYPE_SPELL, ch, 0);
		} else if(CAN_SEE(ch, vict) && number(0,chance)==0 &&
			  GET_HIT(ch)<50){
			act("$n says, 'Cure light wounds!'", 1, ch, 0, 0,
			  TO_ROOM);
			cast_cure_light(GET_LEVEL(ch), ch, "",
			  SPELL_TYPE_SPELL, ch, 0);
		} else if(CAN_SEE(ch, vict) && !IS_AFFECTED(ch,AFF_SANCTUARY)&&
			  GET_LEVEL(ch)>=13 && number(0,chance)==0){
			act("$n says, 'Sanctuary!'", 1, ch, 0, 0, TO_ROOM);
			cast_sanctuary(GET_LEVEL(ch), ch, "",
			  SPELL_TYPE_SPELL, ch, 0);
		}

		funct_ptr=0;
		if(GET_LEVEL(ch)>10 && number(0,chance-1)==0){
			act("$n breathes lightning!", 1, ch, 0, 0, TO_ROOM);
			funct_ptr=cast_lightning_breath;
		} else if(GET_LEVEL(ch)>15 && number(0,chance-2)==0){
			act("$n breathes gas!", 1, ch, 0, 0, TO_ROOM);
			funct_ptr=cast_gas_breath;
		}
		if(funct_ptr){
			if(vict)
				funct_ptr(GET_LEVEL(ch),ch, "",
				  SPELL_TYPE_SPELL, vict, 0);
			for(t_vict=world[ch->in_room].people; t_vict;
			    t_vict= t_vict->next_in_room){
				if(!IS_NPC(t_vict) && CAN_SEE(ch, t_vict) &&
				   number(0,(31-GET_LEVEL(ch))/6)==0 &&
				   vict != t_vict){
					funct_ptr(GET_LEVEL(ch),ch, "",
					  SPELL_TYPE_SPELL, t_vict, 0);
				}
			}
		}
			
		switch(GET_LEVEL(ch)){
		case 1:
		case 2:
		case 3:
		case 4:
		case 5:
		case 6:
		case 7:
		case 8:
		case 9:
		case 10:
		case 11:
		case 12:
		case 13:
		case 14:
		case 15:
		case 16:
		case 17:
		case 18:
		case 19:
		case 20:
		case 21:
		case 22:
		case 23:
		case 24:
		case 25:
		case 26:
		case 27:
		case 28:
		case 29:
		case 30:
		default:
			if(number(0,7)==0){
				act("$n says, 'My minions will destroy your kind!'", 1, ch, 0, 0, TO_ROOM);
			} else if(number(0,6)==0){
				act("$n says, 'You will soon die!'", 1, ch, 0, 0, TO_ROOM);
			} else if(number(0,5)==0){
				act("$n says, 'You are but a speck of sand to my power!'", 1, ch, 0, 0, TO_ROOM);
			} else if(number(0,4)==0){
				act("$n says, 'Pray that I kill you mercifully!'", 1, ch, 0, 0, TO_ROOM);
			}
		}
	} /* ISDEMON */
	if (IS_SET(ch->specials.act, ACT_ISANIMAL) &&
	    IS_FIGHTING(ch)){
		switch(GET_LEVEL(ch)){
		case 1:
		case 2:
		case 3:
		case 4:
		case 5:
		case 6:
		case 7:
		case 8:
		case 9:
		case 10:
		case 11:
		case 12:
		case 13:
		case 14:
		case 15:
		case 16:
		case 17:
		case 18:
		case 19:
		case 20:
		case 21:
		case 22:
		case 23:
		case 24:
		case 25:
		case 26:
		case 27:
		case 28:
		case 29:
		case 30:
		default:
			act("$n growls!", 1, ch, 0, 0, TO_ROOM);
		}
	} /* ISANIMAL */
	if (IS_SET(ch->specials.act, ACT_ISINSECT) &&
	    IS_FIGHTING(ch)){
		switch(GET_LEVEL(ch)){
		case 1:
		case 2:
		case 3:
		case 4:
		case 5:
		case 6:
		case 7:
		case 8:
		case 9:
		case 10:
		case 11:
		case 12:
		case 13:
		case 14:
		case 15:
		case 16:
		case 17:
		case 18:
		case 19:
		case 20:
		case 21:
		case 22:
		case 23:
		case 24:
		case 25:
		case 26:
		case 27:
		case 28:
		case 29:
		case 30:
		default:
		}
	} /* ISINSECT */
	if (IS_SET(ch->specials.act, ACT_CANFLY) &&
	    IS_FIGHTING(ch)){
		switch(GET_LEVEL(ch)){
		case 1:
		case 2:
		case 3:
		case 4:
		case 5:
		case 6:
		case 7:
		case 8:
		case 9:
		case 10:
		case 11:
		case 12:
		case 13:
		case 14:
		case 15:
		case 16:
		case 17:
		case 18:
		case 19:
		case 20:
		case 21:
		case 22:
		case 23:
		case 24:
		case 25:
		case 26:
		case 27:
		case 28:
		case 29:
		case 30:
		case 31:
		case 32:
		default:
		}
	} /* CANFLY */
	if (IS_SET(ch->specials.act, ACT_CANSWIM) &&
	    IS_FIGHTING(ch)){
		switch(GET_LEVEL(ch)){
		case 1:
		case 2:
		case 3:
		case 4:
		case 5:
		case 6:
		case 7:
		case 8:
		case 9:
		case 10:
		case 11:
		case 12:
		case 13:
		case 14:
		case 15:
		case 16:
		case 17:
		case 18:
		case 19:
		case 20:
		case 21:
		case 22:
		case 23:
		case 24:
		case 25:
		case 26:
		case 27:
		case 28:
		case 29:
		case 30:
		default:
		}
	} /* CANSWIM */
	if (IS_SET(ch->specials.act, ACT_HAS_CL) &&
	    IS_FIGHTING(ch)){
		vict=ch->specials.fighting;
		if(vict->in_room!=ch->in_room)
			return;
		chance=niceness(ch);
		if(!CAN_SEE(ch, vict) && GET_LEVEL(ch)>=4 &&
		   IS_AFFECTED(ch, AFF_BLIND)){
			act("$n says, 'Cure blindness!'", 1, ch, 0, 0, TO_ROOM);
			cast_cure_blind(GET_LEVEL(ch), ch, "",
			  SPELL_TYPE_SPELL, ch, 0);
		} else if(CAN_SEE(ch, vict) && GET_LEVEL(ch)>=12 &&
			  IS_AFFECTED(ch, AFF_CURSE)){
			act("$n says, 'Remove curse!'", 1, ch, 0, 0, TO_ROOM);
			cast_remove_curse(GET_LEVEL(ch), ch, "",
			  SPELL_TYPE_SPELL, ch, 0);
		} else if(CAN_SEE(ch, vict) &&  GET_LEVEL(ch)>=9 &&
			  IS_AFFECTED(ch, AFF_POISON)){
			act("$n says, 'Remove poison!'", 1, ch, 0, 0, TO_ROOM);
			cast_remove_poison(GET_LEVEL(ch), ch, "",
			  SPELL_TYPE_SPELL, ch, 0);
		} else if(CAN_SEE(ch, vict) && GET_LEVEL(ch)>=13 &&
			!IS_AFFECTED(ch, AFF_SANCTUARY) && number(0,chance)==0){
			act("$n says, 'Sanctuary!'", 1, ch, 0, 0, TO_ROOM);
			cast_sanctuary(GET_LEVEL(ch), ch, "",
			  SPELL_TYPE_SPELL, ch, 0);
		} else if(CAN_SEE(ch, vict) && GET_LEVEL(ch)>=14 &&
			  GET_HIT(ch)<70 && number(0,chance)==0){
			act("$n says, 'Heal!'", 1, ch, 0, 0, TO_ROOM);
			cast_heal(GET_LEVEL(ch), ch, "",
			  SPELL_TYPE_SPELL, ch, 0);
		} else if(CAN_SEE(ch, vict) && GET_LEVEL(ch)>=9 &&
			  GET_HIT(ch)<60 && number(0,chance)==0){
			act("$n says, 'Cure critical wounds!'", 1, ch,
			  0, 0, TO_ROOM);
			cast_cure_critic(GET_LEVEL(ch), ch, "",
			  SPELL_TYPE_SPELL, ch, 0);
		} else if(CAN_SEE(ch, vict) &&
			  GET_HIT(ch)<50 && number(0,chance)==0){
			act("$n says, 'Cure light wounds!'", 1, ch,
			  0, 0, TO_ROOM);
			cast_cure_light(GET_LEVEL(ch), ch, "",
			  SPELL_TYPE_SPELL, ch, 0);
		} else if(number(0,chance)==0){
			act("$n says, 'Armor!'", 1, ch, 0, 0, TO_ROOM);
			cast_armor(GET_LEVEL(ch), ch, "",
			  SPELL_TYPE_SPELL, ch, 0);
		}
		funct_ptr=0;
		switch(GET_LEVEL(ch)){
		case 1:
		case 2:
		case 3:
		case 4:
		case 5:
		case 6:
			if(CAN_SEE(ch, vict) && number(0,chance)==0 &&
			   !IS_AFFECTED(vict, AFF_POISON)){
				act("$n says, 'Poison!'", 1, ch, 0, 0, TO_ROOM);
				funct_ptr=cast_poison;
			} else if(CAN_SEE(ch, vict) && number(0,chance)==0) {
				act("$n says, 'Blindness!'", 1, ch, 0, 0, TO_ROOM);
				funct_ptr=cast_blindness;
			}
				
			break;
		case 7:
		case 8:
		case 9:
		case 10:
		case 11:
			if(CAN_SEE(ch, vict) && number(0,chance)==0) {
				act("$n says, 'Quake!'", 1, ch, 0, 0, TO_ROOM);
				funct_ptr=cast_earthquake;
			} else  if(CAN_SEE(ch, vict) && IS_GOOD(ch) &&
				   IS_EVIL(vict) && number(0,chance)==0) {
				act("$n says, 'Dispel evil!'", 1, ch, 0, 0, TO_ROOM);
				funct_ptr=cast_dispel_evil;
			}
			break;
		case 12:
		case 13:
		case 14:
		case 15:
			if(CAN_SEE(ch, vict) && !IS_EVIL(ch) &&
			   IS_EVIL(vict) && number(0,chance)==0){
				act("$n says, 'Dispel evil!'", 1, ch, 0, 0, TO_ROOM);
				funct_ptr=cast_dispel_evil;
			} else if(CAN_SEE(ch, vict) && number(0,chance)==0) {
				act("$n says, 'Quake!'", 1, ch, 0, 0, TO_ROOM);
				funct_ptr=cast_earthquake;
			}
			break;
		case 16:
		case 17:
		case 18:
		case 19:
		case 20:
			if(CAN_SEE(ch, vict) && number(0,chance)==0 &&
			   OUTSIDE(ch) && (zone_table[world[ch->in_room].zone].conditions.precip_rate > 5)){
				act("$n says, 'Call lightning!'", 1, ch, 0, 0, TO_ROOM);
				funct_ptr=cast_call_lightning;
			} else if(CAN_SEE(ch, vict) && number(0,chance)==0) {
				act("$n says, 'Harm!'", 1, ch, 0, 0, TO_ROOM);
				funct_ptr=cast_harm;
			} else if(CAN_SEE(ch, vict) && number(0,chance)==0) {
				act("$n says, 'Quake!'", 1, ch, 0, 0, TO_ROOM);
				funct_ptr=cast_earthquake;
			}
			break;
		case 21:
		case 22:
		case 23:
		case 24:
		case 25:
		case 26:
		case 27:
		case 28:
		case 29:
		case 30:
		default:
			if(!IS_EVIL(ch) && IS_EVIL(vict) && number(0,chance)==0){
				act("$n says, 'Dispel evil!'", 1, ch,
				  0, 0, TO_ROOM);
				cast_dispel_evil(GET_LEVEL(ch), ch, "",
				  SPELL_TYPE_SPELL, vict, 0);
			} else if(number(0,chance)==0){
				act("$n says, 'Harm!'", 1, ch, 0, 0, TO_ROOM);
				funct_ptr=cast_harm;
			} else if(CAN_SEE(ch, vict) && number(0,chance)==0 &&
			   OUTSIDE(ch) && (zone_table[world[ch->in_room].zone].conditions.precip_rate > 5)){
				act("$n says, 'Call lightning!'", 1, ch,
				  0, 0, TO_ROOM);
				funct_ptr=cast_call_lightning;
			} else if(CAN_SEE(ch, vict) && number(0,chance)==0) {
				act("$n says, 'Quake!'", 1, ch, 0, 0, TO_ROOM);
				funct_ptr=cast_earthquake;
			}
			break;
		}
		if(funct_ptr){
			if(funct_ptr==cast_earthquake){
				for(t_vict=world[ch->in_room].people;
				    t_vict; t_vict = t_vict->next_in_room){
					if(IS_NPC(t_vict)){ /* No quake if NPCs in the same room */
						act("$n says, 'Blind!'", 1, ch, 0, 0, TO_ROOM);
						funct_ptr=cast_blindness;
						break;
					}
				}
			}
			if(vict)
				funct_ptr(GET_LEVEL(ch), ch, "",
				  SPELL_TYPE_SPELL, vict, 0);
			if(funct_ptr!=cast_earthquake){
				for(t_vict=world[ch->in_room].people; t_vict;
				    t_vict=t_vict->next_in_room){
					if(!IS_NPC(t_vict) &&
					   CAN_SEE(ch, t_vict) &&
					   t_vict != vict &&
					   number(0,(31-GET_LEVEL(ch))/5)==0){
						funct_ptr(GET_LEVEL(ch), ch,
						  "", SPELL_TYPE_SPELL,
						  t_vict, 0);
					}
				}
			}
		}
	} /* HAS_CL */
	if (IS_SET(ch->specials.act, ACT_HAS_MU) &&
	    IS_FIGHTING(ch)){
		chance=niceness(ch);
		vict = ch->specials.fighting;
		if(vict->in_room!=ch->in_room)
			return;
		if(GET_LEVEL(ch)>8 && CAN_SEE(ch, vict) && number(0,chance)==0){
			act("$n says, 'Blindness!'", 1, ch, 0, 0, TO_ROOM);
			cast_blindness(GET_LEVEL(ch), ch, "",
			  SPELL_TYPE_SPELL, vict, 0);
		} else if (CAN_SEE(ch, vict) && GET_LEVEL(ch)>=14 &&
			   number(0,chance)==0){
			act("$n says, 'Sleep!'", 1, ch, 0, 0, TO_ROOM);
			for(t_vict=world[ch->in_room].people; t_vict;
			    t_vict=t_vict->next_in_room){
				if(!IS_NPC(t_vict) && CAN_SEE(ch, t_vict) &&
				   number(0, (31-GET_LEVEL(ch))/6)==0){
					cast_sleep(GET_LEVEL(ch), ch, "",
					  SPELL_TYPE_SPELL, t_vict, 0);
				}
			}
		} else if (CAN_SEE(ch, vict) && GET_LEVEL(ch)>=5 &&
			   number(0,chance)==0){
			act("$n says, 'Armor!'", 1, ch, 0, 0, TO_ROOM);
			cast_armor(GET_LEVEL(ch), ch, "",
			  SPELL_TYPE_SPELL, ch, 0);
		} else if (GET_LEVEL(ch)>=7 && number(0,chance)==0){
			act("$n says, 'Strength!'", 1, ch, 0, 0, TO_ROOM);
			cast_strength(GET_LEVEL(ch), ch, "",
			  SPELL_TYPE_SPELL, ch, 0);
		} else if (CAN_SEE(ch, vict) && GET_LEVEL(ch)>=12 &&
			   number(0,chance)==0){
			act("$n says, 'Curse!'", 1, ch, 0, 0, TO_ROOM);
			cast_curse(GET_LEVEL(ch), ch, "",
			  SPELL_TYPE_SPELL, vict, 0);
		}
		funct_ptr=0;
		switch(GET_LEVEL(ch)){
		case 1:
		case 2:
		case 3:
			if(vict && CAN_SEE(ch, vict) && number(0,chance)==0){
				act("$n says, 'Magic missile!'", 1, ch, 0, 0, TO_ROOM);
				funct_ptr=cast_magic_missile;
			} else if(vict && CAN_SEE(ch, vict) && number(0,chance)==0){
				act("$n says, 'Chill touch!'", 1, ch, 0, 0, TO_ROOM);
				funct_ptr=cast_chill_touch;
			}
			break;
		case 4:
		case 5:
		case 6:
			if(CAN_SEE(ch, vict) && number(0,chance)==0){
				act("$n says, 'Burning hands!'", 1, ch, 0, 0, TO_ROOM);
				funct_ptr=cast_burning_hands;
			} if(CAN_SEE(ch, vict) && number(0,chance)==0){
				act("$n says, 'Chill touch!'", 1, ch, 0, 0, TO_ROOM);
				funct_ptr=cast_chill_touch;
			}
			break;
		case 7:
		case 8:
		case 9:
		case 10:
			if(CAN_SEE(ch, vict) && number(0,chance)==0){
				act("$n says, 'Shocking Grasp!'", 1, ch, 0, 0, TO_ROOM);
				funct_ptr=cast_shocking_grasp;
			} else if(CAN_SEE(ch, vict) && number(0,chance)==0){
				act("$n says, 'Chill touch!'", 1, ch, 0, 0, TO_ROOM);
				funct_ptr=cast_chill_touch;
			}

			break;
		case 11:
		case 12:
		case 13:
			if(CAN_SEE(ch, vict) && number(0,chance)==0){
				act("$n says, 'Colour spray!'", 1, ch, 0, 0, TO_ROOM);
				funct_ptr=cast_colour_spray;
			} if(CAN_SEE(ch, vict) && number(0,chance)==0){
				act("$n says, 'Magic missile!'", 1, ch, 0, 0, TO_ROOM);
				funct_ptr=cast_magic_missile;
			}
			break;
		case 14:
		case 15:
		case 16:
		case 17:
		case 18:
		case 19:
			if(CAN_SEE(ch, vict) && number(0,chance)==0){
				act("$n says, 'Energy drain!'", 1, ch, 0, 0, TO_ROOM);
				funct_ptr=cast_energy_drain;
			} else if(CAN_SEE(ch, vict) && number(0,chance)==0){
				act("$n says, 'Lightning bolt!'", 1, ch, 0, 0, TO_ROOM);
				funct_ptr=cast_lightning_bolt;
			}
			break;
		case 20:
		case 21:
		case 22:
		case 23:
		case 24:
		case 25:
		case 26:
		case 27:
		case 28:
		case 29:
		case 30:
		default:
			if(CAN_SEE(ch, vict) && number(0,chance)==0){
				act("$n says, 'Fireball!'", 1, ch, 0, 0, TO_ROOM);
				funct_ptr=cast_fireball;
			} else if(CAN_SEE(ch, vict) && number(0,chance)==0){
				act("$n says, 'Lightning bolt!'", 1, ch, 0, 0, TO_ROOM);
				funct_ptr=cast_lightning_bolt;
			} else if(CAN_SEE(ch, vict) && number(0,chance)==0 &&
				  !(IS_AFFECTED(vict, AFF_CHARM) &&
				    vict->master==ch)){
				act("$n says, 'Charm!'", 1, ch, 0, 0, TO_ROOM);
				funct_ptr=cast_charm_person;
			}
			break;
		}
		if(funct_ptr){
			if(vict)
				funct_ptr(GET_LEVEL(ch), ch, "",
				  SPELL_TYPE_SPELL, vict, 0);
			for(t_vict=world[ch->in_room].people; t_vict;
			    t_vict=t_vict->next_in_room){
				if(!IS_NPC(t_vict) && t_vict!=vict &&
				   CAN_SEE(ch, t_vict) &&
				   number(0,(31-GET_LEVEL(ch))/6)==0){
					funct_ptr(GET_LEVEL(ch), ch, "",
					  SPELL_TYPE_SPELL, t_vict, 0);
				}
			}
		}
	} /* HAS_MU */
	if (IS_SET(ch->specials.act, ACT_HAS_TH) &&
	    IS_FIGHTING(ch)){
		switch(GET_LEVEL(ch)){
		case 1:
		case 2:
		case 3:
		case 4:
		case 5:
		case 6:
		case 7:
		case 8:
		case 9:
		case 10:
		case 11:
		case 12:
		case 13:
		case 14:
		case 15:
		case 16:
		case 17:
		case 18:
		case 19:
		case 20:
		case 21:
		case 22:
		case 23:
		case 24:
		case 25:
		case 26:
		case 27:
		case 28:
		case 29:
		case 30:
		default:
		}
	} /* HAS_TH */
	if (IS_SET(ch->specials.act, ACT_HAS_WA) &&
	    IS_FIGHTING(ch)){
		vict = ch->specials.fighting;
		chance = niceness(ch);
		if(CAN_SEE(ch, vict) && number(0,chance)==0){
			do_bash(ch, "", 0);
		} else if(CAN_SEE(ch, vict) && number(0,chance)==0){
			do_kick(ch, "", 0);
		}
		if(CAN_SEE(ch, vict) && number(0,chance)==0 && GET_LEVEL(ch)>10){
			do_kick(ch, "", 0);
		} else if(CAN_SEE(ch, vict) &&
			  number(0,chance)==0 && GET_LEVEL(ch)>15){
			do_bash(ch, "", 0);
		}
	} /* HAS_WA */
	}   /* If IS_MOB(ch)  */
}