falko-hartmann.de

Black Knight's Small Cron System für AdminMod v1.1 (09.09.2003)

Beschreibung

Für das Linuxbetriebssystem gab es Bedarf an einem System, dass zu einem bestimmten Zeitpunkt einen Befehl ausführen konnte. Aus diesem Grunde wurde das Cron System entwickelt. Hauptziel war es, sich wiederholende Aufgaben zu bestimmten Zeiten auszuführen, ohne dass sich ein User am Rechner sitzt. Das Konzept, dass entwickelt wurde ist sehr flexibel und einfach. Man muss sich jedoch mit der Syntax auseinandersetzen und diese verstehen. Das mag im ersten Moment nicht einfach erscheinen, man kann aber mit wenigen Zeilen komplexe Abläufe und Aufgaben generieren. Jeder Scheduler muss sich mit diesem System messen lassen.

Ein Cronsystem ist also in der Lage verschiedene vorprogrammierte Aufgaben zu unterschiedlichen Zeiten auszuführen. Aus diesem Grund liegt es nahe dieses System, wenngleich abgespeckt, auch auf AdminMod zu übertragen.

Features:

Einschränkungen:

Verwendungsbeispiele:


Download

plugin_bk_cron


Installation

  1. Stellt sicher, dass AdminMod 2.50.56 oder neuer installiert ist.
  2. plugin_bk_cron.sma und cron_language(de).inc in "myscripts" kopieren und die plugin_bk_cron.sma mit Texteditor öffnen.
  3. Sucht die Zeile
    #include "cron_language(us)"
    und ändert sie in
    #include "cron_language(de)"
    So werden die Logmeldungen auf deutsch ausgegeben. (Ich nehme gerne auch Include-Dateien in anderen Sprachen auf.)
  4. Jetzt noch compilieren (Daran denken, dass Ihr für das Compilieren die aktuelle AdminMod-Distribution auf Eurem Rechner benötigt!)
  5. plugin_bk_cron.amx aus "mybinaries" in den Serverordner "addons/adminmod/scripts" installieren.
  6. Leere schedule.ini im Ordner "addons/adminmod/config/cron" erstellen.
  7. "exec addons/adminmod/config/cron/tasks.cfg" in die server.cfg übernehmen (ganz ans Ende, hier werden CVars über den Mapchange gespeichert). Bei gleichzeitiger Verwendung des CW Creators gehört der Eintrag vor den Verweis auf die war.cfg. Und alle admin_command Zeilen müssen HINTER dem Eintrag stehen.
  8. Wenn hinter der exec-Zeile kein admin_command-Befehl kommt, bitte einen einsetzen, sonst läuft plugin_bk_cron nicht, wenn keiner auf dem Server ist. Man könnte eintragen: admin_command admin_say Mapstart. Das löst den Start von AdminMod aus.
  9. schedule.ini bearbeiten. Möglichst per Consolenbefehle (s.u.).
  10. Optional das Setzen der mp_timeleft aktivieren durch admin_cron_timeleft 1
  11. Mapchange

Konfiguration

Das Trennzeichen ist das Leerzeichen (doppelte Leerzeichen, Tabulatoren, etc. im Zeitbereich führen zu Fehlern, sind aber im Commandbereich zugelassen)

Musterbeispiel:

* * * * * 1 mp_timelimit 20 delete
  1. Spalte: Minuten (0-59,*)
  2. Spalte: Stunden (0-23,*)
  3. Spalte: Tage (1-31,*)
  4. Spalte: Monate (1-12,*)
  5. Spalte: Wochentag (1-7,*) 1=Montag
  6. Spalte: Cvar (nein/ja) (0,1)
  7. Spalte: Der auszuführende Befehl

Besonderheit ist die Spalte 6. Hier muss man angeben, ob es sich um eine CVar handelt. Wenn ja (1) wird dieser Befehl zusätzlich in der tasks.cfg gespeichert und so beim Mapchange wieder übernommen.

Will man dies wieder löschen, so muss man in einem anderen Task den gleichen Befehl angeben und ein "delete" anfügen.

Beispiel:

0 12 * * * 1 mp_timelimit 20 
0 0 * * * 1 mp_timelimit 30 delete

Im ersten Task wird jeden Tag (unabhängig von Monat und Wochentag) Punkt 12 Uhr das Timelimit auf 20 Minuten gesetzt. Dies bleibt über alle Mapchanges erhalten, egal was in der server.cfg steht.

Der zweite Task löscht um 0 Uhr jeden Tages diesen Eintrag aus der tasks.cfg und setzt den Wert auf 30 Minuten. Dieser Wert gilt bis zum Mapchange, anschließend gilt hier der Wert aus der server.cfg, soweit definiert.

Ein Task zu verschiedenen Zeitpunkten

Ich möchte den gleichen Task zu verschiedenen Zeitpunkten ausführen. Dafür stehen mir zwei Möglichkeiten offen. Beispiele, falls ein Task viertelstündlich ausgeführt werden soll:

0,15,30,45 * * * * 0 say Viertelstunde vorbei!
60/4 * * * * 0 say Viertelstunde vorbei!

Beide Beispiele machen das gleiche. Allerdings fängt das zweite immer bei 0 an!

Einen AdminMod-Befehl ausführen

Dies ist relativ einfach zu bewerkstelligen. Vor jeden AdminMod-Befehl gehört ein admin_command. Ein zum oben vergleichbares Beispiel:

0,15,30,45 * * * * 0 admin_command admin_say Viertelstunde vorbei!

Viele Befehle gleichzeitig ausführen

Hierzu verwendet man den "exec"-Befehl. Die entsprechende Datei muss dann natürlich auf dem Server abgelegt werden. Außerdem hat man auch hier die Wahl, ob man das ganze in der tasks.cfg über den Mapchange hinaus speichern möchte oder nur einmalig bis zum Mapende. Wichtig, siehe Einschränkungen unten.

Einschränkungen:

  1. Es ist nicht erlaubt Kommas und Slashes in einer Spalte zu verwenden, in verschiedenen kein Problem!
  2. Es sind prinzipbedingt lediglich 50 Kommandos erlaubt. Dies ist nicht die Anzahl der Einträge in der schedule.ini, sondern die dadurch produzierte. S. Viertelstunde-Beispiel. Hier werden 4 Kommandos produziert. Wenn man die Anzahl der Kommandos vorausberrechnen will, muss man nur die Anzahl der Einträge in den Spalten miteinander multiplizieren. Gleiches Beispiel: 4*1*1*1*1 (Joker zählen als 1).
  3. Pro Spalte sind maximal 10 Kommandos erlaubt.
  4. In der tasks.cfg ist nur 1 exec-Befehl möglich.

Befehle

Für die Befehle braucht Ihr das Recht 65536!

