Creating a basic function call...

HI,

I'm looking to redesign my "buy" command, and figured a few function calls might greatly reduce the amount of needed code. Problem is that for whatever reason, even though I set the function to have a return value of integer and stated what formal parameter I'd want to return, it doesn't return it.

So, before I post the function call code this is what is supposed to happen before it:

  1. You start with 300 soul shards (currency)
  2. You don't start with the spell (which is what the function checks for)
  3. The debug command calls the function, and uses the variable player.SoulShards to replace CurrentShards.

Function Call code:

  ShardCost = 100
  CurrentShards = CurrentShards - ShardCost
  Spellbook.KnowArcaneZap = true
  return (CurrentShards)
}

Now it properly gives the spell, and then sets my player.SoulShards to 0 for some reason.

This is my first foray into Quest functions, and I don't know what I'm doing wrong. And the quest documentation isn't the most helpful either.

Any help would be appreciated.


here's some examples (didn't do every combination, but you should get the idea... if not, ask for help!):

(the main usual issue for people new to coding: they don't realize that something must be done with a returned value, it/data can't just "float around" in code, not doing anything / not being used by anything. A returned value MUST be stored in a VARIABLE or be used as an argument/input in a Function/Command/Object+Script_Attribute+Delgate call/usage)

<game name="example_game">

  <attr name="example_string_attribute" type="string">unknown</attr>
  <attr name="example_integer_attribute" type="int">0</attr>
  <attr name="example_boolean_attribute" type="boolean">false</attr>

  <attr name="start" type="script">

    no_return_value_no_parameter_function

    game.example_string_attribute = return_string_value_function
    msg (game.example_string_attribute)
    msg (return_string_value_function)

    game.example_string_attribute = return_string_value_function_2
    msg (game.example_string_attribute)
    msg (return_string_value_function_2)

    game.example_integer_attribute = return_integer_value_function + 5
    msg (game.example_integer_attribute)
    msg (return_integer_value_function)

    game.example_integer_attribute = return_integer_value_function_2 + 5
    msg (game.example_integer_attribute)
    msg (return_integer_value_function_2)

    game.example_boolean_attribute = return_boolean_value_function
    msg (game.example_boolean_attribute)
    msg (return_boolean_value_function)

    game.example_boolean_attribute = return_boolean_value_function_2
    msg (game.example_boolean_attribute)
    msg (return_boolean_value_function_2)

    game.example_boolean_attribute = return_boolean_value_function_3
    msg (game.example_boolean_attribute)
    msg (return_boolean_value_function_3)

    string_parameter_function ("H", "K")

    integer_parameter_function (37, 21)

    boolean_parameter_function (true, false)

    boolean_parameter_function_2 (true, false)

    game.example_integer_attribute = return_integer_value_and_parameter_function
    msg (game.example_integer_attribute)
    msg (return_integer_value_and_parameter_function)

  </attr>
</game>

<function name="no_return_value_no_parameter_function">
  msg ("hi")
</function>

<function name="return_string_value_function" type="string">
  return ("bye")
</function>

<function name="return_string_value_function_2" type="string">
  example_string_variable = "okay"
  return (example_string_variable)
</function>

<function name="return_integer_value_function" type="int">
  return (10)
</function>

<function name="return_integer_value_function_2" type="int">
  example_integer_variable = 7
  return (example_integer_variable)
</function>

<function name="return_boolean_value_function" type="boolean">
  return (true)
</function>

<function name="return_boolean_value_function_2" type="boolean">
  return (false)
</function>

<function name="return_boolean_value_function_3" type="boolean">
  example_boolean_variable = true
  return (example_boolean_variable)
</function>

<function name="string_parameter_function" parameters="example_parameter_1, example_parameter_2">
  msg (example_parameter_1 + example_parameter_2)
</function>

<function name="integer_parameter_function" parameters="example_parameter_1, example_parameter_2">
  msg (example_parameter_1 + example_parameter_2)
</function>

<function name="boolean_parameter_function" parameters="example_parameter_1, example_parameter_2">
  msg (example_parameter_1 and example_parameter_2)
</function>

<function name="boolean_parameter_function_2" parameters="example_parameter_1, example_parameter_2">
  msg (example_parameter_1 or example_parameter_2)
</function>

<function name="return_integer_value_and_parameter_function" parameters="example_parameter_1, example_parameter_2" type="int">
  return (example_parameter_1 + example_parameter_2)
</function>

Objects and their Script Attributes + Delegates:

