Hi,
I modified the guiPortrait module a bit and I was wondering if someone had an idea on how to add the speed for blink frames...right now this is ignored, so if I place a delay of 40 on a certain blink frame, the animation ignores it completly. SSH is currently too busy to help me out with this so Ive been trying on my own for a while now...and well...I suck! heheh
I think I have to do something with the ".Speed" command, but Im not too sure how to implement it. To test, if I remove the "Portrait_vf.Speed" part in these lines: Portrait_Counter = (Portrait_AnimSpeed + Portrait_vf.Speed + 1);
, the script no longer takes into account the delays in the speech views either, so I believe somehow I need to do something like that, but for the blinking (which I really dont know how to proceed, Ive been trying all night... :-[)
function Portrait_DoFrame()
{
Portrait_vf = Game.GetViewFrame(Portrait_View, Portrait_Loop, Portrait_Frame);
bool flip = Portrait_vf.Flipped;
// Something like:
if (Portrait_AutoFlip && Portrait_AtRight) flip =! flip;
Portrait_Mod = DynamicSprite.CreateFromExistingSprite(Portrait_vf.Graphic, true);
if (Portrait_BlinkTimer == 0)
{
DrawingSurface *mod = Portrait_Mod.GetDrawingSurface();
Portrait_bvf = Game.GetViewFrame(Portrait_BlinkView, Portrait_BlinkLoop, Portrait_BlinkFrame);
mod.DrawImage(0, 0, Portrait_bvf.Graphic);
mod.Release();
Portrait_BlinkFrame++;
if (Portrait_BlinkFrame == Game.GetFrameCountForLoop(Portrait_BlinkView, Portrait_BlinkLoop))
{
Portrait_BlinkTimer = Portrait_BlinkInterval;
Portrait_BlinkFrame = 0;
}
}
// Flip AFTER blink, if required
if (flip) Portrait_Mod.Flip(eFlipLeftToRight);
Portrait_GUI.BackgroundGraphic = Portrait_Mod.Graphic;
}
function repeatedly_execute_always()
{
if (Portrait_Counter == 0)
{
Portrait_Frame++;
if (Portrait_Frame == Game.GetFrameCountForLoop(Portrait_View, Portrait_Loop)) Portrait_Frame = 0;
Portrait_DoFrame();
Portrait_Counter = (Portrait_AnimSpeed + Portrait_vf.Speed + 1);
}
else if (Portrait_Counter >= 0) Portrait_Counter--;
if (Portrait_BlinkTimer > 0) Portrait_BlinkTimer--;
}
// TBD: Animate
// Check for flipped frames
// Blinking: goes on top of speech view
function GSay(this Character*, String what, int view, int loop)
{
if (view < 1) view = this.SpeechView;
Portrait_Frame = 0;
Portrait_Loop = loop;
Portrait_View = view;
Portrait_AnimSpeed = this.SpeechAnimationDelay;
int positioning = GetGameOption(OPT_PORTRAITPOSITION);
int x;
//Left
if (positioning == 0) Portrait_AtRight = false;
//Right
else if (positioning == 1) Portrait_AtRight = true;
//Alternate
else if (positioning == 2)
{
if (this != Portrait_Last_Talker) Portrait_AtRight =! Portrait_AtRight;
}
// Based on Character Position Relation to the Main Player
else
{
if (this == player)
{
player.SetupCharacterPortrait(playerFaceAnim, playerClothes, playerProp);
if (BasePortrait_BASE.BackgroundGraphic != 372) BasePortrait_BASE.BackgroundGraphic = 372;
if (this.x <= partner.x) Portrait_AtRight = false;
else if (this.x > partner.x) Portrait_AtRight = true;
}
else if (this == partner)
{
//Display("Partner's Clothes being st to: %d", partnerClothes);
partner.SetupCharacterPortrait(partnerFaceAnim, partnerClothes, partnerProp);
if (partner == cDispatcherA) BasePortrait_BASE.BackgroundGraphic = 1105;
else if (BasePortrait_BASE.BackgroundGraphic != 372) BasePortrait_BASE.BackgroundGraphic = 372;
if (this.x >= player.x) Portrait_AtRight = true;
else if (this.x < player.x)Portrait_AtRight = false;
}
}
Portrait_DoFrame();
if (Portrait_AtRight == true)
{
x = (System.ViewportWidth - Game.SpriteWidth[Portrait_vf.Graphic] - Portrait_Right_Indent);
BasePortrait_FRAME.X = x;
if (this == player)
{
BasePortrait_PLAYERCLOTHES.X = x;
BasePortrait_PLAYERPROPS.X = x;
}
else if (this == partner)
{
BasePortrait_PARTNERCLOTHES.X = x;
BasePortrait_PARTNERPROPS.X = x;
}
}
else if (Portrait_AtRight == false)
{
x = Portrait_Left_Indent;
BasePortrait_FRAME.X = Portrait_Left_Indent;
if (this == player)
{
BasePortrait_PLAYERCLOTHES.X = Portrait_Left_Indent;
BasePortrait_PLAYERPROPS.X = Portrait_Left_Indent;
}
else if (this == partner)
{
BasePortrait_PARTNERCLOTHES.X = Portrait_Left_Indent;
BasePortrait_PARTNERPROPS.X = Portrait_Left_Indent;
}
}
Portrait_GUI.X = x;
Portrait_GUI.Y = Portrait_Sierra_Y;
BasePortrait_BASE.X = x; //ACL MODIFICATIONS
BasePortrait_BASE.Y = Portrait_Sierra_Y; //ACL MODIFICATIONS
SetGameOption(OPT_PORTRAITPOSITION, Portrait_AtRight);
BasePortrait_BASE.Visible = true;
if(BasePortrait_BASE.BackgroundGraphic == 1105 )
{
BasePortrait_BASE.LockView(19);
BasePortrait_BASE.Animate(0, 5, eRepeat, eNoBlock);
}
else BasePortrait_BASE.UnlockView(false);
BasePortrait_FRAME.Visible = true;
if (this == player)
{
BasePortrait_PLAYERCLOTHES.Visible = true;
BasePortrait_PLAYERPROPS.Visible = true;
}
else if (this == partner)
{
BasePortrait_PARTNERCLOTHES.Visible = true;
BasePortrait_PARTNERPROPS.Visible = true;
}
Portrait_GUI.Visible = true;
Portrait_Counter = (Portrait_AnimSpeed + Portrait_vf.Speed + 1);
if (this.BlinkView > 0)
{
Portrait_BlinkTimer = this.BlinkInterval;
Portrait_BlinkInterval = this.BlinkInterval;
Portrait_BlinkView = this.BlinkView;
Portrait_BlinkLoop = 0;
Portrait_BlinkFrame = 0;
}
else Portrait_BlinkTimer = -1;
this.Say(what);
BasePortrait_BASE.Visible = false;
BasePortrait_FRAME.Visible = false;
if (this == player)
{
BasePortrait_PLAYERCLOTHES.Visible = false;
BasePortrait_PLAYERPROPS.Visible = false;
}
else if (this == partner)
{
BasePortrait_PARTNERCLOTHES.Visible = false;
BasePortrait_PARTNERPROPS.Visible = false;
}
Portrait_GUI.Visible = false;
SetGameOption(OPT_PORTRAITPOSITION, positioning);
Portrait_Counter = -1;
Portrait_BlinkTimer = -1;
player.SetupCharacterPortrait(playerFaceAnim, playerClothes, playerProp);
}
In rep_ex_always, Portrait_BlinkTimer is decreased by one every loop unless it is 0.
In DoFrame, look at these lines:
Portrait_BlinkFrame++;
if (Portrait_BlinkFrame == Game.GetFrameCountForLoop(Portrait_BlinkView, Portrait_BlinkLoop))
{
Portrait_BlinkTimer = Portrait_BlinkInterval;
Portrait_BlinkFrame = 0;
}
So what's done here is every time a new frame of the speech animation is drawn, IF BlinkTimer has already reached 0 by then, the blinking animation is advanced a frame. The blinking timer is then reset to Portrait_BlinkInterval IF the animation has reached its last frame, which is frame 1 of a total of 2, I guess the module assumes.
Try this:
Portrait_BlinkFrame++;
if (Portrait_BlinkFrame == Game.GetFrameCountForLoop(Portrait_BlinkView, Portrait_BlinkLoop))
{
Portrait_BlinkTimer = Portrait_BlinkInterval;
Portrait_BlinkFrame = 0;
}
else {
ViewFrame*v = Game.GetViewFrame(Portrait_BlinkView, Portrait_BlinkLoop, Portrait_BlinkFrame);
Portrait_BlinkTimer = v.Speed;
}
Hey Khris!
Ok, well I tried that and it works, but partially (but I most prob did something wrong somewhere).
It now seems to take into account the delays, but it also seems to "reset" the loop after a few frames only depending on what the character says...it seems that the full loop doesnt have time to display itself fully...so instead of getting 14 frames of animation in loop 0, it seems only the first few frames get animated. They have delays of 40 frames each, approx.
Does it have something to do with modifying these lines in the function GSay to get it to work (Portrait_BlinkTimer here should contain the .Speed too?)
if (this.BlinkView > 0)
{
Portrait_BlinkTimer = this.BlinkInterval;
Portrait_BlinkInterval = this.BlinkInterval;
Portrait_BlinkView = this.BlinkView;
Portrait_BlinkLoop = 0;
Portrait_BlinkFrame = 0;
}
else Portrait_BlinkTimer = -1;
Quoteanimation has reached its last frame, which is frame 1 of a total of 2, I guess the module assumes.
--can we add a script where it wont assume 2 frames, but gets the real number of frames the blink loop actually contains?
Well, the original script did that (get the actual number of frames), it just skipped the rest of the frames because it left BlinkTimer having a value of 0.
My small change is supposed to change that so that the complete loop is shown.
I don't see with that code how the length of the text would influence how much of the blink loop is displayed (except when the text is very short, of course).
The only thing I can think of is you assumed a base speed although I didn't implement one and left some frame speeds set to 0.
crap I retested with the added code and 1 frame with a delay of 120 (to debug) and it doesnt take into account that delay.
So, crap...sorry, actually it doesnt fix the prob! :-[
The least complicated way to solve this is to simply separate the talk animation completely from the blinking animation. This requires rewriting Portrait_DoFrame() and repeatedly_execute_always() a bit.
I guess it's best to put the eye part of the sprite on a button as big as the GUI to avoid messing about with composing DynamicSprites.
You basically just need to duplicate the code for the speech animation but use the blinking view and the button instead of the talking view and the GUI background.
I might give this a shot tomorrow, but it shouldn't be too hard to do yourself.
Hmm, creative idea. Ok Ill try that tonight to see what I can do...if I fail miserably Ill post about how much I suck tomorrow morning! :)
Ok so I made a button the same size as the portrait gui (btn_BlinkView). I got the blinkview now drawn onto it, the only thing is, the blink frame stays drawn on the button "forever"...doesnt get "cleared" so we dont see the blink turn off. This is what I got so far (from your suggestion):
function Portrait_DoFrame()
{
Portrait_vf = Game.GetViewFrame(Portrait_View, Portrait_Loop, Portrait_Frame);
bool flip = Portrait_vf.Flipped;
// Something like:
if (Portrait_AutoFlip && Portrait_AtRight) flip =! flip;
Portrait_Mod = DynamicSprite.CreateFromExistingSprite(Portrait_vf.Graphic, true);
// Flip AFTER blink, if required
if (flip) Portrait_Mod.Flip(eFlipLeftToRight);
Portrait_GUI.BackgroundGraphic = Portrait_Mod.Graphic;
}
function Portrait_DoBlinkFrame()
{
Portrait_bvf = Game.GetViewFrame(Portrait_BlinkView, Portrait_BlinkLoop, Portrait_BlinkFrame);
bool flip = Portrait_bvf.Flipped;
// Something like:
if (Portrait_AutoFlip && Portrait_AtRight) flip =! flip;
// Flip AFTER blink, if required
if (flip) Portrait_bMod.Flip(eFlipLeftToRight);
btn_BlinkView.NormalGraphic = Portrait_bvf.Graphic;
}
function repeatedly_execute_always()
{
if (Portrait_Counter == 0)
{
Portrait_Frame++;
if (Portrait_Frame == Game.GetFrameCountForLoop(Portrait_View, Portrait_Loop)) Portrait_Frame = 0;
Portrait_DoFrame();
Portrait_Counter = (Portrait_AnimSpeed + Portrait_vf.Speed + 1);
}
else if (Portrait_Counter >= 0) Portrait_Counter--;
if (Portrait_BlinkTimer == 0)
{
Portrait_BlinkFrame++;
if (Portrait_BlinkFrame == Game.GetFrameCountForLoop(Portrait_BlinkView, Portrait_BlinkLoop)) Portrait_BlinkFrame = 0;
Portrait_DoBlinkFrame();
Portrait_BlinkTimer = (Portrait_AnimSpeed + Portrait_bvf.Speed + 1);
}
else if (Portrait_BlinkTimer >= 0) Portrait_BlinkTimer--;
}
Quote from: general_knox on Tue 14/09/2010 04:09:37
Ok so I made a button the same size as the portrait gui (btn_BlinkView). I got the blinkview now drawn onto it, the only thing is, the blink frame stays drawn on the button "forever"...doesnt get "cleared" so we dont see the blink turn off.
You aren't using the DynamicSprite.
This should work:
function Portrait_DoBlinkFrame()
{
Portrait_bvf = Game.GetViewFrame(Portrait_BlinkView, Portrait_BlinkLoop, Portrait_BlinkFrame);
bool flip = Portrait_bvf.Flipped;
// Something like:
if (Portrait_AutoFlip && Portrait_AtRight) flip =! flip;
Portrait_bMod = DynamicSprite.CreateFromExistingSprite(Portrait_bvf.Graphic, true); // <-- this line was missing
// Flip AFTER blink, if required
if (flip) Portrait_bMod.Flip(eFlipLeftToRight);
btn_BlinkView.NormalGraphic = Portrait_bMod.Graphic; // <-- DynSprite is put on button, not original frame
}
Perfect, thanks for all your help Khris!