Tips for Tedious Coding
Tips for Tedious Coding Part 1 -- Tips for Tedious Coding: An Introduction into Javascript Have you ever had to produce tedious lines of code, or wanted to produce a cool effect, but didn't feel like writing everything out? Now, I shall unveil and easy way for the production of tedious lines of code. Yay! Have you ever heard of javascript? Its a type of scripting language -- but heres the secret -- that is uncompiled. All you need is a text editor! So, lets open up our favorite text editor -- which I shall assume is Notepad++. For more information, go here: http://www.staredit.net/wiki/Javascript Introduction: Now, let's type in the basic part of the script that we need: Codevar fso = new ActiveXObject("Scripting.FileSystemObject"); var outputFileName = fso.GetParentFolderName(WScript.ScriptFullName) + "\\" + fso.GetBaseName(WScript.ScriptFullName) + ".txt"; var outputStream = fso.CreateTextFile(outputFileName, true);" -Line 1 states we are creating a new object. -Line 2 states what its name shall be. -I don't really know what Line 3 is (I'm guessing it is merely outputs until told to stop.) Now, lets make something we can all enjoy: SPINNING PROBES!!!!! Codevar currentSpinSpeed = 1; while(currentSpinSpeed < 13) { currentSpinSpeed *= 1.02; outputStream.WriteLine(" turncwise " + Math.floor(currentSpinSpeed)); outputStream.WriteLine(" wait 1"); } So, we set our variable "currentSpinSpeed" equal to one. While this variable is less than 13, we multiply it by 1.02. In the text file it will output, it will write the line "turncwise + Math.floor(1.02)" -> "turncwise 1" Can you see with Math.floor does? It takes any non-integer and round it DOWN. Now, our code is almost done, all we need is one final line: CodeoutputStream.Close(); We tell our program to finish and close the file. Our final code looks like: Save the file as: probeBuildUp.js. Now click on the file and it will create probeBuildUp.txt. *This javascript originally comes from BSTRhino. I have used it because if its simplicity -- yet stunning visual effect :P I luve spinning probes :D ----------------------------------- Bouncing Grenades: I have always loved this effect, and all it requires is iscript magic. Codevar currentFrameNumber = 0; Set the current frame number. Codefunction generatePlayFrameCommand() { outputStream.WriteLine(" playfram " + currentFrameNumber); ++currentFrameNumber; if(currentFrameNumber >= 4) { currentFrameNumber = 0; } } We define a function that we will use later in the code. You probably can understand this except for a few things (if you are unfamiliar with coding syntax). '++' == add one to the variable. '>=' == less than or equal to. Codevar arcStepArray = new Array(); for(var currentArcInitialStep = 1; currentArcInitialStep * 2 - 1 <= 64; currentArcInitialStep *= 2) { arcStepArray.push(currentArcInitialStep); outputStream.WriteLine("Arc" + arcStepArray.length + ":"); var currentHeightValue = 0; for(var currentStepValue = currentArcInitialStep; currentStepValue >= 1; currentStepValue /= 2) { currentHeightValue -= currentStepValue; outputStream.WriteLine(" shvertpos " + currentHeightValue); generatePlayFrameCommand(); outputStream.WriteLine(" wait 1"); } var currentDecrementValue = 1; while(true) { currentHeightValue += currentDecrementValue; if(currentHeightValue > 0) { break; } outputStream.WriteLine(" shvertpos " + currentHeightValue); generatePlayFrameCommand(); outputStream.WriteLine(" wait 1"); currentDecrementValue *= 2 } outputStream.WriteLine("goto Arc" + (arcStepArray.length - 1)); outputStream.WriteLine(); } outputStream.Close(); Now, for good practice, analyze that code and see if you can figure out what it means. Here are some tips: 'var1 += var2' == Variable #1 is equal to Variable #2 plus one. 'while(true)' == run this code while the output from is is a non-zero value. Here is the overall code needed for bouncing grenades: *Original script by BSTRhino. Why? Because he owns. ----------------------------------- Application of Javascript (and in fuller understanding -- coding in general) to Effects Using Mathematics: What I am going to create in this section is a circle of explosions that you can use as an attack or death animation for a unit. I usually use it for larger units' deaths and such. I know Starcraft incorporates a large array of players -- from youngling to expert elder -- so, skip this section if you understand polar equations. The equation for a circle using x and y's is Math.sqrt(x*x + y*y) = radius*radius. Writing that equation made me want to puke. Couldn't there be some easier way? Of course there is -- its called a polar equation. the equation for a circle is simply: r = 1. For a spiral, it is r = Theta. A Crash Course on Polar Equations: Polar equations relate angles with radii. At the given angle, the radius will be a certain length. At the end of the radius, it will plot the point. But how are those points found be people like you or me? By these set of equations: x = radius * cos(theta) y = radius * sin(theta) (This is basic Algebra and Trig. And some Geometry I guess... O well.) So, if we are going to use a polar equation in our javascript, we're going to need these two equations as functions: Code//functions function calcx(radians) { xasixnum = Math.round(Math.cos(radians) * 10); return xasixnum; } function calcy(radians) { yasixsum = Math.round(Math.sin(radians) * 10); return yasixsum; } Now, javascript uses radius, which differs from degrees. Degrees * pi / 180 = Radians We want our explosions to go full circle so: Code// Program entry point for(var currentRadians = 0; currentRadians < 2 * Math.PI; currentRadians += Math.PI/16) { outputStream.WriteLine(" imgol 334" + " " + calcx(currentRadians) + " " + calcy(currentRadians)); outputStream.WriteLine(" playsndbtwn 7 12"); outputStream.WriteLine(" wait 1"); } outputStream.Close(); Here is our full code: *Original Code by A_of_s_t. It is currently being used in Disunion and my mod for the Summer Modding Contest. Please give me some kudos if you use these tips in your mod. Cannot add to 1st post at the moment so: PART 2 -- Applications of Javascript (and to a more reaching extent -- coding in general) for Unique Weaponry The Miraculous Sine Missiles: If you have ever viewed the graph of sin(x), you'll see a nice flowing curve. When someone posted that they wanted to see missiles fly to their target in non linear paths, I decided to try it -- and thanks to javascript, I succeeded. Sin Missiles require two sets of equations and -- even worse, two weapons, two flingies, two sprites, and two images. One missile will be used for horizontal fire, and one will be used for vertical: Codevar fso = new ActiveXObject("Scripting.FileSystemObject"); var outputFileName = fso.GetParentFolderName(WScript.ScriptFullName) + "\\" + fso.GetBaseName(WScript.ScriptFullName) + ".icc"; var outputStream = fso.CreateTextFile(outputFileName, true); //functions function calculateyaxis(yaxis, distance) { yaxis = 4 * Math.round(Math.PI * Math.sin(180 * distance / Math.PI)); return yaxis; } // Program entry point for(var currentDistance = 0; currentDistance < 9; currentDistance += 1) { outputStream.WriteLine(" sethorpos " + calculateyaxis(0, currentDistance)); outputStream.WriteLine(" sprul 998 " + calculateyaxis(0, currentDistance) + " 0 # MissleTrail (thingy\smoke.grp)"); outputStream.WriteLine(" wait 1"); } outputStream.Close(); Codevar fso = new ActiveXObject("Scripting.FileSystemObject"); var outputFileName = fso.GetParentFolderName(WScript.ScriptFullName) + "\\" + fso.GetBaseName(WScript.ScriptFullName) + ".icc"; var outputStream = fso.CreateTextFile(outputFileName, true); //functions function calculateyaxis(yaxis, distance) { yaxis = 4 * Math.round(Math.PI * Math.sin(180 * distance / Math.PI)); return yaxis; } // Program entry point for(var currentDistance = 0; currentDistance < 9; currentDistance += 1) { outputStream.WriteLine(" setvertpos " + calculateyaxis(0, currentDistance)); outputStream.WriteLine(" sprul 998 0 " + calculateyaxis(0, currentDistance) + " # MissleTrail (thingy\smoke.grp)"); outputStream.WriteLine(" wait 1"); } outputStream.Close(); Now, copy + paste the output of the first one into an image that is unsed and do the same with the second one. Now, let's go to the Valkyrie and give it two weapons -- one air and one ground -- and have the weapons use "Flies to Target" and have it use a flingy that uses a sprite that uses the images that we edited. Now, go to the Valkyrie's iscript and change its attack to this: CodeValkyrieAirAttkInit: ValkyrieGndAttkInit: wait 1 curdirectcondjmp 0 22 FireBlock1 curdirectcondjmp 64 44 FireBlock2 curdirectcondjmp 128 22 FireBlock1 curdirectcondjmp 192 44 FireBlock2 EndofAttack: gotorepeatattk goto ValkyrieLocal00 ValkyrieLocal00: wait 125 goto ValkyrieLocal00 FireBlock1: wait 1 attackwith 1 wait 1 #useweapon 123 waitrand 10 12 goto EndofAttack FireBlock2: wait 1 attackwith 2 wait 1 #useweapon 125 waitrand 10 12 goto EndofAttack Compile everything and you get a Valkyrie that now fires sinMissiles! What is curdirectcondjmp?: While I'm at it, I shall diescribe how curdirectcondjmp works (thanks to Lord_Agamemnon). curdirectcondjump detects which way the unit is facing and jumps to a block of code if it is facing the right direction. The first number describes what angle it is at. A circle in SC is split into 256 units (not 360). So, to convert: Degress * 256 / 360 = Starcraft Measure Now the second number allows for error, giving a range clockwise and counter-clockwise of this Starcraft measure from the first number. curdirectcondjmp 64 44 FireBlock2 90 Degrees with about 61 degrees left or right of error allotment. (29d to 151d) Commplete generators and codes needed: *Original Generators and Codes thanks to A_of_s_t -- who ownz at mathematics. ------------------------------------------------------------------- Random Attack Sequences: In order to have a unit use random attacks, we need to use the "randcondjmp" opcode in the attack sequence. The probibility in this opcode is based off of 255. x /100 = % / 255 255 * x / 100 = % I know that in the end we will have 20 different attack sequences, plus one critical hit sequence. I know I want the critical hit to happen less than the regular sequence, but will naturally happen because of the nature of SC code. 54 = % So, we will have: randcondjmp 54 AttackStyle0 randcondjmp 54 AttackStyle1 randcondjmp 54 AttackStyle2 randcondjmp 54 AttackStyle3 randcondjmp 54 AttackStyle4 randcondjmp 54 AttackStyle5 randcondjmp 54 AttackStyle6 randcondjmp 54 AttackStyle7 randcondjmp 54 AttackStyle8 randcondjmp 54 AttackStyle9 randcondjmp 54 AttackStyle10 randcondjmp 54 AttackStyle11 randcondjmp 54 AttackStyle12 randcondjmp 54 AttackStyle13 randcondjmp 54 AttackStyle14 randcondjmp 54 AttackStyle15 randcondjmp 54 AttackStyle16 randcondjmp 54 AttackStyle17 randcondjmp 54 AttackStyle18 randcondjmp 54 AttackStyle19 randcondjmp 54 AttackStyle20 randcondjmp 54 AttackStyle21 (Entry point to produce that was: for(var BLARG = 0; BLARG < 22; BLARG ++) { outputStream.WriteLine("randcondjmp 54 AttackStyle" + BLARG); }) Now, our weapons will need to be modified for this version of random weaponry to work: Go to datedit and go to a unit that you would like to change. Make its ground weapon use any weapon that uses Gemini Missile graphics and goes to Max Range. Add some splash damage and make its Max Range about 8. Do the same to the Air weapon, except make its Max Range about 2-4. Now make Weapon 123 any weapon that will use an explosion when it hits its target. Now, we create the code for the random weapons: Codevar fso = new ActiveXObject("Scripting.FileSystemObject"); var outputFileName = fso.GetParentFolderName(WScript.ScriptFullName) + "\\" + fso.GetBaseName(WScript.ScriptFullName) + ".txt"; var outputStream = fso.CreateTextFile(outputFileName, true); var number = 0 for(var attackNum = 1; attackNum < 3; attackNum ++) { for(var turn = 0; turn < 5; turn ++) { outputStream.WriteLine("AttackStyle" + number++ + ":"); outputStream.WriteLine(" turncwise " + turn); outputStream.WriteLine(" attackwith " + attackNum); outputStream.WriteLine(" turnccwise " + turn); outputStream.WriteLine(" goto EndofAttackSequence"); outputStream.WriteLine(""); outputStream.WriteLine("AttackStyle" + number++ + ":"); outputStream.WriteLine(" turnccwise " + turn); outputStream.WriteLine(" attackwith " + attackNum); outputStream.WriteLine(" turncwise " + turn); outputStream.WriteLine(" goto EndofAttackSequence"); outputStream.WriteLine(""); } } outputStream.Close(); We initiate a variable (attackNum) that will change which weapon we use (ground or air). We then initiate a variable that will output what degree our unit will attack. While messing with the randcondjmp, I realized that my method isn't very random... It favors the first random jump. I tried this: Codevar fso = new ActiveXObject("Scripting.FileSystemObject"); var outputFileName = fso.GetParentFolderName(WScript.ScriptFullName) + "\\" + fso.GetBaseName(WScript.ScriptFullName) + ".txt"; var outputStream = fso.CreateTextFile(outputFileName, true); //Functions function func1(n) { i = Math.round(51 + 3.8 * n * 256 / 100); return i } //i = original [51] + (4/total) * BLARG * 256 / 100 //Program Entry Point for(var BLARG = 0; BLARG < 22; BLARG ++) { outputStream.WriteLine("randcondjmp " + func1(BLARG) + " AttackStyle" + BLARG); } outputStream.Close(); Which outputs this: randcondjmp 51 AttackStyle0 randcondjmp 61 AttackStyle1 randcondjmp 70 AttackStyle2 randcondjmp 80 AttackStyle3 randcondjmp 90 AttackStyle4 randcondjmp 100 AttackStyle5 randcondjmp 109 AttackStyle6 randcondjmp 119 AttackStyle7 randcondjmp 129 AttackStyle8 randcondjmp 139 AttackStyle9 randcondjmp 148 AttackStyle10 randcondjmp 158 AttackStyle11 randcondjmp 168 AttackStyle12 randcondjmp 177 AttackStyle13 randcondjmp 187 AttackStyle14 randcondjmp 197 AttackStyle15 randcondjmp 207 AttackStyle16 randcondjmp 216 AttackStyle17 randcondjmp 226 AttackStyle18 randcondjmp 236 AttackStyle19 randcondjmp 246 AttackStyle20 randcondjmp 255 AttackStyle21 And it works fairly better, but it now favors the random jumps at the end. I'm messing around with the random condition jumps so that every single randcondjmp has the same percentage of firing. Here's why the first idea I had was wrong: The first one has a 54/254 chance of firing. The second one has a 54/255 chance of firing IF the first one doesnt fire (201/256). So, the next one needs to have a HIGHER chance of firing so that it is still the same percentage as the first one. math.round(256/(totalNumberOfPaths - n) Next up: Application to Triggers Next up: Application to AI Design Nect up: Advanced Special Attacks and Spell with Application of |