in quest, Delegates looks and acts like a Prototype for a Function (if you know programming languages), except it gives an Object's Script Attribute the same functionality (return values, and arguments/parameters/inputs) as a Function. Now that I learned how to use Delegates, I like them a lot better than global Functions, as Objects are much more powerful (encapsulation and organization), compared to (global) Functions.

<include ref="English.aslx" />
<include ref="Core.aslx" />

<delegate name="two_integer_parameters_and_return_value_delegate" type="int" parameters="integer_parameter_1, integer_parameter_2" />

<game name="example_game">
  <attr name="example_integer_attribute" type="int">0</attr>
  <attr name="start" type="script">

   game.example_integer_attribute = do (arithmetic_object, "addition_of_two_integers_script_attribute", 6, 2)
   msg (game.example_integer_attribute)

   game.example_integer_attribute = do (arithmetic_object, "subtraction_of_two_integers_script_attribute", 6, 2)
   msg (game.example_integer_attribute)

   game.example_integer_attribute = do (arithmetic_object, "multiplication_of_two_integers_script_attribute", 6, 2)
   msg (game.example_integer_attribute)

   game.example_integer_attribute = do (arithmetic_object, "division_of_two_integers_script_attribute", 6, 2)
   msg (game.example_integer_attribute)

  </attr>
</game>

<object name="arithmetic_object">

  <attr name="addition_of_two_integers_script_attribute" type="two_integer_parameters_and_return_value_delegate">
    return (integer_parameter_1 + integer_parameter_2)
  </attr>

  <attr name="multiplication_of_two_integers_script_attribute" type="two_integer_parameters_and_return_value_delegate">
    return (integer_parameter_1 * integer_parameter_2)
  </attr>

  <attr name="subtraction_of_two_integers_script_attribute" type="two_integer_parameters_and_return_value_delegate">
    return (integer_parameter_1 - integer_parameter_2)
  </attr>

  <attr name="division_of_two_integers_script_attribute" type="two_integer_parameters_and_return_value_delegate">
    return (integer_parameter_1 / integer_parameter_2)
  </attr>

</object>

Perhaps I should have also mentioned this code:

player.SoulShards = BuySpells(player.SoulShards)
msg ("You buy the spell Arcane Zap. Your current Soul Shards are = " + player.SoulShards + ".")

The command calls the function, BuySpells, with player.SoulShards replacing the formal parameter and then afterwards my current Soul Shards is turned into the value that CurrentShards in the function; the value that was supposed to be returned.


@lordpalandus: The code you posted looks fine. If it doesn't behave as expected, I'd think the error is elsewhere.

Can you show us the whole function, and the line that calls it?


Ah, replied at around the same time.
That code snippet also looks fine; so I think the issue must be elsewhere in the function.


Oops didn't post the full command (named debug):

BuySpells (player.SoulShards)
player.SoulShards = BuySpells(player.SoulShards)
msg ("You buy the spell Arcane Zap. Your current Soul Shards are = " + player.SoulShards + ".")

Then the actual stuff that happens in the function call:

if (Spellbook.KnowArcaneZap = false) {
  ShardCost = 100
  CurrentShards = CurrentShards - ShardCost
  Spellbook.KnowArcaneZap = true
  return (CurrentShards)
}

To me it should be working; it takes player.SoulShards to replace the formal parameter CurrentShards.

But for some reason the returned value isn't being returned or something.

That is literally all the code being used in the function call and the command that calls the function.


Can you show us the function header for BuySpells() as that may be something that can cause issues and you seem to be overlooking it.
For me personally I actually would pass the entire player object through and then extract the contents of the attribute inside the function, you could then update the player object there too.


With regard to your current issue. If you call that command when the attribute Spellbook.KnowArcaneZap exists and is false, it will set it to true and reduce the player's soulshards by 100.
If you call it when Spellbook.KnowArcaneZap is already true, it will not change it, but will still display the messae saying you learned it, and will set the player's soul shards to zero (because the return statement is inside the if block so is never reached).


