///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// simple maze-generation!
// Its really simple, if a room is flagged as a 1, it is enterable, if it is beside another room flagged with a 1
// that too becomes linked for movement. If the room is a 2, it checks for up/down, in-which case, if it finds a 1 or a 2
// above or below it in Z value's, then movement up or down is available, (or both)
// Maze stems off nicely, if it reaches a point where it maxes out failed attempts, it moves to a new random location
// and starts generating another map from there. In hopes that they infact-meet up somewhere.
// if it fails 10 times in a row, it aborts the generation where it is, logs it, and lets the maze work.
// if the maze at this point in time is completely broken, the player who auto-genned it will know, as it wont' be
// very usable.
// if the maze gen fails, broken becomes true, and it notifies the player that with it being broken, they *CANNOT*
// complete the maze, and will have to re-enter, and hope that the next one does not fail.
//
// The generation here is quick, and painful. We want to ensure that the map is carefully designed as-to not be too
// generic. Which is why the start-z/y/x exist, making each map alittle different from the last, based entirely off of
// how it selects the start-point, and the random direction it chooses to go.
//
// Memory intensity: This system is very memory intensive, massive maps, being created on the fly, constantly. This will
// need to have some-level of management, such as you cannot create a maze if you've recently been in one (like 30 minutes)
// stopping players from entering/exiting until they get the 'type' of map they want. Only caveat for this is if the maze
// is marked as broken. In that case, don't flag them.
//
// On topic of memory intensity. To avoid massive cpu spiking, it would be recommended that the cooldown between mazes
// per player be a min of half an hour.
//
// *Note: If flagging a player, if they quit the maze before completion, or if they complete it, the wait time should
// always be the same. Infact, quitters should most likely be lagged longer, just because they were part of it.
//
// If an entire group quits, at that point in time, the maze is deleted from memory. Upon completion of the maze
// all players will be sent back to the summoning stone for the maze, including the person who entered the maze itself.
// summon stone should be approx 15/20 x/y coords away from a given maze.
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Lexi::List<maze_data *>maze_list; // keep track of our globally used mazes!
#define ROOM_VNUM_MAZE 4 // Like wilderness. Makes life easier.
class maze_data {
public:
maze_data() { sz = 0; sy = 0; sx = 0; actual_size = 0; mx = 0; broken = false;
level = 0; treasure = 0; repop = 0; rare_drop = 0; elite = false;
monsters_left = 0; bosses_left = 0; started = false;
puzzle_start = 0; puzzles_left = 0;
}
~maze_data() { free_string(name);}
private:
vnum_t repop;
vnum_t rare_drop;
short maze[30][250][250];
short puzzle[30][250][250]; // puzzles to go into the next room!
short summon_x; // the mazes X summon-stone location
short summon_y; // the mazes Y summon-stone location
short sz; // Start Z loc
short sx; // Start X loc
short sy; // Start Y loc
short actual_size; // actual size
short mx; // max size (should be on-par with actual-size)
short level;
short treasure;
short monsters_left; // how many monsters are left (after each kill)
short bosses_left; // how many bosses are left!
short mob_start; // original mob counts
short boss_Start; // original boss counts
short puzzle_start; // how many puzzles will be in the maze
short puzzles_left; // how many puzzles are left!
short players_in_maze; // how many players are in the maze!
const char *maze_name; // name of the maze/dungeon your in!
bool elite;
bool broken;
bool maze_started;
public:
short get_start_x() { return sx; }
short get_start_y() { return sy; }
short get_start_z() { return sz; }
short get_summon_x() { return summon_x; }
short get_summon_y() { return summon_y; }
short get_players() { return players_in_maze; }
short get_puzzles() { return puzzles_left; }
short get_maze(short z, short x, short y) { return maze[z][x][y]; } // (0-1-2 (hopefully it doesn't exceed the max))
short get_size() { return actual_size; }
short get_max() { return mx; }
short get_level() {return level; }
short get_monsters() { return monsters_left; }
short get_bosses() { return bosses_left; }
const char *get_name() { return maze_name; }
bool get_broken() { return broken; }
bool started() { return maze_started; }
bool get_elite() { return elite; }
bool get_broken() { return broken; }
void set_start() { maze_started = true; }
void kill_mob(CHAR_DATA *grp) { // done on raw-kill
if(monsters_left > 0) {
monsters_left–;
if(monsters_left == 0) {
// insert leaderboard here (for ALL group members)
if(elite) {
// secondary leaderboard for elite monsters
}
}
}
return;
}
void kill_boss(CHAR_DATA *grp) { // done on raw-kill
if(bosses_left > 0) {
bosses_left–;
if(bosses_left == 0) {
// clearing dungeons = hardcore.
// insert leaderboard here (for ALL group members)
if(elite) {
// secondary leaderboard for elite boss's
}
}
}
return;
}
/////////////////////////////////////////////////////////////////////////////////////////
// Generates a puzzle so that players cannot pass until they have figure'd it out.
// it can be anything from a saying, phrase, special command issue'd.
// the puzzles are selected from lua scripts.
//
// lua-progs that are puzzles, their description is used not to describe its functionality
// but should infact, be a puzzle, riddle, something for the players to figure out.
//
// puzzle's are marked as staff 3 in the lua.
//
// Puzzles are what make the the maze's worth-while. Solving puzzles helps progress through
// the map, aswell as get bonus's, leaderboard titles. And all sorts of other fun-ness.
// Note, after-awhile, the puzzles will be, well, easy, as they will start repeating, which
// means we will have to write hundreds of puzzles, if not thousands to make this worth-while.
// but hey, thats no worries, as it is *WELL* worth it.
//
void generate_puzzle(short z, short y, short z) {
// puzzle will be the vnum of the puzzle chosen.
}
/////////////////////////////////////////////////////////////////////////////////////////
// Spawn a mobile at position z/x/y, roughly mob_level, from repop_vnum, if marked elite
// we increase stats.
void spawn_mobile(short z, short x, short y, short mob_level, vnum_t repop_vnum, bool elite) {
// 55 % chance of spawning a mobile.
// with the size of mazes, (being up to 530 rooms) it seems to reason that
// nomatter what, mobs are going to spawn. And be quite nasty!
// This should allow us to cap out on our mobs/bosses easily enough, most likely
// with room-to-spare, but thats why we let the mobs wander!
if(number_percent() > 55)
return;
if(mob_start == monsters_left)
return;
WILD_MOB *wmob = find_wild_pattern(repop_vnum);
if(!wmob) return;
int spawn = number_range(0,10);
MOB_INDEX_DATA *mob = get_mob_index(wmob->vnum_list[spawn]);
if(!mob) return;
CHAR_DATA *instanced = create_mobile(mob);
// move to the coordinates
instanced->cord[CORD_Z] = z;
instanced->cord[CORD_X] = x;
instanced->cord[CORD_Y] = y;
////////////////////////////////////////////////////////////////////////
// Ensure that the instanced mobs will group up against the enemies.
instanced->group = (repop_vnum+1); // should ensure their groupie-ness!
char_to_room(get_room_index(ROOM_VNUM_MAZE), instanced); // move into the maze
// set the level
instanced->level = number_range(mob_level-5, mob_level+5);
if(instanced->level < 1) instanced->level = 1;
// We want *ALL* of the mobs to be extremely hostile, so we go aggressive for good measure.
if(!IS_SET(instanced->act, ACT_AGGRESSIVE)) SET_BIT(instanced->act, ACT_AGGRESSIVE);
// Let the mobiles wander, this should help spread out the beasties nicely
// especially if they all spawn at the very start of the maze, and not at the end of its
// generation. Eventually, the mobs should walk all over the place :)
if(IS_SET(instanced->act, ACT_SENTINEL)) REMOVE_BIT(instanced->act, ACT_SENTINEL);
// set our boss's.
if(instanced->level == mob_level+5 && boss_left != boss_start) {
if(!IS_SET(instanced->act, ACT_BOSS)) SET_BIT(instanced->act, ACT_BOSS);
bosses_left++;
}
// increment our monsters.
monsters_left++;
// this fixes the stats with the new level and if a boss, with the new boss flag.
correct_mobile(instanced);
// equip the monsters with random gear so that it is worth while to kill these
// creatures. *Note: If the mobs have a rare drops on them, this gets even
// more interesting, as on kill, they risk creating a nice random object.
maze_output(instanced);
return;
}
/////////////////////////////////////////////////////////////////////////////////////////
// This will populate the maze with mobs from the repop_vnum, which loads the spawns from
// wild_mob list, normally reserved for patterns, is now being used here to help populate
// the random maze.
// mob_level assigns the approximate level of the mobs
// repop_vnum pulls the respawned mobs from the pattern maps.
// treasure-level is the approximate worth of the treasure (1-10, 10 being best)
// rare_drop_vnum is the vnum of the object that will be the random-drop on the boss
// mob in the dungeon.
// elite means the players selected elite mobs when they summoned in their friends.
// this means mobs are even stronger, and smarter.
// aswell as improving the treasure (even if it was a 10, they get better)
/////////////////////////////////////////////////////////////////////////////////////////
// Maze generation as easy as maze->generate_maze(20,100,88, 1800, 325, 88, 10, 7, 25, 3, 5, 88, true, "Jaspers Dungeon of Territorial Doom");
// we randomly generate the maze!
// this is fun, smart, and overall, exciting.
void generate_maze(short z, short x, short y, short sum_x, short sum_y, short mob_count, short boss_count, puzzle_count, short mob_level, vnum_t repop_vnum, short treasure_level, vnum_t rare_drop_vnum, bool elite, const char *name) {
int xy, yy, zy;
int max_size = 0;
spawn_mobile(current_z, current_x, current_y, mob_level, repop_vnum, elite);
////////////////////////////////////////////////////////////////////////
// x/y/z variables just allocate our max-size(in total) they don't manage
// how far east/west/up/down/north/south things will go.
// those are maxed anyways. However, we always ensure we are more then
// taken-care of with our overall layout.
// ensure our maximums are not exceeded
if(x > 250) x = 250;
if(y > 250) y = 250;
if(z > 30) z = 30;
maze_name = str_dup(name);
mob_start = mob_count;
boss_start = boss_count;
puzzle_start = puzzle_count;
////////////////////////////////////////////////////////////////////////
// zero the map first. (safe practice before having fun)
for(xy = 0; xy < x; xy++ ) {
for(yy = 0; yy < y; yy++ ) {
for(zy = 0; zy < z; zy++ ) {
maze[x][y][z] = 0;
}
}
}
int counter = 0;
int start_room_x, start_room_y, start_room_z;
summon_x = sum_x;
summon_y = sum_y;
max_size == (x+y)+z; // z feels left out ;) (making a joke with code)
mx = max_size; // set our 'supposed' to be size.
start_room_x = number_range(0,x);
start_room_y = number_range(0,y);
start_room_z = number_range(0,z);
////////////////////////////////////////////////////////////////////////
// make that room in the maze exist!
maze[start_room_z][start_room_x][start_room_y] = 1;
// our start-room in the maze! (MUAHAHAHAHAHA)
sz = start_room_z;
sx = start_room_x;
sy = start_room_y;
// so we know where we are in the map!
int current_x = start_room_x;
int current_y = start_room_y;
int current_z = start_room_z;
int attempt = 0;
int attempt_maxed 0;
// Lets make the maze!
for(;;) {
int direction = number_range(0,6);
bool failed = false;
short jump_back = false;
// map is done! Reached our max-size! Time to populate! (if we managed to breach it
// with the jumpback code, then we say whatever, and carry on peacefully)
if(count >= max_size) break;
if(attempt == 6) {
// failed 6 times, that means all exits around the person, are filled.
// and it wouldn't progress anyfurther. (or it just had bad luck
// randomizing the same number, but, to prevent a potential lockup
// we move the current_x/y/z locations to a random spot, and hope
// it manages to link up with the rest. Else wise, the dungeon
// could be pooched!
attempt = 0; // reset attempt count!
attempt_maxed++; // maxed our attempt 6 times
// now we count that.
// if we have a massive glitch
// we'd like to know!
if(attempt_max == 10) // we maxed our attempts 10 times
{ // now we do some fancy logging when this happens.
broken = true; // yup, its broken.
log_string("[MAZE GEN] %s reached max generation attempts, with a count of %d of %d", __PRETTY_FUNCTION__, count, max_size);
break; // we don't want to lockup
} // so we break the generation
// and hope that all is well.
current_x = number_range(0,x);
current_y = number_range(0,y);
current_z = number_range(0,z);
}
// here is where we get…. creepy!
jump_back = number_range(0,11);
///////////////////////////////////////////////////////////////////////////////////////////////////////
// Jumping back, this got the name because it creates stretch's off of the main-path and then jumps
// back to the path, and carries on with the normal map generation. Sick little plan.
// This will be interesting.
// *Note: east/west/north/south directions care if a room is already-set, and won't move into it.
// however, up/down don't care, and will move into it, and change the exits to 2, so it knows it can
// go up or down.
// the bonus stretches can head off up to 12 rooms (including the original off-shoot)
// the extra stretches are a percent chance to happen, they do not always occur when jump-back takes
// place, this should help create little balls of extra-joy.
///////////////////////////////////////////////////////////////////////////////////////////////////////
if(jump_back == 4) { // why 4? Why not!
short where = number_range(0,3);
short max_p = number_range(3,11);
// change in x/y/z location.
switch(where) {
// NORTH/SOUTH MANIPULATION
default:
case 0:
if(number_range(0,1) == 1) {
current_x++;
if(current_x != 250) {
if(maze[current_z][current_x][current_y] == 0) {
maze[current_z][current_x][current_y] = 1;
count++;
if(number_percent() > number_range(78,100))
for(int p = 0; p < max_p; p++) {
if(current_x+p < 250) {
if(maze[current_z][current_x+p][current_y] == 0) {
maze[current_z][current_x+p][current_y] = 1;
count++;
spawn_mobile(current_z, current_x+p, current_y, mob_level, repop_vnum, elite);
}
}
}
}
current_x–; // go back to our original x location and continue from there!
} else {
current_x++;
if(current_x != 250) {
if(maze[current_z][current_x][current_y] == 0) {
maze[current_z][current_x][current_y] = 1;
count++;
if(number_percent() > number_range(78,100))
for(int p = 0; p < max_p; p++) {
if(current_x-p > -1) {
if(maze[current_z][current_x-p][current_y] == 0) {
maze[current_z][current_x-p][current_y] = 1;
count++;
spawn_mobile(current_z, current_x-p, current_y, mob_level, repop_vnum, elite);
}
}
}
}
current_x–; // go back to our original x location and continue from there!
}
// EAST/WEST CHANGING
case 1:
if(number_range(0,1) == 1) {
current_y++;
if(current_y != 250) {
if(maze[current_z][current_x][current_y] == 0) {
maze[current_z][current_x][current_y] = 1;
count++;
if(number_percent() > number_range(78,100))
for(int p = 0; p < 5; max_p++) {
if(current_y+p < 250) {
if(maze[current_z][current_x][current_y+p] == 0) {
maze[current_z][current_x][current_y+p] = 1;
count++;
spawn_mobile(current_z, current_x, current_y+p, mob_level, repop_vnum, elite);
}
}
}
}
current_y–; // go back to our original x location and continue from there!
} else {
current_y++;
if(current_y != 250) {
if(maze[current_z][current_x][current_y] == 0) {
maze[current_z][current_x][current_y] = 1;
count++;
if(number_percent() > number_range(78,100))
for(int p = 0; p < max_p; p++) {
if(current_y-p > -1) {
if(maze[current_z][current_x][current_y-p] == 0) {
maze[current_z][current_x][current_y-p] = 1;
count++;
spawn_mobile(current_z, current_x, current_y-p, mob_level, repop_vnum, elite);
}
}
}
}
current_y–; // go back to our original x location and continue from there!
}
///////////////////////////////////////////////////////////////////////////////////////////
// UP/DOWN MANIPULATION.. THIS *IS* VITAL AND SCARY AT THE SAME TIME!
case 2:
if(number_range(0,1) == 1) {
current_z++;
if(current_z != 30) {
maze[current_z][current_x][current_y] = 2;
count++;
if(number_percent() > number_range(78,100))
for(int p = 0; p < max_p; p++) {
if(current_x+p < 30) {
maze[current_z+p][current_x][current_y] = 2;
count++;
spawn_mobile(current_z+p, current_x, current_y, mob_level, repop_vnum, elite);
}
}
current_z–; // go back to our original x location and continue from there!
} else {
current_z++;
if(current_z != 30) {
maze[current_z][current_x][current_y] = 2;
count++;
if(number_percent() > number_range(78,100))
for(int p = 0; p < max_p; p++) {
if(current_z-1p > -1) {
maze[current_z-p][current_x][current_y] = 2;
count++;
spawn_mobile(current_z+p, current_x, current_y, mob_level, repop_vnum, elite);
}
}
current_z–; // go back to our original x location and continue from there!
}
break;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
// Continuing the insanity here:
// Our now official goal, if we did, or did not stem off, is to now change our direction, and parse
// through and hopefully generate a really cool new design/layout for the overall map
// because of the treeing system above, we hope to see many sub-paths carry off from the original
// path.. Perfect to hide evil little minions in them.
///////////////////////////////////////////////////////////////////////////////////////////////////////
switch(direction) {
default:
case DIR_NORTH:
// cannot go any-further north!
if(current_x+1 == 250){
failed = true;
break;
}
if(maze[current_x][current_x+1][current_y] == 0) {
current_x++;
maze[current_z][current_x][current_y] = 1;
spawn_mobile(current_z, current_x, current_y, mob_level, repop_vnum, elite);
// here we go with a chance to make an extra direction (helps space-out the map)
if(current_x+1 == 250) break; // not failed because we did increment.
if(number_range(0,5) == number_range(0,5)) {
if(maze[current_z][current_x+1][current_y] == 0) {
current_x++;
count++; // so we keep our counts properly.
maze[current_z][current_x][current_y] = 1;
}
}
} else { failed = true; }
break;
case DIR_SOUTH:
// cannot go any-further north!
if(current_x-1 == -1){
failed = true;
break;
}
if(maze[current_x][current_x-1][current_y] == 0) {
current_x–;
maze[current_z][current_x][current_y] = 1;
spawn_mobile(current_z, current_x, current_y, mob_level, repop_vnum, elite);
// here we go with a chance to make an extra direction (helps space-out the map)
if(current_x-1 == -1) break; // not failed because we did increment.
if(number_range(0,5) == number_range(0,5)) {
if(maze[current_z][current_x-1][current_y] == 0) {
current_x–;
count++; // so we keep our counts properly.
maze[current_z][current_x][current_y] = 1;
}
}
} else { failed = true; }
break;
case DIR_EAST:
// cannot go any-further north!
if(current_y+1 == 250){
failed = true;
break;
}
if(maze[current_z][current_x][current_y+1] == 0) {
current_y++;
maze[current_z][current_x][current_y] = 1;
spawn_mobile(current_z, current_x, current_y, mob_level, repop_vnum, elite);
// here we go with a chance to make an extra direction (helps space-out the map)
if(current_y+1 == 250) break; // not failed because we did increment.
if(number_range(0,5) == number_range(0,5)) {
if(maze[current_z][current_x][current_y+1] == 0) {
current_y++;
count++; // so we keep our counts properly.
maze[current_z][current_x][current_y] = 1;
}
}
} else { failed = true; }
break;
case DIR_WEST:
// cannot go any-further north!
if(current_y-1 == -1){
failed = true;
break;
}
if(maze[current_z][current_x][current_y-1] == 0) {
current_y++;
maze[current_z][current_x][current_y] = 1;
spawn_mobile(current_z, current_x, current_y, mob_level, repop_vnum, elite);
// here we go with a chance to make an extra direction (helps space-out the map)
if(current_y-1 == 250) break; // not failed because we did increment.
if(number_range(0,5) == number_range(0,5)) {
if(maze[current_z][current_x][current_y-1] == 0) {
current_y–;
count++; // so we keep our counts properly.
maze[current_z][current_x][current_y] = 1;
}
}
} else { failed = true; }
break;
case DIR_UP:
// cannot go any-further north!
if(current_z+1 == 30){
failed = true;
break;
}
// up/down don't care if the value is 0, it creates a up/down link anyways!
// helps create a random-link.
current_z++;
spawn_mobile(current_z, current_x, current_y, mob_level, repop_vnum, elite);
maze[current_z][current_x][current_y] = 2; // 2 means it links up!
// here we go with a chance to make an extra direction (helps space-out the map)
if(current_z+1 == 30) break; // not failed because we did increment.
if(number_range(0,5) == number_range(0,5)) {
current_z++;
count++; // so we keep our counts properly.
maze[current_z][current_x][current_y] = 2;
}
break;
case DIR_DOWN:
// cannot go any-further north!
if(current_z-1 == -1){
failed = true;
break;
}
// up/down don't care if the value is 0, it creates a up/down link anyways!
// helps create a random-link.
current_z–;
spawn_mobile(current_z, current_x, current_y, mob_level, repop_vnum, elite);
maze[current_z][current_x][current_y] = 2; // 2 means it links up or down (or both)
// here we go with a chance to make an extra direction (helps space-out the map)
if(current_z+1 == 30) break; // not failed because we did increment.
if(number_range(0,5) == number_range(0,5)) {
current_z–;
count++; // so we keep our counts properly.
maze[current_z][current_x][current_y] = 2;
}
break;
}
if(!failed)
count++;
else
attempt++; // saves us from infinate loop!
}
actual_size = count;
maze_list.push_back(this);
}
};
////////////////////////////////////////////////////////////////////////////////////////
// display some minor information about the maze in question.
COMMAND(do_maze) {
if(ch->in_maze == NULL) {
ch->Sendf("But your not in a maze!\n\r");
return;
}
maze_data *maze = ch->in_maze;
if(NullString(argument)) {
ch->Sendf("Syntax: maze <start|summon|quit|info>\n\r");
return;
}
if(!str_cmp(argument, "summon")) {
if(maze->started()) {
ch->Sendf("You cannot summon once the maze has started!\n\r");
return;
}
// pull the groupies to the maze from the summoning stone.
FOREACH(Lexi::List<CHAR_DATA *ch>, player_list, player_iter) {
CHAR_DATA *groupie = (*player_iter);
if(is_same_group(ch, groupie) && groupie->x == maze->summon_x && groupie->y == maze->summon_y) {
if(groupie->recent_maze != 0) continue;
char_from_room(groupie);
char_to_room(get_room_index(4), ch);
groupie->cord[CORD_X] = ch->cord[CORD_X];
groupie->cord[CORD_Y] = ch->cord[CORD_Y];
groupie->cord[CORD_Z] = ch->cord[CORD_Z];
groupie->in_maze = ch->in_maze;
do_look(groupie, "auto");
in_maze->get_players()++; // increment the players (crazy technique here)
}
}
}
if(!str_cmp(argument, "start")) {
if(maze->started()) {
ch->Sendf("The maze has already been started! Hurry up!\n\r");
return;
}
maze->set_start();
do_function(ch, &do_gtell, "Maze started up! Prepare yourselves %s!", ch->rebel ? "Comrades" : "my good chums");
return;
}
// just know alittle about your dungeon of ultimate doom!
if(!str_cmp(argument, "info")) {
ch->Sendf("\n\r+———————[ %s%s ]———————+\n\r", maze->get_broken ? "[Broken] " : "", maze->get_name());
ch->Sendf(" [ %s ] [Level: %d]", maze->get_elite() ? "Elite" : "Normal", maze->get_level());
ch->Sendf(" [Bosses Left: %d]", maze->get_bosses());
ch->Sendf(" [Monsters Left: %d]", maze->get_monsters());
ch->Sendf(" [Puzzles Left: %d]", maze->get_puzzles());
return;
}
if(!str_cmp(argument, "quit")) {
do_function(ch, &do_gtell, "Sorry %s, but I have to bail! %s.", ch->rebel ? "my friends" : "guys", ch->rebel ? "Cheers" : "Good-bye");
// is it really that simple? Yes, because we aren't modifying the x/y locations, it checks to see if your in_maze, if so.
// it reads and does everything differently! This will restore you back to the worldmap. where you entered (summoning stone)
char_from_room(ch);
char_to_room(get_room_index(3), ch); // wilderness!
// send them back to the summon stone!
ch->x = in_maze->get_summon_x();
ch->y = in_maze->get_summon_y();
ch->in_maze = NULL;
ch->recent_maze = 35; // 35 ticks until you can enter a new one
// you cannot be summoned in unless you have 0
return;
}
ch->Sendf("What option is that!\n\r");
return;
}
////////////////////////////////////////////////////////////////////////////////////////
// Just display what mazes are open. Since they are linked from the world-map
// and are instanced *PER* group, we should see plenty of these open.
COMMAND(cmd_mazelist) {
BUFFER *output;
int count = 0;
output = new_buf();
BufPrintf(output, "Mazes currently in-use!\n\r");
FOREACH(Lexi::List<maze_data *>, maze_list, maze_iter) {
maze_data *maze;
BufPrintf(output, "| %3d: | Start: z%5d x%5d y%5d | Max size: %5d | Actual Size: %5d | Broken: %5s|\n\r", count, maze->get_start_z(), maze->get_start_x(), maze->get_start_y(), maze->get_max(), maze->get_broken() ? "Yes" : "No");
count++;
}
BufPrintf(output, "There are currently %d mazes in-use!\n\r", count);
page_to_char(buf_string(output), ch);
free_buf(output);
return;
}
Anyone done this before and/or know of some resources that might be useful?