Table of Contents

<-CW3 Home<- CRPL Home

Code Examples

Code examples contributed by map makers and coders alike. Feel free to submit your own - it will be much appreciated.

You can also view the scripts in any map: make a copy of the map you want to inspect, rename the copy “save.cw3”, create a new project, and then replace the project's “save.cw3” file.

Telanir contributed an entire section on EasyCRPL.

Manage Treasure Chests in Credits Mission

# Goodie.crpl
# Created on: 9/10/2013 8:36:17 PM
# ------------------------------------------

$score:100

once
	GetCoresWithVar("name" "Player") pop ->player
endonce

if (Distance(CurrentCoords GetUnitAttribute(<-player CONST_COORDX) GetUnitAttribute(<-player CONST_COORDY)) lte(2))
	@ApplyPoints
	PlaySound("Retro20")
	Destroy(Self 1)
endif

:ApplyPoints
	AddAdditionalScore(<-score)
	CreateUnit("CRPLCORE" CurrentCoords) ->fadingPoints
	AddScriptToUnit(<-fadingPoints "FadingPoints.crpl")
	SetScriptVar(<-fadingPoints "FadingPoints.crpl" "pointAmt" <-score)

Contributed by VirgilW

Image Spinner

Specify a rate and which image to rotate. Positive rotation rates are counterclockwise and the rotation rate is in radians per frame.

$rotationRate:0.1
$imageToRotate:"main"

# Make a part spin around
Self <-imageToRotate GetImageRotation ->currentRotation
<-currentRotation <-rotationRate add ->currentRotation
Self <-imageToRotate <-currentRotation SetImageRotation

# This version is more terse and more efficient, but harder to read.
#Self <-imageToRotate Self <-imageToRotate GetImageRotation <-rotationRate add SetImageRotation

Contributed by VirgilW

Can be used for making a blinking light. Changes the transparency of an image from fully transparent to fully opaque in a cycle. The red, green, and blue values can be used to tint the color of the image.

$name:"light"
$customImageName:"custom0"
$red:255
$green:255
$blue:255
$rate:10
$active:1

once
	self <-name <-customImageName SetImage
	self <-name -0.01 SetImagePositionZ
endonce



<-active if
	<-alpha 0 lt if
		0 ->alpha
		<-rate abs ->rate
	else
		<-alpha 255 gt if
			255 ->alpha
			<-rate abs -1 mul ->rate
		endif
	endif

	<-alpha <-rate add ->alpha

	self <-name <-red <-green <-blue <-alpha SetImageColor
else
	self <-name 0 0 0 0 SetImageColor
endif

Contributed by VirgilW

Keep track of unit UIDs

You have some main unit which creates children units and you want to be able to keep track of these children: In this case, you get the UID when you create the other unit. For instance:

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

Contributed by VirgilW

Find player units matching specified criteria

You'd like to find player units that match some criteria: In this case, you can use the GetUnitsInRange function. For instance:

# 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
CurrentCoords <-range GetUnitsInRange ->unitCount
<-unitCount neq0 if
	<-unitCount 0 do
		->unit
		CurrentCoords <-unit CONST_COORDX GetUnitAttribute <-unit CONST_COORDY GetUnitAttribute Distance ->d
		<-d <-closestDistance lt if
			<-d ->closestDistance
			<-unit ->closestUnit
		endif
	loop
endif	
<-closestUnit

The GetUnitsInRange function pushes all of the UIDs of units within the specified radius to the stack. Then, it pushes the count to the top of the stack. If there are no units in range, a single “0” is pushed to the stack. So, you can look at the top of the stack to know how many other things are on the stack, and you know that each of them if a unit UID. A “do” loop becomes useful for iterating through and popping the items from the stack. In the above example, I'm looking for the closest player unit. So, I just get all within range then run through them calculating the distance to each once. Along the way I remember the one that is closest. Note that I could have made a much more sophisticated comparison criteria. I could, for instance, have added the unit's ammo to the distance so that I selected based on a combination of closeness and how much ammo the unit had on board.

Contributed by VirgilW

Locate unit based on value of variable

You want to find the UID of some other CRPLCore based on the value of a variable: Take the following example:

"name" "Gun" GetCoresWithVar ->unitCount
<-unitCount if
   <-unitCount 0 do
      ->unit
      <-unit CONST_MAXHEALTH 10 SetUnitAttribute
      <-unit CONST_HEALTH 10 SetUnitAttribute
   loop
