Author Topic: Here's some code  (Read 3490 times)

Offline Sluggy

  • Friend
  • **
  • Posts: 91
    • View Profile
    • Stellarmass
Here's some code
« on: January 07, 2009, 12:13:14 am »
It's not much and it's not perfect but here's some code for making objects attachable/able to accept attachments. I feel with this great mudlib and all the help I've gotten here I kinda owe something back. I was cleaning it up the other day and it seemed fairly modular so I felt it might be usable to others. I've been using it for silencers and scopes myself.

ATTACHMENTS:
Inherit attachment.c in anything you want to be able to attach. Call SetAttachmentType(string) to set this half of the relationship.


ATTACHMENT ACCEPTORS:
Inherit the events from acceptor.c in anything you want to accept stuff. Call acceptor::create(). Call SetAcceptedAttachments() with a mapping where the keys are the attachment types you want to be able to connect to this object. The values were meant to be the number allowed but I never finished that part.

NOTES: This is kinda weird but when an object is attached to an acceptor, the filename and keyname of that attachment are stored and it is destroyed. During detachment the keyname must be supplied and then the object will be re-created using the filename from before. It's kinda specific to the mud I'm working on but eventually I might have to change it to just store the attachment object in the acceptor.

-Obviously, variables can't be saved for attachment objects.
-All attachments inherit LIB_ITEM. Not a big deal to me some others might not like it.
-Only one type of each attachment is allowed per receiver. I started work on a system
 that would free this up but it got very convoluted and I wasn't even sure I'd ever
 need this so I just dropped it.

Enjoy!

/lib/events/acceptor.c
Code: [Select]
/*
STELLARMASS
1/4/2009
SLUGGY (J.C.)

Events inheritable by any object that should accept attachments.

The attachments are stored in acceptors as mappings containing the keyname used to refer to them
at attachment time as well as its filename. The actual object is destroyed upon attachment.
During detachment the object is re-created using that filename.

Known Issues:
-Obviously, variables can't be saved for attachment objects.
-All attachments inherit LIB_ITEM. Not a big deal to me some others might not like it.
-Only one type of each attchment is allowed per receiver. I started work on a system
that would free this up but it got very convoluted and I wasn't even sure I'd ever
need this so I just droppped it.
*/

private mapping Attached = ([]); //[object's keyname : {attachment type, instances, object ref}]
private mapping Accepted = ([]); //[attachment type : allowed instance]

#define ATTACHMENT_TYPE 0
#define INSTANCES 1
#define OBJECT_REF 2

static void create()
{
this_object()->AddSave( ({"Attached"}) );
}

void SetAcceptedAttachments(mapping types)
{
Accepted = types;
}

mapping GetAttachments()
{
return Attached;
}

mixed CanDetach(string attachment)
{
//make sure we even have the item in question to detach
if(member_array(attachment,keys(Attached)) >= 0)
{return 1;}
return "This " + this_object()->GetKeyName() + " does not have a " + attachment + " attached to it.";
}

int ValidateAttachments(mixed arg,string inType)
{
if(arg[ATTACHMENT_TYPE] == inType) return 1;
return 0;
}

mixed CanAttach(object attachment)
{
string inType = attachment->GetAttachmentType();

//first be sure it allows this type of attachment
if(member_array(inType,keys(Accepted)) >= 0)
{
//now make sure we don't already have one
if(!sizeof(values(Attached)) || !sizeof(filter(values(Attached),(:ValidateAttachments:),inType)))
{return 1;}
return "This " + this_object()->GetKeyName() + " already has " + attachment->GetShort() + " attached to it.";
}
return "This " + this_object()->GetKeyName() + " doesn't accept that " + attachment->GetKeyName() + " as an attachment.";
}

void eventAttach(string attachment,string attachType,string obj)
{
Attached += ([ attachment :({ attachType,1,obj }) ]);
}

