Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Topics - That Guy

#1
I have an inventory object with an interaction defined for "Look at object" and nothing else.

However, calling IsInteractionAvailable() on that object with a parameter of eInteract is returning 1, as though an interaction was defined.

Is this a bug, or am I doing something wrong?

EDIT:  I noticed that if my IF/THEN logic got too complex, the final conditional didn't get evaluated no matter what, whether it used IsActionAvailable() or even GetProperty().

the logic went something like this;

if ((something) || ((one thing) && (another thing))

then (another thing) always returned true, no matter what the condition should have been.  did I get too complicated and break something in the parser?
#2
Okay, so like a typical n00b I decided to try and implement my own SCUMM-style interface without reading any tutorials.  The following is what I came up with... which, upon finaly perusing the older tutorials in the archive, I feel is a fairly clean, straightforward method.

This tutorial is compatible with 2.7 - use for earlier versions at your own risk!

First, here's a shot of the bar in action.  I'd provide you with actual graphics, but as they're styled for a sci-fi game they probably wouldn't fit in your typical SCUMM adventure.

This script assumes your player character has a script name of "cPlayer".  So wherever you see "cPlayer", substitute your own character's script name, characters[EGO], or whatever.  However you refer to your main character in the script.



Step 1: Create the GUI

This part is pretty easy.  You'll need a new GUI object that spans the width of the screen and is as tall as you want your SCUMM bar to be.  Put a custom inventory object on the right, and your stock nine verbs on the left.  Use graphical (image-based) buttons rather than the standard GUI buttons, and don't type anything in the button label.  If you really want a professional-looking effect, provide mouseover images to "light up" your verbs.

After you've added your buttons to the GUI, you need to give the GUI, as well as all the buttons, names.  This is so that you can access them via the script.  I called the GUI "gScummbar" and each button is named in the format "bVerb", so the "Give" button is "bGive".  You give the buttons names by clicking on the button itself in the GUI editor, then clicking on the "script name" property and filling it in there.  Ditto the GUI.

Step 2: Create some stuff to play with

This method works with any object (inventory, character, or hotspot) with no changes.  So put some stuff in your game to interact with.  You'll need 'em to test with.

Step 3: Add the scripting

Open up your global script and add this at the top.  It defines nine string variables with the SCUMM verbs, and also a single string variable that holds our currently-pending verb.

Code: ags

// verb constants

string vGive;
string vPickup;
string vWalkto;
string vUse;
string vOpen;
string vLookat;
string vPush;
string vClose;
string vTalkto;
string vPull;

string verb;


Then, wherever you first perform your start game initialization, add the following.  I have a function called startNewGame() but you can just as easily put it in the master game_start() method.

Code: ags

// set up SCUMM verbs
  
  StrCopy(vGive, 	"Give");
  StrCopy(vPickup,	"Pick up");
  StrCopy(vWalkto,	"Walk to");
  StrCopy(vUse,	"Use");
  StrCopy(vOpen,	"Open");
  StrCopy(vLookat,	"Look at");
  StrCopy(vPush,	"Push");
  StrCopy(vClose,	"Close");
  StrCopy(vTalkto,	"Talk to");
  StrCopy(vPull,	"Pull");
 
  StrCopy(verb, 	vWalkto);
	
  // this line makes the GUI visible, assuming you've named it "gScummbar" in the GUI editor.  Substitute with your own GUI objectname.

  gScummbar.Visible = true;



Okay, now we've got our nine verbs.  Next we need to set up the interface_click method so that it handles our button-pushing.  Here's that method.

Code: ags

function interface_click(int interface, int button) 
  {  
    if (interface == gScummbar.ID)
    {
      if (button != 2)  // this line is now superfluous, since there is no clickable button #2.
      {
        if (button == bGive.ID)
        {
           StrCopy(verb,  vGive);
					
           mouse.Mode = eModeUseinv;
        }
					
        if (button == bPickup.ID)
        {
           StrCopy(verb,  vPickup);
					
           mouse.Mode = eModeInteract;
        }
					
        if (button == bUse.ID)
        {
           StrCopy(verb,  vUse);
					
           mouse.Mode = eModeInteract;
        }
					
        if (button == bOpen.ID)
        {
           StrCopy(verb,  vOpen);
					
           mouse.Mode = eModeInteract;
        }
					
        if (button == bLookat.ID)
        {
           StrCopy(verb,  vLookat);
					
           mouse.Mode = eModeLookat;
        }
					
        if (button == bPush.ID)
        {
           StrCopy(verb,  vPush);
					
           mouse.Mode = eModeInteract;
        }
					
        if (button == bClose.ID)
        {
           StrCopy(verb,  vClose);
					
           mouse.Mode = eModeInteract;
        }
					
        if (button == bTalkto.ID)
        {
           StrCopy(verb,  vTalkto);
					
           mouse.Mode = eModeTalkto;
        }
					
        if (button == bPull.ID)
        {
           StrCopy(verb,  vPull);
					
           mouse.Mode = eModeInteract;
        }
      }
    }
  }


Whoo.  A little messy, huh?  Well, what it does is first see if the interface we clicked is our SCUMM bar.

Then we check the button pressed against all the IDs the game assigns to our buttons, accessable via their ID property.

What we do here is copy the string value of the verb button into our global verb variable.  Then, we set the mouse mode equal to the relevant mode.  The reason we do this is because AGS handles clicking on objects internally based on the mode of the mouse.  We'll use this to trigger our object interaction scripts shortly.  Patience, we're almost ready!

Next, we need to set up unhandled_event().  This method gets called every time an action is performed on an object and that action has no script associated with it.  Basically, we want to reset the verb and remove EGO's active inventory object if they attempt an unhandled interaction.

Code: ags

function unhandled_event(int what, int type) {
  
  StrCopy(verb,  vWalkto);
				  
  mouse.Mode = eModeWalkto;
			
  cPlayer.ActiveInventory = null;
}


Okay, here's the ugly one.  on_mouse_click().  We need to handle clicking on stuff and updating the SCUMM bar.  First, though, go into your game's General Settings and check the box marked "Handle Inventory in script".  This tells the game to call on_mouse_click() whenever you click on the inventory pane in your SCUMM bar.  Normally, the game won't!  With this box checked, it will - passing a value of eMouseLeftInv for button.

Code: ags

function on_mouse_click(MouseButton button) // called when a mouse button is clicked. button is either LEFT or RIGHT
{
  if (IsGamePaused() == 1) // Game is paused, so scram outta the function
  {
      return;
  }
  
   if (button == eMouseLeft) 
  {
      ProcessClick(mouse.x,mouse.y, mouse.Mode);

        StrCopy(verb,  vWalkto);

        mouse.Mode = eModeWalkto;
  }
  
   if (button == eMouseRight)
  {
      string loc;
				
      GetLocationName(mouse.x,  mouse.y,  loc);
				
      if (StrLen(loc) == 0)
      {
         StrCopy(verb,  vWalkto);
				  
         mouse.Mode = eModeWalkto;
					
         cPlayer.ActiveInventory = null;
      }
   }
	
      if (button == eMouseLeftInv)
      {
         InventoryItem *item = InventoryItem.GetAtScreenXY(mouse.x, mouse.y);
		
         if (cPlayer.ActiveInventory == null)
         {			
            // depending on the verb, we may want to run the interaction on this item
					
            if ((StrComp(verb, vGive) != 0) && (StrComp(verb, vUse) != 0))
            {
                if (item != null)
                     item.RunInteraction(mouse.Mode);
            }
            else
            {
                if (StrComp(verb, vUse) == 0)
                    if (item.IsInteractionAvailable(eModeInteract) == 1)
                    {
                         item.RunInteraction(mouse.Mode);
						
                         return;
                    }
					
                    cJustin.ActiveInventory = item;
				
                    mouse.Mode = eModeUseinv;
            }
         }
         else
         {
            if (item != null)
                  item.RunInteraction(mouse.Mode);
      }
  }
}


There's currently three types of clicks we need to care about.  Left click (eMouseLeft) processes clicks in the standard way - which is good, because we want the game to do as much of the dirty work for us as possible.  Basically, as long as you've correctly set the mouse's mode and have the methods set up correctly, the AGS engine will do its thing.  We'll see how that works shortly.

A right click (eMouseRight) will eventually call the default object interaction for that object.  You can check in the AGS manual under "custom object properties" for a way to handle this - or wait for me to implement it and then update this tutorial again.  ;D  It's simple enough.  Right now, though, all the script does is reset the default verb to "Walk to" and clear any active objects if the player right-clicks on a blank spot on screen.

The biggie is a left click on the inventory, aka eMouseLeftInv.  What we do here is check if there's an inventory item under the mouse.  If so, we must have just clicked on it.  So if we don't have an active inventory item and the user is working on constructing a "Give..." or "Use..." sentence, then we want to set the player's activeInventory object to the item we just clicked on.  Otherwise, we want to run the object's interaction script.  If, however, the verb is either "Give" or "Use" and we don't already have an inventory item active (or in the case of Use, if there's no directly-defined Use interaction - we'll see how that works in a sec), we'll set the player object's activeInventory to the item we just clicked on and also set the mouse's mode to eUseinv.  Then, when we run this script again, the next time we click on an inventory object the game will automatically perform a "use item on item" interaction since activeInventory contains an object.

We're in the home stretch.  Now we have to set up the actual statusbar text and get the game to process clicks on things.

Here's how we construct the text.  First, add a label to your SCUMM bar, and make it the width of the GUI.  I called it "command".

Then, in repeatedly_execute()...

Code: ags

function repeatedly_execute() 
  {
  // put anything you want to happen every game cycle here
  
      // update SCUMM bar
		
      string target, text, line;
		
      StrCopy(target,  "");
		
      if (cPlayer.ActiveInventory != null)
            cPlayer.ActiveInventory.GetName(target);
			
      if (StrComp(verb, vGive) == 0)
            if (StrLen(target) > 0)
                  StrCat(target, " to");
			
      if (StrComp(verb, vUse) == 0)
            if (StrLen(target) > 0)
                  StrCat(target, " with");
				
      StrCopy(text, verb);
		
      if (StrLen(target) > 0)
            StrCat(text,  " ");
		
      StrCat(text, target);
		
      // FORMAT: verb (active inventory + linkword) hotspot
		
      StrFormat(line, "%s @OVERHOTSPOT@", text);
			
      command.SetText(line);
			
  }


Basically, we format a string to contain our current verb, the active inventory object (if any), a link word (for "Give (item) to..." or "Use (item) on..." interactions), and the current hotspot - which can be anything.

Finally, we need stuff to happen if the user interacts with objects.  We'll do three of them here; a "Look at" command, a "Use" command, and a "Use (item) with (something) command.

First, let's set up our player's PDA so that if he looks at it, he tells the user "I never go anywhere without my trusty PDA."

Create the inventory item, then click on "Interactions".  Under "Look at item", add a "Run Script" interaction, where the script is;

Code: ags

cPlayer.Say("I never go anywhere without my trusty CyberLink PDA.");


Okay, so what does this do, and why does it work?

When you click on the LOOK AT button on your SCUMM bar, the interface_click() method is called.  It sees that LOOK AT is the clicked button, then copies "Look at" to the verb object.  Next, it sets the mouse mode to eLookat.  Then, when the on_mouse_click() method is called for the inventory item upon being clicked on, the script sees the mouse is in eLookat mode and runs the interaction for "Look at item".  The script above runs, and our hero speaks.  Meanwhile, the SCUMM text bar reads "Look at PDA" for the duration of the action because of how we formatted the text.

Next, let's make it so our player can use his PDA to go to a cool PDA interface screen that I defined as room #2 via the "Use" command.

Click on "Interaction" for your item, then add "Run script" for the "Interact with" event.  The script is as follows;

Code: ags

if (StrComp(verb, vUse) == 0)
{
  cPlayer.ChangeRoom(2);
}
else
   cPlayer.Say("That's not how you use a PDA.");


This script first checks the active verb to make sure the player clicked "Use" in order to interact with the item, because it is also possible, using this script, to click on Push, Pull, Open, Close, or Give (and perhaps others; any time the eInteract mode is assigned to the mouse in interface_click(), this event will fire) in order to interact with the PDA.  If the player did click Use, then the PDA, the player will go to the PDA's "closeup view" room.

Now let's make it possible to give our trusty PDA away to another character, named cGuy.

Click on "Interaction" for said character.

Add an action to "Use inventory on character."  Add a condition "if inventory item was used (1)".  Instead of 1, use whatever number you assigned to the PDA.  For me, it's the first item I created, so it's 1.  Then again, add a Run Script event and make sure the verb used was Give, like so;

Code: ags


if (StrComp(verb, vGive) == 0)
{
  cGuy.say("Thanks man, but I don't need your PDA.");
}
else
{
  // the other way this script will run is if you attempt to "use PDA with Guy".  In that case...

  cGuy.say("What the heck are you doing?");
}



That's it!  Now when you click Give, then the PDA, then the other guy, your sentence bar will construct "Give PDA to (other guy's name)" and go to the new screen.  Why?  Because clicking Give puts the mouse into "interact" mode, and clicking the PDA, since we're working with the GIVE verb, sets the PDA as our active inventory item and then forces the mouse into Useinv mode instead.  Then, when we click the other guy, the game knows that since the mouse is in eUseinv mode and there's an active inventory item, to run the "use item on object" interaction.

