/
roa/
roa/lib/boards/
roa/lib/config/
roa/lib/edits/
roa/lib/help/
roa/lib/misc/
roa/lib/plrobjs/
roa/lib/quests/
roa/lib/socials/
roa/lib/www/
roa/lib/www/LEDSign/
roa/lib/www/LEDSign/fonts/
roa/lib/www/LEDSign/scripts/
roa/src/s_inc/
roa/src/sclient/
roa/src/sclient/binary/
roa/src/sclient/text/
roa/src/util/
/**********************************************************************
  zoneact.c	Realms of Aurealis	zone activities and spec/procs

		But, then I started adding room procs OLCable and activity.c
		got too long, so I have split up that file into two
		called mobact.c and roomact.c...note: sooner or later
		there will be zoneact.c as well to perform zone procs such
		as zone specific weather and what not...
		3/13/97 - zoneact.c has been added -roa

  Author: 	jtrhone aka Vall of RoA
**********************************************************************/
#include "conf.h"
#include "sysdep.h"

#include "structures.h"
#include "utils.h"
#include "db.h"
#include "comm.h"
#include "interpreter.h"
#include "acmd.h"
#include "handler.h"
#include "magic.h"
#include "bard.h"
#include "lists.h"
#include "fight.h"

#define MARK(room)      (SET_BIT(world[room].room_flags, BFS_MARK))
#define UNMARK(room)    (REMOVE_BIT(world[room].room_flags, BFS_MARK))
#define IS_MARKED(room) (ROOM_FLAGGED((room), BFS_MARK))

/* external vars */
extern int rev_dir[];

// external functions
extern void do_zone_storm(int zone);
extern void do_zone_blizzard(int zone);
extern void send_soundfile_to_client(dsdata *d, char *sname);

void check_zone_music(void)
{
  dsdata *d;

  for (d = descriptor_list; d;d=d->next)
  if (D_CHECK(d) && HAS_CLIENT(d) && d->zone_stimer > -1)
  {
    d->zone_stimer--;
    if (d->zone_stimer == 0)
    {
      int tozone;
      if (INVALID_ROOM(d->character->in_room))
        continue;

      tozone = world[d->character->in_room].zone;

      // if not in the original zone, or the sound file is gone...
      if (!zone_table[tozone].sound_file || tozone != d->music_zone)
      {
        d->zone_stimer = -1;
        d->music_zone  = -1;
        continue;
      }

      // else send it and set the numbers...
      send_soundfile_to_client(d, zone_table[tozone].sound_file);
      d->zone_stimer = zone_table[tozone].music_timer;
      d->music_zone  = tozone;
    }
  }
}

/* control various zone aspects */
void	zone_activity(void)
{
  int i;

  check_zone_music();

  for (i=0; i < NUM_ZONES; i++)
  if (REAL_ZONE(i) && !ZONE_FLAGGED(i, Z_FREED))
  {
    if (ZONE_FLAGGED(i, Z_TSTORM))
    {
      if (zone_table[i].current_gtemp > 32)
      {
	if (number(0,1))
	  do_zone_storm(i);
      }
      else
      {
	REMOVE_BIT(ZONE_FLAGS(i), Z_TSTORM);
	SET_BIT(ZONE_FLAGS(i), Z_BLIZZARD);
      }
    }

    if (ZONE_FLAGGED(i, Z_BLIZZARD))
    {
      if (zone_table[i].current_gtemp <= 32)
      {
	if (number(0,1))
	  do_zone_blizzard(i);
      }
      else
      {
	REMOVE_BIT(ZONE_FLAGS(i), Z_BLIZZARD);
	SET_BIT(ZONE_FLAGS(i), Z_TSTORM);
      }
    }
  }
}

// use source rooms to dictate descs for every other room in zone
// except other sources and NOGEN rooms
int generate_descrips(int zone, int *room_stack, int room_top)
{
  int source_stack[100], source_top = 0, spick, i;
  extern exdescdata *free_extra_descrips(exdescdata *head);
  extern exdescdata *dupe_exdesc_over(exdescdata *head);

  // stick all source rooms into a source stack for fast pickins -roa
  for (i = 0; i < room_top; i++)
    if (ROOM_FLAGGED2(room_stack[i], SOURCE_ROOM))
      source_stack[source_top++] = room_stack[i];

  if (!source_top)
  {
    sprintf(buf, "SYSERR: No SOURCE rooms in DESCGEN zone %d.",zone);
    mudlog(buf, BRF, LEV_IMM, TRUE);
    return FALSE;
  }

  // no go thru rooms, each one that isnt SOURCE or NOGEN,
  // assign it a descript from source_stack
  for (i = 0; i < room_top; i++)
    if (!ROOM_FLAGGED2(room_stack[i], SOURCE_ROOM) &&
	!ROOM_FLAGGED2(room_stack[i], NOGEN_ROOM))
    {
      FREENULL(world[room_stack[i]].name);
      FREENULL(world[room_stack[i]].description);
      world[room_stack[i]].exdesc = free_extra_descrips(world[room_stack[i]].exdesc);

      // now pick one from sources, and dupe it over
      spick = number(0, source_top -1);
      world[room_stack[i]].name = STR_DUP(world[source_stack[spick]].name);
      world[room_stack[i]].description = STR_DUP(world[source_stack[spick]].description);
      world[room_stack[i]].exdesc = dupe_exdesc_over(world[source_stack[spick]].exdesc);
    }

  sprintf(buf, "SYSUPD: Zone %d: AutoDescGen with %d source rooms.",zone, source_top-1);
  mudlog(buf, BUG, LEV_IMM, TRUE);
  return TRUE;
}