endif

Here, we are looking for any CrplCore that has a script with a var called “name” that is set to a value of “Gun”. This allows us to add scripts to CrplCores, create a variable like this at the top of the script

$name:"Gun"

, then get objects that have that string value. Since this is an input var in the script, it can be edited by the map author without having to touch the script. Of course the GetCoresWithVar also works with any variable, so you could use it to find Cores that have set some flag, etc.

Contributed by VirgilW

Moving creeper wall

# MoveWall.crpl
# Created on: 2/4/2013 8:00:55 PM
# Author: J
# This script creates a wall of creeper on the left side of the map that moves forward every x frames
# You may choose in-game if the wall should keep going or release the creeper at the end
# If RepeatAtEnd=2 the creeper is released at the right side of the map while a new (empty) wall will run over the map
# If you choose to enable KeepCreeperOut, it will try to keep all other creeper out of the wall
# Spacing is the number of cells the KeepCreeperOut will keep 100% clean of creeper 
# ------------------------------------------
$MoveDelay:30
$InitialWallHeight:500
$InitialDelay:0
$RepeatAtEnd:1
$KeepCreeperOut:1
$Spacing:1

once
	<-InitialDelay Delay false ->stop 0 ->stepx <-MoveDelay ->stept
	MapHeight 0 do 0 I <-InitialWallHeight SetCreeper loop
endonce

<-stop not if
	MapHeight 0 do
		#move creeper back from the left side
		<-stepx neq0 if
			<-stepx I <-stepx 1 sub I GetCreeper AddCreeper
			<-stepx 1 sub I 0 SetCreeper
		endif
		#move creeper back from the right side
		<-stepx MapWidth 1 sub neq if
			<-stepx I <-stepx 1 add I GetCreeper AddCreeper
			<-stepx 1 add I 0 SetCreeper
		endif
		<-KeepCreeperOut if
			#keep creeper out of the wall, left side
			<-stepx 3 gte if
				<-stepx 3 sub <-Spacing sub I <-stepx 2 sub <-Spacing sub I GetCreeper AddCreeper
				<-stepx 2 sub <-Spacing sub I 0 SetCreeper
			endif
			#keep creeper out of the wall, right side
			<-stepx <-Spacing add MapWidth 4 sub lte if
				<-stepx 3 add <-Spacing add I <-stepx 2 add <-Spacing add I GetCreeper AddCreeper
				<-stepx 2 add <-Spacing add I 0 SetCreeper
			endif
		endif
	loop
	
	<-stept 1 sub ->stept
	#move creeper forward if stept is 0
	<-stept eq0 if
		<-stepx MapWidth 1 sub eq if
			<-RepeatAtEnd eq0 if
				true ->stop
			endif
			<-RepeatAtEnd neq0 if
				<-MoveDelay ->stept
				0 ->stepx
				<-RepeatAtEnd 1 eq if
					MapHeight 0 do
					0 I MapWidth 1 sub I GetCreeper AddCreeper
					MapWidth 1 sub I 0 SetCreeper loop
				endif
			endif
		else
			<-MoveDelay ->stept
			MapHeight 0 do
				#move the creeper in the wall forward
				<-stepx 1 add I <-stepx I GetCreeper AddCreeper
				<-stepx I 0 SetCreeper
				#move the creeper in front of the wall forward
				<-KeepCreeperOut if
					<-stepx <-Spacing add MapWidth 5 sub lte if
						<-stepx 4 add <-Spacing add I <-stepx 3 add <-Spacing add I GetCreeper AddCreeper
						<-stepx 3 add <-Spacing add I 0 SetCreeper
					endif
				endif
			loop
			<-stepx 1 add ->stepx
		endif
	endif
endif

Contributed by J

Terrain Rail Walker

# RailWalker.crpl
# ------------------------------------------

$MIN_TERRAIN_HEIGHT:1
$MAX_TERRAIN_HEIGHT:3
$SPEED:2

once
	# Initialize our last position since we don't have one.
	-1 ->lastCellX 
	-1 ->lastCellY 
endonce

#If we aren't moving, choose a new location.  The location will be a neighboring cell.
GetQueuedMoveCount eq0 if
	@ChooseNewCell if
		<-chosenX <-chosenY <-SPEED QueueMove
		CurrentX ->lastCellX
		CurrentY ->lastCellY
	endif
