Sunday, August 20, 2006

Scripting! Scripting!

Last few days, I've scripted my ass off. Got the tank function partway up and running. He can move to where the player right clicks in straight lines. He can be selected in many different ways. I have completed single unit selection with left click a long time ago, and multi unit selection with control click. I just added several new ways to select a unit. Press Q to select all military units, Press A to select all units the same type of the unit currently selected (will also be done via double click, which I haven't done yet), and click and drag to lasso units in a box. (This one was really fun to make :P )

What the tank needs now is to pathfind its way around obstacles, detect a nearby enemy and shoot him, shoot an enemy at the player's command, switch from main gun to machine gun when attacking soft targets. And I need to create the statistics panel for this tank. And make him upgrade from from tank to tank. And so on and so forth.

And this is just one tank.

So I spent all day doing that lasso code. What happens is that the player drags the mouse on the screen. A box is formed. Everything inside that box is selected. It took so long because I realized that the program was dependant on which direction the player dragged the mouse to create the box. And there were four different ways that he could. Check out the diagram:



The black dot is the starting vector of the mouse (mouseCoord1[3]) and the red dot is the final position of the mouse, when the mouse is released (mouseCoord2[3]) and the blue dot is where an entity needs to be if he is to be selected (my.x,my.y). First, I had to check, with the inequalities next to the box name, which box it was by discerning where mouseCoord1 was in relation to mouseCoord2. Then I had to check through the next four inequalities to make sure the unit was in the box. Then I had to check that the unit was the player's and not the computers, and that he was not already selected, and that he wasn't a building (I hated that in Age of Empires, you could lasso buildings and accidently group them along with the army . . . nah, none of that.) And now it works, sort of. I don't have the visible aspects of the lasso, no box on the screen, but my units are selected, but when I lasso selected units, they don't yet deselect. Here it is, the entire freaking script so far:


function deselect()
{
var recorded;
if(!key_ctrl) //if ctrl is not pressed
{
unselect = 1; //set unselect flag to unselect everything
wait(1); //wait a frame
unselect = 0; //re-enable selection
}
while(mouse_left) //while mouseLeft is pressed
{
if(recorded != 1) //if first position if mouse is not recorded
{
mouse_trace();
vec_set(mouseCoord1,target);
recorded = 1;
}
mouse_trace();
vec_set(mouseCoord2,target);
wait(1);
}
mouse_trace();
vec_set(mouseCoord2,target);
mouseCoord3.x = mouseCoord1.x; //find the next two corners
mouseCoord3.y = mouseCoord2.y;
mouseCoord3.z = 0;
mouseCoord4.x = mouseCoord2.x;
mouseCoord4.x = mouseCoord1.y;
mouseCoord4.z = 0;
lasso = 1;
wait(1);
lasso = 0;
recorded = 0;
return; //exit function
}

function lassoMe() //groups tanks via a lasso created by click and drag
{
if((mouseCoord1.x < mouseCoord2.x) && (mouseCoord1.y > mouseCoord2.y))
//box#1,if lasso diagnal went from up to down left to right, then:
{
debug = 1;
if(((my.x <= mouseCoord2.x) && (my.x >= mouseCoord1.x))
&& ((my.y >= mouseCoord2.y) && (my.y <= mouseCoord1.y)))
//if inside the box
{
//select the unit if he is not selected, or is not the humans. If not, deselect.
my.selected = ((my.selected != 1) && (my.person == 1));
}
}
if((mouseCoord1.x < mouseCoord2.x) && (mouseCoord1.y < mouseCoord2.y))
//box#2, if lasso diagnal went from down to up left to right, then:
{
debug = 2;
if(((my.x <= mouseCoord2.x) && (my.x >= mouseCoord1.x))
&& ((my.y >= mouseCoord1.y) && (my.y <= mouseCoord2.y)))
//if inside the box
{
//select the unit if he is not selected, or is not the humans. If not, deselect.
my.selected = ((my.selected != 1) && (my.person == 1));
}
}
if((mouseCoord1.x > mouseCoord2.x) && (mouseCoord1.y < mouseCoord2.y))
//box#3, if lasso diagnal went from down to up right to left, then:
{
debug = 3;
if(((my.x <= mouseCoord1.x) && (my.x >= mouseCoord2.x))
&& ((my.y >= mouseCoord1.y) && (my.y <= mouseCoord2.y)))
//if inside the box
{
//select the unit if he is not selected, or is not the humans. If not, deselect.
my.selected = ((my.selected != 1) && (my.person == 1));
}
}
if((mouseCoord1.x > mouseCoord2.x) && (mouseCoord1.y > mouseCoord2.y))
//box#4, if lasso diagnal went from up to down right to left, then:
{
debug = 4;
if(((my.x <= mouseCoord1.x) && (my.x >= mouseCoord2.x))
&& ((my.y >= mouseCoord2.y) && (my.y <= mouseCoord1.y)))
//if inside the box
{
//select the unit if he is not selected, or is not the humans. If not, deselect.
my.selected = ((my.selected != 1) && (my.person == 1));
}
}
}

