Need help with RandInt Command

Started by Nicant, February 15, 2016, 06:54:10 PM

Previous topic - Next topic

Nicant

Does the RandInt Command only run once? I am using this command for the Creep Forge so it can randomly select an upgrade and when it has completed the upgrade it supposed to get another number via RandInt. But when it gets a number it just gets the same number i just got.
Below is the code...

:GetUpgradeNumber
0 ->UNumber
0 4 RandInt ->UNumber
:UpgradeRange

<-CreepRift 150 eq if
<-RangeCore 0 Destroy

<-UpgradedCReach 5 add ->UpgradedCReach
<-UpgradedMReach 5 add ->UpgradedMReach
<-UpgradedSReach 5 add ->UpgradedSReach
<-UpgradedBReach 5 add ->UpgradedBReach
<-UpgradedSpReach 5 add ->UpgradedSpReach

"IsCannon" "1" GetCoresWithVar @something ->Cannons #GameGibu suggests changing "ForgeX" to a separate var named something like "isTotemSiphon" (must be made to exist in CTotemSiphon.crpl) and is only 1 (meaning TRUE) when it is your special script...
<-Cannons GetListCount ->LIM1
0 ->ILOOP1
while <-ILOOP1 <-LIM1 lt repeat
SetScriptVar(GetListElement(<-Cannons <-ILOOP1) "CCannon.crpl" "reach" <-UpgradedCReach)
<-ILOOP1 add(1) ->ILOOP1
endwhile

"IsMortar" "1" GetCoresWithVar @something ->Mortars #GameGibu suggests changing "ForgeX" to a separate var named something like "isTotemSiphon" (must be made to exist in CTotemSiphon.crpl) and is only 1 (meaning TRUE) when it is your special script...
<-Mortars GetListCount ->LIM2
0 ->ILOOP2
while <-ILOOP2 <-LIM2 lt repeat
SetScriptVar(GetListElement(<-Mortars <-ILOOP2) "CMortar.crpl" "reach" <-UpgradedMReach)
<-ILOOP2 add(1) ->ILOOP2
endwhile

"IsSniper" "1" GetCoresWithVar @something ->Snipers #GameGibu suggests changing "ForgeX" to a separate var named something like "isTotemSiphon" (must be made to exist in CTotemSiphon.crpl) and is only 1 (meaning TRUE) when it is your special script...
<-Snipers GetListCount ->LIM3
0 ->ILOOP3
while <-ILOOP3 <-LIM3 lt repeat
SetScriptVar(GetListElement(<-Snipers <-ILOOP3) "CSniper.crpl" "reach" <-UpgradedSReach)
<-ILOOP3 add(1) ->ILOOP3
endwhile

"IsBeam" "1" GetCoresWithVar @something ->Beams #GameGibu suggests changing "ForgeX" to a separate var named something like "isTotemSiphon" (must be made to exist in CTotemSiphon.crpl) and is only 1 (meaning TRUE) when it is your special script...
<-Beams GetListCount ->LIM4
0 ->ILOOP4
while <-ILOOP4 <-LIM4 lt repeat
SetScriptVar(GetListElement(<-Beams <-ILOOP4) "CBeam.crpl" "reach" <-UpgradedBReach)
<-ILOOP4 add(1) ->ILOOP4
endwhile

"IsSprayer" "1" GetCoresWithVar @something ->Sprayers #GameGibu suggests changing "ForgeX" to a separate var named something like "isTotemSiphon" (must be made to exist in CTotemSiphon.crpl) and is only 1 (meaning TRUE) when it is your special script...
<-Sprayers GetListCount ->LIM5
0 ->ILOOP5
while <-ILOOP5 <-LIM5 lt repeat
SetScriptVar(GetListElement(<-Sprayers <-ILOOP5) "CSprayer.crpl" "reach" <-UpgradedSpReach)
<-ILOOP5 add(1) ->ILOOP5
endwhile
<-RangeCore 0 Destroy
<-CreepRift 150 sub ->CreepRift
"CRPLCore" CurrentCoords CreateUnit ->UpgradeCompleteRange
<-UpgradeCompleteRange "UpgradeComplete.crpl" AddScriptToUnit
1 ->OK2
0 ->OK3
@GetUpgradeNumber
endif


Any help will be greatly appreciated and if you want, be credited!  :)
CW4 hype!!

Grayzzur

How do you know it's only getting the same number? From the bit of a script you show here, you're not actually using the random result anywhere.

Have you tried using the trace commands to see what it's returning when you call it?
"Fate. It protects fools, little children, and ships named 'Enterprise.'" -William T. Riker

GoodMorning

Agreed. The value UNumber is not used in the block you showed.

Also, this seems to apply upgrades to everything, every time.

If I assume that you want to upgrade only one unit type...
What might work better would be a function to call as @ApplyUpgrade. Such as:


CreateList ->MYCONST_UNAMES
<-MYCONST_UNAMES "Cannon" AppendToList
<-MYCONST_UNAMES "Mortar" AppendToList
<-MYCONST_UNAMES "Sniper" AppendToList
<-MYCONST_UNAMES "Beam" AppendToList
<-MYCONST_UNAMES "Sprayer" AppendToList

CreateList ->MYCONST_UABBREV
<-MYCONST_UABBREV "C" AppendToList
<-MYCONST_UABBREV "M" AppendToList
<-MYCONST_UABBREV "S" AppendToList
<-MYCONST_UABBREV "B" AppendToList
<-MYCONST_UABBREV "Sp" AppendToList

:ApplyUpgrade # [UpgradeID - ] The ID is 0 to 4...
   ->UpgradeID
     "Upgraded" <-MYCONST_UABBREV <-UpgradeID GetListElement concat "Reach" concat ->UpgradeVarName
<-UpgradeVarName <-! 5 add <-UpgradeVarName->!
   
<-MYCONST_UNAMES <-UpgradeID GetListElement ->NameStr
"Is" <-NameStr concat "1" GetCoresWithVar @something ->ApplyUnits #GameGibu suggests changing "ForgeX" to a separate var named something like "isTotemSiphon" (must be made to exist in CTotemSiphon.crpl) and is only 1 (meaning TRUE) when it is your special script...

<-ApplyUnits GetListCount ->UPGLIM

0 ->ILOOP5
while <-ILOOP <-UPGLIM lt repeat
SetScriptVar(GetListElement(<-ApplyUnits <-ILOOP) "C" <-NameStr concat ".crpl" concat "reach" <-UpgradeVarName <-!)
<-ILOOP add(1) ->ILOOP
endwhile


This should do the bit between <-RangeCore 0 Destroy and <-RangeCore 0 Destroy (At the top of the "if", and the last "endwhile").

If it is called with the upgrade number, it should do only one upgrade, as indicated by the number.

The constant lists should be placed in a once block nearer the head of the code.
A narrative is a lightly-marked path to another reality.

Nicant

Quote from: GoodMorning on February 15, 2016, 08:54:55 PM
Agreed. The value UNumber is not used in the block you showed.

Also, this seems to apply upgrades to everything, every time.

If I assume that you want to upgrade only one unit type...
What might work better would be a function to call as @ApplyUpgrade. Such as:


CreateList ->MYCONST_UNAMES
<-MYCONST_UNAMES "Cannon" AppendToList
<-MYCONST_UNAMES "Mortar" AppendToList
<-MYCONST_UNAMES "Sniper" AppendToList
<-MYCONST_UNAMES "Beam" AppendToList
<-MYCONST_UNAMES "Sprayer" AppendToList