endif


:ChooseNewCell
	-1 ->chosenX
	-1 ->chosenY

	# Get a list of the neighbors that we can move to.
	# This call returns the coordinate pairs on the stack.
	@GetPossibleCells

	# Choose a random location within the list
	0 <-count RandInt ->randCellNumber

	# Go through the list and pop all of the coordinates off the stack.
	# As we pass the coordinates that we chose in our random number above, remember them.
	# Those are the coordinates we will be returning.
	<-count 0 do
		->y
		->x
		I <-randCellNumber eq if
			<-x ->chosenX
			<-y ->chosenY
		endif
	loop
	# Return if we chose a new location
	<-chosenX -1 neq


:GetPossibleCells
	#Check the four neighboring cells to see if they are acceptable terrain heights.
	0 ->count
	CurrentX 1 add ->cx CurrentY ->cy @CheckCell		#Right
	CurrentX ->cx CurrentY 1 sub ->cy @CheckCell		#Up
	CurrentX 1 sub ->cx CurrentY ->cy @CheckCell		#Left
	CurrentX ->cx CurrentY 1 add ->cy @CheckCell		#Down

	# By default, we won't return the last cell coordinates.  This is so the patrolling unit
	# doesn't return back to where it came from immediately.  But, if the only choice is to return
	# to the previous cell, then that is what we have to do.
	<-count eq0 if 
		<-lastCellX
		<-lastCellY
		1 ->count
	endif


:CheckCell
	#Check to see if the cell we are looking at is the last cell, if so ignore.
	<-cx <-lastCellX neq <-cy <-lastCellY neq or if
		# Check if the target cell is an acceptable terrain height.  If so, push the 
		# coordinates to the stack and increment count.
		<-cx <-cy GetTerrain ->terrainHeight
		<-terrainHeight <-MIN_TERRAIN_HEIGHT gte <-terrainHeight <-MAX_TERRAIN_HEIGHT lte and if
			<-cx
			<-cy
			<-count 1 add ->count
		endif
	endif

Contributed by virgilw

Circular move pattern

Sometimes you want a core to be moving in a circle around a point. Attach this script to make that happen. Change precision to improve movement or make it move counter-clockwise (high values). Remove all “asfloat” and both “0 Round” to make the circle one cell smaller downwards and to the right (4 cells as center instead of 1).

# moves the core in a circle around x and y with a set speed
# ------------------------------------------
$speed:1
$size:16
$x:32
$y:32
$precision:0.2
once
	0.0 ->step
endonce
GetQueuedMoveCount eq0 if
	<-step cos <-size asfloat mul <-x asfloat add 0 Round <-step sin <-size asfloat mul <-y asfloat add 0 Round <-speed QueueMove
	<-step <-precision add ->step
endif

Contributed by J

Connect totems to win

Here's are two scripts that when used, blow up all enemy structures when enough totems are connected. The first script is used to create totems on the map and stores their ID's, so they can be read by the second script. Script 1:

# Author: J
# ------------------------------------------
once
	"TOTEM" CurrentCoords CreateUnit ->totemUID
	"totem" ->unitName
	4 delay self 0 Destroy
endonce

Script 2:

# Author: J
# ------------------------------------------
$ammodrain:0.01
$totemsrequired:1
$scriptname:"totem.crpl"

once
	 2 delay
	 "unitName" "totem" GetCoresWithVar dup ->totemcount 0 do
		 <-scriptname "totemUID" getScriptVar
		 "totem" I concat ->!
	 loop
endonce

0 ->activecount
<-totemcount 0 do
	 "totem" I concat <-! dup ->unitUID CONST_AMMO GetUnitAttribute
	 0 gt if
		 <-activecount 1 add ->activecount
		 <-unitUID CONST_AMMO <-unitUID CONST_AMMO GetUnitAttribute <-ammodrain sub SetUnitAttribute
	 endif
loop

# if all totems are active, blow up all enemy units (insta-win)
<-activecount <-totemsrequired gte if
	 0 0 99999 GetEnemyUnitsInRange 0 do
		 dup Self neq if
			 2 Destroy
		 else
			 pop
		 endif
	 loop
	 Self 2 Destroy
endif

ammodrain: how much ammo it drains from the totem, use values between 0 and 0.05. totemsrequired: how many totems you need to coonect to win, use a number between 1 and how many totems you put on the map with script 1. scriptname: how you named script 1.

