Knuckle Cracker

Particle Fleet => Map Makers, Ship Builders, and Coders => Topic started by: JoaoPistori on October 23, 2016, 11:29:16 AM

Title: (More) PRPL questions
Post by: JoaoPistori on October 23, 2016, 11:29:16 AM
My next map in PF needs some small help in a custom module. I got examples from Planetfall's modules ( http://knucklecracker.com/forums/index.php?topic=21624.0 ) and I picked the Nuker module as a base for a new module. I changed images, max range, projectile strenght and other things. But the main ideia os this module was to fire only at targets that are in a certain max angle offset. What I mean: the module must have a "limited field of view" and shouldn't target units beyond the angle limit. Although I'm having some difficulties in fixing the preference bug:

I changed and added things in the script and it works fine when the module has only one possible target in range (the point: preferences will not make targeting differences, as it has only 1 possible target) - it fires against it when the angle permits.

The problem is when it has more than 1 target, and one of them doesn't match the angle preference:
The module itself has prefered targets (as the own Planetfall's Nuker module), counting firstly by unit type, then the nearest one of the prefered.
The situation: imagine 2 emitters, both are in "range" but one is near from de module than the other. Now imagine that this nearest one doesn't match the angle restriction while the farthest one matches. The module itself doesn't fire, because it prefers to attack the nearest emitter while the angle restriction blocks it (and should block - this is correct). But it also doesn't fire at the farthest emitter that is in "angle range", because it prefers to attack the nearest one. I tried changing things in ":IsTargetValid" script part but then all my ideas of fixing this "bug" (not actually a bug, it's missing correct checks) weren't enough. Some of them resulted im the module not considering angle anymore (even with more than 2 if-else angle checks) and some of them made the module disrespect the angle offset for the type preference (when there's an emitter and a doppel - doppel is higher ranked in preference, then the module was firing at it disrespecting angle restriction, but without the emitter in range, the angle restriction was respected [again, only 1 possible target]).
I'll post the scripts soon after getting a response!

Can anybody help me? I would be very grateful! Thanks
Title: Re: (More) PRPL questions
Post by: planetfall on October 23, 2016, 12:22:28 PM
Did you try something like this?


:IsTargetValid
->priorityReq
<-unit.UnitPixelCoordY self GetUnitPixelCoordY sub <-unit.UnitPixelCoordX self GetUnitPixelCoordX sub atan2 ->angle
<-angle <-ShipAngle sub abs 1.0 gt if
return
endif
<-priority <-priorityReq lt if
<-priorityReq ->priority
<-unit.UnitPixelCoordX <-unit.UnitPixelCoordY CurrentPixelCoords Distance ->nearest
<-unit ->target
else
<-priorityReq <-priority eq if
<-unit.UnitPixelCoordX <-unit.UnitPixelCoordY CurrentPixelCoords Distance ->dist
<-dist <-nearest lt if
<-priorityReq ->priority
<-dist ->nearest
<-unit ->target
endif
endif
endif
Title: Re: (More) PRPL questions
Post by: JoaoPistori on October 23, 2016, 11:04:50 PM
The last one I made was this code:

(note that some parts were just made for in-editor testing and will be excluded after everything gets fixed)


$AngleMaxOffset:0.1964 #a value in radians

[...]

:findTarget
CurrentCoords <-range 0 GetAllShipsInRange ->Ships
0 ->largest
<-Ships GetListCount 0 do
<-Ships[I] GetShipIsEnemy <-IsEnemy neq if
<-Ships[I] GetShipHullSize <-largest gt if
<-Ships[I] GetShipHullSize ->largest
<-Ships[I] ->target
endif
endif
loop
<-target -1 neq if
"ship" ->mode
return
endif
0 ->priority
<-range 4 mul ->nearest
CurrentCoords <-range 0 GetAllUnitsInRange ->Units
<-Units GetListCount 0 do
<-Units[I] ->unit

"- NEW ITEM -" trace
#CurrentCoords <-target1.UnitCoordX <-target1.UnitCoordY @GetAngle ->MainAngle
CurrentCoords <-unit.UnitCoordX <-unit.UnitCoordY @GetAngle ->MainAngle
<-MainAngle mul (Rad2Deg) ->MainDegress
"SHIP DEGRESS:" trace
                <-ShipAngle mul (Rad2Deg) ->ShipDegress
                <-ShipDegress trace #just to easily check if everything is correct
"TARGET DEGRESS:" trace
<-MainDegress trace #just to easily check if everything is correct

<-ShipDegress <-MainDegress sub ->result3
<-ShipAngle <-MainAngle shortestangle ->result2

<-result2 0 lt if
<-result2 -1 mul ->result2
endif

<-result3 0 lt if
<-result3 -1 mul ->result3 #this one doesn't always pick the shortest angle (and shouldn't)
endif

"Diference DEG:" trace
<-result3 trace
"Diference RAD:" trace
<-result2 trace

<-unit GetUnitIsEnemy <-IsEnemy neq if
<-unit GetUnitType ->type
<-type "Doppel" eq if
4 @IsTargetValid
endif
<-type "Doppel(Clone)" eq if
4 @IsTargetValid
endif
<-type "Omni" eq if
4 @IsTargetValid
endif
<-type "PhalanxGun(Clone)" eq if
4 @IsTargetValid
endif
<-type "Emitter" eq if
2 @IsTargetValid
endif
<-type "Emitter(Clone)" eq if
2 @IsTargetValid
endif
# <-type "EnergyMine" eq if
# 3 @IsTargetValid
# endif
# <-type "EnergyMine(Clone)" eq if
# 3 @IsTargetValid
# endif


endif
loop
<-target -1 neq if
"unit" ->mode
endif

:IsTargetValid
->priorityReq