Enjoy!
#3
from out of left field comes...

.NET PROFIT

It is the year 2055.  Justin Hunter, a security consultant freshly hired by CyberWatch Incorporated, has just been transferred to their Beijing office where most of their most hush-hush R&D occurs.

It all just goes downhill from there.










Features:

* Fully-functional CyberLink palmtop allows interaction with the local .NET
* "Jack in" to .NETspace to help solve your problems in the "real" world
* hi-color, 640x480 resolution images
* SCUMM-style interface

09/02/05 update:

Phew.  :P I had thought I'd had a functioning SCUMM gui, but as I delved deeper into interactions beyond getting the sentence constructed I realized I had something very fancy that didn't actually *work*.  I spent most of yesterday rewriting my SCUMM interaction scripts, and now it's all good.  Gonna get back to the artwork in another day or so.

Script's about 25% done, but I'm going to do the rooms and what-not on an incremental basis

09/06/05 update:

Yesterday, I finished Justin's walkcycle.  Today, I decided it sucked and redid it from scratch.  much better.  Now that Our Hero can walk and talk, it's time to modify the SCUMM interface a bit and get crackin' on the implementation of the first act!

09/10/05 Update:

SCUMM system is pretty much complete.  new screenshot of Justin in his hotel room posted to the thread.

