'Interact' command SOMETIMES works- sometimes doesn't (hotspots)

Started by reismahnic, Fri 09/01/2015 00:23:49

Previous topic - Next topic

reismahnic

Hello.
I am making a game in AGS using the XALARCOST template.
For the most part things are going swimmingly, but I've run into a small issue.
I've been using hotspots on a PGN image rather than using each object in the room as an individual Sprite.
This has worked well! I have a fully working room (that leads to a hallway), and every object can be looked at (right click; its XALARCOST), and my character responds in kind.
However, an issue has arisen. Some objects (for example, a dresser in the room) fire the interact (left click) command no problem. Others (for example, a suitcase in the room) simply do not.
The walk to points for all objects work fine. The character walks right up to the object, but then does not say the assigned line of dialogue I've given them.
I set up a blocker at the beginning of the 'interact' command and it seems that this command is not even firing.

My code is very simple.
For example, with the suitcase, here is my code:

Code: ags

//BEDROOM SUITCASE:
//Jessica looks at Suitcase
function hBedroomSuitcase_Look()
{
cJessica.Say("Six days of dirty laundry.");
}



//Jessica tries to interact with Suitcase (walks beside it)
function hBedroomSuitcase_Interact()
{
cJessica.Say("Ah! a suitcase. This code finally works now.");
}



In this example, the line 'Six days of dirty laundry.' works just fine when right clicking.
The left click (interact), however, does not.

I hope someone can help.
This is my first time ever posting in the AGS forums, so I truly apologize if this is not in the appropriate spot.
Thank you all very much.


reismahnic

I should mention I'm not getting errors of any kind.
The game runs without any issues.

monkey0506

Things to check:

- Make sure that the event ("hBedroomSuitcase_Interact") is listed in the Events pane for the hotspot (hBedroom).
- Check the cursor hotspot coordinates of your eModeInteract cursor.
- Make sure that the hotspot is enabled (i.e., check that you aren't disabling it anywhere, or check Hotspot.Enabled from on_mouse_click perhaps).

If none of that fixes the problem:

- Post your on_mouse_click code and a list of any script modules you are using.

reismahnic

So.
1. hBedroomSuitcase_Interact definitely IS listed, right below hBedroomSuitcase_Look.
2. I'm gonna be totally honest here, I don't know how to check the cursor hotspot coordinates. I'm sorry...
I did read the instruction manual, but I cannot for the life of me remember this or where it may be listed.
3. The hotspot does seem to be enabled. For example, as I said, the 'look' command works just fine.

However, it seems that you got banned for that post.
I'm not sure why... can anyone explain (slash help)? I'm really sorry if my post got you banned...

Mandle

Quote from: reismahnic on Fri 09/01/2015 04:44:16
However, it seems that you got banned for that post.
I'm not sure why... can anyone explain (slash help)? I'm really sorry if my post got you banned...

Hahahaha!!! Don't worry...it's a joke: It says that at the bottom of all of his posts...

And I'm betting you just made monkey's year (so far) by being the first to fall for it (laugh)

monkey0506

It was true at least once... (roll)

[/off-topic]

Right, if you're using the same hotspot and it's definitely enabled and the event is listed then it sounds like it's either a cursor hotspot issue or an issue in your on_mouse_click (which you still didn't provide! :-X).

Cursor hotspots can be moved on a per-cursor basis by opening the cursor in the editor. AFAIK you should be able to drag and drop the crosshairs or manually position it in the properties pane. This will affect the portion of the cursor icon you use to click on things.

The on_mouse_click function (GlobalScript) typically just calls ProcessClick (Room.ProcessClick in newer versions), but there could be other code in there that is preventing the Interact mode from working properly. If you're using any script modules they may also have their own on_mouse_click function.

reismahnic

Ohhhh my goodness, you got me good. :wink:

I have checked the cursor coordinates (thank you for spelling it out to a newb, Monkey), and both the 'interact' and 'examine' cursors are in the same location (the mark is in the upper left hand corner), so I should be good there.
Regarding On_Mouse_Click, there are MANY references to this in the GlobalScript.
I have copy/pasted one of them here, but I wasn't sure if you want me to post the entire GlobalScript (it's very long)?
Code: ags


