Developer Store
Support
Member Forums

Screenshots
FAQ
Documentation
License
Known Issues
Downloads

MMOWorkshop BACK!

PyTorque
TGB Web Browser


talentraspel

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

Animated doors

You can watch such doors in action: http://www.duffy1.franken.de/doors.avi

There is a very well done resource for doors that did almost all I need out of the box: http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=11651

I just added two things (see attached doors.cc and doors.h):

  • make the door selectable by simple add ItemObjectType to its type mask
  • add a console function to report its current state as there was only a toggle function

The selecting only works if you apply the item select patch to rpgTSCtrl.cc as described in the section PickupItems.

In the door.cs included in the resource I added this wrapper function as I had some problems getting a proper return code using TGEEval directly from the object (the object returns an int and as long as it's not going through Torque script you won't get the int as a string but get the result of a previous TGEEval):

// wrapper function as TGEEval always return strings
function doorOpenState(%door) {
  return %door.getOpenState();
}

The above adds what you need to show, animate and select a door. The logic i.e. the checks for a key, keeping track of a door's state and so on is done in the python code.

Beware: This is not final. There is quite some debug code in it and it adds doors when you click on it instead of fetching everything from the DB. I share this code to get feedback and suggestions but not really to give you a final version. This may change as I work on it. You've been warned.

Let's start with the class holding the state of a door: mud/world/door.py:

# door definition

from mud.common.persistent import Persistent
from sqlobject import *
from collections import defaultdict

class Door(Persistent):
    doorId = IntCol()
    locked = IntCol(default = 0)
    lockable = IntCol(default = 0)
    lockId = IntCol(default = 0)
    open = IntCol(default = 0)

    def _init(self,*args,**kw):
        Persistent._init(self, *args, **kw)

(TODO: Mention it has to be added to Genesis.py and how)

The select function (again only with the pickup patch) will call PySelect when you click on a door. This function calls select in mud/simulation/simmind.py in the class SimMind. I changed it like that to make it notice a door:

    def select(self,srcId,tgtId,charIndex,doubleClick,modifier_shift):
        if self.selectCredit.get(srcId,None):
            return
        try:
            src = self.simLookup[srcId]
        except KeyError:
            print "simmind.select: source not found"
            return
        try:
            tgt = self.simLookup[tgtId]
        except KeyError:
            try:
                tgt = self.simItemLookup[tgtId]
                #print "simmind: select() : %s"%tgtId
                self.perspective.callRemote('SimAvatar','select',srcId,tgtId,charIndex,doubleClick,modifier_shift)
                return
            except KeyError:
                try:
                    clazz = TGEEval("%d.getClassName();"%tgtId)
                    if clazz == "Door":
                        #TGEEval("%d.toggle();"%tgtId)
                        doorIsOpen = int(TGEEval("doorOpenState(%d);"%tgtId))
                        #print "door state=%d"%doorIsOpen
                        self.perspective.callRemote('SimAvatar','selectDoor',srcId,tgtId,charIndex,doubleClick,modifier_shift,doorIsOpen)
                except:
                    print_exc()
                    print "simmind.select: target ID %d not found"%tgtId
                    return
                return
        
        self.selectCredit[srcId] = True
        
        d = self.perspective.callRemote('SimAvatar','select',srcId,tgtId,charIndex,doubleClick,modifier_shift)
        d.addCallback(self.grantSelectCredit,srcId)
        d.addErrback(self.grantSelectCredit,srcId)
    
    def remote_toggleDoor(self,doorId):
        try:
            TGEEval("%d.toggle();"%doorId)
        except:
            print_exc()

If you don't need any checks server-side you can just uncomment the TGEEval with the toggle function. I did that to test the resource and the changes I did to the door.cc.

As I wanted to check for locked doors and key items I forward the request to the zone code through SimAvatar. mud/world/simavatar.py:

    def perspective_selectDoor(self,srcId,tgtId,charIndex,doubleClick,modifier_shift,isOpen):
        self.zone.selectDoor(self.simLookup[srcId],tgtId,charIndex,doubleClick,modifier_shift,isOpen)

    def toggleDoor(self,door,sound,loc):
        self.mind.callRemote("toggleDoor",door.doorId)
        self.mind.callRemote("playSound",sound,loc)

In the ZoneInstance definition I added a lookup structure for doors:

        self.doors = {}

(TODO: load the doors when the ZoneInstance is created)

mod/world/zone.py:

    def selectDoor(self,srcSimObject,doorId,charindex,doubleClick,modifier_shift,isOpen):
        mob = self.mobLookup[srcSimObject]
        player = mob.player
        if self.doors.has_key(doorId):
            door = self.doors[doorId]
        else:
            door = Door(doorId=doorId)
            # just for testing
            if doorId == 6317:
                door.locked = True
                door.lockable = True
                door.lockId = 6317
            self.doors[doorId] = door

        # door closed and locked: need a key to unlock
        if not isOpen and door.locked and (modifier_shift or doubleClick):
            key = player.getKeyFor(door.lockId)
            if key:
                door.locked = False
                player.sendGameText(RPG_MSG_GAME_GREEN,r'Door is unlocked.\n')
            else:
                player.sendGameText(RPG_MSG_GAME_RED,r'You have no key for this door.\n')
            return
        # door is unlocked and should be locked: need a key
        if door.lockable and (modifier_shift or doubleClick):
            if isOpen:
                self.simAvatar.toggleDoor(door)
            key = player.getKeyFor(door.lockId)
            if key:
                door.locked = True
                player.sendGameText(RPG_MSG_GAME_GREEN,r'Door is locked.\n')
            else:
                player.sendGameText(RPG_MSG_GAME_RED,r'You have no key for this door.\n')
            return
        if not door.locked:
            loc = player.simObject.position
            if isOpen:
                sound = "doorClose.ogg"
            else:
                sound = "doorcreak.ogg"
            self.simAvatar.toggleDoor(door, sound, loc)
        else:
            player.sendGameText(RPG_MSG_GAME_RED,r'Door is locked.\n')

The key checking code is in mud/world/player.py:

    def getKeyFor(self, lockId):
        found = None
        for item in self.curChar.items:
            if item.lockId == lockId:
                found = item
                break
        return found

This needs an additional attribute in the item: lockId. This integer defines the ID of the lock this item can open and close. Currently I just use the door object ID for that.

(TODO: show how to add the lockId to ItemProto, ItemInstance and Item)

This is an example of a key item: put that somewhere in <game root>/genesis/item/

item = DBItemProto(name="Schluessel")
item.itemType = ["COMMON","COMPONENT"]
item.desc = "Ein kleiner Metallschluessel."
item.model = "door/keysilver1.dts"
item.bitmap = "STUFF/24"
item.stackMax = 1
item.worthCopper = 30
item.lockId = 6317

The only important things to mention is the setting of the attribute lockId and make sure it's not stackable (stackMax = 1).

The door definition in the mission as well as its datablock is defined in the door object resource: an example:

   new Door(Door1) {
      canSaveDynamicFields = "1";
      position = "-41.9096 -439.304 139.676";
      rotation = "1 0 0 0";
      scale = "1.5 1 1.25";
      dnStartTime = "-1";
      dnEndTime = "-1";
      dataBlock = "Door1";
   };

Attachments