Walking to objects.

Started by Mr_Threepwood, Fri 21/07/2006 21:59:15

Previous topic - Next topic

Mr_Threepwood

Is there an easy way to do this:

When a player clicks on an object and something is run, in my case open door, then the player walks to the door before changing rooms but without blocking the script.

The reason I ask is if it's easy I'd like to have it so you can click "open" on the door and then while your guy is walking you can click "walk to" somewhere else and have it stop you from going to the door and changing rooms.

Right now I have the script blocking when you walk to the door which works fine but isn't very elegant.

I was thinking maybe I could accomplish this with regions, or even better would be a simple if statement.
I am a mighty pirate

Babar

if you are using the script, the command cChar.Move(x,y,....) has an optional variable eblock (or eNoblock, I think). Just use the eNoblock.

If you are using the interaction editor, I think there is an option where you can set "wait for this to finish" to "false"
The ultimate Professional Amateur

Now, with his very own game: Alien Time Zone

Mr_Threepwood

Thanks for the response, but let me try to re explain my problem.

The problem with using eNoBlock is that it will then continue doing the script (which I want it to do but without the change room), if I just changed it right now from block to noblock then it would make my guy teleport to the new room as soon as you clicked "open door".

What I would like is a way that the script still goes, but "waits" until you are at the door before changing rooms.
I am a mighty pirate

Khris

Code: ags
// script header
import function queuedRoomChange(int reg, int roo, int x, int y);

// global script (top)
bool queue=false;
int qreg;
int qroom;
int qx;
int qy;

function queuedRoomChange(int reg, int room, int x, int y) {
Ã,  queue=true;
Ã,  qreg=reg;
Ã,  qroom=room;
Ã,  qx=x;
Ã,  qy=y;
}

// repeatedly_execute
Ã,  if (queue && Region.GetAtRoomXY(player.x, player.y)==reg) {
Ã,  Ã,  player.ChangeRoom(qroom, qx, qy);
Ã,  Ã,  queue=false;
Ã,  }

// on_mouse_click {
Ã,  queue=false;
Ã,  ...
}

*************

// room script

// open door
player.Walk(x, y)Ã,  // x,y is a point inside the doors trigger region
queuedRoomChange(region, room, x, y);


Then draw little regions around the walk-to points of the doors.
This might work, I didn't test it.

Ashen

#4
This sort of thing (non-blocking, cancelable interactions) has been asked before - if KhrisMUC's code doesn't work, try a forum search. This thread might help.
I know what you're thinking ... Don't think that.

Mr_Threepwood

OK I think I've almost got a way that will work for all objects that I want the character to walk to before interacting, but not blocking the script.  The only problem I am having is I can not figure out how to call a room function from the global script (except for the CallRoomScript one which I dont want because it can only accept one parameter).

The way I have it working (well not quite) is like this:

1.  Call queuedCommand(int x, int y, int itemNum, int CommandNum)
2.  Store all those in variables in the global script, make player walk to x,y.  Store boolean to say a queue is in place, cancel the boolean if player clicks anything else.
3.  In repeatedly execute check if player has reached x,y and que
4.  If player has reached x,y and is still in the queue then run the room function runQueuedCommand(int itemNum, int CommandNum)

That will let me have multiple interactions with items for the queued commands.

The only problem is I can't figure out how to get runQueuedCommand to run from the global script since it is a room script.  Is it possible to do it?  Alternatively I could use the less organized CallRoomScript which only accepts one integer, it would work but if I could organize it better it would be nice.
I am a mighty pirate

Mr_Threepwood

I think that even if you can't call local scripts per se from the global script I've managed to think of a workaround to it, tell me what you think.

For the ItemNum and CommandNum use global ints instead, have the global function runqueued command call the local on_call script, which then calls the reasl runqueuedcommand which then takes the two global integers and then does the command from there.

It's a little messy but to me seems like a good workaround if you can't normally call room scripts from the global script.
I am a mighty pirate

Khris

I guess you want the function inside the room script because it's going to change from room to room, right?

Could you post a short example of a room's queuedCommand function?
If we know what it exactly does, we can help you better.

Mr_Threepwood

