Developer Store
Support
Member Forums

Screenshots
FAQ
Documentation
License
Known Issues
Downloads

MMOWorkshop BACK!

PyTorque
TGB Web Browser


Larson

hallsofvalhalla - Been A while
xapken - Wizards and Champions
J.C. Smith - The Repopulation - 0.5.2 Build Notes
EmpireGames - Elementals in Rise of Heroes
Empire Games - WarPath.
jaidurn - Warcall 0.0.1.0 build notes
medafor - Final detailing of models
Thamior - Presence system GONE! [May 25th 2009)]
... MORE BLOGS!

Building a MMO
Wow I had no idea....
Quest Remnants of Chaos
Checking to see if anyone is sti...
Well here I am again :)
T3D and MMOKit
afx 2.0
Terrain specularity [video]
Torque T3D MMO Kit
[3dFoin] Dragon Bug

Drop and pick up items

Other than some of the existing MMORPGs I want to have items not only in the inventory and a bank account but also as something you can drop and pick up i.e. with a 3D represented object in the world.

This is work in progress and far from being complete. Feedback is welcomed - especially on the persistance.

To be able to drop items on the ground I started in world/PlayerAvatar in the function perspective_expungeItem():

    def perspective_expungeItem(self):
        item = self.player.cursorItem
        self.player.cursorItem = None
        if item.character not in self.player.party.members:
            raise ValueError,"Attempting to expunge an item not belonging to player's present party!"
            return
        item.slot = -1
        self.player.updateCursorItem(item)
        #item.destroySelf()
        # just for testing:
        self.player.dropItem(item)
        self.player.cinfoDirty = True

This means that you can no longer destroy items but throw them on the ground. In future there should be another function so that you can either drop or destroy it.

The dropItem() function in world/Player looks like this:

    def dropItem(self,item):
        if not item:
            return
        pos = self.party.members[0].mob.simObject.position
        rot = self.party.members[0].mob.simObject.rotation
        newpos = tuple([pos[0] + math.cos(rot[3]), pos[1] + math.sin(rot[3]), pos[2], rot[0], rot[1], rot[2], rot[3]])
        self.zone.spawnItem(item, newpos)

The calculation of newpos picks a location a bit in front of the player. The request is forwarded to the zone so that it can keep track of all dropped items.

To make it aware of the ItemDropped class add this to zone.py:

from mud.world.item import ItemDropped,ItemInstance

As I don't have a model for each and every item yet, I use a default so that at least you can see something. We add to defines.py:

RPG_ITEM_DEFAULT_MODEL = "markers/defaultitem.dts"

In world/ZoneInstance is the spawnItem function and its callback:

    # callback for spawnItem. item is the ItemInstance, simItem is the SimItem
    def spawnedItem(self, simItem, item):
        self.itemLookup[simItem] = item
        # make sure the character and player is dereferenced
        item.character = None
        item.player = None
        # store transform and zone in the iteminstance. the ItemDropped will be created in storeToItem
        positionString = ' '.join(map(str,simItem.position))
        rotationString = ' '.join(map(str,simItem.rotation))
        item.position = positionString
        item.rotation = rotationString
        item.zone = self.zone

    # spawn an item given an ItemInstance and a transfom matrix
    def spawnItem(self, item, transform):
        model = item.itemProto.model
        material = item.itemProto.material
        if (model == ""):
            model = RPG_ITEM_DEFAULT_MODEL
        self.simAvatar.spawnItem(item.name, transform, model, material).addCallback(self.spawnedItem, item)

It calls the spawnItem function in SimAvatar and gets a SimItem object back via the callback function. This SimItem is stored in the itemLookup dictionary which is defined in ZoneInstance.__init__:

        self.itemLookup = {}

In world/SimAvatar the request is sent to the simulation engine:

    #items on ground
    def itemSpawned(self, simItem):
        self.addSimItem(simItem)
        #print "spawned an item: %s\n"%(simItem.name)
        return simItem

    #spawn an item, SimItem returned by itemSpawned
    def spawnItem(self,item,transform,model,material):
        d = self.mind.callRemote("spawnItem", item, transform, model, material)
        d.addCallback(self.itemSpawned)
        return d;

The counterpart of the callRemote is in simulation/SimMind:

    def remote_spawnItem(self, itemname, transform, model, material):
        # create datablock
        datablock = CreateStaticShapeData(itemname, model, material)
        t = ' '.join(map(str,transform))
        dbname = datablock.getName()
        #print "create a %s (dbname=%s) at %s\n"%(itemname,dbname,t)
        # create TGE object
        id = int(TGEEval('newItemOnGround("%s","%s","%s");'%(itemname,t,dbname)))

        so = SimItem(id,transform, itemname)
        self.addSimItem(so)

        return so

The datablock to be used for the static shape is defined as this:

def CreateStaticShapeData(itemName, model, material):
    dbname = DBNAME_PARSER.sub('_',itemName).replace(' ','_')
    eval = """
datablock ItemData(%s)
{
   className = Armor;
   sticky=true;
   shapeFile = "~/data/shapes/%s";
};
"""%(dbname+"Data",model)

    #print "evaluating: %s\n"%eval
    TGEEval(eval)
    db = TGEObject(dbname+"Data")
    #db.setDynamic()
    #print "got name=%s\n"%(db.getName())
    return db

The TorqeScript function to create the shape is:

// droppable items

function newItemOnGround(%name,%transform,%dbname)
{
   // Create an item object
   %item = new Item(%name) {
      datablock = %dbname;
      position = %transform;
      collidable = "1";
   };
   MissionCleanup.add(%item);
   %item.setShapeName(%name);
   %item.setTransform(%transform);

   return %item;
}

Note: To store both player=None and character=None for an ItemInstance I had to comment two lines in ItemInstance:

    def storeToItem(self,override = False):
        # Only store items in the posession of a player!
        #if not self.character and not self.player and not override:
        #    return

And here is also the place the ItemDropped is created:

        if self.position and not self.droppedItem:
            self.droppedItem = ItemDropped(item = self.item, zone = self.zone, position = self.position, rotation = self.rotation)

The attributes for the transform and the zone are initialised:

    def __init__(self,item=None):
        self.worthIncreaseTin  = 0
        self.position = None
        self.rotation = None
        self.droppedItem = None
        self.zone = None