admin_cron_add <command>:
Mit diesem Befehl kann man eine neue Aufgabe in eine freie Stelle in der schedule.ini schreiben. "Command" muss der Struktur des Musterbeispiels folgen.
admin_cron_del <line>:
Mit admin_cron_del kann man einen Eintrag in der schedule.ini löschen. Dazu benötigt man zusätzlich die Nummer des Eintrages. Diese bekommt man über admin_cron_list heraus.
admin_cron_edit <line> <command>:
Wenn man den Inhalt einer bestimmten Zeile in der schedule.ini verändern möchte, kommt dieser Befehl zum Zug. Auch hier wird die Zeilennummer benötigt. Der "Command" muss vollständig sein, da die komplette Zeile überschrieben wird.
admin_cron_forcecheck:
Dieser Befehl übergeht den Timer und checkt sofort, ob etwas ausgeführt werden soll. Evtl. mal nützlich, kann aber in der Regel ignoriert werden.
admin_cron_forceexe <line>:
Der Befehl admin_cron_forceexe führt einen Befehl unabhängig vom Zeitpunkt aus. Man benötigt lediglich die Zeilennummer aus der schedule.ini (s. admin_cron_list). Dieser Befehl ist nach einer längeren Auszeit des Servers evtl. wichtig. Man kann den Server dann schnell wieder auf den aktuellen Stand bringen.
admin_cron_list <line>:
Mit diesem Befehl kann man sich den Inhalt der schedule.ini in 10er Schritten ansehen. Der nachstehende Parameter ist optional. Wird beispielsweise 11 angegeben, so zeigt der Befehl alle Zeilen von 11 bis 20 an. Außerdem kann man mit diesem Befehl die Zeilennummer ermitteln, die man für die anderen Befehle benötigt.
admin_cron_refresh:
Dieser sollte ausgeführt werden, sobald die schedule.ini manuell bearbeitet wurde. Die schedule.ini wird dann neu eingelesen. Das gleiche kann man aber auch über einen Mapchange erreichen.
admin_cron_timeleft <0/1>:
Der Befehl deaktiviert/aktiviert (0/1) das Setzen der mp_timeleft Variable. Bei Aktivierung wird das aktuelle Timeleft jede Minute in die Servervariable geschrieben und ist somit nach außen hin sichtbar.

Beispiele

Sonntagsmapcycle

Mal angenommen man möchte jeden Sonntag einen Custommap-Tag machen. Das ganze soll natürlich automatisch ablaufen. Wenn Ihr ein mapcyclefile in der server.cfg angelegt habt, lauten die Tasks dafür:

0 0 * * 7 1 mapcyclefile sunmapcycle.txt
0 0 * * 1 1 mapcyclefile mapcycle.txt delete

Im ersten Task wird jeden Sonntag (7) um 0:00 Uhr die Variable mapcyclefile auf sunmapcycle.txt gesetzt und in die tasks.cfg geschrieben. Dadurch wird der Wert auch über den Mapwechsel hinaus erhalten bleiben.

Im zweiten Task wird jeden Montag (1) um 0:00 Uhr die Variable mapcyclefile auf mapcycle.txt gesetzt und aus der tasks.cfg gelöscht. Ab dem nächsten Mapwechsel gilt dann der Eintrag in der server.cfg (daher gibt man hier schon den Wert aus der server.cfg an).

Ist kein mapcyclefile in der server.cfg angelegt so kann man das auch anders durchführen (Die erste Variante funktioniert hier aber auch.):

0 0 * * 7 0 mapcyclefile sunmapcycle.txt
0 0 * * 1 0 mapcyclefile mapcycle.txt

Da kein Wert in der server.cfg steht, wird dieser beim Mapwechsel auch nicht überschrieben und gilt bis zum nächsten Umsetzen, Servercrash oder -restart. Sollte der Server während des Sonntages also abstürzen, so gilt wieder mapcycle.txt. Variante 1 ist also eher zu empfehlen.

Täglicher Mapcycle

Es kann ja auch sein, dass man einen sich täglich ändernden Cycle machen möchte:

0 0 * * 1 1 mapcyclefile monmapcycle.txt
0 0 * * 2 1 mapcyclefile tuemapcycle.txt
0 0 * * 3 1 mapcyclefile wedmapcycle.txt
0 0 * * 4 1 mapcyclefile thumapcycle.txt
0 0 * * 5 1 mapcyclefile frimapcycle.txt
0 0 * * 6 1 mapcyclefile satmapcycle.txt
0 0 * * 7 1 mapcyclefile sunmapcycle.txt

Auf das "delete" kann hier verzichtet werden, da nur ein mapcyclefile-Eintrag in der tasks.cfg existieren kann und dieser immer überschrieben wird.

Mapcycle 2x im Monat wechseln

0 0 1 * * 1 mapcyclefile mapcycle1.txt
0 0 15 * * 1 mapcyclefile mapcycle2.txt

Am 1. und 15. jedes Monats wird hier der Mapcycle geändert.

Clanwarankündigung

Auf einem Public Server möchte man ja nicht so gerne die Leute einfach kicken. Ein bisschen vorwarnen, dass gleich ein Clanwar losgeht wäre nett:

40,45,50,55 19 * * * 0 admin_command admin_csay Um 20 Uhr ist ClanWar!

Dieser Task führt von 19:40 Uhr bis 19:55 alle 5 Minuten ein CSay durch. Statt der Sternchen kann man auch ein direktes Datum eingeben. Falls man dann vergessen hat den Eintrag zu löschen, wird er am nächsten Tag nicht ausgeführt:

40,45,50,55 19 4 1 * 0 admin_command admin_csay Um 20 Uhr ist ClanWar!

Dieser Eintrag gilt nur für den 4. Januar.

Clanwarstart

Natürlich kann man auch gleich die ClanWar-Konfiguration laden lassen:

0 20 * * * 1 exec cw.cfg
0 23 * * * 1 exec server.cfg delete

Hier werden die CW-Einstellungen von 20-23 Uhr geladen. Leider weiß das Plugin nicht, wann der War zu Ende ist. Ich empfehle daher den CW Creator v3.0.1:

0 20 * * * 0 admin_command admin_war_set [WING] [-+MfG+-] Passwort de_dust de_dust2 esl.cfg

Der War kann dann jederzeit mit admin_war_end beendet werden. Man muss anschließend nur noch diesen einen Eintrag wieder löschen.

Ankündigung Freitag den 13.

OK, ist kein wirklich sinnvolles Beispiel, soll aber mal die Möglichkeiten darstellen:

0 0 13 * 5 0 admin_command admin_tsay Freitag der 13.^nViel Glueck!

An jedem Freitag den 13. um 0 Uhr wird dieser Befehl ausgeführt.


Danksagungen


Quellcode

plugin_bk_cron.sma:

/* Black Knight's AM Cron v1.1 (09.09.2003)
 
Contact: http://www.wing-clan.de, blackknight@wing-clan.de 
 
PS.: The Black Knight always triumphs... */
 
#pragma dynamic 8192
 
#include <core> 
#include <console> 
#include <string> 
#include <admin> 
#include <adminlib>
 
