sorry for being a bit slow but it simply currently is too hot here in
Germany right now to think clearly about something other than how to
get something cool to drink ;-)
I think you are right that it will cost even more performance to
change saving/restoring as you describe.
Could you explain how additional names added with the new commands are
handled currently?
How does this work together with the current save/restore implementation?
I wonder why it works at all currently ;-) Shouldn't the additional
names get lost with each loading of the current state at the beginning
of a move?
Keep cool
Thomas
I wish is was hotter here, it's been quite cold this week. In fact
last week was one of the coldest morning we have had in a long time,
the first time I can ever recall having to spend 15 minutes melting
ice off the windscreen of the car (which was incongruously parked
beneath a palm tree).
For an object's names, each object has a pointer to an object of type
'name' which holds a single string and a pointer to the next name if
the object has more than one. Added more names mallocs a new name
object and changes the pointer of the last name to point to this new
name.
The reason the game still works without the save code being
implemented is that your interpreter is only running one game and only
a single instance of it. As the interpreter doesn't stop running in
between moves, all the correct state is still in memory. If 20 people
started playing at once then the web server would spawn more
interpreters to handle all the requests and then you would start to
see a problem. ie, you play the first 10 moves on interpreter A, and
during that time an object is given a new name, then more users join
and the web server spawns two more interpreters (that will load the
game from scratch). Then on your next move interpreter B is used to
process your command, and you'll see that the object doesn't have the
extra name, only the default ones specified in the game.
Even if there is only one interpreter, if it is running two different
games you will also see the problem. Player 1 uses interpreter A and a
name gets added to an object, then player 2 uses interpreter A and
they see the extra name too. This isn't bad if they are players in the
same game world, but if those two players are in two entirely
different game worlds nothing they do should be affecting each other.
We can do the full same technique described before, but I would still
consider just having enough spare objects in the game to represent all
the object you are likely to need and perhaps then make two extensions
to the interpreter to cope with dynamically named players (or just
have the players controlled pre-defined characters as discussed
before). Anyway, the changes could be 1), make the interpreter always
accept the players login as a name for the object they are currently
controlling (without it actually being a 'name' attached to the object
directly), and 2) add a 'function' option to the 'short' description
just like the one used with 'long' description. You would then have to
add whatever you need to have the 'long' and 'short' functions say,
"You can see" <whatever user id is currently controlling this object>
"here.^" I'd have to look at how your object/ player mapping is done
again to give more specific advice on how to achieve this, but it
might give you the functionality you want without needing to modify
objects, and therefore it would all work with the old save code.
I hope that all makes sense!
Stuart
thanks for explaining!
And the chain of name objects does not get disconnected by loading the
game state from the file every move currently?
How do you do this? You don't change the pointer to the names/chain of
name objects when loading the game state file?
How do you keep the pointer to the dynamically added names intact?
Your suggestions make sense to me. I also think we should try to not
overthrow the complete save mechanism for now.
To make everything full dynamic would be a very big step again and I
think then the move to a database would have to be done.
We should first try how far we can get with the current state
including your 1) and 2).
I would like to begin with creating some content now for my game in
the next time and not so much further extending JACL ;-)
Besides, I give you some warmth from here if you give me some coldness
from your side!
(I have to keep remembering that what I write here is not a private
email but a discussion group entry :-)
Thomas
The string of names doesn't get disconnected because the save/ load
process just doesn't touch it at all. Reloading the game itself would
set things back to their original state, but loading a saved game only
changes the values for the things that are saved (the 12 integer
properties and the attributes in the case of objects), and leaves
everything else as it is (short name, command names, article etc).
If you want some help adding the code needed to the parser and
interpreter to deal with the player objects I'll just need some
details on how to map a username to the object that represents the
player controlling that object. For example, in the parser I will need
to take each word typed by the player and see if it is in the list of
usernames. If it is I will then need to find the number of the object
that is representing that username/ player and mark that it has been
referred to like any other object name. This is how we will avoid the
need for the object to be given the name in the normal fashion.
To display the object we will need to do the reverse -- somehow look
the object up to find out which player it represents. A custom macro
would be nice for this:
write "You can see " noun1{username} " here.^"
{+macro_username
username return_value arg[0]
}
That 'username' command would need to be a new command that set a
string to the username that is controlling the specified object (I'm
presuming there won't be any way to do that lookup using pure JACL
code???) This would mean looking through the list of all the objects
that are representing players, and returning the matching user name if
the specified object is found in the list. Of course this may also
return null if the object passed isn't actually a player object.
Oh, and I don't see any reason why a public forum has to be dry and
impersonal. :)
Stuart
thanks for explaining!
So the next question:
How can I retrieve the values in a string array defined in the JACL
source in C, out of parser.c for example?
Currently I have all the player names stored in such a string array.
The c code will have to look into this array for being able to know if
a player object is addressed in a command.
So what I need c source for is:
Retrieving the value of the "counter" object variable.
Retrieving the info if a user defined attribute "PLAYEROBJECT" is set or not.
Retrieving the values of string variables in a string array "playernames[]".
Thanks! :-)
Thomas
The value of a JACL integer, such as SCORE can be retrieved using:
int value = integer_resolve("SCORE")->value;
The value of an attribute is fetched with this:
long value = user_attribute_resolve("PLAYEROBJECT");
And then an object can tested to see if it has that attribute using:
if (object[index]->user_attributes & value) {
// object # index has the attribute 'value'
}
Strings can be fetched with either:
char * name = string_resolve("playernames[2]"->value;
or
string_resolve("playernames", 2)->value;
The second method is probably more efficient if you are iterating over
a list using C code.
int length = array_length_resolve("playernames");
will give you the number of strings in the array.
Hope this helps,
Stuart
I have a little bug report again. I am currently experimenting with
the macro you suggested. I implemented it like this currently:
# macro "playername"
# Example: write "You can see " noun1{playername} " here.^"
{+macro_playername
setstring return_value playershort[arg[0](counter)]
}
("playershort" is a string array containing all the player's names and
"counter" points to the correct index into this array.)
But this results in error messages in the game:
I call it this way in the game:
[...]
write "MACRO TEST: Your name is: " player{playername} "^"
[...]
And this is the message in the browser:
MACRO TEST: Your name is: mudlab: In function "+macro_playername",
attempt to use object pointer "playershort[arg[0]" that does not point
to an object (-1).
jaxom
Interestingly the correct value is indeed being printed nevertheless
after the error message.
Thomas
I'm more surprised about getting the rise name printed than the error
message. ;) Perhaps 'jaxom' is the first name in the array?
I'll take a look at re-writing the value parsing part of JACL because
at the moment it doesn't handle nested arrays properly. You could get
it to work by splitting the expression up a bit, for example, this
should work:
{+macro_playername
set temp = arg[0](counter)
setstring return_value playershort[temp]
}
As 'arg' is the equivalent of arg[0] you might even be able to do this:
{+macro_playername
setstring return_value playershort[arg(counter)]
}
Either way it would be good if JACL handled more complex nested
expressions so I'll look into it. Can you create an issue on the bug
tracker and assign it to me? Also, the 'inventory' issue is assigned
to you so I can close it, but it is fixed now.
Take care,
Stuart
I've been thinking a bit more about this and maybe it could work to
have all the objects defined in the game get saved as normal and then
a second (presumably smaller) set of object that have been dynamically
created by the game. This would mean that if an object needs any of
the new things to be dynamic, ie, short description or names then it
would have to be a complete dynamic object, as opposed to one that
gets defined in the code and get changed. The only problem I can see
with this is where a normal object needs to reference a dynamic object
at startup time. For example, a hat that is worn by a player that is
yet to be created. This probably isn't such a big problem as you could
just move the hat to the player using a line of code one the player
object has been created.
What I like about this system is that only the dynamic objects get all
the extra information saved and because they are separated into two
separate groups, it should be relatively easy to implement. I'll write
up a procedure a bit like the one below and we can compare.
Stuart
On 4 July 2010 19:10, Thomas Schwarz <schwarz...@gmail.com> wrote:
interesting idea. But I did not fully understand what you mean by:
> at startup time. For example, a hat that is worn by a player that is
> yet to be created. This probably isn't such a big problem as you could
> just move the hat to the player using a line of code one the player
> object has been created.
Where should this line of code come from? Some kind of automatism?
Or does the loading procedure remember such "forward references" to
currently not yet existing objects and then resolves them when all
objects are there?
Thomas
The situation I was thinking of for example is if you had an object
that each player starts the game with, such as a hat.
The hat might be a static object in the game, but it couldn't have a
defined 'parent' element as the object that it would be a child of
doesn't exist yet. This isn't a big deal because the code that creates
the player would just do something like this:
set number_of_players + 1
setstring object_label "player" number_of_players
newobject object_label
move hat_1 to object_label
Well, something like that anyway. Of course the hats could also be
dynamically created so it has a name like 'Thomas' hat'.
The other problem is associating functions with dynamic objects. You
can always use the * prefix to hand code the full function name, which
allows you to manually associate it:
{*examine_player1
write "Some description here.^"
}
But this method falls down a bit when you don't know how many objects
you are going to have and what their labels are going to be. I really
should look at some sort of concept like a class. That way you could
have an examine function that is used for any object that is of the
specified class, such as a 'player object'.
Regards,
Stuart