Contributed by J

Unit Providing Script

This script allows the user to set a type of unit, number of units and energy cost to collect/power the core it's attached to.

$buildCost:10
$unitToGive:"BERTHA"
$numToGive:3

if (not(GetUnitAttribute(Self CONST_ISBUILDING)))
	SetBuildLimit(<-unitToGive <-numToGive)
	Destroy(Self 1)
endif 

:Awake
	if (GetUpdateCount eq (0))
		SetUnitAttribute(Self CONST_ISBUILDING TRUE)
		SetUnitAttribute(Self CONST_BUILDCOST <-buildCost)
		SetUnitAttribute(Self CONST_CONNECTABLE TRUE)
		SetUnitAttribute(Self CONST_REQUESTPACKETS TRUE) 
		SetUnitAttribute(Self CONST_MAXHEALTH <-buildCost)
		SetUnitAttribute(Self CONST_HEALTH 0) 	
		SetUnitAttribute(Self CONST_CREATEPZ FALSE)
	endif

Contributed by VirgilW (posted by teknotiss)

Change Creeper or Anti-Creeper Colors

The following code would show how to make the creeper red at the start of a custom map, but keep the AC to whatever the player has set. (Untested… but it will work, right? :) )

once
   GetCreeperColors ->acB ->acG ->acR ->creeperB ->creeperG ->creeperR
   160 ->creeperR
   0 ->creeperG
   0 ->creeperB
   SetCreeperColors(<-creeperR <-creeperG <-creeperB <-acR <-acG <-acB)
endonce

Contributed by VirgilW

Wrap Creeper around the edges of the map

The following code will allow creeper to flow around the edges of the map. That makes the map feel like a globe. Best use on terrain, that is seamless.

Add this code to a tower. As long as this tower exists, the creeper will leave the map at the left and enter at right, and vise versa.

The parameters can be used to activate or deactivate left-right or top-bottom wrap.

# Author: knattertc
# ------------------------------------------
$wrapLeftRight:1
$wrapTopBottom:1

# Init Vars
MapWidth 1 sub ->right
0 ->left
0 ->top
MapHeight 1 sub ->bottom

# Wrap Left to Right
<-wrapLeftRight neq0 if
	<-bottom <-top do
		# Get Creeper on left and right side - add them up - devide by 2
		<-left I GetCreeper <-right I GetCreeper add 2 div ->mid 
		<-left I <-mid SetCreeper
		<-right I <-mid SetCreeper
	loop
endif

# Wrap Top to Bottom
<-wrapTopBottom neq0 if
	<-left <-right do
 		# Get Creeper on top and bottom - add them up - devide by 2
		I <-top GetCreeper I <-bottom GetCreeper add 2 div ->mid 
		I <-bottom  <-mid SetCreeper
		I <-top <-mid SetCreeper
	loop
endif

Contributed by knattertc

Create an emitter that increases its output rate over time

This script is an example of how to create an emitter that increases its output rate from a minimum value (BaseRate) to a maximum value (MaxRate) over a specified time (RampTime, in seconds) with a specified precision (NumIncrements). All variables are changeable by the user without editing the script.

This script uses Timer0 to track the rate of increase, so the tower is capable of doing other things while this is running (like moving).

The default values create an emitter that deploys creeper every 0.5 seconds starting at a rate of 25 creeper per drop and increasing to a rate of 150 creeper per drop over a period of ten minutes using a precision of 100 increments.

# Author: albrittbrat
#Program to ramp creeper deployment rate over time
#Time is in seconds
#-------------------------------------------------------------------------
$BaseRate:25
$MaxRate:150
$RampTime:600
$NumIncrements:100
$DeployRate:15
once
	<-BaseRate ->CRate
	0 SetTimer0
	<-RampTime 30 mul ->RampTime
	<-RampTime <-NumIncrements div 0 round ->TimerRate
endonce
#If the queue is empty, queue next move
#Drop AC based on input parameters
GetTimer0 eq0 if
	@DetermineCAmount
endif
CurrentCoords <-CRate SetCreeper
<-DeployRate Delay
#Function to determine amount of creeper to drop
#Range goes from BaseRate to MaxRate
:DetermineCAmount
<-CRate <-MaxRate lte if
	<-CRate 1 add ->CRate
	<-TimerRate SetTimer0
endif
#End DetermineCAmount Function

