Knuckle Cracker

Creeper World 3 => The Coder's Corner => Topic started by: Jallun on July 26, 2014, 06:11:04 PM

Title: CRPL code goals
Post by: Jallun on July 26, 2014, 06:11:04 PM
1) Where collecting a certain tech artifact will instantly complete the map, regardless of the status of any emitters/spore towers.
2) A CRPL Core that will fire a bolt like the Bertha that is countered by Snipers.

What code(s) will fill these?
Title: Re: CRPL code goals
Post by: ParkourPenguin on July 27, 2014, 12:25:39 PM
1) Where collecting a certain tech artifact will instantly complete the map, regardless of the status of any emitters/spore towers.
Try looking into the utility command DestroyAllEnemyUnits. Unfortunately, it doesn't have a wiki page, so I have no idea how it works or what it does, but it sounds like it'll destroy all units that count for victory. If it doesn't, just get all the UIDs on the map via GetAllUnitsInRange (http://knucklecracker.com/wiki/doku.php?id=crpl:docs:getallunitsinrange), filter out which ones have the attribute CONST_COUNTSFORVICTORY as true by using GetUnitAttribute (http://knucklecracker.com/wiki/doku.php?id=crpl:docs:getunitattribute), and destroy all of those with the Destroy (http://knucklecracker.com/wiki/doku.php?id=crpl:docs:destroy) command. I think that should cause you to win the map.