#include "cron_language(us)"
 
#define MAX_COMMANDS 50
#define TIMESTRING 10
#define PARAMETER 10
#define TIMECOLUMN 31
 
#define CHAR_INVALID -1
#define FALSE 0
#define NULL_CHAR 0
#define QUOTE_CHAR 34
#define TRUE 1
 
new STRING_VERSION[MAX_DATA_LENGTH] = "1.1";
new timearray[MAX_COMMANDS][TIMESTRING];
new cmdarray[MAX_COMMANDS][MAX_DATA_LENGTH];
new cvarcron[MAX_COMMANDS][2];
new filename[MAX_DATA_LENGTH]="schedule.ini";
new filename2[MAX_DATA_LENGTH]="tasks.cfg";
new crontimeleft=FALSE;
 
strbreak2(str[], first[], second[], maxlen, search[], number) {
	new i = 0;
	new NullPos = CHAR_INVALID;
	new Quote = FALSE;
	new SpacePos = CHAR_INVALID;
	new merk=0;
 
	if (maxlen == 0){
		maxlen = strlen(str);
	}
 
	for(i=0; i<maxlen; i++) {
		if (str[i] == QUOTE_CHAR) {
			if (Quote==FALSE) {
				Quote = TRUE;
			}
			else {
				Quote = FALSE;
			}
		}
		else if (str[i] == search[0] && Quote == FALSE) {
			merk++;
			if (merk==number) {
				SpacePos = i;
			}
		}
		else if (str[i] == NULL_CHAR) {
			NullPos = i;
			break;
		}	
	}
 
	if (SpacePos == CHAR_INVALID) {
		strcpy(first, str, maxlen);
		strinit(second);
	}
	else {
		if (NullPos == CHAR_INVALID) {
			NullPos = maxlen + 1;
		}
		for(i=0; i<SpacePos; i++) { 
			first[i] = str[i];
		}
		first[SpacePos] = NULL_CHAR;
		for(i=SpacePos+1; i<NullPos;i++) {
			second[i - SpacePos - 1] = str[i];
		}
		second[NullPos - SpacePos - 1] = NULL_CHAR;
	}
	return 1;
}
 
/* Splits string at a specific position */
strnsplit(str[],first[],second[],n) {
	new i;
	new maxlen=strlen(str);
	new m=n+1;
 
	for(i=0; i<n; i++){
		first[i]=str[i];
	}
	for(i=m;i<=maxlen;i++){ 
		second[i-m]=str[i];
	}
	return 1;
}
 
/* Splits string at a specific position */
strnsplit2(str[],first[],second[],n) {
	new i;
	new maxlen=strlen(str);
	new m=n+1;
 
	for(i=0; i<=n; i++){
		first[i]=str[i];
	}
	first[n+1]=NULL_CHAR;
	for(i=m;i<=maxlen;i++){ 
		second[i-m]=str[i];
	}
	second[maxlen+1]=NULL_CHAR;
	return 1;
}
 
/* Timestring auf gleiche Laenge formatieren */
format_timestring(timevar[5][], i) {
	new j;
 
	for(j=0;j<=3;j++){
		if (strlen(timevar[j])<=1) {
			if (timevar[j][0]=='*'){
				timearray[i][j+j]='*';
			}
			else {
				timearray[i][j+j]='0';
			}
			timearray[i][j+j+1]=timevar[j][0];
		}
		else {
			timearray[i][j+j]=timevar[j][0];
			timearray[i][j+j+1]=timevar[j][1];
		}
	}
	timearray[i][8]=timevar[4][0];
	return PLUGIN_CONTINUE;
}
 
cron_error(linestring[],line,actionstring[]){
	new string[MAX_DATA_LENGTH];
 
	/* snprintf(string,MAX_DATA_LENGTH,"plugin_bk_cron ERROR in line: %i %s",line,linestring); */
	snprintf(string,MAX_DATA_LENGTH,cron_err,line,linestring);
	log(string);
	log(actionstring);
	return PLUGIN_CONTINUE;
}
 
