/*
* Additionnal cheating-type commands.
* Easier teleportation commands than plugin_cheat.
* by bahrmanou © 2002 e-mail: Amiga5707@hotmail.com
*
* Very handy in cooperative/concjump/pipejump/etc... maps.
*
* All 'admin_pos' commands allowed only for users with permission level ACCESS_TELEPORT.
* The 'say' commands are obviously for all.
*
* History:
* ========
* 2.50.0:
*    - first public version
*
* 2.51.0:
*    - get rid of admin_fun_mode permission for say commands, fun mode having nothing to do here obviously ;)
*    - added command 'say destuckme' (people may be stuck on grounds with a slope when saying 'posme')
*    - say commands no more echoed on screen
*
* 2.52.0:
*       - added admin_posname
*
* 2.53.0:
*       - added admin_poscopy
*
* 2.54.0:
*    - treat the case where user attempt to save his pos while being spectator/dead
*      (only ACCESS_TELEPORT users can do this)
*
* 2.55.0:
*    - added little help message (poshelp)
*
* 2.56.0:
*    - added sounds
*
* 2.57.0:
*       - added admin_possend
*       - added destuckme control to avoid some cheating (a player can destuck himself
*         max 3 times at same horizontal position; the 4th time, he will be sent to
*         his position before first destucking)
*
* 2.58.0:
*       - added admin_posallowuser : allowing per user teleporting.
*
* 2.59.0:
*       - added admin_posdelay : admin can now set a delay between 2 users posme (to avoid some tricks).
*
* 2.60.0:
*	  - added say /s, say /p and say /d
*	  - added default sounds if possound.cfg not present for client
*	  - added admin_posinfo
*
* 2.61.0:
*	  - added read_mapcfg(); this allow per map teleportation enabling/disabling.
*
*/
 
 
#include <core>
#include <console>
#include <string>
#include <admin>
#include <adminlib>
 
new STRING_VERSION[MAX_DATA_LENGTH] = "2.60.0";
 
#define ACCESS_TELEPORT 8192
 
// slots
/* 40 slots seems enough but change it if u want to */
#define NUMSLOTS 40
#define DESTUCK_OFFSET 20
new SlotName[NUMSLOTS][MAX_TEXT_LENGTH];
new SlotX[NUMSLOTS];
new SlotY[NUMSLOTS];
new SlotZ[NUMSLOTS];
new UserX[MAX_PLAYERS] = { -1, ... };
new UserY[MAX_PLAYERS] = { -1, ... };
new UserZ[MAX_PLAYERS] = { -1, ... };
new UserX2[MAX_PLAYERS] = { -1, ... };
new UserY2[MAX_PLAYERS] = { -1, ... };
new UserZ2[MAX_PLAYERS] = { -1, ... };
 
// teleport allowing
// teleport allowed by default
new teleport_allowed = 1;
new player_allowed[MAX_PLAYERS];
// teleport delay is ON by default, delay = 5 secs
new PosDelayStatus = 1;
new PosDelay = 5;
new LastTime[MAX_PLAYERS];
 
//sound playing
// sound playing is ON by default
new pos_sound_flag = 1;
new SNDCFG_FILE[MAX_DATA_LENGTH] = "possound.cfg";
new def_snd_tab[3][18] = {
	"items/r_item1.wav",
	"items/r_item2.wav",
	"items/health1.wav"
};
#define MAX_SOUND 10
#define MAX_SOUND_LENGTH 30
new snd_ind[3];
new snd_tab[3*MAX_SOUND*MAX_SOUND_LENGTH];
 
// destucking
new destuck_count[MAX_PLAYERS+1];
new destuck_pos[3][MAX_PLAYERS+1];
#define NUM_DEST_SENT 5
new dest_sent[NUM_DEST_SENT][30] = {
        "bahrmanou said MOVE!",
        "move first, son...",
        "nice try",
        "nah!",
        "Hey! move!"
};
 
// text buffer
new Text[MAX_TEXT_LENGTH];
 
 
 
 
pos_play_sound(user[], n ) {
        if ( pos_sound_flag) {
            	strcpy(Text,"sound/",MAX_TEXT_LENGTH);
		if (snd_ind[n] ) {
                	new rnd = random(snd_ind[n]);
 
                	strcat(Text,snd_tab[(n*MAX_SOUND+rnd)*MAX_SOUND_LENGTH],MAX_TEXT_LENGTH);
                	playsound(user, Text);
        	}
		else {
                	strcat(Text,def_snd_tab[n],MAX_TEXT_LENGTH);
                	playsound(user, Text);
		}
	}
}
 
