iMagicBae

Untitled

May 13th, 2020
161
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. findplayer("Graal5635647").addweapon(this.name);
  2. // Online Level NPC Editor
  3. // By fp4 (fowlplay4/Jerret)
  4.  
  5. // Note:
  6. //   (npcserver) requires rw access to the levels
  7. //   in order to update NPC changes.
  8. //
  9. // I.e: rw levels/*.nw
  10. //
  11. // Clientside Configuration is down below.
  12.  
  13. function onCreated() {
  14.   // Serverside Folder Configuration
  15.   this.levelfolders = {
  16.     "levels/%s",
  17.     "levels/shared/%s"
  18.   };
  19.   //levels/users/theirID/levels/levelname.nw
  20.   for (temp.pl: allplayers) {
  21.     temp.playerfolder = "levels/users/" @ temp.pl.account @ "/levels/";
  22.     if (!(temp.playerfolder in this.levelfolders)) {
  23.       this.levelfolders.add(temp.playerfolder @ "%s");
  24.     }
  25.   }
  26.   echo(this.levelfolders);
  27.   this.removenonexistantimages = false;
  28. }
  29.  
  30. function onActionServerSide() {
  31.   if (params[0] == "loadlevel") {
  32.     // Find Level
  33.     temp.file = getfile(params[1]);
  34.     // Check if Level Found
  35.     if (temp.file == NULL) {
  36.       player.triggerclient("weapon", this.name, "msg", format("Could not find the file %s for this level! Check Configuration.", params[1]));
  37.       return;
  38.     }
  39.     // Check if Player Has Access to Level
  40.     if (!player.hasright("r", temp.file)) {
  41.       player.triggerclient("weapon", this.name, "msg", "You don't have access to this level!");
  42.       return;
  43.     }
  44.     // Get Level Modification Time
  45.     temp.modtime = getfilemodtime(temp.file);
  46.     // Check if Level Locked
  47.     for (temp.pl: players) {
  48.       temp.lock = temp.pl.client.olne_lock;
  49.       if (temp.lock[0] == temp.file && temp.lock[1] == temp.modtime) {
  50.         player.triggerclient("weapon", this.name, "msg", format("%s is currently editing this level's NPCs!", (temp.pl.communityname ? temp.pl.communityname : temp.pl.account)));
  51.         return;
  52.       }
  53.     }
  54.     // Set Level Lock Flag
  55.     client.olne_lock = {temp.file, temp.modtime};
  56.     // Check if Readonly Access
  57.     temp.readonly = !player.hasright("w", temp.file);
  58.     // Load File
  59.     temp.lines.loadlines(temp.file);
  60.     // Parse NPC Sections of File
  61.     for (temp.line: temp.lines) {
  62.       if (temp.reading) {
  63.         if (temp.line == "NPCEND") {
  64.           temp.leveldata.add({
  65.             temp.npc_img,
  66.             temp.npc_x,
  67.             temp.npc_y,
  68.             temp.npc_script
  69.           });
  70.           temp.reading = false;
  71.         } else {
  72.           temp.npc_script.add(temp.line);
  73.         }
  74.       } else {
  75.         if (temp.line.starts("NPC ")) {
  76.           temp.tokens  = temp.line.tokenize();
  77.           if (temp.tokens.size() == 4) {
  78.             temp.npc_img = temp.tokens[1];
  79.             temp.npc_x   = temp.tokens[2];
  80.             temp.npc_y   = temp.tokens[3];
  81.             temp.npc_script = {};
  82.             temp.reading = true;
  83.           }
  84.         }
  85.       }
  86.     }
  87.     // Send Data to Client
  88.     player.triggerclient("weapon", this.name, "leveldata", temp.leveldata, temp.readonly);
  89.   }
  90.   else if (params[0] == "savelevel") {
  91.     // Find Level
  92.     temp.file = getfile(params[1]);
  93.     // Check for Write Access to File
  94.     if (!player.hasright("w", temp.file)) {
  95.       player.triggerclient("weapon", this.name, "msg", "You can't make changes to this level!");
  96.       return;
  97.     }
  98.     // Load Level
  99.     temp.lines.loadlines(temp.file);
  100.     temp.newlines = {};
  101.     // Parse Level Ignore NPC Sections
  102.     for (temp.line: temp.lines) {
  103.       if (temp.skipping) {
  104.         if (temp.line == "NPCEND") {
  105.           temp.skipping = false;
  106.         }
  107.       } else {
  108.         if (temp.line.starts("NPC ")) {
  109.           temp.skipping = true;
  110.         } else {
  111.           temp.newlines.add(temp.line);
  112.         }
  113.       }
  114.     }
  115.     // Parse NPC Data
  116.     temp.npcdata = params[2];
  117.     for (temp.data: temp.npcdata) {
  118.       temp.npc_img    = temp.data[0];
  119.       temp.npc_x      = temp.data[1];
  120.       temp.npc_y      = temp.data[2];
  121.       temp.npc_script = temp.data[3];
  122.       if ((this.removenonexistantimages && !fileexists(temp.npc_img)) || temp.npc_img.trim() == "") {
  123.         temp.npc_img = "-";
  124.       }
  125.       // Add NPC Sections to Level
  126.       temp.newlines.add(format("NPC %s %s %s", temp.npc_img, temp.npc_x, temp.npc_y));
  127.       if (temp.npc_script != NULL) {
  128.         temp.newlines.addarray(temp.npc_script);
  129.       }
  130.       temp.newlines.add("NPCEND");
  131.     }
  132.     // Save Level
  133.     temp.newlines.savelines(temp.file, 0);
  134.     // Log
  135.     savelog2("olne_log.txt", format("%s updated %s using OLNE!", player.account, temp.file));
  136.     // Unlock Level
  137.     client.olne_lock = "";
  138.     // Send Message
  139.     player.triggerclient("weapon", this.name, "msg", "NPCs Saved!");
  140.   }
  141.   else if (params[0] == "resetlock") {
  142.     client.olne_lock = "";
  143.   }
  144. }
  145.  
  146. /*
  147.   This is where i left off. Check where the filepath is stored and then if it is stored somewhere
  148.   in levels/users/ then format by applying the player's ID as well.
  149.  
  150. */
  151. function getfile(filename) {
  152.   for (temp.folder: this.levelfolders) {
  153.     temp.path = format(temp.folder, filename);
  154.     if (fileexists(temp.path)) {
  155.       return temp.path;
  156.     }
  157.   }
  158.   return NULL;
  159. }
  160.  
  161. //#CLIENTSIDE
  162.  
  163. // Clientside Configuration
  164. const PLACEHOLDER   = "mum_npc_placeholder.png";
  165. const SHOWIMGPART   = true;  // Detects First ShowImgPart Usage (Even if commented out)
  166. const SHOWCHARS     = true;  // Displays Gani Character for NPCs
  167. const RIGHTMENUTIME = 0.3;
  168. const GRAALMINIMUM  = 6;
  169.  
  170. function onPlayerEnters() {
  171.   // Wait for NPCs to Load
  172.   waitfor(this, "RandomEvent", 0.05);
  173.   // Hide Images
  174.   hideimgs(200,20008);
  175.   // Reset Variables
  176.   this.updatedscripts = false;
  177.   this.active = false;
  178.   // Unhide NPCs
  179.   visibleNPCs(true);
  180.   // Reset Lock
  181.   if (client.olne_lock != "") {
  182.     triggerserver("gui", this.name, "resetlock");
  183.   }
  184. }
  185.  
  186. function GraalControl.onKeyUp(key) {
  187.   // Check if F9 Pressed
  188.   if (key == VK_F9) {
  189.     if (!this.active) {
  190.       // Load Level
  191.       displayMSG("Loading NPCs...");
  192.       triggerserver("gui", this.name, "loadlevel", player.level.name, player.account);
  193.     } else {
  194.       // Check if Update Required
  195.       if (this.updatedscripts) {
  196.         displayMSG("Saving NPCs...");
  197.         triggerserver("gui", this.name, "savelevel", player.level.name, getNPCData());
  198.         this.updatedscripts = false;
  199.       } else {
  200.         triggerserver("gui", this.name, "resetlock");
  201.       }
  202.       // Unhide NPCs and Hide Images
  203.       visibleNPCs(true);
  204.       hideimgs(200,10000);
  205.       this.active = false;
  206.     }
  207.   }
  208.   // Check if Delete Pressed
  209.   else if (key == VK_DELETE) {
  210.     // Check if has selection
  211.     if (this.active && this.selected > 0) {
  212.       // Delete selected NPC
  213.       deleteSelection();
  214.     }
  215.   }
  216. }
  217.  
  218. // Displays Message
  219. // Fades Message After 3 Seconds
  220. function displayMSG(msg) {
  221.   with (findimg(20000)) {
  222.     x = screenwidth / 2;
  223.     y = screenheight - 45;
  224.     text = msg;
  225.     style = "bc";
  226.     textshadow = true;
  227.     shadowcolor = "0 0 0";
  228.     zoom = 1;
  229.     alpha = 1;
  230.     layer = 4;
  231.   }
  232.   this.scheduleevent(3, "HideMSG", "");
  233. }
  234.  
  235. // Fades out Message
  236. function onHideMSG() {
  237.   while (findimg(20000).alpha > 0) {
  238.     findimg(20000).alpha -= 0.1;
  239.     waitfor(this, "RandomEvent", 0.05);
  240.   }
  241.   hideimg(20000);
  242. }
  243.  
  244. function onActionClientSide() {
  245.   // Check for Level Data
  246.   if (params[0] == "leveldata") {
  247.     // Hide NPCs
  248.     visibleNPCs(false);
  249.     // Reset Images
  250.     hideimgs(200,10000);
  251.     // Initialize Variables
  252.     temp.leveldata = params[1];
  253.     temp.i = 0;
  254.     this.levelnpcs = {};
  255.     // Determine Top-Left Corner of Level
  256.     if (player.gmap != NULL) {
  257.       temp.tx = player.x - (player.x % 64);
  258.       temp.ty = player.y - (player.y % 64);
  259.     } else {
  260.       temp.tx = temp.ty = 0;
  261.     }
  262.     // Parse NPC Data
  263.     echo(temp.leveldata.size());
  264.     for (temp.data: temp.leveldata) {
  265.       // Determine ID and Other Variables
  266.       temp.npc_id  = 200 + temp.i;
  267.       temp.npc_img = temp.data[0];
  268.       temp.npc_x   = temp.data[1];
  269.       temp.npc_y   = temp.data[2];
  270.       temp.npc_script = temp.data[3];
  271.       // Draw NPC
  272.       updateNPCImage(temp.npc_id, temp.npc_img, temp.npc_x, temp.npc_y, temp.npc_script);
  273.       // Add to Level NPCs Array
  274.       this.levelnpcs.add(temp.npc_id);
  275.       // Increment Counter
  276.       temp.i++;
  277.       echo(temp.npc_script.length());
  278.       echo(temp.i);
  279.     }
  280.     echo("hidemsg");
  281.     // Stop Hide Message Timer
  282.     this.cancelevents("HideMSG");
  283.     // Check if Read-only Access
  284.     if (params[2]) {
  285.       // Warn Read-only
  286.       displayMSG("You don't have rights to change this level!");
  287.     } else {
  288.       // Hide Loading Message
  289.       this.trigger("HideMSG", "");
  290.     }
  291.     // Toggle Active Flag
  292.     this.active = true;
  293.     setTimer(0.05);
  294.   }
  295.   // Check if Displaying Message
  296.   else if (params[0] == "msg") {
  297.     // Disable Fading
  298.     this.cancelevents("HideMSG");
  299.     // Display Message
  300.     displayMSG(params[1]);
  301.   }
  302. }
  303.  
  304. function updateNPCImage(temp.npc_id, temp.npc_img, temp.npc_x, temp.npc_y, temp.npc_script) {
  305.   // Determine Top-Left Corner of Level
  306.   if (player.gmap != NULL) {
  307.     temp.tx = player.x - (player.x % 64);
  308.     temp.ty = player.y - (player.y % 64);
  309.   } else {
  310.     temp.tx = temp.ty = 0;
  311.   }
  312.   with(findimg(temp.npc_id)) {
  313.     x = temp.tx + temp.npc_x;
  314.     y = temp.ty + temp.npc_y;
  315.     // Check if showimgpart NPCs Enabled
  316.     if (temp.npc_script.lower().pos("setimgpart ") >= 0 || temp.npc_script.lower().pos("setimgpart(") >= 0 || temp.npc_script.lower().pos("setgifpart ") >= 0) {
  317.       // Check if contains showimgpart
  318.       if (SHOWIMGPART) {
  319.  
  320.         // Isolate and Determine Parameters
  321.         temp.str = temp.npc_script.substring(temp.npc_script.pos("setimgpart"));
  322.         temp.str = temp.str.substring(0, temp.str.pos(";"));
  323.         temp.str = temp.str.substring("setimgpart ".length());
  324.         temp.tokens = temp.str.tokenize(",");
  325.         if (temp.tokens.size() == 6) temp.tokens.delete(0);
  326.         if (temp.tokens.size() == 5) {
  327.  
  328.           image = temp.tokens[0].trim();
  329.  
  330.           // Remove Quotes and Braces
  331.           while (image.starts("(")) image = image.substring(1);
  332.           while (image.starts('"')) image = image.substring(1);
  333.           while (image.ends('"')) image = image.substring(0,image.length()-1);
  334.  
  335.           // Check if Image Exists
  336.           if (!fileexists(image)) {
  337.             // Draw NPCs Image
  338.             image = (!fileexists(npc_img) ? PLACEHOLDER : npc_img);
  339.             // Determine Width and Height
  340.             this.width  = getimgwidth(image) / 16;
  341.             this.height = getimgheight(image) / 16;
  342.           } else {
  343.             partx = math_eval(temp.tokens[1].trim());
  344.             party = math_eval(temp.tokens[2].trim());
  345.             partw = math_eval(temp.tokens[3].trim());
  346.             parth = temp.tokens[4].trim();
  347.             // Remove End Brace
  348.             while (parth.ends(")")) parth = parth.substring(0, parth.length()-1);
  349.             // Calculate Part Height
  350.             parth = math_eval(parth);
  351.             // Minimum Width and Height
  352.             if (partw < 0) partw = 16;
  353.             if (parth < 0) parth = 16;
  354.             this.width = partw / 16;
  355.             this.height = parth / 16;
  356.           }
  357.         } else {
  358.           // Invalid Default to Placeholder
  359.           image = PLACEHOLDER;
  360.           this.width = this.height = 3;
  361.         }
  362.       } else {
  363.         // Draw Placeholder
  364.         image = PLACEHOLDER;
  365.         this.width = this.height = 3;
  366.       }
  367.     }
  368.     // Check if NPC is Character
  369.     else if (temp.npc_script.pos("showcharacter") >= 0) {
  370.       if (SHOWCHARS) {
  371.         // Set Animation
  372.         ani = getCharAni(npc_script);
  373.         playerlook = false;
  374.         // Head
  375.         temp.head = getActorValue("head", npc_script);
  376.         if (temp.head) actor.head = temp.head;
  377.         // Body
  378.         temp.body = getActorValue("body", npc_script);
  379.         if (temp.body) actor.bodyimg = temp.body;
  380.         // Shield
  381.         temp.shield = getActorValue("shield", npc_script);
  382.         if (temp.shield) actor.shield = temp.shield;
  383.         // Colors
  384.         for (temp.i = 0; temp.i < 5; temp.i++) {
  385.           temp.color = getActorValue("colors", npc_script, temp.i);
  386.           if (temp.color) actor.colors[temp.i] = temp.color;
  387.         }
  388.         // Attributes
  389.         for (temp.i = 0; temp.i < 30; temp.i++) {
  390.           temp.attr = getActorValue("attr", npc_script, temp.i);
  391.           if (temp.attr) actor.attr[temp.i] = temp.attr;
  392.         }
  393.         // Direction
  394.         actor.dir = getVarValue("dir", temp.npc_script);
  395.       } else {
  396.         image = PLACEHOLDER;
  397.       }
  398.       this.width = this.height = 3;
  399.     }
  400.     // NPC Isn't Special
  401.     else {
  402.       // Draw NPCs Image
  403.       image = (!fileexists(npc_img) ? PLACEHOLDER : npc_img);
  404.  
  405.       // Determine Width and Height
  406.       this.width  = getimgwidth(image) / 16;
  407.       this.height = getimgheight(image) / 16;
  408.     }
  409.   }
  410.   // Set Script and Image
  411.   setNPCScript(temp.npc_id, temp.npc_script);
  412.   setNPCImage(temp.npc_id, temp.npc_img);
  413. }
  414.  
  415. function setNPCScript(npc_id, npc_script) {
  416.   thiso.("npcscript_" @ npc_id) = npc_script;
  417. }
  418.  
  419. function getNPCScript(npc_id) {
  420.   return thiso.("npcscript_" @ npc_id);
  421. }
  422.  
  423. function setNPCImage(npc_id, npc_image) {
  424.   thiso.("npcimage_" @ npc_id) = npc_image;
  425. }
  426.  
  427. function getNPCImage(npc_id) {
  428.   return thiso.("npcimage_" @ npc_id) ? this.("npcimage_" @ npc_id) : "";
  429. }
  430.  
  431. function getActorValue(part, npc_script, extra) {
  432.   switch (part) {
  433.     case "head":
  434.       temp.i = getCharPropValue("#3", npc_script);
  435.       if (temp.i == NULL) temp.i = getVarValue("head", npc_script);
  436.       if (temp.i == NULL) temp.i = getVarValue("headimg", npc_script);
  437.       return fileexists(temp.i) ? temp.i : "head0.png";
  438.       break;
  439.     case "body":
  440.       temp.i = getCharPropValue("#8", npc_script);
  441.       if (temp.i == NULL) temp.i = getVarValue("body", npc_script);
  442.       if (temp.i == NULL) temp.i = getVarValue("bodyimg", npc_script);
  443.       return fileexists(temp.i) ? temp.i : "body.png";
  444.       break;
  445.     case "shield":
  446.       temp.i = getCharPropValue("#2", npc_script);
  447.       if (temp.i == NULL) temp.i = getVarValue("shield", npc_script);
  448.       if (temp.i == NULL) temp.i = getVarValue("shieldimg", npc_script);
  449.       return fileexists(temp.i) ? temp.i : "no-shield.png";
  450.       break;
  451.     case "colors":
  452.       temp.i = getCharPropValue("#C" @ extra, npc_script);
  453.       if (temp.i == NULL) temp.i = getVarValue("colors[" @ extra @ "]", npc_script);
  454.       return temp.i; // RED DRAGONS
  455.       break;
  456.     case "attr":
  457.       temp.i = getCharPropValue("#P" @ extra, npc_script);
  458.       if (temp.i == NULL) temp.i = getVarValue("attr[" @ extra @ "]", npc_script);
  459.       return temp.i;
  460.       break;
  461.   }
  462. }
  463.  
  464. function getCharPropValue(prop, npc_script) {
  465.   temp.p = "setcharprop " @ prop @ ",";
  466.   temp.a = npc_script.pos(temp.p);
  467.   if (temp.a >= 0) {
  468.     temp.s = npc_script.substring(temp.a + temp.p.length());
  469.     temp.s = temp.s.substring(0, temp.s.pos(";"));
  470.     if (temp.s == "0") temp.s = "white";
  471.     return temp.s;
  472.   } else {
  473.     return NULL;
  474.   }
  475. }
  476.  
  477. function getVarValue(vari, npc_script) {
  478.   // Find Variable
  479.   temp.aa = npc_script.positions(vari);
  480.   for (temp.a: temp.aa) {
  481.     // Check for Assignment
  482.     temp.s = npc_script.substring(temp.a);
  483.     temp.e = temp.s.pos("=");
  484.     temp.c = temp.s.pos(";");
  485.     // Make Sure Semi-Colon is After Assignment
  486.     if (temp.e < temp.c) {
  487.       // Ignore ""
  488.       if (temp.s.pos("\"\"") >= 0) return "";
  489.       // Determine Value
  490.       temp.s = temp.s.substring(temp.e+1);
  491.       temp.sc = temp.s.pos(";");
  492.       temp.s = temp.s.substring(0, (temp.sc == -1 ? temp.s.length() : temp.sc));
  493.       temp.s = temp.s.trim();
  494.       if (temp.s.size() == 2) {
  495.         temp.s.delete(0);
  496.         temp.s = temp.s[0];
  497.       }
  498.       // Remove Double-Quotes
  499.       while (temp.s.starts('"')) temp.s = temp.s.substring(0);
  500.       while (temp.s.ends('"')) temp.s = temp.s.substring(0,temp.s.length()-1);
  501.       // (0) White Color Fix
  502.       if (vari.starts("colors") && (temp.s == "0")) {
  503.         temp.s = "white";
  504.       }
  505.       // Return Value
  506.       return temp.s;
  507.     }
  508.   }
  509.   return NULL;
  510. }
  511.  
  512. function getCharAni(npc_script) {
  513.   temp.p = npc_script.lower().pos("setcharani ");
  514.   temp.q = npc_script.lower().pos("setcharani(");
  515.   if (temp.p >= 0 || temp.q >= 0) {
  516.     if (temp.q == -1) temp.q = temp.p;
  517.     temp.s = npc_script.substring(temp.q);
  518.     temp.s = temp.s.substring(0, temp.s.pos(",")-1);
  519.     temp.s = temp.s.substring("setcharani ".length());
  520.     if (temp.s.size() == 2) {
  521.       temp.s.delete(0);
  522.       temp.s = temp.s[0];
  523.     }
  524.     // Remove Double Quotes
  525.     while (temp.s.starts('"')) temp.s = temp.s.substring(1);
  526.     while (temp.s.ends('"')) temp.s = temp.s.substring(0, temp.s.length()-1);
  527.     // Return Value
  528.     return (fileexists(temp.s @ ".gani") ? temp.s : "idle");
  529.   }
  530.   return "idle";
  531. }
  532.  
  533. function getNPCData() {
  534.   // Initialize Data Array
  535.   temp.npcdata = {};
  536.   // Loop through NPCs
  537.   for (temp.npc_id: this.levelnpcs) {
  538.     // Check if has script
  539.   temp.npc_script = getNPCScript(temp.npc_id);
  540.     temp.no_script  = (temp.npc_script.size() == 1 && temp.npc_script[0].trim() == "");
  541.   temp.npc_img    = getNPCImage(temp.npc_id);
  542.     with (findimg(temp.npc_id)) {
  543.       // Add NPC Data to Array
  544.       temp.npcdata.add({
  545.         temp.npc_img,
  546.         (x % 64),
  547.         (y % 64),
  548.         (temp.no_script ? NULL : temp.npc_script)
  549.       });
  550.     }
  551.   }
  552.   // Return NPC Data
  553.   return temp.npcdata;
  554. }
  555.  
  556. function onTimeout() {
  557.   // Check if Active
  558.   if (this.active) {
  559.     // Right Drag Menu
  560.     if (this.rightdragging) {
  561.       // Check if Right Mouse Down
  562.       if (!rightmousebutton) {
  563.         // Close Menu
  564.         this.rmorigin_x    = "";
  565.         this.rmorigin_y    = "";
  566.         this.rightdragging = "";
  567.         onHideContextMenu();
  568.       } else {
  569.         // Check If Time to Display Menu Yet
  570.         if (timevar2 > this.rightdragging_init) {
  571.           // Fade in Menu
  572.           if (this.rightalpha < 1) {
  573.             this.rightalpha += 0.25;
  574.           }
  575.           with (findimg(20003)) {
  576.             x = thiso.rmorigin_x;
  577.             y = thiso.rmorigin_y - 0.25;
  578.             text = "Mouse over the NPC to create it!";
  579.             style = "bc";
  580.             textshadow = true;
  581.             shadowcolor = "0 0 0";
  582.             zoom = 0.5;
  583.             alpha = thiso.rightalpha;
  584.           }
  585.           with (findimg(20004)) {
  586.             x = thiso.rmorigin_x - 1.5;
  587.             y = thiso.rmorigin_y - 5;
  588.             image = PLACEHOLDER;
  589.             alpha = thiso.rightalpha;
  590.           }
  591.           with (findimg(20005)) {
  592.             x = thiso.rmorigin_x - 1.5;
  593.             y = thiso.rmorigin_y + 2;
  594.             ani = "idle";
  595.             playerlook = false;
  596.             actor.head = "head0.png";
  597.             actor.colors[0] = "orange";
  598.             actor.colors[1] = "white";
  599.             actor.colors[2] = "blue";
  600.             actor.colors[3] = "red";
  601.             actor.colors[4] = "black";
  602.             actor.shield = "no-shield.png";
  603.             actor.dir = 2;
  604.             actor.alpha = thiso.rightalpha;
  605.           }
  606.           temp.ydiff = mousey - this.rmorigin_y;
  607.           temp.creating = false;
  608.           if (temp.ydiff in |-5,-1.75|) {
  609.             // Create Placeholder
  610.             temp.creating = "placeholder";
  611.           }
  612.           else if (temp.ydiff in |2,5|) {
  613.             // Create NPC
  614.             temp.creating = "npc";
  615.           }
  616.           if (temp.creating) {
  617.             // Hide Images
  618.             onHideContextMenu();
  619.             this.rmorigin_x    = "";
  620.             this.rmorigin_y    = "";
  621.             this.rightdragging = "";
  622.             // Determine Next NPC ID
  623.             temp.npc_id = this.levelnpcs[this.levelnpcs.size()-1] + 1;
  624.             // Set NPC Variables
  625.             temp.npc_x = mousex % 64;
  626.             temp.npc_y = mousey % 64;
  627.             temp.npc_img = "";
  628.             temp.npc_script = {
  629.               "// Created by " @ player.account
  630.             };
  631.             // Generate Script
  632.             if (temp.creating == "npc") {
  633.               temp.npc_script.addarray({
  634.                 "function onCreated() {",
  635.                 "  showcharacter();",
  636.                 "  this.head = \"head0.png\";",
  637.                 "  this.colors[0] = \"orange\";",
  638.                 "  this.colors[1] = \"white\";",
  639.                 "  this.colors[2] = \"blue\";",
  640.                 "  this.colors[3] = \"red\";",
  641.                 "  this.colors[4] = \"black\";",
  642.                 "  this.shield = \"no-shield.png\";",
  643.                 "  this.dir = 2;",
  644.                 "  setcharani(\"idle\",NULL);",
  645.                 "}"
  646.               });
  647.             }
  648.             // Changes Made
  649.             changesMade();
  650.             // Draw NPCs
  651.             updateNPCImage(temp.npc_id, temp.npc_img, temp.npc_x, temp.npc_y, temp.npc_script);
  652.             // Add to List
  653.             this.levelnpcs.add(temp.npc_id);
  654.             // Begin Dragging
  655.             this.dragoffsetx = 1;
  656.             this.dragoffsety = 1;
  657.             this.dragging = temp.npc_id;
  658.           }
  659.         } else {
  660.           this.rmorigin_x = mousex;
  661.           this.rmorigin_y = mousey;
  662.         }
  663.       }
  664.     }
  665.     // Check if Dragging
  666.     else if (this.dragging) {
  667.       // Check if Mouse Button Down
  668.       if (leftmousebutton || rightmousebutton) {
  669.         // Draw GMAP Boundaries
  670.         if (player.gmap != NULL) {
  671.           drawBoundaries();
  672.         }
  673.         // Determine Level Boundaries
  674.         if (player.gmap != NULL) {
  675.           temp.tx = player.x - (player.x % 64);
  676.           temp.ty = player.y - (player.y % 64);
  677.         } else {
  678.           temp.tx = temp.ty = 0;
  679.         }
  680.         // Move NPC
  681.         with (findimg(this.dragging)) {
  682.           x = int(mousex - thiso.dragoffsetx);
  683.           y = int(mousey - thiso.dragoffsety);
  684.           // Force Boundaries
  685.           if (x < temp.tx) x = temp.tx;
  686.           else if (x > (temp.tx + 63)) x = temp.tx + 63;
  687.           if (y < temp.ty) y = temp.ty;
  688.           else if (y > (temp.ty + 63)) y = temp.ty + 63;
  689.           // Set Alpha
  690.           if (actor.head) {
  691.             actor.alpha = (timevar2 > thiso.waitalpha ? 0.5 : 1);
  692.           } else {
  693.             alpha = (timevar2 > thiso.waitalpha ? 0.8 : 1);
  694.           }
  695.         }
  696.         // Update Selected NPC
  697.         this.selected = this.dragging;
  698.       } else {
  699.         // Determine Level Boundaries
  700.         if (player.gmap != NULL) {
  701.           temp.tx = player.x - (player.x % 64);
  702.           temp.ty = player.y - (player.y % 64);
  703.         } else {
  704.           temp.tx = temp.ty = 0;
  705.         }
  706.         with (findimg(this.dragging)) {
  707.           if (!(x in |temp.tx,temp.tx + 64| && temp.ty in |temp.ty,temp.ty + 64|)) {
  708.             temp.outsidebounds = true;
  709.           }
  710.           // Check if Position Changed
  711.           temp.updating = ((x SPC y) != this.original);
  712.           // Set Alpha Back to Normal
  713.           if (actor.head) {
  714.             actor.alpha = 1;
  715.           } else {
  716.             alpha = 1;
  717.           }
  718.           this.original = "";
  719.         }
  720.         if (temp.updating) {
  721.           // Changes Made Tell Editor
  722.           changesMade();
  723.         }
  724.         if (temp.outsidebounds) {
  725.           this.cancelevents("HideMSG");
  726.           displayMSG("Please place the NPC in the boundaries of the level!");
  727.         }
  728.         // Hide Boundaries
  729.         hideBoundaries();
  730.         // Unset Dragging Flag
  731.         this.dragging = false;
  732.       }
  733.     }
  734.     // Check for Selected NPC
  735.     if (this.selected > 0) {
  736.       // Draw Box Around Selection
  737.       drawSelection();
  738.     }
  739.     setTimer(0.05);
  740.   }
  741. }
  742.  
  743. function drawBoundaries() {
  744.   with (findimg(20006)) {
  745.     x = player.x - (player.x % 64);
  746.     y = player.y - (player.y % 64);
  747.     this.width = 64;
  748.     this.height = 64;
  749.     alpha = 0.5;
  750.     polygon = poly_hollowbox(x,y,this.width,this.height);
  751.   }
  752. }
  753.  
  754. function hideBoundaries() {
  755.   hideimg(20006);
  756. }
  757.  
  758. function onHideContextMenu() {
  759.   findimg(20003).alpha -= 0.2;
  760.   findimg(20004).alpha -= 0.2;
  761.   findimg(20005).actor.alpha -= 0.2;
  762.   if (findimg(20003).alpha > 0) {
  763.     this.scheduleevent(0.05, "HideContextMenu", "");
  764.   } else {
  765.     hideimgs(20003,20005);
  766.   }
  767. }
  768.  
  769. // Draws Box Around Selection
  770. function drawSelection() {
  771.   // Glitched in V5
  772.   if (graalversion < 6) {
  773.     with (findimg(this.selected)) {
  774.       alpha = 0.8;
  775.       actor.alpha = 0.5;
  776.     }
  777.     return;
  778.   }
  779.   temp.selection = findimg(this.selected);
  780.   with (findimg(20001)) {
  781.     x = temp.selection.x;
  782.     y = temp.selection.y;
  783.     width = temp.selection.width;
  784.     height = temp.selection.height;
  785.     temp.s = 2/8;
  786.     red = blue = green = 0.9;
  787.     polygon = poly_hollowbox(x-temp.s,y-temp.s,width+(temp.s*1.5),height+(temp.s*1.5));
  788.   }
  789.   this.last_selected = this.selection;
  790. }
  791.  
  792. // poly_funcs::hollow_box()
  793. public function poly_hollowbox(qx,qy,qw,qh) {
  794.   qd=1/8;
  795.   return {qx,qy, qx+qw,qy, qx+qw,qy+qh, qx,qy+qh, qx,qy,
  796.           qx+qd,qy+qd, qx+qd,qy+qh+qd, qx+qw+qd,qy+qh+qd, qx+qw+qd,qy+qd, qx+qd,qy+qd};
  797. }
  798.  
  799. // Deletes Selected NPC
  800. function deleteSelection() {
  801.   // Remove NPC from Level NPCs Array
  802.   this.levelnpcs.remove(this.selected);
  803.   // Hide NPC
  804.   hideimg(this.selected);
  805.   // Notify Editor of Change
  806.   changesMade();
  807.   // Remove Selection Box
  808.   removeSelection();
  809. }
  810.  
  811. function removeSelection() {
  812.   // V5 Selection just does Alpha
  813.   if (graalversion < 6) {
  814.     with (findimg(this.selected)) {
  815.       alpha = 1;
  816.       actor.alpha = 1;
  817.     }
  818.   }
  819.   // Unset Selected NPC Value
  820.   this.selected = "";
  821.   // Hide Box Image
  822.   hideimg(20001);
  823. }
  824.  
  825. function GraalControl.onMouseDown(a, tx, ty, clickcount) {
  826.   if (!this.active) return;
  827.   temp.double = false;
  828.   if (clickcount == 2) {
  829.     temp.dist = vectordist({mousex, mousey, 0}, this.last_click);
  830.     if (temp.dist < 0.5) {
  831.       temp.double = true;
  832.     }
  833.   }
  834.   if (temp.double) {
  835.     onMousePressed("double");
  836.   } else {
  837.     onMousePressed("left");
  838.   }
  839.   this.last_click = {mousex, mousey, 0};
  840. }
  841.  
  842. function GraalControl.onRightMouseDown() {
  843.   if (!this.active) return;
  844.   onMousePressed("right");
  845. }
  846.  
  847. function onMousePressed(click) {
  848.   if (!this.active) return;
  849.   switch (click) {
  850.     case "left":
  851.       // Drag
  852.       if (!this.dragging) {
  853.         // Find Nearest NPC
  854.         this.dragging = getClosestNPCID();
  855.         if (this.dragging > 0) {
  856.           // Determine Drag Offset and Original Position
  857.           with (findimg(this.dragging)) {
  858.             thiso.dragoffsetx = mousex - x;
  859.             thiso.dragoffsety = mousey - y;
  860.             this.original = x SPC y;
  861.           }
  862.           // Draw Selection
  863.           this.selected = this.dragging;
  864.           drawSelection();
  865.           // Set Time Before Turns Transparent
  866.           this.waitalpha = timevar2 + 0.1;
  867.         } else {
  868.           // No NPC was Found
  869.           this.dragging = false;
  870.           // Remove Selection Box
  871.           removeSelection();
  872.         }
  873.       }
  874.       this.lastclick = (int(mousex) SPC int(mousey));
  875.       break;
  876.     case "right":
  877.       // Duplicate
  878.       temp.dupe = getClosestNPCID();
  879.       if (temp.dupe > 0) {
  880.         // Determine Next NPC ID
  881.         temp.npc_id = this.levelnpcs[this.levelnpcs.size()-1] + 1;
  882.         // Find NPC to Dupe
  883.         temp.duping = findimg(temp.dupe);
  884.         // Create New NPC
  885.         temp.npc_img = getNPCImage(temp.dupe);
  886.         temp.npc_x = temp.duping.x % 64;
  887.         temp.npc_y = temp.duping.y % 64;
  888.         temp.npc_script = getNPCScript(temp.dupe);
  889.         updateNPCImage(temp.npc_id, temp.npc_img, temp.npc_x, temp.npc_y, temp.npc_script);
  890.         // Begin Dragging Duplicate NPC
  891.         this.waitalpha = timevar2 + 0.10;
  892.         this.dragoffsetx = mousex - temp.duping.x;
  893.         this.dragoffsety = mousey - temp.duping.y;
  894.         this.dragging = temp.npc_id;
  895.         // Add to Level NPCs Array
  896.         this.levelnpcs.add(temp.npc_id);
  897.         // Notify Editor of Change Made
  898.         changesMade();
  899.         // Display Duplication Message to User
  900.         displayMSG("NPC Duplicated!");
  901.       } else {
  902.         // Remove Selection
  903.         removeSelection();
  904.         // Make sure not Draggin Right Mouse
  905.         if (!this.rightdragging) {
  906.           // Set Origin of Mouse
  907.           this.rmorigin_x = mousex;
  908.           this.rmorigin_y = mousey;
  909.           // Begin Right Drag
  910.           this.rightdragging = true;
  911.           // Declare Time to Create Right-Context Menu
  912.           this.rightdragging_init = timevar2 + RIGHTMENUTIME;
  913.           this.rightalpha = 0;
  914.         }
  915.       }
  916.       break;
  917.     case "double":
  918.       // Record Time of Doubleclick
  919.       if (this.selected > 0) {
  920.         this.doubleclick = timevar2;
  921.       }
  922.       break;
  923.   }
  924. }
  925.  
  926. function GraalControl.onMouseUp() {
  927.   // Check if mouse up within recent double click
  928.   if (timevar2 in |this.doubleclick,this.doubleclick+0.25|) {
  929.     // Open Script of Nearest NPC to Mouse
  930.     temp.closest_id = getClosestNPCID();
  931.     if (temp.closest_id != NULL) {
  932.     temp.npc_script = getNPCScript(temp.closest_id);
  933.     temp.npc_img    = getNPCImage(temp.closest_id);
  934.       with (findimg(temp.closest_id)) {
  935.         createEditorWindow(temp.closest_id, temp.npc_img, x, y, temp.npc_script);
  936.       }
  937.     }
  938.   }
  939. }
  940.  
  941. // Finds Nearest NPC in Level NPCs to Mouse X and Y
  942. function getClosestNPCID() {
  943.   // Loop through NPCs
  944.   for (temp.npc_id: this.levelnpcs) {
  945.     with (findimg(temp.npc_id)) {
  946.       if (mousex in |x,x+this.width| && mousey in |y,y+this.height|) {
  947.         temp.found.add({
  948.           temp.npc_id, x, y
  949.         });
  950.       }
  951.     }
  952.   }
  953.   // Check if any Found
  954.   if (temp.found.size() > 0) {
  955.     if (temp.found.size() == 1) {
  956.       // Set Closest ID to Only One Found
  957.       temp.closest_id = temp.found[0][0];
  958.     } else {
  959.       // Determine Which ID is Closest
  960.       temp.closest_id   = temp.found[0][0];
  961.       temp.closest_dist = vectordist({mousex, mousey, 0}, {temp.found[0][1], temp.found[0][2], 0});
  962.       for (temp.i = 1; temp.i < temp.found.size(); temp.i++) {
  963.         temp.dist = vectordist({mousex, mousey}, temp.found[temp.i].subarray(1));
  964.         if (temp.dist < temp.closest_dist) {
  965.           temp.closest_id   = temp.found[temp.i][0];
  966.           temp.closest_dist = temp.dist;
  967.         }
  968.       }
  969.     }
  970.     // Return Closest NPC ID
  971.     return temp.closest_id;
  972.   } else {
  973.     // No NPC Found
  974.     return NULL;
  975.   }
  976. }
  977.  
  978. function changesMade() {
  979.   // Check if Not Updated
  980.   if (!this.updatedscripts) {
  981.     // Display 'How to Save' Message to User
  982.     displayMSG("Press F9 to save changes when your ready!");
  983.     // Set Updated Flag for Editor
  984.     this.updatedscripts = true;
  985.   }
  986. }
  987.  
  988. // For scheduling display messages
  989. function onReminder(msg) {
  990.   displayMSG(msg);
  991. }
  992.  
  993. // Create Editor Window
  994. function createEditorWindow(temp.npc_id, temp.npc_img, temp.npc_x, temp.npc_y, temp.npc_script) {
  995.   new GuiMLTextEditProfile("SyntaxHighlightLegacyProfile") {
  996.     fontType = fileexists("DejaVuSansMono.ttf") ? "DejaVuSansMono" : "Courier";
  997.     fontSize = (thiso.options.scriptfontsize <= 0 ? 14 : thiso.options.scriptfontsize);
  998.     cursorColor = "0 0 0";
  999.     fillColorHL = "255 255 0";
  1000.     fontColor = "0 0 0";
  1001.     fontColorHL = "192 0 0"; // control words like if, else etc.
  1002.     fontColorSEL = "0 16 0"; // identifiers 0,96,0
  1003.     fontColorLink = "192 0 192"; // strings
  1004.     fontColorLinkHL = "0 0 255"; // numbers
  1005.   }
  1006.   new GuiWindowCtrl("LevelNPC_" @ temp.npc_id @ "_Window") {
  1007.     profile = GuiBlueWindowProfile;
  1008.     clientrelative = true;
  1009.     this.npc_id = temp.npc_id;
  1010.     temp.ww = clientwidth = 600;
  1011.     temp.wh = clientheight = 500;
  1012.     x = (screenwidth - temp.ww) / 2;
  1013.     y = (screenheight - temp.wh) / 2;
  1014.     isexternal = true;
  1015.     text = format("NPC Script Editor (X: %s Y: %s)", temp.npc_x % 64, temp.npc_y % 64);
  1016.     destroyonhide = true;
  1017.     thiso.trigger("CenterExternalWindow", this);
  1018.  
  1019.     new GuiScrollCtrl("LevelNPC_" @ temp.npc_id @ "_ScriptScroll") {
  1020.       profile = GuiBlueScrollProfile;
  1021.       scrollprofile = GuiBlueScrollProfile;
  1022.       useownprofile = true;
  1023.       profile.fillColor = "255 255 255";
  1024.       profile.opaque = true;
  1025.       profile.border = 1;
  1026.       profile.bitmap = "guiblue_scroll_noback.png";
  1027.       horizsizing = "width";
  1028.       vertsizing  = "height";
  1029.       clientwidth  = temp.ww;
  1030.       clientheight = temp.wh - 40;
  1031.  
  1032.       new GuiMLTextEditCtrl("LevelNPC_" @ temp.npc_id @ "_Script") {
  1033.         profile = SyntaxHighlightLegacyProfile;
  1034.         useownprofile = true;
  1035.         profile.fillcolorhl = "80 180 255";
  1036.         profile.fontcolorlink = "255 0 255";
  1037.         profile.fontsize = 15;
  1038.  
  1039.         horizsizing = "width";
  1040.         syntaxhighlighting = true;
  1041.         wordwrap = false;
  1042.         clientheight = temp.wh;
  1043.         clientwidth  = temp.ww - 40;
  1044.         width -= 4;
  1045.  
  1046.         setlines(temp.npc_script);
  1047.         temp.scriptctrl = this;
  1048.  
  1049.         autoindenting = true;
  1050.         tabspaces = 2;
  1051.       }
  1052.     }
  1053.     new GuiButtonCtrl("LevelNPC_" @ temp.npc_id @ "_ScriptClose") {
  1054.       profile = GuiBlueButtonProfile;
  1055.       horizsizing = "left";
  1056.       vertsizing  = "top";
  1057.       clientwidth  = 64;
  1058.       clientheight = 32;
  1059.       x = temp.ww - 68;
  1060.       y = temp.wh - 40 + 4;
  1061.       text = "Close";
  1062.       thiso.catchevent(this.name, "onAction", "onCloseScript");
  1063.     }
  1064.     new GuiButtonCtrl("LevelNPC_" @ temp.npc_id @ "_ScriptApply") {
  1065.       profile = GuiBlueButtonProfile;
  1066.       horizsizing = "left";
  1067.       vertsizing  = "top";
  1068.       clientwidth  = 64;
  1069.       clientheight = 32;
  1070.       x = temp.ww - 68 - 64 - 4;
  1071.       y = temp.wh - 40 + 4;
  1072.       text = "Apply";
  1073.       thiso.catchevent(this.name, "onAction", "onApplyScript");
  1074.     }
  1075.     new GuiTextEditCtrl("LevelNPC_" @ temp.npc_id @ "_Image") {
  1076.       profile = GuiBlueTextEditProfile;
  1077.       clientwidth = 256;
  1078.       clientheight = 24;
  1079.       x = 4;
  1080.       y = temp.wh - 24 - 10;
  1081.       text = temp.npc_img;
  1082.       thiso.catchevent(this.name, "onAction", "onUpdateImage");
  1083.       temp.imgctrl = this;
  1084.     }
  1085.     this.scriptctrl = temp.scriptctrl;
  1086.     this.imgctrl    = temp.imgctrl;
  1087.   }
  1088. }
  1089.  
  1090. function onCenterExternalWindow(obj) {
  1091.   with (obj.externalwindow) {
  1092.     x = screenbounds[0] + (screenbounds[2] - width) / 2;
  1093.     y = screenbounds[1] + (screenbounds[3] - height) / 2;
  1094.   }
  1095. }
  1096.  
  1097. // Update Image in Text Box
  1098. function onUpdateImage(obj) {
  1099.   if (!this.active) return;
  1100.   temp.npc_img = obj.text.trim();
  1101.   with (findimg(obj.parent.npc_id)) {
  1102.     image = temp.npc_img;
  1103.     image = fileexists(image) ? image : PLACEHOLDER;
  1104.     this.width = getimgwidth(image) / 16;
  1105.     this.height = getimgheight(image) / 16;
  1106.   }
  1107.   setNPCImage(temp.npc_id, temp.npc_img);
  1108.   changesMade();
  1109. }
  1110.  
  1111. // Closes Script
  1112. function onCloseScript(obj) {
  1113.   obj.parent.destroy();
  1114. }
  1115.  
  1116. // Saves NPC Script and Image
  1117. function onApplyScript(obj) {
  1118.   if (!this.active) {
  1119.     obj.parent.destroy();
  1120.     return;
  1121.   }
  1122.   temp.npc_id = obj.parent.npc_id;
  1123.   temp.npc_script = obj.parent.scriptctrl.getlines();
  1124.   temp.npc_img = obj.parent.imgctrl.text.trim();
  1125.   obj.parent.destroy();
  1126.   with (findimg(temp.npc_id)) {
  1127.     image = temp.npc_img;
  1128.     image = fileexists(image) ? image : PLACEHOLDER;
  1129.     temp.npc_x = x % 64;
  1130.     temp.npc_y = y % 64;
  1131.   }
  1132.   setNPCImage(temp.npc_id, temp.npc_img);
  1133.   setNPCScript(temp.npc_id, temp.npc_script);
  1134.   if (temp.npc_id > 0) {
  1135.     changesMade();
  1136.     updateNPCImage(temp.npc_id, temp.npc_img, temp.npc_x, temp.npc_y, temp.npc_script);
  1137.   }
  1138. }
  1139.  
  1140. // Hides/Shows Level NPCs
  1141. function visibleNPCs(showing) {
  1142.   // Determine Top-Left Position
  1143.   if (player.gmap != NULL) {
  1144.     temp.tx = player.x - (player.x % 64);
  1145.     temp.ty = player.y - (player.y % 64);
  1146.   } else {
  1147.     temp.tx = temp.ty = 0;
  1148.   }
  1149.   // Loop through NPCs
  1150.   for (temp.npc: npcs) {
  1151.     // Check if Showing NPCs
  1152.     if (showing) {
  1153.       // Check if Was Hidden
  1154.       if (temp.npc.washidden != "") {
  1155.         // Return Original Visible State
  1156.         temp.npc.visible = temp.npc.washidden;
  1157.         temp.npc.washidden = "";
  1158.       }
  1159.     } else {
  1160.       // Check if in Current Level
  1161.       if (temp.npc.x in |temp.tx,temp.tx+64| && temp.npc.y in |temp.ty,temp.ty+64|) {
  1162.         // Hide NPC
  1163.         temp.npc.washidden = temp.npc.visible && !showing;
  1164.         temp.npc.visible = false;
  1165.       }
  1166.     }
  1167.   }
  1168. }
  1169.  
  1170. /*
  1171.    Math Eval Functions
  1172. */
  1173.  
  1174. public function math_eval(temp.equ, temp.stack) {
  1175.   // Brackets
  1176.   temp.stack++;
  1177.   temp.opn = temp.equ.positions("(");
  1178.   temp.end = temp.equ.positions(")");
  1179.   if (opn.size() != end.size()) return "Bracket Mismatch";
  1180.   while (temp.opn.size() > 0) {
  1181.     // Isolate Inner Brackets
  1182.     temp.spos   = temp.opn[temp.opn.size()-1];
  1183.     temp.epos   = temp.equ.substring(temp.spos).pos(")");
  1184.     temp.nequ   = temp.equ.substring(temp.spos+1, temp.epos - 1);
  1185.     temp.result = math_eval(temp.nequ, temp.stack);
  1186.     temp.equ = temp.equ.substring(0, temp.spos) @ temp.result @ temp.equ.substring(temp.spos+temp.epos+1);
  1187.     temp.opn = temp.equ.positions("(");
  1188.   }
  1189.   // Remove Spaces
  1190.   temp.equ = clearSpaces(temp.equ);
  1191.   // Evaluate
  1192.   temp.operations = {"^", "/", "*", "+", "-", "<", ">", "<=", ">=", "!=", "==", "&&", "||"};
  1193.   for (temp.op: temp.operations) {
  1194.     while (temp.equ.pos(temp.op) > 0) {
  1195.       temp.fpos = temp.equ.pos(temp.op);
  1196.       // Find A
  1197.       temp.apos = "";
  1198.       for (temp.j = temp.fpos-temp.op.length(); temp.j > 0 && !temp.apos; temp.j--) {
  1199.         temp.sop = temp.equ.charat(temp.j);
  1200.         temp.dop = temp.sop @ temp.equ.charat(temp.j-1);
  1201.         if (temp.dop in temp.operations || temp.sop in temp.operations) {
  1202.           temp.apos = temp.j;
  1203.           temp.a = temp.equ.substring(temp.apos + 1, temp.fpos - temp.apos - 1);
  1204.         }
  1205.       }
  1206.       if (!temp.apos) {
  1207.         temp.a = temp.equ.substring(0, temp.fpos);
  1208.       }
  1209.       if (hasValue(temp.a)) temp.a = getValue(temp.a);
  1210.       // Find B
  1211.       temp.bpos = "";
  1212.       for (temp.k = temp.fpos+temp.op.length()+1; temp.k < temp.equ.length() && !temp.bpos; temp.k++) {
  1213.         temp.sop = temp.equ.charat(temp.k);
  1214.         temp.dop = temp.sop @ temp.equ.charat(temp.k+1);
  1215.         if (temp.sop in temp.operations || temp.dop in temp.operations) {
  1216.           temp.bpos = k;
  1217.           temp.b = temp.equ.substring(temp.fpos + temp.op.length(), temp.bpos - temp.fpos - 1);
  1218.         }
  1219.       }
  1220.       if (!temp.bpos) {
  1221.         temp.b = temp.equ.substring(temp.fpos+temp.op.length());
  1222.       }
  1223.       if (hasValue(temp.b)) temp.b = getValue(temp.b);
  1224.       // Calculate Result
  1225.       temp.result = evaluate(temp.a, temp.op, temp.b);
  1226.       // Rebuild Equation
  1227.       temp.str = temp.apos ? temp.equ.substring(0, temp.apos + 1) : "";
  1228.       temp.end = temp.bpos ? temp.equ.substring(temp.bpos) : "";
  1229.       temp.equ = temp.str @ temp.result @ temp.end;
  1230.     }
  1231.   }
  1232.   temp.result = hasValue(temp.equ) ? getValue(temp.equ) : float(temp.equ);
  1233.   return temp.result ? temp.equ : temp.result;
  1234. }
  1235.  
  1236. function clearSpaces(temp.l) {
  1237.   while (temp.l.pos(" ") >= 0) {
  1238.     temp.l = temp.l.substring(0, temp.l.pos(" ")) @ temp.l.substring(temp.l.pos(" ")+1);
  1239.   }
  1240.   return temp.l;
  1241. }
  1242.  
  1243. function evaluate(a, op, b) {
  1244.   switch(op) {
  1245.     case "equal":
  1246.     case "==":
  1247.     case "=":
  1248.       return a == b || a == int(float(b));
  1249.     case "&&":
  1250.       return a && b;
  1251.     case "||":
  1252.       return a || b;
  1253.     case "!=":
  1254.       return a != b;
  1255.     case ">":
  1256.       return a > b;
  1257.     case ">=":
  1258.       return a >= b;
  1259.     case "<":
  1260.       return a < b;
  1261.     case "<=":
  1262.       return a <= b;
  1263.     case "&":
  1264.       return a & b;
  1265.     case "^":
  1266.       return a ^ b;
  1267.     case "|":
  1268.       return a | b;
  1269.     case "in": // array only
  1270.       return a in b;
  1271.     case "*":
  1272.       return a * b;
  1273.     case "/":
  1274.       return a / b;
  1275.     case "+":
  1276.       return a + b;
  1277.     case "-":
  1278.       return a -b;
  1279.   }
  1280.   return 0;
  1281. }
  1282.  
  1283. function hasValue(temp.svar) {
  1284.   return getValue(temp.svar);
  1285. }
  1286.  
  1287. function getValue(temp.svar) {
  1288.   return this.(@temp.svar);
  1289. }
Add Comment
Please, Sign In to add comment