mixed eventDetach(string attachment)
{
//the object is re-created using the filename stored during attachment
object obj = new(Attached[attachment][OBJECT_REF]);

if(obj && objectp(obj))
{
//test to make sure we actually created the right thing!
if(!obj->CanAttach(this_object()))
{
//we got something! but it isn't an attachment. eeep!
error("Detached a non-detachable object. Object name: " + obj->GetKeyName() + " Attachment Id: " + attachment);
destruct(obj);
return 0;
}
//success
map_delete(Attached,attachment);
return obj->eventDetachFrom(this_object());
}
//failure, no object
error("Detach did not create a valid object. Object name: " + obj->GetKeyName() + " Attachment Id: " + attachment);
return 0;
}

mixed indirect_attach_obj_to_obj(object this,object target)
{
if(environment() != this_player()) return "#You don't have " + this_object()->GetShort() + ".";
return 1;
}

//NOTE TO SELF: when dealing with string as first param, the
//function becomes 'direct'. Probably due to the fact that this
//object is now technically the first one in the statement.
//Whatever :P
mixed direct_detach_str_from_obj(string attachment,object me)
{
if(environment(this_object()) != this_player()) return "#You don't have " + this_object()->GetShort() + ".";
return CanDetach(attachment);
}

/lib/attachment.c
Code: [Select]
/*
STELLARMASS
1/4/2009
SLUGGY (J.C.)

Inheritable for any object that can be attached to anything that will accept it.

The attachments are stored as mappings containing the keyname used to refer to them at
attachment time as well as its filename. The actual object is destroyed upon attachment.
During detachment the object is re-created using that filename.

Known Issues:
-Obviously, variables can't be saved for attachment objects.
-All attachments inherit LIB_ITEM. Not a big deal to me some others might not like it.
-Only one type of each attchment is allowed per receiver. I started work on a system
that would free this up but it got very convoluted and I wasn't even sure I'd ever
need this so I just droppped it.
*/
#include <lib.h>

inherit LIB_ITEM;

private string AttachmentType = "attachment";

static void create()
{
::create();
SetKeyName("attachment");
SetId(({"attachment"}));
SetShort("an attachment");
SetLong("Some kind of attachment.");
}

void SetAttachmentType(string type)
{
AttachmentType = type;
}

string GetAttachmentType()
{
return AttachmentType;
}

mixed CanAttach(object target)
{
return target->CanAttach(this_object());
}

/******************************************************************
 1/5/2009
 J.C.
This function basically stores the object keyname and filename
in the receiver and then destroys itself. The attachment is
recovered by the receiver's detachment method by re-creating
the object using the filename that was stored.

Yeah, it's weird but for some reason I'm just too afraid to
add extra objects to my firearm's storage. I figure if this
causes the bigger hit I'll change it and if not I'll remove
the extra checks in my firearms' ammo-checking functions.
Either way I'll win! Safety first, optimization later.
/******************************************************************/
mixed eventAttachTo(object target)
{
string fileName = explode(file_name(this_object()),"#")[0];
string shortDesc = GetShort();
string targetDesc = target->GetShort();
mixed result = CanAttach(target);
if(intp(result) && result)
{
//success!
target->eventAttach(GetKeyName(),AttachmentType,fileName);
destruct(this_object());
say(this_player()->GetName() + " attaches " + shortDesc + " to " + targetDesc + ".");
return "You attach " + shortDesc + " to " + targetDesc + ".";
}
return result;
}

mixed eventDetachFrom(object target)
{
eventMove(environment(target));
say(this_player()->GetName() + " detaches " + target->GetShort() + " from " + target->GetShort() + ".");
return "You detach " + GetShort() + " from " + target->GetShort() + ".";
}

mixed direct_attach_obj_to_obj(object attachment,object target)
{
if(environment() != this_player()) return "#You don't have " + GetShort() + ".";
if(GetWielded()) eventUnequip(this_player());
return 1;//CanAttach(target); //for some reason 'target' is null. And here I thought I would be all clever-like :<
}

