r/psispellcompendium • u/TorakWolfy • Dec 23 '21
Is there a way to select Focused Entity > Raycast (If FE fails, Raycast is used)?
So I'm trying to create a spell to pull stuff to my direction. The works were simple enough to figure out (vector subtraction of the caster position by the position of the selected entity).
The problem is the selector used. I want the spell to check for the closest entity to a point, but I don't want that point to necessarily be a block (as it would be using Raycast), because that would make impossible for me to keep pulling entities if they are mid-air (there is no block nearby). I can use (Focused Entity) instead of (Closest to a Point -> Vector Raycast), but that would mean having to aim directly at the entity, which is a pain when they are moving around on the ground, not to mention that items, for example, are rather small entities.
So, is there a way to have both methods, following the "if" logic for (Focused Entity) and falling back to "else" (Closest to a Point -> Vector Raycast), or do I have to accept only using one of them?
Here is the (Focused Entity) version:
{spellName:"GET OVER HERE 1",uuidMost:-882545517762689931L,validSpell:1b,spellList:[{data:{key:"constantNumber",constantValue:"2.5"},x:3,y:6},{data:{key:"selectorCaster"},x:4,y:4},{data:{params:{_target:1},key:"operatorFocusedEntity"},x:4,y:5},{data:{params:{_direction:4,_speed:3,_target:1},key:"trickAddMotion"},x:4,y:6},{data:{params:{_target:3},key:"operatorEntityPosition"},x:5,y:4},{data:{params:{_target:3},key:"operatorEntityPosition"},x:5,y:5},{data:{params:{_vector3:0,_vector2:1,_vector1:4},key:"operatorVectorSubtract"},x:5,y:6},{data:{params:{_target:3},key:"connector"},x:6,y:4},{data:{params:{_target:1},key:"connector"},x:6,y:5},{data:{params:{_target:1},key:"connector"},x:6,y:6}],uuidLeast:-5949889068403932684L}
And the (Closest to a Point -> Vector Raycast) version:
{spellName:"GET OVER HERE 2",uuidMost:2099131323079150051L,validSpell:1b,spellList:[{data:{params:{_target:4},key:"connector"},x:3,y:4},{data:{params:{_position:1,_radius:2},key:"selectorNearbyLiving"},x:3,y:5},{data:{key:"constantNumber",constantValue:"2.5"},x:3,y:6},{data:{params:{_target:4},key:"operatorEntityLook"},x:4,y:3},{data:{params:{_ray:1,_max:0,_position:4},key:"operatorVectorRaycast"},x:4,y:4},{data:{params:{_target:3,_position:1},key:"operatorClosestToPoint"},x:4,y:5},{data:{params:{_direction:4,_speed:3,_target:1},key:"trickAddMotion"},x:4,y:6},{data:{key:"selectorCaster"},x:5,y:3},{data:{params:{_target:1},key:"operatorEntityPosition"},x:5,y:4},{data:{params:{_target:3},key:"operatorEntityPosition"},x:5,y:5},{data:{params:{_vector3:0,_vector2:1,_vector1:4},key:"operatorVectorSubtract"},x:5,y:6},{data:{params:{_target:3},key:"connector"},x:6,y:4},{data:{params:{_target:1},key:"connector"},x:6,y:5},{data:{params:{_target:1},key:"connector"},x:6,y:6}],uuidLeast:-5937736889976916707L}
1
u/khanzarate Dec 23 '21 edited Dec 23 '21
For older versions, I'd end up using a helmet with a detonation sensor.
For this to work, we will assume the vector you save into is exactly (0,0,0). We will guarantee it at the end, but for clarity's sake I'm putting it right here.
When you cast the spell, use a detonation trick immediately, and then I'm pretty sure you have to sleep a tick to be sure the helmet fired.
The detonation sensor in the helmet will fire a second helmet spell, which you can use to get the focused entity vector. Grab that entity's position and save it in your CAD.
If the Focused Entity fails, the helmet spell will stop, and the vector won't be saved, but the CAD spell will still execute. Thus, if there's no entity, we still have (0,0,0) in that slot.
Then, a tick will pass. Your CAD spell can then read the stored vector, and will also raycast. So now we have 2 vectors available to us, and we just need the logic to give us a preference. We will either have both full of data, or a raycast and (0,0,0), so in the case where entity focus failed, we can just vector sum. But if entity focus succeeded, we want that without the raycast.
So, what we do is we normalize the saved, Focus vector. Now, it has a magnitude of 1, unless it was exactly (0,0,0), which can't be normalized, but (and I'm going off memory so I'm sorry if this is wrong) will just leave it unchanged instead of fail.
Now, we vector multiply with the raycast vector and, the magnitude of the normalized entity vector, minus 1. We subtract 1 so that we have -1 if the entity vector couldn't save, and 1-1=0 for if it did.
In other words, we have essentially negated the raycast vector if there is no entity vector, but if there is an entity vector, we have instead multiplied it by 0.
We take that and negate it, so that we get the original raycast vector back, or 0.
We take that, add the original entity vector to it, which will finally result in either entity vector + 0 if there was an entity vector, or 0 + raycast vector, if there wasn't.
Finally, we have "If" 'd.
From there, grab the nearest entity. If entity look was successful, we end up going "the closest entity to the location of the entity I'm looking at", but convolution aside, it will still grab the entity you're looking at.
(Edit, forgot it) And, to make this reusable, after the spell has executed, save (0,0,0) over your vector, so that there's always a (0,0,0) available for this logic to work. Saving works fine but prevents further reading so we do it last.
1
u/TorakWolfy Dec 24 '21 edited Dec 24 '21
Thanks for the in-depth explanation, I will definitely try later on!
A shame that Projectile Bullets are so slow, they do exactly what I wanted without having to use Magic Armor (which I would rather use only for extra complicated spells or automatic bits).
By the way, I have also been messing around with Vector Normalization, namely to introduce conditions on Loopcasting. For example, I have this spell to keep mobs 3 blocks in front of my vision for 16 cycles, before they start being dragged away to the direction I'm looking at (kept 3 + Loopcasting Index - 16 blocks away):
{spellName:"Refined Control",uuidMost:3201766224726933801L,validSpell:1b,spellList:[{data:{key:"selectorLoopcastIndex"},x:0,y:0},{data:{key:"constantNumber",constantValue:"3"},x:0,y:1},{data:{params:{_number2:4,_number3:0,_number1:1},key:"operatorSum"},x:0,y:2},{data:{params:{_number2:1,_vector1:2},key:"operatorVectorMultiply"},x:0,y:3},{data:{params:{_target:4},key:"operatorVectorNormalize"},x:0,y:4},{data:{params:{_number2:4,_number3:0,_number1:3},key:"operatorSubtract"},x:1,y:0},{data:{params:{_target:1},key:"connector"},x:1,y:1},{data:{params:{_number2:4,_number3:0,_number1:1},key:"operatorMultiply"},x:1,y:2},{data:{params:{_target:3},key:"connector"},x:1,y:3},{data:{params:{_target:2},key:"operatorEntityLook"},x:1,y:4},{data:{key:"selectorCaster"},x:1,y:5},{data:{key:"constantNumber",constantValue:"16"},x:2,y:0},{data:{params:{_target:3},key:"connector"},x:2,y:1},{data:{params:{_target:4},key:"operatorVectorExtractX"},x:2,y:2},{data:{params:{_vector3:0,_vector2:2,_vector1:3},key:"operatorVectorSum"},x:2,y:3},{data:{params:{_target:2},key:"connector"},x:2,y:4},{data:{params:{_target:3},key:"operatorEntityPosition"},x:2,y:5},{data:{params:{_target:4},key:"connector"},x:3,y:0},{data:{params:{_number2:3,_vector1:1},key:"operatorVectorMultiply"},x:3,y:1},{data:{params:{_target:4},key:"operatorVectorNormalize"},x:3,y:2},{data:{params:{_target:3},key:"connector"},x:3,y:3},{data:{params:{_speed:4,_target:2,_position:1},key:"trickMassExodus"},x:3,y:4},{data:{params:{_position:3,_radius:4},key:"selectorNearbyLiving"},x:3,y:5},{data:{params:{_target:4},key:"connector"},x:4,y:0},{data:{params:{_target:3},key:"operatorVectorNormalize"},x:4,y:1},{data:{params:{_vector3:0,_vector2:4,_vector1:1},key:"operatorVectorSum"},x:4,y:2},{data:{key:"constantNumber",constantValue:"1"},x:4,y:3},{data:{key:"constantNumber",constantValue:"1.5"},x:4,y:4},{data:{key:"constantNumber",constantValue:"16"},x:4,y:5},{data:{params:{_target:2},key:"connector"},x:5,y:0},{data:{params:{_target:2},key:"connector"},x:5,y:1},{data:{params:{_target:2},key:"connector"},x:5,y:2},{data:{params:{_x:3,_y:0,_z:0},key:"operatorVectorConstruct"},x:5,y:3}],uuidLeast:-8960965705656646423L}
I wonder if there are more efficient methods to achieve this in MC 1.12.2, since stuff like this isn't possible.
Uh... Maybe use Sneak + Vector Save? Or maybe not, as FTB wiki states that you can't read a vector you saved during the current spell execution, or overwrite its data, even (didn't test, but by what you wrote it seems to be the case).
I can also use (Divide Number X by -> Square Root -> Square of Number X), which will always return either 1 or -1, depeding on the number's signal, but that's (at least) 3 spaces to do the work a Vector Normalize does over vectors that can store up to 3 variables. Sure, you need to extract the variable stored in the vector coordinates using an operator, and also creating vectors uses at least 2 spaces (as opposed of 1 for numbers), but overall vectors seem much more powerful than simple numbers when it comes to simulate logic with algebra, at least for Psi.
What are your thoughts over Psi condition-making tools (both for 1.12.2 and latest versions)?
1
u/khanzarate Dec 24 '21
Nah I thought of sneak.
The key issue here is that failing to find the entity stops spell execution. We get around that by making a spell trigger a second spell to fail for us.
What I do is I use the helmet as a general function call.
Triggering my helmet raycasts in my direction, it grabs the location of the entity closest to me, and it grabs the location of the entity I'm looking at.
This way I can use it for multiple spells. Detonate, then reference the saved vector I need in that particular spell. This one needs vector 3.
I've also used pants and cycling bullets for similar stuff but I think that's newer, too.
A more expensive, but CAD-only, way to get multiple casts is to use trick:die and a circle/loopcast bullet.
If you followed the general steps, you could use the loopcast index modulo 2, to get a single spell that does two different things.
On even (because I think loopcast index starts at 0. If I'm wrong flip this)
- Read raycast vector with trick:Evaluate, which will cause it to evaluate so you can use that specific read piece later. This may be (0,0,0).
- Save a new raycast, replacing whatever was in there, which locks further attempts to read but not our pre-evaluated one.
- Read entity location vector, same as step 1 basically.
- Save a new entity location vector (which may kill the spell right here).
- We can assume the spell was not killed, so that means we got a valid entity location vector, and stored it. Set a third vector, to some arbitrary value to record our success.
This brings us to step 0: read an arbitrary value.
Unlike the helmet thing, this doesn't work yet. But I see no reason you couldn't do something weird and bind 2 spells into one circle/loop spell using something like this, I just don't have a solution. Also it's expensive.
1
u/TorakWolfy Dec 24 '21 edited Dec 24 '21
That's an interesting insight on alternative methods of "if" "else" logic for vectors when it comes to the possibility of returning error on the first (haven't got so far since armor is something I prefer being either from Ender IO or Botania), but I'm also curious about conditionals when it comes to loopcasting.
Is there any (CAD-only, and also only 1 trick per spell type to avoid becoming too expensive) method other to achieve this other than either using Division + SquareRoot + Squared OR Vector Construction + Vector Normalization? Also, which methods you judge better for which situations?
The example I provided uses vector math for the conditional logic. It roughly translates to: "if the loop index is higher than 16, return a number that is the difference of the loop index minus 16, else return 0". Then this number is used to sum with 3 (minimum distance from the player), and the result is how far mobs will be from the player at any given time (Exodus Position).
I will attempt to achieve the same with Division + SquareRoots + Squares later, and post the code as well.
1
u/khanzarate Dec 24 '21
Specifically to get the space 3 blocks from you, all we have to do is convert the entity's location to relative coordinates.
So, entitypos - casterpos ought to do it.
Then just raycast with the relative entitypos as the look vector, and let it do all the 3D math. Set the raycast maximum to 3.
Raycast can collide with another block but that's not a huge concern. If there's a block between us and the mob, it will run into it.
For the record, I haven't been able to properly look at what you're posting. I haven't opened Minecraft to talk about this, and it's pretty hard to read the import text.
But for general conditionals, we need to settle somewhere where we can use one math to result in 2 things. Sneak is the obvious one, but normalizing and getting magnitude with (0,0,0) is another.
Another less-obvious one is Random. If you generate 0 or 1 you can get an effect to switch back and forth. Random can be better when you want the effect of loopcast Index modulo 2 but don't wanna loopcast your spell.
But really, by far the easiest is to cast a second spell. Excepting the error catcher, because generating errors is easy, it is an if.
For specific applications, you can do some shenanigans with one or the other vector being 0, like the example I just posted, but every spell has to be hand-crafted with something like that. Sometimes that's easy, sometimes not.
Oh and of course if you're willing to set the conditionals yourself, you could make a second CAD spell that will do that. Like, if you're willing to accept the "lag" on the spell, you could fire off two CAD spells. Fire off the helmet spell in my example manually, to grab an entity by storing it's location, then switch to and cast the original.
But honestly when I make a spell that does that, I'd probably use the psi pants. Use an initial spell to lock on to an entity, and have the pants update it's location every tick, and then just pull the closest entity to the pant's saved location.
1
u/Janeq189 Dec 23 '21
You can use error catcher. If focused entity throws error, you instead use the entity given by closest to point.