CRPL code goals

Started by Jallun, July 26, 2014, 06:11:04 PM

Previous topic - Next topic

Grayzzur

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.
"Fate. It protects fools, little children, and ships named 'Enterprise.'" -William T. Riker

Jallun

#16
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.

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.

ParkourPenguin

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.
"Only a life lived for others is a life worthwhile."
-Albert Einstein

Jallun

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.

ParkourPenguin

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.
"Only a life lived for others is a life worthwhile."
-Albert Einstein

Jallun

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.

ParkourPenguin

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.
"Only a life lived for others is a life worthwhile."
-Albert Einstein

Jallun

#22
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.

ParkourPenguin

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 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.
"Only a life lived for others is a life worthwhile."
-Albert Einstein

Jallun

#24
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?

ParkourPenguin

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]
"Only a life lived for others is a life worthwhile."
-Albert Einstein