- 7
- Posts
- 9
- Years
- Seen Aug 14, 2015
Hi guys, I'm new to the forums but I'm hoping this will be one of many places I'm able to hold a real discussion on something I've been working on for a little while now. As a note going in this topic, I'm a developer not a writer so please excuse my less than perfect writing style. If there's anything I can explain better or is left misunderstood after reading please ask any and all questions :)
What if the process of creating Pokémon based game content could be simplified in a way that it became enjoyable for everyone? Would it be possible to create an entirely new scripting language with a single purpose of being easy to learn, earn to read for those which understand English but also provide enough mechanisms for creators to make exciting content time after time?
Now, if you're anything like me you'll be reading this and grimacing already, "We've got one of these again!" Everyone wants the easy way right? Well I'm very much interested in providing it for them. I'm the head developer of an online Pokémon project where the aim is to have the community build their environment. We've had loads of creative people join the project over the years, but very little genuine interest in the scripting of game content which is absolutely vital. So how to simplify the process further and ensure that the system can be as intuitive as possible for a non-programming mindset, a real challenge.
In the last few months I've spent a great deal of time working with our game editing tool itself, creating our own version of a coding IDE although much less sophisticated of course. It does however provide in depth function templates, tutorial materials, a text editor with error checking/highlighting and even some tools to create some aspects of the scripts for you - copied to the clipboard so you can paste to as many scripts as you like. Still, this is not enough.
Unfortunately I've reached quite a catch 22 type of situation now. In my aims to keep the language as simple to read/write as possible for the vast majority of functions, applying these sample principles to more complex condition checking or parsing of values at runtime becomes very ugly and really against the core design goals.
Let me first talk about some of the limitations and boundaries at play here:
- the scripting system provides no means for variable declaration, controlled string manipulation, multi-language support.
- Every game map has it's own set of scripting files which are independent and unaware of the contents of any other map.
- The scripting language isn't object orientated and we divide our available scripts in to usable blocks available to be called by number. We call these ChatID's, although they can be used for a magnitude of other purposes.
- Players have saved storage which is referenced in bits, this enables us to make use of boolean and/or integer values, although these are defined in the number of bits and not the normal naming convention of byte/int/long or char/int16/int32 depending on the language you're used to. This means we only use the amount of storage we require, to keep player account processing as efficient as possible. We call each bit a Flag.
So let me begin by providing an example of the scripting syntax.
[1]
// This is a comment line so we can explain our scripts, <char> is a keyword which is replaced by our players username at runtime.
CHARSAY Now that I've kicked your butt you can call me <char>
SAY <char> it is
// For general scripts like this, we're 100% successful in our ease of use. I don't think anyone can have any confusion here.
[/1]
[2]
// This script is going to be a bit more complex. As this script is run every time we speak to a NPC, we've got to make sure that the items aren't provided every single time.
IF {isFlag} {1} {} {SAY I've given you everything I've got, try someone else!} {GIVEITEM Pokéball 1\SETFLAG 1 TRUE\SAY Here take this}
// I think for the most part I've managed to be successful with the goal too.
[/2]
[3]
// We have something called a pre-parser, this is effectively a script handler which processes are scripts quickly before they're passed to the main handler which actually executes functions.
// This is so that we can insert some values in to our scripts at runtime, sometimes just to randomise parts of dialogue to make the experience more enjoyable.
SAY RANDPICK[Hi/Hello/Hey you!]
// Simple enough example, here we've selected a single greeting at random from the provided selection.
// Above I mentioned that the scripting language enables us to make use of integers. So here's an example of saving and accessing one of those numbers.
SETBINARY 1 8 100
// What we've done here is allocate 8 bits for an integer and then store the value 100 in this memory space. So now we can recall it in a usable form as simple as possible:
SAY Number stored: READBINARY[1/8]
// would be displayed in a NPC conversation as 'Number Stored: 100'
[/3]
So far so good right? To me at this point I'm not sure we could really make things any easier, if you see something different when reading this please do let me know! But this isn't really where things go crazy, above is just so you can loosely see how things come together, it all falls to pieces when we try to create more variable content, specifically in content generated at runtime based on the players circumstances.
Take this one such example, which is an exert from a script used within a sprite selection shop. This is a good example because it has to refresh the map with NPCs based on the users selection in dialogue, so the available sprites can be displayed and made to do a small moving animation so the user is able to see the sprite from all sides.
What an ugly line of script, impossible to really understand what's going on without a paragraph of notes to accompany it! This is only the tip of the iceberg too, if you're able, take a minute to digest the following set of scripts.
(probably worth copying to notepad for easy reading)
If you've not switched off after starting to read through that mammoth I think you can really start to see some of the problems we face around dynamic content. This is a very simple example in the scheme of things, imagine a random quest generator which can select random maps to fill with a random number of computer opponents which are set to roam the map seeking out the player. We need to be able to create these challenges and re-create them based on the players progress through the challenge at any time they re-enter the map, re-logging in to the game included.
This is where we have the real separation from single player and multi-player experiences, both for players and content creators. In a single player environment we do have to give a little thought to cheat prevention and glitch abuse, but nothing compared to a multi-player environment where a level playing field for everyone is absolutely vital to the projects success. The existing wealth of players can be jeopardised by faulty scripts giving an unfair advantage for those which found an unfair advantage and these kind of things can have long lasting impacts on economy and balance. This makes encouraging playing with scripts like those seen in my last snippet pretty unappealing as the room for error is pretty high, with the possibility of broken scripts disrupting existing player saved data.
So my questions are this:
- Do you see any faults with the way we layout our query structure? Do you have any suggestions for optimising it? Especially with regards to querying multiple pieces of information at once.
- What features of the tools that you guys use to create content do you find most useful?
- Are there any things you wish your tools could do to help speed up the process of creating content?
- Do you have any suggestions for improving the syntax and structure available as a whole?
- As a side point: I'm also interested to know what you guys do to learn a new scripting language or toolset, from the perspective of people who enjoy this kind of thing it's important to make sure we have the appropriate learning resources available. I've been trying determine if the time required to make quality video tutorials would be a worthwhile task.
I've tried to keep project specific information away from the discussion, although if anyone is interested I have no issues with sharing a download link to the editor software in question. However, this is a downloadable executable file which will requires installation. If posting a link to such software is within the rules of the forums I will make one available in place of this sentence, I've not found anything formal to suggest this is acceptable yet though and don't want it to get in the way of starting a discussion.
What if the process of creating Pokémon based game content could be simplified in a way that it became enjoyable for everyone? Would it be possible to create an entirely new scripting language with a single purpose of being easy to learn, earn to read for those which understand English but also provide enough mechanisms for creators to make exciting content time after time?
Now, if you're anything like me you'll be reading this and grimacing already, "We've got one of these again!" Everyone wants the easy way right? Well I'm very much interested in providing it for them. I'm the head developer of an online Pokémon project where the aim is to have the community build their environment. We've had loads of creative people join the project over the years, but very little genuine interest in the scripting of game content which is absolutely vital. So how to simplify the process further and ensure that the system can be as intuitive as possible for a non-programming mindset, a real challenge.
In the last few months I've spent a great deal of time working with our game editing tool itself, creating our own version of a coding IDE although much less sophisticated of course. It does however provide in depth function templates, tutorial materials, a text editor with error checking/highlighting and even some tools to create some aspects of the scripts for you - copied to the clipboard so you can paste to as many scripts as you like. Still, this is not enough.
Unfortunately I've reached quite a catch 22 type of situation now. In my aims to keep the language as simple to read/write as possible for the vast majority of functions, applying these sample principles to more complex condition checking or parsing of values at runtime becomes very ugly and really against the core design goals.
Let me first talk about some of the limitations and boundaries at play here:
- the scripting system provides no means for variable declaration, controlled string manipulation, multi-language support.
- Every game map has it's own set of scripting files which are independent and unaware of the contents of any other map.
- The scripting language isn't object orientated and we divide our available scripts in to usable blocks available to be called by number. We call these ChatID's, although they can be used for a magnitude of other purposes.
- Players have saved storage which is referenced in bits, this enables us to make use of boolean and/or integer values, although these are defined in the number of bits and not the normal naming convention of byte/int/long or char/int16/int32 depending on the language you're used to. This means we only use the amount of storage we require, to keep player account processing as efficient as possible. We call each bit a Flag.
So let me begin by providing an example of the scripting syntax.
[1]
// This is a comment line so we can explain our scripts, <char> is a keyword which is replaced by our players username at runtime.
CHARSAY Now that I've kicked your butt you can call me <char>
SAY <char> it is
// For general scripts like this, we're 100% successful in our ease of use. I don't think anyone can have any confusion here.
[/1]
[2]
// This script is going to be a bit more complex. As this script is run every time we speak to a NPC, we've got to make sure that the items aren't provided every single time.
IF {isFlag} {1} {} {SAY I've given you everything I've got, try someone else!} {GIVEITEM Pokéball 1\SETFLAG 1 TRUE\SAY Here take this}
// I think for the most part I've managed to be successful with the goal too.
[/2]
[3]
// We have something called a pre-parser, this is effectively a script handler which processes are scripts quickly before they're passed to the main handler which actually executes functions.
// This is so that we can insert some values in to our scripts at runtime, sometimes just to randomise parts of dialogue to make the experience more enjoyable.
SAY RANDPICK[Hi/Hello/Hey you!]
// Simple enough example, here we've selected a single greeting at random from the provided selection.
// Above I mentioned that the scripting language enables us to make use of integers. So here's an example of saving and accessing one of those numbers.
SETBINARY 1 8 100
// What we've done here is allocate 8 bits for an integer and then store the value 100 in this memory space. So now we can recall it in a usable form as simple as possible:
SAY Number stored: READBINARY[1/8]
// would be displayed in a NPC conversation as 'Number Stored: 100'
[/3]
So far so good right? To me at this point I'm not sure we could really make things any easier, if you see something different when reading this please do let me know! But this isn't really where things go crazy, above is just so you can loosely see how things come together, it all falls to pieces when we try to create more variable content, specifically in content generated at runtime based on the players circumstances.
Take this one such example, which is an exert from a script used within a sprite selection shop. This is a good example because it has to refresh the map with NPCs based on the users selection in dialogue, so the available sprites can be displayed and made to do a small moving animation so the user is able to see the sprite from all sides.
Code:
CREATENPC (instAvatarREADBINARY[1197/1199])|Avatar,ADD[8+READBINARY[1197/1199]],3,ADD[378+-86+READBINARY[ADD[1170+MULT[READBINARY[1197/1199]*7]]/ADD[1176+MULT[READBINARY[1197/1199]*7]]]],2,0,0,READBINARY[ADD[1170+MULT[READBINARY[1197/1199]*7]]/ADD[1176+MULT[READBINARY[1197/1199]*7]]],300,,0,
What an ugly line of script, impossible to really understand what's going on without a paragraph of notes to accompany it! This is only the tip of the iceberg too, if you're able, take a minute to digest the following set of scripts.
(probably worth copying to notepad for easy reading)
Spoiler:
Code:
[73]
// THIS IS MUCH EASIER TO READ WITHIN THE EDITOR, it will be colour formatted correctly for the most part. Anything it may list as an issue, isn't an issue.
// This will be the start of the sprite shop for the halloween event.
// It's going to work slightly different than last time, although it will share some common principles.
// Reset our variable data.
SETBINARY 1170 1199 0
// We're basically going to let the players see 3 sprites at a time, and store the sprite ids within the temp flags. We need 7 flags (0-127) per spriteid.
// SpriteID 1 Flags 1170-1176
// SpriteID 2 Flags 1177-1183
// SpriteID 3 Flags 1184-1190
// PageID Flags 1191-1196 - will be a number between like 0 and 7.
// OptionID Flags 1197- 1199 - will be number between 0 and 2
SAY So I may have a few more options available than I'd mentioned...
//Load up the page handler.
GOTO 74
[/73]
[74]
// This is the page handler for the witch/sprite handler.
// PageID is stored in Flags 1191-1196
// Reset all Sprite FlagIDs and Sprite optionID
SETBINARY 1170 1190 0
SETBINARY 1197 1199 3
//We mark the OptionID for the creation/destruction loops
// PageID 1. Sprites: 86,87,88
//Destroy Previous instanced NPCs
EXECUTEC 76
// Let's make sure player faces the sprites we create while they're moving around.
RESETPLAYERMOVEQUEUE TRUE
PLAYERSETDIR RIGHT
DELAYPLAYERMOVEMENT 6000
PLAYERSETDIR LEFT
// Page 0
EXECUTEB IF {Compare} {=} {READBINARY[1191/1196]:0} {SETBINARY 1170 1176 86@@@SETBINARY 1177 1183 87@@@SETBINARY 1184 1190 88@@@EXECUTEC 77@@@STARTASK Which option interests you? Page ADD[1+READBINARY[1191/1196]] of 8.|Previous#IF {Compare} {=} {0:READBINARY[1191/1196]} {SETBINARY 1191 1196 7@@@GOTO 74} {INCREMENT 1191 1196 -1@@@GOTO 74}|Sprite 1#SETBINARY 1197 1199 0~GOTO 75|Sprite 2#SETBINARY 1197 1199 1~GOTO 75|Sprite 3#SETBINARY 1197 1199 2~GOTO 75|More#IF {Compare} {=} {7:READBINARY[1191/1196]} {GOTO 74} {INCREMENT 1191 1196 1@@@GOTO 74}} {}
// Page 1
EXECUTEB IF {Compare} {=} {READBINARY[1191/1196]:1} {SETBINARY 1170 1176 89@@@SETBINARY 1177 1183 90@@@SETBINARY 1184 1190 91@@@EXECUTEC 77@@@STARTASK Which option interests you? Page ADD[1+READBINARY[1191/1196]] of 8.|Previous#IF {Compare} {=} {0:READBINARY[1191/1196]} {GOTO 74} {INCREMENT 1191 1196 -1@@@GOTO 74}|Sprite 1#SETBINARY 1197 1199 0~GOTO 75|Sprite 2#SETBINARY 1197 1199 1~GOTO 75|Sprite 3#SETBINARY 1197 1199 2~GOTO 75|More#IF {Compare} {=} {7:READBINARY[1191/1196]} {GOTO 74} {INCREMENT 1191 1196 1@@@GOTO 74}} {}
// Page 2
EXECUTEB IF {Compare} {=} {READBINARY[1191/1196]:2} {SETBINARY 1170 1176 92@@@SETBINARY 1177 1183 93@@@SETBINARY 1184 1190 94@@@EXECUTEC 77@@@STARTASK Which option interests you? Page ADD[1+READBINARY[1191/1196]] of 8.|Previous#IF {Compare} {=} {0:READBINARY[1191/1196]} {GOTO 74} {INCREMENT 1191 1196 -1@@@GOTO 74}|Sprite 1#SETBINARY 1197 1199 0~GOTO 75|Sprite 2#SETBINARY 1197 1199 1~GOTO 75|Sprite 3#SETBINARY 1197 1199 2~GOTO 75|More#IF {Compare} {=} {7:READBINARY[1191/1196]} {GOTO 74} {INCREMENT 1191 1196 1@@@GOTO 74}} {}
// Page 3
EXECUTEB IF {Compare} {=} {READBINARY[1191/1196]:3} {SETBINARY 1170 1176 98@@@SETBINARY 1177 1183 99@@@SETBINARY 1184 1190 100@@@EXECUTEC 77@@@STARTASK Which option interests you? Page ADD[1+READBINARY[1191/1196]] of 8.|Previous#IF {Compare} {=} {0:READBINARY[1191/1196]} {GOTO 74} {INCREMENT 1191 1196 -1@@@GOTO 74}|Sprite 1#SETBINARY 1197 1199 0~GOTO 75|Sprite 2#SETBINARY 1197 1199 1~GOTO 75|Sprite 3#SETBINARY 1197 1199 2~GOTO 75|More#IF {Compare} {=} {7:READBINARY[1191/1196]} {GOTO 74} {INCREMENT 1191 1196 1@@@GOTO 74}} {}
// Page 4
EXECUTEB IF {Compare} {=} {READBINARY[1191/1196]:4} {SETBINARY 1170 1176 101@@@SETBINARY 1177 1183 102@@@SETBINARY 1184 1190 103@@@EXECUTEC 77@@@STARTASK Which option interests you? Page ADD[1+READBINARY[1191/1196]] of 8.|Previous#IF {Compare} {=} {0:READBINARY[1191/1196]} {GOTO 74} {INCREMENT 1191 1196 -1@@@GOTO 74}|Sprite 1#SETBINARY 1197 1199 0~GOTO 75|Sprite 2#SETBINARY 1197 1199 1~GOTO 75|Sprite 3#SETBINARY 1197 1199 2~GOTO 75|More#IF {Compare} {=} {7:READBINARY[1191/1196]} {GOTO 74} {INCREMENT 1191 1196 1@@@GOTO 74}} {}
// Page 5
EXECUTEB IF {Compare} {=} {READBINARY[1191/1196]:5} {SETBINARY 1170 1176 104@@@SETBINARY 1177 1183 105@@@SETBINARY 1184 1190 106@@@EXECUTEC 77@@@STARTASK Which option interests you? Page ADD[1+READBINARY[1191/1196]] of 8.|Previous#IF {Compare} {=} {0:READBINARY[1191/1196]} {GOTO 74} {INCREMENT 1191 1196 -1@@@GOTO 74}|Sprite 1#SETBINARY 1197 1199 0~GOTO 75|Sprite 2#SETBINARY 1197 1199 1~GOTO 75|Sprite 3#SETBINARY 1197 1199 2~GOTO 75|More#IF {Compare} {=} {7:READBINARY[1191/1196]} {GOTO 74} {INCREMENT 1191 1196 1@@@GOTO 74}} {}
// Page 6
EXECUTEB IF {Compare} {=} {READBINARY[1191/1196]:6} {SETBINARY 1170 1176 106@@@SETBINARY 1177 1183 107@@@SETBINARY 1184 1190 108@@@EXECUTEC 77@@@STARTASK Which option interests you? Page ADD[1+READBINARY[1191/1196]] of 8.|Previous#IF {Compare} {=} {0:READBINARY[1191/1196]} {GOTO 74} {INCREMENT 1191 1196 -1@@@GOTO 74}|Sprite 1#SETBINARY 1197 1199 0~GOTO 75|Sprite 2#SETBINARY 1197 1199 1~GOTO 75|Sprite 3#SETBINARY 1197 1199 2~GOTO 75|More#IF {Compare} {=} {7:READBINARY[1191/1196]} {GOTO 74} {INCREMENT 1191 1196 1@@@GOTO 74}} {}
// Page 7
EXECUTEB IF {Compare} {=} {READBINARY[1191/1196]:7} {SETBINARY 1170 1176 109@@@SETBINARY 1177 1183 110@@@SETBINARY 1184 1190 0@@@EXECUTEC 77@@@STARTASK Which option interests you? Page ADD[1+READBINARY[1191/1196]] of 8.|Previous#IF {Compare} {=} {0:READBINARY[1191/1196]} {GOTO 74} {INCREMENT 1191 1196 -1@@@GOTO 74}|Sprite 1#SETBINARY 1197 1199 0~GOTO 75|Sprite 2#SETBINARY 1197 1199 1~GOTO 75|Sprite 3#SETBINARY 1197 1199 2~GOTO 75|More#IF {Compare} {=} {7:READBINARY[1191/1196]} {GOTO 74} {INCREMENT 1191 1196 1@@@GOTO 74}} {}
[/74]
[75]
//Player is interested in one of the player sprites.
// We'll be creating their instanced names based on the OptionID stored in
// Flags 1197-1199
MOVENPC (instAvatarREADBINARY[1197/1199]) DOWN 1
MOVENPC (instAvatarREADBINARY[1197/1199]) UP 1
NPCSETDIR (instAvatarREADBINARY[1197/1199]) LEFT
DELAYNPCMOVEMENT (instAvatarREADBINARY[1197/1199]) 200
NPCSETDIR (instAvatarREADBINARY[1197/1199]) RIGHT
DELAYNPCMOVEMENT (instAvatarREADBINARY[1197/1199]) 200
NPCSETDIR (instAvatarREADBINARY[1197/1199]) DOWN
DELAYNPCMOVEMENT (instAvatarREADBINARY[1197/1199]) 500
MOVENPC (instAvatarREADBINARY[1197/1199]) DOWN 1
WAITNPCMOVE (instAvatarREADBINARY[1197/1199])
STARTASK So is this the one you were after?|Yes#GOTO 78|Back#74|Leave#EXECUTEC 76~CHARSAY I'll probably be back..
[/75]
[76]
// This is our ChatID for clearing up any previously created instanced NPCs for
// Avatar selection. Must be called in the instant handler!
IF {doesINPCExist} {(instAvatar0)} {} {DESTROYNPC (instAvatar0)} {}
IF {doesINPCExist} {(instAvatar1)} {} {DESTROYNPC (instAvatar1)} {}
IF {doesINPCExist} {(instAvatar2)} {} {DESTROYNPC (instAvatar2)} {}
[/76]
[77]
// This ChatID will create each of our instanced NPCs for the avatar shop.
// This is called within the instant handler!
INCREMENT 1197 1199 -1
CREATENPC (instAvatarREADBINARY[1197/1199])|Avatar,ADD[8+READBINARY[1197/1199]],3,ADD[378+-86+READBINARY[ADD[1170+MULT[READBINARY[1197/1199]*7]]/ADD[1176+MULT[READBINARY[1197/1199]*7]]]],2,0,0,READBINARY[ADD[1170+MULT[READBINARY[1197/1199]*7]]/ADD[1176+MULT[READBINARY[1197/1199]*7]]],300,,0,
// We can read the SpriteID from the following FlagIDs: 1170/1176 1177/1183 1184/1190
// Using maths we can determine the FlagIDs from the OptionID using the following:
// Range Min/Max: 1170 + OprionsID * 7 / 1170 + (OptionID*7) + 6
// Written in script as ADD[1170+MULT[READBINARY[1197/1199]*7]] / ADD[1176+MULT[READBINARY[1197/1199]*7]]
// The whole thing becomes pretty ugly lol:
// READBINARY[ADD[1170+MULT[READBINARY[1197/1199]*7]]/ADD[1176+MULT[READBINARY[1197/1199]*7]]]
// Now for this function to work properly, it must call itself again. This is important and is called a recursive loop, it will continue to call itself untill all
// work has been done.
IF {compare} {=} {READBINARY[1197/1199]:0} {} {DELAYNPCMOVEMENT (instAvatarREADBINARY[1197/1199]) MULT[READBINARY[1197/1199]*800]}
// The above line creates a delay before we let the instanced NPC move. We're actually creating the sprites from right to left, but make them start their animations from left to right.
MOVENPC (instAvatarREADBINARY[1197/1199]) DOWN 1
DELAYNPCMOVEMENT (instAvatarREADBINARY[1197/1199]) 150
MOVENPC (instAvatarREADBINARY[1197/1199]) UP 1
NPCSETDIR (instAvatarREADBINARY[1197/1199]) LEFT
DELAYNPCMOVEMENT (instAvatarREADBINARY[1197/1199]) 150
NPCSETDIR (instAvatarREADBINARY[1197/1199]) RIGHT
DELAYNPCMOVEMENT (instAvatarREADBINARY[1197/1199]) 150
NPCSETDIR (instAvatarREADBINARY[1197/1199]) DOWN
IF {Compare} {=} {READBINARY[1197/1199]:0} {} {EXECUTEC 77}
[/77]
[78]
// player is confirming their choice.
//SAY SpriteID: READBINARY[ADD[1170+MULT[READBINARY[1197/1199]*7]]/ADD[1176+MULT[READBINARY[1197/1199]*7]]]
// This query is to make sure the player has enough of the Chocolate item.
EXECUTEB IF {hasItem} {189x400} {} {} {DELAYEDB SAY You need at least 400 chocolates for the real magic to begin!}
EXECUTEB IF {compare} {=} {0:READBINARY[ADD[1170+MULT[READBINARY[1197/1199]*7]]/ADD[1176+MULT[READBINARY[1197/1199]*7]]]} {DELAYEDB SAY Unfortunately there an issue with your selection. Please try again\GOTO 74} {}
// we're good to go.
EXECUTEC 76
STARTASK So if you're certain, that will be 400 Chocolates please?|Yes#REMOVEITEM 189 400~UPDATEPLAYERSPRITEID READBINARY[ADD[1170+MULT[READBINARY[1197/1199]*7]]/ADD[1176+MULT[READBINARY[1197/1199]*7]]]|Back#74|Leave#0
[/78]
If you've not switched off after starting to read through that mammoth I think you can really start to see some of the problems we face around dynamic content. This is a very simple example in the scheme of things, imagine a random quest generator which can select random maps to fill with a random number of computer opponents which are set to roam the map seeking out the player. We need to be able to create these challenges and re-create them based on the players progress through the challenge at any time they re-enter the map, re-logging in to the game included.
This is where we have the real separation from single player and multi-player experiences, both for players and content creators. In a single player environment we do have to give a little thought to cheat prevention and glitch abuse, but nothing compared to a multi-player environment where a level playing field for everyone is absolutely vital to the projects success. The existing wealth of players can be jeopardised by faulty scripts giving an unfair advantage for those which found an unfair advantage and these kind of things can have long lasting impacts on economy and balance. This makes encouraging playing with scripts like those seen in my last snippet pretty unappealing as the room for error is pretty high, with the possibility of broken scripts disrupting existing player saved data.
So my questions are this:
- Do you see any faults with the way we layout our query structure? Do you have any suggestions for optimising it? Especially with regards to querying multiple pieces of information at once.
- What features of the tools that you guys use to create content do you find most useful?
- Are there any things you wish your tools could do to help speed up the process of creating content?
- Do you have any suggestions for improving the syntax and structure available as a whole?
- As a side point: I'm also interested to know what you guys do to learn a new scripting language or toolset, from the perspective of people who enjoy this kind of thing it's important to make sure we have the appropriate learning resources available. I've been trying determine if the time required to make quality video tutorials would be a worthwhile task.
I've tried to keep project specific information away from the discussion, although if anyone is interested I have no issues with sharing a download link to the editor software in question. However, this is a downloadable executable file which will requires installation. If posting a link to such software is within the rules of the forums I will make one available in place of this sentence, I've not found anything formal to suggest this is acceptable yet though and don't want it to get in the way of starting a discussion.