<-result2 <-AngleMaxOffset lte if
    "IS IN ANGLE" trace
<-priority <-priorityReq lt if
<-priorityReq ->priority
<-unit.UnitPixelCoordX <-unit.UnitPixelCoordY CurrentPixelCoords Distance ->nearest
   # <-unit ->target1
#<-result2 <-AngleMaxOffset lte if
<-unit ->target
#endif                             
else
<-priorityReq <-priority eq if
<-unit.UnitPixelCoordX <-unit.UnitPixelCoordY CurrentPixelCoords Distance ->dist
<-dist <-nearest lt if
<-priorityReq ->priority
<-dist ->nearest
#<-unit ->target1
#<-result2 <-AngleMaxOffset lte if
<-unit ->target
#endif                             
endif
endif
endif
else
    "IS NOT IN ANGLE" trace
<-priority <-priorityReq lt if
<-priorityReq ->priority
<-unit.UnitPixelCoordX <-unit.UnitPixelCoordY CurrentPixelCoords Distance ->nearest
<-unit ->target1
#<-result2 <-AngleMaxOffset lte if
#<-unit ->target
#endif
else
<-priorityReq <-priority eq if
<-unit.UnitPixelCoordX <-unit.UnitPixelCoordY CurrentPixelCoords Distance ->dist
<-dist <-nearest lt if
<-priorityReq ->priority
<-dist ->nearest
<-unit ->target1
#<-result2 <-AngleMaxOffset lte if
#<-unit ->target
#endif
endif
endif
endif
endif

:GetAngle
asfloat ->rta_targetY
asfloat ->rta_targetX
asfloat ->rta_curY
asfloat ->rta_curX

<-rta_targetX <-rta_curX sub ->rta_deltaX
<-rta_targetY <-rta_curY sub ->rta_deltaY
<-rta_deltaY <-rta_deltaX atan2