CreateList ->MYCONST_UABBREV
<-MYCONST_UABBREV "C" AppendToList
<-MYCONST_UABBREV "M" AppendToList
<-MYCONST_UABBREV "S" AppendToList
<-MYCONST_UABBREV "B" AppendToList
<-MYCONST_UABBREV "Sp" AppendToList

:ApplyUpgrade # [UpgradeID - ] The ID is 0 to 4...
   ->UpgradeID
     "Upgraded" <-MYCONST_UABBREV <-UpgradeID GetListElement concat "Reach" concat ->UpgradeVarName
<-UpgradeVarName <-! 5 add <-UpgradeVarName->!
   
<-MYCONST_UNAMES <-UpgradeID GetListElement ->NameStr
"Is" <-NameStr concat "1" GetCoresWithVar @something ->ApplyUnits #GameGibu suggests changing "ForgeX" to a separate var named something like "isTotemSiphon" (must be made to exist in CTotemSiphon.crpl) and is only 1 (meaning TRUE) when it is your special script...

<-ApplyUnits GetListCount ->UPGLIM

0 ->ILOOP5
while <-ILOOP <-UPGLIM lt repeat
SetScriptVar(GetListElement(<-ApplyUnits <-ILOOP) "C" <-NameStr concat ".crpl" concat "reach" <-UpgradeVarName <-!)
<-ILOOP add(1) ->ILOOP
endwhile


This should do the bit between <-RangeCore 0 Destroy and <-RangeCore 0 Destroy (At the top of the "if", and the last "endwhile").

If it is called with the upgrade number, it should do only one upgrade, as indicated by the number.

The constant lists should be placed in a once block nearer the head of the code.
The UNumber is to determine what upgrade it will get.

Here is the full code if you need it...
# CForgeNew.crpl
# Created on: 1/27/2016 5:04:28 PM
# ------------------------------------------

# THIS IS THE DEFAULT CREEP DOCUMENT, COPY AND PASTE TO A FRESH .crpl
# VERSION 1.1

# == CUSTOM VARS ==
#This is the amount of CreepRift/Aether the forge contains. Do Not change number if you don't want the forge to buy any upgrades instantly!
$CreepRift:0

# == DEFAULT VARS ==
# Health is simulated differently because there is no direct
# way to know cannon damage and Digitalis is ONLY damaged by
# player actions.
# A side effect is that every unit will have to support Digitalis.

# Health reduces sharply when unit digitalis is damaged.
$health:1.0
# If digitalis under unit is less than min, damage health.
$minDigitalis:1.0
# Digitalis will restore to this value.
$maxDigitalis:1.2

# CONSTANTS (only modify here, or during initialization)
$DEFAULT_IMAGE:"Custom6_128"
$BUILD_SOUND:"Misc7"
$CREEPER_FOR_BUILD:20.0
$CREEP_TYPE:"FORGE"
# Every unit has a forcefield unless range is 0 or below.
# Negative PUSH values will induce a PULL on creeper to "suck it in".
$CREEP_FORCEFIELD_CPUSH:10000
$CREEP_FORCEFIELD_ACPUSH:1000
$CREEP_FORCEFIELD_RANGE:8

# Creep will activate sleep mode
$SLEEP_DISTANCE:50
$SLEEP_TIME:150
# Enabling hard sleep will allow the AI to activate
# SleepAI when the unit is far away from the action
# or can't do anything for a bit. Otherwise, it is up
# to you to make the unit optimized with @IsSleeping
$SUPPORTS_HARDSLEEP:0
# When a unit is in travel mode it will run an alternate
# AI that is called TravelAI where you can perform tasks
# specific to flying mode. As soon as a unit lands on their
# target position they resume standard AI. If ignoring flight
# is enabled, normal AI will continue to run even during flight.
$IGNORES_FLIGHT:0
$FLIGHT_SPEED:1.0
# Beams deal a lot less damage so having a health modifier allows
# player beams to deal a fairer amount of damage. Natural maximum
# health is restored after landing.
$FLIGHT_HEALTH_MODIFIER:0.25

# RUNTIME (do not modify)
$BUILT_ON_SPAWN:1
$IS_BUILT:0
$S_BASE:-1

# THIS SCRIPT DOES NOT SUPPORT RUNNING WHILE PAUSED.
# However, due to internal bugs occasionally CW3 will still give them frame time
# even though nowhere is it explicitly stated they are allowed to run while paused.
IsPaused if
1 SuspendMove
return
endif
# == END DEFAULT ==

once

CurrentX ->CurrentX
CurrentY ->CurrentY
0 ->UNumber
1 ->OK1
1 ->OK2
0 ->OK3
15 ->UpgradedCReach
16 ->UpgradedMReach
25 ->UpgradedSReach
20 ->UpgradedBReach
20 ->UpgradedSpReach
25 ->UpgradedCFireRate
120 ->UpgradedMFireRate
50 ->UpgradedSFireRate
15 ->UpgradedSpFireRate
@GetUpgradeNumber

self "main" <-DEFAULT_IMAGE SetImage
@RegisterImage("main")
Self "main" 1.75 1.75 SetImageScale

# CREATE ABOVE THEN REGISTER CUSTOM (not "main") IMAGES HERE
# @RegisterImage("barrel")

# Flash without sound
self CONST_DESTROYMODE 3 SetUnitAttribute

# Set size here
self CONST_CELLHEIGHT 2 SetUnitAttribute
self CONST_CELLWIDTH 2 SetUnitAttribute

#SetPopupText("This is a sample template!
#Feel free to experiment and create something great.")
#SetPopupTextY(20)

# Set who can target this unit
self CONST_NULLIFIERDAMAGES true SetUnitAttribute
self CONST_BEAMTARGET false SetUnitAttribute
self CONST_SNIPERTARGET false SetUnitAttribute
self CONST_SNIPERIGNORELOS false SetUnitAttribute

self CONST_CREATEPZ false SetUnitAttribute

# REQUIRED TO FUNCTION, DO NOT TOUCH
self CONST_SUPPORTSDIGITALIS true SetUnitAttribute
self CONST_COUNTSFORVICTORY false SetUnitAttribute
self CONST_MAXHEALTH <-health SetUnitAttribute
self CONST_HEALTH <-health SetUnitAttribute
self CONST_HEALRATE 0.001 SetUnitAttribute
@CreeperInitialize
# ==================================
endonce

@StandardCreep

@IsBuilt if
@ConsistentAI
if(or(not(@IsFlying) <-IGNORES_FLIGHT))
if (<-SUPPORTS_HARDSLEEP)
if(@IsSleeping)
@SleepAI
else
@AI
endif
else
@AI
endif
else
@FlightAI
endif
else
@Build
endif

:GetUpgradeNumber
0 ->UNumber
0 4 RandInt ->UNumber
:UpgradeRange

<-CreepRift 150 eq if
<-RangeCore 0 Destroy

<-UpgradedCReach 5 add ->UpgradedCReach
<-UpgradedMReach 5 add ->UpgradedMReach
<-UpgradedSReach 5 add ->UpgradedSReach
<-UpgradedBReach 5 add ->UpgradedBReach
<-UpgradedSpReach 5 add ->UpgradedSpReach

"IsCannon" "1" GetCoresWithVar @something ->Cannons #GameGibu suggests changing "ForgeX" to a separate var named something like "isTotemSiphon" (must be made to exist in CTotemSiphon.crpl) and is only 1 (meaning TRUE) when it is your special script...
<-Cannons GetListCount ->LIM1
0 ->ILOOP1
while <-ILOOP1 <-LIM1 lt repeat
SetScriptVar(GetListElement(<-Cannons <-ILOOP1) "CCannon.crpl" "reach" <-UpgradedCReach)
<-ILOOP1 add(1) ->ILOOP1
endwhile