admin_cron_refresh(){
	new sizeoffile,i,j,k,l;
	new string[MAX_DATA_LENGTH];
	new timeaustausch[MAX_DATA_LENGTH];
	new cmdaustausch[MAX_DATA_LENGTH];
	new cvarcronmerk[2];
	new cmdmerk[MAX_DATA_LENGTH];
	new timevar[5][TIMECOLUMN];
	new merk[TIMECOLUMN];
	new anzahlkomma[5];
	new anzahlslash[5];
	new indexmerk=0;
	new fieldsize=1;
	new dontwrite=FALSE;
	new szaehler[3],snenner[3];
	new zaehler, nenner, teiler;
	new maxtime[4]={59,23,29,11};
	new tmparameter[MAX_TEXT_LENGTH];
	new tmparameter2[MAX_TEXT_LENGTH];
	new merktimearray[MAX_COMMANDS][TIMECOLUMN];
	new blowup;
 
	/* Empty arrays */
	for(i=0;i<MAX_COMMANDS;i++) {
		timearray[i][0]=NULL_CHAR;
		cmdarray[i][0]=NULL_CHAR;
		cvarcron[i][0]=NULL_CHAR;
	}
 
	/* snprintf(tmparameter,MAX_TEXT_LENGTH,"(Too many parameters >%i)",PARAMETER);
	snprintf(tmparameter2,MAX_TEXT_LENGTH,"Parameter No.%i and higher ignored!",PARAMETER+1); */
	snprintf(tmparameter,MAX_TEXT_LENGTH,cron_tmp,PARAMETER);
	snprintf(tmparameter2,MAX_TEXT_LENGTH,cron_tmp2,PARAMETER+1);
 
	if(fileexists(filename)==0){
		/* log("plugin_bk_cron found no schedule.ini."); */
		log(cron_nosched);
		return PLUGIN_CONTINUE;
	}
	sizeoffile=filesize(filename,lines);
 
	for(i=0; i<=sizeoffile-1; i++) {
		/* Schedule.ini auslesen */
		readfile(filename,string,i+1,MAX_DATA_LENGTH);
		if(strlen(string)==0){
			dontwrite=TRUE;
		}
		else{
			/* Timestring vom Commandstring trennen */
			strbreak2(string,timeaustausch,cmdaustausch,MAX_DATA_LENGTH," ",5);
			/* cvarcron-Variable abtrennen */
			strnsplit(cmdaustausch,cvarcronmerk,cmdmerk,1);
			/* Zeitsplit */
			strsplit(timeaustausch," ",timevar[0],TIMECOLUMN,timevar[1],TIMECOLUMN,timevar[2],TIMECOLUMN,timevar[3],TIMECOLUMN,timevar[4],TIMECOLUMN);
 
			/* Converts Slash to comma expression */
			for(j=0;j<=4;j++){
				anzahlkomma[j]=0;
				anzahlslash[j]=0;
				anzahlkomma[j]=strcount(timevar[j],',');
				anzahlslash[j]=strcount(timevar[j],'/');
				/* Check if slashs and commas exist in one column */
				if(anzahlkomma[j]>=1 && anzahlslash[j]>=1) {
					/* cron_error("(Slash and Komma in 1 column)",i+1,"Line ignored!"); */
					cron_error(cron_err_sak,i+1,cron_li);
					dontwrite=TRUE;
					break;
				}
				if(anzahlslash[j]>=1) {
					/* Check if slash exists in the weekdays column */
					if(j==4) {
						/* cron_error("(Slash on weekdays column)",i+1,"Line ignored!"); */
						cron_error(cron_err_sowc,i+1,cron_li);
						dontwrite=TRUE;
						break;
					}
					strsplit(timevar[j],"/",szaehler,3,snenner,3);
					zaehler=strtonum(szaehler);
					nenner=strtonum(snenner);
					if(nenner==0){
						/* cron_error("(Division by zero)",i+1,"Line ignored!"); */
						cron_error(cron_err_dbz,i+1,cron_li);
						dontwrite=TRUE;
						break;
					}
					teiler=zaehler/nenner;
					if(teiler<1){
						teiler=1;
					}
					zaehler=0;
					anzahlkomma[j]=0;
					strcpy(timevar[j],"0",TIMECOLUMN);
					for(k=0;k<=maxtime[j]+1;k++){
						zaehler+=teiler;
						numtostr(zaehler,szaehler);
						strcat(timevar[j],",",TIMECOLUMN);
						strcat(timevar[j],szaehler,TIMECOLUMN);
						anzahlkomma[j]+=1;
						if(zaehler+teiler>=maxtime[j]){
							break;
						}
					}
				}
				if(anzahlkomma[j]>=PARAMETER) {
					anzahlkomma[j]=PARAMETER-1;
					cron_error(tmparameter,i+1,tmparameter2);
				}
			}
		}
		if(dontwrite==FALSE){
			/* Check if this command blows up the array */
			blowup=1;
			for(j=0;j<=4;j++){
				blowup=blowup*(anzahlkomma[j]+1);
			}
			if(blowup+i+indexmerk>=MAX_COMMANDS-1){
				/* cron_error("(Exceeds max time commands)",i+1,"Actual line and remaining lines ignored!"); */
				cron_error(cron_err_emtc,i+1,cron_ali);
				return PLUGIN_HANDLED;
			}
			if(anzahlkomma[0]!=0 || anzahlkomma[1]!=0 || anzahlkomma[2]!=0 || anzahlkomma[3]!=0 || anzahlkomma[4]!=0){
				for(j=0;j<=4;j++){
					if(anzahlkomma[j]!=0){
						/* Copy information for permutation (enlarge field)*/
						for(k=fieldsize;k<=(anzahlkomma[j]+1)*fieldsize-1;k++){
							strcpy(merktimearray[k],merktimearray[k-fieldsize],TIMECOLUMN);
						}
						for(k=0;k<=anzahlkomma[j];k++){
							/* Write all permutative possibilities */
							strbreak2(timevar[j],merk,timevar[j],TIMECOLUMN,",",1);
							strcat(merk," ",TIMECOLUMN);
							for(l=k*fieldsize;l<=(k+1)*fieldsize-1;l++){
								strcat(merktimearray[l],merk,TIMECOLUMN);
							}
						}
						fieldsize=(anzahlkomma[j]+1)*fieldsize;
					}
					else{
						for(k=0;k<=fieldsize-1;k++){
							strcat(merktimearray[k],timevar[j],TIMECOLUMN);
							strcat(merktimearray[k]," ",TIMECOLUMN);
						}
					}
				}
				for(j=0;j<=fieldsize-1;j++){
					for(k=0;k<=4;k++){
						strbreak2(merktimearray[j],timevar[k],merktimearray[j],TIMECOLUMN," ",1);
					}
					format_timestring(timevar,i+indexmerk+j);
					strcpy(cvarcron[i+indexmerk+j],cvarcronmerk,2);
					strcpy(cmdarray[i+indexmerk+j],cmdmerk,MAX_DATA_LENGTH);
				}
				indexmerk+=fieldsize-1;
			}
			else {
				format_timestring(timevar,i+indexmerk);
				strcpy(cvarcron[i+indexmerk],cvarcronmerk,2);
				strcpy(cmdarray[i+indexmerk],cmdmerk,MAX_DATA_LENGTH);
			}
		}
		else{
			indexmerk=indexmerk-1;
		}
		dontwrite=FALSE;
		fieldsize=1;
	}
	/* log("[ADMIN] plugin_bk_cron initialized"); */
	log(cron_init);
	return PLUGIN_CONTINUE;
}
 
admin_cron_check(sTime[]){
	new nullpos;
	new i,j;
	new validate=TRUE;
	new string[MAX_DATA_LENGTH];
	new fcommand[MAX_DATA_LENGTH];
	new scommand[MAX_DATA_LENGTH];
	new sscommand[MAX_DATA_LENGTH];
	new first[MAX_DATA_LENGTH];
	new second[MAX_DATA_LENGTH];
 
	/* Array-Laenge ermitteln (Vermutlich Compilerbug) */
	for(i=0;i<MAX_COMMANDS;i++) {
		if(timearray[i][0]==NULL_CHAR) {
			nullpos=i;
			break;
		}
	}
	if(nullpos==0){
		return PLUGIN_CONTINUE;
	}
	/* Check-Funktion, ob Timestring aktuell/Tabelle gleich */
	for(i=0;i<nullpos;i++) {
		for(j=0;j<9;j++){
			if(timearray[i][j]!='*' && timearray[i][j]!=sTime[j]){
				validate=FALSE;
				break;
			}
		}
		if (validate==TRUE){
			/* Check if admin_command is the first command, uses plugin_exec then */
			if(cvarcron[i][0]=='1'){
				strbreak2(cmdarray[i],first,second,MAX_DATA_LENGTH," ",strcount(cmdarray[i],' '));
				if(streq(second,"delete")){
					edittasks(first,1);
				}
				else{
					strcpy(first,cmdarray[i],MAX_DATA_LENGTH);
					edittasks(first,0);
				}
			}
			else{
				strcpy(first,cmdarray[i],MAX_DATA_LENGTH);
			}
			strbreak2(first,fcommand,scommand,MAX_DATA_LENGTH," ",1);
			if(streq(fcommand,"admin_command")){
				strbreak2(scommand,fcommand,sscommand,MAX_DATA_LENGTH," ",1);
				plugin_exec(fcommand,sscommand);
			}
			else{
				exec(first,0);
			}
			strncpy(first,first,73,MAX_DATA_LENGTH);
			/* snprintf(string,MAX_DATA_LENGTH,"plugin_bk_cron executes: %s",first); */
			snprintf(string,MAX_DATA_LENGTH,cron_exe,first);
			log(string);
		}
		validate=TRUE;
	}
	return PLUGIN_CONTINUE;
}
 
