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 - duckwizard

#1
Hey,

Last week I downloaded 3.1.2 since 3.2 wasn't linked from the website (hadn't dove into the forums yet).

I got pretty far into making a game with 3.1.2 before I found out that 3.2 is available and has some nifty new features (like characters view in room editor) and is all around better.  So I grabbed 3.2 and upgraded my game.

Thankfully I made a backup because now some my GUIs are messed up.  They were just the standard GUIs from the Sierra template game.  The dropdown bar is now just completely black, and the inventory screen just has black boxes instead of buttons.

When I open the GUIs in the GUI editor they look fine.  Save/Load GUI looks fine.  My custom GUIs seem to look fine.

The game is 32-bit color, if that makes a difference.  I am planning to redo the GUIs at some point anyway, but not until near the end of development.  And it's making it hard to test that I can't see my GUIs!  Any advice?
#2
TL,DR: Need multi-frame animated turns that work even when navigating pathfinding waypoints.  Currently using a lot of PauseGame() to get the effect.  Need to know if that's OK and if there's a better way to do it.

I have a situation where it's important for my character to have multi-frame animated turns (i.e. a single diagonal frame is not sufficient).

I scanned the forums and most suggestions amounted to intercepting the walk click, firing a dummy "bullet" character from the ego's position to the click, and then use that dummy character's loop number to figure out which direction to animate to, then processing the click for the character.

After thinking about this I realized it wasn't sufficient because if the character has to navigate around a complex path, he will turn several times during that.  So with the "bullet" idea you get the initial turn (from stopped to the direction of initial walk) but you don't get animated turns while walking.

So I came up with a new idea where I have some logic in repeatedly_execute() that checks A) if the character is moving, and B) if his loop is different from his last loop.  If both these conditions are met, it should simply do the appropriate turning animation(s) to get from the old direction to the new direction.

The problem I had with this was that executing the animations using Animate() caused the actual movement to be cancelled.  So you would click and he would turn, but then he wouldn't actually walk unless you clicked again (or he was already facing that direction).  Checked the manual, and yep - Animate() stops the character if he is moving.

So I tried writing a function to do the animation manually, incrementing/decrementing the frame as appropriate and then calling Wait() in between.  Turns out Wait() doesn't pause his walking so it just ends up being really strange and not working at all.  So I added PauseGame() and UnPauseGame() calls around that to pause his walk.

Code: ags

//Animate Don't Stop
//always blocks, ignores blocking style
//always plays once, ignores repeat style
function AnimateDS(this Character*, int loop, int delay, RepeatStyle rep,  BlockingStyle block, Direction dir)
{
  this.Loop = loop;
  int numFrames = Game.GetFrameCountForLoop(this.View, this.Loop);
  
  
  if(dir == eBackwards)
  {
    this.Frame = numFrames - 1;
    while(this.Frame > 0)
    {
      PauseGame();
      Wait(delay);
      UnPauseGame();
      this.Frame--;
    }
  }
  else
  {
    this.Frame = 0;
    while(this.Frame < numFrames - 1)
    {
      PauseGame();
      Wait(delay);
      UnPauseGame();
      this.Frame++;
    }
  }
  
  PauseGame();
  Wait(delay);
  UnPauseGame();
}


The good news is, it works perfectly.  Animated turns work even while navigating a complex path.

The bad news is, I feel really unsure about subverting PauseGame() to this effect.

This effect is only necessary for a small part of the game (when the character is on a horse) and I don't *think* there will be much background stuff happening (which would get artificially choppy when the turning was happening) but even so it feels wrong to me.

So my question is - what reasons are there why doing this could be bad?  And is there a simpler way to effect animated turns, even while navigating, without resorting to this?
#3
Advanced Technical Forum / Callbacks
Thu 10/03/2011 23:43:18
I wasn't able to use QueueScriptFunction for what I originally wanted, but it did come in handy for something else - namely callbacks.