/verbs/items/attach.c
Code: [Select]
/*
STELLARMASS PROJECT
7/12/2008
JAMES CLARK

UPDATED 1/5/2009 J.C.
-Everything has been made to work in a more generic fasion rather than rely on very
specific functions within my firearms code.

Used for attaching an 'attachment' object to an 'attachable' object. Originally developed for
stellarmass fireams with scopes and silencers. Basically, when an attachment is attached,
the receiver stores only a reference to the object's keyname and file reference. Then the
object is destroyed. This verb makes the receiver re-create the object using the stored filename.

*/

#include <lib.h>
#include <rounds.h>

inherit LIB_VERB;

static void create()
{
::create();

SetVerb("attach");
SetRules("OBJ to OBJ");
SetErrorMessage("Attach what to what?");
SetHelp("Syntax: attach <OBJ> to <OBJ>\n\nAttaches one object to another. They obviously should be components that are capable of attachment.");
}

mixed eventAction(object attachment,object attachable)
{
if(!attachment || !objectp(attachment)) return 0;
if(!attachable || !objectp(attachable)) return 0;

write(attachment->eventAttachTo(attachable));
return 1;
}

mixed can_attach_obj_to_obj(mixed attachment,mixed attachable)
{
if(this_player()->GetParalyzed())
{return "You can't do anything.";}
return this_player()->CanManipulate();
}

mixed do_attach_obj_to_obj(mixed attachment,mixed attachable)
{
if(this_player()->GetInCombat())
{
this_player()->SetAttack(0,(:eventAction,attachment,attachable:),ROUND_OTHER);
return 1;
}
return eventAction(attachment,attachable);
}

/verbs/items/detach.c
Code: [Select]
/*
STELLARMASS PROJECT
7/12/2008
JAMES CLARK

UPDATED 1/5/2009 J.C.
-Everything has been made to work in a more generic fasion rather than rely on very
specific functions within my firearms code.

Used for detaching previously attached objects. Originally developed for stellarmass fireams
with scopes and silencers. Basically, when an attachment is attached, the receiver stores only
a reference to the object's keyname and file reference. Then the object is destroyed. This verb
makes the receiver re-create the object using the stored filename.

NOTE: The detachment event is called from the second object passing the
      attachment keyname as a parameter.
*/

#include <lib.h>
#include <rounds.h>

inherit LIB_VERB;

static void create()
{
::create();

SetVerb("detach");
SetRules("STR from OBJ");
SetErrorMessage("Detach what from what?");
SetHelp("Syntax: detach <STR> from <OBJECT>\n\nDetached one previously attached object from another. The first parameter must be either \"silencer\" or \"scope\" in order to have any effect on firearms.");
}

mixed eventAction(string attachment,object attachable)
{
if(!attachment || !stringp(attachment)) return 0;
if(!attachable || !objectp(attachable)) return 0;

write(attachable->eventDetach(attachment));
return 1;
}

mixed can_detach_str_from_obj(string attachment,object attachable)
{
if(this_player()->GetParalyzed())
{return "You can't do anything.";}
return this_player()->CanManipulate();
}

mixed do_detach_str_from_obj(string attachment,object attachable)
{
if(this_player()->GetInCombat())
{
this_player()->SetAttack(0,(:eventAction, attachment,attachable:),ROUND_OTHER);
return 1;
}
return eventAction(attachment,attachable);
}


Offline daelaskai

  • BFF
  • ***
  • Posts: 174
    • View Profile
Re: Here's some code
« Reply #1 on: January 07, 2009, 11:19:51 pm »
Okay, so you've used this for scopes and silencers.  Any examples of this in use
that we can get a better idea of the full scope of the system?  This sounds
like the 'installable' feature that Cratylus has in the stock lib with the wrist
computer.

Daelas

Offline Sluggy

  • Friend
  • **
  • Posts: 91
    • View Profile
    • Stellarmass
