Author Topic: Problem writing magic token functions [SOLVED]  (Read 5898 times)

CharlieMcF

  • Jr. Member
  • **
  • Posts: 10
    • View Profile
Problem writing magic token functions [SOLVED]
« on: March 02, 2017, 02:58:40 PM »
Me again, another magic token issue. I need to write my own magic token functions which can set the values of variables to be used by other functions. Here's a simple example:

Code: [Select]
local incrvar = 0;

function incrementit() {
incrvar = incrvar + 1;
return incrvar;
}

local showToken = fe.add_text("Token: " + "[!incrementit]", 900, 900, 0, 0);
local showVariable = fe.add_text("Variable: " + incrvar, 900, 1000, 0, 0);


If I run this, the showToken text behaves as I expect, ie the value returned by the incrementit function increases by 1 each time the navigation is called (eg by stepping through the games in the list). However, the showVariable text resolutely stays on the initial value of incrvar and never updates. This seems to be a general rule, ie it doesn't matter how the variables are changed within the magic token function, they remain unchanged when accessed from outside the function. I wondered if it was an issue of scope, but declaring the variable as a global makes no difference. Clearly I'm missing something, probably obvious to someone who knows what they're doing.

In case it helps in diagnosing the problem, the absolute values returned in the text strings aren't what I'd expect either, they're incremented by 2. So with the code above and the problem of the variable not updating, I'd expect showToken to display 1 and showVariable to display 0 in the first instance, but they display 3 and 2 respectively. showToken will then increment with navigation, but showVariable remains at 2. I have no idea what's happening here (story of my life) so if anyone can help out it'd be much appreciated.
« Last Edit: March 03, 2017, 11:01:48 PM by CharlieMcF »

liquid8d

  • Global Moderator
  • Sr. Member
  • *****
  • Posts: 442
    • View Profile
Re: Problem writing magic token functions
« Reply #1 on: March 02, 2017, 04:36:45 PM »
There is no problem there.. in showVariable you are just setting the text to the initial variable value, that line of code is not re-run to update the value. showToken works as expected because you can include functions as a magic token in text and that function is called whenever it needs to update the text value.

I guess you need to explain what you are trying to do.. why does the function option not work for you?

CharlieMcF

  • Jr. Member
  • **
  • Posts: 10
    • View Profile
Re: Problem writing magic token functions
« Reply #2 on: March 02, 2017, 06:18:59 PM »
Thanks for the prompt reply, I'm sure the problem is mainly my lack of understanding. It's not clear to me why showVariable shows the initial value of the variable, not the updated value. I thought the flow would be:

Call increment function via magic token [!incrementit] in showToken
Variable incrvar is incremented
showVariable displays the new value of incrvar

In other words it would be equivalent to

Code: [Select]
incrementit();
local showVariable = fe.add_text("Variable: " + incrvar, 900, 1000, 0, 0);

which does display the updated value of incrvar as I would expect. But obviously it doesn't work this way!

The background to this is in my earlier post on magic tokens - I want to randomly display objects during navigation. keilmillerjr suggested a neat solution, but my problem is that my tweak of his solution randomly crashes AM. Showing or hiding the element based on the value of a variable works fine though, and this strategy would be handy for some other ideas I have. So to redefine the problem: can I update the value of a variable in response to navigation such that other functions can then access and act on the value of that variable? Hope this makes sense.

keilmillerjr

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1167
    • View Profile
Re: Problem writing magic token functions
« Reply #3 on: March 02, 2017, 06:36:04 PM »
showVariable will not be updated because it is not tied to a magic function. It’s static text. Magic functions are called every time the current game changes.

I am not sure what you are trying to do. What was the tweak that ended up crashing attract mode? I can probably help you there. I added those functions to the helpers module I released and they have been tested do work, so maybe your implementation of them has an issue I can spot. Post up the code and I’ll take a look.

CharlieMcF

  • Jr. Member
  • **
  • Posts: 10
    • View Profile
Re: Problem writing magic token functions
« Reply #4 on: March 03, 2017, 01:23:03 AM »
Many thanks. So in my previous thread we ended up with this:

Code: [Select]
function iRand(max) {
    // Generate a pseudo-random integer between 0 and max
    local roll = (1.0 * math.rand() / RAND_MAX) * (max + 1);
    return roll.tointeger();
}

function bRand() {
  if (irand(1) == 1) return true;
  else return false;
}

function showStopper() {
  if (bRand()){
Showelement();
return "On";
}
else {
Hideelement();
return "Off";
}
}

local showText = fe.add_text(„[!showStopper]", 900, 870, 0, 0);

The functions to show and hide the elements look like this:

Code: [Select]
function showelement(){
local breakup = fe.add_image("staticsprite.png", 1000, 100, blip*0.405, blip*0.2 );
breakup.visible = true;
breakup.trigger = Transition.EndNavigation;
breakup.preserve_aspect_ratio = false;

//sprite animation - use a spritesheet to animate specific frames of the sprite sheet
local sprite_cfg = {
    when = When.Always,
    width = 462,
    height = 200,
    frame = 0,
    time = 3000,
    order = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1],
    loop = true
}
animation.add( SpriteAnimation( breakup, sprite_cfg ) );
}

function hideelement(){
local breakup = fe.add_image("staticsprite.png", 1000, 100, blip*0.405, blip*0.2 );
breakup.visible =false
breakup.trigger = Transition.EndNavigation;
breakup.preserve_aspect_ratio = false;

//sprite animation - use a spritesheet to animate specific frames of the sprite sheet
local sprite_cfg = {
    when = When.Always,
    width = 462,
    height = 200,
    frame = 0,
    time = 3000,
    order = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1],
    loop = true
}
animation.add( SpriteAnimation( breakup, sprite_cfg ) );
}