Upon uncommenting [#<-unit ->target1 ; #<-result2 <-AngleMaxOffset lte if ; #endif] it works perfectly with 1 target (because the angle check is just after other checks), but I don't know why it wasn't working with the same check [<-result2 <-AngleMaxOffset lte if] before the other checks (the check above ["IS IN ANGLE" trace])

I was using target1 variable to see with "traces" commands if the targets were being correctly processed, it doesn't really do something more.

I haven't added angle checks for ship targeting yet - but I'll use the same method.
Title: Re: (More) PRPL questions
Post by: GoodMorning on October 24, 2016, 02:32:46 AM
Here's an untested bit of code which will hopefully be easy to understand and integrate properly with your project when copy/pasted in. I have defined some new variable names, so be sure to check for overwrites of variables elsewhere in your project (unlikely, but possible).

This is based on my understanding of your script, as explained in the comments.


$AngleMaxOffset:0.1964 #a value in radians

[...]

:findTarget #[-] Set the variable "target" from -1 to the UID of a unit, by the following criteria:
#Is the largest opposing ship in range, ignoring angular LOS
#If there are no ships in range, consider only units within AngleMaxOffset of ShipAngle. Within this restriction:
#Is the nearest opposing Omni or Doppel,
#If there are none of these, is the nearest opposing Emitter
#If none of the above apply, the variable "target" should remain set to -1.

#First: Target the largest ship in range, disregarding LOS...
<-target -1 neq if
"Target already assigned..." Trace
return
endif #

CurrentCoords <-range 0 GetAllShipsInRange ->Ships
-1 ->TargetSize

<-Ships GetListCount 0 do
<-Ships[I] ->TargetableShip

<-TargetableShip GetShipIsEnemy <-IsEnemy neq if #Opposing
<-TargetableShip GetShipHullSize <-TargetSize gt if #A bigger fish
<-TargetableShip GetShipHullSize ->TargetSize
<-Ships[I] ->target
endif
endif
loop

<-target -1 neq if
"ship" ->mode
return
endif

#Second: No ship, we now try for a unit...

0 ->PriorityOfCurrentTarget
9999.9 ->TargetPixelDistance #Using 9999 here, to be clearer that it should be greater than the furthest unit distance...
#Note: Maps are no more than 500x500, and pixel distance is 4x cell distance. So no unit should be more than (500+500)x4=4000 pixels away.

CurrentCoords <-range 0 GetAllUnitsInRange ->Units
<-Units GetListCount 0 do
<-Units[I] ->Unit

"- NEW ITEM -" trace
Self <-Unit @GetAngle ->AngleOfUnit #From self...
<-AngleOfUnit mul (Rad2Deg) ->AngleOfUnitDegress
"SHIP DEGRESS:" trace
                <-ShipAngle mul (Rad2Deg) ->ShipDegress #Ship rotation
                <-ShipDegress trace
"TARGET DEGRESS:" trace
<-AngleOfUnitDegress trace

<-ShipAngle <-MainAngle ShortestAngle abs ->AngularOffset

#These are now the same number.
"Diference RAD:" trace
<-AngularOffset trace
"Diference DEG:" trace
<-AngularOffset Rad2Deg mul trace #Please default to radians in future, the QUARTERPI command (and other such) was introduced to help this.

<-Unit GetUnitIsEnemy <-IsEnemy neq if #Opposition
<-Unit GetUnitType ->UnitType
<-UnitType "Doppel" eq if
4 @CheckTarget
endif
<-UnitType "Omni" eq if
4 @CheckTarget
endif
<-UnitType "Emitter" eq if
2 @CheckTarget
endif
endif
loop
<-target -1 neq if #Target acquired
"unit" ->mode
endif

:CheckTarget #[UnitPriority - ]
->UnitPriority

<-AngularOffset <-AngleMaxOffset lte if #Within our blinkered LOS

<-PriorityOfCurrentTarget <-UnitPriority lt if #It's worth changing targets
<-Unit ->target
<-UnitPriority ->PriorityOfCurrentTarget
<-Unit @GetPixelDistanceToUnit ->TargetPixelDistance
else
<-PriorityOfCurrentTarget <-UnitPriority eq if
<-Unit @GetPixelDistanceToUnit ->UnitPixelDistance
<-UnitPixelDistance <-TargetPixelDistance lt if
<-Unit ->target
<-UnitPixelDistance ->TargetPixelDistance
endif
endif
endif
endif

:GetAngleBetweenUnits #[UnitA unitB - Angle]
->UID_B ->UID_A

<-UID_A.UnitPixelCoordY <-UID_B.UnitPixelCoordY sub
<-UID_A.UnitPixelCoordX <-UID_B.UnitPixelCoordX sub
atan2 #Recall that atan2 takes deltaY first, for some reason...
--UID_A
--UID_B #Be tidy

:GetPixelDistanceToUnit #[Unit - Distance]
->UnitToCheckDistanceTo
CurrentPixelCoords
<-UnitToCheckDistanceTo.UnitPixelCoordX
<-UnitToCheckDistanceTo.UnitPixelCoordY Distance
--UnitToCheckDistanceTo



Bear in mind, we cannot readily test code we provide, not having the rest of your script at our disposal. Your previous script was slightly difficult to read, so please consider using variable names more descriptive than "result1". Also, I am unsure why you felt the need to check anything about the units once it was established that they were not within the LOS angle, which may have caused your issue.

This unit looks like it could be attacked from the side safely, as targets may move outside the "wedge" but within range, and the ship does not seem inclined to turn to face them even if there are no targets inside the "wedge".
Title: Re: (More) PRPL questions
Post by: JoaoPistori on October 25, 2016, 10:26:45 AM
This is the full module's script and I have made it works as desired and now I'll optimize it as planetfall did. Also working when targeting ships, thanks GoodMorning. The main objective is ready and the last stage is make the ship auto-rotate a bit when it's target is moving out angle and rotate back when target gets out of range.

$AngleMaxOffset:0.1964

once
Self "main" "Custom11" SetImage
Self "main" "Ships" SetImageLayer
Self "main" 1 SetImageOrder
Self "main" 1.66 1.66 SetImageScale
Self "link" "Custom3" SetImage
Self "link" "Ships" SetImageLayer
Self "link" 1 SetImageOrder
Self "link" -0.1 SetImagePositionZ
Self "link" 1.66 2.8 SetImageScale
Self "nuke" "Custom0_256" SetImage
Self "nuke" "Ships" SetImageLayer
Self "nuke" 1 SetImageOrder
Self "nuke" -0.05 SetImagePositionZ
Self "nuke" 1.5 1.5 SetImageScale
Self "nuke" 255 255 255 0 SetImageColor
Self "ShipModule.prpl" "Ship" GetScriptVar ->Ship
<-Ship.ShipIsEnemy ->IsEnemy
endonce

Self "ShipModule.prpl" "ShipAngle" GetScriptVar ->ShipAngle
Self "ShipModule.prpl" "exist" GetScriptVar ->Exist

<-Exist eq0 if
self "main" 0 0 0 0 SetImageColor
self "link" 0 0 0 0 SetImageColor
self "nuke" 255 255 255 0 SetImageColor
0 ->recoil
300 ->cooldown
-1 ->target
return
endif

self "main" <-ShipAngle SetImageRotation
self "link" <-ShipAngle SetImageRotation
self "nuke" <-ShipAngle SetImageRotation

IsPaused if
return
endif

<-Exist 1 eq if
self "main" 255 255 255 128 SetImageColor
self "link" 255 255 255 128 SetImageColor
self "nuke" 255 255 255 0 SetImageColor
else
self "main" 255 255 255 255 SetImageColor
self "link" 255 255 255 192 SetImageColor
<-Ship GetShipHasAmp ->GemPresent
<-GemPresent if
105 ->range    #was 115
2 ->P_number #number of particles "waves" fired by projectile upon exploding
8 ->P_health   #particles' health created by the projectile's explosion
90 ->P_age     #particles' age created by the projectile's explosion
else
    <-IsEnemy if
120 ->range #was 130
3 ->P_number
10 ->P_health
120 ->P_age
else
90 ->range #was 100
1 ->P_number
6 ->P_health
60 ->P_age
endif
endif
<-target -1 eq if
<-cooldown if
<-IsEnemy if
<-cooldown 1 sub ->cooldown
Self "nuke" 255 255 255 255 <-cooldown 1.7 mul sub SetImageColor
else
GetGlobalStoredEnergy 0.75 gte if
GetGlobalStoredEnergy 0.75 sub SetGlobalStoredEnergy
<-cooldown 1 sub ->cooldown
endif
endif
else
@findTarget
endif
else
CurrentPixelCoords ->y ->x
<-mode "ship" eq if
<-target.ShipPixelCoordY ->py
<-target.ShipPixelCoordX ->px
else
<-target.UnitPixelCoordY ->py
<-target.UnitPixelCoordX ->px
endif
<-px <-py <-x <-y Distance <-range 4 mul gt if
-1 ->target
@findTarget
else
<-mode "ship" eq if
<-target.ShipIsDestroyed
else
<-target.UnitIsDestroyed
endif
not if
CurrentCoords GetLand eq0 if
<-IsEnemy eq0 if
GetGlobalStoredEnergy 10 sub SetGlobalStoredEnergy #Ship energy API plox?
endif
<-GemPresent if
210 ->cooldown
else
300 ->cooldown
endif
"PRPLCORE" 0 0 CreateUnit ->Nuke
<-x ->Nuke.UnitPixelCoordX
<-y ->Nuke.UnitPixelCoordY
<-Nuke "EnergyShot.prpl" AddScriptToUnit
<-Nuke "EnergyShot.prpl" "IsEnemy" <-IsEnemy SetScriptVar
<-Nuke "EnergyShot.prpl" "Target" <-target SetScriptVar
<-Nuke "EnergyShot.prpl" "mode" <-mode SetScriptVar
<-Nuke "EnergyShot.prpl" "InitialAngle" <-ShipAngle SetScriptVar
<-Nuke "EnergyShot.prpl" "P_number" <-P_number SetScriptVar
<-Nuke "EnergyShot.prpl" "P_health" <-P_health SetScriptVar
<-Nuke "EnergyShot.prpl" "P_age" <-P_age SetScriptVar
<-IsEnemy ->Nuke.UnitIsEnemy
"Misc4" PlaySound
-1 ->target
endif
endif
endif
endif
Self "nuke" 255 255 255 255 <-cooldown 1.7 mul sub SetImageColor
endif

:findTarget
CurrentCoords <-range 0 GetAllShipsInRange ->Ships
0 ->largest
<-Ships GetListCount 0 do
    <-Ships[I] ->TargetableShip
<-Ships[I] GetShipIsEnemy <-IsEnemy neq if
CurrentCoords <-TargetableShip.ShipCoordX <-TargetableShip.ShipCoordY @GetAngle ->NecessaryAngle
    <-ShipAngle <-NecessaryAngle shortestangle ->AngleOffset
    <-AngleOffset 0 lt if
    <-AngleOffset -1 mul ->AngleOffset
    endif
<-AngleOffset <-AngleMaxOffset lte if
<-Ships[I] GetShipHullSize <-largest gt if
<-Ships[I] GetShipHullSize ->largest
<-Ships[I] ->target
    endif
endif
endif
loop
<-target -1 neq if
"ship" ->mode
return
endif
0 ->priority
<-range 4 mul ->nearest
CurrentCoords <-range 0 GetAllUnitsInRange ->Units
<-Units GetListCount 0 do
<-Units[I] ->unit
CurrentCoords <-unit.UnitCoordX <-unit.UnitCoordY @GetAngle ->NecessaryAngle
<-ShipAngle <-NecessaryAngle shortestangle ->AngleOffset
<-AngleOffset 0 lt if
<-AngleOffset -1 mul ->AngleOffset
endif

<-unit GetUnitIsEnemy <-IsEnemy neq if
<-unit GetUnitType ->type
<-type "Doppel" eq if
4 @IsTargetValid
endif
<-type "Doppel(Clone)" eq if
4 @IsTargetValid
endif
<-type "Omni" eq if
4 @IsTargetValid
endif
<-type "PhalanxGun(Clone)" eq if
4 @IsTargetValid
endif
<-type "Emitter" eq if
2 @IsTargetValid
endif
<-type "Emitter(Clone)" eq if
2 @IsTargetValid
endif
# <-type "EnergyMine" eq if
# 3 @IsTargetValid
# endif
# <-type "EnergyMine(Clone)" eq if
# 3 @IsTargetValid
# endif


endif
loop
<-target -1 neq if
"unit" ->mode
endif

:IsTargetValid
->priorityReq
<-AngleOffset <-AngleMaxOffset lte if
<-priority <-priorityReq lt if
<-priorityReq ->priority
<-unit.UnitPixelCoordX <-unit.UnitPixelCoordY CurrentPixelCoords Distance ->nearest
<-unit ->target
else
<-priorityReq <-priority eq if
<-unit.UnitPixelCoordX <-unit.UnitPixelCoordY CurrentPixelCoords Distance ->dist
<-dist <-nearest lt if
<-priorityReq ->priority
<-dist ->nearest
<-unit ->target
endif
endif
endif
endif

:GetAngle
asfloat ->rta_targetY
asfloat ->rta_targetX
asfloat ->rta_curY
asfloat ->rta_curX

<-rta_targetX <-rta_curX sub ->rta_deltaX
<-rta_targetY <-rta_curY sub ->rta_deltaY
<-rta_deltaY <-rta_deltaX atan2


Hopefully those codes and "hint" will be nice fot others mappers too!
Title: Re: (More) PRPL questions
Post by: JoaoPistori on December 15, 2016, 07:33:43 AM
// Using this already created topic instead of creating a new one //

Hello! I'm planning to add more custom modules into my 4th PF map (no, I haven't uploaded the 2nd and the 3rd yet) and I would like some hints/help in PRPL:

