Need help perfecting a unique cursor system.

Started by Cine Beast, Wed 31/08/2011 20:33:40

Previous topic - Next topic

Cine Beast

Yo, Cine Beast here - asking for aid yet again.  :-[

I'm developing a game that uses the tried-and-true Sierra interface, but I want to mix things up with one of the cursors (a cursor I've added).

I have made a Wand cursor that can be directed just like the others, but I want the following to occur when I left-click a hotspot/object/everything:

A Text GUI appears with a list of spells -
I pick a spell in the textbox and hit "Cast" -
The spell is cast, and the target is affected.

In short, a system similar to the interface in 7 Days a Skeptic & 6 Days a Sacrifice.

I'm pretty much done, but there is an inescapable problem: the GUI shows up, but when I hit "Cast," the effect does not occur.

This is the messy code for when I left-click the hotspot:

  gSpell.Visible = true;
  if (currentspell == 1 && heroicspell == true) {//So, if Incendio is chosen AND cast, the following occurs.
    cEgo.Say("Incendio!");
    Display("Fire streams from your wand and sets the blackness ablaze.");
    heroicspell = false;//So the player just casts the spell once.
    mouse.UseModeGraphic(eModeMagic);
  }

I have it set that when in the GUI, if you select "Incendio," the int "currentspell" is set to 1, and when you click "Cast," the bool "heroicspell" is set to true, so this really should work.

I think the problem is that by the time I've selected the spell and cast it, the function has already ended, and I've missed my chance. If so, I suppose I need some way for the function to repeat, or else become Blocked just after the GUI becomes visible.

I hope I made my problem clear. Thanks in advance.

Khris

#1
You have to run the actual interaction code after the Cast button is pressed, not after the hotspot is clicked.

In the global script, in the section on_mouse_click / eMouseLeft, you should have:

Code: ags
  else if (button == eMouseLeft) {
    ProcessClick(mouse.x, mouse.y, mouse.Mode );
  }


replace this with:

Code: ags
  else if (button == eMouseLeft) {
    if (mouse.Mode != eModeMagic) ProcessClick(mouse.x, mouse.y, mouse.Mode );
    else if (GetLocationType(mouse.x, mouse.y) != eLocationNothing) Cast(mouse.x, mouse.y);
  }


Now put this above the on_mouse_click function:

Code: ags
int cast_lt, cast_id, cast_ia;

void Cast(int x, int y) {

  cast_lt = GetLocationType(x, y);
  cast_ia = IsInteractionAvailable(x, y, eModeMagic);
  
  if (cast_lt == eLocationCharacter) {
    Character*c = Character.GetAtScreenXY(x, y);
    cast_id = c.ID;
  }
  if (cast_lt == eLocationObject) {
    Object*o = Object.GetAtScreenXY(x, y);
    cast_id = o.ID;
  }
  if (cast_lt == eLocationHotspot) {
    Hotspot*h = Hotspot.GetAtScreenXY(x, y);
    cast_id = h.ID;
  }

  gSpell.Visible = true;
}


Now put this in the button's OnClick function:

Code: ags
  String no_event = "The spell fizzles.";
  gSpell.Visible = false;

  if (cast_lt == eLocationCharacter) {
    Character*c = character[cast_id];
    if (cast_ia) c.RunInteraction(eModeMagic);
    else Display(no_event);
  }
  if (cast_lt == eLocationObject) {
    Object*o = object[cast_id];
    if (cast_ia) o.RunInteraction(eModeMagic);
    else Display(no_event);
  }
  if (cast_lt == eLocationHotspot) {
    Hotspot*h = hotspot[cast_id];
    if (cast_ia) h.RunInteraction(eModeMagic);
    else Display(no_event);
  }


So everytime you click on something with the magic cursor, the GUI opens. After clicking the Cast buttons, the GUI is closed. Then AGS checks whether there's a function linked to the "Magic ..." event of whatever was clicked. If there isn't, the game simply displays "The spell fizzles." If there is, the function is executed.

So you'd put this in the hotspot's Magic event function:

Code: ags
  if (currentspell == 1) {   // Incendio is chosen
    cEgo.Say("Incendio!");
    Display("Fire streams from your wand and sets the blackness ablaze.");
  }


This way you won't have to put duplicate code into every hotspot's event functions. The game will also pretend that you can cast every spell on anything up until the Cast button is actually clicked, i.e. every hotspot will display the spell GUI first before giving the "that doesn't work message".

Cine Beast

*whistle*

Wow, thanks for all the effort, man, that's awesome.

I'm getting an error right now, though, in the code above the on_mouse_click function:

int cast_lt, cast_id;

void Cast(int x, int y) {

  cast_lt = GetLocationType(x, y);
 
  if (lt == eLocationCharacter) {                                   < Right here . . . AGS finds the 'symbol lt undefined.'
    Character*c = Character.GetAtScreenXY(x, y);
    cast_id = c.ID;

I'm afraid that this level of coding is over my head, so I don't know what the problem could be.

pcj

It looks like you mis-copied the code, it should be cast_lt, not just lt.
Space Quest: Vohaul Strikes Back is now available to download!

Khris

#4
Sorry, yeah, I feared this would happen because I changed the variable name while writing the code :)

I have corrected the code, so either re-paste it or manually replace every "lt" with "cast_lt".

What the code does is store the type of what was clicked (cast_lt) and its ID (cast_id) for later use; then after Cast is clicked, use these two variables to process the actual action.

Cine Beast

Okay, okay, gettin' there . . .  ;D

Now a different error is assailing me, though:


  if (cast_lt == eLocationHotspot) {
    Hotspot*h = Hotspot.GetAtScreenXY(x, y);
    cast_id = h.id;      < Here.
  }


AGS says that "'.id' is not a public member of 'Hotspot.'"

Huh. Do I need to specify the hotspot or something?

pcj

The .ID property for Hotspot is capitalized on both letters.  So it should be; cast_id = h.ID;
Space Quest: Vohaul Strikes Back is now available to download!

Cine Beast

Ah, duh, I should have noticed that.

. . . now AGS insists that ".IsInteractionAvailable" cannot be used the way it is currently being used:


  if (cast_lt == eLocationCharacter) {
    Character*c = character[cast_id];
    if (c.IsInteractionAvailable(eModeMagic)) c.RunInteraction(eModeMagic);  < Here.
    else Display(no_event);
  }


Actually, the error message is rather vague, and it won't let me read the whole thing.

I'm really taking up your time now, sorry.

pcj

#8
From what I can tell, that line should be:

Code: ags
if (IsInteractionAvailable(c.x,c.y, eModeMagic)) c.RunInteraction(eModeMagic);


And similarly with the other lines.

EDIT: Corrected the suggested modification. I finally got around to reading through the entire code.  ::)
Space Quest: Vohaul Strikes Back is now available to download!

Khris

pcj: Storing the clicked coordinates is an alternative way of doing this, yes; it can lead to undesired results in certain cases though. Storing what was actually clicked is fool-proof.

I have corrected the code again, sorry for the mess. Re-paste the two long blocks of code and it should really work now :)

pcj

Space Quest: Vohaul Strikes Back is now available to download!

Cine Beast

 ;D

It works just like I hoped it would!

Thanks for all the help, dudes. If you ever need anything from me (not that I have much to offer at this point), just let me know.

Khris

Glad it finally does, I should at least test for syntax errors with that many lines of code I guess :=

SMF spam blocked by CleanTalk