"IsMortar" "1" GetCoresWithVar @something ->Mortars #GameGibu suggests changing "ForgeX" to a separate var named something like "isTotemSiphon" (must be made to exist in CTotemSiphon.crpl) and is only 1 (meaning TRUE) when it is your special script...
<-Mortars GetListCount ->LIM2
0 ->ILOOP2
while <-ILOOP2 <-LIM2 lt repeat
SetScriptVar(GetListElement(<-Mortars <-ILOOP2) "CMortar.crpl" "reach" <-UpgradedMReach)
<-ILOOP2 add(1) ->ILOOP2
endwhile

"IsSniper" "1" GetCoresWithVar @something ->Snipers #GameGibu suggests changing "ForgeX" to a separate var named something like "isTotemSiphon" (must be made to exist in CTotemSiphon.crpl) and is only 1 (meaning TRUE) when it is your special script...
<-Snipers GetListCount ->LIM3
0 ->ILOOP3
while <-ILOOP3 <-LIM3 lt repeat
SetScriptVar(GetListElement(<-Snipers <-ILOOP3) "CSniper.crpl" "reach" <-UpgradedSReach)
<-ILOOP3 add(1) ->ILOOP3
endwhile

"IsBeam" "1" GetCoresWithVar @something ->Beams #GameGibu suggests changing "ForgeX" to a separate var named something like "isTotemSiphon" (must be made to exist in CTotemSiphon.crpl) and is only 1 (meaning TRUE) when it is your special script...
<-Beams GetListCount ->LIM4
0 ->ILOOP4
while <-ILOOP4 <-LIM4 lt repeat
SetScriptVar(GetListElement(<-Beams <-ILOOP4) "CBeam.crpl" "reach" <-UpgradedBReach)
<-ILOOP4 add(1) ->ILOOP4
endwhile

"IsSprayer" "1" GetCoresWithVar @something ->Sprayers #GameGibu suggests changing "ForgeX" to a separate var named something like "isTotemSiphon" (must be made to exist in CTotemSiphon.crpl) and is only 1 (meaning TRUE) when it is your special script...
<-Sprayers GetListCount ->LIM5
0 ->ILOOP5
while <-ILOOP5 <-LIM5 lt repeat
SetScriptVar(GetListElement(<-Sprayers <-ILOOP5) "CSprayer.crpl" "reach" <-UpgradedSpReach)
<-ILOOP5 add(1) ->ILOOP5
endwhile
<-RangeCore 0 Destroy
<-CreepRift 150 sub ->CreepRift
"CRPLCore" CurrentCoords CreateUnit ->UpgradeCompleteRange
<-UpgradeCompleteRange "UpgradeComplete.crpl" AddScriptToUnit
1 ->OK2
0 ->OK3
@GetUpgradeNumber

endif
:UpgradeFireRate

<-CreepRift 250 eq if
<-FireRateCore 0 Destroy

<-UpgradedCFireRate 5 sub ->UpgradedCFireRate
<-UpgradedMFireRate 5 sub ->UpgradedMFireRate
<-UpgradedSFireRate 5 sub ->UpgradedSFireRate
<-UpgradedSpFireRate 5 sub ->UpgradedSpFireRate

"IsCannon" "1" GetCoresWithVar @something ->Cannons #GameGibu suggests changing "ForgeX" to a separate var named something like "isTotemSiphon" (must be made to exist in CTotemSiphon.crpl) and is only 1 (meaning TRUE) when it is your special script...
<-Cannons GetListCount ->LIM1
0 ->ILOOP1
while <-ILOOP1 <-LIM1 lt repeat
SetScriptVar(GetListElement(<-Cannons <-ILOOP1) "CCannon.crpl" "cooldown" <-UpgradedCFireRate)
<-ILOOP1 add(1) ->ILOOP1
endwhile

"IsMortar" "1" GetCoresWithVar @something ->Mortars #GameGibu suggests changing "ForgeX" to a separate var named something like "isTotemSiphon" (must be made to exist in CTotemSiphon.crpl) and is only 1 (meaning TRUE) when it is your special script...
<-Mortars GetListCount ->LIM2
0 ->ILOOP2
while <-ILOOP2 <-LIM2 lt repeat
SetScriptVar(GetListElement(<-Mortars <-ILOOP2) "CMortar.crpl" "cooldown" <-UpgradedMFireRate)
<-ILOOP2 add(1) ->ILOOP2
endwhile

"IsSniper" "1" GetCoresWithVar @something ->Snipers #GameGibu suggests changing "ForgeX" to a separate var named something like "isTotemSiphon" (must be made to exist in CTotemSiphon.crpl) and is only 1 (meaning TRUE) when it is your special script...
<-Snipers GetListCount ->LIM3
0 ->ILOOP3
while <-ILOOP3 <-LIM3 lt repeat
SetScriptVar(GetListElement(<-Snipers <-ILOOP3) "CSniper.crpl" "cooldown" <-UpgradedSFireRate)
<-ILOOP3 add(1) ->ILOOP3
endwhile

"IsSprayer" "1" GetCoresWithVar @something ->Sprayers #GameGibu suggests changing "ForgeX" to a separate var named something like "isTotemSiphon" (must be made to exist in CTotemSiphon.crpl) and is only 1 (meaning TRUE) when it is your special script...
<-Sprayers GetListCount ->LIM5
0 ->ILOOP5
while <-ILOOP5 <-LIM5 lt repeat
SetScriptVar(GetListElement(<-Sprayers <-ILOOP5) "CSprayer.crpl" "cooldown" <-UpgradeSpFireRate)
<-ILOOP5 add(1) ->ILOOP5
endwhile
<-FireRateCore 0 Destroy
<-CreepRift 250 sub ->CreepRift
"CRPLCore" CurrentCoords CreateUnit ->UpgradeCompleteRange
<-UpgradeCompleteRange "UpgradeComplete.crpl" AddScriptToUnit
1 ->OK2
0 ->OK3
@GetUpgradeNumber

endif
:LaunchCreepRiftTorpedo

<-CreepRift 500 eq if
<-CTorpedo 0 Destroy
"CRPLCore" CurrentCoords CreateUnit ->TorpedoC
<-TorpedoC "CreepTorpedo.crpl" AddScriptToUnit
<-CTorpedo 0 Destroy
<-CreepRift 500 sub ->CreepRift
1 ->OK2
0 ->OK3
@GetUpgradeNumber

endif
:AI
#custom code here
#Upgrade Number 1 is RANGE So when the UNumber is 1, the forge will work on upgrading CreepRange!
#Upgrade Number 2 is Fire Rate So when the UNumber is 2, the forge will work on upgrading Creep Fire Rate!
#Upgrade Number 3 is Fire Creep Rift Torpedo So when the UNumber is 3, the forge will launch a Creep Torpedo!
#OK1 will make sure that the core only Get a UNumber once. NO LONGER NEEDED!
#OK2 will make sure that the core will only use an upgrade once. The Reason is if there is no OK2 and every time the core goes through the Ai function the core will keep going through the Upgrade Function.
#OK3 will tell the core that it has already went through an upgrade function. Now it needs to keep on repeating the upgrade function so it can keep an eye on the CreepRift Number.

<-UNumber 0 eq if
@GetUpgradeNumber
endif