1) Any direct way of dealing area damage to particles? I mean, if there's a native function that already does it, but if there's not, I know I can read particles in range and calculate distance, angle and deal damage (I want to add damage reduction with range and "push" particles with the explosion);

2) The same for ships - about dealind area damage into their hull/CM/"Doppel CM" without the creation of particles under them, or at least if there's a way to create invisible particles under them, so it wouldn't act like a very forged explosion;

3) How can I target/spawn emergent (with or without mired land), spawn/target enemy missiles (like lasers, cannons and beams do), target/create plasma and target mired/unmired land?

4) Some unis in the map ate "clickable", even if it does nothing. Is it possible to read whether this "native selector" is active in a unit? (This means the script will know when the unit is selected) Then I can use it to check whether a PRPL core is selected and then open a "menu", activate an action or something like for it. But if not possible, I'll try to do like the PAC selector script;

5) Where can I find effect names and sound names with audio? CW3 map editor has (I mean the sound part) but PF map editor doesn't have.

//edit: At number 3, I've tried getallunitsinrage and putting their respective unit names and other possible names - no sucess

Sorry if I could already have found something in the wiki - I haven't deeeply checked it yet because seems that a lot of information is still being built and added.
Any help will be a great help, thanks!
Title: Re: (More) PRPL questions
Post by: planetfall on December 15, 2016, 09:16:03 AM
1. Nope. But what you describe isn't too difficult. I just wonder about the "right" way to deal knockback.
2. You'd have to call GetNearestTarget to get individual ship hull segments. I've requested a GetAllTargetsInRange at least twice, no dice. AFAIK, no way to make invisible particles.
3.One at a time:
In the beta, I tried "Emergent" CurrentCoords CreateUnit which technically worked, albeit broke the game. For targeting you can GetAllUnitsInRange and filter by GetUnitType "Emergent" eq. I also tried the latter in beta, didn't work then but seems to work now. I haven't tested whether spawning emergent works now.

