/*
* Rooms.c
*/
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <memory.h>
#include <string.h>
#include "config.h"
#include "player.h"
#include "fix.h"
#include "dynamic.h"
/* Our Extern Functions */
extern void dynamic_free(dfile *df,int key);
extern dfile *dynamic_init(char *file,int granularity);
extern int dynamic_load(dfile *df,int key,char *data);
extern int dynamic_save(dfile *df,char *data,int l,int key);
extern char *end_string(char *str);
extern saved_player *find_saved_player(char *name);
extern char *get_int(int *dest, char *source);
extern char *get_string(char *dest, char *source);
extern file load_file(char *filename);
extern int load_player(player * p);
extern void log(char *file, char *string);
extern int restore_player(player * p, char *name);
extern void save_player(player * p);
extern char *store_int(char *dest, int source);
extern char *store_string(char *dest, char *source);
extern void init_your_rooms(void);
/* Local Function Prototypes */
void delete_room(player * p, char *str);
/* Local Variables */
dfile *room_df;
void delete_room(player * p, char *str)
{
char *oldstack;
room *scan, **previous, *r;
oldstack = stack;
#ifdef ROOM_TRACK
printf("delete_room(%s, %s)\n", p->lower_name, str);
#endif
if (!current_room)
{
return;
}
if (!strcmp("system", current_room->owner->lower_name) &&
!strcmp("void", current_room->id))
return;
r = current_room;
while (r->players_top)
{}
previous = &(r->owner->rooms);
scan = *previous;
for (; scan && scan != r; scan = scan->next)
previous = &(scan->next);
if (scan)
{
*previous = scan->next;
if (scan->text.where)
FREE(scan->text.where);
if (scan->exits.where)
FREE(scan->exits.where);
if (scan->automessage.where)
FREE(scan->automessage.where);
dynamic_free(room_df,scan->data_key);
FREE(scan);
} else
*previous = 0;
stack = oldstack;
}
/* creates a new standard room */
room *create_room(player * p)
{
room *r, *scan;
saved_player *sp;
int number, home = 1, unique = 1;
char id[MAX_ID];
#ifdef ROOM_TRACK
printf("create_room(%s)\n", p->lower_name);
#endif
sp = p->saved;
if (!sp)
{
return 0;
}
sprintf(id, "room.%d", unique);
do
{
for (scan = sp->rooms, number = 1; scan; number++, scan = scan->next)
{
if (!strcmp(scan->id, id))
{
unique++;
sprintf(id, "room.%d", unique);
break;
}
if (scan->flags & HOME_ROOM)
home = 0;
}
} while (scan);
if (number > p->max_rooms)
return 0;
r = (room *) MALLOC(sizeof(room));
memset(r, 0, sizeof(room));
strcpy(r->id, id);
sprintf(r->name, "in somewhere belonging to %s.", p->name);
sprintf(r->enter_msg, "goes to a room belonging to %s.", p->name);
r->flags = (home * HOME_ROOM)|ROOM_UPDATED;
sprintf(stack, "\n A bare room, belonging to %s.\n"
" Isn't it time to write a description ?\n", p->name);
number = strlen(stack) + 1;
r->text.where = (char *) MALLOC(number);
memcpy(r->text.where, stack, number);
r->text.length = number;
r->exits.length = 0;
r->exits.where = 0;
r->auto_base = 30;
r->automessage.length = 0;
r->automessage.where = 0;
r->owner = sp;
r->players_top = 0;
r->next = sp->rooms;
sp->rooms = r;
r->flags |= ROOM_UPDATED;
return r;
}
/* change decompress room to get from disk */
int decompress_room(room *r)
{
int length;
char *oldstack,*tmp;
#ifdef ROOM_TRACK
printf("decompress_room(%s)\n", r->id);
#endif
oldstack=stack;
if (!(r->flags&COMPRESSED)) return 1;
length=dynamic_load(room_df,r->data_key,stack);
if (length<=0) {
current_room=r;
delete_room(current_player,0);
return 0;
}
tmp=stack;
stack+=length;
tmp=get_string(stack,tmp);
length=strlen(stack)+1;
r->text.length=length;
if (r->text.where) FREE(r->text.where);
r->text.where=(char *)MALLOC(length);
strcpy(r->text.where,stack);
tmp=get_string(stack,tmp);
length=strlen(stack)+1;
if (length==1) {
r->exits.length=0;
r->exits.where=0;
}
else {
r->exits.length=length;
if (r->exits.where) FREE(r->exits.where);
r->exits.where=(char *)MALLOC(length);
strcpy(r->exits.where,stack);
}
tmp=get_string(stack,tmp);
length=strlen(stack)+1;
if (length==1) {
r->automessage.length=0;
r->automessage.where=0;
}
else {
r->automessage.length=length;
if (r->automessage.where) FREE(r->automessage.where);
r->automessage.where=(char *)MALLOC(length);
strcpy(r->automessage.where,stack);
}
r->flags &= ~(COMPRESSED|ROOM_UPDATED);
stack=oldstack;
return 1;
}
/* and the compress room chugs to the disk */
void compress_room(room *r)
{
int length;
char *oldstack;
oldstack=stack;
#ifdef ROOM_TRACK
printf("compress_room(%s)\n", r->id);
#endif
if (r->flags&COMPRESSED) return;
if (r->owner && r->owner->residency==STANDARD_ROOMS) return;
/* printf("compress key = %d, id = %s\n",r->data_key,r->id); */
if (r->flags&ROOM_UPDATED) {
if (r->text.where) stack=store_string(stack,r->text.where);
else stack=store_string(stack,"");
if (r->exits.where) stack=store_string(stack,r->exits.where);
else stack=store_string(stack,"");
if (r->automessage.where) stack=store_string(stack,r->automessage.where);
else stack=store_string(stack,"");
length=(int)stack-(int)oldstack;
r->data_key=dynamic_save(room_df,oldstack,length,r->data_key);
}
if (r->text.where) FREE(r->text.where);
r->text.where=0;
r->text.length=0;
if (r->exits.where) FREE(r->exits.where);
r->exits.where=0;
r->exits.length=0;
if (r->automessage.where) FREE(r->automessage.where);
r->automessage.where=0;
r->automessage.length=0;
r->flags |= COMPRESSED;
r->flags &= ~ROOM_UPDATED;
stack=oldstack;
}
/* destroy all the room data */
void free_room_data(saved_player *sp)
{
room *room_list,*next;
#ifdef ROOM_TRACK
printf("free_room_data(%s)\n", sp->lower_name);
#endif
if (!sp->rooms) return;
room_list=sp->rooms;
while(room_list) {
next=room_list->next;
if (room_list->text.where) FREE(room_list->text.where);
if (room_list->exits.where) FREE(room_list->exits.where);
if (room_list->automessage.where) FREE(room_list->automessage.where);
dynamic_free(room_df,room_list->data_key);
FREE(room_list);
room_list=next;
}
sp->rooms=0;
}
/* collect all the room data ready for saving */
void construct_room_save(saved_player *sp)
{
room *room_list;
char *tmpstack;
int length;
#ifdef ROOM_TRACK
printf("construct_room_save(%s)\n", sp->lower_name);
#endif
for(room_list=sp->rooms;room_list;room_list=room_list->next) {
if (!room_list->players_top || (sys_flags&(SHUTDOWN|PANIC)))
compress_room(room_list);
tmpstack=stack;
stack+=4;
stack=store_string(stack,room_list->name);
stack=store_string(stack,room_list->id);
stack=store_string(stack,room_list->enter_msg);
stack=store_int(stack,room_list->auto_base);
stack=store_int(stack,room_list->flags);
stack=store_int(stack,room_list->data_key);
length=(int)stack-(int)tmpstack;
(void) store_int(tmpstack,length);
}
stack=store_int(stack,0);
}
/* retrieve room data from a save file */
char *retrieve_room_data(saved_player *sp,char *where)
{
int length;
room *r,**last;
#ifdef ROOM_TRACK
printf("retrieve_room_data(%s, %s)\n", sp->lower_name, where);
#endif
free_room_data(sp);
last=&sp->rooms;
where=get_int(&length,where);
for(;length;where=get_int(&length,where))
{
r=(room *)MALLOC(sizeof(room));
memset(r,0,sizeof(room));
where=get_string(r->name,where);
where=get_string(r->id,where);
where=get_string(r->enter_msg,where);
where=get_int(&r->auto_base,where);
where=get_int(&r->flags,where);
where=get_int(&r->data_key,where);
r->flags|=COMPRESSED;
*last=r;
last=&r->next;
r->owner=sp;
r->players_top=0;
r->next=0;
}
*last=0;
return where;
}
/* convert a room string into an actual room */
room *convert_room_verbose(player *p,char *str,int verbose)
{
char *scan,*oldstack;
saved_player *sp;
room *r;
#ifdef ROOM_TRACK
printf("convert_room_verbose(%s, %s, v:%d)\n",
p->lower_name, str, verbose);
#endif
oldstack=stack;
scan=str;
while(*scan && *scan!='.')
*stack++=*scan++;
if (!*scan)
{
stack=oldstack;
return 0;
}
*stack++=0;
scan++;
if (!*oldstack)
strcpy(oldstack,p->name);
lower_case(oldstack);
sp=find_saved_player(oldstack);
if (!sp)
{
stack=oldstack;
return 0;
}
strcpy(oldstack,scan);
lower_case(oldstack);
stack=end_string(oldstack);
r=sp->rooms;
while(r)
{
strcpy(stack,r->id);
lower_case(stack);
if (!strcmp(stack,oldstack))
{
stack=oldstack;
current_room=r;
if (!decompress_room(r))
return 0;
return r;
}
if (!sp)
{
stack=oldstack;
return 0;
}
strcpy(oldstack,scan);
lower_case(oldstack);
stack=end_string(oldstack);
r=sp->rooms;
while(r)
{
strcpy(stack,r->id);
lower_case(stack);
if (!strcmp(stack,oldstack))
{
stack=oldstack;
current_room=r;
if (!decompress_room(r))
return 0;
return r;
}
r=r->next;
}
stack=oldstack;
return 0;
}
return r;
}
room *convert_room(player *p, char *str)
{
return convert_room_verbose(p, str, 1);
}
/* load in the standard rooms and initialise */
char *get_line(file * f)
{
char *start;
#ifdef ROOM_TRACK
printf("get_line(%s)\n", f->where);
#endif
while (*(f->where) == '#')
{
while ((f->length > 0) && *(f->where) != '\n')
{
f->where++;
f->length--;
}
if (f->length == 0)
return 0;
f->where++;
f->length--;
}
start = f->where;
while (*(f->where) && *(f->where) != '\n' && *(f->where) != '\r')
{
f->where++;
f->length--;
}
if (*(f->where))
{
*(f->where)++ = 0;
f->length--;
}
if (*(f->where) == '\r' || *(f->where) == '\n')
{
*(f->where)++ = 0;
f->length--;
}
return start;
}
void init_room(char *name, file rf)
{
char *line, *oldstack, *file_start;
saved_player *sp;
room *r;
player np;
#ifdef ROOM_TRACK
printf("init_room(%s, %s)\n", name, rf.where);
#endif
oldstack = stack;
/* if (!malloc_verify()) printf("wrong HERE 1\n"); */
file_start = rf.where;
sp = find_saved_player(name);
if (!sp)
{
memset(&np, 0, sizeof(player));
np.fd = 0;
np.location = (room *) - 1;
restore_player(&np, name);
np.residency = SYSTEM_ROOM;
np.saved_residency = SYSTEM_ROOM;
np.email[0] = -1;
np.password[0] = -1;
np.max_exits=30;
np.max_rooms=30;
np.max_autos=30;
np.max_list=1;
save_player(&np);
sp = find_saved_player(name);
sp->list_top = 0;
}
sp->residency=SYSTEM_ROOM;
sp->rooms = 0;
/* if (!malloc_verify()) printf("wrong HERE 2\n"); */
while (rf.length > 0)
{
line = get_line(&rf);
if (rf.length <= 0 || !(*line))
break;
r = (room *) MALLOC(sizeof(room));
memset(r, 0, sizeof(room));
r->owner = sp;
r->players_top = 0;
r->next = sp->rooms;
sp->rooms = r;
strncpy(r->id, line, MAX_ID - 2);
line = get_line(&rf);
strncpy(r->name, line, MAX_ROOM_NAME - 2);
line = get_line(&rf);
strncpy(r->enter_msg, line, MAX_ENTER_MSG - 2);
r->flags = OPEN | ROOM_UPDATED;
while (*(rf.where) != '#')
if (*(rf.where) != '\r')
{
*stack++ = *rf.where++;
rf.length--;
} else
{
rf.where++;
rf.length--;
}
*stack++ = 0;
r->text.length = strlen(oldstack) + 1;
r->text.where = (char *) MALLOC(r->text.length);
strcpy(r->text.where, oldstack);
stack = oldstack;
line = get_line(&rf);
while (strcasecmp(line, "end"))
{
while (*line)
*stack++ = *line++;
*stack++ = '\n';
line = get_line(&rf);
}
*stack++ = 0;
r->exits.length = strlen(oldstack) + 1;
if (r->exits.length == 1)
{
r->exits.where = 0;
r->exits.length = 0;
} else
{
r->exits.where = (char *) MALLOC(r->exits.length);
strcpy(r->exits.where, oldstack);
}
stack = oldstack;
line = get_line(&rf);
while (strcasecmp(line, "end"))
{
while (*line)
*stack++ = *line++;
*stack++ = '\n';
line = get_line(&rf);
}
*stack++ = 0;
r->automessage.length = strlen(oldstack) + 1;
if (r->automessage.length == 1)
{
r->automessage.where = 0;
r->automessage.length = 0;
} else
{
r->automessage.where = (char *) MALLOC(r->automessage.length);
strcpy(r->automessage.where, oldstack);
r->flags |= AUTO_MESSAGE;
}
stack = oldstack;
}
/* if (!malloc_verify()) printf("wrong HERE 3\n"); */
FREE(file_start);
stack = oldstack;
}
void init_rooms(void)
{
room_df=dynamic_init("rooms", 256);
init_your_rooms();
}