<-UNumber 4 eq if
@GetUpgradeNumber
endif
# -----------------------------------------------------------------
<-UNumber 1 eq if
<-OK3 1 eq if
@UpgradeRange
endif
endif

<-UNumber 2 eq if
<-OK3 1 eq if
@UpgradeFireRate
endif
endif

<-UNumber 3 eq if
<-OK3 1 eq if
@LaunchCreepRiftTorpedo
endif
endif

# ------------------------------------------------------------------

<-UNumber 1 eq if
<-OK2 1 eq if
"CRPLCore" CurrentCoords CreateUnit ->RangeCore
<-RangeCore "UpgradeCore1.crpl" AddScriptToUnit
@UpgradeRange
0 ->OK2
1 ->OK3
endif
endif

<-UNumber 2 eq if
<-OK2 1 eq if
"CRPLCore" CurrentCoords CreateUnit ->FireRateCore
<-FireRateCore "UpgradeCore2.crpl" AddScriptToUnit
@UpgradeFireRate
0 ->OK2
1 ->OK3
endif
endif

<-UNumber 3 eq if
<-OK2 1 eq if
"CRPLCore" CurrentCoords CreateUnit ->CTorpedo
<-CTorpedo "TorpedoConstructCore.crpl" AddScriptToUnit
@LaunchCreepRiftTorpedo
0 ->OK2
1 ->OK3
endif
endif

:ConsistentAI
#custom code here, runs every tick regardless of circumstance

"IsTotemSiphon" "1" GetCoresWithVar @something ->TotemSiphons #GameGibu suggests changing "ForgeX" to a separate var named something like "isTotemSiphon" (must be made to exist in CTotemSiphon.crpl) and is only 1 (meaning TRUE) when it is your special script...
<-TotemSiphons GetListCount ->LIM
0 ->ILOOP
while <-ILOOP <-LIM lt repeat
SetScriptVar(GetListElement(<-TotemSiphons <-ILOOP) "CTotemSiphon.crpl" "ForgeX" <-CurrentX)
SetScriptVar(GetListElement(<-TotemSiphons <-ILOOP) "CTotemSiphon.crpl" "ForgeY" <-CurrentY)
<-ILOOP add(1) ->ILOOP
endwhile

<-CreepRift SetText
0.5 SetTextSize

:SleepAI

#custom code here

:FlightAI
#custom code here

:built
once
"Misc29" PlaySound
ClearConversation
1 "[WARNING!!!] A Creep Forge has been built!" AddConversationMessage
ShowConversation
endonce

:death
#custom code here
"Explosion0" PlaySound

:something
   #Trace("@buildList, Args:") TraceStack
   ->bui_LIM
   if(<-bui_LIM 1 lt)
      CreateList
   else
      0 ->bui_ILOOP
      CreateList ->bui_LIST
      while <-bui_ILOOP <-bui_LIM lt repeat
         ->unit
         AppendToList(<-bui_LIST <-unit)
         <-bui_ILOOP add(1) ->bui_ILOOP
      endwhile
      #Trace("bui_LIST: " concat(<-bui_LIST))
      CopyList(<-bui_LIST)
endif

# ===============================
# ===== STANDARD CREEP CODE =====
# ===============================

# Bare minimum required code to run each tick.
# Ensures that player can damage sleeping Creeps.
:StandardCreep
if(not(@IsFlying))
@CreepSleep
CurrentCoords GetCreeper 0 lt if
self 0.05 Damage
endif
CurrentCoords GetDigitalis <-minDigitalis lt if
self 0.30 Damage
endif
@IsBuilt if
@Repair
endif
endif
@AnimateFlight


:RandomFixCoord
while not(@IsPointOnMap(<-RF_X <-RF_Y)) repeat
CurrentCoords 10 RandCoordsInRange ->RF_Y ->RF_X
endwhile
<-RF_Y
<-RF_X

# Function :IsPointOnMap
# Takes a set of cell-coordinates and returns true
# if the coordinates are on the map.
# Notation: x y - b1
# eg. -1 -1 @IsPointOnMap ->onMap #(will return false)
:IsPointOnMap
->pom_pointY
->pom_pointX
1 ->pom_onMap
<-pom_pointY MapHeight gt if
0 ->pom_onMap
endif
<-pom_pointY 0 lt if
0 ->pom_onMap
endif
<-pom_pointX MapWidth gt if
0 ->pom_onMap
endif
<-pom_pointX 0 lt if
0 ->pom_onMap
endif
<-pom_onMap

:AnimateFlight
-?C_FLIGHT if
self "main" 1 GetImageScaleX ->C_FX
<-C_FLIGHT if
# Liftoff
<-C_FX 1.3 lt if
<-C_FX 0.02 add ->C_FSN
GetListCount(<-C_IMAGES) 0 do
self GetListElement(<-C_IMAGES I) <-C_FSN <-C_FSN SetImageScale
loop
else
GetQueuedMoveCount eq0 if
<-C_FLIGHT_MOVE if
false ->C_FLIGHT_MOVE
@ExecuteLanding
else
self CONST_BEAMTARGET true SetUnitAttribute
true ->C_FLIGHT_MOVE
if(not(@IsPointOnMap(<-C_FLIGHT_X <-C_FLIGHT_Y)))
@RandomFixCoord ->C_FLIGHT_X ->C_FLIGHT_Y
else
<-C_FLIGHT_X <-C_FLIGHT_Y <-FLIGHT_SPEED QueueMove
endif
true ->C_FLYING
endif
endif
endif
else
# Landing
<-C_FX 1 gt if
<-C_FX 0.02 sub ->C_FSN
GetListCount(<-C_IMAGES) 0 do
self GetListElement(<-C_IMAGES I) <-C_FSN <-C_FSN SetImageScale
loop
else
11 CurrentPixelCoords 0.01 1 1 0.03 CreateEffect
"UnitLand" PlaySound
--C_FLIGHT
self CONST_BEAMTARGET false SetUnitAttribute
CurrentCoords @SetForcefieldCoords
@CreateForcefield
#<-CREEP_FORCEFIELD_RANGE <-CREEP_FORCEFIELD_CPUSH <-CREEP_FORCEFIELD_ACPUSH 0 true EnableTowerField
CurrentCoords GetDigitalisGrowth neq0 ->C_DIGITALIS_PRESENT
CurrentCoords true SetDigitalisGrowth
CurrentCoords 1.0 SetDigitalis
endif
endif
endif

:SetFlightLandingTarget
->C_FLIGHT_Y
->C_FLIGHT_X
<-C_FLIGHT_X <-C_FLIGHT_Y GetUnitAttribute(self CONST_CELLWIDTH) sub(1) div(2) @OccupyArea
-?C_FLIGHT and(<-C_FLYING) if
AbortMove
<-C_FLIGHT_X <-C_FLIGHT_Y <-FLIGHT_SPEED QueueMove
endif

# Function :OccupyArea
# Safety net for @AddOccupy to prevent bad areas.
# Notation: x y f1 -
# eg. <-targetX <-targetY 1 @OccupyArea # this would occupy an area of land
# #in a 3x3 grid around the central point, useful for flying units looking to land
:OccupyArea
-?OA_OCCUPIED not if
# First occupation is legal.
->OA_RAD
->OA_Y
->OA_X

<-OA_X <-OA_Y <-OA_RAD true @AddOccupy
# Does occupy, is initialized.
true ->OA_OCCUPIED
else
<-OA_OCCUPIED if
# If occupying land already, disable occupation for re-assigning.
<-OA_X <-OA_Y <-OA_RAD false @AddOccupy
endif
->OA_RAD
->OA_Y
->OA_X
<-OA_OCCUPY if
<-OA_X <-OA_Y <-OA_RAD true @AddOccupy
endif
<-OA_OCCUPY ->OA_OCCUPIED
endif