(If you don't mind me poking my nose in, I'd suggest a more practical organisation would be to have a function BuySpell which takes a spell name as its parameter. It seems redundant to pass in player.SoulShards as a parameter, because I haven't seen anything in your game that suggests spells are ever bought using points from a different pool.

If I was working on this, the function would look something like…

<function name="BuySpell" parameters="SpellName" type="boolean">
  ShortSpellName = Replace (SpellName, " ", "")
  if (GetBoolean (Spellbook, "Known"+ShortSpellName)) {
    msg ("You already have the spell "+SpellName)
    return (false)
  }
  cost = GetSpellCost(SpellName)
  if (cost = -1) {
    return (false)
  }
  if (cost > player.SoulShards) {
    msg (SpellName+" costs "+cost+" Soul Shards, but you only have "+player.SoulShards+".")
    return (false)
  }
  player.SoulShards = player.SoulShards - cost
  set (Spellbook, "Known"+ShortSpellName, true)
  msg ("You buy the spell "+SpellName+". Your current Soul Shards are = " + player.SoulShards + ".")
  return (true)
</function>

<function name="GetSpellCost" parameters="SpellName" type="integer">
  ShortSpellName = Replace (SpellName, " ", "")
  switch (ShortSpellName) {
    case ("ArcaneZap", "AnotherSpell", "ListOfSpellsThatCost100", "SomeSpell") {
      return (100)
    }
    case ("MorePowerfulSpell", "TheseAllCost200", "SomeOtherSpell") {
      return (200)
    }
    case ("SuperUberSpell") {
      return (1000)
    }
    default {
      msg ("there isn't a spell called "+SpellName)
      return (-1)
    }
  }
</function>

Just off the top of my head; hopefully you can see the logic there)


How do I show you the function header? When I select all the code bits in the UI and hit code view, the code I posted is all the stuff selected.

Well, with the function I posted, I did it with a race that doesn't start with Arcane Zap, so its false by default. However, it sets my Soul Shards to 0 after calling the function. It doesn't reduce it by 100, it reduces it by effectively 300; or it multiplies by 0 whatever is currently stored in my player.SoulShards variable.

The way I have spells and spell names setup is quite a bit more complex than what you are assuming. Spells in my game are setup in this fashion:

  1. The spellbook has a Boolean variable called KnowArcaneZap. If it is false, you cannot cast the spell. If it is true, then you can.
  2. All spells in the spellbook default to false. You learn spells by buying them or finding a spellbook as loot, and in either case, will set the Boolean for the spellbook, to true.
  3. Once the spell is known, you cast it by using one of two commands = cast #text# or cast #text# at #object#. Damage spells use the cast spell at target command, whereas buffs, or indirect casting spells use cast spell command.
  4. The name of the spell, does nothing, except is used to navigate the switches and if-else conditionals until the spell is actually cast, mana points are depleted and the effect of the spell occurs.

That is in a nutshell how my casting system works. There may be more elegant ways of casting spells, but after spending about 4-5 months devising, designing, and developing this specific spellcasting system, I'm unsure of how it could be done better. Each spell is not an object, as I've found that the way I do spells, they don't need to be... plus as the quest engine only allows you to do stuff to objects if they are visible, I didn't want the player's inventory to be bloated with spell objects.


(filler for getting my edited post, updated/posted)


terminology:

// Function's 'definition' (setup / creation):

<function name="example_function" parameters="example_parameter" type="string"> <!-- Function's 'header/signature' (special parameters/attributes and etc, starting tag block line) -->
  // Function's 'body' (contents: scripting):
  return (example_parameter)
</function>

// Function's call/usage/activation/execution, scripting example:

game.example_string_attribute = example_function ("hi")

