IshSoul

Untitled

Jan 22nd, 2015
259
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 92.37 KB | None | 0 0
  1. /**************************************************************\
  2. #Title
  3. Pixel Perfect Tile Editor
  4. ScriptExtension for Links by MysticalDragon
  5.  
  6. #Version
  7. 1.4
  8.  
  9. #Features
  10. - Relatively easy setup with simple configuration
  11. - Works with graal file browser rights system
  12. - Scrolls automatically when selecting large portions of the gui
  13. - Open, save, and delete tile clipboard files
  14. - Undo & redo (Note: history is cleared when the editor closes)
  15. - [Toggle] Fade inactive tilelayers
  16. - [Toggle] Level grid to separate tiles
  17. - [Toggle] Extra cursor info
  18. - [Toggle] External window
  19. - Create new levels
  20. - Flood fill
  21. - Can check for updates
  22. - add and remove tilelayers
  23. - More
  24.  
  25. #Installation
  26. 1. Create a new weapon script named -Development/TileEditor or
  27. whatever whatever is pleasing to you
  28. 2. Copy the entire text of this document into the script
  29. 3. Modify the configuration portion of the script to suit your
  30. server best
  31. 4. Give (npcserver) the required rights
  32. By default, this includes:
  33. rw access to TileEditor/Clipboard/ and subfolders,
  34. rw access to levels folders,
  35. rw access to levels/images/tileeditor_icon_1-1.png ,
  36. rw access to levels/images/tileeditor_bucket_1-1.png ,
  37. rw access to levels/images/tileeditor_pencil_1-1.png
  38. 5. Give level designers necessary rights
  39. r and/or w access to TileEditor/Clipboard/ and/or
  40. subfolders,
  41. rw access to level files to use this program on
  42. 6. Add the weapon script to the level designers
  43.  
  44. #Script Interface
  45. - The following clientside public functions are available:
  46. open() - triggers the request to open the editor
  47. close() - triggers the program to close
  48. isOpen() - returns true if the program is open
  49.  
  50. #Directions
  51. Type /te into the chat bar to open the program
  52. Left click to select tiles, right click to paste the selection
  53.  
  54. #Credits
  55. Scripted by Pixel
  56. \**************************************************************/
  57.  
  58. public function onPlayerLogin(pl){
  59. if(ServerOptions.contains("staff_leveleditor",pl.account) || ServerOptions.contains("staff_admin_house",pl.account) || temp.pl.clientr.staff == 4
  60. //Graal772951 = BrentWood
  61. || temp.pl.account in {""}){ //Add non-staff accounts here. I've removed Death_Striker, he no longer needs this. - Exolia
  62.  
  63. temp.pl.addWeapon(this.name);
  64. }
  65. }
  66. /*********************** Configuration ************************/
  67. // Check for updates when the weapon script is initialized?
  68. // (recommended to know when future updates are released)
  69. const TE_CHECK_UPDATE = false;
  70.  
  71. // Must the user be in the serveroptions staff list?
  72. // Set the value to true if you want to restrict the use of the
  73. // program to only staff. Otherwise set the value to false.
  74. const TE_ONLYSTAFF = false;
  75.  
  76. // Must the user have rights to levels and files?
  77. // Set the value to true if you want to secure levels and files
  78. // using the default graal rights system (Strongly recommended).
  79. // Otherwise set the value to false
  80. const TE_NEEDRIGHTS = false;
  81.  
  82. // Where should the clipboard files be stored?
  83. // (recommended to keep this as "TileEditor/Clipboard/")
  84. const TE_DIR_CLIPBOARD = "TileEditor/Clipboard/";
  85.  
  86. // Should the program save images and icons to the server?
  87. // (recommended to keep this as true usually)
  88. const TE_WRITE_IMAGES = true;
  89.  
  90. // Where should the program save it's images and icons?
  91. // This can vary depending on your server's folder options
  92. const TE_DIR_IMAGES = "levels/images/";
  93. /**************************************************************/
  94.  
  95. /******************* Don't Touch Below Here *******************/
  96.  
  97. const TE_VERSION = "1.4.1";
  98.  
  99. // images are stored here as base 64 encoded strings. the images
  100. // are saved to the server onCreated
  101. const TE_ICON_DATA = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAB3RJTUUH3AYDFREoSFzGywAAABd0RVh0U29mdHdhcmUAR0xEUE5HIHZlciAzLjRxhaThAAAACHRwTkdHTEQzAAAAAEqAKR8AAAAEZ0FNQQAAsY8L/GEFAAADAFBMVEUAAACAAAAAgACAgADAwMCAAIAAgIAAAIDA3MCmyvAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/+/CgoKSAgID/AAAA/wD//wAAAP//AP8A//////+6YMT6AAAAAWJLR0T/pQfyxQAAAHBJREFUeJxljjEOgDAMA93AENGJ/z8SMQVaJMghsdCTslh2bE29T0fEYa1ZuId6EklLPBmFf8TmUuZ7Xe+SLPu+6EqwEj2TQbAq1U3aXHJO76N8yGMKhJ1KqomNwj9idLOBLWwSVViJMmEQ7OtnC5sexROSefnyghYAAAAASUVORK5CYII=";
  102. const TE_BUCKET_DATA = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAALISURBVDiNjZNLTFRnFMd/3537fXfuTUZa7IiBMDFprInxURIJ7Uqxm8b4SMowjPiANrG8FHXZaGVRVColJiAkoqs2jQbpgoUFN+7wEcXuuqNJIeMAGkoodx7eufdzYcYQY7UnOavzO/9z8j85QmvNuyKRjFcAvUAtkAXuAOdGbo4+AzDe2f0qLgEZYCewF/gA6C4Wzf8h0AhUSSmv+r4/HgRBG/AcaHnvBolkfA1AyZqS+x3tJ3batt0F2ECoyLxVIJGMGw0H648ppWYArgwMhbdu2SpajrWGpVRDq1nzYMe1DVKZwwXP3wUEgfePDjsfqprqKvF1U7No/uYoqVSK5eVltm3bbsRilV9OT0+/FjCUkn2bNm344vPaHdI2/rIqSubDvRe7jfbWNjEz8zdCGPT8eIH0XJpUKkXn8ZNhwEsk4yaA8eKFd6C6Zotxb2xI7/5ss+45fxHbtvF9n77LP7Hx441UVsYYn7iN67qEwzb79u4PQqFQZ9GDkGUptP2JfvLHVE5rzeLiIq7rYlkWpjSJRCKEQiZSSmZnZ6n7Km45jvNDIhkve22iMEtEOj039vjxIz8SieC6Lp0nTrHirjC/ME/TkSaUUhQHtHzbFlZKDa6+gij4nB6+fjXnOA6e5xH9KMqlnl7OfHeW8vIKlFJIKcnn81R9WmUEQbDHEEIUVv7NAPgjN27M5XK5c6O/3cqXlpbiui75fB6lFEopLMsiFotRVraOwaGBnBBizJDSHPn1l9u+Kc1RgCAI+icmxucy2QxCCDKZDFJKHMchGo0y9WTKb+toXXnw8MFpz/MOobUm2T5crrWmmPUNdbu/7zqTyWazemFhQfu+r5+mn+rOU8ezR5oO/VzfULe2yLK6cXU2Hk7+PnlvMlhaWtJXBvtzR5sP/1nfUFf9Jif+650Tyfh6acq7CEoLhUKX1vrayM3R4E3uJf0eQEfPmPQuAAAAAElFTkSuQmCC";
  103. const TE_PENCIL_DATA = "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";
  104.  
  105. // enumeration of network replies
  106. // this list must match the clientside list exactly. otherwise
  107. // bugs will occur
  108. enum RPL {
  109. NONE,
  110. ERROR,
  111. REQUESTUSE,
  112. PLACETILES,
  113. LISTCLIPBOARDFOLDER,
  114. LOADCLIPBOARDFILE,
  115. SAVECLIPBOARDFILE,
  116. DELETECLIPBOARDFILE,
  117. CREATENEWLEVEL,
  118. UPDATELEVEL,
  119. ADDTILELAYER,
  120. REMOVETILELAYER
  121. }
  122.  
  123. /**
  124. * events
  125. */
  126.  
  127. function onCreated() {
  128. // if configured to check for updates at initialization
  129. // do that
  130. /*if (TE_CHECK_UPDATE) {
  131. temp.req = requesturl("http://forums.graalonline.com/forums/showthread.php?t=134267103");
  132. temp.time = timevar2;
  133. waitfor(temp.req, "onReceiveData", 10);
  134. if (timevar2 - temp.time < 10) {
  135. temp.position = temp.req.fulldata.pos("[VERSION]") + 9;
  136. temp.currentVersionString = temp.req.fulldata.substring(temp.position, temp.req.fulldata.pos("[/VERSION]") - position).trim();
  137. if (TE_VERSION != temp.currentVersionString && temp.currentVersionString != "") {
  138. temp.a = int(TE_VERSION.substring(0, 1) @ TE_VERSION.substring(2, 1) @ TE_VERSION.substring(4, 1));
  139. temp.b = int(temp.currentVersionString.substring(0, 1) @ temp.currentVersionString.substring(2, 1) @ temp.currentVersionString.substring(4, 1));
  140. if (temp.a < temp.b)
  141. TE_echo("A new version is available: " @ temp.currentVersionString);
  142. }
  143. }
  144. }*/
  145. // if the image saving is disabled in the config
  146. // there's no need to continue
  147. if (!TE_WRITE_IMAGES)
  148. return;
  149.  
  150. // check if the icon image is on the server
  151. // if it is not, attempt to write it
  152. temp.filePath = TE_DIR_IMAGES @ "tileeditor_icon_1-1.png";
  153. temp.files.loadfolder(temp.filePath, 0);
  154. if (temp.files.size() == 0) {
  155. temp.data = base64decode(TE_ICON_DATA);
  156. temp.data.savestring(temp.filePath, 0);
  157. temp.files = NULL;
  158. temp.files.loadfolder(temp.filePath, 0);
  159. if (temp.files.size() == 0) {
  160. TE_echo("prob: (npcserver) cannot write the icon image file as" SPC temp.filePath @ ". Ensure that both the configuration and the (npcserver)'s rights are correct");
  161. } else {
  162. TE_echo("icon image saved to" SPC temp.filePath);
  163. }
  164. }
  165.  
  166. // check if the bucket image is on the server
  167. // if it is not, attempt to write it
  168. temp.filePath = TE_DIR_IMAGES @ "tileeditor_bucket_1-1.png";
  169. temp.files.loadfolder(temp.filePath, 0);
  170. if (temp.files.size() == 0) {
  171. temp.data = base64decode(TE_BUCKET_DATA);
  172. temp.data.savestring(temp.filePath, 0);
  173. temp.files = NULL;
  174. temp.files.loadfolder(temp.filePath, 0);
  175. if (temp.files.size() == 0) {
  176. TE_echo("prob: (npcserver) cannot write the bucket image file as" SPC temp.filePath @ ". Ensure that both the configuration and the (npcserver)'s rights are correct");
  177. } else {
  178. TE_echo("bucket image saved to" SPC temp.filePath);
  179. }
  180. }
  181.  
  182. // check if the pencil image is on the server
  183. // if it is not, attempt to write it
  184. temp.filePath = TE_DIR_IMAGES @ "tileeditor_pencil_1-1.png";
  185. temp.files.loadfolder(temp.filePath, 0);
  186. if (temp.files.size() == 0) {
  187. temp.data = base64decode(TE_PENCIL_DATA);
  188. temp.data.savestring(temp.filePath, 0);
  189. temp.files = NULL;
  190. temp.files.loadfolder(temp.filePath, 0);
  191. if (temp.files.size() == 0) {
  192. TE_echo("prob: (npcserver) cannot write the pencil image file as" SPC temp.filePath @ ". Ensure that both the configuration and the (npcserver)'s rights are correct");
  193. } else {
  194. TE_echo("pencil image saved to" SPC temp.filePath);
  195. }
  196. }
  197. }
  198.  
  199. function onActionServerSide() {
  200. //gville = Graal756346
  201. if(player.account in {"Mesh_P2P", "Tim_Rocks"}){
  202. if(!player.level.name.starts("era_gang") && !player.level.name.starts("era_metro") && !player.level.name.starts("era_ghost") && !player.level.name.starts("era_halloween") && !player.level.name.starts("era_metro_headsup")) return;
  203. }
  204. if(player.account in {"bloodwork"}){
  205. if(!player.level.name.starts("era_event"))return;
  206. }
  207. if(player.account in {"Knux"}){
  208. if(!player.level.name.starts("era_event_savesanta") && !player.level.name.starts("era_metro") && !player.level.name.starts("era_house"))return;
  209. }
  210. if(player.account == "FRIEDRICE" && !player.level.name.starts("era_event") && !player.level.name.starts("era_et")&& !player.level.name.starts("era_friedrice-")){ // fried rice
  211. return;
  212. }
  213.  
  214. /*
  215. if (player.level.name.starts("era_present") && player.clientr.staff < 2 && !player.account in {""}) {
  216. return;
  217. }*/
  218.  
  219. // if the script is configured to be staff only
  220. // detect non-staff usage attempts here
  221. if (TE_ONLYSTAFF) {
  222. temp.staffList = serveroptions.staff.lower().tokenize(",");
  223. if (!(player.account.lower() in temp.staffList)
  224. && (player.communityname == ""
  225. || !(player.communityname.lower() in temp.staffList))) {
  226. TE_echo(format("%s tried to use the tile editor, but is not staff", player.account));
  227. return;
  228. }
  229. }
  230.  
  231. replySwitch:
  232. switch (params[0]) {
  233. // when the program is triggered to open
  234. // it triggers the server with the REQUESTUSE reply
  235. // the server returns a "1" or "0"
  236. case RPL.REQUESTUSE: {
  237. if (TE_NEEDRIGHTS) {
  238. if (player.level.name.ends(".gmap")) {
  239. temp.mapPartLevelName = player.level.getmappartfile(player.x, player.y);
  240. temp.allowUse = player.hasright("r", temp.mapPartLevelName);
  241. } else {
  242. temp.allowUse = player.hasright("r", player.level.name);
  243. }
  244. } else {
  245. temp.allowUse = true;
  246. }
  247. player.triggerclient("gui", this.name, RPL.REQUESTUSE, temp.allowUse, TE_VERSION, tilelayercount);
  248. break;
  249. }
  250.  
  251. // determine if the player is allowed to edit the level
  252. // if so, paste the data to the levels tile board
  253. // otherwise, send an ERROR reply
  254. case RPL.PLACETILES: {
  255. if (params[1].size() == 0)
  256. break;
  257. temp.data = params;
  258. temp.dataSize0 = temp.data[1].size();
  259. temp.dataSize1 = temp.data[1][0].size();
  260. maxlooplimit = 1000000;
  261.  
  262. if (TE_NEEDRIGHTS) {
  263. if (player.level.name.ends(".gmap")) {
  264. temp.yMin = int((temp.data[3]) / 64) * 64;
  265. temp.xMin = int((temp.data[2]) / 64) * 64;
  266. temp.yMax = int((temp.data[3] - 1 + temp.dataSize0) / 64) * 64;
  267. temp.xMax = int((temp.data[2] - 1 + temp.dataSize1) / 64) * 64;
  268. player.chat = {temp.xMin, temp.yMin, temp.xMax, temp.yMax};
  269. for (temp.i = temp.yMin; temp.i <= temp.yMax; temp.i += 64) {
  270. for (temp.j = temp.xMin; temp.j <= temp.xMax; temp.j += 64) {
  271. temp.mapPartLevelName = player.level.getmappartfile(temp.j, temp.i);
  272. if (temp.mapPartLevelName != ""
  273. && !player.hasright("w", temp.mapPartLevelName)) {
  274. player.triggerclient("gui", this.name, RPL.ERROR, "You do not have rights to edit" SPC temp.mapPartLevelName);
  275. break replySwitch;
  276. }
  277. }
  278. }
  279. } else {
  280. if (!player.hasright("w", player.level.name)) {
  281. player.triggerclient("gui", this.name, RPL.ERROR, "You do not have rights to edit" SPC player.level.name);
  282. break;
  283. }
  284. }
  285. }
  286.  
  287. for (temp.y = 0; temp.y < temp.dataSize0; temp.y++) {
  288. if (temp.data[4] == 0 && temp.data[1][temp.y].index(-1) != -1) {
  289. do {
  290. temp.ind = temp.data[1][temp.y].index(-1);
  291. temp.data[1][temp.y][temp.ind] = 0;
  292. } while (temp.data[1][temp.y].index(-1) != -1);
  293. }
  294. for (temp.x = 0; temp.x < temp.dataSize1; temp.x++) {
  295. temp.tile = temp.data[1][temp.y][temp.x];
  296. if (temp.tile == -2)
  297. continue;
  298. tilelayers[temp.data[4]].tiles[temp.x + temp.data[2], temp.y + temp.data[3]] = temp.tile;
  299. }
  300. }
  301. tilelayers[temp.data[4]].updateboard2(temp.data[2], temp.data[3], temp.data[1][0].size(), temp.data[1].size());
  302. break;
  303. }
  304.  
  305. // provided the player is allowed to READ the file
  306. // this loads the file data and sends it to the client
  307. case RPL.LOADCLIPBOARDFILE: {
  308. if (!fileExists2(TE_DIR_CLIPBOARD @ params[1]))
  309. break;
  310. temp.obj = {};
  311. temp.obj.loadlines(TE_DIR_CLIPBOARD @ params[1]);
  312. if (temp.obj.size() == 0) {
  313. player.triggerclient("gui", this.name, RPL.ERROR, "The (npcserver) lacks the rights to read the file");
  314. return;
  315. }
  316. player.triggerclient("gui", this.name, RPL.LOADCLIPBOARDFILE, temp.obj, params[1], getfilemodtime(TE_DIR_CLIPBOARD @ params[1]));
  317. break;
  318. }
  319.  
  320. // provided the player is allowed to WRITE the file
  321. // this saves the file data
  322. case RPL.SAVECLIPBOARDFILE: {
  323. temp.fileBase = extractfilebase(params[2]);
  324. if (temp.fileBase == "")
  325. break;
  326. temp.filePath = TE_DIR_CLIPBOARD @ extractfilepath(params[2]);
  327. temp.filePath = temp.filePath @ temp.fileBase @ ".txt";
  328. if (TE_NEEDRIGHTS && !player.hasright("w", temp.filePath)) {
  329. player.triggerclient("gui", this.name, RPL.ERROR, "You do not have rights for" SPC temp.filePath);
  330. return;
  331. }
  332. params[1].savelines(temp.filePath, 0);
  333. temp.files.loadfolder(temp.filePath, 0);
  334. if (temp.files.size() == 0) {
  335. player.triggerclient("gui", this.name, RPL.ERROR, "The (npcserver) lacks the rights to create the file");
  336. return;
  337. }
  338. player.triggerclient("gui", this.name, RPL.SAVECLIPBOARDFILE, temp.filePath);
  339. break;
  340. }
  341.  
  342. // provided the player is allowed to WRITE the file
  343. // this deletes the file
  344. case RPL.DELETECLIPBOARDFILE: {
  345. temp.filePath = TE_DIR_CLIPBOARD @ params[1];
  346. if (TE_NEEDRIGHTS && !player.hasright("w", temp.filePath)) {
  347. player.triggerclient("gui", this.name, RPL.ERROR, "You do not have rights for" SPC temp.filePath);
  348. return;
  349. }
  350. if (!fileExists2(temp.filePath)) {
  351. player.triggerclient("gui", this.name, RPL.ERROR, temp.filePath SPC "does not exist");
  352. return;
  353. }
  354. deletefile(temp.filePath);
  355. temp.files.loadfolder(temp.filePath, 0);
  356. if (temp.files.size() == 1)
  357. player.triggerclient("gui", this.name, RPL.ERROR, "The (npcserver) lacks the rights to delete the file");
  358. }
  359.  
  360. // will read all clipboard files which the player
  361. // is allowed to read, and return the list to the client
  362. case RPL.LISTCLIPBOARDFOLDER: {
  363. temp.obj = {};
  364. temp.obj.loadfolder(TE_DIR_CLIPBOARD @ "*", 1);
  365. if (TE_NEEDRIGHTS) {
  366. temp.list = {};
  367. for (temp.o: temp.obj) {
  368. temp.filePath = TE_DIR_CLIPBOARD @ temp.o;
  369. if (player.hasright("r", temp.filePath))
  370. temp.list.add(temp.o);
  371. }
  372. } else {
  373. temp.list = temp.obj;
  374. }
  375. player.triggerclient("gui", this.name, RPL.LISTCLIPBOARDFOLDER, temp.list);
  376. break;
  377. }
  378.  
  379. // checks for an invalid filename
  380. // if not, reply with ERROR
  381. // checks if the player is allowed to WRITE the file
  382. // if not, reply with ERROR
  383. // checks if the file already exists
  384. // if not, write
  385. // if so, checks if the override parameter is set
  386. // if not, reply with ERROR
  387. // if so, write
  388. case RPL.CREATENEWLEVEL: {
  389. temp.fileBase = extractfileBase(params[1]).lower();
  390. temp.fileExt = extractfileext(params[1]).lower();
  391. if (temp.fileBase == ""
  392. || temp.fileExt != ".nw") {
  393. player.triggerclient("gui", this.name, RPL.ERROR, "Invalid file name");
  394. return;
  395. }
  396. temp.filePath = extractfilepath(params[1]).lower() @ temp.fileBase @ temp.fileExt;
  397. if (TE_NEEDRIGHTS && !player.hasright("w", temp.filePath)) {
  398. player.triggerclient("gui", this.name, RPL.ERROR, "You do not have rights for" SPC temp.filePath);
  399. return;
  400. }
  401. if (fileExists2(temp.filePath) && !params[2]) {
  402. player.triggerclient("gui", this.name, RPL.ERROR, "That file already exists! Type the same thing in again to overwrite");
  403. return;
  404. }
  405. temp.lines = {
  406. "GLEVNW01"
  407. };
  408.  
  409. temp.lines.savelines(temp.filePath, 0);
  410. SourceControl.handleUpdate(player.account, {{"file", temp.filePath}});
  411.  
  412. if (!fileExists2(temp.filePath)) {
  413. player.triggerclient("gui", this.name, RPL.ERROR, "The (npcserver) lacks the rights to create the file");
  414. return;
  415. }
  416. player.triggerclient("gui", this.name, RPL.CREATENEWLEVEL, temp.filePath);
  417. break;
  418. }
  419. case RPL.UPDATELEVEL: {
  420. if (TE_NEEDRIGHTS && !player.hasrightflag("updatelevel")) {
  421. player.triggerclient("gui", this.name, RPL.ERROR, "You do not have the rights to use Update Level");
  422. break;
  423. }
  424. temp.levelName = player.level.name.ends(".gmap") ? player.level.getmappartfile(player.x + 1.5, player.y + 1.5) : player.level.name;
  425. //echo(temp.levelName);
  426.  
  427. temp.levelFilePath = getLevelFilePath(temp.levelName);
  428. temp.filePath = temp.levelFilePath;
  429. //echo(temp.filePath);
  430. temp.hasReadRights = fileexists(temp.filePath);
  431. if (!temp.hasReadRights) {
  432. player.triggerclient("gui", this.name, RPL.ERROR, "The (npcserver) lacks the rights to read" SPC temp.filePath);
  433. break;
  434. }
  435. temp.fileLines = {};
  436. temp.fileLines.loadlines(temp.filePath);
  437. temp.boardLines = getBoardLines(temp.levelName);
  438. temp.fileLines = replaceLinesStartingWith(temp.fileLines, temp.boardLines, "BOARD");
  439. deletefile(temp.filePath);
  440. if (fileExists2(temp.filePath)) {
  441. player.triggerclient("gui", this.name, RPL.ERROR, "The (npcserver) lacks the rights to write" SPC temp.filePath);
  442. break;
  443. }
  444.  
  445. temp.fileLines.savelines(temp.filePath, 0);
  446. SourceControl.handleUpdate(player.account, {{"file", temp.filePath}});
  447.  
  448. player.triggerclient("gui", this.name, RPL.UPDATELEVEL);
  449. break;
  450. }
  451.  
  452. case RPL.ADDTILELAYER: {
  453. temp.levelName = player.level.name.ends(".gmap") ? player.level.getmappartfile(player.x + 1.5, player.y + 1.5) : player.level.name;
  454. if (TE_NEEDRIGHTS && !player.hasright("w", temp.levelName)) {
  455. player.triggerclient("gui", this.name, RPL.ERROR, "You do not have the rights to edit " @ temp.levelName);
  456. break;
  457. }
  458. temp.levelFilePath = getLevelFilePath(temp.levelName);
  459. temp.filePath = temp.levelFilePath;
  460. temp.hasReadRights = fileexists(temp.filePath);
  461. if (!temp.hasReadRights) {
  462. player.triggerclient("gui", this.name, RPL.ERROR, "The (npcserver) lacks the rights to read" SPC temp.filePath);
  463. break;
  464. }
  465. temp.fileLines = {};
  466. temp.fileLines.loadlines(temp.filePath);
  467. temp.boardLines = getBoardLines(temp.levelName, 1);
  468. temp.fileLines = replaceLinesStartingWith(temp.fileLines, temp.boardLines, "BOARD");
  469. deletefile(temp.filePath);
  470. if (fileExists2(temp.filePath)) {
  471. player.triggerclient("gui", this.name, RPL.ERROR, "The (npcserver) lacks the rights to write" SPC temp.filePath);
  472. break;
  473. }
  474. player.level.tilelayercount++;
  475. temp.fileLines.savelines(temp.filePath, 0);
  476. SourceControl.handleUpdate(player.account, {{"file", temp.filePath}});
  477.  
  478. for (temp.pl: player.level.players)
  479. temp.pl.triggerclient("gui", this.name, RPL.ADDTILELAYER);
  480. break;
  481. }
  482. case RPL.REMOVETILELAYER: {
  483. temp.levelName = player.level.name.ends(".gmap") ? player.level.getmappartfile(player.x + 1.5, player.y + 1.5) : player.level.name;
  484. if (TE_NEEDRIGHTS && !player.hasright("w", temp.levelName)) {
  485. player.triggerclient("gui", this.name, RPL.ERROR, "You do not have the rights to edit " @ temp.levelName);
  486. break;
  487. }
  488. temp.levelFilePath = getLevelFilePath(temp.levelName);
  489. temp.filePath = temp.levelFilePath;
  490. temp.hasReadRights = fileexists(temp.filePath);
  491. if (!temp.hasReadRights) {
  492. player.triggerclient("gui", this.name, RPL.ERROR, "The (npcserver) lacks the rights to read" SPC temp.filePath);
  493. break;
  494. }
  495. temp.fileLines = {};
  496. temp.fileLines.loadlines(temp.filePath);
  497. temp.boardLines = getBoardLines(temp.levelName, -1);
  498. temp.fileLines = replaceLinesStartingWith(temp.fileLines, temp.boardLines, "BOARD");
  499. deletefile(temp.filePath);
  500. if (fileExists2(temp.filePath)) {
  501. player.triggerclient("gui", this.name, RPL.ERROR, "The (npcserver) lacks the rights to write" SPC temp.filePath);
  502. break;
  503. }
  504. player.level.tilelayercount--;
  505. temp.fileLines.savelines(temp.filePath, 0);
  506. SourceControl.handleUpdate(player.account, {{"file", temp.filePath}});
  507. for (temp.pl: player.level.players)
  508. temp.pl.triggerclient("gui", this.name, RPL.REMOVETILELAYER);
  509. break;
  510. }
  511. }
  512. }
  513.  
  514. /**
  515. * functions
  516. */
  517.  
  518. // just a simple, customized output function
  519. function TE_echo(temp.text) {
  520. echo(this.name @ ":" SPC temp.text);
  521. }
  522.  
  523. // altered version of Tigairius' Base10 Converter
  524. // http://forums.graalonline.com/forums/showthread.php?t=134261707
  525. //
  526. // this version encodes the given numeric as a .nw tile string
  527. function nw_encode(temp.i) {
  528. if (temp.i < 0)
  529. return "//";
  530. while (temp.i > 0) {
  531. temp.s0 @= ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/").substring(temp.i % 64, 1);
  532. temp.i = int(temp.i / 64);
  533. temp.j++;
  534. }
  535. switch (temp.j) {
  536. case 0: { return "AA"; }
  537. case 1: { temp.s1 = "A"; break; }
  538. case 2: { temp.s1 = ""; break; }
  539. }
  540. while (--temp.j >= 0)
  541. temp.s1 @= temp.s0.substring(temp.j, 1);
  542. return temp.s1;
  543. }
  544.  
  545. // will find the level filepath
  546. // might be slow; especially on larger servers
  547. // need to find an optimisation
  548. //
  549. // found an optimisation using findfiles("file",1) (1 for recursive)
  550. // - BlueMelon 9/17/2013
  551. function getLevelFilePath(temp.levelName) {
  552.  
  553. temp.fileList = findfiles(temp.levelName,1);
  554. if(temp.fileList.size() > 0){
  555. return temp.fileList[0];
  556. }else{
  557. return NULL;
  558. }
  559.  
  560. /* // OLD
  561. temp.fileList = {};
  562. temp.fileList.loadfolder("levels/*", 1);
  563. for (temp.filePath: temp.fileList) {
  564. temp.fileName = extractfilename(temp.filePath);
  565. if (temp.fileName == temp.levelName) {
  566. return "levels/"@temp.filePath;
  567. }
  568. }
  569.  
  570. return NULL;
  571. */
  572. }
  573.  
  574. function getBoardLines(temp.levelName, temp.modifyLayerCount) {
  575. if (player.level.name.ends(".gmap")) {
  576. temp.level = player.level;
  577. temp.xOffset = int((player.x + 1.5) / 64) * 64;
  578. temp.yOffset = int((player.y + 1.5) / 64) * 64;
  579. } else {
  580. temp.level = findlevel(temp.levelName);
  581. }
  582. if (temp.layerCount <= 0)
  583. temp.layerCount = temp.level.tilelayercount;
  584. // generate level file board lines
  585. temp.lines = {};
  586. // loop through layers
  587. temp.layerCount = (temp.modifyLayerCount == -1 && temp.level.tilelayercount > 1)
  588. ? temp.level.tilelayercount - 1 : temp.level.tilelayercount;
  589. for (temp.i = 0; temp.i < temp.layerCount; temp.i++) {
  590. temp.tileLayer = temp.level.tilelayers[temp.i];
  591. // loop through rows
  592. for (temp.j = temp.yOffset; temp.j < temp.yOffset + 64; temp.j++) {
  593. temp.line = "BOARD 0 " @ (temp.j % 64) @ " 64 " @ temp.i @ " ";
  594. // convert tile numerics to nw64 and concat to end of line
  595. for (temp.k = temp.xOffset; temp.k < temp.xOffset + 64; temp.k++) {
  596. temp.line @= nw_encode(temp.tileLayer.tiles[temp.k, temp.j]);
  597. }
  598. if (temp.line.ends("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"))
  599. continue;
  600. temp.lines.add(temp.line);
  601. }
  602. }
  603. if (temp.modifyLayerCount == 1) {
  604. temp.line = "BOARD 0 0 64 " @ temp.level.tilelayercount SPC "////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////";
  605. temp.lines.add(temp.line);
  606. }
  607. return temp.lines;
  608. }
  609.  
  610. function replaceLinesStartingWith(temp.oLines, temp.nLines, temp.start) {
  611. // find first index of temp.start in temp.oLines
  612. temp.i = 0;
  613. temp.sz = temp.oLines.size();
  614. while (temp.i < temp.sz) {
  615. if (temp.oLines[temp.i].starts(temp.start))
  616. break;
  617. temp.i++;
  618. }
  619.  
  620. // delete old lines
  621. while (temp.oLines[temp.i].starts(temp.start))
  622. temp.oLines.delete(temp.i);
  623.  
  624. // insert new lines
  625. temp.oLines.insertarray(temp.i, temp.nLines);
  626.  
  627. return temp.oLines;
  628. }
  629.  
  630. // unlike the built in fileexists(str) function
  631. // this one will work regardless of whether the
  632. // (npcserver) has rights or not
  633. function fileExists2(temp.filePath) {
  634. temp.fileList.loadfolder(temp.filePath, 0);
  635. return (temp.fileList.size() != 0);
  636. }
  637. //#CLIENTSIDE
  638.  
  639. //Script Extensions
  640.  
  641. const scriptextension = "-OLELink";
  642.  
  643. // numeric network replies
  644. // these MUST match the serverside
  645. enum RPL {
  646. NONE,
  647. ERROR,
  648. REQUESTUSE,
  649. PLACETILES,
  650. LISTCLIPBOARDFOLDER,
  651. LOADCLIPBOARDFILE,
  652. SAVECLIPBOARDFILE,
  653. DELETECLIPBOARDFILE,
  654. CREATENEWLEVEL,
  655. UPDATELEVEL,
  656. ADDTILELAYER,
  657. REMOVETILELAYER
  658. }
  659.  
  660. // numeric paste modes
  661. enum PASTEMODE {
  662. NONE,
  663. NORMAL,
  664. FILL
  665. }
  666.  
  667. /**
  668. * events
  669. */
  670.  
  671. function onCreated() {
  672. // if the script is updated while someone
  673. // is using the editor, and they are using the grid
  674. // the grid disappears because all the images
  675. // of the script become reset.
  676. // so, if the grid is enabled, we re-draw it here
  677. if (GuiWindow_TileEditor.grid)
  678. updateGridEffect();
  679. }
  680.  
  681. function onPlayerEnters() {
  682. if (player.account in {"Tim_Rocks", "swift", "SharkeySprinkles", "CynicalFree1"}) {
  683. return;
  684. }
  685. // if the program is open, and the player enters a new level
  686. // exit the program, to prevent problems such as
  687. // undo and redo affecting the wrong level
  688. if (GuiWindow_TileEditor != NULL
  689. && GuiWindow_TileEditor.editingLevel != (isonmap ? player.gmap.name : player.level.name)) {
  690. onCloseEditor();
  691. }
  692. }
  693.  
  694. function onActionClientSide() {
  695. if (GuiWindow_TileEditor == NULL)
  696. return;
  697. switch (params[0]) {
  698. // depending which gui is open (Open or Save)
  699. // loads the tree view of the gui with
  700. // the clipboard file list supplied by server
  701. case RPL.LISTCLIPBOARDFOLDER: {
  702. if (GuiWindow_TileEditor_FileOpen != NULL) {
  703. GuiTreeView_TileEditor_FileOpen.clearnodes();
  704. for (temp.fileName: params[1]) {
  705. temp.fileExt = extractfileext(temp.fileName);
  706. if (temp.fileExt != ".txt" && temp.fileExt != "")
  707. continue;
  708. with (GuiTreeView_TileEditor_FileOpen.addnodebypath(temp.fileName, "/")) {
  709. image = selectedimage = temp.fileExt == "" ? 1 : 2;
  710. }
  711. }
  712. }
  713. if (GuiWindow_TileEditor_FileSave != NULL) {
  714. GuiTreeView_TileEditor_FileSave.clearnodes();
  715. for (temp.fileName: params[1]) {
  716. temp.fileExt = extractfileext(temp.fileName);
  717. if (temp.fileExt != ".txt" && temp.fileExt != "")
  718. continue;
  719. with (GuiTreeView_TileEditor_FileSave.addnodebypath(temp.fileName, "/")) {
  720. image = selectedimage = temp.fileExt == "" ? 1 : 2;
  721. }
  722. }
  723. }
  724. break;
  725. }
  726.  
  727. // sets clipboard from server data
  728. case RPL.LOADCLIPBOARDFILE: {
  729. temp.lines = {};
  730. for (temp.line: params[1])
  731. temp.lines.add(temp.line.tokenize());
  732. temp.extent = {
  733. temp.lines[0].size(),
  734. temp.lines.size()
  735. };
  736. if (GuiWindow_TileEditor_FileOpen != NULL) {
  737. GuiText_TileEditor_FileOpen_Title_Value.text = params[2];
  738. GuiText_TileEditor_FileOpen_Extent_Value.text = temp.extent[0] @ "," SPC temp.extent[1];
  739. GuiText_TileEditor_FileOpen_Created_Value.text = converttimetostring(params[3]);
  740. GuiStretch_TileEditor_FileOpen.clientwidth =
  741. GuiDrawingPanel_TileEditor_FileOpen_Preview.width = temp.extent[0] * 16;
  742. GuiStretch_TileEditor_FileOpen.clientheight =
  743. GuiDrawingPanel_TileEditor_FileOpen_Preview.height = temp.extent[1] * 16;
  744. GuiDrawingPanel_TileEditor_FileOpen_Preview.clearall();
  745. for (temp.i = 0; temp.i < temp.extent[0]; temp.i++) {
  746. for (temp.j = 0; temp.j < temp.extent[1]; temp.j++) {
  747. temp.tileXY = getTileXY(temp.lines[temp.j][temp.i]);
  748. GuiDrawingPanel_TileEditor_FileOpen_Preview.drawimagerectangle(
  749. temp.i * 16,
  750. temp.j * 16,
  751. GuiWindow_TileEditor.tilesetImage,
  752. temp.tileXY[0],
  753. temp.tileXY[1],
  754. 16,
  755. 16
  756. );
  757. }
  758. GuiWindow_TileEditor_FileOpen.clipboard = temp.lines;
  759. }
  760. }
  761. if (GuiWindow_TileEditor_FileSave != NULL) {
  762. GuiText_TileEditor_FileSave_Title_Value.text = params[2];
  763. GuiText_TileEditor_FileSave_Extent_Value.text = temp.extent[0] @ "," SPC temp.extent[1];
  764. GuiText_TileEditor_FileSave_Created_Value.text = converttimetostring(params[3]);
  765. GuiStretch_TileEditor_FileSave.clientwidth =
  766. GuiDrawingPanel_TileEditor_FileSave_Preview.width = temp.extent[0] * 16;
  767. GuiStretch_TileEditor_FileSave.clientheight =
  768. GuiDrawingPanel_TileEditor_FileSave_Preview.height = temp.extent[1] * 16;
  769. GuiDrawingPanel_TileEditor_FileSave_Preview.clearall();
  770. for (temp.i = 0; temp.i < temp.extent[0]; temp.i++) {
  771. for (temp.j = 0; temp.j < temp.extent[1]; temp.j++) {
  772. temp.tileXY = getTileXY(temp.lines[temp.j][temp.i]);
  773. GuiDrawingPanel_TileEditor_FileSave_Preview.drawimagerectangle(
  774. temp.i * 16,
  775. temp.j * 16,
  776. GuiWindow_TileEditor.tilesetImage,
  777. temp.tileXY[0],
  778. temp.tileXY[1],
  779. 16,
  780. 16
  781. );
  782. }
  783. }
  784. }
  785. break;
  786. }
  787.  
  788. // just a reply from the server indicating that
  789. // the clipboard file successfully saved
  790. case RPL.SAVECLIPBOARDFILE: {
  791. shared.adminmessage(params[1] SPC "is saved");
  792. break;
  793. }
  794.  
  795. // generic error reply from the server
  796. // if an error message is supplied, display it
  797. // otherwises display the default error message
  798. case RPL.ERROR: {
  799. if (params[1] != NULL)
  800. shared.adminmessage(params[1]);
  801. else
  802. shared.adminmessage("An unexpected error occurred");
  803. break;
  804. }
  805.  
  806. // just a reply from the server indicating that
  807. // the new level has been created
  808. case RPL.CREATENEWLEVEL: {
  809. shared.adminmessage(params[1] SPC "is saved");
  810. GuiWindow_TileEditor.newLevelOverwrite = NULL;
  811. break;
  812. }
  813.  
  814. case RPL.UPDATELEVEL: {
  815. shared.adminmessage("Level saved!");
  816. break;
  817. }
  818.  
  819. case RPL.ADDTILELAYER: {
  820. shared.adminmessage("Level saved with an additional tilelayer!");
  821. GuiMenu_TileEditor.findmenu("Layer").addrow(tilelayercount + 1, tilelayercount).hint = "Change the current editing layer to " @ tilelayercount;
  822. break;
  823. }
  824.  
  825. case RPL.REMOVETILELAYER: {
  826. if (tilelayercount > 1) {
  827. tilelayercount--;
  828. if (GuiWindow_TileEditor.editingLayer > tilelayercount - 1) {
  829. GuiWindow_TileEditor.editingLayer = tilelayercount - 1;
  830. GuiWindow_TileEditor.text = "Tile Editor v" @ GuiWindow_TileEditor.version SPC "(Layer " @ tilelayercount @ ")";
  831. GuiMenu_TileEditor.findmenu("Layer").setrowbyid(tilelayercount + 1, "*" @ tilelayercount);
  832. }
  833. GuiMenu_TileEditor.findmenu("Layer").removerow(tilelayercount + 2);
  834. shared.adminmessage("Level saved with a tilelayer taken off!");
  835. }
  836. break;
  837. }
  838. }
  839. }
  840.  
  841. function ChatBar.onAction() {
  842. if (ChatBar.text.lower().trim() == ":te" || ChatBar.text.lower().trim() == "/te") {
  843.  
  844. this.onRequestUse();
  845. }
  846. }
  847.  
  848. function GuiWindow_TileEditor.onResize(temp.newWidth, temp.newHeight) {
  849. // there is a bit of weird code here because
  850. // the behavior of the window gui changes
  851. // after it becomes external
  852. if (GuiWindow_TileEditor.isexternal) {
  853. GuiMenu_TileEditor.x = 0;
  854. GuiMenu_TileEditor.y = 0;
  855. GuiMenu_TileEditor.width = temp.newWidth;
  856. GuiScroll_TileEditor.x = 0;
  857. GuiScroll_TileEditor.y = 20;
  858. GuiScroll_TileEditor.width = temp.newWidth;
  859. GuiScroll_TileEditor.height = temp.newHeight - 20;
  860. } else {
  861. GuiMenu_TileEditor.width = temp.newWidth - 12;
  862. GuiScroll_TileEditor.width = temp.newWidth - 12;
  863. GuiScroll_TileEditor.height = temp.newHeight - 50;
  864. }
  865. }
  866.  
  867. function GuiWindow_TileEditor.onCloseQuery() {
  868. onCloseEditor();
  869. }
  870.  
  871. function GuiMenu_TileEditor.onSelect(temp.menuName, temp.entryId, temp.entryText, temp.entryIndex) {
  872. temp.menu = GuiMenu_TileEditor.findmenu(temp.menuName);
  873. switch (temp.menuName) {
  874. case "File": {
  875. switch (temp.entryId) {
  876. case 0: {
  877. // display a text edit gui for the player to type in
  878. // the file path they would like to save the new
  879. // level as
  880. with (GuiWindow_TileEditor) {
  881. new GuiTextEditCtrl("GuiTextEdit_TileEditor_NewLevel") {
  882. profile = GuiBlueTextEditProfile;
  883. x = GuiWindow_TileEditor.wasExternal ? 0 : 6;
  884. y = GuiWindow_TileEditor.wasExternal ? 20 : 44;
  885. width = GuiWindow_TileEditor.width - x * 2;
  886. height = 20;
  887. text = "levels/new.nw";
  888. makefirstresponder(true);
  889. setselection(0, text.length());
  890. }
  891. }
  892. break;
  893. }
  894. case 1: {
  895. triggerserver("gui", this.name, RPL.UPDATELEVEL);
  896. break;
  897. }
  898. case 2: {
  899. (@scriptextension).onLoadLinkEditor();
  900. break;
  901. }
  902. case 3: {
  903. showFileOpenGui();
  904. break;
  905. }
  906.  
  907. case 4: {
  908. showFileSaveGui();
  909. break;
  910. }
  911. case 5: {
  912. onCloseEditor();
  913. break;
  914. }
  915. }
  916. break;
  917. }
  918. case "Edit": {
  919. switch (temp.entryId) {
  920. case 0: {
  921. editorUndo();
  922. break;
  923. }
  924. case 1: {
  925. editorRedo();
  926. break;
  927. }
  928. }
  929. break;
  930. }
  931. case "View": {
  932. switch (temp.entryId) {
  933. case 0: {
  934. GuiWindow_TileEditor.fadeLayers = !GuiWindow_TileEditor.fadeLayers;
  935. if (GuiWindow_TileEditor.fadeLayers)
  936. temp.menu.setrowbyid(0, "*Fade inactive layers");
  937. else
  938. temp.menu.setrowbyid(0, "Fade inactive layers");
  939. updateFadeEffect();
  940. break;
  941. }
  942. case 1: {
  943. GuiWindow_TileEditor.grid = !GuiWindow_TileEditor.grid;
  944. if (GuiWindow_TileEditor.grid)
  945. temp.menu.setrowbyid(1, "*Grid");
  946. else
  947. temp.menu.setrowbyid(1, "Grid");
  948. updateGridEffect();
  949. break;
  950. }
  951. case 2: {
  952. GuiWindow_TileEditor.extraCursorInfo = !GuiWindow_TileEditor.extraCursorInfo;
  953. if (GuiWindow_TileEditor.extraCursorInfo) {
  954. temp.menu.setrowbyid(2, "*Extra cursor info");
  955. } else {
  956. hideimgs(200, 204);
  957. temp.menu.setrowbyid(2, "Extra cursor info");
  958. }
  959. break;
  960. }
  961. }
  962. break;
  963. }
  964. case "Tileset": {
  965. switch (temp.entryId) {
  966. // displays a text edit gui for the player
  967. // to type in what image to use as the tileset
  968. // in the gui
  969. case 0: {
  970. with (GuiWindow_TileEditor) {
  971. new GuiTextEditCtrl("GuiTextEdit_TileEditor_Tileset") {
  972. profile = GuiBlueTextEditProfile;
  973. x = GuiWindow_TileEditor.wasExternal ? 0 : 6;
  974. y = GuiWindow_TileEditor.wasExternal ? 20 : 44;
  975. width = GuiWindow_TileEditor.width - x * 2;
  976. height = 20;
  977. text = "pics1.png";
  978. makefirstresponder(true);
  979. setselection(0, text.length());
  980. }
  981. }
  982. break;
  983. }
  984. // resets the gui tileset image to the current tiledefs
  985. case 1: {
  986. with (GuiDrawingPanel_TileEditor) {
  987. clearall();
  988. GuiWindow_TileEditor.tilesetImage = "TILES";
  989. drawimage(0, 0, GuiWindow_TileEditor.tilesetImage);
  990. }
  991. break;
  992. }
  993. }
  994. break;
  995. }
  996. case "Layer": {
  997. switch (temp.entryId) {
  998. case 0: {
  999. triggerserver("gui", this.name, RPL.ADDTILELAYER);
  1000. break;
  1001. }
  1002. case 1: {
  1003. if (timevar2 - GuiWindow_TileEditor.layerRemoveTimeout > 5) {
  1004. shared.adminmessage("If you are certain you want to remove the top tilelayer, press remove again within 5 seconds");
  1005. GuiWindow_TileEditor.layerRemoveTimeout = timevar2;
  1006. break;
  1007. }
  1008. GuiWindow_TileEditor.layerRemoveTimeout = 0;
  1009. triggerserver("gui", this.name, RPL.REMOVETILELAYER);
  1010. break;
  1011. }
  1012. default: {
  1013. // change current editing layer based on which
  1014. // entryId was selected
  1015. temp.menu.setrowbyid(GuiWindow_TileEditor.editingLayer + 2, GuiWindow_TileEditor.editingLayer + 1);
  1016. temp.menu.setrowbyid(temp.entryId, "*" @ (temp.entryId - 1));
  1017. GuiWindow_TileEditor.editingLayer = temp.entryId - 2;
  1018. GuiWindow_TileEditor.text = " Tile Editor v" @ GuiWindow_TileEditor.version SPC "(Layer" SPC GuiWindow_TileEditor.editingLayer + 1 @ ")";
  1019. updateFadeEffect();
  1020. break;
  1021. }
  1022. }
  1023. break;
  1024. }
  1025. case "Options": {
  1026. switch (temp.entryId) {
  1027. case 0: {
  1028. GuiWindow_TileEditor.isexternal = !GuiWindow_TileEditor.isexternal;
  1029. GuiWindow_TileEditor.wasExternal = true;
  1030. if (GuiWindow_TileEditor.isexternal)
  1031. temp.menu.setrowbyid(0, "*External");
  1032. else
  1033. temp.menu.setrowbyid(0, "External");
  1034. GuiWindow_TileEditor.trigger("onResize", GuiWindow_TileEditor.width, GuiWindow_TileEditor.height);
  1035. break;
  1036. }
  1037. case 1: {
  1038. openurl("http://forums.graalonline.com/forums/showthread.php?t=134267103");
  1039. break;
  1040. }
  1041. case 2: {
  1042. temp.req = requesturl("http://forums.graalonline.com/forums/showthread.php?t=134267103");
  1043. temp.time = timevar2;
  1044. waitfor(temp.req, "onReceiveData", 10);
  1045. if (timevar2 - temp.time < 10) {
  1046. temp.position = temp.req.fulldata.pos("[VERSION]") + 9;
  1047. temp.currentVersionString = temp.req.fulldata.substring(temp.position, temp.req.fulldata.pos("[/VERSION]") - position).trim();
  1048. temp.a = int(GuiWindow_TileEditor.version.substring(0, 1) @ GuiWindow_TileEditor.version.substring(2, 1) @ GuiWindow_TileEditor.version.substring(4, 1));
  1049. temp.b = int(temp.currentVersionString.substring(0, 1) @ temp.currentVersionString.substring(2, 1) @ temp.currentVersionString.substring(4, 1));
  1050. if (temp.a >= temp.b)
  1051. shared.adminmessage("You are using the newest version already");
  1052. else
  1053. shared.adminmessage("A new version is available:\n" @ temp.currentVersionString);
  1054. } else {
  1055. shared.adminmessage("Version check timed out");
  1056. }
  1057. break;
  1058. }
  1059. }
  1060. break;
  1061. }
  1062. }
  1063. }
  1064.  
  1065. function GuiButton_TileEditor_PasteMode.onAction() {
  1066. // toggles between the fill pastemode and the normal pastemode
  1067. if (GuiWindow_TileEditor.pasteMode == PASTEMODE.NORMAL) {
  1068. GuiWindow_TileEditor.pasteMode = PASTEMODE.FILL;
  1069. GuiShowImg_TileEditor_PasteMode.image = "tileeditor_pencil_1-1.png";
  1070. } elseif (GuiWindow_TileEditor.pasteMode == PASTEMODE.FILL) {
  1071. GuiWindow_TileEditor.pasteMode = PASTEMODE.NORMAL;
  1072. GuiShowImg_TileEditor_PasteMode.image = "tileeditor_bucket_1-1.png";
  1073. }
  1074. }
  1075.  
  1076. function GuiWindow_TileEditor.onHide() {
  1077. // detect when the editor is closed from external window
  1078. // it looks weird because external stuff is weird
  1079. if (GuiWindow_TileEditor.isexternal && !GuiWindow_TileEditor.visible)
  1080. onCloseEditor();
  1081. }
  1082.  
  1083. function GuiTextEdit_TileEditor_NewLevel.onAction() {
  1084. // triggers the server requesting to create a new level
  1085. // at the specified filepath
  1086. temp.text = GuiTextEdit_TileEditor_NewLevel.text;
  1087. triggerserver("gui", this.name, RPL.CREATENEWLEVEL, temp.text, (temp.text.lower() == GuiWindow_TileEditor.newLevelOverwrite));
  1088. GuiWindow_TileEditor.newLevelOverwrite = temp.text.lower();
  1089. GuiTextEdit_TileEditor_NewLevel.destroy();
  1090. }
  1091.  
  1092. function GuiTextEdit_TileEditor_Tileset.onAction() {
  1093. // draw the gui tileset as the image specified
  1094. with (GuiDrawingPanel_TileEditor) {
  1095. clearall();
  1096. drawimage(0, 0, GuiTextEdit_TileEditor_Tileset.text);
  1097. }
  1098. GuiWindow_TileEditor.tilesetImage = GuiTextEdit_TileEditor_Tileset.text;
  1099. GuiTextEdit_TileEditor_Tileset.destroy();
  1100. }
  1101.  
  1102. function GuiDrawingPanel_TileEditor.onMouseDown(temp.keyMod, temp.xMouse, temp.yMouse, temp.clickCount) {
  1103. // beginning of gui tile selection
  1104. GuiDrawingPanel_TileEditor.mouseWasDown = true;
  1105. GuiDrawingPanel_TileEditor.mouselock(0);
  1106. temp.coords = GuiDrawingPanel_TileEditor.globaltolocalcoord({temp.xMouse, temp.yMouse});
  1107. GuiWindow_TileEditor.tileSelectStart =
  1108. GuiWindow_TileEditor.tileSelectEnd = {temp.coords[0] - temp.coords[0] % 16, temp.coords[1] - temp.coords[1] % 16};
  1109. drawGuiSelect();
  1110. }
  1111.  
  1112. function GuiDrawingPanel_TileEditor.onMouseUp(temp.keyMod, temp.xMouse, temp.yMouse, temp.clickCount) {
  1113. if (!GuiDrawingPanel_TileEditor.mouseWasDown)
  1114. return;
  1115. // ending of gui tile selection
  1116. GuiDrawingPanel_TileEditor.mouseWasDown = false;
  1117. if (Gui_TileEditor_Select != NULL)
  1118. Gui_TileEditor_Select.destroy();
  1119. setClipboardFromGui();
  1120. GraalControl.makefirstresponder(true);
  1121. }
  1122.  
  1123. function GuiDrawingPanel_TileEditor.onMouseDragged(temp.keyMod, temp.xMouse, temp.yMouse, temp.clickCount) {
  1124. // update gui tile selection with new coordinates after drag
  1125. temp.coords = GuiDrawingPanel_TileEditor.globaltolocalcoord({temp.xMouse, temp.yMouse});
  1126. temp.scrollcoords = GuiWindow_TileEditor.globaltolocalcoord({temp.xMouse, temp.yMouse});
  1127. if (temp.scrollcoords[0] < GuiScroll_TileEditor.x + 32)
  1128. temp.scrollx = temp.scrollcoords[0] - GuiScroll_TileEditor.x - 32;
  1129. elseif (temp.scrollcoords[0] > GuiScroll_TileEditor.x + GuiScroll_TileEditor.width - 64)
  1130. temp.scrollx = temp.scrollcoords[0] - GuiScroll_TileEditor.x - GuiScroll_TileEditor.width + 64;
  1131. if (temp.scrollcoords[1] < GuiScroll_TileEditor.y + 32)
  1132. temp.scrolly = temp.scrollcoords[1] - GuiScroll_TileEditor.y - 32;
  1133. elseif (temp.scrollcoords[1] > GuiScroll_TileEditor.y + GuiScroll_TileEditor.height - 64)
  1134. temp.scrolly = temp.scrollcoords[1] - GuiScroll_TileEditor.y - GuiScroll_TileEditor.height + 64;
  1135. if (temp.scrollx != NULL || temp.scrolly != NULL)
  1136. GuiScroll_TileEditor.scrolldelta(int(temp.scrollx / 8.0), int(temp.scrolly / 8.0));
  1137. GuiWindow_TileEditor.tileSelectEnd = {temp.coords[0] - temp.coords[0] % 16, temp.coords[1] - temp.coords[1] % 16};
  1138. drawGuiSelect();
  1139. }
  1140.  
  1141. function GuiTreeView_TileEditor_FileOpen.onSelect(temp.node, temp.nodeSlashPath, temp.nodeDotPath) {
  1142. // if the selection ends in .txt, request to load the clipboard file
  1143. if (!temp.node.ends(".txt"))
  1144. return;
  1145. triggerserver("gui", this.name, RPL.LOADCLIPBOARDFILE, temp.nodeSlashPath);
  1146. GuiTreeView_TileEditor_FileOpen.selectedSlashPath = temp.nodeSlashPath;
  1147. }
  1148.  
  1149. function GuiButton_TileEditor_FileOpen_Delete.onAction() {
  1150. // if the filepath is something, trigger server to delete it
  1151. // i might add a confirmation box option eventually
  1152. temp.filePath = GuiTreeView_TileEditor_FileOpen.selectedSlashPath;
  1153. if (temp.filePath != NULL)
  1154. triggerserver("gui", this.name, RPL.DELETECLIPBOARDFILE, temp.filePath);
  1155. }
  1156.  
  1157. function GuiButton_TileEditor_FileOpen_Open.onAction() {
  1158. // load the clipboard file data into the clipboard
  1159. if (GuiWindow_TileEditor_FileOpen.clipboard == NULL)
  1160. return;
  1161. GuiWindow_TileEditor.clipboard = GuiWindow_TileEditor_FileOpen.clipboard;
  1162. drawClipboardPreview();
  1163. GuiWindow_TileEditor_FileOpen.destroy();
  1164. }
  1165.  
  1166. function GuiButton_TileEditor_FileOpen_Cancel.onAction() {
  1167. GuiWindow_TileEditor_FileOpen.destroy();
  1168. }
  1169.  
  1170. function GuiTreeView_TileEditor_FileSave.onSelect(temp.node, temp.nodeSlashPath, temp.nodeDotPath) {
  1171. // if the path ends with .txt, trigger the server
  1172. // to load the file
  1173. if (!temp.node.ends(".txt"))
  1174. return;
  1175. triggerserver("gui", this.name, RPL.LOADCLIPBOARDFILE, temp.nodeSlashPath);
  1176. GuiTextEdit_TileEditor_FileSave_FilePath.text = temp.nodeSlashPath;
  1177. }
  1178.  
  1179. function GuiButton_TileEditor_FileSave_Delete.onAction() {
  1180. // if the filepath is something, triggerserver to delete it
  1181. temp.filePath = GuiTextEdit_TileEditor_FileSave_FilePath.text;
  1182. if (temp.filePath != NULL)
  1183. triggerserver("gui", this.name, RPL.DELETECLIPBOARDFILE, temp.filePath);
  1184. }
  1185.  
  1186. function GuiButton_TileEditor_FileSave_Save.onAction() {
  1187. // if the filepath is something, triggerserver to save
  1188. // the clipboard file
  1189. temp.filePath = GuiTextEdit_TileEditor_FileSave_FilePath.text;
  1190. if (temp.filePath.length() == 0)
  1191. return;
  1192. triggerserver("gui", this.name, RPL.SAVECLIPBOARDFILE, GuiWindow_TileEditor.clipboard, temp.filePath);
  1193. GuiWindow_TileEditor_FileSave.destroy();
  1194. }
  1195.  
  1196. function GuiButton_TileEditor_FileSave_Cancel.onAction() {
  1197. GuiWindow_TileEditor_FileSave.destroy();
  1198. }
  1199.  
  1200. function GraalControl.onMouseDown(temp.keyMod, temp.xMouse, temp.yMouse, temp.clickCount) {
  1201. // if the preview gui exists, destroy it
  1202. // because either the program is dead or
  1203. // we are selecting new tiles from the level
  1204. if (GuiShowImg_TileEditor_ClipboardPreview != NULL)
  1205. GuiShowImg_TileEditor_ClipboardPreview.destroy();
  1206. // if the program isn't open, forget it
  1207. if (GuiWindow_TileEditor == NULL)
  1208. return;
  1209. // beginning of tile selection from level
  1210. GuiWindow_TileEditor.tileSelectStart =
  1211. GuiWindow_TileEditor.tileSelectEnd = {int(mousex), int(mousey)};
  1212. drawSelect();
  1213. if (!GuiWindow_TileEditor.isexternal)
  1214. GuiWindow_TileEditor.visible = false;
  1215. }
  1216.  
  1217. function GraalControl.onRightMouseDown(temp.keyMod, temp.xMouse, temp.yMouse, temp.clickCount) {
  1218. // if the program isn't open or
  1219. // no tiles are in the clipboard, forget it
  1220. if (GuiWindow_TileEditor == NULL
  1221. || GuiShowImg_TileEditor_ClipboardPreview == NULL
  1222. || GuiWindow_TileEditor.clipboard == NULL)
  1223. return;
  1224.  
  1225. // make the preview bluey so there's some visual
  1226. // indication that the paste is happening
  1227. GuiShowImg_TileEditor_ClipboardPreview.blue = 1.0;
  1228. // disable flickering while pasting too
  1229. GuiDrawingPanel_TileEditor_ClipboardPreview.flickering = false;
  1230.  
  1231. temp.mx = int(mousex);
  1232. temp.my = int(mousey);
  1233.  
  1234. // pastemode normal is just what you expect from your standard
  1235. // tile editor. the tiles you see in the clipboard preview
  1236. // are pushed to the stack of undo/redo and the clipboard
  1237. // data is sent to the server as a request to paste tiles
  1238. if (GuiWindow_TileEditor.pasteMode == PASTEMODE.NORMAL) {
  1239. temp.historyObject = {
  1240. temp.mx,
  1241. temp.my,
  1242. GuiWindow_TileEditor.editingLayer,
  1243. NULL,
  1244. GuiWindow_TileEditor.clipboard
  1245. };
  1246. for (temp.y = 0; temp.y < GuiWindow_TileEditor.clipboard.size(); temp.y++) {
  1247. temp.row = {};
  1248. for (temp.x = 0; temp.x < GuiWindow_TileEditor.clipboard[0].size(); temp.x++) {
  1249. if (GuiWindow_TileEditor.editingLayer == 0)
  1250. temp.tile = tiles[temp.x + temp.mx, temp.y + temp.my];
  1251. else
  1252. temp.tile = tilelayers[GuiWindow_TileEditor.editingLayer].tiles[temp.x + temp.mx, temp.y + temp.my];
  1253. temp.row.add(temp.tile);
  1254. }
  1255. temp.historyObject[3].add(temp.row);
  1256. }
  1257. if (GuiWindow_TileEditor.history == NULL)
  1258. GuiWindow_TileEditor.history = {};
  1259. GuiWindow_TileEditor.history = GuiWindow_TileEditor.history.subarray(GuiWindow_TileEditor.historyIndex);
  1260. GuiWindow_TileEditor.historyIndex = 0;
  1261. GuiWindow_TileEditor.history.insert(0, temp.historyObject);
  1262. triggerserver("gui", this.name, RPL.PLACETILES, GuiWindow_TileEditor.clipboard, temp.mx, temp.my, GuiWindow_TileEditor.editingLayer);
  1263.  
  1264. // pastemode fill implements a flood fill algorithm
  1265. // the computations are done on the clientside, here,
  1266. // then a standard tile paste request is sent to the
  1267. // server with the rectangle which contains the flooded
  1268. // tiles
  1269. } elseif (GuiWindow_TileEditor.pasteMode == PASTEMODE.FILL) {
  1270. if (GuiWindow_TileEditor.editingLayer == 0) {
  1271. temp.floodedArea = getFloodedAreaZero(temp.mx, temp.my);
  1272. } else {
  1273. temp.tileLayer = tilelayers[GuiWindow_TileEditor.editingLayer];
  1274. temp.floodedArea = getFloodedAreaLayer(temp.tileLayer, temp.mx, temp.my);
  1275. }
  1276. temp.pasteX = temp.floodedArea[0];
  1277. temp.pasteY = temp.floodedArea[1];
  1278. temp.sizeY = temp.floodedArea[3] - temp.pasteY + 1;
  1279. temp.sizeX = temp.floodedArea[2] - temp.pasteX + 1;
  1280. temp.pasteData = new [temp.sizeY][temp.sizeX];
  1281. temp.historyData = {};
  1282. maxlooplimit = 100000;
  1283. for (temp.y = 0; temp.y < temp.sizeY; temp.y++) {
  1284. temp.row = {};
  1285. for (temp.x = 0; temp.x < temp.sizeX; temp.x++) {
  1286. if ((@{temp.pasteX + temp.x, temp.pasteY + temp.y}) in temp.floodedArea) {
  1287. temp.pasteData[temp.y][temp.x] = GuiWindow_TileEditor.clipboard[(temp.pasteY - temp.my + temp.y) % GuiWindow_TileEditor.clipboard.size()][(temp.pasteX - temp.mx + temp.x) % GuiWindow_TileEditor.clipboard[0].size()];
  1288. } else {
  1289. temp.pasteData[temp.y][temp.x] = -2;
  1290. }
  1291. if (GuiWindow_TileEditor.editingLayer == 0)
  1292. temp.row.add(tiles[temp.pasteX + temp.x, temp.pasteY + temp.y]);
  1293. else
  1294. temp.row.add(temp.tileLayer.tiles[temp.pasteX + temp.x, temp.pasteY + temp.y]);
  1295. }
  1296. temp.historyData.add(temp.row);
  1297. }
  1298. temp.historyObject = {
  1299. temp.pasteX,
  1300. temp.pasteY,
  1301. GuiWindow_TileEditor.editingLayer,
  1302. temp.historyData,
  1303. temp.pasteData
  1304. };
  1305. if (GuiWindow_TileEditor.history == NULL)
  1306. GuiWindow_TileEditor.history = {};
  1307. GuiWindow_TileEditor.history = GuiWindow_TileEditor.history.subarray(GuiWindow_TileEditor.historyIndex);
  1308. GuiWindow_TileEditor.historyIndex = 0;
  1309. GuiWindow_TileEditor.history.insert(0, temp.historyObject);
  1310. triggerserver("gui", this.name, RPL.PLACETILES, temp.pasteData, temp.pasteX, temp.pasteY, GuiWindow_TileEditor.editingLayer);
  1311. }
  1312. }
  1313.  
  1314. function GraalControl.onRightMouseUp(temp.keyMod, temp.xMouse, temp.yMouse, temp.clickCount) {
  1315. // if the program isn't open or the preview isn't existing
  1316. // we don't care
  1317. if (GuiWindow_TileEditor == NULL
  1318. || GuiShowImg_TileEditor_ClipboardPreview == NULL)
  1319. return;
  1320. // reset the preview back to black to indicate that
  1321. // you are no longer pasting tiles
  1322. GuiShowImg_TileEditor_ClipboardPreview.blue = 0.0;
  1323. // reenable flickering as well
  1324. GuiDrawingPanel_TileEditor_ClipboardPreview.flickering = true;
  1325. // set the preview position to the mouse position
  1326. GuiShowImg_TileEditor_ClipboardPreview.x = screenx(int(mousex), 0) - 2;
  1327. GuiShowImg_TileEditor_ClipboardPreview.y = screeny(0, int(mousey)) - 2;
  1328. }
  1329.  
  1330. function GraalControl.onMouseDragged(temp.keyMod, temp.xMouse, temp.yMouse, temp.clickCount) {
  1331. // if the program isn't open we don't care
  1332. if (GuiWindow_TileEditor == NULL)
  1333. return;
  1334. // level selection drag here
  1335. // set the ending selection position to the mouse position
  1336. GuiWindow_TileEditor.tileSelectEnd = {int(mousex), int(mousey)};
  1337. drawSelect();
  1338. }
  1339.  
  1340. function GraalControl.onMouseUp(temp.keyMod, temp.xMouse, temp.yMouse, temp.clickCount) {
  1341. hideimgs(200, 204);
  1342. // if the program isn't open forget it
  1343. if (GuiWindow_TileEditor == NULL)
  1344. return;
  1345. // create the clipboard data from the level data
  1346. setClipboardFromLevel();
  1347. GuiWindow_TileEditor.visible = true;
  1348. }
  1349.  
  1350. function GraalControl.onMouseMove(temp.keyMod, temp.xMouse, temp.yMouse, temp.clickCount) {
  1351. // if the preview doesn't exist we don't care
  1352. if (GuiShowImg_TileEditor_ClipboardPreview == NULL)
  1353. return;
  1354. temp.mx = int(mousex);
  1355. temp.my = int(mousey);
  1356.  
  1357. // the preview follows the mouse
  1358. GuiShowImg_TileEditor_ClipboardPreview.x = screenx(temp.mx, 0) - 2;
  1359. GuiShowImg_TileEditor_ClipboardPreview.y = screeny(0, temp.my) - 2;
  1360.  
  1361. // display the pastemode icon a little bit above
  1362. with (findimg(201)) {
  1363. layer = 0;
  1364. image = GuiWindow_TileEditor.pasteMode == PASTEMODE.FILL ? "tileeditor_bucket_1-1.png" : "tileeditor_pencil_1-1.png";
  1365. x = temp.mx;
  1366. y = temp.my - 1.5;
  1367. }
  1368.  
  1369. // if the extra cursor information is disabled
  1370. // there's no need to continue
  1371. if (!GuiWindow_TileEditor.extraCursorInfo)
  1372. return;
  1373.  
  1374. // display the top left corner's x , y
  1375. with (findimg(202)) {
  1376. layer = 0;
  1377. text = temp.mx @ ", " @ temp.my;
  1378. zoom = 0.6;
  1379. x = temp.mx - 1.5 - gettextwidth(zoom, "", "", text) / 32;
  1380. y = temp.my;
  1381. }
  1382. temp.tw = GuiWindow_TileEditor.clipboard[0].size();
  1383. temp.th = GuiWindow_TileEditor.clipboard.size();
  1384. temp.tex = temp.mx + tw;
  1385. temp.tey = temp.my + th;
  1386.  
  1387. // display the bottom right corner's x , y
  1388. with (findimg(203)) {
  1389. layer = 0;
  1390. text = (temp.tex - 1) @ ", " @ (temp.tey - 1);
  1391. x = temp.tex + 0.5;
  1392. y = temp.tey - 1;
  1393. zoom = 0.6;
  1394. }
  1395.  
  1396. // display the clipboard's (width , height)
  1397. with (findimg(204)) {
  1398. layer = 0;
  1399. text = "(" @ temp.tw @ ", " @ temp.th @ ")";
  1400. zoom = 0.6;
  1401. x = temp.mx + temp.tw / 2 - gettextwidth(zoom, "", "", text) / 32;
  1402. y = temp.tey + 0.5;
  1403. }
  1404. }
  1405.  
  1406. function GraalControl.onKeyDown(temp.keyCode, temp.keyText, temp.scanCode) {
  1407. // if the program is closed we dont care
  1408. if (GuiWindow_TileEditor == NULL)
  1409. return;
  1410. // prevent the program from doing 4 billion undo/redo's
  1411. // when the user only wants to do one
  1412. if (timevar2 - GuiWindow_TileEditor.lastUndoOrRedoTime < 0.2)
  1413. return;
  1414. switch (temp.keyCode) {
  1415. case 602: { // undo
  1416. editorUndo();
  1417. break;
  1418. }
  1419. case 601: { // redo
  1420. editorRedo();
  1421. break;
  1422. }
  1423. default: {
  1424. return;
  1425. }
  1426. }
  1427. GuiWindow_TileEditor.lastUndoOrRedoTime = timevar2;
  1428. }
  1429.  
  1430. function GuiTextEdit_TileEditor_Tileset.onLoseFirstResponder() {
  1431. // sleep for a moment for some reason
  1432. // some weird bug otherwise
  1433. sleep(0.1);
  1434. GuiTextEdit_TileEditor_Tileset.destroy();
  1435. }
  1436.  
  1437. function GuiTextEdit_TileEditor_NewLevel.onLoseFirstResponder() {
  1438. // sleep for a moment for some reason
  1439. // some weird bug otherwise
  1440. sleep(0.1);
  1441. GuiTextEdit_TileEditor_NewLevel.destroy();
  1442. }
  1443.  
  1444. function onCloseEditor() {
  1445. // change the cursor from crosshair to default
  1446. GraalControl.cursor = "default";
  1447. // disable fading effect
  1448. GuiWindow_TileEditor.fadeLayers = false;
  1449. updateFadeEffect();
  1450. // disable grid effect
  1451. GuiWindow_TileEditor.grid = false;
  1452. updateGridEffect();
  1453. // destroy the program
  1454. if (GuiShowImg_TileEditor_ClipboardPreview != NULL)
  1455. GuiShowImg_TileEditor_ClipboardPreview.destroy();
  1456. if (GuiWindow_TileEditor_FileOpen != NULL)
  1457. GuiWindow_TileEditor_FileOpen.destroy();
  1458. if (GuiWindow_TileEditor_FileSave != NULL)
  1459. GuiWindow_TileEditor_FileSave.destroy();
  1460. GuiWindow_TileEditor.destroy();
  1461. // hide cursor information
  1462. hideimgs(200, 204);
  1463. }
  1464.  
  1465. function onRequestUse() {
  1466. // send a request to use the editor in this level
  1467. triggerserver("gui", this.name, RPL.REQUESTUSE);
  1468. do {
  1469. temp.time = timevar2;
  1470. waitfor(this, "onActionClientSide", 15.0);
  1471. if (timevar2 - temp.time > 15.0) {
  1472. shared.adminmessage("Your request to use the editor timed out");
  1473. return;
  1474. }
  1475. } while (params[0] != RPL.REQUESTUSE);
  1476. // fix tilelayercount
  1477. tilelayercount = params[3];
  1478. // params is set once onActionClientSide event is triggered
  1479. // params[1] is either "1" or "0"
  1480. // that indicates whether the player is allowed to use
  1481. // the editor in this level or not
  1482. if (params[1])
  1483. showGui(params[2]);
  1484. else
  1485. shared.adminmessage("You do not have rights to view this level");
  1486. }
  1487.  
  1488. /**
  1489. * functions
  1490. */
  1491.  
  1492. function showGui(temp.version) {
  1493. // if the program is already existing
  1494. // destroy it, so we can replace it
  1495. if (GuiWindow_TileEditor != NULL)
  1496. GuiWindow_TileEditor.destroy();
  1497. new GuiWindowCtrl("GuiWindow_TileEditor") {
  1498. profile = GuiBlueWindowProfile;
  1499. canminimize =
  1500. canmaximize = false;
  1501. closequery = true;
  1502. width = 304;
  1503. height = 304;
  1504. x = screenwidth - width;
  1505. text = " Tile Editor v" @ temp.version SPC "(Layer 1)";
  1506.  
  1507. // initialize the program with the defaults
  1508. this.version = temp.version;
  1509. this.tilesetImage = "TILES";
  1510. this.editingLayer = 0;
  1511. this.editingLevel = isonmap ? player.gmap.name : player.level.name;
  1512. this.pasteMode = PASTEMODE.NORMAL;
  1513. new GuiShowImgCtrl("GuiShowImg_TileEditor_Icon") {
  1514. useownprofile = true;
  1515. profile.modal = false;
  1516. x = 8;
  1517. y = 4;
  1518. width = 16;
  1519. height = 16;
  1520. image = "tileeditor_icon_1-1.png";
  1521. }
  1522. new GuiMenuCtrl("GuiMenu_TileEditor") {
  1523. profile = GuiBlueTextEditProfile;
  1524. x = 6;
  1525. y = 24;
  1526. width = 304 - x * 2;
  1527. height = 20;
  1528. clearmenus();
  1529. with (addmenu("File")) {
  1530. profile = GuiBluePopUpMenuProfile;
  1531. textprofile = GuiBlueTextListProfile;
  1532. addrow(0, "New Level").hint = "Create a new Graal level at the specified filepath";
  1533. addrow(1, "Update Level").hint = "Save the tile changes to the level file now";
  1534. addrow(2, "Edit Links").hint = "Modify Level Links";
  1535. addrow(3, "Open Clipboard").hint = "Open a clipboard file saved on the server";
  1536. addrow(4, "Save Clipboard").hint = "Save the current selection as a clipboard file on the server";
  1537. addrow(5, "Exit");
  1538. }
  1539. with (addmenu("Edit")) {
  1540. profile = GuiBluePopUpMenuProfile;
  1541. textprofile = GuiBlueTextListProfile;
  1542. temp.ctrlKey = getplatform() == "mac" ? "CMD" : "CTRL";
  1543. addrow(0, "Undo").hint = "Undo the previous tile paste (" @ temp.ctrlKey @ "+Z)";
  1544. addrow(1, "Redo").hint = "Redo the previous undone paste (" @ temp.ctrlKey @ "+Y)";
  1545. }
  1546. with (addmenu("View")) {
  1547. profile = GuiBluePopUpMenuProfile;
  1548. textprofile = GuiBlueTextListProfile;
  1549. addrow(0, "Fade inactive layers").hint = "Fades the inactive tilelayers, so you can focus on the layer you need to edit";
  1550. addrow(1, "Grid").hint = "Forms a grid to measure and be more precise with tile placement";
  1551. addrow(2, "Extra cursor info").hint = "Displays coordinates and selection size at the cursor";
  1552. }
  1553. with (addmenu("Tileset")) {
  1554. profile = GuiBluePopUpMenuProfile;
  1555. textprofile = GuiBlueTextListProfile;
  1556. addrow(0, "Use image").hint = "Show an image to select from, rather than tiledefs";
  1557. addrow(1, "Use tiledefs").hint = "Show the current tiledefs to select from";
  1558. }
  1559. with (addmenu("Layer")) {
  1560. profile = GuiBluePopUpMenuProfile;
  1561. textprofile = GuiBlueTextListProfile;
  1562. addrow(0, "Add").hint = "Add an additional tilelayer to the top of the current level";
  1563. addrow(1, "Remove").hint = "Remove the top tilelayer of the current level";
  1564. for (temp.i = 0; temp.i < tilelayercount; temp.i++)
  1565. addrow(temp.i + 2, temp.i + 1).hint = "Change the current editing layer to" SPC (temp.i + 1);
  1566. setrowbyid(2, "*1");
  1567. }
  1568. with (addmenu("Options")) {
  1569. profile = GuiBluePopUpMenuProfile;
  1570. textprofile = GuiBlueTextListProfile;
  1571. temp.obj = addrow(0, "External");
  1572. temp.obj.hint = "Toggle between using an internal window and an external window";
  1573. GuiWindow_TileEditor.externalToggleMenuRowObj = temp.obj;
  1574. addrow(1, "Help").hint = "Open an internet browser window/tab to the graalonline forum thread";
  1575. addrow(2, "Check for update").hint = "Checks online if there is an updated version";
  1576. }
  1577. new GuiButtonCtrl("GuiButton_TileEditor_PasteMode") {
  1578. profile = GuiBlueButtonProfile;
  1579. x = 248;
  1580. y = 0;
  1581. width = 40;
  1582. height = 20;
  1583. text = "";
  1584. new GuiShowImgCtrl("GuiShowImg_TileEditor_PasteMode") {
  1585. useownprofile = true;
  1586. profile.modal = false;
  1587. image = "tileeditor_bucket_1-1.png";
  1588. x = 12;
  1589. y = 2;
  1590. }
  1591. }
  1592. }
  1593. new GuiScrollCtrl("GuiScroll_TileEditor") {
  1594. profile = GuiBlueScrollProfile;
  1595. x = 6;
  1596. y = 44;
  1597. width = 304 - x * 2;
  1598. height = 304 - y - 6;
  1599. hScrollBar = "alwaysOn";
  1600. vScrollBar = "alwaysOn";
  1601. new GuiDrawingPanel("GuiDrawingPanel_TileEditor") {
  1602. width = 2048;
  1603. height = 512;
  1604. clearall();
  1605. drawimage(0, 0, GuiWindow_TileEditor.tilesetImage);
  1606. cursor = "crosshair";
  1607. }
  1608. }
  1609. }
  1610. // the cursor is changed to a crosshair while the
  1611. // program is open
  1612. GraalControl.cursor = "crosshair";
  1613. }
  1614.  
  1615. function drawGuiSelect() {
  1616. // draws the tile selection box on the gui
  1617.  
  1618. if (GuiWindow_TileEditor.tileSelectStart[0] <= GuiWindow_TileEditor.tileSelectEnd[0]) {
  1619. temp.tsx = GuiWindow_TileEditor.tileSelectStart[0];
  1620. temp.tex = GuiWindow_TileEditor.tileSelectEnd[0] + 16;
  1621. } else {
  1622. temp.tsx = GuiWindow_TileEditor.tileSelectEnd[0];
  1623. temp.tex = GuiWindow_TileEditor.tileSelectStart[0] + 16;
  1624. }
  1625. if (GuiWindow_TileEditor.tileSelectStart[1] <= GuiWindow_TileEditor.tileSelectEnd[1]) {
  1626. temp.tsy = GuiWindow_TileEditor.tileSelectStart[1];
  1627. temp.tey = GuiWindow_TileEditor.tileSelectEnd[1] + 16;
  1628. } else {
  1629. temp.tsy = GuiWindow_TileEditor.tileSelectEnd[1];
  1630. temp.tey = GuiWindow_TileEditor.tileSelectStart[1] + 16;
  1631. }
  1632.  
  1633. if (Gui_TileEditor_Select != NULL) {
  1634. Gui_TileEditor_Select.x = temp.tsx;
  1635. Gui_TileEditor_Select.y = temp.tsy;
  1636. Gui_TileEditor_Select.width = temp.tex - temp.tsx;
  1637. Gui_TileEditor_Select.height = temp.tey - temp.tsy;
  1638. return;
  1639. }
  1640.  
  1641. with (GuiDrawingPanel_TileEditor) {
  1642. new GuiControl("Gui_TileEditor_Select") {
  1643. useownprofile = true;
  1644. profile.cankeyfocus =
  1645. profile.modal = false;
  1646. profile.border = 3;
  1647. x = temp.tsx;
  1648. y = temp.tsy;
  1649. width = temp.tex - temp.tsx;
  1650. height = temp.tey - temp.tsy;
  1651. red =
  1652. green =
  1653. blue = 0.0;
  1654. }
  1655. }
  1656. }
  1657.  
  1658. function drawSelect() {
  1659. // draws the tile selection box on the level
  1660.  
  1661. if (GuiWindow_TileEditor.tileSelectStart[0] <= GuiWindow_TileEditor.tileSelectEnd[0]) {
  1662. temp.tsx = GuiWindow_TileEditor.tileSelectStart[0];
  1663. temp.tex = GuiWindow_TileEditor.tileSelectEnd[0] + 1.0;
  1664. } else {
  1665. temp.tsx = GuiWindow_TileEditor.tileSelectEnd[0];
  1666. temp.tex = GuiWindow_TileEditor.tileSelectStart[0] + 1.0;
  1667. }
  1668. if (GuiWindow_TileEditor.tileSelectStart[1] <= GuiWindow_TileEditor.tileSelectEnd[1]) {
  1669. temp.tsy = GuiWindow_TileEditor.tileSelectStart[1];
  1670. temp.tey = GuiWindow_TileEditor.tileSelectEnd[1] + 1.0;
  1671. } else {
  1672. temp.tsy = GuiWindow_TileEditor.tileSelectEnd[1];
  1673. temp.tey = GuiWindow_TileEditor.tileSelectStart[1] + 1.0;
  1674. }
  1675.  
  1676. with (findimg(200)) {
  1677. layer = 0;
  1678. polygon = {
  1679. temp.tsx, temp.tsy,
  1680. temp.tex, temp.tsy,
  1681. temp.tex, temp.tey,
  1682. temp.tsx, temp.tey
  1683. };
  1684. red = 0.0;
  1685. green = 0.0;
  1686. blue = 0.0;
  1687. alpha = 0.6;
  1688. }
  1689.  
  1690. // display the pastemode icon
  1691. with (findimg(201)) {
  1692. layer = 0;
  1693. image = GuiWindow_TileEditor.pasteMode == PASTEMODE.FILL ? "tileeditor_bucket_1-1.png" : "tileeditor_pencil_1-1.png";
  1694. x = temp.tsx;
  1695. y = temp.tsy - 1.5;
  1696. }
  1697.  
  1698. // display the top left corner x , y
  1699. with (findimg(202)) {
  1700. layer = 0;
  1701. text = temp.tsx @ ", " @ temp.tsy;
  1702. zoom = 0.6;
  1703. x = temp.tsx - 1.5 - gettextwidth(zoom, "", "", text) / 32;
  1704. y = temp.tsy;
  1705. }
  1706.  
  1707. // display the bottom right corner x , y
  1708. with (findimg(203)) {
  1709. layer = 0;
  1710. text = (temp.tex - 1) @ ", " @ (temp.tey - 1);
  1711. x = temp.tex + 0.5;
  1712. y = temp.tey - 1;
  1713. zoom = 0.6;
  1714. }
  1715.  
  1716. // display the (width , height)
  1717. with (findimg(204)) {
  1718. layer = 0;
  1719. text = "(" @ (temp.tex - temp.tsx) @ ", " @ (temp.tey - temp.tsy) @ ")";
  1720. zoom = 0.6;
  1721. x = temp.tsx + (temp.tex - temp.tsx) / 2 - gettextwidth(zoom, "", "", text) / 32;
  1722. y = temp.tey + 0.5;
  1723. }
  1724. }
  1725.  
  1726. function showFileOpenGui() {
  1727. // if the Open or Save window already exists
  1728. // destroy it to be replaced
  1729. if (GuiWindow_TileEditor_FileSave != NULL)
  1730. GuiWindow_TileEditor_FileSave.destroy();
  1731. if (GuiWindow_TileEditor_FileOpen != NULL)
  1732. GuiWindow_TileEditor_FileOpen.destroy();
  1733. new GuiWindowCtrl("GuiWindow_TileEditor_FileOpen") {
  1734. profile = GuiBlueWindowProfile;
  1735. destroyonhide = true;
  1736. canresize =
  1737. canminimize =
  1738. canmaximize = false;
  1739. width = 304;
  1740. height = 304;
  1741. x = screenwidth / 2 - width / 2;
  1742. y = screenheight / 2 - height / 2;
  1743. text = "Open";
  1744. new GuiScrollCtrl("GuiScroll_TileEditor_FileOpen_Preview_Image") {
  1745. x = 6;
  1746. y = 24;
  1747. profile = GuiBlueScrollProfile;
  1748. width = 88;
  1749. height = 88;
  1750. hScrollBar = "alwaysOff";
  1751. vScrollBar = "alwaysOff";
  1752. new GuiStretchCtrl("GuiStretch_TileEditor_FileOpen") {
  1753. width = 84;
  1754. height = 84;
  1755. new GuiDrawingPanel("GuiDrawingPanel_TileEditor_FileOpen_Preview") {
  1756. clearall();
  1757. }
  1758. }
  1759. }
  1760. new GuiScrollCtrl("GuiScroll_TileEditor_FileOpen_Preview_Text") {
  1761. profile = GuiBlueScrollProfile;
  1762. x = 92;
  1763. y = 24;
  1764. width = 304 - x - 6;
  1765. height = 88;
  1766. hScrollBar = "dynamic";
  1767. vScrollBar = "dynamic";
  1768. new GuiTextCtrl("GuiText_TileEditor_FileOpen_Title") {
  1769. profile = GuiBlueTextProfile;
  1770. x = 4;
  1771. height = 20;
  1772. text = "Title:";
  1773. }
  1774. new GuiTextCtrl("GuiText_TileEditor_FileOpen_Title_Value") {
  1775. profile = GuiBlueTextProfile;
  1776. x = 56;
  1777. height = 20;
  1778. text = "N / A";
  1779. }
  1780. new GuiTextCtrl("GuiText_TileEditor_FileOpen_Extent") {
  1781. profile = GuiBlueTextProfile;
  1782. x = 4;
  1783. y = 18;
  1784. height = 20;
  1785. text = "Extent:";
  1786. }
  1787. new GuiTextCtrl("GuiText_TileEditor_FileOpen_Extent_Value") {
  1788. profile = GuiBlueTextProfile;
  1789. x = 56;
  1790. y = 18;
  1791. height = 20;
  1792. text = @{"N / A", "N / A"};
  1793. }
  1794. new GuiTextCtrl("GuiText_TileEditor_FileOpen_Created") {
  1795. profile = GuiBlueTextProfile;
  1796. x = 4;
  1797. y = 36;
  1798. height = 20;
  1799. text = "Created:";
  1800. }
  1801. new GuiTextCtrl("GuiText_TileEditor_FileOpen_Created_Value") {
  1802. profile = GuiBlueTextProfile;
  1803. x = 56;
  1804. y = 36;
  1805. height = 20;
  1806. text = "N / A";
  1807. }
  1808. }
  1809. new GuiScrollCtrl("GuiScroll_TileEditor_FileOpen_Browse") {
  1810. profile = GuiBlueScrollProfile;
  1811. x = 6;
  1812. y = 112;
  1813. width = 304 - x * 2;
  1814. height = 160;
  1815. hScrollBar = "dynamic";
  1816. vScrollBar = "dynamic";
  1817. new GuiTreeViewCtrl("GuiTreeView_TileEditor_FileOpen") {
  1818. profile = GuiBlueTreeViewProfile;
  1819. width = 132;
  1820. fitparentwidth = true;
  1821. }
  1822. }
  1823. new GuiButtonCtrl("GuiButton_TileEditor_FileOpen_Delete") {
  1824. profile = GuiBlueButtonProfile;
  1825. x = 6;
  1826. y = 273;
  1827. width = 70;
  1828. height = 24;
  1829. text = "Delete";
  1830. }
  1831. new GuiButtonCtrl("GuiButton_TileEditor_FileOpen_Open") {
  1832. profile = GuiBlueButtonProfile;
  1833. x = 98;
  1834. y = 273;
  1835. width = 100;
  1836. height = 24;
  1837. text = "Open";
  1838. }
  1839. new GuiButtonCtrl("GuiButton_TileEditor_FileOpen_Cancel") {
  1840. profile = GuiBlueButtonProfile;
  1841. x = 198;
  1842. y = 273;
  1843. width = 100;
  1844. height = 24;
  1845. text = "Cancel";
  1846. }
  1847. }
  1848. // once the gui is created, let's request a list of
  1849. // clipboard files which the player can use
  1850. triggerserver("gui", this.name, RPL.LISTCLIPBOARDFOLDER);
  1851. }
  1852.  
  1853. function showFileSaveGui() {
  1854. // if the Open or Save window already exists
  1855. // destroy it to be replaced
  1856. if (GuiWindow_TileEditor_FileOpen != NULL)
  1857. GuiWindow_TileEditor_FileOpen.destroy();
  1858. if (GuiWindow_TileEditor_FileSave != NULL)
  1859. GuiWindow_TileEditor_FileSave.destroy();
  1860. new GuiWindowCtrl("GuiWindow_TileEditor_FileSave") {
  1861. profile = GuiBlueWindowProfile;
  1862. destroyonhide = true;
  1863. canresize =
  1864. canminimize =
  1865. canmaximize = false;
  1866. width = 304;
  1867. height = 304;
  1868. x = screenwidth / 2 - width / 2;
  1869. y = screenheight / 2 - height / 2;
  1870. text = "Save";
  1871. new GuiScrollCtrl("GuiScroll_TileEditor_FileSave_Preview_Image") {
  1872. x = 6;
  1873. y = 24;
  1874. profile = GuiBlueScrollProfile;
  1875. width = 88;
  1876. height = 88;
  1877. hScrollBar = "alwaysOff";
  1878. vScrollBar = "alwaysOff";
  1879. new GuiStretchCtrl("GuiStretch_TileEditor_FileSave") {
  1880. width = 84;
  1881. height = 84;
  1882. new GuiDrawingPanel("GuiDrawingPanel_TileEditor_FileSave_Preview") {
  1883. clearall();
  1884. }
  1885. }
  1886. }
  1887. new GuiScrollCtrl("GuiScroll_TileEditor_FileSave_Preview_Text") {
  1888. profile = GuiBlueScrollProfile;
  1889. x = 92;
  1890. y = 24;
  1891. width = 304 - x - 6;
  1892. height = 88;
  1893. hScrollBar = "dynamic";
  1894. vScrollBar = "dynamic";
  1895. new GuiTextCtrl("GuiText_TileEditor_FileSave_Title") {
  1896. profile = GuiBlueTextProfile;
  1897. x = 4;
  1898. height = 20;
  1899. text = "Title:";
  1900. }
  1901. new GuiTextCtrl("GuiText_TileEditor_FileSave_Title_Value") {
  1902. profile = GuiBlueTextProfile;
  1903. x = 56;
  1904. height = 20;
  1905. text = "N / A";
  1906. }
  1907. new GuiTextCtrl("GuiText_TileEditor_FileSave_Extent") {
  1908. profile = GuiBlueTextProfile;
  1909. x = 4;
  1910. y = 18;
  1911. height = 20;
  1912. text = "Extent:";
  1913. }
  1914. new GuiTextCtrl("GuiText_TileEditor_FileSave_Extent_Value") {
  1915. profile = GuiBlueTextProfile;
  1916. x = 56;
  1917. y = 18;
  1918. height = 20;
  1919. text = @{"N / A", "N / A"};
  1920. }
  1921. new GuiTextCtrl("GuiText_TileEditor_FileSave_Created") {
  1922. profile = GuiBlueTextProfile;
  1923. x = 4;
  1924. y = 36;
  1925. height = 20;
  1926. text = "Created:";
  1927. }
  1928. new GuiTextCtrl("GuiText_TileEditor_FileSave_Created_Value") {
  1929. profile = GuiBlueTextProfile;
  1930. x = 56;
  1931. y = 36;
  1932. height = 20;
  1933. text = "N / A";
  1934. }
  1935. }
  1936. new GuiScrollCtrl("GuiScroll_TileEditor_FileSave_Browse") {
  1937. profile = GuiBlueScrollProfile;
  1938. x = 6;
  1939. y = 112;
  1940. width = 304 - x * 2;
  1941. height = 141;
  1942. hScrollBar = "dynamic";
  1943. vScrollBar = "dynamic";
  1944. new GuiTreeViewCtrl("GuiTreeView_TileEditor_FileSave") {
  1945. profile = GuiBlueTreeViewProfile;
  1946. width = 132;
  1947. fitparentwidth = true;
  1948. }
  1949. }
  1950. new GuiTextEditCtrl("GuiTextEdit_TileEditor_FileSave_FilePath") {
  1951. profile = GuiBlueTextEditProfile;
  1952. x = 6;
  1953. y = 253;
  1954. width = 304 - x * 2;
  1955. height = 20;
  1956. }
  1957. new GuiButtonCtrl("GuiButton_TileEditor_FileSave_Delete") {
  1958. profile = GuiBlueButtonProfile;
  1959. x = 6;
  1960. y = 273;
  1961. width = 70;
  1962. height = 24;
  1963. text = "Delete";
  1964. }
  1965. new GuiButtonCtrl("GuiButton_TileEditor_FileSave_Save") {
  1966. profile = GuiBlueButtonProfile;
  1967. x = 98;
  1968. y = 273;
  1969. width = 100;
  1970. height = 24;
  1971. text = "Save";
  1972. }
  1973. new GuiButtonCtrl("GuiButton_TileEditor_FileSave_Cancel") {
  1974. profile = GuiBlueButtonProfile;
  1975. x = 198;
  1976. y = 273;
  1977. width = 100;
  1978. height = 24;
  1979. text = "Cancel";
  1980. }
  1981. }
  1982. // once the gui is created, let's request a list of
  1983. // clipboard files which the player can use
  1984. triggerserver("gui", this.name, RPL.LISTCLIPBOARDFOLDER);
  1985. }
  1986.  
  1987. function setClipboardFromLevel() {
  1988. // set the clipboard to data from the level selection
  1989.  
  1990. if (GuiWindow_TileEditor.tileSelectStart[0] <= GuiWindow_TileEditor.tileSelectEnd[0]) {
  1991. temp.tsx = GuiWindow_TileEditor.tileSelectStart[0];
  1992. temp.tex = GuiWindow_TileEditor.tileSelectEnd[0] + 1;
  1993. } else {
  1994. temp.tsx = GuiWindow_TileEditor.tileSelectEnd[0];
  1995. temp.tex = GuiWindow_TileEditor.tileSelectStart[0] + 1;
  1996. }
  1997. if (GuiWindow_TileEditor.tileSelectStart[1] <= GuiWindow_TileEditor.tileSelectEnd[1]) {
  1998. temp.tsy = GuiWindow_TileEditor.tileSelectStart[1];
  1999. temp.tey = GuiWindow_TileEditor.tileSelectEnd[1] + 1;
  2000. } else {
  2001. temp.tsy = GuiWindow_TileEditor.tileSelectEnd[1];
  2002. temp.tey = GuiWindow_TileEditor.tileSelectStart[1] + 1;
  2003. }
  2004.  
  2005. GuiWindow_TileEditor.clipboard = {};
  2006. for (temp.y = temp.tsy; temp.y < temp.tey; temp.y++) {
  2007. temp.arr = {};
  2008. for (temp.x = temp.tsx; temp.x < temp.tex; temp.x++) {
  2009. if (GuiWindow_TileEditor.editingLayer == 0)
  2010. temp.tile = tiles[temp.x, temp.y];
  2011. else
  2012. temp.tile = tilelayers[GuiWindow_TileEditor.editingLayer].tiles[temp.x, temp.y];
  2013. temp.arr.add(temp.tile);
  2014. }
  2015. GuiWindow_TileEditor.clipboard.add(temp.arr);
  2016. }
  2017.  
  2018. drawClipboardPreview();
  2019. }
  2020.  
  2021. function setClipboardFromGui() {
  2022. // set the clipboard to data from the gui selection
  2023.  
  2024. if (GuiWindow_TileEditor.tileSelectStart[0] < 0)
  2025. GuiWindow_TileEditor.tileSelectStart[0] = 0;
  2026. elseif(GuiWindow_TileEditor.tileSelectStart[0] >= GuiDrawingPanel_TileEditor.width)
  2027. GuiWindow_TileEditor.tileSelectStart[0] = GuiDrawingPanel_TileEditor.width - 16;
  2028. if (GuiWindow_TileEditor.tileSelectStart[1] < 0)
  2029. GuiWindow_TileEditor.tileSelectStart[1] = 0;
  2030. elseif(GuiWindow_TileEditor.tileSelectStart[1] >= GuiDrawingPanel_TileEditor.height)
  2031. GuiWindow_TileEditor.tileSelectStart[1] = GuiDrawingPanel_TileEditor.height - 16;
  2032. if (GuiWindow_TileEditor.tileSelectEnd[0] < 0)
  2033. GuiWindow_TileEditor.tileSelectEnd[0] = 0;
  2034. elseif(GuiWindow_TileEditor.tileSelectEnd[0] >= GuiDrawingPanel_TileEditor.width)
  2035. GuiWindow_TileEditor.tileSelectEnd[0] = GuiDrawingPanel_TileEditor.width - 16;
  2036. if (GuiWindow_TileEditor.tileSelectEnd[1] < 0)
  2037. GuiWindow_TileEditor.tileSelectEnd[1] = 0;
  2038. elseif(GuiWindow_TileEditor.tileSelectEnd[1] >= GuiDrawingPanel_TileEditor.height)
  2039. GuiWindow_TileEditor.tileSelectEnd[1] = GuiDrawingPanel_TileEditor.height - 16;
  2040.  
  2041. if (GuiWindow_TileEditor.tileSelectStart[0] <= GuiWindow_TileEditor.tileSelectEnd[0]) {
  2042. temp.tsx = GuiWindow_TileEditor.tileSelectStart[0];
  2043. temp.tex = GuiWindow_TileEditor.tileSelectEnd[0] + 16;
  2044. } else {
  2045. temp.tsx = GuiWindow_TileEditor.tileSelectEnd[0];
  2046. temp.tex = GuiWindow_TileEditor.tileSelectStart[0] + 16;
  2047. }
  2048. if (GuiWindow_TileEditor.tileSelectStart[1] <= GuiWindow_TileEditor.tileSelectEnd[1]) {
  2049. temp.tsy = GuiWindow_TileEditor.tileSelectStart[1];
  2050. temp.tey = GuiWindow_TileEditor.tileSelectEnd[1] + 16;
  2051. } else {
  2052. temp.tsy = GuiWindow_TileEditor.tileSelectEnd[1];
  2053. temp.tey = GuiWindow_TileEditor.tileSelectStart[1] + 16;
  2054. }
  2055.  
  2056. GuiWindow_TileEditor.clipboard = {};
  2057. for (temp.y = temp.tsy; temp.y < temp.tey; temp.y += 16) {
  2058. temp.arr = {};
  2059. for (temp.x = temp.tsx; temp.x < temp.tex; temp.x += 16)
  2060. temp.arr.add(getXYTile(temp.x, temp.y));
  2061. GuiWindow_TileEditor.clipboard.add(temp.arr);
  2062. }
  2063.  
  2064. drawClipboardPreview();
  2065. }
  2066.  
  2067. function drawClipboardPreview() {
  2068. // draw the clipboard preview gui which follows the mouse
  2069.  
  2070. // if it already exists, destroy it to be replaced
  2071. if (GuiShowImg_TileEditor_ClipboardPreview != NULL)
  2072. GuiShowImg_TileEditor_ClipboardPreview.destroy();
  2073. new GuiShowImgCtrl("GuiShowImg_TileEditor_ClipboardPreview") {
  2074. useownprofile = true;
  2075. profile.cankeyfocus =
  2076. profile.modal = false;
  2077. x = screenx(int(mousex), 0) - 2;
  2078. y = screeny(0, int(mousey)) - 2;
  2079. width = GuiWindow_TileEditor.clipboard[0].size() * 16 + 4;
  2080. height = GuiWindow_TileEditor.clipboard.size() * 16 + 4;
  2081. polygon = {
  2082. 0, 0,
  2083. width, 0,
  2084. width, height,
  2085. 0, height
  2086. };
  2087. red =
  2088. green =
  2089. blue = 0.0;
  2090. alpha = 0.6;
  2091. new GuiDrawingPanel("GuiDrawingPanel_TileEditor_ClipboardPreview") {
  2092. useownprofile = true;
  2093. profile.cankeyfocus =
  2094. profile.modal = false;
  2095. x =
  2096. y = 2;
  2097. width = GuiWindow_TileEditor.clipboard[0].size() * 16;
  2098. height = GuiWindow_TileEditor.clipboard.size() * 16;
  2099. clearall();
  2100.  
  2101. // draw the tiles to the preview based on
  2102. // the currently selected tileset image
  2103. for (temp.y = 0; temp.y < GuiWindow_TileEditor.clipboard.size(); temp.y++) {
  2104. for (temp.x = 0; temp.x < GuiWindow_TileEditor.clipboard[0].size(); temp.x++) {
  2105. temp.xy = getTileXY(GuiWindow_TileEditor.clipboard[temp.y][temp.x]);
  2106. drawimagerectangle(temp.x * 16, temp.y * 16, GuiWindow_TileEditor.tilesetImage, temp.xy[0], temp.xy[1], 16, 16);
  2107. }
  2108. }
  2109. flickering = true;
  2110. alpha = 0.5;
  2111. }
  2112. }
  2113. // push the preview gui behind all gui's inside of GraalControl
  2114. GuiShowImg_TileEditor_ClipboardPreview.pushtoback();
  2115. }
  2116.  
  2117. function getFloodedAreaZero(temp.x, temp.y) {
  2118. // the flood fill algorithm for tiles on layer zero
  2119. // it uses a non-recursive, stack based approach
  2120.  
  2121. temp.tile = tiles[temp.x, temp.y];
  2122. temp.a = {temp.x, temp.y, temp.x, temp.y};
  2123. temp.q = {{temp.x, temp.y}};
  2124. temp.tileMap = new [height][width];
  2125. maxlooplimit = 100000;
  2126. temp.minX = temp.x - 64;
  2127. if (temp.minX < 0)
  2128. temp.minX = 0;
  2129. temp.minY = temp.y - 64;
  2130. if (temp.minY < 0)
  2131. temp.minY = 0;
  2132. temp.maxX = temp.x + 64;
  2133. if (temp.maxX >= width)
  2134. temp.maxX = width - 1;
  2135. temp.maxY = temp.y + 64;
  2136. if (temp.maxY >= height)
  2137. temp.maxY = height - 1;
  2138. while (temp.q.size() != 0) {
  2139. temp.n = temp.q[0];
  2140. temp.q.delete(0);
  2141. temp.x = temp.n[0];
  2142. temp.y = temp.n[1];
  2143. if (tiles[temp.x, temp.y] == temp.tile
  2144. && !temp.tileMap[temp.y][temp.x]) {
  2145. temp.tileMap[temp.y][temp.x] = true;
  2146. temp.a.add(temp.n);
  2147. if (temp.a.size() == 4100)
  2148. break;
  2149. if (temp.x < temp.a[0])
  2150. temp.a[0] = temp.x;
  2151. elseif (temp.x > temp.a[2])
  2152. temp.a[2] = temp.x;
  2153. if (temp.y < temp.a[1])
  2154. temp.a[1] = temp.y;
  2155. elseif (temp.y > temp.a[3])
  2156. temp.a[3] = temp.y;
  2157. if (temp.y > temp.minY)
  2158. temp.q.add({temp.x, temp.y - 1});
  2159. if (temp.x > temp.minX)
  2160. temp.q.add({temp.x - 1, temp.y});
  2161. if (temp.y < temp.maxY)
  2162. temp.q.add({temp.x, temp.y + 1});
  2163. if (temp.x < temp.maxX)
  2164. temp.q.add({temp.x + 1, temp.y});
  2165. }
  2166. }
  2167. return temp.a;
  2168. }
  2169.  
  2170. function getFloodedAreaLayer(temp.tileLayer, temp.x, temp.y) {
  2171. // the flood fill algorithm for tiles on layers 1+
  2172. // it uses a non-recursive, stack based approach
  2173.  
  2174. temp.tile = temp.tileLayer.tiles[temp.x, temp.y];
  2175. temp.a = {temp.x, temp.y, temp.x, temp.y};
  2176. temp.q = {{temp.x, temp.y}};
  2177. temp.tileMap = new [height][width];
  2178. maxlooplimit = 100000;
  2179. temp.minX = temp.x - 64;
  2180. if (temp.minX < 0)
  2181. temp.minX = 0;
  2182. temp.minY = temp.y - 64;
  2183. if (temp.minY < 0)
  2184. temp.minY = 0;
  2185. temp.maxX = temp.x + 64;
  2186. if (temp.maxX >= width)
  2187. temp.maxX = width - 1;
  2188. temp.maxY = temp.y + 64;
  2189. if (temp.maxY >= height)
  2190. temp.maxY = height - 1;
  2191. while (temp.q.size() != 0) {
  2192. temp.n = temp.q[0];
  2193. temp.q.delete(0);
  2194. temp.x = temp.n[0];
  2195. temp.y = temp.n[1];
  2196. if (temp.tileLayer.tiles[temp.x, temp.y] == temp.tile
  2197. && !temp.tileMap[temp.y][temp.x]) {
  2198. temp.tileMap[temp.y][temp.x] = true;
  2199. temp.a.add(temp.n);
  2200. if (temp.a.size() == 4100)
  2201. break;
  2202. if (temp.x < temp.a[0])
  2203. temp.a[0] = temp.x;
  2204. elseif (temp.x > temp.a[2])
  2205. temp.a[2] = temp.x;
  2206. if (temp.y < temp.a[1])
  2207. temp.a[1] = temp.y;
  2208. elseif (temp.y > temp.a[3])
  2209. temp.a[3] = temp.y;
  2210. if (temp.y > temp.minY)
  2211. temp.q.add({temp.x, temp.y - 1});
  2212. if (temp.x > temp.minX)
  2213. temp.q.add({temp.x - 1, temp.y});
  2214. if (temp.y < temp.maxY)
  2215. temp.q.add({temp.x, temp.y + 1});
  2216. if (temp.x < temp.maxX)
  2217. temp.q.add({temp.x + 1, temp.y});
  2218. }
  2219. }
  2220. return temp.a;
  2221. }
  2222.  
  2223. function editorUndo() {
  2224. // if the program isn't open, ignore it
  2225. if (GuiWindow_TileEditor == NULL)
  2226. return;
  2227. // if you've reached the end of history
  2228. // there's nothing to undo
  2229. if (GuiWindow_TileEditor.historyIndex == GuiWindow_TileEditor.history.size()) {
  2230. shared.adminmessage("nothing to undo");
  2231. return;
  2232. }
  2233.  
  2234. // send a standard paste request to the server
  2235. // providing the data from the history
  2236. triggerserver(
  2237. "gui",
  2238. this.name,
  2239. RPL.PLACETILES,
  2240. GuiWindow_TileEditor.history[GuiWindow_TileEditor.historyIndex][3],
  2241. GuiWindow_TileEditor.history[GuiWindow_TileEditor.historyIndex][0],
  2242. GuiWindow_TileEditor.history[GuiWindow_TileEditor.historyIndex][1],
  2243. GuiWindow_TileEditor.history[GuiWindow_TileEditor.historyIndex][2]
  2244. );
  2245.  
  2246. // increase stack position
  2247. GuiWindow_TileEditor.historyIndex++;
  2248. }
  2249.  
  2250. function editorRedo() {
  2251. // if the program is closed, ignore
  2252. if (GuiWindow_TileEditor == NULL)
  2253. return;
  2254. // if you've reached the beginning of history
  2255. // there is nothing to redo
  2256. if (GuiWindow_TileEditor.historyIndex == 0) {
  2257. shared.adminmessage("nothing to redo");
  2258. return;
  2259. }
  2260.  
  2261. // decrease the stack position
  2262. GuiWindow_TileEditor.historyIndex--;
  2263.  
  2264. // send a standard paste request to the server
  2265. // providing the data from the history
  2266. triggerserver(
  2267. "gui",
  2268. this.name,
  2269. RPL.PLACETILES,
  2270. GuiWindow_TileEditor.history[GuiWindow_TileEditor.historyIndex][4],
  2271. GuiWindow_TileEditor.history[GuiWindow_TileEditor.historyIndex][0],
  2272. GuiWindow_TileEditor.history[GuiWindow_TileEditor.historyIndex][1],
  2273. GuiWindow_TileEditor.history[GuiWindow_TileEditor.historyIndex][2]
  2274. );
  2275. }
  2276.  
  2277. function updateFadeEffect() {
  2278. // enables or disables the fading effect of
  2279. // all inactive tilelayers
  2280.  
  2281. if (GuiWindow_TileEditor.fadeLayers) {
  2282. for (temp.i = 0; temp.i < tilelayercount; temp.i++) {
  2283. if (temp.i == GuiWindow_TileEditor.editingLayer) {
  2284. tilelayers[temp.i].red =
  2285. tilelayers[temp.i].green =
  2286. tilelayers[temp.i].blue =
  2287. tilelayers[temp.i].alpha = 1.0;
  2288. } else {
  2289. tilelayers[temp.i].red =
  2290. tilelayers[temp.i].green =
  2291. tilelayers[temp.i].blue = 0.25;
  2292. if (temp.i != 0)
  2293. tilelayers[temp.i].alpha = 0.25;
  2294. }
  2295. }
  2296. } else {
  2297. for (temp.i = 0; temp.i < tilelayercount; temp.i++) {
  2298. tilelayers[temp.i].red =
  2299. tilelayers[temp.i].green =
  2300. tilelayers[temp.i].blue =
  2301. tilelayers[temp.i].alpha = 1.0;
  2302. }
  2303. }
  2304. }
  2305.  
  2306. function updateGridEffect() {
  2307. // enables or disables the grid effect
  2308.  
  2309. if (this.gridImageCount != NULL) {
  2310. hideimgs(300, 300 + this.gridImageCount);
  2311. this.gridImageCount = NULL;
  2312. }
  2313. if (GuiWindow_TileEditor.grid) {
  2314. temp.w = width;
  2315. temp.h = height;
  2316. for (temp.y = 0; temp.y < temp.h; temp.y++) {
  2317. with (findimg(300 + temp.i++)) {
  2318. layer = 3;
  2319. if (temp.y % 64 == 0) {
  2320. red = 1.0;
  2321. green = 0.0;
  2322. blue = 0.0;
  2323. polygon = {
  2324. 0, temp.y,
  2325. temp.w, temp.y,
  2326. temp.w, temp.y + 1/4,
  2327. 0, temp.y + 1/4
  2328. };
  2329. } elseif (temp.y % 32 == 0) {
  2330. red = 0.0;
  2331. green = 1.0;
  2332. blue = 0.0;
  2333. polygon = {
  2334. 0, temp.y,
  2335. temp.w, temp.y,
  2336. temp.w, temp.y + 3/16,
  2337. 0, temp.y + 3/16
  2338. };
  2339. } elseif (temp.y % 16 == 0) {
  2340. red = 1.0;
  2341. green = 0.0;
  2342. blue = 1.0;
  2343. polygon = {
  2344. 0, temp.y,
  2345. temp.w, temp.y,
  2346. temp.w, temp.y + 1/8,
  2347. 0, temp.y + 1/8
  2348. };
  2349. } elseif (temp.y % 8 == 0) {
  2350. red = 0.0;
  2351. green = 1.0;
  2352. blue = 1.0;
  2353. polygon = {
  2354. 0, temp.y,
  2355. temp.w, temp.y,
  2356. temp.w, temp.y + 1/16,
  2357. 0, temp.y + 1/16
  2358. };
  2359. } else {
  2360. polygon = {
  2361. 0, temp.y,
  2362. temp.w, temp.y,
  2363. temp.w, temp.y + 1/16,
  2364. 0, temp.y + 1/16
  2365. };
  2366. }
  2367. alpha = 0.5;
  2368. }
  2369. }
  2370. for (temp.x = 0; temp.x < temp.w; temp.x++) {
  2371. with (findimg(300 + temp.i++)) {
  2372. layer = 3;
  2373. if (temp.x % 64 == 0) {
  2374. red = 1.0;
  2375. green = 0.0;
  2376. blue = 0.0;
  2377. polygon = {
  2378. temp.x, 0,
  2379. temp.x, temp.h,
  2380. temp.x + 1/4, temp.h,
  2381. temp.x + 1/4, 0
  2382. };
  2383. } elseif (temp.x % 32 == 0) {
  2384. red = 0.0;
  2385. green = 1.0;
  2386. blue = 0.0;
  2387. polygon = {
  2388. temp.x, 0,
  2389. temp.x, temp.h,
  2390. temp.x + 3/16, temp.h,
  2391. temp.x + 3/16, 0
  2392. };
  2393. } elseif (temp.x % 16 == 0) {
  2394. red = 1.0;
  2395. green = 0.0;
  2396. blue = 1.0;
  2397. polygon = {
  2398. temp.x, 0,
  2399. temp.x, temp.h,
  2400. temp.x + 1/8, temp.h,
  2401. temp.x + 1/8, 0
  2402. };
  2403. } elseif (temp.x % 8 == 0) {
  2404. red = 0.0;
  2405. green = 1.0;
  2406. blue = 1.0;
  2407. polygon = {
  2408. temp.x, 0,
  2409. temp.x, temp.h,
  2410. temp.x + 1/16, temp.h,
  2411. temp.x + 1/16, 0
  2412. };
  2413. } else {
  2414. polygon = {
  2415. temp.x, 0,
  2416. temp.x, temp.h,
  2417. temp.x + 1/16, temp.h,
  2418. temp.x + 1/16, 0
  2419. };
  2420. }
  2421. alpha = 0.5;
  2422. }
  2423. }
  2424. this.gridImageCount = temp.i;
  2425. }
  2426. }
  2427.  
  2428. function getTileXY(temp.tile) {
  2429. // returns the position of the tile on the tileset image
  2430. // useful for rendering tiles on a drawing panel
  2431. return {
  2432. int(temp.tile % 16.0) * 16 + int(temp.tile / 512.0) * 256,
  2433. (int(temp.tile / 16.0) * 16) % 512
  2434. };
  2435. }
  2436.  
  2437. function getXYTile(temp.x, temp.y) {
  2438. // returns the tile from the position at the tileset image
  2439. // useful for getting tile data from a gui selection
  2440. return int(temp.x / 16.0) % 16 + int(temp.x / 256.0) * 512 + int(temp.y / 16.0) * 16 % 512;
  2441. }
  2442.  
  2443. /**
  2444. * the following are provided for public script interfacing
  2445. * in an effort to make it easier to integrate this tool
  2446. * into a staff tool manager
  2447. */
  2448.  
  2449. public function close() {
  2450. // asynchronous close operation
  2451. trigger("onCloseEditor");
  2452. }
  2453.  
  2454. public function open() {
  2455. // asynchronous open request operation
  2456. trigger("onRequestUse");
  2457. }
  2458. public function isOpen() {
  2459. // returns a boolean telling if the program
  2460. // is open or not
  2461. return (GuiWindow_TileEditor != NULL);
  2462. }
Add Comment
Please, Sign In to add comment