"Missile" X Y CreateUnit
<-uid <-targetParticleUID InitMissile
You can pick up missiles and CannonShots in GetAllUnitsInRange.

PRPL can't interact with plasma, I'm afraid.

For mire you'd have to do a circular search and GetMire on every cell, there's no GetNearestMire to my knowledge. Doing it manually like that would slow the game down to a crawl. There's also no way I know to create the blue shots that damage mire/struc.

4. Nope. "Set cores not selectable" is coming though, so maybe we'll get "get core is selected" at the same time.
5. Most sounds accessible to PRPL are those from CW3. The default sounds are not, save for "JumpIn" and "JumpOut." The misc sounds go up to at least Misc38. Misc36 and Misc38 are used in the final mission. I'm not sure where Misc37 is used, if anywhere.
Title: Re: (More) PRPL questions
Post by: JoaoPistori on December 15, 2016, 11:12:16 AM
Thank you!
I'll make some tests about the mired land and if it lags the map even more (lots of ships + lots of particles already lags a bit) I will probably remove it.
I'll also take a look at the sounds from CW3 like you said.
Nice tactical custom modules coming with my next map!
Title: Re: (More) PRPL questions
Post by: GoodMorning on December 15, 2016, 04:27:12 PM
V has mire API planned, so that might help you.
Title: Re: (More) PRPL questions
Post by: JoaoPistori on December 19, 2016, 12:34:05 PM
Hello! Could someone please help me with GetShipEnergyCap command?

For now, this custom module is just reading and telling me the ship's current energy and energy capacity:
...
"Current Energy:" trace
<-Ship GetShipEnergy trace #working perfectly
"Max Energy:" trace
<-Ship GetShipEnergyCap trace #always returns -1
...


Current Energy is working perfectly. Although Max Energy is always showing me a value of -1. I've tried putting more arguments for testing and seems that it only needs the Ship's uid, already especified.

The complete module's code:
# --ReactorModule-- 12/19/2016 2:43:43 PM

once
Self "main" "Custom14" SetImage
Self "main" "Ships" SetImageLayer
Self "main" 1 SetImageOrder
Self "main" 1 1 SetImageScale
Self "ShipModule.prpl" "Ship" GetScriptVar ->Ship
<-Ship.ShipIsEnemy ->IsEnemy
-1 ->target
#self "RadiusDisplay.prpl" AddScriptToUnit
#self "RadiusDisplay.prpl" "SCRIPT_NAME" "LaserWeapon.prpl" SetScriptVar
#self "RadiusDisplay.prpl" "RADIUS_VARNAME" "range" SetScriptVar
#self "RadiusDisplay.prpl" "IMAGE" "Custom8_256" SetScriptVar
#Pink circle range that does nothing
endonce

Self "ShipModule.prpl" "ShipAngle" GetScriptVar ->ShipAngle
Self "ShipModule.prpl" "delta" GetScriptVar ->Delta
Self "ShipModule.prpl" "exist" GetScriptVar ->Exist

<-Exist eq0 if
self "main" 0 0 0 0 SetImageColor
self "barrel" 0 0 0 0 SetImageColor
self "barrel" 0 0 -0.05 SetImagePosition
0 ->recoil
0 ->cooldown
<-target -1 neq if
<-mode "Particle" eq if
<-target "SNIPER_P" concat 0 ->!*
else
<-target "SNIPER_U" concat 0 ->!*
endif
-1 ->target
endif
return
endif

self "main" <-ShipAngle SetImageRotation

IsPaused if
return
endif

<-Exist 1 eq if
self "main" 255 255 255 128 SetImageColor
else
self "main" 255 255 255 255 SetImageColor
<-Ship GetShipHasAmp ->GemPresent
<-GemPresent if
0.1 ->production
else
    <-IsEnemy if
0.15 ->production
else
0.05 ->production
endif
endif
    <-Ship GetShipEnergyCap ->maxcap
<-Ship GetShipEnergy ->energy
#<-maxcap 50 add ->maxcap
#<-Ship <-maxcap SetShipEnergyCap

#<-energy <-production add ->energy
#<-Ship <-energy SetShipEnergy

# 2 tanks = 1050 energy max
# 1 tank = 550 energy max
# no tank = 50 energy max

# Ships have 50 energy cap.
# Each tank gives +500 energy cap.
"Current Energy:" trace
<-energy trace
"Max Energy:" trace
<-maxcap trace
<-Ship GetShipEnergyCap trace #testing without other variable
endif

#:destroyed
#<-Ship GetShipEnergyCap 50 sub SetShipEnergyCap


Edit: Forget about RadiusDisplay configuration, cooldown and recoil, they were part of the previous script that I copied and forgot to erase
Title: Re: (More) PRPL questions
Post by: planetfall on December 19, 2016, 12:43:05 PM
Try GetShipEnergyMax instead. GetShipEnergyCap is an overridey sort of thing.
Title: Re: (More) PRPL questions
Post by: JoaoPistori on December 19, 2016, 01:23:49 PM
"Invalid Token"

Also tried:
GetShipMaxEnergy
GetShipEnergyMaxCap
GetShipMaxEnergyCap
GetShipCapEnergyMax
GetShipEnergyCapMax