:ReleaseOccupiedArea
<-OA_OCCUPIED if
# If occupying land already, disable occupation.
<-OA_X <-OA_Y <-OA_RAD false @AddOccupy
false ->OA_OCCUPIED
endif

# Function :AddOccupy
# Returns whether or not a certain area is occupied by one or
# more other units. Radius is measured in cells.
# Notation: x y f1 b1 -
# eg. CurrentCoords 3 false @AddOccupy #this would allow another unit to land
:AddOccupy
->OC_ADD
->OC_RAD
->OC_Y
->OC_X

<-OC_RAD mul(2) add(1) ->OC_LENGTH
<-OC_RAD ->OC_MID

<-OC_LENGTH 0 do
<-OC_LENGTH 0 do
<-OC_Y I add <-OC_MID sub ->OC_AOY
<-OC_X J add <-OC_MID sub ->OC_AOX
<-OC_AOX <-OC_AOY GetCellOccupiedCount ->OC_COUNT
<-OC_ADD if
<-OC_AOX <-OC_AOY <-OC_COUNT add(1) SetCellOccupiedCount
else
<-OC_AOX <-OC_AOY <-OC_COUNT sub(1) SetCellOccupiedCount
endif
loop
loop

:ExecuteLiftoff
<-C_DIGITALIS_PRESENT not if
CurrentCoords 0 SetDigitalis
CurrentCoords false SetDigitalisGrowth
true ->C_DIGITALIS_PRESENT
endif
self CONST_TAKEMAPSPACE false SetUnitAttribute
"UnitTakeOff" PlaySound
true ->C_FLIGHT
false ->C_FLYING
@WipeForcefield

# Beams deal significantly less damage, therefore, lower health to
# within acceptable parameters.
self CONST_HEALTH dup2 GetUnitAttribute mul(<-FLIGHT_HEALTH_MODIFIER) SetUnitAttribute
self CONST_MAXHEALTH dup2 GetUnitAttribute mul(<-FLIGHT_HEALTH_MODIFIER) SetUnitAttribute

GetListCount(<-C_IMAGES) 0 do
GetListElement(<-C_IMAGES I) ->EX_IM
self <-EX_IM GetImagePositionZ ->EX_ZPOS
self <-EX_IM <-EX_ZPOS sub(0.1) SetImagePositionZ
loop

:ExecuteLanding
self CONST_TAKEMAPSPACE true SetUnitAttribute
false ->IS_SLEEPING
false ->C_FLIGHT
false ->C_FLYING

# Restore health back to normal values.
self CONST_MAXHEALTH dup2 GetUnitAttribute div(<-FLIGHT_HEALTH_MODIFIER) SetUnitAttribute
self CONST_HEALTH dup2 GetUnitAttribute div(<-FLIGHT_HEALTH_MODIFIER) SetUnitAttribute

GetListCount(<-C_IMAGES) 0 do
GetListElement(<-C_IMAGES I) ->EX_IM
self <-EX_IM GetImagePositionZ ->EX_ZPOS
self <-EX_IM <-EX_ZPOS add(0.1) SetImagePositionZ
loop

:IsFlying
-?C_FLIGHT

:Build
CurrentCoords GetCreeper ->C_CRP
<-CREEPER_FOR_BUILD 0 lte if
@FinishBuild
else
<-C_CRP 0 gt if
self CONST_MAXAMMOAC GetUnitAttribute self CONST_AMMOAC GetUnitAttribute sub ->C_CRPN
<-C_CRP <-C_CRPN gt if
<-C_CRP <-C_CRPN sub ->C_LEFT
CurrentCoords <-C_LEFT SetCreeper
@FinishBuild
else
self CONST_AMMOAC dup2 GetUnitAttribute <-C_CRP add SetUnitAttribute
CurrentCoords 0 SetCreeper
endif
endif
endif

:FinishBuild
GetListCount(<-C_IMAGES) 0 do
GetListElement(<-C_IMAGES I) 255 @SetImageAlpha
loop

self CONST_AMMO 0 SetUnitAttribute
self CONST_MAXAMMOAC 0 SetUnitAttribute
self CONST_SHOWAMMOACBAR false SetUnitAttribute
true ->IS_BUILT

@OverrideWipeForcefieldProperties
@SetForcefieldProperties(<-CREEP_FORCEFIELD_RANGE <-CREEP_FORCEFIELD_CPUSH <-CREEP_FORCEFIELD_ACPUSH)
CurrentCoords @SetForcefieldCoords
@CreateForcefield

#<-CREEP_FORCEFIELD_RANGE <-CREEP_FORCEFIELD_CPUSH <-CREEP_FORCEFIELD_ACPUSH 0 true EnableTowerField
<-BUILD_SOUND PlaySound
@built

:CreepSleep
@IsBuilt if
<-C_SLEEP 0 lte if
false ->IS_SLEEPING
CurrentCoords <-SLEEP_DISTANCE <-PLAYER_UNITS @GetClosestUnit ->C_UNIT
<-C_UNIT eq(-1) if
<-SLEEP_TIME @Sleep
endif
endif
<-C_SLEEP 1 sub ->C_SLEEP
endif

:Repair
CurrentCoords GetDigitalis <-minDigitalis lt if
CurrentCoords CurrentCoords GetDigitalis 0.16 add SetDigitalis
else
CurrentCoords GetDigitalis <-maxDigitalis lt if
CurrentCoords CurrentCoords GetDigitalis 0.0006 add SetDigitalis
endif
endif

:Sleep
->C_SLEEP
true ->IS_SLEEPING

:IsSleeping
<-IS_SLEEPING

:IsBuilt
<-IS_BUILT

:destroyed
-?C_FLIGHT_X and(-?C_FLIGHT_Y) if
<-C_FLIGHT_X <-C_FLIGHT_Y GetUnitAttribute(self CONST_CELLWIDTH) sub(1) div(2) @ReleaseOccupiedArea
endif
<-C_DIGITALIS_PRESENT not if
CurrentCoords 0 SetDigitalis
CurrentCoords false SetDigitalisGrowth
endif
@WipeForcefield
@death

:CreeperInitialize
<-BUILT_ON_SPAWN not if
GetListCount(<-C_IMAGES) 0 do
GetListElement(<-C_IMAGES I) 125 @SetImageAlpha
loop

self CONST_MAXAMMOAC <-CREEPER_FOR_BUILD SetUnitAttribute
self CONST_AMMOAC 0 SetUnitAttribute
self CONST_SHOWAMMOACBAR true SetUnitAttribute

0.2 <-CREEPER_FOR_BUILD mul sqrt ->C_RANGE
<-C_RANGE 5 lt if
5 ->C_RANGE
endif
8000 <-C_RANGE mul neg ->C_PULL

<-C_RANGE <-C_PULL 0 @SetForcefieldProperties
@CreateForcefield
else
0 ->CREEPER_FOR_BUILD
endif

@BeginList
"ALL:BUILT,LANDED"
"COMMANDNODE"
"COLLECTOR" "RELAY" "REACTOR:rank=2" "OREMINE:rank=1.5" "SIPHON:rank=1.5" "TERP" "GUPPY"
"PULSECANNON" "MORTAR" "STRAFER" "BOMBER" "SPRAYER" "NULLIFIER:rank=5" "BEAM" "SNIPER:rank=3"
"SHIELD"
"FORGE"
"BERTHA" "THOR"
@BuildList ->PLAYER_UNITS