#8
well I dont have it working but it would look like this I think:

Code: ags

//in the room script
function runQueuedCommand (int itemNum, int commandNum){

//door is itenNum, commandNum is open.Ã,  These numbers are just made up by me, no script references based on the actual objects number.Ã,  This way It could work with hotspots as well as objects

if(itemNum==1){
if(commandNum==1){
cEgo.ChangeRoom(5,100,100);
}
}else if (itemNum==2){
if(commandNum==1){
//in this case let itemNum be a book and command num be pick up
//5 is a book in the game inventory items
cEgo.AddInventory(5)
}
}

}

//now here's how I'd call a run queued command from an items interaction (in my case I always use usermode 1, and have a global int that tracks what they are doing (IE use, walk to, pick up);

//usermode 1 on item or hotspot

//global int 10 being 1 represents player pressing "open" on something
if (GetGlobalInt(10)==1){
//global function

//this is what I'd like to work, where 140,140 is where the character moves and 1,1 is the itemnum and object num.Ã,  The last two could be global ints instead if that makes it easier.

QueueCommand(140,140,1,1);

//so now my character will walk to 140,140 and when he reaches it it does runQueuedCommand 1,1.Ã,  Which from this example will open the door.



Sorry If I didn't explain it well, if there's any confusion just say so and I'll try to explain it better.  I'm pretty sure this would work, the only thing getting in the way is I don't know how to call a room script from the global one, and if you can't then I think I could call the one parameter room script on_call, which in turn just calls the runQueuedCommand.
I am a mighty pirate

Khris

Instead of putting every interaction into a single function, you could AGS's system and call Object.RunInteraction(eModeInteract);, same for characters and hotspots.

Then use global variables to store the coords and the verb, and put the responses into the Objects "Interact with" interaction.

I think that's a good way to workaround the non-possibility to call functions in room scripts from the global script.

There's another way, too:
Code: ags
function MovePlayer(int x, int y) {
Ã,  player.Walk(x, y);
Ã,  bool run=true;
Ã,  while (run) {
Ã,  Ã,  if (player.Moving==false) run=false;
Ã,  Ã,  if (IsButtonDown(eMouseLeft)) run=false;
Ã,  Ã,  // ...
Ã,  Ã,  Wait(1);
Ã,  }
Ã,  player.StopMoving();
Ã,  if (player.x=x && player.y=y) return 1;
Ã,  return 0;
}


In the interaction, just use
Code: ags
if (MovePlayer(140,140)) {
Ã,  // Do stuff
}


(partly from Lucasfan's Maniac Mansion Mania)

Mr_Threepwood

Alright I tried the other way you said to do it with the MoveTo, it  sort of works.  The problem is that the onMouseClicked thing in the while loop gets activated immediately since you are clicking the door, a solution to that would be to put in a wait but it causes the character to delay doing stuff which is annoying.

I did however get a way that works, and doesn't even block the global script.  It doesnt seem very elegant so if there's a way I can make it cleaner or something just tell me.

Code: ags

//in room script for interact with object
//this moves player to 290, 140 with item to run on 1 and command to run on item 1
queuedCommand(290, 140, 1, 1);


//global script

bool inQueue=false;
int qx;
int qy;

function queuedCommand(int x, int y,int itemNum, int commandNum){
	inQueue=true;
	player.Walk(x, y);
	qx=x;
	qy=y;
	SetGlobalInt(20, itemNum);
	SetGlobalInt(21, commandNum);
  }

function repeatedly_execute() {
  if (inQueue&&player.x==qx&&player.y==qy){
    inQueue=false;
    CallRoomScript(0);
  }


//in on mouse click
inQueue=false;



//back to room script now
function on_call(int dummy){
  int itemNum=GetGlobalInt(20);
  int commandNum=GetGlobalInt(21);
  //Display("ARRIVED");
  if (itemNum==1&&commandNum==1){
    cEgo.ChangeRoom(5,45,160);
    }
  }


That did it, and it works but seems like stuff is getting passed around to different scripts like crazy.  Tell me what you think about it, it's a decent solution to the problem I think and manages to decoy the games on_call function.
I am a mighty pirate

SMF spam blocked by CleanTalk