09/12/05 update:

Replaced a few screenies showing off intro and opening cinematics. Fixed more bugs in the SCUMM system.  Oy.
#4
Okay, so I did something similar to the following (in the interaction script of an inventory object called iCyberLink);

string text, trigger, name;

command.getText(text);  // this gets the text of a GUI label

iCyberLink.getName(name);  // this gets the name of the object

StrFormat(trigger, "Use %s", name);  //this formats trigger so it reads "Use CyberLink"

if (StrComp(trigger, text) == 0)
{
   // run interaction for object if text reads "Use CyberLink"
}

Trouble is, both StrComp and StrCaseComp refuse to return 0 (indicating identical strings) when I compared trigger and text.  In fact, in no way, shape, or form could I get any combination of a literal ("Use CyberLink") and/or a variable containing the string ("Use CyberLink") to compare against a second variable containing the same text.  I even printed out both strings prior to comparing them and they did in fact have the same text in them, and in my eye, should have returned a match.

What am I overlooking?
#5
Critics' Lounge / .NET Profit - screenshot C&C
Fri 26/08/2005 05:37:05
Gents,

Here's the first screenshot of the game I'm fiddling with, a cyberpunk adventure called .NET Profit.Ã,  It's a spiritual successor (I hope) to that great classic of yore, Interplay's Neuromancer.



I'm primarily interested in a critique on the art style and sprites, since it's my first whack at anything like this, but feel free to pick apart anything you see.Ã,  I can take it.Ã,  ;D

Thanks in advance,
TG

* EDITED - new background, new EGO sprite.
#6
If so, how do I define them?

Apologies if this is in the manual, but I couldn't find it.
#7
Gents,

Let's say I've got a few situations I need to keep track of in-game, like whether or not the hero has visited six specific locations and I want to trigger some kind of event once the they've set foot on the sixth.

Now, I can think of several ways to do it.

One, I can create a global script variable called "numVisits" and bump it up every time they first enter the relevant rooms.  Two, I can stick a custom property on each room and flag it once the player enters, then loop through the rooms and check.  Or three, I can do some variation of the above.

Now, I'd wager that custom properties and special states of each object get saved when a game is saved automatically, but what about script variables?  Can I globally declare a few int counters and rely on them being the same values I set them to during gameplay when the game is restored?

Hope this makes sense, and thanks in advance.

TG
SMF spam blocked by CleanTalk