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

Messages - monkey0506

#221
Does File.Exists support $SAVEGAMEDIR$? By default the save games are named "agssave.XXX" (IIRC), so you should be able to pretty easily do:

Code: ags
if (File.Exists(String.Format("$SAVEGAMEDIR$/agssave.%03d", slot)))
{
  // ...
}
#222
The Rumpus Room / Teach me Trigonometry
Fri 10/04/2015 16:28:02
My only experience with trig was in Pre-Calculus in high school, 10 years ago. I am now finally enrolled in college, and I am considering taking trigonometry over the course of a 3 week mini-mester, starting next month. In preparation for that, teach me everything about trig, sage AGSers!

Thanks!
#223
If you need coordinates relative to the player, why not just use the player's coordinates?

Code: ags
player.Walk(player.x + 5, player.y); // sidestep to the right by 5 px
player.Walk(player.x - 5, player.y); // sidestep to the left by 5 px
player.Walk(player.x, player.y + 5); // step toward the bottom of the screen by 5 px
player.Walk(player.x, player.y - 5); // step toward the top of the screen by 5 px
#224
You said you solved the photos disappearing in an ugly way, but didn't post any code. Just for reference, here's how I'd do it:

Code: ags
function oPhotos_AnyClick()
{
  // do stuff
}

function on_mouse_click(MouseButton button)
{
  if (button == eMouseLeft) // TODO: modify this to prevent conflict with global on_mouse_click, etc.
  {
    if (Object.GetAtScreenXY(mouse.x, mouse.y) != oPhotos)
    {
      oPhotos.Visible = false;
    }
  }
}

function on_event(EventType event, int data)
{
  if ((event == eEventGUIMouseDown) || (event == eEventGUIMouseUp))
  {
    oPhotos.Visible = false;
  }
}


Not too messy, I think.
#225
The module might reset it (so you might have to modify the module code), but it seems like the GUI.Clickable and Button.Clickable properties are being set to false, while you want them to be set to true if there is an image on the buttons. If you simply try setting them clickable again, does that work?

Code: ags
  // set the button graphics...then...
  gYOURGUIHERE.Clickable = true;
  btnYOURBUTTONHERE.Clickable = true;
#226
Hey! Thanks for the feedback, everyone. The team really appreciated it. This was the first time for all of us attempting this, and so there's definitely a lot that could be improved.

Unless I'm mistaken, today is the day we are showing off our work to the rest of the class, so our fingers are crossed that they have similarly positive things to say about it. All-in-all, it's really been a fun experience!

(Will post a link to the full video later, for those interested)
#227
Okay. Let's start over.

1) What code do you currently have?
2) What results do you expect?
3) What results do you get? Include any error messages you might get as well.
#228
I don't think layout modifications would be off-the-table yet, so long as there's no need to introduce whole new classes or libraries.

The issue of the Events pane being "hidden" inside the Properties pane is something that is (in my experience, anyway) extremely common. The only IDEs I've really used for any type of GUI development have been Visual Studio (C++ and C#) and Eclipse (Java) (Edit: That is, the official WindowBuilder plugin for Eclipse). Both of these IDEs have the same behavior, where there is a Properties pane with a button you click to access the Events for the selected item.

It may be possible to allow dragging that out to a separate window/tab. Probably the best person to ask about that would be tzachs. But in any case, I don't really find it "gimmicky" so much as I find it familiar...
#229
I could be wrong about this, but I don't think that Object.Animate starts from the current frame. I believe it always starts from frame 0 of the specified loop.

In any case, you do not need to use loops to track the state of a single variable.

You also should not use the object array in room scripts, because referring to the objects by ID makes your code less readable and thereby more error-prone.

What would probably be the simplest thing to do is to use a character instead of an object, as characters already persist across rooms. If you insist on using an object, you'll probably have to handle animating it (at least to the end of its loop) manually.
#230
I'm a bit confused now...is this problem solved?

Also please don't quote the entire post you are responding to. We generally just quote specific portions of posts for emphasis. Quoting the entire post (especially when it's the post right above yours) is rather distracting.
#231
When you say that you named the protagonist Donovan, is Donovan actually selected as the player character? That is, in Donovan's Character tab in the editor, is the "This is the player character" box checked?

If so, does the function "hfencegate_Interact" actually appear in the Events pane (click the Lightning bolt icon in the Properties pane) of hfencegate?

If so, is the function executing? You can easily tell this by putting:

Code: ags
Display("CHANGING ROOMS....");


Just above the call to ChangeRoomAutoPosition.

If that isn't being called, could you post the on_mouse_click function from your GlobalScript, as well as tell us any templates or modules you may be using?

There's a lot of things to consider as to why this might not be working. ;)
#232
This is far from what I originally envisioned, but I'm pretty happy with how it came out given the time constraints and such.

http://i.imgur.com/d58cpeJ.gifv

This is slightly lower quality as I exported it as a GIF animation, which Imgur converted back to a video anyway, and it lacks the sound effects. Still, curious what people think of it.