And whatever possible combination with "Cap", "Max" and "Energy".
The only one that didn't get error was "GetShipEnergyCap", but as you said it's an overridey sort of thing.

Edit: Also tried with "Capacity" (instead of "Cap")

Edit2: Put a line with "<-Ship 2000 SetShipEnergyCap":
...
<-Exist 1 eq if
self "main" 255 255 255 128 SetImageColor
else
self "main" 255 255 255 255 SetImageColor
<-Ship GetShipHasAmp ->GemPresent
<-GemPresent if
0.1 ->production
else
    <-IsEnemy if
0.15 ->production
else
0.05 ->production
endif
endif
<-Ship 2000 SetShipEnergyCap
    <-Ship GetShipEnergyCap ->maxcap
<-Ship GetShipEnergy ->energy
#<-maxcap 50 add ->maxcap
#<-Ship <-maxcap SetShipEnergyCap

#<-energy <-production add ->energy
#<-Ship <-energy SetShipEnergy

# 2 tanks = 1050 energy max
# 1 tank = 550 energy max
# no tank = 50 energy max

# Ships have 50 energy cap.
# Each tank gives +500 energy cap.
"Current Energy:" trace
<-energy trace
"Max Energy:" trace
<-maxcap trace
#<-Ship GetShipEnergyMaxCapacity trace #testing without other variable
endif
...

Max energy is now printing correctly the "2000" value. But the Ship doesn't reach it. It's energy always stops at 1050 max (it has 2 native energy tanks modules).
Title: Re: (More) PRPL questions
Post by: GoodMorning on December 19, 2016, 04:06:03 PM
SetShipEnergyCap sets a hard limit on ship power, probably intended for enemies.

What it does is prevent ship internal energy from rising higher, in the case where it otherwise would. Ship power can go up to 50 + 500 x tanks. So if you set the cap to 1000 on the ship you are building, it will not fill further than 1K, but will still try to, requesting 30eps and having the energy value clipped on each frame following the arrival of each packet.

I haven't found a way to give a ship a storage compression upgrade.
Title: Re: (More) PRPL questions
Post by: JoaoPistori on December 19, 2016, 04:17:47 PM
That's true and why I couldn't increase its max energy. Have tested with "400" instead of "2000" and it limited exactly at 400.
My plans with this custom module were to "mix" the reactor and the tank into a single upgraded module, with higher energy production and some more storage. So, I'll let just the extra energy production and probably add one more tank. Thanks.
Title: Re: (More) PRPL questions
Post by: JoaoPistori on December 20, 2016, 08:20:12 AM
// ===== VERY BIG BUG OVER THERE ===== //

I was testing a new custom module's behavior and seems that when damaging ships, the game completely freezes every unit (even energy packets and ship's energy), exept PRPL cores and energy storage (storage exceeds 100 and goes into the infinite).
The custom modules (PRPL cores) keeps trying to do what they should do (unit and particle targeting system gets bugged, but this is due of the freeze), example: The gun keeps firing, creating the light blue beam.

This happens when damaging ship's hull that has a module over it. Well... it prefers to bug when damaging Mk7 and Fighter bases... cannons, missiles, beams and lasers don't seem to bug.

I'm sure that the reason is at my ship-damaging system. Probably ship's hull doesn't count as units (<-variable.UnitHealth, .UnitCoordX/Y, GetUnit"Something" and everything else always return -1 when Reading a ship's hull uid***), so I have made a script that Spawn cannonshots under any ship hull:

***
Spoiler
But reads coords perfectly when rotating/aiming the cannon into it
[close]

1) The gun targets the ship's hull with GetNearestTarget. Working perfectly at identifying it and aiming at***.

2) It fires the light blue decorative beam. It does nothing - just decoration.

3) At the same time, it reads a small circular area around the target. Then, GetNearestTarget (with range 0) is called for each single cell in the circle, identifying if there's a ship hull.

4) If there's a ship hull, spawn a cannon shot under it. At this point, everything is working perfectly, but when damaging a hull with module, the big bug comes. You can't see the cannon shots since they are instantly destroyed when damaging hull, but at the image they were freezed so you can see a lot of them.

(There's a lot of Loops in the script but it's not lagging anything yet)

This is the part of the code that has what I said:
...
#Arguments for @DamageHull:
#x, y, range, damage amount (although I didn't use this variable when spawning cannon shots)
<-GemPresent if
<-px <-py PixelToCell 3 1 @DamageHull
else
<-px <-py PixelToCell 2 1 @DamageHull
endif

:DamageHull
  #Load up the arguments.
  ->amount ->r ->y0 ->x0
  "SHOULD HAVE DAMAGED IT" trace
  #Optimization: precalculate r^2.
  <-r dup mul ->r2
  #Consider a radius shaped box about the origin.
  <-r 1 add 0 <-r sub do
    <-r 1 add 0 <-r sub do
      #Cull squares in the box not in the circle.
      I dup mul j dup mul add <-r2 lte if
        #Translate to our site of action.
        I <-x0 add J <-y0 add dup2
            #DAMAGE!
#<-x0 <-y0 CellToPixel 0 0 0 0 CreateParticle

#<-x0 <-y0
->p6y ->p6x
-1 ->ship_hull
<-p6x <-p6y 0 1 0 1 0 0 GetNearestTarget ->ship_hull
<-ship_hull -1 neq if
"CannonShot" <-p6x <-p6y CreateUnit ->Cshot


#<-p6x <-p6y 20 0 GetNearestShipInRange ->Ship
#<-Cshot <-Ship InitCannonShot
#<-p5X <-p5Y 0 0 0 0 CreateParticle
endif
      endif
    Loop
  Loop
...


And this is the complete modules code for now:
# --HowitzerWeapon-- 12/18/2016 10:45:46 PM

