festivecasual / sigma-mud

Experimental MUD server in Python
0 stars 0 forks source link

Given items should have to be accepted between players #7

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
I think we should definitely ensure that the recipient accepts an item
given to them by default; otherwise, it opens players up to 'spam' gives
where they're given a whole bunch of stuff they don't want...

Original issue reported on code.google.com by meagains...@gmail.com on 11 Aug 2008 at 4:40

GoogleCodeExporter commented 9 years ago
This is an interesting MUD problem...

How do you handle the acceptance?  Waiting for the user to respond would require
taking the user out of play state and into a special STATE_ACCEPT_GIVE.  This 
could
effectively disable the player's ability to interact with the world (and could 
end up
being exploitable from a PVP combat perspective).

Did this feature exist in DR?  How was it handled?

I could see queueing item transfers in the intended-receiving Player object, 
then
adding an "accept" command that would target an exchange in the queue.  The 
queue
would be dumped after leaving the room, and queued exchanges would be 
invalidated if
the offering player has left the room upon "accept"ing the item.

The above solution would be essentially asynchronous (and I can't see how async
wouldn't be the preferable universal solution in MUDs), and changing the state 
would
be very close to synchronous (less error, more blockage).

Original comment by bmcca...@gmail.com on 12 Aug 2008 at 12:08

GoogleCodeExporter commented 9 years ago
Yep, you've pretty much got it. The give would set up a queue that would last 
say, 30
seconds, in which the receiving player can use an ACCEPT command which would 
then
allow the transfer. Note that the receiving player and the giving player must 
be in
the same room at the time the command is ACCEPTed (I don't think that the queue 
needs
to be dumped at a leave -- they can always come back, and if it has a timer, 
then its
not a problem of someone's give queue being permanently disabled, as it will 
cease to
exist as soon as it ends). You're right, it has to be asynchronous.

A player should only be able to be GIVEn one thing at a time, as this reduces
confusion on what exactly they're accepting.

I could also if the player has the ability to set a preference to always accept
items, but I don't think it should be on by default.

Original comment by meagains...@gmail.com on 12 Aug 2008 at 12:27

GoogleCodeExporter commented 9 years ago
This leads to the next question: Is there a mechanic for an 'ad-hoc' timer yet? 
Tasks
seem suited for cases like checking for a certain status at a steady interval, 
but it
doesn't seem like its the right structure for something like this. If another
structure is needed, I'm willing to create it, and own this issue.

Original comment by meagains...@gmail.com on 12 Aug 2008 at 5:58

GoogleCodeExporter commented 9 years ago
Revision 90's libsigma allows for ad hoc one-shot timers by inserting a task 
with a 
TTL of 1 (meaning one iteration before it's deleted from the task queue).  The 
rewrite of say(...) below has a nasty crash bug (with debug activated) if the 
active 
player leaves the room or game, but replacing the stock function with this 
illustrates how the timer functionality would work with a more complete 
function.

In this example, everyone in the speaker's room would hear two echoes, 10 
seconds 
apart from each other and from the original speaking.

@handler
def say(data):
  speaker = data["speaker"]
  tail = data["tail"]

  report(SELF | ROOM, "$actor $verb, '" + tail + "'", speaker, ("say", "says"))

  def echo(speaker):
    return lambda: report(SELF | ROOM, "You hear an echo.", speaker)

  insert_task("echo", echo(speaker), 10, 2)

Original comment by bmcca...@gmail.com on 12 Aug 2008 at 4:02

GoogleCodeExporter commented 9 years ago
Proposed solution:

. Implement a task for item acceptance management.  This runs every 20 seconds.

. Add a dictionary object to the world module with the id(...) of the recipient 
character object as the key and values being a tuple of the item to be 
transferred, 
the offering character, and the system time of the offer.  The recipient gets a 
message asking them to "accept" the item if they wish.  The room hears a 
report(...).

. When the task runs, iterating over each offer in the dictionary:

.. Offers more than 60 seconds old are terminated.  Both sides are notified.

.. Offers older than 40 seconds give a strong warning to the recipient.

.. Offers older than 20 seconds give a weak warning to the recipient.

. The "give" handler checks that a recipient doesn't already have an 
outstanding 
offer before queuing a new one.  This is easy because the recipient object is 
keyed 
to the dictionary.  No report(...) to the room for a failure, but messages are 
sent 
to the two active characters in the proposed transaction.

. The "accept" and "refuse" functions dequeue the offer (removing the key from 
the 
dictionary).  If the item is accepted, both characters must still be in the 
same 
room, the offering character must still have the specific item offered, and the 
recipient must have enough inventory room to accept.  If so, the transfer is 
made 
with a report(...) to the room.

. Outright refusals are noted in a room report(...), but implicit (60 second 
timeout) refusals are not.

Original comment by bmcca...@gmail.com on 17 Mar 2009 at 8:54

GoogleCodeExporter commented 9 years ago
Fixed in r129.  Privacy is not addressed significantly, so there is room for 
future 
improvement.

Original comment by bmcca...@gmail.com on 9 Jan 2010 at 7:22

GoogleCodeExporter commented 9 years ago

I'd definitely advice against using timers for this. Not only it makes code 
more complex but I also find 
the resulting functionality unrealistic.

Here's my suggestion:

1) a reference to an offered item is kept in a 'offered_items' table, together 
with a reference of the 
recipient.

2) as long as the item is listed in this dict, it is susceptible to a 'take' 
command from the recipient

3) if the giver uses the item or stores it (say, put in a bag), the item is 
cleared from the 
'offered_items' dict.

4) If the giver moves, the 'offered_items' dict is emptied.

Original comment by hello.ja...@gmail.com on 5 Feb 2010 at 5:38

GoogleCodeExporter commented 9 years ago
Already implemented using the task framework. This implementation is superior 
to the 
suggested because of the following:

- Creates an automatic sunset for any offer.
- Allows giving while en-route (will be important once grouping mechanics are 
implemented)
- Does not overload what will be a 'popular' verb in 'take' (the proposed 
suggestion 
would make 'take' have to access another collection, which would make a 
requirement 
to implement a 'from X' implementation on the verb. We may already need to do 
this 
for allowing taking from freestanding containers, throwing people in the mix 
makes 
this more difficult)

There is room for improvement, but for 1.0, the current implementation is 
sufficient.

Original comment by meagains...@gmail.com on 16 Feb 2010 at 7:25