action Tank //controls tanks
{
my.metal = on;
my.narrow = on;
my.fat = off;
my.health = 250 + TankBonus; //set health to 250. Since this is the USA, apply a bonus
my.LoS = 500; //set view distance
my.enable_click = on; //enable click
my.event = handleTankEvents; //handle events, such as stuck, collision, click
my.team = 1; //team is set to 1, these are the player's units and the player defaults to team 1.
my.person = 1; //used by player one, the human player
my.stance = aggressive; //default stance is agressive
my.type = 2; //is a vehicle
my.mode = 0; //moving or no?
my.civ = America; //civ is set by the tank factory that creates it. (AMERICAN FOR TESTING)
my.pan = ang(my.pan); //set rotation to -180 . . . +180 range
my.selected = off; //default to unselected
createTurret(my.civ); //create the turret according to civilization and era.
while(my.health > 0)
{
if(degroup == 1) { my.group = 0; }
if(lasso == 1) { lassoMe(); }
if(my.selected == on) //if selected
{
if(my.selecter != 1) //if doesn't have selection ring
{
ent_create(selectBMP,my.x,selectSprite); //create it
my.selecter = 1; //set selecter to one
}
my.selected = (unselect == 0); //deselect if something else is clicked on
if((mouse_right) && (!key_x)) //if rightclicked while selected
{
mouse_trace(); //find coordinate
ent_create(targBMP,target,beacon);
if(you != null)
{
wait(1);
}
vec_set(my.targX,target); //set to unit's targets
my.mode = 1; //set him to move
}
if(key_ctrl) //assign hotkeys on ctrl+#
{
if(key_1) { ungroup(); my.group = 1; ent_create(grpNum1,my.x,grpNum); }
if(key_2) { ungroup(); my.group = 2; ent_create(grpNum1,my.x,grpNum); }
if(key_3) { ungroup(); my.group = 3; ent_create(grpNum1,my.x,grpNum); }
if(key_4) { ungroup(); my.group = 4; ent_create(grpNum1,my.x,grpNum); }
if(key_5) { ungroup(); my.group = 5; ent_create(grpNum1,my.x,grpNum); }
if(key_6) { ungroup(); my.group = 6; ent_create(grpNum1,my.x,grpNum); }
if(key_7) { ungroup(); my.group = 7; ent_create(grpNum1,my.x,grpNum); }
if(key_8) { ungroup(); my.group = 8; ent_create(grpNum1,my.x,grpNum); }
if(key_9) { ungroup(); my.group = 9; ent_create(grpNum1,my.x,grpNum); }
if(key_0) { my.group = 0; } //Ungroup via ctrl+0.
}
if(key_del) { my.health = -50; } //kill on delete command
if(key_s) { my.mode = 0; } //stop the unit on key s
if(key_a) { selectAllOfType(); } //select all of the same unit on key a
if(key_e) { /*evacuate();*/ } //on e evacuate all units in the tank.
if((key_x) && (mouse_right)) //attack ground on X + rightclick
{
mouse_trace();
vec_set(my.targX,target);
my.mode = 2;
}
}
if(my.mode == 0) //if standing still:
{
if(my.stance != noAttack)
{
//scan for enemies at LOS range, if one is found, move in and attack according to stance.
temp.pan = 360;
temp.tilt = 0;
temp.z = my.LoS;
scan_entity(my.x,temp);
if(you != null)
{
if(you.team != my.team)
{
my.mode = 2;
}
}
}
}
if(my.mode == 1) //if moving
{
moveVehicle(10);
if(vec_dist(my.x,my.targX) <= 20) { my.mode = 0; } //when there, return to still mode.
}
if(my.mode == 2) //if attacking
{
if(my.stance == aggressive)
{
if(vec_dist(my.x,my.targX) > p1TankRange)
{
moveVehicle(10); //move in range
}
else
{
my.inRange = on; //rotate turret. Turret commences the attack.
}
}
if(my.stance == standGround)
{
if(vec_dist(my.x,my.targX) < p1TankRange)
{
my.inRange = on;
}
else
{
my.mode = 0;
}
}

}
wait(1);
}
//run death animation, make passable and remove
ent_remove(me);
}


It when the player presses the mouse. A trace is fired from the mouse and records its position. Then a trace is fired from the mouse again and records the mouses new position until the mouse is no longer being pressed (this is happening in function deselect(); which is called by the mouse) then the other corners of the box are defined (but unused, I'll need them for the visual). The lasso variable set to one and during the wait command, the tanks call lassoMe(); and then the variable is set back to zero so no more tanks try to add themselves to the selected group.

Then in lassoMe(), each possible stroke that the player can make with the mouse is defined. There are four of them, determined by where mouseCoord1 is in respect to mouseCoord2 (see diagram). Then I check to see if the entity is in the box (see diagram) and then I have him selected.

And you'll notice that the selection command has a conditional in it. Yep, something I found out about recently. Since a true condition returns 1 and a false one returns zero, I can set flags this way and save space on the editor.

Speaking of space, this is enough typing.
while(thisCodeDoesntWork)
{
smashComputer(); //take out some pent out anger
throwDartsAtBoss(); //take out more anger
sleep(6*60*60); //sleep six hours
}

No comments: