So I like to decorate my games with uninteractable objects, which is also referred as scenery
This becomes a problem quickly, when you have 100 scenery objects in your game, your players are just mindlessly clicking everything to search for the objects that actually have any verbs to interact with.
There are a few ways of design to solve this problem, even though I like the (3) idea most as it shows how many possible interactions there are.
Understand that I want a code that automatically shows objects are interactable in the whole game at all rooms, my games can have like 100 rooms, and it would be chore to write codes for all of them.
From the above design solutions, there are actually further complications:
But, you can mark objects as scenery objects, and then they're not shown as links to click on in the quest engine... So that already existing system could work with what you said about adding a print message mentioning them. Then people would read them in the description, and if they choose to type "look sceneryobject" they would get whatever more detailed description you gave the object. or the default "it looks ordinary" whatever that is in your game. So every object where you choose "scenery" on the object's setup tab will not show up as a link, but is reachable and visible. You'd just add it to your room description text.
However, I think it's also a fun idea to make a separate "inventory" window to display the scenery objects. You could use the existing Second Inventory library by Pixie https://github.com/ThePix/quest/wiki/Library:-Second-inventory and then, rather than having just one room that you'd "set" as the inventory room, you would do something like make the game's "before room enter" script switch to whatever scenery room corresponds to the room your player is entering. This then would mean you'd make 2 rooms for every room. "Library" and "Libraryscenery" where those objects would end up in Inventory pane 2.
In one of my games, I have an Inv2 and Inv3 because one pane houses magic and the other houses verses. So you can create as many extra panes as you need with Pixie's lib, just changing the names in a couple of places on the base code.
Here's hoping this helps you narrow down from your options. Also, If you're lucky, MrAngel will help you brainstorm. He's a Quest Genius and almost always has the best solutions.
Thanks for the help Ip Man
I still like the idea of number of verbs besides alias, because if the code is doable, you only need one code for the whole game,
also that it might be able to automatically update objects that were previously uninteractable/0 verbs, but due to a game event, it is now interactable/3 verbs
The main worry still exist, that it might override any existing game coding that makes use of alias like
But, you can mark objects as scenery objects, and then they're not shown as links to click on in the quest engine... So that already existing system could work with what you said about adding a print message mentioning them. Then people would read them in the description, and if they choose to type "look sceneryobject" they would get whatever more detailed description you gave the object. or the default "it looks ordinary" whatever that is in your game. So every object where you choose "scenery" on the object's setup tab will not show up as a link, but is reachable and visible. You'd just add it to your room description text.
Generally I am a lazy game creator and expect my players to be lazy as well, so nobody will click at look at verb or type in look at command parser for most of my mundane objects
So generally, I use a scenery generator, to randomize each room's outlook to make travelling more fun, while the players doesn't really have to interact it, but this would be an issue for players unfamiliar with my game, they will probably be clicking all of the room objects trying to find out which object is interactable
However, I think it's also a fun idea to make a separate "inventory" window to display the scenery objects. You could use the existing Second Inventory library by Pixie https://github.com/ThePix/quest/wiki/Library:-Second-inventory and then, rather than having just one room that you'd "set" as the inventory room, you would do something like make the game's "before room enter" script switch to whatever scenery room corresponds to the room your player is entering. This then would mean you'd make 2 rooms for every room. "Library" and "Libraryscenery" where those objects would end up in Inventory pane 2.
As usual, I had a hard time dealing with library
After a long time, generally the fix was to create a room named "spells_known" (Yeah I might be english blind, have some problems with reading)
The second fix was to move objects out of the room "spells_known" rather than making them invisible, because hiding them does not do anything, they still appear
So rather than making 2 rooms for every room, which sounds like self abuse, I had something like this
This code is placed at when entering a new room
if (game.pov.parent = room) {
if (RandomChance(50)) {
MoveObject (kangaroo, spells_unknown)
}
else {
MoveObject (kangaroo, spells_known)
}
}
UpdateInv2
Yeah, dun forget about UpdateInv2 at the end of code, I already know you will forget about it, daeun
And before the code, you need to move all available scenery objects out of the room to hide them
Another walkaround solution is to create an object named scenery in the required rooms
Copy and paste the following code on entering specific rooms
scenery.alias = scenery.name+ ": "
if (RandomChance(100)) {
scenery.alias = scenery.alias+ "floor"
}
if (RandomChance(40)) {
scenery.alias = scenery.alias+ ",table"
}
if (RandomChance(40)) {
scenery.alias = scenery.alias+ ",windows"
}
if (RandomChance(40)) {
scenery.alias = scenery.alias+ ",coffee"
}
if (RandomChance(40)) {
scenery.alias = scenery.alias+ ",madam"
}
if (RandomChance(40)) {
scenery.alias = scenery.alias+ ",table"
}
Although I dun like this, it does have its positive qualities
The limitations
So the code to access the number of verbs, whether a certain verb exists and changing of the verb can create a list of intermediate coding solutions like
Pseudo code
In short, this is just to convince you to help me write out the code to access the number of verbs, whether a certain verb already exists and changing of the verb
I had a small success
Verbs are just script attributes
based on https://docs.textadventures.co.uk/quest/using_verbs.html
object.displayverbs = ListCombine(object.displayverbs, Split("Attack"))
https://docs.textadventures.co.uk/quest/display_verbs.html
Script when entering a room:
foreach (objectx, ScopeVisible()) {
if (HasAttribute(objectx, "fight")) {
}
else {
if (HasAttribute(objectx, "hp stat")) {
objectx.displayverbs = ListCombine(objectx.displayverbs, Split("fight"))
objectx.fight => {
msg ("You deal 1 damage to donkey<br/>Donkey retaliates with 2 damage")
}
}
}
}
I now have a moderate success
Script when entering a room:
foreach (objectx, ScopeVisible()) {
objectx.verbcountstat = 0
if (HasAttribute(objectx, "fight")) {
objectx.verbcountstat = objectx.verbcountstat+1
}
if (HasAttribute(objectx, "trade")) {
objectx.verbcountstat = objectx.verbcountstat+1
}
if (HasAttribute(objectx, "ride")) {
objectx.verbcountstat = objectx.verbcountstat+1
}
objectx.alias = objectx.name+" ("+ objectx.verbcountstat+")"
}
The issue with this, is that if I have too many verbs like 100 different verbs, I probably have to write a long code as well, so if someone can help directly source the verb names from the verb folder, that would be great, I am guess this have to do with for each loop and dictionary, which I am unfamiliar with
Also, as stated previously, this can conflict with internal game codes like
Copied and pasted from previous statement
If you use objectx.alias = objectx.alias + verbcount = it will show it correctly as goblin (3),
but the next time you enter the room, it will become goblin (3) (3), and it will keep adding on and on, which is hard to interpret
I might have solved the problem the way I want it to be,
rather than putting number of verbs to all objects like donkey (3),
I will only put number of verbs to scenery objects, objects that do not have a single verb,
and let the players automatically realise that the others are interactable,
In short it should be like this:
Flower (0)
Dirt path (0)
NPC Jerry (0)
Dog
Shovel
Thus, the player will eventually find out that (0) means it have no verbs, and that dog and shovel are interactable, because I do not change their aliases, their in game code stays untouched, so I guess, problem solved?
So the below code looks like it works, but it still conflicts with 2 issues
Script when entering a new room
foreach (objectx, ScopeVisible()) {
objectx.verbcountstat = 0
if (ListContains(objectx.displayverbs, "Take")) {
objectx.verbcountstat = objectx.verbcountstat+1
}
if (HasAttribute(objectx, "speak")) {
objectx.verbcountstat = objectx.verbcountstat+1
}
if (HasAttribute(objectx, "look")) {
objectx.verbcountstat = objectx.verbcountstat+1
}
if (HasAttribute(objectx, "buy")) {
objectx.verbcountstat = objectx.verbcountstat+1
}
if (objectx.feature_usegive = true) {
objectx.verbcountstat = objectx.verbcountstat+1
}
if (HasAttribute(objectx, "catch")) {
objectx.verbcountstat = objectx.verbcountstat+1
}
if (HasAttribute(objectx, "hunt")) {
objectx.verbcountstat = objectx.verbcountstat+1
}
if (objectx.verbcountstat=0) {
objectx.alias = objectx.name+" ("+ objectx.verbcountstat+")"
}
}
Scenery generator that got conflicted
foreach (object, GetDirectChildren (game.pov.parent)) {
if (object.alias = "red squirrel") {
object.parent = null
}
if (object.alias = "swaying grass") {
object.parent = null
}
if (object.alias = "girl in dress") {
object.parent = null
}
}
MakeObjectVisible (picnic object)
if (RandomChance(12)) {
picnic object.alias = "red squirrel"
CloneObjectAndMoveHere (picnic object)
}
if (RandomChance(12)) {
picnic object.alias = "swaying grass"
CloneObjectAndMoveHere (picnic object)
}
if (RandomChance(12)) {
picnic object.alias = "girl in dress"
CloneObjectAndMoveHere (picnic object)
}
The original code of the scenery generator is 50 times longer, so perhaps the longness is creating trouble
If you look at it, both scenery generator and numberofverbs generator generates when entering a room,
while the long code is triggering, it accidentally conflicts with numberofverbs generator creating random stuffs
But I am still not sure what is the fix, how do I control a code to load before the other code?
Scenery generators loads when entering specific room
Numberofverbs generator loads when entering all rooms
Delaying the scenery generator for 2 seconds seems to give some insights on what is happening,
basically the second time the player enters the room, the numberofverbs generator changes the aliases of the scenery objects, therefore the scenery generator was not able to clear those objects
So how am I going to clear those objects with random names?
I tried a lot of methods, and realized the issue is not about clearing random names, or rather to disable random names from appearing in the first place, which random names are being generated because clone generator makes use of object.names + "" and numberofverbs makes use of object.names + "", therefore they override each other
So despite all the attempts, there is only one true solution which is to directly write (0) on the clone generator for each objects, and have it not being targeted by numberofverbs generator
Same goes for the Residential area1 (0), Residential area2 (0), Residential area3 (0), Residential area4 (0),
we need to give it a made up attribute like object.skipverbstat, and modify numberofverbs generator to skip any objects that have skipverbstat
Overall, this seems like a lot of work compared to just manually add (0) to aliases to objects
If you just want to find out the number of verbs that can be used on an object, you can do that quite easily. You could do something like:
verbcount = 0
foreach (verb, game.verbattributes) {
if (HasAttribute (object, verb)) {
verbcount = verbcount + 1
}
}
However, this won't tell you if an object is really interactable or not, because it only checks verbs – it doesn't check for commands like "take" or "look at".
You could make those special cases – but then, would you want it to include objects that you can't take but the player might try to? There might be objects in a game that aren't supposed to be taken because that would be silly (maybe scenery objects like trees), but also objects that can't be taken because they're nailed down; where trying to take them gives the player information. So should "Take" be included in the number of verbs or not?
One way to do this would be modifying the built-in javascript function updateObjectLinks
, which is responsible for building the pop-up menu of verbs for clickable object links. Then, the number would just show how many items will appear in that little menu, but I think that might be what you want. Then, if you don't want "Take" and "Look at" to be counted, you can just remove them from an object's displayverbs.
The function would look something like:
function updateObjectLinks(data) {
$(".elementmenu").each(function (index, e) {
var $e = $(e);
$e.children(".verbcount").remove();
var verbs = data[$e.data("elementid")];
if (verbs) {
$e.removeClass("disabled");
$e.data("verbs", verbs);
$e.attr("data-verbs", verbs);
$("<small>", {class: "verbcount"}).text(" ("+verbs.split("/").length+")").appendTo($e);
} else {
$e.addClass("disabled");
}
});
}
Or, in a form you can just paste into Quest's UI Initialisation script:
JS.eval("updateObjectLinks=function(d){$('.elementmenu').each(function(e,a){var t=$(a);t.children('.verbcount').remove();a=d[t.data('elementid')];a?(t.removeClass('disabled'),t.data('verbs',a),t.attr('data-verbs',a),$('<small>',{class:'verbcount'}).text(' ('+a.split('/').length+')').appendTo(t)):t.addClass('disabled')})};")
That's off the top of my head, but it might do something like what you want.
I combine your first code into a working minimalist code
Script when entering a room
foreach (objectx, ScopeVisible()) {
verbcount = 0
foreach (verb, game.verbattributes) {
if (HasAttribute (objectx, verb)) {
verbcount = verbcount + 1
}
}
objectx.alias = objectx.name+" ("+ verbcount+")"
}
The following code seems to work on my current game, but somehow it failed to combine with your code
if (ListContains(objectx.displayverbs, "Take")) {
objectx.verbcountstat = objectx.verbcountstat+1
}
if (HasAttribute(objectx, "speak")) {
objectx.verbcountstat = objectx.verbcountstat+1
}
if (HasAttribute(objectx, "look")) {
objectx.verbcountstat = objectx.verbcountstat+1
}
if (HasAttribute(objectx, "buy")) {
objectx.verbcountstat = objectx.verbcountstat+1
}
if (objectx.feature_usegive = true) {
objectx.verbcountstat = objectx.verbcountstat+1
}
There might be objects in a game that aren't supposed to be taken because that would be silly (maybe scenery objects like trees), but also objects that can't be taken because they're nailed down; where trying to take them gives the player information. So should "Take" be included in the number of verbs or not?
I guess you are talking about change of situation, from my perspective, I would like it to be like an example scenario 1. Scenery Tree (0) can't be interacted 2. Player gets an axe from another room, and return to this room 3. Scenery tree becomes (1), and it now have a "chop tree" verb 4. (I purposefully require player to move to another room as I know the verb only updates on enter room.)
Your second code can't be used, it might be due to my coding inexperience
if (game.enablehyperlinks) {
data = NewStringDictionary()
foreach (object, ScopeVisible()) {
dictionary add (data, object.name, Join(GetDisplayVerbs(object), "/"))
}
JS.updateObjectLinks (data)
exits = NewStringList()
foreach (exit, ScopeExits()) {
list add (exits, exit.name)
}
JS.updateExitLinks (exits)
commands = NewStringList()
foreach (cmd, ScopeCommands()) {
list add (commands, cmd.name)
}
JS.updateCommandLinks (commands)
}
Your last code works brilliantly, but it is giving a message rather than changing the objects aliases, or perhaps that is the intention? Since this might probably stops it from interfering with any in game codes that makes use of aliases
This is probably my final favourite code, although if new commands pops up, I might meet into potential problems again
This just makes me wants to return to my alternative walkaround, which is to just add (0) to scenery objects,
but if anyone wants a code that can calculate the number of verbs, you might want this final code
foreach (objectx, ScopeVisible()) {
verbcount = 0
foreach (verb, game.verbattributes) {
if (HasAttribute (objectx, verb)) {
verbcount = verbcount + 1
}
}
if (ListContains(objectx.displayverbs, "Take")) {
verbcount = verbcount + 1
}
if (HasAttribute(objectx, "speak")) {
verbcount = verbcount + 1
}
if (HasAttribute(objectx, "look")) {
verbcount = verbcount + 1
}
if (HasAttribute(objectx, "buy")) {
verbcount = verbcount + 1
}
if (objectx.feature_usegive = true) {
verbcount = verbcount + 1
}
objectx.alias = objectx.name+" ("+ verbcount+")"
}
For mrangel's last code
I get
You can see an apple (1), an apple1 (2), an apple2 (2), an apple3 (2), an apple4 (3) and apple5 (4).
It is almost accurate until the apple3, the code does not counts in the use verb
After a good night's sleep, my brain seems to work better
This final code be better
foreach (objectx, ScopeVisible()) {
verbcount = 0
foreach (verb, game.verbattributes) {
if (HasAttribute (objectx, verb)) {
verbcount = verbcount + 1
}
}
if (ListContains(objectx.displayverbs, "Take")) {
verbcount = verbcount + 1
}
if (HasAttribute(objectx, "look")) {
verbcount = verbcount + 1
}
if (objectx.feature_usegive = true) {
verbcount = verbcount + 1
}
objectx.alias = objectx.name+" ("+ verbcount+")"
}
I am going to guess mrangel's foreach verb game code loop already counts in Speak verb and Buy verb, even though it does not appears on the quest app's left hand side inside the Verbs folder
But of course, this game code is going to interfere with in game codes that makes use of objects.aliases, so apparently my refreshed mind have a new idea
Pseudocode
Main code gives us alias1
Numberofverbs generator gives us alias2
When entering all rooms,
all objects.alias = all objects.alias1 + all objects.alias2
But yeah, it is hard to redo my current game with 100+ rooms for now, so both of these codes will have to be delayed to the future, while currently I just use the scenery objects = (0) trick first
But if you run into any issue, maybe you can post it first and let the amazing mrangel take a look
Small demostration available at
https://textadventures.co.uk/games/view/57zl3sqjdeoeuqwqok9r5q/test