/**********************************************************************
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;
}