This is my first-ever attempt at stop-motion, and we can't really make changes now, but feedback is appreciated. :)
#233
Quote from: Crimson Wizard on Wed 25/03/2015 08:31:35Hi, please don't do "#if (__cplusplus <= 199711L)" in the local function code. Since the type is common (a set of strings) make a typedef in the global header instead.
You may see Common/util/string_types.h for the reference.

This is also because you would need to include different header for GCC.

(I wish we could do template typedefs, but that does not work in C++03)

I did put a comment that the conditional compilation shouldn't really exist inside the local function. What might make the most sense would be to add a conditional macro (in a header, of course) to select either std::tr1 or std depending on whether C++11 is supported. This would be sufficient to still use the actual templates in lieu of alias templates in C++03.

Quote from: Crimson Wizard on Wed 25/03/2015 08:31:35
Quote from: monkey_05_06 on Wed 25/03/2015 05:33:13
Code: cpp

    // TODO: REPLACE char** GameState::do_once_tokens with unordered_set* GameState::do_once_tokens
    //     NOTE: use a pointer to the unordered_set to preserve the size of the GameState struct (VS2008 reports sizeof(unordered_set) at 64)
    // TODO: REMOVE int GameState::num_do_once_tokens (now available as GameState::do_once_tokens->size())
    return play.do_once_tokens->insert(token).second; // all we need to know is whether insertion took place
}


GameState::num_do_once_tokens would probably be best left as an additional reserved space, since I know how touchy AGS is about struct layouts.

Is there any reason why anyone would object to this? Storing a pointer to the unordered_set isn't necessarily ideal, but it does preserve the existing layout and doesn't incur additional overhead as dereferencing was taking place anyway.

There is no problem in replacing this part of the GameState struct, because it's not referenced in script, nor exported to plugin API. Only upper part of the struct is. See my comments inside the struct like "up to here is referenced in the script "game." object". Therefore you do not need to use the "pointer trick" in this case.

The save game should not store any actual pointers (this was fixed long ago), it saves 0 always. It needs just to save the number of tokens, meaning the format won't change with this modification.

I see, that's good to know.

Quote from: Crimson Wizard on Wed 25/03/2015 08:31:35Regarding removing string limits, you may reference changes to the GUI name length:
Code: cpp
    if (gui_version < kGuiVersion_340)
    {
        Name.WriteCount(out, GUIMAIN_NAME_LENGTH);
        OnClickHandler.WriteCount(out, GUIMAIN_EVENTHANDLER_LENGTH);
    }
    else
    {
        StrUtil::WriteString(Name, out);
        StrUtil::WriteString(OnClickHandler, out);
    }


Checking game data version should work for now. In the future, if the save format is replaced, the individual format number for Game State could be used.

Thanks for the tip. I'll go ahead and make these changes then.
#234
This recent post in the Beginner's forum got me thinking about the implementation of Game.DoOnceOnly, and I came across this:

Code: cpp
int Game_DoOnceOnly(const char *token)
{
    if (strlen(token) > 199)
        quit("!Game.DoOnceOnly: token length cannot be more than 200 chars");

    for (int i = 0; i < play.num_do_once_tokens; i++)
    {
        if (strcmp(play.do_once_tokens[i], token) == 0)
        {
            return 0;
        }
    }
    play.do_once_tokens = (char**)realloc(play.do_once_tokens, sizeof(char*) * (play.num_do_once_tokens + 1));
    play.do_once_tokens[play.num_do_once_tokens] = (char*)malloc(strlen(token) + 1);
    strcpy(play.do_once_tokens[play.num_do_once_tokens], token);
    play.num_do_once_tokens++;
    return 1;
}


Yikes!

I don't think that CJ was using anything (at all) from the TR1 namespace, but C++11's unordered_set is available with VS2008 in the TR1 namespace (which I know is now used in some places), and seems like it would be vastly more efficient for this.

The implementation could simply be changed to:

Code: cpp
#include <unordered_set>
#include <string>

int Game_DoOnceOnly(const char *token)
{
    // TODO: move these typedefs somewhere more useful :P
#if (__cplusplus <= 199711L)
    typedef std::tr1::unordered_set<std::string> unordered_set;
#else
    typedef std::unordered_set<std::string> unordered_set; // don't use "using" syntax here to avoid additional checks for VS versions earlier than 2013
#endif
    if (strlen(token) > 199) // TODO: remove this limit from save game format?
        quit("!Game.DoOnceOnly: token length cannot be more than 200 chars");
    // TODO: REPLACE char** GameState::do_once_tokens with unordered_set* GameState::do_once_tokens
    //     NOTE: use a pointer to the unordered_set to preserve the size of the GameState struct (VS2008 reports sizeof(unordered_set) at 64)
    // TODO: REMOVE int GameState::num_do_once_tokens (now available as GameState::do_once_tokens->size())
    return play.do_once_tokens->insert(token).second; // all we need to know is whether insertion took place
}


GameState::num_do_once_tokens would probably be best left as an additional reserved space, since I know how touchy AGS is about struct layouts.

Is there any reason why anyone would object to this? Storing a pointer to the unordered_set isn't necessarily ideal, but it does preserve the existing layout and doesn't incur additional overhead as dereferencing was taking place anyway.