read_sound_file(file[]="") {
        new i;
        new num_line= 0;
        new positem = 0;
        new str[MAX_SOUND_LENGTH];
        new line_buffer[MAX_TEXT_LENGTH];
 
        if (fileexists(file)<=0) {
                snprintf(Text, MAX_TEXT_LENGTH, "plugin_teleport: cannot find sound cfg file -- %s --, using defaults.", file);
                selfmessage(Text);
                log(Text);
                return -1;
        }
 
        for (i=0; i<MAX_SOUND*MAX_SOUND_LENGTH*3; i++)
        snd_tab[i] = 0;
 
        for (i=0; i<3; i++)
        snd_ind[i] = 0;
 
        while (positem < 3) {
                if (!readfile(file, line_buffer, num_line, MAX_TEXT_LENGTH)) {
                        snprintf(Text, MAX_TEXT_LENGTH, "plugin_teleport: error reading sound cfg file %s, line %i.", file, num_line);
                        selfmessage(Text);
                        log(Text);
                        return -1;
                }
                // if a comment or blank line, pass it
                if ( (strncmp(line_buffer, "#", 1) != 0) && (strlen(line_buffer) != 0) ) {
                        new x;
                        new j;
 
                       for(i=0; i<MAX_SOUND; i++) {
                                x = (positem*MAX_SOUND + i) * MAX_SOUND_LENGTH;
 
                                strsep(line_buffer, ";", str, MAX_SOUND_LENGTH, line_buffer, MAX_TEXT_LENGTH);
                                strtrim(str, " ^t", 2);
 
                                for (j=0; j<MAX_SOUND_LENGTH; j++)
                                snd_tab[x+j] = str[j];
 
                                if (str[0]!=0) {
                                        snd_ind[positem] = snd_ind[positem] + 1;
                                }
                                if (line_buffer[0]==0) break;
                        }
                        positem++;
                }
                num_line++;
        }
        return 0;
}
 
 
/*
*       syntax:
*
*       admin_possound flag             flag: 'on' | 'off' | 0 | 1
*       admin_possound                  display current teleporting sound status
*
*/
public admin_possound(HLCommand,HLData,HLUserName,UserIndex) {
        new Data[MAX_DATA_LENGTH];
        new flag[MAX_DATA_LENGTH];
        new i;
 
        convert_string(HLData,Data,MAX_DATA_LENGTH);
        if (strlen(Data)==0) {
                if (pos_sound_flag==0) {
                        strcpy(flag, "disabled", MAX_TEXT_LENGTH);
                } else {
                        strcpy(flag, "enabled", MAX_TEXT_LENGTH);
                }
                snprintf(Text, MAX_TEXT_LENGTH, "Teleporting sound is %s.", flag);
                selfmessage(Text);
                return PLUGIN_HANDLED;
        }
        i = strtonum(Data);
        if (streq(Data, "on")==1 || i==1) {
                pos_sound_flag = 1;
                selfmessage("Teleporting sound enabled.");
        } else if (streq(Data, "off")==1 || i==0) {
                pos_sound_flag = 0;
                selfmessage("Teleporting sound disabled.");
 
        }
        return PLUGIN_HANDLED;
}
 
/*
*       syntax:
*
*       admin_poscopy #user1 #user2             copy personnal position of #user1 (saved by 'saveme') to #user2
*
*/
public admin_poscopy(HLCommand,HLData,HLUserName,UserIndex) {
        new Data[MAX_DATA_LENGTH];
        new strUser1[MAX_DATA_LENGTH];
        new strUser2[MAX_DATA_LENGTH];
        new i;
        new j;
 
        convert_string(HLData,Data,MAX_DATA_LENGTH);
        strbreak(Data,strUser1,strUser2, MAX_DATA_LENGTH);
        if (strlen(strUser2)==0 || strlen(strUser1)==0) {
                selfmessage( "Unparsable format: no user value found.");
                return PLUGIN_HANDLED;
        }
        if (check_user(strUser1)==1 && check_user(strUser2)==1) {
                i = strtonum(strUser1);
                j = strtonum(strUser2);
                if (i==0) {
                        get_userindex(strUser1, i);
                }
                if (j==0) {
                        get_userindex(strUser2, j);
                }
                if (UserX[i]==-1 && UserY[i]==-1 && UserZ[i]==-1) {
                        snprintf(Text, MAX_TEXT_LENGTH, "Failed : position of user %i is not set yet.", i);
                        selfmessage(Text);
                } else {
                        UserX[j] = UserX[i];
                        UserY[j] = UserY[i];
                        UserZ[j] = UserZ[i];
                        snprintf(Text, MAX_TEXT_LENGTH, "Succeeded : copied user %i position to user %i", i, j);
                        selfmessage(Text);
                }
        } else {
                if (check_user(strUser1)!=1) {
                        snprintf(Text, MAX_TEXT_LENGTH, "Unrecognized player : %s", strUser1);
                } else {
                        snprintf(Text, MAX_TEXT_LENGTH, "Unrecognized player : %s", strUser2);
                }
                selfmessage(Text);
        }
        return PLUGIN_HANDLED;
}
 
/*
*       syntax:
*
*       admin_possend #user1 #user2                     send #user1 to #user2 current position (stack on #user2)
*       admin_possend #user1 #user2 Zshift              send #user1 to #user2 current position shifted on Z coord by Zshift
*
*/
public admin_possend(HLCommand,HLData,HLUserName,UserIndex) {
        new Data[MAX_DATA_LENGTH];
        new strUser1[MAX_DATA_LENGTH];
        new strUser2[MAX_DATA_LENGTH];
        new strShift[MAX_DATA_LENGTH];
        new X;
        new Y;
        new Z;
        new shift;
        new i;
        new j;
 
        convert_string(HLData,Data,MAX_DATA_LENGTH);
        strbreak(Data,strUser1,Text, MAX_DATA_LENGTH);
        if (strlen(strUser1)==0 || strlen(Text)==0) {
                selfmessage( "Unparsable format: no user value found.");
                return PLUGIN_HANDLED;
        }
        strbreak(Text,strUser2,strShift,MAX_DATA_LENGTH);
        if (strlen(strShift)==0) {
                shift = 96;
        } else {
                shift = strtonum(strShift);
                if (shift==0) shift = 96;
        }
        if (check_user(strUser1)==1 && check_user(strUser2)==1) {
                i = strtonum(strUser1);
                j = strtonum(strUser2);
                if (i==0) {
                        get_userindex(strUser1, i);
                }
                if (j==0) {
                        get_userindex(strUser2, j);
                }
                if (get_userorigin(strUser2, X,Y,Z)==1) {
                        if (teleport(strUser1,X,Y,Z+shift)==1) {
                                selfmessage("Succeeded.");
                        } else {
                                selfmessage("Failed.");
                        }
                } else {
                        selfmessage("Failed.");
                }
        } else {
                if (check_user(strUser1)!=1) {
                        snprintf(Text, MAX_TEXT_LENGTH, "Unrecognized player : %s", strUser1);
                } else {
                        snprintf(Text, MAX_TEXT_LENGTH, "Unrecognized player : %s", strUser2);
                }
                selfmessage(Text);
        }
        return PLUGIN_HANDLED;
}
 
/*
*       syntax:
*
*       admin_posallow flag             flag: 'on' | 'off' | 0 | 1
*       admin_posallow                  display current teleporting status
*
*/
public admin_posallow(HLCommand,HLData,HLUserName,UserIndex) {
        new Data[MAX_DATA_LENGTH];
        new alow[MAX_DATA_LENGTH];
        new i;
 
        convert_string(HLData,Data,MAX_DATA_LENGTH);
        if (strlen(Data)==0) {
                if (teleport_allowed==0) {
                        strcpy(alow, "disabled", MAX_TEXT_LENGTH);
                } else {
                        strcpy(alow, "enabled", MAX_TEXT_LENGTH);
                }
                snprintf(Text, MAX_TEXT_LENGTH, "Teleporting is %s.", alow);
                selfmessage(Text);
                return PLUGIN_HANDLED;
        }
        i = strtonum(Data);
        if (streq(Data, "on")==1 || i==1) {
                teleport_allowed = 1;
                selfmessage("Teleporting enabled.");
        } else if (streq(Data, "off")==1 || i==0) {
                teleport_allowed = 0;
                selfmessage("Teleporting disabled.");
        }
        return PLUGIN_HANDLED;
}
 
/*
*       syntax:
*
*       admin_posallowuser #user flag           flag: 'on' | 'off' | '0'| '1'
*       admin_posallowuser #user
*       admin_posallowuser
*
*/
public admin_posallowuser(HLCommand,HLData,HLUserName,UserIndex) {
        new Data[MAX_DATA_LENGTH];
        new strUser[MAX_DATA_LENGTH];
        new strFlag[MAX_DATA_LENGTH];
        new userName[MAX_NAME_LENGTH];
        new userIndex;
        new strStatus[2][10] = { "disabled", "enabled" };
 
        convert_string(HLData,Data,MAX_DATA_LENGTH);
        strbreak(Data,strUser,strFlag, MAX_DATA_LENGTH);
        if (strlen(strUser)==0) {
                new i;
                new iMaxPlayers = maxplayercount();
                for (i = 1; i <= iMaxPlayers; i++) {
                        if (playerinfo(i,userName,MAX_NAME_LENGTH) != 0) {
                                snprintf(Text, MAX_TEXT_LENGTH, "%s: %s", userName, strStatus[player_allowed[i-1]]);
                                selfmessage(Text);
                        }
                }
                return PLUGIN_HANDLED;
        }
        if (check_user(strUser)==1) {
                if (get_userindex(strUser, userIndex)) {
                        if (get_username( strUser, userName, MAX_NAME_LENGTH )) {
                                if (strlen(strFlag)==0) {
                                        snprintf(Text,MAX_TEXT_LENGTH,"Player %s: teleporting %s", userName, strStatus[player_allowed[userIndex-1]]);
                                        selfmessage(Text);
                                } else {
                                        new flag = strtonum(strFlag);
 
                                        if (streq(strFlag, "on")==1) {
                                                flag = 1;
                                        } else if (streq(strFlag,"off")==1) {
                                                flag = 0;
                                        }
                                        if (flag!=0 && flag!=1) {
                                                selfmessage("bad argument: flag must be 'on'|1 or 'off'|0");
                                                return PLUGIN_HANDLED;
                                        }
                                        player_allowed[userIndex-1] = flag;
                                        snprintf(Text,MAX_TEXT_LENGTH,"Player %s: teleporting status set to %i", userName, player_allowed[userIndex-1]);
                                        selfmessage(Text);
                                }
                        } else selfmessage("Error: cannot get user name");
                } else selfmessage("Error: cannot get user index");
        } else {
                snprintf(Text, MAX_TEXT_LENGTH, "Unrecognized player : %s", strUser);
                selfmessage(Text);
        }
        return PLUGIN_HANDLED;
}
 
/*
*       syntax:
*
*       admin_posempty                  empty positions list
*
*/
public admin_posempty(HLCommand,HLData,HLUserName,UserIndex) {
        new i;
 
        for (i=0; i<MAX_PLAYERS; i++) {
                UserX[i] = -1;
                UserY[i] = -1;
                UserZ[i] = -1;
        }
        for (i=0; i<NUMSLOTS; i++) {
                snprintf(SlotName[i], MAX_TEXT_LENGTH, "pos%i", i+1);
                SlotX[i] = -1;
                SlotY[i] = -1;
                SlotZ[i] = -1;
        }
        selfmessage("The list is now empty.");
        return PLUGIN_HANDLED;
}
 
/*
*       syntax:
*
*       admin_posadd #user              add #user position to list
*       admin_posadd                    add commanduser position to list
*
*/
public admin_posadd(HLCommand,HLData,HLUserName,UserIndex) {
        new strUser[MAX_DATA_LENGTH];
        new i;
        new X;
        new Y;
        new Z;
 
        convert_string(HLData,strUser,MAX_DATA_LENGTH);
        if (strlen(strUser)==0) {
                strcpy(strUser, "1", MAX_TEXT_LENGTH);
        }
 
        if (check_user(strUser)==1) {
                if (get_userorigin(strUser, X,Y,Z)==1) {
                        for (i=0; i<NUMSLOTS; i++) {
                                if (SlotX[i]==-1 && SlotY[i]==-1 && SlotZ[i]==-1) {
                                        SlotX[i] = X;
                                        SlotY[i] = Y;
                                        SlotZ[i] = Z;
                                        snprintf(Text, MAX_TEXT_LENGTH, "Success : player %s position added in slot #%i", strUser, i+1);
                                        selfmessage(Text);
                                        return PLUGIN_HANDLED;
                                }
                        }
                        selfmessage("No more slot available.");
                } else {
                        selfmessage("Failed.");
                }
        } else {
                snprintf(Text, MAX_TEXT_LENGTH, "Unrecognized player : %s", strUser);
                selfmessage(Text);
        }
        return PLUGIN_HANDLED;
}
 
/*
*       syntax:
*
*       admin_posmem #user #slot        memorize #user position in #slot
*
*/
public admin_posmem(HLCommand,HLData,HLUserName,UserIndex) {
        new Data[MAX_DATA_LENGTH];
        new User[MAX_DATA_LENGTH];
 
        new i;
        new strSlot[MAX_DATA_LENGTH];
        new strUser[MAX_DATA_LENGTH];
 
        new X;
        new Y;
        new Z;
 
        convert_string(HLData,Data,MAX_DATA_LENGTH);
        convert_string(HLUserName,User,MAX_DATA_LENGTH);
 
 
        strbreak(Data,strUser,strSlot, MAX_DATA_LENGTH);
        if(strlen(strSlot)==0) {
                selfmessage( "Unparsable format: no slot value found.");
                return PLUGIN_HANDLED;
        }
        i = strtonum(strSlot);
 
        // slots number are [1-NUMSLOTS] in commands.
        if (i<1 || i>NUMSLOTS) {
                snprintf(Text, MAX_TEXT_LENGTH, "Bad Slot Number: %s", strSlot);
                selfmessage(Text);
                return PLUGIN_HANDLED;
        }
 
        // slots numbers are [0 - NUMSLOTS-1] in intern.
        --i;
 
        if (check_user(strUser)==1) {
                if (get_userorigin(strUser, X,Y,Z)==1) {
                        SlotX[i] = X;
                        SlotY[i] = Y;
                        SlotZ[i] = Z;
                        snprintf(Text, MAX_TEXT_LENGTH, "Success : player %s position set in slot #%i", strUser, i+1);
                        selfmessage(Text);
                } else {
                        selfmessage("Failed.");
                }
        } else {
                snprintf(Text, MAX_TEXT_LENGTH, "Unrecognized player : %s", strUser);
                selfmessage(Text);
        }
        return PLUGIN_HANDLED;
}
 
/*
*       syntax:
*
*       admin_posname <#slot> <name>    name the slot number #slot
*       admin_posname <#slot>           unname the slot #slot (back to name 'posxx' where xx is the slot number)
*
*/
public admin_posname(HLCommand,HLData,HLUserName,UserIndex) {
        new Data[MAX_DATA_LENGTH];
        new strSlot[MAX_TEXT_LENGTH];
        new strName[MAX_TEXT_LENGTH];
        new i;
        new noname = 0;
 
        convert_string(HLData,Data,MAX_DATA_LENGTH);
        strbreak(Data,strSlot,strName, MAX_DATA_LENGTH);
 
        if (strlen(strName)==0) {
                noname = 1;
        }
        if (strlen(strSlot)==0) {
                selfmessage( "Unparsable format: no slot value found.");
                return PLUGIN_HANDLED;
        }
        i = strtonum(strSlot);
        if (i<1 || i>NUMSLOTS) {
                snprintf(Text, MAX_TEXT_LENGTH, "Bad Slot Number: %s", strSlot);
                selfmessage(Text);
                return PLUGIN_HANDLED;
        }
        if (noname==1) {
                snprintf(strName, MAX_TEXT_LENGTH, "pos%i", i);
        } else {
                strcpy(SlotName[i-1], strName, MAX_TEXT_LENGTH);
        }
        selfmessage("Succeeded.");
        return PLUGIN_HANDLED;
}
 
