Objects in ChoiceScript

I’ve written some JS that enables objects in CS. You can define object types, create objects of that type, assign values to the elements of an object, assign an object’s element values to CS variables, create an object by copying an existing one, access objects through references, and store object references in other objects. The code is too extensive to post here, but you can check out what it allows you to do in a demo game I created for it at the following URL:

http://eposic.org/diversions/csobjects

The web directory of the demo game, including the objects.js file that enables the new CS object commands, are packaged in a zip file that can be downloaded from this URL:

http://eposic.org/diversions/CSObjects.zip

I know this is beyond the understanding of some CS authors. I also know there are some CS authors who are quite adept at programming, and I’m hoping that those of you who fit the latter category will check this out and let me know what you think of it.

The demo game doesn’t include any saving capability, but the tests that I ran in this regard indicated that the existing save mechanisms will save objects and object types in existence at the time of the save.

I’d appreciate any feedback I can get from anyone about this. Even just trying out the demo game and giving me feedback on what you think of the capabilities that this new object code makes possible would be beneficial. If I can get enough eyes looking at it and programmers trying it out so I can feel confident it’s production quality, I would submit it to Dan Fabulich for inclusion in the official CS baseline. For those who understand the code, it makes some things a lot easier than what is possible in official CS right now.

The zip file includes the scenes of the game, so you can see what I did to get the game to do what it does. I added liberal comments, and hope they will help with understanding how to use the new commands. The objects.js file is also liberally documented. So, if you’re interested in using an object model for data in CS, check out the demo game and the zip file and let me know what you think. B-)

1 Like

Maybe I’m not the best person to review this as I’m not a programmer by any stretch, but aside from creating an endless list of characters, I can’t see anything here I can’t do with ordinary choicescript.

Choose a name for your character:
*input_text char1
Is {char1} male or female? \*choice __#male ____\*goto strength_choice __#female ____\*set he "she" ____\*set sex1 "female" ____\*goto strength_choice \*label strength_choice How strong is {char1}?
*choice
__#Very
____*set strength1 95
____*set magic1 100 - strength
____*goto weapon_choose
__#Average
____*set strength1 50
____*set magic1 100 - strength
____*goto weapon_choose
__#Not very
____*set strength1 15
____*set magic1 100 - strength
____*goto weapon_choose
*label weapon_choose
Which weapon will {char1} wield? \*choice __#Sabre ____\*set weapon1 "Sabre" ____\*set weapon1_atk 4 ____Weapon description here ____\*goto display_char1 __#Dirk ____\*set weapon1 "Dirk ____\*set weapon1_atk 1 ____Weapon description here ____\*goto display_char1 \*display_char1 This is your first character: Name: {char1}
Sex: {sex1} Strength: {strength1}
Magic: {magic1} Weapon: {weapon1}

Simply copy, paste, and replace 1 with 2 for character 2.

What this does allow though, is much shorter code which would save a lot of time if you need a large number of characters. In fact, if I can get my head around it properly, I might, with your permission, borrow it for Blackraven. In particular, the stats for each of the 200 collector cards you can obtain in the game.

Impressive stuff @eposic !

Aww man, you are a freaking legend!
I can’t look at the code right now but I’m thinking a weapon is an object so instead of assigning five seperate strings and variables for its values you merely need to print or assign the one “object”?

I cannot begin to comprehend how useful that will be…

@andy

It doesn’t allow anything “new” to be done but it is CONSIDERABLY quicker and more efficient than current methods.

1 Like

@andymwhy, you are not quite correct, objects do allow you to do something you can’t already do in CS. In your example, you said to copy the code for character #2. Did you notice that my demo code allows you to create unlimited characters? Now that’s not necessarily something you’d want to do in a game, but it is something you can’t currently do in CS. Of course, there is a practical limit due to memory, but in theory, my code could keep creating characters forever. You can’t keep copying and pasting code forever. :stuck_out_tongue: From a practical viewpoint, however, you’re right.