This approach works initially but AM will crash a few transitions later. OTOH if I have a variable such as myGlobal which I set to 1 or 0 and then do this:

Code: [Select]
local breakup = fe.add_image("staticsprite.png", 1000, 100, blip*0.405, blip*0.2 );
if (myGlobal == 1) breakup.visible = true;
else breakup.visible = false;
breakup.trigger = Transition.EndNavigation;
breakup.preserve_aspect_ratio = false;

//sprite animation - use a spritesheet to animate specific frames of the sprite sheet
local sprite_cfg = {
    when = When.Always,
    width = 462,
    height = 200,
    frame = 0,
    time = 3000,
    order = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1],
    loop = true
}
animation.add( SpriteAnimation( breakup, sprite_cfg ) );

It works fine, hence my enthusiasm for being able to set variable values using a magic token. Does this make sense now?

keilmillerjr

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1167
    • View Profile
Re: Problem writing magic token functions
« Reply #5 on: March 03, 2017, 07:03:57 AM »
I am not very good at animations, so bear with me if I don’t fully understand how they work. However, why not use transitions to run a function and just toggle visibility? The animation can run regardless, but user won’t see it if its randomly hidden. If it sounds ok, I can try to provide an example.

CharlieMcF

  • Jr. Member
  • **
  • Posts: 10
    • View Profile
Re: Problem writing magic token functions
« Reply #6 on: March 03, 2017, 01:37:46 PM »
Sure: any approach which can show or hide an element (snap, animation, image, text etc) in response to navigation would be great. Sample code would be very helpful, thanks.

keilmillerjr

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1167
    • View Profile
Re: Problem writing magic token functions
« Reply #7 on: March 03, 2017, 02:53:39 PM »
You will need to add in your animation bits. It should work for regular objects. Like I said, I have no animation experience. Hopefully it will work with your animation. I assume the animation will still run, and this will just toggle its visibility between game switches.

Code: [Select]
// Include module with those helpers that I updated.
fe.load_module("helpers“);

// Create your artwork object, and don’t worry about visibility
// …

// Create your sprite animation and apply it to your artwork object
// …

// Create transition that will toggle artwork visibility
fe.add_transition_callback(„updateArtwork“);
function updateElement(ttype, var, transition_time) {
  if (ttype == Transition.StartLayout || Transition.ToNewSelection || Transition.ToNewList ) {
    artwork.visible = randBool();
  }
}

CharlieMcF

  • Jr. Member
  • **
  • Posts: 10
    • View Profile
Re: Problem writing magic token functions
« Reply #8 on: March 03, 2017, 09:52:16 PM »
Thanks again! So at its simplest, if I just look at hiding/displaying a single image:

Code: [Select]
local artwork = fe.add_image("fanart.png", 1000, 100, blip*0.405, blip*0.2 );

// Create transition that will toggle artwork visibility
fe.add_transition_callback("updateArtwork");
function updateElement(ttype, var, transition_time) {
  if (ttype == Transition.StartLayout || Transition.ToNewSelection || Transition.ToNewList ) {
    artwork.visible = randBool();
  }
}

Running this always displays the image, regardless of transitions. I assume I need to call updateElement at some point, but not sure what parameters it's expecting?

keilmillerjr

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1167
    • View Profile
Re: Problem writing magic token functions
« Reply #9 on: March 03, 2017, 10:18:32 PM »
Sorry. I made an error with the function name. I adjusted the if statement with the ttype as well. Heres the same code that I tested and it does now indeed work. Transition function will run at layout start, new list, and when navigation ends. You can test it with your sprite, or send the sprite to me and I’ll test it as well.

Code: [Select]
// Include module with those helpers that I updated.
fe.load_module("helpers“);

// Create your artwork object, and don’t worry about visibility
local artwork = fe.add_image("white.png", 0, 0, percentage(10, flw), percentage(10, flh));

// Create your sprite animation and apply it to your artwork object
// …

// Create transition that will toggle artwork visibility
fe.add_transition_callback(„updateArtwork“);
function updateArtwork(ttype, var, transition_time) {
  if ((ttype == Transition.StartLayout) || (ttype == Transition.ToNewList) || (ttype == Transition.EndNavigation)) {
    artwork.visible = randBool();
  }
}

CharlieMcF

  • Jr. Member
  • **
  • Posts: 10
    • View Profile
Re: Problem writing magic token functions [SOLVED]
« Reply #10 on: March 03, 2017, 11:00:56 PM »
Brilliant, works like a dream! I've tried it with image, sprite and text elements and it works perfectly. Here's the sprite code:

Code: [Select]
local artwork = fe.add_image("staticsprite.png", 1000, 100, blip*0.405, blip*0.2 );

//sprite animation - use a spritesheet to animate specific frames of the sprite sheet
local sprite_cfg = {
    when = When.Always,
    width = 462,
    height = 200,
    frame = 0,
    time = 3000,
    order = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1],
    loop = true
}
animation.add( SpriteAnimation( artwork, sprite_cfg ) );

// Create transition that will toggle artwork visibility
fe.add_transition_callback("updateArtwork");
function updateArtwork(ttype, var, transition_time) {
if ((ttype == Transition.StartLayout) || (ttype == Transition.ToNewList) || (ttype == Transition.EndNavigation)){
    artwork.visible = randBool();
  }
}

Thanks heaps: I've learned a lot, hopefully this might help others out too.