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