edittasks(searchstring[],delete){
	new ebreak=1;
	new fcommand[MAX_DATA_LENGTH];
	new fcommand2[MAX_DATA_LENGTH];
	new scommand[MAX_DATA_LENGTH];
	new sizeoffile;
	new string[MAX_DATA_LENGTH];
	new i;
	new emptyspace=-1;
 
	strbreak2(searchstring,fcommand,scommand,MAX_DATA_LENGTH," ",ebreak);
	if(streq(fcommand,"admin_command")){
		ebreak=2;
		strbreak2(searchstring,fcommand,scommand,MAX_DATA_LENGTH," ",ebreak);
	}
	sizeoffile=filesize(filename2,lines);
	for(i=0; i<=sizeoffile-1; i++) {
		readfile(filename2,string,i+1,MAX_DATA_LENGTH);
		strbreak2(string,fcommand2,scommand,MAX_DATA_LENGTH," ",ebreak);
		if(streq(fcommand2,fcommand)){
			if(delete==1){
				writefile(filename2,"",i+1);
				return PLUGIN_CONTINUE;
			}
			else{
				writefile(filename2,searchstring,i+1);
				return PLUGIN_CONTINUE;
			}
		}
		if(strlen(fcommand2)==0 && emptyspace==-1){
			emptyspace=i+1;
		}
	}
	if(delete!=1){
		writefile(filename2,searchstring,emptyspace);
	}
	else{
		/* log("plugin_bk_cron did not found string to be deleted"); */
		log(cron_notfound);
	}
	return PLUGIN_CONTINUE;
}
 
/* Start regular timer */
public regular_timer(Timer,Repeat,HLUser,HLParam){
 
	set_timer("admin_cron_check2",60,99999);
	lag_check();
 
	set_timeleft();
 
	return PLUGIN_CONTINUE;
}
 
/* Reads Servertime and issues check */ 
public admin_cron_check2(Timer,Repeat,HLUser,HLParam){
 
	lag_check();
 
	set_timeleft();
 
	return PLUGIN_CONTINUE;
}
 
/* Lag check (max. 5 minutes) */
lag_check(){
	new sTime[TIMESTRING];
	new sTimeold[TIMESTRING];
	new sTimem[TIMESTRING];
	new sTimew[TIMESTRING];
	new lastcheck=0;
	new iTime;
	new lagcompensation;
	new i;
	new slastcheck[3];
 
	/* get_vaultnumdata("last_cron",lastcheck); */
	get_serverinfo("last_cron",slastcheck,3);
	lastcheck=strtonum(slastcheck);
	servertime(sTime,TIMESTRING,"%H%d%m%w");
	servertime(sTimem,TIMESTRING,"%M");
	iTime=strtonum(sTimem);
	if(iTime-lastcheck<0){
		lastcheck-=60;
		oldtimestring(sTime,sTimeold);
	}
	lagcompensation=iTime-lastcheck;
	if(lagcompensation>5){
		lagcompensation=5;
		/* log("plugin_bk_cron detected too much lag. Last 5 minutes going to be compensated."); */
		log(cron_comp);
	}
	if(lagcompensation>1){
		for(i=iTime-lagcompensation;i<=iTime;i++){
			if(i<0){
				snprintf(sTimew,TIMESTRING,"%i%s",i+60,sTimeold);
			}
			else if(i>=0 && i<=9){
				snprintf(sTimew,TIMESTRING,"0%i%s",i,sTime);
			}
			else{
				snprintf(sTimew,TIMESTRING,"%i%s",i,sTime);
			}
			admin_cron_check(sTimew);
		}
		/* log("plugin_bk_cron lag compensation done"); */
		log(cron_compdone);
	}
	else{
		strcat(sTimem,sTime,TIMESTRING);
		admin_cron_check(sTimem);
	}
	/* set_vaultnumdata("last_cron",iTime); */
	numtostr(iTime,sTime);
	set_serverinfo("last_cron",sTime);
 
	return PLUGIN_CONTINUE;
}
 
oldtimestring(sTime[],sTime2[]){
	new i;
	new Time[3];
	new iTime[5];
	new timemerk[3];
 
	for(i=0;i<=2;i++){
		Time[0]=sTime[i*2];
		Time[1]=sTime[i*2+1];
		iTime[i]=strtonum(Time);
	}
	Time[0]=sTime[6];
	Time[1]=NULL_CHAR;
	iTime[3]=strtonum(Time);
	iTime[0]=iTime[0]-1;
	if(iTime[0]<0){
		iTime[0]=23;
		iTime[1]=iTime[1]-1;
		iTime[3]=iTime[3]-1;
		if(iTime[1]<1){
			iTime[1]=31;
			iTime[2]=iTime[2]-1;
			if(iTime[2]<1){
				iTime[2]=12;
			}
		}
		if(iTime[3]<1){
			iTime[3]=7;
		}
	}
	for(i=0;i<=2;i++){
		if(iTime[i]<10){
			snprintf(timemerk,3,"0%i",iTime[i]);
		}
		else{
			numtostr(iTime[i],timemerk);
		}
		strcat(sTime2,timemerk,TIMESTRING);
	}
	numtostr(iTime[3],timemerk);
	strcat(sTime2,timemerk,TIMESTRING);
 
	return PLUGIN_CONTINUE;
}
 
public admin_cron_refresh2(HLCommand,HLData,HLUserName,UserIndex){
	admin_cron_refresh();
	return PLUGIN_HANDLED;
}
 
public admin_cron_fcheck(HLCommand,HLData,HLUserName,UserIndex){
	lag_check();
	return PLUGIN_HANDLED;
}
 
public admin_cron_list(HLCommand,HLData,HLUserName,UserIndex){
	new snumber[4];
	new inumber;
	new sizeoffile;
	new remaining;
	new Msg[MAX_TEXT_LENGTH];
	new string[MAX_DATA_LENGTH];
	new first[95];
	new second[MAX_DATA_LENGTH];
	new i;
 
	convert_string(HLData,snumber,4);
	inumber=strtonum(snumber);
	if(inumber==0){
		inumber=1;
	}
 
	sizeoffile=filesize(filename,lines);
	/* selfmessage("Nr.: Time and command string"); */
	selfmessage(cron_listtitle);
	if(sizeoffile<inumber || sizeoffile==0){
		/* selfmessage("No schedule tasks available"); */
		selfmessage(cron_listnotasks);
		return PLUGIN_HANDLED;
	}
	if(inumber+9>sizeoffile){
		remaining=sizeoffile;
	}
	else{
		remaining=inumber+9;
	}
	for(i=inumber; i<=remaining; i++) {
		readfile(filename,string,i,MAX_DATA_LENGTH);
		strnsplit2(string, first, second, 93);
		/* strncpy(string2,string,93,95); */
		snprintf(Msg,MAX_TEXT_LENGTH,"%i: %s",i,first);
		selfmessage(Msg);
		if(strlen(string)>93){
			strncpy(first,second,93,95);
			selfmessage(first);
		}
	}
	/* snprintf(Msg,MAX_TEXT_LENGTH,"Showing %i to %i of %i.",inumber,remaining,sizeoffile); */
	snprintf(Msg,MAX_TEXT_LENGTH,cron_listshow,inumber,remaining,sizeoffile);
	selfmessage(Msg);
	if(remaining<sizeoffile){
		/* snprintf(Msg,MAX_TEXT_LENGTH,"For more, type admin_cron_list %i",remaining+1); */
		snprintf(Msg,MAX_TEXT_LENGTH,cron_listmore,remaining+1);
		selfmessage(Msg);
	}
 
	return PLUGIN_HANDLED;
}
 
