deltamud/deltamud/
deltamud/deltamud/bin/
deltamud/deltamud/cnf/
deltamud/deltamud/lib/
deltamud/deltamud/lib/etc/
deltamud/deltamud/lib/misc/
deltamud/deltamud/lib/plrobjs/
deltamud/deltamud/lib/text/
deltamud/deltamud/lib/text/help/
deltamud/deltamud/lib/world/
deltamud/deltamud/lib/world/trg/
/* ************************************************************************
   *   File: mobact.c                                      Part of CircleMUD *
   *  Usage: Functions for generating intelligent (?) behavior in mobiles    *
   *                                                                         *
   *  All rights reserved.  See license.doc for complete information.        *
   *                                                                         *
   *  Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University *
   *  CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991.               *
   ************************************************************************ */

#include "conf.h"
#include "sysdep.h"

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

/* external structs */
extern struct char_data *character_list;
extern struct index_data *mob_index;
extern struct room_data *world;
extern struct str_app_type str_app[];

#define MOB_AGGR_TO_ALIGN (MOB_AGGR_EVIL | MOB_AGGR_NEUTRAL | MOB_AGGR_GOOD)

void 
mobile_activity (void)
{
  register struct char_data *ch, *next_ch, *vict;
  struct obj_data *obj, *best_obj;
  int door, found, max;
  memory_rec *names;
  int reverse_att=0;

  extern int no_specials;

  ACMD (do_get);

  for (ch = character_list; ch; ch = next_ch)
    {
      next_ch = ch->next;

      if (!IS_MOB (ch))
	continue;

      /* Examine call for special procedure */
      if (MOB_FLAGGED (ch, MOB_SPEC) && !no_specials)
	{
	  if (mob_index[GET_MOB_RNUM (ch)].func == NULL)
	    {
	      sprintf (buf, "SYSERR: %s (#%d): Attempting to call non-existing mob func",
		       GET_NAME (ch), GET_MOB_VNUM (ch));
	      log (buf);
	      REMOVE_BIT (MOB_FLAGS (ch), MOB_SPEC);
	    }
	  else
	    {
	      if ((mob_index[GET_MOB_RNUM (ch)].func) (ch, ch, 0, ""))
		continue;	/* go to next char */
	    }
	}

      /* If the mob has no specproc, do the default actions */
      if (FIGHTING (ch) || !AWAKE (ch))
	continue;

      /* Scavenger (picking up objects) */
      if (MOB_FLAGGED (ch, MOB_SCAVENGER) && !FIGHTING (ch) && AWAKE (ch))
	if (world[ch->in_room].contents && !number (0, 10))
	  {
	    max = 1;
	    best_obj = NULL;
	    for (obj = world[ch->in_room].contents; obj; obj = obj->next_content)
	      if (CAN_GET_OBJ (ch, obj) && GET_OBJ_COST (obj) > max)
		{
		  best_obj = obj;
		  max = GET_OBJ_COST (obj);
		}
	    if (best_obj != NULL)
	      {
		obj_from_room (best_obj);
		obj_to_char (best_obj, ch);
		act ("$n gets $p.", FALSE, ch, best_obj, 0, TO_ROOM);
	      }
	  }

      /* Mob Movement */
      if (!MOB_FLAGGED (ch, MOB_SENTINEL) && (GET_POS (ch) == POS_STANDING) &&
	  ((door = number (0, 18)) < NUM_OF_DIRS) && CAN_GO (ch, door) &&
	!ROOM_FLAGGED (EXIT (ch, door)->to_room, ROOM_NOMOB | ROOM_DEATH) &&
	  (!MOB_FLAGGED (ch, MOB_STAY_ZONE) ||
	 (world[EXIT (ch, door)->to_room].zone == world[ch->in_room].zone)))
	{
	  perform_move (ch, door, 1);
	}

      /* Aggressive Mobs */
      if (MOB_FLAGGED (ch, MOB_AGGRESSIVE | MOB_AGGR_TO_ALIGN))
	{
	  found = FALSE;
	  for (vict = world[ch->in_room].people; vict && !found; vict = vict->next_in_room)
	    {
	      if (!vict)
		continue;
	      if (IS_NPC (vict))
		continue;
	      if (!CAN_SEE (ch, vict))
		continue;
	      if (PRF_FLAGGED (vict, PRF_NOHASSLE))
		continue;
              if ((GET_POS(vict) < POS_SLEEPING) && (MOB_FLAGGED(ch, MOB_MERCY))) {
                    sprintf (buf, "%s decides not to kill %s, lying on the ground dying...\r\n",
			GET_NAME(ch), GET_NAME(vict));
                    send_to_room(buf, ch->in_room);
              return;
		}
	      if (MOB_FLAGGED (ch, MOB_WIMPY) && AWAKE (vict))
		continue;
	      if (!MOB_FLAGGED (ch, MOB_AGGR_TO_ALIGN) ||
		  (MOB_FLAGGED (ch, MOB_AGGR_EVIL) && IS_EVIL (vict)) ||
		(MOB_FLAGGED (ch, MOB_AGGR_NEUTRAL) && IS_NEUTRAL (vict)) ||
		  (MOB_FLAGGED (ch, MOB_AGGR_GOOD) && IS_GOOD (vict)))
		{
		  hit (ch, vict, TYPE_UNDEFINED);
		  found = TRUE;
		}
	    }
	}

      /* Mob Memory */
      if (MOB_FLAGGED (ch, MOB_MEMORY) && MEMORY (ch))
	{
	  found = FALSE;
	  for (vict = world[ch->in_room].people; vict && !found; vict = vict->next_in_room)
	    {
	      if (IS_NPC (vict) || !CAN_SEE (ch, vict) || PRF_FLAGGED (vict, PRF_NOHASSLE))
		continue;
	      for (names = MEMORY (ch); names && !found; names = names->next)
		if (names->id == GET_IDNUM (vict))
		  {
		    found = TRUE;
                 if ((GET_POS(vict) < POS_SLEEPING) && (MOB_FLAGGED(ch, MOB_MERCY))) {
                    sprintf (buf, "%s looks down in triumph at %s, dying in agony...\r\n", GET_NAME(ch), 
        		GET_NAME(vict));
                    send_to_room(buf, ch->in_room);
                    }
                     else {
		    act ("'Hey!  You're the fiend that attacked me!!!', exclaims $n.",
			 FALSE, ch, 0, 0, TO_ROOM);
		    hit (ch, vict, TYPE_UNDEFINED);
                    }
		  }
	    }
	}

      /* Helper Mobs */
      if (MOB_FLAGGED (ch, MOB_HELPER))
	{
	  found = FALSE;
	  for (vict = world[ch->in_room].people; vict && !found; vict = vict->next_in_room)
	    if (ch != vict && IS_NPC (vict) && FIGHTING (vict) &&
		!IS_NPC (FIGHTING (vict)) && ch != FIGHTING (vict))
	      {
		act ("$n jumps to the aid of $N!", FALSE, ch, 0, vict, TO_ROOM);
		hit (ch, FIGHTING (vict), TYPE_UNDEFINED);
		found = TRUE;
	      }
	}

      if (MOB_FLAGGED (ch, MOB_PCHELPER_GOOD) && !FIGHTING(ch))
        {
          for (vict = world[ch->in_room].people; vict ; vict = vict->next_in_room)
            if (ch != vict && FIGHTING (vict) && !IS_NPC (vict) && IS_GOOD(vict))
              {
                if ((PLR_FLAGGED(vict, PLR_KILLER) || PLR_FLAGGED(vict, PLR_THIEF)) &&
!IS_NPC(FIGHTING(vict)) && !(PLR_FLAGGED(FIGHTING(vict), PLR_KILLER) || PLR_FLAGGED(FIGHTING(vict),
PLR_THIEF))) reverse_att=1;
                // Help the good guys instead :)
                act ("$n flashes you a brave smile.", FALSE, ch, 0, (!reverse_att ? vict :
FIGHTING(vict)), TO_VICT);
                act ("$n exclaims, 'BANZAII!!!'", FALSE, ch, 0, 0, TO_ROOM);
                act ("$n jumps to your aid!", FALSE, ch, 0, (!reverse_att ? vict : FIGHTING(vict)),
TO_VICT);
                act ("$n jumps to the aid of $N!", FALSE, ch, 0, (!reverse_att ? vict : FIGHTING(vict)),
TO_NOTVICT);
                hit (ch, (reverse_att ? vict : FIGHTING(vict)), TYPE_UNDEFINED);
                break;
              }
          reverse_att=0;
        }

      if (MOB_FLAGGED (ch, MOB_PCHELPER_NEUT) && !FIGHTING(ch))
        {
          for (vict = world[ch->in_room].people; vict ; vict = vict->next_in_room)
            if (ch != vict && FIGHTING (vict) && !IS_NPC (vict) && IS_NEUTRAL(vict))
              {
                act ("$n jumps to your aid!", FALSE, ch, 0, vict, TO_VICT);
                act ("$n jumps to the aid of $N!", FALSE, ch, 0, vict, TO_NOTVICT);
                hit (ch, FIGHTING(vict), TYPE_UNDEFINED);
                break;
              }
        }

      if (MOB_FLAGGED (ch, MOB_PCHELPER_EVIL) && !FIGHTING(ch))
        {
          for (vict = world[ch->in_room].people; vict ; vict = vict->next_in_room)
            if (ch != vict && FIGHTING (vict) && !IS_NPC (vict) && IS_EVIL(vict))
              {
                if (!(PLR_FLAGGED(vict, PLR_KILLER) || PLR_FLAGGED(vict, PLR_THIEF)) &&
!IS_NPC(FIGHTING(vict)) && (PLR_FLAGGED(FIGHTING(vict), PLR_KILLER) || PLR_FLAGGED(FIGHTING(vict),
PLR_THIEF))) reverse_att=1;
                // Help the bad guys instead !@$!@$
                act ("$n snarls viciously at you!", FALSE, ch, 0, (reverse_att ? vict : FIGHTING(vict)),
TO_VICT);
                act ("$n snarls viciously at $N!", FALSE, ch, 0, (reverse_att ? vict : FIGHTING(vict)),
TO_NOTVICT);
                hit (ch, (reverse_att ? vict : FIGHTING(vict)), TYPE_UNDEFINED);
                break;
              }
        }
      /* Add new mobile actions here */

    }				/* end for() */
}