Re: Here's some code
« Reply #2 on: January 08, 2009, 08:24:31 am »
Hmm, I couldn't actually find this wrist computer you were talking about but the install system itself doesn't seem to do much but check for the hooks. It's a little more flexible but a little less ready-made.

The attachment system here can be taken at exactly face value. It's kinda like a very fancy way for the user to put one thing in another thing's inventory ;)  The reason for the destruction and filename storage was due to my backwards thinking at 4AM. I was going along the lines of 1) My firearms store their ammo inside of them and I don't want to confuse that with any attachments. 2)Why use the memory for an object that effectively sits there and does nothing. I do realize that there are limitations i.e. you can't call code from these objects but until I need that functionality I didn't see a reason to go back and fix it. Although it would really be little more than changing a couple line to do so.

You can make an example using the instructions in my first post like so:

Thing that accepts attachmentA:
Code: [Select]
#include <lib.h>

inherit LIB_ITEM;
inherit "/lib/event/acceptor"

static void create()
{
item::create();
acceptor::create();

SetKeyName("Acceptor");
SetId(({"acceptor"}));
SetShort("an acceptor");
SetLong("Just a thing that accepts other things.");

SetAcceptAttachments( ([
"attachment type 1":1
]));
}

That that can be attached:
Code: [Select]
#include <lib.h>

inherit "/lib/attachment";

static void create()
{
::create();

SetKeyName("Attachment Thingy");
SetId(({"attachment thingy","attachment"}));
SetShort("an attachable thingy");
SetLong("Just a thing that can be attached to other things.");

SetAttachmentType("attachment type 1");
}

The command 'attach attachment to acceptor' will then do just that. If there is already one attached then it will tell you that you can't because there is already one there. If pass a different string to SetAttachmentType() then try it, you will be told that the first object doesn't accept the second as an attachment. In your code you can find out what is attached using GetAttachments() to return the current map. Basically I guess this all just moves the messaging and item moving out of your code when you use 'install'.

hth

Offline daelaskai

  • BFF
  • ***
  • Posts: 174
    • View Profile
Re: Here's some code
« Reply #3 on: January 08, 2009, 11:09:27 am »
Pretty cool.  I'll play around it wit a bit and see how it goes.  Thanks for
the submission.  I actually made something on par with this called an
effects system, which was based off of a system Silenus had shown
me that was really cool.

My effect system allows another "effect object" to be attached to
a weapon, drink, container, etc... to allow different effects such as
a booby trap (though Crat has a system to do this too which I like),
and stuff like fire/poison damage upon hitting.

For your attachment system, I'm probably going to modify it a bit
to not destruct the attached object so I can reference code in it.
This would be great for hollow-point bullets, maybe explosive rounds, etc..

Thanks for the submission.  I think this has promise to it.

Daelas

Offline Sluggy

  • Friend
  • **
  • Posts: 91
    • View Profile
    • Stellarmass
Re: Here's some code
« Reply #4 on: January 08, 2009, 04:08:40 pm »
Oh neat! I'm working on two system kinda like that. One was a 'Skill Effects' system which I recentrly realized might actually just be a more complicated version of the powers system in stock DS. Don't I feel silly. The other is a status system which basically uses invisible objects with heart beats as status effects that operate on whatever they are contained by and can restore an original state when removed. I felt kinda restricted by the one in Stokc DS. This one will be useful for things like DoT, HoT, and even a shifter class we're making that can change race and stats.

If you ever care to release details I'd love to see how that works out for you. Glad you found a use for the code!

Offline daelaskai

  • BFF
  • ***
  • Posts: 174
    • View Profile
Re: Here's some code
« Reply #5 on: January 08, 2009, 04:42:51 pm »
If you're thinking of a "skill effects" sytem to just add integers to skill checks, etc..., there
was a post about implementing hooks into DS.  It was very useful to me.  I'm not sure if that
was what you meant.  If it is, you should check out: Hook Support for DS.

Daelas