After messing around a bunch, I think the movement would make the most sense if a monster with no model gets spawned in the most possible "flee from party" brain that it can muster, with animation speed high and cooldown speed low:
function spawnUnturningFleeingMonster()
spawn("air_elemental", party.level, party.x, party.y, party.facing, party.elevation, "fleeingAirElemental")
fleeingAirElemental:getComponent("turn"):disable()
fleeingAirElemental:getComponent("basicAttack"):disable()
fleeingAirElemental:getComponent("sound"):disable()
fleeingAirElemental:getComponent("move"):setSound("nulltiny")
fleeingAirElemental:getComponent("move"):setCooldown(0.001)
fleeingAirElemental:getComponent("move"):setAnimationSpeed(400)
fleeingAirElemental:getComponent("brain"):setSight(0)
fleeingAirElemental:getComponent("brain"):startFleeing(600)
fleeingAirElemental:getComponent("brain"):setMorale(0)
-- WIP delayedCall(fleeingAirElemental, 10, destroy())
end
nulltiny is a custom definition I made to inject a null sound, you can remove this line if you test it.
something like this, then from there it can get the world position before being destroyed, subtract that world position from the party's world position and move to the new position over a series of setWorldPosition pings. This ensures that the movement is possible because the monster collides (even at this insane speed). Then, all we need to do is find which way the player is facing and apply the setWorldPosition in that direction, either adding x OR adding y OR subtracting x OR subtracting y which is really simple.
My current problem(s):
1) I don't know how to just make a spell or device or screen button call the function. Right now I have it hooked up to a lever because I wanted to test if it was possible to make a monster flee in a straight path like this at all.
2) Speaking of which, this air elemental brain does funny things sometimes. I noticed if I spawned an x+1 with slower animspeed and cooldown it would sometimes hitch, likely from it's brain attempting turns or some other actions even though I'm trying to get it to flee as much as possible. I'm not sure what the actual best approach here is, but giving it these high speeds and spawning it at my location without the ability to turn DOES appear to make it beeline away from me pretty quick which is nice - like before it can even think it's already further than I would want the "jump" to be.
I also got a setWorldPosition movement script working already, it basically defines a 'frames' variable, divides the distance of your tiles jump by this frames amount and then moves that amount. setPosition wont work for a smooth animation like this because we can't feed it decimal values, so the actual jump animation if it's applied to the party must be done via setWorldPosition, which doesn't break anything if you never go out of bounds which shouldn't happen using a fleeing monster to get a final position thanks to monsters colliding with the bounds anyways (though it is possible to break if we just move based on facing, which also has problems with phasing through walls and stuff - not that this method doesn't have that problem like for example if a monster moves in your path AFTER the check if things are there is done, but the idea is that it should be fast firing anyways so this is whatever).
The actual getPosition grid is like:
0,0 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 31,0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
0,31 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 31,31
where the world position grid is:
1.5,(z),94.5 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 94.5,(z),94.5
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1.5,(z),1.5 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 94.5,(z),1.5
I've basically abandoned the setPosition command for moving things though, because as I said we can't input decimals so if you want the party to appear moving in a smooth way using worldPosition is honestly best.
Something to note here is that there's a 1.5 offset, and a 3 unit multiple difference if you were to ever convert worldPosition to position or vice versa.
So for example for my test on an object I can define 2 squares of movement (runAmount), and then the actual runDist is runAmount*3 (basically always, we know it's 3 so is there a point to define a new grid conversion variable?). Then the runLength (amount of distance to move each time the function is pinged) is your runDist/frames (in my case 6/60) and then I have a timer activate and ping the function until it hits 60 where it resets 1) a counter made just to let it know it's active so it can't be retriggered, 2) the counter that is counting to 60, 3) the timer gets stopped and deactivated.
Using that I was able to move a teleporter a distance of 2 in-game units using worldPosition !!!
![Very Happy :D](./images/smilies/icon_e_biggrin.gif)
which was pretty exciting not gonna lie. Though, I'm not a great programmer so maybe someone else can do some more epic stuff. At the very least it gives me a way to make a linear animation for walls without adding an animation, though an animation is likely a better solution and I was mostly making this to figure out the jump stuff. Not sure what I'm expecting here I just thought I'd update where I'm at with this and maybe see if some script wizard can run with it a bit more.
So the code for the moving teleporter is
Setup:
runTeleporter - teleporter placed bottom right of the map, facing doesn't matter really. You could technically make any object I guess
theRunCounter - a counter that just makes sure the script cant be reinitiated while running. 0.
counterForSpacing - this ticks up to the 'frames' value by incrementing each time the script is called. 0.
timerPulses - a timer that is set to 0.016667. This should really be set to 1/frames in the script but I had set it to a specific value just in case, because as I said I'm bad at programming so I was removing as much complication as possible. This timer starts with the timer disabled, everything unchecked,
connected (onActivate) to the script to call the main function (teleporterRun()).
Then a lever that activates incrementToBreak() and startTheTimer(). Increment to break simply makes it so if you're flipping the lever after nothing can happen until it resets, and start the timer activates the timer if that counter is 1 (as in, if its infinity-0 or 2-inifinity it does nothing, so doing anything until the reset doesn't retrigger the timer under any circumstances).
function incrementToBreak()
local counter3ID = findEntity("theRunCounter")
counter3ID:getComponent("counter"):increment()
end
function startTheTimer()
local counter3ID = findEntity("theRunCounter")
local timer5ID = findEntity("timerPulses")
if counter3ID:getComponent("counter"):getValue() == 1 then
timer5ID:getComponent("timer"):enable()
timer5ID:getComponent("timer"):start()
end
end
Code: Select all
function teleporterRun()
local counter3ID = findEntity("theRunCounter")
local counter4ID = findEntity("counterForSpacing")
local timer5ID = findEntity("timerPulses")
local runCeiling = 94.5
local runOffset = 1.5
-- this variable could be used if ever using setPosition(), however the idea is to not use setPos due to non decimal.
local addToNonworldPos = 1
-- the tile length you want to move in a 'non world amount' sense
local runAmount = 2
-- 3 is the distance of a unit on the grid, use runAmount to change movement distance
local runDist = runAmount*3
local frames = 60
local runLength = runDist/frames
local floorHeight1 = 94.5
local levelNumberFindWorld = 1
if counter3ID:getComponent("counter"):getValue() >= 1 then
if counter4ID:getComponent("counter"):getValue() <= 60 then
counter4ID:getComponent("counter"):increment()
counter3ID:getComponent("counter"):setValue(1)
print("Started. CounterForSpacing=",counter4ID:getComponent("counter"):getValue(),"/60. TheRunCounter=1")
if counter4ID:getComponent("counter"):getValue() == 60 then
print ("Frame 60 hit")
local counter3IDinLoop = findEntity("theRunCounter")
local counter4IDinLoop = findEntity("counterForSpacing")
counter3IDinLoop:getComponent("counter"):setValue(0)
timer5ID:getComponent("timer"):stop()
timer5ID:getComponent("timer"):disable()
counter4IDinLoop:getComponent("counter"):reset()
print ("Frame 60 hit. theRunCounter = 0, timer stopped. counterForSpacing reset.")
end
print ("In the main push")
local objTele = findEntity("runTeleporter")
local originalworldataX, originalworldataZ, originalworldataY, originalworldataElev, originalworldataLevel = unpack(objTele:getWorldPosition())
-- ORGANIZED FOR setPosition INPUT, XZY(0)(1)
local outdataX = 0+originalworldataX
local outdataZ = 0+originalworldataZ
local outdataY = 0+originalworldataY+runLength
local outdataElev = 0+originalworldataElev
local posChangeRapid = vec(outdataX, outdataZ, outdataY, outdataElev, levelNumberFindWorld)
objTele:setWorldPosition(posChangeRapid)
end
end
end
and then yeah if you wanna mess with the monster one:
Code: Select all
function spawnUnturningFleeingMonster()
spawn("air_elemental", party.level, party.x, party.y, party.facing, party.elevation, "fleeingAirElemental")
fleeingAirElemental:getComponent("turn"):disable()
fleeingAirElemental:getComponent("basicAttack"):disable()
fleeingAirElemental:getComponent("sound"):disable()
-- fleeingAirElemental:getComponent("move"):setSound("nulltiny")
fleeingAirElemental:getComponent("move"):setCooldown(0.001)
fleeingAirElemental:getComponent("move"):setAnimationSpeed(400)
fleeingAirElemental:getComponent("brain"):setSight(0)
fleeingAirElemental:getComponent("brain"):startFleeing(600)
fleeingAirElemental:getComponent("brain"):setMorale(0)
end
It can be hooked to any button really, I just used a lever because my dumb self is trigger happy so this prevents me from double firing which crashes it because I don't know how to work with IDs properly yet.