This is a really simple plugin (surprised it hasn't been done already, judging by my scan of the plugins board).  It exports two functions

void ExecuteFunction(String fnName, int global)
void ExecuteFunctionParam(String fnName, int global, int param)

The first form just executes the function called fnName.  If global is zero, it executes that function in the current room script.  Otherwise, it executes that function in the global script.

The second form does the same, but allows you to pass a single int parameter to the function you want to call.

Here is the DLL if anyone is interested.

Example use case for callbacks:

My character has a wallet with a certain amount of money in it.  When he uses the wallet on something, I want a GUI to come up that asks him how much money he wants to give.  The GUI has a "give" button that closes the wallet GUI.  And then what happens?

Without callbacks, you probably stored some variable that said whom or what you were giving the money to. Then, in the WalletGiveButton_OnClick handler you do ALL the logic for every possible thing you could give money to.

With callbacks, your OpenWallet function takes the name of the function that you want to be called when money is given:

Code: ags

//room5.asc
function oBeggar_UseInv()
{
	if(cEgo.ActiveInventory == iWallet) // not an apple product (yet)
	{
		OpenWallet("gaveBeggarMoney");	
	}
}

function gaveBeggarMoney(int howMuch)
{
	if(howMuch < 20)
	{
		Display("What a cheapo!");	
	}
	else
	{
		BeggarGivesTreasureMapOrSomething();	
	}	
}

//GlobalScript.asc
String walletCallback;
function OpenWallet(String roomCallback)
{
	walletCallback = roomCallback;
	gWallet.Visible = true;
}

function btnWalletGive_OnClick()
{
	if(walletCallback == null) return;
	ExecuteFunctionParam(walletCallback, 0, sldWalletAmount.Value);
	walletCallback = null;
	gWallet.Visible = false;
}



Now whenever you want to open the wallet from any room script, you can just pass in a string with the name of the room function that you want to be called when the player has selected the money amount.  The money amount will be passed in to that function.  Whee!

Tiny source code (didn't bother to rename the template source file)

Hereby public domain (on my end anyway - source contains a copyright message from CJ), feel free to use, improve, or lambaste me for making something useless :)

For example, you could add a way to call a function with two parameters as that's supported by QueueScriptFunction.  But I don't have a need for it right now, so I didn't.

Edited: forgot to clean up wallet GUI in use case code; it probably would have crashed.  Be careful :)
#4
I have a spot that when you interact with it, it causes cEgo to walk there and play an animation to sit down.  That works great.

But now I want it so if you walk somewhere else, he will play a "stand up" animation before he starts to walk.

I tried making a 1 pixel region where he is programmed to sit, and when cEgo leaves that region it plays the stand up animation.  But by that time he is already walking, so it's too late for this to work.

I could work around this by disabling walk and forcing you to interact with something (like the rest of the floor I guess) in order to stand up, then re-enabling walk.  But that is not ideal.  So I thought I would check if anyone has ideas for making this happen.

There is probably something I could do with invisible dummy characters or dummy objects.  I will try to mess with that.  But I'm hoping there's an elegant solution because I am a little OCD when it comes to inelegance and I go to great (even ridiculous) lengths to avoid it.
#5
Not sure if this belongs in the Module forums instead, but it is pretty Technical :)

I was kind of bummed on the way character events are only handled in the global script - it seemed like it would be far more useful if they could be handled in the room script instead (so characters can do different things in different rooms without having a giant mess of if/else in their single event handler).

So I wrote a simple plugin that lets you dispatch an unhandled event to the room script from unhandled_event().  When there is an unhandled event, it will figure out the character (or object) name and the action that wasn't handled, and then it will try to call the corresponding function in the room script.

Example: You have a character called cChrisJones.  When you're in room 1 and you look at him, he should say "You're in room 1!" and when you're in room 2 he should say "Toto, I've a feeling we're not in room 1 anymore!":

Code: ags

//room1.asc
function cChrisJones_Look()
{
        cChrisJones.Say("You're in room 1!");
}