Contributed by albrittbrat

Emitter that spawns more emitters on death

This script makes a “hydra-like” or “splitting” enemy that gets worse the more you hurt it, at least for a little while. When it's not just been killed, it's simply an emitter, but in theory you could add stuff to the emitting part to make it a much nastier beast, or use other scripts alongside it. The other scripts or functions of the beast, if you wanted the “children” to also have them, would require modifying the inside of the while loop in the destroyed function to add in those scripts and any relevant variables as well.

# HydraEmitter.crpl
# A basic emitter at first.
# Creates an emitter which spawns new emitters in random locations within a defined range when it dies, which themselves also spawn new emitters. 
# Note that the decay rates are multiplied, so in theory you could make them bigger than 1 and have the rate/amount/range increase with each death rather than decrease.
# Note also, the spawn code checks to make sure it's not spawning on void. You can comment out that line if you want it to spawn in void, but be careful to not spawn outside of the map!
# ------------------------------------------
$rate:15
$amount:100
$rateDecay:1.0
$amountDecay:.5
$newHeads:3
$headLossPerDeath:1
$headRange:100
$headRangeDecay:.80

CurrentCoords <-amount AddCreeper
<-rate Delay

:destroyed
	0 ->count
	while <-count lt(<-newHeads) repeat
		CurrentCoords <-headRange RandCoordsInRange ->deathX ->deathY
		if(<-deathX <-deathY GetVoid not)
			"CRPLCORE" <-deathX <-deathY CreateUnit ->currUnit
			<-currUnit "main" "CustomEmitter" SetImage 
			<-currUnit "HydraEmitter.crpl" AddScriptToUnit
			<-currUnit "HydraEmitter.crpl" "rate" <-rate mul(<-rateDecay) SetScriptVar
			<-currUnit "HydraEmitter.crpl" "amount" <-amount mul(<-amountDecay) SetScriptVar
			<-currUnit "HydraEmitter.crpl" "rateDecay" <-rateDecay SetScriptVar
			<-currUnit "HydraEmitter.crpl" "amountDecay" <-amountDecay SetScriptVar
			<-currUnit "HydraEmitter.crpl" "newHeads" <-newHeads sub(<-headLossPerDeath) SetScriptVar
			<-currUnit "HydraEmitter.crpl" "headLossPerDeath" <-headLossPerDeath SetScriptVar
			<-currUnit "HydraEmitter.crpl" "headRange" <-headRange mul(<-headRangeDecay) SetScriptVar
			<-currUnit "HydraEmitter.crpl" "<-headRangeDecay" <-headRangeDecay SetScriptVar
			<-count add(1) ->count
		endif
	endwhile

Contributed by Xindaris

Make circular terrain

With this modified version of Mistet's script, you can create circular terrain. Choose the terrain level (or digitalis, or wall, or terrain override), choose the radius, and even choose an internal radius! This script is applied to a CRPLcore. The CRPLcore generates a circle of terrain around itself of the chosen type and size. The external radius is most important: this determines the size of the circle and is measured in cells on the map. Remember it is a radius, not a diameter. The terrain variable is also important. This determines the height of the terrain that it will change to. The internal radius variable allows you to create a smaller circle within the larger. This smaller circle will ignore terrain changes and is useful for creating rings. If this variable is larger than the external radius, the script will automatically swap the two so it works anyway.

