Author Topic: Using the avoid script  (Read 25288 times)

0 Members and 1 Guest are viewing this topic.

Offline Collector

Re: Using the avoid script
« Reply #15 on: January 20, 2013, 05:11:50 PM »
What about getting the goat's location and if it has not changed by at least X amount after a given time, set isStopped to true. It would be interesting to see how Sierra did it in KQ1SCI.
KQII Remake Pic

Offline gumby

Re: Using the avoid script
« Reply #16 on: January 20, 2013, 06:23:30 PM »
I was thinking about how to address the simpler approach with the MoveTo motion.  The seemingly difficult scenario that comes to mind is a winding path down a mountain, or the castle path in BC.  You'd set the actor at the beginning of the path and the destination at the end of it. I'm thinking the actor would look like a pinball in a chute, bouncing back and forth all the way down. 

Seems like we'd have to take the angle of incident of the control line w/regard to the motion of the actor into account when determining where to 're-aim' the actor before the next movement.  E.g. if the motion of the actor was perpendicular to the control line when it was hit, you'd probably want to change the angle before the next movement quite drastically, perhaps 90 degrees.  However if the actor hits the control line at a shallow angle, where the actor is nearly parallel to the control line you'd want to change the angle less drastically, maybe just a few degrees.

It'll be interesting to see what you come up with.
In the Great Underground Empire (Zork port in development)
Winter Break 2012 Rope Prop Competition

Offline Cloudee1

Re: Using the avoid script
« Reply #17 on: January 20, 2013, 07:51:34 PM »
Unfortunately, I am already stuck and I'm not real sure why.

I started from scratch, with an actor and an ego. I wrote a rather generic little bit of code that does an alright job of following the actor. I then threw up a control line and have been trying to get it to recognise and tell me that it has hit a boundry. It hasn't.

Room700
Code: [Select]
/************************************************/
(include "sci.sh")(include "game.sh")                              (script 700)
/************************************************/
(use "Controls")(use "Cycle")(use "Feature")(use "Game")(use "Main")(use "Obj")
/************************************************/
(local
   targetX
   targetY
   currentX
   currentY
   recentX
   recentY
   currentDistance
   currentDistanceX
   currentDistanceY
   theStatus
   theStatus2
   currentCtl
   attempt = 0
  
   sendActor = FALSE    // actor walking
   stealControl = FALSE // take control from the main doit loop
)
//***********************************************
(instance public pathfinding of Rgn
(properties)
  (method (init)
  (super:init())
  
  (self:setScript(pathScript))
  (thisActor:init()setCycle(Walk))
  
  )// end method
)// end instance
//***************************************************
(instance thisActor of Act(properties x 10 y 100 view 1 loop 0 cel 0))
//***************************************************
(instance pathScript of Script
(properties)
  (method (doit)
  (super:doit())
(if(sendActor) // actor is walking

// step 1. get actors position...
//*******************************
= currentX (thisActor:x)
= currentY (thisActor:y)

// step 2. get ego's position...
//*******************************
= targetX (send gEgo:x)
= targetY (send gEgo:y)

// step 3. determine distance...
//********************************
= currentDistanceX (- currentX targetX)
= currentDistanceY (- currentY targetY)

(if(< currentDistanceX 0) // should be an absolute operator, but I don't know it.
= currentDistanceX (* currentDistanceX -1)
)
(if(< currentDistanceY 0)
= currentDistanceY (* currentDistanceY -1)
)

// step 4. determine if hungup
//*******************************
(if(== (thisActor:isStopped) 0) // should be moving.
  (if((== recentX currentX) and (== recentY currentY))
   Print("stuck")
   = stealControl TRUE
     (if(== attempt 3)
      = attempt 0
 )
 (else
  ++attempt
 )
  )
  (else
  = recentX currentX
  = recentY currentY
  )
)

// step 10. make a path...
//********************************
// Now that we have some variables, lets send our actor walking...
  (if((> currentDistanceX 30) or (> currentDistanceY 20))
  (if(not(stealControl))
    (thisActor:setMotion(MoveTo targetX targetY))
)
(else
// Try an alternative path here
(switch(attempt)
(case 0 (thisActor:setMotion(MoveTo currentX (- currentY 30) pathScript)))
(case 1 (thisActor:setMotion(MoveTo currentX (+ currentY 30) pathScript)))
(case 2 (thisActor:setMotion(MoveTo (- currentX 30) currentY pathScript)))
(case 3 (thisActor:setMotion(MoveTo (+ currentX 30) currentY pathScript)))
)
)
  )
  (else
  (thisActor:setMotion(NULL))
  )
)// end sendActor TRUE
  )// end method

(method (handleEvent pEvent)
(super:handleEvent(pEvent))

(if(Said('hi'))
= sendActor TRUE
= targetX (send gEgo:x)
= targetY (send gEgo:y)
= theStatus (thisActor:canBeHere((thisActor:x) (thisActor:y)))
= theStatus2 (thisActor:canBeHere(targetX targetY))
FormatPrint("targetX: %d  y: %d\nthisActorX: %d  y: %d\ncanBeHere: %d\ncanBeThere: %d" targetX targetY (thisActor:x) (thisActor:y) theStatus theStatus2)
    

    = currentCtl (thisActor:onControl())
FormatPrint("Control: %d\nStopped: %d" currentCtl (thisActor:isStopped))
)
  
  
)// end method


(method (changeState newState)
(= state newState)
(switch (newState)
(default
// Handle state changes
= stealControl FALSE
)
)
)
)

