mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-10 13:56:31 -04:00
*** empty log message ***
This commit is contained in:
parent
59d17bc208
commit
0ba45e5eda
0
direct/src/level/AndLoEntity.py
Executable file
0
direct/src/level/AndLoEntity.py
Executable file
58
direct/src/level/AndLoEntityAI.py
Executable file
58
direct/src/level/AndLoEntityAI.py
Executable file
@ -0,0 +1,58 @@
|
|||||||
|
"""AndLoEntityAI.py: contains the AndLoEntity class"""
|
||||||
|
|
||||||
|
|
||||||
|
import PandaObject
|
||||||
|
import DirectNotifyGlobal
|
||||||
|
import Entity
|
||||||
|
|
||||||
|
|
||||||
|
class AndLoEntityAI(Entity.Entity, PandaObject.PandaObject):
|
||||||
|
if __debug__:
|
||||||
|
notify = DirectNotifyGlobal.directNotify.newCategory(
|
||||||
|
'AndLoEntityAI')
|
||||||
|
|
||||||
|
def __init__(self, air, levelDoId, entId, zoneId=None):
|
||||||
|
"""entId: """
|
||||||
|
assert(self.debugPrint(
|
||||||
|
"AndLoEntityAI(air=%s, levelDoId=%s, entId=%s, zoneId=%s)"
|
||||||
|
%("the air", levelDoId, entId, zoneId)))
|
||||||
|
self.input1 = None
|
||||||
|
self.input2 = None
|
||||||
|
self.levelDoId = levelDoId
|
||||||
|
level = air.doId2do[self.levelDoId]
|
||||||
|
Entity.Entity.__init__(self, level, entId)
|
||||||
|
self.initializeEntity()
|
||||||
|
self.setInput_input1_bool(self.input_input1_bool)
|
||||||
|
self.setInput_input2_bool(self.input_input2_bool)
|
||||||
|
|
||||||
|
def setIsInput1(self, isTrue):
|
||||||
|
assert(self.debugPrint("setIsInput1(isTrue=%s)"%(isTrue,)))
|
||||||
|
self.isInput1=isTrue
|
||||||
|
if self.isInput2:
|
||||||
|
messenger.send(self.getName(), [isTrue])
|
||||||
|
|
||||||
|
def setIsInput2(self, isTrue):
|
||||||
|
assert(self.debugPrint("setIsInput1(isTrue=%s)"%(isTrue,)))
|
||||||
|
self.isInput2=isTrue
|
||||||
|
if self.isInput1:
|
||||||
|
messenger.send(self.getName(), [isTrue])
|
||||||
|
|
||||||
|
def setInput_input1_bool(self, event):
|
||||||
|
assert(self.debugPrint("setInput_input1_bool(event=%s)"%(event,)))
|
||||||
|
if self.input1:
|
||||||
|
self.ignore(self.input1)
|
||||||
|
self.input1 = "switch-%s"%(event,)
|
||||||
|
if self.input1:
|
||||||
|
self.accept(self.input1, self.setIsInput1)
|
||||||
|
|
||||||
|
def setInput_input2_bool(self, event):
|
||||||
|
assert(self.debugPrint("setInput_input2_bool(event=%s)"%(event,)))
|
||||||
|
if self.input2:
|
||||||
|
self.ignore(self.input2)
|
||||||
|
self.input2 = "switch-%s"%(event,)
|
||||||
|
if self.input2:
|
||||||
|
self.accept(self.input2, self.setIsInput2)
|
||||||
|
|
||||||
|
def getName(self):
|
||||||
|
#return "andLoEntity-%s"%(self.entId,)
|
||||||
|
return "switch-%s"%(self.entId,)
|
56
direct/src/level/BasicEntities.py
Executable file
56
direct/src/level/BasicEntities.py
Executable file
@ -0,0 +1,56 @@
|
|||||||
|
"""BasicEntities module: contains the BasicEntities class"""
|
||||||
|
|
||||||
|
import Entity
|
||||||
|
import DistributedEntity
|
||||||
|
import NodePath
|
||||||
|
|
||||||
|
# this is an internal class, do not instantiate.
|
||||||
|
class privNodePathImpl(NodePath.NodePath):
|
||||||
|
def __init__(self, name):
|
||||||
|
node = hidden.attachNewNode(name)
|
||||||
|
NodePath.NodePath.__init__(self, node)
|
||||||
|
|
||||||
|
def initializeEntity(self):
|
||||||
|
self.callSetters(('pos','x','y','z',
|
||||||
|
'hpr','h','p','r',
|
||||||
|
'scale','sx','sx','sz'))
|
||||||
|
|
||||||
|
if hasattr(self, 'parent'):
|
||||||
|
self.level.requestReparent(self, self.parent)
|
||||||
|
|
||||||
|
def destroy(self):
|
||||||
|
self.removeNode()
|
||||||
|
|
||||||
|
class NodePathEntity(Entity.Entity, privNodePathImpl):
|
||||||
|
"""This is an entity that represents a NodePath on the client.
|
||||||
|
It may be instantiated directly or used as a base class for other
|
||||||
|
entity types."""
|
||||||
|
def __init__(self, level, entId):
|
||||||
|
Entity.Entity.__init__(self, level, entId)
|
||||||
|
privNodePathImpl.__init__(self, str(self))
|
||||||
|
self.initializeEntity()
|
||||||
|
|
||||||
|
def initializeEntity(self):
|
||||||
|
Entity.Entity.initializeEntity(self)
|
||||||
|
privNodePathImpl.initializeEntity(self)
|
||||||
|
|
||||||
|
def destroy(self):
|
||||||
|
Entity.Entity.destroy(self)
|
||||||
|
privNodePathImpl.initializeEntity(self)
|
||||||
|
|
||||||
|
class DistributedNodePathEntity(DistributedEntity.DistributedEntity,
|
||||||
|
privNodePathImpl):
|
||||||
|
"""This is a distributed version of NodePathEntity. It should not
|
||||||
|
be instantiated directly; derive your client-side distEntity from
|
||||||
|
this class instead of DistributedEntity."""
|
||||||
|
def __init__(self, cr):
|
||||||
|
DistributedEntity.DistributedEntity.__init__(self, cr)
|
||||||
|
privNodePathImpl.__init__(self, 'DistributedNodePathEntity')
|
||||||
|
|
||||||
|
def initializeEntity(self):
|
||||||
|
DistributedEntity.DistributedEntity.initializeEntity(self)
|
||||||
|
privNodePathImpl.initializeEntity(self)
|
||||||
|
|
||||||
|
def destroy(self):
|
||||||
|
DistributedEntity.DistributedEntity.destroy(self)
|
||||||
|
privNodePathImpl.destroy(self)
|
46
direct/src/level/DistributedEntity.py
Executable file
46
direct/src/level/DistributedEntity.py
Executable file
@ -0,0 +1,46 @@
|
|||||||
|
import DistributedObject
|
||||||
|
import Entity
|
||||||
|
import DirectNotifyGlobal
|
||||||
|
|
||||||
|
class DistributedEntity(DistributedObject.DistributedObject, Entity.Entity):
|
||||||
|
notify = DirectNotifyGlobal.directNotify.newCategory(
|
||||||
|
'DistributedEntity')
|
||||||
|
|
||||||
|
def __init__(self, cr):
|
||||||
|
DistributedObject.DistributedObject.__init__(self, cr)
|
||||||
|
|
||||||
|
def generateInit(self):
|
||||||
|
DistributedEntity.notify.debug('generateInit')
|
||||||
|
DistributedObject.DistributedObject.generateInit(self)
|
||||||
|
# load stuff
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
DistributedEntity.notify.debug('generate')
|
||||||
|
DistributedObject.DistributedObject.generate(self)
|
||||||
|
|
||||||
|
def setLevelDoId(self, levelDoId):
|
||||||
|
DistributedEntity.notify.debug('setLevelDoId: %s' % levelDoId)
|
||||||
|
self.levelDoId = levelDoId
|
||||||
|
|
||||||
|
def setEntId(self, entId):
|
||||||
|
DistributedEntity.notify.debug('setEntId: %s' % entId)
|
||||||
|
self.entId = entId
|
||||||
|
|
||||||
|
def announceGenerate(self):
|
||||||
|
DistributedEntity.notify.debug('announceGenerate')
|
||||||
|
|
||||||
|
# ask our level obj for our spec data
|
||||||
|
level = toonbase.tcr.doId2do[self.levelDoId]
|
||||||
|
Entity.Entity.__init__(self, level, self.entId)
|
||||||
|
# this sets all of our initial spec parameters on ourselves
|
||||||
|
self.initializeEntity()
|
||||||
|
|
||||||
|
DistributedObject.DistributedObject.announceGenerate(self)
|
||||||
|
|
||||||
|
def disable(self):
|
||||||
|
DistributedEntity.notify.debug('disable')
|
||||||
|
# stop things
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
DistributedEntity.notify.debug('delete')
|
||||||
|
# unload things
|
35
direct/src/level/DistributedEntityAI.py
Executable file
35
direct/src/level/DistributedEntityAI.py
Executable file
@ -0,0 +1,35 @@
|
|||||||
|
import DistributedObjectAI
|
||||||
|
import Entity
|
||||||
|
import DirectNotifyGlobal
|
||||||
|
|
||||||
|
class DistributedEntityAI(DistributedObjectAI.DistributedObjectAI,
|
||||||
|
Entity.Entity):
|
||||||
|
notify = DirectNotifyGlobal.directNotify.newCategory(
|
||||||
|
'DistributedEntityAI')
|
||||||
|
|
||||||
|
def __init__(self, air, levelDoId, entId):
|
||||||
|
DistributedObjectAI.DistributedObjectAI.__init__(self, air)
|
||||||
|
self.levelDoId = levelDoId
|
||||||
|
level = self.air.doId2do[self.levelDoId]
|
||||||
|
Entity.Entity.__init__(self, level, entId)
|
||||||
|
# get our spec data
|
||||||
|
self.initializeEntity()
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
self.notify.debug('generate')
|
||||||
|
DistributedObjectAI.DistributedObjectAI.generate(self)
|
||||||
|
|
||||||
|
def destroy(self):
|
||||||
|
self.notify.debug('destroy')
|
||||||
|
Entity.Entity.destroy(self)
|
||||||
|
self.requestDelete()
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
self.notify.debug('delete')
|
||||||
|
DistributedObjectAI.DistributedObjectAI.delete(self)
|
||||||
|
|
||||||
|
def getLevelDoId(self):
|
||||||
|
return self.levelDoId
|
||||||
|
|
||||||
|
def getEntId(self):
|
||||||
|
return self.entId
|
151
direct/src/level/DistributedInteractiveEntity.py
Normal file
151
direct/src/level/DistributedInteractiveEntity.py
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
""" DistributedInteractiveEntity module: contains the DistributedInteractiveEntity
|
||||||
|
class, the client side representation of a 'landmark door'."""
|
||||||
|
|
||||||
|
from ShowBaseGlobal import *
|
||||||
|
from ClockDelta import *
|
||||||
|
|
||||||
|
import DirectNotifyGlobal
|
||||||
|
import FSM
|
||||||
|
import DistributedEntity
|
||||||
|
|
||||||
|
class DistributedInteractiveEntity(DistributedEntity.DistributedEntity):
|
||||||
|
"""
|
||||||
|
DistributedInteractiveEntity class: The client side representation of any
|
||||||
|
simple animated prop.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if __debug__:
|
||||||
|
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedInteractiveEntity')
|
||||||
|
|
||||||
|
def __init__(self, cr):
|
||||||
|
"""constructor for the DistributedInteractiveEntity"""
|
||||||
|
DistributedEntity.DistributedEntity.__init__(self, cr)
|
||||||
|
assert(self.debugPrint("__init()"))
|
||||||
|
|
||||||
|
self.fsm = FSM.FSM('Distribu, levelDoId, entIdtedInteractiveEntity',
|
||||||
|
[State.State('off',
|
||||||
|
self.enterOff,
|
||||||
|
self.exitOff,
|
||||||
|
['playing',
|
||||||
|
'attract']),
|
||||||
|
State.State('attract',
|
||||||
|
self.enterAttract,
|
||||||
|
self.exitAttract,
|
||||||
|
['playing']),
|
||||||
|
State.State('playing',
|
||||||
|
self.enterPlaying,
|
||||||
|
self.exitPlaying,
|
||||||
|
['attract'])],
|
||||||
|
# Initial State
|
||||||
|
'off',
|
||||||
|
# Final State
|
||||||
|
'off',
|
||||||
|
)
|
||||||
|
self.fsm.enterInitialState()
|
||||||
|
# self.generate will be called automatically.
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
"""generate(self)
|
||||||
|
This method is called when the DistributedEntity is reintroduced
|
||||||
|
to the world, either for the first time or from the cache.
|
||||||
|
"""
|
||||||
|
assert(self.debugPrint("generate()"))
|
||||||
|
DistributedEntity.DistributedEntity.generate(self)
|
||||||
|
|
||||||
|
def disable(self):
|
||||||
|
assert(self.debugPrint("disable()"))
|
||||||
|
# Go to the off state when the object is put in the cache
|
||||||
|
self.fsm.request("off")
|
||||||
|
DistributedEntity.DistributedEntity.disable(self)
|
||||||
|
# self.delete() will automatically be called.
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
assert(self.debugPrint("delete()"))
|
||||||
|
del self.fsm
|
||||||
|
DistributedEntity.DistributedEntity.delete(self)
|
||||||
|
|
||||||
|
def setAvatarInteract(self, avatarId):
|
||||||
|
"""
|
||||||
|
required dc field.
|
||||||
|
"""
|
||||||
|
assert(self.debugPrint("setAvatarInteract(%s)"%(avatarId,)))
|
||||||
|
assert(not self.__dict__.has_key(avatarId))
|
||||||
|
self.avatarId=avatarId
|
||||||
|
|
||||||
|
def setOwnerDoId(self, ownerDoId):
|
||||||
|
"""
|
||||||
|
required dc field.
|
||||||
|
"""
|
||||||
|
assert(self.debugPrint("setOwnerDoId(%s)"%(ownerDoId,)))
|
||||||
|
assert(not self.__dict__.has_key("ownerDoId"))
|
||||||
|
self.ownerDoId=ownerDoId
|
||||||
|
|
||||||
|
def setInitialState(self, state, timestamp):
|
||||||
|
"""
|
||||||
|
required dc field.
|
||||||
|
"""
|
||||||
|
assert(self.debugPrint("setInitialState(%s, %d)" % (state, timestamp)))
|
||||||
|
assert(not self.__dict__.has_key("initialState"))
|
||||||
|
self.initialState = state
|
||||||
|
self.initialStateTimestamp = timestamp
|
||||||
|
|
||||||
|
def setState(self, state, timestamp):
|
||||||
|
assert(self.debugPrint("setState(%s, %d)" % (state, timestamp)))
|
||||||
|
self.fsm.request(state, [globalClockDelta.localElapsedTime(timestamp)])
|
||||||
|
|
||||||
|
#def __getPropNodePath(self):
|
||||||
|
# assert(self.debugPrint("__getPropNodePath()"))
|
||||||
|
# if (not self.__dict__.has_key('propNodePath')):
|
||||||
|
# self.propNodePath=self.cr.playGame.hood.loader.geom.find(
|
||||||
|
# "**/prop"+self.entID+":*_DNARoot")
|
||||||
|
# return self.propNodePath
|
||||||
|
|
||||||
|
def enterTrigger(self, args=None):
|
||||||
|
assert(self.debugPrint("enterTrigger(args="+str(args)+")"))
|
||||||
|
messenger.send("DistributedInteractiveEntity_enterTrigger")
|
||||||
|
self.sendUpdate("requestInteract")
|
||||||
|
# the AI server will reply with toonInteract or rejectInteract.
|
||||||
|
|
||||||
|
def exitTrigger(self, args=None):
|
||||||
|
assert(self.debugPrint("exitTrigger(args="+str(args)+")"))
|
||||||
|
messenger.send("DistributedInteractiveEntity_exitTrigger")
|
||||||
|
self.sendUpdate("requestExit")
|
||||||
|
# the AI server will reply with avatarExit.
|
||||||
|
|
||||||
|
def rejectInteract(self):
|
||||||
|
"""Server doesn't let the avatar interact with prop"""
|
||||||
|
assert(self.debugPrint("rejectInteract()"))
|
||||||
|
self.cr.playGame.getPlace().setState('walk')
|
||||||
|
|
||||||
|
def avatarExit(self, avatarId):
|
||||||
|
assert(self.debugPrint("avatarExit(avatarId=%s)"%(avatarId,)))
|
||||||
|
|
||||||
|
##### off state #####
|
||||||
|
|
||||||
|
def enterOff(self):
|
||||||
|
assert(self.debugPrint("enterOff()"))
|
||||||
|
|
||||||
|
def exitOff(self):
|
||||||
|
assert(self.debugPrint("exitOff()"))
|
||||||
|
|
||||||
|
##### attract state #####
|
||||||
|
|
||||||
|
def enterAttract(self, ts):
|
||||||
|
assert(self.debugPrint("enterAttract()"))
|
||||||
|
|
||||||
|
def exitAttract(self):
|
||||||
|
assert(self.debugPrint("exitAttract()"))
|
||||||
|
|
||||||
|
##### playing state #####
|
||||||
|
|
||||||
|
def enterPlaying(self, ts):
|
||||||
|
assert(self.debugPrint("enterPlaying()"))
|
||||||
|
|
||||||
|
def exitPlaying(self):
|
||||||
|
assert(self.debugPrint("exitPlaying()"))
|
||||||
|
|
||||||
|
if __debug__:
|
||||||
|
def debugPrint(self, message):
|
||||||
|
"""for debugging"""
|
||||||
|
return self.notify.debug(
|
||||||
|
str(self.__dict__.get('entId', '?'))+' '+message)
|
144
direct/src/level/DistributedInteractiveEntityAI.py
Normal file
144
direct/src/level/DistributedInteractiveEntityAI.py
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
""" DistributedInteractiveEntityAI module: contains the DistributedInteractiveEntityAI
|
||||||
|
class, the server side representation of a simple, animated, interactive
|
||||||
|
prop."""
|
||||||
|
|
||||||
|
|
||||||
|
from AIBaseGlobal import *
|
||||||
|
from ClockDelta import *
|
||||||
|
|
||||||
|
import DirectNotifyGlobal
|
||||||
|
import FSM
|
||||||
|
import DistributedEntityAI
|
||||||
|
import State
|
||||||
|
|
||||||
|
|
||||||
|
class DistributedInteractiveEntityAI(DistributedEntityAI.DistributedEntityAI):
|
||||||
|
"""
|
||||||
|
DistributedInteractiveEntityAI class: The server side representation of
|
||||||
|
an animated prop. This is the object that remembers what the
|
||||||
|
prop is doing. The child of this object, the DistributedAnimatedProp
|
||||||
|
object, is the client side version and updates the display that
|
||||||
|
client's display based on the state of the prop.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if __debug__:
|
||||||
|
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedInteractiveEntityAI')
|
||||||
|
|
||||||
|
def __init__(self, air, levelDoId, entId):
|
||||||
|
"""entId: a unique identifier for this prop."""
|
||||||
|
DistributedEntityAI.DistributedEntityAI.__init__(self, air,
|
||||||
|
levelDoId, entId)
|
||||||
|
assert(self.debugPrint(
|
||||||
|
"DistributedInteractiveEntityAI(air=%s, entId=%s)"
|
||||||
|
%("the air", entId)))
|
||||||
|
self.fsm = FSM.FSM('DistributedInteractiveEntityAI',
|
||||||
|
[State.State('off',
|
||||||
|
self.enterOff,
|
||||||
|
self.exitOff,
|
||||||
|
['playing']),
|
||||||
|
# Attract is an idle mode. It is named attract
|
||||||
|
# because the prop is not interacting with an
|
||||||
|
# avatar, and is therefore trying to attract an
|
||||||
|
# avatar.
|
||||||
|
State.State('attract',
|
||||||
|
self.enterAttract,
|
||||||
|
self.exitAttract,
|
||||||
|
['playing']),
|
||||||
|
# Playing is for when an avatar is interacting
|
||||||
|
# with the prop.
|
||||||
|
State.State('playing',
|
||||||
|
self.enterPlaying,
|
||||||
|
self.exitPlaying,
|
||||||
|
['attract'])],
|
||||||
|
# Initial State
|
||||||
|
'off',
|
||||||
|
# Final State
|
||||||
|
'off',
|
||||||
|
)
|
||||||
|
self.fsm.enterInitialState()
|
||||||
|
self.avatarId=0
|
||||||
|
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
del self.fsm
|
||||||
|
DistributedEntityAI.DistributedEntityAI.delete(self)
|
||||||
|
|
||||||
|
def getAvatarInteract(self):
|
||||||
|
assert(self.debugPrint("getAvatarInteract() returning: %s"%(self.avatarId,)))
|
||||||
|
return self.avatarId
|
||||||
|
|
||||||
|
def getInitialState(self):
|
||||||
|
assert(self.debugPrint("getInitialState()"))
|
||||||
|
return [self.fsm.getCurrentState().getName(),
|
||||||
|
globalClockDelta.getRealNetworkTime()]
|
||||||
|
|
||||||
|
def getOwnerDoId(self):
|
||||||
|
assert(self.debugPrint("getOwnerDoId() returning: %s"%(self.ownerDoId,)))
|
||||||
|
return self.ownerDoId
|
||||||
|
|
||||||
|
def requestInteract(self):
|
||||||
|
assert(self.debugPrint("requestInteract()"))
|
||||||
|
avatarId = self.air.msgSender
|
||||||
|
assert(self.notify.debug(" avatarId:%s"%(avatarId,)))
|
||||||
|
stateName = self.fsm.getCurrentState().getName()
|
||||||
|
if stateName != 'playing':
|
||||||
|
self.sendUpdate("setAvatarInteract", [avatarId])
|
||||||
|
self.avatarId=avatarId
|
||||||
|
self.fsm.request('playing')
|
||||||
|
else:
|
||||||
|
self.sendUpdateToAvatarId(avatarId, "rejectInteract", [])
|
||||||
|
|
||||||
|
def requestExit(self):
|
||||||
|
assert(self.debugPrint("requestExit()"))
|
||||||
|
avatarId = self.air.msgSender
|
||||||
|
assert(self.notify.debug(" avatarId:%s"%(avatarId,)))
|
||||||
|
if avatarId==self.avatarId:
|
||||||
|
stateName = self.fsm.getCurrentState().getName()
|
||||||
|
if stateName == 'playing':
|
||||||
|
self.sendUpdate("avatarExit", [avatarId])
|
||||||
|
self.fsm.request('attract')
|
||||||
|
else:
|
||||||
|
assert(self.notify.debug(" requestExit: invalid avatarId"))
|
||||||
|
|
||||||
|
def getState(self):
|
||||||
|
assert(self.debugPrint("getState()"))
|
||||||
|
return [self.fsm.getCurrentState().getName(),
|
||||||
|
globalClockDelta.getRealNetworkTime()]
|
||||||
|
|
||||||
|
def d_setState(self, state):
|
||||||
|
assert(self.debugPrint("d_setState(state=%s)"%(state,)))
|
||||||
|
self.sendUpdate('setState', [state, globalClockDelta.getRealNetworkTime()])
|
||||||
|
|
||||||
|
##### off state #####
|
||||||
|
|
||||||
|
def enterOff(self):
|
||||||
|
assert(self.debugPrint("enterOff()"))
|
||||||
|
#self.d_setState('off')
|
||||||
|
|
||||||
|
def exitOff(self):
|
||||||
|
assert(self.debugPrint("exitOff()"))
|
||||||
|
|
||||||
|
##### attract state #####
|
||||||
|
|
||||||
|
def enterAttract(self):
|
||||||
|
assert(self.debugPrint("enterAttract()"))
|
||||||
|
self.d_setState('attract')
|
||||||
|
|
||||||
|
def exitAttract(self):
|
||||||
|
assert(self.debugPrint("exitAttract()"))
|
||||||
|
|
||||||
|
##### open state #####
|
||||||
|
|
||||||
|
def enterPlaying(self):
|
||||||
|
assert(self.debugPrint("enterPlaying()"))
|
||||||
|
self.d_setState('playing')
|
||||||
|
|
||||||
|
def exitPlaying(self):
|
||||||
|
assert(self.debugPrint("exitPlaying()"))
|
||||||
|
|
||||||
|
if __debug__:
|
||||||
|
def debugPrint(self, message):
|
||||||
|
"""for debugging"""
|
||||||
|
return self.notify.debug(
|
||||||
|
str(self.__dict__.get('entId', '?'))+' '+message)
|
||||||
|
|
254
direct/src/level/DistributedLevel.py
Executable file
254
direct/src/level/DistributedLevel.py
Executable file
@ -0,0 +1,254 @@
|
|||||||
|
"""DistributedLevel.py: contains the DistributedLevel class"""
|
||||||
|
|
||||||
|
from ClockDelta import *
|
||||||
|
from PythonUtil import Functor, sameElements, list2dict, uniqueElements
|
||||||
|
import ToontownGlobals
|
||||||
|
import DistributedObject
|
||||||
|
import LevelBase
|
||||||
|
import DirectNotifyGlobal
|
||||||
|
import EntityCreator
|
||||||
|
|
||||||
|
class DistributedLevel(DistributedObject.DistributedObject,
|
||||||
|
LevelBase.LevelBase):
|
||||||
|
"""DistributedLevel"""
|
||||||
|
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedLevel')
|
||||||
|
|
||||||
|
WantVisibility = config.GetBool('level-visibility', 0)
|
||||||
|
HideZones = config.GetBool('level-hidezones', 1)
|
||||||
|
|
||||||
|
def __init__(self, cr):
|
||||||
|
DistributedObject.DistributedObject.__init__(self, cr)
|
||||||
|
LevelBase.LevelBase.__init__(self)
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
self.notify.debug('generate')
|
||||||
|
DistributedObject.DistributedObject.generate(self)
|
||||||
|
|
||||||
|
self.setLevelId(self.doId)
|
||||||
|
|
||||||
|
# this dict stores entity reparents if the parent hasn't been
|
||||||
|
# created yet
|
||||||
|
self.pendingEntId2ParentId = {}
|
||||||
|
|
||||||
|
# Most (if not all) of the timed entities of levels
|
||||||
|
# run on looping intervals that are started once based on
|
||||||
|
# the level's start time.
|
||||||
|
# This sync request is *NOT* guaranteed to finish by the time
|
||||||
|
# the entities get created.
|
||||||
|
# We should listen for any and all time-sync events and re-sync
|
||||||
|
# all our entities at that time.
|
||||||
|
toonbase.tcr.timeManager.synchronize('DistributedLevel.generate')
|
||||||
|
|
||||||
|
# required fields
|
||||||
|
def setZoneIds(self, zoneIds):
|
||||||
|
self.notify.debug('setZoneIds: %s' % zoneIds)
|
||||||
|
self.zoneIds = zoneIds
|
||||||
|
|
||||||
|
def setStartTimestamp(self, timestamp):
|
||||||
|
self.notify.debug('setStartTimestamp: %s' % timestamp)
|
||||||
|
self.startTime = globalClockDelta.networkToLocalTime(timestamp,bits=32)
|
||||||
|
|
||||||
|
def setScenarioIndex(self, scenarioIndex):
|
||||||
|
self.scenarioIndex = scenarioIndex
|
||||||
|
|
||||||
|
def initializeLevel(self, spec):
|
||||||
|
""" subclass should call this as soon as it's located its spec data """
|
||||||
|
LevelBase.LevelBase.initializeLevel(self, spec, self.scenarioIndex)
|
||||||
|
# load stuff
|
||||||
|
self.geom = loader.loadModel(self.spec['modelFilename'])
|
||||||
|
|
||||||
|
def findNumberedNodes(baseString, model=self.geom, self=self):
|
||||||
|
# finds nodes whose name follows the pattern 'baseString#'
|
||||||
|
# where there are no characters after #
|
||||||
|
# returns dictionary that maps # to node
|
||||||
|
potentialNodes = model.findAllMatches(
|
||||||
|
'**/%s*' % baseString).asList()
|
||||||
|
num2node = {}
|
||||||
|
for potentialNode in potentialNodes:
|
||||||
|
name = potentialNode.getName()
|
||||||
|
self.notify.debug('potential match for %s: %s' %
|
||||||
|
(baseString, name))
|
||||||
|
try:
|
||||||
|
num = int(name[len(baseString):])
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
|
||||||
|
num2node[num] = potentialNode
|
||||||
|
|
||||||
|
return num2node
|
||||||
|
|
||||||
|
# find the zones in the model and fix them up
|
||||||
|
self.zoneNum2Node = findNumberedNodes('Zone')
|
||||||
|
# add the UberZone
|
||||||
|
self.zoneNum2Node[0] = self.geom
|
||||||
|
|
||||||
|
# fix up the floor collisions for walkable zones
|
||||||
|
for zoneNum, zoneNode in self.zoneNum2Node.items():
|
||||||
|
# if this is a walkable zone, fix up the model
|
||||||
|
floorColl = zoneNode.find('**/*FloorCollision*')
|
||||||
|
if not floorColl.isEmpty():
|
||||||
|
# rename the floor collision node, and make sure no other
|
||||||
|
# nodes under the ZoneNode have that name
|
||||||
|
floorCollName = 'Zone%sFloor' % zoneNum
|
||||||
|
others = zoneNode.findAllMatches(
|
||||||
|
'**/%s' % floorCollName).asList()
|
||||||
|
for other in others:
|
||||||
|
other.setName('%s_renamed' % floorCollName)
|
||||||
|
floorColl.setName(floorCollName)
|
||||||
|
|
||||||
|
# listen for zone enter events from floor collisions
|
||||||
|
def handleZoneEnter(collisionEntry,
|
||||||
|
self=self, zoneNum=zoneNum):
|
||||||
|
# eat the collisionEntry
|
||||||
|
self.enterZone(zoneNum)
|
||||||
|
self.accept('enter%s' % floorCollName, handleZoneEnter)
|
||||||
|
|
||||||
|
self.zoneNums = self.zoneNum2Node.keys()
|
||||||
|
self.zoneNums.sort()
|
||||||
|
self.notify.debug('zones: %s' % self.zoneNums)
|
||||||
|
assert sameElements(self.zoneNums, self.spec['zones'].keys() + [0])
|
||||||
|
|
||||||
|
# find the doorway nodes
|
||||||
|
self.doorwayNum2Node = findNumberedNodes('Doorway')
|
||||||
|
|
||||||
|
self.initVisibility()
|
||||||
|
|
||||||
|
# create client-side Entities
|
||||||
|
# TODO: only create client-side Entities for the
|
||||||
|
# currently-visible zones?
|
||||||
|
self.localEntities = {}
|
||||||
|
for entId, spec in self.entId2Spec.iteritems():
|
||||||
|
entity = EntityCreator.createEntity(spec['type'], self, entId)
|
||||||
|
if entity is not None:
|
||||||
|
self.localEntities[entId] = entity
|
||||||
|
|
||||||
|
# there should not be any pending reparents left
|
||||||
|
assert len(self.pendingEntId2ParentId) == 0
|
||||||
|
|
||||||
|
def announceGenerate(self):
|
||||||
|
self.notify.debug('announceGenerate')
|
||||||
|
DistributedObject.DistributedObject.announceGenerate(self)
|
||||||
|
|
||||||
|
def disable(self):
|
||||||
|
self.notify.debug('disable')
|
||||||
|
DistributedObject.DistributedObject.disable(self)
|
||||||
|
self.ignoreAll()
|
||||||
|
|
||||||
|
# destroy all of the local entities
|
||||||
|
for entId, entity in self.localEntities.items():
|
||||||
|
entity.destroy()
|
||||||
|
del self.localEntities
|
||||||
|
|
||||||
|
self.destroyLevel()
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
self.notify.debug('delete')
|
||||||
|
DistributedObject.DistributedObject.delete(self)
|
||||||
|
|
||||||
|
def getDoorwayNode(self, doorwayNum):
|
||||||
|
# returns node that doors should parent themselves to
|
||||||
|
return self.doorwayNum2Node[doorwayNum]
|
||||||
|
|
||||||
|
def requestReparent(self, entity, parent):
|
||||||
|
if parent is 'zone':
|
||||||
|
entity.reparentTo(self.zoneNum2Node[entity.zone])
|
||||||
|
else:
|
||||||
|
parentId = parent
|
||||||
|
assert(entity.entId != parentId)
|
||||||
|
|
||||||
|
if self.entities.has_key(parentId):
|
||||||
|
# parent has already been created
|
||||||
|
entity.reparentTo(self.entities[parentId])
|
||||||
|
else:
|
||||||
|
# parent hasn't been created yet; schedule the reparent
|
||||||
|
self.notify.debug(
|
||||||
|
'entity %s requesting reparent to %s, not yet created' %
|
||||||
|
(entity, parent))
|
||||||
|
entId = entity.entId
|
||||||
|
self.pendingEntId2ParentId[entId] = parentId
|
||||||
|
entity.reparentTo(hidden)
|
||||||
|
# do the reparent once the parent is initialized
|
||||||
|
def doReparent(entId=entId, parentId=parentId, self=self):
|
||||||
|
entity=self.getEntity(entId)
|
||||||
|
parent=self.getEntity(parentId)
|
||||||
|
self.notify.debug(
|
||||||
|
'performing pending reparent of %s to %s' %
|
||||||
|
(entity, parent))
|
||||||
|
entity.reparentTo(parent)
|
||||||
|
del self.pendingEntId2ParentId[entId]
|
||||||
|
self.accept(self.getEntityCreateEvent(parentId), doReparent)
|
||||||
|
|
||||||
|
def showZone(self, zoneNum):
|
||||||
|
self.zoneNum2Node[zoneNum].show()
|
||||||
|
|
||||||
|
def hideZone(self, zoneNum):
|
||||||
|
self.zoneNum2Node[zoneNum].hide()
|
||||||
|
|
||||||
|
def setTransparency(self, alpha, zone=None):
|
||||||
|
self.geom.setTransparency(1)
|
||||||
|
if zone is None:
|
||||||
|
node = self.geom
|
||||||
|
else:
|
||||||
|
node = self.zoneNum2Node[zone]
|
||||||
|
node.setAlphaScale(alpha)
|
||||||
|
|
||||||
|
def initVisibility(self):
|
||||||
|
# start out with every zone visible, since none of the zones have
|
||||||
|
# been hidden
|
||||||
|
self.curVisibleZoneNums = list2dict(self.zoneNums)
|
||||||
|
# we have not entered any zone yet
|
||||||
|
self.curZoneNum = None
|
||||||
|
|
||||||
|
# TODO: make this data-driven
|
||||||
|
firstZone = 16
|
||||||
|
self.enterZone(firstZone)
|
||||||
|
|
||||||
|
def enterZone(self, zoneNum):
|
||||||
|
if not DistributedLevel.WantVisibility:
|
||||||
|
return
|
||||||
|
|
||||||
|
if zoneNum == self.curZoneNum:
|
||||||
|
return
|
||||||
|
|
||||||
|
print "enterZone %s" % zoneNum
|
||||||
|
zoneSpec = self.spec['zones'][zoneNum]
|
||||||
|
# use dicts to efficiently ensure that there are no duplicates
|
||||||
|
visibleZoneNums = list2dict([zoneNum])
|
||||||
|
visibleZoneNums.update(list2dict(zoneSpec['visibility']))
|
||||||
|
|
||||||
|
if DistributedLevel.HideZones:
|
||||||
|
# figure out which zones are new and which are going invisible
|
||||||
|
# use dicts because it's faster to use dict.has_key(x)
|
||||||
|
# than 'x in list'
|
||||||
|
addedZoneNums = []
|
||||||
|
removedZoneNums = []
|
||||||
|
allVZ = dict(visibleZoneNums)
|
||||||
|
allVZ.update(self.curVisibleZoneNums)
|
||||||
|
for vz,None in allVZ.items():
|
||||||
|
new = vz in visibleZoneNums
|
||||||
|
old = vz in self.curVisibleZoneNums
|
||||||
|
if new and old:
|
||||||
|
continue
|
||||||
|
if new:
|
||||||
|
addedZoneNums.append(vz)
|
||||||
|
else:
|
||||||
|
removedZoneNums.append(vz)
|
||||||
|
# show the new, hide the old
|
||||||
|
self.notify.debug('showing zones %s' % addedZoneNums)
|
||||||
|
for az in addedZoneNums:
|
||||||
|
self.showZone(az)
|
||||||
|
self.notify.debug('hiding zones %s' % removedZoneNums)
|
||||||
|
for rz in removedZoneNums:
|
||||||
|
self.hideZone(rz)
|
||||||
|
|
||||||
|
# convert the zone numbers into their actual zoneIds
|
||||||
|
# always include Toontown and factory uberZones
|
||||||
|
visibleZoneIds = [ToontownGlobals.UberZone, self.getZoneId(0)]
|
||||||
|
for vz in visibleZoneNums.keys():
|
||||||
|
visibleZoneIds.append(self.getZoneId(vz))
|
||||||
|
assert(uniqueElements(visibleZoneIds))
|
||||||
|
self.notify.debug('new viz list: %s' % visibleZoneIds)
|
||||||
|
|
||||||
|
toonbase.tcr.sendSetZoneMsg(self.getZoneId(zoneNum), visibleZoneIds)
|
||||||
|
self.curZoneNum = zoneNum
|
||||||
|
self.curVisibleZoneNums = visibleZoneNums
|
80
direct/src/level/DistributedLevelAI.py
Executable file
80
direct/src/level/DistributedLevelAI.py
Executable file
@ -0,0 +1,80 @@
|
|||||||
|
"""DistributedLevelAI.py: contains the DistributedLevelAI class"""
|
||||||
|
|
||||||
|
from ClockDelta import *
|
||||||
|
import DistributedObjectAI
|
||||||
|
import LevelBase
|
||||||
|
import DirectNotifyGlobal
|
||||||
|
import EntityCreatorAI
|
||||||
|
import WeightedChoice
|
||||||
|
|
||||||
|
class DistributedLevelAI(DistributedObjectAI.DistributedObjectAI,
|
||||||
|
LevelBase.LevelBase):
|
||||||
|
"""DistributedLevelAI"""
|
||||||
|
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedLevelAI')
|
||||||
|
|
||||||
|
def __init__(self, air):
|
||||||
|
DistributedObjectAI.DistributedObjectAI.__init__(self, air)
|
||||||
|
LevelBase.LevelBase.__init__(self)
|
||||||
|
|
||||||
|
def initializeLevel(self, spec, uberZoneId):
|
||||||
|
self.uberZoneId = uberZoneId
|
||||||
|
|
||||||
|
# choose a scenario
|
||||||
|
wc = WeightedChoice.WeightedChoice(spec['scenarios'], 1)
|
||||||
|
scenario = wc.choose()
|
||||||
|
scenarioIndex = spec['scenarios'].index(scenario)
|
||||||
|
|
||||||
|
LevelBase.LevelBase.initializeLevel(self, spec, scenarioIndex)
|
||||||
|
|
||||||
|
# allocate the rest of the zones; add one for the uber-zone
|
||||||
|
self.numZones = len(self.spec['zones']) + 1
|
||||||
|
self.zoneIds = [self.uberZoneId]
|
||||||
|
for i in range(1,self.numZones):
|
||||||
|
# there is error checking in air.allocateZone
|
||||||
|
self.zoneIds.append(self.air.allocateZone())
|
||||||
|
|
||||||
|
# record the level's start time so that we can sync the clients
|
||||||
|
self.startTime = globalClock.getRealTime()
|
||||||
|
self.startTimestamp = globalClockDelta.localToNetworkTime(
|
||||||
|
self.startTime, bits=32)
|
||||||
|
|
||||||
|
# required-field getters
|
||||||
|
def getZoneIds(self):
|
||||||
|
return self.zoneIds
|
||||||
|
|
||||||
|
def getStartTimestamp(self):
|
||||||
|
return self.startTimestamp
|
||||||
|
|
||||||
|
def getScenarioIndex(self):
|
||||||
|
return self.scenarioIndex
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
self.notify.debug('generate')
|
||||||
|
DistributedObjectAI.DistributedObjectAI.generate(self)
|
||||||
|
|
||||||
|
self.setLevelId(self.doId)
|
||||||
|
|
||||||
|
# create the Entities
|
||||||
|
self.aiEntities = {}
|
||||||
|
for entId, spec in self.entId2Spec.iteritems():
|
||||||
|
self.notify.debug('creating %s %s' % (spec['type'], entId))
|
||||||
|
entity = EntityCreatorAI.createEntity(
|
||||||
|
spec['type'], self.air, self.doId, entId,
|
||||||
|
self.getZoneId(spec['zone']))
|
||||||
|
if entity is not None:
|
||||||
|
self.aiEntities[entId] = entity
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
self.notify.debug('delete')
|
||||||
|
|
||||||
|
for entId in self.aiEntities.keys():
|
||||||
|
self.aiEntities[entId].destroy()
|
||||||
|
del self.aiEntities
|
||||||
|
|
||||||
|
# we do not allocate the uberZone for now, so don't deallocate it
|
||||||
|
for zoneId in self.zoneIds[1:]:
|
||||||
|
self.air.deallocateZone(zoneId)
|
||||||
|
|
||||||
|
self.destroyLevel()
|
||||||
|
|
||||||
|
DistributedObjectAI.DistributedObjectAI.delete(self)
|
74
direct/src/level/Entity.py
Executable file
74
direct/src/level/Entity.py
Executable file
@ -0,0 +1,74 @@
|
|||||||
|
"""Entity.py: contains the Entity class"""
|
||||||
|
|
||||||
|
import string
|
||||||
|
|
||||||
|
class Entity:
|
||||||
|
"""Entity is the base class for all objects that exist in a Level
|
||||||
|
and can be edited with the LevelEditor."""
|
||||||
|
|
||||||
|
# these are values that can be changed in the level editor
|
||||||
|
# TODO: pick a good name for these values;
|
||||||
|
# parameters, tweakables, attributes, attribs, traits,
|
||||||
|
Tweakables = (
|
||||||
|
# Name, PythonType, CallSetterOnInitialization
|
||||||
|
('name', str, 0),
|
||||||
|
('comment', str, 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, level, entId, tweakables=None):
|
||||||
|
self.level = level
|
||||||
|
self.entId = entId
|
||||||
|
|
||||||
|
self.tweakables = Entity.Tweakables
|
||||||
|
# add any additional tweakable values
|
||||||
|
if tweakables is not None:
|
||||||
|
self.tweakables.update(tweakables)
|
||||||
|
|
||||||
|
# TODO: funcs to populate the entity with its spec data, and system
|
||||||
|
# to call back when data changes
|
||||||
|
def initializeEntity(self):
|
||||||
|
"""Call this once on initialization to set this entity's
|
||||||
|
spec data"""
|
||||||
|
self.level.initializeEntity(self)
|
||||||
|
|
||||||
|
def destroy(self):
|
||||||
|
del self.level
|
||||||
|
|
||||||
|
def privGetSetter(self, attrib):
|
||||||
|
setFuncName = 'set%s%s' % (string.upper(attrib[0]), attrib[1:])
|
||||||
|
if hasattr(self, setFuncName):
|
||||||
|
return getattr(self, setFuncName)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def callSetters(self, attribList):
|
||||||
|
"""call this with a list of attribs, and any that exist on the
|
||||||
|
entity and have setters will be passed to their setter"""
|
||||||
|
for attrib in attribList:
|
||||||
|
if hasattr(self, attrib):
|
||||||
|
setter = self.privGetSetter(attrib)
|
||||||
|
if setter is not None:
|
||||||
|
setter(getattr(self, attrib))
|
||||||
|
|
||||||
|
def paramChanged(self):
|
||||||
|
"""This is called when a parameter is tweaked and no setter
|
||||||
|
is called; i.e. the value is set directly on the object.
|
||||||
|
Some Entities might want to completely reset every time anything
|
||||||
|
is tweaked; this is the place to do it; override this func in your
|
||||||
|
derived class
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def getTweakables(self):
|
||||||
|
return self.tweakables
|
||||||
|
|
||||||
|
def privTweak(self, name, value):
|
||||||
|
self.__dict__[name] = value
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'ent%s(%s)' % (self.entId, self.level.getEntityType(self.entId))
|
||||||
|
|
||||||
|
if __debug__:
|
||||||
|
def debugPrint(self, message):
|
||||||
|
"""for debugging"""
|
||||||
|
return self.notify.debug(
|
||||||
|
str(self.__dict__.get('entId', '?'))+' '+message)
|
35
direct/src/level/EntityCreator.py
Executable file
35
direct/src/level/EntityCreator.py
Executable file
@ -0,0 +1,35 @@
|
|||||||
|
"""EntityCreator.py: contains methods for creation of Entities"""
|
||||||
|
|
||||||
|
from PythonUtil import Functor
|
||||||
|
import PlatformEntity
|
||||||
|
import BasicEntities
|
||||||
|
|
||||||
|
def nothing(level, entId):
|
||||||
|
"""For entities that don't need to be created by the client"""
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Client-side entity ctors:
|
||||||
|
EntityType2Ctor = {
|
||||||
|
# Map entity type name to constructor function that takes
|
||||||
|
# (level, entId)
|
||||||
|
'beanBarrel': nothing,
|
||||||
|
'door': nothing,
|
||||||
|
'gagBarrel': nothing,
|
||||||
|
'lift': nothing,
|
||||||
|
'nodepath': BasicEntities.NodePathEntity,
|
||||||
|
#'platform': PlatformEntity.PlatformEntity,
|
||||||
|
'stomper': nothing,
|
||||||
|
'switch': nothing,
|
||||||
|
|
||||||
|
'andLogicObject': nothing,
|
||||||
|
'orLogicObject': nothing,
|
||||||
|
'xorLogicObject': nothing, #XorLoEntity.XorLoEntity,
|
||||||
|
}
|
||||||
|
|
||||||
|
# TODO: what other args will be required?
|
||||||
|
def createEntity(entType, level, entId):
|
||||||
|
if not EntityType2Ctor.has_key(entType):
|
||||||
|
print "createEntity(entType=%s, entId=%s) not found"%(
|
||||||
|
entType, entId)
|
||||||
|
return None
|
||||||
|
return EntityType2Ctor[entType](level, entId)
|
49
direct/src/level/EntityCreatorAI.py
Executable file
49
direct/src/level/EntityCreatorAI.py
Executable file
@ -0,0 +1,49 @@
|
|||||||
|
"""EntityCreatorAI.py: contains methods for creation of Entities"""
|
||||||
|
|
||||||
|
from PythonUtil import Functor
|
||||||
|
import DistributedBeanBarrelAI
|
||||||
|
import DistributedLiftAI
|
||||||
|
import DistributedDoorEntityAI
|
||||||
|
import DistributedGagBarrelAI
|
||||||
|
#import DistributedStomperPairAI
|
||||||
|
import DistributedSwitchAI
|
||||||
|
import DistributedStomperAI
|
||||||
|
import AndLoEntityAI
|
||||||
|
import OrLoEntityAI
|
||||||
|
#import XorLoEntity
|
||||||
|
|
||||||
|
|
||||||
|
def cDE(AIclass, air, levelDoId, entId, zoneId):
|
||||||
|
"""create a distributed entity"""
|
||||||
|
ent = AIclass(air, levelDoId, entId)
|
||||||
|
ent.generateWithRequired(zoneId)
|
||||||
|
return ent
|
||||||
|
|
||||||
|
def nothing(air, levelDoId, entId, zoneId):
|
||||||
|
"""Create entity that doesn't have a server side representation."""
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Server (AI) side factory functions:
|
||||||
|
EntityType2Ctor = {
|
||||||
|
# Map entity type name to constructor function that takes
|
||||||
|
# (air, level doId, entId, zoneId)
|
||||||
|
'beanBarrel': Functor(cDE, DistributedBeanBarrelAI.DistributedBeanBarrelAI),
|
||||||
|
'door': DistributedDoorEntityAI.DistributedDoorEntityAI,
|
||||||
|
'gagBarrel': Functor(cDE, DistributedGagBarrelAI.DistributedGagBarrelAI),
|
||||||
|
'lift': Functor(cDE, DistributedLiftAI.DistributedLiftAI),
|
||||||
|
'nodepath': nothing,
|
||||||
|
'platform': nothing,
|
||||||
|
'stomper': Functor(cDE, DistributedStomperAI.DistributedStomperAI),
|
||||||
|
'switch': DistributedSwitchAI.DistributedSwitchAI,
|
||||||
|
|
||||||
|
'andLogicObject': AndLoEntityAI.AndLoEntityAI,
|
||||||
|
'orLogicObject': OrLoEntityAI.OrLoEntityAI,
|
||||||
|
'xorLogicObject': nothing, #XorLoEntity.XorLoEntity,
|
||||||
|
}
|
||||||
|
|
||||||
|
def createEntity(entType, air, levelDoId, entId, zoneId):
|
||||||
|
if not EntityType2Ctor.has_key(entType):
|
||||||
|
print "createEntity(entType=%s, air=%s, levelDoId=%s, entId=%s, zoneId=%s) not found"%(
|
||||||
|
entType, "the air", levelDoId, entId, zoneId)
|
||||||
|
return None
|
||||||
|
return EntityType2Ctor[entType](air, levelDoId, entId, zoneId)
|
91
direct/src/level/LevelBase.py
Executable file
91
direct/src/level/LevelBase.py
Executable file
@ -0,0 +1,91 @@
|
|||||||
|
"""LevelBase.py: contains the LevelBase class"""
|
||||||
|
|
||||||
|
import DirectNotifyGlobal
|
||||||
|
import string
|
||||||
|
|
||||||
|
class LevelBase:
|
||||||
|
"""LevelBase: shared client and AI code
|
||||||
|
representation of a game level, keeps track of all of the
|
||||||
|
Level Entities and their interrelations"""
|
||||||
|
notify = DirectNotifyGlobal.directNotify.newCategory('LevelBase')
|
||||||
|
|
||||||
|
def __init__(self, levelId=None):
|
||||||
|
if levelId is not None:
|
||||||
|
self.setLevelId(levelId)
|
||||||
|
|
||||||
|
def setLevelId(self, levelId):
|
||||||
|
self.levelId = levelId
|
||||||
|
|
||||||
|
def initializeLevel(self, spec, scenarioIndex):
|
||||||
|
""" subclass should call this as soon as it has located
|
||||||
|
its spec data """
|
||||||
|
self.spec = spec
|
||||||
|
self.scenarioIndex = scenarioIndex
|
||||||
|
|
||||||
|
# create a complete set of global and scenario-specific entity specs
|
||||||
|
globalEntities = self.spec['globalEntities']
|
||||||
|
scenarioEntities = self.spec['scenarios'][self.scenarioIndex][0]
|
||||||
|
entId2Spec = {}
|
||||||
|
entId2Spec.update(globalEntities)
|
||||||
|
entId2Spec.update(scenarioEntities)
|
||||||
|
self.entId2Spec = entId2Spec
|
||||||
|
|
||||||
|
# this will be filled in as the entities are created and report in
|
||||||
|
self.entities = {}
|
||||||
|
|
||||||
|
def destroyLevel(self):
|
||||||
|
del self.entities
|
||||||
|
del self.entId2Spec
|
||||||
|
del self.spec
|
||||||
|
|
||||||
|
def initializeEntity(self, entity):
|
||||||
|
"""populate an entity with its spec data"""
|
||||||
|
entId = entity.entId
|
||||||
|
spec = self.entId2Spec[entId]
|
||||||
|
# on initialization, set items directly on entity
|
||||||
|
for key,value in spec.items():
|
||||||
|
if key in ('type', 'name', 'comment',):
|
||||||
|
continue
|
||||||
|
if hasattr(entity, key):
|
||||||
|
self.notify.warning('entity %s (%s) already has member %s' %
|
||||||
|
(entId, spec['type'], key))
|
||||||
|
entity.__dict__[key] = value
|
||||||
|
|
||||||
|
# entity is initialized, add it to the list of entities
|
||||||
|
self.entities[entity.entId] = entity
|
||||||
|
# send the create event
|
||||||
|
messenger.send(self.getEntityCreateEvent(entity.entId))
|
||||||
|
|
||||||
|
"""
|
||||||
|
# set items directly on entity, or call callback functions...
|
||||||
|
for key,value in spec.items():
|
||||||
|
# filter out some entries; we might want to restructure the
|
||||||
|
# spec data into different categories of properties instead
|
||||||
|
# of filtering them here
|
||||||
|
if key in ('type', 'name', 'comment', 'zone',):
|
||||||
|
continue
|
||||||
|
setFuncName = 'set%s%s' % (string.upper(key[0]), key[1:])
|
||||||
|
if hasattr(entity, setFuncName):
|
||||||
|
# call the setter
|
||||||
|
func = getattr(entity, setFuncName)
|
||||||
|
func(value)
|
||||||
|
else:
|
||||||
|
# set the param directly on the object
|
||||||
|
entity.__dict__[key] = value
|
||||||
|
"""
|
||||||
|
|
||||||
|
def getEntityCreateEvent(self, entId):
|
||||||
|
"""This is the event that is thrown immediately after an entity
|
||||||
|
is initialized"""
|
||||||
|
return 'entityCreate-%s-%s' % (self.levelId, entId)
|
||||||
|
|
||||||
|
def getEntity(self, entId):
|
||||||
|
return self.entities[entId]
|
||||||
|
|
||||||
|
def getEntityType(self, entId):
|
||||||
|
return self.entId2Spec[entId]['type']
|
||||||
|
|
||||||
|
def getZoneId(self, index):
|
||||||
|
# get the actual zoneId for this index
|
||||||
|
# TODO: perhaps the zones should be fixed up in the specs
|
||||||
|
return self.zoneIds[index]
|
56
direct/src/level/NandLoEntityAI.py
Executable file
56
direct/src/level/NandLoEntityAI.py
Executable file
@ -0,0 +1,56 @@
|
|||||||
|
"""NandLoEntityAI.py: contains the NandLoEntity class"""
|
||||||
|
|
||||||
|
|
||||||
|
import PandaObject
|
||||||
|
import DirectNotifyGlobal
|
||||||
|
import Entity
|
||||||
|
|
||||||
|
|
||||||
|
class NandLoEntityAI(Entity.Entity, PandaObject.PandaObject):
|
||||||
|
if __debug__:
|
||||||
|
notify = DirectNotifyGlobal.directNotify.newCategory(
|
||||||
|
'NandLoEntityAI')
|
||||||
|
|
||||||
|
def __init__(self, air, levelDoId, entId, zoneId=None):
|
||||||
|
"""entId: """
|
||||||
|
assert(self.debugPrint(
|
||||||
|
"NandLoEntityAI(air=%s, levelDoId=%s, entId=%s, zoneId=%s)"
|
||||||
|
%("the air", levelDoId, entId, zoneId)))
|
||||||
|
self.input1 = None
|
||||||
|
self.input2 = None
|
||||||
|
self.levelDoId = levelDoId
|
||||||
|
level = air.doId2do[self.levelDoId]
|
||||||
|
Entity.Entity.__init__(self, level, entId)
|
||||||
|
self.initializeEntity()
|
||||||
|
self.setInput_input1_bool(self.input_input1_bool)
|
||||||
|
self.setInput_input2_bool(self.input_input2_bool)
|
||||||
|
|
||||||
|
def setIsInput1(self, isTrue):
|
||||||
|
assert(self.debugPrint("setIsInput1(isTrue=%s)"%(isTrue,)))
|
||||||
|
self.isInput1=isTrue
|
||||||
|
messenger.send(self.getName(), [not (isTrue or self.isInput2)])
|
||||||
|
|
||||||
|
def setIsInput2(self, isTrue):
|
||||||
|
assert(self.debugPrint("setIsInput1(isTrue=%s)"%(isTrue,)))
|
||||||
|
self.isInput2=isTrue
|
||||||
|
messenger.send(self.getName(), [not (isTrue or self.isInput1)])
|
||||||
|
|
||||||
|
def setInput_input1_bool(self, event):
|
||||||
|
assert(self.debugPrint("setInput_input1_bool(event=%s)"%(event,)))
|
||||||
|
if self.input1:
|
||||||
|
self.ignore(self.input1)
|
||||||
|
self.input1 = "switch-%s"%(event,)
|
||||||
|
if self.input1:
|
||||||
|
self.accept(self.input1, self.setIsInput1)
|
||||||
|
|
||||||
|
def setInput_input2_bool(self, event):
|
||||||
|
assert(self.debugPrint("setInput_input2_bool(event=%s)"%(event,)))
|
||||||
|
if self.input2:
|
||||||
|
self.ignore(self.input2)
|
||||||
|
self.input2 = "switch-%s"%(event,)
|
||||||
|
if self.input2:
|
||||||
|
self.accept(self.input2, self.setIsInput2)
|
||||||
|
|
||||||
|
def getName(self):
|
||||||
|
#return "NandLoEntity-%s"%(self.entId,)
|
||||||
|
return "switch-%s"%(self.entId,)
|
19
direct/src/level/OrLoEntity.py
Executable file
19
direct/src/level/OrLoEntity.py
Executable file
@ -0,0 +1,19 @@
|
|||||||
|
"""OrLoEntity.py: contains the OrLoEntity class"""
|
||||||
|
|
||||||
|
class OrLoEntity(Entity.Entity):
|
||||||
|
if __debug__:
|
||||||
|
notify = DirectNotifyGlobal.directNotify.newCategory(
|
||||||
|
'OrLoEntity')
|
||||||
|
|
||||||
|
def __init__(self, air, levelDoId, entId, zoneId=None):
|
||||||
|
"""entId: """
|
||||||
|
assert(self.debugPrint(
|
||||||
|
"DistributedDoorEntityAI(air=%s, levelDoId=%s, entId=%s, zoneId=%s)"
|
||||||
|
%("the air", levelDoId, entId, zoneId)))
|
||||||
|
self.doLaterTask=None
|
||||||
|
self.isOpenInput = None
|
||||||
|
DistributedInteractiveEntityAI.DistributedInteractiveEntityAI.__init__(
|
||||||
|
self, air, levelDoId, entId)
|
||||||
|
self.fsm.setName('DistributedDoorEntity')
|
||||||
|
if zoneId is not None:
|
||||||
|
self.generateWithRequired(zoneId)
|
60
direct/src/level/OrLoEntityAI.py
Executable file
60
direct/src/level/OrLoEntityAI.py
Executable file
@ -0,0 +1,60 @@
|
|||||||
|
"""OrLoEntityAI.py: contains the OrLoEntity class"""
|
||||||
|
|
||||||
|
|
||||||
|
import PandaObject
|
||||||
|
import DirectNotifyGlobal
|
||||||
|
import Entity
|
||||||
|
|
||||||
|
|
||||||
|
class OrLoEntityAI(Entity.Entity, PandaObject.PandaObject):
|
||||||
|
if __debug__:
|
||||||
|
notify = DirectNotifyGlobal.directNotify.newCategory(
|
||||||
|
'OrLoEntityAI')
|
||||||
|
|
||||||
|
def __init__(self, air, levelDoId, entId, zoneId=None):
|
||||||
|
"""entId: """
|
||||||
|
assert(self.debugPrint(
|
||||||
|
"OrLoEntityAI(air=%s, levelDoId=%s, entId=%s, zoneId=%s)"
|
||||||
|
%("the air", levelDoId, entId, zoneId)))
|
||||||
|
self.input1 = None
|
||||||
|
self.input2 = None
|
||||||
|
self.levelDoId = levelDoId
|
||||||
|
level = air.doId2do[self.levelDoId]
|
||||||
|
Entity.Entity.__init__(self, level, entId)
|
||||||
|
self.initializeEntity()
|
||||||
|
self.setInput_input1_bool(self.input_input1_bool)
|
||||||
|
self.setInput_input2_bool(self.input_input2_bool)
|
||||||
|
|
||||||
|
def setIsInput1(self, isTrue):
|
||||||
|
assert(self.debugPrint("setIsInput1(isTrue=%s)"%(isTrue,)))
|
||||||
|
self.isInput1=isTrue
|
||||||
|
if not self.isInput2:
|
||||||
|
# ...we already sent the messege when input2 was set.
|
||||||
|
messenger.send(self.getName(), [isTrue])
|
||||||
|
|
||||||
|
def setIsInput2(self, isTrue):
|
||||||
|
assert(self.debugPrint("setIsInput1(isTrue=%s)"%(isTrue,)))
|
||||||
|
self.isInput2=isTrue
|
||||||
|
if not self.isInput1:
|
||||||
|
# ...we already sent the messege when input1 was set.
|
||||||
|
messenger.send(self.getName(), [isTrue])
|
||||||
|
|
||||||
|
def setInput_input1_bool(self, event):
|
||||||
|
assert(self.debugPrint("setInput_input1_bool(event=%s)"%(event,)))
|
||||||
|
if self.input1:
|
||||||
|
self.ignore(self.input1)
|
||||||
|
self.input1 = "switch-%s"%(event,)
|
||||||
|
if self.input1:
|
||||||
|
self.accept(self.input1, self.setIsInput1)
|
||||||
|
|
||||||
|
def setInput_input2_bool(self, event):
|
||||||
|
assert(self.debugPrint("setInput_input2_bool(event=%s)"%(event,)))
|
||||||
|
if self.input2:
|
||||||
|
self.ignore(self.input2)
|
||||||
|
self.input2 = "switch-%s"%(event,)
|
||||||
|
if self.input2:
|
||||||
|
self.accept(self.input2, self.setIsInput2)
|
||||||
|
|
||||||
|
def getName(self):
|
||||||
|
#return "orLoEntity-%s"%(self.entId,)
|
||||||
|
return "switch-%s"%(self.entId,)
|
3
direct/src/level/Sources.pp
Normal file
3
direct/src/level/Sources.pp
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
// For now, since we are not installing Python files, this file can
|
||||||
|
// remain empty.
|
||||||
|
|
0
direct/src/level/XorLoEntity.py
Executable file
0
direct/src/level/XorLoEntity.py
Executable file
56
direct/src/level/XorLoEntityAI.py
Executable file
56
direct/src/level/XorLoEntityAI.py
Executable file
@ -0,0 +1,56 @@
|
|||||||
|
"""XorLoEntityAI.py: contains the XorLoEntity class"""
|
||||||
|
|
||||||
|
|
||||||
|
import PandaObject
|
||||||
|
import DirectNotifyGlobal
|
||||||
|
import Entity
|
||||||
|
|
||||||
|
|
||||||
|
class XorLoEntityAI(Entity.Entity, PandaObject.PandaObject):
|
||||||
|
if __debug__:
|
||||||
|
notify = DirectNotifyGlobal.directNotify.newCategory(
|
||||||
|
'XorLoEntityAI')
|
||||||
|
|
||||||
|
def __init__(self, air, levelDoId, entId, zoneId=None):
|
||||||
|
"""entId: """
|
||||||
|
assert(self.debugPrint(
|
||||||
|
"XorLoEntityAI(air=%s, levelDoId=%s, entId=%s, zoneId=%s)"
|
||||||
|
%("the air", levelDoId, entId, zoneId)))
|
||||||
|
self.input1 = None
|
||||||
|
self.input2 = None
|
||||||
|
self.levelDoId = levelDoId
|
||||||
|
level = air.doId2do[self.levelDoId]
|
||||||
|
Entity.Entity.__init__(self, level, entId)
|
||||||
|
self.initializeEntity()
|
||||||
|
self.setInput_input1_bool(self.input_input1_bool)
|
||||||
|
self.setInput_input2_bool(self.input_input2_bool)
|
||||||
|
|
||||||
|
def setIsInput1(self, isTrue):
|
||||||
|
assert(self.debugPrint("setIsInput1(isTrue=%s)"%(isTrue,)))
|
||||||
|
self.isInput1=isTrue
|
||||||
|
messenger.send(self.getName(), [(not (isTrue and self.isInput2)) and (isTrue or self.isInput2)])
|
||||||
|
|
||||||
|
def setIsInput2(self, isTrue):
|
||||||
|
assert(self.debugPrint("setIsInput1(isTrue=%s)"%(isTrue,)))
|
||||||
|
self.isInput2=isTrue
|
||||||
|
messenger.send(self.getName(), [(not (isTrue and self.isInput2)) and (isTrue or self.isInput2)])
|
||||||
|
|
||||||
|
def setInput_input1_bool(self, event):
|
||||||
|
assert(self.debugPrint("setInput_input1_bool(event=%s)"%(event,)))
|
||||||
|
if self.input1:
|
||||||
|
self.ignore(self.input1)
|
||||||
|
self.input1 = "switch-%s"%(event,)
|
||||||
|
if self.input1:
|
||||||
|
self.accept(self.input1, self.setIsInput1)
|
||||||
|
|
||||||
|
def setInput_input2_bool(self, event):
|
||||||
|
assert(self.debugPrint("setInput_input2_bool(event=%s)"%(event,)))
|
||||||
|
if self.input2:
|
||||||
|
self.ignore(self.input2)
|
||||||
|
self.input2 = "switch-%s"%(event,)
|
||||||
|
if self.input2:
|
||||||
|
self.accept(self.input2, self.setIsInput2)
|
||||||
|
|
||||||
|
def getName(self):
|
||||||
|
#return "xorLoEntity-%s"%(self.entId,)
|
||||||
|
return "switch-%s"%(self.entId,)
|
Loading…
x
Reference in New Issue
Block a user