# circular_terrain.crpl
# A modified version of MakeCircle.crpl from Mistet
# Made by VirgilW
# Modified by Clean0nion
# ------------------------------------------
#   HOW TO USE THIS SCRIPT
#   1. Create a square map with odd dimensions.
#      e.g. 255 x 255
#           51 x 51
#
#   2. Add this script to the map.
#      Go to Edit Map -> Units -> Scripts
#      Type "circular_terrain" into the bar.
#      Press Create.
#      Find it in the list and click Edit.
#      Paste in this code.
#
#   3. Place a CRPLcore anywhere in the map.
#      Edit Map -> Units -> CRPLcore
#      Then put your mouse anywhere on the map and press B.
#
#   4. Change the variables on the CRPLcore.
#      Double click the CRPLcore.
#      Open the "Attached Scripts" bar, find this code, and
#        click "Add".   
#      In the new list, double click "circular_terrain.crpl"
#      The variables will appear.
#
# "terrain" is the height of the terrain you want to create.
# "rad_external" is the external radius of the circle.
# "rad_internal" is the internal radius of the circle.
#
# For example, "terrain"=5; "rad_external"=20; "rad_internal"=0 will create a circle of land that is 40 cells across, and is oh terrain level 5. There will be no gap in the middle of the circle.
#
#
#
#   5. Once the variables have been set, save the map.
#
#   6. Finally, run the script.
#      Click the red X to leave the level editor and return 
#        to the game.
#      Unpause the game.
#      Wait until the circle has finished generating then 
#        pause again.
#      Your circle is done.
#
#   7. If you want to, run the script again with different 
#     variables.
#
# !!! If "terrain" is a value from 1 - 10, that level terrain will be placed.
# If "terrain" is 0 or below, void will be placed.
# If "terrain" is 11 or above, that level terrain override will be placed.
# If "terrain" is "0.1", digitalis will be placed.
# If "terrain" is "0.2", digitalis will be removed.
# If "terrain" is "0.3", wall will be placed.
# If "terrain" is "0.4", wall will be removed.
# If "terrain" is "0.5", terrain override will be removed.
# If "terrain" is "2.1", creeper will be added that is twice the terrain height.
# If "terrain" is anything else, either nothing will happen, or something entirely unpredictable will happen.



$terrain:0.2
$rad_external:70
$rad_internal:60

once
   PlaySound("Retro26")
   <-rad_external <-rad_internal lt if
      <-rad_external ->internal
      <-rad_internal ->external
   else
      <-rad_external ->external
      <-rad_internal ->internal
   endif
endonce


if (<-row lt (MapHeight))
   @DoRow
   <-row add(1) ->row
endif   


:DoRow
   do(MapWidth 0)
      Distance(CurrentCoords I <-row) ->distance
      if (<-distance gte(<-internal))
         if (<-distance lte(<-external))
            0.1 <-terrain eq if
               I <-row 2 SetDigitalisGrowth
            else
               0.2 <-terrain eq if
                  I <-row 0 SetDigitalisGrowth
               else
                  0.3 <-terrain eq if
                     I <-row 1 SetWall
                  else
                     0.4 <-terrain eq if
                        I <-row 0 SetWall
                     else
                        0.5 <-terrain eq if
                           I <-row GetTerrain SetTerrainOverride
                        else
                           <-terrain 11 gte if
                              I <-row <-terrain SetTerrainOverride
                           else
                              2.1 <-terrain eq if
                                 I <-row GetTerrain 2 mul SetCreeper
                              else
                                 I <-row <-terrain SetTerrain
                              endif
                           endif
                        endif
                     endif
                  endif
               endif
            endif
         endif
      endif
   loop

Made and submitted by Clean0nion

Flip-Emitters

Use suffitient quantities of AC to turn an emitter into an AC emitter.

# Converterv2.crpl
# Created on: 1/3/2014 1:53:35 PM
# ------------------------------------------
$amtCreeper:50
$amtAnti:-25
$interval:60
$startState:0
#Initializes state, thanks to Grayzzur for the idea.
Once
<-startState ->state
"
" ->lineBreak
endonce
#Checks if there is creeper, if there is, sets the converter to make creeper.
CurrentCoords GetCreeper 0 gt if
1 ->state
SetPopUpText("amt: " <-amtCreeper <-lineBreak "delay: " <-interval 30 div concat concat concat concat)
SetUnitAttribute(Self CONST_COUNTSFORVICTORY TRUE)
endif
#Checks if there is anticreeper, if there is, sets the converter to make AC
CurrentCoords GetCreeper 0 lt if
0 ->state
#the linebreak is on purpose, and concat because the amt isn't always the same.
SetPopUpText("amt: " <-amtAnti <-lineBreak "delay: " <-interval 30 div concat concat concat concat)
SetUnitAttribute(Self CONST_COUNTSFORVICTORY FALSE)
endif
#Checks the state, remember if there was nothing under it, it will use it's last state!
<-state if
CurrentCoords <-amtCreeper SetCreeper
else
CurrentCoords <-amtAnti SetCreeper
endif
<-interval Delay

Made and submitted by Flabort; named by VirgilW

Frames to minutes

Converts an amount of frames to minutes in M:SS format. Frames stored in variable “frames”; result placed at top of stack. This is best used with Timers as it doesn't work when “frames” is 0. As in, it reaches 0:00 then just disappears. 1800 displays 1:00; 60 displays 0:02; 2400 displays 1:20.