false ->IS_SLEEPING
0 ->C_SLEEP
300 ->C_SLEEPCHECK

CurrentCoords GetDigitalisGrowth neq0 ->C_DIGITALIS_PRESENT
CurrentCoords true SetDigitalisGrowth
CurrentCoords 1.0 SetDigitalis

:RegisterImage
->ri_name
if(not(-?C_IMAGES))
CreateList ->C_IMAGES
endif
if(not(<-C_IMAGES <-ri_name @DoesListContain))
<-C_IMAGES <-ri_name AppendToList
endif

:SetImageAlpha
->si_alpha_new
->si_image
self <-si_image GetImageColor ->si_alpha ->si_blue ->si_green ->si_red
self <-si_image <-si_red <-si_green <-si_blue <-si_alpha_new SetImageColor

:BeginList
StackSize ->BL_I

:BuildList
StackSize ->BL_M
CreateList ->BL_L
<-BL_M <-BL_I do
->BL_O
<-BL_L <-BL_O PrependToList
loop
<-BL_L

#======================================
#======== FORCEFIELD MANAGER ==========
#======================================

# Sets the Forcefield properties.
# Order goes: RANGE CPUSH ACPUSH
# The higher the PUSH values the more the
# forcefield repels from the epicenter.
# Values are in millionths per unit of creeper moved.
# Notation: f1 i1 i2 -
# 12.5 100000 100000 @SetForcefieldProperties
:SetForcefieldProperties
-?FF_INITIALIZED not if
->FF_ACPUSH
->FF_CPUSH
->FF_RANGE
true ->FF_INITIALIZED
-?FF_X or(-?FF_Y) not if
CurrentCoords ->FF_Y ->FF_X
endif
endif

# Function :SetForcefieldCoords
# Sets the coordinates of future forcefields.
# If a previous forcefield was present it removes
# the old one and creates a new one.
# Notation: x y -
# e.g. CurrentCoords @SetForcefieldCoords
:SetForcefieldCoords
-?FORCEFIELD_AVAILABLE if
@WipeForcefield
->FF_Y
->FF_X
@CreateForcefield
else
->FF_Y
->FF_X
endif

# Function :OverrideWipeForcefieldProperties
# By default initializing forcefield properties locks the
# method and helps prevent leftover forcefields.
:OverrideWipeForcefieldProperties
@WipeForcefield
0 ->FF_ACPUSH
0 ->FF_CPUSH
0 ->FF_RANGE
--FF_INITIALIZED

# Function :WipeForcefield
# Safe method to wipe forcefield, if there is none it will be ignored.
# Notation: -
# e.g. @WipeForcefield
:WipeForcefield
-?FF_INITIALIZED if
-?FORCEFIELD_AVAILABLE if
--FORCEFIELD_AVAILABLE
@ModifyForcefield(<-FF_X <-FF_Y <-FF_RANGE <-FF_CPUSH neg <-FF_ACPUSH neg)
endif
endif

# Function :CreateForcefield
# Creates a Forcefield with the initialized parameters.
# Notation: -
# e.g. @CreateForcefield
:CreateForcefield
-?FF_INITIALIZED if
-?FORCEFIELD_AVAILABLE not if
true ->FORCEFIELD_AVAILABLE
@ModifyForcefield(<-FF_X <-FF_Y <-FF_RANGE <-FF_CPUSH <-FF_ACPUSH)
endif
endif

# Major props to Tyler, thanks for helping make forcefields work as intended.
# Function :ModifyForcefield
# Adds input creeper and anti-creeper to surrounding field cells with
# strength decreasing with distance form the epicenter.
# Negative values will modify the forces in opposite directions and 0 will change nothing.
# Notation: x y f1 i1 i2 -
# e.g. CurrentCoords 10 100000 -100000 @ModifyForcefield
:ModifyForcefield
neg ->SF_ACPUSH
neg ->SF_CPUSH
asfloat ->SF_RANGE # float-value is required for the div operations
->SF_Y
->SF_X

<-SF_RANGE 2 mul 1 add 0
do
<-SF_RANGE 2 mul 1 add 0
do
<-SF_X J add <-SF_RANGE sub ->xCell
<-SF_Y I add <-SF_RANGE sub ->yCell

<-xCell neq(<-SF_X) or(<-yCell neq(<-SF_Y)) if
<-SF_X <-SF_Y <-xCell <-yCell Distance ->SF_DIST
<-SF_DIST lte(<-SF_RANGE) if
<-SF_DIST neg add(<-SF_RANGE) div(<-SF_RANGE) mul(0.7) add(0.3) ->SF_MOD
<-SF_ACPUSH mul(<-SF_MOD) asint ->SF_ACPUSHMOD
<-SF_CPUSH mul(<-SF_MOD) asint ->SF_CPUSHMOD
@GetVector(@GetAngle(<-xCell <-yCell <-SF_X <-SF_Y) <-SF_CPUSHMOD) ->cRLCell ->cUDCell
@GetVector(@GetAngle(<-xCell <-yCell <-SF_X <-SF_Y) <-SF_ACPUSHMOD) ->acUDCell ->acRLCell
GetFieldCell(<-xCell <-yCell) ->oacRLCell ->oacUDCell ->ocRLCell ->ocUDCell
SetFieldCell(<-xCell <-yCell <-cUDCell add(<-ocUDCell) <-cRLCell add(<-ocRLCell) <-acUDCell add(<-oacUDCell) <-acRLCell add(<-oacRLCell)) # n1, n2, n3 and n4 are for creeper U(+)/D(-), creeper R(+)/L(-), AC U/D and AC R/L
endif
endif
loop
loop

#======================================
#==== VARIOUS CONVENIENCE METHODS =====
#======================================

# Function :GetVector
# Uses an angle, and speed and returns a vector
# You can add the vector to a position to get a moving effect
# Notation: f1 f2 - x y
# eg. <-angle 1.5 @GetVector ->y ->x
:GetVector
asfloat ->gv_vrsm
asfloat ->gv_vrAngle

<-gv_vrAngle sin ->gv_vrY
<-gv_vrAngle cos ->gv_vrX
<-gv_vrX <-gv_vrY @NormalizeVector ->gv_vrY ->gv_vrX
<-gv_vrY <-gv_vrsm mul ->gv_vrY
<-gv_vrX <-gv_vrsm mul ->gv_vrX
<-gv_vrX
<-gv_vrY neg

# Function :NormalizeVector
# Takes an (x,y) coordinate and returns it in terms of 0 to 1,
# with 1 being the maximum length (traveling directly up/down or left/right)
# and 0 being the minimum.
# Notation: x y - x y
# eg. <-vectorX <-vectorY @NormalizeVector ->vectorY ->vectorX
:NormalizeVector
asfloat ->nv_theY
asfloat ->nv_theX
<-nv_theX <-nv_theY @GetLength ->nv_length
<-nv_theY <-nv_length div ->nv_ny
<-nv_theX <-nv_length div ->nv_nx
<-nv_nx
<-nv_ny

# Function :GetLength
# Takes a width and height and calculates a length.
# Notation: x y - f1
# eg. 4 3 @GetLength ->length #(will return 5)
:GetLength
asfloat ->gl_theY
asfloat ->gl_theX
<-gl_theX 2.0 pow <-gl_theY 2.0 pow add sqrt

# Function :GetAngle
# Takes an initial position and a target position,
# then calculates an angle to face the target.
# Value returned in radians.
# Notation: x y x2 y2 - f1
# eg. CurrentCoords <-targetUnit @UnitCoords @GetAngle ->angle
:GetAngle
asfloat ->ga_targetY
asfloat ->ga_targetX
asfloat ->ga_curY
asfloat ->ga_curX

<-ga_targetX <-ga_curX sub ->ga_deltaX
<-ga_curY <-ga_targetY sub ->ga_deltaY
<-ga_deltaY <-ga_deltaX atan2 ->ga_desiredAngle
<-ga_desiredAngle

# Function :GetClosestUnit
# WARNING: use this convenience function sparingly, tens of CRPL Cores
# running this all at once every frame will slow the game down significantly.
#
# This function uses a flexible algorithm to filter
# units within a certain distance and retrieve the one
# closest to the position given to the function.
# It requires a position, a maximum distance, and an
# instruction list.
#
# The instruction list can contain multiple objects (but at least one is needed).
# An instruction follows this format: "unittype:parameter1,parameter2,parameter3=value,parameter4=value..."
# All applicable unit types can be found on:
# https://knucklecracker.com/wiki/doku.php?id=crpl:docs:getunittype
#
# The following parameters are acceptable:
# LANDED BUILT RANK=value
# LANDED and BUILT can accept modifiers. * means __either__, - means NOT, no modifier means IS
# If the parameter is none of the three, and the unit type is defined as "CRPLCORE" the assumed
# parameter type is a CRPLCore variable which is defined like so: myVar=myVal
#
# The unit type can be substituted by ALL which will affect all instructions, ALL must be in the
# beginning of the list or it will be assumed to be a unit type.
# ALL does not accept RANK or script variables as parameters.
#
# == EXAMPLE ==
# @BeginList "ALL:BUILT" "COLLECTOR" "relay:*built,rank=0.5" "pulsecannon:-landed,rank=2" "crplcore:emit=3.5" @BuildList ->instructions
# CurrentCoords 50 <-instructions @GetClosestUnit ->unit
#
# Explanation: All of the instructions within the list are acceptable. The only time the parameters are
# case sensitive is when defining script parameters. CONST_ISLANDED and CONST_ISBUILDING do not affect CRPLCores.
# According to these instructions, to get the closest unit within a range of 50 we will accept any built collector,
# any relay that is built or not but we give the a half the normal rank so the algorithm will treat them as if
# they are twice the distance away from anything else in the way. A collector and relay at the same distance will
# always return the collector. Next we prioritize any flying pulse cannon and override the ALL parameter, we
# then also look for any CRPLCores we made that had a script variable of "emit" that is equal to 3.5.
#
# Notation: x y f1 L1 - u
# e.g. CurrentCoords 50 <-instructionList @GetClosestUnit ->unit
:GetClosestUnit
->un_list
asfloat ->un_dist
asfloat ->un_y
asfloat ->un_x

-1 ->un_unit
-1 ->un_udist

<-un_x <-un_y <-un_dist <-un_list @GetAllUnits ->un_count
<-un_count neq0 if
<-un_count 0 do
->un_temp
<-un_temp GetUnitType ->un_type
# GET INSTRUCTION FOR THIS UNIT TYPE
<-un_instructions GetListCount 0 do
<-un_instructions GetListElement(I) ->un_inst
# found correct instruction
<-un_inst StartsWith(<-un_type) if
<-un_inst Split(" ") ->un_ilist
<-un_ilist GetListElement(3) asfloat ->une_rank

# now we apply the priority and get the closest unit
<-un_x <-un_y @UnitCoords(<-un_temp) Distance div(<-une_rank) ->un_tdist
<-un_tdist lt(<-un_udist) or(<-un_udist eq(-1)) if
<-un_tdist ->un_udist
<-un_temp ->un_unit
endif
break
endif
loop
loop
endif
<-un_unit

# Function :GetAllUnits
# Grabs all units of specified instruction within a radius of
# a given point. Read :GetClosestUnit for more info.
# Notation: x y f1 L1 - [u1 u2...]i1
# e.g.
# CurrentCoords 50 <-instructionList @GetAllUnits ->unitCount
# <-unitCount 0 do
# # code here
# loop
:GetAllUnits
->un_list
asfloat ->un_dist
asfloat ->un_y
asfloat ->un_x

CreateList ->un_units
--un_all_landed
--un_all_built

<-un_list GetListCount gt(0) if
<-un_list GetListElement(0) ToUpper ->un_elm
<-un_elm StartsWith("ALL") if
<-un_elm StringReplace("ALL:" "") ->un_elm
<-un_elm Split(",") ->un_values
<-un_values GetListCount 0 do
<-un_values GetListElement(I) ->un_elm
<-un_elm ToUpper EndsWith("LANDED") if
<-un_elm StartsWith("-") if
false ->un_all_landed
else
true ->un_all_landed
endif
endif
<-un_elm ToUpper EndsWith("BUILT") if
<-un_elm StartsWith("-") if
false ->un_all_built
else
true ->un_all_built
endif
endif
loop
endif
endif

CreateList ->un_instructions
<-un_list GetListCount 0 do
"" ->compile_task
"" ->un_type
1.0 ->rank

--un_landed_req
--un_built_req

-?un_all_landed if <-un_all_landed ->un_landed_req endif
-?un_all_built if <-un_all_built ->un_built_req endif

<-un_list GetListElement(I) ->un_elm
<-un_elm Split(":") ->un_lelm

<-un_lelm GetListElement(0) ToUpper ->un_type

<-un_type ->compile_task
"" ->append_task

<-un_lelm GetListCount gt(1) if
<-un_lelm GetListElement(1) ->un_elm
<-un_elm StringReplace(<-un_type concat(":") "") ->un_elm
<-un_elm Split(",") ->un_values
<-un_values GetListCount 0 do
<-un_values GetListElement(I) ->un_elm
true ->definingVariable
<-un_elm ToUpper EndsWith("LANDED") if
<-un_elm StartsWith("-") if
false ->un_landed_req
else
true ->un_landed_req
endif
<-un_elm StartsWith("*") if
--un_landed_req
endif
false ->definingVariable
endif
<-un_elm ToUpper EndsWith("BUILT") if
<-un_elm StartsWith("-") if
false ->un_built_req
else
true ->un_built_req
endif
<-un_elm StartsWith("*") if
--un_built_req
endif
false ->definingVariable
endif
<-un_elm ToUpper StartsWith("RANK") if
<-un_elm Split("=") ->un_rankl
<-un_rankl GetListElement(1) asfloat ->rank
false ->definingVariable
endif

<-definingVariable and(<-un_type eq("CRPLCORE")) if
<-un_elm Split("=") ->un_varl
<-append_task concat(" ") concat(<-un_varl GetListElement(0)) concat(" ") concat(<-un_varl GetListElement(1) StringReplace("true" "1") StringReplace("false" "0")) ->append_task
endif
loop
endif
# 2 means not applicable
<-compile_task concat(" ") ->compile_task
-?un_built_req if <-compile_task concat(<-un_built_req) else <-compile_task concat("2") endif ->compile_task
<-compile_task concat(" ") ->compile_task
-?un_landed_req if <-compile_task concat(<-un_landed_req) else <-compile_task concat("2") endif ->compile_task
<-compile_task concat(" ") ->compile_task
<-compile_task concat(<-rank) ->compile_task
<-compile_task concat(<-append_task) ->un_instruction
<-un_instructions AppendToList(<-un_instruction)
loop