Then in the room1 script simply add the call to use the region
Code: [Select]
(self:setRegions(700)) // actor
Now all you need to test it is a view saved as 1.

Like I said, the bit that follows the ego around works, and to make it happen you just type in "hi". Also to view the variables set up, just retype hi. My initial thoughts of using dpath in conjunction with the doit method didn't quite work out like I had planned. I'm trying to start out simply and work my way up to something.

This part here is never returning TRUE even though I am pretty sure that it should when the actor gets stuck. My plan to handle the problem won't work in the long run, this is just a starting point to figure out where in the code to do stuff.
Code: [Select]
(if((== recentX currentX) and (== recentY currentY))
« Last Edit: January 20, 2013, 08:02:53 PM by Cloudee1 »
Halloween Competition Brass Lantern Prop Competition Groundhog Day Competition

Offline Collector

Re: Using the avoid script
« Reply #18 on: January 20, 2013, 08:43:44 PM »
That last bit is something along the lines of what I was suggesting, but what if the hang allows some movement. Checking for an exact match of X and Y might not reveal that the character is hung if it has moved by even a couple of pixels. Seems like you would have to test against a range.
KQII Remake Pic

Offline gumby

Re: Using the avoid script
« Reply #19 on: January 20, 2013, 08:46:34 PM »
Hey, for the absolute value just wrap the value with the Abs() kernel function call.

Code: [Select]
  Abs(currentDistanceX)

I've implemented your region and have it working as you've described.  The actor will follow the ego and the actor does get stuck.  Moving the ego around the actor unsticks the actor, so at least that works.  I'll play around with this and see if I can make any progress.

EDIT:  Cloudee, change this line here, this will cause the actor to unstick itself:

Code: [Select]
  // step 4. determine if hungup
//*******************************
(if(== (thisActor:isStopped) 0) // should be moving.      <------ change the zero to one.

The 'stuck' message fires, the actor gets unstuck and heads off to edge of the screen, but at least it doesn't get stuck!
« Last Edit: January 20, 2013, 08:54:08 PM by gumby »
In the Great Underground Empire (Zork port in development)
Winter Break 2012 Rope Prop Competition

Offline Cloudee1

Re: Using the avoid script
« Reply #20 on: January 20, 2013, 08:59:34 PM »
But that line checks against a real value. If you type hi while the actor is moving, you will see that it returns 0. Hit hi again while he is stopped, but not because he is stuck, and you will see that it returns 1. Try it again while he is stuck but should be moving and you'll see the 0 again. So in the case of the 1, you are sending him off and running when he shouldn't be moving at all... Remember the first time you hit hi, he is stopped, he doesn't start until after the print statement....

That is pretty cool though that he does something. Just not quite sure why he is doing what he's doing lol with that value changed to 1

Collector, the x step of a character varies, but is usually pretty small. A single valid step may only be a few pixels. Since I am checking every cycle, I want to know when he comes to a dead stop. Which clearly happens, by checking the hi values repeatedly when he is stuck, the current = recent check should come up positive.

Oh yeah Gumby thanks for the absolute operator, I knew there was one out there just couldn't remember what it was.

EDIT:
Wow, that was really ugly...
So I know my boundary is a vertical line. At this point I am just trying some options to get around it. Here is what I did.
First I changed section 4, including the line that Gumby pointed out

Code: [Select]
// step 4. determine if hungup
//*******************************
(if(== (thisActor:isStopped) 1) // should be moving.
  (if((== recentX currentX) and (== recentY currentY))
  // Print("stuck")
   = stealControl TRUE
     = attempt Random(0 3)

  )
  (else
  = recentX currentX
  = recentY currentY
  )
)

Oh yeah, I also trimmed down section 3 to what it should have been originally.

Code: [Select]
// step 3. determine distance...
//********************************
= currentDistanceX Abs(- currentX targetX)
= currentDistanceY Abs(- currentY targetY)

And I changed the values in section 10, like I said I know how he's stuck and which side I am sticking him on so while these won't get us anywhere near production, it is at least a good test with expectable results. Regardless though, this sort of worked but not really at all.

Code: [Select]

// step 10. make a path...
//********************************
// Now that we have some variables, lets send our actor walking...
   (if((> currentDistanceX 30) or (> currentDistanceY 20))
      (if(not(stealControl))
      (thisActor:setMotion(MoveTo targetX targetY))
      )
      (else
      // Try an alternative path here
        (switch(attempt)
          (case 0 (thisActor:setMotion(MoveTo (- currentX 2) (- currentY 30)(pathScript:changeState(0)))))
          (case 1 (thisActor:setMotion(MoveTo (- currentX 2) (- currentY 60) (pathScript:changeState(0)))))
          (case 2 (thisActor:setMotion(MoveTo (- currentX 30) currentY (pathScript:changeState(0)))))
          (case 3 (thisActor:setMotion(MoveTo (- currentX 60) currentY (pathScript:changeState(0)))))
       )
     )
    )
    (else
    (thisActor:setMotion(NULL))
    )

And finally, I changed the default line in the changestate method so that it was the case 0 that the moveto in the last section was looking for in order to trigger the following bit of code again.

Code: [Select]
(method (changeState newState)
(= state newState)
(switch (newState)
(case 0 = stealControl FALSE)
)
)// end method

The good news, suprisingly the actor made it around the solid line. The bad news, he didn't do it in any sort of fashion that he should have. It was ugly and not at all recognisable by the moveTo statements. Also, with the isStopped value changed, when he is successful and made it within the distance to ego the stuck message still fired. I am still positive that check should be set to 0

EDIT #2
And actually, even though my attempt to get him around the boundary was to subtract from his x position, he got around the wall just as well going from east to west. I certainly don't think that should have been the case. This is just plain wierd... but he got around the wall from both sides. I guess I need to make a box or a harder shape and see what happens.
« Last Edit: January 20, 2013, 09:42:35 PM by Cloudee1 »
Halloween Competition Brass Lantern Prop Competition Groundhog Day Competition

Offline Cloudee1

Re: Using the avoid script
« Reply #21 on: May 06, 2015, 08:35:40 AM »
Alright Phil, since you are back here again... I figured I would resurrect this thread. The avoid script really doesn't seem functional... Was wondering if you might want to run the sq3 avoid script through the decompiler again just in case some of the commented out assembly code that is still there might be better translated.

Currently, using this line to init an actor... when the actor hits a white control line, it takes off in the opposite direction and never really looks back.

Code: [Select]
(testViewAvoid:init()setCycle(Walk)setMotion(Follow gEgo 15)setAvoider(Avoid))
Halloween Competition Brass Lantern Prop Competition Groundhog Day Competition

Offline MusicallyInspired

Re: Using the avoid script
« Reply #22 on: May 06, 2015, 09:28:32 AM »
I noticed the Avoid script is in SQ4 too. I don't know how different it is, having not compared, but it might be worth taking a look at too.
Brass Lantern Prop Competition

Offline troflip

Re: Using the avoid script
« Reply #23 on: May 06, 2015, 11:52:45 AM »
Here's the decompiled SQ3 one (note that the script number is different, so you'll need to change that).

I'm not sure how well it will work, since it needs proper support for embedded if statements and I'm not sure if the old SCI Companion supported that properly. At the very least you'll get lots of warnings.

I was able to use the Avoid script somewhat successfully in Cascade Quest. But I do recall in rare circumstances it would get infinitely stuck.
« Last Edit: May 06, 2015, 01:11:31 PM by troflip »
Check out my website: http://icefallgames.com
Groundhog Day Competition

Offline Cloudee1

Re: Using the avoid script
« Reply #24 on: May 11, 2015, 02:57:35 PM »
Holy Crap, I got it to work...

All I had to do was replace the init method of the avoid script.

What it was
Code: [Select]
    (method (init theClient theOffScreenOk)
        (if (>= paramTotal 1)
            (= client theClient)
            (if (>= paramTotal 2)
                (= offScreenOK theOffScreenOk)
            )
            (= heading (send client:heading))
        )
        (= counter 0)
        (= nonBumps 10)
        (= escaping 0)
    )

and what it should be
Code: [Select]
    (method (init theClient theOffScreenOK)
        (if (>= paramTotal 1)
            = client theClient
        )
        (if (>= paramTotal 2)
            = offScreenOK theOffScreenOK
        )
        = heading (send client:heading)
        = counter 0
        = nonBumps 10
        = escaping 0
    )

and with that, I used this code to get it all going with the actor...
Code: [Select]
(scientist:setCycle(Walk)setMotion(Follow gEgo 20)setAvoider(Avoid 1))

actually I may not have needed to change the init method afterall, but it definately apperas as though you need to send the second parameter across. With the 1 removed or set to 0 I get the same reaction of the actor hitting a control line and promptly walking in the opposite direction.


... Ah Crap, when trying to leave the room I get an oops error
« Last Edit: May 11, 2015, 03:15:17 PM by Cloudee1 »
Halloween Competition Brass Lantern Prop Competition Groundhog Day Competition

Offline troflip

Re: Using the avoid script
« Reply #25 on: May 11, 2015, 03:17:04 PM »
Does it work properly now? Like, does it still get stuck?


Also, what's the difference between the two code snippets? They look functionally identical except that the second one will crash if no parameters are passed to Avoid (since client will be null, it will send heading to a null object).
Check out my website: http://icefallgames.com
Groundhog Day Competition

Offline Cloudee1

Re: Using the avoid script
« Reply #26 on: May 11, 2015, 03:36:37 PM »
I never had the issue with it getting stuck. The actor would touch a control line and the head in the exact opposite direction without ever looking back again. At least now, the actor bounces around a bit instead which is a vast improvement.

And yeah, the two snippets are pretty much the same except that heading was pulled out regardless of the parameter settings. It turns out (I assume) that the real difference this time was sending 1 ...setAvoider(Avoid 1)

Unfortunately now I can't leave the room without getting the oops error. So things are still looking bad on my end of things.

Also sending a 0 instead of the 1 reproduces the original failing avoid scenario
« Last Edit: May 11, 2015, 03:41:45 PM by Cloudee1 »
Halloween Competition Brass Lantern Prop Competition Groundhog Day Competition

Offline lskovlun

Re: Using the avoid script
« Reply #27 on: May 11, 2015, 03:46:04 PM »
Unfortunately now I can't leave the room without getting the oops error. So things are still looking bad on my end of things.
sciv -d will give you more useful debug messages instead of an oops (and, I believe, an opportunity to inspect the send stack).

Offline troflip

Re: Using the avoid script
« Reply #28 on: May 11, 2015, 03:58:21 PM »
How do you pass command line parameters to an exe in DOSBox? For the life of me I can't figure it out. You'd think it would be a common scenario, but the documentation mentions nothing.
Check out my website: http://icefallgames.com
Groundhog Day Competition

Offline Cloudee1

Re: Using the avoid script
« Reply #29 on: May 11, 2015, 04:01:13 PM »
Ok, but I really don't know what it is that this tells me... I assume that it has something to do with avoid being a class of the obj... but yeah
Code: [Select]
Not an object: $e226

Avoid
mul
acc:e226    sp:1868    pp:1860

Phil, if you used the dosboxsetup thing, then there will be dosbox.conf file in your games root folder. In the autoexec bit, add the bit to the command line
Code: [Select]
[autoexec]
cls
@ECHO OFF
mount c .
c:
cd \
SCIV.EXE -d
exit

Halloween Competition Brass Lantern Prop Competition Groundhog Day Competition


SMF 2.0.19 | SMF © 2021, Simple Machines
Simple Audio Video Embedder

Page created in 0.082 seconds with 21 queries.