once
Self "main" "Custom5" SetImage # OR Custom 7
Self "main" "Ships" SetImageLayer
Self "main" 1 SetImageOrder
Self "main" 2.25 2.25 SetImageScale
Self "barrel" "Custom6" SetImage
Self "barrel" "Ships" SetImageLayer
Self "barrel" 1 SetImageOrder
Self "barrel" -0.05 SetImagePositionZ
Self "barrel" 3.15 4.33 SetImageScale
Self "ShipModule.prpl" "Ship" GetScriptVar ->Ship
<-Ship.ShipIsEnemy ->IsEnemy
-1 ->target
self "RadiusDisplay.prpl" AddScriptToUnit
self "RadiusDisplay.prpl" "SCRIPT_NAME" "HowitzerWeapon.prpl" SetScriptVar
self "RadiusDisplay.prpl" "RADIUS_VARNAME" "range" SetScriptVar
self "RadiusDisplay.prpl" "IMAGE" "Custom6_256" SetScriptVar
#Black circle range
endonce

Self "ShipModule.prpl" "ShipAngle" GetScriptVar ->ShipAngle
Self "ShipModule.prpl" "delta" GetScriptVar ->Delta
Self "ShipModule.prpl" "exist" GetScriptVar ->Exist

<-Exist eq0 if
self "main" 0 0 0 0 SetImageColor
self "barrel" 0 0 0 0 SetImageColor
self "barrel" 0 0 -0.05 SetImagePosition
0 ->recoil
0 ->cooldown
<-target -1 neq if
<-mode "Particle" eq if
<-target "SNIPER_P" concat 0 ->!*
else
<-target "SNIPER_U" concat 0 ->!*
endif
-1 ->target
endif
return
endif

self "main" <-ShipAngle SetImageRotation

IsPaused if
return
endif

<-Exist 1 eq if
self "main" 255 255 255 128 SetImageColor
self "barrel" 255 255 255 128 SetImageColor
self "barrel" <-ShipAngle SetImageRotation
<-ShipAngle ->BarrelAngle
else
self "main" 255 255 255 255 SetImageColor
self "barrel" 255 255 255 255 SetImageColor
<-Ship GetShipHasAmp ->GemPresent
<-GemPresent if
108 ->range
else
    <-IsEnemy if
124 ->range
else
92 ->range
endif
endif
<-BarrelAngle <-Delta add ->BarrelAngle
<-recoil if
<-recoil 1 sub ->recoil
endif
<-target -1 eq if
<-cooldown if
<-cooldown 1 sub ->cooldown
else
@findTarget
endif
else
CurrentPixelCoords ->y ->x
#<-DamageParticles 1 eq if
<-mode "Particle" eq if
<-target GetParticlePosition ->py ->px
else
<-target.UnitPixelCoordY ->py
<-target.UnitPixelCoordX ->px
endif
<-px <-py <-x <-y Distance <-range 4 mul gt if
<-mode "Particle" eq if
<-target "SNIPER_P" concat 0 ->!*
else
<-target "SNIPER_U" concat 0 ->!*
endif
-1 ->target
@findTarget
else
1 ->validate
#<-DamageParticles 1 eq if
<-mode "Particle" eq if
<-target.particleHealth 0 gte ->validate #was 3 =========================================
else
<-target.UnitIsDestroyed not ->validate
endif
<-validate eq0 if
<-mode "Particle" eq if
<-target "SNIPER_P" concat 0 ->!*
else
<-target "SNIPER_U" concat 0 ->!*
endif
-1 ->target
else
<-py <-y sub <-px <-x sub atan2 ->targetAngle
<-targetAngle <-BarrelAngle ShortestAngle ->dist
<-dist abs 0.08 lt if
<-targetAngle ->BarrelAngle
CurrentCoords GetLand eq0 if
0 ->energy_use
<-GemPresent if
15 ->energy_use
else
20 ->energy_use
endif
<-Ship GetShipEnergy <-energy_use gte <-IsEnemy or if
<-Ship GetShipEnergy <-energy_use sub ->energy
<-Ship <-energy SetShipEnergy
    <-GemPresent if
    40 ->cooldown
    12 ->recoil
else
    60 ->cooldown
    15 ->recoil
endif
"PRPLCORE" 0 0 CreateUnit ->beam
<-px ->beam.UnitPixelCoordX
<-py ->beam.UnitPixelCoordY
<-beam "BeamEffect.prpl" AddScriptToUnit
<-beam "BeamEffect.prpl" "Duration" 30 SetScriptVar
<-beam "main" "Custom1" SetImage
<-beam "main" <-x <-y <-px <-py Distance 12 div 0.9 SetImageScale
<-beam "main" <-targetAngle SetImageRotation
<-beam "main" "Ships" SetImageLayer
<-beam "main" 1 SetImageOrder
<-beam "BeamEffect.prpl" "R" 128 SetScriptVar  # ===============================
<-beam "BeamEffect.prpl" "G" 255 SetScriptVar  # ===============================
<-beam "BeamEffect.prpl" "B" 255 SetScriptVar  # ===============================
<-beam "main" 128 255 255 255 SetImageColor    # ===============================
<-beam "main" <-x <-px sub 2 div <-y <-py sub 2 div -0.025 SetImagePosition
#"Weapons19" PlaySound
"Weapons30" PlaySound
<-DamageParticles 1 eq if
    @Damage
else
    @Damage2
endif
-1 ->target
endif
endif
else
<-dist 0 gt if
    <-GemPresent if
    <-BarrelAngle 0.025 sub ->BarrelAngle
else
    <-BarrelAngle 0.015 sub ->BarrelAngle
endif
else
    <-GemPresent if
    <-BarrelAngle 0.025 add ->BarrelAngle