@CJW, yes, it is just a reference that is stored in the parent object. Basically, if you have one object obj1, and you want to use the data in that object in association with another object obj2, then you save off the string “obj1” in an element of obj2. Then you go on with your coding, and later, when you want to use obj2 and you have a need for the data in the obj1 as well, you will use the “obj1” string stored in obj2 to reference the obj1 object. The beauty of this is that during the time since you created obj1 you could have modified its elements, and when you reference it later when obj2 needs it, you’ll pick up all of the changes to the obj1 elements. If you don’t want that to happen, you can copy obj1 into, say, obj1copy, and store the string “obj1copy” in obj2 instead of “obj1”, then fiddle with obj1 data, but still have the original data in obj1copy.

If several objects referenced obj1, you would only have to change obj1 for all of the other objects to pick up those changes. I don’t exactly show this in my demo game, but if you were to assign a dirk, for instance, to each of the characters you create, and you were to then change the description for the dirk, then when you review the characters and their weapons, you’d see the change to the dirk’s description in each of the character reviews.

@andymwhy and anyone else who is interested in using this code in your own games, please feel free to do so. It should work in the experimental browser on the Kindle, but it won’t work in a native Kindle app unless Dan Fabulich does his magic to support it. It will work on the web, obviously, and it should work in devices that support JS natively, though I don’t have any such devices to test on.

Very interesting. I will try it out.

@andymwhy, sorry, after reading your post again, I see that you said “aside from creating an endless list of characters”. Okay, so you were right on the money, and my saying you were not quite correct was not quite correct. :-S

@eposic while I can’t see a reason to create infinite characters, creating a lot of items quickly would be beneficial. As I said, for Blackraven, I have around 200 cards you can collect. Each card has a name, 3 stats and a description. The current plan is to do it all manually (lots of copy and paste) and I’ve set up around 30 cards (with the other 170 set up but blank). I’m debating now whether to use your object code or not… When the game is completed would Dan Fabulich support it or not. Aside from concerns like that, it’d mean learning another chunk of code and reworking what I’ve already done… perhaps this will have to wait until my next game for me. But then again… decisions, decisions! Either way, the more I think about it, the better this is - There’s a lot of potential with this addition.

/me facepalms
Sorry ^^ - I see it now!

Thanks for clarifying Eposic, after looking at it more closely I do believe, to some degree, this may also help us get around choicescript not supporting arrays. In my case in-particular, that will help to no end.

I’ll experiment and get back to you on any pros/cons I uncover, but damn man, fine work as always. If I use it you will most certainly get due credit :slight_smile:

EDIT: One thing I did notice is that I can’t give two characters “The Great Terbutje”, but I can give two Characters a dirk (and seemingly any other weapon). I’m not sure if this is intentional, with it being “The” (not "a), it may very well be…

@CJW, no mystery with “The Great Terbutje”. It’s simply got *hide_reuse in front of it. So, yeah, intentional.

Which memory are you talking about, browser space or RAM/HDD?

How many objects do you reckon? Tens? Hundreds? Thousands?

In an CS game, the number of variables you can have is limited by the amount of memory your browser is willing to allocate on your behalf. Where the space comes from is dependent on how your browser is implemented–some browsers might use only RAM, though I think most of them use disk space too as needed for temporary memory for application data that is not in immediate use.

Since these CS objects are basically nothing more than a different way to access certain variables, the memory they use is similar to what you’d use if you set up all your variables without using the objects. Consider that you had three characters in your game, and each of them had four stats, and those were the only variables you were using in your game. Your stats array in mygames.js might look like this:

stats = {
  name1: "Joe"
  ,sex1: "male"
  ,strength1: 50
  ,health1: 50
  ,name2: "Jane"
  ,sex2: "female"
  ,strength2: 50
  ,health2: 50
  ,name3: "Harry"
  ,sex3: "male"
  ,strength3: 25
  ,health3: 75
};

If you used CS objects for this, you’d have three objects, each with four elements: name, sex, strength, and health. Then you’d have four element variables with the same names. None of these are defined in the JS stats array. So the stats array would look like this:

stats = {};

In your CS code, you’d have the following instructions to define your object type:

*define_object_type character c_name c_sex c_strength c_heatlh

The above instruction allocates some overhead space for the object type definition and for the four “element variables”: c_name, c_sex, c_strength, and c_health.

Then you would create your three objects and assign values to their elements:

*create_object char1 character
*create_object char2 character
*create_object char3 character
*set_all_elems char1 "Joe" "male" 50 50
*set_all_elems char2 "Jane" "female" 50 50
*set_all_elems char3 "Harry" "male" 25 75

This creates objects char1, char2, and char3 all of the defined object type “character” as was defined in the *define_object_type instruction and assigns the same values to them as was used in the regular CS approach. This allocates a little overhead space for a reference to each of the objects. It also allocates space for four elements per object, but this is not overhead space, this is the space your original variables would have used anyway. That is, in the normal CS approach, your “name1” variable is equivalent to the “c_name” element in the “char1” object. The “health3” variable is equivalent to the “c_health” element in the “char3” object.

If you decided to add a fourth character, compare what would happen in the two different ways of doing things. In the normal CS approach, you’d be adding name4, sex4, strength4, and health4 to your stats array. In the CS object approach, you’d call \*create_object char4 character and then \*set_all_elems char4 "Sally" "female" 25 75. You create the overhead of the additional object reference, but your four elements still take up the same space as the four normal CS variables would use.

So in this scenario, you have the object model approach using some amount of overhead space (depending on the number of elements you declare) for the object type definition. You also use 25% additional space per object: Four elements take the same space the four variables normally would, but you have an additional object reference. Four-plus-one is a 25% increase. If you had more elements in the object, this percentage would go down. For instance, if you had 10 elements per object, ten-plus-one would be a 10% increase.

There is also the possibility of saving space by using objects. Suppose each character could have a weapon, and each weapon has a name, damage rating, and ammo capacity. Each character would also need to have a current ammo count. So the normal CS approach might look like this in the mygames.js file, assuming just three characters:

stats = {
  name1: "Joe"
  ,sex1: "male"
  ,strength1: 50
  ,health1: 50
  ,weapon1: "pistol"
  ,damage1: 5
  ,capacity1: 6
  ,ammo1: 3 // how much ammo is remaining to this character
  ,name2: "Jane"
  ,sex2: "female"
  ,strength2: 50
  ,health2: 50
  ,weapon2: "pistol"
  ,damage2: 5
  ,capacity2: 6
  ,ammo2: 6
  ,name3: "Harry"
  ,sex3: "male"
  ,strength3: 25
  ,health3: 75
  ,weapon3: "crossbow"
  ,damage1: 10
  ,capacity1: 1
  ,ammo1: 20
};

You’ve added twelve new variables to the stats array. Using objects, you’d have something like this:

*define_object_type weapon w_name w_damage w_capacity
*define_object_type character c_name c_sex c_strength c_heatlh c_weapon_ref c_ammo
*create_object wpn1 "pistol" 5 6
*create_object wpn2 "crossbow" 10 1
*create_object char1 character
*create_object char2 character
*create_object char3 character
*set_all_elems char1 "Joe" "male" 50 50 "wpn1" 3
*set_all_elems char2 "Jane" "female" 50 50 "wpn1" 6
*set_all_elems char3 "Harry" "male" 25 75 "wpn2" 20

Since Joe and Jane are both using the same type of weapon, a pistol, they both have a reference to wpn1. This saves having to store the information about a pistol twice–once for Joe and once for Jane–like you’d be doing in the regular CS “tons of variables” approach.

If we decided to add Sally to the above mix, we’d have eight new CS variables for her in the normal CS variable approach, but in the object approach, we’d have these two additional lines:


*create_object char4 character
*set_all_elems char4 "Sally" "female" 25 75 "wpn2" 15

The above indicates that Sally is carrying a crossbow and 15 crossbow bolts. We also know from the wpn2 object that a crossbow deals 10 damage and has a capacity of 1 shot, but we don’t have to carry that info around with Sally.

You could, of course, do some magic with *setref and {var} to do something similar to what objects allow you to do, but that would actually incur overhead similar to what the object approach does, and is so damn difficult to read and maintain imo .That’s one of the reasons I implemented objects–my code was becoming impossible to read/understand using *setref and {var}, and trying to add one stinking new variable to the mix required me to go to a half dozen places and add in code just to manage the new variable. And it looked horrendous, with concatenations out the wazoo. With several characters running around, each with a dozen or more stats and each with multiple weapons which had about a dozen stats each, I just couldn’t take it anymore.

With the objects approach, if I now want to access the elements for, say, Joe, I use two commands to get at those values:

*get_all_elems char1
*get_all_elems_ref c_weapon_ref

With those two calls, I can now use the element variables c_name, c_sex, c_strength, c_heatlh, c_ammo, w_name, w_damage, and w_capacity. These “element variables” are normal CS variables, but they are currently loaded with the values pertaining to Joe (char1). If I wanted to get the values pertaining to Jane (char2), I’d do this:

*get_all_elems char2
*get_all_elems_ref c_weapon_ref

This would overwrite the values in the “element variables” (c_name, c_sex, etc.) with the values for Jane. If you wanted to retain some values for Joe so you could compare to the values for Jane, you’d need to save off the values of the element variables for Joe into some other CS variables before you got the values for Jane. This uses a bit more space, but you only need extra CS variables for the values you want to compare. There are additional object instructions that allow you to copy just the element values you want into other CS variables, to help with that.

Sorry for the long reply, but I hope I’ve addressed the question of space differences satisfactorily. :slight_smile:

O.o … Wow, yes, definitely. Thank you!
So in effect, it’s not much more efficient in terms of space, just tidier and more organised.

Cheers

You are correct: Organization, readability, and maintainability were my primary goals, not space savings. The space usage is still comparable, though objects make it easier for you to use more space. :blush:

Pure genius Eposic, keep up the good work.

If anyone is making use of the CS objects code, you should grab another copy of the zip file. I had to make a fix for boolean elements to be supported correctly. You can get the updated zip file here: http://eposic.org/diversions/CSObjects.zip?v=1.1

The demo game is also updated to include use of boolean elements. It now states in the weapon description whether the weapon is a unique weapon, which means that it can only be chosen by one character. If you don’t see this new detail, you may need to clear your browser cache and reload the page.

The weapon object type (wpn_type) is given a couple of elements to indicate if the weapon is unique and to track if at least one of that type of weapon has been taken by a character. The demo does away with the *hide_reuse instruction, yet still allows The Great Terbutje to be taken by only one character. Doing away with the *hide_reuse instruction in itself is nothing earth-shattering, but taking a look at the demo code to see how I did that can give you an idea of why boolean elements might be useful in objects.

Just to see the beauty of booleans in action, you can edit the testing1.txt scene file on your local computer, changing line 21 *set_elem wpn3 w_unique false to *set_elem wpn3 w_unique true. This will make the dirk a unique weapon. Without making any other change, if you now run the game, you will only be able to give a dirk to one character. You can even make The Great Terbutje not unique by changing line 29 *set_elem wpn4 w_unique true to *set_elem wpn4 w_unique false.

Will replacing the objects.js file be enough/i.e. it won’t broke any c/s code I’ve already written?

@CJW, you can replace the objects.js file without breaking any c/s code you’ve written. The implemented instructions are still the same and still accept the same arguments in the same order. Basically, I changed != in a couple places in objects.js to !== instead.

If you don’t replace the objects.js file and use booleans as element values in your CS objects, then boolean true is transformed to the string “true” and boolean false is transformed to the string “false”. This can have subtle effects on your code that would be extremely difficult to debug. The following code would have taken the nogo branch before my fix:

*define_object_type booltype boolelem
*create_object boolobj booltype
*set_elem boolobj boolelem true
*get_elem boolobj boolelem
*if (boolelem = true)
  *goto okay
*else
  *goto nogo

If you replace the objects.js file, the object code will preserve the boolean nature of any elements that you assign boolean values to, so that in the example above, the okay branch will be the one taken.

Alright, so cool, straight swap? Cheers man :slight_smile:
By the way, I’ve been using it for a while now and I’m really, really liking what I can do with it, not to mention I’ve had no issues, no errors… I hadn’t even got round to using booleans yet so didn’t notice that. Regardless, I think it’s worth submitting to Dan, it seems solid enough to me and indescribably useful :slight_smile: