/* This plugin will assist in creating name zone files for identifying map locations */ /* $Id: plugin_MapZone.sma,v 1.0.1.6 1/29/03 by Douglas Bliss $ */ #include <core> #include <string> #include <admin> #include <adminlib> new STRING_VERSION[MAX_DATA_LENGTH] = "1.0.1.6 (c) Douglas Bliss"; #define ACCESS_ZONETEAM ACCESS_KICK // Access required to locate team players #define ACCESS_ZONEALL ACCESS_RCON // Access required to locate all players #define ACCESS_ZONEMAP ACCESS_RCON // Access required to edit map files #define INVALID_LINE -1 // Assigned to current line when there is no current zone #define FLOOR_SPACE 25 // Buffer room for floor (bury) #define CEILING_SPACE 100 // Buffer room for ceiling (jumping...) #define WALL_SPACE 5 // Buffer room for wall #define HIGH_Z 9999 // Max altitude value (given to comments during sort) new MapFile[MAX_DATA_LENGTH]; // Name of map file (init'd in CheckMapFile) new Undo[MAX_DATA_LENGTH]; // Undo buffer (for update errors) new UndoLine = INVALID_LINE; // Undo line number new CurrentZone[MAX_DATA_LENGTH]; // Name of current zone new CurrentLine = INVALID_LINE; // Current zone's line number from file new x1,y1,z1,x2,y2,z2; // Current zone's bounds (min x, ... max z) /******************* * Building Blocks * *******************/ // strips a number from a line of text. StripNumber(Data[MAX_TEXT_LENGTH]) { new Temp[MAX_DATA_LENGTH]; strbreak(Data,Temp,Data,0); return strtonum(Temp); } // Returns the minimum z value (for sorting) GetMinZ(DataLine[]) { new Zone[MAX_TEXT_LENGTH]; new Data[MAX_TEXT_LENGTH]; new Temp; if (strncmp(DataLine,"#",1)==0) return HIGH_Z; strbreak(DataLine,Zone,Data,0); Temp = StripNumber(Data); // x1 Temp = StripNumber(Data); // y1 Temp = StripNumber(Data); // z1 return Temp; } // Ensures that the mapfile is set to the correct map and it exists CheckMapFile() { new DataLine[MAX_TEXT_LENGTH]; new MapName[MAX_NAME_LENGTH]; if ((strlen(MapFile)==0) || (fileexists(MapFile)==0)) { currentmap(MapName,MAX_NAME_LENGTH); snprintf(MapFile,MAX_DATA_LENGTH,"MapData/%s.txt",MapName); if(fileexists(MapFile)!=1) { snprintf(DataLine,MAX_TEXT_LENGTH,"# Map Data File for map %s Created by plugin_MapZone, by Douglas Bliss",MapName); writefile(MapFile,DataLine); writefile(MapFile,"# Format: ^"in/at/on location/room^" x1 y1 z1 x2 y2 z2"); writefile(MapFile,"# Rules: x1 < x2, y1 < y2, z1 < z2"); } } return 1; } // Loads a map entry into the current zone. LoadMapEntry(MapLine) { new DataLine[MAX_TEXT_LENGTH]; readfile(MapFile,DataLine,MapLine,MAX_TEXT_LENGTH); if (strncmp(DataLine,"#",1)!=0) { strbreak(DataLine,CurrentZone,DataLine,0); x1 = StripNumber(DataLine); y1 = StripNumber(DataLine); z1 = StripNumber(DataLine); x2 = StripNumber(DataLine); y2 = StripNumber(DataLine); z2 = StripNumber(DataLine); CurrentLine=MapLine; return 1; } return 0; } // Locates existing zone by name FindZoneByName(ZoneName[]) { new DataLine[MAX_TEXT_LENGTH]; new Zone[MAX_TEXT_LENGTH]; for(new i=1;i<=filesize(MapFile);i++) { readfile(MapFile,DataLine,i,MAX_TEXT_LENGTH); if (strncmp(DataLine,"#",1)!=0) { strbreak(DataLine,Zone,DataLine,0); if (strcasecmp(Zone,ZoneName)==0) { return LoadMapEntry(i); } } } return 0; } // Locates existing zone from x,y,z position FindZoneByLoc(x,y,z,MakeCurrent,ZoneName[]) { new DataLine[MAX_TEXT_LENGTH]; new Zone[MAX_TEXT_LENGTH]; new xa,ya,za,xb,yb,zb; for(new i=1;i<=filesize(MapFile,lines);i++) { readfile(MapFile,DataLine,i,MAX_TEXT_LENGTH); if (strncmp(DataLine,"#",1)!=0) { strbreak(DataLine,Zone,DataLine,0); xa = StripNumber(DataLine); ya = StripNumber(DataLine); za = StripNumber(DataLine); xb = StripNumber(DataLine); yb = StripNumber(DataLine); zb = StripNumber(DataLine); if((x>=xa)&&(x<=xb)&&(y>=ya)&&(y<=yb)&&(z>=za)&&(z<=zb)) { strcpy(ZoneName,Zone,MAX_TEXT_LENGTH); if(MakeCurrent==1) { strcpy(CurrentZone,Zone,MAX_TEXT_LENGTH); CurrentLine=i; x1 = xa; y1 = ya; z1 = za; x2 = xb; y2 = yb; z2 = zb; } return 1; } } } strinit(ZoneName); return 0; } // Resets coordinate data for the current zone ResetZone(x,y,z) { new DataLine[MAX_TEXT_LENGTH]; x1 = x - WALL_SPACE; y1 = y - WALL_SPACE; z1 = z - FLOOR_SPACE; x2 = x + WALL_SPACE; y2 = y + WALL_SPACE; z2 = z + CEILING_SPACE; UndoLine = CurrentLine; readfile(MapFile,Undo,UndoLine,MAX_TEXT_LENGTH); snprintf(DataLine,MAX_TEXT_LENGTH,"^"%s^" %i %i %i %i %i %i",CurrentZone,x1,y1,z1,x2,y2,z2); return writefile(MapFile,DataLine,CurrentLine); } // Initialize data for a new Zone InitZone(ZoneName[],x,y,z) { strcpy(CurrentZone,ZoneName,MAX_TEXT_LENGTH); CurrentLine=filesize(MapFile,lines)+1; return ResetZone(x,y,z); } // updates the Current Zone to include position (and writes to file). UpdateZone(x,y,z) { new DataLine[MAX_TEXT_LENGTH]; x1 = min(x1,x - WALL_SPACE); y1 = min(y1,y - WALL_SPACE); z1 = min(z1,z - FLOOR_SPACE); x2 = max(x2,x + WALL_SPACE); y2 = max(y2,y + WALL_SPACE); z2 = max(z2,z + CEILING_SPACE); UndoLine = CurrentLine; readfile(MapFile,Undo,UndoLine,MAX_TEXT_LENGTH); snprintf(DataLine,MAX_TEXT_LENGTH,"^"%s^" %i %i %i %i %i %i",CurrentZone,x1,y1,z1,x2,y2,z2); return writefile(MapFile,DataLine,CurrentLine); } /******************** * Primary Routines * ********************/ // admin_locate <target> // Tells where the target is based on current location and map data. public admin_locate(HLCommand,HLData,HLUserName,UserIndex) { new Text[MAX_TEXT_LENGTH]; new User[MAX_NAME_LENGTH]; new Target[MAX_NAME_LENGTH]; new Zone[MAX_TEXT_LENGTH]; new x,y,z; new iTeam1,iTeam2; new MakeCurrent; CheckMapFile(); convert_string(HLUserName,User,MAX_NAME_LENGTH); convert_string(HLData,Target,MAX_DATA_LENGTH); strstripquotes(Target); if (strlen(Target)==0) strcpy(Target,User,MAX_NAME_LENGTH); MakeCurrent = streq(User,Target); if (check_user(Target)==0) { snprintf(Text,MAX_TEXT_LENGTH,"Error: Unable To Determine Who %s Is.",Target); messageex(User,Text,print_chat); return PLUGIN_HANDLED; } get_userTeam(User,iTeam1); get_userTeam(Target,iTeam2); if ((iTeam1!=iTeam2) && (access(ACCESS_ZONEALL)!=1)) { messageex(User,"Error: You may only locate players on your team.",print_chat); return PLUGIN_HANDLED; } if (get_userorigin(Target,x,y,z)==0) { snprintf(Text,MAX_TEXT_LENGTH,"Error: %s's Location Could Not Be Determined.",Target); } else if (FindZoneByLoc(x,y,z,MakeCurrent,Zone)==1) { if (MakeCurrent==1) { snprintf(Text,MAX_TEXT_LENGTH,"You are %s",Zone); } else { snprintf(Text,MAX_TEXT_LENGTH,"%s is %s",Target,Zone); } } else { snprintf(Text,MAX_TEXT_LENGTH,"Error: %s Is Not In Any Zone In Map File.",Target); } messageex(User,Text,print_chat); return PLUGIN_HANDLED; } // admin_zonecreate <in main blue respawn> // Creates a new zone record (for multiple zones by same name). public admin_zonecreate(HLCommand,HLData,HLUserName,UserIndex) { new Data[MAX_DATA_LENGTH]; new User[MAX_NAME_LENGTH]; new x,y,z; CheckMapFile(); convert_string(HLUserName,User,MAX_NAME_LENGTH); convert_string(HLData,Data,MAX_DATA_LENGTH); strstripquotes(Data); if (get_userorigin(User,x,y,z) == 0) { messageex(User,"Error: Your Location Could Not Be Determined.",print_chat); return PLUGIN_HANDLED; } else if (strlen(Data)>0) { if (InitZone(Data,x,y,z)==1) { messageex(User,"New Zone Initiated.",print_chat); } else { messageex(User,"Error initializing New Zone.",print_chat); } return PLUGIN_HANDLED; } else { messageex(User,"Error: Missing Zone Name.",print_chat); } return PLUGIN_HANDLED; } // admin_zoneupdate <in main blue respawn> // Updates a new or existing zone (blank = previous zone); public admin_zoneupdate(HLCommand,HLData,HLUserName,UserIndex) { new Data[MAX_DATA_LENGTH]; new User[MAX_NAME_LENGTH]; new x,y,z; CheckMapFile(); convert_string(HLUserName,User,MAX_NAME_LENGTH); convert_string(HLData,Data,MAX_DATA_LENGTH); strstripquotes(Data); if (get_userorigin(User,x,y,z) == 0) { messageex(User,"Error: Your Location Could Not Be Determined.",print_chat); return PLUGIN_HANDLED; } else if ((CurrentLine==INVALID_LINE) && (strlen(Data)==0)) { messageex(User,"Error: No Current Or Specified Zone.",print_chat); return PLUGIN_HANDLED; } else if (strlen(Data)>0) { // find specified zone or initialize a new one if (FindZoneByName(Data)!=1) { if (InitZone(Data,x,y,z)==1) { messageex(User,"New Zone Initiated.",print_chat); } else { messageex(User,"Error Initializing New Zone.",print_chat); } return PLUGIN_HANDLED; } } // Update existing zone data if (UpdateZone(x,y,z)==1) { messageex(User,"Zone Updated.",print_chat); } else { messageex(User,"Error Updating Zone.",print_chat); } return PLUGIN_HANDLED; } // admin_zonereset <in main blue respawn> // Resets an existing zone to current location only (blank = previous zone); public admin_zonereset(HLCommand,HLData,HLUserName,UserIndex) { new Data[MAX_DATA_LENGTH]; new User[MAX_NAME_LENGTH]; new x,y,z; CheckMapFile(); convert_string(HLUserName,User,MAX_NAME_LENGTH); convert_string(HLData,Data,MAX_DATA_LENGTH); strstripquotes(Data); if (get_userorigin(User,x,y,z) == 0) { messageex(User,"Error: Your Location Could Not Be Determined.",print_chat); return PLUGIN_HANDLED; } else if ((CurrentLine==INVALID_LINE) && (strlen(Data)==0)) { messageex(User,"Error: No Current Or Specified Zone.",print_chat); return PLUGIN_HANDLED; } else if (strlen(Data)>0) { // find specified zone or initialize a new one if (FindZoneByName(Data)!=1) { messageex(User,"Error: Zone Not Found.",print_chat); return PLUGIN_HANDLED; } } // Reset existing zone data if (ResetZone(x,y,z)==1) { messageex(User,"Zone Reset.",print_chat); } else { messageex(User,"Error Reseting Zone.",print_chat); } return PLUGIN_HANDLED; } // admin_zoneundo // Undoes the last update command public admin_zoneundo(HLCommand,HLData,HLUserName,UserIndex) { new User[MAX_NAME_LENGTH]; CheckMapFile(); convert_string(HLUserName,User,MAX_NAME_LENGTH); if (UndoLine==INVALID_LINE) { messageex(User,"Error: No undo available.",print_chat); } else if (writefile(MapFile,Undo,UndoLine)==1) { UndoLine = INVALID_LINE; messageex(User,"Undo Complete.",print_chat); } else { messageex(User,"Error: Unable To Undo.",print_chat); } return PLUGIN_HANDLED; } // admin_zonesort // Sorts map file to remove elevation conflicts (also clears current zone). public admin_zonesort(HLCommand,HLData,HLUserName,UserIndex) { new User[MAX_NAME_LENGTH]; new DataLineI[MAX_TEXT_LENGTH]; new DataLineJ[MAX_TEXT_LENGTH]; new zI,zJ; new i,j,iMax; convert_string(HLUserName,User,MAX_NAME_LENGTH); CheckMapFile(); iMax = filesize(MapFile,lines); // Not the most efficient sort, but we should be dealing with a small number of entries for (i=1;i<iMax;i++) { readfile(MapFile,DataLineI,i,MAX_TEXT_LENGTH); zI = GetMinZ(DataLineI); if (zI < HIGH_Z) { for (j=i+1;j<=iMax;j++) { readfile(MapFile,DataLineJ,j,MAX_TEXT_LENGTH); zJ = GetMinZ(DataLineJ); if (zJ > zI) { writefile(MapFile,DataLineI,j); writefile(MapFile,DataLineJ,i); // Only need to retain DataLineJ as DataLineI now... strcpy(DataLineI,DataLineJ,MAX_TEXT_LENGTH); zI = zJ; } } } } messageex(User,"Sort Completed.",print_chat); UndoLine = INVALID_LINE; CurrentLine = INVALID_LINE; } /******************** * Admin Mod Plugin * ********************/ public plugin_init() { plugin_registerinfo("DougWare Map Zones","Creates map zone/location files.",STRING_VERSION); plugin_registercmd("admin_locate","admin_locate",ACCESS_ZONETEAM,"admin_locate <target>: Tells where the target is based on current location (target optional)."); plugin_registercmd("admin_zonecreate","admin_zonecreate",ACCESS_ZONEMAP,"admin_zonecreate <zone name>: Initializes a new zone even if name matches an existing zone."); plugin_registercmd("admin_zoneupdate","admin_zoneupdate",ACCESS_ZONEMAP,"admin_zoneupdate <zone name>: Updates an existing zone or initializes a new zone (name optional)."); plugin_registercmd("admin_zonereset","admin_zonereset",ACCESS_ZONEMAP,"admin_zonereset <zone name>: Resets an existing zone to current location only (blank = previous zone)."); plugin_registercmd("admin_zoneundo","admin_zoneundo",ACCESS_ZONEMAP,"admin_zoneundo: Undoes the last update command."); plugin_registercmd("admin_zonesort","admin_zonesort",ACCESS_ZONEMAP,"admin_zonesort: Sorts map file to remove elevation conflicts (also clears current zone)."); // also register commands for "admin_help plugin_mapzone" plugin_registerhelp("plugin_mapzone",ACCESS_ZONETEAM,"admin_locate <target>: Tells where the target is based on current location (target optional)."); plugin_registerhelp("plugin_mapzone",ACCESS_ZONEMAP,"admin_zonecreate <zone name>: Initializes a new zone even if name matches an existing zone."); plugin_registerhelp("plugin_mapzone",ACCESS_ZONEMAP,"admin_zoneupdate <zone name>: Updates an existing zone or initializes a new zone (name optional)."); plugin_registerhelp("plugin_mapzone",ACCESS_ZONEMAP,"admin_zonereset <zone name>: Resets an existing zone to current location only (blank = previous zone)."); plugin_registerhelp("plugin_mapzone",ACCESS_ZONEMAP,"admin_zoneundo: Undoes the last update command."); plugin_registerhelp("plugin_mapzone",ACCESS_ZONEMAP,"admin_zonesort: Sorts map file to remove elevation conflicts (also clears current zone)."); return PLUGIN_CONTINUE; }