<-frames 1800 div ceil dup <-frames 30 div ceil swap 60 mul sub 60 mod ":" swap
dup 10 lt if
	"0" swap
endif
StackSize 1 do
	concat
loop

Written, coded, developed, procrastinated over, contributed, posted, wiki'd, wordified, done, made, finished and submitted by Clean0nion

Survival Pod

Attach to a core to create a survival pod. Survival pods must be rescued. If they are destroyed, the mission will fail. Makes use of the Message script found in the next entry below.

GetCreeper(CurrentCoords) ->creeper
if (not(<-ascending) and (<-creeper gt (0)))
	FailMission
	Destroy(Self 2)
endif
if ( not(<-ascending or (GetUnitAttribute(Self CONST_ISBUILDING))) )
	AscendToOrbit
	true ->ascending
	PlaySound("Misc17")
	SetPopupText("")
	ShowGameEventTag("GREEN" "INFO" "Survival Pod" "Rescued!" GetUnitAttribute(Self CONST_PIXELCOORDX) GetUnitAttribute(Self CONST_PIXELCOORDY))
endif

if (<-ascending)
	GetUnitTransformPosition ->z ->y ->x
	#CreateEffect(10 <-x <-y -1 2 2 0.04)
	CreateEffect(8 <-x <-y -1 2 2 0.04)
else
	SetPopupText(GetUnitAttribute(Self CONST_HEALTH) "/" concat "30" concat)
	SetPopupTextX(0)
endif

:Awake
if (GetUpdateCount eq (0))
	SetUnitAttribute(Self CONST_ISBUILDING TRUE)
	SetUnitAttribute(Self CONST_BUILDCOST 30)
	SetUnitAttribute(Self CONST_HEALTH 0)
	SetPopupTextAlwaysVisible(true)
	SetPopupTextY(-12)
endif

:Destroyed
	CreateUnit("CRPLCORE" 0 0) ->message
	AddScriptToUnit(<-message "PodMessage.crpl") 
	if (<-ascending)
		SetScriptVar(<-message "PodMessage.crpl" "message" "Pod Rescued")
	else
		SetScriptVar(<-message "PodMessage.crpl" "message" "Pod Destroyed!")
		SetScriptVar(<-message "PodMessage.crpl" "red" 255)
		SetScriptVar(<-message "PodMessage.crpl" "green" 0)
		SetScriptVar(<-message "PodMessage.crpl" "blue" 0)
		
		CreateUnit("CRPLCORE" CurrentCoords) ->tombstone
		AddScriptToUnit(<-tombstone "PodDestroyed.crpl") 

		ShowGameEventTag("RED" "INFO" "Survival Pod" "Destroyed" GetUnitAttribute(Self CONST_PIXELCOORDX) GetUnitAttribute(Self CONST_PIXELCOORDY))
		
	endif

Contributed by virgilw

PodMessage

Shows a message on the map that goes away. Used by the SurvivalPod script above.

$timeToLive:180
$solidTime:120
$message:"Pod Rescued"
$red:255
$green:255
$blue:255

once
	<-timeToLive sub(<-solidTime) ->fadeTime
	SetText(<-message)
	SetTextColor(<-red <-green <-blue 0)
endonce

if (GetUpdateCount gte(<-timeToLive))
	Destroy(Self 0)
endif

if (GetUpdateCount gt(1))
	if (GetUpdateCount gte(<-solidTime))
		<-timeToLive sub(GetUpdateCount) asfloat div(<-fadeTime) mul(255) ->alpha
	else
		255 ->alpha
	endif

	SetTextColor(<-red <-green <-blue <-alpha)
	SetImageColor(Self "Main" 32 32 32 <-alpha sub(60))
endif

:Awake
	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) 
	
	SetScreenMode(TRUE)
	SetTextY(-5)
	SetTextSize(2)
	SetScreenPixelCoordX(ScreenWidth div(2))
	SetScreenPixelCoordY(135)	
	
	SetImage(Self "Main" "Custom1")
	SetImageScaleX(Self "Main" 14)
	SetImageScaleY(Self "Main" 1.5)
	SetImageColor(Self "Main" 32 32 32 0)
	
	PlaySound("Retro9") 

Contributed by virgilw

GetClosestUnitToCoords