2) A CRPL Core that will fire a bolt like the Bertha that is countered by Snipers.
Virgil made a gun script a while back on his blog post Chimera (http://knucklecracker.com/blog/index.php/2013/01/chimera/). I've attached both of the scripts he used below. To get the projectiles to be targeted by snipers, just set CONST_SNIPERTARGET to true and mess around with CONST_HEALTH / CONST_MAXHEALTH in the bullet script.
Title: Re: CRPL code goals
Post by: knucracker on July 28, 2014, 09:10:27 AM
DestroyAllEnemyUnits looks like it will destroy all units that are set as something a Nullifier will fire at.
Title: Re: CRPL code goals
Post by: Jallun on July 28, 2014, 05:31:31 PM
Quote from: ParkourPenguin on July 27, 2014, 12:25:39 PM2) A CRPL Core that will fire a bolt like the Bertha that is countered by Snipers.
Virgil made a gun script a while back on his blog post Chimera (http://knucklecracker.com/blog/index.php/2013/01/chimera/). I've attached both of the scripts he used below. To get the projectiles to be targeted by snipers, just set CONST_SNIPERTARGET to true and mess around with CONST_HEALTH / CONST_MAXHEALTH in the bullet script.

For this one in particular, I set the Sniper target thing against the CRBullet so the sniper will shoot down the shots?
Title: Re: CRPL code goals
Post by: ParkourPenguin on July 28, 2014, 06:31:37 PM
Quote from: Jallun on July 28, 2014, 05:31:31 PM
For this one in particular, I set the Sniper target thing against the CRBullet so the sniper will shoot down the shots?

Yup. You can do everything that I previously mentioned by adding the following lines of code into the once...endonce block of CRBullet.crpl:
SetUnitAttribute(Self CONST_SNIPERTARGET TRUE)
SetUnitAttribute(Self CONST_SNIPERIGNORELOS TRUE)
SetUnitAttribute(Self CONST_MAXHEALTH 20)
SetUnitAttribute(Self CONST_HEALTH 20)


Each shot from the sniper deals 20 damage, I believe (please correct me if I'm wrong).

I also added one thing: by setting CONST_SNIPERIGNORELOS to true, snipers don't care whether or not their target is in their line of sight. This is useful if their target is suppose to be flying through the air, like a bullet.
Title: Re: CRPL code goals
Post by: Jallun on July 28, 2014, 06:57:24 PM
Quote from: ParkourPenguin on July 28, 2014, 06:31:37 PM
Quote from: Jallun on July 28, 2014, 05:31:31 PM
For this one in particular, I set the Sniper target thing against the CRBullet so the sniper will shoot down the shots?

Yup. You can do everything that I previously mentioned by adding the following lines of code into the once...endonce block of CRBullet.crpl:
SetUnitAttribute(Self CONST_SNIPERTARGET TRUE)
SetUnitAttribute(Self CONST_SNIPERIGNORELOS TRUE)
SetUnitAttribute(Self CONST_MAXHEALTH 20)
SetUnitAttribute(Self CONST_HEALTH 20)


Each shot from the sniper deals 20 damage, I believe (please correct me if I'm wrong).

I also added one thing: by setting CONST_SNIPERIGNORELOS to true, snipers don't care whether or not their target is in their line of sight. This is useful if their target is suppose to be flying through the air, like a bullet.

Alright, and another thing: how to modify the interval of the shots and their range?

Edit: How does a crpl file get imported?
Title: Re: CRPL code goals
Post by: ParkourPenguin on July 28, 2014, 07:50:28 PM
Quote from: Jallun on July 28, 2014, 06:57:24 PM
Alright, and another thing: how to modify the interval of the shots and their range?

Edit: How does a crpl file get imported?

How to import CRPL files:
If you already have a CRPL file, all you need to do is to move it to the "scripts" folder where your world is saved in the world editor. For me on windows, it's located at C:\Users\ParkourPenguin\Documents\creeperworld3\WorldEditor. Here, all the maps in the world editor are saved, including all the scripts for these maps.

Locate which world you want to import the script(s) to, open that folder, then there should be a folder in there called "scripts". Just move the .crpl files into that folder.

After that, get back into the world editor in Creeper World 3. In edit mode, select the "Unit" tab, and click on the blue "Scripts" button near the right. Then, just click on "Compile All" near the bottom of the thing that pops up, and the scripts should be ready to be added to CRPL cores.

How to modify the interval of the shots and their range:
The range should be easy. Once you build a CRPL core and add the CRGun script to it, just select the script's name from the box directly below where you added it, and a second box labeled "Input Variables" should pop up right below it. Here, you can modify the range of it.

However, the interval of the shots is a bit harder, since I don't believe Virgil made that an input variable. However, it's possible to modify the script and make it an input variable. I've attached a slightly modified version of Virgil's script that does this to this post. I added an input variable called "interval" that dictates how many frames it should wait before firing again. 30 frames is 1 second, so by default (60 frames), it will wait 2 seconds.


I hope this helped! Please don't hesitate to ask if you have any more questions!
Title: Re: CRPL code goals
Post by: Jallun on July 28, 2014, 08:22:09 PM
Quote from: ParkourPenguin on July 28, 2014, 07:50:28 PM
How to modify the interval of the shots and their range:
The range should be easy. Once you build a CRPL core and add the CRGun script to it, just select the script's name from the box directly below where you added it, and a second box labeled "Input Variables" should pop up right below it. Here, you can modify the range of it.

How is the range measured (Metres, Yards etc.)? Also, it appears I cannot type into that box.
Title: Re: CRPL code goals
Post by: Lost in Nowhere on July 28, 2014, 08:48:51 PM
The range is measured in tiles, which don't have any specific conversion to real-world sizes; if you need one, just choose one that works.
Title: Re: CRPL code goals
Post by: Asbestos on July 28, 2014, 10:32:51 PM
You have to select one of the scripts and then modify the variables below the box.
Title: Re: CRPL code goals
Post by: ParkourPenguin on July 28, 2014, 10:53:01 PM
Quote from: Jallun on July 28, 2014, 08:22:09 PM
How is the range measured (Metres, Yards etc.)? Also, it appears I cannot type into that box.

As Lost in Nowhere stated, the radius is measured in tiles. Tiles is probably the most common unit of distance in CW3; however, pixels is also used in some commands.

Also, which box are you talking about? I attached an image below detailing the process if it helps out at all.
Title: Re: CRPL code goals
Post by: Jallun on July 28, 2014, 11:19:16 PM
Quote from: ParkourPenguin on July 28, 2014, 10:53:01 PM
Quote from: Jallun on July 28, 2014, 08:22:09 PM
How is the range measured (Metres, Yards etc.)? Also, it appears I cannot type into that box.

As Lost in Nowhere stated, the radius is measured in tiles. Tiles is probably the most common unit of distance in CW3; however, pixels is also used in some commands.

Also, which box are you talking about? I attached an image below detailing the process if it helps out at all.

I got the gun to work after remembering to import the two CR scripts, though as separate CRPL cores. Now to make the gun effect do two things:
1) Refresh every 3 minutes
2) Only start firing upon building of at least 2 Snipers or a long wait of 10 minutes.

Since right now, it fires upon the map starting and a CN isn't even imprinted onto the map at that point.
Title: Re: CRPL code goals
Post by: ParkourPenguin on July 29, 2014, 12:05:45 AM
Quote from: Jallun on July 28, 2014, 11:19:16 PM
I got the gun to work after remembering to import the two CR scripts, though as separate CRPL cores. Now to make the gun effect do two things:
1) Refresh every 3 minutes
2) Only start firing upon building of at least 2 Snipers or a long wait of 10 minutes.