<-un_x <-un_y <-un_dist false GetAllUnitsInRange ->un_count
<-un_count neq0 if
<-un_count 0 do
->un_temp
<-un_temp neq(self) if
<-un_temp GetUnitType ->un_type
# GET INSTRUCTION FOR THIS UNIT TYPE
<-un_instructions GetListCount 0 do
<-un_instructions GetListElement(I) ->un_inst
<-un_inst StartsWith(<-un_type) if
<-un_inst Split(" ") ->un_ilist
--une_built
--une_landed
# 0 is the type
<-un_ilist GetListElement(1) ->une_t <-une_t neq(2) if <-une_t ->une_built endif
<-un_ilist GetListElement(2) ->une_t <-une_t neq(2) if <-une_t ->une_landed endif
<-un_ilist GetListElement(3) asfloat ->une_rank

false ->skip
<-un_type eq("CRPLCORE") if
4 ->unc_index
while <-unc_index lt(<-un_ilist GetListCount) repeat
<-un_ilist GetListElement(<-unc_index) ->unc_var
<-unc_index add(1) ->unc_index
<-un_ilist GetListElement(<-unc_index) ->unc_val
<-unc_index add(1) ->unc_index
<-un_temp <-unc_var <-unc_val @CRPLMatchesValue ->unc_match
<-unc_match not if
true ->skip
endif
endwhile
endif
not(<-skip) if
# MATCH VALUES
<-un_type @BuildApplies if
-?une_built if GetUnitAttribute(<-un_temp CONST_ISBUILDING) eq(<-une_built) ->skip endif
endif
<-un_type @LandedApplies if
-?une_landed and(not(<-skip)) if GetUnitAttribute(<-un_temp CONST_ISLANDED) neq(<-une_landed) ->skip endif
endif
not(<-skip) if
<-un_units AppendToList(<-un_temp)
endif
endif
break
endif
loop
endif
loop
endif
<-un_units GetListCount 0 do
<-un_units GetListElement(I)
loop
<-un_units GetListCount

:BuildApplies
->ba_type
# list of what DOESN'T
-?ba_applies not if
@BeginList
"GUPPYAIR" "BOMBERAIR" "STRAFERAIR" "CRPLCORE" "EMITTER" "SPORETOWER" "RUNNER" "RUNNERNEST"
"AETOWER" "INHIBITOR" "POWERZONE" "OREDEPOSIT" "RESOURCEPACK" "TOTEM" "AOO" "SHIELDKEY"
"MESSAGEARTIFACT"
@BuildList ->ba_applies
endif
not(<-applies @DoesListContain(<-ba_type))

:LandedApplies
->la_type
# list of what DOES
-?la_applies not if
@BeginList
"TERP" "SHIELD" "PULSECANNON" "MORTAR" "SPRAYER" "BEAM" "SNIPER"
@BuildList ->la_applies
endif
<-la_applies @DoesListContain(<-la_type)

# Function :CRPLMatchesValue
# Takes a unit, a value and a variable and determines
# without a given script whether or not the CRPLCore
# has a variable with that value.
# Notation: u s1 * - b1
# e.g. self "myVar" 5 @CRPLMatchesValue ->matchesValue
:CRPLMatchesValue
->uv_val
->uv_var
->uv_unit
false ->uv_found

<-uv_var <-uv_val GetCoresWithVar ->uv_count
<-uv_count neq(0) if
<-uv_count 0 do
->uv_temp
<-uv_temp eq(<-uv_unit) if
true ->uv_found
endif
loop
endif
<-uv_found

# 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
asint ->uc_u
<-uc_u CONST_COORDX GetUnitAttribute
<-uc_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

# == END REQUIRED CREEP CODE == #
CW4 hype!!

GoodMorning

Having looked in more detail; these are the questions I would put. Please let me know if I have anything wrong.

1. What exactly are the symptoms? Can you show a trace?

2. (Probably safe, but...) What are OK2 and 3 achieving?
OK2 Controls Core creation, held in common over the three upgrade paths,
OK3 seems to be related to upgrade count control?

The existence of external Cores makes little sense to me, excepting the Creep Torpedo.

3. UNumber shouldn't ever be 4. See under https://knucklecracker.com/wiki/doku.php?id=crpl:docs:randint

4.The UNumber indicates a target upgrade. Why keep running the upgrade function, instead of a test function?

More I cannot say without some idea of the function performed by the CRPL Cores you generate. Why, though, is the script that they run, made external?
A narrative is a lightly-marked path to another reality.

Nicant

#5
Quote from: GoodMorning on February 15, 2016, 11:15:32 PM
Having looked in more detail; these are the questions I would put. Please let me know if I have anything wrong.

1. What exactly are the symptoms? Can you show a trace?

2. (Probably safe, but...) What are OK2 and 3 achieving?
OK2 Controls Core creation, held in common over the three upgrade paths,
OK3 seems to be related to upgrade count control?

The existence of external Cores makes little sense to me, excepting the Creep Torpedo.

3. UNumber shouldn't ever be 4. See under https://knucklecracker.com/wiki/doku.php?id=crpl:docs:randint

4.The UNumber indicates a target upgrade. Why keep running the upgrade function, instead of a test function?

More I cannot say without some idea of the function performed by the CRPL Cores you generate. Why, though, is the script that they run, made external?
1. I did a trace and it said it was taking a(n) item from an empty stack. The symptom is when the core selects an upgrade. When it selects an upgrade, the upgrade number does not change when the upgrade is complete. So once it selects an upgrade, it will not change and will keep upgrading the same upgrade over and over again without selecting another upgrade.

2. "OK2" makes sure the core only goes through a function once, makes an "UpgradeCore", and changes the value of "OK3" to 1. "OK3" makes it so it still goes through the upgrade function, but does not make an "UpgradeCore". All "UpgradeCores" do is display a text the tells the player what upgrade the forge is working on. I did this because i have no idea how to have the forge display 2 texts at once with their own different size and position. Hopefully that made sense. :)

3. I read the wiki page more carefully and removed those lines of code that gets another number if the UNumber is 0 or 4.

4. That is a good idea to have a test function! :) I made most of the code late at night so i really wasn't thinking.

Hopefully this makes sense! :) (Most likely does not :P )
CW4 hype!!

GoodMorning

My replies were written partially late in my night, so I may be equally guilty.

I don't know about the text display, so don't break something that works. (Si non confectus, non recifiat.)

If OK3 should do nothing but be the opposite of OK2, you can merge them into TextCoreCreated, or some such.
(Something like: replace "<-OK3" with "<-OK2 not", or vice versa.)

UNumber, as far as I could see, can be {0,1,2,3}. The 0 could be used for something else... but needs to be tested for.

The "empty stack" means that somewhere you have functions that are eating arguments from elsewhere. More stack tracing will be required, but the UNumber is not your issue, seemingly.
e.g. <-arg1 <-arg2 @eatArgs, where :eatargs ->take1 ->take2 ->take3
Removing from an empty stack can be problematic, the number is probably being used elsewhere.
There is an important note on debugging: TraceStack doesn't modify the stack.
Trace, Trace2 etc... remove their arguments from the stack.

On a side note, I have found it helpful to use the battleship-style documentation for functions.
i.e. :FuncDef # [ in1 in2 - out1 out2] Description
This can help in debugging, or helping others understand.

There is going to be pain in finding the bug, but the TraceStack command will be your friend.

Having said that, you should be able to clean up a few potential bugs by using a test function.

Have fun, and I wouldn't mind knowing what you find.
A narrative is a lightly-marked path to another reality.