A customizable method to grab a nearest unit of any kind. Specify what types of units you want to grab, at what position, and with what radius. Strings are used for clarity to grab units that you need, you can delete or comment out units you wont be using once you copy the code. The code contains 3 methods that are commented for use on the battle-field. Contains two additional convenience methods.

#Function :GetClosestUnitToCoords
#Warning: use this convenience function sparingly, tens of CRPL Cores
#running this all at once every frame can slow the game down.

#Notation: x y f1 - i1
#eg. CurrentCoords 10 @GetClosestUnitToCoords ->unit
#If all units are outside of the maxDistance or none found returns integer value '-1'.
:GetClosestUnitToCoords
	asfloat ->gcu_mdist
	asfloat ->gcu_y
	asfloat ->gcu_x
	StackSize ->gcu_szmin

	# Reference: https://knucklecracker.com/wiki/doku.php?id=crpl:docs:getunittype
	# Place Unit Types that you /WANT/ to look for here.
	# Simply comment '#' out or remove any that you don't want. All this area does is push strings to the stack.
	"COMMANDNODE"
	"COLLECTOR" "RELAY" "REACTOR" "OREMINE" "SIPHON" "TERP" "GUPPY"
	"PULSECANNON" "MORTAR" "STRAFER" "BOMBER" "SPRAYER" "NULLIFIER" "BEAM" "SNIPER"
	"FORGE" "BERTHA" "THOR"
	"GUPPYAIR" "STRAFERAIR" "BOMBERAIR"
	"POWERZONE" "OREDEPOSIT" "RESOURCEPACK" "TOTEM"
	"SHIELDKEY" "TECHARTIFACT" "MESSAGEARTIFACT"
	#"CRPLCORE" #Not recommended as this will grab literally any CRPL Core.
	"EMITTER" "SPORETOWER" "RUNNERNEST" "AETOWER" "INHIBITOR"
	"RUNNER"
	# =====

	#Finding the boundary stack size (how many elements were added to stack)
	#and then forming a list from the units we want.
	StackSize ->gcu_szmax
	CreateList ->gcu_types
	<-gcu_szmax <-gcu_szmin do
		->gcu_t
		<-gcu_types <-gcu_t AppendToList
	loop

	#initialize unit
	-1 ->gcu_unit
	999999 ->gcu_unitd

	#retrieve /all/ nearby units
	
	# x y distance boolean(true-square, false-circle)
	# unit checks have been ordered in perceived processing complexity
	<-gcu_x <-gcu_y <-gcu_mdist false GetAllUnitsInRange ->gcu_count
	<-gcu_count neq0 if
		<-gcu_count 0 do
			->gcu_tempunit
			<-gcu_tempunit GetUnitType ->gcu_t
			#get the distance
			<-gcu_x <-gcu_y @UnitCoords(<-gcu_tempunit) Distance ->gcu_d
			#is that distance closer?
			<-gcu_d <-gcu_unitd lt if
				#do we care about this unit type?
				<-gcu_types <-gcu_t @DoesListContain if
					#set our new baseline distance and unit
					<-gcu_d ->gcu_unitd
					<-gcu_tempunit ->gcu_unit
				endif
			endif
		loop
	endif
	
	<-gcu_unit

#Function :UnitCoords
#Simple convenience method. Takes a unit and returns the coordinates.
#'CurrentCoords' and 'self @UnitCoords' are equivalent.
#Notation: n1 - x y
#eg. <-myUnitID @UnitCoords ->unitX ->unitY
:UnitCoords
	->u
	<-u CONST_COORDX GetUnitAttribute
	<-u CONST_COORDY GetUnitAttribute

#Function :DoesListContain
#This function an object, then a list and returns a boolean value.
#Notation: L1 n1 - b1
#eg. <-myList <-myValue @DoesListContain ->contains
:DoesListContain
	->dl_value
	->dl_list
	false ->dl_contained

	<-dl_list GetListCount 0 do
		<-dl_list I GetListElement eq(<-dl_value) if
			true ->dl_contained
			break
		endif
	loop

	<-dl_contained

Contributed by Telanir

CRPL generating CRPL

This CRPL will generate CRPL with custom program (if it is in the map scripts)

CreateUnit("CRPLCORE" CurrentX CurrentY) ->unit			
AddScriptToUnit(<-unit "[Programname].crpl")

Stolen from Teknotiss(who took it from virgil), where pyramids make golems. I simply changed golem to unit. Added by cpaca, known as Karma's coming on map search