An Idea I've had.
Picture the CW3 shield, basically a way to re-create that, so it would repulse Particles in a certain field around itself, unless either there was too many Particles or they were above a certain speed.
So, my challenge to you PRPL savvy users out there, can you program this? I'd assume it would involve some (functions/settings/attributes?) such as SetParticleImmidateForce and getparticlemass.
Or I may just be being stupid and its harder than I think :P
Find X particles in range.
Find each particle position, speed, and direction.
Reset each particle direction in to be perpendicular to previous direction.
Change speed?
Voila!
Note: Make X a decent size 20-50? so most particles will be pushed out of the region, but not all.
Note: Might require a list, maybe not.
I've found GetParticlePosition & GetParticleMotion... I'm not exactly sure what it means by 'Delta X' and 'Delta Y' for motion... probably to do with angles and such. As for how to set it perpendicular... all I can recall is graphs xD (Gradient of 2nd line is equal to negative one over gradient of 1st)
EDIT: on further examination, Delta refers to the speed. (as in the parameters for 'Max Speed' it says 'MAX_DELTA')
Yeah, it won't be completely easy. I don't have all the parameters in mind, but it's doable. Essentially will work like any other weapon targeting, but on mass. Also, you have to find a way to check that the same particle isn't affected twice in the same frame (hence the list).
If you want a CW3 shield, you can apply a force which is a multiple of the particle offset.
Give me a minute at a real keyboard, which will mean a delay.
Quote from: GoodMorning on November 13, 2016, 01:12:21 AM
If you want a CW3 shield, you can apply a force which is a multiple of the particle offset.
Give me a minute at a real keyboard, which will mean a delay.
Yay, we got someone who knows what he's doing interested! :o
Going off Sorrontis's idea (cause I've been working on it a bit) here's what I've got currently:
CurrentCoords 5 0 1 GetParticlesInRange ->particles
do (<-particles GetListCount 0)
<-particles[I] GetParticlePosition ->OPpos
<-particles[I] GetParticleMotion ->OPmot
<-particles[I] SetParticleMotion (neg(<-OPmot))
loop
This is not my natural programming style... I've been doing VB for a semester xD
But I'm good at it though. Top of my class.
Well, I haven't recently touched particle dynamics, only positioning, but here's an untested back-of-the-envelope modification:
CurrentCoords 5 0 1 GetParticlesInRange ->particles
do (<-particles GetListCount 0)
<-particles[I] ->PID #Particle ID
<-PID GetParticlePosition ->PY ->PX
CurrentPixelCoords <-PX <-PY Distance ->Dist
CurrentPixelX <-PX sub <-Dist div ->SFX #Multiply this Shield Force X by shield power.
CurrentPixelY <-PY sub <-Dist div ->SFY
<-PID GetParticleMotion ->PFY ->PFX
<-PFX <-SFX sub ->PFX <-PFY <-SFY sub ->PFY
<-PID <-PFX <-PFY SetParticleMotion
loop
Essentially, take the displacement, normalize, subtract from velocity. I may have lost a negative, one moment while I test...
Also, Sorrontis?
Quote from: Sorrontis on November 13, 2016, 01:13:48 AM
...who knows what he's doing...
To summarize my opinion of this: ??? (Really?)
On testing it, the result is that particles reach the center of the core, before being flung off the map, followed by 'empty stack' warnings in the debug screen.
As for the other one (That I was working on) it makes them bounce off XD Just bounce....
The trouble I've got now, is getting it to let particles through once there's more than 50 in range... (it now stops and occasionally bounces.)
you could try throwing a IF statement in it to prevent stack warnings
CurrentCoords 5 0 1 GetParticlesInRange ->particles
<-particles GetListCount 0 eq if
do (<-particles GetListCount 0)
<-particles[I] ->PID #Particle ID
<-PID GetParticlePosition ->PY ->PX
CurrentPixelCoords <-PX <-PY Distance ->Dist
CurrentPixelX <-PX sub <-Dist div ->SFX #Multiply this Shield Force X by shield power.
CurrentPixelY <-PY sub <-Dist div ->SFY
<-PID GetParticleMotion ->PFY ->PFX
<-PFX <-SFX sub ->PFX <-PFY <-SFY sub ->PFY
<-PID <-PFX <-PFY SetParticleMotion
loop
endif
don't know how to make it do more than 50 particulate though, probably just not processing all the particles in range in time
It doesn't have a limit, and that's the problem, although, the way I've got it running seems to be working well.
# --Repulse-- 11/13/2016 4:11:50 PM
once
self MaxHealth
endonce
if (IsPaused)
return
endif
CurrentCoords 30 0 1 GetParticlesInRange ->particles
do (<-particles 0)
<-particles[I] GetParticleMotion ->OPmotY ->OPmotX
<-particles[I] SetParticleMotion (<-OPmotY 0.8 mul) (<-OPmotX 0.8 mul)
loop
doesn't that only slow them down? or is that what you want?
It slows them to a virtual standstill, so for simulating a CW3 Shield, which holds creeper back, but it still encroaches on the field, it works quite well.
Currently I'm trying to create a unit that will act as the shield, will have health and be destroyed etc. And its being dodgy. I put it down to the fact I've got no clue what I'm doing :D
Spoiler
# --Create-- 11/13/2016 8:44:47 PM
once
"PRPLCORE" 93 28 CreateUnit ->Shield
<-Shield self "Repulse.prpl" AddScriptToUnit
<-Shield "main" "Custom0" SetImage
<-Shield "main" "Ships" SetImageLayer
<-Shield "main" 1 SetImageOrder
<-Shield self SetUnitIsEnemy (0)
<-Shield self SetUnitMaxHealth (20)
<-Shield self SetUnitHealth (10)
<-Shield self SetUnitParticlesDamage (1)
<-Shield self SetUnitReceivesPackets (1)
<-Shield self SetUnitHasEnergyBar (1)
<-Shield self SetUnitHasHealthBar (1)
<-Shield self SetUnitMaxEnergy (40)
<-Shield self SetUnitEnergyPackDelay (10)
endonce
Spoiler
# --Repulse-- 11/13/2016 4:11:50 PM
if (IsPaused)
return
endif
If (<-Shield GetUnitHealth 40 neq)
<-Shield GetUnitHealth 0.5 add <-Shield SetUnitHealth ->Shield
endif
if (<-Shield GetUnitEnergy 0 gt)
CurrentCoords 30 0 1 GetParticlesInRange ->particles
do (<-particles 0)
<-particles[I] GetParticleMotion ->OPmotY ->OPmotX
<-particles[I] SetParticleMotion (<-OPmotY 0.8 mul) (<-OPmotX 0.8 mul)
<-Shield GetUnitEnergy 1 sub <-Shield SetUnitEnergy ->Shield
loop
endif
Code in spoilers can render poorly on some devices, so you know.
Here's one that was working before my connection dropped for some hours.
# --CW3 Shield-- 11/13/2016 4:32:48 PM
CurrentCoords 30 0 1 GetParticlesInRange ->particles
do (<-particles GetListCount 0)
<-particles[I] ->PID #Particle ID
<-PID GetParticlePosition ->PY ->PX
#CurrentPixelCoords <-PX <-PY Distance ->Dist
#Self GetUnitPixelCoordX <-PX substance ->Dist
#Self GetUnitPixelCoordY <-PY sub <-Dist div ->SFYist div ->SFX #Multiply this Shield Force X by shield power.
Self GetUnitPixelCoordX <-PX sub ->SFX #Multiply this Shield Force X by shield power.
Self GetUnitPixelCoordY <-PY sub ->SFY
<-PID <-SFY <-SFX atan2 -0.008 SetParticleImmediateForce
#<-PFX <-SFX sub ->PFX <-PFY <-SFY sub ->PFY
#<-PID <-PFX <-PFY SetParticleMotion
loop
-ve 0.008 results in a gentle outward push. Probably you want it to be inversely proportional to the count in range.
Yes, the code is untidy.
I couldn't get it to work :(
The effect is rather weak with that version. The problem is calibration: too strong and particles bounce off. Too weak, and particles don't notice. The effect at that strength is subtle, not enough to keep particles off a mine, only to change their paths as they travel there.
I attach a map that demonstrates the version attached. Easier to tweak, can be added to a module or a static core. Note that the right-hand shield collapses suddenly when under enough strain, while the left one will gradually be pushed in on against mounting pressure. Also note that the left one needs a far smaller power value.
I hope this helps. It should be easy enough to add code to disable it (or you could drop the power to 0).
Sorrontis, this could be an interesting way to react to an assault: Once the particle count inside the shield drops (or on ship detection?), reverse the field. Destruction is served.
The same kind of code could be used for a box-field.
So giving the a neg value to SetParticleImmediateForce always applies the force directly opposite to where the particle is heading?
Umm...
I admit that I built this through a quick look at the wiki and guesswork. However...
I apply the force away from the Core, which on the test map is (usually) directly under the mine that the particle is targeting.
You can apply the force at any angle.
While the idea is sound, How useful will something like that really be if it pushing only 50 since it seems the maps that are being built are using 3K or more particles especially as you get closer to the emitters? At distance with 1.5k where you have spread particles are not usually a problem unless they are corralled by a field but it seems to me that at the 3k mark and above which seems to be the magic number for most cartographers will render a shield effectively useless.
Right now my biggest gripe with the game is the mass amount of particles the cartographers use combined with the ease with which lathes are destroyed and the constant back and forth of needed to build due to the lack of hot keys. I can see the shields being just another mechanic that is nice in theory but will not be worth using. Just like the maps that require constant building of suicide ships to blow particle away it is just not fun for those of us that don't have a worn out "p" key.
Cheers
The shield itself doesn't have to be particularly helpful, also, because its PRPL code, it can be modified so that based on the map the creator is making the strength of the field can vary, including the range for however he/she chooses to make their map. If anything this would make it so it would be an interesting enemy to deal with or a very helpful "space bubble" for lathes and what not.
The script I uploaded will work on all particles in range.
The point of a shield is to give a little breathing space, by effectively providing a controllable friendly field.
One mod this takes easily is mounting to a tiny ship which is otherwise unarmed, or a ship which channels particles into a ball, and then kills with lasers.
We won't know the usefulness of the script until we try.
Quote from: GoodMorning on November 13, 2016, 09:07:41 AM
The script I uploaded will work on all particles in range.
The point of a shield is to give a little breathing space, by effectively providing a controllable friendly field.
One mod this takes easily is mounting to a tiny ship which is otherwise unarmed, or a ship which channels particles into a ball, and then kills with lasers.
We won't know the usefulness of the script until we try.
This is very true, I just put up my thoughts for others to consider as they continue to improve and modify the game and make it as fun as possible for everyone and every level.
Cheers
Quote from: chwooly on November 13, 2016, 08:46:21 AM
While the idea is sound, How useful will something like that really be if it pushing only 50 since it seems the maps that are being built are using 3K or more particles especially as you get closer to the emitters? At distance with 1.5k where you have spread particles are not usually a problem unless they are corralled by a field but it seems to me that at the 3k mark and above which seems to be the magic number for most cartographers will render a shield effectively useless.
Right now my biggest gripe with the game is the mass amount of particles the cartographers use combined with the ease with which lathes are destroyed and the constant back and forth of needed to build due to the lack of hot keys. I can see the shields being just another mechanic that is nice in theory but will not be worth using. Just like the maps that require constant building of suicide ships to blow particle away it is just not fun for those of us that don't have a worn out "p" key.
Cheers
Yep, that is a problem in general. That is why V gave use the ability to change the health of particles, to encourage the use of lower particle counts. Easier on the CPUs after all.
Quote from: GoodMorning on November 13, 2016, 07:00:26 AM
[...]
Sorrontis, this could be an interesting way to react to an assault: Once the particle count inside the shield drops (or on ship detection?), reverse the field. Destruction is served.
[...]
Interesting thought ;)
Ok, part 1 is complete, I'm happy with the function of the shield, what I need to do now is, make it a Unit that requests energy, uses energy, has health, and is destroyed on contact with particles.
Also, for some reason this bit of code:
#If (<-Shield GetUnitHealth 40 neq)
# <-Shield GetUnitHealth 0.5 add <-Shield SetUnitHealth ->Shield
#endif
Causes Amp gem factories to self-destruct ???
That could be because you have calculated a health value, and then passed it as the UID, with the intended UID as the value.
I.e. Swapping the arguments for SetUnitHealth.
I don't even know why you are trying to ->Shield thereafter.
Have a look at planetfall's shield, then. Particle contact destroy is similar.
Also, which code are you using? I found an interesting effect using SetParticleMotion to small values, and then putting an Emitter some way into the field, which did some asymmetrical particle funnelling.
Would be amazing if you could constantly slightly adjust the field strength and range outwards and downwards, making a spiral. Lots of patterns possibly found from this
I had the same thought, try this. It can make a spiral.
# --CW3 Shield-- 11/13/2016 4:32:48 PM
$Range:50
$Power:1.0
$PerParticle:0
$TwistAngle:0.0
CurrentCoords <-Range 0 1 GetParticlesInRange ->Particles
<-Particles GetListCount ->ParticleCount
<-ParticleCount 0 do
<-Particles[I] ->PID #Particle ID
<-PID GetParticlePosition ->PY ->PX
Self GetUnitPixelCoordX <-PX sub ->SFX
Self GetUnitPixelCoordY <-PY sub ->SFY
<-SFY <-SFX atan2 <-TwistAngle add ->ForceAngle
<-Power neg ->Force
<-PerParticle if
<-Force <-ParticleCount div ->Force
endif
<-PID <-ForceAngle <-Force SetParticleImmediateForce
loop
TwistAngle will turn the force somewhat before applying it.
3.14: Reverse
+/- 1.57: Sideways
+/- 0.76: Spiral. (Tuning and attraction source required.)
This is the script for the shield itself.
# --Repulse-- 11/13/2016 4:11:50 PM
$Range:30
$Slowness:0.8
if (IsPaused)
return
endif
#If (<-Shield GetUnitHealth 40 neq)
# <-Shield GetUnitHealth 0.5 add <-Shield SetUnitHealth ->Shield
#endif
#CurrentCoords 30 0 1 GetParticleCountInRadius ->count
#if (<-Shield GetUnitEnergy 0 gt)
CurrentCoords <-Range 0 1 GetParticlesInRange ->particles
do (<-particles 0)
<-particles[I] GetParticleMotion ->OPmotY ->OPmotX
<-particles[I] SetParticleMotion (<-OPmotY <-Slowness mul) (<-OPmotX <-Slowness mul)
# <-Shield GetUnitEnergy 1 sub <-Shield SetUnitEnergy ->Shield
loop
#endif
The trouble I'm having is working out how to run it as a unit.
# --Create-- 11/13/2016 8:44:47 PM
once
"PRPLCORE" 93 28 CreateUnit ->Shield
<-Shield self "Repulse.prpl" AddScriptToUnit
<-Shield "main" "Custom0" SetImage
<-Shield "main" "Ships" SetImageLayer
<-Shield "main" 1 SetImageOrder
<-Shield self SetUnitIsEnemy (0)
<-Shield self SetUnitMaxHealth (20)
<-Shield self SetUnitHealth (10)
<-Shield self SetUnitParticlesDamage (1)
<-Shield self SetUnitReceivesPackets (1)
<-Shield self SetUnitHasEnergyBar (1)
<-Shield self SetUnitHasHealthBar (1)
<-Shield self SetUnitMaxEnergy (40)
<-Shield self SetUnitEnergyPackDelay (10)
endonce
Also, planetfalls shield?
planetfall built a shield using a set of fixed particles, in a ring.
I advise looking at Inception and planetfall's Exchange maps. Inception has some PRPL custom modules (and probably the shield unit), Exchange has the shield and some more custom modules. There's also a dedicated thread (http://knucklecracker.com/forums/index.php?topic=21624.msg149063#msg149063) for custom modules.
A module that interacts directly be detecting mouse clicks is harder, but can be done.
Also, does this do what you wish for power use?
#<-Shield GetUnitEnergy 1 sub <-Shield SetUnitEnergy ->Shield
<-Shield.UnitEnergy 1 sub ->Shield.UnitEnergy
Unfortunately, it doesn't work for power use. And I'm not quite planning on using it as a custom module yet, more like the cannons in story mode type units.
I'll take a closer look at some point. I'll try for the fixed form.
Edit:
Here we are, burning power nicely. Also:
Shuts down when empty
- Recharges, to make sure ther's enough power available
- Bursts power to make a tiny space
- Gradually opens out to full size, preventing repeat shutdown.
Internal reactor
- Can drain power (constant load)
- Can behave differently when shut down.
- Can be set (by mapmaker) not to request energy packets.
- Can work for free
- Can require a certain initial power level to boot up
- Field can be angled or inward
- Setting to be shutdown or not initially
- Option for whether to show the power bar (for hidden instances)
Yes, feature creep. It all works, but beware of lag if you use it to contain a large number of particles.
It's probably a good idea to make the field work less on high-health particles, but I will not add that now...
Too much XD
Thanks, but I'm looking for just a simple way to add power drain into the code I've already got :P
I can't really pinpoint how to do that however :/
Other than that, I think I can figure out how to get rid of it once its destroyed, and if there's any other problems I find, I can always return to ask :)
Also, on the topic of custom modules. Would it be better to wait for the upcoming support rather than try to use current methods?
-Edit-
I've actually found it, I think, so I'll be testing out power drain once more.
Yes, I overdid. Hopefully others will find a use for that, though.
For custom modules, it's up to you. The integrated support will result in tighter integration, so that we do not have to use the global store, for instance, but the template that planetfall has built is available now.
Good luck with your project, I'm interested to see the finished product.
Currently, I've pretty much finished. Just a mixture of tweaking, and of course, working out how to manage it being destroyed xP
I was going to try and go overboard myself, adding the ability to turn it on & off for rebuilding during runtime... but a UI is beyond my level of... everything XD
The final inception map has code related to when a mouse hovers over a specific coord, or in the case of the map, the PRPL Core itself, and someone did make a particle editing map that involved clicking on cores to adjust settings, you could look at those if you wanted to user-interactive UI with your shield, click on and off.
How hard would it be to write a bit of code that only affected, say, every other particle, or a random particle?
Using
mod 2 eq if
and
<-Particles[0 <-Particles GetListCount RandInt]
I have no idea what this will do... but that's the point?
-edit-
Well, the 'mod 2 eq if' doesn't seem to work :/
Nor does '2 mod eq if'
# --Randomiser-- 11/15/2016 2:23:28 PM
if (IsPaused)
return
endif
once
RandInt(2 20) ->VelX
RandInt(3 19) ->VelY
RandInt(2 3) ->Strength
SetTimer0 (50)
endonce
if (GetTimer0 eq0)
mod 2 eq if
neg(RandInt(2 20)) ->VelX
neg(RandInt(3 19)) ->VelY
endif
RandInt(2 20) ->VelX
RandInt(3 19) ->VelY
RandInt(2 3) ->Strength
SetTimer0 (50)
endif
CurrentCoords 2 0 1 GetParticlesInRange ->particles
<-particles GetListCount 0 do
mod 2 eq if
<-particles[I] GetParticleHealth ->Health
<-particles[I] <-Health <-Strength mul SetParticleHealth
endif
<-particles[0 <-particles GetListCount RandInt] ->RandParticle
mod 2 eq if
<-particles[<-RandParticle] GetParticleMotion ->OPmotY ->OPmotX
<-particles[<-RandParticle] SetParticleMotion (<-OPmotY <-VelY mul) (<-OPmotX <-VelX mul)
else
<-particles[<-RandParticle] SetParticleMotion (<-VelY) (<-VelX)
endif
loop
I made a typo, but this is what I had in mind. (Adapted onto the above).
# --Randomiser-- 11/15/2016 2:23:28 PM
if (IsPaused)
return
endif
once
RandInt(2 20) ->VelX
RandInt(3 19) ->VelY
RandInt(2 3) ->Strength
SetTimer0 (50)
endonce
if (GetTimer0 eq0)
neg(RandInt(2 20)) ->VelX
neg(RandInt(3 19)) ->VelY
endif
RandInt(2 20) ->VelX
RandInt(3 19) ->VelY
RandInt(2 3) ->Strength
SetTimer0 (50)
endif
CurrentCoords 2 0 1 GetParticlesInRange ->particles
<-particles GetListCount 0 do
I 2 mod eq0 if #Affecting every second particle
<-particles[I] GetParticleHealth ->Health
<-particles[I] <-Health <-Strength mul SetParticleHealth
endif
loop
<-particles[0 <-particles GetListCount RandInt] ->RandParticle #Extract a random particle UID from the list.
<-RandParticle GetParticleMotion ->OPmotY ->OPmotX
0 2 RandInt if #Flip a notional coin
<-RandParticle SetParticleMotion (<-OPmotY <-VelY mul) (<-OPmotX <-VelX mul)
else
<-particles[<-RandParticle] SetParticleMotion (<-VelY) (<-VelX)
endif
I still don't get how the mod would work, and it seems to effect all of them. Mod just pushes the remainder of I divided by 2.
Mod does. If there is no remainder, it pushes 0. This will happen on every other execution. I.e. every second time.
If you wish for a given particle to be affected at all (or not) over multiple frames, then you will have more difficulty. This takes every second particle in range during a single frame, and ignores such things as past frames.
Replacing I with <-particles[ I ] will use the UID, which will result in the same frames being affected from frame to frame, but may have unexpected effects resulting from correlations in particle creation order.
Edit: There's an I in square brackets after the <-particles, which I had forgotten would be interpreted by the forum software as italics.
hmm.... Well, It'll be interesting then, because otherwise I'll have exponential health particles
There are tricks to use for stopping the exponential runaway. The least expensive will sometimes cause the script to heal a damaged particle as a side effect: Change health iff it will not go over some limit.
However, health boosting will be problematic to balance at the best of times.
I've moved on from that now. The problem I'm dealing with is the InitMissile command... I'm making a PRPL Missile tower that will launch missiles at all ships in range, but will scale how many missiles per ship to launch depending on the amount of ships in range.
Here's what I've got so far... I'm going PRPL crazy :D
# --MissileTower-- 11/15/2016 9:10:31 PM
$Health:40
$FireRate:75 #in frames E.G. 30 = 1 second, 60 = 2 etc.
$Range:30
$Critical:1 #y/n
$CriticalAmount:10 #of health
$CriticalMul:2
$IsMissionGoal:1
$LatheDamage:0.3
once
Self ->Self
Self SetUnitMaxHealth (<-Health)
Self SetUnitLatheTargets(1)
Self SetUnitMissionGoal(<-IsMissionGoal)
Self SetUnitLatheDamageAmt(<-LatheDamage)
SetTimer0(<-FireRate)
endonce
if(GetTimer0 eq0)
CurrentCoords <-Range 0 GetAllShipsInRange ->Ships
<-Ships GetListCount 0 do
if(<-Ships GetListCount 2 lte)
4 0 do
I <-Ships[K] 1 InitMissile
loop
endif
if(<-Ships GetListCount 2 gt <-Ships GetListCount 4 lte and)
3 0 do
I <-Ships[K] 1 InitMissile
loop
endif
if(<-Ships GetListCount 4 gt)
2 0 do
I <-Ships[K] 1 InitMissile
loop
endif
loop
<-Critical 1 eq <-Self.UnitHealth <-CriticalAmount lte and if
<-FireRate <-CriticalMul mul SetTimer0
else
SetTimer0 (<-FireRate)
endif
If you're not dealing with shields anymore, break off to a new topic.
In case anyone reads this far is search of a general-purpose circular field script, I attach the latest (final) version. Not that if particles go after ships just inside shield range, then power drain will rise, and also that lag can ensure of there are very large numbers of particles inside the field.
The range image is a slightly modified shield umbrella from the Sleeper template, and changes colour (green-yellow-red) with power level. Set UmbrellaGraphicSlot to NONE if you don't want it to show.
Higher-health particles will drain power to move, but will be moved just as much.
Disclaimer: No guarantees that if a shield is swamped in particles and has a small battery size that it will be able to restart after a collapse. The battery may be drained entirely by the initial push to try to get some space to put the shield up in.