function on_mouse_click(MouseButton button) {
	// called when a mouse button is clicked. button is either eMouseLeft or eMouseRight, unless you custom handle inventory clicks
	
	// custom click handling within inventory window
	if (gInventory.Visible == true) {
		InventoryItem*i = InventoryItem.GetAtScreenXY(mouse.x, mouse.y);
		if (button == eMouseLeftInv) {
			if (mouse.Mode == eModePointer) {
				if (!i.IsInteractionAvailable(eModeInteract)) {
					player.ActiveInventory = i; // select the inventory item that player clicked to be the active inventory cursor
				}
				else i.RunInteraction(eModeInteract);
			}
			else if (mouse.Mode == eModeUseinv) {
				i.RunInteraction(eModeUseinv);
				if (i.IsInteractionAvailable(eModeUseinv)) mouse.Mode = eModePointer;
			}
		}
		else if (button == eMouseRightInv) {
			// don't need to check if i != null, because any click that doesn't fall on an inventory item is somehow not counted
			// to make right click get rid of current inventory cursor, we use on_event eEventGUIMouseUp
			i.RunInteraction(eModeExamine);
		}
		return;
	}



I'm sorry if this is not what you're looking for. Please let me know if there's anything else I can provide.

There are two other script modules in XALARCOST (or default AGS?): GUIColors and KeyboardMovement_102.
However, neither of them make any reference to on_mouse_click. GlobalScript is the only one that does. And it does a few times (and even more in comments).
Thanks!!

monkey0506

That's the right function, yes, but it looks like you didn't copy the whole function? This portion only refers to clicks on an inventory item...

You don't need to copy the entire GlobalScript, but if you could provide that function in its entirety, that seems the most likely culprit for your issues.

reismahnic

Ah! Here is the full function.

Code: ags


function on_mouse_click(MouseButton button) {
	// called when a mouse button is clicked. button is either eMouseLeft or eMouseRight, unless you custom handle inventory clicks
	
	// custom click handling within inventory window
	if (gInventory.Visible == true) {
		InventoryItem*i = InventoryItem.GetAtScreenXY(mouse.x, mouse.y);
		if (button == eMouseLeftInv) {
			if (mouse.Mode == eModePointer) {
				if (!i.IsInteractionAvailable(eModeInteract)) {
					player.ActiveInventory = i; // select the inventory item that player clicked to be the active inventory cursor
				}
				else i.RunInteraction(eModeInteract);
			}
			else if (mouse.Mode == eModeUseinv) {
				i.RunInteraction(eModeUseinv);
				if (i.IsInteractionAvailable(eModeUseinv)) mouse.Mode = eModePointer;
			}
		}
		else if (button == eMouseRightInv) {
			// don't need to check if i != null, because any click that doesn't fall on an inventory item is somehow not counted
			// to make right click get rid of current inventory cursor, we use on_event eEventGUIMouseUp
			i.RunInteraction(eModeExamine);
		}
		return;
	}
	
	if (IsGamePaused() == 1) {
		// Game is paused, so do nothing (ie. don't allow mouse click) (game is paused when GUI interfaces are run) because ProcessClick ignores all GUI interfaces and clicks directly on the game screen, GUI button presses are not handled with this function anyway
		return;
	}
	else {
		// GOT THERE
		tgx = 0; // reset the values so that interactions won't be run twice (the second time under repeatedly_execute) when interacting with another non-gothere hotspot (no "if..return" line, hence interaction will run under on_mouse_click first) right after arriving
		tgy = 0; // ..at a gothere hotspot. these values will again be overwritten when interacting with a gothere hotspot and GoThere() is called
		tfd = eNowhere;
		fx = 0;
		fy = 0;
	}
	
	if (button == eMouseLeft) {
		if (mouse.Mode == eModeWarp) { // for hotspots that are actually exits to another room
			// GOT THERE and DOUBLE CLICK
			__arrived = false;
			mm = eModeInteract; // can't change mouse.Mode directly, if not after a single click the cursor will change and the second click will not be as eModeWarp
			lt = GetLocationType(mouse.x, mouse.y);
			Hotspot*h = Hotspot.GetAtScreenXY(mouse.x, mouse.y);
			lid = h.ID; // to pass to repeatedly_execute to run the relevant interaction
			// GOT THERE end
			// double-clicks are only possible with the warp cursor on exits, treated as a single-click under all other circumstances
			if (lastclick && mouse.x==mx && mouse.y==my) {
				// registers as a double-click on the same spot (within a set delay after the last click)
				lastclick = 0; // resets the counter
				__arrived = true; // makes sure player doesn't bother to walk there first before executing the interaction which is a ChangeRoom, so that player can Warp to next room on double-click on exit. also, now the interaction won't be called under repeatedly_execute
			}
			else {
				// registers as a single-click
				lastclick=1; // starts the counter to see if it can trigger a double click
				mx=mouse.x; // ..that is on the same spot
				my=mouse.y;
				// no return, will lead to ProcessClick later, means no delay before single clicks are processed, i.e. immediate
			}
			// DOUBLE CLICK end
		}
		else if (GetLocationType(mouse.x,mouse.y) != eLocationNothing) { // click on something i.e. hotspot/character/object
			__arrived = false; // GOT THERE disables the regular interaction from running when called with ProcessClick under on_mouse_click if the "if..GoThere..return" line is present, but enables an interaction to be run with RunInteraction under repeatedly_execute if player co-ords match GoThere()'s if GoThere() is called in the interaction
			// GOT THERE following allows appropriate interaction to be called with RunInteraction under repeatedly_execute instead of on_mouse_click when GoThere is called with the "if..return" line
			lt = GetLocationType(mouse.x, mouse.y);
			if (lt == eLocationHotspot) {
				Hotspot*h = Hotspot.GetAtScreenXY(mouse.x, mouse.y);
				lid = h.ID;
			}
			else if (lt == eLocationObject) {
				Object*o = Object.GetAtScreenXY(mouse.x, mouse.y);
				lid = o.ID;
			}
			else if (lt == eLocationCharacter) {
				Character*c = Character.GetAtScreenXY(mouse.x, mouse.y);
				lid = c.ID;
			}
			// GOT THERE end
			if (mouse.Mode == eModeUseinv) {} // don't change the Useinv cursor
			else mouse.Mode = eModeInteract; // if you left-click on a hotspot (or object or character), interact with it. ProcessClick is called later with the relevant mouse mode, hence no return command
			mm = mouse.Mode; // GOT THERE
		}
		else { // click on nothing
			__arrived = true; // GOT THERE disables interaction from running with RunInteraction under repeatedly_execute, but enables the regular interaction to run even after the "if..GoThere..return" line when called with ProcessClick under on_mouse_click in the following line
			if (mouse.Mode == eModeUseinv) {
				ProcessClick(mouse.x, mouse.y, eModeWalk); // even with the Useinv cursor, players can walk as long as they click on nothing. however, the cursor remains the Useinv
				return; // so the later ProcessClick doesn't run again
			}
			else mouse.Mode = eModeWalk; // left-clicking on nothing makes player walk there, or as close as possible. automatically restricted to walkable areas
			mm = mouse.Mode; // GOT THERE
		}
	}
	else if (button == eMouseRight) {
		if (player.Room == MAPROOM) return;
		else if (mouse.Mode == eModeUseinv) {
			mouse.Mode = eModeWalk;
			return;
		}
		else if (GetLocationType(mouse.x,mouse.y) != eLocationNothing) {
			__arrived = true; // GOT THERE
			mouse.Mode = eModeExamine; // right-clicking on something makes player examine it
		}
		else if (mouse.Mode == eModeWalk) {
			mouse.Mode = eModeUseinv;
			return;
		}
		else return; // don't walk when right-clicking on nothing
		mm = mouse.Mode; // GOT THERE
	}

	// GOT THERE automatic version. with this code, it's unnecessary to set individual "if (!GotThere()) { GoThere(x,y); return; }" lines in interaction events code. leave this if you want the GoThere code to be handled automatically, get rid of it if you want to set it manually for each interaction. note that if you use this, it will still make the player go to the walk-to point for manually-called unhandled_events.
	if ((IsInteractionAvailable(mouse.x, mouse.y, mm) == 1) && (player.Room != MAPROOM)) {
		if (!GotThere()) {
			GoThereA();
			if ((tgx != 0) && (tgy != 0)) return;
		}
	}
	
	ProcessClick(mouse.x, mouse.y, mm); // about the same as RunInteraction in terms of what it runs (dunno about walk mode though), which means the relevant function linked under events for the relevant mouse mode in the properties window, except the inputs are different. ProcessClick uses mouse co-ords, RunInteraction uses the hotspot/object/character. if walk-to point is defined, both initiate a blocking walk to that point before the interaction is run unless game.auto_use_walkto_points is changed
}





Thank you so much for being so patient, Monkey.

monkey0506

Yeah, I hadn't really realized how large and unwieldy this template is. Looks like Lemonhead actually merged several modules together into a single script...ugh.

Okay, at this point we really have to narrow down where the problem is occurring at. Toward the end of that function, I want you to add a little test.

Code: ags
        if ((IsInteractionAvailable(mouse.x, mouse.y, mm) == 1) && (player.Room != MAPROOM)) {
                if (!GotThere()) {
                        Display("Going to (%d, %d) with hotspot ID = %d", mouse.x, mouse.y, lid); // ADD THIS LINE
                        GoThereA();
                        if ((tgx != 0) && (tgy != 0)) return;
                }
        }


I want you to see if that line consistently appears and that the coordinates that appear actually match where your hotspot is at and you are clicking. The last bit should be the ID of the hotspot, so make sure that matches the hotspot you clicked on as well.

If that doesn't appear every time you click on the hotspot then we know that the problem lies earlier in the code.

P.S. This isn't happening in room 3, is it? (MAPROOM is defined as 3 by default, and it handles map room clicks differently)

reismahnic

Ok, got it set up.
It DOES display at every hotspot click, and DOES display the correct hotspot number.

No, this is not room 3, although THANK YOU for reminding me that I should probably not use room 3 when it comes to that (I have rooms 1 and 2, but not 3).

Monkey, the reason I chose this template was that I wanted a two-click interface. One button interacts, one button looks. And that's it.
I'm very adamant about that (my grandmother should be able to play this game). Would you recommend going with a simpler one, and if so, which?
Lemonhead seems to have filled XALARCOST with features that, while useful for a lot of people with specific needs, I may not be needing.
The main reason I chose it was just having a two click interface, and hopefully retaining an inventory. I'm also having an issue where SOMETIMES clicking one a door once will take me to another room,
but depending on where the hotspot is placed it SOMETIMES doesn't, instead requiring a DOUBLE click.  What do you recommend I do? Should I continue along with this template?

As always, thank you.

Cassiebsg

The BASS is two button template. Also with Left button = interact and Right button = Look. You could try that one. Don't think it has a double click function though (if that's important for your game).
There are those who believe that life here began out there...