Since right now, it fires upon the map starting and a CN isn't even imprinted onto the map at that point.

Don't attach the CRBullet script to any CRPL core. The CRGun script will automatically make use of the CRBullet script itself. Just having the CRBullet script compiled is enough.

1) If you mean you want it to fire every 3 minutes, then set the interval to the equivalent number of frames. 3 minutes = 180 seconds = 5400 frames. Therefore, the input variable "interval" should be set to 5400.

2) I've updated the CRGun script with both of these features implemented. I wasn't able to test this, as it's pretty late where I'm at right now, so if there are any bugs, let us know, and someone will fix it. It's attached to the previous post with only CRGun.crpl attached; click here (http://knucklecracker.com/forums/index.php?action=dlattach;topic=16856.0;attach=18565) to download it.
Title: Re: CRPL code goals
Post by: Jallun on July 29, 2014, 08:51:54 AM
Quote from: ParkourPenguin on July 29, 2014, 12:05:45 AM
2) I've updated the CRGun script with both of these features implemented. I wasn't able to test this, as it's pretty late where I'm at right now, so if there are any bugs, let us know, and someone will fix it. It's attached to the previous post with only CRGun.crpl attached; click here (http://knucklecracker.com/forums/index.php?action=dlattach;topic=16856.0;attach=18565) to download it.

I've found that while the gun does aim correctly to the closest target, it does not fire regardless of what I do. I've built ~8 Snipers and 1.5 hours into the map and no shot whatsoever.
Title: Re: CRPL code goals
Post by: ParkourPenguin on July 29, 2014, 09:35:08 AM
Quote from: Jallun on July 29, 2014, 08:51:54 AM
I've found that while the gun does aim correctly to the closest target, it does not fire regardless of what I do. I've built ~8 Snipers and 1.5 hours into the map and no shot whatsoever.

I did some testing, and it seems to work perfectly as intended. I can't seem to replicate what happened to you. Could you list step-by-step everything you do, including the values of all the input variables? That would help me determine what's causing that problem.
Title: Re: CRPL code goals
Post by: Grayzzur on July 29, 2014, 09:38:16 AM
You can also attach the save.cw3 file from your map project to this thread, and that may help figure out what's wrong with it.
Title: Re: CRPL code goals
Post by: Jallun on July 29, 2014, 11:34:42 AM
Quote from: ParkourPenguin on July 29, 2014, 09:35:08 AM
Quote from: Jallun on July 29, 2014, 08:51:54 AM
I've found that while the gun does aim correctly to the closest target, it does not fire regardless of what I do. I've built ~8 Snipers and 1.5 hours into the map and no shot whatsoever.

I did some testing, and it seems to work perfectly as intended. I can't seem to replicate what happened to you. Could you list step-by-step everything you do, including the values of all the input variables? That would help me determine what's causing that problem.

All the input variables listed by use of the CRGun.crpl file (CRBullet.crpl is compiled in):

name: Gun1
barrelOffset: 1
barrelRecoil: 1
barrelRecoilRate: 30
maxRotationSpeed: 10
Range: 150
Payload: 30
Interval: 5400

