/*
* Change.c (last update 3rd may, 2001)
*
* Allows adding and removing of changes while online,
* also handles displaying the changes to the player.
*
* Would be a good thing to add to a players login,
* but keep the MAX_CHANGE low in that case, so the player
* doesn't get spammed to much.
*
* Code by Brian Graversen aka Jobo
*/
/*
* Note, the code uses memory recycling, even though it's
* probably a waste of time, since most muds won't add that
* many changes in between each copyover. But I figured why
* not make it right the first time around.
*/
#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "merc.h"
#define MAX_CHANGE 15
CHANGE_DATA *change_list = NULL;
CHANGE_DATA *change_last = NULL;
CHANGE_DATA *change_free = NULL;
bool remove_change args((int i));
/*
* load_changes simply loads the list of changes,
* should only be called at boot time. Add this
* call to db.c's boot function.
*/
void load_changes()
{
CHANGE_DATA *change;
FILE *fp;
char *name;
if ((fp = fopen("../txt/changes.txt", "r")) == NULL)
{
log_string("Non-fatal error: changes.txt not found!");
return;
}
name = fread_word(fp);
while (str_cmp(name, END_MARKER))
{
change = alloc_perm(sizeof(CHANGE_DATA));
change->imm = str_dup(name);
change->date = fread_string(fp);
change->text = fread_string(fp);
if (change_list)
change_list->prev = change;
change->next = change_list;
change_list = change;
if (!change_last) change_last = change;
name = fread_word(fp);
}
fclose(fp);
}
/*
* save_changes handles the storage of the change_list into
* a file. It is called each time the list is changed.
*/
void save_changes()
{
FILE *fp;
CHANGE_DATA *change;
int i = 0;
if ((fp = fopen("../txt/changes.txt","w")) == NULL)
{
log_string("Error writing to changes.txt");
return;
}
for (change = change_last; change; change = change->prev)
{
if (++i > MAX_CHANGE) break;
fprintf(fp, "%s\n", change->imm);
fprintf(fp, "%s~\n", change->date);
fprintf(fp, "%s~\n", change->text);
}
fprintf(fp, "%s\n", END_MARKER);
fclose(fp);
}
/*
* This is the immortal function, which allows any
* immortal with access to the function to add new
* changes to the changes list. The immortals name
* will also be added to the list, as well as the
* date the change was added.
*/
void do_addchange( CHAR_DATA *ch, char *argument )
{
CHANGE_DATA *change;
CHANGE_DATA *cchange;
char *strtime;
char buf[50];
int i;
if (IS_NPC(ch)) return;
/* we need something to add to the list */
if (argument[0] == '\0' || strlen(argument) < 5)
{
send_to_char("What did you change?\n\r", ch);
return;
}
/* Mainly to avoid that the list looks ugly */
if (strlen(argument) > 120)
{
send_to_char("Keep it down to 120 chars please.\n\r", ch);
return;
}
/* Set the current time */
strtime = ctime(¤t_time);
for (i = 0; i < 6; i++)
{
buf[i] = strtime[i + 4];
}
buf[6] = '\0';
/* If we have a free change, we reuse it */
if (change_free)
{
change = change_free;
change_free = change_free->next;
change->next = NULL;
if (change_free) change_free->prev = NULL;
}
else
change = alloc_perm(sizeof(*change));
/* set the strings for the change */
change->imm = str_dup(ch->name);
change->text = str_dup(argument);
change->date = str_dup(buf);
/* If theres already a change, just add to the list */
if (change_last)
{
change_last->next = change;
change->prev = change_last;
change->next = NULL;
change_last = change;
}
else // there are no changes.
{
change->next = change_list;
change_list = change;
change_last = change;
}
/* Removing the oldest change if the list has gone beyond the max */
cchange = change_list; i = 0;
while ((cchange = cchange->next) != NULL) i++;
if (i >= MAX_CHANGE)
remove_change(1);
send_to_char("Change added.\n\r", ch );
save_changes();
return;
}
/*
* The player function.
* simply lists the last MAX_CHANGE changes
*/
void do_changes(CHAR_DATA *ch, char *argument)
{
CHANGE_DATA *change;
char buf[MAX_STRING_LENGTH];
char tempbuf[MAX_STRING_LENGTH];
bool found = FALSE;
int i = 0;
if (IS_NPC(ch)) return;
sprintf(buf, " #R[#0***#R] #yMinor Code Changes and Quick Messages #R[#0***#R]#n\n\r\n\r");
for (change = change_list; change; change = change->next)
{
found = TRUE;
++i;
sprintf(tempbuf, " #R[#0%3d#R] #G%-6s #L%-9s #C%s#n\n\r",
i, change->date, change->imm, change->text);
strcat(buf, tempbuf);
}
if (found) send_to_char(buf, ch);
else send_to_char("No changes.\n\r", ch);
return;
}
/*
* delchange removes a given change, and adds the
* change to a free_list so it can be recycled later
*/
void do_delchange(CHAR_DATA *ch, char *argument)
{
char arg[MAX_INPUT_LENGTH];
bool found = FALSE;
int i;
if (IS_NPC(ch)) return;
one_argument(argument, arg);
if ((i = atoi(arg)) < 1)
{
send_to_char("Which number change did you want to remove ?\n\r", ch);
return;
}
found = remove_change(i);
if (!found) send_to_char("No such change.\n\r", ch);
else send_to_char("Change removed.\n\r", ch);
save_changes();
return;
}
/*
* This function handles the actual removing of the change
*/
bool remove_change(int i)
{
CHANGE_DATA *change;
bool found = FALSE;
for (change = change_list; change; change = change->next)
{
if (--i > 0) continue;
found = TRUE;
/* clearing out the strings */
free_string(change->imm);
free_string(change->text);
free_string(change->date);
/* update the pointer to the last change if needed */
if (change == change_last) change_last = change->prev;
/* handle the special case of the first change */
if (change == change_list)
{
change_list = change->next;
if (change->next) change->next->prev = NULL;
}
else
{
change->prev->next = change->next;
if (change->next)
change->next->prev = change->prev;
}
/* Handle the free list */
change->next = change_free;
change->prev = NULL;
if (change_free) change_free->prev = change;
change_free = change;
/* terminate the loop */
break;
}
/* did we remove anything ? */
return found;
}