// given zone, two room rnums, and the stack (unused at this point)
// try to "rconnect" them with an unused direction
int hookup_rooms(int zone, int cur, int pick, int *room_stack, int room_top)
{
  int dir, rdir, num = 0;
  rmdata *otherroom, *thisroom;
 
  do {
    dir = number(0, NUM_OF_DIRS - 1);
    if (num++ > 50)  // check umpteen times
    {
      // log("Gave up.");
      return FALSE;	// couldn't find one :(
    }
    // if lateral zone, don't go up or down -roa
  } while (DIR(cur, dir) || DIR(pick, rev_dir[dir]) || 
	   (ZONE_FLAGGED(zone, Z_EXITGENLAT) && (dir == 4 || dir == 5)));

  rdir = rev_dir[dir];
  thisroom = &world[cur];
  otherroom = &world[pick];

  // create dir to new room
  CREATE(thisroom->dir_option[dir], rmdirdata, 1);
  thisroom->dir_option[dir]->keyword = NULL;
  thisroom->dir_option[dir]->exit_descr = NULL;

  // Exit messages. 03/24/98 -callahan
  thisroom->dir_option[dir]->enter = NULL;
  thisroom->dir_option[dir]->oenter = NULL;
  thisroom->dir_option[dir]->drop = NULL;
  thisroom->dir_option[dir]->odrop = NULL;

  thisroom->dir_option[dir]->to_room_virtual = otherroom->number;
  thisroom->dir_option[dir]->to_room = pick;

  // create dir from new room to thisroom
  CREATE(otherroom->dir_option[rdir], rmdirdata, 1);
  otherroom->dir_option[rdir]->keyword = NULL;
  otherroom->dir_option[rdir]->exit_descr = NULL;


  // Exit messages. 03/24/98 -callahan
  otherroom->dir_option[rdir]->enter = NULL;
  otherroom->dir_option[rdir]->oenter = NULL;
  otherroom->dir_option[rdir]->drop = NULL;
  otherroom->dir_option[rdir]->odrop = NULL;

  otherroom->dir_option[rdir]->to_room_virtual = thisroom->number;
  otherroom->dir_option[rdir]->to_room = real_room(thisroom->number);

  return TRUE;
}

// only call if EXITGENALL or EXITGENLAT zone
int wax_dirs(int zone, int *stk, int top)
{
  int i = 0, dir;
  
  if (!ZONE_FLAGGED(zone, Z_EXITGENALL) && !ZONE_FLAGGED(zone, Z_EXITGENLAT))
    return FALSE;

  for ( ; i < top; i++) 
    for (dir = 0; dir < NUM_OF_DIRS; dir++)
    {
      // if it leads to another zone, dont kill it
      if (DIR(stk[i], dir) && !EXIT_FLAGGED(DIR(stk[i], dir), EX_NOGEN) &&
	  (INVALID_ROOM(DIR(stk[i], dir)->to_room) || 
	  world[DIR(stk[i], dir)->to_room].zone == zone))
      {
	// wax the puppy
	FREENULL(DIR(stk[i], dir)->keyword);
	FREENULL(DIR(stk[i], dir)->exit_descr);

        // Nuke exit messages. 03/24/98 -callahan
	FREENULL(DIR(stk[i], dir)->enter);
	FREENULL(DIR(stk[i], dir)->oenter);
	FREENULL(DIR(stk[i], dir)->drop);
	FREENULL(DIR(stk[i], dir)->odrop);

	FREENULL(DIR(stk[i], dir));
      }
    }
  return TRUE;
}

// there is an unmarked room in said stack of rnums
int has_unmarked(int *stk, int top)
{
  int i;
  for (i = 0; i < top; i++)
    if (!IS_MARKED(stk[i]))
      return TRUE;
  return FALSE;
}

// generate a random zone for auto generate zones
int generate_zone(int zone)
{
  int cur, pick;
  int rnum, vnum, last;
  int room_stack[100], picked_stack[100];
  int room_top = 0, picked_top = 0;

  last = zone*100+99;

  for (vnum=zone*100; vnum <= last; vnum++)
    if ((rnum = real_room(vnum)) > 0)
    {
      UNMARK(rnum);
      room_stack[room_top++] = rnum;
    }

  if (!room_top)	// no rooms in zone?
  {
    sprintf(buf, "SYSERR: No rooms in autogen zone %d.",zone);
    mudlog(buf, BRF, LEV_IMM, TRUE);
    return FALSE; 
  }

  // ok, we have our stack of rooms from this zone
  // now send it over to generate_descripts
  if (ZONE_FLAGGED(zone, Z_DESCGEN))
    generate_descrips(zone, room_stack, room_top);

  // ok we done with descrips for now, if no exit to be done, go home
  if (!ZONE_FLAGGED(zone, Z_EXITGENALL) && !ZONE_FLAGGED(zone, Z_EXITGENLAT))
    return TRUE;

  // ok, assume descrips are generated, now do dirs...
  wax_dirs(zone, room_stack, room_top);

  // the actual dir generation algorithm

  cur = room_stack[number(0, room_top - 1)];
  MARK(cur);

  while (has_unmarked(room_stack, room_top)) // this could take forever!
  {
    pick = room_stack[number(0, room_top - 1)];
    if (IS_MARKED(pick) && picked_top > 0)
    {
      cur = picked_stack[--picked_top];
    }
    else
    {
      if (!IS_MARKED(pick))
        if (hookup_rooms(zone, cur, pick, room_stack, room_top))
          MARK(pick);
      picked_stack[picked_top++] = cur;
      cur = pick;
    }
  }
  sprintf(buf, "SYSUPD: Zone %d: AutoExit Generation.", zone);
  mudlog(buf, BUG, LEV_IMM, TRUE);
  return TRUE;
}