Edit: The check for sniper count appears to be missing. Same thing for the original 10 minute timer. The gun should fire starting from the second Sniper being built completely "or" when the Mission Time value hits 00:10:00

Quote from: Grayzzur on July 29, 2014, 09:38:16 AM
You can also attach the save.cw3 file from your map project to this thread, and that may help figure out what's wrong with it.

File is attached below. Intention for the script that isn't firing is the gun-shaped object at the north-east corner.
(http://i.imgur.com/ATQxbL8.jpg)
This is the map; the red circle at the bottom left means that the 2nd Sniper is just finished building. At that point, the gun at the top-right corner should start firing.
Title: Re: CRPL code goals
Post by: ParkourPenguin on July 29, 2014, 02:33:58 PM
I think I found the problem. In CRBullet.crpl, the input variables are like this:
$targetX:25$targetY:63$speed:2.0
$payload:20

when they should be like this:
$targetX:25
$targetY:63
$speed:2.0
$payload:20

Try making that change, then hitting "COMPILE ALL" in the "Scripts" menu in the editor. If you get the message "2 Scripts successfully compiled..." in the message box under that, then it means that you're good to go. If you get any errors, then something's wrong with the scripts.

By the way: you've probably figured this out by now, but you need to use custom images to get the tower base, barrel, and bullet to show up correctly. "Custom1" is the barrel's image location, and "Custom2" is the bullet's image location. You'll have to set the tower base's image manually in the CRPL tower's "properties" window.
Title: Re: CRPL code goals
Post by: Jallun on July 29, 2014, 03:05:07 PM
Quote from: ParkourPenguin on July 29, 2014, 02:33:58 PM
I think I found the problem. In CRBullet.crpl, the input variables are like this:
$targetX:25$targetY:63$speed:2.0
$payload:20

when they should be like this:
$targetX:25
$targetY:63
$speed:2.0
$payload:20

Try making that change, then hitting "COMPILE ALL" in the "Scripts" menu in the editor. If you get the message "2 Scripts successfully compiled..." in the message box under that, then it means that you're good to go. If you get any errors, then something's wrong with the scripts.

By the way: you've probably figured this out by now, but you need to use custom images to get the tower base, barrel, and bullet to show up correctly. "Custom1" is the barrel's image location, and "Custom2" is the bullet's image location. You'll have to set the tower base's image manually in the CRPL tower's "properties" window.

Something about this code isn't working when I build the two snipers:

:checkFor2Snipers
0 ->count
GetUnitsInRange(MapWidth 2 div ceil MapHeight 2 div ceil dup2 max 3 mul) 0 do
   if(GetUnitType "SNIPER" eq)
   <-count 1 add ->count
   endif
loop
<-count 2 gte
--count


I don't understand what the itallics part is doing.
Title: Re: CRPL code goals
Post by: ParkourPenguin on July 29, 2014, 03:45:06 PM
Quote from: Jallun on July 29, 2014, 03:05:07 PM
Something about this code isn't working when I build the two snipers:

:checkFor2Snipers
0 ->count
GetUnitsInRange(MapWidth 2 div ceil MapHeight 2 div ceil dup2 max 3 mul) 0 do
   if(GetUnitType "SNIPER" eq)
   <-count 1 add ->count
   endif
loop
<-count 2 gte
--count


I don't understand what the itallics part is doing.

The part in the italics is suppose to compute a big enough radius to fit every unit on the map in without it being unnecessarily large. You can replace that with this if you really wanted to:
GetUnitsInRange(CurrentCoords 999999) 0 do
But I don't know if there are any benefits (at least in terms of performance) to having a smaller radius.
Anyways, try replacing it. The previous code still works for me, but if the part in italics is causing it to fail for you, then replacing it with CurrentCoords 999999 will definitely get any snipers placed anywhere on the map.
Title: Re: CRPL code goals
Post by: Jallun on July 29, 2014, 07:00:10 PM
Quote from: ParkourPenguin on July 29, 2014, 03:45:06 PM
The part in the italics is suppose to compute a big enough radius to fit every unit on the map in without it being unnecessarily large. You can replace that with this if you really wanted to:
GetUnitsInRange(CurrentCoords 999999) 0 do
But I don't know if there are any benefits (at least in terms of performance) to having a smaller radius.
Anyways, try replacing it. The previous code still works for me, but if the part in italics is causing it to fail for you, then replacing it with CurrentCoords 999999 will definitely get any snipers placed anywhere on the map.

Looks like replacing it didn't fire upon the snipers being built. Could an ElapsedTime function fix it where the 10 minute wait is concerned? With this map, it shouldn't be a problem building Snipers early on.
Title: Re: CRPL code goals
Post by: ParkourPenguin on July 29, 2014, 08:04:17 PM
I have absolutely no idea as to why it's not working for you. No matter what I try, on that map you gave me, everything works out fine. When I build 2 snipers, it starts firing. After exactly 10 minutes, it starts firing.

The best thing that I can offer you at this point is to help you debug it on your own. Attached is a CRGun.crpl script that will print out some stuff to the tracelog. Namely, what values are being returned by the 10-minute threshold and the 2-sniper threshold every second, as well as if it successfully creates a bullet.

I also noticed that you didn't add the attributes to the CRBullet.crpl script. I've attached that as well with the attributes from earlier. The bullet should also print out one thing to the tracelog.

Please say exactly what is printed out to the tracelog.
Title: Re: CRPL code goals
Post by: Jallun on July 29, 2014, 09:39:02 PM
Quote from: ParkourPenguin on July 29, 2014, 08:04:17 PM
Please say exactly what is printed out to the tracelog.

The tracelog says: I am a bullet.

I'll change that to missile if needed, since the gun is a missile launcher.

Also, it finally fires properly, though a 2 second time interval for 5400 interval input variable seems off.
Title: Re: CRPL code goals
Post by: ParkourPenguin on July 29, 2014, 10:08:45 PM
I didn't make any changes to the scripts, other than adding those 4 attributes I talked about earlier into the bullet script, which shouldn't have had an effect on it not firing.

Also, with regards to the 2 second interval, that's the default value (60 frames), so it might be a bug in updating scripts. Try deleting the tower and rebuilding it.

Beyond that, there were no changes made to the CRGun script other than adding a bunch of stuff to trace.  You can click here (http://knucklecracker.com/forums/index.php?action=dlattach;topic=16856.0;attach=18565) to download that version of the CRGun.crpl script again to remove all the tracelog stuff. The CRBullet.crpl script should be easy to remove all the tracelog things: just remove those 2 lines of code at the beginning of the once...endonce block. It should look like this when you're done:
$targetX:25
$targetY:63
$speed:2.0
$payload:20

once
SetUnitAttribute(self CONST_CREATEPZ FALSE)
SetUnitAttribute(self CONST_TAKEMAPSPACE FALSE)
SetUnitAttribute(Self CONST_SUPPORTSDIGITALIS FALSE)
SetUnitAttribute(Self CONST_NULLIFIERDAMAGES FALSE)
SetUnitAttribute(Self CONST_COUNTSFORVICTORY FALSE)
SetUnitAttribute(Self CONST_SNIPERTARGET TRUE)
SetUnitAttribute(Self CONST_SNIPERIGNORELOS TRUE)
SetUnitAttribute(Self CONST_MAXHEALTH 20)
SetUnitAttribute(Self CONST_HEALTH 20)

QueueMove(<-targetX <-targetY <-speed)
endonce

if (GetQueuedMoveCount eq0)
CurrentCoords <-payload SetCreeper
Destroy(self 0)
endif


So... the best thing I can tell you to do right now would be to delete that CRGun CRPL core, recompile both scripts (without the tracelog stuff, obviously), then rebuild the CRPL core and add the CRGun script to it again.
Title: Re: CRPL code goals
Post by: Jallun on July 29, 2014, 10:37:59 PM
Phew, the gun's a success now. Just built two snipers and it started firing, and same goes with waiting the 10 minutes.

Edit: In a manner similar to Farbor, I have this within CRGun:

:AddConversationMessage
<-onTarget GetGameTimeFrames 18000 gte @checkFor2Snipers or and
ClearConversation
PauseGame
AddConversationMessage(0 "What is that projectile!?")
AddConversationMessage(1 "This is what I feared. The creeper is using that missile launcher to remotely fire creeper at us.")
AddConversationMessage(7 "Those missiles have hard shells. Maybe the sniper can shoot through?")
AddConversationMessage(1 "I'm not sure. That weapon hasn't actually been deployed before.")
AddConversationMessage(0 "We'll just try his suggestion and see what happens.")
ShowConversation
#Endfunc

Is that correct?
Title: Re: CRPL code goals
Post by: ParkourPenguin on July 30, 2014, 10:07:54 AM
You have the basic idea down; however, you didn't use that function at all in the middle of the script where it should be called. Basically, when it fires, you want it to show that message dialog; however, you don't want it to show that every time it fires, so you have to add a boolean in there that will only allow it to be shown once. Just remember that you'll have to initialize that boolean in the once...endonce for it to properly work.

Also, I don't know how naming conventions work, but I normally don't like functions to have the same name as commands, so I changed the function's name from :AddConversationMessage to :ShowCRGunMessage.

Here's some code below with everything I added in bold:
Spoiler
# WBWGun.crpl
# Created on: 1/8/2013 11:16:41 AM
# ------------------------------------------


$name:"Gun1"
$barrelOffset:10
$barrelRecoil:10
$barrelRecoilRate:0.5
$maxRotationSpeed:0.1
$range:15
$payload:30
$interval:60

once
   self "barrel" "Custom1" SetImage
   0 ->targetX
   0 ->targetY
   
   self "barrel" 0 SetImageRotation
   self "barrel" 0 0 -0.01 SetImagePosition
   
   True ->messageNotShown
   
   <-barrelOffset ->currentBarrelOffset
endonce

# Find the closest unit.  0 is returned if no unit is in range
@GetClosestUnit ->closestUnit

# Get the x and y coordinate of the closest unit and set them
# on targetX and targetY.  If no unit is in range, set -1.
<-closestUnit neq0 if
   <-closestUnit CONST_COORDX GetUnitAttribute ->targetX
   <-closestUnit CONST_COORDY GetUnitAttribute ->targetY
else
   -1 ->targetX -1 ->targetY
endif

# Move the barrel to point at the target.
# The return from this call tells us if we are pointing at the target.
@ManageBarrel ->onTarget

# This offsets the barrel position based on the current recoil amount.
@HandleRecoil

# If we are pointing at the target then fire.
# Only fire so quickly, hence the timer check.
# When we fire, we also set the barrel recoil.
<-onTarget GetGameTimeFrames 18000 gte @checkFor2Snipers or and if
   GetTimer0 eq0 if
      <-messageNotShown if
         @ShowCRGunMessage
         False ->messageNotShown
      endif

      PlaySound("Weapons26")
      @CreateBullet
      <-currentBarrelOffset <-barrelRecoil sub ->currentBarrelOffset
      <-currentBarrelOffset 0 lt if 0 ->currentBarrelOffset endif
      <-interval SetTimer0
   endif
endif

# Func :CreateBullet
# Creates a bullet object
:CreateBullet
   "CRPLCore" CurrentX CurrentY CreateUnit ->unit
   <-unit "CRBullet.crpl" AddScriptToUnit
   <-unit "CRBullet.crpl" "targetX" <-targetX SetScriptVar
   <-unit "CRBullet.crpl" "targetY" <-targetY SetScriptVar
   <-unit "CRBullet.crpl" "payload" <-payload SetScriptVar
   <-unit "main" "Custom2" SetImage
   <-unit "main" -0.01 SetImagePositionZ
   <-unit "main" self "barrel" GetImageRotation SetImageRotation
# EndFunc


# Func :GetClosestUnit
# Finds the nearest unit in range.
# Returns the unit uid of the closest unit, or 0 if no unit is in range
:GetClosestUnit
   99999999 ->closestDistance
   0 ->closestUnit
   #All 'player' units are returned, including power zones and artifacts.  If you don't want them to be targeted, they must be excluded...
   GetUnitsInRange(CurrentCoords <-range)  ->unitCount
   do (<-unitCount 0)
      ->unit
      CurrentCoords <-unit CONST_COORDX GetUnitAttribute <-unit CONST_COORDY GetUnitAttribute Distance ->d
      if (<-d lt(<-closestDistance))
         GetUnitType(<-unit) ->ut
         if ( not(<-ut eq ("POWERZONE") or (<-ut eq ("TECHARTIFACT")) or (<-ut eq("MESSAGEARTIFACT")) or (<-ut eq("SHIELDKEY"))) )
            <-d ->closestDistance
            <-unit ->closestUnit
         endif   
      endif
   loop
   <-closestUnit
# EndFunc


# Func :ManageBarrel
# Rotates the barrel towards the target.
# Returns 1 if the barrel is facing the target
:ManageBarrel

# If no target is set, just return
<-targetX -1 eq if
   0
   return
endif

# Get the desired angle for the barrel based on the target coordinates.
# The calculation for deltaY seems backwards.  The reason is because the
# Y axis is inverted when using map coordinates.  The origin of the map is
# in the upper left hand corner of the map rather than the lower left.
# To compensate for this, we reverse the order we do the subtraction.
<-targetX CurrentX sub ->deltaX
CurrentY <-targetY sub ->deltaY
<-deltaY <-deltaX atan2 ->desiredAngle

# Determine the smallest angle between our current rotation and the desired rotation.
# This angle can be positive or negative.  This determines the direction the barrel
# should rotate to reach the desired angle.
self "barrel" GetImageRotation <-desiredAngle ShortestAngle ->rot

# The barrel can only rotate by some maximum amount per update.
# So we limit rot to the maxRotationSpeed.  Note that rot can
# be positive or negative, so we check both cases.
<-rot <-maxRotationSpeed gt if
   <-maxRotationSpeed ->rot
else
   <-rot <-maxRotationSpeed -1 mul lt if
      <-maxRotationSpeed -1 mul ->rot
   endif
endif

<-rot abs 0.0001 lt if
   1 ->onTarget
else
   0 ->onTarget
endif

# Add the rot to the current rotation
self "barrel" GetImageRotation <-rot add ->rot

# Set the barrel's new rotation
self "barrel" <-rot SetImageRotation

<-onTarget
# EndFunc


# Func :HandleRecoil
# Causes the barrel to recover from the recoil.
# Offsets that barrel based on the current recoil.
:HandleRecoil
<-currentBarrelOffset <-barrelOffset lt if
   <-currentBarrelOffset <-barrelRecoilRate add ->currentBarrelOffset
   <-currentBarrelOffset <-barrelOffset gt if <-barrelOffset ->currentBarrelOffset endif
endif

self "barrel" GetImageRotation ->rot

<-rot cos <-currentBarrelOffset mul ->barrelX
<-rot sin <-currentBarrelOffset mul ->barrelY

self "barrel" <-barrelX <-barrelY -0.01 SetImagePosition
# Endfunc



:checkFor2Snipers
0 ->count
GetUnitsInRange(MapWidth 2 div ceil MapHeight 2 div ceil dup2 max 3 mul) 0 do
   if(GetUnitType "SNIPER" eq)
   <-count 1 add ->count
   endif
loop
<-count 2 gte
--count
#Endfunc

:ShowCRGunMessage
ClearConversation
AddConversationMessage(0 "What is that projectile!?")
AddConversationMessage(1 "This is what I feared. The creeper is using that missile launcher to remotely fire creeper at us.")
AddConversationMessage(7 "Those missiles have hard shells. Maybe the sniper can shoot through?")
AddConversationMessage(1 "I'm not sure. That weapon hasn't actually been deployed before.")
AddConversationMessage(0 "We'll just try his suggestion and see what happens.")
ShowConversation
PauseGame
#Endfunc
[close]