public admin_cron_del(HLCommand,HLData,HLUserName,UserIndex){
	new snumber[4];
	new inumber;
	new sizeoffile;
 
	convert_string(HLData,snumber,4);
	inumber=strtonum(snumber);
 
	sizeoffile=filesize(filename,lines);
	/* sizeoffile=realfilesize(filename);*/
	if(sizeoffile<1 || sizeoffile<inumber){
		/* selfmessage("Nothing to delete. Line number invalid!"); */
		selfmessage(cron_dellni);
		/* selfmessage("Usage: admin_cron_del <line number>"); */
		selfmessage(cron_deluse);
		return PLUGIN_HANDLED;
	}
	writefile(filename,"",inumber);
	/* selfmessage("Line deleted!"); */
	selfmessage(cron_del);
	admin_cron_refresh();
 
	return PLUGIN_HANDLED;
}
 
public admin_cron_add(HLCommand,HLData,HLUserName,UserIndex){
	new task[MAX_DATA_LENGTH];
	new sizeoffile;
	new i;
	new written=-1;
	new string[MAX_DATA_LENGTH];
 
	convert_string(HLData,task,MAX_DATA_LENGTH);
 
	if(strcount(task,' ')<6){
		/* selfmessage("Task not valid!"); */
		selfmessage(cron_tnv);
		/* selfmessage("Usage: admin_cron_add <min> <h> <d> <month> <weekday> <cvarcron> <command>"); */
		selfmessage(cron_adduse);
		return PLUGIN_HANDLED;
	}
 
	sizeoffile=filesize(filename,lines);
	/* sizeoffile=realfilesize(filename);*/
	for(i=1; i<=sizeoffile; i++) {
		readfile(filename,string,i,MAX_DATA_LENGTH);
		if(strlen(string)==0){
			written=i;
			break;
		}
	}
	if(sizeoffile<=MAX_COMMANDS){
		writefile(filename,task,written);
		/* selfmessage("Line added!"); */
		selfmessage(cron_add);
		admin_cron_refresh();
	}
	else{
		/* selfmessage("Too many tasks! Delete unneeded tasks first."); */
		selfmessage(cron_addtmt);
	}
 
	return PLUGIN_HANDLED;
}
 
public admin_cron_edit(HLCommand,HLData,HLUserName,UserIndex){
	new task[MAX_DATA_LENGTH];
	new cmdtask[MAX_DATA_LENGTH];
	new line[MAX_DATA_LENGTH];
	new iline;
	new sizeoffile;
 
	convert_string(HLData,task,MAX_DATA_LENGTH);
 
	if(strcount(task,' ')<7){
		/* selfmessage("Task not valid!"); */
		selfmessage(cron_tnv);
		/* selfmessage("Usage: admin_cron_edit <line> <min> <h> <d> <month> <weekday> <cvarcron> <command>"); */
		selfmessage(cron_edituse);
		return PLUGIN_HANDLED;
	}
 
	strbreak2(task,line,cmdtask,MAX_DATA_LENGTH," ",1);
	iline=strtonum(line);
 
	sizeoffile=filesize(filename,lines);
 
	if(sizeoffile>=iline){
		writefile(filename,cmdtask,iline);
		/* selfmessage("Line edited!"); */
		selfmessage(cron_edit);
		admin_cron_refresh();
	}
	else{
		/* selfmessage("No valid line given!"); */
		selfmessage(cron_nvlg);
		/* selfmessage("Usage: admin_cron_edit <line> <min> <h> <d> <month> <weekday> <cvarcron> <command>"); */
		selfmessage(cron_edituse);
	}
 
	return PLUGIN_HANDLED;
}
 
public admin_cron_fexe(HLCommand,HLData,HLUserName,UserIndex){
	new line[4];
	new iline;
	new sizeoffile;
	new string[MAX_DATA_LENGTH];
	new cmdaustausch[MAX_DATA_LENGTH];
	new timeaustausch[MAX_DATA_LENGTH];
	new fcommand[MAX_DATA_LENGTH];
	new scommand[MAX_DATA_LENGTH];
	new sscommand[MAX_DATA_LENGTH];
 
	convert_string(HLData,line,4);
	iline=strtonum(line);
 
	sizeoffile=filesize(filename,lines);
	if(sizeoffile<1 || sizeoffile<iline){
		/* selfmessage("No valid line given!"); */
		selfmessage(cron_nvlg);
		/* selfmessage("Usage: admin_cron_forceexe <line number>"); */
		selfmessage(cron_fexeuse);
		return PLUGIN_HANDLED;
	}
 
	readfile(filename,string,iline,MAX_DATA_LENGTH);
	strbreak2(string,timeaustausch,cmdaustausch,MAX_DATA_LENGTH," ",6);
	strbreak2(cmdaustausch,fcommand,scommand,MAX_DATA_LENGTH," ",1);
	if(streq(fcommand,"admin_command")){
		strbreak2(scommand,fcommand,sscommand,MAX_DATA_LENGTH," ",1);
		plugin_exec(fcommand,sscommand);
	}
	else{
		strcpy(scommand,cmdaustausch,MAX_DATA_LENGTH);
		exec(scommand,0);
	}
	/* snprintf(string,MAX_DATA_LENGTH,"plugin_bk_cron executes: %s",scommand); */
	snprintf(string,MAX_DATA_LENGTH,cron_exe,scommand);
	log(string);
	selfmessage(string);
 
	return PLUGIN_HANDLED;
}
 
set_timeleft(){
 
	if(crontimeleft==TRUE){
		new itimeleft;
		new stimeleft[MAX_DATA_LENGTH];
		itimeleft=timeleft(0);
		snprintf(stimeleft,MAX_DATA_LENGTH,"mp_timeleft %i",itimeleft);
		exec(stimeleft,0);
	}
	return PLUGIN_CONTINUE;
}
 
