/* * Original code by Xkilla * Ported to SWR by Atrox * Cleaned up and modified further by Greven and Gavin of Dark Warriors */ #include <sys/types.h> #include <sys/time.h> #include <ctype.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <unistd.h> #include <stdarg.h> #include "mud.h" #include "changes.h" /* * Globals */ char * current_date args( ( void ) ); int num_changes args( ( void ) ); /* * Local Functions */ int maxChanges; int immortal_changes; #define VERSION 0 #define NULLSTR( str ) ( str == NULL || str[0] == '\0' ) CHANGE_DATA * changes_table; /* Hacktastic to make sure warning doesn't show up.. thats what man pages says todo :D */ size_t my_strftime(char *s, size_t max, const char *fmt, const struct tm *tm) { return strftime(s, max, fmt, tm); } void load_changes(void) { FILE *fp; int i; if ( !(fp = fopen( CHANGES_FILE, "r")) ) { bug( "Could not open Changes File for reading."); return; } immortal_changes = 0; fscanf( fp, "%d\n", &maxChanges ); changes_table = (CHANGE_DATA*)calloc(1, sizeof( CHANGE_DATA) * (maxChanges+1) ); for( i = 0; i < maxChanges; i++ ) { changes_table[i].change = fread_string( fp ); changes_table[i].coder = fread_string( fp ); changes_table[i].date = fread_string( fp ); changes_table[i].mudtime = fread_number( fp ); // Add imm variables to each data so we know if it should only show up for imms changes_table[i].immchange = fread_number( fp ); if ( changes_table[i].immchange == 1) immortal_changes++; } fclose(fp); log_string(" Done changes " ); return; } char * current_date( ) { static char buf [ 128 ]; struct tm * datetime; datetime = localtime( ¤t_time ); my_strftime( buf, 128, "%x", datetime ); return buf; } void save_changes(void) { FILE *fp; int i; if ( !(fp = fopen( CHANGES_FILE,"w")) ) { perror( CHANGES_FILE ); return; } fprintf( fp, "%d\n", maxChanges ); for( i = 0; i < maxChanges; i++ ) { fprintf (fp, "%s~\n", changes_table[i].change); fprintf (fp, "%s~\n", changes_table[i].coder); fprintf (fp, "%s~\n", changes_table[i].date); fprintf (fp, "%ld\n", changes_table[i].mudtime ); fprintf (fp, "%d\n", changes_table[i].immchange ); fprintf( fp, "\n" ); } fclose(fp); return; } void delete_change(int iChange) { int i,j; CHANGE_DATA * new_table; new_table = (CHANGE_DATA*)calloc(1, sizeof( CHANGE_DATA ) * maxChanges ); if( !new_table ) { return; } for ( i= 0, j = 0; i < maxChanges+1; i++) { if( i != iChange ) { new_table[j] = changes_table[i]; j++; } else { if ( changes_table[i].change ) STRFREE(changes_table[i].change); if ( changes_table[i].coder ) STRFREE(changes_table[i].coder); if ( changes_table[i].date ) STRFREE(changes_table[i].date); } } free( changes_table ); changes_table = new_table; maxChanges--; return; } void do_addchange(CHAR_DATA *ch, char *argument ) { CHANGE_DATA * new_table; char buf[MAX_STRING_LENGTH]; if ( IS_NPC( ch ) ) return; if ( argument[0] == '\0' ) { send_to_char( "Syntax: addchange <change>\n\r", ch); send_to_char( "Type 'changes' to view the list.\n\r", ch); return; } maxChanges++; new_table = (CHANGE_DATA*)realloc( changes_table, sizeof( CHANGE_DATA ) *(maxChanges+1) ); if (!new_table) /* realloc failed */ { send_to_char ("Memory allocation failed. Brace for impact.\n\r",ch); return; } changes_table = new_table; changes_table[maxChanges-1].change = STRALLOC( argument ); changes_table[maxChanges-1].coder = STRALLOC( ch->name ); changes_table[maxChanges-1].date = STRALLOC(current_date()); changes_table[maxChanges-1].mudtime = current_time; //Auto set it to Normal Change changes_table[maxChanges-1].immchange = FALSE; //send_to_char("Changes Created.\n\r",ch); //send_to_char("Type 'changes' to see the changes.\n\r",ch); //snprintf (buf, MAX_STRING_LENGTH, "%s", "A new change has been added, type 'CHANGES' to see it." ); sprintf (buf, "&c%s &whas added a new change, type '&Ychanges&w' to see what it was",ch->name); echo_to_all( AT_IMMORT, buf, ECHOTAR_ALL ); save_changes(); return; } /* * Added by greven for imm changes * */ void do_addimmchange(CHAR_DATA *ch, char *argument ) { CHANGE_DATA * new_table; char buf[MAX_STRING_LENGTH]; if ( IS_NPC( ch ) ) return; if ( argument[0] == '\0' ) { send_to_char( "Syntax: addimmchange <change>\n\r", ch ); send_to_char( "Type 'changes' to view the list.\n\r", ch ); return; } maxChanges++; new_table = (CHANGE_DATA*)realloc( changes_table, sizeof( CHANGE_DATA ) *(maxChanges+1) ); if (!new_table) /* realloc failed */ { send_to_char ("Memory allocation failed. Brace for impact.\n\r",ch); return; } changes_table = new_table; changes_table[maxChanges-1].change = STRALLOC( argument ); changes_table[maxChanges-1].coder = STRALLOC( ch->name ); changes_table[maxChanges-1].date = STRALLOC(current_date()); changes_table[maxChanges-1].mudtime = current_time; // Autoset to imm change, do NOT echo it to the mud changes_table[maxChanges-1].immchange = TRUE; immortal_changes++; //send_to_char("Changes Created.\n\r",ch); //send_to_char("Type 'changes' to see the changes.\n\r",ch); //sprintf( buf, "A new change has been added, type 'CHANGES' to see it." ); sprintf (buf, "&c%s &whas added a new change, type '&Ychanges&w' to see what it was",ch->name); echo_to_all( AT_IMMORT, buf, ECHOTAR_IMM ); save_changes(); return; } void do_chedit( CHAR_DATA *ch, char *argument ) { char arg1[MAX_INPUT_LENGTH]; char arg2[MAX_INPUT_LENGTH]; argument = one_argument( argument, arg1 ); argument = one_argument( argument, arg2 ); if ( IS_NPC(ch) ) return; if (!ch->desc || NULLSTR(arg1) ) { ch_printf( ch, "Syntax: chedit load/save\n\r" ); ch_printf( ch, "Syntax: chedit delete (change number)\n\r" ); ch_printf( ch, "Syntax: chedit immchange (change number)\n\r" ); return; } if ( !str_cmp(arg1,"load") ) { load_changes( ); send_to_char("Changes Loaded.\n\r",ch); return; } if ( !str_cmp(arg1,"save") ) { save_changes( ); send_to_char("Changes Saved.\n\r",ch); return; } if ( !str_cmp(arg1,"immchange") ) { int num; if ( NULLSTR(arg2) || !is_number( arg2 ) ) { send_to_char("&wFor chedit immchange, you must provide a change number.\n\r",ch); send_to_char("Syntax: chedit immchange (change number)\n\r",ch); return; } num = atoi( arg2 ); num--; if ( num < 0 || num > maxChanges ) { ch_printf( ch, "Valid changes are from 1 to %d.\n\r", maxChanges ); return; } if ( changes_table[num].immchange == FALSE) changes_table[num].immchange = TRUE; else changes_table[num].immchange = FALSE; immortal_changes++; save_changes( ); send_to_char("Change flag changed.\n\r",ch); return; } if ( !str_cmp(arg1, "delete")) { int num; if ( NULLSTR(arg2) || !is_number( arg2 ) ) { send_to_char("#wFor chsave delete, you must provide a change number.{x\n\r",ch); send_to_char("Syntax: chsave delete (change number)\n\r",ch); return; } num = atoi( arg2 ); num--; if ( num < 0 || num > maxChanges ) { ch_printf( ch, "Valid changes are from 0 to %d.\n\r", maxChanges ); return; } delete_change( num ); save_changes( ); send_to_char("Change deleted.\n\r",ch); return; } return; } char *line_indent (char *text, int wBegin, int wMax) { static char buf[MAX_STRING_LENGTH]; char *ptr; char *ptr2; int count = 0; bool stop = FALSE; int wEnd = 0; buf[0] = '\0'; ptr = text; ptr2 = buf; while (!stop) { if (count == 0) { if (*ptr == '\0') wEnd = wMax - wBegin; else if (strlen (ptr) < (wMax - wBegin)) wEnd = wMax - wBegin; else { int x = 0; while (*(ptr + (wMax - wBegin - x)) != ' ') x++; wEnd = wMax - wBegin - (x - 1); if (wEnd < 1) wEnd = wMax - wBegin; } } if (count == 0 && *ptr == ' ') ptr++; else if (++count != wEnd) { if ((*ptr2++ = *ptr++) == '\0') stop = TRUE; } else if (*ptr == '\0') { stop = TRUE; *ptr2 = '\0'; } else { int k; count = 0; *ptr2++ = '\n'; *ptr2++ = '\r'; for (k = 0; k < wBegin; k++) *ptr2++ = ' '; } } return buf; } // Modified by greven for immortal stuff, as well as fixing crash if there are less than 10 changes // Further Modifications needed to implement a no-disconnect status for players. - Kalthizar 3.31.09 void do_changes (CHAR_DATA * ch, char *argument) { char arg[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH], buf[MAX_STRING_LENGTH], *test; int i, page = 0, maxpage = 0, today; int display = 0; argument = one_argument (argument, arg); argument = one_argument (argument, arg2); if (IS_NPC (ch)) return; if (maxChanges < 1) return; i = 0; test = current_date (); today = 0; for (i = 0; i < maxChanges; i++) { if (!str_cmp (test, changes_table[i].date)) today++; } if (is_number (arg)) page = atoi (arg); //maxpage = (maxChanges/10)+1; maxpage = (maxChanges + 9) / 10; if (page > 0) { if (page > maxpage) { sprintf (buf, "Show which page 1-%d\n\r", maxpage); send_to_char (buf, ch); return; } page *= 10; } send_to_char ("&wNUMBER &cIMMORTAL &YDATE &wCHANGE &D\n\r", ch); send_to_char ("&w-&z==============================================================================&w-\n\r", ch); if (!str_cmp (arg, "search")) { int dsp = 0; if (arg2[0] == '\0') { send_to_char ("What do you want to search for??.\n\r", ch); return; } for (i = 0; i < maxChanges; i++) { if (!str_infix (arg2, changes_table[i].change) || !str_infix (arg2, changes_table[i].coder)) // if (strstr(changes_table[i].change, arg2)) { sprintf (buf, "&z[&w%4d&z] &c%-13s &Y%11s &c- &w%-52s\n\r", (++dsp), changes_table[i].coder, changes_table[i].date, line_indent (changes_table[i].change, 35, 79)); send_to_char (buf, ch); } } if (dsp == 0) send_to_char ("There is NO match with what you have entered!.", ch); send_to_char ("&w-&z==============================================================================&w-\n\r", ch); return; } for (i = 0; i < maxChanges; i++) { if (page == 0 && changes_table[i].mudtime + (2 * 24L * 3600L) < current_time) continue; display++; if (page > 0 && (page > 0 && (i < (page - 10) || i >= page))) continue; sprintf (buf, "&z[&w%4d&z] &c%-13s &Y%11s &c- &w%-55s\n\r", (i + 1), changes_table[i].coder, changes_table[i].date, line_indent (changes_table[i].change, 35, 79)); send_to_char (buf, ch); } send_to_char ("&w-&z==============================================================================&w-\n\r", ch); if (today > 0) sprintf (buf, "&wThere is a total of [&r%d&w] changes of which [&c%d&w] %s been added today.&D\n\r", maxChanges, today, today > 1 ? "have" : "has"); else sprintf (buf, "&wThere is a total of [&r%d&w] changes.&D", maxChanges); send_to_char (buf, ch); send_to_char ("&w-&z==============================================================================&w-\n\r", ch); sprintf (buf, "&wTo see pages of changes use: 'changes <&c1&w-&r%d&w>'\n\r", (maxChanges + 9) / 10); send_to_char (buf, ch); send_to_char ("&wTo search all changes for a change use: 'changes search <&cword&w>'&D\n\r", ch); send_to_char ("&w-&z==============================================================================&w-\n\r", ch); } int num_changes(void) { char *test; int today; int i; i = 0; test = current_date(); today = 0; for ( i = 0; i < maxChanges; i++) if (!str_cmp(test,changes_table[i].date)) today++; return today; } void nnum_changes (CHAR_DATA *ch) { char buf[MAX_INPUT_LENGTH]; char *test; int today; int i; i = 0; test = current_date (); today = 0; for (i = 0; i < maxChanges; i++) { if (!str_cmp (test, changes_table[i].date)) today++; } if ( today > 0 ) { sprintf( buf, "&CThere have been &R%d&C changes added to the MUD today&B( &G%d&R total&B )&D\n\r&CType &b'&cchanges&b'&Cto view them&D\n\r", today - (IS_IMMORTAL(ch) ? 0 : immortal_changes), maxChanges - (IS_IMMORTAL(ch) ? 0 : immortal_changes) ); send_to_char( buf, ch ); return; } return; }