Game.DoOnceOnly likely isn't used as a speed-critical method, but this seems to me like a relatively simple optimization.

P.S. This would, of course, require other minor modifications, such as changing the method that writes the tokens to a save game, but iterating the unordered_set is extremely simple as well.
#235
I don't have the time or the knowledge to work on this, but I had an idea that could maybe prove useful for implementing proper forward declarations. We already have all of the syntax and keywords that are needed (import and export are sufficient there), the problem AFAICT is that when a user tries to reference an imported item before it has been fully defined the engine isn't linking it properly.

I could be totally off-base here, but it seems like the compiler (which is also acting as the linker, isn't it?) should be able to tell at compile-time whether or not an invocation of an imported item has been appropriately linked to the full definition. Assuming that is correct (and eating my foot if it's not), then the compiler should be able to keep track of imports that aren't linked.

From that point (if I haven't derailed completely yet), it seems that the compiler should be able to just make one more pass through the symbols that have been fully defined, and check for any matching definitions. If it finds a matching definition, then it can link it.

Any thoughts on this? Could it work this way?
#236
Quote from: Snarky on Sun 22/03/2015 09:40:35I discovered an interesting wrinkle on this when refactoring some code. For a function, you would usually put the import statement in the header of the script that defines it. But you don't actually have to. As long as there is an import before you try to use it, it will be fine. For example, if I have three script modules: UsefulModule.acs, MagicModule.acs and DoStuff.acs, and there is a function called fixLights() in UsefulModule that is not declared in the header, but the MagicModule header for some reason says "import void fixLights();", then you can call fixLights() from DoStuff, and it will run the code in UsefulModule.

This is actually the expected behavior. imports don't even have to appear in a header (ever). IIRC it just simply imports the first matching definition. As an example, if ScriptA defines a function but does not have an import for the function in its header, then ScriptB may define an exactly identical function without causing any problems (as long as ScriptB's header similarly does not import the function). You could then have an import in ScriptC's header, ScriptC's main script file, or even in a room script file, and (again, IIRC) the import would refer exclusively to ScriptA's function and ignore changes to ScriptB's function. I believe that SSH encountered this with the BackwardsCompatibility module, where he inadvertently was pulling deprecated functions back into scope rather than redefining them (which was his original intention). Pumaman said that this was by-design (the deprecated functions just simply lack imports, but otherwise could be used at will).

The import may appear before or after the function, in any script or script header. If an import appears in a script header, then it will be included in all subsequent scripts (additional imports of the same item will cause an "already defined" compile error).

The imported item cannot be used in any script prior to its definition.

In a manner of speaking, you can think of import in AGS as being similar to C++'s extern, with the main difference being that AGS lacks proper forward declaration. Attempting to use the imported item before its full definition will cause a failure to link, and an "unresolved import" error. Understanding the difference between declaration and definition is helpful here, with a note that AGS doesn't allow you to use anything that isn't fully defined.
#237
Here's something I came across a couple days ago. I am a native (American) English speaker, but it kind of bothers me when I see or (shudder) use contractions inside of a hashtag. Granted, I don't use hashtags very often, and when I do it's usually meant as a joke more than anything else.

The other day I was posting (to Facebook) about working out, and I was quite exhausted, so I appended the hashtag, "#pleaseexcusemewhileImdead". Including the apostrophe would break the hashtag, but saying, "while I am dead" just sounded excessively formal.

Obviously hashtags aren't even remotely proper grammar, but I was curious what the general convention is for cases like this. :-\
#238
I'm fairly certain that the 9 verb template uses hard-coded sprite values. Not sure if they can be customized, you might check the template's headers (under the "Scripts" branch, look for a header referencing those sprite numbers). I don't have AGS handy ATM or I'd check.
#239
Quote from: Ghost on Mon 23/03/2015 03:09:52DoOnceOnly takes a string as parameter; it's up to you what you type but IIRC it must be unique.

The parameter to Game.DoOnceOnly has to be unique to the condition. It's perfectly legal to have a usage like:

Code: ags
void SomeFunction()
{
  if (Game.DoOnceOnly("didthething")) {}
}

void SomeOtherFunction()
{
  if (Game.DoOnceOnly("didthething")) {}
}


The point is that you are creating a condition that will only run once per game, but there are valid cases where you might need to check that same condition in more than one place.

Also note that since the condition is actually a string, you can name it pretty much anything from "Has the player done that thing with the inventory item yet?" to "123", so you don't have to restrict yourself to valid variable names.
#240
Quote from: Andail on Fri 20/03/2015 11:00:39Unless "Century" is a name of your boat, and you've owned 20 before, you spell it century, lower case c.





20th Century Fox

Only because you gave such a specific example about boats... :P Obviously, any time (not just pertaining to boats) it's being used as part of a name (and isn't being stylized for aesthetic purposes), then the first letter should be capitalized.

As an additional note (an an unabashed attempt to have something actually relevant to post), even in its anglicized form ("century"), the Roman "centuria" is not capitalized either.

And I've also just realized that "anglicized" isn't capitalized (unlike "Anglican"). (roll) The more you know...
SMF spam blocked by CleanTalk