/*
*       syntax:
*
*       admin_pos #user #slot   teleport #user at position from #slot
*       admin_pos #user slotname teleport #user at position named slotname
*       admin_pos #user         teleport #user at position from last slot
*       admin_pos                       teleport commanduser at position from last slot
*
*/
public admin_pos(HLCommand,HLData,HLUserName,UserIndex) {
        new Data[MAX_DATA_LENGTH];
        new User[MAX_DATA_LENGTH];
 
        new i = -1;
        new strSlot[MAX_DATA_LENGTH];
        new strUser[MAX_DATA_LENGTH];
 
        convert_string(HLData,Data,MAX_DATA_LENGTH);
        convert_string(HLUserName,User,MAX_DATA_LENGTH);
 
        strbreak(Data,strUser,strSlot, MAX_DATA_LENGTH);
        strstripquotes(strSlot);
        strstripquotes(strUser);
 
        if(strlen(strSlot)==0) {
                for (i=NUMSLOTS; i; i--) {
                        if (!(SlotX[i-1]==-1 && SlotY[i-1]==-1 && SlotZ[i-1]==-1)) {
                                break;
                        }
                }
                if (i==-1) {
                        selfmessage( "No slot so far.");
                        return PLUGIN_HANDLED;
                }
        } else {
                i = strtonum(strSlot);
        }
 
        // slots number are [1-NUMSLOTS] in commands.
        if (i==0) {
                if (streq(strSlot, "0")==1) {
                        snprintf(Text, MAX_TEXT_LENGTH, "Bad Slot Number: %s", strSlot);
                        selfmessage(Text);
                        return PLUGIN_HANDLED;
                }
                // maybe a slot name
                for (i=0; i<NUMSLOTS; i++) {
                        if (streq(strSlot, SlotName[i])==1) {
                                i++;
                                break;
                        }
                }
        }
        if (i>NUMSLOTS) {
                snprintf(Text, MAX_TEXT_LENGTH, "Bad Slot Number or Unknown Slot: %s", strSlot);
                selfmessage(Text);
                return PLUGIN_HANDLED;
        }
 
        // slots numbers are [0 - NUMSLOTS-1] in intern.
        --i;
 
        if (SlotX[i]==-1 && SlotY[i]==-1 && SlotZ[i]==-1) {
                snprintf(Text, MAX_TEXT_LENGTH, "Unitialized Slot : %s", strSlot);
                selfmessage(Text);
                return PLUGIN_HANDLED;
        }
 
        if (strlen(strUser)==0) {
                strcpy(strUser, User, MAX_TEXT_LENGTH);
        }
        if (check_user(strUser)==1) {
                if (teleport(strUser,SlotX[i],SlotY[i],SlotZ[i])==1) {
                        selfmessage("Succeeded.");
                } else {
                        selfmessage("Failed.");
                }
        } else {
                snprintf(Text, MAX_TEXT_LENGTH, "Unrecognized player : %s", strUser);
                selfmessage(Text);
        }
 
        return PLUGIN_HANDLED;
}
 
/*
*       syntax:
*
*       admin_poslist           display the list
*
*/
public admin_poslist(HLCommand,HLData,HLUserName,UserIndex) {
        new i;
        new n = 0;
 
        for (i=0; i<NUMSLOTS; i++) {
                if (!(SlotX[i]==-1 && SlotY[i]==-1 && SlotZ[i]==-1)) {
                        n++;
                        snprintf(Text, MAX_TEXT_LENGTH, "Slot %i: X %i, Y %i, Z %i ; %s", i+1, SlotX[i], SlotY[i], SlotZ[i], SlotName[i]);
                        selfmessage(Text);
                }
        }
        if (n==0) {
                selfmessage("The list is empty.");
        }
        return PLUGIN_HANDLED;
}
 
/*
*       syntax:
*
*       admin_possave file      save the list in file
*       admin_possave           save the list in defaultfile ('pos/map_name.pos')
*
*/
public admin_possave(HLCommand,HLData,HLUserName,UserIndex) {
        new filename[MAX_TEXT_LENGTH];
        new map[MAX_TEXT_LENGTH];
        new i;
 
        convert_string(HLData,filename,MAX_TEXT_LENGTH);
        if(strlen(filename)==0) {
                currentmap(map,MAX_NAME_LENGTH);
                snprintf(filename, MAX_TEXT_LENGTH, "pos/%s.pos", map);
        }
        for (i=0; i<NUMSLOTS; i++) {
                snprintf(Text, MAX_TEXT_LENGTH, "%i %i %i %s", SlotX[i], SlotY[i], SlotZ[i], SlotName[i]);
                if (writefile(filename, Text, i+1)!=1) {
                        selfmessage("Error writing file.");
                        return PLUGIN_HANDLED;
                }
        }
        snprintf(Text, MAX_TEXT_LENGTH, "Succeded - saved to file %s.", filename);
        selfmessage(Text);
        return PLUGIN_HANDLED;
}
 