public admin_cron_tl(HLCommand,HLData,HLUserName,UserIndex){
	new option[2];
	new ioption;
	new Msg[MAX_TEXT_LENGTH];
 
	convert_string(HLData,option,2);
	ioption=strtonum(option);
	if(streq(option,"") || ioption<0 || ioption>1){
		/* selfmessage("Usage: admin_cron_timeleft <0/1>"); */
		selfmessage(cron_tluse);
		return PLUGIN_HANDLED;
	}
	else{
		set_vaultnumdata("cron_timeleft",ioption);
		/* snprintf(Msg,MAX_TEXT_LENGTH,"cron_timeleft set to %i",ioption); */
		snprintf(Msg,MAX_TEXT_LENGTH,cron_tl,ioption);
		crontimeleft=ioption;
		selfmessage(Msg);
		log(Msg);
	}
 
	return PLUGIN_HANDLED;
}
 
public plugin_init(){
	new write=getvar("file_access_write");
	new read=getvar("file_access_read");
	new vault[MAX_DATA_LENGTH];
	new ivault=1;
 
	getstrvar("admin_vault_file",vault,MAX_DATA_LENGTH);
	if(streq(vault,"0")){
		ivault=0;
	}
	if(write==1 && read==1 && ivault==1){
		/* plugin_registerinfo("Black Knights AM-Cron","Small Cronsystem for AM",STRING_VERSION);
		plugin_registercmd("admin_cron_refresh","admin_cron_refresh2",ACCESS_RCON,"Refreshes time table");
		plugin_registercmd("admin_cron_forcecheck","admin_cron_fcheck",ACCESS_RCON,"Forces cron check");
		plugin_registercmd("admin_cron_list","admin_cron_list",ACCESS_RCON,"Lists schedule.ini.");
		plugin_registercmd("admin_cron_del","admin_cron_del",ACCESS_RCON,"Deletes specific line in schedule.ini");
		plugin_registercmd("admin_cron_add","admin_cron_add",ACCESS_RCON,"Adds given line to schedule.ini");
		plugin_registercmd("admin_cron_edit","admin_cron_edit",ACCESS_RCON,"Edits specific line in schedule.ini");
		plugin_registercmd("admin_cron_forceexe","admin_cron_fexe",ACCESS_RCON,"Forces task execution without time check");
		plugin_registercmd("admin_cron_timeleft","admin_cron_tl",ACCESS_RCON,"Toggles setting of mp_timeleft"); */
 
		plugin_registerinfo("Black Knights AM-Cron",cron_info,STRING_VERSION);
		plugin_registercmd("admin_cron_refresh","admin_cron_refresh2",ACCESS_RCON,cron_inforf);
		plugin_registercmd("admin_cron_forcecheck","admin_cron_fcheck",ACCESS_RCON,cron_infofr);
		plugin_registercmd("admin_cron_list","admin_cron_list",ACCESS_RCON,cron_infolist);
		plugin_registercmd("admin_cron_del","admin_cron_del",ACCESS_RCON,cron_infodel);
		plugin_registercmd("admin_cron_add","admin_cron_add",ACCESS_RCON,cron_infoadd);
		plugin_registercmd("admin_cron_edit","admin_cron_edit",ACCESS_RCON,cron_infoedit);
		plugin_registercmd("admin_cron_forceexe","admin_cron_fexe",ACCESS_RCON,cron_infofexe);
		plugin_registercmd("admin_cron_timeleft","admin_cron_tl",ACCESS_RCON,cron_infotl);
 
		/* Pfadgenerierung */
		new pathname[MAX_DATA_LENGTH];
		getstrvar("amv_default_config_dir",pathname,MAX_DATA_LENGTH);
		snprintf(filename,MAX_DATA_LENGTH,"%s/cron/%s",pathname,filename);
		snprintf(filename2,MAX_DATA_LENGTH,"%s/cron/%s",pathname,filename2);
 
		admin_cron_refresh();
 
		new sTime[TIMESTRING];
		new iTime;
 
		servertime(sTime,TIMESTRING,"%S");
		iTime=strtonum(sTime);
 
		set_timer("regular_timer",61-iTime,0);
 
		get_vaultnumdata("cron_timeleft",crontimeleft);
		set_timeleft();
 
	}
	else{
		/* plugin_registerinfo("Black Knights AM-Cron","Disabled! Check your cvarcrons",STRING_VERSION); */
		plugin_registerinfo("Black Knights AM-Cron",cron_infodis,STRING_VERSION);
		/* log("Check file_access_read, file_access_write, admin_vault_file."); */
		log(cron_check);
	}
 
	return PLUGIN_CONTINUE; 
}

cron_language(de).inc:

new cron_err[MAX_DATA_LENGTH]="plugin_bk_cron FEHLER in Zeile: %i %s";
new cron_tmp[MAX_TEXT_LENGTH]="(Zu viele Parameter >%i)";
new cron_tmp2[MAX_TEXT_LENGTH]="Parameter Nr.%i und groesser werden ignoriert!";
new cron_nosched[MAX_TEXT_LENGTH]="plugin_bk_cron fand keine schedule.ini.";
new cron_li[MAX_TEXT_LENGTH]="Zeile ignoriert!";
new cron_ali[MAX_TEXT_LENGTH]="Die aktuelle und alle folgenden Zeilen werden ignoriert!";
new cron_err_sak[MAX_TEXT_LENGTH]="(Slash und Komma in einer Spalte)";
new cron_err_sowc[MAX_TEXT_LENGTH]="(Slash in der Wochentagsspalte)";
new cron_err_dbz[MAX_TEXT_LENGTH]="(Division durch Null)";
new cron_err_emtc[MAX_TEXT_LENGTH]="(Ueberschreitet die Maximalzahl an Befehlen)";
new cron_init[MAX_TEXT_LENGTH]="plugin_bk_cron initiiert";
new cron_exe[MAX_DATA_LENGTH]="plugin_bk_cron fuehrt aus: %s";
new cron_notfound[MAX_TEXT_LENGTH]="plugin_bk_cron hat en zu loeschenden Befehl nicht gefunden.";
new cron_comp[MAX_TEXT_LENGTH]="plugin_bk_cron hat Lag erkannt. Die letzten fuenf Minuten werden kompensiert.";
new cron_compdone[MAX_TEXT_LENGTH]="plugin_bk_cron Lagkompensierung abgeschlossen.";
new cron_listtitle[MAX_TEXT_LENGTH]="Nr.: Zeit- und Befehlszeile";
new cron_listnotasks[MAX_TEXT_LENGTH]="Keine Aufgaben gefunden.";
new cron_listshow[MAX_TEXT_LENGTH]="Zeige %i bis %i von %i.";
new cron_listmore[MAX_TEXT_LENGTH]="Fuer mehr, schreibe admin_cron_list %i";
new cron_dellni[MAX_TEXT_LENGTH]="Nichts zum loeschen. Zeilennummer ungueltig!";
new cron_deluse[MAX_TEXT_LENGTH]="Verwendung: admin_cron_del <Zeilennummer>";
new cron_del[MAX_TEXT_LENGTH]="Zeile geloescht!";
new cron_tnv[MAX_TEXT_LENGTH]="Aufgabe ungueltig!";
new cron_adduse[MAX_TEXT_LENGTH]="Verwendung: admin_cron_add <min> <h> <d> <Monat> <Wochentag> <permanent?> <Befehl>";
new cron_add[MAX_TEXT_LENGTH]="Zeile angefügt!";
new cron_addtmt[MAX_TEXT_LENGTH]="Zu viele Aufgaben! Loesche zuerst nicht benoetigte Aufgaben.";
new cron_edituse[MAX_TEXT_LENGTH]="Verwendung: admin_cron_edit <Zeile> <min> <h> <d> <Monat> <Wochentag> <permanent?> <Befehl>";
new cron_edit[MAX_TEXT_LENGTH]="Zeile bearbeitet!";
new cron_nvlg[MAX_TEXT_LENGTH]="Keine gueltige Zeile gegeben!";
new cron_fexeuse[MAX_TEXT_LENGTH]="Verwendung: admin_cron_forceexe <Zeilennummer>";
new cron_tluse[MAX_TEXT_LENGTH]="Verwendung: admin_cron_timeleft <0/1>";
new cron_tl[MAX_TEXT_LENGTH]="cron_timeleft gesetzt auf %i";
new cron_info[MAX_TEXT_LENGTH]="Small Cronsystem fuer AM";
new cron_inforf[MAX_TEXT_LENGTH]="admin_cron_refresh: Erneuert Aufgabentabelle";
new cron_infofr[MAX_TEXT_LENGTH]="admin_cron_forcecheck: Erzwingt einen Check";
new cron_infolist[MAX_TEXT_LENGTH]="admin_cron_list: Gibt den Inhalt der schedule.ini wider";
new cron_infodel[MAX_TEXT_LENGTH]="admin_cron_del: Loescht eine bestimmte Zeile in der schedule.ini";
new cron_infoadd[MAX_TEXT_LENGTH]="admin_cron_add: Fuegt eine Zeile an die schedule.ini an";
new cron_infoedit[MAX_TEXT_LENGTH]="admin_cron_edit: Bearbeitet eine bestimmte Zeile in der schedule.ini";
new cron_infofexe[MAX_TEXT_LENGTH]="admin_cron_forceexe: Erzwingt die Ausfuehrung einer Aufgabe";
new cron_infotl[MAX_TEXT_LENGTH]="admin_cron_timeleft: (De-)aktiviert das Setzen von mp_timeleft";
new cron_infodis[MAX_TEXT_LENGTH]="Abgeschaltet! Ueberpruefe die cvars";
new cron_check[MAX_TEXT_LENGTH]="Ueberpruefe: file_access_read, file_access_write, admin_vault_file.";