/* Mob Memory Routines */

/* make ch remember victim */
void 
remember (struct char_data *ch, struct char_data *victim)
{
  memory_rec *tmp;
  bool present = FALSE;

  if (!IS_NPC (ch) || IS_NPC (victim) || (GET_LEVEL (victim) >= LVL_IMMORT))
    return;

  for (tmp = MEMORY (ch); tmp && !present; tmp = tmp->next)
    if (tmp->id == GET_IDNUM (victim))
      present = TRUE;

  if (!present)
    {
      CREATE (tmp, memory_rec, 1);
      tmp->next = MEMORY (ch);
      tmp->id = GET_IDNUM (victim);
      MEMORY (ch) = tmp;
    }
}


/* make ch forget victim */
void 
forget (struct char_data *ch, struct char_data *victim)
{
  memory_rec *curr, *prev = NULL;

  if (!(curr = MEMORY (ch)))
    return;

  while (curr && curr->id != GET_IDNUM (victim))
    {
      prev = curr;
      curr = curr->next;
    }

  if (!curr)
    return;			/* person wasn't there at all. */

  if (curr == MEMORY (ch))
    MEMORY (ch) = curr->next;
  else
    prev->next = curr->next;

  free (curr);
}


/* erase ch's memory */
void 
clearMemory (struct char_data *ch)
{
  memory_rec *curr, *next;

  curr = MEMORY (ch);

  while (curr)
    {
      next = curr->next;
      free (curr);
      curr = next;
    }

  MEMORY (ch) = NULL;
}