/*
*       syntax:
*
*       admin_posload file      load the list from file
*       admin_posload           load the list from defaultfile ('pos/map_name.pos')
*
*/
public admin_posload(HLCommand,HLData,HLUserName,UserIndex) {
        new filename[MAX_TEXT_LENGTH];
        new map[MAX_TEXT_LENGTH];
        new i;
        new strX[MAX_NUMBER_LENGTH];
        new strY[MAX_NUMBER_LENGTH];
        new strZ[MAX_NUMBER_LENGTH];
 
        convert_string(HLData,filename,MAX_TEXT_LENGTH);
        if(strlen(filename)==0) {
                currentmap(map,MAX_NAME_LENGTH);
                snprintf(filename, MAX_TEXT_LENGTH, "pos/%s.pos", map);
        }
        if (fileexists(filename)==1) {
                for (i=0; i<NUMSLOTS; i++) {
                        if (readfile( filename, Text, i+1, MAX_TEXT_LENGTH)==1) {
                                strgsep(Text, " ", "^"", strX, MAX_NUMBER_LENGTH, strY, MAX_NUMBER_LENGTH, strZ, MAX_NUMBER_LENGTH, SlotName[i], MAX_TEXT_LENGTH);
                                SlotX[i] = strtonum(strX);
                                SlotY[i] = strtonum(strY);
                                SlotZ[i] = strtonum(strZ);
                        } else {
                                snprintf(Text, MAX_TEXT_LENGTH, "Error reading file: %s, line %d.", filename, i+1);
                                selfmessage(Text);
                                return PLUGIN_HANDLED;
                        }
                }
                snprintf(Text, MAX_TEXT_LENGTH, "Succeeded - Loading from file %s.", filename);
                selfmessage(Text);
        } else {
                selfmessage("Unknown file.");
        }
        return PLUGIN_HANDLED;
}
 
PlayerAllowedToSave(User[], UserIndex)
{
        new UserID;
        new WonID;
        new Team;
        new Dead;
 
        if (teleport_allowed==0) {
                messageex(User, "Teleporting currently not allowed.", print_chat);
                return 0;
        }
        if (player_allowed[UserIndex-1]==0) {
                messageex(User, "You are not allowed to teleport.", print_chat);
                return 0;
        }
        // only players with access ACCESS_TELEPORT can save position while spectator/dead.
        playerinfo(UserIndex, User, MAX_NAME_LENGTH, UserID, WonID, Team, Dead);
        if (Team==0 || Dead==1) {
                if (access(ACCESS_TELEPORT, User) == 0) {
                        messageex(User, "You cannot save while being spectator or dead, sorry!", print_chat);
                        return 0;
                }
        }
        return 1;
}
 
PlayerAllowedToPos(User[], UserIndex)
{
        if (teleport_allowed==0) {
                messageex(User, "Teleporting not allowed now.", print_chat);
                return 0;
        }
        if (player_allowed[UserIndex-1]==0) {
                messageex(User, "You are not allowed to teleport.", print_chat);
                return 0;
        }
 
        if (PosDelayStatus == 0)
        return 1;
 
        if (access(ACCESS_TELEPORT, User) == 0) {
                new CurTime;
                new SecsAgo;
 
                CurTime = systemtime();
 
                if (LastTime[UserIndex-1] == 0) {
                        LastTime[UserIndex-1] = CurTime;
                        return 1;
                }
 
                SecsAgo = CurTime - LastTime[UserIndex-1];
 
                if (SecsAgo < PosDelay) {
                        snprintf(Text, MAX_TEXT_LENGTH, "You are not allowed to teleport yet: %d seconds remaining...", PosDelay-SecsAgo);
                        messageex(User, Text, print_chat);
                        return 0;
                } else {
                        LastTime[UserIndex-1] = CurTime;
                }
        }
        return 1;
}
 
/*
*       syntax:
*
*       admin_posdelay          get the delay status and value
*       admin_posdelay 0        set delay status OFF
*       admin_posdelay secs     set delay status ON and value in seconds
*
*/
public admin_posdelay(HLCommand,HLData,HLUserName,UserIndex) {
        new Data[MAX_DATA_LENGTH];
        new delay;
 
        convert_string(HLData,Data,MAX_DATA_LENGTH);
        if (strlen(Data) == 0) {
                if (PosDelayStatus==0) {
                        selfmessage("Posme delay is disabled.");
                } else {
                        snprintf(Text,MAX_TEXT_LENGTH,"Posme delay is enabled and set to %d seconds.", PosDelay);
                        selfmessage(Text);
                }
                return PLUGIN_HANDLED;
        }
        delay = strtonum(Data);
        if (delay == 0) {
                PosDelayStatus = 0;
                selfmessage("Posme delay is now disabled.");
        } else {
                PosDelayStatus = 1;
                PosDelay = delay;
                snprintf(Text,MAX_TEXT_LENGTH,"Posme delay is now enabled and set to %d seconds.", delay);
                selfmessage(Text);
        }
        return PLUGIN_HANDLED;
}
 
/*
 *	syntax:
 *
 *	admin_posinfo
 *
 */
public admin_posinfo(HLCommand,HLData,HLUserName,UserIndex) {
        new X;
        new Y;
        new Z;
        new User[MAX_NAME_LENGTH];
 
        convert_string(HLUserName,User,MAX_NAME_LENGTH);
        if (get_userorigin(User, X,Y,Z)==1) {
		snprintf(Text,MAX_TEXT_LENGTH, "Your position is: X = %d, Y = %d, Z = %d.", X, Y, Z);
	        messageex(User, Text, print_chat);
	}
}
 
public plugin_connect(HLUserName, HLIP, UserIndex) {
        if (UserIndex >= 1 && UserIndex <= MAX_PLAYERS) {
                player_allowed[UserIndex-1] = 1;
                LastTime[UserIndex-1] = 0;
                destuck_count[UserIndex] = 0;
        }
 
        return PLUGIN_CONTINUE;
 
}
 
public plugin_disconnect(HLUserName, UserIndex)
{
        if (UserIndex >= 1 && UserIndex <= MAX_PLAYERS)
        destuck_count[UserIndex] = 0;
        return PLUGIN_CONTINUE;
}
 
/*
*       syntax:
*
*       say saveme                      save commanduser position 1
*       say saveme2                     save commanduser position 2
*       say posme                       teleport commanduser to 1st saved position
*       say posme2                      teleport commanduser to 2nd saved position
*       say destuckme                   un-stuck player by offseting the height
*       say poshelp                     display a help message
*
*       for these commands to work, teleporting must be allowed by admin_posallow and admin_posallowuser.
*/
public HandleSay(HLCommand,HLData,HLUserName,UserIndex) {
        new X;
        new Y;
        new Z;
        new Data[MAX_DATA_LENGTH];
        new User[MAX_NAME_LENGTH];
 
        if (UserIndex < 1 || UserIndex >= MAX_PLAYERS)
        return PLUGIN_CONTINUE;
 
        convert_string(HLData,Data,MAX_DATA_LENGTH);
        convert_string(HLUserName,User,MAX_NAME_LENGTH);
        strstripquotes(Data);
 
        if (streq(Data, "poshelp")==1 && teleport_allowed!=0) {
                messageex(User, "Teleporting commands by Bahrmanou:", print_chat);
                messageex(User, "say saveme or /s   : save your current position.", print_chat);
                messageex(User, "say posme or /p    : teleport you at your saved position.", print_chat);
                messageex(User, "say destuckme or /d: offset your height position a bit when you are stuck.", print_chat);
                messageex(User, "say poshelp   : display this help message.", print_chat);
                messageex(User, "*** DON'T SAVE ON A SLOPE OR YOU'LL GET STUCK!! ***",print_chat);
                return PLUGIN_HANDLED;
        }
        if (streq(Data, "saveme2")==1) {
                if (PlayerAllowedToSave(User,UserIndex)==0)
                return PLUGIN_CONTINUE;
                if (get_userorigin(User, X,Y,Z)==1) {
                        UserX2[UserIndex] = X;
                        UserY2[UserIndex] = Y;
                        UserZ2[UserIndex] = Z;
                        pos_play_sound(User, 1);
                        messageex(User, "Your second position has been saved.", print_chat);
                } else {
                        messageex(User,"Saving failed.", print_chat);
                }
                return PLUGIN_HANDLED;
        } else if (streq(Data, "saveme")==1 || streq(Data, "/s")==1) {
                if (PlayerAllowedToSave(User,UserIndex)==0)
                return PLUGIN_CONTINUE;
                if (get_userorigin(User, X,Y,Z)==1) {
                        UserX[UserIndex] = X;
                        UserY[UserIndex] = Y;
                        UserZ[UserIndex] = Z;
                        pos_play_sound(User, 1);
                        messageex(User, "Your position has been saved.", print_chat);
                } else {
                        messageex(User,"Saving failed.", print_chat);
                }
                return PLUGIN_HANDLED;
        } else if (streq(Data, "posme2")==1) {
                if (PlayerAllowedToPos(User,UserIndex)==0)
                return PLUGIN_CONTINUE;
                if (UserX2[UserIndex]!=-1 || UserY2[UserIndex]!=-1 || UserZ2[UserIndex]!=-1) {
                        if (teleport(User,UserX2[UserIndex],UserY2[UserIndex],UserZ2[UserIndex])==1) {
                                pos_play_sound(User, 0);
                                messageex(User, "Teleporting succeeded.", print_chat);
                        } else {
                                messageex(User, "Teleporting failed.", print_chat);
                        }
                } else {
                        messageex(User, "Your position was not saved before.", print_chat);
                }
                return PLUGIN_HANDLED;
        } else if (streq(Data, "posme")==1 || streq(Data, "/p")==1) {
                if (PlayerAllowedToPos(User,UserIndex)==0)
                return PLUGIN_CONTINUE;
                if (UserX[UserIndex]!=-1 || UserY[UserIndex]!=-1 || UserZ[UserIndex]!=-1) {
                        if (teleport(User,UserX[UserIndex],UserY[UserIndex],UserZ[UserIndex])==1) {
                                pos_play_sound(User, 0);
                                messageex(User, "Teleporting succeeded.", print_chat);
                        } else {
                                messageex(User, "Teleporting failed.", print_chat);
                        }
                } else {
                        messageex(User, "Your position was not saved before.", print_chat);
                }
                return PLUGIN_HANDLED;
        } else if (streq(Data, "destuckme")==1 || streq(Data, "/d")==1) {
                if (teleport_allowed==0) {
                        messageex(User, "Teleporting not allowed now.", print_chat);
                        return PLUGIN_CONTINUE;
                }
                if (player_allowed[UserIndex-1]==0) {
                        messageex(User, "You are not allowed to teleport.", print_chat);
                        return PLUGIN_CONTINUE;
                }
                if (get_userorigin(User, X,Y,Z)==1) {
                        if (destuck_count[UserIndex]==0) {
                                destuck_pos[0][UserIndex] = X;
                                destuck_pos[1][UserIndex] = Y;
                                destuck_pos[2][UserIndex] = Z;
                                destuck_count[UserIndex] = 1;
                        } else {
                                if (X == destuck_pos[0][UserIndex] && Y == destuck_pos[1][UserIndex]) {
                                        if (destuck_count[UserIndex] == 3) {
                                                teleport(User, destuck_pos[0][UserIndex], destuck_pos[1][UserIndex], destuck_pos[2][UserIndex]);
                                                messageex(User, "Max three destuckme at same position please!", print_chat);
                                                destuck_count[UserIndex] = destuck_count[UserIndex] + 1;
                                                return PLUGIN_HANDLED;
                                        } else if (destuck_count[UserIndex] == 4) {
                                                messageex(User, dest_sent[random(NUM_DEST_SENT)], print_chat);
                                                return PLUGIN_HANDLED;
                                        }
                                        destuck_count[UserIndex] = destuck_count[UserIndex] + 1;
                                } else {
                                        destuck_pos[0][UserIndex] = X;
                                        destuck_pos[1][UserIndex] = Y;
                                        destuck_pos[2][UserIndex] = Z;
                                        destuck_count[UserIndex] = 1;
                                }
                        }
                        if (teleport(User, X, Y, Z+DESTUCK_OFFSET)==1) {
                                pos_play_sound(User, 2);
                                messageex(User, "Teleporting succeeded.", print_chat);
                        } else {
                                messageex(User, "Teleporting failed.", print_chat);
                        }
                } else {
                        messageex(User, "Failed.", print_chat);
                }
                return PLUGIN_HANDLED;
        }
 
        return PLUGIN_CONTINUE;
}
 
public read_mapcfg() {
	new Text[MAX_TEXT_LENGTH];
	new map[100], mappath[100] = "maps/";
	new Line = 0;
	new valuestr[2];
 
	currentmap(map,100);
	strcat(mappath, map, 100);
	strcat(mappath, ".cfg", 100);
	if (fileexists(mappath)) {
		while ( readfile(mappath, Text, Line++, MAX_TEXT_LENGTH) ) {
			if ( strncasecmp(Text, "teleport_allowed", 16)==0 ) {
				if ( strtok(Text, " ", valuestr, 1)!=-1 ) {
					if (valuestr[0]=='1') {
						teleport_allowed = 1;
						snprintf(Text, MAX_TEXT_LENGTH, "plugin_teleport: teleporting ON from file '%s'.", mappath);
						log(Text);
					} else {
						teleport_allowed = 0;
						snprintf(Text, MAX_TEXT_LENGTH, "plugin_teleport: teleporting OFF from file '%s'.", mappath);
						log(Text);
					}
				}
			}
		}
	} else {
		snprintf(Text, MAX_TEXT_LENGTH, "plugin_teleport: map config file '%s' not found, teleporting is ON by default.", mappath);
		log(Text);
	}
}
 
public plugin_init() {
        plugin_registerinfo("Admin additionnal teleporting plugin","Better and easier teleporting functions.",STRING_VERSION);
 
        plugin_registercmd("admin_posallow","admin_posallow",ACCESS_TELEPORT,"admin_posallow ['on'|'off']: Teleport - Allow/disallow teleporting.");
        plugin_registercmd("admin_posallowuser","admin_posallowuser",ACCESS_TELEPORT,"admin_posallowuser <target> ['on'|'off']: Teleport - Allow/disallow teleporting for target.");
        plugin_registercmd("admin_posempty","admin_posempty",ACCESS_TELEPORT,"admin_posempty: Teleport - Remove all positions in list.");
        plugin_registercmd("admin_posadd","admin_posadd",ACCESS_TELEPORT,"admin_posadd [target]: Teleport - Add target position in first free slot.");
        plugin_registercmd("admin_posmem","admin_posmem",ACCESS_TELEPORT,"admin_posmem <target> <Slot_num>: Teleport - Memorize target position in a slot.");
        plugin_registercmd("admin_pos","admin_pos",ACCESS_TELEPORT,"admin_pos <target> <Slot_num | Slot_name>: Teleport - Teleport target from a Slot.");
        plugin_registercmd("admin_poslist","admin_poslist",ACCESS_TELEPORT,"admin_poslist: Teleport - Display memorised positions.");
        plugin_registercmd("admin_posload","admin_posload",ACCESS_TELEPORT,"admin_posload [file]: Teleport - Load positions from file.");
        plugin_registercmd("admin_possave","admin_possave",ACCESS_TELEPORT,"admin_possave [file]: Teleport - Save positions to file.");
        plugin_registercmd("admin_posname","admin_posname",ACCESS_TELEPORT,"admin_posname <Slot_num> [Slot_Name]: Teleport - Name or unname a slot.");
        plugin_registercmd("admin_poscopy","admin_poscopy",ACCESS_TELEPORT,"admin_poscopy <user> <target>: Teleport - Copy the user position to target.");
        plugin_registercmd("admin_possend","admin_possend",ACCESS_TELEPORT,"admin_possend <user> <target>: Teleport - Stack user on target.");
        plugin_registercmd("admin_possound","admin_possound",ACCESS_TELEPORT,"admin_possound ['on'|'off']: Teleport - Allow/disallow teleport sound.");
        plugin_registercmd("admin_posdelay","admin_posdelay",ACCESS_TELEPORT,"admin_posdelay [delay]: Teleport - Set a delay between 2 posme (0 = OFF).");
        plugin_registercmd("admin_posinfo","admin_posinfo",ACCESS_TELEPORT,"admin_posinfo: Teleport - Display the current position coordinates.");
        plugin_registercmd("say","HandleSay",ACCESS_ALL);
        plugin_registerhelp("say",ACCESS_ALL,"say saveme: Teleport - Save your first current position.");
        plugin_registerhelp("say",ACCESS_ALL,"say saveme2: Teleport - Save your second current position.");
        plugin_registerhelp("say",ACCESS_ALL,"say posme: Teleport - Teleport you at your first saved position.");
        plugin_registerhelp("say",ACCESS_ALL,"say posme2: Teleport - Teleport you at your second saved position.");
        plugin_registerhelp("say",ACCESS_ALL,"say destuckme: Teleport - Offset your height position a bit when you are stuck.");
        plugin_registerhelp("say",ACCESS_ALL,"say poshelp: Teleport - Little reminder display.");
 
        /* empty and load list (if file exists) at map change automatically */
        admin_posempty(0,0,0,0);
        admin_posload(0,0,0,0);
        read_sound_file(SNDCFG_FILE);
 
		read_mapcfg();
 
        return PLUGIN_CONTINUE;
}