//room2.asc
function cChrisJones_Look()
{
        cChrisJones.Say("Toto, I've a feeling we're not in room 1 anymore!");
}


I compiled my plugin and it works great out-of-the-box.  Except for one thing.  If I had a room with cChrisJones in it, and I didn't supply a cChrisJones_Look() function in that room script, it crashes because I'm trying to call a function that doesn't exist.

So my question is: is there any way to check if the function exists before I call it with QueueGameScriptFunction?

Thanks!

Edited: forgot to close my code block
#6
Is there any way to return a struct from a function?

MyStruct foo() { ... } gives me "Cannot return entire struct from function."
MyStruct* foo() { ... } works if I make MyStruct a managed type, but then I can't create a MyStruct.

What should I do?
#7
Currently AGS matches the center point of the loop with the X coordinate of the character.  What would be really fun is if each loop could have an X "anchor" value that would specify an alternate point to use instead.

The reason I think this would be neat is for when you have a lot of loops in a view where the feet don't necessarily line up with the feet in the other loops.  For example your talking loop might be really slim if the guy has his arms at his sides, and that loop fits naturally because there is no space on either side of him.  But if you have another loop where he gestures to one side, then you'll have a bunch of space on that side for his arm to move around.  You either have to edit all your sprites in order to pad the other side of the guy, or you have to adjust the character's X coordinate before you run the loop.  Otherwise, the guy will "jump" to one side while that loop plays and then jump back when you switch back to the normal loop.

In fact it might be cool if you had both an X and a Y that you could use to anchor the loop.  But even just the X coordinate would be awesome.

Just something to consider if the contributors have too much time on their hands :)
#8
I've written a script that uses DialogOptionsRenderingInfo functions to render my own dialog options window.  It is working great (thanks for asking) except for one thing: if the DialogToRender has text parser enabled, I want to make extra room on the bottom of the window for the text box.  If not, I don't want that extra space.  But I cannot figure out how I can get the value of that option.  The Dialog managed type does not have a property that corresponds to the ShowTextParser property from the dialog's property sheet.

Any advice?

Thanks!
#9
I have some animated GIFs that I exported from an SCI game.  I have been trying for hours to get them to import properly using Quick Import GIF Frames and I can't quite seem to get it right.

First of all, the reason that I'm using GIF frames is that the SCI export tool positions each frame within the animated GIF properly so that I won't have characters moving around within the loop when they're not supposed to.  So if I can figure out how to use the GIF frames feature properly, it will save me a lot of time in the long run.

First problem: Stuff from previous frames shows up in subsequent frames, if the subsequent frame is smaller than the previous one.  This one can be solved using Filters -> Animation -> Unoptimize in GIMP.  Took me a while to figure that one out.

Next problem: Transparency.  My game is in True Color mode.  Obviously the GIFs are indexed color.  I have tried every combination of:
1. Make the transparent color be the first palette entry.  This didn't work; it just makes it black where it should be transparent.
2. Making the transparent color be the first palette entry, AND making sure it is #FF00FF even though it displays as transparent.  Same as above.
3. Making no transparency in the GIF and filling in #FF00FF instead of transparency.  Now I just get sprites surrounded by #FF00FF.

I have always made sure that the top-left pixel of each frame is the color that ought to be transparent.

So my question is: what is the precise behavior of this utility?

Edit: (before I even finished posting) I think I figured out what I was doing wrong.  "Quick Import" seems to take the transparency settings that you last used.  I couldn't find documentation on that, but I had previously imported a sprite with "No Transparency", so manually importing a sprite with proper transparency settings and then re-importing my GIF frames (with #FF00FF filled in to transparent areas) has solved the issue.  I'm going to post this anyway in case someone else has the same issue and does a forum search.

For SCI-exported GIFs, the Unoptimize filter in GIMP seems to be sufficient for good import (i.e. you don't have to fill in #FF00FF everywhere).
SMF spam blocked by CleanTalk