else
    <-BarrelAngle 0.015 add ->BarrelAngle
endif
endif
endif
endif
endif
endif
Self "barrel" <-BarrelAngle SetImageRotation
Self "barrel" <-BarrelAngle cos <-recoil mul -0.5 mul <-BarrelAngle sin <-recoil mul -0.5 mul -0.05 SetImagePosition
endif

:findTarget
CurrentPixelCoords ->y ->x
-1 ->target
<-range 2 div ->range_2
#x, y, range, bool for enemy, bool for finding untargeted particles, exclude normal, exclude virtual, only enemy ship
CurrentCoords <-range_2 1 0 1 0 0 GetNearestTarget ->target


<-target -1 eq if
    #"TARGETED PARTICLE!" trace
CurrentCoords <-range 0 <-IsEnemy not GetParticlesInRange ->particles
0 ->most #was 3 =================================================================================
<-range 4 mul ->nearest
<-particles GetListCount 0 do
<-particles[I] ->p
        #<-p GetParticlePosition ->py ->px
<-p GetParticlePosition PixelToCell 9 0 <-IsEnemy not GetParticlesInRange ->particles3
<-particles3 GetListCount ->particles_on_area
<-particles_on_area <-most gt if
    <-p GetParticlePosition <-x <-y Distance ->nearest
<-particles_on_area ->most
<-p ->target
else
    <-particles_on_area <-most eq if
    <-p GetParticlePosition <-x <-y Distance ->Distance
<-dist <-nearest lt if
    <-dist ->nearest
<-particles_on_area ->most
<-p ->target
endif
endif
endif
loop

<-target -1 neq if
1 ->DamageParticles
0 ->DamageShips
endif
else
    #"DIDNT TARGET PARTICLE!" trace
    0 ->DamageParticles
1 ->DamaheShips
endif

#Damage (max) = 10;
#Damage (min) = 0;
#Damage Range = 14;
#Full-Damage range = 4;

:Damage
#<-px <-py
<-px <-py PixelToCell 18 0 <-IsEnemy not GetParticlesInRange ->particles2
#<-range 4 mul ->nearest
<-particles2 GetListCount 0 do
<-particles2[I] ->p2
<-p2 GetAllConnectedBonds 0 do ### ====================
DestroyBond                ### ====================
loop                           ### ====================
<-p2 GetParticlePosition <-px <-py Distance ->dist
<-dist 8 lte if
    <-p2.ParticleHealth 10 gt if
    <-p2.ParticleHealth 10 sub ->p2.ParticleHealth
    else
<-p2 0 DestroyParticle
endif
else
<-dist 18 lte if
    #8 range = 10 damage
    #18 range = 0 damage
    #y = ax+b
    #a = (0-10)/(18-8)
    #a = -1
    #b = 18 (as it's proportional, we can extract it directly)
    #y = -1x + 18 this is the function for Damage
    -1 <-dist mul 18 add ->damage
<-p2.ParticleHealth <-damage gt if
        <-p2.ParticleHealth <-damage sub ->p2.ParticleHealth
    else
    <-p2 0 DestroyParticle
endif
    endif
endif

        #HERE IT WILL PUSH PARTICLES *AWAY* FROM THE *SHIP*
<-p2 GetParticlePosition ->p2y ->p2x
<-p2y <-y sub <-p2x <-x sub atan2 ->targetAngle2
<-p2 <-targetAngle2 1.0 SetParticleImmediateForce
Loop

:Damage2
@Damage
<-GemPresent if
<-px <-py PixelToCell 3 1 @DamageHull
else
<-px <-py PixelToCell 2 1 @DamageHull
endif

:DamageHull
  #Load up the arguments.
  ->amount ->r ->y0 ->x0
  "SHOULD HAVE DAMAGED IT" trace
  #Optimization: precalculate r^2.
  <-r dup mul ->r2
  #Consider a radius shaped box about the origin.
  <-r 1 add 0 <-r sub do
    <-r 1 add 0 <-r sub do
      #Cull squares in the box not in the circle.
      I dup mul j dup mul add <-r2 lte if
        #Translate to our site of action.
        I <-x0 add J <-y0 add dup2
            #DAMAGE!
#<-x0 <-y0 CellToPixel 0 0 0 0 CreateParticle

#<-x0 <-y0
->p6y ->p6x
-1 ->ship_hull
<-p6x <-p6y 0 1 0 1 0 0 GetNearestTarget ->ship_hull
<-ship_hull -1 neq if
"CannonShot" <-p6x <-p6y CreateUnit ->Cshot


#<-p6x <-p6y 20 0 GetNearestShipInRange ->Ship
#<-Cshot <-Ship InitCannonShot
#<-p5X <-p5Y 0 0 0 0 CreateParticle
endif
      endif
    Loop
  Loop

:destroyed
<-target -1 neq if
<-mode "Particle" eq if
<-target "SNIPER_P" concat 0 ->!*
else
<-target "SNIPER_U" concat 0 ->!*
endif
-1 ->target
endif


Obs: The function I used for reading the circle range at @DamageHull can be found at http://knucklecracker.com/wiki/doku.php?id=crpl:docs:setdigitalis

Any other idea why this bug is happening?
And any other way to damage enemy ship hull without creating cannon shots, missiles, particles?

Thanks everyone for reading and helping me!
Title: Re: (More) PRPL questions
Post by: GoodMorning on December 20, 2016, 05:51:31 PM
Once this bug is resolved, you might want to make a new thread to keep things clear.

I think you will need to actually run InitCannonShot. It could be that a half-initialised one is breaking something important.

Also, I do not see any point to the dup2 command, except to inflate the stack?

Finally, the ship may not be aligned with the grid, so you will need a larger range than 0.

I haven't time yet to pick though the entire script, but if that helps...