if you're using only the web/on-line version, then you can't get at the full game code to see your Function (unless you download your game). You can click on your Function (in the left side's "tree of stuff"), and you'll have to look at (and tell/post to us): what are your adding parameters' names, if your Function has a return value and what type is it, and lastly, your Function's scripting (its body). Lastly, you then got to tell/post us, the Function call/usage scripting lines of it.


otherwise, there's a notepaper like button in the menu bar at the top of the screen, this is a toggle between the GUI/Editor mode and Code View (this is the full game code) mode. Or, you can just right click on your game file and open it up with a text editor software (notepad, wordpad, notepad++, Apple: text editor, etc). You then just find your Function in your game code.


There's also the individual scripting note-paper-like button on the popup window in the middle of the screen for individual scripting Elements (Verbs, Functions, Commands, etc), that lets you go into code view only for that specific scripting Element's scripting (body).


K.V.

How do I show you the function header?

image


If you're online, you can download the entire game's .aslx file, then open that in a text editor, and copy and paste the whole thing here. (Or to a GitHub Gist, if it's really long. Then just drop a link to the Gist here.)


If you have the desktop editor:

image


That will get you into the full code view.

CTRL+A
CTRL+C

Then come back here and:


```
CTRL+V
```

I'm prototyping the code in my actual game, and the source file for it is over 800kb. So, if I posted the entire code base, expect about 30,000+ lines of code; trying to read through that gives me a headache just thinking of it.

Well if it is hitting that code view button, then 100% of the code I posted is ALL that the function does and contains.

It has 1 formal parameter; CurrentShards
It has a return value of CurrentShards

I don't know why it isn't working and what other code you need, as there is no other code to provide you.

I have to say, I have a lot easier time doing function calls in C++, than I do in Quest. Create a function declaration, a function definition, and have a place in your code that calls the function, replacing the arguments for the format parameters and then return a value of type int or double, or nothing. Probably helps that I can declare variables all by themselves, rather than be forced to declare member variables of a class.


Okay I fiddled around with it, and got it to work... sort of. I don't understand why it is working, buy yah.

So, what I did, was I removed the CurrentShards - 100, from within the if-else branch, and had it built into the return value. The issue with this is that it should only cost the player if they don't know the spell.

Don't know why it is not performing the calculation in the if-else but will run it outside of the if-else. THAT is a headscratcher.

EDIT: I think I kind of know what is going on, but why it is going on doesn't make sense to me.

The only way the function will work, is if you build the subtraction calculation INTO the return value, and not pass the value to the returned value.

So it will not accept this:

CurrentShards = CurrentShards - 100
return (CurrentShards)
-> If you do it this way, then for some reason it returns 0 or a null value, and that's why my soul shards gets reset to 0.

However it will accept this:

return (CurrentShards - 100)

The strange thing is that it is properly using the value of the argument player.SoulShards to replace the formal parameter CurrentShards.

This just confuses the hell out of me. Why does it work one way and not the other?


I think 'mrangel' answered it in this post:

http://textadventures.co.uk/forum/quest/topic/l5shmzqm00_actlrsuj19q/creating-a-basic-function-call#e18f549a-77e9-43c6-ab1b-cee17cabff44


so, try this fix:

(I assume that 'CurrentShards' is given a Value somehow, lol)

if (Spellbook.KnowArcaneZap = false) {
  ShardCost = 100
  CurrentShards = CurrentShards - ShardCost
  Spellbook.KnowArcaneZap = true
}
return (CurrentShards)

as to why it returns '0', that's probably because it's programmed to do that, the returned '0' represents an error: a Value wasn't returned, when one was suppose to be returned.


The best way to debug something like that is to use a debug msg() like this:

Msg("Current shards before calc: " + CurrentShards)
CurrentShards = CurrentShards - 100
Msg("Current shards after calc: " + CurrentShards)

K.V.

I see that you got it (mostly) working now. That's awesome!


@hegemonkhan ; ... CurrentShards is the formal parameter, and as such the function fails unless you have an argument that gives it a value. If it was a local variable, then the function wouldn't care. But if you have a formal parameter, at least for C++, you need to fill it with something. In this case, it is player.SoulShards (the variable that holds your currency) which starts at 300.

Logically, it should in theory take the value in SoulShards (300), and then subtract 100 = 200, and then pass that value to return value (CurrentShards) which should contain the value 200. But it doesn't. When you build the subtraction into the return value (CurrentShards - 100) then it will properly do the subtraction and return a value of 200. Else it returns 0. For whatever reason.


I had a game that was 850+ kb. I talked to The Pixie about it. It turns out most of that is image data.

I only have one picture in the game and one picture for the game listing. I just had to upload it multiple times to get the right size. If I deleted the old files, it would be around 200-350+ kb.


@lordpalandus So, why don't you do player.SouldShards = player.SoulSards - 100__? Is it for aesthetic reasons?

That's how I do it.


Well my game is all text and code, and no images. Plus the new V4 source is about 1,200 kb now.

I am doing it that way with the current system. But I was hoping to have the system replaced with function calls, but it doesn't look like function calls will help to reduce my spell purchasing code. Might be useful elsewhere, but not in spell purchasing.

Probably. I'll have to see when I begin my major code refactor tomorrow, as I just released V4 beta of my game; its in the WIP section of the browser playable games here. Probably tomorrow as I've been working hard enough today to get V4 out to playtesters, and need a break from coding.


How do you have so much code? Why is it 1,200 kb? How did you even count the lines of code?


Lots of switches, if-else conditionals, and quite a few turnscripts.

I plan to reduce a lot of that down, so hopefully after the refactor it will be back to being less than 1000 kb.


Thanks. But how did you count the lines of code?


there's software/programs that do (and display) it for you (for example, notepad++, probably any IDE/SDK, like visual basic)


Well, with a bit of refactoring, and using function calls to reduce some redundancy, I've gotten it down to about 1090 kb. Not quite finished with the code refactor, but I'm definitely making significant progress. And the best thing is that it will be significantly easier to add to the code later on.


This topic is now closed. Topics are closed after 60 days of inactivity.

Support

Forums