cron_language(us).inc:

new cron_err[MAX_DATA_LENGTH]="plugin_bk_cron ERROR in line: %i %s";
new cron_tmp[MAX_TEXT_LENGTH]="(Too many parameters >%i)";
new cron_tmp2[MAX_TEXT_LENGTH]="Parameter No.%i and higher ignored!";
new cron_nosched[MAX_TEXT_LENGTH]="plugin_bk_cron found no schedule.ini.";
new cron_li[MAX_TEXT_LENGTH]="Line ignored!";
new cron_ali[MAX_TEXT_LENGTH]="Actual line and remaining lines ignored!";
new cron_err_sak[MAX_TEXT_LENGTH]="(Slash and Komma in 1 column)";
new cron_err_sowc[MAX_TEXT_LENGTH]="(Slash on weekdays column)";
new cron_err_dbz[MAX_TEXT_LENGTH]="(Division by zero)";
new cron_err_emtc[MAX_TEXT_LENGTH]="(Exceeds max time commands)";
new cron_init[MAX_TEXT_LENGTH]="[ADMIN] plugin_bk_cron initialized";
new cron_exe[MAX_DATA_LENGTH]="plugin_bk_cron executes: %s";
new cron_notfound[MAX_TEXT_LENGTH]="plugin_bk_cron did not found string to be deleted";
new cron_comp[MAX_TEXT_LENGTH]="plugin_bk_cron detected too much lag. Last 5 minutes going to be compensated.";
new cron_compdone[MAX_TEXT_LENGTH]="plugin_bk_cron lag compensation done";
new cron_listtitle[MAX_TEXT_LENGTH]="Nr.: Time and command string";
new cron_listnotasks[MAX_TEXT_LENGTH]="No schedule tasks available";
new cron_listshow[MAX_TEXT_LENGTH]="Showing %i to %i of %i.";
new cron_listmore[MAX_TEXT_LENGTH]="For more, type admin_cron_list %i";
new cron_dellni[MAX_TEXT_LENGTH]="Nothing to delete. Line number invalid!";
new cron_deluse[MAX_TEXT_LENGTH]="Usage: admin_cron_del <line number>";
new cron_del[MAX_TEXT_LENGTH]="Line deleted!";
new cron_tnv[MAX_TEXT_LENGTH]="Task not valid!";
new cron_adduse[MAX_TEXT_LENGTH]="Usage: admin_cron_add <min> <h> <d> <month> <weekday> <permanent?> <command>";
new cron_add[MAX_TEXT_LENGTH]="Line added!";
new cron_addtmt[MAX_TEXT_LENGTH]="Too many tasks! Delete unneeded tasks first.";
new cron_edituse[MAX_TEXT_LENGTH]="Usage: admin_cron_edit <line> <min> <h> <d> <month> <weekday> <permanent?> <command>";
new cron_edit[MAX_TEXT_LENGTH]="Line edited!";
new cron_nvlg[MAX_TEXT_LENGTH]="No valid line given!";
new cron_fexeuse[MAX_TEXT_LENGTH]="Usage: admin_cron_forceexe <line number>";
new cron_tluse[MAX_TEXT_LENGTH]="Usage: admin_cron_timeleft <0/1>";
new cron_tl[MAX_TEXT_LENGTH]="cron_timeleft set to %i";
new cron_info[MAX_TEXT_LENGTH]="Small Cronsystem for AM";
new cron_inforf[MAX_TEXT_LENGTH]="admin_cron_refresh: Refreshes time table";
new cron_infofr[MAX_TEXT_LENGTH]="admin_cron_forcecheck: Forces cron check";
new cron_infolist[MAX_TEXT_LENGTH]="admin_cron_list: Lists schedule.ini";
new cron_infodel[MAX_TEXT_LENGTH]="admin_cron_del: Deletes specific line in schedule.ini";
new cron_infoadd[MAX_TEXT_LENGTH]="admin_cron_add: Adds given line to schedule.ini";
new cron_infoedit[MAX_TEXT_LENGTH]="admin_cron_edit: Edits specific line in schedule.ini";
new cron_infofexe[MAX_TEXT_LENGTH]="admin_cron_forceexe: Forces task execution without time check";
new cron_infotl[MAX_TEXT_LENGTH]="admin_cron_timeleft: Toggles setting of mp_timeleft";
new cron_infodis[MAX_TEXT_LENGTH]="Disabled! Check your cvars";
new cron_check[MAX_TEXT_LENGTH]="Check file_access_read, file_access_write, admin_vault_file.";