reismahnic

Thank you for the recommendation, Cassiebsg.
I see that the BASS is already sitting in my AGS folder.
Is there a way to move to this template without having to sacrifice all my hotspots, etc, or should I just be starting from scratch (which is fine, I understand).

monkey0506

I'd first like to say that I don't necessarily think abandoning ship is always best or necessary. I'd be interested in determining if there is a bug in the template. However, it might be easier for you to restart with a less bloated template that better fits your needs.

You should be able to:

- Create a new project based on another template.
- Copy (don't "Cut", just in case something goes wrong) all of the room CRM files from your old project folder into your new project folder (do NOT replace existing rooms this way, rename the room files from your old project as needed).
- Open the new project in AGS, right click on "Rooms" and select "Import existing room". Do this for each room you are bringing in from the old project.
- Now you can delete unused rooms and/or change room numbers.

Characters and GUIs should can also be exported and imported between projects.

reismahnic

Ok, I have rebuilt the rooms in LW BASS. I am much happier with this template for this project.
Everything now works as it should. The only minor issue I'm seeing is that inventory items seem to be overlapping a bit.

(pictured:)


But I also haven't looked on the forums to see if this is a known issue yet.
Thank you so much, everyone. Really helpful!
Can't wait to get back to work.

monkey0506

My recommendation for that would be to check that your ItemHeight and ItemWidth are set properly for your InvWindow. This can change in the editor as well as in the script.

reismahnic


SMF spam blocked by CleanTalk